| @@ -0,0 +1,46 @@ | |||
| ###################################################################### | |||
| # Build Tools | |||
| .gradle | |||
| /build/ | |||
| !gradle/wrapper/gradle-wrapper.jar | |||
| target/ | |||
| !.mvn/wrapper/maven-wrapper.jar | |||
| ###################################################################### | |||
| # IDE | |||
| ### STS ### | |||
| .apt_generated | |||
| .classpath | |||
| .factorypath | |||
| .project | |||
| .settings | |||
| .springBeans | |||
| ### IntelliJ IDEA ### | |||
| .idea | |||
| *.iws | |||
| *.iml | |||
| *.ipr | |||
| ### JRebel ### | |||
| rebel.xml | |||
| ### NetBeans ### | |||
| nbproject/private/ | |||
| build/* | |||
| nbbuild/ | |||
| dist/ | |||
| nbdist/ | |||
| .nb-gradle/ | |||
| ###################################################################### | |||
| # Others | |||
| *.log | |||
| *.xml.versionsBackup | |||
| *.swp | |||
| !*/build/*.java | |||
| !*/build/*.html | |||
| !*/build/*.xml | |||
| @@ -0,0 +1,20 @@ | |||
| The MIT License (MIT) | |||
| Copyright (c) 2018 RuoYi | |||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | |||
| this software and associated documentation files (the "Software"), to deal in | |||
| the Software without restriction, including without limitation the rights to | |||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | |||
| the Software, and to permit persons to whom the Software is furnished to do so, | |||
| subject to the following conditions: | |||
| The above copyright notice and this permission notice shall be included in all | |||
| copies or substantial portions of the Software. | |||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | |||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | |||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
| @@ -0,0 +1,102 @@ | |||
| <p align="center"> | |||
| <img alt="logo" src="https://oscimg.oschina.net/oscnet/up-dd77653d7c9f197dd9d93684f3c8dcfbab6.png"> | |||
| </p> | |||
| <h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v4.7.9</h1> | |||
| <h4 align="center">基于SpringBoot开发的轻量级Java快速开发框架</h4> | |||
| <p align="center"> | |||
| <a href="https://gitee.com/y_project/RuoYi/stargazers"><img src="https://gitee.com/y_project/RuoYi/badge/star.svg?theme=gvp"></a> | |||
| <a href="https://gitee.com/y_project/RuoYi"><img src="https://img.shields.io/badge/RuoYi-v4.7.9-brightgreen.svg"></a> | |||
| <a href="https://gitee.com/y_project/RuoYi/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a> | |||
| </p> | |||
| ## 平台简介 | |||
| 一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适的。于是利用空闲休息时间开始自己写了一套后台系统。如此有了。她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。 | |||
| 性别男,是给女儿取的名字(寓意:你若不离不弃,我必生死相依) | |||
| 是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 | |||
| * 前后端分离版本,请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud) | |||
| * 感谢 [hplus](https://gitee.com/hplus_admin/hplus) 后台主题 UI 框架。 | |||
| * 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip) | |||
| * 阿里云优惠券:[点我领取](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console) | |||
| ## 内置功能 | |||
| 1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 | |||
| 2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 | |||
| 3. 岗位管理:配置系统用户所属担任职务。 | |||
| 4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 | |||
| 5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 | |||
| 6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 | |||
| 7. 参数管理:对系统动态配置常用参数。 | |||
| 8. 通知公告:系统通知公告信息发布维护。 | |||
| 9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 | |||
| 10. 登录日志:系统登录日志记录查询包含登录异常。 | |||
| 11. 在线用户:当前系统中活跃用户状态监控。 | |||
| 12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 | |||
| 13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 | |||
| 14. 系统接口:根据业务代码自动生成相关的api接口文档。 | |||
| 15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 | |||
| 16. 缓存监控:对系统的缓存查询,删除、清空等操作。 | |||
| 17. 在线构建器:拖动表单元素生成相应的HTML代码。 | |||
| 18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 | |||
| ## 在线体验 | |||
| - admin/admin123 | |||
| - 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。 | |||
| 演示地址:http://ruoyi.vip | |||
| 文档地址:http://doc.ruoyi.vip | |||
| ## 演示图 | |||
| <table> | |||
| <tr> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-42e518aa72a24d228427a1261cb3679f395.png"/></td> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-7f20dd0edba25e5187c5c4dd3ec7d3d9797.png"/></td> | |||
| </tr> | |||
| <tr> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-2dae3d87f6a8ca05057db059cd9a411d51d.png"/></td> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-ea4d98423471e55fba784694e45d12bd4bb.png"/></td> | |||
| </tr> | |||
| <tr> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-7f6c6e9f5873efca09bd2870ee8468b8fce.png"/></td> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-c708b65f2c382a03f69fe1efa8d341e6cff.png"/></td> | |||
| </tr> | |||
| <tr> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-9ab586c47dd5c7b92bca0d727962c90e3b8.png"/></td> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-ef954122a2080e02013112db21754b955c6.png"/></td> | |||
| </tr> | |||
| <tr> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-088edb4d531e122415a1e2342bccb1a9691.png"/></td> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-f886fe19bd820c0efae82f680223cac196c.png"/></td> | |||
| </tr> | |||
| <tr> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-c7a2eb71fa65d6e660294b4bccca613d638.png"/></td> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-e60137fb0787defe613bd83331dc4755a70.png"/></td> | |||
| </tr> | |||
| <tr> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-7c51c1b5758f0a0f92ed3c60469b7526f9f.png"/></td> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-15181aed45bb2461aa97b594cbf2f86ea5f.png"/></td> | |||
| </tr> | |||
| <tr> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-83326ad52ea63f67233d126226738054d98.png"/></td> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-3bd6d31e913b70df00107db51d64ef81df7.png"/></td> | |||
| </tr> | |||
| <tr> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-70a2225836bc82042a6785edf6299e2586a.png"/></td> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-0184d6ab01fdc6667a14327fcaf8b46345d.png"/></td> | |||
| </tr> | |||
| <tr> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-64d8086dc2c02c8f71170290482f7640098.png"/></td> | |||
| <td><img src="https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png"/></td> | |||
| </tr> | |||
| </table> | |||
| ## 交流群 | |||
| QQ群: [](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [](https://jq.qq.com/?_wv=1027&k=5cHeRVW) [](https://jq.qq.com/?_wv=1027&k=53R0L5Z) [](https://jq.qq.com/?_wv=1027&k=5g75dCU) [](https://jq.qq.com/?_wv=1027&k=58cPoHA) [](https://jq.qq.com/?_wv=1027&k=5Ofd4Pb) [](https://jq.qq.com/?_wv=1027&k=5yugASz) [](https://jq.qq.com/?_wv=1027&k=5Rf3d2P) [](https://jq.qq.com/?_wv=1027&k=5ZIjaeP) [](https://jq.qq.com/?_wv=1027&k=5CJw1jY) [](https://jq.qq.com/?_wv=1027&k=5omzbKc) [](https://jq.qq.com/?_wv=1027&k=qPIKBb7s) [](https://jq.qq.com/?_wv=1027&k=4NsjKbtU) [](https://jq.qq.com/?_wv=1027&k=VD2pkz2G) [](https://jq.qq.com/?_wv=1027&k=HlshFwkJ) [](https://jq.qq.com/?_wv=1027&k=0ARRrO9V) [](https://jq.qq.com/?_wv=1027&k=up9k3ZXJ) [](https://jq.qq.com/?_wv=1027&k=540WfdEr) [](https://jq.qq.com/?_wv=1027&k=ss91fC4t) [](https://jq.qq.com/?_wv=1027&k=Cqd66IKe) [](https://jq.qq.com/?_wv=1027&k=7FplYUnR) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=lqMHu_5Fskm7H2S1vNAQTtzAUokVydwc&authKey=ptw0Fpch5pbNocML3CIJKKqZBaq2DI7cusKuzIgfMNiY3t9Pvd9hP%2BA8WYx3yaY1&noverify=0&group_code=174942938) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=blYlRDmwZXSXI5pVrPPU7ZJ1stFJ6Q2Q&authKey=ForGBWffHVlPt9NE3d7g4DoOIouBh%2BqvAj2lp1CLReHfZAUaK7SRrdwsChKpRJDJ&noverify=0&group_code=287843737) | |||
| @@ -0,0 +1,12 @@ | |||
| @echo off | |||
| echo. | |||
| echo [信息] 清理工程target生成路径。 | |||
| echo. | |||
| %~d0 | |||
| cd %~dp0 | |||
| cd .. | |||
| call mvn clean | |||
| pause | |||
| @@ -0,0 +1,12 @@ | |||
| @echo off | |||
| echo. | |||
| echo [信息] 打包Web工程,生成war/jar包文件。 | |||
| echo. | |||
| %~d0 | |||
| cd %~dp0 | |||
| cd .. | |||
| call mvn clean package -Dmaven.test.skip=true | |||
| pause | |||
| @@ -0,0 +1,14 @@ | |||
| @echo off | |||
| echo. | |||
| echo [信息] 使用Jar命令运行Web工程。 | |||
| echo. | |||
| cd %~dp0 | |||
| cd ../rwk-admin/target | |||
| set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m | |||
| java -jar %JAVA_OPTS% rwk-admin.jar | |||
| cd bin | |||
| pause | |||
| @@ -0,0 +1,255 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <groupId>com.rwk</groupId> | |||
| <artifactId>rwk</artifactId> | |||
| <version>4.7.9</version> | |||
| <name>rwk</name> | |||
| <url>http://www.ruoyi.vip</url> | |||
| <description>人物库</description> | |||
| <properties> | |||
| <rwk.version>4.7.9</rwk.version> | |||
| <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |||
| <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | |||
| <java.version>1.8</java.version> | |||
| <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> | |||
| <shiro.version>1.13.0</shiro.version> | |||
| <spring-framework.version>5.3.33</spring-framework.version> | |||
| <thymeleaf.extras.shiro.version>2.1.0</thymeleaf.extras.shiro.version> | |||
| <druid.version>1.2.23</druid.version> | |||
| <bitwalker.version>1.21</bitwalker.version> | |||
| <kaptcha.version>2.3.3</kaptcha.version> | |||
| <swagger.version>3.0.0</swagger.version> | |||
| <pagehelper.boot.version>1.4.7</pagehelper.boot.version> | |||
| <fastjson.version>1.2.83</fastjson.version> | |||
| <oshi.version>6.6.1</oshi.version> | |||
| <commons.io.version>2.16.1</commons.io.version> | |||
| <poi.version>4.1.2</poi.version> | |||
| <velocity.version>2.3</velocity.version> | |||
| </properties> | |||
| <!-- 依赖声明 --> | |||
| <dependencyManagement> | |||
| <dependencies> | |||
| <!-- SpringFramework的依赖配置--> | |||
| <dependency> | |||
| <groupId>org.springframework</groupId> | |||
| <artifactId>spring-framework-bom</artifactId> | |||
| <version>${spring-framework.version}</version> | |||
| <type>pom</type> | |||
| <scope>import</scope> | |||
| </dependency> | |||
| <!-- SpringBoot的依赖配置--> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-dependencies</artifactId> | |||
| <version>2.5.15</version> | |||
| <type>pom</type> | |||
| <scope>import</scope> | |||
| </dependency> | |||
| <!-- 阿里数据库连接池 --> | |||
| <dependency> | |||
| <groupId>com.alibaba</groupId> | |||
| <artifactId>druid-spring-boot-starter</artifactId> | |||
| <version>${druid.version}</version> | |||
| </dependency> | |||
| <!-- 验证码 --> | |||
| <dependency> | |||
| <groupId>pro.fessional</groupId> | |||
| <artifactId>kaptcha</artifactId> | |||
| <version>${kaptcha.version}</version> | |||
| </dependency> | |||
| <!-- Shiro核心框架 --> | |||
| <dependency> | |||
| <groupId>org.apache.shiro</groupId> | |||
| <artifactId>shiro-core</artifactId> | |||
| <version>${shiro.version}</version> | |||
| </dependency> | |||
| <!-- Shiro使用Spring框架 --> | |||
| <dependency> | |||
| <groupId>org.apache.shiro</groupId> | |||
| <artifactId>shiro-spring</artifactId> | |||
| <version>${shiro.version}</version> | |||
| </dependency> | |||
| <!-- Shiro使用EhCache缓存框架 --> | |||
| <dependency> | |||
| <groupId>org.apache.shiro</groupId> | |||
| <artifactId>shiro-ehcache</artifactId> | |||
| <version>${shiro.version}</version> | |||
| </dependency> | |||
| <!-- thymeleaf模板引擎和shiro框架的整合 --> | |||
| <dependency> | |||
| <groupId>com.github.theborakompanioni</groupId> | |||
| <artifactId>thymeleaf-extras-shiro</artifactId> | |||
| <version>${thymeleaf.extras.shiro.version}</version> | |||
| </dependency> | |||
| <!-- 解析客户端操作系统、浏览器等 --> | |||
| <dependency> | |||
| <groupId>eu.bitwalker</groupId> | |||
| <artifactId>UserAgentUtils</artifactId> | |||
| <version>${bitwalker.version}</version> | |||
| </dependency> | |||
| <!-- pagehelper 分页插件 --> | |||
| <dependency> | |||
| <groupId>com.github.pagehelper</groupId> | |||
| <artifactId>pagehelper-spring-boot-starter</artifactId> | |||
| <version>${pagehelper.boot.version}</version> | |||
| </dependency> | |||
| <!-- 获取系统信息 --> | |||
| <dependency> | |||
| <groupId>com.github.oshi</groupId> | |||
| <artifactId>oshi-core</artifactId> | |||
| <version>${oshi.version}</version> | |||
| </dependency> | |||
| <!-- Swagger3依赖 --> | |||
| <dependency> | |||
| <groupId>io.springfox</groupId> | |||
| <artifactId>springfox-boot-starter</artifactId> | |||
| <version>${swagger.version}</version> | |||
| <exclusions> | |||
| <exclusion> | |||
| <groupId>io.swagger</groupId> | |||
| <artifactId>swagger-models</artifactId> | |||
| </exclusion> | |||
| </exclusions> | |||
| </dependency> | |||
| <!-- io常用工具类 --> | |||
| <dependency> | |||
| <groupId>commons-io</groupId> | |||
| <artifactId>commons-io</artifactId> | |||
| <version>${commons.io.version}</version> | |||
| </dependency> | |||
| <!-- excel工具 --> | |||
| <dependency> | |||
| <groupId>org.apache.poi</groupId> | |||
| <artifactId>poi-ooxml</artifactId> | |||
| <version>${poi.version}</version> | |||
| </dependency> | |||
| <!-- velocity代码生成使用模板 --> | |||
| <dependency> | |||
| <groupId>org.apache.velocity</groupId> | |||
| <artifactId>velocity-engine-core</artifactId> | |||
| <version>${velocity.version}</version> | |||
| </dependency> | |||
| <!-- 阿里JSON解析器 --> | |||
| <dependency> | |||
| <groupId>com.alibaba</groupId> | |||
| <artifactId>fastjson</artifactId> | |||
| <version>${fastjson.version}</version> | |||
| </dependency> | |||
| <!-- 定时任务--> | |||
| <dependency> | |||
| <groupId>com.rwk</groupId> | |||
| <artifactId>rwk-quartz</artifactId> | |||
| <version>${rwk.version}</version> | |||
| </dependency> | |||
| <!-- 代码生成--> | |||
| <dependency> | |||
| <groupId>com.rwk</groupId> | |||
| <artifactId>rwk-generator</artifactId> | |||
| <version>${rwk.version}</version> | |||
| </dependency> | |||
| <!-- 核心模块--> | |||
| <dependency> | |||
| <groupId>com.rwk</groupId> | |||
| <artifactId>rwk-framework</artifactId> | |||
| <version>${rwk.version}</version> | |||
| </dependency> | |||
| <!-- 系统模块--> | |||
| <dependency> | |||
| <groupId>com.rwk</groupId> | |||
| <artifactId>rwk-system</artifactId> | |||
| <version>${rwk.version}</version> | |||
| </dependency> | |||
| <!-- 通用工具--> | |||
| <dependency> | |||
| <groupId>com.rwk</groupId> | |||
| <artifactId>rwk-common</artifactId> | |||
| <version>${rwk.version}</version> | |||
| </dependency> | |||
| </dependencies> | |||
| </dependencyManagement> | |||
| <modules> | |||
| <module>rwk-admin</module> | |||
| <module>rwk-framework</module> | |||
| <module>rwk-system</module> | |||
| <module>rwk-quartz</module> | |||
| <module>rwk-generator</module> | |||
| <module>rwk-common</module> | |||
| </modules> | |||
| <packaging>pom</packaging> | |||
| <dependencies> | |||
| </dependencies> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-compiler-plugin</artifactId> | |||
| <version>3.1</version> | |||
| <configuration> | |||
| <source>${java.version}</source> | |||
| <target>${java.version}</target> | |||
| <encoding>${project.build.sourceEncoding}</encoding> | |||
| </configuration> | |||
| </plugin> | |||
| </plugins> | |||
| </build> | |||
| <repositories> | |||
| <repository> | |||
| <id>public</id> | |||
| <name>aliyun nexus</name> | |||
| <url>https://maven.aliyun.com/repository/public</url> | |||
| <releases> | |||
| <enabled>true</enabled> | |||
| </releases> | |||
| </repository> | |||
| </repositories> | |||
| <pluginRepositories> | |||
| <pluginRepository> | |||
| <id>public</id> | |||
| <name>aliyun nexus</name> | |||
| <url>https://maven.aliyun.com/repository/public</url> | |||
| <releases> | |||
| <enabled>true</enabled> | |||
| </releases> | |||
| <snapshots> | |||
| <enabled>false</enabled> | |||
| </snapshots> | |||
| </pluginRepository> | |||
| </pluginRepositories> | |||
| </project> | |||
| @@ -0,0 +1,167 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | |||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
| <parent> | |||
| <artifactId>rwk</artifactId> | |||
| <groupId>com.rwk</groupId> | |||
| <version>4.7.9</version> | |||
| </parent> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <packaging>jar</packaging> | |||
| <artifactId>rwk-admin</artifactId> | |||
| <description> | |||
| web服务入口 | |||
| </description> | |||
| <dependencies> | |||
| <!-- SpringBoot集成thymeleaf模板 --> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-starter-thymeleaf</artifactId> | |||
| </dependency> | |||
| <!-- spring-boot-devtools --> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-devtools</artifactId> | |||
| <optional>true</optional> <!-- 表示依赖不会传递 --> | |||
| </dependency> | |||
| <!-- swagger3--> | |||
| <dependency> | |||
| <groupId>io.springfox</groupId> | |||
| <artifactId>springfox-boot-starter</artifactId> | |||
| </dependency> | |||
| <!-- 防止进入swagger页面报类型转换错误,排除3.0.0中的引用,手动增加1.6.2版本 --> | |||
| <dependency> | |||
| <groupId>io.swagger</groupId> | |||
| <artifactId>swagger-models</artifactId> | |||
| <version>1.6.2</version> | |||
| </dependency> | |||
| <!-- Mysql驱动包 --> | |||
| <dependency> | |||
| <groupId>mysql</groupId> | |||
| <artifactId>mysql-connector-java</artifactId> | |||
| </dependency> | |||
| <!-- 达梦驱动--> | |||
| <dependency> | |||
| <groupId>com.dameng</groupId> | |||
| <artifactId>Dm8JdbcDriver18</artifactId> | |||
| <version>8.1.1.49</version> | |||
| </dependency> | |||
| <!-- 核心模块--> | |||
| <dependency> | |||
| <groupId>com.rwk</groupId> | |||
| <artifactId>rwk-framework</artifactId> | |||
| </dependency> | |||
| <!-- 定时任务--> | |||
| <dependency> | |||
| <groupId>com.rwk</groupId> | |||
| <artifactId>rwk-quartz</artifactId> | |||
| </dependency> | |||
| <!-- 代码生成--> | |||
| <dependency> | |||
| <groupId>com.rwk</groupId> | |||
| <artifactId>rwk-generator</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-starter-test</artifactId> | |||
| <scope>test</scope> | |||
| <version>2.5.0</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.h2database</groupId> | |||
| <artifactId>h2</artifactId> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.junit.vintage</groupId> | |||
| <artifactId>junit-vintage-engine</artifactId> | |||
| <scope>test</scope> | |||
| <exclusions> | |||
| <exclusion> | |||
| <groupId>org.hamcrest</groupId> | |||
| <artifactId>hamcrest-core</artifactId> | |||
| </exclusion> | |||
| </exclusions> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-maven-plugin</artifactId> | |||
| <version>2.5.15</version> | |||
| <configuration> | |||
| <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 --> | |||
| </configuration> | |||
| <executions> | |||
| <execution> | |||
| <goals> | |||
| <goal>repackage</goal> | |||
| </goals> | |||
| </execution> | |||
| </executions> | |||
| </plugin> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-war-plugin</artifactId> | |||
| <version>3.0.0</version> | |||
| <configuration> | |||
| <failOnMissingWebXml>false</failOnMissingWebXml> | |||
| <warName>${project.artifactId}</warName> | |||
| </configuration> | |||
| </plugin> | |||
| <!-- YUI Compressor (CSS/JS压缩) | |||
| <plugin> | |||
| <groupId>net.alchim31.maven</groupId> | |||
| <artifactId>yuicompressor-maven-plugin</artifactId> | |||
| <version>1.5.1</version> | |||
| <executions> | |||
| <execution> | |||
| <phase>prepare-package</phase> | |||
| <goals> | |||
| <goal>compress</goal> | |||
| </goals> | |||
| </execution> | |||
| </executions> | |||
| <configuration> | |||
| <encoding>UTF-8</encoding> | |||
| <jswarn>false</jswarn> | |||
| <nosuffix>true</nosuffix> | |||
| <linebreakpos>50000</linebreakpos> | |||
| <sourceDirectory>src/main/resources/static</sourceDirectory> | |||
| <force>true</force> | |||
| <includes> | |||
| <include>**/*.js</include> | |||
| <include>**/*.css</include> | |||
| </includes> | |||
| <excludes> | |||
| <exclude>**/*.min.js</exclude> | |||
| <exclude>**/*.min.css</exclude> | |||
| <exclude>**/fileinput.js</exclude> | |||
| <exclude>**/validate/**</exclude> | |||
| <exclude>**/bootstrap-table/**</exclude> | |||
| </excludes> | |||
| </configuration> | |||
| </plugin> --> | |||
| </plugins> | |||
| <finalName>${project.artifactId}</finalName> | |||
| </build> | |||
| </project> | |||
| @@ -0,0 +1,25 @@ | |||
| package com.rwk; | |||
| import org.springframework.boot.SpringApplication; | |||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; | |||
| import org.springframework.context.ConfigurableApplicationContext; | |||
| import org.springframework.core.env.Environment; | |||
| /** | |||
| * 启动程序 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) | |||
| public class RuoYiApplication | |||
| { | |||
| public static void main(String[] args) | |||
| { | |||
| // System.setProperty("spring.devtools.restart.enabled", "false"); | |||
| ConfigurableApplicationContext run = SpringApplication.run(RuoYiApplication.class, args); | |||
| System.out.println("(♥◠‿◠)ノ゙ 启动成功 ლ(´ڡ`ლ)゙ "); | |||
| Environment env = run.getEnvironment(); | |||
| System.out.println("系统访问地址:http://localhost:" + env.getProperty("server.port") + env.getProperty("server.servlet.context-path")); | |||
| } | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| package com.rwk; | |||
| import org.springframework.boot.builder.SpringApplicationBuilder; | |||
| import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; | |||
| /** | |||
| * web容器中进行部署 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| public class RuoYiServletInitializer extends SpringBootServletInitializer | |||
| { | |||
| @Override | |||
| protected SpringApplicationBuilder configure(SpringApplicationBuilder application) | |||
| { | |||
| return application.sources(RuoYiApplication.class); | |||
| } | |||
| } | |||
| @@ -0,0 +1,127 @@ | |||
| package com.rwk.web.controller.ability; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.system.domain.RwkFamilyMember; | |||
| import com.rwk.system.service.IRwkFamilyMemberService; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.utils.poi.ExcelUtil; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| /** | |||
| * 家庭成员Controller | |||
| * | |||
| * @author rick | |||
| * @date 2024-11-06 | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/member") | |||
| public class RwkFamilyMemberController extends BaseController | |||
| { | |||
| private String prefix = "system/member"; | |||
| @Autowired | |||
| private IRwkFamilyMemberService rwkFamilyMemberService; | |||
| @RequiresPermissions("system:member:view") | |||
| @GetMapping() | |||
| public String member() | |||
| { | |||
| return prefix + "/member"; | |||
| } | |||
| /** | |||
| * 查询家庭成员列表 | |||
| */ | |||
| @RequiresPermissions("system:member:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public TableDataInfo list(RwkFamilyMember rwkFamilyMember) | |||
| { | |||
| startPage(); | |||
| List<RwkFamilyMember> list = rwkFamilyMemberService.selectRwkFamilyMemberList(rwkFamilyMember); | |||
| return getDataTable(list); | |||
| } | |||
| /** | |||
| * 导出家庭成员列表 | |||
| */ | |||
| @RequiresPermissions("system:member:export") | |||
| @Log(title = "家庭成员", businessType = BusinessType.EXPORT) | |||
| @PostMapping("/export") | |||
| @ResponseBody | |||
| public AjaxResult export(RwkFamilyMember rwkFamilyMember) | |||
| { | |||
| List<RwkFamilyMember> list = rwkFamilyMemberService.selectRwkFamilyMemberList(rwkFamilyMember); | |||
| ExcelUtil<RwkFamilyMember> util = new ExcelUtil<RwkFamilyMember>(RwkFamilyMember.class); | |||
| return util.exportExcel(list, "家庭成员数据"); | |||
| } | |||
| /** | |||
| * 新增家庭成员 | |||
| */ | |||
| @GetMapping("/add") | |||
| public String add() | |||
| { | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存家庭成员 | |||
| */ | |||
| @RequiresPermissions("system:member:add") | |||
| @Log(title = "家庭成员", businessType = BusinessType.INSERT) | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(RwkFamilyMember rwkFamilyMember) | |||
| { | |||
| return toAjax(rwkFamilyMemberService.insertRwkFamilyMember(rwkFamilyMember)); | |||
| } | |||
| /** | |||
| * 修改家庭成员 | |||
| */ | |||
| @RequiresPermissions("system:member:edit") | |||
| @GetMapping("/edit/{id}") | |||
| public String edit(@PathVariable("id") Long id, ModelMap mmap) | |||
| { | |||
| RwkFamilyMember rwkFamilyMember = rwkFamilyMemberService.selectRwkFamilyMemberById(id); | |||
| mmap.put("rwkFamilyMember", rwkFamilyMember); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改保存家庭成员 | |||
| */ | |||
| @RequiresPermissions("system:member:edit") | |||
| @Log(title = "家庭成员", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(RwkFamilyMember rwkFamilyMember) | |||
| { | |||
| return toAjax(rwkFamilyMemberService.updateRwkFamilyMember(rwkFamilyMember)); | |||
| } | |||
| /** | |||
| * 删除家庭成员 | |||
| */ | |||
| @RequiresPermissions("system:member:remove") | |||
| @Log(title = "家庭成员", businessType = BusinessType.DELETE) | |||
| @PostMapping( "/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| return toAjax(rwkFamilyMemberService.deleteRwkFamilyMemberByIds(ids)); | |||
| } | |||
| } | |||
| @@ -0,0 +1,127 @@ | |||
| package com.rwk.web.controller.ability; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.system.domain.RwkStaffInformation; | |||
| import com.rwk.system.service.IRwkStaffInformationService; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.utils.poi.ExcelUtil; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| /** | |||
| * 人员信息Controller | |||
| * | |||
| * @author rick | |||
| * @date 2024-11-06 | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/information") | |||
| public class RwkStaffInformationController extends BaseController | |||
| { | |||
| private String prefix = "system/information"; | |||
| @Autowired | |||
| private IRwkStaffInformationService rwkStaffInformationService; | |||
| @RequiresPermissions("system:information:view") | |||
| @GetMapping() | |||
| public String information() | |||
| { | |||
| return prefix + "/information"; | |||
| } | |||
| /** | |||
| * 查询人员信息列表 | |||
| */ | |||
| @RequiresPermissions("system:information:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public TableDataInfo list(RwkStaffInformation rwkStaffInformation) | |||
| { | |||
| startPage(); | |||
| List<RwkStaffInformation> list = rwkStaffInformationService.selectRwkStaffInformationList(rwkStaffInformation); | |||
| return getDataTable(list); | |||
| } | |||
| /** | |||
| * 导出人员信息列表 | |||
| */ | |||
| @RequiresPermissions("system:information:export") | |||
| @Log(title = "人员信息", businessType = BusinessType.EXPORT) | |||
| @PostMapping("/export") | |||
| @ResponseBody | |||
| public AjaxResult export(RwkStaffInformation rwkStaffInformation) | |||
| { | |||
| List<RwkStaffInformation> list = rwkStaffInformationService.selectRwkStaffInformationList(rwkStaffInformation); | |||
| ExcelUtil<RwkStaffInformation> util = new ExcelUtil<RwkStaffInformation>(RwkStaffInformation.class); | |||
| return util.exportExcel(list, "人员信息数据"); | |||
| } | |||
| /** | |||
| * 新增人员信息 | |||
| */ | |||
| @GetMapping("/add") | |||
| public String add() | |||
| { | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存人员信息 | |||
| */ | |||
| @RequiresPermissions("system:information:add") | |||
| @Log(title = "人员信息", businessType = BusinessType.INSERT) | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(RwkStaffInformation rwkStaffInformation) | |||
| { | |||
| return toAjax(rwkStaffInformationService.insertRwkStaffInformation(rwkStaffInformation)); | |||
| } | |||
| /** | |||
| * 修改人员信息 | |||
| */ | |||
| @RequiresPermissions("system:information:edit") | |||
| @GetMapping("/edit/{id}") | |||
| public String edit(@PathVariable("id") Long id, ModelMap mmap) | |||
| { | |||
| RwkStaffInformation rwkStaffInformation = rwkStaffInformationService.selectRwkStaffInformationById(id); | |||
| mmap.put("rwkStaffInformation", rwkStaffInformation); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改保存人员信息 | |||
| */ | |||
| @RequiresPermissions("system:information:edit") | |||
| @Log(title = "人员信息", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(RwkStaffInformation rwkStaffInformation) | |||
| { | |||
| return toAjax(rwkStaffInformationService.updateRwkStaffInformation(rwkStaffInformation)); | |||
| } | |||
| /** | |||
| * 删除人员信息 | |||
| */ | |||
| @RequiresPermissions("system:information:remove") | |||
| @Log(title = "人员信息", businessType = BusinessType.DELETE) | |||
| @PostMapping( "/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| return toAjax(rwkStaffInformationService.deleteRwkStaffInformationByIds(ids)); | |||
| } | |||
| } | |||
| @@ -0,0 +1,158 @@ | |||
| package com.rwk.web.controller.common; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import javax.servlet.http.HttpServletResponse; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.http.MediaType; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import com.rwk.common.config.RuoYiConfig; | |||
| import com.rwk.common.constant.Constants; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.utils.StringUtils; | |||
| import com.rwk.common.utils.file.FileUploadUtils; | |||
| import com.rwk.common.utils.file.FileUtils; | |||
| /** | |||
| * 通用请求处理 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/common") | |||
| public class CommonController | |||
| { | |||
| private static final Logger log = LoggerFactory.getLogger(CommonController.class); | |||
| private static final String FILE_DELIMETER = ","; | |||
| /** | |||
| * 通用下载请求 | |||
| * | |||
| * @param fileName 文件名称 | |||
| * @param delete 是否删除 | |||
| */ | |||
| @GetMapping("/download") | |||
| public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) | |||
| { | |||
| try | |||
| { | |||
| if (!FileUtils.checkAllowDownload(fileName)) | |||
| { | |||
| throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); | |||
| } | |||
| String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); | |||
| String filePath = RuoYiConfig.getDownloadPath() + fileName; | |||
| response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); | |||
| FileUtils.setAttachmentResponseHeader(response, realFileName); | |||
| FileUtils.writeBytes(filePath, response.getOutputStream()); | |||
| if (delete) | |||
| { | |||
| FileUtils.deleteFile(filePath); | |||
| } | |||
| } | |||
| catch (Exception e) | |||
| { | |||
| log.error("下载文件失败", e); | |||
| } | |||
| } | |||
| /** | |||
| * 通用上传请求(单个) | |||
| */ | |||
| @PostMapping("/upload") | |||
| @ResponseBody | |||
| public AjaxResult uploadFile(MultipartFile file) throws Exception | |||
| { | |||
| try | |||
| { | |||
| // 上传文件路径 | |||
| String filePath = RuoYiConfig.getUploadPath(); | |||
| // 上传并返回新文件名称 | |||
| String fileName = FileUploadUtils.upload(filePath, file); | |||
| // String url = serverConfig.getUrl() + fileName; | |||
| AjaxResult ajax = AjaxResult.success(); | |||
| ajax.put("url", fileName); | |||
| ajax.put("fileName", fileName); | |||
| ajax.put("newFileName", FileUtils.getName(fileName)); | |||
| ajax.put("originalFilename", file.getOriginalFilename()); | |||
| return ajax; | |||
| } | |||
| catch (Exception e) | |||
| { | |||
| return AjaxResult.error(e.getMessage()); | |||
| } | |||
| } | |||
| /** | |||
| * 通用上传请求(多个) | |||
| */ | |||
| @PostMapping("/uploads") | |||
| @ResponseBody | |||
| public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception | |||
| { | |||
| try | |||
| { | |||
| // 上传文件路径 | |||
| String filePath = RuoYiConfig.getUploadPath(); | |||
| List<String> urls = new ArrayList<String>(); | |||
| List<String> fileNames = new ArrayList<String>(); | |||
| List<String> newFileNames = new ArrayList<String>(); | |||
| List<String> originalFilenames = new ArrayList<String>(); | |||
| for (MultipartFile file : files) | |||
| { | |||
| // 上传并返回新文件名称 | |||
| String fileName = FileUploadUtils.upload(filePath, file); | |||
| // String url = serverConfig.getUrl() + fileName; | |||
| urls.add(fileName); | |||
| fileNames.add(fileName); | |||
| newFileNames.add(FileUtils.getName(fileName)); | |||
| originalFilenames.add(file.getOriginalFilename()); | |||
| } | |||
| AjaxResult ajax = AjaxResult.success(); | |||
| ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER)); | |||
| ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER)); | |||
| ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER)); | |||
| ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER)); | |||
| return ajax; | |||
| } | |||
| catch (Exception e) | |||
| { | |||
| return AjaxResult.error(e.getMessage()); | |||
| } | |||
| } | |||
| /** | |||
| * 本地资源通用下载 | |||
| */ | |||
| @GetMapping("/download/resource") | |||
| public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) | |||
| throws Exception | |||
| { | |||
| try | |||
| { | |||
| if (!FileUtils.checkAllowDownload(resource)) | |||
| { | |||
| throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource)); | |||
| } | |||
| // 本地资源路径 | |||
| String localPath = RuoYiConfig.getProfile(); | |||
| // 数据库资源地址 | |||
| String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX); | |||
| // 下载名称 | |||
| String downloadName = StringUtils.substringAfterLast(downloadPath, "/"); | |||
| response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); | |||
| FileUtils.setAttachmentResponseHeader(response, downloadName); | |||
| FileUtils.writeBytes(downloadPath, response.getOutputStream()); | |||
| } | |||
| catch (Exception e) | |||
| { | |||
| log.error("下载文件失败", e); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,98 @@ | |||
| package com.rwk.web.controller.demo.controller; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| /** | |||
| * 模态窗口 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/demo/modal") | |||
| public class DemoDialogController | |||
| { | |||
| private String prefix = "demo/modal"; | |||
| /** | |||
| * 模态窗口 | |||
| */ | |||
| @GetMapping("/dialog") | |||
| public String dialog() | |||
| { | |||
| return prefix + "/dialog"; | |||
| } | |||
| /** | |||
| * 弹层组件 | |||
| */ | |||
| @GetMapping("/layer") | |||
| public String layer() | |||
| { | |||
| return prefix + "/layer"; | |||
| } | |||
| /** | |||
| * 表单 | |||
| */ | |||
| @GetMapping("/form") | |||
| public String form() | |||
| { | |||
| return prefix + "/form"; | |||
| } | |||
| /** | |||
| * 表格 | |||
| */ | |||
| @GetMapping("/table") | |||
| public String table() | |||
| { | |||
| return prefix + "/table"; | |||
| } | |||
| /** | |||
| * 表格check | |||
| */ | |||
| @GetMapping("/check") | |||
| public String check() | |||
| { | |||
| return prefix + "/table/check"; | |||
| } | |||
| /** | |||
| * 表格radio | |||
| */ | |||
| @GetMapping("/radio") | |||
| public String radio() | |||
| { | |||
| return prefix + "/table/radio"; | |||
| } | |||
| /** | |||
| * 表格回传父窗体 | |||
| */ | |||
| @GetMapping("/parent") | |||
| public String parent() | |||
| { | |||
| return prefix + "/table/parent"; | |||
| } | |||
| /** | |||
| * 多层窗口frame1 | |||
| */ | |||
| @GetMapping("/frame1") | |||
| public String frame1() | |||
| { | |||
| return prefix + "/table/frame1"; | |||
| } | |||
| /** | |||
| * 多层窗口frame2 | |||
| */ | |||
| @GetMapping("/frame2") | |||
| public String frame2() | |||
| { | |||
| return prefix + "/table/frame2"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,35 @@ | |||
| package com.rwk.web.controller.demo.controller; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| /** | |||
| * 图标相关 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/demo/icon") | |||
| public class DemoIconController | |||
| { | |||
| private String prefix = "demo/icon"; | |||
| /** | |||
| * FontAwesome图标 | |||
| */ | |||
| @GetMapping("/fontawesome") | |||
| public String fontAwesome() | |||
| { | |||
| return prefix + "/fontawesome"; | |||
| } | |||
| /** | |||
| * Glyphicons图标 | |||
| */ | |||
| @GetMapping("/glyphicons") | |||
| public String glyphicons() | |||
| { | |||
| return prefix + "/glyphicons"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,326 @@ | |||
| package com.rwk.web.controller.demo.controller; | |||
| import java.util.ArrayList; | |||
| import java.util.LinkedHashMap; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.page.PageDomain; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| import com.rwk.common.core.page.TableSupport; | |||
| import com.rwk.common.core.text.Convert; | |||
| import com.rwk.common.exception.ServiceException; | |||
| import com.rwk.common.utils.StringUtils; | |||
| import com.rwk.common.utils.poi.ExcelUtil; | |||
| import com.rwk.web.controller.demo.domain.CustomerModel; | |||
| import com.rwk.web.controller.demo.domain.UserOperateModel; | |||
| /** | |||
| * 操作控制 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/demo/operate") | |||
| public class DemoOperateController extends BaseController | |||
| { | |||
| private String prefix = "demo/operate"; | |||
| private final static Map<Integer, UserOperateModel> users = new LinkedHashMap<Integer, UserOperateModel>(); | |||
| { | |||
| users.put(1, new UserOperateModel(1, "1000001", "测试1", "0", "15888888888", "ry@qq.com", 150.0, "0")); | |||
| users.put(2, new UserOperateModel(2, "1000002", "测试2", "1", "15666666666", "ry@qq.com", 180.0, "1")); | |||
| users.put(3, new UserOperateModel(3, "1000003", "测试3", "0", "15666666666", "ry@qq.com", 110.0, "1")); | |||
| users.put(4, new UserOperateModel(4, "1000004", "测试4", "1", "15666666666", "ry@qq.com", 220.0, "1")); | |||
| users.put(5, new UserOperateModel(5, "1000005", "测试5", "0", "15666666666", "ry@qq.com", 140.0, "1")); | |||
| users.put(6, new UserOperateModel(6, "1000006", "测试6", "1", "15666666666", "ry@qq.com", 330.0, "1")); | |||
| users.put(7, new UserOperateModel(7, "1000007", "测试7", "0", "15666666666", "ry@qq.com", 160.0, "1")); | |||
| users.put(8, new UserOperateModel(8, "1000008", "测试8", "1", "15666666666", "ry@qq.com", 170.0, "1")); | |||
| users.put(9, new UserOperateModel(9, "1000009", "测试9", "0", "15666666666", "ry@qq.com", 180.0, "1")); | |||
| users.put(10, new UserOperateModel(10, "1000010", "测试10", "0", "15666666666", "ry@qq.com", 210.0, "1")); | |||
| users.put(11, new UserOperateModel(11, "1000011", "测试11", "1", "15666666666", "ry@qq.com", 110.0, "1")); | |||
| users.put(12, new UserOperateModel(12, "1000012", "测试12", "0", "15666666666", "ry@qq.com", 120.0, "1")); | |||
| users.put(13, new UserOperateModel(13, "1000013", "测试13", "1", "15666666666", "ry@qq.com", 380.0, "1")); | |||
| users.put(14, new UserOperateModel(14, "1000014", "测试14", "0", "15666666666", "ry@qq.com", 280.0, "1")); | |||
| users.put(15, new UserOperateModel(15, "1000015", "测试15", "0", "15666666666", "ry@qq.com", 570.0, "1")); | |||
| users.put(16, new UserOperateModel(16, "1000016", "测试16", "1", "15666666666", "ry@qq.com", 260.0, "1")); | |||
| users.put(17, new UserOperateModel(17, "1000017", "测试17", "1", "15666666666", "ry@qq.com", 210.0, "1")); | |||
| users.put(18, new UserOperateModel(18, "1000018", "测试18", "1", "15666666666", "ry@qq.com", 340.0, "1")); | |||
| users.put(19, new UserOperateModel(19, "1000019", "测试19", "1", "15666666666", "ry@qq.com", 160.0, "1")); | |||
| users.put(20, new UserOperateModel(20, "1000020", "测试20", "1", "15666666666", "ry@qq.com", 220.0, "1")); | |||
| users.put(21, new UserOperateModel(21, "1000021", "测试21", "1", "15666666666", "ry@qq.com", 120.0, "1")); | |||
| users.put(22, new UserOperateModel(22, "1000022", "测试22", "1", "15666666666", "ry@qq.com", 130.0, "1")); | |||
| users.put(23, new UserOperateModel(23, "1000023", "测试23", "1", "15666666666", "ry@qq.com", 490.0, "1")); | |||
| users.put(24, new UserOperateModel(24, "1000024", "测试24", "1", "15666666666", "ry@qq.com", 570.0, "1")); | |||
| users.put(25, new UserOperateModel(25, "1000025", "测试25", "1", "15666666666", "ry@qq.com", 250.0, "1")); | |||
| users.put(26, new UserOperateModel(26, "1000026", "测试26", "1", "15666666666", "ry@qq.com", 250.0, "1")); | |||
| } | |||
| /** | |||
| * 表格 | |||
| */ | |||
| @GetMapping("/table") | |||
| public String table() | |||
| { | |||
| return prefix + "/table"; | |||
| } | |||
| /** | |||
| * 其他 | |||
| */ | |||
| @GetMapping("/other") | |||
| public String other() | |||
| { | |||
| return prefix + "/other"; | |||
| } | |||
| /** | |||
| * 查询数据 | |||
| */ | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public TableDataInfo list(UserOperateModel userModel) | |||
| { | |||
| TableDataInfo rspData = new TableDataInfo(); | |||
| List<UserOperateModel> userList = new ArrayList<UserOperateModel>(users.values()); | |||
| // 查询条件过滤 | |||
| if (StringUtils.isNotEmpty(userModel.getSearchValue())) | |||
| { | |||
| userList.clear(); | |||
| for (Map.Entry<Integer, UserOperateModel> entry : users.entrySet()) | |||
| { | |||
| if (entry.getValue().getUserName().equals(userModel.getSearchValue())) | |||
| { | |||
| userList.add(entry.getValue()); | |||
| } | |||
| } | |||
| } | |||
| else if (StringUtils.isNotEmpty(userModel.getUserName())) | |||
| { | |||
| userList.clear(); | |||
| for (Map.Entry<Integer, UserOperateModel> entry : users.entrySet()) | |||
| { | |||
| if (entry.getValue().getUserName().equals(userModel.getUserName())) | |||
| { | |||
| userList.add(entry.getValue()); | |||
| } | |||
| } | |||
| } | |||
| PageDomain pageDomain = TableSupport.buildPageRequest(); | |||
| if (null == pageDomain.getPageNum() || null == pageDomain.getPageSize()) | |||
| { | |||
| rspData.setRows(userList); | |||
| rspData.setTotal(userList.size()); | |||
| return rspData; | |||
| } | |||
| Integer pageNum = (pageDomain.getPageNum() - 1) * 10; | |||
| Integer pageSize = pageDomain.getPageNum() * 10; | |||
| if (pageSize > userList.size()) | |||
| { | |||
| pageSize = userList.size(); | |||
| } | |||
| rspData.setRows(userList.subList(pageNum, pageSize)); | |||
| rspData.setTotal(userList.size()); | |||
| return rspData; | |||
| } | |||
| /** | |||
| * 新增用户 | |||
| */ | |||
| @GetMapping("/add") | |||
| public String add(ModelMap mmap) | |||
| { | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存用户 | |||
| */ | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(UserOperateModel user) | |||
| { | |||
| Integer userId = users.size() + 1; | |||
| user.setUserId(userId); | |||
| return AjaxResult.success(users.put(userId, user)); | |||
| } | |||
| /** | |||
| * 新增保存主子表信息 | |||
| */ | |||
| @PostMapping("/customer/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(CustomerModel customerModel) | |||
| { | |||
| System.out.println(customerModel.toString()); | |||
| return AjaxResult.success(); | |||
| } | |||
| /** | |||
| * 修改用户 | |||
| */ | |||
| @GetMapping("/edit/{userId}") | |||
| public String edit(@PathVariable("userId") Integer userId, ModelMap mmap) | |||
| { | |||
| mmap.put("user", users.get(userId)); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改保存用户 | |||
| */ | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(UserOperateModel user) | |||
| { | |||
| return AjaxResult.success(users.put(user.getUserId(), user)); | |||
| } | |||
| /** | |||
| * 导出 | |||
| */ | |||
| @PostMapping("/export") | |||
| @ResponseBody | |||
| public AjaxResult export(UserOperateModel user) | |||
| { | |||
| List<UserOperateModel> list = new ArrayList<UserOperateModel>(users.values()); | |||
| ExcelUtil<UserOperateModel> util = new ExcelUtil<UserOperateModel>(UserOperateModel.class); | |||
| return util.exportExcel(list, "用户数据"); | |||
| } | |||
| /** | |||
| * 下载模板 | |||
| */ | |||
| @GetMapping("/importTemplate") | |||
| @ResponseBody | |||
| public AjaxResult importTemplate() | |||
| { | |||
| ExcelUtil<UserOperateModel> util = new ExcelUtil<UserOperateModel>(UserOperateModel.class); | |||
| return util.importTemplateExcel("用户数据"); | |||
| } | |||
| /** | |||
| * 导入数据 | |||
| */ | |||
| @PostMapping("/importData") | |||
| @ResponseBody | |||
| public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception | |||
| { | |||
| ExcelUtil<UserOperateModel> util = new ExcelUtil<UserOperateModel>(UserOperateModel.class); | |||
| List<UserOperateModel> userList = util.importExcel(file.getInputStream()); | |||
| String message = importUser(userList, updateSupport); | |||
| return AjaxResult.success(message); | |||
| } | |||
| /** | |||
| * 删除用户 | |||
| */ | |||
| @PostMapping("/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| Integer[] userIds = Convert.toIntArray(ids); | |||
| for (Integer userId : userIds) | |||
| { | |||
| users.remove(userId); | |||
| } | |||
| return AjaxResult.success(); | |||
| } | |||
| /** | |||
| * 查看详细 | |||
| */ | |||
| @GetMapping("/detail/{userId}") | |||
| public String detail(@PathVariable("userId") Integer userId, ModelMap mmap) | |||
| { | |||
| mmap.put("user", users.get(userId)); | |||
| return prefix + "/detail"; | |||
| } | |||
| @PostMapping("/clean") | |||
| @ResponseBody | |||
| public AjaxResult clean() | |||
| { | |||
| users.clear(); | |||
| return success(); | |||
| } | |||
| /** | |||
| * 导入用户数据 | |||
| * | |||
| * @param userList 用户数据列表 | |||
| * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 | |||
| * @return 结果 | |||
| */ | |||
| public String importUser(List<UserOperateModel> userList, Boolean isUpdateSupport) | |||
| { | |||
| if (StringUtils.isNull(userList) || userList.size() == 0) | |||
| { | |||
| throw new ServiceException("导入用户数据不能为空!"); | |||
| } | |||
| int successNum = 0; | |||
| int failureNum = 0; | |||
| StringBuilder successMsg = new StringBuilder(); | |||
| StringBuilder failureMsg = new StringBuilder(); | |||
| for (UserOperateModel user : userList) | |||
| { | |||
| try | |||
| { | |||
| // 验证是否存在这个用户 | |||
| boolean userFlag = false; | |||
| for (Map.Entry<Integer, UserOperateModel> entry : users.entrySet()) | |||
| { | |||
| if (entry.getValue().getUserName().equals(user.getUserName())) | |||
| { | |||
| userFlag = true; | |||
| break; | |||
| } | |||
| } | |||
| if (!userFlag) | |||
| { | |||
| Integer userId = users.size() + 1; | |||
| user.setUserId(userId); | |||
| users.put(userId, user); | |||
| successNum++; | |||
| successMsg.append("<br/>" + successNum + "、用户 " + user.getUserName() + " 导入成功"); | |||
| } | |||
| else if (isUpdateSupport) | |||
| { | |||
| users.put(user.getUserId(), user); | |||
| successNum++; | |||
| successMsg.append("<br/>" + successNum + "、用户 " + user.getUserName() + " 更新成功"); | |||
| } | |||
| else | |||
| { | |||
| failureNum++; | |||
| failureMsg.append("<br/>" + failureNum + "、用户 " + user.getUserName() + " 已存在"); | |||
| } | |||
| } | |||
| catch (Exception e) | |||
| { | |||
| failureNum++; | |||
| String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败:"; | |||
| failureMsg.append(msg + e.getMessage()); | |||
| } | |||
| } | |||
| if (failureNum > 0) | |||
| { | |||
| failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); | |||
| throw new ServiceException(failureMsg.toString()); | |||
| } | |||
| else | |||
| { | |||
| successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); | |||
| } | |||
| return successMsg.toString(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,53 @@ | |||
| package com.rwk.web.controller.demo.controller; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| /** | |||
| * 报表 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/demo/report") | |||
| public class DemoReportController | |||
| { | |||
| private String prefix = "demo/report"; | |||
| /** | |||
| * 百度ECharts | |||
| */ | |||
| @GetMapping("/echarts") | |||
| public String echarts() | |||
| { | |||
| return prefix + "/echarts"; | |||
| } | |||
| /** | |||
| * 图表插件 | |||
| */ | |||
| @GetMapping("/peity") | |||
| public String peity() | |||
| { | |||
| return prefix + "/peity"; | |||
| } | |||
| /** | |||
| * 线状图插件 | |||
| */ | |||
| @GetMapping("/sparkline") | |||
| public String sparkline() | |||
| { | |||
| return prefix + "/sparkline"; | |||
| } | |||
| /** | |||
| * 图表组合 | |||
| */ | |||
| @GetMapping("/metrics") | |||
| public String metrics() | |||
| { | |||
| return prefix + "/metrics"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,116 @@ | |||
| package com.rwk.web.controller.demo.domain; | |||
| import java.util.List; | |||
| import org.apache.commons.lang3.builder.ToStringBuilder; | |||
| import org.apache.commons.lang3.builder.ToStringStyle; | |||
| /** | |||
| * 客户测试信息 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| public class CustomerModel | |||
| { | |||
| /** | |||
| * 客户姓名 | |||
| */ | |||
| private String name; | |||
| /** | |||
| * 客户手机 | |||
| */ | |||
| private String phonenumber; | |||
| /** | |||
| * 客户性别 | |||
| */ | |||
| private String sex; | |||
| /** | |||
| * 客户生日 | |||
| */ | |||
| private String birthday; | |||
| /** | |||
| * 客户描述 | |||
| */ | |||
| private String remark; | |||
| /** | |||
| * 商品信息 | |||
| */ | |||
| private List<GoodsModel> goods; | |||
| public String getName() | |||
| { | |||
| return name; | |||
| } | |||
| public void setName(String name) | |||
| { | |||
| this.name = name; | |||
| } | |||
| public String getPhonenumber() | |||
| { | |||
| return phonenumber; | |||
| } | |||
| public void setPhonenumber(String phonenumber) | |||
| { | |||
| this.phonenumber = phonenumber; | |||
| } | |||
| public String getSex() | |||
| { | |||
| return sex; | |||
| } | |||
| public void setSex(String sex) | |||
| { | |||
| this.sex = sex; | |||
| } | |||
| public String getBirthday() | |||
| { | |||
| return birthday; | |||
| } | |||
| public void setBirthday(String birthday) | |||
| { | |||
| this.birthday = birthday; | |||
| } | |||
| public String getRemark() | |||
| { | |||
| return remark; | |||
| } | |||
| public void setRemark(String remark) | |||
| { | |||
| this.remark = remark; | |||
| } | |||
| public List<GoodsModel> getGoods() | |||
| { | |||
| return goods; | |||
| } | |||
| public void setGoods(List<GoodsModel> goods) | |||
| { | |||
| this.goods = goods; | |||
| } | |||
| @Override | |||
| public String toString() { | |||
| return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) | |||
| .append("name", getName()) | |||
| .append("phonenumber", getPhonenumber()) | |||
| .append("sex", getSex()) | |||
| .append("birthday", getBirthday()) | |||
| .append("goods", getGoods()) | |||
| .append("remark", getRemark()) | |||
| .toString(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,99 @@ | |||
| package com.rwk.web.controller.demo.domain; | |||
| import java.util.Date; | |||
| import org.apache.commons.lang3.builder.ToStringBuilder; | |||
| import org.apache.commons.lang3.builder.ToStringStyle; | |||
| /** | |||
| * 商品测试信息 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| public class GoodsModel | |||
| { | |||
| /** | |||
| * 商品名称 | |||
| */ | |||
| private String name; | |||
| /** | |||
| * 商品重量 | |||
| */ | |||
| private Integer weight; | |||
| /** | |||
| * 商品价格 | |||
| */ | |||
| private Double price; | |||
| /** | |||
| * 商品日期 | |||
| */ | |||
| private Date date; | |||
| /** | |||
| * 商品种类 | |||
| */ | |||
| private String type; | |||
| public String getName() | |||
| { | |||
| return name; | |||
| } | |||
| public void setName(String name) | |||
| { | |||
| this.name = name; | |||
| } | |||
| public Integer getWeight() | |||
| { | |||
| return weight; | |||
| } | |||
| public void setWeight(Integer weight) | |||
| { | |||
| this.weight = weight; | |||
| } | |||
| public Double getPrice() | |||
| { | |||
| return price; | |||
| } | |||
| public void setPrice(Double price) | |||
| { | |||
| this.price = price; | |||
| } | |||
| public Date getDate() | |||
| { | |||
| return date; | |||
| } | |||
| public void setDate(Date date) | |||
| { | |||
| this.date = date; | |||
| } | |||
| public String getType() | |||
| { | |||
| return type; | |||
| } | |||
| public void setType(String type) | |||
| { | |||
| this.type = type; | |||
| } | |||
| @Override | |||
| public String toString() { | |||
| return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) | |||
| .append("name", getName()) | |||
| .append("weight", getWeight()) | |||
| .append("price", getPrice()) | |||
| .append("date", getDate()) | |||
| .append("type", getType()) | |||
| .toString(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,149 @@ | |||
| package com.rwk.web.controller.demo.domain; | |||
| import java.util.Date; | |||
| import com.rwk.common.annotation.Excel; | |||
| import com.rwk.common.annotation.Excel.Type; | |||
| import com.rwk.common.core.domain.BaseEntity; | |||
| import com.rwk.common.utils.DateUtils; | |||
| public class UserOperateModel extends BaseEntity | |||
| { | |||
| private static final long serialVersionUID = 1L; | |||
| private int userId; | |||
| @Excel(name = "用户编号") | |||
| private String userCode; | |||
| @Excel(name = "用户姓名") | |||
| private String userName; | |||
| @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知") | |||
| private String userSex; | |||
| @Excel(name = "用户手机") | |||
| private String userPhone; | |||
| @Excel(name = "用户邮箱") | |||
| private String userEmail; | |||
| @Excel(name = "用户余额") | |||
| private double userBalance; | |||
| @Excel(name = "用户状态", readConverterExp = "0=正常,1=停用") | |||
| private String status; | |||
| @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) | |||
| private Date createTime; | |||
| public UserOperateModel() | |||
| { | |||
| } | |||
| public UserOperateModel(int userId, String userCode, String userName, String userSex, String userPhone, | |||
| String userEmail, double userBalance, String status) | |||
| { | |||
| this.userId = userId; | |||
| this.userCode = userCode; | |||
| this.userName = userName; | |||
| this.userSex = userSex; | |||
| this.userPhone = userPhone; | |||
| this.userEmail = userEmail; | |||
| this.userBalance = userBalance; | |||
| this.status = status; | |||
| this.createTime = DateUtils.getNowDate(); | |||
| } | |||
| public int getUserId() | |||
| { | |||
| return userId; | |||
| } | |||
| public void setUserId(int userId) | |||
| { | |||
| this.userId = userId; | |||
| } | |||
| public String getUserCode() | |||
| { | |||
| return userCode; | |||
| } | |||
| public void setUserCode(String userCode) | |||
| { | |||
| this.userCode = userCode; | |||
| } | |||
| public String getUserName() | |||
| { | |||
| return userName; | |||
| } | |||
| public void setUserName(String userName) | |||
| { | |||
| this.userName = userName; | |||
| } | |||
| public String getUserSex() | |||
| { | |||
| return userSex; | |||
| } | |||
| public void setUserSex(String userSex) | |||
| { | |||
| this.userSex = userSex; | |||
| } | |||
| public String getUserPhone() | |||
| { | |||
| return userPhone; | |||
| } | |||
| public void setUserPhone(String userPhone) | |||
| { | |||
| this.userPhone = userPhone; | |||
| } | |||
| public String getUserEmail() | |||
| { | |||
| return userEmail; | |||
| } | |||
| public void setUserEmail(String userEmail) | |||
| { | |||
| this.userEmail = userEmail; | |||
| } | |||
| public double getUserBalance() | |||
| { | |||
| return userBalance; | |||
| } | |||
| public void setUserBalance(double userBalance) | |||
| { | |||
| this.userBalance = userBalance; | |||
| } | |||
| public String getStatus() | |||
| { | |||
| return status; | |||
| } | |||
| public void setStatus(String status) | |||
| { | |||
| this.status = status; | |||
| } | |||
| @Override | |||
| public Date getCreateTime() | |||
| { | |||
| return createTime; | |||
| } | |||
| @Override | |||
| public void setCreateTime(Date createTime) | |||
| { | |||
| this.createTime = createTime; | |||
| } | |||
| } | |||
| @@ -0,0 +1,90 @@ | |||
| package com.rwk.web.controller.monitor; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.framework.web.service.CacheService; | |||
| /** | |||
| * 缓存监控 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/monitor/cache") | |||
| public class CacheController extends BaseController | |||
| { | |||
| private String prefix = "monitor/cache"; | |||
| @Autowired | |||
| private CacheService cacheService; | |||
| @RequiresPermissions("monitor:cache:view") | |||
| @GetMapping() | |||
| public String cache(ModelMap mmap) | |||
| { | |||
| mmap.put("cacheNames", cacheService.getCacheNames()); | |||
| return prefix + "/cache"; | |||
| } | |||
| @RequiresPermissions("monitor:cache:view") | |||
| @PostMapping("/getNames") | |||
| public String getCacheNames(String fragment, ModelMap mmap) | |||
| { | |||
| mmap.put("cacheNames", cacheService.getCacheNames()); | |||
| return prefix + "/cache::" + fragment; | |||
| } | |||
| @RequiresPermissions("monitor:cache:view") | |||
| @PostMapping("/getKeys") | |||
| public String getCacheKeys(String fragment, String cacheName, ModelMap mmap) | |||
| { | |||
| mmap.put("cacheName", cacheName); | |||
| mmap.put("cacheKeys", cacheService.getCacheKeys(cacheName)); | |||
| return prefix + "/cache::" + fragment; | |||
| } | |||
| @RequiresPermissions("monitor:cache:view") | |||
| @PostMapping("/getValue") | |||
| public String getCacheValue(String fragment, String cacheName, String cacheKey, ModelMap mmap) | |||
| { | |||
| mmap.put("cacheName", cacheName); | |||
| mmap.put("cacheKey", cacheKey); | |||
| mmap.put("cacheValue", cacheService.getCacheValue(cacheName, cacheKey)); | |||
| return prefix + "/cache::" + fragment; | |||
| } | |||
| @RequiresPermissions("monitor:cache:view") | |||
| @PostMapping("/clearCacheName") | |||
| @ResponseBody | |||
| public AjaxResult clearCacheName(String cacheName, ModelMap mmap) | |||
| { | |||
| cacheService.clearCacheName(cacheName); | |||
| return AjaxResult.success(); | |||
| } | |||
| @RequiresPermissions("monitor:cache:view") | |||
| @PostMapping("/clearCacheKey") | |||
| @ResponseBody | |||
| public AjaxResult clearCacheKey(String cacheName, String cacheKey, ModelMap mmap) | |||
| { | |||
| cacheService.clearCacheKey(cacheName, cacheKey); | |||
| return AjaxResult.success(); | |||
| } | |||
| @RequiresPermissions("monitor:cache:view") | |||
| @GetMapping("/clearAll") | |||
| @ResponseBody | |||
| public AjaxResult clearAll(ModelMap mmap) | |||
| { | |||
| cacheService.clearAll(); | |||
| return AjaxResult.success(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,26 @@ | |||
| package com.rwk.web.controller.monitor; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| /** | |||
| * druid 监控 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/monitor/data") | |||
| public class DruidController extends BaseController | |||
| { | |||
| private String prefix = "/druid"; | |||
| @RequiresPermissions("monitor:data:view") | |||
| @GetMapping() | |||
| public String index() | |||
| { | |||
| return redirect(prefix + "/index.html"); | |||
| } | |||
| } | |||
| @@ -0,0 +1,31 @@ | |||
| package com.rwk.web.controller.monitor; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.framework.web.domain.Server; | |||
| /** | |||
| * 服务器监控 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/monitor/server") | |||
| public class ServerController extends BaseController | |||
| { | |||
| private String prefix = "monitor/server"; | |||
| @RequiresPermissions("monitor:server:view") | |||
| @GetMapping() | |||
| public String server(ModelMap mmap) throws Exception | |||
| { | |||
| Server server = new Server(); | |||
| server.copyTo(); | |||
| mmap.put("server", server); | |||
| return prefix + "/server"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,102 @@ | |||
| package com.rwk.web.controller.monitor; | |||
| import java.util.List; | |||
| import com.rwk.framework.shiro.service.SysPasswordService; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.utils.poi.ExcelUtil; | |||
| import com.rwk.system.domain.SysLogininfor; | |||
| import com.rwk.system.service.ISysLogininforService; | |||
| /** | |||
| * 系统访问记录 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/monitor/logininfor") | |||
| public class SysLogininforController extends BaseController | |||
| { | |||
| private String prefix = "monitor/logininfor"; | |||
| @Autowired | |||
| private ISysLogininforService logininforService; | |||
| @Autowired | |||
| private SysPasswordService passwordService; | |||
| @RequiresPermissions("monitor:logininfor:view") | |||
| @GetMapping() | |||
| public String logininfor() | |||
| { | |||
| return prefix + "/logininfor"; | |||
| } | |||
| @RequiresPermissions("monitor:logininfor:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public TableDataInfo list(SysLogininfor logininfor) | |||
| { | |||
| startPage(); | |||
| String loginName = getSysUser().getLoginName(); | |||
| if ("sjgly".equals(loginName)){ | |||
| logininfor.setRemark("1"); | |||
| logininfor.setSearchValue("sjgly,aqgly,xtgly"); | |||
| }else if ("aqgly".equals(loginName)){ | |||
| logininfor.setRemark("2"); | |||
| logininfor.setSearchValue("aqgly,xtgly"); | |||
| } | |||
| List<SysLogininfor> list = logininforService.selectLogininforList(logininfor); | |||
| return getDataTable(list); | |||
| } | |||
| @Log(title = "登录日志", businessType = BusinessType.EXPORT) | |||
| @RequiresPermissions("monitor:logininfor:export") | |||
| @PostMapping("/export") | |||
| @ResponseBody | |||
| public AjaxResult export(SysLogininfor logininfor) | |||
| { | |||
| List<SysLogininfor> list = logininforService.selectLogininforList(logininfor); | |||
| ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class); | |||
| return util.exportExcel(list, "登录日志"); | |||
| } | |||
| @RequiresPermissions("monitor:logininfor:remove") | |||
| @Log(title = "登录日志", businessType = BusinessType.DELETE) | |||
| @PostMapping("/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| return toAjax(logininforService.deleteLogininforByIds(ids)); | |||
| } | |||
| @RequiresPermissions("monitor:logininfor:remove") | |||
| @Log(title = "登录日志", businessType = BusinessType.CLEAN) | |||
| @PostMapping("/clean") | |||
| @ResponseBody | |||
| public AjaxResult clean() | |||
| { | |||
| logininforService.cleanLogininfor(); | |||
| return success(); | |||
| } | |||
| @RequiresPermissions("monitor:logininfor:unlock") | |||
| @Log(title = "账户解锁", businessType = BusinessType.OTHER) | |||
| @PostMapping("/unlock") | |||
| @ResponseBody | |||
| public AjaxResult unlock(String loginName) | |||
| { | |||
| passwordService.clearLoginRecordCache(loginName); | |||
| return success(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,98 @@ | |||
| package com.rwk.web.controller.monitor; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.utils.poi.ExcelUtil; | |||
| import com.rwk.system.domain.SysOperLog; | |||
| import com.rwk.system.service.ISysOperLogService; | |||
| /** | |||
| * 操作日志记录 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/monitor/operlog") | |||
| public class SysOperlogController extends BaseController | |||
| { | |||
| private String prefix = "monitor/operlog"; | |||
| @Autowired | |||
| private ISysOperLogService operLogService; | |||
| @RequiresPermissions("monitor:operlog:view") | |||
| @GetMapping() | |||
| public String operlog() | |||
| { | |||
| return prefix + "/operlog"; | |||
| } | |||
| @RequiresPermissions("monitor:operlog:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public TableDataInfo list(SysOperLog operLog) | |||
| { | |||
| startPage(); | |||
| String loginName = getSysUser().getLoginName(); | |||
| if ("sjgly".equals(loginName)){ | |||
| operLog.setRemark("1"); | |||
| operLog.setSearchValue("sjgly,aqgly,xtgly"); | |||
| }else if ("aqgly".equals(loginName)){ | |||
| operLog.setRemark("2"); | |||
| operLog.setSearchValue("aqgly,xtgly"); | |||
| } | |||
| List<SysOperLog> list = operLogService.selectOperLogList(operLog); | |||
| return getDataTable(list); | |||
| } | |||
| @Log(title = "操作日志", businessType = BusinessType.EXPORT) | |||
| @RequiresPermissions("monitor:operlog:export") | |||
| @PostMapping("/export") | |||
| @ResponseBody | |||
| public AjaxResult export(SysOperLog operLog) | |||
| { | |||
| List<SysOperLog> list = operLogService.selectOperLogList(operLog); | |||
| ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class); | |||
| return util.exportExcel(list, "操作日志"); | |||
| } | |||
| @Log(title = "操作日志", businessType = BusinessType.DELETE) | |||
| @RequiresPermissions("monitor:operlog:remove") | |||
| @PostMapping("/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| return toAjax(operLogService.deleteOperLogByIds(ids)); | |||
| } | |||
| @RequiresPermissions("monitor:operlog:detail") | |||
| @GetMapping("/detail/{operId}") | |||
| public String detail(@PathVariable("operId") Long operId, ModelMap mmap) | |||
| { | |||
| mmap.put("operLog", operLogService.selectOperLogById(operId)); | |||
| return prefix + "/detail"; | |||
| } | |||
| @Log(title = "操作日志", businessType = BusinessType.CLEAN) | |||
| @RequiresPermissions("monitor:operlog:remove") | |||
| @PostMapping("/clean") | |||
| @ResponseBody | |||
| public AjaxResult clean() | |||
| { | |||
| operLogService.cleanOperLog(); | |||
| return success(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,88 @@ | |||
| package com.rwk.web.controller.monitor; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.Logical; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| import com.rwk.common.core.text.Convert; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.enums.OnlineStatus; | |||
| import com.rwk.common.utils.ShiroUtils; | |||
| import com.rwk.framework.shiro.session.OnlineSession; | |||
| import com.rwk.framework.shiro.session.OnlineSessionDAO; | |||
| import com.rwk.system.domain.SysUserOnline; | |||
| import com.rwk.system.service.ISysUserOnlineService; | |||
| /** | |||
| * 在线用户监控 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/monitor/online") | |||
| public class SysUserOnlineController extends BaseController | |||
| { | |||
| private String prefix = "monitor/online"; | |||
| @Autowired | |||
| private ISysUserOnlineService userOnlineService; | |||
| @Autowired | |||
| private OnlineSessionDAO onlineSessionDAO; | |||
| @RequiresPermissions("monitor:online:view") | |||
| @GetMapping() | |||
| public String online() | |||
| { | |||
| return prefix + "/online"; | |||
| } | |||
| @RequiresPermissions("monitor:online:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public TableDataInfo list(SysUserOnline userOnline) | |||
| { | |||
| startPage(); | |||
| List<SysUserOnline> list = userOnlineService.selectUserOnlineList(userOnline); | |||
| return getDataTable(list); | |||
| } | |||
| @RequiresPermissions(value = { "monitor:online:batchForceLogout", "monitor:online:forceLogout" }, logical = Logical.OR) | |||
| @Log(title = "在线用户", businessType = BusinessType.FORCE) | |||
| @PostMapping("/batchForceLogout") | |||
| @ResponseBody | |||
| public AjaxResult batchForceLogout(String ids) | |||
| { | |||
| for (String sessionId : Convert.toStrArray(ids)) | |||
| { | |||
| SysUserOnline online = userOnlineService.selectOnlineById(sessionId); | |||
| if (online == null) | |||
| { | |||
| return error("用户已下线"); | |||
| } | |||
| OnlineSession onlineSession = (OnlineSession) onlineSessionDAO.readSession(online.getSessionId()); | |||
| if (onlineSession == null) | |||
| { | |||
| return error("用户已下线"); | |||
| } | |||
| if (sessionId.equals(ShiroUtils.getSessionId())) | |||
| { | |||
| return error("当前登录用户无法强退"); | |||
| } | |||
| onlineSessionDAO.delete(onlineSession); | |||
| online.setStatus(OnlineStatus.off_line); | |||
| userOnlineService.saveOnline(online); | |||
| userOnlineService.removeUserCache(online.getLoginName(), sessionId); | |||
| } | |||
| return success(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,92 @@ | |||
| package com.rwk.web.controller.system; | |||
| import java.awt.image.BufferedImage; | |||
| import java.io.IOException; | |||
| import javax.annotation.Resource; | |||
| import javax.imageio.ImageIO; | |||
| import javax.servlet.ServletOutputStream; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import javax.servlet.http.HttpServletResponse; | |||
| import javax.servlet.http.HttpSession; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.servlet.ModelAndView; | |||
| import com.google.code.kaptcha.Constants; | |||
| import com.google.code.kaptcha.Producer; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| /** | |||
| * 图片验证码(支持算术形式) | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/captcha") | |||
| public class SysCaptchaController extends BaseController | |||
| { | |||
| @Resource(name = "captchaProducer") | |||
| private Producer captchaProducer; | |||
| @Resource(name = "captchaProducerMath") | |||
| private Producer captchaProducerMath; | |||
| /** | |||
| * 验证码生成 | |||
| */ | |||
| @GetMapping(value = "/captchaImage") | |||
| public ModelAndView getKaptchaImage(HttpServletRequest request, HttpServletResponse response) | |||
| { | |||
| ServletOutputStream out = null; | |||
| try | |||
| { | |||
| HttpSession session = request.getSession(); | |||
| response.setDateHeader("Expires", 0); | |||
| response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); | |||
| response.addHeader("Cache-Control", "post-check=0, pre-check=0"); | |||
| response.setHeader("Pragma", "no-cache"); | |||
| response.setContentType("image/jpeg"); | |||
| String type = request.getParameter("type"); | |||
| String capStr = null; | |||
| String code = null; | |||
| BufferedImage bi = null; | |||
| if ("math".equals(type)) | |||
| { | |||
| String capText = captchaProducerMath.createText(); | |||
| capStr = capText.substring(0, capText.lastIndexOf("@")); | |||
| code = capText.substring(capText.lastIndexOf("@") + 1); | |||
| bi = captchaProducerMath.createImage(capStr); | |||
| } | |||
| else if ("char".equals(type)) | |||
| { | |||
| capStr = code = captchaProducer.createText(); | |||
| bi = captchaProducer.createImage(capStr); | |||
| } | |||
| session.setAttribute(Constants.KAPTCHA_SESSION_KEY, code); | |||
| out = response.getOutputStream(); | |||
| ImageIO.write(bi, "jpg", out); | |||
| out.flush(); | |||
| } | |||
| catch (Exception e) | |||
| { | |||
| e.printStackTrace(); | |||
| } | |||
| finally | |||
| { | |||
| try | |||
| { | |||
| if (out != null) | |||
| { | |||
| out.close(); | |||
| } | |||
| } | |||
| catch (IOException e) | |||
| { | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| } | |||
| @@ -0,0 +1,157 @@ | |||
| package com.rwk.web.controller.system; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.utils.poi.ExcelUtil; | |||
| import com.rwk.system.domain.SysConfig; | |||
| import com.rwk.system.service.ISysConfigService; | |||
| /** | |||
| * 参数配置 信息操作处理 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/config") | |||
| public class SysConfigController extends BaseController | |||
| { | |||
| private String prefix = "system/config"; | |||
| @Autowired | |||
| private ISysConfigService configService; | |||
| @RequiresPermissions("system:config:view") | |||
| @GetMapping() | |||
| public String config() | |||
| { | |||
| return prefix + "/config"; | |||
| } | |||
| /** | |||
| * 查询参数配置列表 | |||
| */ | |||
| @RequiresPermissions("system:config:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public TableDataInfo list(SysConfig config) | |||
| { | |||
| startPage(); | |||
| List<SysConfig> list = configService.selectConfigList(config); | |||
| return getDataTable(list); | |||
| } | |||
| @Log(title = "参数管理", businessType = BusinessType.EXPORT) | |||
| @RequiresPermissions("system:config:export") | |||
| @PostMapping("/export") | |||
| @ResponseBody | |||
| public AjaxResult export(SysConfig config) | |||
| { | |||
| List<SysConfig> list = configService.selectConfigList(config); | |||
| ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class); | |||
| return util.exportExcel(list, "参数数据"); | |||
| } | |||
| /** | |||
| * 新增参数配置 | |||
| */ | |||
| @GetMapping("/add") | |||
| public String add() | |||
| { | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存参数配置 | |||
| */ | |||
| @RequiresPermissions("system:config:add") | |||
| @Log(title = "参数管理", businessType = BusinessType.INSERT) | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(@Validated SysConfig config) | |||
| { | |||
| if (!configService.checkConfigKeyUnique(config)) | |||
| { | |||
| return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); | |||
| } | |||
| config.setCreateBy(getLoginName()); | |||
| return toAjax(configService.insertConfig(config)); | |||
| } | |||
| /** | |||
| * 修改参数配置 | |||
| */ | |||
| @RequiresPermissions("system:config:edit") | |||
| @GetMapping("/edit/{configId}") | |||
| public String edit(@PathVariable("configId") Long configId, ModelMap mmap) | |||
| { | |||
| mmap.put("config", configService.selectConfigById(configId)); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改保存参数配置 | |||
| */ | |||
| @RequiresPermissions("system:config:edit") | |||
| @Log(title = "参数管理", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(@Validated SysConfig config) | |||
| { | |||
| if (!configService.checkConfigKeyUnique(config)) | |||
| { | |||
| return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); | |||
| } | |||
| config.setUpdateBy(getLoginName()); | |||
| return toAjax(configService.updateConfig(config)); | |||
| } | |||
| /** | |||
| * 删除参数配置 | |||
| */ | |||
| @RequiresPermissions("system:config:remove") | |||
| @Log(title = "参数管理", businessType = BusinessType.DELETE) | |||
| @PostMapping("/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| configService.deleteConfigByIds(ids); | |||
| return success(); | |||
| } | |||
| /** | |||
| * 刷新参数缓存 | |||
| */ | |||
| @RequiresPermissions("system:config:remove") | |||
| @Log(title = "参数管理", businessType = BusinessType.CLEAN) | |||
| @GetMapping("/refreshCache") | |||
| @ResponseBody | |||
| public AjaxResult refreshCache() | |||
| { | |||
| configService.resetConfigCache(); | |||
| return success(); | |||
| } | |||
| /** | |||
| * 校验参数键名 | |||
| */ | |||
| @PostMapping("/checkConfigKeyUnique") | |||
| @ResponseBody | |||
| public boolean checkConfigKeyUnique(SysConfig config) | |||
| { | |||
| return configService.checkConfigKeyUnique(config); | |||
| } | |||
| } | |||
| @@ -0,0 +1,198 @@ | |||
| package com.rwk.web.controller.system; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.constant.UserConstants; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.domain.Ztree; | |||
| import com.rwk.common.core.domain.entity.SysDept; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.utils.StringUtils; | |||
| import com.rwk.system.service.ISysDeptService; | |||
| /** | |||
| * 部门信息 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/dept") | |||
| public class SysDeptController extends BaseController | |||
| { | |||
| private String prefix = "system/dept"; | |||
| @Autowired | |||
| private ISysDeptService deptService; | |||
| @RequiresPermissions("system:dept:view") | |||
| @GetMapping() | |||
| public String dept() | |||
| { | |||
| return prefix + "/dept"; | |||
| } | |||
| @RequiresPermissions("system:dept:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public List<SysDept> list(SysDept dept) | |||
| { | |||
| List<SysDept> deptList = deptService.selectDeptList(dept); | |||
| return deptList; | |||
| } | |||
| /** | |||
| * 新增部门 | |||
| */ | |||
| @GetMapping("/add/{parentId}") | |||
| public String add(@PathVariable("parentId") Long parentId, ModelMap mmap) | |||
| { | |||
| if (!getSysUser().isAdmin()) | |||
| { | |||
| parentId = getSysUser().getDeptId(); | |||
| } | |||
| mmap.put("dept", deptService.selectDeptById(parentId)); | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存部门 | |||
| */ | |||
| @Log(title = "部门管理", businessType = BusinessType.INSERT) | |||
| @RequiresPermissions("system:dept:add") | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(@Validated SysDept dept) | |||
| { | |||
| if (!deptService.checkDeptNameUnique(dept)) | |||
| { | |||
| return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); | |||
| } | |||
| dept.setCreateBy(getLoginName()); | |||
| return toAjax(deptService.insertDept(dept)); | |||
| } | |||
| /** | |||
| * 修改部门 | |||
| */ | |||
| @RequiresPermissions("system:dept:edit") | |||
| @GetMapping("/edit/{deptId}") | |||
| public String edit(@PathVariable("deptId") Long deptId, ModelMap mmap) | |||
| { | |||
| deptService.checkDeptDataScope(deptId); | |||
| SysDept dept = deptService.selectDeptById(deptId); | |||
| if (StringUtils.isNotNull(dept) && 100L == deptId) | |||
| { | |||
| dept.setParentName("无"); | |||
| } | |||
| mmap.put("dept", dept); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改保存部门 | |||
| */ | |||
| @Log(title = "部门管理", businessType = BusinessType.UPDATE) | |||
| @RequiresPermissions("system:dept:edit") | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(@Validated SysDept dept) | |||
| { | |||
| Long deptId = dept.getDeptId(); | |||
| deptService.checkDeptDataScope(deptId); | |||
| if (!deptService.checkDeptNameUnique(dept)) | |||
| { | |||
| return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); | |||
| } | |||
| else if (dept.getParentId().equals(deptId)) | |||
| { | |||
| return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); | |||
| } | |||
| else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0) | |||
| { | |||
| return AjaxResult.error("该部门包含未停用的子部门!"); | |||
| } | |||
| dept.setUpdateBy(getLoginName()); | |||
| return toAjax(deptService.updateDept(dept)); | |||
| } | |||
| /** | |||
| * 删除 | |||
| */ | |||
| @Log(title = "部门管理", businessType = BusinessType.DELETE) | |||
| @RequiresPermissions("system:dept:remove") | |||
| @GetMapping("/remove/{deptId}") | |||
| @ResponseBody | |||
| public AjaxResult remove(@PathVariable("deptId") Long deptId) | |||
| { | |||
| if (deptService.selectDeptCount(deptId) > 0) | |||
| { | |||
| return AjaxResult.warn("存在下级部门,不允许删除"); | |||
| } | |||
| if (deptService.checkDeptExistUser(deptId)) | |||
| { | |||
| return AjaxResult.warn("部门存在用户,不允许删除"); | |||
| } | |||
| deptService.checkDeptDataScope(deptId); | |||
| return toAjax(deptService.deleteDeptById(deptId)); | |||
| } | |||
| /** | |||
| * 校验部门名称 | |||
| */ | |||
| @PostMapping("/checkDeptNameUnique") | |||
| @ResponseBody | |||
| public boolean checkDeptNameUnique(SysDept dept) | |||
| { | |||
| return deptService.checkDeptNameUnique(dept); | |||
| } | |||
| /** | |||
| * 选择部门树 | |||
| * | |||
| * @param deptId 部门ID | |||
| * @param excludeId 排除ID | |||
| */ | |||
| @GetMapping(value = { "/selectDeptTree/{deptId}", "/selectDeptTree/{deptId}/{excludeId}" }) | |||
| public String selectDeptTree(@PathVariable("deptId") Long deptId, | |||
| @PathVariable(value = "excludeId", required = false) Long excludeId, ModelMap mmap) | |||
| { | |||
| mmap.put("dept", deptService.selectDeptById(deptId)); | |||
| mmap.put("excludeId", excludeId); | |||
| return prefix + "/tree"; | |||
| } | |||
| /** | |||
| * 加载部门列表树 | |||
| */ | |||
| @GetMapping("/treeData") | |||
| @ResponseBody | |||
| public List<Ztree> treeData() | |||
| { | |||
| List<Ztree> ztrees = deptService.selectDeptTree(new SysDept()); | |||
| return ztrees; | |||
| } | |||
| /** | |||
| * 加载部门列表树(排除下级) | |||
| */ | |||
| @GetMapping("/treeData/{excludeId}") | |||
| @ResponseBody | |||
| public List<Ztree> treeDataExcludeChild(@PathVariable(value = "excludeId", required = false) Long excludeId) | |||
| { | |||
| SysDept dept = new SysDept(); | |||
| dept.setExcludeId(excludeId); | |||
| List<Ztree> ztrees = deptService.selectDeptTreeExcludeChild(dept); | |||
| return ztrees; | |||
| } | |||
| } | |||
| @@ -0,0 +1,121 @@ | |||
| package com.rwk.web.controller.system; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.domain.entity.SysDictData; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.utils.poi.ExcelUtil; | |||
| import com.rwk.system.service.ISysDictDataService; | |||
| /** | |||
| * 数据字典信息 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/dict/data") | |||
| public class SysDictDataController extends BaseController | |||
| { | |||
| private String prefix = "system/dict/data"; | |||
| @Autowired | |||
| private ISysDictDataService dictDataService; | |||
| @RequiresPermissions("system:dict:view") | |||
| @GetMapping() | |||
| public String dictData() | |||
| { | |||
| return prefix + "/data"; | |||
| } | |||
| @PostMapping("/list") | |||
| @RequiresPermissions("system:dict:list") | |||
| @ResponseBody | |||
| public TableDataInfo list(SysDictData dictData) | |||
| { | |||
| startPage(); | |||
| List<SysDictData> list = dictDataService.selectDictDataList(dictData); | |||
| return getDataTable(list); | |||
| } | |||
| @Log(title = "字典数据", businessType = BusinessType.EXPORT) | |||
| @RequiresPermissions("system:dict:export") | |||
| @PostMapping("/export") | |||
| @ResponseBody | |||
| public AjaxResult export(SysDictData dictData) | |||
| { | |||
| List<SysDictData> list = dictDataService.selectDictDataList(dictData); | |||
| ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class); | |||
| return util.exportExcel(list, "字典数据"); | |||
| } | |||
| /** | |||
| * 新增字典类型 | |||
| */ | |||
| @GetMapping("/add/{dictType}") | |||
| public String add(@PathVariable("dictType") String dictType, ModelMap mmap) | |||
| { | |||
| mmap.put("dictType", dictType); | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存字典类型 | |||
| */ | |||
| @Log(title = "字典数据", businessType = BusinessType.INSERT) | |||
| @RequiresPermissions("system:dict:add") | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(@Validated SysDictData dict) | |||
| { | |||
| dict.setCreateBy(getLoginName()); | |||
| return toAjax(dictDataService.insertDictData(dict)); | |||
| } | |||
| /** | |||
| * 修改字典类型 | |||
| */ | |||
| @RequiresPermissions("system:dict:edit") | |||
| @GetMapping("/edit/{dictCode}") | |||
| public String edit(@PathVariable("dictCode") Long dictCode, ModelMap mmap) | |||
| { | |||
| mmap.put("dict", dictDataService.selectDictDataById(dictCode)); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改保存字典类型 | |||
| */ | |||
| @Log(title = "字典数据", businessType = BusinessType.UPDATE) | |||
| @RequiresPermissions("system:dict:edit") | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(@Validated SysDictData dict) | |||
| { | |||
| dict.setUpdateBy(getLoginName()); | |||
| return toAjax(dictDataService.updateDictData(dict)); | |||
| } | |||
| @Log(title = "字典数据", businessType = BusinessType.DELETE) | |||
| @RequiresPermissions("system:dict:remove") | |||
| @PostMapping("/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| dictDataService.deleteDictDataByIds(ids); | |||
| return success(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,188 @@ | |||
| package com.rwk.web.controller.system; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.domain.Ztree; | |||
| import com.rwk.common.core.domain.entity.SysDictType; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.utils.poi.ExcelUtil; | |||
| import com.rwk.system.service.ISysDictTypeService; | |||
| /** | |||
| * 数据字典信息 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/dict") | |||
| public class SysDictTypeController extends BaseController | |||
| { | |||
| private String prefix = "system/dict/type"; | |||
| @Autowired | |||
| private ISysDictTypeService dictTypeService; | |||
| @RequiresPermissions("system:dict:view") | |||
| @GetMapping() | |||
| public String dictType() | |||
| { | |||
| return prefix + "/type"; | |||
| } | |||
| @PostMapping("/list") | |||
| @RequiresPermissions("system:dict:list") | |||
| @ResponseBody | |||
| public TableDataInfo list(SysDictType dictType) | |||
| { | |||
| startPage(); | |||
| List<SysDictType> list = dictTypeService.selectDictTypeList(dictType); | |||
| return getDataTable(list); | |||
| } | |||
| @Log(title = "字典类型", businessType = BusinessType.EXPORT) | |||
| @RequiresPermissions("system:dict:export") | |||
| @PostMapping("/export") | |||
| @ResponseBody | |||
| public AjaxResult export(SysDictType dictType) | |||
| { | |||
| List<SysDictType> list = dictTypeService.selectDictTypeList(dictType); | |||
| ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class); | |||
| return util.exportExcel(list, "字典类型"); | |||
| } | |||
| /** | |||
| * 新增字典类型 | |||
| */ | |||
| @GetMapping("/add") | |||
| public String add() | |||
| { | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存字典类型 | |||
| */ | |||
| @Log(title = "字典类型", businessType = BusinessType.INSERT) | |||
| @RequiresPermissions("system:dict:add") | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(@Validated SysDictType dict) | |||
| { | |||
| if (!dictTypeService.checkDictTypeUnique(dict)) | |||
| { | |||
| return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); | |||
| } | |||
| dict.setCreateBy(getLoginName()); | |||
| return toAjax(dictTypeService.insertDictType(dict)); | |||
| } | |||
| /** | |||
| * 修改字典类型 | |||
| */ | |||
| @RequiresPermissions("system:dict:edit") | |||
| @GetMapping("/edit/{dictId}") | |||
| public String edit(@PathVariable("dictId") Long dictId, ModelMap mmap) | |||
| { | |||
| mmap.put("dict", dictTypeService.selectDictTypeById(dictId)); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改保存字典类型 | |||
| */ | |||
| @Log(title = "字典类型", businessType = BusinessType.UPDATE) | |||
| @RequiresPermissions("system:dict:edit") | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(@Validated SysDictType dict) | |||
| { | |||
| if (!dictTypeService.checkDictTypeUnique(dict)) | |||
| { | |||
| return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); | |||
| } | |||
| dict.setUpdateBy(getLoginName()); | |||
| return toAjax(dictTypeService.updateDictType(dict)); | |||
| } | |||
| @Log(title = "字典类型", businessType = BusinessType.DELETE) | |||
| @RequiresPermissions("system:dict:remove") | |||
| @PostMapping("/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| dictTypeService.deleteDictTypeByIds(ids); | |||
| return success(); | |||
| } | |||
| /** | |||
| * 刷新字典缓存 | |||
| */ | |||
| @RequiresPermissions("system:dict:remove") | |||
| @Log(title = "字典类型", businessType = BusinessType.CLEAN) | |||
| @GetMapping("/refreshCache") | |||
| @ResponseBody | |||
| public AjaxResult refreshCache() | |||
| { | |||
| dictTypeService.resetDictCache(); | |||
| return success(); | |||
| } | |||
| /** | |||
| * 查询字典详细 | |||
| */ | |||
| @RequiresPermissions("system:dict:list") | |||
| @GetMapping("/detail/{dictId}") | |||
| public String detail(@PathVariable("dictId") Long dictId, ModelMap mmap) | |||
| { | |||
| mmap.put("dict", dictTypeService.selectDictTypeById(dictId)); | |||
| mmap.put("dictList", dictTypeService.selectDictTypeAll()); | |||
| return "system/dict/data/data"; | |||
| } | |||
| /** | |||
| * 校验字典类型 | |||
| */ | |||
| @PostMapping("/checkDictTypeUnique") | |||
| @ResponseBody | |||
| public boolean checkDictTypeUnique(SysDictType dictType) | |||
| { | |||
| return dictTypeService.checkDictTypeUnique(dictType); | |||
| } | |||
| /** | |||
| * 选择字典树 | |||
| */ | |||
| @GetMapping("/selectDictTree/{columnId}/{dictType}") | |||
| public String selectDeptTree(@PathVariable("columnId") Long columnId, @PathVariable("dictType") String dictType, | |||
| ModelMap mmap) | |||
| { | |||
| mmap.put("columnId", columnId); | |||
| mmap.put("dict", dictTypeService.selectDictTypeByType(dictType)); | |||
| return prefix + "/tree"; | |||
| } | |||
| /** | |||
| * 加载字典列表树 | |||
| */ | |||
| @GetMapping("/treeData") | |||
| @ResponseBody | |||
| public List<Ztree> treeData() | |||
| { | |||
| List<Ztree> ztrees = dictTypeService.selectDictTree(new SysDictType()); | |||
| return ztrees; | |||
| } | |||
| } | |||
| @@ -0,0 +1,178 @@ | |||
| package com.rwk.web.controller.system; | |||
| import java.util.Date; | |||
| import java.util.List; | |||
| import javax.servlet.http.Cookie; | |||
| import javax.servlet.http.HttpServletResponse; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.config.RuoYiConfig; | |||
| import com.rwk.common.constant.ShiroConstants; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.domain.entity.SysMenu; | |||
| import com.rwk.common.core.domain.entity.SysUser; | |||
| import com.rwk.common.core.text.Convert; | |||
| import com.rwk.common.utils.CookieUtils; | |||
| import com.rwk.common.utils.DateUtils; | |||
| import com.rwk.common.utils.ServletUtils; | |||
| import com.rwk.common.utils.StringUtils; | |||
| import com.rwk.framework.shiro.service.SysPasswordService; | |||
| import com.rwk.system.service.ISysConfigService; | |||
| import com.rwk.system.service.ISysMenuService; | |||
| /** | |||
| * 首页 业务处理 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| public class SysIndexController extends BaseController | |||
| { | |||
| @Autowired | |||
| private ISysMenuService menuService; | |||
| @Autowired | |||
| private ISysConfigService configService; | |||
| @Autowired | |||
| private SysPasswordService passwordService; | |||
| // 系统首页 | |||
| @GetMapping("/index") | |||
| public String index(ModelMap mmap) | |||
| { | |||
| // 取身份信息 | |||
| SysUser user = getSysUser(); | |||
| // 根据用户id取出菜单 | |||
| List<SysMenu> menus = menuService.selectMenusByUser(user); | |||
| mmap.put("menus", menus); | |||
| mmap.put("user", user); | |||
| mmap.put("sideTheme", configService.selectConfigByKey("sys.index.sideTheme")); | |||
| mmap.put("skinName", configService.selectConfigByKey("sys.index.skinName")); | |||
| Boolean footer = Convert.toBool(configService.selectConfigByKey("sys.index.footer"), true); | |||
| Boolean tagsView = Convert.toBool(configService.selectConfigByKey("sys.index.tagsView"), true); | |||
| mmap.put("footer", footer); | |||
| mmap.put("tagsView", tagsView); | |||
| mmap.put("mainClass", contentMainClass(footer, tagsView)); | |||
| mmap.put("copyrightYear", RuoYiConfig.getCopyrightYear()); | |||
| mmap.put("demoEnabled", RuoYiConfig.isDemoEnabled()); | |||
| mmap.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate())); | |||
| mmap.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate())); | |||
| mmap.put("isMobile", ServletUtils.checkAgentIsMobile(ServletUtils.getRequest().getHeader("User-Agent"))); | |||
| // 菜单导航显示风格 | |||
| String menuStyle = configService.selectConfigByKey("sys.index.menuStyle"); | |||
| // 移动端,默认使左侧导航菜单,否则取默认配置 | |||
| String indexStyle = ServletUtils.checkAgentIsMobile(ServletUtils.getRequest().getHeader("User-Agent")) ? "index" : menuStyle; | |||
| // 优先Cookie配置导航菜单 | |||
| Cookie[] cookies = ServletUtils.getRequest().getCookies(); | |||
| for (Cookie cookie : cookies) | |||
| { | |||
| if (StringUtils.isNotEmpty(cookie.getName()) && "nav-style".equalsIgnoreCase(cookie.getName())) | |||
| { | |||
| indexStyle = cookie.getValue(); | |||
| break; | |||
| } | |||
| } | |||
| String webIndex = "topnav".equalsIgnoreCase(indexStyle) ? "index-topnav" : "index"; | |||
| return webIndex; | |||
| } | |||
| // 锁定屏幕 | |||
| @GetMapping("/lockscreen") | |||
| public String lockscreen(ModelMap mmap) | |||
| { | |||
| mmap.put("user", getSysUser()); | |||
| ServletUtils.getSession().setAttribute(ShiroConstants.LOCK_SCREEN, true); | |||
| return "lock"; | |||
| } | |||
| // 解锁屏幕 | |||
| @PostMapping("/unlockscreen") | |||
| @ResponseBody | |||
| public AjaxResult unlockscreen(String password) | |||
| { | |||
| SysUser user = getSysUser(); | |||
| if (StringUtils.isNull(user)) | |||
| { | |||
| return AjaxResult.error("服务器超时,请重新登录"); | |||
| } | |||
| if (passwordService.matches(user, password)) | |||
| { | |||
| ServletUtils.getSession().removeAttribute(ShiroConstants.LOCK_SCREEN); | |||
| return AjaxResult.success(); | |||
| } | |||
| return AjaxResult.error("密码不正确,请重新输入。"); | |||
| } | |||
| // 切换主题 | |||
| @GetMapping("/system/switchSkin") | |||
| public String switchSkin() | |||
| { | |||
| return "skin"; | |||
| } | |||
| // 切换菜单 | |||
| @GetMapping("/system/menuStyle/{style}") | |||
| public void menuStyle(@PathVariable String style, HttpServletResponse response) | |||
| { | |||
| CookieUtils.setCookie(response, "nav-style", style); | |||
| } | |||
| // 系统介绍 | |||
| @GetMapping("/system/main") | |||
| public String main(ModelMap mmap) | |||
| { | |||
| mmap.put("version", RuoYiConfig.getVersion()); | |||
| return "main"; | |||
| } | |||
| // content-main class | |||
| public String contentMainClass(Boolean footer, Boolean tagsView) | |||
| { | |||
| if (!footer && !tagsView) | |||
| { | |||
| return "tagsview-footer-hide"; | |||
| } | |||
| else if (!footer) | |||
| { | |||
| return "footer-hide"; | |||
| } | |||
| else if (!tagsView) | |||
| { | |||
| return "tagsview-hide"; | |||
| } | |||
| return StringUtils.EMPTY; | |||
| } | |||
| // 检查初始密码是否提醒修改 | |||
| public boolean initPasswordIsModify(Date pwdUpdateDate) | |||
| { | |||
| Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify")); | |||
| return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null; | |||
| } | |||
| // 检查密码是否过期 | |||
| public boolean passwordIsExpiration(Date pwdUpdateDate) | |||
| { | |||
| Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays")); | |||
| if (passwordValidateDays != null && passwordValidateDays > 0) | |||
| { | |||
| if (StringUtils.isNull(pwdUpdateDate)) | |||
| { | |||
| // 如果从未修改过初始密码,直接提醒过期 | |||
| return true; | |||
| } | |||
| Date nowDate = DateUtils.getNowDate(); | |||
| return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays; | |||
| } | |||
| return false; | |||
| } | |||
| } | |||
| @@ -0,0 +1,82 @@ | |||
| package com.rwk.web.controller.system; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import javax.servlet.http.HttpServletResponse; | |||
| import org.apache.shiro.SecurityUtils; | |||
| import org.apache.shiro.authc.AuthenticationException; | |||
| import org.apache.shiro.authc.UsernamePasswordToken; | |||
| import org.apache.shiro.subject.Subject; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.text.Convert; | |||
| import com.rwk.common.utils.ServletUtils; | |||
| import com.rwk.common.utils.StringUtils; | |||
| import com.rwk.framework.web.service.ConfigService; | |||
| /** | |||
| * 登录验证 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| public class SysLoginController extends BaseController | |||
| { | |||
| /** | |||
| * 是否开启记住我功能 | |||
| */ | |||
| @Value("${shiro.rememberMe.enabled: false}") | |||
| private boolean rememberMe; | |||
| @Autowired | |||
| private ConfigService configService; | |||
| @GetMapping("/login") | |||
| public String login(HttpServletRequest request, HttpServletResponse response, ModelMap mmap) | |||
| { | |||
| // 如果是Ajax请求,返回Json字符串。 | |||
| if (ServletUtils.isAjaxRequest(request)) | |||
| { | |||
| return ServletUtils.renderString(response, "{\"code\":\"1\",\"msg\":\"未登录或登录超时。请重新登录\"}"); | |||
| } | |||
| // 是否开启记住我 | |||
| mmap.put("isRemembered", rememberMe); | |||
| // 是否开启用户注册 | |||
| mmap.put("isAllowRegister", Convert.toBool(configService.getKey("sys.account.registerUser"), false)); | |||
| return "login"; | |||
| } | |||
| @PostMapping("/login") | |||
| @ResponseBody | |||
| public AjaxResult ajaxLogin(String username, String password, Boolean rememberMe) | |||
| { | |||
| UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe); | |||
| Subject subject = SecurityUtils.getSubject(); | |||
| try | |||
| { | |||
| subject.login(token); | |||
| return success(); | |||
| } | |||
| catch (AuthenticationException e) | |||
| { | |||
| String msg = "用户或密码错误"; | |||
| if (StringUtils.isNotEmpty(e.getMessage())) | |||
| { | |||
| msg = e.getMessage(); | |||
| } | |||
| return error(msg); | |||
| } | |||
| } | |||
| @GetMapping("/unauth") | |||
| public String unauth() | |||
| { | |||
| return "error/unauth"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,197 @@ | |||
| package com.rwk.web.controller.system; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.domain.Ztree; | |||
| import com.rwk.common.core.domain.entity.SysMenu; | |||
| import com.rwk.common.core.domain.entity.SysRole; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.utils.ShiroUtils; | |||
| import com.rwk.framework.shiro.util.AuthorizationUtils; | |||
| import com.rwk.system.service.ISysMenuService; | |||
| /** | |||
| * 菜单信息 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/menu") | |||
| public class SysMenuController extends BaseController | |||
| { | |||
| private String prefix = "system/menu"; | |||
| @Autowired | |||
| private ISysMenuService menuService; | |||
| @RequiresPermissions("system:menu:view") | |||
| @GetMapping() | |||
| public String menu() | |||
| { | |||
| return prefix + "/menu"; | |||
| } | |||
| @RequiresPermissions("system:menu:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public List<SysMenu> list(SysMenu menu) | |||
| { | |||
| Long userId = ShiroUtils.getUserId(); | |||
| List<SysMenu> menuList = menuService.selectMenuList(menu, userId); | |||
| return menuList; | |||
| } | |||
| /** | |||
| * 删除菜单 | |||
| */ | |||
| @Log(title = "菜单管理", businessType = BusinessType.DELETE) | |||
| @RequiresPermissions("system:menu:remove") | |||
| @GetMapping("/remove/{menuId}") | |||
| @ResponseBody | |||
| public AjaxResult remove(@PathVariable("menuId") Long menuId) | |||
| { | |||
| if (menuService.selectCountMenuByParentId(menuId) > 0) | |||
| { | |||
| return AjaxResult.warn("存在子菜单,不允许删除"); | |||
| } | |||
| if (menuService.selectCountRoleMenuByMenuId(menuId) > 0) | |||
| { | |||
| return AjaxResult.warn("菜单已分配,不允许删除"); | |||
| } | |||
| AuthorizationUtils.clearAllCachedAuthorizationInfo(); | |||
| return toAjax(menuService.deleteMenuById(menuId)); | |||
| } | |||
| /** | |||
| * 新增 | |||
| */ | |||
| @GetMapping("/add/{parentId}") | |||
| public String add(@PathVariable("parentId") Long parentId, ModelMap mmap) | |||
| { | |||
| SysMenu menu = null; | |||
| if (0L != parentId) | |||
| { | |||
| menu = menuService.selectMenuById(parentId); | |||
| } | |||
| else | |||
| { | |||
| menu = new SysMenu(); | |||
| menu.setMenuId(0L); | |||
| menu.setMenuName("主目录"); | |||
| } | |||
| mmap.put("menu", menu); | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存菜单 | |||
| */ | |||
| @Log(title = "菜单管理", businessType = BusinessType.INSERT) | |||
| @RequiresPermissions("system:menu:add") | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(@Validated SysMenu menu) | |||
| { | |||
| if (!menuService.checkMenuNameUnique(menu)) | |||
| { | |||
| return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); | |||
| } | |||
| menu.setCreateBy(getLoginName()); | |||
| AuthorizationUtils.clearAllCachedAuthorizationInfo(); | |||
| return toAjax(menuService.insertMenu(menu)); | |||
| } | |||
| /** | |||
| * 修改菜单 | |||
| */ | |||
| @RequiresPermissions("system:menu:edit") | |||
| @GetMapping("/edit/{menuId}") | |||
| public String edit(@PathVariable("menuId") Long menuId, ModelMap mmap) | |||
| { | |||
| mmap.put("menu", menuService.selectMenuById(menuId)); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改保存菜单 | |||
| */ | |||
| @Log(title = "菜单管理", businessType = BusinessType.UPDATE) | |||
| @RequiresPermissions("system:menu:edit") | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(@Validated SysMenu menu) | |||
| { | |||
| if (!menuService.checkMenuNameUnique(menu)) | |||
| { | |||
| return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); | |||
| } | |||
| menu.setUpdateBy(getLoginName()); | |||
| AuthorizationUtils.clearAllCachedAuthorizationInfo(); | |||
| return toAjax(menuService.updateMenu(menu)); | |||
| } | |||
| /** | |||
| * 选择菜单图标 | |||
| */ | |||
| @GetMapping("/icon") | |||
| public String icon() | |||
| { | |||
| return prefix + "/icon"; | |||
| } | |||
| /** | |||
| * 校验菜单名称 | |||
| */ | |||
| @PostMapping("/checkMenuNameUnique") | |||
| @ResponseBody | |||
| public boolean checkMenuNameUnique(SysMenu menu) | |||
| { | |||
| return menuService.checkMenuNameUnique(menu); | |||
| } | |||
| /** | |||
| * 加载角色菜单列表树 | |||
| */ | |||
| @GetMapping("/roleMenuTreeData") | |||
| @ResponseBody | |||
| public List<Ztree> roleMenuTreeData(SysRole role) | |||
| { | |||
| Long userId = ShiroUtils.getUserId(); | |||
| List<Ztree> ztrees = menuService.roleMenuTreeData(role, userId); | |||
| return ztrees; | |||
| } | |||
| /** | |||
| * 加载所有菜单列表树 | |||
| */ | |||
| @GetMapping("/menuTreeData") | |||
| @ResponseBody | |||
| public List<Ztree> menuTreeData() | |||
| { | |||
| Long userId = ShiroUtils.getUserId(); | |||
| List<Ztree> ztrees = menuService.menuTreeData(userId); | |||
| return ztrees; | |||
| } | |||
| /** | |||
| * 选择菜单树 | |||
| */ | |||
| @GetMapping("/selectMenuTree/{menuId}") | |||
| public String selectMenuTree(@PathVariable("menuId") Long menuId, ModelMap mmap) | |||
| { | |||
| mmap.put("menu", menuService.selectMenuById(menuId)); | |||
| return prefix + "/tree"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,124 @@ | |||
| package com.rwk.web.controller.system; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.system.domain.SysNotice; | |||
| import com.rwk.system.service.ISysNoticeService; | |||
| /** | |||
| * 公告 信息操作处理 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/notice") | |||
| public class SysNoticeController extends BaseController | |||
| { | |||
| private String prefix = "system/notice"; | |||
| @Autowired | |||
| private ISysNoticeService noticeService; | |||
| @RequiresPermissions("system:notice:view") | |||
| @GetMapping() | |||
| public String notice() | |||
| { | |||
| return prefix + "/notice"; | |||
| } | |||
| /** | |||
| * 查询公告列表 | |||
| */ | |||
| @RequiresPermissions("system:notice:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public TableDataInfo list(SysNotice notice) | |||
| { | |||
| startPage(); | |||
| List<SysNotice> list = noticeService.selectNoticeList(notice); | |||
| return getDataTable(list); | |||
| } | |||
| /** | |||
| * 新增公告 | |||
| */ | |||
| @GetMapping("/add") | |||
| public String add() | |||
| { | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存公告 | |||
| */ | |||
| @RequiresPermissions("system:notice:add") | |||
| @Log(title = "通知公告", businessType = BusinessType.INSERT) | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(@Validated SysNotice notice) | |||
| { | |||
| notice.setCreateBy(getLoginName()); | |||
| return toAjax(noticeService.insertNotice(notice)); | |||
| } | |||
| /** | |||
| * 修改公告 | |||
| */ | |||
| @RequiresPermissions("system:notice:edit") | |||
| @GetMapping("/edit/{noticeId}") | |||
| public String edit(@PathVariable("noticeId") Long noticeId, ModelMap mmap) | |||
| { | |||
| mmap.put("notice", noticeService.selectNoticeById(noticeId)); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改保存公告 | |||
| */ | |||
| @RequiresPermissions("system:notice:edit") | |||
| @Log(title = "通知公告", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(@Validated SysNotice notice) | |||
| { | |||
| notice.setUpdateBy(getLoginName()); | |||
| return toAjax(noticeService.updateNotice(notice)); | |||
| } | |||
| /** | |||
| * 查询公告详细 | |||
| */ | |||
| @RequiresPermissions("system:notice:list") | |||
| @GetMapping("/view/{noticeId}") | |||
| public String view(@PathVariable("noticeId") Long noticeId, ModelMap mmap) | |||
| { | |||
| mmap.put("notice", noticeService.selectNoticeById(noticeId)); | |||
| return prefix + "/view"; | |||
| } | |||
| /** | |||
| * 删除公告 | |||
| */ | |||
| @RequiresPermissions("system:notice:remove") | |||
| @Log(title = "通知公告", businessType = BusinessType.DELETE) | |||
| @PostMapping("/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| return toAjax(noticeService.deleteNoticeByIds(ids)); | |||
| } | |||
| } | |||
| @@ -0,0 +1,162 @@ | |||
| package com.rwk.web.controller.system; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.utils.poi.ExcelUtil; | |||
| import com.rwk.system.domain.SysPost; | |||
| import com.rwk.system.service.ISysPostService; | |||
| /** | |||
| * 岗位信息操作处理 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/post") | |||
| public class SysPostController extends BaseController | |||
| { | |||
| private String prefix = "system/post"; | |||
| @Autowired | |||
| private ISysPostService postService; | |||
| @RequiresPermissions("system:post:view") | |||
| @GetMapping() | |||
| public String operlog() | |||
| { | |||
| return prefix + "/post"; | |||
| } | |||
| @RequiresPermissions("system:post:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public TableDataInfo list(SysPost post) | |||
| { | |||
| startPage(); | |||
| List<SysPost> list = postService.selectPostList(post); | |||
| return getDataTable(list); | |||
| } | |||
| @Log(title = "岗位管理", businessType = BusinessType.EXPORT) | |||
| @RequiresPermissions("system:post:export") | |||
| @PostMapping("/export") | |||
| @ResponseBody | |||
| public AjaxResult export(SysPost post) | |||
| { | |||
| List<SysPost> list = postService.selectPostList(post); | |||
| ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class); | |||
| return util.exportExcel(list, "岗位数据"); | |||
| } | |||
| @RequiresPermissions("system:post:remove") | |||
| @Log(title = "岗位管理", businessType = BusinessType.DELETE) | |||
| @PostMapping("/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| try | |||
| { | |||
| return toAjax(postService.deletePostByIds(ids)); | |||
| } | |||
| catch (Exception e) | |||
| { | |||
| return error(e.getMessage()); | |||
| } | |||
| } | |||
| /** | |||
| * 新增岗位 | |||
| */ | |||
| @GetMapping("/add") | |||
| public String add() | |||
| { | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存岗位 | |||
| */ | |||
| @RequiresPermissions("system:post:add") | |||
| @Log(title = "岗位管理", businessType = BusinessType.INSERT) | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(@Validated SysPost post) | |||
| { | |||
| if (!postService.checkPostNameUnique(post)) | |||
| { | |||
| return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); | |||
| } | |||
| else if (!postService.checkPostCodeUnique(post)) | |||
| { | |||
| return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); | |||
| } | |||
| post.setCreateBy(getLoginName()); | |||
| return toAjax(postService.insertPost(post)); | |||
| } | |||
| /** | |||
| * 修改岗位 | |||
| */ | |||
| @RequiresPermissions("system:post:edit") | |||
| @GetMapping("/edit/{postId}") | |||
| public String edit(@PathVariable("postId") Long postId, ModelMap mmap) | |||
| { | |||
| mmap.put("post", postService.selectPostById(postId)); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改保存岗位 | |||
| */ | |||
| @RequiresPermissions("system:post:edit") | |||
| @Log(title = "岗位管理", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(@Validated SysPost post) | |||
| { | |||
| if (!postService.checkPostNameUnique(post)) | |||
| { | |||
| return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); | |||
| } | |||
| else if (!postService.checkPostCodeUnique(post)) | |||
| { | |||
| return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); | |||
| } | |||
| post.setUpdateBy(getLoginName()); | |||
| return toAjax(postService.updatePost(post)); | |||
| } | |||
| /** | |||
| * 校验岗位名称 | |||
| */ | |||
| @PostMapping("/checkPostNameUnique") | |||
| @ResponseBody | |||
| public boolean checkPostNameUnique(SysPost post) | |||
| { | |||
| return postService.checkPostNameUnique(post); | |||
| } | |||
| /** | |||
| * 校验岗位编码 | |||
| */ | |||
| @PostMapping("/checkPostCodeUnique") | |||
| @ResponseBody | |||
| public boolean checkPostCodeUnique(SysPost post) | |||
| { | |||
| return postService.checkPostCodeUnique(post); | |||
| } | |||
| } | |||
| @@ -0,0 +1,181 @@ | |||
| package com.rwk.web.controller.system; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.RequestParam; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.config.RuoYiConfig; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.domain.entity.SysUser; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.utils.DateUtils; | |||
| import com.rwk.common.utils.ShiroUtils; | |||
| import com.rwk.common.utils.StringUtils; | |||
| import com.rwk.common.utils.file.FileUploadUtils; | |||
| import com.rwk.common.utils.file.MimeTypeUtils; | |||
| import com.rwk.framework.shiro.service.SysPasswordService; | |||
| import com.rwk.system.service.ISysUserService; | |||
| /** | |||
| * 个人信息 业务处理 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/user/profile") | |||
| public class SysProfileController extends BaseController | |||
| { | |||
| private static final Logger log = LoggerFactory.getLogger(SysProfileController.class); | |||
| private String prefix = "system/user/profile"; | |||
| @Autowired | |||
| private ISysUserService userService; | |||
| @Autowired | |||
| private SysPasswordService passwordService; | |||
| /** | |||
| * 个人信息 | |||
| */ | |||
| @GetMapping() | |||
| public String profile(ModelMap mmap) | |||
| { | |||
| SysUser user = getSysUser(); | |||
| mmap.put("user", user); | |||
| mmap.put("roleGroup", userService.selectUserRoleGroup(user.getUserId())); | |||
| mmap.put("postGroup", userService.selectUserPostGroup(user.getUserId())); | |||
| return prefix + "/profile"; | |||
| } | |||
| @GetMapping("/checkPassword") | |||
| @ResponseBody | |||
| public boolean checkPassword(String password) | |||
| { | |||
| SysUser user = getSysUser(); | |||
| return passwordService.matches(user, password); | |||
| } | |||
| @GetMapping("/resetPwd") | |||
| public String resetPwd(ModelMap mmap) | |||
| { | |||
| SysUser user = getSysUser(); | |||
| mmap.put("user", userService.selectUserById(user.getUserId())); | |||
| return prefix + "/resetPwd"; | |||
| } | |||
| @Log(title = "重置密码", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/resetPwd") | |||
| @ResponseBody | |||
| public AjaxResult resetPwd(String oldPassword, String newPassword) | |||
| { | |||
| SysUser user = getSysUser(); | |||
| if (!passwordService.matches(user, oldPassword)) | |||
| { | |||
| return error("修改密码失败,旧密码错误"); | |||
| } | |||
| if (passwordService.matches(user, newPassword)) | |||
| { | |||
| return error("新密码不能与旧密码相同"); | |||
| } | |||
| user.setSalt(ShiroUtils.randomSalt()); | |||
| user.setPassword(passwordService.encryptPassword(user.getLoginName(), newPassword, user.getSalt())); | |||
| user.setPwdUpdateDate(DateUtils.getNowDate()); | |||
| if (userService.resetUserPwd(user) > 0) | |||
| { | |||
| setSysUser(userService.selectUserById(user.getUserId())); | |||
| return success(); | |||
| } | |||
| return error("修改密码异常,请联系管理员"); | |||
| } | |||
| /** | |||
| * 修改用户 | |||
| */ | |||
| @GetMapping("/edit") | |||
| public String edit(ModelMap mmap) | |||
| { | |||
| SysUser user = getSysUser(); | |||
| mmap.put("user", userService.selectUserById(user.getUserId())); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改头像 | |||
| */ | |||
| @GetMapping("/avatar") | |||
| public String avatar(ModelMap mmap) | |||
| { | |||
| SysUser user = getSysUser(); | |||
| mmap.put("user", userService.selectUserById(user.getUserId())); | |||
| return prefix + "/avatar"; | |||
| } | |||
| /** | |||
| * 修改用户 | |||
| */ | |||
| @Log(title = "个人信息", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/update") | |||
| @ResponseBody | |||
| public AjaxResult update(SysUser user) | |||
| { | |||
| SysUser currentUser = getSysUser(); | |||
| currentUser.setUserName(user.getUserName()); | |||
| currentUser.setEmail(user.getEmail()); | |||
| currentUser.setPhonenumber(user.getPhonenumber()); | |||
| currentUser.setSex(user.getSex()); | |||
| if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser)) | |||
| { | |||
| return error("修改用户'" + currentUser.getLoginName() + "'失败,手机号码已存在"); | |||
| } | |||
| else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser)) | |||
| { | |||
| return error("修改用户'" + currentUser.getLoginName() + "'失败,邮箱账号已存在"); | |||
| } | |||
| if (userService.updateUserInfo(currentUser) > 0) | |||
| { | |||
| setSysUser(userService.selectUserById(currentUser.getUserId())); | |||
| return success(); | |||
| } | |||
| return error(); | |||
| } | |||
| /** | |||
| * 保存头像 | |||
| */ | |||
| @Log(title = "个人信息", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/updateAvatar") | |||
| @ResponseBody | |||
| public AjaxResult updateAvatar(@RequestParam("avatarfile") MultipartFile file) | |||
| { | |||
| SysUser currentUser = getSysUser(); | |||
| try | |||
| { | |||
| if (!file.isEmpty()) | |||
| { | |||
| String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION); | |||
| currentUser.setAvatar(avatar); | |||
| if (userService.updateUserInfo(currentUser) > 0) | |||
| { | |||
| setSysUser(userService.selectUserById(currentUser.getUserId())); | |||
| return success(); | |||
| } | |||
| } | |||
| return error(); | |||
| } | |||
| catch (Exception e) | |||
| { | |||
| log.error("修改头像失败!", e); | |||
| return error(e.getMessage()); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,46 @@ | |||
| package com.rwk.web.controller.system; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.domain.entity.SysUser; | |||
| import com.rwk.common.utils.StringUtils; | |||
| import com.rwk.framework.shiro.service.SysRegisterService; | |||
| import com.rwk.system.service.ISysConfigService; | |||
| /** | |||
| * 注册验证 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| public class SysRegisterController extends BaseController | |||
| { | |||
| @Autowired | |||
| private SysRegisterService registerService; | |||
| @Autowired | |||
| private ISysConfigService configService; | |||
| @GetMapping("/register") | |||
| public String register() | |||
| { | |||
| return "register"; | |||
| } | |||
| @PostMapping("/register") | |||
| @ResponseBody | |||
| public AjaxResult ajaxRegister(SysUser user) | |||
| { | |||
| if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) | |||
| { | |||
| return error("当前系统没有开启注册功能!"); | |||
| } | |||
| String msg = registerService.register(user); | |||
| return StringUtils.isEmpty(msg) ? success() : error(msg); | |||
| } | |||
| } | |||
| @@ -0,0 +1,322 @@ | |||
| package com.rwk.web.controller.system; | |||
| import java.util.List; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.domain.Ztree; | |||
| import com.rwk.common.core.domain.entity.SysRole; | |||
| import com.rwk.common.core.domain.entity.SysUser; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.utils.poi.ExcelUtil; | |||
| import com.rwk.framework.shiro.util.AuthorizationUtils; | |||
| import com.rwk.system.domain.SysUserRole; | |||
| import com.rwk.system.service.ISysDeptService; | |||
| import com.rwk.system.service.ISysRoleService; | |||
| import com.rwk.system.service.ISysUserService; | |||
| /** | |||
| * 角色信息 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/role") | |||
| public class SysRoleController extends BaseController | |||
| { | |||
| private String prefix = "system/role"; | |||
| @Autowired | |||
| private ISysRoleService roleService; | |||
| @Autowired | |||
| private ISysUserService userService; | |||
| @Autowired | |||
| private ISysDeptService deptService; | |||
| @RequiresPermissions("system:role:view") | |||
| @GetMapping() | |||
| public String role() | |||
| { | |||
| return prefix + "/role"; | |||
| } | |||
| @RequiresPermissions("system:role:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public TableDataInfo list(SysRole role) | |||
| { | |||
| startPage(); | |||
| List<SysRole> list = roleService.selectRoleList(role); | |||
| return getDataTable(list); | |||
| } | |||
| @Log(title = "角色管理", businessType = BusinessType.EXPORT) | |||
| @RequiresPermissions("system:role:export") | |||
| @PostMapping("/export") | |||
| @ResponseBody | |||
| public AjaxResult export(SysRole role) | |||
| { | |||
| List<SysRole> list = roleService.selectRoleList(role); | |||
| ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class); | |||
| return util.exportExcel(list, "角色数据"); | |||
| } | |||
| /** | |||
| * 新增角色 | |||
| */ | |||
| @GetMapping("/add") | |||
| public String add() | |||
| { | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存角色 | |||
| */ | |||
| @RequiresPermissions("system:role:add") | |||
| @Log(title = "角色管理", businessType = BusinessType.INSERT) | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(@Validated SysRole role) | |||
| { | |||
| if (!roleService.checkRoleNameUnique(role)) | |||
| { | |||
| return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); | |||
| } | |||
| else if (!roleService.checkRoleKeyUnique(role)) | |||
| { | |||
| return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); | |||
| } | |||
| role.setCreateBy(getLoginName()); | |||
| AuthorizationUtils.clearAllCachedAuthorizationInfo(); | |||
| return toAjax(roleService.insertRole(role)); | |||
| } | |||
| /** | |||
| * 修改角色 | |||
| */ | |||
| @RequiresPermissions("system:role:edit") | |||
| @GetMapping("/edit/{roleId}") | |||
| public String edit(@PathVariable("roleId") Long roleId, ModelMap mmap) | |||
| { | |||
| roleService.checkRoleDataScope(roleId); | |||
| mmap.put("role", roleService.selectRoleById(roleId)); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 修改保存角色 | |||
| */ | |||
| @RequiresPermissions("system:role:edit") | |||
| @Log(title = "角色管理", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(@Validated SysRole role) | |||
| { | |||
| roleService.checkRoleAllowed(role); | |||
| roleService.checkRoleDataScope(role.getRoleId()); | |||
| if (!roleService.checkRoleNameUnique(role)) | |||
| { | |||
| return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); | |||
| } | |||
| else if (!roleService.checkRoleKeyUnique(role)) | |||
| { | |||
| return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); | |||
| } | |||
| role.setUpdateBy(getLoginName()); | |||
| AuthorizationUtils.clearAllCachedAuthorizationInfo(); | |||
| return toAjax(roleService.updateRole(role)); | |||
| } | |||
| /** | |||
| * 角色分配数据权限 | |||
| */ | |||
| @GetMapping("/authDataScope/{roleId}") | |||
| public String authDataScope(@PathVariable("roleId") Long roleId, ModelMap mmap) | |||
| { | |||
| mmap.put("role", roleService.selectRoleById(roleId)); | |||
| return prefix + "/dataScope"; | |||
| } | |||
| /** | |||
| * 保存角色分配数据权限 | |||
| */ | |||
| @RequiresPermissions("system:role:edit") | |||
| @Log(title = "角色管理", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/authDataScope") | |||
| @ResponseBody | |||
| public AjaxResult authDataScopeSave(SysRole role) | |||
| { | |||
| roleService.checkRoleAllowed(role); | |||
| roleService.checkRoleDataScope(role.getRoleId()); | |||
| role.setUpdateBy(getLoginName()); | |||
| if (roleService.authDataScope(role) > 0) | |||
| { | |||
| setSysUser(userService.selectUserById(getUserId())); | |||
| return success(); | |||
| } | |||
| return error(); | |||
| } | |||
| @RequiresPermissions("system:role:remove") | |||
| @Log(title = "角色管理", businessType = BusinessType.DELETE) | |||
| @PostMapping("/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| return toAjax(roleService.deleteRoleByIds(ids)); | |||
| } | |||
| /** | |||
| * 校验角色名称 | |||
| */ | |||
| @PostMapping("/checkRoleNameUnique") | |||
| @ResponseBody | |||
| public boolean checkRoleNameUnique(SysRole role) | |||
| { | |||
| return roleService.checkRoleNameUnique(role); | |||
| } | |||
| /** | |||
| * 校验角色权限 | |||
| */ | |||
| @PostMapping("/checkRoleKeyUnique") | |||
| @ResponseBody | |||
| public boolean checkRoleKeyUnique(SysRole role) | |||
| { | |||
| return roleService.checkRoleKeyUnique(role); | |||
| } | |||
| /** | |||
| * 选择菜单树 | |||
| */ | |||
| @GetMapping("/selectMenuTree") | |||
| public String selectMenuTree() | |||
| { | |||
| return prefix + "/tree"; | |||
| } | |||
| /** | |||
| * 角色状态修改 | |||
| */ | |||
| @Log(title = "角色管理", businessType = BusinessType.UPDATE) | |||
| @RequiresPermissions("system:role:edit") | |||
| @PostMapping("/changeStatus") | |||
| @ResponseBody | |||
| public AjaxResult changeStatus(SysRole role) | |||
| { | |||
| roleService.checkRoleAllowed(role); | |||
| roleService.checkRoleDataScope(role.getRoleId()); | |||
| return toAjax(roleService.changeStatus(role)); | |||
| } | |||
| /** | |||
| * 分配用户 | |||
| */ | |||
| @RequiresPermissions("system:role:edit") | |||
| @GetMapping("/authUser/{roleId}") | |||
| public String authUser(@PathVariable("roleId") Long roleId, ModelMap mmap) | |||
| { | |||
| mmap.put("role", roleService.selectRoleById(roleId)); | |||
| return prefix + "/authUser"; | |||
| } | |||
| /** | |||
| * 查询已分配用户角色列表 | |||
| */ | |||
| @RequiresPermissions("system:role:list") | |||
| @PostMapping("/authUser/allocatedList") | |||
| @ResponseBody | |||
| public TableDataInfo allocatedList(SysUser user) | |||
| { | |||
| startPage(); | |||
| List<SysUser> list = userService.selectAllocatedList(user); | |||
| return getDataTable(list); | |||
| } | |||
| /** | |||
| * 取消授权 | |||
| */ | |||
| @RequiresPermissions("system:role:edit") | |||
| @Log(title = "角色管理", businessType = BusinessType.GRANT) | |||
| @PostMapping("/authUser/cancel") | |||
| @ResponseBody | |||
| public AjaxResult cancelAuthUser(SysUserRole userRole) | |||
| { | |||
| return toAjax(roleService.deleteAuthUser(userRole)); | |||
| } | |||
| /** | |||
| * 批量取消授权 | |||
| */ | |||
| @RequiresPermissions("system:role:edit") | |||
| @Log(title = "角色管理", businessType = BusinessType.GRANT) | |||
| @PostMapping("/authUser/cancelAll") | |||
| @ResponseBody | |||
| public AjaxResult cancelAuthUserAll(Long roleId, String userIds) | |||
| { | |||
| return toAjax(roleService.deleteAuthUsers(roleId, userIds)); | |||
| } | |||
| /** | |||
| * 选择用户 | |||
| */ | |||
| @GetMapping("/authUser/selectUser/{roleId}") | |||
| public String selectUser(@PathVariable("roleId") Long roleId, ModelMap mmap) | |||
| { | |||
| mmap.put("role", roleService.selectRoleById(roleId)); | |||
| return prefix + "/selectUser"; | |||
| } | |||
| /** | |||
| * 查询未分配用户角色列表 | |||
| */ | |||
| @RequiresPermissions("system:role:list") | |||
| @PostMapping("/authUser/unallocatedList") | |||
| @ResponseBody | |||
| public TableDataInfo unallocatedList(SysUser user) | |||
| { | |||
| startPage(); | |||
| List<SysUser> list = userService.selectUnallocatedList(user); | |||
| return getDataTable(list); | |||
| } | |||
| /** | |||
| * 批量选择用户授权 | |||
| */ | |||
| @RequiresPermissions("system:role:edit") | |||
| @Log(title = "角色管理", businessType = BusinessType.GRANT) | |||
| @PostMapping("/authUser/selectAll") | |||
| @ResponseBody | |||
| public AjaxResult selectAuthUserAll(Long roleId, String userIds) | |||
| { | |||
| roleService.checkRoleDataScope(roleId); | |||
| return toAjax(roleService.insertAuthUsers(roleId, userIds)); | |||
| } | |||
| /** | |||
| * 加载角色部门(数据权限)列表树 | |||
| */ | |||
| @RequiresPermissions("system:role:edit") | |||
| @GetMapping("/deptTreeData") | |||
| @ResponseBody | |||
| public List<Ztree> deptTreeData(SysRole role) | |||
| { | |||
| List<Ztree> ztrees = deptService.roleDeptTreeData(role); | |||
| return ztrees; | |||
| } | |||
| } | |||
| @@ -0,0 +1,373 @@ | |||
| package com.rwk.web.controller.system; | |||
| import java.util.List; | |||
| import java.util.stream.Collectors; | |||
| import org.apache.commons.lang3.ArrayUtils; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.ui.ModelMap; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import com.rwk.common.annotation.Log; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.AjaxResult; | |||
| import com.rwk.common.core.domain.Ztree; | |||
| import com.rwk.common.core.domain.entity.SysDept; | |||
| import com.rwk.common.core.domain.entity.SysRole; | |||
| import com.rwk.common.core.domain.entity.SysUser; | |||
| import com.rwk.common.core.page.TableDataInfo; | |||
| import com.rwk.common.core.text.Convert; | |||
| import com.rwk.common.enums.BusinessType; | |||
| import com.rwk.common.utils.DateUtils; | |||
| import com.rwk.common.utils.ShiroUtils; | |||
| import com.rwk.common.utils.StringUtils; | |||
| import com.rwk.common.utils.poi.ExcelUtil; | |||
| import com.rwk.framework.shiro.service.SysPasswordService; | |||
| import com.rwk.framework.shiro.util.AuthorizationUtils; | |||
| import com.rwk.system.service.ISysDeptService; | |||
| import com.rwk.system.service.ISysPostService; | |||
| import com.rwk.system.service.ISysRoleService; | |||
| import com.rwk.system.service.ISysUserService; | |||
| /** | |||
| * 用户信息 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/system/user") | |||
| public class SysUserController extends BaseController | |||
| { | |||
| private String prefix = "system/user"; | |||
| @Autowired | |||
| private ISysUserService userService; | |||
| @Autowired | |||
| private ISysRoleService roleService; | |||
| @Autowired | |||
| private ISysDeptService deptService; | |||
| @Autowired | |||
| private ISysPostService postService; | |||
| @Autowired | |||
| private SysPasswordService passwordService; | |||
| @RequiresPermissions("system:user:view") | |||
| @GetMapping() | |||
| public String user() | |||
| { | |||
| return prefix + "/user"; | |||
| } | |||
| @RequiresPermissions("system:user:list") | |||
| @PostMapping("/list") | |||
| @ResponseBody | |||
| public TableDataInfo list(SysUser user) | |||
| { | |||
| startPage(); | |||
| List<SysUser> list = userService.selectUserList(user); | |||
| return getDataTable(list); | |||
| } | |||
| @Log(title = "用户管理", businessType = BusinessType.EXPORT) | |||
| @RequiresPermissions("system:user:export") | |||
| @PostMapping("/export") | |||
| @ResponseBody | |||
| public AjaxResult export(SysUser user) | |||
| { | |||
| List<SysUser> list = userService.selectUserList(user); | |||
| ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class); | |||
| return util.exportExcel(list, "用户数据"); | |||
| } | |||
| @Log(title = "用户管理", businessType = BusinessType.IMPORT) | |||
| @RequiresPermissions("system:user:import") | |||
| @PostMapping("/importData") | |||
| @ResponseBody | |||
| public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception | |||
| { | |||
| ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class); | |||
| List<SysUser> userList = util.importExcel(file.getInputStream()); | |||
| String message = userService.importUser(userList, updateSupport, getLoginName()); | |||
| return AjaxResult.success(message); | |||
| } | |||
| @RequiresPermissions("system:user:view") | |||
| @GetMapping("/importTemplate") | |||
| @ResponseBody | |||
| public AjaxResult importTemplate() | |||
| { | |||
| ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class); | |||
| return util.importTemplateExcel("用户数据"); | |||
| } | |||
| /** | |||
| * 新增用户 | |||
| */ | |||
| @GetMapping("/add") | |||
| public String add(ModelMap mmap) | |||
| { | |||
| mmap.put("roles", roleService.selectRoleAll().stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); | |||
| mmap.put("posts", postService.selectPostAll()); | |||
| return prefix + "/add"; | |||
| } | |||
| /** | |||
| * 新增保存用户 | |||
| */ | |||
| @RequiresPermissions("system:user:add") | |||
| @Log(title = "用户管理", businessType = BusinessType.INSERT) | |||
| @PostMapping("/add") | |||
| @ResponseBody | |||
| public AjaxResult addSave(@Validated SysUser user) | |||
| { | |||
| deptService.checkDeptDataScope(user.getDeptId()); | |||
| roleService.checkRoleDataScope(user.getRoleIds()); | |||
| if (!userService.checkLoginNameUnique(user)) | |||
| { | |||
| return error("新增用户'" + user.getLoginName() + "'失败,登录账号已存在"); | |||
| } | |||
| else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) | |||
| { | |||
| return error("新增用户'" + user.getLoginName() + "'失败,手机号码已存在"); | |||
| } | |||
| else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) | |||
| { | |||
| return error("新增用户'" + user.getLoginName() + "'失败,邮箱账号已存在"); | |||
| } | |||
| user.setSalt(ShiroUtils.randomSalt()); | |||
| user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt())); | |||
| user.setPwdUpdateDate(DateUtils.getNowDate()); | |||
| user.setCreateBy(getLoginName()); | |||
| return toAjax(userService.insertUser(user)); | |||
| } | |||
| /** | |||
| * 修改用户 | |||
| */ | |||
| @RequiresPermissions("system:user:edit") | |||
| @GetMapping("/edit/{userId}") | |||
| public String edit(@PathVariable("userId") Long userId, ModelMap mmap) | |||
| { | |||
| userService.checkUserDataScope(userId); | |||
| List<SysRole> roles = roleService.selectRolesByUserId(userId); | |||
| mmap.put("user", userService.selectUserById(userId)); | |||
| mmap.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); | |||
| mmap.put("posts", postService.selectPostsByUserId(userId)); | |||
| return prefix + "/edit"; | |||
| } | |||
| /** | |||
| * 查询用户详细 | |||
| */ | |||
| @RequiresPermissions("system:user:list") | |||
| @GetMapping("/view/{userId}") | |||
| public String view(@PathVariable("userId") Long userId, ModelMap mmap) | |||
| { | |||
| userService.checkUserDataScope(userId); | |||
| mmap.put("user", userService.selectUserById(userId)); | |||
| mmap.put("roleGroup", userService.selectUserRoleGroup(userId)); | |||
| mmap.put("postGroup", userService.selectUserPostGroup(userId)); | |||
| return prefix + "/view"; | |||
| } | |||
| /** | |||
| * 修改保存用户 | |||
| */ | |||
| @RequiresPermissions("system:user:edit") | |||
| @Log(title = "用户管理", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/edit") | |||
| @ResponseBody | |||
| public AjaxResult editSave(@Validated SysUser user) | |||
| { | |||
| userService.checkUserAllowed(user); | |||
| userService.checkUserDataScope(user.getUserId()); | |||
| deptService.checkDeptDataScope(user.getDeptId()); | |||
| roleService.checkRoleDataScope(user.getRoleIds()); | |||
| if (!userService.checkLoginNameUnique(user)) | |||
| { | |||
| return error("修改用户'" + user.getLoginName() + "'失败,登录账号已存在"); | |||
| } | |||
| else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) | |||
| { | |||
| return error("修改用户'" + user.getLoginName() + "'失败,手机号码已存在"); | |||
| } | |||
| else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) | |||
| { | |||
| return error("修改用户'" + user.getLoginName() + "'失败,邮箱账号已存在"); | |||
| } | |||
| user.setUpdateBy(getLoginName()); | |||
| AuthorizationUtils.clearAllCachedAuthorizationInfo(); | |||
| return toAjax(userService.updateUser(user)); | |||
| } | |||
| @RequiresPermissions("system:user:resetPwd") | |||
| @GetMapping("/resetPwd/{userId}") | |||
| public String resetPwd(@PathVariable("userId") Long userId, ModelMap mmap) | |||
| { | |||
| mmap.put("user", userService.selectUserById(userId)); | |||
| return prefix + "/resetPwd"; | |||
| } | |||
| @RequiresPermissions("system:user:resetPwd") | |||
| @Log(title = "重置密码", businessType = BusinessType.UPDATE) | |||
| @PostMapping("/resetPwd") | |||
| @ResponseBody | |||
| public AjaxResult resetPwdSave(SysUser user) | |||
| { | |||
| userService.checkUserAllowed(user); | |||
| userService.checkUserDataScope(user.getUserId()); | |||
| user.setSalt(ShiroUtils.randomSalt()); | |||
| user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt())); | |||
| if (userService.resetUserPwd(user) > 0) | |||
| { | |||
| if (ShiroUtils.getUserId().longValue() == user.getUserId().longValue()) | |||
| { | |||
| setSysUser(userService.selectUserById(user.getUserId())); | |||
| } | |||
| return success(); | |||
| } | |||
| return error(); | |||
| } | |||
| /** | |||
| * 进入授权角色页 | |||
| */ | |||
| @GetMapping("/authRole/{userId}") | |||
| public String authRole(@PathVariable("userId") Long userId, ModelMap mmap) | |||
| { | |||
| SysUser user = userService.selectUserById(userId); | |||
| // 获取用户所属的角色列表 | |||
| List<SysRole> roles = roleService.selectRolesByUserId(userId); | |||
| mmap.put("user", user); | |||
| mmap.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); | |||
| return prefix + "/authRole"; | |||
| } | |||
| /** | |||
| * 用户授权角色 | |||
| */ | |||
| @RequiresPermissions("system:user:edit") | |||
| @Log(title = "用户管理", businessType = BusinessType.GRANT) | |||
| @PostMapping("/authRole/insertAuthRole") | |||
| @ResponseBody | |||
| public AjaxResult insertAuthRole(Long userId, Long[] roleIds) | |||
| { | |||
| userService.checkUserDataScope(userId); | |||
| roleService.checkRoleDataScope(roleIds); | |||
| userService.insertUserAuth(userId, roleIds); | |||
| AuthorizationUtils.clearAllCachedAuthorizationInfo(); | |||
| return success(); | |||
| } | |||
| @RequiresPermissions("system:user:remove") | |||
| @Log(title = "用户管理", businessType = BusinessType.DELETE) | |||
| @PostMapping("/remove") | |||
| @ResponseBody | |||
| public AjaxResult remove(String ids) | |||
| { | |||
| if (ArrayUtils.contains(Convert.toLongArray(ids), getUserId())) | |||
| { | |||
| return error("当前用户不能删除"); | |||
| } | |||
| return toAjax(userService.deleteUserByIds(ids)); | |||
| } | |||
| /** | |||
| * 校验用户名 | |||
| */ | |||
| @PostMapping("/checkLoginNameUnique") | |||
| @ResponseBody | |||
| public boolean checkLoginNameUnique(SysUser user) | |||
| { | |||
| return userService.checkLoginNameUnique(user); | |||
| } | |||
| /** | |||
| * 校验手机号码 | |||
| */ | |||
| @PostMapping("/checkPhoneUnique") | |||
| @ResponseBody | |||
| public boolean checkPhoneUnique(SysUser user) | |||
| { | |||
| return userService.checkPhoneUnique(user); | |||
| } | |||
| /** | |||
| * 校验email邮箱 | |||
| */ | |||
| @PostMapping("/checkEmailUnique") | |||
| @ResponseBody | |||
| public boolean checkEmailUnique(SysUser user) | |||
| { | |||
| return userService.checkEmailUnique(user); | |||
| } | |||
| /** | |||
| * 用户状态修改 | |||
| */ | |||
| @Log(title = "用户管理", businessType = BusinessType.UPDATE) | |||
| @RequiresPermissions("system:user:edit") | |||
| @PostMapping("/changeStatus") | |||
| @ResponseBody | |||
| public AjaxResult changeStatus(SysUser user) | |||
| { | |||
| userService.checkUserAllowed(user); | |||
| userService.checkUserDataScope(user.getUserId()); | |||
| return toAjax(userService.changeStatus(user)); | |||
| } | |||
| /** | |||
| * 加载部门列表树 | |||
| */ | |||
| @RequiresPermissions("system:user:list") | |||
| @GetMapping("/deptTreeData") | |||
| @ResponseBody | |||
| public List<Ztree> deptTreeData() | |||
| { | |||
| List<Ztree> ztrees = deptService.selectDeptTree(new SysDept()); | |||
| return ztrees; | |||
| } | |||
| /** | |||
| * 选择部门树 | |||
| * | |||
| * @param deptId 部门ID | |||
| */ | |||
| @RequiresPermissions("system:user:list") | |||
| @GetMapping("/selectDeptTree/{deptId}") | |||
| public String selectDeptTree(@PathVariable("deptId") Long deptId, ModelMap mmap) | |||
| { | |||
| mmap.put("dept", deptService.selectDeptById(deptId)); | |||
| return prefix + "/deptTree"; | |||
| } | |||
| /** | |||
| * 搜索用户名称 | |||
| */ | |||
| @RequiresPermissions("system:user:list") | |||
| @GetMapping("/userModel") | |||
| @ResponseBody | |||
| public AjaxResult userModel(String type) | |||
| { | |||
| SysUser sysUser = new SysUser(); | |||
| sysUser.setRemark(type); | |||
| AjaxResult ajax = new AjaxResult(); | |||
| List<SysUser> list = userService.selectUserList(sysUser); | |||
| for (SysUser user: list) { | |||
| user.setRemark(user.getDept().getDeptName()); | |||
| } | |||
| ajax.put("code", 200); | |||
| ajax.put("value", list); | |||
| return ajax; | |||
| } | |||
| } | |||
| @@ -0,0 +1,26 @@ | |||
| package com.rwk.web.controller.tool; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| /** | |||
| * build 表单构建 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/tool/build") | |||
| public class BuildController extends BaseController | |||
| { | |||
| private String prefix = "tool/build"; | |||
| @RequiresPermissions("tool:build:view") | |||
| @GetMapping() | |||
| public String build() | |||
| { | |||
| return prefix + "/build"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| package com.rwk.web.controller.tool; | |||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||
| import org.springframework.stereotype.Controller; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| /** | |||
| * swagger 接口 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Controller | |||
| @RequestMapping("/tool/swagger") | |||
| public class SwaggerController extends BaseController | |||
| { | |||
| @RequiresPermissions("tool:swagger:view") | |||
| @GetMapping() | |||
| public String index() | |||
| { | |||
| return redirect("/swagger-ui/index.html"); | |||
| } | |||
| } | |||
| @@ -0,0 +1,183 @@ | |||
| package com.rwk.web.controller.tool; | |||
| import java.util.ArrayList; | |||
| import java.util.LinkedHashMap; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import org.springframework.web.bind.annotation.DeleteMapping; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.PutMapping; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| import com.rwk.common.core.controller.BaseController; | |||
| import com.rwk.common.core.domain.R; | |||
| import com.rwk.common.utils.StringUtils; | |||
| import io.swagger.annotations.Api; | |||
| import io.swagger.annotations.ApiImplicitParam; | |||
| import io.swagger.annotations.ApiImplicitParams; | |||
| import io.swagger.annotations.ApiModel; | |||
| import io.swagger.annotations.ApiModelProperty; | |||
| import io.swagger.annotations.ApiOperation; | |||
| /** | |||
| * swagger 用户测试方法 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Api("用户信息管理") | |||
| @RestController | |||
| @RequestMapping("/test/user") | |||
| public class TestController extends BaseController | |||
| { | |||
| private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>(); | |||
| { | |||
| users.put(1, new UserEntity(1, "admin", "admin123", "15888888888")); | |||
| users.put(2, new UserEntity(2, "ry", "admin123", "15666666666")); | |||
| } | |||
| @ApiOperation("获取用户列表") | |||
| @GetMapping("/list") | |||
| public R<List<UserEntity>> userList() | |||
| { | |||
| List<UserEntity> userList = new ArrayList<UserEntity>(users.values()); | |||
| return R.ok(userList); | |||
| } | |||
| @ApiOperation("获取用户详细") | |||
| @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) | |||
| @GetMapping("/{userId}") | |||
| public R<UserEntity> getUser(@PathVariable Integer userId) | |||
| { | |||
| if (!users.isEmpty() && users.containsKey(userId)) | |||
| { | |||
| return R.ok(users.get(userId)); | |||
| } | |||
| else | |||
| { | |||
| return R.fail("用户不存在"); | |||
| } | |||
| } | |||
| @ApiOperation("新增用户") | |||
| @ApiImplicitParams({ | |||
| @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class), | |||
| @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class), | |||
| @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class), | |||
| @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class) | |||
| }) | |||
| @PostMapping("/save") | |||
| public R<String> save(UserEntity user) | |||
| { | |||
| if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) | |||
| { | |||
| return R.fail("用户ID不能为空"); | |||
| } | |||
| users.put(user.getUserId(), user); | |||
| return R.ok(); | |||
| } | |||
| @ApiOperation("更新用户") | |||
| @PutMapping("/update") | |||
| public R<String> update(@RequestBody UserEntity user) | |||
| { | |||
| if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) | |||
| { | |||
| return R.fail("用户ID不能为空"); | |||
| } | |||
| if (users.isEmpty() || !users.containsKey(user.getUserId())) | |||
| { | |||
| return R.fail("用户不存在"); | |||
| } | |||
| users.remove(user.getUserId()); | |||
| users.put(user.getUserId(), user); | |||
| return R.ok(); | |||
| } | |||
| @ApiOperation("删除用户信息") | |||
| @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) | |||
| @DeleteMapping("/{userId}") | |||
| public R<String> delete(@PathVariable Integer userId) | |||
| { | |||
| if (!users.isEmpty() && users.containsKey(userId)) | |||
| { | |||
| users.remove(userId); | |||
| return R.ok(); | |||
| } | |||
| else | |||
| { | |||
| return R.fail("用户不存在"); | |||
| } | |||
| } | |||
| } | |||
| @ApiModel(value = "UserEntity", description = "用户实体") | |||
| class UserEntity | |||
| { | |||
| @ApiModelProperty("用户ID") | |||
| private Integer userId; | |||
| @ApiModelProperty("用户名称") | |||
| private String username; | |||
| @ApiModelProperty("用户密码") | |||
| private String password; | |||
| @ApiModelProperty("用户手机") | |||
| private String mobile; | |||
| public UserEntity() | |||
| { | |||
| } | |||
| public UserEntity(Integer userId, String username, String password, String mobile) | |||
| { | |||
| this.userId = userId; | |||
| this.username = username; | |||
| this.password = password; | |||
| this.mobile = mobile; | |||
| } | |||
| public Integer getUserId() | |||
| { | |||
| return userId; | |||
| } | |||
| public void setUserId(Integer userId) | |||
| { | |||
| this.userId = userId; | |||
| } | |||
| public String getUsername() | |||
| { | |||
| return username; | |||
| } | |||
| public void setUsername(String username) | |||
| { | |||
| this.username = username; | |||
| } | |||
| public String getPassword() | |||
| { | |||
| return password; | |||
| } | |||
| public void setPassword(String password) | |||
| { | |||
| this.password = password; | |||
| } | |||
| public String getMobile() | |||
| { | |||
| return mobile; | |||
| } | |||
| public void setMobile(String mobile) | |||
| { | |||
| this.mobile = mobile; | |||
| } | |||
| } | |||
| @@ -0,0 +1,67 @@ | |||
| package com.rwk.web.core.config; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.context.annotation.Bean; | |||
| import org.springframework.context.annotation.Configuration; | |||
| import com.rwk.common.config.RuoYiConfig; | |||
| import io.swagger.annotations.ApiOperation; | |||
| import springfox.documentation.builders.ApiInfoBuilder; | |||
| import springfox.documentation.builders.PathSelectors; | |||
| import springfox.documentation.builders.RequestHandlerSelectors; | |||
| import springfox.documentation.service.ApiInfo; | |||
| import springfox.documentation.service.Contact; | |||
| import springfox.documentation.spi.DocumentationType; | |||
| import springfox.documentation.spring.web.plugins.Docket; | |||
| /** | |||
| * Swagger2的接口配置 | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @Configuration | |||
| public class SwaggerConfig | |||
| { | |||
| /** 是否开启swagger */ | |||
| @Value("${swagger.enabled}") | |||
| private boolean enabled; | |||
| /** | |||
| * 创建API | |||
| */ | |||
| @Bean | |||
| public Docket createRestApi() | |||
| { | |||
| return new Docket(DocumentationType.OAS_30) | |||
| // 是否启用Swagger | |||
| .enable(enabled) | |||
| // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息) | |||
| .apiInfo(apiInfo()) | |||
| // 设置哪些接口暴露给Swagger展示 | |||
| .select() | |||
| // 扫描所有有注解的api,用这种方式更灵活 | |||
| .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) | |||
| // 扫描指定包中的swagger注解 | |||
| //.apis(RequestHandlerSelectors.basePackage("com.rwk.project.tool.swagger")) | |||
| // 扫描所有 .apis(RequestHandlerSelectors.any()) | |||
| .paths(PathSelectors.any()) | |||
| .build(); | |||
| } | |||
| /** | |||
| * 添加摘要信息 | |||
| */ | |||
| private ApiInfo apiInfo() | |||
| { | |||
| // 用ApiInfoBuilder进行定制 | |||
| return new ApiInfoBuilder() | |||
| // 设置标题 | |||
| .title("标题:管理系统_接口文档") | |||
| // 描述 | |||
| .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...") | |||
| // 作者信息 | |||
| .contact(new Contact(RuoYiConfig.getName(), null, null)) | |||
| // 版本 | |||
| .version("版本号:" + RuoYiConfig.getVersion()) | |||
| .build(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,61 @@ | |||
| # 数据源配置 | |||
| spring: | |||
| datasource: | |||
| type: com.alibaba.druid.pool.DruidDataSource | |||
| driverClassName: dm.jdbc.driver.DmDriver | |||
| druid: | |||
| # 主库数据源 | |||
| master: | |||
| url: jdbc:dm://localhost:5236/TZB_RWK?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true | |||
| username: TZB_RWK | |||
| password: hk64335593 | |||
| # 从库数据源 | |||
| slave: | |||
| # 从数据源开关/默认关闭 | |||
| enabled: false | |||
| url: | |||
| username: | |||
| password: | |||
| # 初始连接数 | |||
| initialSize: 5 | |||
| # 最小连接池数量 | |||
| minIdle: 10 | |||
| # 最大连接池数量 | |||
| maxActive: 20 | |||
| # 配置获取连接等待超时的时间 | |||
| maxWait: 60000 | |||
| # 配置连接超时时间 | |||
| connectTimeout: 30000 | |||
| # 配置网络超时时间 | |||
| socketTimeout: 60000 | |||
| # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 | |||
| timeBetweenEvictionRunsMillis: 60000 | |||
| # 配置一个连接在池中最小生存的时间,单位是毫秒 | |||
| minEvictableIdleTimeMillis: 300000 | |||
| # 配置一个连接在池中最大生存的时间,单位是毫秒 | |||
| maxEvictableIdleTimeMillis: 900000 | |||
| # 配置检测连接是否有效 | |||
| validationQuery: SELECT 1 FROM DUAL | |||
| testWhileIdle: true | |||
| testOnBorrow: false | |||
| testOnReturn: false | |||
| webStatFilter: | |||
| enabled: true | |||
| statViewServlet: | |||
| enabled: true | |||
| # 设置白名单,不填则允许所有访问 | |||
| allow: | |||
| url-pattern: /druid/* | |||
| # 控制台管理用户名和密码 | |||
| login-username: ruoyi | |||
| login-password: 123456 | |||
| filter: | |||
| stat: | |||
| enabled: true | |||
| # 慢SQL记录 | |||
| log-slow-sql: true | |||
| slow-sql-millis: 1000 | |||
| merge-sql: true | |||
| wall: | |||
| config: | |||
| multi-statement-allow: true | |||
| @@ -0,0 +1,143 @@ | |||
| # 项目相关配置 | |||
| ruoyi: | |||
| # 名称 | |||
| name: rwk | |||
| # 版本 | |||
| version: 4.7.9 | |||
| # 版权年份 | |||
| copyrightYear: 2024 | |||
| # 实例演示开关 | |||
| demoEnabled: false | |||
| # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) | |||
| profile: D:/ruoyi/uploadPath | |||
| # profile: /home/ruoyi/uploadPath | |||
| # 获取ip地址开关 | |||
| addressEnabled: false | |||
| # 开发环境配置 | |||
| server: | |||
| # 服务器的HTTP端口,默认为80 | |||
| port: 8080 | |||
| servlet: | |||
| # 应用的访问路径 | |||
| context-path: / | |||
| tomcat: | |||
| # tomcat的URI编码 | |||
| uri-encoding: UTF-8 | |||
| # 连接数满后的排队数,默认为100 | |||
| accept-count: 1000 | |||
| threads: | |||
| # tomcat最大线程数,默认为200 | |||
| max: 800 | |||
| # Tomcat启动初始化的线程数,默认值10 | |||
| min-spare: 100 | |||
| # 日志配置 | |||
| logging: | |||
| level: | |||
| com.rwk: debug | |||
| org.springframework: warn | |||
| # 用户配置 | |||
| user: | |||
| password: | |||
| # 密码错误{maxRetryCount}次锁定10分钟 | |||
| maxRetryCount: 5 | |||
| # Spring配置 | |||
| spring: | |||
| # 模板引擎 | |||
| thymeleaf: | |||
| mode: HTML | |||
| encoding: utf-8 | |||
| # 禁用缓存 | |||
| cache: false | |||
| # 资源信息 | |||
| messages: | |||
| # 国际化资源文件路径 | |||
| basename: static/i18n/messages | |||
| jackson: | |||
| time-zone: GMT+8 | |||
| date-format: yyyy-MM-dd HH:mm:ss | |||
| profiles: | |||
| active: druid | |||
| # 文件上传 | |||
| servlet: | |||
| multipart: | |||
| # 单个文件大小 | |||
| max-file-size: 100MB | |||
| # 设置总上传的文件大小 | |||
| max-request-size: 500MB | |||
| # 服务模块 | |||
| devtools: | |||
| restart: | |||
| # 热部署开关 | |||
| enabled: true | |||
| # MyBatis | |||
| mybatis: | |||
| # 搜索指定包别名 | |||
| typeAliasesPackage: com.rwk.**.domain | |||
| # 配置mapper的扫描,找到所有的mapper.xml映射文件 | |||
| mapperLocations: classpath*:mapper/**/*Mapper.xml | |||
| # 加载全局的配置文件 | |||
| configLocation: classpath:mybatis/mybatis-config.xml | |||
| # PageHelper分页插件 | |||
| pagehelper: | |||
| helperDialect: mysql | |||
| supportMethodsArguments: true | |||
| params: count=countSql | |||
| # Shiro | |||
| shiro: | |||
| user: | |||
| # 登录地址 | |||
| loginUrl: /login | |||
| # 权限认证失败地址 | |||
| unauthorizedUrl: /unauth | |||
| # 首页地址 | |||
| indexUrl: /index | |||
| # 验证码开关 | |||
| captchaEnabled: false | |||
| # 验证码类型 math 数字计算 char 字符验证 | |||
| captchaType: math | |||
| cookie: | |||
| # 设置Cookie的域名 默认空,即当前访问的域名 | |||
| domain: | |||
| # 设置cookie的有效访问路径 | |||
| path: / | |||
| # 设置HttpOnly属性 | |||
| httpOnly: true | |||
| # 设置Cookie的过期时间,天为单位 | |||
| maxAge: 30 | |||
| # 设置密钥,务必保持唯一性(生成方式,直接拷贝到main运行即可)Base64.encodeToString(CipherUtils.generateNewKey(128, "AES").getEncoded()) (默认启动生成随机秘钥,随机秘钥会导致之前客户端RememberMe Cookie无效,如设置固定秘钥RememberMe Cookie则有效) | |||
| cipherKey: | |||
| session: | |||
| # Session超时时间,-1代表永不过期(默认30分钟) | |||
| expireTime: 30 | |||
| # 同步session到数据库的周期(默认1分钟) | |||
| dbSyncPeriod: 1 | |||
| # 相隔多久检查一次session的有效性,默认就是10分钟 | |||
| validationInterval: 10 | |||
| # 同一个用户最大会话数,比如2的意思是同一个账号允许最多同时两个人登录(默认-1不限制) | |||
| maxSession: -1 | |||
| # 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户 | |||
| kickoutAfter: false | |||
| rememberMe: | |||
| # 是否开启记住我 | |||
| enabled: true | |||
| # 防止XSS攻击 | |||
| xss: | |||
| # 过滤开关 | |||
| enabled: true | |||
| # 排除链接(多个用逗号分隔) | |||
| excludes: /system/notice/* | |||
| # 匹配链接 | |||
| urlPatterns: /system/*,/monitor/*,/tool/* | |||
| # Swagger配置 | |||
| swagger: | |||
| # 是否开启swagger | |||
| enabled: true | |||
| @@ -0,0 +1,24 @@ | |||
| Application Version: ${ruoyi.version} | |||
| Spring Boot Version: ${spring-boot.version} | |||
| //////////////////////////////////////////////////////////////////// | |||
| // _ooOoo_ // | |||
| // o8888888o // | |||
| // 88" . "88 // | |||
| // (| ^_^ |) // | |||
| // O\ = /O // | |||
| // ____/`---'\____ // | |||
| // .' \\| |// `. // | |||
| // / \\||| : |||// \ // | |||
| // / _||||| -:- |||||- \ // | |||
| // | | \\\ - /// | | // | |||
| // | \_| ''\---/'' | | // | |||
| // \ .-\__ `-` ___/-. / // | |||
| // ___`. .' /--.--\ `. . ___ // | |||
| // ."" '< `.___\_<|>_/___.' >'"". // | |||
| // | | : `- \`.;`\ _ /`;.`/ - ` : | | // | |||
| // \ \ `-. \_ __\ /__ _/ .-` / / // | |||
| // ========`-.____`-.___\_____/___.-`____.-'======== // | |||
| // `=---=' // | |||
| // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // | |||
| // 佛祖保佑 永不宕机 永无BUG // | |||
| //////////////////////////////////////////////////////////////////// | |||
| @@ -0,0 +1,91 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <ehcache name="ruoyi" updateCheck="false"> | |||
| <!-- 磁盘缓存位置 --> | |||
| <diskStore path="java.io.tmpdir"/> | |||
| <!-- maxEntriesLocalHeap:堆内存中最大缓存对象数,0没有限制 --> | |||
| <!-- maxElementsInMemory: 在内存中缓存的element的最大数目。--> | |||
| <!-- eternal:elements是否永久有效,如果为true,timeouts将被忽略,element将永不过期 --> | |||
| <!-- timeToIdleSeconds:失效前的空闲秒数,当eternal为false时,这个属性才有效,0为不限制 --> | |||
| <!-- timeToLiveSeconds:失效前的存活秒数,创建时间到失效时间的间隔为存活时间,当eternal为false时,这个属性才有效,0为不限制 --> | |||
| <!-- overflowToDisk: 如果内存中数据超过内存限制,是否要缓存到磁盘上 --> | |||
| <!-- statistics:是否收集统计信息。如果需要监控缓存使用情况,应该打开这个选项。默认为关闭(统计会影响性能)。设置statistics="true"开启统计 --> | |||
| <!-- 默认缓存 --> | |||
| <defaultCache | |||
| maxEntriesLocalHeap="1000" | |||
| eternal="false" | |||
| timeToIdleSeconds="3600" | |||
| timeToLiveSeconds="3600" | |||
| overflowToDisk="false"> | |||
| </defaultCache> | |||
| <!-- 登录记录缓存 锁定10分钟 --> | |||
| <cache name="loginRecordCache" | |||
| maxEntriesLocalHeap="2000" | |||
| eternal="false" | |||
| timeToIdleSeconds="600" | |||
| timeToLiveSeconds="0" | |||
| overflowToDisk="false" | |||
| statistics="false"> | |||
| </cache> | |||
| <!-- 系统活跃用户缓存 --> | |||
| <cache name="sys-userCache" | |||
| maxEntriesLocalHeap="10000" | |||
| overflowToDisk="false" | |||
| eternal="false" | |||
| diskPersistent="false" | |||
| timeToLiveSeconds="0" | |||
| timeToIdleSeconds="0" | |||
| statistics="false"> | |||
| </cache> | |||
| <!-- 系统用户授权缓存 没必要过期 --> | |||
| <cache name="sys-authCache" | |||
| maxEntriesLocalHeap="10000" | |||
| overflowToDisk="false" | |||
| eternal="false" | |||
| diskPersistent="false" | |||
| timeToLiveSeconds="0" | |||
| timeToIdleSeconds="0" | |||
| memoryStoreEvictionPolicy="LRU" | |||
| statistics="false"/> | |||
| <!-- 系统缓存 --> | |||
| <cache name="sys-cache" | |||
| maxEntriesLocalHeap="1000" | |||
| eternal="true" | |||
| overflowToDisk="true" | |||
| statistics="false"> | |||
| </cache> | |||
| <!-- 系统参数缓存 --> | |||
| <cache name="sys-config" | |||
| maxEntriesLocalHeap="1000" | |||
| eternal="true" | |||
| overflowToDisk="true" | |||
| statistics="false"> | |||
| </cache> | |||
| <!-- 系统字典缓存 --> | |||
| <cache name="sys-dict" | |||
| maxEntriesLocalHeap="1000" | |||
| eternal="true" | |||
| overflowToDisk="true" | |||
| statistics="false"> | |||
| </cache> | |||
| <!-- 系统会话缓存 --> | |||
| <cache name="shiro-activeSessionCache" | |||
| maxEntriesLocalHeap="10000" | |||
| overflowToDisk="false" | |||
| eternal="false" | |||
| diskPersistent="false" | |||
| timeToLiveSeconds="0" | |||
| timeToIdleSeconds="0" | |||
| statistics="false"/> | |||
| </ehcache> | |||
| @@ -0,0 +1,93 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <configuration> | |||
| <!-- 日志存放路径 --> | |||
| <property name="log.path" value="/home/ruoyi/logs" /> | |||
| <!-- 日志输出格式 --> | |||
| <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> | |||
| <!-- 控制台输出 --> | |||
| <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> | |||
| <encoder> | |||
| <pattern>${log.pattern}</pattern> | |||
| </encoder> | |||
| </appender> | |||
| <!-- 系统日志输出 --> | |||
| <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> | |||
| <file>${log.path}/sys-info.log</file> | |||
| <!-- 循环政策:基于时间创建日志文件 --> | |||
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |||
| <!-- 日志文件名格式 --> | |||
| <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern> | |||
| <!-- 日志最大的历史 60天 --> | |||
| <maxHistory>60</maxHistory> | |||
| </rollingPolicy> | |||
| <encoder> | |||
| <pattern>${log.pattern}</pattern> | |||
| </encoder> | |||
| <filter class="ch.qos.logback.classic.filter.LevelFilter"> | |||
| <!-- 过滤的级别 --> | |||
| <level>INFO</level> | |||
| <!-- 匹配时的操作:接收(记录) --> | |||
| <onMatch>ACCEPT</onMatch> | |||
| <!-- 不匹配时的操作:拒绝(不记录) --> | |||
| <onMismatch>DENY</onMismatch> | |||
| </filter> | |||
| </appender> | |||
| <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> | |||
| <file>${log.path}/sys-error.log</file> | |||
| <!-- 循环政策:基于时间创建日志文件 --> | |||
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |||
| <!-- 日志文件名格式 --> | |||
| <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern> | |||
| <!-- 日志最大的历史 60天 --> | |||
| <maxHistory>60</maxHistory> | |||
| </rollingPolicy> | |||
| <encoder> | |||
| <pattern>${log.pattern}</pattern> | |||
| </encoder> | |||
| <filter class="ch.qos.logback.classic.filter.LevelFilter"> | |||
| <!-- 过滤的级别 --> | |||
| <level>ERROR</level> | |||
| <!-- 匹配时的操作:接收(记录) --> | |||
| <onMatch>ACCEPT</onMatch> | |||
| <!-- 不匹配时的操作:拒绝(不记录) --> | |||
| <onMismatch>DENY</onMismatch> | |||
| </filter> | |||
| </appender> | |||
| <!-- 用户访问日志输出 --> | |||
| <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender"> | |||
| <file>${log.path}/sys-user.log</file> | |||
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |||
| <!-- 按天回滚 daily --> | |||
| <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern> | |||
| <!-- 日志最大的历史 60天 --> | |||
| <maxHistory>60</maxHistory> | |||
| </rollingPolicy> | |||
| <encoder> | |||
| <pattern>${log.pattern}</pattern> | |||
| </encoder> | |||
| </appender> | |||
| <!-- 系统模块日志级别控制 --> | |||
| <logger name="com.rwk" level="info" /> | |||
| <!-- Spring日志级别控制 --> | |||
| <logger name="org.springframework" level="warn" /> | |||
| <root level="info"> | |||
| <appender-ref ref="console" /> | |||
| </root> | |||
| <!--系统操作日志--> | |||
| <root level="info"> | |||
| <appender-ref ref="file_info" /> | |||
| <appender-ref ref="file_error" /> | |||
| </root> | |||
| <!--系统用户操作日志--> | |||
| <logger name="sys-user" level="info"> | |||
| <appender-ref ref="sys-user"/> | |||
| </logger> | |||
| </configuration> | |||
| @@ -0,0 +1,20 @@ | |||
| <?xml version="1.0" encoding="UTF-8" ?> | |||
| <!DOCTYPE configuration | |||
| PUBLIC "-//mybatis.org//DTD Config 3.0//EN" | |||
| "http://mybatis.org/dtd/mybatis-3-config.dtd"> | |||
| <configuration> | |||
| <!-- 全局参数 --> | |||
| <settings> | |||
| <!-- 使全局的映射器启用或禁用缓存 --> | |||
| <setting name="cacheEnabled" value="true" /> | |||
| <!-- 允许JDBC 支持自动生成主键 --> | |||
| <setting name="useGeneratedKeys" value="true" /> | |||
| <!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 --> | |||
| <setting name="defaultExecutorType" value="SIMPLE" /> | |||
| <!-- 指定 MyBatis 所用日志的具体实现 --> | |||
| <setting name="logImpl" value="SLF4J" /> | |||
| <!-- 使用驼峰命名法转换字段 --> | |||
| <!-- <setting name="mapUnderscoreToCamelCase" value="true"/> --> | |||
| </settings> | |||
| </configuration> | |||
| @@ -0,0 +1,617 @@ | |||
| /*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */ | |||
| /* | |||
| The MIT License (MIT) | |||
| Copyright (c) 2007-2013 Einar Lielmanis and contributors. | |||
| Permission is hereby granted, free of charge, to any person | |||
| obtaining a copy of this software and associated documentation files | |||
| (the "Software"), to deal in the Software without restriction, | |||
| including without limitation the rights to use, copy, modify, merge, | |||
| publish, distribute, sublicense, and/or sell copies of the Software, | |||
| and to permit persons to whom the Software is furnished to do so, | |||
| subject to the following conditions: | |||
| The above copyright notice and this permission notice shall be | |||
| included in all copies or substantial portions of the Software. | |||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
| BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |||
| ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| SOFTWARE. | |||
| Style HTML | |||
| --------------- | |||
| Written by Nochum Sossonko, (nsossonko@hotmail.com) | |||
| Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv> | |||
| http://jsbeautifier.org/ | |||
| Usage: | |||
| style_html(html_source); | |||
| style_html(html_source, options); | |||
| The options are: | |||
| indent_size (default 4) — indentation size, | |||
| indent_char (default space) — character to indent with, | |||
| max_char (default 250) - maximum amount of characters per line (0 = disable) | |||
| brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | |||
| 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. | |||
| unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted | |||
| indent_scripts (default normal) - "keep"|"separate"|"normal" | |||
| e.g. | |||
| style_html(html_source, { | |||
| 'indent_size': 2, | |||
| 'indent_char': ' ', | |||
| 'max_char': 78, | |||
| 'brace_style': 'expand', | |||
| 'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u'] | |||
| }); | |||
| */ | |||
| (function() { | |||
| function style_html(html_source, options, js_beautify, css_beautify) { | |||
| //Wrapper function to invoke all the necessary constructors and deal with the output. | |||
| var multi_parser, | |||
| indent_size, | |||
| indent_character, | |||
| max_char, | |||
| brace_style, | |||
| unformatted; | |||
| options = options || {}; | |||
| indent_size = options.indent_size || 4; | |||
| indent_character = options.indent_char || ' '; | |||
| brace_style = options.brace_style || 'collapse'; | |||
| max_char = options.max_char === 0 ? Infinity : options.max_char || 250; | |||
| 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']; | |||
| function Parser() { | |||
| this.pos = 0; //Parser position | |||
| this.token = ''; | |||
| this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT | |||
| this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values | |||
| parent: 'parent1', | |||
| parentcount: 1, | |||
| parent1: '' | |||
| }; | |||
| this.tag_type = ''; | |||
| this.token_text = this.last_token = this.last_text = this.token_type = ''; | |||
| this.Utils = { //Uilities made available to the various functions | |||
| whitespace: "\n\r\t ".split(''), | |||
| 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 | |||
| extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them | |||
| in_array: function (what, arr) { | |||
| for (var i=0; i<arr.length; i++) { | |||
| if (what === arr[i]) { | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| }; | |||
| this.get_content = function () { //function to capture regular content between tags | |||
| var input_char = '', | |||
| content = [], | |||
| space = false; //if a space is needed | |||
| while (this.input.charAt(this.pos) !== '<') { | |||
| if (this.pos >= this.input.length) { | |||
| return content.length?content.join(''):['', 'TK_EOF']; | |||
| } | |||
| input_char = this.input.charAt(this.pos); | |||
| this.pos++; | |||
| this.line_char_count++; | |||
| if (this.Utils.in_array(input_char, this.Utils.whitespace)) { | |||
| if (content.length) { | |||
| space = true; | |||
| } | |||
| this.line_char_count--; | |||
| continue; //don't want to insert unnecessary space | |||
| } | |||
| else if (space) { | |||
| if (this.line_char_count >= this.max_char) { //insert a line when the max_char is reached | |||
| content.push('\n'); | |||
| for (var i=0; i<this.indent_level; i++) { | |||
| content.push(this.indent_string); | |||
| } | |||
| this.line_char_count = 0; | |||
| } | |||
| else{ | |||
| content.push(' '); | |||
| this.line_char_count++; | |||
| } | |||
| space = false; | |||
| } | |||
| content.push(input_char); //letter at-a-time (or string) inserted to an array | |||
| } | |||
| return content.length?content.join(''):''; | |||
| }; | |||
| this.get_contents_to = function (name) { //get the full content of a script or style to pass to js_beautify | |||
| if (this.pos === this.input.length) { | |||
| return ['', 'TK_EOF']; | |||
| } | |||
| var input_char = ''; | |||
| var content = ''; | |||
| var reg_match = new RegExp('</' + name + '\\s*>', 'igm'); | |||
| reg_match.lastIndex = this.pos; | |||
| var reg_array = reg_match.exec(this.input); | |||
| var end_script = reg_array?reg_array.index:this.input.length; //absolute end of script | |||
| if(this.pos < end_script) { //get everything in between the script tags | |||
| content = this.input.substring(this.pos, end_script); | |||
| this.pos = end_script; | |||
| } | |||
| return content; | |||
| }; | |||
| this.record_tag = function (tag){ //function to record a tag and its parent in this.tags Object | |||
| if (this.tags[tag + 'count']) { //check for the existence of this tag type | |||
| this.tags[tag + 'count']++; | |||
| this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level | |||
| } | |||
| else { //otherwise initialize this tag type | |||
| this.tags[tag + 'count'] = 1; | |||
| this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level | |||
| } | |||
| 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) | |||
| this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1') | |||
| }; | |||
| this.retrieve_tag = function (tag) { //function to retrieve the opening tag to the corresponding closer | |||
| if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it | |||
| var temp_parent = this.tags.parent; //check to see if it's a closable tag. | |||
| while (temp_parent) { //till we reach '' (the initial value); | |||
| if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it | |||
| break; | |||
| } | |||
| temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree | |||
| } | |||
| if (temp_parent) { //if we caught something | |||
| this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly | |||
| this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent | |||
| } | |||
| delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference... | |||
| delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself | |||
| if (this.tags[tag + 'count'] === 1) { | |||
| delete this.tags[tag + 'count']; | |||
| } | |||
| else { | |||
| this.tags[tag + 'count']--; | |||
| } | |||
| } | |||
| }; | |||
| this.get_tag = function (peek) { //function to get a full tag and parse its type | |||
| var input_char = '', | |||
| content = [], | |||
| comment = '', | |||
| space = false, | |||
| tag_start, tag_end, | |||
| orig_pos = this.pos, | |||
| orig_line_char_count = this.line_char_count; | |||
| peek = peek !== undefined ? peek : false; | |||
| do { | |||
| if (this.pos >= this.input.length) { | |||
| if (peek) { | |||
| this.pos = orig_pos; | |||
| this.line_char_count = orig_line_char_count; | |||
| } | |||
| return content.length?content.join(''):['', 'TK_EOF']; | |||
| } | |||
| input_char = this.input.charAt(this.pos); | |||
| this.pos++; | |||
| this.line_char_count++; | |||
| if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space | |||
| space = true; | |||
| this.line_char_count--; | |||
| continue; | |||
| } | |||
| if (input_char === "'" || input_char === '"') { | |||
| if (!content[1] || content[1] !== '!') { //if we're in a comment strings don't get treated specially | |||
| input_char += this.get_unformatted(input_char); | |||
| space = true; | |||
| } | |||
| } | |||
| if (input_char === '=') { //no space before = | |||
| space = false; | |||
| } | |||
| if (content.length && content[content.length-1] !== '=' && input_char !== '>' && space) { | |||
| //no space after = or before > | |||
| if (this.line_char_count >= this.max_char) { | |||
| this.print_newline(false, content); | |||
| this.line_char_count = 0; | |||
| } | |||
| else { | |||
| content.push(' '); | |||
| this.line_char_count++; | |||
| } | |||
| space = false; | |||
| } | |||
| if (input_char === '<') { | |||
| tag_start = this.pos - 1; | |||
| } | |||
| content.push(input_char); //inserts character at-a-time (or string) | |||
| } while (input_char !== '>'); | |||
| var tag_complete = content.join(''); | |||
| var tag_index; | |||
| if (tag_complete.indexOf(' ') !== -1) { //if there's whitespace, thats where the tag name ends | |||
| tag_index = tag_complete.indexOf(' '); | |||
| } | |||
| else { //otherwise go with the tag ending | |||
| tag_index = tag_complete.indexOf('>'); | |||
| } | |||
| var tag_check = tag_complete.substring(1, tag_index).toLowerCase(); | |||
| if (tag_complete.charAt(tag_complete.length-2) === '/' || | |||
| 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 /) | |||
| if ( ! peek) { | |||
| this.tag_type = 'SINGLE'; | |||
| } | |||
| } | |||
| else if (tag_check === 'script') { //for later script handling | |||
| if ( ! peek) { | |||
| this.record_tag(tag_check); | |||
| this.tag_type = 'SCRIPT'; | |||
| } | |||
| } | |||
| else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content) | |||
| if ( ! peek) { | |||
| this.record_tag(tag_check); | |||
| this.tag_type = 'STYLE'; | |||
| } | |||
| } | |||
| else if (this.is_unformatted(tag_check, unformatted)) { // do not reformat the "unformatted" tags | |||
| comment = this.get_unformatted('</'+tag_check+'>', tag_complete); //...delegate to get_unformatted function | |||
| content.push(comment); | |||
| // Preserve collapsed whitespace either before or after this tag. | |||
| if (tag_start > 0 && this.Utils.in_array(this.input.charAt(tag_start - 1), this.Utils.whitespace)){ | |||
| content.splice(0, 0, this.input.charAt(tag_start - 1)); | |||
| } | |||
| tag_end = this.pos - 1; | |||
| if (this.Utils.in_array(this.input.charAt(tag_end + 1), this.Utils.whitespace)){ | |||
| content.push(this.input.charAt(tag_end + 1)); | |||
| } | |||
| this.tag_type = 'SINGLE'; | |||
| } | |||
| else if (tag_check.charAt(0) === '!') { //peek for <!-- comment | |||
| if (tag_check.indexOf('[if') !== -1) { //peek for <!--[if conditional comment | |||
| if (tag_complete.indexOf('!IE') !== -1) { //this type needs a closing --> so... | |||
| comment = this.get_unformatted('-->', tag_complete); //...delegate to get_unformatted | |||
| content.push(comment); | |||
| } | |||
| if ( ! peek) { | |||
| this.tag_type = 'START'; | |||
| } | |||
| } | |||
| else if (tag_check.indexOf('[endif') !== -1) {//peek for <!--[endif end conditional comment | |||
| this.tag_type = 'END'; | |||
| this.unindent(); | |||
| } | |||
| else if (tag_check.indexOf('[cdata[') !== -1) { //if it's a <[cdata[ comment... | |||
| comment = this.get_unformatted(']]>', tag_complete); //...delegate to get_unformatted function | |||
| content.push(comment); | |||
| if ( ! peek) { | |||
| this.tag_type = 'SINGLE'; //<![CDATA[ comments are treated like single tags | |||
| } | |||
| } | |||
| else { | |||
| comment = this.get_unformatted('-->', tag_complete); | |||
| content.push(comment); | |||
| this.tag_type = 'SINGLE'; | |||
| } | |||
| } | |||
| else if ( ! peek) { | |||
| if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending | |||
| this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors | |||
| this.tag_type = 'END'; | |||
| } | |||
| else { //otherwise it's a start-tag | |||
| this.record_tag(tag_check); //push it on the tag stack | |||
| this.tag_type = 'START'; | |||
| } | |||
| if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line | |||
| this.print_newline(true, this.output); | |||
| } | |||
| } | |||
| if (peek) { | |||
| this.pos = orig_pos; | |||
| this.line_char_count = orig_line_char_count; | |||
| } | |||
| return content.join(''); //returns fully formatted tag | |||
| }; | |||
| this.get_unformatted = function (delimiter, orig_tag) { //function to return unformatted content in its entirety | |||
| if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) !== -1) { | |||
| return ''; | |||
| } | |||
| var input_char = ''; | |||
| var content = ''; | |||
| var space = true; | |||
| do { | |||
| if (this.pos >= this.input.length) { | |||
| return content; | |||
| } | |||
| input_char = this.input.charAt(this.pos); | |||
| this.pos++; | |||
| if (this.Utils.in_array(input_char, this.Utils.whitespace)) { | |||
| if (!space) { | |||
| this.line_char_count--; | |||
| continue; | |||
| } | |||
| if (input_char === '\n' || input_char === '\r') { | |||
| content += '\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' | |||
| for (var i=0; i<this.indent_level; i++) { | |||
| content += this.indent_string; | |||
| } | |||
| space = false; //...and make sure other indentation is erased | |||
| */ | |||
| this.line_char_count = 0; | |||
| continue; | |||
| } | |||
| } | |||
| content += input_char; | |||
| this.line_char_count++; | |||
| space = true; | |||
| } while (content.toLowerCase().indexOf(delimiter) === -1); | |||
| return content; | |||
| }; | |||
| this.get_token = function () { //initial handler for token-retrieval | |||
| var token; | |||
| if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript | |||
| var type = this.last_token.substr(7); | |||
| token = this.get_contents_to(type); | |||
| if (typeof token !== 'string') { | |||
| return token; | |||
| } | |||
| return [token, 'TK_' + type]; | |||
| } | |||
| if (this.current_mode === 'CONTENT') { | |||
| token = this.get_content(); | |||
| if (typeof token !== 'string') { | |||
| return token; | |||
| } | |||
| else { | |||
| return [token, 'TK_CONTENT']; | |||
| } | |||
| } | |||
| if (this.current_mode === 'TAG') { | |||
| token = this.get_tag(); | |||
| if (typeof token !== 'string') { | |||
| return token; | |||
| } | |||
| else { | |||
| var tag_name_type = 'TK_TAG_' + this.tag_type; | |||
| return [token, tag_name_type]; | |||
| } | |||
| } | |||
| }; | |||
| this.get_full_indent = function (level) { | |||
| level = this.indent_level + level || 0; | |||
| if (level < 1) { | |||
| return ''; | |||
| } | |||
| return Array(level + 1).join(this.indent_string); | |||
| }; | |||
| this.is_unformatted = function(tag_check, unformatted) { | |||
| //is this an HTML5 block-level link? | |||
| if (!this.Utils.in_array(tag_check, unformatted)){ | |||
| return false; | |||
| } | |||
| if (tag_check.toLowerCase() !== 'a' || !this.Utils.in_array('a', unformatted)){ | |||
| return true; | |||
| } | |||
| //at this point we have an tag; is its first child something we want to remain | |||
| //unformatted? | |||
| var next_tag = this.get_tag(true /* peek. */); | |||
| // tets next_tag to see if it is just html tag (no external content) | |||
| var tag = (next_tag || "").match(/^\s*<\s*\/?([a-z]*)\s*[^>]*>\s*$/); | |||
| // if next_tag comes back but is not an isolated tag, then | |||
| // let's treat the 'a' tag as having content | |||
| // and respect the unformatted option | |||
| if (!tag || this.Utils.in_array(tag, unformatted)){ | |||
| return true; | |||
| } else { | |||
| return false; | |||
| } | |||
| }; | |||
| this.printer = function (js_source, indent_character, indent_size, max_char, brace_style) { //handles input/output and some other printing functions | |||
| this.input = js_source || ''; //gets the input for the Parser | |||
| this.output = []; | |||
| this.indent_character = indent_character; | |||
| this.indent_string = ''; | |||
| this.indent_size = indent_size; | |||
| this.brace_style = brace_style; | |||
| this.indent_level = 0; | |||
| this.max_char = max_char; | |||
| this.line_char_count = 0; //count to see if max_char was exceeded | |||
| for (var i=0; i<this.indent_size; i++) { | |||
| this.indent_string += this.indent_character; | |||
| } | |||
| this.print_newline = function (ignore, arr) { | |||
| this.line_char_count = 0; | |||
| if (!arr || !arr.length) { | |||
| return; | |||
| } | |||
| if (!ignore) { //we might want the extra line | |||
| while (this.Utils.in_array(arr[arr.length-1], this.Utils.whitespace)) { | |||
| arr.pop(); | |||
| } | |||
| } | |||
| arr.push('\n'); | |||
| for (var i=0; i<this.indent_level; i++) { | |||
| arr.push(this.indent_string); | |||
| } | |||
| }; | |||
| this.print_token = function (text) { | |||
| this.output.push(text); | |||
| }; | |||
| this.indent = function () { | |||
| this.indent_level++; | |||
| }; | |||
| this.unindent = function () { | |||
| if (this.indent_level > 0) { | |||
| this.indent_level--; | |||
| } | |||
| }; | |||
| }; | |||
| return this; | |||
| } | |||
| /*_____________________--------------------_____________________*/ | |||
| multi_parser = new Parser(); //wrapping functions Parser | |||
| multi_parser.printer(html_source, indent_character, indent_size, max_char, brace_style); //initialize starting values | |||
| while (true) { | |||
| var t = multi_parser.get_token(); | |||
| multi_parser.token_text = t[0]; | |||
| multi_parser.token_type = t[1]; | |||
| if (multi_parser.token_type === 'TK_EOF') { | |||
| break; | |||
| } | |||
| switch (multi_parser.token_type) { | |||
| case 'TK_TAG_START': | |||
| multi_parser.print_newline(false, multi_parser.output); | |||
| multi_parser.print_token(multi_parser.token_text); | |||
| multi_parser.indent(); | |||
| multi_parser.current_mode = 'CONTENT'; | |||
| break; | |||
| case 'TK_TAG_STYLE': | |||
| case 'TK_TAG_SCRIPT': | |||
| multi_parser.print_newline(false, multi_parser.output); | |||
| multi_parser.print_token(multi_parser.token_text); | |||
| multi_parser.current_mode = 'CONTENT'; | |||
| break; | |||
| case 'TK_TAG_END': | |||
| //Print new line only if the tag has no content and has child | |||
| if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') { | |||
| var tag_name = multi_parser.token_text.match(/\w+/)[0]; | |||
| var tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length -1].match(/<\s*(\w+)/); | |||
| if (tag_extracted_from_last_output === null || tag_extracted_from_last_output[1] !== tag_name) { | |||
| multi_parser.print_newline(true, multi_parser.output); | |||
| } | |||
| } | |||
| multi_parser.print_token(multi_parser.token_text); | |||
| multi_parser.current_mode = 'CONTENT'; | |||
| break; | |||
| case 'TK_TAG_SINGLE': | |||
| // Don't add a newline before elements that should remain unformatted. | |||
| var tag_check = multi_parser.token_text.match(/^\s*<([a-z]+)/i); | |||
| if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)){ | |||
| multi_parser.print_newline(false, multi_parser.output); | |||
| } | |||
| multi_parser.print_token(multi_parser.token_text); | |||
| multi_parser.current_mode = 'CONTENT'; | |||
| break; | |||
| case 'TK_CONTENT': | |||
| if (multi_parser.token_text !== '') { | |||
| multi_parser.print_token(multi_parser.token_text); | |||
| } | |||
| multi_parser.current_mode = 'TAG'; | |||
| break; | |||
| case 'TK_STYLE': | |||
| case 'TK_SCRIPT': | |||
| if (multi_parser.token_text !== '') { | |||
| multi_parser.output.push('\n'); | |||
| var text = multi_parser.token_text, | |||
| _beautifier, | |||
| script_indent_level = 1; | |||
| if (multi_parser.token_type === 'TK_SCRIPT') { | |||
| _beautifier = typeof js_beautify === 'function' && js_beautify; | |||
| } else if (multi_parser.token_type === 'TK_STYLE') { | |||
| _beautifier = typeof css_beautify === 'function' && css_beautify; | |||
| } | |||
| if (options.indent_scripts === "keep") { | |||
| script_indent_level = 0; | |||
| } else if (options.indent_scripts === "separate") { | |||
| script_indent_level = -multi_parser.indent_level; | |||
| } | |||
| var indentation = multi_parser.get_full_indent(script_indent_level); | |||
| if (_beautifier) { | |||
| // call the Beautifier if avaliable | |||
| text = _beautifier(text.replace(/^\s*/, indentation), options); | |||
| } else { | |||
| // simply indent the string otherwise | |||
| var white = text.match(/^\s*/)[0]; | |||
| var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1; | |||
| var reindent = multi_parser.get_full_indent(script_indent_level -_level); | |||
| text = text.replace(/^\s*/, indentation) | |||
| .replace(/\r\n|\r|\n/g, '\n' + reindent) | |||
| .replace(/\s*$/, ''); | |||
| } | |||
| if (text) { | |||
| multi_parser.print_token(text); | |||
| multi_parser.print_newline(true, multi_parser.output); | |||
| } | |||
| } | |||
| multi_parser.current_mode = 'TAG'; | |||
| break; | |||
| } | |||
| multi_parser.last_token = multi_parser.token_type; | |||
| multi_parser.last_text = multi_parser.token_text; | |||
| } | |||
| return multi_parser.output.join(''); | |||
| } | |||
| // If we're running a web page and don't have either of the above, add our one global | |||
| window.html_beautify = function(html_source, options) { | |||
| return style_html(html_source, options, window.js_beautify, window.css_beautify); | |||
| }; | |||
| }()); | |||
| @@ -0,0 +1,620 @@ | |||
| /*! | |||
| * jQuery blockUI plugin | |||
| * Version 2.70.0-2014.11.23 | |||
| * Requires jQuery v1.7 or later | |||
| * | |||
| * Examples at: http://malsup.com/jquery/block/ | |||
| * Copyright (c) 2007-2013 M. Alsup | |||
| * Dual licensed under the MIT and GPL licenses: | |||
| * http://www.opensource.org/licenses/mit-license.php | |||
| * http://www.gnu.org/licenses/gpl.html | |||
| * | |||
| * Thanks to Amir-Hossein Sobhi for some excellent contributions! | |||
| */ | |||
| ;(function() { | |||
| /*jshint eqeqeq:false curly:false latedef:false */ | |||
| "use strict"; | |||
| function setup($) { | |||
| $.fn._fadeIn = $.fn.fadeIn; | |||
| var noOp = $.noop || function() {}; | |||
| // this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle | |||
| // confusing userAgent strings on Vista) | |||
| var msie = /MSIE/.test(navigator.userAgent); | |||
| var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent); | |||
| var mode = document.documentMode || 0; | |||
| var setExpr = $.isFunction( document.createElement('div').style.setExpression ); | |||
| // global $ methods for blocking/unblocking the entire page | |||
| $.blockUI = function(opts) { install(window, opts); }; | |||
| $.unblockUI = function(opts) { remove(window, opts); }; | |||
| // convenience method for quick growl-like notifications (http://www.google.com/search?q=growl) | |||
| $.growlUI = function(title, message, timeout, onClose) { | |||
| var $m = $('<div class="growlUI"></div>'); | |||
| if (title) $m.append('<h1>'+title+'</h1>'); | |||
| if (message) $m.append('<h2>'+message+'</h2>'); | |||
| if (timeout === undefined) timeout = 3000; | |||
| // Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications | |||
| var callBlock = function(opts) { | |||
| opts = opts || {}; | |||
| $.blockUI({ | |||
| message: $m, | |||
| fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700, | |||
| fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000, | |||
| timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout, | |||
| centerY: false, | |||
| showOverlay: false, | |||
| onUnblock: onClose, | |||
| css: $.blockUI.defaults.growlCSS | |||
| }); | |||
| }; | |||
| callBlock(); | |||
| var nonmousedOpacity = $m.css('opacity'); | |||
| $m.mouseover(function() { | |||
| callBlock({ | |||
| fadeIn: 0, | |||
| timeout: 30000 | |||
| }); | |||
| var displayBlock = $('.blockMsg'); | |||
| displayBlock.stop(); // cancel fadeout if it has started | |||
| displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency | |||
| }).mouseout(function() { | |||
| $('.blockMsg').fadeOut(1000); | |||
| }); | |||
| // End konapun additions | |||
| }; | |||
| // plugin method for blocking element content | |||
| $.fn.block = function(opts) { | |||
| if ( this[0] === window ) { | |||
| $.blockUI( opts ); | |||
| return this; | |||
| } | |||
| var fullOpts = $.extend({}, $.blockUI.defaults, opts || {}); | |||
| this.each(function() { | |||
| var $el = $(this); | |||
| if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked')) | |||
| return; | |||
| $el.unblock({ fadeOut: 0 }); | |||
| }); | |||
| return this.each(function() { | |||
| if ($.css(this,'position') == 'static') { | |||
| this.style.position = 'relative'; | |||
| $(this).data('blockUI.static', true); | |||
| } | |||
| this.style.zoom = 1; // force 'hasLayout' in ie | |||
| install(this, opts); | |||
| }); | |||
| }; | |||
| // plugin method for unblocking element content | |||
| $.fn.unblock = function(opts) { | |||
| if ( this[0] === window ) { | |||
| $.unblockUI( opts ); | |||
| return this; | |||
| } | |||
| return this.each(function() { | |||
| remove(this, opts); | |||
| }); | |||
| }; | |||
| $.blockUI.version = 2.70; // 2nd generation blocking at no extra cost! | |||
| // override these in your code to change the default behavior and style | |||
| $.blockUI.defaults = { | |||
| // message displayed when blocking (use null for no message) | |||
| message: '<div class="loaderbox"><div class="loading-activity"></div> 加载中......</div>', | |||
| title: null, // title string; only used when theme == true | |||
| draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded) | |||
| theme: false, // set to true to use with jQuery UI themes | |||
| // styles for the message when blocking; if you wish to disable | |||
| // these and use an external stylesheet then do this in your code: | |||
| // $.blockUI.defaults.css = {}; | |||
| css: { | |||
| padding: 0, | |||
| margin: 0, | |||
| width: '30%', | |||
| top: '40%', | |||
| left: '35%', | |||
| textAlign: 'center', | |||
| color: '#000', | |||
| border: '0px', | |||
| backgroundColor:'transparent', | |||
| cursor: 'wait' | |||
| }, | |||
| // minimal style set used when themes are used | |||
| themedCSS: { | |||
| width: '30%', | |||
| top: '40%', | |||
| left: '35%' | |||
| }, | |||
| // styles for the overlay | |||
| overlayCSS: { | |||
| backgroundColor: '#000', | |||
| opacity: 0.6, | |||
| cursor: 'wait' | |||
| }, | |||
| // style to replace wait cursor before unblocking to correct issue | |||
| // of lingering wait cursor | |||
| cursorReset: 'default', | |||
| // styles applied when using $.growlUI | |||
| growlCSS: { | |||
| width: '350px', | |||
| top: '10px', | |||
| left: '', | |||
| right: '10px', | |||
| border: 'none', | |||
| padding: '5px', | |||
| opacity: 0.6, | |||
| cursor: 'default', | |||
| color: '#fff', | |||
| backgroundColor: '#000', | |||
| '-webkit-border-radius':'10px', | |||
| '-moz-border-radius': '10px', | |||
| 'border-radius': '10px' | |||
| }, | |||
| // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w | |||
| // (hat tip to Jorge H. N. de Vasconcelos) | |||
| /*jshint scripturl:true */ | |||
| iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank', | |||
| // force usage of iframe in non-IE browsers (handy for blocking applets) | |||
| forceIframe: false, | |||
| // z-index for the blocking overlay | |||
| baseZ: 1000, | |||
| // set these to true to have the message automatically centered | |||
| centerX: true, // <-- only effects element blocking (page block controlled via css above) | |||
| centerY: true, | |||
| // allow body element to be stetched in ie6; this makes blocking look better | |||
| // on "short" pages. disable if you wish to prevent changes to the body height | |||
| allowBodyStretch: true, | |||
| // enable if you want key and mouse events to be disabled for content that is blocked | |||
| bindEvents: true, | |||
| // be default blockUI will supress tab navigation from leaving blocking content | |||
| // (if bindEvents is true) | |||
| constrainTabKey: true, | |||
| // fadeIn time in millis; set to 0 to disable fadeIn on block | |||
| fadeIn: 200, | |||
| // fadeOut time in millis; set to 0 to disable fadeOut on unblock | |||
| fadeOut: 400, | |||
| // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock | |||
| timeout: 0, | |||
| // disable if you don't want to show the overlay | |||
| showOverlay: true, | |||
| // if true, focus will be placed in the first available input field when | |||
| // page blocking | |||
| focusInput: true, | |||
| // elements that can receive focus | |||
| focusableElements: ':input:enabled:visible', | |||
| // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity) | |||
| // no longer needed in 2012 | |||
| // applyPlatformOpacityRules: true, | |||
| // callback method invoked when fadeIn has completed and blocking message is visible | |||
| onBlock: null, | |||
| // callback method invoked when unblocking has completed; the callback is | |||
| // passed the element that has been unblocked (which is the window object for page | |||
| // blocks) and the options that were passed to the unblock call: | |||
| // onUnblock(element, options) | |||
| onUnblock: null, | |||
| // callback method invoked when the overlay area is clicked. | |||
| // setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used. | |||
| onOverlayClick: null, | |||
| // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493 | |||
| quirksmodeOffsetHack: 4, | |||
| // class name of the message block | |||
| blockMsgClass: 'blockMsg', | |||
| // if it is already blocked, then ignore it (don't unblock and reblock) | |||
| ignoreIfBlocked: false | |||
| }; | |||
| // private data and functions follow... | |||
| var pageBlock = null; | |||
| var pageBlockEls = []; | |||
| function install(el, opts) { | |||
| var css, themedCSS; | |||
| var full = (el == window); | |||
| var msg = (opts && opts.message !== undefined ? opts.message : undefined); | |||
| opts = $.extend({}, $.blockUI.defaults, opts || {}); | |||
| if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked')) | |||
| return; | |||
| opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {}); | |||
| css = $.extend({}, $.blockUI.defaults.css, opts.css || {}); | |||
| if (opts.onOverlayClick) | |||
| opts.overlayCSS.cursor = 'pointer'; | |||
| themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {}); | |||
| msg = msg === undefined ? opts.message : msg; | |||
| // remove the current block (if there is one) | |||
| if (full && pageBlock) | |||
| remove(window, {fadeOut:0}); | |||
| // if an existing element is being used as the blocking content then we capture | |||
| // its current place in the DOM (and current display style) so we can restore | |||
| // it when we unblock | |||
| if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) { | |||
| var node = msg.jquery ? msg[0] : msg; | |||
| var data = {}; | |||
| $(el).data('blockUI.history', data); | |||
| data.el = node; | |||
| data.parent = node.parentNode; | |||
| data.display = node.style.display; | |||
| data.position = node.style.position; | |||
| if (data.parent) | |||
| data.parent.removeChild(node); | |||
| } | |||
| $(el).data('blockUI.onUnblock', opts.onUnblock); | |||
| var z = opts.baseZ; | |||
| // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform; | |||
| // layer1 is the iframe layer which is used to supress bleed through of underlying content | |||
| // layer2 is the overlay layer which has opacity and a wait cursor (by default) | |||
| // layer3 is the message content that is displayed while blocking | |||
| var lyr1, lyr2, lyr3, s; | |||
| if (msie || opts.forceIframe) | |||
| lyr1 = $('<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>'); | |||
| else | |||
| lyr1 = $('<div class="blockUI" style="display:none"></div>'); | |||
| if (opts.theme) | |||
| lyr2 = $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>'); | |||
| else | |||
| lyr2 = $('<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>'); | |||
| if (opts.theme && full) { | |||
| s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">'; | |||
| if ( opts.title ) { | |||
| s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || ' ')+'</div>'; | |||
| } | |||
| s += '<div class="ui-widget-content ui-dialog-content"></div>'; | |||
| s += '</div>'; | |||
| } | |||
| else if (opts.theme) { | |||
| s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">'; | |||
| if ( opts.title ) { | |||
| s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || ' ')+'</div>'; | |||
| } | |||
| s += '<div class="ui-widget-content ui-dialog-content"></div>'; | |||
| s += '</div>'; | |||
| } | |||
| else if (full) { | |||
| s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>'; | |||
| } | |||
| else { | |||
| s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>'; | |||
| } | |||
| lyr3 = $(s); | |||
| // if we have a message, style it | |||
| if (msg) { | |||
| if (opts.theme) { | |||
| lyr3.css(themedCSS); | |||
| lyr3.addClass('ui-widget-content'); | |||
| } | |||
| else | |||
| lyr3.css(css); | |||
| } | |||
| // style the overlay | |||
| if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/) | |||
| lyr2.css(opts.overlayCSS); | |||
| lyr2.css('position', full ? 'fixed' : 'absolute'); | |||
| // make iframe layer transparent in IE | |||
| if (msie || opts.forceIframe) | |||
| lyr1.css('opacity',0.0); | |||
| //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el); | |||
| var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el); | |||
| $.each(layers, function() { | |||
| this.appendTo($par); | |||
| }); | |||
| if (opts.theme && opts.draggable && $.fn.draggable) { | |||
| lyr3.draggable({ | |||
| handle: '.ui-dialog-titlebar', | |||
| cancel: 'li' | |||
| }); | |||
| } | |||
| // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling) | |||
| var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0); | |||
| if (ie6 || expr) { | |||
| // give body 100% height | |||
| if (full && opts.allowBodyStretch && $.support.boxModel) | |||
| $('html,body').css('height','100%'); | |||
| // fix ie6 issue when blocked element has a border width | |||
| if ((ie6 || !$.support.boxModel) && !full) { | |||
| var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth'); | |||
| var fixT = t ? '(0 - '+t+')' : 0; | |||
| var fixL = l ? '(0 - '+l+')' : 0; | |||
| } | |||
| // simulate fixed position | |||
| $.each(layers, function(i,o) { | |||
| var s = o[0].style; | |||
| s.position = 'absolute'; | |||
| if (i < 2) { | |||
| if (full) | |||
| s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"'); | |||
| else | |||
| s.setExpression('height','this.parentNode.offsetHeight + "px"'); | |||
| if (full) | |||
| s.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"'); | |||
| else | |||
| s.setExpression('width','this.parentNode.offsetWidth + "px"'); | |||
| if (fixL) s.setExpression('left', fixL); | |||
| if (fixT) s.setExpression('top', fixT); | |||
| } | |||
| else if (opts.centerY) { | |||
| if (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"'); | |||
| s.marginTop = 0; | |||
| } | |||
| else if (!opts.centerY && full) { | |||
| var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0; | |||
| var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"'; | |||
| s.setExpression('top',expression); | |||
| } | |||
| }); | |||
| } | |||
| // show the message | |||
| if (msg) { | |||
| if (opts.theme) | |||
| lyr3.find('.ui-widget-content').append(msg); | |||
| else | |||
| lyr3.append(msg); | |||
| if (msg.jquery || msg.nodeType) | |||
| $(msg).show(); | |||
| } | |||
| if ((msie || opts.forceIframe) && opts.showOverlay) | |||
| lyr1.show(); // opacity is zero | |||
| if (opts.fadeIn) { | |||
| var cb = opts.onBlock ? opts.onBlock : noOp; | |||
| var cb1 = (opts.showOverlay && !msg) ? cb : noOp; | |||
| var cb2 = msg ? cb : noOp; | |||
| if (opts.showOverlay) | |||
| lyr2._fadeIn(opts.fadeIn, cb1); | |||
| if (msg) | |||
| lyr3._fadeIn(opts.fadeIn, cb2); | |||
| } | |||
| else { | |||
| if (opts.showOverlay) | |||
| lyr2.show(); | |||
| if (msg) | |||
| lyr3.show(); | |||
| if (opts.onBlock) | |||
| opts.onBlock.bind(lyr3)(); | |||
| } | |||
| // bind key and mouse events | |||
| bind(1, el, opts); | |||
| if (full) { | |||
| pageBlock = lyr3[0]; | |||
| pageBlockEls = $(opts.focusableElements,pageBlock); | |||
| if (opts.focusInput) | |||
| setTimeout(focus, 20); | |||
| } | |||
| else | |||
| center(lyr3[0], opts.centerX, opts.centerY); | |||
| if (opts.timeout) { | |||
| // auto-unblock | |||
| var to = setTimeout(function() { | |||
| if (full) | |||
| $.unblockUI(opts); | |||
| else | |||
| $(el).unblock(opts); | |||
| }, opts.timeout); | |||
| $(el).data('blockUI.timeout', to); | |||
| } | |||
| } | |||
| // remove the block | |||
| function remove(el, opts) { | |||
| var count; | |||
| var full = (el == window); | |||
| var $el = $(el); | |||
| var data = $el.data('blockUI.history'); | |||
| var to = $el.data('blockUI.timeout'); | |||
| if (to) { | |||
| clearTimeout(to); | |||
| $el.removeData('blockUI.timeout'); | |||
| } | |||
| opts = $.extend({}, $.blockUI.defaults, opts || {}); | |||
| bind(0, el, opts); // unbind events | |||
| if (opts.onUnblock === null) { | |||
| opts.onUnblock = $el.data('blockUI.onUnblock'); | |||
| $el.removeData('blockUI.onUnblock'); | |||
| } | |||
| var els; | |||
| if (full) // crazy selector to handle odd field errors in ie6/7 | |||
| els = $('body').children().filter('.blockUI').add('body > .blockUI'); | |||
| else | |||
| els = $el.find('>.blockUI'); | |||
| // fix cursor issue | |||
| if ( opts.cursorReset ) { | |||
| if ( els.length > 1 ) | |||
| els[1].style.cursor = opts.cursorReset; | |||
| if ( els.length > 2 ) | |||
| els[2].style.cursor = opts.cursorReset; | |||
| } | |||
| if (full) | |||
| pageBlock = pageBlockEls = null; | |||
| if (opts.fadeOut) { | |||
| count = els.length; | |||
| els.stop().fadeOut(opts.fadeOut, function() { | |||
| if ( --count === 0) | |||
| reset(els,data,opts,el); | |||
| }); | |||
| } | |||
| else | |||
| reset(els, data, opts, el); | |||
| } | |||
| // move blocking element back into the DOM where it started | |||
| function reset(els,data,opts,el) { | |||
| var $el = $(el); | |||
| if ( $el.data('blockUI.isBlocked') ) | |||
| return; | |||
| els.each(function(i,o) { | |||
| // remove via DOM calls so we don't lose event handlers | |||
| if (this.parentNode) | |||
| this.parentNode.removeChild(this); | |||
| }); | |||
| if (data && data.el) { | |||
| data.el.style.display = data.display; | |||
| data.el.style.position = data.position; | |||
| data.el.style.cursor = 'default'; // #59 | |||
| if (data.parent) | |||
| data.parent.appendChild(data.el); | |||
| $el.removeData('blockUI.history'); | |||
| } | |||
| if ($el.data('blockUI.static')) { | |||
| $el.css('position', 'static'); // #22 | |||
| } | |||
| if (typeof opts.onUnblock == 'function') | |||
| opts.onUnblock(el,opts); | |||
| // fix issue in Safari 6 where block artifacts remain until reflow | |||
| var body = $(document.body), w = body.width(), cssW = body[0].style.width; | |||
| body.width(w-1).width(w); | |||
| body[0].style.width = cssW; | |||
| } | |||
| // bind/unbind the handler | |||
| function bind(b, el, opts) { | |||
| var full = el == window, $el = $(el); | |||
| // don't bother unbinding if there is nothing to unbind | |||
| if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked'))) | |||
| return; | |||
| $el.data('blockUI.isBlocked', b); | |||
| // don't bind events when overlay is not in use or if bindEvents is false | |||
| if (!full || !opts.bindEvents || (b && !opts.showOverlay)) | |||
| return; | |||
| // bind anchors and inputs for mouse and key events | |||
| var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove'; | |||
| if (b) | |||
| $(document).bind(events, opts, handler); | |||
| else | |||
| $(document).unbind(events, handler); | |||
| // former impl... | |||
| // var $e = $('a,:input'); | |||
| // b ? $e.bind(events, opts, handler) : $e.unbind(events, handler); | |||
| } | |||
| // event handler to suppress keyboard/mouse events when blocking | |||
| function handler(e) { | |||
| // allow tab navigation (conditionally) | |||
| if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) { | |||
| if (pageBlock && e.data.constrainTabKey) { | |||
| var els = pageBlockEls; | |||
| var fwd = !e.shiftKey && e.target === els[els.length-1]; | |||
| var back = e.shiftKey && e.target === els[0]; | |||
| if (fwd || back) { | |||
| setTimeout(function(){focus(back);},10); | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| var opts = e.data; | |||
| var target = $(e.target); | |||
| if (target.hasClass('blockOverlay') && opts.onOverlayClick) | |||
| opts.onOverlayClick(e); | |||
| // allow events within the message content | |||
| if (target.parents('div.' + opts.blockMsgClass).length > 0) | |||
| return true; | |||
| // allow events for content that is not being blocked | |||
| return target.parents().children().filter('div.blockUI').length === 0; | |||
| } | |||
| function focus(back) { | |||
| if (!pageBlockEls) | |||
| return; | |||
| var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0]; | |||
| if (e) | |||
| e.focus(); | |||
| } | |||
| function center(el, x, y) { | |||
| var p = el.parentNode, s = el.style; | |||
| var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth'); | |||
| var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth'); | |||
| if (x) s.left = l > 0 ? (l+'px') : '0'; | |||
| if (y) s.top = t > 0 ? (t+'px') : '0'; | |||
| } | |||
| function sz(el, p) { | |||
| return parseInt($.css(el,p),10)||0; | |||
| } | |||
| } | |||
| /*global define:true */ | |||
| if (typeof define === 'function' && define.amd && define.amd.jQuery) { | |||
| define(['jquery'], setup); | |||
| } else { | |||
| setup(jQuery); | |||
| } | |||
| })(); | |||
| @@ -0,0 +1,688 @@ | |||
| /*! | |||
| * bootstrap-fileinput v5.5.2 | |||
| * http://plugins.krajee.com/file-input | |||
| * | |||
| * Krajee default styling for bootstrap-fileinput. | |||
| * | |||
| * Author: Kartik Visweswaran | |||
| * Copyright: 2014 - 2022, Kartik Visweswaran, Krajee.com | |||
| * | |||
| * Licensed under the BSD-3-Clause | |||
| * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md | |||
| */ | |||
| .file-loading input[type=file], | |||
| input[type=file].file-loading { | |||
| width: 0; | |||
| height: 0; | |||
| } | |||
| .file-no-browse { | |||
| position: absolute; | |||
| left: 50%; | |||
| bottom: 20%; | |||
| width: 1px; | |||
| height: 1px; | |||
| font-size: 0; | |||
| opacity: 0; | |||
| border: none; | |||
| background: none; | |||
| outline: none; | |||
| box-shadow: none; | |||
| } | |||
| .kv-hidden, | |||
| .file-caption-icon, | |||
| .file-zoom-dialog .modal-header:before, | |||
| .file-zoom-dialog .modal-header:after, | |||
| .file-input-new .file-preview, | |||
| .file-input-new .close, | |||
| .file-input-new .glyphicon-file, | |||
| .file-input-new .fileinput-remove-button, | |||
| .file-input-new .fileinput-upload-button, | |||
| .file-input-new .no-browse .input-group-btn, | |||
| .file-input-ajax-new .fileinput-remove-button, | |||
| .file-input-ajax-new .fileinput-upload-button, | |||
| .file-input-ajax-new .no-browse .input-group-btn, | |||
| .hide-content .kv-file-content, | |||
| .is-locked .fileinput-upload-button, | |||
| .is-locked .fileinput-remove-button { | |||
| display: none; | |||
| } | |||
| .file-caption .input-group { | |||
| align-items: center; | |||
| } | |||
| .btn-file input[type=file], | |||
| .file-caption-icon, | |||
| .file-preview .fileinput-remove, | |||
| .krajee-default .file-thumb-progress, | |||
| .file-zoom-dialog .btn-navigate, | |||
| .file-zoom-dialog .floating-buttons { | |||
| position: absolute; | |||
| } | |||
| .file-caption-icon .kv-caption-icon { | |||
| line-height: inherit; | |||
| } | |||
| .file-input, | |||
| .file-loading:before, | |||
| .btn-file, | |||
| .file-caption, | |||
| .file-preview, | |||
| .krajee-default.file-preview-frame, | |||
| .krajee-default .file-thumbnail-footer, | |||
| .file-zoom-dialog .modal-dialog { | |||
| position: relative; | |||
| } | |||
| .file-error-message pre, | |||
| .file-error-message ul, | |||
| .krajee-default .file-actions, | |||
| .krajee-default .file-other-error { | |||
| text-align: left; | |||
| } | |||
| .file-error-message pre, | |||
| .file-error-message ul { | |||
| margin: 0; | |||
| } | |||
| .krajee-default .file-drag-handle, | |||
| .krajee-default .file-upload-indicator { | |||
| float: left; | |||
| margin-top: 10px; | |||
| width: 16px; | |||
| height: 16px; | |||
| } | |||
| .file-thumb-progress .progress, | |||
| .file-thumb-progress .progress-bar { | |||
| font-family: Verdana, Helvetica, sans-serif; | |||
| font-size: 0.7rem; | |||
| } | |||
| .krajee-default .file-thumb-progress .progress, | |||
| .kv-upload-progress .progress { | |||
| background-color: #ccc; | |||
| } | |||
| .krajee-default .file-caption-info, | |||
| .krajee-default .file-size-info { | |||
| display: block; | |||
| white-space: nowrap; | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| width: 160px; | |||
| height: 15px; | |||
| margin: auto; | |||
| } | |||
| .file-zoom-content > .file-object.type-video, | |||
| .file-zoom-content > .file-object.type-flash, | |||
| .file-zoom-content > .file-object.type-image { | |||
| max-width: 100%; | |||
| max-height: 100%; | |||
| width: auto; | |||
| } | |||
| .file-zoom-content > .file-object.type-video, | |||
| .file-zoom-content > .file-object.type-flash { | |||
| height: 100%; | |||
| } | |||
| .file-zoom-content > .file-object.type-pdf, | |||
| .file-zoom-content > .file-object.type-html, | |||
| .file-zoom-content > .file-object.type-text, | |||
| .file-zoom-content > .file-object.type-default { | |||
| width: 100%; | |||
| } | |||
| .file-loading:before { | |||
| content: " Loading..."; | |||
| display: inline-block; | |||
| padding-left: 20px; | |||
| line-height: 16px; | |||
| font-size: 13px; | |||
| font-variant: small-caps; | |||
| color: #999; | |||
| background: transparent url(loading.gif) top left no-repeat; | |||
| } | |||
| .file-object { | |||
| margin: 0 0 -5px 0; | |||
| padding: 0; | |||
| } | |||
| .btn-file { | |||
| overflow: hidden; | |||
| } | |||
| .btn-file input[type=file] { | |||
| top: 0; | |||
| left: 0; | |||
| min-width: 100%; | |||
| min-height: 100%; | |||
| text-align: right; | |||
| opacity: 0; | |||
| background: none repeat scroll 0 0 transparent; | |||
| cursor: inherit; | |||
| display: block; | |||
| } | |||
| .btn-file ::-ms-browse { | |||
| font-size: 10000px; | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| .file-caption.icon-visible .file-caption-icon { | |||
| display: inline-block; | |||
| } | |||
| .file-caption.icon-visible .file-caption-name { | |||
| padding-left: 25px; | |||
| } | |||
| .file-caption.icon-visible > .input-group-lg .file-caption-name { | |||
| padding-left: 30px; | |||
| } | |||
| .file-caption.icon-visible > .input-group-sm .file-caption-name { | |||
| padding-left: 22px; | |||
| } | |||
| .file-caption-name:not(.file-caption-disabled) { | |||
| background-color: transparent; | |||
| } | |||
| .file-caption-name.file-processing { | |||
| font-style: italic; | |||
| border-color: #bbb; | |||
| opacity: 0.5; | |||
| } | |||
| .file-caption-icon { | |||
| padding: 7px 5px; | |||
| left: 4px; | |||
| } | |||
| .input-group-lg .file-caption-icon { | |||
| font-size: 1.25rem; | |||
| } | |||
| .input-group-sm .file-caption-icon { | |||
| font-size: 0.875rem; | |||
| padding: 0.25rem; | |||
| } | |||
| .file-error-message { | |||
| color: #a94442; | |||
| background-color: #f2dede; | |||
| margin: 5px; | |||
| border: 1px solid #ebccd1; | |||
| border-radius: 4px; | |||
| padding: 15px; | |||
| } | |||
| .file-error-message pre { | |||
| margin: 5px 0; | |||
| } | |||
| .file-caption-disabled { | |||
| background-color: #eee; | |||
| cursor: not-allowed; | |||
| opacity: 1; | |||
| } | |||
| .file-preview { | |||
| border-radius: 5px; | |||
| border: 1px solid #ddd; | |||
| padding: 8px; | |||
| width: 100%; | |||
| margin-bottom: 5px; | |||
| } | |||
| .file-preview .btn-xs { | |||
| padding: 1px 5px; | |||
| font-size: 12px; | |||
| line-height: 1.5; | |||
| border-radius: 3px; | |||
| } | |||
| .file-preview .fileinput-remove { | |||
| top: 1px; | |||
| right: 1px; | |||
| line-height: 10px; | |||
| } | |||
| .file-preview .clickable { | |||
| cursor: pointer; | |||
| } | |||
| .file-preview-image { | |||
| font: 40px Impact, Charcoal, sans-serif; | |||
| color: #008000; | |||
| width: auto; | |||
| height: auto; | |||
| max-width: 100%; | |||
| max-height: 100%; | |||
| } | |||
| .krajee-default.file-preview-frame { | |||
| margin: 8px; | |||
| border: 1px solid rgba(0, 0, 0, 0.2); | |||
| box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.2); | |||
| padding: 6px; | |||
| float: left; | |||
| text-align: center; | |||
| } | |||
| .krajee-default.file-preview-frame .kv-file-content { | |||
| width: 213px; | |||
| height: 160px; | |||
| } | |||
| .krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered { | |||
| width: 400px; | |||
| } | |||
| .krajee-default.file-preview-frame[data-template="audio"] .kv-file-content { | |||
| width: 240px; | |||
| height: 55px; | |||
| } | |||
| .krajee-default.file-preview-frame .file-thumbnail-footer { | |||
| height: 70px; | |||
| } | |||
| .krajee-default.file-preview-frame:not(.file-preview-error):hover { | |||
| border: 1px solid rgba(0, 0, 0, 0.3); | |||
| box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.4); | |||
| } | |||
| .krajee-default .file-preview-text { | |||
| color: #428bca; | |||
| border: 1px solid #ddd; | |||
| outline: none; | |||
| resize: none; | |||
| } | |||
| .krajee-default .file-preview-html { | |||
| border: 1px solid #ddd; | |||
| } | |||
| .krajee-default .file-other-icon { | |||
| font-size: 6em; | |||
| line-height: 1; | |||
| } | |||
| .krajee-default .file-footer-buttons { | |||
| float: right; | |||
| } | |||
| .krajee-default .file-footer-caption { | |||
| display: block; | |||
| text-align: center; | |||
| padding-top: 4px; | |||
| font-size: 11px; | |||
| color: #999; | |||
| margin-bottom: 30px; | |||
| } | |||
| .file-upload-stats { | |||
| font-size: 10px; | |||
| text-align: center; | |||
| width: 100%; | |||
| } | |||
| .kv-upload-progress .file-upload-stats { | |||
| font-size: 12px; | |||
| margin: -10px 0 5px; | |||
| } | |||
| .krajee-default .file-preview-error { | |||
| opacity: 0.65; | |||
| box-shadow: none; | |||
| } | |||
| .krajee-default .file-thumb-progress { | |||
| top: 37px; | |||
| left: 0; | |||
| right: 0; | |||
| } | |||
| .krajee-default.kvsortable-ghost { | |||
| background: #e1edf7; | |||
| border: 2px solid #a1abff; | |||
| } | |||
| .krajee-default .file-preview-other:hover { | |||
| opacity: 0.8; | |||
| } | |||
| .krajee-default .file-preview-frame:not(.file-preview-error) .file-footer-caption:hover { | |||
| color: #000; | |||
| } | |||
| .kv-upload-progress .progress { | |||
| height: 20px; | |||
| margin: 10px 0; | |||
| overflow: hidden; | |||
| } | |||
| .kv-upload-progress .progress-bar { | |||
| height: 20px; | |||
| font-family: Verdana, Helvetica, sans-serif; | |||
| } | |||
| /*noinspection CssOverwrittenProperties*/ | |||
| .file-zoom-dialog .file-other-icon { | |||
| font-size: 22em; | |||
| font-size: 50vmin; | |||
| } | |||
| .file-zoom-dialog .modal-dialog { | |||
| width: auto; | |||
| } | |||
| .file-zoom-dialog .modal-header { | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: space-between; | |||
| } | |||
| .file-zoom-dialog .btn-navigate { | |||
| margin: 0 0.1rem; | |||
| padding: 0; | |||
| font-size: 1.2rem; | |||
| width: 2.4rem; | |||
| height: 2.4rem; | |||
| top: 50%; | |||
| border-radius: 50%; | |||
| text-align: center; | |||
| } | |||
| .btn-navigate * { | |||
| width: auto; | |||
| } | |||
| .file-zoom-dialog .floating-buttons { | |||
| top: 5px; | |||
| right: 10px; | |||
| } | |||
| .file-zoom-dialog .btn-kv-prev { | |||
| left: 0; | |||
| } | |||
| .file-zoom-dialog .btn-kv-next { | |||
| right: 0; | |||
| } | |||
| .file-zoom-dialog .kv-zoom-header { | |||
| padding: 0.5rem; | |||
| } | |||
| .file-zoom-dialog .kv-zoom-body { | |||
| padding: 0.25rem; | |||
| } | |||
| .file-zoom-dialog .kv-zoom-description { | |||
| position: absolute; | |||
| opacity: 0.8; | |||
| font-size: 0.8rem; | |||
| background-color: #1a1a1a; | |||
| padding: 1rem; | |||
| text-align: center; | |||
| border-radius: 0.5rem; | |||
| color: #fff; | |||
| left: 15%; | |||
| right: 15%; | |||
| bottom: 15%; | |||
| } | |||
| .file-zoom-dialog .kv-desc-hide { | |||
| float: right; | |||
| color: #fff; | |||
| padding: 0 0.1rem; | |||
| background: none; | |||
| border: none; | |||
| } | |||
| .file-zoom-dialog .kv-desc-hide:hover { | |||
| opacity: 0.7; | |||
| } | |||
| .file-zoom-dialog .kv-desc-hide:focus { | |||
| opacity: 0.9; | |||
| } | |||
| .file-input-new .no-browse .form-control { | |||
| border-top-right-radius: 4px; | |||
| border-bottom-right-radius: 4px; | |||
| } | |||
| .file-input-ajax-new .no-browse .form-control { | |||
| border-top-right-radius: 4px; | |||
| border-bottom-right-radius: 4px; | |||
| } | |||
| .file-caption { | |||
| width: 100%; | |||
| position: relative; | |||
| } | |||
| .file-thumb-loading { | |||
| background: transparent url(loading.gif) no-repeat scroll center center content-box !important; | |||
| } | |||
| .file-drop-zone { | |||
| border: 1px dashed #aaa; | |||
| min-height: 260px; | |||
| border-radius: 4px; | |||
| text-align: center; | |||
| vertical-align: middle; | |||
| margin: 12px 15px 12px 12px; | |||
| padding: 5px; | |||
| } | |||
| .file-drop-zone.clickable:hover { | |||
| border: 2px dashed #999; | |||
| } | |||
| .file-drop-zone.clickable:focus { | |||
| border: 2px solid #5acde2; | |||
| } | |||
| .file-drop-zone .file-preview-thumbnails { | |||
| cursor: default; | |||
| } | |||
| .file-drop-zone-title { | |||
| color: #aaa; | |||
| font-size: 1.6em; | |||
| text-align: center; | |||
| padding: 85px 10px; | |||
| cursor: default; | |||
| } | |||
| .file-highlighted { | |||
| border: 2px dashed #999 !important; | |||
| background-color: #eee; | |||
| } | |||
| .file-uploading { | |||
| background: url(loading-sm.gif) no-repeat center bottom 10px; | |||
| opacity: 0.65; | |||
| } | |||
| .file-zoom-fullscreen .modal-dialog { | |||
| min-width: 100%; | |||
| margin: 0; | |||
| } | |||
| .file-zoom-fullscreen .modal-content { | |||
| border-radius: 0; | |||
| box-shadow: none; | |||
| min-height: 100vh; | |||
| } | |||
| .file-zoom-fullscreen .kv-zoom-body { | |||
| overflow-y: auto; | |||
| } | |||
| .floating-buttons { | |||
| z-index: 3000; | |||
| } | |||
| .floating-buttons .btn-kv { | |||
| margin-left: 3px; | |||
| z-index: 3000; | |||
| } | |||
| .kv-zoom-actions { | |||
| min-width: 140px; | |||
| } | |||
| .kv-zoom-actions .btn-kv { | |||
| margin-left: 3px; | |||
| } | |||
| .file-zoom-content { | |||
| text-align: center; | |||
| white-space: nowrap; | |||
| min-height: 300px; | |||
| } | |||
| .file-zoom-content:hover { | |||
| background: transparent; | |||
| } | |||
| .file-zoom-content .file-preview-image { | |||
| max-height: 100%; | |||
| } | |||
| .file-zoom-content .file-preview-video { | |||
| max-height: 100%; | |||
| } | |||
| .file-zoom-content > .file-object.type-image { | |||
| height: auto; | |||
| min-height: inherit; | |||
| } | |||
| .file-zoom-content > .file-object.type-audio { | |||
| width: auto; | |||
| height: 30px; | |||
| } | |||
| @media (min-width: 576px) { | |||
| .file-zoom-dialog .modal-dialog { | |||
| max-width: 500px; | |||
| } | |||
| } | |||
| @media (min-width: 992px) { | |||
| .file-zoom-dialog .modal-lg { | |||
| max-width: 800px; | |||
| } | |||
| } | |||
| @media (max-width: 767px) { | |||
| .file-preview-thumbnails { | |||
| display: flex; | |||
| justify-content: center; | |||
| align-items: center; | |||
| flex-direction: column; | |||
| } | |||
| .file-zoom-dialog .modal-header { | |||
| flex-direction: column; | |||
| } | |||
| } | |||
| @media (max-width: 350px) { | |||
| .krajee-default.file-preview-frame:not([data-template="audio"]) .kv-file-content { | |||
| width: 160px; | |||
| } | |||
| } | |||
| @media (max-width: 420px) { | |||
| .krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered { | |||
| width: 100%; | |||
| } | |||
| } | |||
| .file-loading[dir=rtl]:before { | |||
| background: transparent url(loading.gif) top right no-repeat; | |||
| padding-left: 0; | |||
| padding-right: 20px; | |||
| } | |||
| .clickable .file-drop-zone-title { | |||
| cursor: pointer; | |||
| } | |||
| .file-sortable .file-drag-handle:hover { | |||
| opacity: 0.7; | |||
| } | |||
| .file-sortable .file-drag-handle { | |||
| cursor: grab; | |||
| opacity: 1; | |||
| } | |||
| .file-grabbing, | |||
| .file-grabbing * { | |||
| cursor: not-allowed !important; | |||
| } | |||
| .file-grabbing .file-preview-thumbnails * { | |||
| cursor: grabbing !important; | |||
| } | |||
| .file-preview-frame.sortable-chosen { | |||
| background-color: #d9edf7; | |||
| border-color: #17a2b8; | |||
| box-shadow: none !important; | |||
| } | |||
| .file-preview .kv-zoom-cache { | |||
| display: none; | |||
| } | |||
| .file-preview-other-frame, .file-preview-object, .kv-file-content, .kv-zoom-body { | |||
| display: flex; | |||
| align-items: center; | |||
| justify-content: center; | |||
| } | |||
| .btn-kv-rotate, | |||
| .kv-file-rotate { | |||
| display: none; | |||
| } | |||
| .rotatable:not(.hide-rotate) .btn-kv-rotate, | |||
| .rotatable:not(.hide-rotate) .kv-file-rotate { | |||
| display: inline-block; | |||
| } | |||
| .rotatable .file-zoom-detail, | |||
| .rotatable .kv-file-content, | |||
| .rotatable .kv-file-content > :first-child { | |||
| transform-origin: center center; | |||
| } | |||
| .rotate-animate { | |||
| transition: transform 0.3s ease; | |||
| } | |||
| .kv-overflow-hidden { | |||
| overflow: hidden; | |||
| } | |||
| @@ -0,0 +1,459 @@ | |||
| /*! | |||
| * Bootstrap-select v1.13.18 (https://developer.snapappointments.com/bootstrap-select) | |||
| * | |||
| * Copyright 2012-2020 SnapAppointments, LLC | |||
| * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE) | |||
| */ | |||
| @-webkit-keyframes bs-notify-fadeOut { | |||
| 0% { | |||
| opacity: 0.9; | |||
| } | |||
| 100% { | |||
| opacity: 0; | |||
| } | |||
| } | |||
| @-o-keyframes bs-notify-fadeOut { | |||
| 0% { | |||
| opacity: 0.9; | |||
| } | |||
| 100% { | |||
| opacity: 0; | |||
| } | |||
| } | |||
| @keyframes bs-notify-fadeOut { | |||
| 0% { | |||
| opacity: 0.9; | |||
| } | |||
| 100% { | |||
| opacity: 0; | |||
| } | |||
| } | |||
| select.bs-select-hidden, | |||
| .bootstrap-select > select.bs-select-hidden, | |||
| select.selectpicker { | |||
| display: none !important; | |||
| } | |||
| .bootstrap-select { | |||
| width: 220px \0; | |||
| /*IE9 and below*/ | |||
| vertical-align: middle; | |||
| } | |||
| .bootstrap-select > .dropdown-toggle { | |||
| position: relative; | |||
| width: 100%; | |||
| text-align: right; | |||
| white-space: nowrap; | |||
| display: -webkit-inline-box; | |||
| display: -webkit-inline-flex; | |||
| display: -ms-inline-flexbox; | |||
| display: inline-flex; | |||
| -webkit-box-align: center; | |||
| -webkit-align-items: center; | |||
| -ms-flex-align: center; | |||
| align-items: center; | |||
| -webkit-box-pack: justify; | |||
| -webkit-justify-content: space-between; | |||
| -ms-flex-pack: justify; | |||
| justify-content: space-between; | |||
| } | |||
| .bootstrap-select > .dropdown-toggle:after { | |||
| margin-top: -1px; | |||
| } | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder:hover, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder:focus, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder:active { | |||
| color: #999; | |||
| } | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:hover, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:hover, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:hover, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:hover, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:hover, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:hover, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:focus, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:focus, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:focus, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:focus, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:focus, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:focus, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-primary:active, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-secondary:active, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-success:active, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-danger:active, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-info:active, | |||
| .bootstrap-select > .dropdown-toggle.bs-placeholder.btn-dark:active { | |||
| color: rgba(255, 255, 255, 0.5); | |||
| } | |||
| .bootstrap-select > select { | |||
| position: absolute !important; | |||
| bottom: 0; | |||
| left: 50%; | |||
| display: block !important; | |||
| width: 0.5px !important; | |||
| height: 100% !important; | |||
| padding: 0 !important; | |||
| opacity: 0 !important; | |||
| border: none; | |||
| z-index: 0 !important; | |||
| } | |||
| .bootstrap-select > select.mobile-device { | |||
| top: 0; | |||
| left: 0; | |||
| display: block !important; | |||
| width: 100% !important; | |||
| z-index: 2 !important; | |||
| } | |||
| .has-error .bootstrap-select .dropdown-toggle, | |||
| .error .bootstrap-select .dropdown-toggle, | |||
| .bootstrap-select.is-invalid .dropdown-toggle, | |||
| .was-validated .bootstrap-select select:invalid + .dropdown-toggle { | |||
| border-color: #b94a48; | |||
| } | |||
| .bootstrap-select.is-valid .dropdown-toggle, | |||
| .was-validated .bootstrap-select select:valid + .dropdown-toggle { | |||
| border-color: #28a745; | |||
| } | |||
| .bootstrap-select.fit-width { | |||
| width: auto !important; | |||
| } | |||
| .bootstrap-select:not([class*="col-"]):not([class*="form-control"]):not(.input-group-btn) { | |||
| width: 220px; | |||
| } | |||
| .bootstrap-select > select.mobile-device:focus + .dropdown-toggle, | |||
| .bootstrap-select .dropdown-toggle:focus { | |||
| outline: thin dotted #333333 !important; | |||
| outline: 5px auto -webkit-focus-ring-color !important; | |||
| outline-offset: -2px; | |||
| } | |||
| .bootstrap-select.form-control { | |||
| margin-bottom: 0; | |||
| padding: 0; | |||
| border: none; | |||
| height: auto; | |||
| } | |||
| :not(.input-group) > .bootstrap-select.form-control:not([class*="col-"]) { | |||
| width: 100%; | |||
| } | |||
| .bootstrap-select.form-control.input-group-btn { | |||
| float: none; | |||
| z-index: auto; | |||
| } | |||
| .form-inline .bootstrap-select, | |||
| .form-inline .bootstrap-select.form-control:not([class*="col-"]) { | |||
| width: auto; | |||
| } | |||
| .bootstrap-select:not(.input-group-btn), | |||
| .bootstrap-select[class*="col-"] { | |||
| float: none; | |||
| display: inline-block; | |||
| margin-left: 0; | |||
| } | |||
| .bootstrap-select.dropdown-menu-right, | |||
| .bootstrap-select[class*="col-"].dropdown-menu-right, | |||
| .row .bootstrap-select[class*="col-"].dropdown-menu-right { | |||
| float: right; | |||
| } | |||
| .form-inline .bootstrap-select, | |||
| .form-horizontal .bootstrap-select, | |||
| .form-group .bootstrap-select { | |||
| margin-bottom: 0; | |||
| } | |||
| .form-group-lg .bootstrap-select.form-control, | |||
| .form-group-sm .bootstrap-select.form-control { | |||
| padding: 0; | |||
| } | |||
| .form-group-lg .bootstrap-select.form-control .dropdown-toggle, | |||
| .form-group-sm .bootstrap-select.form-control .dropdown-toggle { | |||
| height: 100%; | |||
| font-size: inherit; | |||
| line-height: inherit; | |||
| border-radius: inherit; | |||
| } | |||
| .bootstrap-select.form-control-sm .dropdown-toggle, | |||
| .bootstrap-select.form-control-lg .dropdown-toggle { | |||
| font-size: inherit; | |||
| line-height: inherit; | |||
| border-radius: inherit; | |||
| } | |||
| .bootstrap-select.form-control-sm .dropdown-toggle { | |||
| padding: 0.25rem 0.5rem; | |||
| } | |||
| .bootstrap-select.form-control-lg .dropdown-toggle { | |||
| padding: 0.5rem 1rem; | |||
| } | |||
| .form-inline .bootstrap-select .form-control { | |||
| width: 100%; | |||
| } | |||
| .bootstrap-select.disabled, | |||
| .bootstrap-select > .disabled { | |||
| cursor: not-allowed; | |||
| } | |||
| .bootstrap-select.disabled:focus, | |||
| .bootstrap-select > .disabled:focus { | |||
| outline: none !important; | |||
| } | |||
| .bootstrap-select.bs-container { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| height: 0 !important; | |||
| padding: 0 !important; | |||
| } | |||
| .bootstrap-select.bs-container .dropdown-menu { | |||
| z-index: 1060; | |||
| } | |||
| .bootstrap-select .dropdown-toggle .filter-option { | |||
| position: static; | |||
| top: 0; | |||
| left: 0; | |||
| float: left; | |||
| height: 100%; | |||
| width: 100%; | |||
| text-align: left; | |||
| overflow: hidden; | |||
| -webkit-box-flex: 0; | |||
| -webkit-flex: 0 1 auto; | |||
| -ms-flex: 0 1 auto; | |||
| flex: 0 1 auto; | |||
| } | |||
| .bs3.bootstrap-select .dropdown-toggle .filter-option { | |||
| padding-right: inherit; | |||
| } | |||
| .input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option { | |||
| position: absolute; | |||
| padding-top: inherit; | |||
| padding-bottom: inherit; | |||
| padding-left: inherit; | |||
| float: none; | |||
| } | |||
| .input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option .filter-option-inner { | |||
| padding-right: inherit; | |||
| } | |||
| .bootstrap-select .dropdown-toggle .filter-option-inner-inner { | |||
| overflow: hidden; | |||
| } | |||
| .bootstrap-select .dropdown-toggle .filter-expand { | |||
| width: 0 !important; | |||
| float: left; | |||
| opacity: 0 !important; | |||
| overflow: hidden; | |||
| } | |||
| .bootstrap-select .dropdown-toggle .caret { | |||
| position: absolute; | |||
| top: 50%; | |||
| right: 12px; | |||
| margin-top: -2px; | |||
| vertical-align: middle; | |||
| } | |||
| .input-group .bootstrap-select.form-control .dropdown-toggle { | |||
| border-radius: inherit; | |||
| } | |||
| .bootstrap-select[class*="col-"] .dropdown-toggle { | |||
| width: 100%; | |||
| } | |||
| .bootstrap-select .dropdown-menu { | |||
| min-width: 100%; | |||
| -webkit-box-sizing: border-box; | |||
| -moz-box-sizing: border-box; | |||
| box-sizing: border-box; | |||
| } | |||
| .bootstrap-select .dropdown-menu > .inner:focus { | |||
| outline: none !important; | |||
| } | |||
| .bootstrap-select .dropdown-menu.inner { | |||
| position: static; | |||
| float: none; | |||
| border: 0; | |||
| padding: 0; | |||
| margin: 0; | |||
| border-radius: 0; | |||
| -webkit-box-shadow: none; | |||
| box-shadow: none; | |||
| } | |||
| .bootstrap-select .dropdown-menu li { | |||
| position: relative; | |||
| } | |||
| .bootstrap-select .dropdown-menu li.active small { | |||
| color: rgba(255, 255, 255, 0.5) !important; | |||
| } | |||
| .bootstrap-select .dropdown-menu li.disabled a { | |||
| cursor: not-allowed; | |||
| } | |||
| .bootstrap-select .dropdown-menu li a { | |||
| cursor: pointer; | |||
| -webkit-user-select: none; | |||
| -moz-user-select: none; | |||
| -ms-user-select: none; | |||
| user-select: none; | |||
| } | |||
| .bootstrap-select .dropdown-menu li a.opt { | |||
| position: relative; | |||
| padding-left: 2.25em; | |||
| } | |||
| .bootstrap-select .dropdown-menu li a span.check-mark { | |||
| display: none; | |||
| } | |||
| .bootstrap-select .dropdown-menu li a span.text { | |||
| display: inline-block; | |||
| } | |||
| .bootstrap-select .dropdown-menu li small { | |||
| padding-left: 0.5em; | |||
| } | |||
| .bootstrap-select .dropdown-menu .notify { | |||
| position: absolute; | |||
| bottom: 5px; | |||
| width: 96%; | |||
| margin: 0 2%; | |||
| min-height: 26px; | |||
| padding: 3px 5px; | |||
| background: #f5f5f5; | |||
| border: 1px solid #e3e3e3; | |||
| -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); | |||
| box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); | |||
| pointer-events: none; | |||
| opacity: 0.9; | |||
| -webkit-box-sizing: border-box; | |||
| -moz-box-sizing: border-box; | |||
| box-sizing: border-box; | |||
| } | |||
| .bootstrap-select .dropdown-menu .notify.fadeOut { | |||
| -webkit-animation: 300ms linear 750ms forwards bs-notify-fadeOut; | |||
| -o-animation: 300ms linear 750ms forwards bs-notify-fadeOut; | |||
| animation: 300ms linear 750ms forwards bs-notify-fadeOut; | |||
| } | |||
| .bootstrap-select .no-results { | |||
| padding: 3px; | |||
| background: #f5f5f5; | |||
| margin: 0 5px; | |||
| white-space: nowrap; | |||
| } | |||
| .bootstrap-select.fit-width .dropdown-toggle .filter-option { | |||
| position: static; | |||
| display: inline; | |||
| padding: 0; | |||
| } | |||
| .bootstrap-select.fit-width .dropdown-toggle .filter-option-inner, | |||
| .bootstrap-select.fit-width .dropdown-toggle .filter-option-inner-inner { | |||
| display: inline; | |||
| } | |||
| .bootstrap-select.fit-width .dropdown-toggle .bs-caret:before { | |||
| content: '\00a0'; | |||
| } | |||
| .bootstrap-select.fit-width .dropdown-toggle .caret { | |||
| position: static; | |||
| top: auto; | |||
| margin-top: -1px; | |||
| } | |||
| .bootstrap-select.show-tick .dropdown-menu .selected span.check-mark { | |||
| position: absolute; | |||
| display: inline-block; | |||
| right: 15px; | |||
| top: 5px; | |||
| } | |||
| .bootstrap-select.show-tick .dropdown-menu li a span.text { | |||
| margin-right: 34px; | |||
| } | |||
| .bootstrap-select .bs-ok-default:after { | |||
| content: ''; | |||
| display: block; | |||
| width: 0.5em; | |||
| height: 1em; | |||
| border-style: solid; | |||
| border-width: 0 0.26em 0.26em 0; | |||
| -webkit-transform-style: preserve-3d; | |||
| transform-style: preserve-3d; | |||
| -webkit-transform: rotate(45deg); | |||
| -ms-transform: rotate(45deg); | |||
| -o-transform: rotate(45deg); | |||
| transform: rotate(45deg); | |||
| } | |||
| .bootstrap-select.show-menu-arrow.open > .dropdown-toggle, | |||
| .bootstrap-select.show-menu-arrow.show > .dropdown-toggle { | |||
| z-index: 1061; | |||
| } | |||
| .bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:before { | |||
| content: ''; | |||
| border-left: 7px solid transparent; | |||
| border-right: 7px solid transparent; | |||
| border-bottom: 7px solid rgba(204, 204, 204, 0.2); | |||
| position: absolute; | |||
| bottom: -4px; | |||
| left: 9px; | |||
| display: none; | |||
| } | |||
| .bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:after { | |||
| content: ''; | |||
| border-left: 6px solid transparent; | |||
| border-right: 6px solid transparent; | |||
| border-bottom: 6px solid white; | |||
| position: absolute; | |||
| bottom: -4px; | |||
| left: 10px; | |||
| display: none; | |||
| } | |||
| .bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:before { | |||
| bottom: auto; | |||
| top: -4px; | |||
| border-top: 7px solid rgba(204, 204, 204, 0.2); | |||
| border-bottom: 0; | |||
| } | |||
| .bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:after { | |||
| bottom: auto; | |||
| top: -4px; | |||
| border-top: 6px solid white; | |||
| border-bottom: 0; | |||
| } | |||
| .bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:before { | |||
| right: 12px; | |||
| left: auto; | |||
| } | |||
| .bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:after { | |||
| right: 13px; | |||
| left: auto; | |||
| } | |||
| .bootstrap-select.show-menu-arrow.open > .dropdown-toggle .filter-option:before, | |||
| .bootstrap-select.show-menu-arrow.show > .dropdown-toggle .filter-option:before, | |||
| .bootstrap-select.show-menu-arrow.open > .dropdown-toggle .filter-option:after, | |||
| .bootstrap-select.show-menu-arrow.show > .dropdown-toggle .filter-option:after { | |||
| display: block; | |||
| } | |||
| .bs-searchbox, | |||
| .bs-actionsbox, | |||
| .bs-donebutton { | |||
| padding: 4px 8px; | |||
| } | |||
| .bs-actionsbox { | |||
| width: 100%; | |||
| -webkit-box-sizing: border-box; | |||
| -moz-box-sizing: border-box; | |||
| box-sizing: border-box; | |||
| } | |||
| .bs-actionsbox .btn-group button { | |||
| width: 50%; | |||
| } | |||
| .bs-donebutton { | |||
| float: left; | |||
| width: 100%; | |||
| -webkit-box-sizing: border-box; | |||
| -moz-box-sizing: border-box; | |||
| box-sizing: border-box; | |||
| } | |||
| .bs-donebutton .btn-group button { | |||
| width: 100%; | |||
| } | |||
| .bs-searchbox + .bs-actionsbox { | |||
| padding: 0 8px 4px; | |||
| } | |||
| .bs-searchbox .form-control { | |||
| margin-bottom: 0; | |||
| width: 100%; | |||
| float: none; | |||
| } | |||
| @@ -0,0 +1,95 @@ | |||
| /** | |||
| * @author: Alec Fenichel | |||
| * @webSite: https://fenichelar.com | |||
| * @update: zhixin wen <wenzhixin2010@gmail.com> | |||
| */ | |||
| var Utils = $.fn.bootstrapTable.utils | |||
| $.extend($.fn.bootstrapTable.defaults, { | |||
| autoRefresh: false, | |||
| showAutoRefresh: true, | |||
| autoRefreshInterval: 60, | |||
| autoRefreshSilent: true, | |||
| autoRefreshStatus: true, | |||
| autoRefreshFunction: null | |||
| }) | |||
| $.extend($.fn.bootstrapTable.defaults.icons, { | |||
| autoRefresh: { | |||
| bootstrap3: 'glyphicon-time icon-time', | |||
| bootstrap5: 'bi-clock', | |||
| materialize: 'access_time', | |||
| 'bootstrap-table': 'icon-clock' | |||
| }[$.fn.bootstrapTable.theme] || 'fa-clock' | |||
| }) | |||
| $.extend($.fn.bootstrapTable.locales, { | |||
| formatAutoRefresh () { | |||
| return 'Auto Refresh' | |||
| } | |||
| }) | |||
| $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales) | |||
| $.BootstrapTable = class extends $.BootstrapTable { | |||
| init (...args) { | |||
| super.init(...args) | |||
| if (this.options.autoRefresh && this.options.autoRefreshStatus) { | |||
| this.setupRefreshInterval() | |||
| } | |||
| } | |||
| initToolbar (...args) { | |||
| if (this.options.autoRefresh) { | |||
| this.buttons = Object.assign(this.buttons, { | |||
| autoRefresh: { | |||
| html: ` | |||
| <button class="auto-refresh ${this.constants.buttonsClass} | |||
| ${this.options.autoRefreshStatus ? ` ${this.constants.classes.buttonActive}` : ''}" | |||
| type="button" name="autoRefresh" title="${this.options.formatAutoRefresh()}"> | |||
| ${this.options.showButtonIcons ? Utils.sprintf(this.constants.html.icon, this.options.iconsPrefix, this.options.icons.autoRefresh) : ''} | |||
| ${this.options.showButtonText ? this.options.formatAutoRefresh() : ''} | |||
| </button> | |||
| `, | |||
| event: this.toggleAutoRefresh | |||
| } | |||
| }) | |||
| } | |||
| super.initToolbar(...args) | |||
| } | |||
| toggleAutoRefresh () { | |||
| if (this.options.autoRefresh) { | |||
| if (this.options.autoRefreshStatus) { | |||
| clearInterval(this.options.autoRefreshFunction) | |||
| this.$toolbar.find('>.columns .auto-refresh') | |||
| .removeClass(this.constants.classes.buttonActive) | |||
| } else { | |||
| this.setupRefreshInterval() | |||
| this.$toolbar.find('>.columns .auto-refresh') | |||
| .addClass(this.constants.classes.buttonActive) | |||
| } | |||
| this.options.autoRefreshStatus = !this.options.autoRefreshStatus | |||
| } | |||
| } | |||
| destroy () { | |||
| if (this.options.autoRefresh && this.options.autoRefreshStatus) { | |||
| clearInterval(this.options.autoRefreshFunction) | |||
| } | |||
| super.destroy() | |||
| } | |||
| setupRefreshInterval () { | |||
| this.options.autoRefreshFunction = setInterval(() => { | |||
| if (!this.options.autoRefresh || !this.options.autoRefreshStatus) { | |||
| return | |||
| } | |||
| this.refresh({ silent: this.options.autoRefreshSilent }) | |||
| }, this.options.autoRefreshInterval * 1000) | |||
| } | |||
| } | |||
| @@ -0,0 +1,606 @@ | |||
| /** | |||
| * @author: Dennis Hernández | |||
| * @update zhixin wen <wenzhixin2010@gmail.com> | |||
| */ | |||
| var Utils = $.fn.bootstrapTable.utils | |||
| var UtilsCookie = { | |||
| cookieIds: { | |||
| sortOrder: 'bs.table.sortOrder', | |||
| sortName: 'bs.table.sortName', | |||
| sortPriority: 'bs.table.sortPriority', | |||
| pageNumber: 'bs.table.pageNumber', | |||
| pageList: 'bs.table.pageList', | |||
| hiddenColumns: 'bs.table.hiddenColumns', | |||
| cardView: 'bs.table.cardView', | |||
| customView: 'bs.table.customView', | |||
| searchText: 'bs.table.searchText', | |||
| reorderColumns: 'bs.table.reorderColumns', | |||
| filterControl: 'bs.table.filterControl', | |||
| filterBy: 'bs.table.filterBy' | |||
| }, | |||
| getCurrentHeader (that) { | |||
| return that.options.height ? that.$tableHeader : that.$header | |||
| }, | |||
| getCurrentSearchControls (that) { | |||
| return that.options.height ? 'table select, table input' : 'select, input' | |||
| }, | |||
| isCookieSupportedByBrowser () { | |||
| return navigator.cookieEnabled | |||
| }, | |||
| isCookieEnabled (that, cookieName) { | |||
| return that.options.cookiesEnabled.includes(cookieName) | |||
| }, | |||
| setCookie (that, cookieName, cookieValue) { | |||
| if ( | |||
| !that.options.cookie || | |||
| !UtilsCookie.isCookieEnabled(that, cookieName) | |||
| ) { | |||
| return | |||
| } | |||
| return that._storage.setItem(`${that.options.cookieIdTable}.${cookieName}`, cookieValue) | |||
| }, | |||
| getCookie (that, cookieName) { | |||
| if ( | |||
| !cookieName || | |||
| !UtilsCookie.isCookieEnabled(that, cookieName) | |||
| ) { | |||
| return null | |||
| } | |||
| return that._storage.getItem(`${that.options.cookieIdTable}.${cookieName}`) | |||
| }, | |||
| deleteCookie (that, cookieName) { | |||
| return that._storage.removeItem(`${that.options.cookieIdTable}.${cookieName}`) | |||
| }, | |||
| calculateExpiration (cookieExpire) { | |||
| const time = cookieExpire.replace(/[0-9]*/, '') // s,mi,h,d,m,y | |||
| cookieExpire = cookieExpire.replace(/[A-Za-z]{1,2}/, '') // number | |||
| switch (time.toLowerCase()) { | |||
| case 's': | |||
| cookieExpire = +cookieExpire | |||
| break | |||
| case 'mi': | |||
| cookieExpire *= 60 | |||
| break | |||
| case 'h': | |||
| cookieExpire = cookieExpire * 60 * 60 | |||
| break | |||
| case 'd': | |||
| cookieExpire = cookieExpire * 24 * 60 * 60 | |||
| break | |||
| case 'm': | |||
| cookieExpire = cookieExpire * 30 * 24 * 60 * 60 | |||
| break | |||
| case 'y': | |||
| cookieExpire = cookieExpire * 365 * 24 * 60 * 60 | |||
| break | |||
| default: | |||
| cookieExpire = undefined | |||
| break | |||
| } | |||
| if (!cookieExpire) { | |||
| return '' | |||
| } | |||
| const d = new Date() | |||
| d.setTime(d.getTime() + cookieExpire * 1000) | |||
| return d.toGMTString() | |||
| }, | |||
| initCookieFilters (that) { | |||
| setTimeout(() => { | |||
| const parsedCookieFilters = JSON.parse( | |||
| UtilsCookie.getCookie(that, UtilsCookie.cookieIds.filterControl)) | |||
| if (!that._filterControlValuesLoaded && parsedCookieFilters) { | |||
| const cachedFilters = {} | |||
| const header = UtilsCookie.getCurrentHeader(that) | |||
| const searchControls = UtilsCookie.getCurrentSearchControls(that) | |||
| const applyCookieFilters = (element, filteredCookies) => { | |||
| filteredCookies.forEach(cookie => { | |||
| const value = element.value.toString() | |||
| const text = cookie.text | |||
| if ( | |||
| text === '' || | |||
| element.type === 'radio' && | |||
| value !== text | |||
| ) { | |||
| return | |||
| } | |||
| if ( | |||
| element.tagName === 'INPUT' && | |||
| element.type === 'radio' && | |||
| value === text | |||
| ) { | |||
| element.checked = true | |||
| cachedFilters[cookie.field] = text | |||
| } else if (element.tagName === 'INPUT') { | |||
| element.value = text | |||
| cachedFilters[cookie.field] = text | |||
| } else if ( | |||
| element.tagName === 'SELECT' && | |||
| that.options.filterControlContainer | |||
| ) { | |||
| element.value = text | |||
| cachedFilters[cookie.field] = text | |||
| } else if (text !== '' && element.tagName === 'SELECT') { | |||
| cachedFilters[cookie.field] = text | |||
| for (const currentElement of element) { | |||
| if (currentElement.value === text) { | |||
| currentElement.selected = true | |||
| return | |||
| } | |||
| } | |||
| const option = document.createElement('option') | |||
| option.value = text | |||
| option.text = text | |||
| element.add(option, element[1]) | |||
| element.selectedIndex = 1 | |||
| } | |||
| }) | |||
| } | |||
| let filterContainer = header | |||
| if (that.options.filterControlContainer) { | |||
| filterContainer = $(`${that.options.filterControlContainer}`) | |||
| } | |||
| filterContainer.find(searchControls).each(function () { | |||
| const field = $(this).closest('[data-field]').data('field') | |||
| const filteredCookies = parsedCookieFilters.filter(cookie => cookie.field === field) | |||
| applyCookieFilters(this, filteredCookies) | |||
| }) | |||
| that.initColumnSearch(cachedFilters) | |||
| that._filterControlValuesLoaded = true | |||
| that.initServer() | |||
| } | |||
| }, 250) | |||
| } | |||
| } | |||
| Object.assign($.fn.bootstrapTable.defaults, { | |||
| cookie: false, | |||
| cookieExpire: '2h', | |||
| cookiePath: null, | |||
| cookieDomain: null, | |||
| cookieSecure: null, | |||
| cookieSameSite: 'Lax', | |||
| cookieIdTable: '', | |||
| cookiesEnabled: [ | |||
| 'bs.table.sortOrder', 'bs.table.sortName', 'bs.table.sortPriority', | |||
| 'bs.table.pageNumber', 'bs.table.pageList', | |||
| 'bs.table.hiddenColumns', 'bs.table.searchText', | |||
| 'bs.table.filterControl', 'bs.table.filterBy', | |||
| 'bs.table.reorderColumns', 'bs.table.cardView', 'bs.table.customView' | |||
| ], | |||
| cookieStorage: 'cookieStorage', // localStorage, sessionStorage, customStorage | |||
| cookieCustomStorageGet: null, | |||
| cookieCustomStorageSet: null, | |||
| cookieCustomStorageDelete: null, | |||
| // internal variable | |||
| _filterControls: [], | |||
| _filterControlValuesLoaded: false, | |||
| _storage: { | |||
| setItem: undefined, | |||
| getItem: undefined, | |||
| removeItem: undefined | |||
| } | |||
| }) | |||
| $.fn.bootstrapTable.methods.push('getCookies') | |||
| $.fn.bootstrapTable.methods.push('deleteCookie') | |||
| Object.assign($.fn.bootstrapTable.utils, { | |||
| setCookie: UtilsCookie.setCookie, | |||
| getCookie: UtilsCookie.getCookie | |||
| }) | |||
| $.BootstrapTable = class extends $.BootstrapTable { | |||
| init () { | |||
| if (this.options.cookie) { | |||
| if ( | |||
| this.options.cookieStorage === 'cookieStorage' && | |||
| !UtilsCookie.isCookieSupportedByBrowser() | |||
| ) { | |||
| throw new Error('Cookies are not enabled in this browser.') | |||
| } | |||
| this.configureStorage() | |||
| // FilterBy logic | |||
| const filterByCookieValue = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.filterBy) | |||
| if (typeof filterByCookieValue === 'boolean' && !filterByCookieValue) { | |||
| throw new Error('The cookie value of filterBy must be a json!') | |||
| } | |||
| let filterByCookie = {} | |||
| try { | |||
| filterByCookie = JSON.parse(filterByCookieValue) | |||
| } catch (e) { | |||
| throw new Error('Could not parse the json of the filterBy cookie!') | |||
| } | |||
| this.filterColumns = filterByCookie ? filterByCookie : {} | |||
| // FilterControl logic | |||
| this._filterControls = [] | |||
| this._filterControlValuesLoaded = false | |||
| this.options.cookiesEnabled = typeof this.options.cookiesEnabled === 'string' ? | |||
| this.options.cookiesEnabled.replace('[', '').replace(']', '') | |||
| .replace(/'/g, '').replace(/ /g, '').split(',') : | |||
| this.options.cookiesEnabled | |||
| if (this.options.filterControl) { | |||
| const that = this | |||
| this.$el.on('column-search.bs.table', (e, field, text) => { | |||
| let isNewField = true | |||
| for (let i = 0; i < that._filterControls.length; i++) { | |||
| if (that._filterControls[i].field === field) { | |||
| that._filterControls[i].text = text | |||
| isNewField = false | |||
| break | |||
| } | |||
| } | |||
| if (isNewField) { | |||
| that._filterControls.push({ | |||
| field, | |||
| text | |||
| }) | |||
| } | |||
| UtilsCookie.setCookie(that, UtilsCookie.cookieIds.filterControl, JSON.stringify(that._filterControls)) | |||
| }).on('created-controls.bs.table', UtilsCookie.initCookieFilters(that)) | |||
| } | |||
| } | |||
| super.init() | |||
| } | |||
| initServer (...args) { | |||
| if ( | |||
| this.options.cookie && | |||
| this.options.filterControl && | |||
| !this._filterControlValuesLoaded | |||
| ) { | |||
| const cookie = JSON.parse(UtilsCookie.getCookie(this, UtilsCookie.cookieIds.filterControl)) | |||
| if (cookie) { | |||
| return | |||
| } | |||
| } | |||
| super.initServer(...args) | |||
| } | |||
| initTable (...args) { | |||
| super.initTable(...args) | |||
| this.initCookie() | |||
| } | |||
| onSort (...args) { | |||
| super.onSort(...args) | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| if (this.options.sortName === undefined || this.options.sortOrder === undefined) { | |||
| UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortName) | |||
| UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortOrder) | |||
| } else { | |||
| this.options.sortPriority = null | |||
| UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortPriority) | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.sortOrder, this.options.sortOrder) | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.sortName, this.options.sortName) | |||
| } | |||
| } | |||
| onMultipleSort (...args) { | |||
| super.onMultipleSort(...args) | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| if (this.options.sortPriority === undefined) { | |||
| UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortPriority) | |||
| } else { | |||
| this.options.sortName = undefined | |||
| this.options.sortOrder = undefined | |||
| UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortName) | |||
| UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds.sortOrder) | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.sortPriority, JSON.stringify(this.options.sortPriority)) | |||
| } | |||
| } | |||
| onPageNumber (...args) { | |||
| super.onPageNumber(...args) | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber) | |||
| } | |||
| onPageListChange (...args) { | |||
| super.onPageListChange(...args) | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageList, | |||
| this.options.pageSize === this.options.formatAllRows() ? 'all' : this.options.pageSize) | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber) | |||
| } | |||
| onPagePre (...args) { | |||
| super.onPagePre(...args) | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber) | |||
| } | |||
| onPageNext (...args) { | |||
| super.onPageNext(...args) | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber) | |||
| } | |||
| _toggleColumn (...args) { | |||
| super._toggleColumn(...args) | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.hiddenColumns, JSON.stringify(this.getHiddenColumns().map(column => column.field))) | |||
| } | |||
| _toggleAllColumns (...args) { | |||
| super._toggleAllColumns(...args) | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.hiddenColumns, JSON.stringify(this.getHiddenColumns().map(column => column.field))) | |||
| } | |||
| toggleView () { | |||
| super.toggleView() | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.cardView, this.options.cardView) | |||
| } | |||
| toggleCustomView () { | |||
| super.toggleCustomView() | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.customView, this.customViewDefaultView) | |||
| } | |||
| selectPage (page) { | |||
| super.selectPage(page) | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, page) | |||
| } | |||
| onSearch (event) { | |||
| super.onSearch(event, arguments.length > 1 ? arguments[1] : true) | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| if (this.options.search) { | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.searchText, this.searchText) | |||
| } | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.pageNumber, this.options.pageNumber) | |||
| } | |||
| initHeader (...args) { | |||
| if (this.options.reorderableColumns && this.options.cookie) { | |||
| this.columnsSortOrder = JSON.parse(UtilsCookie.getCookie(this, UtilsCookie.cookieIds.reorderColumns)) | |||
| } | |||
| super.initHeader(...args) | |||
| } | |||
| persistReorderColumnsState (that) { | |||
| UtilsCookie.setCookie(that, UtilsCookie.cookieIds.reorderColumns, JSON.stringify(that.columnsSortOrder)) | |||
| } | |||
| filterBy (...args) { | |||
| super.filterBy(...args) | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| UtilsCookie.setCookie(this, UtilsCookie.cookieIds.filterBy, JSON.stringify(this.filterColumns)) | |||
| } | |||
| initCookie () { | |||
| if (!this.options.cookie) { | |||
| return | |||
| } | |||
| if (this.options.cookieIdTable === '' || this.options.cookieExpire === '') { | |||
| console.error('Configuration error. Please review the cookieIdTable and the cookieExpire property. If the properties are correct, then this browser does not support cookies.') | |||
| this.options.cookie = false // Make sure that the cookie extension is disabled | |||
| return | |||
| } | |||
| const sortOrderCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.sortOrder) | |||
| const sortOrderNameCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.sortName) | |||
| let sortPriorityCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.sortPriority) | |||
| const pageNumberCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.pageNumber) | |||
| const pageListCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.pageList) | |||
| const searchTextCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.searchText) | |||
| const cardViewCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.cardView) | |||
| const customViewCookie = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.customView) | |||
| const hiddenColumnsCookieValue = UtilsCookie.getCookie(this, UtilsCookie.cookieIds.hiddenColumns) | |||
| let hiddenColumnsCookie = {} | |||
| try { | |||
| hiddenColumnsCookie = JSON.parse(hiddenColumnsCookieValue) | |||
| } catch (e) { | |||
| throw new Error('Could not parse the json of the hidden columns cookie!', hiddenColumnsCookieValue) | |||
| } | |||
| try { | |||
| sortPriorityCookie = JSON.parse(sortPriorityCookie) | |||
| } catch (e) { | |||
| throw new Error('Could not parse the json of the sortPriority cookie!', sortPriorityCookie) | |||
| } | |||
| if (!sortPriorityCookie) { | |||
| // sortOrder | |||
| this.options.sortOrder = sortOrderCookie ? sortOrderCookie : this.options.sortOrder | |||
| // sortName | |||
| this.options.sortName = sortOrderNameCookie ? sortOrderNameCookie : this.options.sortName | |||
| } else { | |||
| this.options.sortOrder = undefined | |||
| this.options.sortName = undefined | |||
| } | |||
| // sortPriority | |||
| this.options.sortPriority = sortPriorityCookie ? sortPriorityCookie : this.options.sortPriority | |||
| if (this.options.sortOrder || this.options.sortName) { | |||
| // sortPriority | |||
| this.options.sortPriority = null | |||
| } | |||
| // pageNumber | |||
| this.options.pageNumber = pageNumberCookie ? +pageNumberCookie : this.options.pageNumber | |||
| // pageSize | |||
| this.options.pageSize = pageListCookie ? pageListCookie === 'all' ? | |||
| this.options.formatAllRows() : +pageListCookie : this.options.pageSize | |||
| // searchText | |||
| if (UtilsCookie.isCookieEnabled(this, UtilsCookie.cookieIds.searchText) && this.options.searchText === '') { | |||
| this.options.searchText = searchTextCookie ? searchTextCookie : '' | |||
| } | |||
| // cardView | |||
| if (cardViewCookie !== null) { | |||
| this.options.cardView = cardViewCookie === 'true' ? cardViewCookie : false | |||
| } | |||
| this.customViewDefaultView = customViewCookie === 'true' | |||
| if (hiddenColumnsCookie) { | |||
| for (const column of this.columns) { | |||
| if (!column.switchable) { | |||
| continue | |||
| } | |||
| column.visible = this.isSelectionColumn(column) || | |||
| !hiddenColumnsCookie.includes(column.field) | |||
| } | |||
| } | |||
| } | |||
| getCookies () { | |||
| const bootstrapTable = this | |||
| const cookies = {} | |||
| for (const [key, value] of Object.entries(UtilsCookie.cookieIds)) { | |||
| cookies[key] = UtilsCookie.getCookie(bootstrapTable, value) | |||
| if (key === 'columns' || key === 'hiddenColumns' || key === 'sortPriority') { | |||
| cookies[key] = JSON.parse(cookies[key]) | |||
| } | |||
| } | |||
| return cookies | |||
| } | |||
| deleteCookie (cookieName) { | |||
| if (!cookieName) { | |||
| return | |||
| } | |||
| UtilsCookie.deleteCookie(this, UtilsCookie.cookieIds[cookieName]) | |||
| } | |||
| configureStorage () { | |||
| const that = this | |||
| this._storage = {} | |||
| switch (this.options.cookieStorage) { | |||
| case 'cookieStorage': | |||
| this._storage.setItem = function (cookieName, cookieValue) { | |||
| document.cookie = [ | |||
| cookieName, '=', encodeURIComponent(cookieValue), | |||
| `; expires=${UtilsCookie.calculateExpiration(that.options.cookieExpire)}`, | |||
| that.options.cookiePath ? `; path=${that.options.cookiePath}` : '', | |||
| that.options.cookieDomain ? `; domain=${that.options.cookieDomain}` : '', | |||
| that.options.cookieSecure ? '; secure' : '', | |||
| `;SameSite=${that.options.cookieSameSite}` | |||
| ].join('') | |||
| } | |||
| this._storage.getItem = function (cookieName) { | |||
| const value = `; ${document.cookie}` | |||
| const parts = value.split(`; ${cookieName}=`) | |||
| return parts.length === 2 ? decodeURIComponent(parts.pop().split(';').shift()) : null | |||
| } | |||
| this._storage.removeItem = function (cookieName) { | |||
| document.cookie = [ | |||
| encodeURIComponent(cookieName), '=', | |||
| '; expires=Thu, 01 Jan 1970 00:00:00 GMT', | |||
| that.options.cookiePath ? `; path=${that.options.cookiePath}` : '', | |||
| that.options.cookieDomain ? `; domain=${that.options.cookieDomain}` : '', | |||
| `;SameSite=${that.options.cookieSameSite}` | |||
| ].join('') | |||
| } | |||
| break | |||
| case 'localStorage': | |||
| this._storage.setItem = function (cookieName, cookieValue) { | |||
| localStorage.setItem(cookieName, cookieValue) | |||
| } | |||
| this._storage.getItem = function (cookieName) { | |||
| return localStorage.getItem(cookieName) | |||
| } | |||
| this._storage.removeItem = function (cookieName) { | |||
| localStorage.removeItem(cookieName) | |||
| } | |||
| break | |||
| case 'sessionStorage': | |||
| this._storage.setItem = function (cookieName, cookieValue) { | |||
| sessionStorage.setItem(cookieName, cookieValue) | |||
| } | |||
| this._storage.getItem = function (cookieName) { | |||
| return sessionStorage.getItem(cookieName) | |||
| } | |||
| this._storage.removeItem = function (cookieName) { | |||
| sessionStorage.removeItem(cookieName) | |||
| } | |||
| break | |||
| case 'customStorage': | |||
| if ( | |||
| !this.options.cookieCustomStorageSet || | |||
| !this.options.cookieCustomStorageGet || | |||
| !this.options.cookieCustomStorageDelete | |||
| ) { | |||
| throw new Error('The following options must be set while using the customStorage: cookieCustomStorageSet, cookieCustomStorageGet and cookieCustomStorageDelete') | |||
| } | |||
| this._storage.setItem = function (cookieName, cookieValue) { | |||
| Utils.calculateObjectValue(that.options, that.options.cookieCustomStorageSet, [cookieName, cookieValue], '') | |||
| } | |||
| this._storage.getItem = function (cookieName) { | |||
| return Utils.calculateObjectValue(that.options, that.options.cookieCustomStorageGet, [cookieName], '') | |||
| } | |||
| this._storage.removeItem = function (cookieName) { | |||
| Utils.calculateObjectValue(that.options, that.options.cookieCustomStorageDelete, [cookieName], '') | |||
| } | |||
| break | |||
| default: | |||
| throw new Error('Storage method not supported.') | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,135 @@ | |||
| /** | |||
| * @author: Dustin Utecht | |||
| * @github: https://github.com/UtechtDustin | |||
| */ | |||
| var Utils = $.fn.bootstrapTable.utils | |||
| Object.assign($.fn.bootstrapTable.defaults, { | |||
| customView: false, | |||
| showCustomView: false, | |||
| customViewDefaultView: false | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.defaults.icons, { | |||
| customViewOn: { | |||
| bootstrap3: 'glyphicon glyphicon-list', | |||
| bootstrap5: 'bi-list', | |||
| bootstrap4: 'fa fa-list', | |||
| semantic: 'fa fa-list', | |||
| foundation: 'fa fa-list', | |||
| bulma: 'fa fa-list', | |||
| materialize: 'list' | |||
| }[$.fn.bootstrapTable.theme] || 'fa-list', | |||
| customViewOff: { | |||
| bootstrap3: 'glyphicon glyphicon-eye-open', | |||
| bootstrap5: 'bi-grid', | |||
| bootstrap4: 'fa fa-th', | |||
| semantic: 'fa fa-th', | |||
| foundation: 'fa fa-th', | |||
| bulma: 'fa fa-th', | |||
| materialize: 'grid_on' | |||
| }[$.fn.bootstrapTable.theme] || 'fa-th' | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.defaults, { | |||
| onCustomViewPostBody () { | |||
| return false | |||
| }, | |||
| onCustomViewPreBody () { | |||
| return false | |||
| }, | |||
| onToggleCustomView () { | |||
| return false | |||
| } | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.locales, { | |||
| formatToggleCustomViewOn () { | |||
| return 'Show custom view' | |||
| }, | |||
| formatToggleCustomViewOff () { | |||
| return 'Hide custom view' | |||
| } | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales) | |||
| $.fn.bootstrapTable.methods.push('toggleCustomView') | |||
| Object.assign($.fn.bootstrapTable.events, { | |||
| 'custom-view-post-body.bs.table': 'onCustomViewPostBody', | |||
| 'custom-view-pre-body.bs.table': 'onCustomViewPreBody', | |||
| 'toggle-custom-view.bs.table': 'onToggleCustomView' | |||
| }) | |||
| $.BootstrapTable = class extends $.BootstrapTable { | |||
| init () { | |||
| this.customViewDefaultView = this.options.customViewDefaultView | |||
| super.init() | |||
| } | |||
| initToolbar (...args) { | |||
| if (this.options.customView && this.options.showCustomView) { | |||
| this.buttons = Object.assign(this.buttons, { | |||
| customView: { | |||
| text: this.options.customViewDefaultView ? this.options.formatToggleCustomViewOff() : this.options.formatToggleCustomViewOn(), | |||
| icon: this.options.customViewDefaultView ? this.options.icons.customViewOn : this.options.icons.customViewOff, | |||
| event: this.toggleCustomView, | |||
| attributes: { | |||
| 'aria-label': this.options.customViewDefaultView ? this.options.formatToggleCustomViewOff() : this.options.formatToggleCustomViewOn(), | |||
| title: this.options.customViewDefaultView ? this.options.formatToggleCustomViewOff() : this.options.formatToggleCustomViewOn() | |||
| } | |||
| } | |||
| }) | |||
| } | |||
| super.initToolbar(...args) | |||
| } | |||
| initBody () { | |||
| super.initBody() | |||
| if (!this.options.customView) { | |||
| return | |||
| } | |||
| const $table = this.$el | |||
| const $customViewContainer = this.$container.find('.fixed-table-custom-view') | |||
| $table.hide() | |||
| $customViewContainer.hide() | |||
| if (!this.options.customView || !this.customViewDefaultView) { | |||
| $table.show() | |||
| return | |||
| } | |||
| const data = this.getData().slice(this.pageFrom - 1, this.pageTo) | |||
| const value = Utils.calculateObjectValue(this, this.options.customView, [data], '') | |||
| this.trigger('custom-view-pre-body', data, value) | |||
| if ($customViewContainer.length === 1) { | |||
| $customViewContainer.show().html(value) | |||
| } else { | |||
| this.$tableBody.after(`<div class="fixed-table-custom-view">${value}</div>`) | |||
| } | |||
| this.trigger('custom-view-post-body', data, value) | |||
| } | |||
| toggleCustomView () { | |||
| this.customViewDefaultView = !this.customViewDefaultView | |||
| const icon = this.options.showButtonIcons ? this.customViewDefaultView ? this.options.icons.customViewOn : this.options.icons.customViewOff : '' | |||
| const text = this.options.showButtonText ? this.customViewDefaultView ? this.options.formatToggleCustomViewOff() : this.options.formatToggleCustomViewOn() : '' | |||
| this.$toolbar.find('button[name="customView"]') | |||
| .html(`${Utils.sprintf(this.constants.html.icon, this.options.iconsPrefix, icon)} ${text}`) | |||
| .attr('aria-label', text) | |||
| .attr('title', text) | |||
| this.initBody() | |||
| this.trigger('toggle-custom-view', this.customViewDefaultView) | |||
| } | |||
| } | |||
| @@ -0,0 +1,674 @@ | |||
| /*! X-editable - v1.5.3 | |||
| * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery | |||
| * http://github.com/vitalets/x-editable | |||
| * Copyright (c) 2019 Vitaliy Potapov; Licensed MIT */ | |||
| .editableform { | |||
| margin-bottom: 0; /* overwrites bootstrap margin */ | |||
| } | |||
| .editableform .control-group { | |||
| margin-bottom: 0; /* overwrites bootstrap margin */ | |||
| white-space: nowrap; /* prevent wrapping buttons on new line */ | |||
| line-height: 20px; /* overwriting bootstrap line-height. See #133 */ | |||
| } | |||
| /* | |||
| BS3 fix: stop css from breaking when the form is inside a popup and inside a form with the class .form-horizontal | |||
| See: https://github.com/vitalets/x-editable/issues/682 | |||
| */ | |||
| .form-horizontal .editable-popup .editableform .form-group { | |||
| margin-left:0; | |||
| margin-right:0; | |||
| } | |||
| /* | |||
| BS3 width:1005 for inputs breaks editable form in popup | |||
| See: https://github.com/vitalets/x-editable/issues/393 | |||
| */ | |||
| .editableform .form-control { | |||
| width: auto; | |||
| } | |||
| .editable-buttons { | |||
| display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ | |||
| vertical-align: top; | |||
| margin-left: 7px; | |||
| /* inline-block emulation for IE7*/ | |||
| zoom: 1; | |||
| *display: inline; | |||
| } | |||
| .editable-buttons.editable-buttons-bottom { | |||
| display: block; | |||
| margin-top: 7px; | |||
| margin-left: 0; | |||
| } | |||
| .editable-input { | |||
| vertical-align: top; | |||
| display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ | |||
| width: auto; /* bootstrap-responsive has width: 100% that breakes layout */ | |||
| white-space: normal; /* reset white-space decalred in parent*/ | |||
| /* display-inline emulation for IE7*/ | |||
| zoom: 1; | |||
| *display: inline; | |||
| } | |||
| .editable-buttons .editable-cancel { | |||
| margin-left: 7px; | |||
| } | |||
| /*for jquery-ui buttons need set height to look more pretty*/ | |||
| .editable-buttons button.ui-button-icon-only { | |||
| height: 24px; | |||
| width: 30px; | |||
| } | |||
| .editableform-loading { | |||
| background: url('loading.gif') center center no-repeat; | |||
| height: 25px; | |||
| width: auto; | |||
| min-width: 25px; | |||
| } | |||
| .editable-inline .editableform-loading { | |||
| background-position: left 5px; | |||
| } | |||
| .editable-error-block { | |||
| max-width: 300px; | |||
| margin: 5px 0 0 0; | |||
| width: auto; | |||
| white-space: normal; | |||
| } | |||
| /*add padding for jquery ui*/ | |||
| .editable-error-block.ui-state-error { | |||
| padding: 3px; | |||
| } | |||
| .editable-error { | |||
| color: red; | |||
| } | |||
| /* ---- For specific types ---- */ | |||
| .editableform .editable-date { | |||
| padding: 0; | |||
| margin: 0; | |||
| float: left; | |||
| } | |||
| /* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */ | |||
| .editable-inline .add-on .icon-th { | |||
| margin-top: 3px; | |||
| margin-left: 1px; | |||
| } | |||
| /* checklist vertical alignment */ | |||
| .editable-checklist label input[type="checkbox"], | |||
| .editable-checklist label span { | |||
| vertical-align: middle; | |||
| margin: 0; | |||
| } | |||
| .editable-checklist label { | |||
| white-space: nowrap; | |||
| } | |||
| /* set exact width of textarea to fit buttons toolbar */ | |||
| .editable-wysihtml5 { | |||
| width: 566px; | |||
| height: 250px; | |||
| } | |||
| /* clear button shown as link in date inputs */ | |||
| .editable-clear { | |||
| clear: both; | |||
| font-size: 0.9em; | |||
| text-decoration: none; | |||
| text-align: right; | |||
| } | |||
| /* IOS-style clear button for text inputs */ | |||
| .editable-clear-x { | |||
| background: url('clear.png') center center no-repeat; | |||
| display: block; | |||
| width: 13px; | |||
| height: 13px; | |||
| position: absolute; | |||
| opacity: 0.6; | |||
| z-index: 100; | |||
| top: 50%; | |||
| right: 6px; | |||
| margin-top: -6px; | |||
| } | |||
| .editable-clear-x:hover { | |||
| opacity: 1; | |||
| } | |||
| .editable-pre-wrapped { | |||
| white-space: pre-wrap; | |||
| } | |||
| .editable-container.editable-popup { | |||
| max-width: none !important; /* without this rule poshytip/tooltip does not stretch */ | |||
| } | |||
| .editable-container.popover { | |||
| width: auto; /* without this rule popover does not stretch */ | |||
| } | |||
| .editable-container.editable-inline { | |||
| display: inline-block; | |||
| vertical-align: middle; | |||
| width: auto; | |||
| /* inline-block emulation for IE7*/ | |||
| zoom: 1; | |||
| *display: inline; | |||
| } | |||
| .editable-container.ui-widget { | |||
| font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */ | |||
| z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */ | |||
| } | |||
| .editable-click, | |||
| a.editable-click, | |||
| a.editable-click:hover { | |||
| text-decoration: none; | |||
| border-bottom: dashed 1px #0088cc; | |||
| } | |||
| .editable-click.editable-disabled, | |||
| a.editable-click.editable-disabled, | |||
| a.editable-click.editable-disabled:hover { | |||
| color: #585858; | |||
| cursor: default; | |||
| border-bottom: none; | |||
| } | |||
| .editable-empty, .editable-empty:hover, .editable-empty:focus{ | |||
| font-style: italic; | |||
| color: #DD1144; | |||
| /* border-bottom: none; */ | |||
| text-decoration: none; | |||
| } | |||
| .editable-unsaved { | |||
| font-weight: bold; | |||
| } | |||
| .editable-unsaved:after { | |||
| /* content: '*'*/ | |||
| } | |||
| .editable-bg-transition { | |||
| -webkit-transition: background-color 1400ms ease-out; | |||
| -moz-transition: background-color 1400ms ease-out; | |||
| -o-transition: background-color 1400ms ease-out; | |||
| -ms-transition: background-color 1400ms ease-out; | |||
| transition: background-color 1400ms ease-out; | |||
| } | |||
| /*see https://github.com/vitalets/x-editable/issues/139 */ | |||
| .form-horizontal .editable | |||
| { | |||
| padding-top: 5px; | |||
| display:inline-block; | |||
| } | |||
| /*! | |||
| * Datepicker for Bootstrap | |||
| * | |||
| * Copyright 2012 Stefan Petre | |||
| * Improvements by Andrew Rowls | |||
| * Licensed under the Apache License v2.0 | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| */ | |||
| .datepicker { | |||
| padding: 4px; | |||
| -webkit-border-radius: 4px; | |||
| -moz-border-radius: 4px; | |||
| border-radius: 4px; | |||
| direction: ltr; | |||
| /*.dow { | |||
| border-top: 1px solid #ddd !important; | |||
| }*/ | |||
| } | |||
| .datepicker-inline { | |||
| width: 220px; | |||
| } | |||
| .datepicker.datepicker-rtl { | |||
| direction: rtl; | |||
| } | |||
| .datepicker.datepicker-rtl table tr td span { | |||
| float: right; | |||
| } | |||
| .datepicker-dropdown { | |||
| top: 0; | |||
| left: 0; | |||
| } | |||
| .datepicker-dropdown:before { | |||
| content: ''; | |||
| display: inline-block; | |||
| border-left: 7px solid transparent; | |||
| border-right: 7px solid transparent; | |||
| border-bottom: 7px solid #ccc; | |||
| border-bottom-color: rgba(0, 0, 0, 0.2); | |||
| position: absolute; | |||
| top: -7px; | |||
| left: 6px; | |||
| } | |||
| .datepicker-dropdown:after { | |||
| content: ''; | |||
| display: inline-block; | |||
| border-left: 6px solid transparent; | |||
| border-right: 6px solid transparent; | |||
| border-bottom: 6px solid #ffffff; | |||
| position: absolute; | |||
| top: -6px; | |||
| left: 7px; | |||
| } | |||
| .datepicker > div { | |||
| display: none; | |||
| } | |||
| .datepicker.days div.datepicker-days { | |||
| display: block; | |||
| } | |||
| .datepicker.months div.datepicker-months { | |||
| display: block; | |||
| } | |||
| .datepicker.years div.datepicker-years { | |||
| display: block; | |||
| } | |||
| .datepicker table { | |||
| margin: 0; | |||
| } | |||
| .datepicker td, | |||
| .datepicker th { | |||
| text-align: center; | |||
| width: 20px; | |||
| height: 20px; | |||
| -webkit-border-radius: 4px; | |||
| -moz-border-radius: 4px; | |||
| border-radius: 4px; | |||
| border: none; | |||
| } | |||
| .table-striped .datepicker table tr td, | |||
| .table-striped .datepicker table tr th { | |||
| background-color: transparent; | |||
| } | |||
| .datepicker table tr td.day:hover { | |||
| background: #eeeeee; | |||
| cursor: pointer; | |||
| } | |||
| .datepicker table tr td.old, | |||
| .datepicker table tr td.new { | |||
| color: #999999; | |||
| } | |||
| .datepicker table tr td.disabled, | |||
| .datepicker table tr td.disabled:hover { | |||
| background: none; | |||
| color: #999999; | |||
| cursor: default; | |||
| } | |||
| .datepicker table tr td.today, | |||
| .datepicker table tr td.today:hover, | |||
| .datepicker table tr td.today.disabled, | |||
| .datepicker table tr td.today.disabled:hover { | |||
| background-color: #fde19a; | |||
| background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); | |||
| background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); | |||
| background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); | |||
| background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); | |||
| background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); | |||
| background-image: linear-gradient(top, #fdd49a, #fdf59a); | |||
| background-repeat: repeat-x; | |||
| filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); | |||
| border-color: #fdf59a #fdf59a #fbed50; | |||
| border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |||
| filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); | |||
| color: #000; | |||
| } | |||
| .datepicker table tr td.today:hover, | |||
| .datepicker table tr td.today:hover:hover, | |||
| .datepicker table tr td.today.disabled:hover, | |||
| .datepicker table tr td.today.disabled:hover:hover, | |||
| .datepicker table tr td.today:active, | |||
| .datepicker table tr td.today:hover:active, | |||
| .datepicker table tr td.today.disabled:active, | |||
| .datepicker table tr td.today.disabled:hover:active, | |||
| .datepicker table tr td.today.active, | |||
| .datepicker table tr td.today:hover.active, | |||
| .datepicker table tr td.today.disabled.active, | |||
| .datepicker table tr td.today.disabled:hover.active, | |||
| .datepicker table tr td.today.disabled, | |||
| .datepicker table tr td.today:hover.disabled, | |||
| .datepicker table tr td.today.disabled.disabled, | |||
| .datepicker table tr td.today.disabled:hover.disabled, | |||
| .datepicker table tr td.today[disabled], | |||
| .datepicker table tr td.today:hover[disabled], | |||
| .datepicker table tr td.today.disabled[disabled], | |||
| .datepicker table tr td.today.disabled:hover[disabled] { | |||
| background-color: #fdf59a; | |||
| } | |||
| .datepicker table tr td.today:active, | |||
| .datepicker table tr td.today:hover:active, | |||
| .datepicker table tr td.today.disabled:active, | |||
| .datepicker table tr td.today.disabled:hover:active, | |||
| .datepicker table tr td.today.active, | |||
| .datepicker table tr td.today:hover.active, | |||
| .datepicker table tr td.today.disabled.active, | |||
| .datepicker table tr td.today.disabled:hover.active { | |||
| background-color: #fbf069 \9; | |||
| } | |||
| .datepicker table tr td.today:hover:hover { | |||
| color: #000; | |||
| } | |||
| .datepicker table tr td.today.active:hover { | |||
| color: #fff; | |||
| } | |||
| .datepicker table tr td.range, | |||
| .datepicker table tr td.range:hover, | |||
| .datepicker table tr td.range.disabled, | |||
| .datepicker table tr td.range.disabled:hover { | |||
| background: #eeeeee; | |||
| -webkit-border-radius: 0; | |||
| -moz-border-radius: 0; | |||
| border-radius: 0; | |||
| } | |||
| .datepicker table tr td.range.today, | |||
| .datepicker table tr td.range.today:hover, | |||
| .datepicker table tr td.range.today.disabled, | |||
| .datepicker table tr td.range.today.disabled:hover { | |||
| background-color: #f3d17a; | |||
| background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a); | |||
| background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a); | |||
| background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a)); | |||
| background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a); | |||
| background-image: -o-linear-gradient(top, #f3c17a, #f3e97a); | |||
| background-image: linear-gradient(top, #f3c17a, #f3e97a); | |||
| background-repeat: repeat-x; | |||
| filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0); | |||
| border-color: #f3e97a #f3e97a #edde34; | |||
| border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |||
| filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); | |||
| -webkit-border-radius: 0; | |||
| -moz-border-radius: 0; | |||
| border-radius: 0; | |||
| } | |||
| .datepicker table tr td.range.today:hover, | |||
| .datepicker table tr td.range.today:hover:hover, | |||
| .datepicker table tr td.range.today.disabled:hover, | |||
| .datepicker table tr td.range.today.disabled:hover:hover, | |||
| .datepicker table tr td.range.today:active, | |||
| .datepicker table tr td.range.today:hover:active, | |||
| .datepicker table tr td.range.today.disabled:active, | |||
| .datepicker table tr td.range.today.disabled:hover:active, | |||
| .datepicker table tr td.range.today.active, | |||
| .datepicker table tr td.range.today:hover.active, | |||
| .datepicker table tr td.range.today.disabled.active, | |||
| .datepicker table tr td.range.today.disabled:hover.active, | |||
| .datepicker table tr td.range.today.disabled, | |||
| .datepicker table tr td.range.today:hover.disabled, | |||
| .datepicker table tr td.range.today.disabled.disabled, | |||
| .datepicker table tr td.range.today.disabled:hover.disabled, | |||
| .datepicker table tr td.range.today[disabled], | |||
| .datepicker table tr td.range.today:hover[disabled], | |||
| .datepicker table tr td.range.today.disabled[disabled], | |||
| .datepicker table tr td.range.today.disabled:hover[disabled] { | |||
| background-color: #f3e97a; | |||
| } | |||
| .datepicker table tr td.range.today:active, | |||
| .datepicker table tr td.range.today:hover:active, | |||
| .datepicker table tr td.range.today.disabled:active, | |||
| .datepicker table tr td.range.today.disabled:hover:active, | |||
| .datepicker table tr td.range.today.active, | |||
| .datepicker table tr td.range.today:hover.active, | |||
| .datepicker table tr td.range.today.disabled.active, | |||
| .datepicker table tr td.range.today.disabled:hover.active { | |||
| background-color: #efe24b \9; | |||
| } | |||
| .datepicker table tr td.selected, | |||
| .datepicker table tr td.selected:hover, | |||
| .datepicker table tr td.selected.disabled, | |||
| .datepicker table tr td.selected.disabled:hover { | |||
| background-color: #9e9e9e; | |||
| background-image: -moz-linear-gradient(top, #b3b3b3, #808080); | |||
| background-image: -ms-linear-gradient(top, #b3b3b3, #808080); | |||
| background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080)); | |||
| background-image: -webkit-linear-gradient(top, #b3b3b3, #808080); | |||
| background-image: -o-linear-gradient(top, #b3b3b3, #808080); | |||
| background-image: linear-gradient(top, #b3b3b3, #808080); | |||
| background-repeat: repeat-x; | |||
| filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0); | |||
| border-color: #808080 #808080 #595959; | |||
| border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |||
| filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); | |||
| color: #fff; | |||
| text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | |||
| } | |||
| .datepicker table tr td.selected:hover, | |||
| .datepicker table tr td.selected:hover:hover, | |||
| .datepicker table tr td.selected.disabled:hover, | |||
| .datepicker table tr td.selected.disabled:hover:hover, | |||
| .datepicker table tr td.selected:active, | |||
| .datepicker table tr td.selected:hover:active, | |||
| .datepicker table tr td.selected.disabled:active, | |||
| .datepicker table tr td.selected.disabled:hover:active, | |||
| .datepicker table tr td.selected.active, | |||
| .datepicker table tr td.selected:hover.active, | |||
| .datepicker table tr td.selected.disabled.active, | |||
| .datepicker table tr td.selected.disabled:hover.active, | |||
| .datepicker table tr td.selected.disabled, | |||
| .datepicker table tr td.selected:hover.disabled, | |||
| .datepicker table tr td.selected.disabled.disabled, | |||
| .datepicker table tr td.selected.disabled:hover.disabled, | |||
| .datepicker table tr td.selected[disabled], | |||
| .datepicker table tr td.selected:hover[disabled], | |||
| .datepicker table tr td.selected.disabled[disabled], | |||
| .datepicker table tr td.selected.disabled:hover[disabled] { | |||
| background-color: #808080; | |||
| } | |||
| .datepicker table tr td.selected:active, | |||
| .datepicker table tr td.selected:hover:active, | |||
| .datepicker table tr td.selected.disabled:active, | |||
| .datepicker table tr td.selected.disabled:hover:active, | |||
| .datepicker table tr td.selected.active, | |||
| .datepicker table tr td.selected:hover.active, | |||
| .datepicker table tr td.selected.disabled.active, | |||
| .datepicker table tr td.selected.disabled:hover.active { | |||
| background-color: #666666 \9; | |||
| } | |||
| .datepicker table tr td.active, | |||
| .datepicker table tr td.active:hover, | |||
| .datepicker table tr td.active.disabled, | |||
| .datepicker table tr td.active.disabled:hover { | |||
| background-color: #006dcc; | |||
| background-image: -moz-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -ms-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); | |||
| background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -o-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: linear-gradient(top, #0088cc, #0044cc); | |||
| background-repeat: repeat-x; | |||
| filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); | |||
| border-color: #0044cc #0044cc #002a80; | |||
| border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |||
| filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); | |||
| color: #fff; | |||
| text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | |||
| } | |||
| .datepicker table tr td.active:hover, | |||
| .datepicker table tr td.active:hover:hover, | |||
| .datepicker table tr td.active.disabled:hover, | |||
| .datepicker table tr td.active.disabled:hover:hover, | |||
| .datepicker table tr td.active:active, | |||
| .datepicker table tr td.active:hover:active, | |||
| .datepicker table tr td.active.disabled:active, | |||
| .datepicker table tr td.active.disabled:hover:active, | |||
| .datepicker table tr td.active.active, | |||
| .datepicker table tr td.active:hover.active, | |||
| .datepicker table tr td.active.disabled.active, | |||
| .datepicker table tr td.active.disabled:hover.active, | |||
| .datepicker table tr td.active.disabled, | |||
| .datepicker table tr td.active:hover.disabled, | |||
| .datepicker table tr td.active.disabled.disabled, | |||
| .datepicker table tr td.active.disabled:hover.disabled, | |||
| .datepicker table tr td.active[disabled], | |||
| .datepicker table tr td.active:hover[disabled], | |||
| .datepicker table tr td.active.disabled[disabled], | |||
| .datepicker table tr td.active.disabled:hover[disabled] { | |||
| background-color: #0044cc; | |||
| } | |||
| .datepicker table tr td.active:active, | |||
| .datepicker table tr td.active:hover:active, | |||
| .datepicker table tr td.active.disabled:active, | |||
| .datepicker table tr td.active.disabled:hover:active, | |||
| .datepicker table tr td.active.active, | |||
| .datepicker table tr td.active:hover.active, | |||
| .datepicker table tr td.active.disabled.active, | |||
| .datepicker table tr td.active.disabled:hover.active { | |||
| background-color: #003399 \9; | |||
| } | |||
| .datepicker table tr td span { | |||
| display: block; | |||
| width: 23%; | |||
| height: 54px; | |||
| line-height: 54px; | |||
| float: left; | |||
| margin: 1%; | |||
| cursor: pointer; | |||
| -webkit-border-radius: 4px; | |||
| -moz-border-radius: 4px; | |||
| border-radius: 4px; | |||
| } | |||
| .datepicker table tr td span:hover { | |||
| background: #eeeeee; | |||
| } | |||
| .datepicker table tr td span.disabled, | |||
| .datepicker table tr td span.disabled:hover { | |||
| background: none; | |||
| color: #999999; | |||
| cursor: default; | |||
| } | |||
| .datepicker table tr td span.active, | |||
| .datepicker table tr td span.active:hover, | |||
| .datepicker table tr td span.active.disabled, | |||
| .datepicker table tr td span.active.disabled:hover { | |||
| background-color: #006dcc; | |||
| background-image: -moz-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -ms-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); | |||
| background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -o-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: linear-gradient(top, #0088cc, #0044cc); | |||
| background-repeat: repeat-x; | |||
| filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); | |||
| border-color: #0044cc #0044cc #002a80; | |||
| border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |||
| filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); | |||
| color: #fff; | |||
| text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | |||
| } | |||
| .datepicker table tr td span.active:hover, | |||
| .datepicker table tr td span.active:hover:hover, | |||
| .datepicker table tr td span.active.disabled:hover, | |||
| .datepicker table tr td span.active.disabled:hover:hover, | |||
| .datepicker table tr td span.active:active, | |||
| .datepicker table tr td span.active:hover:active, | |||
| .datepicker table tr td span.active.disabled:active, | |||
| .datepicker table tr td span.active.disabled:hover:active, | |||
| .datepicker table tr td span.active.active, | |||
| .datepicker table tr td span.active:hover.active, | |||
| .datepicker table tr td span.active.disabled.active, | |||
| .datepicker table tr td span.active.disabled:hover.active, | |||
| .datepicker table tr td span.active.disabled, | |||
| .datepicker table tr td span.active:hover.disabled, | |||
| .datepicker table tr td span.active.disabled.disabled, | |||
| .datepicker table tr td span.active.disabled:hover.disabled, | |||
| .datepicker table tr td span.active[disabled], | |||
| .datepicker table tr td span.active:hover[disabled], | |||
| .datepicker table tr td span.active.disabled[disabled], | |||
| .datepicker table tr td span.active.disabled:hover[disabled] { | |||
| background-color: #0044cc; | |||
| } | |||
| .datepicker table tr td span.active:active, | |||
| .datepicker table tr td span.active:hover:active, | |||
| .datepicker table tr td span.active.disabled:active, | |||
| .datepicker table tr td span.active.disabled:hover:active, | |||
| .datepicker table tr td span.active.active, | |||
| .datepicker table tr td span.active:hover.active, | |||
| .datepicker table tr td span.active.disabled.active, | |||
| .datepicker table tr td span.active.disabled:hover.active { | |||
| background-color: #003399 \9; | |||
| } | |||
| .datepicker table tr td span.old, | |||
| .datepicker table tr td span.new { | |||
| color: #999999; | |||
| } | |||
| .datepicker th.datepicker-switch { | |||
| width: 145px; | |||
| } | |||
| .datepicker thead tr:first-child th, | |||
| .datepicker tfoot tr th { | |||
| cursor: pointer; | |||
| } | |||
| .datepicker thead tr:first-child th:hover, | |||
| .datepicker tfoot tr th:hover { | |||
| background: #eeeeee; | |||
| } | |||
| .datepicker .cw { | |||
| font-size: 10px; | |||
| width: 12px; | |||
| padding: 0 2px 0 5px; | |||
| vertical-align: middle; | |||
| } | |||
| .datepicker thead tr:first-child th.cw { | |||
| cursor: default; | |||
| background-color: transparent; | |||
| } | |||
| .input-append.date .add-on i, | |||
| .input-prepend.date .add-on i { | |||
| display: block; | |||
| cursor: pointer; | |||
| width: 16px; | |||
| height: 16px; | |||
| } | |||
| .input-daterange input { | |||
| text-align: center; | |||
| } | |||
| .input-daterange input:first-child { | |||
| -webkit-border-radius: 3px 0 0 3px; | |||
| -moz-border-radius: 3px 0 0 3px; | |||
| border-radius: 3px 0 0 3px; | |||
| } | |||
| .input-daterange input:last-child { | |||
| -webkit-border-radius: 0 3px 3px 0; | |||
| -moz-border-radius: 0 3px 3px 0; | |||
| border-radius: 0 3px 3px 0; | |||
| } | |||
| .input-daterange .add-on { | |||
| display: inline-block; | |||
| width: auto; | |||
| min-width: 16px; | |||
| height: 18px; | |||
| padding: 4px 5px; | |||
| font-weight: normal; | |||
| line-height: 18px; | |||
| text-align: center; | |||
| text-shadow: 0 1px 0 #ffffff; | |||
| vertical-align: middle; | |||
| background-color: #eeeeee; | |||
| border: 1px solid #ccc; | |||
| margin-left: -5px; | |||
| margin-right: -5px; | |||
| } | |||
| @@ -0,0 +1,189 @@ | |||
| /* eslint-disable no-unused-vars */ | |||
| /** | |||
| * @author zhixin wen <wenzhixin2010@gmail.com> | |||
| * extensions: https://github.com/vitalets/x-editable | |||
| */ | |||
| var Utils = $.fn.bootstrapTable.utils | |||
| $.extend($.fn.bootstrapTable.defaults, { | |||
| editable: true, | |||
| onEditableInit () { | |||
| return false | |||
| }, | |||
| onEditableSave (field, row, rowIndex, oldValue, $el) { | |||
| return false | |||
| }, | |||
| onEditableShown (field, row, $el, editable) { | |||
| return false | |||
| }, | |||
| onEditableHidden (field, row, $el, reason) { | |||
| return false | |||
| } | |||
| }) | |||
| $.extend($.fn.bootstrapTable.columnDefaults, { | |||
| alwaysUseFormatter: false | |||
| }) | |||
| $.extend($.fn.bootstrapTable.events, { | |||
| 'editable-init.bs.table': 'onEditableInit', | |||
| 'editable-save.bs.table': 'onEditableSave', | |||
| 'editable-shown.bs.table': 'onEditableShown', | |||
| 'editable-hidden.bs.table': 'onEditableHidden' | |||
| }) | |||
| $.BootstrapTable = class extends $.BootstrapTable { | |||
| initTable () { | |||
| super.initTable() | |||
| if (!this.options.editable) { | |||
| return | |||
| } | |||
| this.editedCells = [] | |||
| $.each(this.columns, (i, column) => { | |||
| if (!column.editable) { | |||
| return | |||
| } | |||
| const editableOptions = {} | |||
| const editableDataMarkup = [] | |||
| const editableDataPrefix = 'editable-' | |||
| const processDataOptions = (key, value) => { | |||
| // Replace camel case with dashes. | |||
| const dashKey = key.replace(/([A-Z])/g, $1 => `-${$1.toLowerCase()}`) | |||
| if (dashKey.indexOf(editableDataPrefix) === 0) { | |||
| editableOptions[dashKey.replace(editableDataPrefix, 'data-')] = value | |||
| } | |||
| } | |||
| $.each(this.options, processDataOptions) | |||
| column.formatter = column.formatter || (value => value) | |||
| column._formatter = column._formatter ? column._formatter : column.formatter | |||
| column.formatter = (value, row, index, field) => { | |||
| let result = Utils.calculateObjectValue(column, column._formatter, [value, row, index], value) | |||
| result = typeof result === 'undefined' || result === null ? this.options.undefinedText : result | |||
| if (this.options.uniqueId !== undefined && !column.alwaysUseFormatter) { | |||
| const uniqueId = Utils.getItemField(row, this.options.uniqueId, false) | |||
| if ($.inArray(column.field + uniqueId, this.editedCells) !== -1) { | |||
| result = value | |||
| } | |||
| } | |||
| $.each(column, processDataOptions) | |||
| $.each(editableOptions, (key, value) => { | |||
| editableDataMarkup.push(` ${key}="${value}"`) | |||
| }) | |||
| let noEditFormatter = false | |||
| const editableOpts = Utils.calculateObjectValue(column, | |||
| column.editable, [index, row], {}) | |||
| if (editableOpts.hasOwnProperty('noEditFormatter')) { | |||
| noEditFormatter = editableOpts.noEditFormatter(value, row, index, field) | |||
| } | |||
| if (noEditFormatter === false) { | |||
| return `<a href="javascript:void(0)" | |||
| data-name="${column.field}" | |||
| data-pk="${row[this.options.idField]}" | |||
| data-value="${result}" | |||
| ${editableDataMarkup.join('')}></a>` | |||
| } | |||
| return noEditFormatter | |||
| } | |||
| }) | |||
| } | |||
| initBody (fixedScroll) { | |||
| super.initBody(fixedScroll) | |||
| if (!this.options.editable) { | |||
| return | |||
| } | |||
| $.each(this.columns, (i, column) => { | |||
| if (!column.editable) { | |||
| return | |||
| } | |||
| const data = this.getData({ escape: true }) | |||
| const $field = this.$body.find(`a[data-name="${column.field}"]`) | |||
| $field.each((i, element) => { | |||
| const $element = $(element) | |||
| const $tr = $element.closest('tr') | |||
| const index = $tr.data('index') | |||
| const row = data[index] | |||
| const editableOpts = Utils.calculateObjectValue(column, | |||
| column.editable, [index, row, $element], {}) | |||
| $element.editable(editableOpts) | |||
| }) | |||
| $field.off('save').on('save', ({ currentTarget }, { submitValue }) => { | |||
| const $this = $(currentTarget) | |||
| const data = this.getData() | |||
| const rowIndex = $this.parents('tr[data-index]').data('index') | |||
| const row = data[rowIndex] | |||
| const oldValue = row[column.field] | |||
| if (this.options.uniqueId !== undefined && !column.alwaysUseFormatter) { | |||
| const uniqueId = Utils.getItemField(row, this.options.uniqueId, false) | |||
| if ($.inArray(column.field + uniqueId, this.editedCells) === -1) { | |||
| this.editedCells.push(column.field + uniqueId) | |||
| } | |||
| } | |||
| submitValue = Utils.escapeHTML(submitValue) | |||
| $this.data('value', submitValue) | |||
| row[column.field] = submitValue | |||
| this.trigger('editable-save', column.field, row, rowIndex, oldValue, $this) | |||
| this.initBody() | |||
| }) | |||
| $field.off('shown').on('shown', ({ currentTarget }, editable) => { | |||
| const $this = $(currentTarget) | |||
| const data = this.getData() | |||
| const rowIndex = $this.parents('tr[data-index]').data('index') | |||
| const row = data[rowIndex] | |||
| this.trigger('editable-shown', column.field, row, $this, editable) | |||
| }) | |||
| $field.off('hidden').on('hidden', ({ currentTarget }, reason) => { | |||
| const $this = $(currentTarget) | |||
| const data = this.getData() | |||
| const rowIndex = $this.parents('tr[data-index]').data('index') | |||
| const row = data[rowIndex] | |||
| this.trigger('editable-hidden', column.field, row, $this, reason) | |||
| }) | |||
| }) | |||
| this.trigger('editable-init') | |||
| } | |||
| getData (params) { | |||
| const data = super.getData(params) | |||
| if (params && params.escape) { | |||
| for (const row of data) { | |||
| for (const [key, value] of Object.entries(row)) { | |||
| if (typeof(value) !== "number") { | |||
| row[key] = Utils.unescapeHTML(value) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return data | |||
| } | |||
| } | |||
| @@ -0,0 +1,335 @@ | |||
| /** | |||
| * @author zhixin wen <wenzhixin2010@gmail.com> | |||
| * extensions: https://github.com/hhurz/tableExport.jquery.plugin | |||
| */ | |||
| var Utils = $.fn.bootstrapTable.utils | |||
| const TYPE_NAME = { | |||
| json: 'JSON', | |||
| xml: 'XML', | |||
| png: 'PNG', | |||
| csv: 'CSV', | |||
| txt: 'TXT', | |||
| sql: 'SQL', | |||
| doc: 'MS-Word', | |||
| excel: 'MS-Excel', | |||
| xlsx: 'MS-Excel (OpenXML)', | |||
| powerpoint: 'MS-Powerpoint', | |||
| pdf: 'PDF' | |||
| } | |||
| Object.assign($.fn.bootstrapTable.defaults, { | |||
| showExport: false, | |||
| exportDataType: 'basic', // basic, all, selected | |||
| exportTypes: ['json', 'xml', 'csv', 'txt', 'sql', 'excel'], | |||
| exportOptions: {}, | |||
| exportFooter: false | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.columnDefaults, { | |||
| forceExport: false, | |||
| forceHide: false | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.defaults.icons, { | |||
| export: { | |||
| bootstrap3: 'glyphicon-export icon-share', | |||
| bootstrap5: 'bi-download', | |||
| materialize: 'file_download', | |||
| 'bootstrap-table': 'icon-download' | |||
| }[$.fn.bootstrapTable.theme] || 'fa-download' | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.locales, { | |||
| formatExport () { | |||
| return 'Export data' | |||
| } | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales) | |||
| $.fn.bootstrapTable.methods.push('exportTable') | |||
| Object.assign($.fn.bootstrapTable.defaults, { | |||
| // eslint-disable-next-line no-unused-vars | |||
| onExportSaved (exportedRows) { | |||
| return false | |||
| }, | |||
| onExportStarted () { | |||
| return false | |||
| } | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.events, { | |||
| 'export-saved.bs.table': 'onExportSaved', | |||
| 'export-started.bs.table': 'onExportStarted' | |||
| }) | |||
| $.BootstrapTable = class extends $.BootstrapTable { | |||
| initToolbar (...args) { | |||
| const o = this.options | |||
| let exportTypes = o.exportTypes | |||
| this.showToolbar = this.showToolbar || o.showExport | |||
| if (this.options.showExport) { | |||
| if (typeof exportTypes === 'string') { | |||
| const types = exportTypes.slice(1, -1).replace(/ /g, '').split(',') | |||
| exportTypes = types.map(t => t.slice(1, -1)) | |||
| } | |||
| if (typeof o.exportOptions === 'string') { | |||
| o.exportOptions = Utils.calculateObjectValue(null, o.exportOptions) | |||
| } | |||
| this.$export = this.$toolbar.find('>.columns div.export') | |||
| if (this.$export.length) { | |||
| this.updateExportButton() | |||
| return | |||
| } | |||
| this.buttons = Object.assign(this.buttons, { | |||
| export: { | |||
| html: | |||
| () => { | |||
| if (exportTypes.length === 1) { | |||
| return ` | |||
| <div class="export ${this.constants.classes.buttonsDropdown}" | |||
| data-type="${exportTypes[0]}"> | |||
| <button class="${this.constants.buttonsClass}" | |||
| aria-label="${o.formatExport()}" | |||
| type="button" | |||
| title="${o.formatExport()}"> | |||
| ${o.showButtonIcons ? Utils.sprintf(this.constants.html.icon, o.iconsPrefix, o.icons.export) : ''} | |||
| ${o.showButtonText ? o.formatExport() : ''} | |||
| </button> | |||
| </div> | |||
| ` | |||
| } | |||
| const html = [] | |||
| html.push(` | |||
| <div class="export ${this.constants.classes.buttonsDropdown}"> | |||
| <button class="${this.constants.buttonsClass} dropdown-toggle" | |||
| aria-label="${o.formatExport()}" | |||
| ${this.constants.dataToggle}="dropdown" | |||
| type="button" | |||
| title="${o.formatExport()}"> | |||
| ${o.showButtonIcons ? Utils.sprintf(this.constants.html.icon, o.iconsPrefix, o.icons.export) : ''} | |||
| ${o.showButtonText ? o.formatExport() : ''} | |||
| ${this.constants.html.dropdownCaret} | |||
| </button> | |||
| ${this.constants.html.toolbarDropdown[0]} | |||
| `) | |||
| for (const type of exportTypes) { | |||
| if (TYPE_NAME.hasOwnProperty(type)) { | |||
| const $item = $(Utils.sprintf(this.constants.html.pageDropdownItem, '', TYPE_NAME[type])) | |||
| $item.attr('data-type', type) | |||
| html.push($item.prop('outerHTML')) | |||
| } | |||
| } | |||
| html.push(this.constants.html.toolbarDropdown[1], '</div>') | |||
| return html.join('') | |||
| } | |||
| } | |||
| }) | |||
| } | |||
| super.initToolbar(...args) | |||
| this.$export = this.$toolbar.find('>.columns div.export') | |||
| if (!this.options.showExport) { | |||
| return | |||
| } | |||
| this.updateExportButton() | |||
| let $exportButtons = this.$export.find('[data-type]') | |||
| if (exportTypes.length === 1) { | |||
| $exportButtons = this.$export | |||
| } | |||
| $exportButtons.click(e => { | |||
| e.preventDefault() | |||
| this.trigger('export-started') | |||
| this.exportTable({ | |||
| type: $(e.currentTarget).data('type') | |||
| }) | |||
| }) | |||
| this.handleToolbar() | |||
| } | |||
| handleToolbar () { | |||
| if (!this.$export) { | |||
| return | |||
| } | |||
| if (super.handleToolbar) { | |||
| super.handleToolbar() | |||
| } | |||
| } | |||
| exportTable (options) { | |||
| const o = this.options | |||
| const stateField = this.header.stateField | |||
| const isCardView = o.cardView | |||
| const doExport = callback => { | |||
| if (stateField) { | |||
| this.hideColumn(stateField) | |||
| } | |||
| if (isCardView) { | |||
| this.toggleView() | |||
| } | |||
| this.columns.forEach(row => { | |||
| if (row.forceHide) { | |||
| this.hideColumn(row.field) | |||
| } | |||
| }) | |||
| const data = this.getData() | |||
| if (o.detailView && o.detailViewIcon) { | |||
| const detailViewIndex = o.detailViewAlign === 'left' ? 0 : this.getVisibleFields().length + Utils.getDetailViewIndexOffset(this.options) | |||
| o.exportOptions.ignoreColumn = [detailViewIndex].concat(o.exportOptions.ignoreColumn || []) | |||
| } | |||
| if (o.exportFooter && o.height) { | |||
| const $footerRow = this.$tableFooter.find('tr').first() | |||
| const footerData = {} | |||
| const footerHtml = [] | |||
| $.each($footerRow.children(), (index, footerCell) => { | |||
| const footerCellHtml = $(footerCell).children('.th-inner').first().html() | |||
| footerData[this.columns[index].field] = footerCellHtml === ' ' ? null : footerCellHtml | |||
| // grab footer cell text into cell index-based array | |||
| footerHtml.push(footerCellHtml) | |||
| }) | |||
| this.$body.append(this.$body.children().last()[0].outerHTML) | |||
| const $lastTableRow = this.$body.children().last() | |||
| $.each($lastTableRow.children(), (index, lastTableRowCell) => { | |||
| $(lastTableRowCell).html(footerHtml[index]) | |||
| }) | |||
| } | |||
| const hiddenColumns = this.getHiddenColumns() | |||
| hiddenColumns.forEach(row => { | |||
| if (row.forceExport) { | |||
| this.showColumn(row.field) | |||
| } | |||
| }) | |||
| if (typeof o.exportOptions.fileName === 'function') { | |||
| options.fileName = o.exportOptions.fileName() | |||
| } | |||
| this.$el.tableExport(Utils.extend({ | |||
| onAfterSaveToFile: () => { | |||
| if (o.exportFooter) { | |||
| this.load(data) | |||
| } | |||
| if (stateField) { | |||
| this.showColumn(stateField) | |||
| } | |||
| if (isCardView) { | |||
| this.toggleView() | |||
| } | |||
| hiddenColumns.forEach(row => { | |||
| if (row.forceExport) { | |||
| this.hideColumn(row.field) | |||
| } | |||
| }) | |||
| this.columns.forEach(row => { | |||
| if (row.forceHide) { | |||
| this.showColumn(row.field) | |||
| } | |||
| }) | |||
| if (callback) callback() | |||
| } | |||
| }, o.exportOptions, options)) | |||
| } | |||
| if (o.exportDataType === 'all' && o.pagination) { | |||
| const eventName = o.sidePagination === 'server' ? | |||
| 'post-body.bs.table' : 'page-change.bs.table' | |||
| const virtualScroll = this.options.virtualScroll | |||
| this.$el.one(eventName, () => { | |||
| setTimeout(() => { | |||
| const data = this.getData() | |||
| doExport(() => { | |||
| this.options.virtualScroll = virtualScroll | |||
| this.togglePagination() | |||
| }) | |||
| this.trigger('export-saved', data) | |||
| }, 0) | |||
| }) | |||
| this.options.virtualScroll = false | |||
| this.togglePagination() | |||
| } else if (o.exportDataType === 'selected') { | |||
| let data = this.getData() | |||
| let selectedData = this.getSelections() | |||
| const pagination = o.pagination | |||
| if (!selectedData.length) { | |||
| return | |||
| } | |||
| if (o.sidePagination === 'server') { | |||
| data = { | |||
| total: o.totalRows, | |||
| [this.options.dataField]: data | |||
| } | |||
| selectedData = { | |||
| total: selectedData.length, | |||
| [this.options.dataField]: selectedData | |||
| } | |||
| } | |||
| this.load(selectedData) | |||
| if (pagination) { | |||
| this.togglePagination() | |||
| } | |||
| doExport(() => { | |||
| if (pagination) { | |||
| this.togglePagination() | |||
| } | |||
| this.load(data) | |||
| }) | |||
| this.trigger('export-saved', selectedData) | |||
| } else { | |||
| doExport() | |||
| this.trigger('export-saved', this.getData(true)) | |||
| } | |||
| } | |||
| updateSelected () { | |||
| super.updateSelected() | |||
| this.updateExportButton() | |||
| } | |||
| updateExportButton () { | |||
| if (this.options.exportDataType === 'selected') { | |||
| this.$export.find('> button') | |||
| .prop('disabled', !this.getSelections().length) | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,92 @@ | |||
| /* | |||
| tableExport.jquery.plugin | |||
| Version 1.10.24 | |||
| Copyright (c) 2015-2021 hhurz, https://github.com/hhurz/tableExport.jquery.plugin | |||
| Based on https://github.com/kayalshri/tableExport.jquery.plugin | |||
| Licensed under the MIT License | |||
| */ | |||
| var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(d,k,y){d instanceof String&&(d=String(d));for(var C=d.length,v=0;v<C;v++){var R=d[v];if(k.call(y,R,v,d))return{i:v,v:R}}return{i:-1,v:void 0}};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(d,k,y){d!=Array.prototype&&d!=Object.prototype&&(d[k]=y.value)}; | |||
| $jscomp.getGlobal=function(d){return"undefined"!=typeof window&&window===d?d:"undefined"!=typeof global&&null!=global?global:d};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(d,k,y,C){if(k){y=$jscomp.global;d=d.split(".");for(C=0;C<d.length-1;C++){var v=d[C];v in y||(y[v]={});y=y[v]}d=d[d.length-1];C=y[d];k=k(C);k!=C&&null!=k&&$jscomp.defineProperty(y,d,{configurable:!0,writable:!0,value:k})}}; | |||
| $jscomp.polyfill("Array.prototype.find",function(d){return d?d:function(d,y){return $jscomp.findInternal(this,d,y).v}},"es6","es3"); | |||
| (function(d){d.fn.tableExport=function(k){function y(b){var c=[];v(b,"thead").each(function(){c.push.apply(c,v(d(this),a.theadSelector).toArray())});return c}function C(b){var c=[];v(b,"tbody").each(function(){c.push.apply(c,v(d(this),a.tbodySelector).toArray())});a.tfootSelector.length&&v(b,"tfoot").each(function(){c.push.apply(c,v(d(this),a.tfootSelector).toArray())});return c}function v(b,a){var c=b[0].tagName,q=b.parents(c).length;return b.find(a).filter(function(){return q===d(this).closest(c).parents(c).length})} | |||
| function R(b){var a=[],e=0,q=0,f=0;d(b).find("thead").first().find("th").each(function(b,c){b=void 0!==d(c).attr("data-field");"undefined"!==typeof c.parentNode.rowIndex&&q!==c.parentNode.rowIndex&&(q=c.parentNode.rowIndex,e=f=0);var h=J(c);for(e+=h?h:1;f<e;)a[f]=b?d(c).attr("data-field"):f.toString(),f++});return a}function I(b){var a="undefined"!==typeof b[0].rowIndex,e=!1===a&&"undefined"!==typeof b[0].cellIndex,q=e||a?Ja(b):b.is(":visible"),f=b.attr("data-tableexport-display");e&&"none"!==f&& | |||
| "always"!==f&&(b=d(b[0].parentNode),a="undefined"!==typeof b[0].rowIndex,f=b.attr("data-tableexport-display"));a&&"none"!==f&&"always"!==f&&(f=b.closest("table").attr("data-tableexport-display"));return"none"!==f&&(!0===q||"always"===f)}function Ja(b){var a=[];V&&(a=K.filter(function(){var a=!1;this.nodeType===b[0].nodeType&&("undefined"!==typeof this.rowIndex&&this.rowIndex===b[0].rowIndex?a=!0:"undefined"!==typeof this.cellIndex&&this.cellIndex===b[0].cellIndex&&"undefined"!==typeof this.parentNode.rowIndex&& | |||
| "undefined"!==typeof b[0].parentNode.rowIndex&&this.parentNode.rowIndex===b[0].parentNode.rowIndex&&(a=!0));return a}));return!1===V||0===a.length}function ta(b,c,e){var q=!1;I(b)?0<a.ignoreColumn.length&&(-1!==d.inArray(e,a.ignoreColumn)||-1!==d.inArray(e-c,a.ignoreColumn)||S.length>e&&"undefined"!==typeof S[e]&&-1!==d.inArray(S[e],a.ignoreColumn))&&(q=!0):q=!0;return q}function E(b,c,e,q,f){if("function"===typeof f){var h=!1;"function"===typeof a.onIgnoreRow&&(h=a.onIgnoreRow(d(b),e));if(!1===h&& | |||
| (0===a.ignoreRow.length||-1===d.inArray(e,a.ignoreRow)&&-1===d.inArray(e-q,a.ignoreRow))&&I(d(b))){b=v(d(b),c);var n=b.length,l=0,u=0;b.each(function(){var b=d(this),a=J(this),c=T(this),h;d.each(G,function(){if(e>this.s.r&&e<=this.e.r&&l>=this.s.c&&l<=this.e.c)for(h=0;h<=this.e.c-this.s.c;++h)n++,u++,f(null,e,l++)});if(c||a)a=a||1,G.push({s:{r:e,c:l},e:{r:e+(c||1)-1,c:l+a-1}});!1===ta(b,n,u++)&&f(this,e,l++);if(1<a)for(h=0;h<a-1;++h)u++,f(null,e,l++)});d.each(G,function(){if(e>=this.s.r&&e<=this.e.r&& | |||
| l>=this.s.c&&l<=this.e.c)for(ea=0;ea<=this.e.c-this.s.c;++ea)f(null,e,l++)})}}}function ua(b,a,e,d){if("undefined"!==typeof d.images&&(e=d.images[e],"undefined"!==typeof e)){a=a.getBoundingClientRect();var c=b.width/b.height,h=a.width/a.height,q=b.width,l=b.height,u=19.049976/25.4,g=0;h<=c?(l=Math.min(b.height,a.height),q=a.width*l/a.height):h>c&&(q=Math.min(b.width,a.width),l=a.height*q/a.width);q*=u;l*=u;l<b.height&&(g=(b.height-l)/2);try{d.doc.addImage(e.src,b.textPos.x,b.y+g,q,l)}catch(Pa){}b.textPos.x+= | |||
| q}}function va(b,c){if("string"===a.outputMode)return b.output();if("base64"===a.outputMode)return L(b.output());if("window"===a.outputMode)window.URL=window.URL||window.webkitURL,window.open(window.URL.createObjectURL(b.output("blob")));else try{var e=b.output("blob");saveAs(e,a.fileName+".pdf")}catch(q){ka(a.fileName+".pdf","data:application/pdf"+(c?"":";base64")+",",c?b.output("blob"):b.output())}}function wa(b,a,e){var c=0;"undefined"!==typeof e&&(c=e.colspan);if(0<=c){for(var f=b.width,d=b.textPos.x, | |||
| n=a.table.columns.indexOf(a.column),l=1;l<c;l++)f+=a.table.columns[n+l].width;1<c&&("right"===b.styles.halign?d=b.textPos.x+f-b.width:"center"===b.styles.halign&&(d=b.textPos.x+(f-b.width)/2));b.width=f;b.textPos.x=d;"undefined"!==typeof e&&1<e.rowspan&&(b.height*=e.rowspan);if("middle"===b.styles.valign||"bottom"===b.styles.valign)e=("string"===typeof b.text?b.text.split(/\r\n|\r|\n/g):b.text).length||1,2<e&&(b.textPos.y-=(2-1.15)/2*a.row.styles.fontSize*(e-2)/3);return!0}return!1}function xa(b, | |||
| a,e){"undefined"!==typeof b&&null!==b&&(b.hasAttribute("data-tableexport-canvas")?(a=(new Date).getTime(),d(b).attr("data-tableexport-canvas",a),e.images[a]={url:'[data-tableexport-canvas="'+a+'"]',src:null}):"undefined"!==a&&null!=a&&a.each(function(){if(d(this).is("img")){var a=ya(this.src);e.images[a]={url:this.src,src:this.src}}xa(b,d(this).children(),e)}))}function Ka(b,a){function c(b){if(b.url)if(b.src){var c=new Image;q=++f;c.crossOrigin="Anonymous";c.onerror=c.onload=function(){if(c.complete&& | |||
| (0===c.src.indexOf("data:image/")&&(c.width=b.width||c.width||0,c.height=b.height||c.height||0),c.width+c.height)){var e=document.createElement("canvas"),d=e.getContext("2d");e.width=c.width;e.height=c.height;d.drawImage(c,0,0);b.src=e.toDataURL("image/png")}--f||a(q)};c.src=b.url}else{var e=d(b.url);e.length&&(q=++f,html2canvas(e[0]).then(function(c){b.src=c.toDataURL("image/png");--f||a(q)}))}}var q=0,f=0;if("undefined"!==typeof b.images)for(var h in b.images)b.images.hasOwnProperty(h)&&c(b.images[h]); | |||
| (b=f)||(a(q),b=void 0);return b}function za(b,c,e){c.each(function(){if(d(this).is("div")){var c=fa(M(this,"background-color"),[255,255,255]),f=fa(M(this,"border-top-color"),[0,0,0]),h=ha(this,"border-top-width",a.jspdf.unit),n=this.getBoundingClientRect(),l=this.offsetLeft*e.wScaleFactor,u=this.offsetTop*e.hScaleFactor,g=n.width*e.wScaleFactor;n=n.height*e.hScaleFactor;e.doc.setDrawColor.apply(void 0,f);e.doc.setFillColor.apply(void 0,c);e.doc.setLineWidth(h);e.doc.rect(b.x+l,b.y+u,g,n,h?"FD":"F")}else d(this).is("img")&& | |||
| (c=ya(this.src),ua(b,this,c,e));za(b,d(this).children(),e)})}function Aa(b,c,e){if("function"===typeof e.onAutotableText)e.onAutotableText(e.doc,b,c);else{var q=b.textPos.x,f=b.textPos.y,h={halign:b.styles.halign,valign:b.styles.valign};if(c.length){for(c=c[0];c.previousSibling;)c=c.previousSibling;for(var n=!1,l=!1;c;){var u=c.innerText||c.textContent||"",g=u.length&&" "===u[0]?" ":"",k=1<u.length&&" "===u[u.length-1]?" ":"";!0!==a.preserve.leadingWS&&(u=g+la(u));!0!==a.preserve.trailingWS&&(u=ma(u)+ | |||
| k);d(c).is("br")&&(q=b.textPos.x,f+=e.doc.internal.getFontSize());d(c).is("b")?n=!0:d(c).is("i")&&(l=!0);(n||l)&&e.doc.setFontType(n&&l?"bolditalic":n?"bold":"italic");if(g=e.doc.getStringUnitWidth(u)*e.doc.internal.getFontSize()){"linebreak"===b.styles.overflow&&q>b.textPos.x&&q+g>b.textPos.x+b.width&&(0<=".,!%*;:=-".indexOf(u.charAt(0))&&(k=u.charAt(0),g=e.doc.getStringUnitWidth(k)*e.doc.internal.getFontSize(),q+g<=b.textPos.x+b.width&&(e.doc.autoTableText(k,q,f,h),u=u.substring(1,u.length)),g= | |||
| e.doc.getStringUnitWidth(u)*e.doc.internal.getFontSize()),q=b.textPos.x,f+=e.doc.internal.getFontSize());if("visible"!==b.styles.overflow)for(;u.length&&q+g>b.textPos.x+b.width;)u=u.substring(0,u.length-1),g=e.doc.getStringUnitWidth(u)*e.doc.internal.getFontSize();e.doc.autoTableText(u,q,f,h);q+=g}if(n||l)d(c).is("b")?n=!1:d(c).is("i")&&(l=!1),e.doc.setFontType(n||l?n?"bold":"italic":"normal");c=c.nextSibling}b.textPos.x=q;b.textPos.y=f}else e.doc.autoTableText(b.text,b.textPos.x,b.textPos.y,h)}} | |||
| function W(b,a,e){return null==b?"":b.toString().replace(new RegExp(null==a?"":a.toString().replace(/([.*+?^=!:${}()|\[\]\/\\])/g,"\\$1"),"g"),e)}function la(b){return null==b?"":b.toString().replace(/^\s+/,"")}function ma(b){return null==b?"":b.toString().replace(/\s+$/,"")}function La(b){if(0===a.date.html.length)return!1;a.date.pattern.lastIndex=0;var c=a.date.pattern.exec(b);if(null==c)return!1;b=+c[a.date.match_y];if(0>b||8099<b)return!1;var e=1*c[a.date.match_m];c=1*c[a.date.match_d];if(!isFinite(c))return!1; | |||
| var d=new Date(b,e-1,c,0,0,0);return d.getFullYear()===b&&d.getMonth()===e-1&&d.getDate()===c?new Date(Date.UTC(b,e-1,c,0,0,0)):!1}function na(b){b=b||"0";""!==a.numbers.html.thousandsSeparator&&(b=W(b,a.numbers.html.thousandsSeparator,""));"."!==a.numbers.html.decimalMark&&(b=W(b,a.numbers.html.decimalMark,"."));return"number"===typeof b||!1!==jQuery.isNumeric(b)?b:!1}function Ma(b){-1<b.indexOf("%")?(b=na(b.replace(/%/g,"")),!1!==b&&(b/=100)):b=!1;return b}function D(b,c,e,q){var f="",h="text"; | |||
| if(null!==b){var n=d(b);n.removeData("teUserDefText");if(n[0].hasAttribute("data-tableexport-canvas"))var l="";else if(n[0].hasAttribute("data-tableexport-value"))l=(l=n.attr("data-tableexport-value"))?l+"":"",n.data("teUserDefText",1);else if(l=n.html(),"function"===typeof a.onCellHtmlData)l=a.onCellHtmlData(n,c,e,l),n.data("teUserDefText",1);else if(""!==l){b=d.parseHTML(l);var g=0,k=0;l="";d.each(b,function(){if(d(this).is("input"))l+=n.find("input").eq(g++).val();else if(d(this).is("select"))l+= | |||
| n.find("select option:selected").eq(k++).text();else if(d(this).is("br"))l+="<br>";else{if("undefined"===typeof d(this).html())l+=d(this).text();else if(void 0===jQuery().bootstrapTable||!1===d(this).hasClass("fht-cell")&&!1===d(this).hasClass("filterControl")&&0===n.parents(".detail-view").length)l+=d(this).html();if(d(this).is("a")){var b=n.find("a").attr("href")||"";f="function"===typeof a.onCellHtmlHyperlink?f+a.onCellHtmlHyperlink(n,c,e,b,l):"href"===a.htmlHyperlink?f+b:f+l;l=""}}})}if(l&&""!== | |||
| l&&!0===a.htmlContent)f=d.trim(l);else if(l&&""!==l)if(""!==n.attr("data-tableexport-cellformat")){var m=l.replace(/\n/g,"\u2028").replace(/(<\s*br([^>]*)>)/gi,"\u2060"),p=d("<div/>").html(m).contents();b=!1;m="";d.each(p.text().split("\u2028"),function(b,c){0<b&&(m+=" ");!0!==a.preserve.leadingWS&&(c=la(c));m+=!0!==a.preserve.trailingWS?ma(c):c});d.each(m.split("\u2060"),function(b,c){0<b&&(f+="\n");!0!==a.preserve.leadingWS&&(c=la(c));!0!==a.preserve.trailingWS&&(c=ma(c));f+=c.replace(/\u00AD/g, | |||
| "")});f=f.replace(/\u00A0/g," ");if("json"===a.type||"excel"===a.type&&"xmlss"===a.mso.fileFormat||!1===a.numbers.output)b=na(f),!1!==b&&(h="number",f=Number(b));else if(a.numbers.html.decimalMark!==a.numbers.output.decimalMark||a.numbers.html.thousandsSeparator!==a.numbers.output.thousandsSeparator)if(b=na(f),!1!==b){p=(""+b.substr(0>b?1:0)).split(".");1===p.length&&(p[1]="");var t=3<p[0].length?p[0].length%3:0;h="number";f=(0>b?"-":"")+(a.numbers.output.thousandsSeparator?(t?p[0].substr(0,t)+a.numbers.output.thousandsSeparator: | |||
| "")+p[0].substr(t).replace(/(\d{3})(?=\d)/g,"$1"+a.numbers.output.thousandsSeparator):p[0])+(p[1].length?a.numbers.output.decimalMark+p[1]:"")}}else f=l;!0===a.escape&&(f=escape(f));"function"===typeof a.onCellData&&(f=a.onCellData(n,c,e,f,h),n.data("teUserDefText",1))}void 0!==q&&(q.type=h);return f}function Ba(b){return 0<b.length&&!0===a.preventInjection&&0<="=+-@".indexOf(b.charAt(0))?"'"+b:b}function Na(b,a,e){return a+"-"+e.toLowerCase()}function fa(b,a){(b=/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/.exec(b))&& | |||
| (a=[parseInt(b[1]),parseInt(b[2]),parseInt(b[3])]);return a}function Ca(b){var a=M(b,"text-align"),e=M(b,"font-weight"),d=M(b,"font-style"),f="";"start"===a&&(a="rtl"===M(b,"direction")?"right":"left");700<=e&&(f="bold");"italic"===d&&(f+=d);""===f&&(f="normal");a={style:{align:a,bcolor:fa(M(b,"background-color"),[255,255,255]),color:fa(M(b,"color"),[0,0,0]),fstyle:f},colspan:J(b),rowspan:T(b)};null!==b&&(b=b.getBoundingClientRect(),a.rect={width:b.width,height:b.height});return a}function J(b){var a= | |||
| d(b).attr("data-tableexport-colspan");"undefined"===typeof a&&d(b).is("[colspan]")&&(a=d(b).attr("colspan"));return parseInt(a)||0}function T(b){var a=d(b).attr("data-tableexport-rowspan");"undefined"===typeof a&&d(b).is("[rowspan]")&&(a=d(b).attr("rowspan"));return parseInt(a)||0}function M(a,c){try{return window.getComputedStyle?(c=c.replace(/([a-z])([A-Z])/,Na),window.getComputedStyle(a,null).getPropertyValue(c)):a.currentStyle?a.currentStyle[c]:a.style[c]}catch(e){}return""}function ha(a,c,e){c= | |||
| M(a,c).match(/\d+/);if(null!==c){c=c[0];a=a.parentElement;var b=document.createElement("div");b.style.overflow="hidden";b.style.visibility="hidden";a.appendChild(b);b.style.width=100+e;e=100/b.offsetWidth;a.removeChild(b);return c*e}return 0}function Oa(a){for(var b=new ArrayBuffer(a.length),e=new Uint8Array(b),d=0;d!==a.length;++d)e[d]=a.charCodeAt(d)&255;return b}function oa(a){var b=a.c,e="";for(++b;b;b=Math.floor((b-1)/26))e=String.fromCharCode((b-1)%26+65)+e;return e+(""+(a.r+1))}function pa(a, | |||
| c){if("undefined"===typeof c||"number"===typeof c)return pa(a.s,a.e);"string"!==typeof a&&(a=oa(a));"string"!==typeof c&&(c=oa(c));return a===c?a:a+":"+c}function Da(a,c){var b=Number(a);if(isFinite(b))return b;var d=1;""!==c.thousandsSeparator&&(a=a.replace(new RegExp("([\\d])"+c.thousandsSeparator+"([\\d])","g"),"$1$2"));"."!==c.decimalMark&&(a=a.replace(new RegExp("([\\d])"+c.decimalMark+"([\\d])","g"),"$1.$2"));a=a.replace(/[$]/g,"").replace(/[%]/g,function(){d*=100;return""});if(isFinite(b=Number(a)))return b/ | |||
| d;a=a.replace(/[(](.*)[)]/,function(a,b){d=-d;return b});return isFinite(b=Number(a))?b/d:b}function ya(a){var b=0,d;if(0===a.length)return b;var q=0;for(d=a.length;q<d;q++){var f=a.charCodeAt(q);b=(b<<5)-b+f;b|=0}return b}function N(b,c,d,q,f,h){var e=!0;"function"===typeof a.onBeforeSaveToFile&&(e=a.onBeforeSaveToFile(b,c,d,q,f),"boolean"!==typeof e&&(e=!0));if(e)try{if(Ea=new Blob([b],{type:d+";charset="+q}),saveAs(Ea,c,!1===h),"function"===typeof a.onAfterSaveToFile)a.onAfterSaveToFile(b,c)}catch(l){ka(c, | |||
| "data:"+d+(q.length?";charset="+q:"")+(f.length?";"+f:"")+",",h?"\ufeff"+b:b)}}function ka(b,c,d){var e=window.navigator.userAgent;if(!1!==b&&window.navigator.msSaveOrOpenBlob)window.navigator.msSaveOrOpenBlob(new Blob([d]),b);else if(!1!==b&&(0<e.indexOf("MSIE ")||e.match(/Trident.*rv\:11\./))){if(c=document.createElement("iframe")){document.body.appendChild(c);c.setAttribute("style","display:none");c.contentDocument.open("txt/plain","replace");c.contentDocument.write(d);c.contentDocument.close(); | |||
| c.contentWindow.focus();switch(b.substr(b.lastIndexOf(".")+1)){case "doc":case "json":case "png":case "pdf":case "xls":case "xlsx":b+=".txt"}c.contentDocument.execCommand("SaveAs",!0,b);document.body.removeChild(c)}}else{var f=document.createElement("a");if(f){var h=null;f.style.display="none";!1!==b?f.download=b:f.target="_blank";"object"===typeof d?(window.URL=window.URL||window.webkitURL,e=[],e.push(d),h=window.URL.createObjectURL(new Blob(e,{type:c})),f.href=h):0<=c.toLowerCase().indexOf("base64,")? | |||
| f.href=c+L(d):f.href=c+encodeURIComponent(d);document.body.appendChild(f);if(document.createEvent)null===ia&&(ia=document.createEvent("MouseEvents")),ia.initEvent("click",!0,!1),f.dispatchEvent(ia);else if(document.createEventObject)f.fireEvent("onclick");else if("function"===typeof f.onclick)f.onclick();setTimeout(function(){h&&window.URL.revokeObjectURL(h);document.body.removeChild(f);if("function"===typeof a.onAfterSaveToFile)a.onAfterSaveToFile(d,b)},100)}}}function L(a){var b,d="",q=0;if("string"=== | |||
| typeof a){a=a.replace(/\x0d\x0a/g,"\n");var f="";for(b=0;b<a.length;b++){var h=a.charCodeAt(b);128>h?f+=String.fromCharCode(h):(127<h&&2048>h?f+=String.fromCharCode(h>>6|192):(f+=String.fromCharCode(h>>12|224),f+=String.fromCharCode(h>>6&63|128)),f+=String.fromCharCode(h&63|128))}a=f}for(;q<a.length;){var n=a.charCodeAt(q++);f=a.charCodeAt(q++);b=a.charCodeAt(q++);h=n>>2;n=(n&3)<<4|f>>4;var l=(f&15)<<2|b>>6;var g=b&63;isNaN(f)?l=g=64:isNaN(b)&&(g=64);d=d+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(h)+ | |||
| "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(n)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(l)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(g)}return d}var a={csvEnclosure:'"',csvSeparator:",",csvUseBOM:!0,date:{html:"dd/mm/yyyy"},displayTableName:!1,escape:!1,exportHiddenCells:!1,fileName:"tableExport",htmlContent:!1,htmlHyperlink:"content",ignoreColumn:[],ignoreRow:[],jsonScope:"all",jspdf:{orientation:"p", | |||
| unit:"pt",format:"a4",margins:{left:20,right:10,top:10,bottom:10},onDocCreated:null,autotable:{styles:{cellPadding:2,rowHeight:12,fontSize:8,fillColor:255,textColor:50,fontStyle:"normal",overflow:"ellipsize",halign:"inherit",valign:"middle"},headerStyles:{fillColor:[52,73,94],textColor:255,fontStyle:"bold",halign:"inherit",valign:"middle"},alternateRowStyles:{fillColor:245},tableExport:{doc:null,onAfterAutotable:null,onBeforeAutotable:null,onAutotableText:null,onTable:null,outputImages:!0}}},mso:{fileFormat:"xlshtml", | |||
| onMsoNumberFormat:null,pageFormat:"a4",pageOrientation:"portrait",rtl:!1,styles:[],worksheetName:"",xslx:{formatId:{date:14,numbers:2}}},numbers:{html:{decimalMark:".",thousandsSeparator:","},output:{decimalMark:".",thousandsSeparator:","}},onAfterSaveToFile:null,onBeforeSaveToFile:null,onCellData:null,onCellHtmlData:null,onCellHtmlHyperlink:null,onIgnoreRow:null,onTableExportBegin:null,onTableExportEnd:null,outputMode:"file",pdfmake:{enabled:!1,docDefinition:{pageSize:"A4",pageOrientation:"portrait", | |||
| styles:{header:{background:"#34495E",color:"#FFFFFF",bold:!0,alignment:"center",fillColor:"#34495E"},alternateRow:{fillColor:"#f5f5f5"}},defaultStyle:{color:"#000000",fontSize:8,font:"Roboto"}},fonts:{}},preserve:{leadingWS:!1,trailingWS:!1},preventInjection:!0,sql:{tableEnclosure:"`",columnEnclosure:"`"},tbodySelector:"tr",tfootSelector:"tr",theadSelector:"tr",tableName:"Table",type:"csv"},O={a0:[2383.94,3370.39],a1:[1683.78,2383.94],a2:[1190.55,1683.78],a3:[841.89,1190.55],a4:[595.28,841.89],a5:[419.53, | |||
| 595.28],a6:[297.64,419.53],a7:[209.76,297.64],a8:[147.4,209.76],a9:[104.88,147.4],a10:[73.7,104.88],b0:[2834.65,4008.19],b1:[2004.09,2834.65],b2:[1417.32,2004.09],b3:[1000.63,1417.32],b4:[708.66,1000.63],b5:[498.9,708.66],b6:[354.33,498.9],b7:[249.45,354.33],b8:[175.75,249.45],b9:[124.72,175.75],b10:[87.87,124.72],c0:[2599.37,3676.54],c1:[1836.85,2599.37],c2:[1298.27,1836.85],c3:[918.43,1298.27],c4:[649.13,918.43],c5:[459.21,649.13],c6:[323.15,459.21],c7:[229.61,323.15],c8:[161.57,229.61],c9:[113.39, | |||
| 161.57],c10:[79.37,113.39],dl:[311.81,623.62],letter:[612,792],"government-letter":[576,756],legal:[612,1008],"junior-legal":[576,360],ledger:[1224,792],tabloid:[792,1224],"credit-card":[153,243]},B=this,ia=null,r=[],w=[],p=0,t="",S=[],G=[],Ea,K=[],V=!1;d.extend(!0,a,k);"xlsx"===a.type&&(a.mso.fileFormat=a.type,a.type="excel");"undefined"!==typeof a.excelFileFormat&&"undefined"===a.mso.fileFormat&&(a.mso.fileFormat=a.excelFileFormat);"undefined"!==typeof a.excelPageFormat&&"undefined"===a.mso.pageFormat&& | |||
| (a.mso.pageFormat=a.excelPageFormat);"undefined"!==typeof a.excelPageOrientation&&"undefined"===a.mso.pageOrientation&&(a.mso.pageOrientation=a.excelPageOrientation);"undefined"!==typeof a.excelRTL&&"undefined"===a.mso.rtl&&(a.mso.rtl=a.excelRTL);"undefined"!==typeof a.excelstyles&&"undefined"===a.mso.styles&&(a.mso.styles=a.excelstyles);"undefined"!==typeof a.onMsoNumberFormat&&"undefined"===a.mso.onMsoNumberFormat&&(a.mso.onMsoNumberFormat=a.onMsoNumberFormat);"undefined"!==typeof a.worksheetName&& | |||
| "undefined"===a.mso.worksheetName&&(a.mso.worksheetName=a.worksheetName);a.mso.pageOrientation="l"===a.mso.pageOrientation.substr(0,1)?"landscape":"portrait";a.date.html=a.date.html||"";if(a.date.html.length){k=[];k.dd="(3[01]|[12][0-9]|0?[1-9])";k.mm="(1[012]|0?[1-9])";k.yyyy="((?:1[6-9]|2[0-2])\\d{2})";k.yy="(\\d{2})";var z=a.date.html.match(/[^a-zA-Z0-9]/)[0];z=a.date.html.toLowerCase().split(z);a.date.regex="^\\s*";a.date.regex+=k[z[0]];a.date.regex+="(.)";a.date.regex+=k[z[1]];a.date.regex+= | |||
| "\\2";a.date.regex+=k[z[2]];a.date.regex+="\\s*$";a.date.pattern=new RegExp(a.date.regex,"g");k=z.indexOf("dd")+1;a.date.match_d=k+(1<k?1:0);k=z.indexOf("mm")+1;a.date.match_m=k+(1<k?1:0);k=(0<=z.indexOf("yyyy")?z.indexOf("yyyy"):z.indexOf("yy"))+1;a.date.match_y=k+(1<k?1:0)}S=R(B);if("function"===typeof a.onTableExportBegin)a.onTableExportBegin();if("csv"===a.type||"tsv"===a.type||"txt"===a.type){var P="",Z=0;G=[];p=0;var qa=function(b,c,e){b.each(function(){t="";E(this,c,p,e+b.length,function(b, | |||
| c,d){var e=t,f="";if(null!==b)if(b=D(b,c,d),c=null===b||""===b?"":b.toString(),"tsv"===a.type)b instanceof Date&&b.toLocaleString(),f=W(c,"\t"," ");else if(b instanceof Date)f=a.csvEnclosure+b.toLocaleString()+a.csvEnclosure;else if(f=Ba(c),f=W(f,a.csvEnclosure,a.csvEnclosure+a.csvEnclosure),0<=f.indexOf(a.csvSeparator)||/[\r\n ]/g.test(f))f=a.csvEnclosure+f+a.csvEnclosure;t=e+(f+("tsv"===a.type?"\t":a.csvSeparator))});t=d.trim(t).substring(0,t.length-1);0<t.length&&(0<P.length&&(P+="\n"),P+=t);p++}); | |||
| return b.length};Z+=qa(d(B).find("thead").first().find(a.theadSelector),"th,td",Z);v(d(B),"tbody").each(function(){Z+=qa(v(d(this),a.tbodySelector),"td,th",Z)});a.tfootSelector.length&&qa(d(B).find("tfoot").first().find(a.tfootSelector),"td,th",Z);P+="\n";if("string"===a.outputMode)return P;if("base64"===a.outputMode)return L(P);if("window"===a.outputMode){ka(!1,"data:text/"+("csv"===a.type?"csv":"plain")+";charset=utf-8,",P);return}N(P,a.fileName+"."+a.type,"text/"+("csv"===a.type?"csv":"plain"), | |||
| "utf-8","","csv"===a.type&&a.csvUseBOM)}else if("sql"===a.type){p=0;G=[];var A="INSERT INTO "+a.sql.tableEnclosure+a.tableName+a.sql.tableEnclosure+" (";r=y(d(B));d(r).each(function(){E(this,"th,td",p,r.length,function(b,c,d){b=D(b,c,d)||"";-1<b.indexOf(a.sql.columnEnclosure)&&(b=W(b.toString(),a.sql.columnEnclosure,a.sql.columnEnclosure+a.sql.columnEnclosure));A+=a.sql.columnEnclosure+b+a.sql.columnEnclosure+","});p++;A=d.trim(A).substring(0,A.length-1)});A+=") VALUES ";w=C(d(B));d(w).each(function(){t= | |||
| "";E(this,"td,th",p,r.length+w.length,function(a,c,d){a=D(a,c,d)||"";-1<a.indexOf("'")&&(a=W(a.toString(),"'","''"));t+="'"+a+"',"});3<t.length&&(A+="("+t,A=d.trim(A).substring(0,A.length-1),A+="),");p++});A=d.trim(A).substring(0,A.length-1);A+=";";if("string"===a.outputMode)return A;if("base64"===a.outputMode)return L(A);N(A,a.fileName+".sql","application/sql","utf-8","",!1)}else if("json"===a.type){var X=[];G=[];r=y(d(B));d(r).each(function(){var a=[];E(this,"th,td",p,r.length,function(b,d,g){a.push(D(b, | |||
| d,g))});X.push(a)});var ra=[];w=C(d(B));d(w).each(function(){var a={},c=0;E(this,"td,th",p,r.length+w.length,function(b,d,f){X.length?a[X[X.length-1][c]]=D(b,d,f):a[c]=D(b,d,f);c++});!1===d.isEmptyObject(a)&&ra.push(a);p++});k="head"===a.jsonScope?JSON.stringify(X):"data"===a.jsonScope?JSON.stringify(ra):JSON.stringify({header:X,data:ra});if("string"===a.outputMode)return k;if("base64"===a.outputMode)return L(k);N(k,a.fileName+".json","application/json","utf-8","base64",!1)}else if("xml"===a.type){p= | |||
| 0;G=[];var Q='<?xml version="1.0" encoding="utf-8"?>';Q+="<tabledata><fields>";r=y(d(B));d(r).each(function(){E(this,"th,td",p,r.length,function(a,d,e){Q+="<field>"+D(a,d,e)+"</field>"});p++});Q+="</fields><data>";var Fa=1;w=C(d(B));d(w).each(function(){var a=1;t="";E(this,"td,th",p,r.length+w.length,function(b,d,g){t+="<column-"+a+">"+D(b,d,g)+"</column-"+a+">";a++});0<t.length&&"<column-1></column-1>"!==t&&(Q+='<row id="'+Fa+'">'+t+"</row>",Fa++);p++});Q+="</data></tabledata>";if("string"===a.outputMode)return Q; | |||
| if("base64"===a.outputMode)return L(Q);N(Q,a.fileName+".xml","application/xml","utf-8","base64",!1)}else if("excel"===a.type&&"xmlss"===a.mso.fileFormat){var sa=[],F=[];d(B).filter(function(){return I(d(this))}).each(function(){function b(a,b,c){var f=[];d(a).each(function(){var b=0,e=0;t="";E(this,"td,th",p,c+a.length,function(a,c,h){if(null!==a){var l="";c=D(a,c,h);h="String";if(!1!==jQuery.isNumeric(c))h="Number";else{var n=Ma(c);!1!==n&&(c=n,h="Number",l+=' ss:StyleID="pct1"')}"Number"!==h&&(c= | |||
| c.replace(/\n/g,"<br>"));n=J(a);a=T(a);d.each(f,function(){if(p>=this.s.r&&p<=this.e.r&&e>=this.s.c&&e<=this.e.c)for(var a=0;a<=this.e.c-this.s.c;++a)e++,b++});if(a||n)a=a||1,n=n||1,f.push({s:{r:p,c:e},e:{r:p+a-1,c:e+n-1}});1<n&&(l+=' ss:MergeAcross="'+(n-1)+'"',e+=n-1);1<a&&(l+=' ss:MergeDown="'+(a-1)+'" ss:StyleID="rsp1"');0<b&&(l+=' ss:Index="'+(e+1)+'"',b=0);t+="<Cell"+l+'><Data ss:Type="'+h+'">'+d("<div />").text(c).html()+"</Data></Cell>\r";e++}});0<t.length&&(H+='<Row ss:AutoFitHeight="0">\r'+ | |||
| t+"</Row>\r");p++});return a.length}var c=d(this),e="";"string"===typeof a.mso.worksheetName&&a.mso.worksheetName.length?e=a.mso.worksheetName+" "+(F.length+1):"undefined"!==typeof a.mso.worksheetName[F.length]&&(e=a.mso.worksheetName[F.length]);e.length||(e=c.find("caption").text()||"");e.length||(e="Table "+(F.length+1));e=d.trim(e.replace(/[\\\/[\]*:?'"]/g,"").substring(0,31));F.push(d("<div />").text(e).html());!1===a.exportHiddenCells&&(K=c.find("tr, th, td").filter(":hidden"),V=0<K.length); | |||
| p=0;S=R(this);H="<Table>\r";e=b(y(c),"th,td",0);b(C(c),"td,th",e);H+="</Table>\r";sa.push(H)});k={};z={};for(var m,aa,Y=0,ea=F.length;Y<ea;Y++)m=F[Y],aa=k[m],aa=k[m]=null==aa?1:aa+1,2===aa&&(F[z[m]]=F[z[m]].substring(0,29)+"-1"),1<k[m]?F[Y]=F[Y].substring(0,29)+"-"+k[m]:z[m]=Y;k='<?xml version="1.0" encoding="UTF-8"?>\r<?mso-application progid="Excel.Sheet"?>\r<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"\r xmlns:o="urn:schemas-microsoft-com:office:office"\r xmlns:x="urn:schemas-microsoft-com:office:excel"\r xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"\r xmlns:html="http://www.w3.org/TR/REC-html40">\r<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">\r <Created>'+ | |||
| (new Date).toISOString()+'</Created>\r</DocumentProperties>\r<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">\r <AllowPNG/>\r</OfficeDocumentSettings>\r<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">\r <WindowHeight>9000</WindowHeight>\r <WindowWidth>13860</WindowWidth>\r <WindowTopX>0</WindowTopX>\r <WindowTopY>0</WindowTopY>\r <ProtectStructure>False</ProtectStructure>\r <ProtectWindows>False</ProtectWindows>\r</ExcelWorkbook>\r<Styles>\r <Style ss:ID="Default" ss:Name="Normal">\r <Alignment ss:Vertical="Bottom"/>\r <Borders/>\r <Font/>\r <Interior/>\r <NumberFormat/>\r <Protection/>\r </Style>\r <Style ss:ID="rsp1">\r <Alignment ss:Vertical="Center"/>\r </Style>\r <Style ss:ID="pct1">\r <NumberFormat ss:Format="Percent"/>\r </Style>\r</Styles>\r'; | |||
| for(z=0;z<sa.length;z++)k+='<Worksheet ss:Name="'+F[z]+'" ss:RightToLeft="'+(a.mso.rtl?"1":"0")+'">\r'+sa[z],k=a.mso.rtl?k+'<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">\r<DisplayRightToLeft/>\r</WorksheetOptions>\r':k+'<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel"/>\r',k+="</Worksheet>\r";k+="</Workbook>\r";if("string"===a.outputMode)return k;if("base64"===a.outputMode)return L(k);N(k,a.fileName+".xml","application/xml","utf-8","base64",!1)}else if("excel"=== | |||
| a.type&&"xlsx"===a.mso.fileFormat){var ba=[],Ga=XLSX.utils.book_new();d(B).filter(function(){return I(d(this))}).each(function(){for(var b=d(this),c={},e=this.getElementsByTagName("tr"),g={s:{r:0,c:0},e:{r:0,c:0}},f=[],h,n=[],l=0,u=0,k,m,p,t,r,w=XLSX.SSF.get_table();l<e.length&&1E7>u;++l)if(k=e[l],m=!1,"function"===typeof a.onIgnoreRow&&(m=a.onIgnoreRow(d(k),l)),!0!==m&&(0===a.ignoreRow.length||-1===d.inArray(l,a.ignoreRow)&&-1===d.inArray(l-e.length,a.ignoreRow))&&!1!==I(d(k))){var y=k.children, | |||
| B=0;for(k=0;k<y.length;++k)r=y[k],t=+J(r)||1,B+=t;var z=0;for(k=m=0;k<y.length;++k)if(r=y[k],t=+J(r)||1,h=k+z,!ta(d(r),B,h+(h<m?m-h:0))){z+=t-1;for(h=0;h<f.length;++h){var v=f[h];v.s.c==m&&v.s.r<=u&&u<=v.e.r&&(m=v.e.c+1,h=-1)}(0<(p=+T(r))||1<t)&&f.push({s:{r:u,c:m},e:{r:u+(p||1)-1,c:m+t-1}});var C={type:""};h=D(r,l,k+z,C);v={t:"s",v:h};var A="";if(""!==(d(r).attr("data-tableexport-cellformat")||"")){var x=parseInt(d(r).attr("data-tableexport-xlsxformatid")||0);0===x&&"function"===typeof a.mso.xslx.formatId.numbers&& | |||
| (x=a.mso.xslx.formatId.numbers(d(r),l,k+z));0===x&&"function"===typeof a.mso.xslx.formatId.date&&(x=a.mso.xslx.formatId.date(d(r),l,k+z));if(49===x||"@"===x)A="s";else if("number"===C.type||0<x&&14>x||36<x&&41>x||48===x)A="n";else if("date"===C.type||13<x&&37>x||44<x&&48>x||56===x)A="d"}else A="s";if(null!=h)if(0===h.length)v.t="z";else if(0!==h.trim().length)if("s"===A)d(r).find("a").length&&(h="href"!==a.htmlHyperlink?h:"",v={f:'=HYPERLINK("'+d(r).find("a").attr("href")+(h.length?'","'+h:"")+'")'}); | |||
| else if("function"===C.type)v={f:h};else if("TRUE"===h)v={t:"b",v:!0};else if("FALSE"===h)v={t:"b",v:!1};else if("n"===A||isFinite(Da(h,a.numbers.output))){if(r=Da(h,a.numbers.output),0===x&&"function"!==typeof a.mso.xslx.formatId.numbers&&(x=a.mso.xslx.formatId.numbers),isFinite(r)||isFinite(h))v={t:"n",v:isFinite(r)?r:h,z:"string"===typeof x?x:x in w?w[x]:"0.00"}}else if(!1!==(r=La(h))||"d"===A)0===x&&"function"!==typeof a.mso.xslx.formatId.date&&(x=a.mso.xslx.formatId.date),v={t:"d",v:!1!==r?r: | |||
| h,z:"string"===typeof x?x:x in w?w[x]:"m/d/yy"};c[oa({c:m,r:u})]=v;g.e.c<m&&(g.e.c=m);m+=t}++u}f.length&&(c["!merges"]=f);n.length&&(c["!rows"]=n);g.e.r=u-1;c["!ref"]=pa(g);1E7<=u&&(c["!fullref"]=pa((g.e.r=e.length-l+u-1,g)));e="";"string"===typeof a.mso.worksheetName&&a.mso.worksheetName.length?e=a.mso.worksheetName+" "+(ba.length+1):"undefined"!==typeof a.mso.worksheetName[ba.length]&&(e=a.mso.worksheetName[ba.length]);e.length||(e=b.find("caption").text()||"");e.length||(e="Table "+(ba.length+ | |||
| 1));e=d.trim(e.replace(/[\\\/[\]*:?'"]/g,"").substring(0,31));ba.push(e);XLSX.utils.book_append_sheet(Ga,c,e)});k=XLSX.write(Ga,{type:"binary",bookType:a.mso.fileFormat,bookSST:!1});N(Oa(k),a.fileName+"."+a.mso.fileFormat,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","UTF-8","",!1)}else if("excel"===a.type||"xls"===a.type||"word"===a.type||"doc"===a.type){k="excel"===a.type||"xls"===a.type?"excel":"word";z="excel"===k?"xls":"doc";m='xmlns:x="urn:schemas-microsoft-com:office:'+ | |||
| k+'"';var H="",ca="";d(B).filter(function(){return I(d(this))}).each(function(){var b=d(this);""===ca&&(ca=a.mso.worksheetName||b.find("caption").text()||"Table",ca=d.trim(ca.replace(/[\\\/[\]*:?'"]/g,"").substring(0,31)));!1===a.exportHiddenCells&&(K=b.find("tr, th, td").filter(":hidden"),V=0<K.length);p=0;G=[];S=R(this);H+="<table><thead>";r=y(b);d(r).each(function(){var b=d(this);t="";E(this,"th,td",p,r.length,function(d,c,f){if(null!==d){var e="";t+="<th";if(a.mso.styles.length){var n=document.defaultView.getComputedStyle(d, | |||
| null),l=document.defaultView.getComputedStyle(b[0],null),g;for(g in a.mso.styles){var k=n[a.mso.styles[g]];""===k&&(k=l[a.mso.styles[g]]);""!==k&&"0px none rgb(0, 0, 0)"!==k&&"rgba(0, 0, 0, 0)"!==k&&(e+=""===e?'style="':";",e+=a.mso.styles[g]+":"+k)}}""!==e&&(t+=" "+e+'"');e=J(d);0<e&&(t+=' colspan="'+e+'"');e=T(d);0<e&&(t+=' rowspan="'+e+'"');t+=">"+D(d,c,f)+"</th>"}});0<t.length&&(H+="<tr>"+t+"</tr>");p++});H+="</thead><tbody>";w=C(b);d(w).each(function(){var b=d(this);t="";E(this,"td,th",p,r.length+ | |||
| w.length,function(c,g,f){if(null!==c){var e=D(c,g,f),n="",l=d(c).attr("data-tableexport-msonumberformat");"undefined"===typeof l&&"function"===typeof a.mso.onMsoNumberFormat&&(l=a.mso.onMsoNumberFormat(c,g,f));"undefined"!==typeof l&&""!==l&&(n="style=\"mso-number-format:'"+l+"'");if(a.mso.styles.length){g=document.defaultView.getComputedStyle(c,null);f=document.defaultView.getComputedStyle(b[0],null);for(var k in a.mso.styles)l=g[a.mso.styles[k]],""===l&&(l=f[a.mso.styles[k]]),""!==l&&"0px none rgb(0, 0, 0)"!== | |||
| l&&"rgba(0, 0, 0, 0)"!==l&&(n+=""===n?'style="':";",n+=a.mso.styles[k]+":"+l)}t+="<td";""!==n&&(t+=" "+n+'"');n=J(c);0<n&&(t+=' colspan="'+n+'"');c=T(c);0<c&&(t+=' rowspan="'+c+'"');"string"===typeof e&&""!==e&&(e=Ba(e),e=e.replace(/\n/g,"<br>"));t+=">"+e+"</td>"}});0<t.length&&(H+="<tr>"+t+"</tr>");p++});a.displayTableName&&(H+="<tr><td></td></tr><tr><td></td></tr><tr><td>"+D(d("<p>"+a.tableName+"</p>"))+"</td></tr>");H+="</tbody></table>"});m='<html xmlns:o="urn:schemas-microsoft-com:office:office" '+ | |||
| m+' xmlns="http://www.w3.org/TR/REC-html40">'+('<meta http-equiv="content-type" content="application/vnd.ms-'+k+'; charset=UTF-8">')+"<head>";"excel"===k&&(m+="\x3c!--[if gte mso 9]>",m+="<xml>",m+="<x:ExcelWorkbook>",m+="<x:ExcelWorksheets>",m+="<x:ExcelWorksheet>",m+="<x:Name>",m+=ca,m+="</x:Name>",m+="<x:WorksheetOptions>",m+="<x:DisplayGridlines/>",a.mso.rtl&&(m+="<x:DisplayRightToLeft/>"),m+="</x:WorksheetOptions>",m+="</x:ExcelWorksheet>",m+="</x:ExcelWorksheets>",m+="</x:ExcelWorkbook>",m+= | |||
| "</xml>",m+="<![endif]--\x3e");m+="<style>";m+="@page { size:"+a.mso.pageOrientation+"; mso-page-orientation:"+a.mso.pageOrientation+"; }";m+="@page Section1 {size:"+O[a.mso.pageFormat][0]+"pt "+O[a.mso.pageFormat][1]+"pt";m+="; margin:1.0in 1.25in 1.0in 1.25in;mso-header-margin:.5in;mso-footer-margin:.5in;mso-paper-source:0;}";m+="div.Section1 {page:Section1;}";m+="@page Section2 {size:"+O[a.mso.pageFormat][1]+"pt "+O[a.mso.pageFormat][0]+"pt";m+=";mso-page-orientation:"+a.mso.pageOrientation+";margin:1.25in 1.0in 1.25in 1.0in;mso-header-margin:.5in;mso-footer-margin:.5in;mso-paper-source:0;}"; | |||
| m+="div.Section2 {page:Section2;}";m+="br {mso-data-placement:same-cell;}";m+="</style>";m+="</head>";m+="<body>";m+='<div class="Section'+("landscape"===a.mso.pageOrientation?"2":"1")+'">';m+=H;m+="</div>";m+="</body>";m+="</html>";if("string"===a.outputMode)return m;if("base64"===a.outputMode)return L(m);N(m,a.fileName+"."+z,"application/vnd.ms-"+k,"","base64",!1)}else if("png"===a.type)html2canvas(d(B)[0]).then(function(b){b=b.toDataURL();for(var c=atob(b.substring(22)),d=new ArrayBuffer(c.length), | |||
| g=new Uint8Array(d),f=0;f<c.length;f++)g[f]=c.charCodeAt(f);if("string"===a.outputMode)return c;if("base64"===a.outputMode)return L(b);"window"===a.outputMode?window.open(b):N(d,a.fileName+".png","image/png","","",!1)});else if("pdf"===a.type)if(!0===a.pdfmake.enabled){var U={content:[]};d.extend(!0,U,a.pdfmake.docDefinition);G=[];d(B).filter(function(){return I(d(this))}).each(function(){var b=d(this),c=[],e=[];p=0;var g=function(a,b,c){var f=0;d(a).each(function(){var a=[];E(this,b,p,c,function(c, | |||
| d,f){if("undefined"!==typeof c&&null!==c){var e=J(c),h=T(c);c={text:D(c,d,f)||" "};if(1<e||1<h)c.colSpan=e||1,c.rowSpan=h||1}else c={text:" "};0<=b.indexOf("th")&&(c.style="header");a.push(c)});for(var d=a.length;d<c;d++)a.push("");a.length&&e.push(a);f<a.length&&(f=a.length);p++});return f};r=y(b);for(var f=g(r,"th,td",r.length),h=c.length;h<f;h++)c.push("*");w=C(b);f=g(w,"td",r.length+w.length);for(h=c.length;h<f;h++)c.push("*");U.content.push({table:{headerRows:r.length?r.length:null,widths:c, | |||
| body:e},layout:{layout:"noBorders",hLineStyle:function(a,b){return 0},vLineWidth:function(a,b){return 0},hLineColor:function(b,c){return b<c.table.headerRows?a.pdfmake.docDefinition.styles.header.background:a.pdfmake.docDefinition.styles.alternateRow.fillColor},vLineColor:function(b,c){return b<c.table.headerRows?a.pdfmake.docDefinition.styles.header.background:a.pdfmake.docDefinition.styles.alternateRow.fillColor},fillColor:function(b,c,d){return 0===b%2?a.pdfmake.docDefinition.styles.alternateRow.fillColor: | |||
| null}},pageBreak:U.content.length?"before":void 0})});"undefined"!==typeof pdfMake&&"undefined"!==typeof pdfMake.createPdf&&(pdfMake.fonts={Roboto:{normal:"Roboto-Regular.ttf",bold:"Roboto-Medium.ttf",italics:"Roboto-Italic.ttf",bolditalics:"Roboto-MediumItalic.ttf"}},pdfMake.vfs.hasOwnProperty("Mirza-Regular.ttf")?(U.defaultStyle.font="Mirza",d.extend(!0,pdfMake.fonts,{Mirza:{normal:"Mirza-Regular.ttf",bold:"Mirza-Bold.ttf",italics:"Mirza-Medium.ttf",bolditalics:"Mirza-SemiBold.ttf"}})):pdfMake.vfs.hasOwnProperty("gbsn00lp.ttf")? | |||
| (U.defaultStyle.font="gbsn00lp",d.extend(!0,pdfMake.fonts,{gbsn00lp:{normal:"gbsn00lp.ttf",bold:"gbsn00lp.ttf",italics:"gbsn00lp.ttf",bolditalics:"gbsn00lp.ttf"}})):pdfMake.vfs.hasOwnProperty("ZCOOLXiaoWei-Regular.ttf")&&(U.defaultStyle.font="ZCOOLXiaoWei",d.extend(!0,pdfMake.fonts,{ZCOOLXiaoWei:{normal:"ZCOOLXiaoWei-Regular.ttf",bold:"ZCOOLXiaoWei-Regular.ttf",italics:"ZCOOLXiaoWei-Regular.ttf",bolditalics:"ZCOOLXiaoWei-Regular.ttf"}})),d.extend(!0,pdfMake.fonts,a.pdfmake.fonts),pdfMake.createPdf(U).getBuffer(function(b){N(b, | |||
| a.fileName+".pdf","application/pdf","","",!1)}))}else if(!1===a.jspdf.autotable){k={dim:{w:ha(d(B).first().get(0),"width","mm"),h:ha(d(B).first().get(0),"height","mm")},pagesplit:!1};var Ha=new jsPDF(a.jspdf.orientation,a.jspdf.unit,a.jspdf.format);Ha.addHTML(d(B).first(),a.jspdf.margins.left,a.jspdf.margins.top,k,function(){va(Ha,!1)})}else{var g=a.jspdf.autotable.tableExport;if("string"===typeof a.jspdf.format&&"bestfit"===a.jspdf.format.toLowerCase()){var ja="",da="",Ia=0;d(B).each(function(){if(I(d(this))){var a= | |||
| ha(d(this).get(0),"width","pt");if(a>Ia){a>O.a0[0]&&(ja="a0",da="l");for(var c in O)O.hasOwnProperty(c)&&O[c][1]>a&&(ja=c,da="l",O[c][0]>a&&(da="p"));Ia=a}}});a.jspdf.format=""===ja?"a4":ja;a.jspdf.orientation=""===da?"w":da}if(null==g.doc&&(g.doc=new jsPDF(a.jspdf.orientation,a.jspdf.unit,a.jspdf.format),g.wScaleFactor=1,g.hScaleFactor=1,"function"===typeof a.jspdf.onDocCreated))a.jspdf.onDocCreated(g.doc);!0===g.outputImages&&(g.images={});"undefined"!==typeof g.images&&(d(B).filter(function(){return I(d(this))}).each(function(){var b= | |||
| 0;G=[];!1===a.exportHiddenCells&&(K=d(this).find("tr, th, td").filter(":hidden"),V=0<K.length);r=y(d(this));w=C(d(this));d(w).each(function(){E(this,"td,th",r.length+b,r.length+w.length,function(a){xa(a,d(a).children(),g)});b++})}),r=[],w=[]);Ka(g,function(){d(B).filter(function(){return I(d(this))}).each(function(){var b;p=0;G=[];!1===a.exportHiddenCells&&(K=d(this).find("tr, th, td").filter(":hidden"),V=0<K.length);S=R(this);g.columns=[];g.rows=[];g.teCells={};if("function"===typeof g.onTable&& | |||
| !1===g.onTable(d(this),a))return!0;a.jspdf.autotable.tableExport=null;var c=d.extend(!0,{},a.jspdf.autotable);a.jspdf.autotable.tableExport=g;c.margin={};d.extend(!0,c.margin,a.jspdf.margins);c.tableExport=g;"function"!==typeof c.beforePageContent&&(c.beforePageContent=function(a){if(1===a.pageCount){var b=a.table.rows.concat(a.table.headerRow);d.each(b,function(){0<this.height&&(this.height+=(2-1.15)/2*this.styles.fontSize,a.table.height+=(2-1.15)/2*this.styles.fontSize)})}});"function"!==typeof c.createdHeaderCell&& | |||
| (c.createdHeaderCell=function(a,b){a.styles=d.extend({},b.row.styles);if("undefined"!==typeof g.columns[b.column.dataKey]){var e=g.columns[b.column.dataKey];if("undefined"!==typeof e.rect){a.contentWidth=e.rect.width;if("undefined"===typeof g.heightRatio||0===g.heightRatio){var f=b.row.raw[b.column.dataKey].rowspan?b.row.raw[b.column.dataKey].rect.height/b.row.raw[b.column.dataKey].rowspan:b.row.raw[b.column.dataKey].rect.height;g.heightRatio=a.styles.rowHeight/f}f=b.row.raw[b.column.dataKey].rect.height* | |||
| g.heightRatio;f>a.styles.rowHeight&&(a.styles.rowHeight=f)}a.styles.halign="inherit"===c.headerStyles.halign?"center":c.headerStyles.halign;a.styles.valign=c.headerStyles.valign;"undefined"!==typeof e.style&&!0!==e.style.hidden&&("inherit"===c.headerStyles.halign&&(a.styles.halign=e.style.align),"inherit"===c.styles.fillColor&&(a.styles.fillColor=e.style.bcolor),"inherit"===c.styles.textColor&&(a.styles.textColor=e.style.color),"inherit"===c.styles.fontStyle&&(a.styles.fontStyle=e.style.fstyle))}}); | |||
| "function"!==typeof c.createdCell&&(c.createdCell=function(a,b){b=g.teCells[b.row.index+":"+b.column.dataKey];a.styles.halign="inherit"===c.styles.halign?"center":c.styles.halign;a.styles.valign=c.styles.valign;"undefined"!==typeof b&&"undefined"!==typeof b.style&&!0!==b.style.hidden&&("inherit"===c.styles.halign&&(a.styles.halign=b.style.align),"inherit"===c.styles.fillColor&&(a.styles.fillColor=b.style.bcolor),"inherit"===c.styles.textColor&&(a.styles.textColor=b.style.color),"inherit"===c.styles.fontStyle&& | |||
| (a.styles.fontStyle=b.style.fstyle))});"function"!==typeof c.drawHeaderCell&&(c.drawHeaderCell=function(a,b){var c=g.columns[b.column.dataKey];return(!0!==c.style.hasOwnProperty("hidden")||!0!==c.style.hidden)&&0<=c.rowIndex?wa(a,b,c):!1});"function"!==typeof c.drawCell&&(c.drawCell=function(a,b){var c=g.teCells[b.row.index+":"+b.column.dataKey];if(!0!==("undefined"!==typeof c&&c.isCanvas))wa(a,b,c)&&(g.doc.rect(a.x,a.y,a.width,a.height,a.styles.fillStyle),"undefined"===typeof c||"undefined"!==typeof c.hasUserDefText&& | |||
| !0===c.hasUserDefText||"undefined"===typeof c.elements||!c.elements.length?Aa(a,{},g):(b=a.height/c.rect.height,b>g.hScaleFactor&&(g.hScaleFactor=b),g.wScaleFactor=a.width/c.rect.width,b=a.textPos.y,za(a,c.elements,g),a.textPos.y=b,Aa(a,c.elements,g)));else{c=c.elements[0];var e=d(c).attr("data-tableexport-canvas"),f=c.getBoundingClientRect();a.width=f.width*g.wScaleFactor;a.height=f.height*g.hScaleFactor;b.row.height=a.height;ua(a,c,e,g)}return!1});g.headerrows=[];r=y(d(this));d(r).each(function(){b= | |||
| 0;g.headerrows[p]=[];E(this,"th,td",p,r.length,function(a,c,d){var e=Ca(a);e.title=D(a,c,d);e.key=b++;e.rowIndex=p;g.headerrows[p].push(e)});p++});if(0<p)for(var e=p-1;0<=e;)d.each(g.headerrows[e],function(){var a=this;0<e&&null===this.rect&&(a=g.headerrows[e-1][this.key]);null!==a&&0<=a.rowIndex&&(!0!==a.style.hasOwnProperty("hidden")||!0!==a.style.hidden)&&g.columns.push(a)}),e=0<g.columns.length?-1:e-1;var k=0;w=[];w=C(d(this));d(w).each(function(){var a=[];b=0;E(this,"td,th",p,r.length+w.length, | |||
| function(c,e,f){if("undefined"===typeof g.columns[b]){var h={title:"",key:b,style:{hidden:!0}};g.columns.push(h)}a.push(D(c,e,f));"undefined"!==typeof c&&null!==c?(h=Ca(c),h.isCanvas=c.hasAttribute("data-tableexport-canvas"),h.elements=h.isCanvas?d(c):d(c).children(),"undefined"!==typeof d(c).data("teUserDefText")&&(h.hasUserDefText=!0)):(h=d.extend(!0,{},g.teCells[k+":"+(b-1)]),h.colspan=-1);g.teCells[k+":"+b++]=h});a.length&&(g.rows.push(a),k++);p++});if("function"===typeof g.onBeforeAutotable)g.onBeforeAutotable(d(this), | |||
| g.columns,g.rows,c);g.doc.autoTable(g.columns,g.rows,c);if("function"===typeof g.onAfterAutotable)g.onAfterAutotable(d(this),c);a.jspdf.autotable.startY=g.doc.autoTableEndPosY()+c.margin.top});va(g.doc,"undefined"!==typeof g.images&&!1===jQuery.isEmptyObject(g.images));"undefined"!==typeof g.headerrows&&(g.headerrows.length=0);"undefined"!==typeof g.columns&&(g.columns.length=0);"undefined"!==typeof g.rows&&(g.rows.length=0);delete g.doc;g.doc=null})}if("function"===typeof a.onTableExportEnd)a.onTableExportEnd(); | |||
| return this}})(jQuery); | |||
| @@ -0,0 +1,123 @@ | |||
| /** | |||
| * @author: Dennis Hernández | |||
| * @update zhixin wen <wenzhixin2010@gmail.com> | |||
| */ | |||
| const debounce = (func, wait) => { | |||
| let timeout = 0 | |||
| return (...args) => { | |||
| const later = () => { | |||
| timeout = 0 | |||
| func(...args) | |||
| } | |||
| clearTimeout(timeout) | |||
| timeout = setTimeout(later, wait) | |||
| } | |||
| } | |||
| Object.assign($.fn.bootstrapTable.defaults, { | |||
| mobileResponsive: false, | |||
| minWidth: 562, | |||
| minHeight: undefined, | |||
| heightThreshold: 100, // just slightly larger than mobile chrome's auto-hiding toolbar | |||
| checkOnInit: true, | |||
| columnsHidden: [] | |||
| }) | |||
| $.BootstrapTable = class extends $.BootstrapTable { | |||
| init (...args) { | |||
| super.init(...args) | |||
| if (!this.options.mobileResponsive || !this.options.minWidth) { | |||
| return | |||
| } | |||
| if (this.options.minWidth < 100 && this.options.resizable) { | |||
| console.warn('The minWidth when the resizable extension is active should be greater or equal than 100') | |||
| this.options.minWidth = 100 | |||
| } | |||
| let old = { | |||
| width: $(window).width(), | |||
| height: $(window).height() | |||
| } | |||
| $(window).on('resize orientationchange', debounce(() => { | |||
| // reset view if height has only changed by at least the threshold. | |||
| const width = $(window).width() | |||
| const height = $(window).height() | |||
| const $activeElement = $(document.activeElement) | |||
| if ($activeElement.length && ['INPUT', 'SELECT', 'TEXTAREA'].includes($activeElement.prop('nodeName'))) { | |||
| return | |||
| } | |||
| if ( | |||
| Math.abs(old.height - height) > this.options.heightThreshold || | |||
| old.width !== width | |||
| ) { | |||
| this.changeView(width, height) | |||
| old = { | |||
| width, | |||
| height | |||
| } | |||
| } | |||
| }, 200)) | |||
| if (this.options.checkOnInit) { | |||
| const width = $(window).width() | |||
| const height = $(window).height() | |||
| this.changeView(width, height) | |||
| old = { | |||
| width, | |||
| height | |||
| } | |||
| } | |||
| } | |||
| conditionCardView () { | |||
| this.changeTableView(false) | |||
| this.showHideColumns(false) | |||
| } | |||
| conditionFullView () { | |||
| this.changeTableView(true) | |||
| this.showHideColumns(true) | |||
| } | |||
| changeTableView (cardViewState) { | |||
| this.options.cardView = cardViewState | |||
| this.toggleView() | |||
| } | |||
| showHideColumns (checked) { | |||
| if (this.options.columnsHidden.length > 0) { | |||
| this.columns.forEach(column => { | |||
| if (this.options.columnsHidden.includes(column.field)) { | |||
| if (column.visible !== checked) { | |||
| this._toggleColumn(this.fieldsColumnsIndex[column.field], checked, true) | |||
| } | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| changeView (width, height) { | |||
| if (this.options.minHeight) { | |||
| if (width <= this.options.minWidth && height <= this.options.minHeight) { | |||
| this.conditionCardView() | |||
| } else if (width > this.options.minWidth && height > this.options.minHeight) { | |||
| this.conditionFullView() | |||
| } | |||
| } else if (width <= this.options.minWidth) { | |||
| this.conditionCardView() | |||
| } else if (width > this.options.minWidth) { | |||
| this.conditionFullView() | |||
| } | |||
| this.resetView() | |||
| } | |||
| } | |||
| @@ -0,0 +1,312 @@ | |||
| /** | |||
| * @update zhixin wen <wenzhixin2010@gmail.com> | |||
| */ | |||
| var Utils = $.fn.bootstrapTable.utils | |||
| function printPageBuilderDefault (table, styles) { | |||
| return ` | |||
| <html> | |||
| <head> | |||
| ${styles} | |||
| <style type="text/css" media="print"> | |||
| @page { | |||
| size: auto; | |||
| margin: 25px 0 25px 0; | |||
| } | |||
| </style> | |||
| <style type="text/css" media="all"> | |||
| table { | |||
| border-collapse: collapse; | |||
| font-size: 12px; | |||
| } | |||
| table, th, td { | |||
| border: 1px solid grey; | |||
| } | |||
| th, td { | |||
| text-align: center; | |||
| vertical-align: middle; | |||
| } | |||
| p { | |||
| font-weight: bold; | |||
| margin-left:20px; | |||
| } | |||
| table { | |||
| width: 94%; | |||
| margin-left: 3%; | |||
| margin-right: 3%; | |||
| } | |||
| div.bs-table-print { | |||
| text-align: center; | |||
| } | |||
| </style> | |||
| </head> | |||
| <title>Print Table</title> | |||
| <body> | |||
| <p>Printed on: ${new Date} </p> | |||
| <div class="bs-table-print">${table}</div> | |||
| </body> | |||
| </html> | |||
| ` | |||
| } | |||
| Object.assign($.fn.bootstrapTable.locales, { | |||
| formatPrint () { | |||
| return 'Print' | |||
| } | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales) | |||
| Object.assign($.fn.bootstrapTable.defaults, { | |||
| showPrint: false, | |||
| printAsFilteredAndSortedOnUI: true, | |||
| printSortColumn: undefined, | |||
| printSortOrder: 'asc', | |||
| printStyles: [], | |||
| printPageBuilder (table, styles) { | |||
| return printPageBuilderDefault(table, styles) | |||
| } | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.columnDefaults, { | |||
| printFilter: undefined, | |||
| printIgnore: false, | |||
| printFormatter: undefined | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.defaults.icons, { | |||
| print: { | |||
| bootstrap3: 'glyphicon-print icon-share', | |||
| bootstrap5: 'bi-printer', | |||
| 'bootstrap-table': 'icon-printer' | |||
| }[$.fn.bootstrapTable.theme] || 'fa-print' | |||
| }) | |||
| $.BootstrapTable = class extends $.BootstrapTable { | |||
| init (...args) { | |||
| super.init(...args) | |||
| if (!this.options.showPrint) { | |||
| return | |||
| } | |||
| this.mergedCells = [] | |||
| } | |||
| initToolbar (...args) { | |||
| this.showToolbar = this.showToolbar || this.options.showPrint | |||
| if (this.options.showPrint) { | |||
| this.buttons = Object.assign(this.buttons, { | |||
| print: { | |||
| text: this.options.formatPrint(), | |||
| icon: this.options.icons.print, | |||
| event: () => { | |||
| this.doPrint(this.options.printAsFilteredAndSortedOnUI ? this.getData() : this.options.data.slice(0)) | |||
| }, | |||
| attributes: { | |||
| 'aria-label': this.options.formatPrint(), | |||
| title: this.options.formatPrint() | |||
| } | |||
| } | |||
| }) | |||
| } | |||
| super.initToolbar(...args) | |||
| } | |||
| mergeCells (options) { | |||
| super.mergeCells(options) | |||
| if (!this.options.showPrint) { | |||
| return | |||
| } | |||
| let col = this.getVisibleFields().indexOf(options.field) | |||
| if (Utils.hasDetailViewIcon(this.options)) { | |||
| col += 1 | |||
| } | |||
| this.mergedCells.push({ | |||
| row: options.index, | |||
| col, | |||
| rowspan: options.rowspan || 1, | |||
| colspan: options.colspan || 1 | |||
| }) | |||
| } | |||
| doPrint (data) { | |||
| const canPrint = column => { | |||
| return !column.printIgnore && column.visible | |||
| } | |||
| const formatValue = (row, i, column) => { | |||
| const value_ = Utils.getItemField(row, column.field, this.options.escape, column.escape) | |||
| const value = Utils.calculateObjectValue(column, | |||
| column.printFormatter || column.formatter, | |||
| [value_, row, i], value_) | |||
| return typeof value === 'undefined' || value === null ? | |||
| this.options.undefinedText : value | |||
| } | |||
| const buildTable = (data, columnsArray) => { | |||
| const dir = this.$el.attr('dir') || 'ltr' | |||
| const html = [`<table dir="${dir}"><thead>`] | |||
| for (const columns of columnsArray) { | |||
| html.push('<tr>') | |||
| for (let h = 0; h < columns.length; h++) { | |||
| if (canPrint(columns[h])) { | |||
| html.push( | |||
| `<th | |||
| ${Utils.sprintf(' rowspan="%s"', columns[h].rowspan)} | |||
| ${Utils.sprintf(' colspan="%s"', columns[h].colspan)} | |||
| >${columns[h].title}</th>`) | |||
| } | |||
| } | |||
| html.push('</tr>') | |||
| } | |||
| html.push('</thead><tbody>') | |||
| const notRender = [] | |||
| if (this.mergedCells) { | |||
| for (let mc = 0; mc < this.mergedCells.length; mc++) { | |||
| const currentMergedCell = this.mergedCells[mc] | |||
| for (let rs = 0; rs < currentMergedCell.rowspan; rs++) { | |||
| const row = currentMergedCell.row + rs | |||
| for (let cs = 0; cs < currentMergedCell.colspan; cs++) { | |||
| const col = currentMergedCell.col + cs | |||
| notRender.push(`${row},${col}`) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| for (let i = 0; i < data.length; i++) { | |||
| html.push('<tr>') | |||
| const columns = columnsArray.flat(1) | |||
| columns.sort((c1, c2) => { | |||
| return c1.colspanIndex - c2.colspanIndex | |||
| }) | |||
| for (let j = 0; j < columns.length; j++) { | |||
| if (columns[j].colspanGroup > 0) continue | |||
| let rowspan = 0 | |||
| let colspan = 0 | |||
| if (this.mergedCells) { | |||
| for (let mc = 0; mc < this.mergedCells.length; mc++) { | |||
| const currentMergedCell = this.mergedCells[mc] | |||
| if (currentMergedCell.col === j && currentMergedCell.row === i) { | |||
| rowspan = currentMergedCell.rowspan | |||
| colspan = currentMergedCell.colspan | |||
| } | |||
| } | |||
| } | |||
| if ( | |||
| canPrint(columns[j]) && | |||
| ( | |||
| !notRender.includes(`${i},${j}`) || | |||
| rowspan > 0 && colspan > 0 | |||
| ) | |||
| ) { | |||
| if (rowspan > 0 && colspan > 0) { | |||
| html.push(`<td ${Utils.sprintf(' rowspan="%s"', rowspan)} ${Utils.sprintf(' colspan="%s"', colspan)}>`, formatValue(data[i], i, columns[j]), '</td>') | |||
| } else { | |||
| html.push('<td>', formatValue(data[i], i, columns[j]), '</td>') | |||
| } | |||
| } | |||
| } | |||
| html.push('</tr>') | |||
| } | |||
| html.push('</tbody>') | |||
| if (this.options.showFooter) { | |||
| html.push('<footer><tr>') | |||
| for (const columns of columnsArray) { | |||
| for (let h = 0; h < columns.length; h++) { | |||
| if (canPrint(columns)) { | |||
| const footerData = Utils.trToData(columns, this.$el.find('>tfoot>tr')) | |||
| const footerValue = Utils.calculateObjectValue(columns[h], columns[h].footerFormatter, [data], footerData[0] && footerData[0][columns[h].field] || '') | |||
| html.push(`<th>${footerValue}</th>`) | |||
| } | |||
| } | |||
| } | |||
| html.push('</tr></footer>') | |||
| } | |||
| html.push('</table>') | |||
| return html.join('') | |||
| } | |||
| const sortRows = (data, colName, sortOrder) => { | |||
| if (!colName) { | |||
| return data | |||
| } | |||
| let reverse = sortOrder !== 'asc' | |||
| reverse = -(+reverse || -1) | |||
| return data.sort((a, b) => reverse * a[colName].localeCompare(b[colName])) | |||
| } | |||
| const filterRow = (row, filters) => { | |||
| for (let index = 0; index < filters.length; ++index) { | |||
| if (row[filters[index].colName] !== filters[index].value) { | |||
| return false | |||
| } | |||
| } | |||
| return true | |||
| } | |||
| const filterRows = (data, filters) => data.filter(row => filterRow(row, filters)) | |||
| const getColumnFilters = columns => !columns || !columns[0] ? [] : columns[0].filter(col => col.printFilter).map(col => ({ | |||
| colName: col.field, | |||
| value: col.printFilter | |||
| })) | |||
| data = filterRows(data, getColumnFilters(this.options.columns)) | |||
| data = sortRows(data, this.options.printSortColumn, this.options.printSortOrder) | |||
| const table = buildTable(data, this.options.columns) | |||
| const newWin = window.open('') | |||
| const printStyles = typeof this.options.printStyles === 'string' ? | |||
| this.options.printStyles.replace(/\[|\]| /g, '').toLowerCase().split(',') : | |||
| this.options.printStyles | |||
| const styles = printStyles.map(it => | |||
| `<link rel="stylesheet" href="${it}" />`).join('') | |||
| const calculatedPrintPage = Utils.calculateObjectValue(this, this.options.printPageBuilder, | |||
| [table, styles], printPageBuilderDefault(table, styles)) | |||
| const startPrint = () => { | |||
| newWin.focus() | |||
| newWin.print() | |||
| newWin.close() | |||
| } | |||
| newWin.document.write(calculatedPrintPage) | |||
| newWin.document.close() | |||
| if (printStyles.length) { | |||
| const links = document.getElementsByTagName('link') | |||
| const lastLink = links[links.length - 1] | |||
| lastLink.onload = startPrint | |||
| } else { | |||
| startPrint() | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,212 @@ | |||
| /** | |||
| * @author: Dennis Hernández | |||
| * @update: https://github.com/wenzhixin | |||
| * @version: v1.2.0 | |||
| */ | |||
| $.akottr.dragtable.prototype._restoreState = function (persistObj) { | |||
| let i = 0 | |||
| for (const [field, value] of Object.entries(persistObj)) { | |||
| const $th = this.originalTable.el.find(`th[data-field="${field}"]`) | |||
| if (!$th.length) { | |||
| i++ | |||
| continue | |||
| } | |||
| this.originalTable.startIndex = $th.prevAll().length + 1 | |||
| this.originalTable.endIndex = parseInt(value, 10) + 1 - i | |||
| this._bubbleCols() | |||
| } | |||
| } | |||
| // From MDN site, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter | |||
| const filterFn = () => { | |||
| if (!Array.prototype.filter) { | |||
| Array.prototype.filter = function (fun/* , thisArg*/) { | |||
| if (this === undefined || this === null) { | |||
| throw new TypeError() | |||
| } | |||
| const t = Object(this) | |||
| const len = t.length >>> 0 | |||
| if (typeof fun !== 'function') { | |||
| throw new TypeError() | |||
| } | |||
| const res = [] | |||
| const thisArg = arguments.length >= 2 ? arguments[1] : undefined | |||
| for (let i = 0; i < len; i++) { | |||
| if (i in t) { | |||
| const val = t[i] | |||
| // NOTE: Technically this should Object.defineProperty at | |||
| // the next index, as push can be affected by | |||
| // properties on Object.prototype and Array.prototype. | |||
| // But this method's new, and collisions should be | |||
| // rare, so use the more-compatible alternative. | |||
| if (fun.call(thisArg, val, i, t)) { | |||
| res.push(val) | |||
| } | |||
| } | |||
| } | |||
| return res | |||
| } | |||
| } | |||
| } | |||
| Object.assign($.fn.bootstrapTable.defaults, { | |||
| reorderableColumns: false, | |||
| maxMovingRows: 10, | |||
| // eslint-disable-next-line no-unused-vars | |||
| onReorderColumn (headerFields) { | |||
| return false | |||
| }, | |||
| dragaccept: null | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.events, { | |||
| 'reorder-column.bs.table': 'onReorderColumn' | |||
| }) | |||
| $.fn.bootstrapTable.methods.push('orderColumns') | |||
| $.BootstrapTable = class extends $.BootstrapTable { | |||
| initHeader (...args) { | |||
| super.initHeader(...args) | |||
| if (!this.options.reorderableColumns) { | |||
| return | |||
| } | |||
| this.makeColumnsReorderable() | |||
| } | |||
| _toggleColumn (...args) { | |||
| super._toggleColumn(...args) | |||
| if (!this.options.reorderableColumns) { | |||
| return | |||
| } | |||
| this.makeColumnsReorderable() | |||
| } | |||
| toggleView (...args) { | |||
| super.toggleView(...args) | |||
| if (!this.options.reorderableColumns) { | |||
| return | |||
| } | |||
| if (this.options.cardView) { | |||
| return | |||
| } | |||
| this.makeColumnsReorderable() | |||
| } | |||
| resetView (...args) { | |||
| super.resetView(...args) | |||
| if (!this.options.reorderableColumns) { | |||
| return | |||
| } | |||
| this.makeColumnsReorderable() | |||
| } | |||
| makeColumnsReorderable (order = null) { | |||
| try { | |||
| $(this.$el).dragtable('destroy') | |||
| } catch (e) { | |||
| // do nothing | |||
| } | |||
| $(this.$el).dragtable({ | |||
| maxMovingRows: this.options.maxMovingRows, | |||
| dragaccept: this.options.dragaccept, | |||
| clickDelay: 200, | |||
| dragHandle: '.th-inner', | |||
| restoreState: order ? order : this.columnsSortOrder, | |||
| beforeStop: table => { | |||
| const sortOrder = {} | |||
| table.el.find('th').each((i, el) => { | |||
| sortOrder[$(el).data('field')] = i | |||
| }) | |||
| this.columnsSortOrder = sortOrder | |||
| if (this.options.cookie) { | |||
| this.persistReorderColumnsState(this) | |||
| } | |||
| const ths = [] | |||
| const formatters = [] | |||
| const columns = [] | |||
| let columnsHidden = [] | |||
| let columnIndex = -1 | |||
| const optionsColumns = [] | |||
| this.$header.find('th:not(.detail)').each((i, el) => { | |||
| ths.push($(el).data('field')) | |||
| formatters.push($(el).data('formatter')) | |||
| }) | |||
| // Exist columns not shown | |||
| if (ths.length < this.columns.length) { | |||
| columnsHidden = this.columns.filter(column => !column.visible) | |||
| for (let i = 0; i < columnsHidden.length; i++) { | |||
| ths.push(columnsHidden[i].field) | |||
| formatters.push(columnsHidden[i].formatter) | |||
| } | |||
| } | |||
| for (let i = 0; i < ths.length; i++) { | |||
| columnIndex = this.fieldsColumnsIndex[ths[i]] | |||
| if (columnIndex !== -1) { | |||
| this.fieldsColumnsIndex[ths[i]] = i | |||
| this.columns[columnIndex].fieldIndex = i | |||
| columns.push(this.columns[columnIndex]) | |||
| } | |||
| } | |||
| this.columns = columns | |||
| filterFn() // Support <IE9 | |||
| $.each(this.columns, (i, column) => { | |||
| let found = false | |||
| const field = column.field | |||
| this.options.columns[0].filter(item => { | |||
| if (!found && item['field'] === field) { | |||
| optionsColumns.push(item) | |||
| found = true | |||
| return false | |||
| } | |||
| return true | |||
| }) | |||
| }) | |||
| this.options.columns[0] = optionsColumns | |||
| this.header.fields = ths | |||
| this.header.formatters = formatters | |||
| this.initHeader() | |||
| this.initToolbar() | |||
| this.initSearchText() | |||
| this.initBody() | |||
| this.resetView() | |||
| this.trigger('reorder-column', ths) | |||
| } | |||
| }) | |||
| } | |||
| orderColumns (order) { | |||
| this.columnsSortOrder = order | |||
| this.makeColumnsReorderable() | |||
| } | |||
| } | |||
| @@ -0,0 +1,145 @@ | |||
| /** | |||
| * @author: Dennis Hernández | |||
| * @update zhixin wen <wenzhixin2010@gmail.com> | |||
| */ | |||
| const rowAttr = (row, index) => ({ | |||
| id: `customId_${index}` | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.defaults, { | |||
| reorderableRows: false, | |||
| onDragStyle: null, | |||
| onDropStyle: null, | |||
| onDragClass: 'reorder-rows-on-drag-class', | |||
| dragHandle: '>tbody>tr>td:not(.bs-checkbox)', | |||
| useRowAttrFunc: false, | |||
| // eslint-disable-next-line no-unused-vars | |||
| onReorderRowsDrag (row) { | |||
| return false | |||
| }, | |||
| // eslint-disable-next-line no-unused-vars | |||
| onReorderRowsDrop (row) { | |||
| return false | |||
| }, | |||
| // eslint-disable-next-line no-unused-vars | |||
| onReorderRow (newData) { | |||
| return false | |||
| }, | |||
| onDragStop () {}, | |||
| onAllowDrop () { | |||
| return true | |||
| } | |||
| }) | |||
| Object.assign($.fn.bootstrapTable.events, { | |||
| 'reorder-row.bs.table': 'onReorderRow' | |||
| }) | |||
| $.BootstrapTable = class extends $.BootstrapTable { | |||
| init (...args) { | |||
| if (!this.options.reorderableRows) { | |||
| super.init(...args) | |||
| return | |||
| } | |||
| if (this.options.useRowAttrFunc) { | |||
| this.options.rowAttributes = rowAttr | |||
| } | |||
| const onPostBody = this.options.onPostBody | |||
| this.options.onPostBody = () => { | |||
| setTimeout(() => { | |||
| this.makeRowsReorderable() | |||
| onPostBody.call(this.options, this.options.data) | |||
| }, 1) | |||
| } | |||
| super.init(...args) | |||
| } | |||
| makeRowsReorderable () { | |||
| this.$el.tableDnD({ | |||
| onDragStyle: this.options.onDragStyle, | |||
| onDropStyle: this.options.onDropStyle, | |||
| onDragClass: this.options.onDragClass, | |||
| onAllowDrop: (hoveredRow, draggedRow) => this.onAllowDrop(hoveredRow, draggedRow), | |||
| onDragStop: (table, draggedRow) => this.onDragStop(table, draggedRow), | |||
| onDragStart: (table, droppedRow) => this.onDropStart(table, droppedRow), | |||
| onDrop: (table, droppedRow) => this.onDrop(table, droppedRow), | |||
| dragHandle: this.options.dragHandle | |||
| }) | |||
| } | |||
| onDropStart (table, draggingTd) { | |||
| this.$draggingTd = $(draggingTd).css('cursor', 'move') | |||
| this.draggingIndex = $(this.$draggingTd.parent()).data('index') | |||
| // Call the user defined function | |||
| this.options.onReorderRowsDrag(this.data[this.draggingIndex]) | |||
| } | |||
| onDragStop (table, draggedRow) { | |||
| const rowIndexDraggedRow = $(draggedRow).data('index') | |||
| const draggedRowItem = this.data[rowIndexDraggedRow] | |||
| this.options.onDragStop(table, draggedRowItem, draggedRow) | |||
| } | |||
| onAllowDrop (hoveredRow, draggedRow) { | |||
| const rowIndexDraggedRow = $(draggedRow).data('index') | |||
| const rowIndexHoveredRow = $(hoveredRow).data('index') | |||
| const draggedRowItem = this.data[rowIndexDraggedRow] | |||
| const hoveredRowItem = this.data[rowIndexHoveredRow] | |||
| return this.options.onAllowDrop(hoveredRowItem, draggedRowItem, hoveredRow, draggedRow) | |||
| } | |||
| onDrop (table) { | |||
| this.$draggingTd.css('cursor', '') | |||
| const pageNum = this.options.pageNumber | |||
| const pageSize = this.options.pageSize | |||
| const newData = [] | |||
| for (let i = 0; i < table.tBodies[0].rows.length; i++) { | |||
| const $tr = $(table.tBodies[0].rows[i]) | |||
| newData.push(this.data[$tr.data('index')]) | |||
| $tr.data('index', i) | |||
| } | |||
| const draggingRow = this.data[this.draggingIndex] | |||
| const droppedIndex = newData.indexOf(this.data[this.draggingIndex]) | |||
| const droppedRow = this.data[droppedIndex] | |||
| const index = (pageNum - 1) * pageSize + this.options.data.indexOf(this.data[droppedIndex]) | |||
| this.options.data.splice(this.options.data.indexOf(draggingRow), 1) | |||
| this.options.data.splice(index, 0, draggingRow) | |||
| this.initSearch() | |||
| if (this.options.sidePagination === 'server') { | |||
| this.data = [...this.options.data] | |||
| } | |||
| // Call the user defined function | |||
| this.options.onReorderRowsDrop(droppedRow) | |||
| // Call the event reorder-row | |||
| this.trigger('reorder-row', newData, draggingRow, droppedRow) | |||
| } | |||
| initSearch () { | |||
| this.ignoreInitSort = true | |||
| super.initSearch() | |||
| } | |||
| initSort () { | |||
| if (this.ignoreInitSort) { | |||
| this.ignoreInitSort = false | |||
| return | |||
| } | |||
| super.initSort() | |||
| } | |||
| } | |||
| @@ -0,0 +1,603 @@ | |||
| /** | |||
| * TableDnD plug-in for JQuery, allows you to drag and drop table rows | |||
| * You can set up various options to control how the system will work | |||
| * Copyright (c) Denis Howlett <denish@isocra.com> | |||
| * License: MIT. | |||
| * See https://github.com/isocra/TableDnD | |||
| */ | |||
| !function ($, window, document, undefined) { | |||
| var startEvent = 'touchstart mousedown', | |||
| moveEvent = 'touchmove mousemove', | |||
| endEvent = 'touchend mouseup'; | |||
| $(document).ready(function () { | |||
| function parseStyle(css) { | |||
| var objMap = {}, | |||
| parts = css.match(/([^;:]+)/g) || []; | |||
| while (parts.length) | |||
| objMap[parts.shift()] = parts.shift().trim(); | |||
| return objMap; | |||
| } | |||
| $('table').each(function () { | |||
| if ($(this).data('table') === 'dnd') { | |||
| $(this).tableDnD({ | |||
| onDragStyle: $(this).data('ondragstyle') && parseStyle($(this).data('ondragstyle')) || null, | |||
| onDropStyle: $(this).data('ondropstyle') && parseStyle($(this).data('ondropstyle')) || null, | |||
| onDragClass: $(this).data('ondragclass') === undefined && "tDnD_whileDrag" || $(this).data('ondragclass'), | |||
| onDrop: $(this).data('ondrop') && new Function('table', 'row', $(this).data('ondrop')), // 'return eval("'+$(this).data('ondrop')+'");') || null, | |||
| onDragStart: $(this).data('ondragstart') && new Function('table', 'row' ,$(this).data('ondragstart')), // 'return eval("'+$(this).data('ondragstart')+'");') || null, | |||
| onDragStop: $(this).data('ondragstop') && new Function('table', 'row' ,$(this).data('ondragstop')), | |||
| scrollAmount: $(this).data('scrollamount') || 5, | |||
| sensitivity: $(this).data('sensitivity') || 10, | |||
| hierarchyLevel: $(this).data('hierarchylevel') || 0, | |||
| indentArtifact: $(this).data('indentartifact') || '<div class="indent"> </div>', | |||
| autoWidthAdjust: $(this).data('autowidthadjust') || true, | |||
| autoCleanRelations: $(this).data('autocleanrelations') || true, | |||
| jsonPretifySeparator: $(this).data('jsonpretifyseparator') || '\t', | |||
| serializeRegexp: $(this).data('serializeregexp') && new RegExp($(this).data('serializeregexp')) || /[^\-]*$/, | |||
| serializeParamName: $(this).data('serializeparamname') || false, | |||
| dragHandle: $(this).data('draghandle') || null | |||
| }); | |||
| } | |||
| }); | |||
| }); | |||
| jQuery.tableDnD = { | |||
| /** Keep hold of the current table being dragged */ | |||
| currentTable: null, | |||
| /** Keep hold of the current drag object if any */ | |||
| dragObject: null, | |||
| /** The current mouse offset */ | |||
| mouseOffset: null, | |||
| /** Remember the old value of X and Y so that we don't do too much processing */ | |||
| oldX: 0, | |||
| oldY: 0, | |||
| /** Actually build the structure */ | |||
| build: function(options) { | |||
| // Set up the defaults if any | |||
| this.each(function() { | |||
| // This is bound to each matching table, set up the defaults and override with user options | |||
| this.tableDnDConfig = $.extend({ | |||
| onDragStyle: null, | |||
| onDropStyle: null, | |||
| // Add in the default class for whileDragging | |||
| onDragClass: "tDnD_whileDrag", | |||
| onDrop: null, | |||
| onDragStart: null, | |||
| onDragStop: null, | |||
| scrollAmount: 5, | |||
| /** Sensitivity setting will throttle the trigger rate for movement detection */ | |||
| sensitivity: 10, | |||
| /** Hierarchy level to support parent child. 0 switches this functionality off */ | |||
| hierarchyLevel: 0, | |||
| /** The html artifact to prepend the first cell with as indentation */ | |||
| indentArtifact: '<div class="indent"> </div>', | |||
| /** Automatically adjust width of first cell */ | |||
| autoWidthAdjust: true, | |||
| /** Automatic clean-up to ensure relationship integrity */ | |||
| autoCleanRelations: true, | |||
| /** Specify a number (4) as number of spaces or any indent string for JSON.stringify */ | |||
| jsonPretifySeparator: '\t', | |||
| /** The regular expression to use to trim row IDs */ | |||
| serializeRegexp: /[^\-]*$/, | |||
| /** If you want to specify another parameter name instead of the table ID */ | |||
| serializeParamName: false, | |||
| /** If you give the name of a class here, then only Cells with this class will be draggable */ | |||
| dragHandle: null | |||
| }, options || {}); | |||
| // Now make the rows draggable | |||
| $.tableDnD.makeDraggable(this); | |||
| // Prepare hierarchy support | |||
| this.tableDnDConfig.hierarchyLevel | |||
| && $.tableDnD.makeIndented(this); | |||
| }); | |||
| // Don't break the chain | |||
| return this; | |||
| }, | |||
| makeIndented: function (table) { | |||
| var config = table.tableDnDConfig, | |||
| rows = table.rows, | |||
| firstCell = $(rows).first().find('td:first')[0], | |||
| indentLevel = 0, | |||
| cellWidth = 0, | |||
| longestCell, | |||
| tableStyle; | |||
| if ($(table).hasClass('indtd')) | |||
| return null; | |||
| tableStyle = $(table).addClass('indtd').attr('style'); | |||
| $(table).css({whiteSpace: "nowrap"}); | |||
| for (var w = 0; w < rows.length; w++) { | |||
| if (cellWidth < $(rows[w]).find('td:first').text().length) { | |||
| cellWidth = $(rows[w]).find('td:first').text().length; | |||
| longestCell = w; | |||
| } | |||
| } | |||
| $(firstCell).css({width: 'auto'}); | |||
| for (w = 0; w < config.hierarchyLevel; w++) | |||
| $(rows[longestCell]).find('td:first').prepend(config.indentArtifact); | |||
| firstCell && $(firstCell).css({width: firstCell.offsetWidth}); | |||
| tableStyle && $(table).css(tableStyle); | |||
| for (w = 0; w < config.hierarchyLevel; w++) | |||
| $(rows[longestCell]).find('td:first').children(':first').remove(); | |||
| config.hierarchyLevel | |||
| && $(rows).each(function () { | |||
| indentLevel = $(this).data('level') || 0; | |||
| indentLevel <= config.hierarchyLevel | |||
| && $(this).data('level', indentLevel) | |||
| || $(this).data('level', 0); | |||
| for (var i = 0; i < $(this).data('level'); i++) | |||
| $(this).find('td:first').prepend(config.indentArtifact); | |||
| }); | |||
| return this; | |||
| }, | |||
| /** This function makes all the rows on the table draggable apart from those marked as "NoDrag" */ | |||
| makeDraggable: function(table) { | |||
| var config = table.tableDnDConfig; | |||
| config.dragHandle | |||
| // We only need to add the event to the specified cells | |||
| && $(config.dragHandle, table).each(function() { | |||
| if (! $(this).hasClass("nodrag")) { | |||
| // The cell is bound to "this" | |||
| $(this).bind(startEvent, function(e) { | |||
| if (e.target.tagName === "TD" && event.target.className !== "nodrag") { | |||
| $.tableDnD.initialiseDrag($(this).parents('tr')[0], table, this, e, config); | |||
| return false; | |||
| } | |||
| return true; | |||
| }); | |||
| } | |||
| }) | |||
| // For backwards compatibility, we add the event to the whole row | |||
| // get all the rows as a wrapped set | |||
| || $(table.rows).each(function() { | |||
| // Iterate through each row, the row is bound to "this" | |||
| if (! $(this).hasClass("nodrag")) { | |||
| $(this).bind(startEvent, function(e) { | |||
| if (e.target.tagName === "TD" && event.target.className !== "nodrag") { | |||
| $.tableDnD.initialiseDrag(this, table, this, e, config); | |||
| return false; | |||
| } | |||
| }).css("cursor", "move"); // Store the tableDnD object | |||
| } else { | |||
| $(this).css("cursor", ""); // Remove the cursor if we don't have the nodrag class | |||
| } | |||
| }); | |||
| }, | |||
| currentOrder: function() { | |||
| var rows = this.currentTable.rows; | |||
| return $.map(rows, function (val) { | |||
| return ($(val).data('level') + val.id).replace(/\s/g, ''); | |||
| }).join(''); | |||
| }, | |||
| initialiseDrag: function(dragObject, table, target, e, config) { | |||
| this.dragObject = dragObject; | |||
| this.currentTable = table; | |||
| this.mouseOffset = this.getMouseOffset(target, e); | |||
| this.originalOrder = this.currentOrder(); | |||
| // Now we need to capture the mouse up and mouse move event | |||
| // We can use bind so that we don't interfere with other event handlers | |||
| $(document) | |||
| .bind(moveEvent, this.mousemove) | |||
| .bind(endEvent, this.mouseup); | |||
| // Call the onDragStart method if there is one | |||
| config.onDragStart | |||
| && config.onDragStart(table, target); | |||
| }, | |||
| updateTables: function() { | |||
| this.each(function() { | |||
| // this is now bound to each matching table | |||
| if (this.tableDnDConfig) | |||
| $.tableDnD.makeDraggable(this); | |||
| }); | |||
| }, | |||
| /** Get the mouse coordinates from the event (allowing for browser differences) */ | |||
| mouseCoords: function(e) { | |||
| if (e.originalEvent.changedTouches) | |||
| return { | |||
| x: e.originalEvent.changedTouches[0].clientX, | |||
| y: e.originalEvent.changedTouches[0].clientY | |||
| }; | |||
| if(e.pageX || e.pageY) | |||
| return { | |||
| x: e.pageX, | |||
| y: e.pageY | |||
| }; | |||
| return { | |||
| x: e.clientX + document.body.scrollLeft - document.body.clientLeft, | |||
| y: e.clientY + document.body.scrollTop - document.body.clientTop | |||
| }; | |||
| }, | |||
| /** Given a target element and a mouse eent, get the mouse offset from that element. | |||
| To do this we need the element's position and the mouse position */ | |||
| getMouseOffset: function(target, e) { | |||
| var mousePos, | |||
| docPos; | |||
| e = e || window.event; | |||
| docPos = this.getPosition(target); | |||
| mousePos = this.mouseCoords(e); | |||
| return { | |||
| x: mousePos.x - docPos.x, | |||
| y: mousePos.y - docPos.y | |||
| }; | |||
| }, | |||
| /** Get the position of an element by going up the DOM tree and adding up all the offsets */ | |||
| getPosition: function(element) { | |||
| var left = 0, | |||
| top = 0; | |||
| // Safari fix -- thanks to Luis Chato for this! | |||
| // Safari 2 doesn't correctly grab the offsetTop of a table row | |||
| // this is detailed here: | |||
| // http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/ | |||
| // the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild. | |||
| // note that firefox will return a text node as a first child, so designing a more thorough | |||
| // solution may need to take that into account, for now this seems to work in firefox, safari, ie | |||
| if (element.offsetHeight === 0) | |||
| element = element.firstChild; // a table cell | |||
| while (element.offsetParent) { | |||
| left += element.offsetLeft; | |||
| top += element.offsetTop; | |||
| element = element.offsetParent; | |||
| } | |||
| left += element.offsetLeft; | |||
| top += element.offsetTop; | |||
| return { | |||
| x: left, | |||
| y: top | |||
| }; | |||
| }, | |||
| autoScroll: function (mousePos) { | |||
| var config = this.currentTable.tableDnDConfig, | |||
| yOffset = window.pageYOffset, | |||
| windowHeight = window.innerHeight | |||
| ? window.innerHeight | |||
| : document.documentElement.clientHeight | |||
| ? document.documentElement.clientHeight | |||
| : document.body.clientHeight; | |||
| // Windows version | |||
| // yOffset=document.body.scrollTop; | |||
| if (document.all) | |||
| if (typeof document.compatMode !== 'undefined' | |||
| && document.compatMode !== 'BackCompat') | |||
| yOffset = document.documentElement.scrollTop; | |||
| else if (typeof document.body !== 'undefined') | |||
| yOffset = document.body.scrollTop; | |||
| mousePos.y - yOffset < config.scrollAmount | |||
| && window.scrollBy(0, - config.scrollAmount) | |||
| || windowHeight - (mousePos.y - yOffset) < config.scrollAmount | |||
| && window.scrollBy(0, config.scrollAmount); | |||
| }, | |||
| moveVerticle: function (moving, currentRow) { | |||
| if (0 !== moving.vertical | |||
| // If we're over a row then move the dragged row to there so that the user sees the | |||
| // effect dynamically | |||
| && currentRow | |||
| && this.dragObject !== currentRow | |||
| && this.dragObject.parentNode === currentRow.parentNode) | |||
| 0 > moving.vertical | |||
| && this.dragObject.parentNode.insertBefore(this.dragObject, currentRow.nextSibling) | |||
| || 0 < moving.vertical | |||
| && this.dragObject.parentNode.insertBefore(this.dragObject, currentRow); | |||
| }, | |||
| moveHorizontal: function (moving, currentRow) { | |||
| var config = this.currentTable.tableDnDConfig, | |||
| currentLevel; | |||
| if (!config.hierarchyLevel | |||
| || 0 === moving.horizontal | |||
| // We only care if moving left or right on the current row | |||
| || !currentRow | |||
| || this.dragObject !== currentRow) | |||
| return null; | |||
| currentLevel = $(currentRow).data('level'); | |||
| 0 < moving.horizontal | |||
| && currentLevel > 0 | |||
| && $(currentRow).find('td:first').children(':first').remove() | |||
| && $(currentRow).data('level', --currentLevel); | |||
| 0 > moving.horizontal | |||
| && currentLevel < config.hierarchyLevel | |||
| && $(currentRow).prev().data('level') >= currentLevel | |||
| && $(currentRow).children(':first').prepend(config.indentArtifact) | |||
| && $(currentRow).data('level', ++currentLevel); | |||
| }, | |||
| mousemove: function(e) { | |||
| var dragObj = $($.tableDnD.dragObject), | |||
| config = $.tableDnD.currentTable.tableDnDConfig, | |||
| currentRow, | |||
| mousePos, | |||
| moving, | |||
| x, | |||
| y; | |||
| e && e.preventDefault(); | |||
| if (!$.tableDnD.dragObject) | |||
| return false; | |||
| // prevent touch device screen scrolling | |||
| e.type === 'touchmove' | |||
| && event.preventDefault(); // TODO verify this is event and not really e | |||
| // update the style to show we're dragging | |||
| config.onDragClass | |||
| && dragObj.addClass(config.onDragClass) | |||
| || dragObj.css(config.onDragStyle); | |||
| mousePos = $.tableDnD.mouseCoords(e); | |||
| x = mousePos.x - $.tableDnD.mouseOffset.x; | |||
| y = mousePos.y - $.tableDnD.mouseOffset.y; | |||
| // auto scroll the window | |||
| $.tableDnD.autoScroll(mousePos); | |||
| currentRow = $.tableDnD.findDropTargetRow(dragObj, y); | |||
| moving = $.tableDnD.findDragDirection(x, y); | |||
| $.tableDnD.moveVerticle(moving, currentRow); | |||
| $.tableDnD.moveHorizontal(moving, currentRow); | |||
| return false; | |||
| }, | |||
| findDragDirection: function (x,y) { | |||
| var sensitivity = this.currentTable.tableDnDConfig.sensitivity, | |||
| oldX = this.oldX, | |||
| oldY = this.oldY, | |||
| xMin = oldX - sensitivity, | |||
| xMax = oldX + sensitivity, | |||
| yMin = oldY - sensitivity, | |||
| yMax = oldY + sensitivity, | |||
| moving = { | |||
| horizontal: x >= xMin && x <= xMax ? 0 : x > oldX ? -1 : 1, | |||
| vertical : y >= yMin && y <= yMax ? 0 : y > oldY ? -1 : 1 | |||
| }; | |||
| // update the old value | |||
| if (moving.horizontal !== 0) | |||
| this.oldX = x; | |||
| if (moving.vertical !== 0) | |||
| this.oldY = y; | |||
| return moving; | |||
| }, | |||
| /** We're only worried about the y position really, because we can only move rows up and down */ | |||
| findDropTargetRow: function(draggedRow, y) { | |||
| var rowHeight = 0, | |||
| rows = this.currentTable.rows, | |||
| config = this.currentTable.tableDnDConfig, | |||
| rowY = 0, | |||
| row = null; | |||
| for (var i = 0; i < rows.length; i++) { | |||
| row = rows[i]; | |||
| rowY = this.getPosition(row).y; | |||
| rowHeight = parseInt(row.offsetHeight) / 2; | |||
| if (row.offsetHeight === 0) { | |||
| rowY = this.getPosition(row.firstChild).y; | |||
| rowHeight = parseInt(row.firstChild.offsetHeight) / 2; | |||
| } | |||
| // Because we always have to insert before, we need to offset the height a bit | |||
| if (y > (rowY - rowHeight) && y < (rowY + rowHeight)) | |||
| // that's the row we're over | |||
| // If it's the same as the current row, ignore it | |||
| if (draggedRow.is(row) | |||
| || (config.onAllowDrop | |||
| && !config.onAllowDrop(draggedRow, row)) | |||
| // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic) | |||
| || $(row).hasClass("nodrop")) | |||
| return null; | |||
| else | |||
| return row; | |||
| } | |||
| return null; | |||
| }, | |||
| processMouseup: function() { | |||
| if (!this.currentTable || !this.dragObject) | |||
| return null; | |||
| var config = this.currentTable.tableDnDConfig, | |||
| droppedRow = this.dragObject, | |||
| parentLevel = 0, | |||
| myLevel = 0; | |||
| // Unbind the event handlers | |||
| $(document) | |||
| .unbind(moveEvent, this.mousemove) | |||
| .unbind(endEvent, this.mouseup); | |||
| config.hierarchyLevel | |||
| && config.autoCleanRelations | |||
| && $(this.currentTable.rows).first().find('td:first').children().each(function () { | |||
| myLevel = $(this).parents('tr:first').data('level'); | |||
| myLevel | |||
| && $(this).parents('tr:first').data('level', --myLevel) | |||
| && $(this).remove(); | |||
| }) | |||
| && config.hierarchyLevel > 1 | |||
| && $(this.currentTable.rows).each(function () { | |||
| myLevel = $(this).data('level'); | |||
| if (myLevel > 1) { | |||
| parentLevel = $(this).prev().data('level'); | |||
| while (myLevel > parentLevel + 1) { | |||
| $(this).find('td:first').children(':first').remove(); | |||
| $(this).data('level', --myLevel); | |||
| } | |||
| } | |||
| }); | |||
| // If we have a dragObject, then we need to release it, | |||
| // The row will already have been moved to the right place so we just reset stuff | |||
| config.onDragClass | |||
| && $(droppedRow).removeClass(config.onDragClass) | |||
| || $(droppedRow).css(config.onDropStyle); | |||
| this.dragObject = null; | |||
| // Call the onDrop method if there is one | |||
| config.onDrop | |||
| && this.originalOrder !== this.currentOrder() | |||
| && $(droppedRow).hide().fadeIn('fast') | |||
| && config.onDrop(this.currentTable, droppedRow); | |||
| // Call the onDragStop method if there is one | |||
| config.onDragStop | |||
| && config.onDragStop(this.currentTable, droppedRow); | |||
| this.currentTable = null; // let go of the table too | |||
| }, | |||
| mouseup: function(e) { | |||
| e && e.preventDefault(); | |||
| $.tableDnD.processMouseup(); | |||
| return false; | |||
| }, | |||
| jsonize: function(pretify) { | |||
| var table = this.currentTable; | |||
| if (pretify) | |||
| return JSON.stringify( | |||
| this.tableData(table), | |||
| null, | |||
| table.tableDnDConfig.jsonPretifySeparator | |||
| ); | |||
| return JSON.stringify(this.tableData(table)); | |||
| }, | |||
| serialize: function() { | |||
| return $.param(this.tableData(this.currentTable)); | |||
| }, | |||
| serializeTable: function(table) { | |||
| var result = ""; | |||
| var paramName = table.tableDnDConfig.serializeParamName || table.id; | |||
| var rows = table.rows; | |||
| for (var i=0; i<rows.length; i++) { | |||
| if (result.length > 0) result += "&"; | |||
| var rowId = rows[i].id; | |||
| if (rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) { | |||
| rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0]; | |||
| result += paramName + '[]=' + rowId; | |||
| } | |||
| } | |||
| return result; | |||
| }, | |||
| serializeTables: function() { | |||
| var result = []; | |||
| $('table').each(function() { | |||
| this.id && result.push($.param($.tableDnD.tableData(this))); | |||
| }); | |||
| return result.join('&'); | |||
| }, | |||
| tableData: function (table) { | |||
| var config = table.tableDnDConfig, | |||
| previousIDs = [], | |||
| currentLevel = 0, | |||
| indentLevel = 0, | |||
| rowID = null, | |||
| data = {}, | |||
| getSerializeRegexp, | |||
| paramName, | |||
| currentID, | |||
| rows; | |||
| if (!table) | |||
| table = this.currentTable; | |||
| if (!table || !table.rows || !table.rows.length) | |||
| return {error: { code: 500, message: "Not a valid table."}}; | |||
| if (!table.id && !config.serializeParamName) | |||
| return {error: { code: 500, message: "No serializable unique id provided."}}; | |||
| rows = config.autoCleanRelations | |||
| && table.rows | |||
| || $.makeArray(table.rows); | |||
| paramName = config.serializeParamName || table.id; | |||
| currentID = paramName; | |||
| getSerializeRegexp = function (rowId) { | |||
| if (rowId && config && config.serializeRegexp) | |||
| return rowId.match(config.serializeRegexp)[0]; | |||
| return rowId; | |||
| }; | |||
| data[currentID] = []; | |||
| !config.autoCleanRelations | |||
| && $(rows[0]).data('level') | |||
| && rows.unshift({id: 'undefined'}); | |||
| for (var i=0; i < rows.length; i++) { | |||
| if (config.hierarchyLevel) { | |||
| indentLevel = $(rows[i]).data('level') || 0; | |||
| if (indentLevel === 0) { | |||
| currentID = paramName; | |||
| previousIDs = []; | |||
| } | |||
| else if (indentLevel > currentLevel) { | |||
| previousIDs.push([currentID, currentLevel]); | |||
| currentID = getSerializeRegexp(rows[i-1].id); | |||
| } | |||
| else if (indentLevel < currentLevel) { | |||
| for (var h = 0; h < previousIDs.length; h++) { | |||
| if (previousIDs[h][1] === indentLevel) | |||
| currentID = previousIDs[h][0]; | |||
| if (previousIDs[h][1] >= currentLevel) | |||
| previousIDs[h][1] = 0; | |||
| } | |||
| } | |||
| currentLevel = indentLevel; | |||
| if (!$.isArray(data[currentID])) | |||
| data[currentID] = []; | |||
| rowID = getSerializeRegexp(rows[i].id); | |||
| rowID && data[currentID].push(rowID); | |||
| } | |||
| else { | |||
| rowID = getSerializeRegexp(rows[i].id); | |||
| rowID && data[currentID].push(rowID); | |||
| } | |||
| } | |||
| return data; | |||
| } | |||
| }; | |||
| jQuery.fn.extend( | |||
| { | |||
| tableDnD : $.tableDnD.build, | |||
| tableDnDUpdate : $.tableDnD.updateTables, | |||
| tableDnDSerialize : $.proxy($.tableDnD.serialize, $.tableDnD), | |||
| tableDnDSerializeAll : $.tableDnD.serializeTables, | |||
| tableDnDData : $.proxy($.tableDnD.tableData, $.tableDnD) | |||
| } | |||
| ); | |||
| }(jQuery, window, window.document); | |||
| @@ -0,0 +1,68 @@ | |||
| /** | |||
| * @author: Dennis Hernández | |||
| * @version: v2.0.0 | |||
| */ | |||
| const isInit = that => that.$el.data('resizableColumns') !== undefined | |||
| const initResizable = that => { | |||
| if ( | |||
| that.options.resizable && | |||
| !that.options.cardView && | |||
| !isInit(that) && | |||
| that.$el.is(':visible') | |||
| ) { | |||
| that.$el.resizableColumns({ | |||
| store: window.store | |||
| }) | |||
| } | |||
| } | |||
| const destroy = that => { | |||
| if (isInit(that)) { | |||
| that.$el.data('resizableColumns').destroy() | |||
| } | |||
| } | |||
| const reInitResizable = that => { | |||
| destroy(that) | |||
| initResizable(that) | |||
| } | |||
| Object.assign($.fn.bootstrapTable.defaults, { | |||
| resizable: false | |||
| }) | |||
| $.BootstrapTable = class extends $.BootstrapTable { | |||
| initBody (...args) { | |||
| super.initBody(...args) | |||
| this.$el.off('column-switch.bs.table page-change.bs.table') | |||
| .on('column-switch.bs.table page-change.bs.table', () => { | |||
| reInitResizable(this) | |||
| }) | |||
| reInitResizable(this) | |||
| } | |||
| toggleView (...args) { | |||
| super.toggleView(...args) | |||
| if (this.options.resizable && this.options.cardView) { | |||
| // Destroy the plugin | |||
| destroy(this) | |||
| } | |||
| } | |||
| resetView (...args) { | |||
| super.resetView(...args) | |||
| if (this.options.resizable) { | |||
| // because in fitHeader function, we use setTimeout(func, 100); | |||
| setTimeout(() => { | |||
| initResizable(this) | |||
| }, 100) | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,109 @@ | |||
| /** | |||
| * Bootstrap Table Chinese translation | |||
| * Author: Zhixin Wen<wenzhixin2010@gmail.com> | |||
| */ | |||
| $.fn.bootstrapTable.locales['zh-CN'] = { | |||
| formatShowSearch: function formatShowSearch() { | |||
| return '隐藏/显示搜索'; | |||
| }, | |||
| formatPageGo: function formatPageGo() { | |||
| return '跳转'; | |||
| }, | |||
| formatCopyRows: function formatCopyRows() { | |||
| return '复制行'; | |||
| }, | |||
| formatPrint: function formatPrint() { | |||
| return '打印'; | |||
| }, | |||
| formatLoadingMessage: function formatLoadingMessage() { | |||
| return '正在努力地加载数据中,请稍候'; | |||
| }, | |||
| formatRecordsPerPage: function formatRecordsPerPage(pageNumber) { | |||
| return "每页显示 ".concat(pageNumber, " 条记录"); | |||
| }, | |||
| formatShowingRows: function formatShowingRows(pageFrom, pageTo, totalRows, totalNotFiltered) { | |||
| if (totalNotFiltered !== undefined && totalNotFiltered > 0 && totalNotFiltered > totalRows) { | |||
| return "显示第 ".concat(pageFrom, " 到第 ").concat(pageTo, " 条记录,总共 ").concat(totalRows, " 条记录(从 ").concat(totalNotFiltered, " 总记录中过滤)"); | |||
| } | |||
| return "显示第 ".concat(pageFrom, " 到第 ").concat(pageTo, " 条记录,总共 ").concat(totalRows, " 条记录"); | |||
| }, | |||
| formatSRPaginationPreText: function formatSRPaginationPreText() { | |||
| return '上一页'; | |||
| }, | |||
| formatSRPaginationPageText: function formatSRPaginationPageText(page) { | |||
| return "第".concat(page, "页"); | |||
| }, | |||
| formatSRPaginationNextText: function formatSRPaginationNextText() { | |||
| return '下一页'; | |||
| }, | |||
| formatDetailPagination: function formatDetailPagination(totalRows) { | |||
| return "总共 ".concat(totalRows, " 条记录"); | |||
| }, | |||
| formatClearSearch: function formatClearSearch() { | |||
| return '清空过滤'; | |||
| }, | |||
| formatSearch: function formatSearch() { | |||
| return '搜索'; | |||
| }, | |||
| formatNoMatches: function formatNoMatches() { | |||
| return '没有找到匹配的记录'; | |||
| }, | |||
| formatPaginationSwitch: function formatPaginationSwitch() { | |||
| return '隐藏/显示分页'; | |||
| }, | |||
| formatPaginationSwitchDown: function formatPaginationSwitchDown() { | |||
| return '显示分页'; | |||
| }, | |||
| formatPaginationSwitchUp: function formatPaginationSwitchUp() { | |||
| return '隐藏分页'; | |||
| }, | |||
| formatRefresh: function formatRefresh() { | |||
| return '刷新'; | |||
| }, | |||
| formatToggle: function formatToggle() { | |||
| return '切换'; | |||
| }, | |||
| formatToggleOn: function formatToggleOn() { | |||
| return '显示卡片视图'; | |||
| }, | |||
| formatToggleOff: function formatToggleOff() { | |||
| return '隐藏卡片视图'; | |||
| }, | |||
| formatColumns: function formatColumns() { | |||
| return '列'; | |||
| }, | |||
| formatColumnsToggleAll: function formatColumnsToggleAll() { | |||
| return '切换所有'; | |||
| }, | |||
| formatFullscreen: function formatFullscreen() { | |||
| return '全屏'; | |||
| }, | |||
| formatAllRows: function formatAllRows() { | |||
| return '所有'; | |||
| }, | |||
| formatAutoRefresh: function formatAutoRefresh() { | |||
| return '自动刷新'; | |||
| }, | |||
| formatExport: function formatExport() { | |||
| return '导出数据'; | |||
| }, | |||
| formatJumpTo: function formatJumpTo() { | |||
| return '跳转'; | |||
| }, | |||
| formatAdvancedSearch: function formatAdvancedSearch() { | |||
| return '高级搜索'; | |||
| }, | |||
| formatAdvancedCloseButton: function formatAdvancedCloseButton() { | |||
| return '关闭'; | |||
| }, | |||
| formatFilterControlSwitch: function formatFilterControlSwitch() { | |||
| return '隐藏/显示过滤控制'; | |||
| }, | |||
| formatFilterControlSwitchHide: function formatFilterControlSwitchHide() { | |||
| return '隐藏过滤控制'; | |||
| }, | |||
| formatFilterControlSwitchShow: function formatFilterControlSwitchShow() { | |||
| return '显示过滤控制'; | |||
| } | |||
| }; | |||
| $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['zh-CN']); | |||
| @@ -0,0 +1 @@ | |||
| $.fn.bootstrapTable.locales["zh-CN"]={formatShowSearch:function formatShowSearch(){return"隐藏/显示搜索"},formatPageGo:function formatPageGo(){return"跳转"},formatCopyRows:function formatCopyRows(){return"复制行"},formatPrint:function formatPrint(){return"打印"},formatLoadingMessage:function formatLoadingMessage(){return"正在努力地加载数据中,请稍候"},formatRecordsPerPage:function formatRecordsPerPage(pageNumber){return"每页显示 ".concat(pageNumber," 条记录")},formatShowingRows:function formatShowingRows(pageFrom,pageTo,totalRows,totalNotFiltered){if(totalNotFiltered!==undefined&&totalNotFiltered>0&&totalNotFiltered>totalRows){return"显示第 ".concat(pageFrom," 到第 ").concat(pageTo," 条记录,总共 ").concat(totalRows," 条记录(从 ").concat(totalNotFiltered," 总记录中过滤)")}return"显示第 ".concat(pageFrom," 到第 ").concat(pageTo," 条记录,总共 ").concat(totalRows," 条记录")},formatSRPaginationPreText:function formatSRPaginationPreText(){return"上一页"},formatSRPaginationPageText:function formatSRPaginationPageText(page){return"第".concat(page,"页")},formatSRPaginationNextText:function formatSRPaginationNextText(){return"下一页"},formatDetailPagination:function formatDetailPagination(totalRows){return"总共 ".concat(totalRows," 条记录")},formatClearSearch:function formatClearSearch(){return"清空过滤"},formatSearch:function formatSearch(){return"搜索"},formatNoMatches:function formatNoMatches(){return"没有找到匹配的记录"},formatPaginationSwitch:function formatPaginationSwitch(){return"隐藏/显示分页"},formatPaginationSwitchDown:function formatPaginationSwitchDown(){return"显示分页"},formatPaginationSwitchUp:function formatPaginationSwitchUp(){return"隐藏分页"},formatRefresh:function formatRefresh(){return"刷新"},formatToggle:function formatToggle(){return"切换"},formatToggleOn:function formatToggleOn(){return"显示卡片视图"},formatToggleOff:function formatToggleOff(){return"隐藏卡片视图"},formatColumns:function formatColumns(){return"列"},formatColumnsToggleAll:function formatColumnsToggleAll(){return"切换所有"},formatFullscreen:function formatFullscreen(){return"全屏"},formatAllRows:function formatAllRows(){return"所有"},formatAutoRefresh:function formatAutoRefresh(){return"自动刷新"},formatExport:function formatExport(){return"导出数据"},formatJumpTo:function formatJumpTo(){return"跳转"},formatAdvancedSearch:function formatAdvancedSearch(){return"高级搜索"},formatAdvancedCloseButton:function formatAdvancedCloseButton(){return"关闭"},formatFilterControlSwitch:function formatFilterControlSwitch(){return"隐藏/显示过滤控制"},formatFilterControlSwitchHide:function formatFilterControlSwitchHide(){return"隐藏过滤控制"},formatFilterControlSwitchShow:function formatFilterControlSwitchShow(){return"显示过滤控制"}};$.extend($.fn.bootstrapTable.defaults,$.fn.bootstrapTable.locales["zh-CN"]); | |||
| @@ -0,0 +1,304 @@ | |||
| /*! | |||
| * Cropper.js v1.5.12 | |||
| * https://fengyuanchen.github.io/cropperjs | |||
| * | |||
| * Copyright 2015-present Chen Fengyuan | |||
| * Released under the MIT license | |||
| * | |||
| * Date: 2021-06-12T08:00:11.623Z | |||
| */ | |||
| .cropper-container { | |||
| direction: ltr; | |||
| font-size: 0; | |||
| line-height: 0; | |||
| position: relative; | |||
| -ms-touch-action: none; | |||
| touch-action: none; | |||
| -webkit-user-select: none; | |||
| -moz-user-select: none; | |||
| -ms-user-select: none; | |||
| user-select: none; | |||
| } | |||
| .cropper-container img { | |||
| display: block; | |||
| height: 100%; | |||
| image-orientation: 0deg; | |||
| max-height: none !important; | |||
| max-width: none !important; | |||
| min-height: 0 !important; | |||
| min-width: 0 !important; | |||
| width: 100%; | |||
| } | |||
| .cropper-wrap-box, | |||
| .cropper-canvas, | |||
| .cropper-drag-box, | |||
| .cropper-crop-box, | |||
| .cropper-modal { | |||
| bottom: 0; | |||
| left: 0; | |||
| position: absolute; | |||
| right: 0; | |||
| top: 0; | |||
| } | |||
| .cropper-wrap-box, | |||
| .cropper-canvas { | |||
| overflow: hidden; | |||
| } | |||
| .cropper-drag-box { | |||
| background-color: #fff; | |||
| opacity: 0; | |||
| } | |||
| .cropper-modal { | |||
| background-color: #000; | |||
| opacity: 0.5; | |||
| } | |||
| .cropper-view-box { | |||
| display: block; | |||
| height: 100%; | |||
| outline: 1px solid #39f; | |||
| outline-color: rgba(51, 153, 255, 0.75); | |||
| overflow: hidden; | |||
| width: 100%; | |||
| } | |||
| .cropper-dashed { | |||
| border: 0 dashed #eee; | |||
| display: block; | |||
| opacity: 0.5; | |||
| position: absolute; | |||
| } | |||
| .cropper-dashed.dashed-h { | |||
| border-bottom-width: 1px; | |||
| border-top-width: 1px; | |||
| height: calc(100% / 3); | |||
| left: 0; | |||
| top: calc(100% / 3); | |||
| width: 100%; | |||
| } | |||
| .cropper-dashed.dashed-v { | |||
| border-left-width: 1px; | |||
| border-right-width: 1px; | |||
| height: 100%; | |||
| left: calc(100% / 3); | |||
| top: 0; | |||
| width: calc(100% / 3); | |||
| } | |||
| .cropper-center { | |||
| display: block; | |||
| height: 0; | |||
| left: 50%; | |||
| opacity: 0.75; | |||
| position: absolute; | |||
| top: 50%; | |||
| width: 0; | |||
| } | |||
| .cropper-center::before, | |||
| .cropper-center::after { | |||
| background-color: #eee; | |||
| content: ' '; | |||
| display: block; | |||
| position: absolute; | |||
| } | |||
| .cropper-center::before { | |||
| height: 1px; | |||
| left: -3px; | |||
| top: 0; | |||
| width: 7px; | |||
| } | |||
| .cropper-center::after { | |||
| height: 7px; | |||
| left: 0; | |||
| top: -3px; | |||
| width: 1px; | |||
| } | |||
| .cropper-face, | |||
| .cropper-line, | |||
| .cropper-point { | |||
| display: block; | |||
| height: 100%; | |||
| opacity: 0.1; | |||
| position: absolute; | |||
| width: 100%; | |||
| } | |||
| .cropper-face { | |||
| background-color: #fff; | |||
| left: 0; | |||
| top: 0; | |||
| } | |||
| .cropper-line { | |||
| background-color: #39f; | |||
| } | |||
| .cropper-line.line-e { | |||
| cursor: ew-resize; | |||
| right: -3px; | |||
| top: 0; | |||
| width: 5px; | |||
| } | |||
| .cropper-line.line-n { | |||
| cursor: ns-resize; | |||
| height: 5px; | |||
| left: 0; | |||
| top: -3px; | |||
| } | |||
| .cropper-line.line-w { | |||
| cursor: ew-resize; | |||
| left: -3px; | |||
| top: 0; | |||
| width: 5px; | |||
| } | |||
| .cropper-line.line-s { | |||
| bottom: -3px; | |||
| cursor: ns-resize; | |||
| height: 5px; | |||
| left: 0; | |||
| } | |||
| .cropper-point { | |||
| background-color: #39f; | |||
| height: 5px; | |||
| opacity: 0.75; | |||
| width: 5px; | |||
| } | |||
| .cropper-point.point-e { | |||
| cursor: ew-resize; | |||
| margin-top: -3px; | |||
| right: -3px; | |||
| top: 50%; | |||
| } | |||
| .cropper-point.point-n { | |||
| cursor: ns-resize; | |||
| left: 50%; | |||
| margin-left: -3px; | |||
| top: -3px; | |||
| } | |||
| .cropper-point.point-w { | |||
| cursor: ew-resize; | |||
| left: -3px; | |||
| margin-top: -3px; | |||
| top: 50%; | |||
| } | |||
| .cropper-point.point-s { | |||
| bottom: -3px; | |||
| cursor: s-resize; | |||
| left: 50%; | |||
| margin-left: -3px; | |||
| } | |||
| .cropper-point.point-ne { | |||
| cursor: nesw-resize; | |||
| right: -3px; | |||
| top: -3px; | |||
| } | |||
| .cropper-point.point-nw { | |||
| cursor: nwse-resize; | |||
| left: -3px; | |||
| top: -3px; | |||
| } | |||
| .cropper-point.point-sw { | |||
| bottom: -3px; | |||
| cursor: nesw-resize; | |||
| left: -3px; | |||
| } | |||
| .cropper-point.point-se { | |||
| bottom: -3px; | |||
| cursor: nwse-resize; | |||
| height: 20px; | |||
| opacity: 1; | |||
| right: -3px; | |||
| width: 20px; | |||
| } | |||
| @media (min-width: 768px) { | |||
| .cropper-point.point-se { | |||
| height: 15px; | |||
| width: 15px; | |||
| } | |||
| } | |||
| @media (min-width: 992px) { | |||
| .cropper-point.point-se { | |||
| height: 10px; | |||
| width: 10px; | |||
| } | |||
| } | |||
| @media (min-width: 1200px) { | |||
| .cropper-point.point-se { | |||
| height: 5px; | |||
| opacity: 0.75; | |||
| width: 5px; | |||
| } | |||
| } | |||
| .cropper-point.point-se::before { | |||
| background-color: #39f; | |||
| bottom: -50%; | |||
| content: ' '; | |||
| display: block; | |||
| height: 200%; | |||
| opacity: 0; | |||
| position: absolute; | |||
| right: -50%; | |||
| width: 200%; | |||
| } | |||
| .cropper-invisible { | |||
| opacity: 0; | |||
| } | |||
| .cropper-bg { | |||
| background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC'); | |||
| } | |||
| .cropper-hide { | |||
| display: block; | |||
| height: 0; | |||
| position: absolute; | |||
| width: 0; | |||
| } | |||
| .cropper-hidden { | |||
| display: none !important; | |||
| } | |||
| .cropper-move { | |||
| cursor: move; | |||
| } | |||
| .cropper-crop { | |||
| cursor: crosshair; | |||
| } | |||
| .cropper-disabled .cropper-drag-box, | |||
| .cropper-disabled .cropper-face, | |||
| .cropper-disabled .cropper-line, | |||
| .cropper-disabled .cropper-point { | |||
| cursor: not-allowed; | |||
| } | |||
| @@ -0,0 +1,9 @@ | |||
| /*! | |||
| * Cropper.js v1.5.12 | |||
| * https://fengyuanchen.github.io/cropperjs | |||
| * | |||
| * Copyright 2015-present Chen Fengyuan | |||
| * Released under the MIT license | |||
| * | |||
| * Date: 2021-06-12T08:00:11.623Z | |||
| */.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.cropper-container img{image-orientation:0deg;display:block;height:100%;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-canvas,.cropper-wrap-box{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:rgba(51,153,255,.75);overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:33.33333%;left:0;top:33.33333%;width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:33.33333%;top:0;width:33.33333%}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:after,.cropper-center:before{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media (min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media (min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media (min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed} | |||
| @@ -0,0 +1,406 @@ | |||
| /*! | |||
| * jQuery cxSelect | |||
| * @name jquery.cxselect.js | |||
| * @version 1.4.2 | |||
| * @date 2017-09-26 | |||
| * @author ciaoca | |||
| * @email ciaoca@gmail.com | |||
| * @site https://github.com/ciaoca/cxSelect | |||
| * @license Released under the MIT license | |||
| */ | |||
| (function(factory) { | |||
| if (typeof define === 'function' && define.amd) { | |||
| define(['jquery'], factory); | |||
| } else { | |||
| factory(window.jQuery || window.Zepto || window.$); | |||
| }; | |||
| }(function($) { | |||
| var cxSelect = function() { | |||
| var self = this; | |||
| var dom, settings, callback; | |||
| // 分配参数 | |||
| for (var i = 0, l = arguments.length; i < l; i++) { | |||
| if (cxSelect.isJquery(arguments[i]) || cxSelect.isZepto(arguments[i])) { | |||
| dom = arguments[i]; | |||
| } else if (cxSelect.isElement(arguments[i])) { | |||
| dom = $(arguments[i]); | |||
| } else if (typeof arguments[i] === 'function') { | |||
| callback = arguments[i]; | |||
| } else if (typeof arguments[i] === 'object') { | |||
| settings = arguments[i]; | |||
| }; | |||
| }; | |||
| var api = new cxSelect.init(dom, settings); | |||
| if (typeof callback === 'function') { | |||
| callback(api); | |||
| }; | |||
| return api; | |||
| }; | |||
| cxSelect.isElement = function(o){ | |||
| if (o && (typeof HTMLElement === 'function' || typeof HTMLElement === 'object') && o instanceof HTMLElement) { | |||
| return true; | |||
| } else { | |||
| return (o && o.nodeType && o.nodeType === 1) ? true : false; | |||
| }; | |||
| }; | |||
| cxSelect.isJquery = function(o){ | |||
| return (o && o.length && (typeof jQuery === 'function' || typeof jQuery === 'object') && o instanceof jQuery) ? true : false; | |||
| }; | |||
| cxSelect.isZepto = function(o){ | |||
| return (o && o.length && (typeof Zepto === 'function' || typeof Zepto === 'object') && Zepto.zepto.isZ(o)) ? true : false; | |||
| }; | |||
| cxSelect.getIndex = function(n, required) { | |||
| return required ? n : n - 1; | |||
| }; | |||
| cxSelect.getData = function(data, space) { | |||
| if (typeof space === 'string' && space.length) { | |||
| space = space.split('.'); | |||
| for (var i = 0, l = space.length; i < l; i++) { | |||
| data = data[space[i]]; | |||
| }; | |||
| }; | |||
| return data; | |||
| }; | |||
| cxSelect.init = function(dom, settings) { | |||
| var self = this; | |||
| if (!cxSelect.isJquery(dom) && !cxSelect.isZepto(dom)) {return}; | |||
| var theSelect = { | |||
| dom: { | |||
| box: dom | |||
| } | |||
| }; | |||
| self.attach = cxSelect.attach.bind(theSelect); | |||
| self.detach = cxSelect.detach.bind(theSelect); | |||
| self.setOptions = cxSelect.setOptions.bind(theSelect); | |||
| self.clear = cxSelect.clear.bind(theSelect); | |||
| theSelect.changeEvent = function() { | |||
| cxSelect.selectChange.call(theSelect, this.className); | |||
| }; | |||
| theSelect.settings = $.extend({}, $.cxSelect.defaults, settings, { | |||
| url: theSelect.dom.box.data('url'), | |||
| emptyStyle: theSelect.dom.box.data('emptyStyle'), | |||
| required: theSelect.dom.box.data('required'), | |||
| firstTitle: theSelect.dom.box.data('firstTitle'), | |||
| firstValue: theSelect.dom.box.data('firstValue'), | |||
| jsonSpace: theSelect.dom.box.data('jsonSpace'), | |||
| jsonName: theSelect.dom.box.data('jsonName'), | |||
| jsonValue: theSelect.dom.box.data('jsonValue'), | |||
| jsonSub: theSelect.dom.box.data('jsonSub') | |||
| }); | |||
| var _dataSelects = theSelect.dom.box.data('selects'); | |||
| if (typeof _dataSelects === 'string' && _dataSelects.length) { | |||
| theSelect.settings.selects = _dataSelects.split(','); | |||
| }; | |||
| self.setOptions(); | |||
| self.attach(); | |||
| // 使用独立接口获取数据 | |||
| if (!theSelect.settings.url && !theSelect.settings.data) { | |||
| cxSelect.start.apply(theSelect); | |||
| // 设置自定义数据 | |||
| } else if ($.isArray(theSelect.settings.data)) { | |||
| cxSelect.start.call(theSelect, theSelect.settings.data); | |||
| // 设置 URL,通过 Ajax 获取数据 | |||
| } else if (typeof theSelect.settings.url === 'string' && theSelect.settings.url.length) { | |||
| $.getJSON(theSelect.settings.url, function(json) { | |||
| cxSelect.start.call(theSelect, json); | |||
| }); | |||
| }; | |||
| }; | |||
| // 设置参数 | |||
| cxSelect.setOptions = function(opts) { | |||
| var self = this; | |||
| if (opts) { | |||
| $.extend(self.settings, opts); | |||
| }; | |||
| // 初次或重设选择器组 | |||
| if (!$.isArray(self.selectArray) || !self.selectArray.length || (opts && opts.selects)) { | |||
| self.selectArray = []; | |||
| if ($.isArray(self.settings.selects) && self.settings.selects.length) { | |||
| var _tempSelect; | |||
| for (var i = 0, l = self.settings.selects.length; i < l; i++) { | |||
| _tempSelect = self.dom.box.find('select.' + self.settings.selects[i]); | |||
| if (!_tempSelect || !_tempSelect.length) {break}; | |||
| self.selectArray.push(_tempSelect); | |||
| }; | |||
| }; | |||
| }; | |||
| if (opts) { | |||
| if (!$.isArray(opts.data) && typeof opts.url === 'string' && opts.url.length) { | |||
| $.getJSON(self.settings.url, function(json) { | |||
| cxSelect.start.call(self, json); | |||
| }); | |||
| } else { | |||
| cxSelect.start.call(self, opts.data); | |||
| }; | |||
| }; | |||
| }; | |||
| // 绑定 | |||
| cxSelect.attach = function() { | |||
| var self = this; | |||
| if (!self.attachStatus) { | |||
| self.dom.box.on('change', 'select', self.changeEvent); | |||
| }; | |||
| if (typeof self.attachStatus === 'boolean') { | |||
| cxSelect.start.call(self); | |||
| }; | |||
| self.attachStatus = true; | |||
| }; | |||
| // 移除绑定 | |||
| cxSelect.detach = function() { | |||
| var self = this; | |||
| self.dom.box.off('change', 'select', self.changeEvent); | |||
| self.attachStatus = false; | |||
| }; | |||
| // 清空选项 | |||
| cxSelect.clear = function(index) { | |||
| var self = this; | |||
| var _style = { | |||
| display: '', | |||
| visibility: '' | |||
| }; | |||
| index = isNaN(index) ? 0 : index; | |||
| // 清空后面的 select | |||
| for (var i = index, l = self.selectArray.length; i < l; i++) { | |||
| self.selectArray[i].empty().prop('disabled', true); | |||
| if (self.settings.emptyStyle === 'none') { | |||
| _style.display = 'none'; | |||
| } else if (self.settings.emptyStyle === 'hidden') { | |||
| _style.visibility = 'hidden'; | |||
| }; | |||
| self.selectArray[i].css(_style); | |||
| }; | |||
| }; | |||
| cxSelect.start = function(data) { | |||
| var self = this; | |||
| if ($.isArray(data)) { | |||
| self.settings.data = cxSelect.getData(data, self.settings.jsonSpace); | |||
| }; | |||
| if (!self.selectArray.length) {return}; | |||
| // 保存默认值 | |||
| for (var i = 0, l = self.selectArray.length; i < l; i++) { | |||
| if (typeof self.selectArray[i].attr('data-value') !== 'string' && self.selectArray[i][0].options.length) { | |||
| self.selectArray[i].attr('data-value', self.selectArray[i].val()); | |||
| }; | |||
| }; | |||
| if (self.settings.data || (typeof self.selectArray[0].data('url') === 'string' && self.selectArray[0].data('url').length)) { | |||
| cxSelect.getOptionData.call(self, 0); | |||
| } else if (self.selectArray[0][0].options.length && typeof self.selectArray[0].attr('data-value') === 'string' && self.selectArray[0].attr('data-value').length) { | |||
| self.selectArray[0].val(self.selectArray[0].attr('data-value')); | |||
| cxSelect.getOptionData.call(self, 1); | |||
| } else { | |||
| self.selectArray[0].prop('disabled', false).css({ | |||
| 'display': '', | |||
| 'visibility': '' | |||
| }); | |||
| }; | |||
| }; | |||
| // 获取选项数据 | |||
| cxSelect.getOptionData = function(index) { | |||
| var self = this; | |||
| if (typeof index !== 'number' || isNaN(index) || index < 0 || index >= self.selectArray.length) {return}; | |||
| var _indexPrev = index - 1; | |||
| var _select = self.selectArray[index]; | |||
| var _selectData; | |||
| var _valueIndex; | |||
| var _dataUrl = _select.data('url'); | |||
| var _jsonSpace = typeof _select.data('jsonSpace') === 'undefined' ? self.settings.jsonSpace : _select.data('jsonSpace'); | |||
| var _query = {}; | |||
| var _queryName; | |||
| var _selectName; | |||
| var _selectValue; | |||
| cxSelect.clear.call(self, index); | |||
| // 使用独立接口 | |||
| if (typeof _dataUrl === 'string' && _dataUrl.length) { | |||
| if (index > 0) { | |||
| for (var i = 0, j = 1; i < index; i++, j++) { | |||
| _queryName = self.selectArray[j].data('queryName'); | |||
| _selectName = self.selectArray[i].attr('name'); | |||
| _selectValue = self.selectArray[i].val(); | |||
| if (typeof _queryName === 'string' && _queryName.length) { | |||
| _query[_queryName] = _selectValue; | |||
| } else if (typeof _selectName === 'string' && _selectName.length) { | |||
| _query[_selectName] = _selectValue; | |||
| }; | |||
| }; | |||
| }; | |||
| $.getJSON(_dataUrl, _query, function(json) { | |||
| _selectData = cxSelect.getData(json, _jsonSpace); | |||
| cxSelect.buildOption.call(self, index, _selectData); | |||
| }); | |||
| // 使用整合数据 | |||
| } else if (self.settings.data && typeof self.settings.data === 'object') { | |||
| _selectData = self.settings.data; | |||
| for (var i = 0; i < index; i++) { | |||
| _valueIndex = cxSelect.getIndex(self.selectArray[i][0].selectedIndex, typeof self.selectArray[i].data('required') === 'boolean' ? self.selectArray[i].data('required') : self.settings.required); | |||
| if (typeof _selectData[_valueIndex] === 'object' && $.isArray(_selectData[_valueIndex][self.settings.jsonSub]) && _selectData[_valueIndex][self.settings.jsonSub].length) { | |||
| _selectData = _selectData[_valueIndex][self.settings.jsonSub]; | |||
| } else { | |||
| _selectData = null; | |||
| break; | |||
| }; | |||
| }; | |||
| cxSelect.buildOption.call(self, index, _selectData); | |||
| }; | |||
| }; | |||
| // 构建选项列表 | |||
| cxSelect.buildOption = function(index, data) { | |||
| var self = this; | |||
| var _select = self.selectArray[index]; | |||
| var _required = typeof _select.data('required') === 'boolean' ? _select.data('required') : self.settings.required; | |||
| var _firstTitle = typeof _select.data('firstTitle') === 'undefined' ? self.settings.firstTitle : _select.data('firstTitle'); | |||
| var _firstValue = typeof _select.data('firstValue') === 'undefined' ? self.settings.firstValue : _select.data('firstValue'); | |||
| var _jsonName = typeof _select.data('jsonName') === 'undefined' ? self.settings.jsonName : _select.data('jsonName'); | |||
| var _jsonValue = typeof _select.data('jsonValue') === 'undefined' ? self.settings.jsonValue : _select.data('jsonValue'); | |||
| if (!$.isArray(data)) {return}; | |||
| var _html = !_required ? '<option value="' + String(_firstValue) + '">' + String(_firstTitle) + '</option>' : ''; | |||
| // 区分标题、值的数据 | |||
| if (typeof _jsonName === 'string' && _jsonName.length) { | |||
| // 无值字段时使用标题作为值 | |||
| if (typeof _jsonValue !== 'string' || !_jsonValue.length) { | |||
| _jsonValue = _jsonName; | |||
| }; | |||
| for (var i = 0, l = data.length; i < l; i++) { | |||
| _html += '<option value="' + String(data[i][_jsonValue]) + '">' + String(data[i][_jsonName]) + '</option>'; | |||
| }; | |||
| // 数组即为值的数据 | |||
| } else { | |||
| for (var i = 0, l = data.length; i < l; i++) { | |||
| _html += '<option value="' + String(data[i]) + '">' + String(data[i]) + '</option>'; | |||
| }; | |||
| }; | |||
| _select.html(_html).prop('disabled', false).css({ | |||
| 'display': '', | |||
| 'visibility': '' | |||
| }); | |||
| // 初次加载设置默认值 | |||
| if (typeof _select.attr('data-value') === 'string') { | |||
| _select.val(String(_select.attr('data-value'))).removeAttr('data-value'); | |||
| if (_select[0].selectedIndex < 0) { | |||
| _select[0].options[0].selected = true; | |||
| }; | |||
| }; | |||
| if (_required || _select[0].selectedIndex > 0) { | |||
| _select.trigger('change'); | |||
| }; | |||
| }; | |||
| // 改变选择时的处理 | |||
| cxSelect.selectChange = function(name) { | |||
| var self = this; | |||
| if (typeof name !== 'string' || !name.length) {return}; | |||
| var index; | |||
| name = name.replace(/\s+/g, ','); | |||
| name = ',' + name + ','; | |||
| // 获取当前 select 位置 | |||
| for (var i = 0, l = self.selectArray.length; i < l; i++) { | |||
| if (name.indexOf(',' + self.settings.selects[i] + ',') > -1) { | |||
| index = i; | |||
| break; | |||
| }; | |||
| }; | |||
| if (typeof index === 'number' && index > -1) { | |||
| index += 1; | |||
| cxSelect.getOptionData.call(self, index); | |||
| }; | |||
| }; | |||
| $.cxSelect = function() { | |||
| return cxSelect.apply(this, arguments); | |||
| }; | |||
| // 默认值 | |||
| $.cxSelect.defaults = { | |||
| selects: [], // 下拉选框组 | |||
| url: null, // 列表数据文件路径(URL)或数组数据 | |||
| data: null, // 自定义数据 | |||
| emptyStyle: null, // 无数据状态显示方式 | |||
| required: false, // 是否为必选 | |||
| firstTitle: '请选择', // 第一个选项的标题 | |||
| firstValue: '', // 第一个选项的值 | |||
| jsonSpace: '', // 数据命名空间 | |||
| jsonName: 'n', // 数据标题字段名称 | |||
| jsonValue: '', // 数据值字段名称 | |||
| jsonSub: 's' // 子集数据字段名称 | |||
| }; | |||
| $.fn.cxSelect = function(settings, callback) { | |||
| this.each(function(i) { | |||
| $.cxSelect(this, settings, callback); | |||
| }); | |||
| return this; | |||
| }; | |||
| })); | |||
| @@ -0,0 +1,418 @@ | |||
| /*! | |||
| * Datetimepicker for Bootstrap | |||
| * | |||
| * Copyright 2012 Stefan Petre | |||
| * Improvements by Andrew Rowls | |||
| * Licensed under the Apache License v2.0 | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| */ | |||
| .datetimepicker { | |||
| padding: 4px; | |||
| margin-top: 1px; | |||
| -webkit-border-radius: 4px; | |||
| -moz-border-radius: 4px; | |||
| border-radius: 4px; | |||
| direction: ltr; | |||
| } | |||
| .datetimepicker-inline { | |||
| width: 220px; | |||
| } | |||
| .datetimepicker.datetimepicker-rtl { | |||
| direction: rtl; | |||
| } | |||
| .datetimepicker.datetimepicker-rtl table tr td span { | |||
| float: right; | |||
| } | |||
| .datetimepicker-dropdown, .datetimepicker-dropdown-left { | |||
| top: 0; | |||
| left: 0; | |||
| } | |||
| [class*=" datetimepicker-dropdown"]:before { | |||
| content: ''; | |||
| display: inline-block; | |||
| border-left: 7px solid transparent; | |||
| border-right: 7px solid transparent; | |||
| border-bottom: 7px solid #cccccc; | |||
| border-bottom-color: rgba(0, 0, 0, 0.2); | |||
| position: absolute; | |||
| } | |||
| [class*=" datetimepicker-dropdown"]:after { | |||
| content: ''; | |||
| display: inline-block; | |||
| border-left: 6px solid transparent; | |||
| border-right: 6px solid transparent; | |||
| border-bottom: 6px solid #ffffff; | |||
| position: absolute; | |||
| } | |||
| [class*=" datetimepicker-dropdown-top"]:before { | |||
| content: ''; | |||
| display: inline-block; | |||
| border-left: 7px solid transparent; | |||
| border-right: 7px solid transparent; | |||
| border-top: 7px solid #cccccc; | |||
| border-top-color: rgba(0, 0, 0, 0.2); | |||
| border-bottom: 0; | |||
| } | |||
| [class*=" datetimepicker-dropdown-top"]:after { | |||
| content: ''; | |||
| display: inline-block; | |||
| border-left: 6px solid transparent; | |||
| border-right: 6px solid transparent; | |||
| border-top: 6px solid #ffffff; | |||
| border-bottom: 0; | |||
| } | |||
| .datetimepicker-dropdown-bottom-left:before { | |||
| top: -7px; | |||
| right: 6px; | |||
| } | |||
| .datetimepicker-dropdown-bottom-left:after { | |||
| top: -6px; | |||
| right: 7px; | |||
| } | |||
| .datetimepicker-dropdown-bottom-right:before { | |||
| top: -7px; | |||
| left: 6px; | |||
| } | |||
| .datetimepicker-dropdown-bottom-right:after { | |||
| top: -6px; | |||
| left: 7px; | |||
| } | |||
| .datetimepicker-dropdown-top-left:before { | |||
| bottom: -7px; | |||
| right: 6px; | |||
| } | |||
| .datetimepicker-dropdown-top-left:after { | |||
| bottom: -6px; | |||
| right: 7px; | |||
| } | |||
| .datetimepicker-dropdown-top-right:before { | |||
| bottom: -7px; | |||
| left: 6px; | |||
| } | |||
| .datetimepicker-dropdown-top-right:after { | |||
| bottom: -6px; | |||
| left: 7px; | |||
| } | |||
| .datetimepicker > div { | |||
| display: none; | |||
| } | |||
| .datetimepicker.minutes div.datetimepicker-minutes { | |||
| display: block; | |||
| } | |||
| .datetimepicker.hours div.datetimepicker-hours { | |||
| display: block; | |||
| } | |||
| .datetimepicker.days div.datetimepicker-days { | |||
| display: block; | |||
| } | |||
| .datetimepicker.months div.datetimepicker-months { | |||
| display: block; | |||
| } | |||
| .datetimepicker.years div.datetimepicker-years { | |||
| display: block; | |||
| } | |||
| .datetimepicker table { | |||
| margin: 0; | |||
| } | |||
| .datetimepicker td, | |||
| .datetimepicker th { | |||
| text-align: center; | |||
| width: 20px; | |||
| height: 20px; | |||
| -webkit-border-radius: 4px; | |||
| -moz-border-radius: 4px; | |||
| border-radius: 4px; | |||
| border: none; | |||
| } | |||
| .table-striped .datetimepicker table tr td, | |||
| .table-striped .datetimepicker table tr th { | |||
| background-color: transparent; | |||
| } | |||
| .datetimepicker table tr td.minute:hover { | |||
| background: #eeeeee; | |||
| cursor: pointer; | |||
| } | |||
| .datetimepicker table tr td.hour:hover { | |||
| background: #eeeeee; | |||
| cursor: pointer; | |||
| } | |||
| .datetimepicker table tr td.day:hover { | |||
| background: #eeeeee; | |||
| cursor: pointer; | |||
| } | |||
| .datetimepicker table tr td.old, | |||
| .datetimepicker table tr td.new { | |||
| color: #999999; | |||
| } | |||
| .datetimepicker table tr td.disabled, | |||
| .datetimepicker table tr td.disabled:hover { | |||
| background: none; | |||
| color: #999999; | |||
| cursor: default; | |||
| } | |||
| .datetimepicker table tr td.today, | |||
| .datetimepicker table tr td.today:hover, | |||
| .datetimepicker table tr td.today.disabled, | |||
| .datetimepicker table tr td.today.disabled:hover { | |||
| background-color: #fde19a; | |||
| background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); | |||
| background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); | |||
| background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); | |||
| background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); | |||
| background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); | |||
| background-image: linear-gradient(to bottom, #fdd49a, #fdf59a); | |||
| background-repeat: repeat-x; | |||
| filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); | |||
| border-color: #fdf59a #fdf59a #fbed50; | |||
| border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |||
| filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); | |||
| } | |||
| .datetimepicker table tr td.today:hover, | |||
| .datetimepicker table tr td.today:hover:hover, | |||
| .datetimepicker table tr td.today.disabled:hover, | |||
| .datetimepicker table tr td.today.disabled:hover:hover, | |||
| .datetimepicker table tr td.today:active, | |||
| .datetimepicker table tr td.today:hover:active, | |||
| .datetimepicker table tr td.today.disabled:active, | |||
| .datetimepicker table tr td.today.disabled:hover:active, | |||
| .datetimepicker table tr td.today.active, | |||
| .datetimepicker table tr td.today:hover.active, | |||
| .datetimepicker table tr td.today.disabled.active, | |||
| .datetimepicker table tr td.today.disabled:hover.active, | |||
| .datetimepicker table tr td.today.disabled, | |||
| .datetimepicker table tr td.today:hover.disabled, | |||
| .datetimepicker table tr td.today.disabled.disabled, | |||
| .datetimepicker table tr td.today.disabled:hover.disabled, | |||
| .datetimepicker table tr td.today[disabled], | |||
| .datetimepicker table tr td.today:hover[disabled], | |||
| .datetimepicker table tr td.today.disabled[disabled], | |||
| .datetimepicker table tr td.today.disabled:hover[disabled] { | |||
| background-color: #fdf59a; | |||
| } | |||
| .datetimepicker table tr td.today:active, | |||
| .datetimepicker table tr td.today:hover:active, | |||
| .datetimepicker table tr td.today.disabled:active, | |||
| .datetimepicker table tr td.today.disabled:hover:active, | |||
| .datetimepicker table tr td.today.active, | |||
| .datetimepicker table tr td.today:hover.active, | |||
| .datetimepicker table tr td.today.disabled.active, | |||
| .datetimepicker table tr td.today.disabled:hover.active { | |||
| background-color: #fbf069; | |||
| } | |||
| .datetimepicker table tr td.active, | |||
| .datetimepicker table tr td.active:hover, | |||
| .datetimepicker table tr td.active.disabled, | |||
| .datetimepicker table tr td.active.disabled:hover { | |||
| background-color: #006dcc; | |||
| background-image: -moz-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -ms-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); | |||
| background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -o-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: linear-gradient(to bottom, #0088cc, #0044cc); | |||
| background-repeat: repeat-x; | |||
| filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); | |||
| border-color: #0044cc #0044cc #002a80; | |||
| border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |||
| filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); | |||
| color: #ffffff; | |||
| text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | |||
| } | |||
| .datetimepicker table tr td.active:hover, | |||
| .datetimepicker table tr td.active:hover:hover, | |||
| .datetimepicker table tr td.active.disabled:hover, | |||
| .datetimepicker table tr td.active.disabled:hover:hover, | |||
| .datetimepicker table tr td.active:active, | |||
| .datetimepicker table tr td.active:hover:active, | |||
| .datetimepicker table tr td.active.disabled:active, | |||
| .datetimepicker table tr td.active.disabled:hover:active, | |||
| .datetimepicker table tr td.active.active, | |||
| .datetimepicker table tr td.active:hover.active, | |||
| .datetimepicker table tr td.active.disabled.active, | |||
| .datetimepicker table tr td.active.disabled:hover.active, | |||
| .datetimepicker table tr td.active.disabled, | |||
| .datetimepicker table tr td.active:hover.disabled, | |||
| .datetimepicker table tr td.active.disabled.disabled, | |||
| .datetimepicker table tr td.active.disabled:hover.disabled, | |||
| .datetimepicker table tr td.active[disabled], | |||
| .datetimepicker table tr td.active:hover[disabled], | |||
| .datetimepicker table tr td.active.disabled[disabled], | |||
| .datetimepicker table tr td.active.disabled:hover[disabled] { | |||
| background-color: #0044cc; | |||
| } | |||
| .datetimepicker table tr td.active:active, | |||
| .datetimepicker table tr td.active:hover:active, | |||
| .datetimepicker table tr td.active.disabled:active, | |||
| .datetimepicker table tr td.active.disabled:hover:active, | |||
| .datetimepicker table tr td.active.active, | |||
| .datetimepicker table tr td.active:hover.active, | |||
| .datetimepicker table tr td.active.disabled.active, | |||
| .datetimepicker table tr td.active.disabled:hover.active { | |||
| background-color: #003399; | |||
| } | |||
| .datetimepicker table tr td span { | |||
| display: block; | |||
| width: 23%; | |||
| height: 54px; | |||
| line-height: 54px; | |||
| float: left; | |||
| margin: 1%; | |||
| cursor: pointer; | |||
| -webkit-border-radius: 4px; | |||
| -moz-border-radius: 4px; | |||
| border-radius: 4px; | |||
| } | |||
| .datetimepicker .datetimepicker-hours span { | |||
| height: 26px; | |||
| line-height: 26px; | |||
| } | |||
| .datetimepicker .datetimepicker-hours table tr td span.hour_am, | |||
| .datetimepicker .datetimepicker-hours table tr td span.hour_pm { | |||
| width: 14.6%; | |||
| } | |||
| .datetimepicker .datetimepicker-hours fieldset legend, | |||
| .datetimepicker .datetimepicker-minutes fieldset legend { | |||
| margin-bottom: inherit; | |||
| line-height: 30px; | |||
| } | |||
| .datetimepicker .datetimepicker-minutes span { | |||
| height: 26px; | |||
| line-height: 26px; | |||
| } | |||
| .datetimepicker table tr td span:hover { | |||
| background: #eeeeee; | |||
| } | |||
| .datetimepicker table tr td span.disabled, | |||
| .datetimepicker table tr td span.disabled:hover { | |||
| background: none; | |||
| color: #999999; | |||
| cursor: default; | |||
| } | |||
| .datetimepicker table tr td span.active, | |||
| .datetimepicker table tr td span.active:hover, | |||
| .datetimepicker table tr td span.active.disabled, | |||
| .datetimepicker table tr td span.active.disabled:hover { | |||
| background-color: #006dcc; | |||
| background-image: -moz-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -ms-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); | |||
| background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: -o-linear-gradient(top, #0088cc, #0044cc); | |||
| background-image: linear-gradient(to bottom, #0088cc, #0044cc); | |||
| background-repeat: repeat-x; | |||
| filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); | |||
| border-color: #0044cc #0044cc #002a80; | |||
| border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | |||
| filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); | |||
| color: #ffffff; | |||
| text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | |||
| } | |||
| .datetimepicker table tr td span.active:hover, | |||
| .datetimepicker table tr td span.active:hover:hover, | |||
| .datetimepicker table tr td span.active.disabled:hover, | |||
| .datetimepicker table tr td span.active.disabled:hover:hover, | |||
| .datetimepicker table tr td span.active:active, | |||
| .datetimepicker table tr td span.active:hover:active, | |||
| .datetimepicker table tr td span.active.disabled:active, | |||
| .datetimepicker table tr td span.active.disabled:hover:active, | |||
| .datetimepicker table tr td span.active.active, | |||
| .datetimepicker table tr td span.active:hover.active, | |||
| .datetimepicker table tr td span.active.disabled.active, | |||
| .datetimepicker table tr td span.active.disabled:hover.active, | |||
| .datetimepicker table tr td span.active.disabled, | |||
| .datetimepicker table tr td span.active:hover.disabled, | |||
| .datetimepicker table tr td span.active.disabled.disabled, | |||
| .datetimepicker table tr td span.active.disabled:hover.disabled, | |||
| .datetimepicker table tr td span.active[disabled], | |||
| .datetimepicker table tr td span.active:hover[disabled], | |||
| .datetimepicker table tr td span.active.disabled[disabled], | |||
| .datetimepicker table tr td span.active.disabled:hover[disabled] { | |||
| background-color: #0044cc; | |||
| } | |||
| .datetimepicker table tr td span.active:active, | |||
| .datetimepicker table tr td span.active:hover:active, | |||
| .datetimepicker table tr td span.active.disabled:active, | |||
| .datetimepicker table tr td span.active.disabled:hover:active, | |||
| .datetimepicker table tr td span.active.active, | |||
| .datetimepicker table tr td span.active:hover.active, | |||
| .datetimepicker table tr td span.active.disabled.active, | |||
| .datetimepicker table tr td span.active.disabled:hover.active { | |||
| background-color: #003399; | |||
| } | |||
| .datetimepicker table tr td span.old { | |||
| color: #999999; | |||
| } | |||
| .datetimepicker th.switch { | |||
| width: 145px; | |||
| } | |||
| .datetimepicker th span.glyphicon { | |||
| pointer-events: none; | |||
| } | |||
| .datetimepicker thead tr:first-child th, | |||
| .datetimepicker tfoot th { | |||
| cursor: pointer; | |||
| } | |||
| .datetimepicker thead tr:first-child th:hover, | |||
| .datetimepicker tfoot th:hover { | |||
| background: #eeeeee; | |||
| } | |||
| .input-append.date .add-on i, | |||
| .input-prepend.date .add-on i, | |||
| .input-group.date .input-group-addon span { | |||
| cursor: pointer; | |||
| width: 14px; | |||
| height: 14px; | |||
| } | |||
| @@ -0,0 +1,86 @@ | |||
| /* | |||
| * Bootstrap Duallistbox - v3.0.9 | |||
| * A responsive dual listbox widget optimized for Twitter Bootstrap. It works on all modern browsers and on touch devices. | |||
| * https://www.virtuosoft.eu/code/bootstrap-duallistbox/ | |||
| * | |||
| * Made by István Ujj-Mészáros | |||
| * Under Apache License v2.0 License | |||
| */ | |||
| .bootstrap-duallistbox-container .buttons { | |||
| width: 100%; | |||
| margin-bottom: -1px; | |||
| } | |||
| .bootstrap-duallistbox-container label { | |||
| display: block; | |||
| } | |||
| .bootstrap-duallistbox-container .info { | |||
| display: inline-block; | |||
| margin-bottom: 5px; | |||
| font-size: 11px; | |||
| } | |||
| .bootstrap-duallistbox-container .clear1, | |||
| .bootstrap-duallistbox-container .clear2 { | |||
| display: none; | |||
| font-size: 10px; | |||
| } | |||
| .bootstrap-duallistbox-container .box1.filtered .clear1, | |||
| .bootstrap-duallistbox-container .box2.filtered .clear2 { | |||
| display: inline-block; | |||
| } | |||
| .bootstrap-duallistbox-container .move, | |||
| .bootstrap-duallistbox-container .remove { | |||
| width: 60%; | |||
| } | |||
| .bootstrap-duallistbox-container .btn-group .btn { | |||
| border-bottom-left-radius: 0; | |||
| border-bottom-right-radius: 0; | |||
| } | |||
| .bootstrap-duallistbox-container select { | |||
| border-top-left-radius: 0; | |||
| border-top-right-radius: 0; | |||
| } | |||
| .bootstrap-duallistbox-container .moveall, | |||
| .bootstrap-duallistbox-container .removeall { | |||
| width: 40%; | |||
| } | |||
| .bootstrap-duallistbox-container.bs2compatible .btn-group > .btn + .btn { | |||
| margin-left: 0; | |||
| } | |||
| .bootstrap-duallistbox-container select { | |||
| width: 100%; | |||
| height: 300px; | |||
| padding: 0; | |||
| } | |||
| .bootstrap-duallistbox-container .filter { | |||
| display: inline-block; | |||
| width: 100%; | |||
| height: 31px; | |||
| margin: 0 0 5px 0; | |||
| -webkit-box-sizing: border-box; | |||
| -moz-box-sizing: border-box; | |||
| box-sizing: border-box; | |||
| } | |||
| .bootstrap-duallistbox-container .filter.placeholder { | |||
| color: #aaa; | |||
| } | |||
| .bootstrap-duallistbox-container.moveonselect .move, | |||
| .bootstrap-duallistbox-container.moveonselect .remove { | |||
| display:none; | |||
| } | |||
| .bootstrap-duallistbox-container.moveonselect .moveall, | |||
| .bootstrap-duallistbox-container.moveonselect .removeall { | |||
| width: 100%; | |||
| } | |||