新建项目

This commit is contained in:
jinqiming 2020-09-16 15:33:51 +08:00
commit 5ac8e8a2c2
636 changed files with 157451 additions and 0 deletions

43
.gitignore vendored Normal file
View File

@ -0,0 +1,43 @@
######################################################################
# 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
### NetBeans ###
nbproject/private/
build/*
nbbuild/
dist/
nbdist/
.nb-gradle/
######################################################################
# Others
*.log
*.xml.versionsBackup
!*/build/*.java
!*/build/*.html
!*/build/*.xml

20
LICENSE Normal file
View File

@ -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.

87
README.md Normal file
View File

@ -0,0 +1,87 @@
## 平台简介
一直想做一款后台管理系统看了很多优秀的开源项目但是发现没有合适的。于是利用空闲休息时间开始自己写了一套后台系统。如此有了若依。她可以用于所有的Web应用程序如网站管理后台网站会员中心CMSCRMOA。所有前端后台代码封装过后十分精简易上手出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
性别男,若依是给还没有出生女儿取的名字(寓意:你若不离不弃,我必生死相依)
* 感谢 [hplus](https://gitee.com/hplus_admin/hplus) 后台主题 UI 框架。
* 前后端分离版本,请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)
* 阿里云优惠券:[点我进入](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)  
## 内置功能
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
3. 岗位管理:配置系统用户所属担任职务。
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
7. 参数管理:对系统动态配置常用参数。
8. 通知公告:系统通知公告信息发布维护。
9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
10. 登录日志:系统登录日志记录查询包含登录异常。
11. 在线用户:当前系统中活跃用户状态监控。
12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
13. 代码生成前后端代码的生成java、html、xml、sql支持CRUD下载 。
14. 系统接口根据业务代码自动生成相关的api接口文档。
15. 服务监控监视当前系统CPU、内存、磁盘、堆栈等相关信息。
16. 在线构建器拖动表单元素生成相应的HTML代码。
17. 连接池监视监视当前系统数据库连接池状态可进行分析SQL找出系统性能瓶颈。
## 在线体验
- admin/admin123
- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。
演示地址http://ruoyi.vip
文档地址http://doc.ruoyi.vip
## 演示图
<table>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/25b5e333768d013d45a990c152dbe4d9d6e.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/e29fd81b2d43b517f99535564af41f9d1d5.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/629f1510fb6205f773c8c284863406b694f.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/9124eda87df0e72427cd63f458b813e3363.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/438c59467afd0097cfbe9c89db932661687.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/72a015041db6843aca7f7b273688cb346f8.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/ecb5f1c9929f1933f733f796749b2df73d9.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/e4283d500eb10e8dd8701e7742f7facb065.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/2531dbf419a1b114e1177f8d2a120b8a9c3.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/8b740a42dddc1e5a8a150d97c5060df258b.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/00e642dc3515919b3760968cc496a12a849.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/f72d28a3e60413a4e1b5c7c2f45f962fd65.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/19222e495869a2a99fc31c5d2bd4539e1e7.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/264d25176f4e22b4b38e95fe6ce73775299.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/d85fbb59be27fb33f68bdbb6e8bc967c97b.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/bb902d2c54bad02a052e9a05e5f22a93df1.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/30cda883bb9a7f74f1454314e64f949942d.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/deebaaa8d6b14a419ed5911f49e3f222a6f.jpg"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/bed2b98a44e7ae820c2885329e711965c28.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-6d73c2140ce694e3de4c05035fdc1868d4c.png"/></td>
</tr>
</table>
## 若依交流群
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [![加入QQ群](https://img.shields.io/badge/已满-1679294-blue.svg)](https://jq.qq.com/?_wv=1027&k=5cHeRVW) [![加入QQ群](https://img.shields.io/badge/已满-1529866-blue.svg)](https://jq.qq.com/?_wv=1027&k=53R0L5Z) [![加入QQ群](https://img.shields.io/badge/已满-1772718-blue.svg)](https://jq.qq.com/?_wv=1027&k=5g75dCU) [![加入QQ群](https://img.shields.io/badge/已满-1366522-blue.svg)](https://jq.qq.com/?_wv=1027&k=58cPoHA) [![加入QQ群](https://img.shields.io/badge/已满-1382251-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Ofd4Pb) [![加入QQ群](https://img.shields.io/badge/已满-1145125-blue.svg)](https://jq.qq.com/?_wv=1027&k=5yugASz) [![加入QQ群](https://img.shields.io/badge/已满-86752435-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Rf3d2P) [![加入QQ群](https://img.shields.io/badge/已满-134072510-blue.svg)](https://jq.qq.com/?_wv=1027&k=5ZIjaeP) [![加入QQ群](https://img.shields.io/badge/已满-210336300-blue.svg)](https://jq.qq.com/?_wv=1027&k=5CJw1jY) [![加入QQ群](https://img.shields.io/badge/339522636-blue.svg)](https://jq.qq.com/?_wv=1027&k=5omzbKc)

12
bin/clean.bat Normal file
View File

@ -0,0 +1,12 @@
@echo off
echo.
echo [信息] 清理生成路径。
echo.
%~d0
cd %~dp0
cd ..
call mvn clean
pause

12
bin/package.bat Normal file
View File

@ -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

14
bin/run.bat Normal file
View File

@ -0,0 +1,14 @@
@echo off
echo.
echo [信息] 运行Web工程。
echo.
cd %~dp0
cd ../ruoyi-admin/target
set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
java -jar %JAVA_OPTS% ruoyi-admin.jar
cd bin
pause

Binary file not shown.

264
pom.xml Normal file
View File

@ -0,0 +1,264 @@
<?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.snow</groupId>
<artifactId>snow</artifactId>
<version>4.3.1</version>
<name>snow</name>
<url>http://www.ruoyi.vip</url>
<description>snow管理系统</description>
<properties>
<ruoyi.version>4.3.1</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<shiro.version>1.5.3</shiro.version>
<thymeleaf.extras.shiro.version>2.0.0</thymeleaf.extras.shiro.version>
<mybatis.boot.version>1.3.2</mybatis.boot.version>
<druid.version>1.1.14</druid.version>
<bitwalker.version>1.19</bitwalker.version>
<kaptcha.version>2.3.2</kaptcha.version>
<swagger.version>2.9.2</swagger.version>
<pagehelper.boot.version>1.2.5</pagehelper.boot.version>
<fastjson.version>1.2.70</fastjson.version>
<oshi.version>3.9.1</oshi.version>
<commons.io.version>2.5</commons.io.version>
<commons.fileupload.version>1.3.3</commons.fileupload.version>
<poi.version>3.17</poi.version>
<velocity.version>1.7</velocity.version>
</properties>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
<!-- SpringBoot的依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.1.RELEASE</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>com.github.penggle</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使用Srping框架 -->
<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>
<!-- swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- swagger2-UI-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!--io常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<!--文件上传工具类 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons.fileupload.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</artifactId>
<version>${velocity.version}</version>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- 定时任务-->
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-quartz</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-generator</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- 核心模块-->
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-framework</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- 系统模块-->
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-system</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-common</artifactId>
<version>${ruoyi.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>snow-admin</module>
<module>snow-framework</module>
<module>snow-system</module>
<module>snow-quartz</module>
<module>snow-generator</module>
<module>snow-common</module>
<module>snow-dingtalk</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>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

86
ry.sh Normal file
View File

@ -0,0 +1,86 @@
#!/bin/bash
AppName=ruoyi-admin.jar
#JVM参数
JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
APP_HOME=`pwd`
LOG_PATH=$APP_HOME/logs/$AppName.log
if [ "$1" = "" ];
then
echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m"
exit 1
fi
if [ "$AppName" = "" ];
then
echo -e "\033[0;31m 未输入应用名 \033[0m"
exit 1
fi
function start()
{
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
if [ x"$PID" != x"" ]; then
echo "$AppName is running..."
else
nohup java -jar $JVM_OPTS target/$AppName > /dev/null 2>&1 &
echo "Start $AppName success..."
fi
}
function stop()
{
echo "Stop $AppName"
PID=""
query(){
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
}
query
if [ x"$PID" != x"" ]; then
kill -TERM $PID
echo "$AppName (pid:$PID) exiting..."
while [ x"$PID" != x"" ]
do
sleep 1
query
done
echo "$AppName exited."
else
echo "$AppName already stopped."
fi
}
function restart()
{
stop
sleep 2
start
}
function status()
{
PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l`
if [ $PID != 0 ];then
echo "$AppName is running..."
else
echo "$AppName is not running..."
fi
}
case $1 in
start)
start;;
stop)
stop;;
restart)
restart;;
status)
status;;
*)
esac

116
snow-admin/pom.xml Normal file
View File

@ -0,0 +1,116 @@
<?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>snow</artifactId>
<groupId>com.snow</groupId>
<version>4.3.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>snow-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>
<!-- swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<!--防止进入swagger页面报类型转换错误排除2.9.2中的引用手动增加1.5.21版本-->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
</dependency>
<!-- swagger2-UI-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 核心模块-->
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-framework</artifactId>
<version>4.3.1</version>
</dependency>
<!-- 定时任务-->
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-quartz</artifactId>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-generator</artifactId>
<version>4.3.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</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>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>
</project>

View File

@ -0,0 +1,20 @@
package com.snow;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* 启动程序
*
* @author snow
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class RuoYiApplication
{
public static void main(String[] args)
{
// System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(RuoYiApplication.class, args);
}
}

View File

@ -0,0 +1,18 @@
package com.snow;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
* web容器中进行部署
*
* @author snow
*/
public class RuoYiServletInitializer extends SpringBootServletInitializer
{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
{
return application.sources(RuoYiApplication.class);
}
}

View File

@ -0,0 +1,112 @@
package com.snow.web.controller.common;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 org.springframework.web.multipart.MultipartFile;
import com.snow.common.config.Global;
import com.snow.common.config.ServerConfig;
import com.snow.common.constant.Constants;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.utils.StringUtils;
import com.snow.common.utils.file.FileUploadUtils;
import com.snow.common.utils.file.FileUtils;
/**
* 通用请求处理
*
* @author snow
*/
@Controller
public class CommonController
{
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
@Autowired
private ServerConfig serverConfig;
/**
* 通用下载请求
*
* @param fileName 文件名称
* @param delete 是否删除
*/
@GetMapping("common/download")
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
{
try
{
if (!FileUtils.isValidFilename(fileName))
{
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
}
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
String filePath = Global.getDownloadPath() + fileName;
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition",
"attachment;fileName=" + FileUtils.setFileDownloadHeader(request, realFileName));
FileUtils.writeBytes(filePath, response.getOutputStream());
if (delete)
{
FileUtils.deleteFile(filePath);
}
}
catch (Exception e)
{
log.error("下载文件失败", e);
}
}
/**
* 通用上传请求
*/
@PostMapping("/common/upload")
@ResponseBody
public AjaxResult uploadFile(MultipartFile file) throws Exception
{
try
{
// 上传文件路径
String filePath = Global.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
AjaxResult ajax = AjaxResult.success();
ajax.put("fileName", fileName);
ajax.put("url", url);
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
/**
* 本地资源通用下载
*/
@GetMapping("/common/download/resource")
public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
throws Exception
{
// 本地资源路径
String localPath = Global.getProfile();
// 数据库资源地址
String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
// 下载名称
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition",
"attachment;fileName=" + FileUtils.setFileDownloadHeader(request, downloadName));
FileUtils.writeBytes(downloadPath, response.getOutputStream());
}
}

View File

@ -0,0 +1,80 @@
package com.snow.web.controller.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 模态窗口
*
* @author snow
*/
@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";
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,35 @@
package com.snow.web.controller.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 图标相关
*
* @author snow
*/
@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";
}
}

View File

@ -0,0 +1,326 @@
package com.snow.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.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.page.PageDomain;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.core.page.TableSupport;
import com.snow.common.core.text.Convert;
import com.snow.common.exception.BusinessException;
import com.snow.common.utils.StringUtils;
import com.snow.common.utils.poi.ExcelUtil;
import com.snow.web.controller.demo.domain.CustomerModel;
import com.snow.web.controller.demo.domain.UserOperateModel;
/**
* 操作控制
*
* @author snow
*/
@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 BusinessException("导入用户数据不能为空!");
}
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 BusinessException(failureMsg.toString());
}
else
{
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
}
return successMsg.toString();
}
}

View File

@ -0,0 +1,53 @@
package com.snow.web.controller.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 报表
*
* @author snow
*/
@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";
}
}

View File

@ -0,0 +1,441 @@
package com.snow.web.controller.demo.controller;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.page.PageDomain;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.core.page.TableSupport;
import com.snow.common.utils.DateUtils;
import com.snow.common.utils.StringUtils;
/**
* 表格相关
*
* @author snow
*/
@Controller
@RequestMapping("/demo/table")
public class DemoTableController extends BaseController
{
private String prefix = "demo/table";
private final static List<UserTableModel> users = new ArrayList<UserTableModel>();
{
users.add(new UserTableModel(1, "1000001", "测试1", "0", "15888888888", "ry@qq.com", 150.0, "0"));
users.add(new UserTableModel(2, "1000002", "测试2", "1", "15666666666", "ry@qq.com", 180.0, "1"));
users.add(new UserTableModel(3, "1000003", "测试3", "0", "15666666666", "ry@qq.com", 110.0, "1"));
users.add(new UserTableModel(4, "1000004", "测试4", "1", "15666666666", "ry@qq.com", 220.0, "1"));
users.add(new UserTableModel(5, "1000005", "测试5", "0", "15666666666", "ry@qq.com", 140.0, "1"));
users.add(new UserTableModel(6, "1000006", "测试6", "1", "15666666666", "ry@qq.com", 330.0, "1"));
users.add(new UserTableModel(7, "1000007", "测试7", "0", "15666666666", "ry@qq.com", 160.0, "1"));
users.add(new UserTableModel(8, "1000008", "测试8", "1", "15666666666", "ry@qq.com", 170.0, "1"));
users.add(new UserTableModel(9, "1000009", "测试9", "0", "15666666666", "ry@qq.com", 180.0, "1"));
users.add(new UserTableModel(10, "1000010", "测试10", "0", "15666666666", "ry@qq.com", 210.0, "1"));
users.add(new UserTableModel(11, "1000011", "测试11", "1", "15666666666", "ry@qq.com", 110.0, "1"));
users.add(new UserTableModel(12, "1000012", "测试12", "0", "15666666666", "ry@qq.com", 120.0, "1"));
users.add(new UserTableModel(13, "1000013", "测试13", "1", "15666666666", "ry@qq.com", 380.0, "1"));
users.add(new UserTableModel(14, "1000014", "测试14", "0", "15666666666", "ry@qq.com", 280.0, "1"));
users.add(new UserTableModel(15, "1000015", "测试15", "0", "15666666666", "ry@qq.com", 570.0, "1"));
users.add(new UserTableModel(16, "1000016", "测试16", "1", "15666666666", "ry@qq.com", 260.0, "1"));
users.add(new UserTableModel(17, "1000017", "测试17", "1", "15666666666", "ry@qq.com", 210.0, "1"));
users.add(new UserTableModel(18, "1000018", "测试18", "1", "15666666666", "ry@qq.com", 340.0, "1"));
users.add(new UserTableModel(19, "1000019", "测试19", "1", "15666666666", "ry@qq.com", 160.0, "1"));
users.add(new UserTableModel(20, "1000020", "测试20", "1", "15666666666", "ry@qq.com", 220.0, "1"));
users.add(new UserTableModel(21, "1000021", "测试21", "1", "15666666666", "ry@qq.com", 120.0, "1"));
users.add(new UserTableModel(22, "1000022", "测试22", "1", "15666666666", "ry@qq.com", 130.0, "1"));
users.add(new UserTableModel(23, "1000023", "测试23", "1", "15666666666", "ry@qq.com", 490.0, "1"));
users.add(new UserTableModel(24, "1000024", "测试24", "1", "15666666666", "ry@qq.com", 570.0, "1"));
users.add(new UserTableModel(25, "1000025", "测试25", "1", "15666666666", "ry@qq.com", 250.0, "1"));
users.add(new UserTableModel(26, "1000026", "测试26", "1", "15666666666", "ry@qq.com", 250.0, "1"));
}
/**
* 搜索相关
*/
@GetMapping("/search")
public String search()
{
return prefix + "/search";
}
/**
* 数据汇总
*/
@GetMapping("/footer")
public String footer()
{
return prefix + "/footer";
}
/**
* 组合表头
*/
@GetMapping("/groupHeader")
public String groupHeader()
{
return prefix + "/groupHeader";
}
/**
* 表格导出
*/
@GetMapping("/export")
public String export()
{
return prefix + "/export";
}
/**
* 翻页记住选择
*/
@GetMapping("/remember")
public String remember()
{
return prefix + "/remember";
}
/**
* 跳转至指定页
*/
@GetMapping("/pageGo")
public String pageGo()
{
return prefix + "/pageGo";
}
/**
* 自定义查询参数
*/
@GetMapping("/params")
public String params()
{
return prefix + "/params";
}
/**
* 多表格
*/
@GetMapping("/multi")
public String multi()
{
return prefix + "/multi";
}
/**
* 点击按钮加载表格
*/
@GetMapping("/button")
public String button()
{
return prefix + "/button";
}
/**
* 直接加载表格数据
*/
@GetMapping("/data")
public String data(ModelMap mmap)
{
mmap.put("users", users);
return prefix + "/data";
}
/**
* 表格冻结列
*/
@GetMapping("/fixedColumns")
public String fixedColumns()
{
return prefix + "/fixedColumns";
}
/**
* 自定义触发事件
*/
@GetMapping("/event")
public String event()
{
return prefix + "/event";
}
/**
* 表格细节视图
*/
@GetMapping("/detail")
public String detail()
{
return prefix + "/detail";
}
/**
* 表格父子视图
*/
@GetMapping("/child")
public String child()
{
return prefix + "/child";
}
/**
* 表格图片预览
*/
@GetMapping("/image")
public String image()
{
return prefix + "/image";
}
/**
* 动态增删改查
*/
@GetMapping("/curd")
public String curd()
{
return prefix + "/curd";
}
/**
* 表格拖拽操作
*/
@GetMapping("/reorder")
public String reorder()
{
return prefix + "/reorder";
}
/**
* 表格行内编辑操作
*/
@GetMapping("/editable")
public String editable()
{
return prefix + "/editable";
}
/**
* 主子表提交
*/
@GetMapping("/subdata")
public String subdata()
{
return prefix + "/subdata";
}
/**
* 表格自动刷新
*/
@GetMapping("/refresh")
public String refresh()
{
return prefix + "/refresh";
}
/**
* 表格打印配置
*/
@GetMapping("/print")
public String print()
{
return prefix + "/print";
}
/**
* 表格其他操作
*/
@GetMapping("/other")
public String other()
{
return prefix + "/other";
}
/**
* 查询数据
*/
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(UserTableModel userModel)
{
TableDataInfo rspData = new TableDataInfo();
List<UserTableModel> userList = new ArrayList<UserTableModel>(Arrays.asList(new UserTableModel[users.size()]));
Collections.copy(userList, users);
// 查询条件过滤
if (StringUtils.isNotEmpty(userModel.getUserName()))
{
userList.clear();
for (UserTableModel user : users)
{
if (user.getUserName().equals(userModel.getUserName()))
{
userList.add(user);
}
}
}
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;
}
}
class UserTableModel
{
/** 用户ID */
private int userId;
/** 用户编号 */
private String userCode;
/** 用户姓名 */
private String userName;
/** 用户性别 */
private String userSex;
/** 用户手机 */
private String userPhone;
/** 用户邮箱 */
private String userEmail;
/** 用户余额 */
private double userBalance;
/** 用户状态0正常 1停用 */
private String status;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
public UserTableModel()
{
}
public UserTableModel(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;
}
public Date getCreateTime()
{
return createTime;
}
public void setCreateTime(Date createTime)
{
this.createTime = createTime;
}
}

View File

@ -0,0 +1,116 @@
package com.snow.web.controller.demo.domain;
import java.util.List;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 客户测试信息
*
* @author snow
*/
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();
}
}

View File

@ -0,0 +1,82 @@
package com.snow.web.controller.demo.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 商品测试信息
*
* @author snow
*/
public class GoodsModel
{
/**
* 商品名称
*/
private String name;
/**
* 商品重量
*/
private Integer weight;
/**
* 商品价格
*/
private Double price;
/**
* 商品种类
*/
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 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("type", getType())
.toString();
}
}

View File

@ -0,0 +1,149 @@
package com.snow.web.controller.demo.domain;
import java.util.Date;
import com.snow.common.annotation.Excel;
import com.snow.common.annotation.Excel.Type;
import com.snow.common.core.domain.BaseEntity;
import com.snow.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;
}
}

View File

@ -0,0 +1,26 @@
package com.snow.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.snow.common.core.controller.BaseController;
/**
* druid 监控
*
* @author snow
*/
@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");
}
}

View File

@ -0,0 +1,31 @@
package com.snow.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.snow.common.core.controller.BaseController;
import com.snow.framework.web.domain.Server;
/**
* 服务器监控
*
* @author snow
*/
@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";
}
}

View File

@ -0,0 +1,94 @@
package com.snow.web.controller.monitor;
import java.util.List;
import com.snow.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.snow.common.annotation.Log;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.enums.BusinessType;
import com.snow.common.utils.poi.ExcelUtil;
import com.snow.system.domain.SysLogininfor;
import com.snow.system.service.ISysLogininforService;
/**
* 系统访问记录
*
* @author snow
*/
@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();
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.unlock(loginName);
return success();
}
}

View File

@ -0,0 +1,89 @@
package com.snow.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.snow.common.annotation.Log;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.enums.BusinessType;
import com.snow.common.utils.poi.ExcelUtil;
import com.snow.system.domain.SysOperLog;
import com.snow.system.service.ISysOperLogService;
/**
* 操作日志记录
*
* @author snow
*/
@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();
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, "操作日志");
}
@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();
}
}

View File

@ -0,0 +1,88 @@
package com.snow.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.snow.common.annotation.Log;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.core.text.Convert;
import com.snow.common.enums.BusinessType;
import com.snow.common.enums.OnlineStatus;
import com.snow.framework.shiro.session.OnlineSession;
import com.snow.framework.shiro.session.OnlineSessionDAO;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysUserOnline;
import com.snow.system.service.ISysUserOnlineService;
/**
* 在线用户监控
*
* @author snow
*/
@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("当前登陆用户无法强退");
}
onlineSession.setStatus(OnlineStatus.off_line);
onlineSessionDAO.update(onlineSession);
online.setStatus(OnlineStatus.off_line);
userOnlineService.saveOnline(online);
}
return success();
}
}

View File

@ -0,0 +1,92 @@
package com.snow.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.snow.common.core.controller.BaseController;
/**
* 图片验证码支持算术形式
*
* @author snow
*/
@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;
}
}

View File

@ -0,0 +1,157 @@
package com.snow.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.snow.common.annotation.Log;
import com.snow.common.constant.UserConstants;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.enums.BusinessType;
import com.snow.common.utils.poi.ExcelUtil;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysConfig;
import com.snow.system.service.ISysConfigService;
/**
* 参数配置 信息操作处理
*
* @author snow
*/
@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 (UserConstants.CONFIG_KEY_NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
{
return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
}
config.setCreateBy(ShiroUtils.getLoginName());
return toAjax(configService.insertConfig(config));
}
/**
* 修改参数配置
*/
@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 (UserConstants.CONFIG_KEY_NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
{
return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
}
config.setUpdateBy(ShiroUtils.getLoginName());
return toAjax(configService.updateConfig(config));
}
/**
* 删除参数配置
*/
@RequiresPermissions("system:config:remove")
@Log(title = "参数管理", businessType = BusinessType.DELETE)
@PostMapping("/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(configService.deleteConfigByIds(ids));
}
/**
* 清空缓存
*/
@RequiresPermissions("system:config:remove")
@Log(title = "参数管理", businessType = BusinessType.CLEAN)
@GetMapping("/clearCache")
@ResponseBody
public AjaxResult clearCache()
{
configService.clearCache();
return success();
}
/**
* 校验参数键名
*/
@PostMapping("/checkConfigKeyUnique")
@ResponseBody
public String checkConfigKeyUnique(SysConfig config)
{
return configService.checkConfigKeyUnique(config);
}
}

View File

@ -0,0 +1,203 @@
package com.snow.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.snow.common.annotation.Log;
import com.snow.common.constant.UserConstants;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.domain.Ztree;
import com.snow.common.enums.BusinessType;
import com.snow.common.utils.StringUtils;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysDept;
import com.snow.system.domain.SysRole;
import com.snow.system.service.ISysDeptService;
/**
* 部门信息
*
* @author snow
*/
@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)
{
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 (UserConstants.DEPT_NAME_NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
{
return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}
dept.setCreateBy(ShiroUtils.getLoginName());
return toAjax(deptService.insertDept(dept));
}
/**
* 修改
*/
@GetMapping("/edit/{deptId}")
public String edit(@PathVariable("deptId") Long deptId, ModelMap mmap)
{
SysDept dept = deptService.selectDeptById(deptId);
if (StringUtils.isNotNull(dept) && 100L == deptId)
{
dept.setParentName("");
}
mmap.put("dept", dept);
return prefix + "/edit";
}
/**
* 保存
*/
@Log(title = "部门管理", businessType = BusinessType.UPDATE)
@RequiresPermissions("system:dept:edit")
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(@Validated SysDept dept)
{
if (UserConstants.DEPT_NAME_NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
{
return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}
else if (dept.getParentId().equals(dept.getDeptId()))
{
return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
}
else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())
&& deptService.selectNormalChildrenDeptById(dept.getDeptId()) > 0)
{
return AjaxResult.error("该部门包含未停用的子部门!");
}
dept.setUpdateBy(ShiroUtils.getLoginName());
return toAjax(deptService.updateDept(dept));
}
/**
* 删除
*/
@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("部门存在用户,不允许删除");
}
return toAjax(deptService.deleteDeptById(deptId));
}
/**
* 校验部门名称
*/
@PostMapping("/checkDeptNameUnique")
@ResponseBody
public String 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) String 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.setDeptId(excludeId);
List<Ztree> ztrees = deptService.selectDeptTreeExcludeChild(dept);
return ztrees;
}
/**
* 加载角色部门数据权限列表树
*/
@GetMapping("/roleDeptTreeData")
@ResponseBody
public List<Ztree> deptTreeData(SysRole role)
{
List<Ztree> ztrees = deptService.roleDeptTreeData(role);
return ztrees;
}
}

View File

@ -0,0 +1,120 @@
package com.snow.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.snow.common.annotation.Log;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.enums.BusinessType;
import com.snow.common.utils.poi.ExcelUtil;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysDictData;
import com.snow.system.service.ISysDictDataService;
/**
* 数据字典信息
*
* @author snow
*/
@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(ShiroUtils.getLoginName());
return toAjax(dictDataService.insertDictData(dict));
}
/**
* 修改字典类型
*/
@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(ShiroUtils.getLoginName());
return toAjax(dictDataService.updateDictData(dict));
}
@Log(title = "字典数据", businessType = BusinessType.DELETE)
@RequiresPermissions("system:dict:remove")
@PostMapping("/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(dictDataService.deleteDictDataByIds(ids));
}
}

View File

@ -0,0 +1,188 @@
package com.snow.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.snow.common.annotation.Log;
import com.snow.common.constant.UserConstants;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.domain.Ztree;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.enums.BusinessType;
import com.snow.common.utils.poi.ExcelUtil;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysDictType;
import com.snow.system.service.ISysDictTypeService;
/**
* 数据字典信息
*
* @author snow
*/
@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 (UserConstants.DICT_TYPE_NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
{
return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
}
dict.setCreateBy(ShiroUtils.getLoginName());
return toAjax(dictTypeService.insertDictType(dict));
}
/**
* 修改字典类型
*/
@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 (UserConstants.DICT_TYPE_NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
{
return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
}
dict.setUpdateBy(ShiroUtils.getLoginName());
return toAjax(dictTypeService.updateDictType(dict));
}
@Log(title = "字典类型", businessType = BusinessType.DELETE)
@RequiresPermissions("system:dict:remove")
@PostMapping("/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(dictTypeService.deleteDictTypeByIds(ids));
}
/**
* 清空缓存
*/
@RequiresPermissions("system:dict:remove")
@Log(title = "字典类型", businessType = BusinessType.CLEAN)
@GetMapping("/clearCache")
@ResponseBody
public AjaxResult clearCache()
{
dictTypeService.clearCache();
return success();
}
/**
* 查询字典详细
*/
@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 String 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;
}
}

View File

@ -0,0 +1,61 @@
package com.snow.web.controller.system;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import com.snow.common.config.Global;
import com.snow.common.core.controller.BaseController;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysMenu;
import com.snow.system.domain.SysUser;
import com.snow.system.service.ISysConfigService;
import com.snow.system.service.ISysMenuService;
/**
* 首页 业务处理
*
* @author snow
*/
@Controller
public class SysIndexController extends BaseController
{
@Autowired
private ISysMenuService menuService;
@Autowired
private ISysConfigService configService;
// 系统首页
@GetMapping("/index")
public String index(ModelMap mmap)
{
// 取身份信息
SysUser user = ShiroUtils.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"));
mmap.put("copyrightYear", Global.getCopyrightYear());
mmap.put("demoEnabled", Global.isDemoEnabled());
return "index";
}
// 切换主题
@GetMapping("/system/switchSkin")
public String switchSkin(ModelMap mmap)
{
return "skin";
}
// 系统介绍
@GetMapping("/system/main")
public String main(ModelMap mmap)
{
mmap.put("version", Global.getVersion());
return "main";
}
}

View File

@ -0,0 +1,65 @@
package com.snow.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.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.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.utils.ServletUtils;
import com.snow.common.utils.StringUtils;
/**
* 登录验证
*
* @author snow
*/
@Controller
public class SysLoginController extends BaseController
{
@GetMapping("/login")
public String login(HttpServletRequest request, HttpServletResponse response)
{
// 如果是Ajax请求返回Json字符串
if (ServletUtils.isAjaxRequest(request))
{
return ServletUtils.renderString(response, "{\"code\":\"1\",\"msg\":\"未登录或登录超时。请重新登录\"}");
}
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";
}
}

View File

@ -0,0 +1,196 @@
package com.snow.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.snow.common.annotation.Log;
import com.snow.common.constant.UserConstants;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.domain.Ztree;
import com.snow.common.enums.BusinessType;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysMenu;
import com.snow.system.domain.SysRole;
import com.snow.system.service.ISysMenuService;
/**
* 菜单信息
*
* @author snow
*/
@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("菜单已分配,不允许删除");
}
ShiroUtils.clearCachedAuthorizationInfo();
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 (UserConstants.MENU_NAME_NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
{
return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
}
menu.setCreateBy(ShiroUtils.getLoginName());
ShiroUtils.clearCachedAuthorizationInfo();
return toAjax(menuService.insertMenu(menu));
}
/**
* 修改菜单
*/
@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 (UserConstants.MENU_NAME_NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
{
return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
}
menu.setUpdateBy(ShiroUtils.getLoginName());
ShiroUtils.clearCachedAuthorizationInfo();
return toAjax(menuService.updateMenu(menu));
}
/**
* 选择菜单图标
*/
@GetMapping("/icon")
public String icon()
{
return prefix + "/icon";
}
/**
* 校验菜单名称
*/
@PostMapping("/checkMenuNameUnique")
@ResponseBody
public String 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";
}
}

View File

@ -0,0 +1,112 @@
package com.snow.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.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.snow.common.annotation.Log;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.enums.BusinessType;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysNotice;
import com.snow.system.service.ISysNoticeService;
/**
* 公告 信息操作处理
*
* @author snow
*/
@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(SysNotice notice)
{
notice.setCreateBy(ShiroUtils.getLoginName());
return toAjax(noticeService.insertNotice(notice));
}
/**
* 修改公告
*/
@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(SysNotice notice)
{
notice.setUpdateBy(ShiroUtils.getLoginName());
return toAjax(noticeService.updateNotice(notice));
}
/**
* 删除公告
*/
@RequiresPermissions("system:notice:remove")
@Log(title = "通知公告", businessType = BusinessType.DELETE)
@PostMapping("/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
return toAjax(noticeService.deleteNoticeByIds(ids));
}
}

View File

@ -0,0 +1,163 @@
package com.snow.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.snow.common.annotation.Log;
import com.snow.common.constant.UserConstants;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.enums.BusinessType;
import com.snow.common.utils.poi.ExcelUtil;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysPost;
import com.snow.system.service.ISysPostService;
/**
* 岗位信息操作处理
*
* @author snow
*/
@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 (UserConstants.POST_NAME_NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
{
return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
}
else if (UserConstants.POST_CODE_NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
{
return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
}
post.setCreateBy(ShiroUtils.getLoginName());
return toAjax(postService.insertPost(post));
}
/**
* 修改岗位
*/
@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 (UserConstants.POST_NAME_NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
{
return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
}
else if (UserConstants.POST_CODE_NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
{
return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
}
post.setUpdateBy(ShiroUtils.getLoginName());
return toAjax(postService.updatePost(post));
}
/**
* 校验岗位名称
*/
@PostMapping("/checkPostNameUnique")
@ResponseBody
public String checkPostNameUnique(SysPost post)
{
return postService.checkPostNameUnique(post);
}
/**
* 校验岗位编码
*/
@PostMapping("/checkPostCodeUnique")
@ResponseBody
public String checkPostCodeUnique(SysPost post)
{
return postService.checkPostCodeUnique(post);
}
}

View File

@ -0,0 +1,173 @@
package com.snow.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.snow.common.annotation.Log;
import com.snow.common.config.Global;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.enums.BusinessType;
import com.snow.common.utils.StringUtils;
import com.snow.common.utils.file.FileUploadUtils;
import com.snow.framework.shiro.service.SysPasswordService;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysUser;
import com.snow.system.service.ISysUserService;
/**
* 个人信息 业务处理
*
* @author snow
*/
@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 = ShiroUtils.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 = ShiroUtils.getSysUser();
if (passwordService.matches(user, password))
{
return true;
}
return false;
}
@GetMapping("/resetPwd")
public String resetPwd(ModelMap mmap)
{
SysUser user = ShiroUtils.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 = ShiroUtils.getSysUser();
if (StringUtils.isNotEmpty(newPassword) && passwordService.matches(user, oldPassword))
{
user.setSalt(ShiroUtils.randomSalt());
user.setPassword(passwordService.encryptPassword(user.getLoginName(), newPassword, user.getSalt()));
if (userService.resetUserPwd(user) > 0)
{
ShiroUtils.setSysUser(userService.selectUserById(user.getUserId()));
return success();
}
return error();
}
else
{
return error("修改密码失败,旧密码错误");
}
}
/**
* 修改用户
*/
@GetMapping("/edit")
public String edit(ModelMap mmap)
{
SysUser user = ShiroUtils.getSysUser();
mmap.put("user", userService.selectUserById(user.getUserId()));
return prefix + "/edit";
}
/**
* 修改头像
*/
@GetMapping("/avatar")
public String avatar(ModelMap mmap)
{
SysUser user = ShiroUtils.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 = ShiroUtils.getSysUser();
currentUser.setUserName(user.getUserName());
currentUser.setEmail(user.getEmail());
currentUser.setPhonenumber(user.getPhonenumber());
currentUser.setSex(user.getSex());
if (userService.updateUserInfo(currentUser) > 0)
{
ShiroUtils.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 = ShiroUtils.getSysUser();
try
{
if (!file.isEmpty())
{
String avatar = FileUploadUtils.upload(Global.getAvatarPath(), file);
currentUser.setAvatar(avatar);
if (userService.updateUserInfo(currentUser) > 0)
{
ShiroUtils.setSysUser(userService.selectUserById(currentUser.getUserId()));
return success();
}
}
return error();
}
catch (Exception e)
{
log.error("修改头像失败!", e);
return error(e.getMessage());
}
}
}

View File

@ -0,0 +1,46 @@
package com.snow.web.controller.system;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.framework.shiro.service.SysRegisterService;
import com.snow.system.domain.SysUser;
import com.snow.system.service.ISysConfigService;
/**
* 注册验证
*
* @author snow
*/
@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);
}
}

View File

@ -0,0 +1,304 @@
package com.snow.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.snow.common.annotation.Log;
import com.snow.common.constant.UserConstants;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.enums.BusinessType;
import com.snow.common.utils.poi.ExcelUtil;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysRole;
import com.snow.system.domain.SysUser;
import com.snow.system.domain.SysUserRole;
import com.snow.system.service.ISysRoleService;
import com.snow.system.service.ISysUserService;
/**
* 角色信息
*
* @author snow
*/
@Controller
@RequestMapping("/system/role")
public class SysRoleController extends BaseController
{
private String prefix = "system/role";
@Autowired
private ISysRoleService roleService;
@Autowired
private ISysUserService userService;
@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 (UserConstants.ROLE_NAME_NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
{
return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
}
else if (UserConstants.ROLE_KEY_NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
{
return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
}
role.setCreateBy(ShiroUtils.getLoginName());
ShiroUtils.clearCachedAuthorizationInfo();
return toAjax(roleService.insertRole(role));
}
/**
* 修改角色
*/
@GetMapping("/edit/{roleId}")
public String edit(@PathVariable("roleId") Long roleId, ModelMap mmap)
{
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);
if (UserConstants.ROLE_NAME_NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
{
return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
}
else if (UserConstants.ROLE_KEY_NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
{
return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
}
role.setUpdateBy(ShiroUtils.getLoginName());
ShiroUtils.clearCachedAuthorizationInfo();
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);
role.setUpdateBy(ShiroUtils.getLoginName());
if (roleService.authDataScope(role) > 0)
{
ShiroUtils.setSysUser(userService.selectUserById(ShiroUtils.getSysUser().getUserId()));
return success();
}
return error();
}
@RequiresPermissions("system:role:remove")
@Log(title = "角色管理", businessType = BusinessType.DELETE)
@PostMapping("/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
try
{
return toAjax(roleService.deleteRoleByIds(ids));
}
catch (Exception e)
{
return error(e.getMessage());
}
}
/**
* 校验角色名称
*/
@PostMapping("/checkRoleNameUnique")
@ResponseBody
public String checkRoleNameUnique(SysRole role)
{
return roleService.checkRoleNameUnique(role);
}
/**
* 校验角色权限
*/
@PostMapping("/checkRoleKeyUnique")
@ResponseBody
public String 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);
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);
}
/**
* 取消授权
*/
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PostMapping("/authUser/cancel")
@ResponseBody
public AjaxResult cancelAuthUser(SysUserRole userRole)
{
return toAjax(roleService.deleteAuthUser(userRole));
}
/**
* 批量取消授权
*/
@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);
}
/**
* 批量选择用户授权
*/
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PostMapping("/authUser/selectAll")
@ResponseBody
public AjaxResult selectAuthUserAll(Long roleId, String userIds)
{
return toAjax(roleService.insertAuthUsers(roleId, userIds));
}
}

View File

@ -0,0 +1,291 @@
package com.snow.web.controller.system;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.snow.common.annotation.Log;
import com.snow.common.constant.UserConstants;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.page.TableDataInfo;
import com.snow.common.enums.BusinessType;
import com.snow.common.utils.poi.ExcelUtil;
import com.snow.framework.shiro.service.SysPasswordService;
import com.snow.framework.util.ShiroUtils;
import com.snow.system.domain.SysRole;
import com.snow.system.domain.SysUser;
import com.snow.system.service.ISysPostService;
import com.snow.system.service.ISysRoleService;
import com.snow.system.service.ISysUserService;
/**
* 用户信息
*
* @author snow
*/
@Controller
@RequestMapping("/system/user")
public class SysUserController extends BaseController
{
private String prefix = "system/user";
@Autowired
private ISysUserService userService;
@Autowired
private ISysRoleService roleService;
@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 operName = ShiroUtils.getSysUser().getLoginName();
String message = userService.importUser(userList, updateSupport, operName);
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)
{
if (UserConstants.USER_NAME_NOT_UNIQUE.equals(userService.checkLoginNameUnique(user.getLoginName())))
{
return error("新增用户'" + user.getLoginName() + "'失败,登录账号已存在");
}
else if (UserConstants.USER_PHONE_NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{
return error("新增用户'" + user.getLoginName() + "'失败,手机号码已存在");
}
else if (UserConstants.USER_EMAIL_NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{
return error("新增用户'" + user.getLoginName() + "'失败,邮箱账号已存在");
}
user.setSalt(ShiroUtils.randomSalt());
user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt()));
user.setCreateBy(ShiroUtils.getLoginName());
return toAjax(userService.insertUser(user));
}
/**
* 修改用户
*/
@GetMapping("/edit/{userId}")
public String edit(@PathVariable("userId") Long userId, ModelMap mmap)
{
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:edit")
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PostMapping("/edit")
@ResponseBody
public AjaxResult editSave(@Validated SysUser user)
{
userService.checkUserAllowed(user);
if (UserConstants.USER_PHONE_NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{
return error("修改用户'" + user.getLoginName() + "'失败,手机号码已存在");
}
else if (UserConstants.USER_EMAIL_NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{
return error("修改用户'" + user.getLoginName() + "'失败,邮箱账号已存在");
}
user.setUpdateBy(ShiroUtils.getLoginName());
return toAjax(userService.updateUser(user));
}
@RequiresPermissions("system:user:resetPwd")
@Log(title = "重置密码", businessType = BusinessType.UPDATE)
@GetMapping("/resetPwd/{userId}")
public String resetPwd(@PathVariable("userId") Long userId, ModelMap mmap)
{
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);
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())
{
ShiroUtils.setSysUser(userService.selectUserById(user.getUserId()));
}
return success();
}
return error();
}
/**
* 进入授权角色页
*/
@GetMapping("/authRole/{userId}")
public String authRole(@PathVariable("userId") Long userId, ModelMap mmap)
{
SysUser user = userService.selectUserById(userId);
// 获取用户所属的角色列表
List<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:add")
@Log(title = "用户管理", businessType = BusinessType.GRANT)
@PostMapping("/authRole/insertAuthRole")
@ResponseBody
public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
{
userService.insertUserAuth(userId, roleIds);
return success();
}
@RequiresPermissions("system:user:remove")
@Log(title = "用户管理", businessType = BusinessType.DELETE)
@PostMapping("/remove")
@ResponseBody
public AjaxResult remove(String ids)
{
try
{
return toAjax(userService.deleteUserByIds(ids));
}
catch (Exception e)
{
return error(e.getMessage());
}
}
/**
* 校验用户名
*/
@PostMapping("/checkLoginNameUnique")
@ResponseBody
public String checkLoginNameUnique(SysUser user)
{
return userService.checkLoginNameUnique(user.getLoginName());
}
/**
* 校验手机号码
*/
@PostMapping("/checkPhoneUnique")
@ResponseBody
public String checkPhoneUnique(SysUser user)
{
return userService.checkPhoneUnique(user);
}
/**
* 校验email邮箱
*/
@PostMapping("/checkEmailUnique")
@ResponseBody
public String 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);
return toAjax(userService.changeStatus(user));
}
}

View File

@ -0,0 +1,26 @@
package com.snow.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.snow.common.core.controller.BaseController;
/**
* build 表单构建
*
* @author snow
*/
@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";
}
}

View File

@ -0,0 +1,24 @@
package com.snow.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.snow.common.core.controller.BaseController;
/**
* swagger 接口
*
* @author snow
*/
@Controller
@RequestMapping("/tool/swagger")
public class SwaggerController extends BaseController
{
@RequiresPermissions("tool:swagger:view")
@GetMapping()
public String index()
{
return redirect("/swagger-ui.html");
}
}

View File

@ -0,0 +1,175 @@
package com.snow.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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
/**
* swagger 用户测试方法
*
* @author snow
*/
@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 AjaxResult userList()
{
List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
return AjaxResult.success(userList);
}
@ApiOperation("获取用户详细")
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path")
@GetMapping("/{userId}")
public AjaxResult getUser(@PathVariable Integer userId)
{
if (!users.isEmpty() && users.containsKey(userId))
{
return AjaxResult.success(users.get(userId));
}
else
{
return error("用户不存在");
}
}
@ApiOperation("新增用户")
@ApiImplicitParam(name = "userEntity", value = "新增用户信息", dataType = "UserEntity")
@PostMapping("/save")
public AjaxResult save(UserEntity user)
{
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{
return error("用户ID不能为空");
}
return AjaxResult.success(users.put(user.getUserId(), user));
}
@ApiOperation("更新用户")
@ApiImplicitParam(name = "userEntity", value = "新增用户信息", dataType = "UserEntity")
@PutMapping("/update")
public AjaxResult update(UserEntity user)
{
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{
return error("用户ID不能为空");
}
if (users.isEmpty() || !users.containsKey(user.getUserId()))
{
return error("用户不存在");
}
users.remove(user.getUserId());
return AjaxResult.success(users.put(user.getUserId(), user));
}
@ApiOperation("删除用户信息")
@ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path")
@DeleteMapping("/{userId}")
public AjaxResult delete(@PathVariable Integer userId)
{
if (!users.isEmpty() && users.containsKey(userId))
{
users.remove(userId);
return success();
}
else
{
return error("用户不存在");
}
}
}
@ApiModel("用户实体")
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;
}
}

View File

@ -0,0 +1,69 @@
package com.snow.web.core.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.snow.common.config.Global;
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;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Swagger2的接口配置
*
* @author snow
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig
{
/** 是否开启swagger */
@Value("${swagger.enabled}")
private boolean enabled;
/**
* 创建API
*/
@Bean
public Docket createRestApi()
{
return new Docket(DocumentationType.SWAGGER_2)
// 是否启用Swagger
.enable(enabled)
// 用来创建该API的基本信息展示在文档的页面中自定义展示的信息
.apiInfo(apiInfo())
// 设置哪些接口暴露给Swagger展示
.select()
// 扫描所有有注解的api用这种方式更灵活
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
// 扫描指定包中的swagger注解
//.apis(RequestHandlerSelectors.basePackage("com.snow.project.tool.swagger"))
// 扫描所有 .apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
/**
* 添加摘要信息
*/
private ApiInfo apiInfo()
{
// 用ApiInfoBuilder进行定制
return new ApiInfoBuilder()
// 设置标题
.title("标题若依管理系统_接口文档")
// 描述
.description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
// 作者信息
.contact(new Contact(Global.getName(), null, null))
// 版本
.version("版本号:" + Global.getVersion())
.build();
}
}

View File

@ -0,0 +1,57 @@
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://rm-bp1j1554xv1qs04295o.mysql.rds.aliyuncs.com:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: cloud_root
password: Jin!152377
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 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:
login-password:
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true

View File

@ -0,0 +1,137 @@
# 项目相关配置
ruoyi:
# 名称
name: snow
# 版本
version: 4.3.1
# 版权年份
copyrightYear: 2019
# 实例演示开关
demoEnabled: true
# 文件路径 示例( Windows配置D:/snow/uploadPathLinux配置 /home/snow/uploadPath
profile: D:/snow/uploadPath
# 获取ip地址开关
addressEnabled: false
# 开发环境配置
server:
# 服务器的HTTP端口默认为80
port: 80
servlet:
# 应用的访问路径
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# tomcat最大线程数默认为200
max-threads: 800
# Tomcat启动初始化的线程数默认值25
min-spare-threads: 30
# 日志配置
logging:
level:
com.ruoyi: 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: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
# 服务模块
devtools:
restart:
# 热部署开关
enabled: true
# MyBatis
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.snow.**.domain
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# PageHelper分页插件
pagehelper:
helperDialect: mysql
reasonable: true
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运行即可KeyGenerator keygen = KeyGenerator.getInstance("AES"); SecretKey deskey = keygen.generateKey(); System.out.println(Base64.encodeToString(deskey.getEncoded()));
cipherKey: zSyK5Kp6PZAAjlT+eeNMlg==
session:
# Session超时时间-1代表永不过期默认30分钟
expireTime: 30
# 同步session到数据库的周期默认1分钟
dbSyncPeriod: 1
# 相隔多久检查一次session的有效性默认就是10分钟
validationInterval: 10
# 同一个用户最大会话数比如2的意思是同一个账号允许最多同时两个人登录默认-1不限制
maxSession: -1
# 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户
kickoutAfter: false
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /system/notice/*
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
# Swagger配置
swagger:
# 是否开启swagger
enabled: true

View File

@ -0,0 +1,24 @@
Application Version: ${ruoyi.version}
Spring Boot Version: ${spring-boot.version}
////////////////////////////////////////////////////////////////////
// _ooOoo_ //
// o8888888o //
// 88" . "88 //
// (| ^_^ |) //
// O\ = /O //
// ____/`---'\____ //
// .' \\| |// `. //
// / \\||| : |||// \ //
// / _||||| -:- |||||- \ //
// | | \\\ - /// | | //
// | \_| ''\---/'' | | //
// \ .-\__ `-` ___/-. / //
// ___`. .' /--.--\ `. . ___ //
// ."" '< `.___\_<|>_/___.' >'"". //
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
// \ \ `-. \_ __\ /__ _/ .-` / / //
// ========`-.____`-.___\_____/___.-`____.-'======== //
// `=---=' //
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
// 佛祖保佑 永不宕机 永无BUG //
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="snow" updateCheck="false">
<!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir"/>
<!-- maxEntriesLocalHeap:堆内存中最大缓存对象数0没有限制 -->
<!-- maxElementsInMemory 在内存中缓存的element的最大数目。-->
<!-- eternal:elements是否永久有效如果为truetimeouts将被忽略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="true">
</cache>
<!-- 系统活跃用户缓存 -->
<cache name="sys-userCache"
maxEntriesLocalHeap="10000"
overflowToDisk="false"
eternal="false"
diskPersistent="false"
timeToLiveSeconds="0"
timeToIdleSeconds="0"
statistics="true">
</cache>
<!-- 系统缓存 -->
<cache name="sys-cache"
maxEntriesLocalHeap="1000"
eternal="true"
overflowToDisk="true"
statistics="true">
</cache>
<!-- 系统参数缓存 -->
<cache name="sys-config"
maxEntriesLocalHeap="1000"
eternal="true"
overflowToDisk="true"
statistics="true">
</cache>
<!-- 系统字典缓存 -->
<cache name="sys-dict"
maxEntriesLocalHeap="1000"
eternal="true"
overflowToDisk="true"
statistics="true">
</cache>
<!-- 系统会话缓存 -->
<cache name="shiro-activeSessionCache"
maxElementsInMemory="10000"
overflowToDisk="true"
eternal="true"
timeToLiveSeconds="0"
timeToIdleSeconds="0"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="600">
</cache>
</ehcache>

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<property name="log.path" value="/home/snow/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.snow" 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>

View File

@ -0,0 +1,15 @@
<?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" /> <!-- 全局映射器启用缓存 -->
<setting name="useGeneratedKeys" value="true" /> <!-- 允许 JDBC 支持自动生成主键 -->
<setting name="defaultExecutorType" value="REUSE" /> <!-- 配置默认的执行器 -->
<setting name="logImpl" value="SLF4J" /> <!-- 指定 MyBatis 所用日志的具体实现 -->
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> 驼峰式命名 -->
</settings>
</configuration>

View File

@ -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);
};
}());

View File

@ -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 || '&nbsp;')+'</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 || '&nbsp;')+'</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);
}
})();

View File

@ -0,0 +1,550 @@
/*!
* bootstrap-fileinput v5.0.4
* http://plugins.krajee.com/file-input
*
* Krajee default styling for bootstrap-fileinput.
*
* Author: Kartik Visweswaran
* Copyright: 2014 - 2019, Kartik Visweswaran, Krajee.com
*
* Licensed under the BSD-3-Clause
* https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
*/
.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;
}
.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;
}
.krajee-default .file-thumb-progress .progress, .krajee-default .file-thumb-progress .progress-bar {
height: 20px;
font-family: Verdana, Helvetica, sans-serif;
font-size: 9px;
}
.krajee-default .file-thumb-progress .progress, .kv-upload-progress .progress {
background-color: #ccc;
}
.krajee-default .file-caption-info, .krajee-default .file-size-info {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 160px;
height: 15px;
margin: auto;
}
.file-zoom-content > .file-object.type-video, .file-zoom-content > .file-object.type-flash, .file-zoom-content > .file-object.type-image {
max-width: 100%;
max-height: 100%;
width: auto;
}
.file-zoom-content > .file-object.type-video, .file-zoom-content > .file-object.type-flash {
height: 100%;
}
.file-zoom-content > .file-object.type-pdf, .file-zoom-content > .file-object.type-html, .file-zoom-content > .file-object.type-text, .file-zoom-content > .file-object.type-default {
width: 100%;
}
.file-loading:before {
content: " Loading...";
display: inline-block;
padding-left: 20px;
line-height: 16px;
font-size: 13px;
font-variant: small-caps;
color: #999;
background: transparent url(loading.gif) top left no-repeat;
}
.file-object {
margin: 0 0 -5px 0;
padding: 0;
}
.btn-file {
overflow: hidden;
}
.btn-file input[type=file] {
top: 0;
left: 0;
min-width: 100%;
min-height: 100%;
text-align: right;
opacity: 0;
background: none repeat scroll 0 0 transparent;
cursor: inherit;
display: block;
}
.btn-file ::-ms-browse {
font-size: 10000px;
width: 100%;
height: 100%;
}
.file-caption .file-caption-name {
width: 100%;
margin: 0;
padding: 0;
box-shadow: none;
border: none;
background: none;
outline: none;
}
.file-caption.icon-visible .file-caption-icon {
display: inline-block;
}
.file-caption.icon-visible .file-caption-name {
padding-left: 15px;
}
.file-caption-icon {
left: 8px;
}
.file-error-message {
color: #a94442;
background-color: #f2dede;
margin: 5px;
border: 1px solid #ebccd1;
border-radius: 4px;
padding: 15px;
}
.file-error-message pre {
margin: 5px 0;
}
.file-caption-disabled {
background-color: #eee;
cursor: not-allowed;
opacity: 1;
}
.file-preview {
border-radius: 5px;
border: 1px solid #ddd;
padding: 8px;
width: 100%;
margin-bottom: 5px;
}
.file-preview .btn-xs {
padding: 1px 5px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
}
.file-preview .fileinput-remove {
top: 1px;
right: 1px;
line-height: 10px;
}
.file-preview .clickable {
cursor: pointer;
}
.file-preview-image {
font: 40px Impact, Charcoal, sans-serif;
color: #008000;
}
.krajee-default.file-preview-frame {
margin: 8px;
border: 1px solid rgba(0,0,0,0.2);
box-shadow: 0 0 10px 0 rgba(0,0,0,0.2);
padding: 6px;
float: left;
text-align: center;
}
.krajee-default.file-preview-frame .kv-file-content {
width: 213px;
height: 160px;
}
.krajee-default .file-preview-other-frame {
display: flex;
align-items: center;
justify-content: center;
}
.krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered {
width: 400px;
}
.krajee-default.file-preview-frame[data-template="audio"] .kv-file-content {
width: 240px;
height: 55px;
}
.krajee-default.file-preview-frame .file-thumbnail-footer {
height: 70px;
}
.krajee-default.file-preview-frame:not(.file-preview-error):hover {
border: 1px solid rgba(0,0,0,0.3);
box-shadow: 0 0 10px 0 rgba(0,0,0,0.4);
}
.krajee-default .file-preview-text {
display: block;
color: #428bca;
border: 1px solid #ddd;
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
outline: none;
padding: 8px;
resize: none;
}
.krajee-default .file-preview-html {
border: 1px solid #ddd;
padding: 8px;
overflow: auto;
}
.krajee-default .file-other-icon {
font-size: 6em;
line-height: 1;
}
.krajee-default .file-footer-buttons {
float: right;
}
.krajee-default .file-footer-caption {
display: block;
text-align: center;
padding-top: 4px;
font-size: 11px;
color: #777;
margin-bottom: 30px;
}
.file-upload-stats {
font-size: 10px;
text-align: center;
width: 100%;
}
.kv-upload-progress .file-upload-stats {
font-size: 12px;
margin: -10px 0 5px;
}
.krajee-default .file-preview-error {
opacity: 0.65;
box-shadow: none;
}
.krajee-default .file-thumb-progress {
height: 11px;
top: 37px;
left: 0;
right: 0;
}
.krajee-default.kvsortable-ghost {
background: #e1edf7;
border: 2px solid #a1abff;
}
.krajee-default .file-preview-other:hover {
opacity: 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 {
padding: 0;
margin: 0;
background: transparent;
text-decoration: none;
outline: none;
opacity: 0.7;
top: 45%;
font-size: 4em;
color: #1c94c4;
}
.file-zoom-dialog .btn-navigate:not([disabled]):hover {
outline: none;
box-shadow: none;
opacity: 0.6;
}
.file-zoom-dialog .floating-buttons {
top: 5px;
right: 10px;
}
.file-zoom-dialog .btn-navigate[disabled] {
opacity: 0.3;
}
.file-zoom-dialog .btn-prev {
left: 1px;
}
.file-zoom-dialog .btn-next {
right: 1px;
}
.file-zoom-dialog .kv-zoom-title {
font-weight: 300;
color: #999;
max-width: 50%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.file-input-new .no-browse .form-control {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.file-input-ajax-new .no-browse .form-control {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
.file-caption-main {
width: 100%;
}
.file-thumb-loading {
background: transparent url(loading.gif) no-repeat scroll center center content-box !important;
}
.file-drop-zone {
border: 1px dashed #aaa;
border-radius: 4px;
text-align: center;
vertical-align: middle;
margin: 12px 15px 12px 12px;
padding: 5px;
}
.file-drop-zone.clickable:hover {
border: 2px dashed #999;
}
.file-drop-zone.clickable:focus {
border: 2px solid #5acde2;
}
.file-drop-zone .file-preview-thumbnails {
cursor: default;
}
.file-drop-zone-title {
color: #aaa;
font-size: 1.6em;
padding: 85px 10px;
cursor: default;
}
.file-highlighted {
border: 2px dashed #999 !important;
background-color: #eee;
}
.file-uploading {
background: url(loading-sm.gif) 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 .modal-body {
overflow-y: auto;
}
.floating-buttons {
z-index: 3000;
}
.floating-buttons .btn-kv {
margin-left: 3px;
z-index: 3000;
}
.kv-zoom-actions .btn-kv {
margin-left: 3px;
}
.file-zoom-content {
height: 480px;
text-align: center;
}
.file-zoom-content .file-preview-image {
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;
}
.file-sortable .file-drag-handle {
cursor: move;
opacity: 1;
}
.file-sortable .file-drag-handle:hover {
opacity: 0.7;
}
.clickable .file-drop-zone-title {
cursor: pointer;
}
.file-preview-initial.sortable-chosen {
background-color: #d9edf7;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

View File

@ -0,0 +1,429 @@
/*!
* Bootstrap-select v1.13.10 (https://developer.snapappointments.com/bootstrap-select)
*
* Copyright 2012-2019 SnapAppointments, LLC
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
*/
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 .selectpicker:invalid + .dropdown-toggle {
border-color: #b94a48;
}
.bootstrap-select.is-valid .dropdown-toggle,
.was-validated .bootstrap-select .selectpicker: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 .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: 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;
}
/*# sourceMappingURL=bootstrap-select.css.map */

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,663 @@
/*! X-editable - v1.5.1
* In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
* http://github.com/vitalets/x-editable
* Copyright (c) 2013 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 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;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,119 @@
/**
* @author zhixin wen <wenzhixin2010@gmail.com>
* extensions: https://github.com/kayalshri/tableExport.jquery.plugin
*/
(function ($) {
'use strict';
var sprintf = $.fn.bootstrapTable.utils.sprintf;
var TYPE_NAME = {
csv: 'CSV',
txt: 'TXT',
doc: 'Word',
excel: 'Excel'
};
$.extend($.fn.bootstrapTable.defaults, {
showExport: false,
exportDataType: 'all', // basic, all, selected
exportTypes: ['csv', 'txt', 'doc', 'excel'],
exportOptions: {
ignoreColumn: [0] //忽略列索引
}
});
$.extend($.fn.bootstrapTable.defaults.icons, {
export: 'glyphicon glyphicon-save'
});
$.extend($.fn.bootstrapTable.locales, {
formatExport: function () {
return '导出';
}
});
$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales);
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initToolbar = BootstrapTable.prototype.initToolbar;
BootstrapTable.prototype.initToolbar = function () {
this.showToolbar = this.options.showExport;
_initToolbar.apply(this, Array.prototype.slice.apply(arguments));
if (this.options.showExport) {
var that = this,
$btnGroup = this.$toolbar.find('>.btn-group'),
$export = $btnGroup.find('div.export');
if (!$export.length) {
$export = $([
'<div class="export btn-group">',
'<button class="btn' +
sprintf(' btn-%s', this.options.buttonsClass) +
sprintf(' btn-%s', this.options.iconSize) +
' dropdown-toggle" ' +
'title="' + this.options.formatExport() + '" ' +
'data-toggle="dropdown" type="button">',
sprintf('<i class="%s %s"></i> ', this.options.iconsPrefix, this.options.icons.export),
'<span class="caret"></span>',
'</button>',
'<ul class="dropdown-menu" role="menu">',
'</ul>',
'</div>'].join('')).appendTo($btnGroup);
var $menu = $export.find('.dropdown-menu'),
exportTypes = this.options.exportTypes;
if (typeof this.options.exportTypes === 'string') {
var types = this.options.exportTypes.slice(1, -1).replace(/ /g, '').split(',');
exportTypes = [];
$.each(types, function (i, value) {
exportTypes.push(value.slice(1, -1));
});
}
$.each(exportTypes, function (i, type) {
if (TYPE_NAME.hasOwnProperty(type)) {
$menu.append(['<li data-type="' + type + '">',
'<a href="javascript:void(0)">',
TYPE_NAME[type],
'</a>',
'</li>'].join(''));
}
});
$menu.find('li').click(function () {
var type = $(this).data('type'),
doExport = function () {
that.$el.tableExport($.extend({}, that.options.exportOptions, {
type: type,
escape: false
}));
};
if (that.options.exportDataType === 'all' && that.options.pagination) {
that.$el.one(that.options.sidePagination === 'server' ? 'post-body.bs.table' : 'page-change.bs.table', function () {
doExport();
that.togglePagination();
});
that.togglePagination();
} else if (that.options.exportDataType === 'selected') {
//修改sidePagination属性为server无法导出选中数据
var trs = that.$body.children();
for (var i = 0; i < trs.length; i++) {
var $this = $(trs[i]);
if(!$this.find(sprintf('[name="%s"]',that.options.selectItemName)).prop('checked')){
$this['hide']();
}}
doExport();
that.getRowsHidden(true);
} else {
doExport();
}
});
}
}
};
})(jQuery);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,117 @@
/**
* @author: Dennis Hernández
* 实现表格拖拽功能
* @version: v1.0.1
*/
(function ($) {
'use strict';
var isSearch = false;
var rowAttr = function (row, index) {
return {
id: 'customId_' + index
};
};
$.extend($.fn.bootstrapTable.defaults, {
reorderableRows: false,
onDragStyle: null,
onDropStyle: null,
onDragClass: "reorder_rows_onDragClass",
dragHandle: null,
useRowAttrFunc: false,
onReorderRowsDrag: function (table, row) {
return false;
},
onReorderRowsDrop: function (table, row) {
return false;
},
onReorderRow: function (newData) {
return false;
}
});
$.extend($.fn.bootstrapTable.Constructor.EVENTS, {
'reorder-row.bs.table': 'onReorderRow'
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_init = BootstrapTable.prototype.init,
_initSearch = BootstrapTable.prototype.initSearch;
BootstrapTable.prototype.init = function () {
if (!this.options.reorderableRows) {
_init.apply(this, Array.prototype.slice.apply(arguments));
return;
}
var that = this;
if (this.options.useRowAttrFunc) {
this.options.rowAttributes = rowAttr;
}
var onPostBody = this.options.onPostBody;
this.options.onPostBody = function () {
setTimeout(function () {
that.makeRowsReorderable();
onPostBody.apply();
}, 1);
};
_init.apply(this, Array.prototype.slice.apply(arguments));
};
BootstrapTable.prototype.initSearch = function () {
_initSearch.apply(this, Array.prototype.slice.apply(arguments));
if (!this.options.reorderableRows) {
return;
}
//Known issue after search if you reorder the rows the data is not display properly
//isSearch = true;
};
BootstrapTable.prototype.makeRowsReorderable = function () {
if (this.options.cardView) {
return;
}
var that = this;
this.$el.tableDnD({
onDragStyle: that.options.onDragStyle,
onDropStyle: that.options.onDropStyle,
onDragClass: that.options.onDragClass,
onDrop: that.onDrop,
onDragStart: that.options.onReorderRowsDrag,
dragHandle: that.options.dragHandle
});
};
BootstrapTable.prototype.onDrop = function (table, droppedRow) {
var tableBs = $(table),
tableBsData = tableBs.data('bootstrap.table'),
tableBsOptions = tableBs.data('bootstrap.table').options,
row = null,
newData = [];
for (var i = 0; i < table.tBodies[0].rows.length; i++) {
row = $(table.tBodies[0].rows[i]);
newData.push(tableBsOptions.data[row.data('index')]);
row.data('index', i).attr('data-index', i);
}
tableBsOptions.data = tableBsOptions.data.slice(0, tableBsData.pageFrom - 1)
.concat(newData)
.concat(tableBsOptions.data.slice(tableBsData.pageTo));
//Call the user defined function
tableBsOptions.onReorderRowsDrop.apply(table, [table, droppedRow]);
//Call the event reorder-row
tableBsData.trigger('reorder-row', newData);
};
})(jQuery);

View File

@ -0,0 +1,598 @@
/**
* 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">&nbsp;</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">&nbsp;</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() {
// The cell is bound to "this"
$(this).bind(startEvent, function(e) {
$.tableDnD.initialiseDrag($(this).parents('tr')[0], table, this, e, config);
return false;
});
})
// 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);

View File

@ -0,0 +1,771 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) :
typeof define === 'function' && define.amd ? define(['jquery'], factory) :
(global = global || self, factory(global.jQuery));
}(this, (function ($) { 'use strict';
$ = $ && Object.prototype.hasOwnProperty.call($, 'default') ? $['default'] : $;
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var check = function (it) {
return it && it.Math == Math && it;
};
// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
var global_1 =
// eslint-disable-next-line no-undef
check(typeof globalThis == 'object' && globalThis) ||
check(typeof window == 'object' && window) ||
check(typeof self == 'object' && self) ||
check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
// eslint-disable-next-line no-new-func
Function('return this')();
var fails = function (exec) {
try {
return !!exec();
} catch (error) {
return true;
}
};
// Thank's IE8 for his funny defineProperty
var descriptors = !fails(function () {
return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7;
});
var nativePropertyIsEnumerable = {}.propertyIsEnumerable;
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
// Nashorn ~ JDK8 bug
var NASHORN_BUG = getOwnPropertyDescriptor && !nativePropertyIsEnumerable.call({ 1: 2 }, 1);
// `Object.prototype.propertyIsEnumerable` method implementation
// https://tc39.github.io/ecma262/#sec-object.prototype.propertyisenumerable
var f = NASHORN_BUG ? function propertyIsEnumerable(V) {
var descriptor = getOwnPropertyDescriptor(this, V);
return !!descriptor && descriptor.enumerable;
} : nativePropertyIsEnumerable;
var objectPropertyIsEnumerable = {
f: f
};
var createPropertyDescriptor = function (bitmap, value) {
return {
enumerable: !(bitmap & 1),
configurable: !(bitmap & 2),
writable: !(bitmap & 4),
value: value
};
};
var toString = {}.toString;
var classofRaw = function (it) {
return toString.call(it).slice(8, -1);
};
var split = ''.split;
// fallback for non-array-like ES3 and non-enumerable old V8 strings
var indexedObject = fails(function () {
// throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
// eslint-disable-next-line no-prototype-builtins
return !Object('z').propertyIsEnumerable(0);
}) ? function (it) {
return classofRaw(it) == 'String' ? split.call(it, '') : Object(it);
} : Object;
// `RequireObjectCoercible` abstract operation
// https://tc39.github.io/ecma262/#sec-requireobjectcoercible
var requireObjectCoercible = function (it) {
if (it == undefined) throw TypeError("Can't call method on " + it);
return it;
};
// toObject with fallback for non-array-like ES3 strings
var toIndexedObject = function (it) {
return indexedObject(requireObjectCoercible(it));
};
var isObject = function (it) {
return typeof it === 'object' ? it !== null : typeof it === 'function';
};
// `ToPrimitive` abstract operation
// https://tc39.github.io/ecma262/#sec-toprimitive
// instead of the ES6 spec version, we didn't implement @@toPrimitive case
// and the second argument - flag - preferred type is a string
var toPrimitive = function (input, PREFERRED_STRING) {
if (!isObject(input)) return input;
var fn, val;
if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
if (typeof (fn = input.valueOf) == 'function' && !isObject(val = fn.call(input))) return val;
if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
throw TypeError("Can't convert object to primitive value");
};
var hasOwnProperty = {}.hasOwnProperty;
var has = function (it, key) {
return hasOwnProperty.call(it, key);
};
var document = global_1.document;
// typeof document.createElement is 'object' in old IE
var EXISTS = isObject(document) && isObject(document.createElement);
var documentCreateElement = function (it) {
return EXISTS ? document.createElement(it) : {};
};
// Thank's IE8 for his funny defineProperty
var ie8DomDefine = !descriptors && !fails(function () {
return Object.defineProperty(documentCreateElement('div'), 'a', {
get: function () { return 7; }
}).a != 7;
});
var nativeGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
// `Object.getOwnPropertyDescriptor` method
// https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptor
var f$1 = descriptors ? nativeGetOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {
O = toIndexedObject(O);
P = toPrimitive(P, true);
if (ie8DomDefine) try {
return nativeGetOwnPropertyDescriptor(O, P);
} catch (error) { /* empty */ }
if (has(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
};
var objectGetOwnPropertyDescriptor = {
f: f$1
};
var anObject = function (it) {
if (!isObject(it)) {
throw TypeError(String(it) + ' is not an object');
} return it;
};
var nativeDefineProperty = Object.defineProperty;
// `Object.defineProperty` method
// https://tc39.github.io/ecma262/#sec-object.defineproperty
var f$2 = descriptors ? nativeDefineProperty : function defineProperty(O, P, Attributes) {
anObject(O);
P = toPrimitive(P, true);
anObject(Attributes);
if (ie8DomDefine) try {
return nativeDefineProperty(O, P, Attributes);
} catch (error) { /* empty */ }
if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
if ('value' in Attributes) O[P] = Attributes.value;
return O;
};
var objectDefineProperty = {
f: f$2
};
var createNonEnumerableProperty = descriptors ? function (object, key, value) {
return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
} : function (object, key, value) {
object[key] = value;
return object;
};
var setGlobal = function (key, value) {
try {
createNonEnumerableProperty(global_1, key, value);
} catch (error) {
global_1[key] = value;
} return value;
};
var SHARED = '__core-js_shared__';
var store = global_1[SHARED] || setGlobal(SHARED, {});
var sharedStore = store;
var functionToString = Function.toString;
// this helper broken in `3.4.1-3.4.4`, so we can't use `shared` helper
if (typeof sharedStore.inspectSource != 'function') {
sharedStore.inspectSource = function (it) {
return functionToString.call(it);
};
}
var inspectSource = sharedStore.inspectSource;
var WeakMap = global_1.WeakMap;
var nativeWeakMap = typeof WeakMap === 'function' && /native code/.test(inspectSource(WeakMap));
var shared = createCommonjsModule(function (module) {
(module.exports = function (key, value) {
return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
})('versions', []).push({
version: '3.6.0',
mode: 'global',
copyright: '© 2019 Denis Pushkarev (zloirock.ru)'
});
});
var id = 0;
var postfix = Math.random();
var uid = function (key) {
return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id + postfix).toString(36);
};
var keys = shared('keys');
var sharedKey = function (key) {
return keys[key] || (keys[key] = uid(key));
};
var hiddenKeys = {};
var WeakMap$1 = global_1.WeakMap;
var set, get, has$1;
var enforce = function (it) {
return has$1(it) ? get(it) : set(it, {});
};
var getterFor = function (TYPE) {
return function (it) {
var state;
if (!isObject(it) || (state = get(it)).type !== TYPE) {
throw TypeError('Incompatible receiver, ' + TYPE + ' required');
} return state;
};
};
if (nativeWeakMap) {
var store$1 = new WeakMap$1();
var wmget = store$1.get;
var wmhas = store$1.has;
var wmset = store$1.set;
set = function (it, metadata) {
wmset.call(store$1, it, metadata);
return metadata;
};
get = function (it) {
return wmget.call(store$1, it) || {};
};
has$1 = function (it) {
return wmhas.call(store$1, it);
};
} else {
var STATE = sharedKey('state');
hiddenKeys[STATE] = true;
set = function (it, metadata) {
createNonEnumerableProperty(it, STATE, metadata);
return metadata;
};
get = function (it) {
return has(it, STATE) ? it[STATE] : {};
};
has$1 = function (it) {
return has(it, STATE);
};
}
var internalState = {
set: set,
get: get,
has: has$1,
enforce: enforce,
getterFor: getterFor
};
var redefine = createCommonjsModule(function (module) {
var getInternalState = internalState.get;
var enforceInternalState = internalState.enforce;
var TEMPLATE = String(String).split('String');
(module.exports = function (O, key, value, options) {
var unsafe = options ? !!options.unsafe : false;
var simple = options ? !!options.enumerable : false;
var noTargetGet = options ? !!options.noTargetGet : false;
if (typeof value == 'function') {
if (typeof key == 'string' && !has(value, 'name')) createNonEnumerableProperty(value, 'name', key);
enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string' ? key : '');
}
if (O === global_1) {
if (simple) O[key] = value;
else setGlobal(key, value);
return;
} else if (!unsafe) {
delete O[key];
} else if (!noTargetGet && O[key]) {
simple = true;
}
if (simple) O[key] = value;
else createNonEnumerableProperty(O, key, value);
// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
})(Function.prototype, 'toString', function toString() {
return typeof this == 'function' && getInternalState(this).source || inspectSource(this);
});
});
var path = global_1;
var aFunction = function (variable) {
return typeof variable == 'function' ? variable : undefined;
};
var getBuiltIn = function (namespace, method) {
return arguments.length < 2 ? aFunction(path[namespace]) || aFunction(global_1[namespace])
: path[namespace] && path[namespace][method] || global_1[namespace] && global_1[namespace][method];
};
var ceil = Math.ceil;
var floor = Math.floor;
// `ToInteger` abstract operation
// https://tc39.github.io/ecma262/#sec-tointeger
var toInteger = function (argument) {
return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor : ceil)(argument);
};
var min = Math.min;
// `ToLength` abstract operation
// https://tc39.github.io/ecma262/#sec-tolength
var toLength = function (argument) {
return argument > 0 ? min(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
};
var max = Math.max;
var min$1 = Math.min;
// Helper for a popular repeating case of the spec:
// Let integer be ? ToInteger(index).
// If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
var toAbsoluteIndex = function (index, length) {
var integer = toInteger(index);
return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
};
// `Array.prototype.{ indexOf, includes }` methods implementation
var createMethod = function (IS_INCLUDES) {
return function ($this, el, fromIndex) {
var O = toIndexedObject($this);
var length = toLength(O.length);
var index = toAbsoluteIndex(fromIndex, length);
var value;
// Array#includes uses SameValueZero equality algorithm
// eslint-disable-next-line no-self-compare
if (IS_INCLUDES && el != el) while (length > index) {
value = O[index++];
// eslint-disable-next-line no-self-compare
if (value != value) return true;
// Array#indexOf ignores holes, Array#includes - not
} else for (;length > index; index++) {
if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
} return !IS_INCLUDES && -1;
};
};
var arrayIncludes = {
// `Array.prototype.includes` method
// https://tc39.github.io/ecma262/#sec-array.prototype.includes
includes: createMethod(true),
// `Array.prototype.indexOf` method
// https://tc39.github.io/ecma262/#sec-array.prototype.indexof
indexOf: createMethod(false)
};
var indexOf = arrayIncludes.indexOf;
var objectKeysInternal = function (object, names) {
var O = toIndexedObject(object);
var i = 0;
var result = [];
var key;
for (key in O) !has(hiddenKeys, key) && has(O, key) && result.push(key);
// Don't enum bug & hidden keys
while (names.length > i) if (has(O, key = names[i++])) {
~indexOf(result, key) || result.push(key);
}
return result;
};
// IE8- don't enum bug keys
var enumBugKeys = [
'constructor',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'toLocaleString',
'toString',
'valueOf'
];
var hiddenKeys$1 = enumBugKeys.concat('length', 'prototype');
// `Object.getOwnPropertyNames` method
// https://tc39.github.io/ecma262/#sec-object.getownpropertynames
var f$3 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
return objectKeysInternal(O, hiddenKeys$1);
};
var objectGetOwnPropertyNames = {
f: f$3
};
var f$4 = Object.getOwnPropertySymbols;
var objectGetOwnPropertySymbols = {
f: f$4
};
// all object keys, includes non-enumerable and symbols
var ownKeys = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
var keys = objectGetOwnPropertyNames.f(anObject(it));
var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
};
var copyConstructorProperties = function (target, source) {
var keys = ownKeys(source);
var defineProperty = objectDefineProperty.f;
var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (!has(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
}
};
var replacement = /#|\.prototype\./;
var isForced = function (feature, detection) {
var value = data[normalize(feature)];
return value == POLYFILL ? true
: value == NATIVE ? false
: typeof detection == 'function' ? fails(detection)
: !!detection;
};
var normalize = isForced.normalize = function (string) {
return String(string).replace(replacement, '.').toLowerCase();
};
var data = isForced.data = {};
var NATIVE = isForced.NATIVE = 'N';
var POLYFILL = isForced.POLYFILL = 'P';
var isForced_1 = isForced;
var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
/*
options.target - name of the target object
options.global - target is the global object
options.stat - export as static methods of target
options.proto - export as prototype methods of target
options.real - real prototype method for the `pure` version
options.forced - export even if the native feature is available
options.bind - bind methods to the target, required for the `pure` version
options.wrap - wrap constructors to preventing global pollution, required for the `pure` version
options.unsafe - use the simple assignment of property instead of delete + defineProperty
options.sham - add a flag to not completely full polyfills
options.enumerable - export as enumerable property
options.noTargetGet - prevent calling a getter on target
*/
var _export = function (options, source) {
var TARGET = options.target;
var GLOBAL = options.global;
var STATIC = options.stat;
var FORCED, target, key, targetProperty, sourceProperty, descriptor;
if (GLOBAL) {
target = global_1;
} else if (STATIC) {
target = global_1[TARGET] || setGlobal(TARGET, {});
} else {
target = (global_1[TARGET] || {}).prototype;
}
if (target) for (key in source) {
sourceProperty = source[key];
if (options.noTargetGet) {
descriptor = getOwnPropertyDescriptor$1(target, key);
targetProperty = descriptor && descriptor.value;
} else targetProperty = target[key];
FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
// contained in target
if (!FORCED && targetProperty !== undefined) {
if (typeof sourceProperty === typeof targetProperty) continue;
copyConstructorProperties(sourceProperty, targetProperty);
}
// add a flag to not completely full polyfills
if (options.sham || (targetProperty && targetProperty.sham)) {
createNonEnumerableProperty(sourceProperty, 'sham', true);
}
// extend global
redefine(target, key, sourceProperty, options);
}
};
// `IsArray` abstract operation
// https://tc39.github.io/ecma262/#sec-isarray
var isArray = Array.isArray || function isArray(arg) {
return classofRaw(arg) == 'Array';
};
// `ToObject` abstract operation
// https://tc39.github.io/ecma262/#sec-toobject
var toObject = function (argument) {
return Object(requireObjectCoercible(argument));
};
var createProperty = function (object, key, value) {
var propertyKey = toPrimitive(key);
if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));
else object[propertyKey] = value;
};
var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {
// Chrome 38 Symbol has incorrect toString conversion
// eslint-disable-next-line no-undef
return !String(Symbol());
});
var useSymbolAsUid = nativeSymbol
// eslint-disable-next-line no-undef
&& !Symbol.sham
// eslint-disable-next-line no-undef
&& typeof Symbol() == 'symbol';
var WellKnownSymbolsStore = shared('wks');
var Symbol$1 = global_1.Symbol;
var createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : uid;
var wellKnownSymbol = function (name) {
if (!has(WellKnownSymbolsStore, name)) {
if (nativeSymbol && has(Symbol$1, name)) WellKnownSymbolsStore[name] = Symbol$1[name];
else WellKnownSymbolsStore[name] = createWellKnownSymbol('Symbol.' + name);
} return WellKnownSymbolsStore[name];
};
var SPECIES = wellKnownSymbol('species');
// `ArraySpeciesCreate` abstract operation
// https://tc39.github.io/ecma262/#sec-arrayspeciescreate
var arraySpeciesCreate = function (originalArray, length) {
var C;
if (isArray(originalArray)) {
C = originalArray.constructor;
// cross-realm fallback
if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;
else if (isObject(C)) {
C = C[SPECIES];
if (C === null) C = undefined;
}
} return new (C === undefined ? Array : C)(length === 0 ? 0 : length);
};
var userAgent = getBuiltIn('navigator', 'userAgent') || '';
var process = global_1.process;
var versions = process && process.versions;
var v8 = versions && versions.v8;
var match, version;
if (v8) {
match = v8.split('.');
version = match[0] + match[1];
} else if (userAgent) {
match = userAgent.match(/Edge\/(\d+)/);
if (!match || match[1] >= 74) {
match = userAgent.match(/Chrome\/(\d+)/);
if (match) version = match[1];
}
}
var v8Version = version && +version;
var SPECIES$1 = wellKnownSymbol('species');
var arrayMethodHasSpeciesSupport = function (METHOD_NAME) {
// We can't use this feature detection in V8 since it causes
// deoptimization and serious performance degradation
// https://github.com/zloirock/core-js/issues/677
return v8Version >= 51 || !fails(function () {
var array = [];
var constructor = array.constructor = {};
constructor[SPECIES$1] = function () {
return { foo: 1 };
};
return array[METHOD_NAME](Boolean).foo !== 1;
});
};
var IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable');
var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded';
// We can't use this feature detection in V8 since it causes
// deoptimization and serious performance degradation
// https://github.com/zloirock/core-js/issues/679
var IS_CONCAT_SPREADABLE_SUPPORT = v8Version >= 51 || !fails(function () {
var array = [];
array[IS_CONCAT_SPREADABLE] = false;
return array.concat()[0] !== array;
});
var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat');
var isConcatSpreadable = function (O) {
if (!isObject(O)) return false;
var spreadable = O[IS_CONCAT_SPREADABLE];
return spreadable !== undefined ? !!spreadable : isArray(O);
};
var FORCED = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT;
// `Array.prototype.concat` method
// https://tc39.github.io/ecma262/#sec-array.prototype.concat
// with adding support of @@isConcatSpreadable and @@species
_export({ target: 'Array', proto: true, forced: FORCED }, {
concat: function concat(arg) { // eslint-disable-line no-unused-vars
var O = toObject(this);
var A = arraySpeciesCreate(O, 0);
var n = 0;
var i, k, length, len, E;
for (i = -1, length = arguments.length; i < length; i++) {
E = i === -1 ? O : arguments[i];
if (isConcatSpreadable(E)) {
len = toLength(E.length);
if (n + len > MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
} else {
if (n >= MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
createProperty(A, n++, E);
}
}
A.length = n;
return A;
}
});
/**
* Bootstrap Table Chinese translation
* Author: Zhixin Wen<wenzhixin2010@gmail.com>
*/
$.fn.bootstrapTable.locales['zh-CN'] = {
formatLoadingMessage: function formatLoadingMessage() {
return '正在努力地加载数据中,请稍候';
},
formatRecordsPerPage: function formatRecordsPerPage(pageNumber) {
return "\u6BCF\u9875\u663E\u793A ".concat(pageNumber, " \u6761\u8BB0\u5F55");
},
formatShowingRows: function formatShowingRows(pageFrom, pageTo, totalRows, totalNotFiltered) {
if (totalNotFiltered !== undefined && totalNotFiltered > 0 && totalNotFiltered > totalRows) {
return "\u663E\u793A\u7B2C ".concat(pageFrom, " \u5230\u7B2C ").concat(pageTo, " \u6761\u8BB0\u5F55\uFF0C\u603B\u5171 ").concat(totalRows, " \u6761\u8BB0\u5F55\uFF08\u4ECE ").concat(totalNotFiltered, " \u603B\u8BB0\u5F55\u4E2D\u8FC7\u6EE4\uFF09");
}
return "\u663E\u793A\u7B2C ".concat(pageFrom, " \u5230\u7B2C ").concat(pageTo, " \u6761\u8BB0\u5F55\uFF0C\u603B\u5171 ").concat(totalRows, " \u6761\u8BB0\u5F55");
},
formatSRPaginationPreText: function formatSRPaginationPreText() {
return '上一页';
},
formatSRPaginationPageText: function formatSRPaginationPageText(page) {
return "\u7B2C".concat(page, "\u9875");
},
formatSRPaginationNextText: function formatSRPaginationNextText() {
return '下一页';
},
formatDetailPagination: function formatDetailPagination(totalRows) {
return "\u603B\u5171 ".concat(totalRows, " \u6761\u8BB0\u5F55");
},
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']);
})));

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,747 @@
/**
* 基于bootstrapTreeTable/bootstrap-table-treegrid修改
* Copyright (c) 2019 snow
*/
(function($) {
"use strict";
$.fn.bootstrapTreeTable = function(options, param) {
var target = $(this).data('bootstrap.tree.table');
target = target ? target : $(this);
// 如果是调用方法
if (typeof options == 'string') {
return $.fn.bootstrapTreeTable.methods[options](target, param);
}
// 如果是初始化组件
options = $.extend({}, $.fn.bootstrapTreeTable.defaults, options || {});
target.hasSelectItem = false;// 是否有radio或checkbox
target.data_list = null; //用于缓存格式化后的数据-按父分组
target.data_obj = null; //用于缓存格式化后的数据-按id存对象
target.hiddenColumns = []; //用于存放被隐藏列的field
target.lastAjaxParams; //用户最后一次请求的参数
target.isFixWidth=false; //是否有固定宽度
// 初始化
var init = function() {
// 初始化容器
initContainer();
// 初始化工具栏
initToolbar();
// 初始化表头
initHeader();
// 初始化表体
initBody();
// 初始化数据服务
initServer();
// 动态设置表头宽度
autoTheadWidth(true);
// 缓存target对象
target.data('bootstrap.tree.table', target);
}
// 初始化容器
var initContainer = function() {
// 在外层包装一下div样式用的bootstrap-table的
var $main_div = $("<div class='bootstrap-tree-table'></div>");
var $treetable = $("<div class='treetable-table'></div>");
target.before($main_div);
$main_div.append($treetable);
$treetable.append(target);
target.addClass("table");
if (options.striped) {
target.addClass('table-striped');
}
if (options.bordered) {
target.addClass('table-bordered');
}
if (options.hover) {
target.addClass('table-hover');
}
if (options.condensed) {
target.addClass('table-condensed');
}
target.html("");
}
// 初始化工具栏
var initToolbar = function() {
var $toolbar = $("<div class='treetable-bars'></div>");
if (options.toolbar) {
$(options.toolbar).addClass('tool-left');
$toolbar.append($(options.toolbar));
}
var $rightToolbar = $('<div class="btn-group tool-right">');
$toolbar.append($rightToolbar);
target.parent().before($toolbar);
// snow 是否显示检索信息
if (options.showSearch) {
var $searchBtn = $('<button class="btn btn-default btn-outline" type="button" aria-label="search" title="搜索"><i class="glyphicon glyphicon-search"></i></button>');
$rightToolbar.append($searchBtn);
registerSearchBtnClickEvent($searchBtn);
}
// 是否显示刷新按钮
if (options.showRefresh) {
var $refreshBtn = $('<button class="btn btn-default btn-outline" type="button" aria-label="refresh" title="刷新"><i class="glyphicon glyphicon-repeat"></i></button>');
$rightToolbar.append($refreshBtn);
registerRefreshBtnClickEvent($refreshBtn);
}
// 是否显示列选项
if (options.showColumns) {
var $columns_div = $('<div class="btn-group pull-right" title="列"><button type="button" aria-label="columns" class="btn btn-default btn-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="glyphicon glyphicon-list"></i> <span class="caret"></span></button></div>');
var $columns_ul = $('<ul class="dropdown-menu columns" role="menu"></ul>');
$.each(options.columns, function(i, column) {
if (column.field != 'selectItem') {
var _li = null;
if(typeof column.visible == "undefined"||column.visible==true){
_li = $('<li role="menuitem"><label><input type="checkbox" checked="checked" data-field="'+column.field+'" value="'+column.field+'" > '+column.title+'</label></li>');
}else{
_li = $('<li role="menuitem"><label><input type="checkbox" data-field="'+column.field+'" value="'+column.field+'" > '+column.title+'</label></li>');
target.hiddenColumns.push(column.field);
}
$columns_ul.append(_li);
}
});
$columns_div.append($columns_ul);
$rightToolbar.append($columns_div);
// 注册列选项事件
registerColumnClickEvent();
}else{
$.each(options.columns, function(i, column) {
if (column.field != 'selectItem') {
if(!(typeof column.visible == "undefined"||column.visible==true)){
target.hiddenColumns.push(column.field);
}
}
});
}
}
// 初始化隐藏列
var initHiddenColumns = function(){
$.each(target.hiddenColumns, function(i, field) {
target.find("."+field+"_cls").hide();
});
}
// 初始化表头
var initHeader = function() {
var $thr = $('<tr></tr>');
$.each(options.columns, function(i, column) {
var $th = null;
// 判断有没有选择列
if (i == 0 && column.field == 'selectItem') {
target.hasSelectItem = true;
$th = $('<th style="width:36px"></th>');
} else {
$th = $('<th style="' + ((column.width) ? ('width:' + column.width) : '') + '" class="' + column.field + '_cls"></th>');
}
if((!target.isFixWidth)&& column.width){
target.isFixWidth = column.width.indexOf("px")>-1?true:false;
}
$th.text(column.title);
$thr.append($th);
});
var $thead = $('<thead class="treetable-thead"></thead>');
$thead.append($thr);
target.append($thead);
}
// 初始化表体
var initBody = function() {
var $tbody = $('<tbody class="treetable-tbody"></tbody>');
target.append($tbody);
// 默认高度
if (options.height) {
$tbody.css("height", options.height);
}
}
// 初始化数据服务
var initServer = function(parms) {
// 加载数据前先清空
target.data_list = {};
target.data_obj = {};
var $tbody = target.find("tbody");
// 添加加载loading
var $loading = '<tr><td colspan="' + options.columns.length + '"><div style="display: block;text-align: center;">正在努力地加载数据中,请稍候……</div></td></tr>'
$tbody.html($loading);
if (options.url) {
$.ajax({
type: options.type,
url: options.url,
data: parms ? parms : options.ajaxParams,
dataType: "JSON",
success: function(data, textStatus, jqXHR) {
data = calculateObjectValue(options, options.responseHandler, [data], data);
renderTable(data);
calculateObjectValue(options, options.onLoadSuccess, [data], data);
},
error: function(xhr, textStatus) {
var _errorMsg = '<tr><td colspan="' + options.columns.length + '"><div style="display: block;text-align: center;">' + xhr.responseText + '</div></td></tr>'
$tbody.html(_errorMsg);
},
});
} else {
renderTable(options.data);
}
}
// 加载完数据后渲染表格
var renderTable = function(data) {
var $tbody = target.find("tbody");
// 先清空
$tbody.html("");
if (!data || data.length <= 0) {
var _empty = '<tr><td colspan="' + options.columns.length + '"><div style="display: block;text-align: center;">没有找到匹配的记录</div></td></tr>'
$tbody.html(_empty);
return;
}
// 缓存并格式化数据
formatData(data);
// 获取所有根节点
var rootNode = target.data_list["_root_"];
// 开始绘制
if (rootNode) {
$.each(rootNode, function(i, item) {
var _child_row_id = "row_id_" + i
recursionNode(item, 1, _child_row_id, "row_root");
});
}
// 下边的操作主要是为了查询时让一些没有根节点的节点显示
$.each(data, function(i, item) {
if (!item.isShow) {
var tr = renderRow(item, false, 1, "", "");
$tbody.append(tr);
}
});
target.append($tbody);
registerExpanderEvent();
registerRowClickEvent();
initHiddenColumns();
// 动态设置表头宽度
autoTheadWidth()
}
// 动态设置表头宽度
var autoTheadWidth = function(initFlag) {
if(options.height>0){
var $thead = target.find("thead");
var $tbody = target.find("tbody");
var borderWidth = parseInt(target.css("border-left-width")) + parseInt(target.css("border-right-width"))
$thead.css("width", $tbody.children(":first").width());
if(initFlag){
var resizeWaiter = false;
$(window).resize(function() {
if(!resizeWaiter){
resizeWaiter = true;
setTimeout(function(){
if(!target.isFixWidth){
$tbody.css("width", target.parent().width()-borderWidth);
}
$thead.css("width", $tbody.children(":first").width());
resizeWaiter = false;
}, 300);
}
});
}
}
}
// 缓存并格式化数据
var formatData = function(data) {
var _root = options.rootIdValue ? options.rootIdValue : null;
// 父节点属性列表
var parentCodes = [];
var rootFlag = false;
$.each(data, function(index, item) {
if($.inArray(item[options.parentCode], parentCodes) == -1){
parentCodes.push(item[options.parentCode]);
}
});
$.each(data, function(index, item) {
// 添加一个默认属性,用来判断当前节点有没有被显示
item.isShow = false;
// 顶级节点校验判断兼容0,'0','',null
var _defaultRootFlag = item[options.parentCode] == '0' ||
item[options.parentCode] == 0 ||
item[options.parentCode] == null ||
item[options.parentCode] == '' ||
$.inArray(item[options.code], parentCodes) > 0 && !rootFlag;
if (!item[options.parentCode] || (_root ? (item[options.parentCode] == options.rootIdValue) : _defaultRootFlag)) {
rootFlag = true;
if (!target.data_list["_root_"]) {
target.data_list["_root_"] = [];
}
if (!target.data_obj["id_" + item[options.code]]) {
target.data_list["_root_"].push(item);
}
} else {
if (!target.data_list["_n_" + item[options.parentCode]]) {
target.data_list["_n_" + item[options.parentCode]] = [];
}
if (!target.data_obj["id_" + item[options.code]]) {
target.data_list["_n_" + item[options.parentCode]].push(item);
}
}
target.data_obj["id_" + item[options.code]] = item;
});
}
// 递归获取子节点并且设置子节点
var recursionNode = function(parentNode, lv, row_id, p_id) {
var $tbody = target.find("tbody");
var _ls = target.data_list["_n_" + parentNode[options.code]];
var $tr = renderRow(parentNode, _ls ? true : false, lv, row_id, p_id);
$tbody.append($tr);
if (_ls) {
$.each(_ls, function(i, item) {
var _child_row_id = row_id + "_" + i
recursionNode(item, (lv + 1), _child_row_id, row_id)
});
}
};
// 绘制行
var renderRow = function(item, isP, lv, row_id, p_id) {
// 标记已显示
item.isShow = true;
item.row_id = row_id;
item.p_id = p_id;
item.lv = lv;
var $tr = $('<tr id="' + row_id + '" pid="' + p_id + '"></tr>');
var _icon = options.expanderCollapsedClass;
if (options.expandAll) {
$tr.css("display", "table");
_icon = options.expanderExpandedClass;
} else if (lv == 1) {
$tr.css("display", "table");
_icon = (options.expandFirst) ? options.expanderExpandedClass : options.expanderCollapsedClass;
} else if (lv == 2) {
if (options.expandFirst) {
$tr.css("display", "table");
} else {
$tr.css("display", "none");
}
_icon = options.expanderCollapsedClass;
} else {
$tr.css("display", "none");
_icon = options.expanderCollapsedClass;
}
$.each(options.columns, function(index, column) {
// 判断有没有选择列
if (column.field == 'selectItem') {
target.hasSelectItem = true;
var $td = $('<td style="text-align:center;width:36px"></td>');
if (column.radio) {
var _ipt = $('<input name="select_item" type="radio" value="' + item[options.code] + '"></input>');
$td.append(_ipt);
}
if (column.checkbox) {
var _ipt = $('<input name="select_item" type="checkbox" value="' + item[options.code] + '"></input>');
$td.append(_ipt);
}
$tr.append($td);
} else {
var $td = $('<td name="' + column.field + '" class="' + column.field + '_cls"></td>');
if(column.width){
$td.css("width",column.width);
}
if(column.align){
$td.css("text-align",column.align);
}
if(options.expandColumn == index){
$td.css("text-align","left");
}
if(column.valign){
$td.css("vertical-align",column.valign);
}
if(options.showTitle){
$td.addClass("ellipsis");
}
// 增加formatter渲染
if (column.formatter) {
$td.html(column.formatter.call(this, getItemField(item, column.field), item, index));
} else {
if(options.showTitle){
// 只在字段没有formatter时才添加title属性
$td.attr("title",item[column.field]);
}
$td.text(getItemField(item, column.field));
}
if (options.expandColumn == index) {
if (!isP) {
$td.prepend('<span class="treetable-expander"></span>')
} else {
$td.prepend('<span class="treetable-expander ' + _icon + '"></span>')
}
for (var int = 0; int < (lv - 1); int++) {
$td.prepend('<span class="treetable-indent"></span>')
}
}
$tr.append($td);
}
});
return $tr;
}
// 检索信息按钮点击事件
var registerSearchBtnClickEvent = function(btn) {
$(btn).off('click').on('click', function () {
$(".search-collapse").slideToggle();
});
}
// 注册刷新按钮点击事件
var registerRefreshBtnClickEvent = function(btn) {
$(btn).off('click').on('click', function () {
target.refresh();
});
}
// 注册列选项事件
var registerColumnClickEvent = function() {
$(".bootstrap-tree-table .treetable-bars .columns label input").off('click').on('click', function () {
var $this = $(this);
if($this.prop('checked')){
target.showColumn($(this).val());
}else{
target.hideColumn($(this).val());
}
});
}
// 注册行点击选中事件
var registerRowClickEvent = function() {
target.find("tbody").find("tr").unbind();
target.find("tbody").find("tr").click(function() {
if (target.hasSelectItem) {
var _ipt = $(this).find("input[name='select_item']");
if (_ipt.attr("type") == "radio") {
_ipt.prop('checked', true);
target.find("tbody").find("tr").removeClass("treetable-selected");
$(this).addClass("treetable-selected");
} else if (_ipt.attr("type") == "checkbox") {
if (_ipt.prop('checked')) {
_ipt.prop('checked', true);
target.find("tbody").find("tr").removeClass("treetable-selected");
$(this).addClass("treetable-selected");
} else {
_ipt.prop('checked', false);
target.find("tbody").find("tr").removeClass("treetable-selected");
}
} else {
if (_ipt.prop('checked')) {
_ipt.prop('checked', false);
$(this).removeClass("treetable-selected");
} else {
_ipt.prop('checked', true);
$(this).addClass("treetable-selected");
}
}
}
});
}
// 注册小图标点击事件--展开缩起
var registerExpanderEvent = function() {
target.find("tbody").find("tr").find(".treetable-expander").unbind();
target.find("tbody").find("tr").find(".treetable-expander").click(function() {
var _isExpanded = $(this).hasClass(options.expanderExpandedClass);
var _isCollapsed = $(this).hasClass(options.expanderCollapsedClass);
if (_isExpanded || _isCollapsed) {
var tr = $(this).parent().parent();
var row_id = tr.attr("id");
var _ls = target.find("tbody").find("tr[id^='" + row_id + "_']"); //下所有
if (_isExpanded) {
$(this).removeClass(options.expanderExpandedClass);
$(this).addClass(options.expanderCollapsedClass);
if (_ls && _ls.length > 0) {
$.each(_ls, function(index, item) {
$(item).css("display", "none");
});
}
} else {
$(this).removeClass(options.expanderCollapsedClass);
$(this).addClass(options.expanderExpandedClass);
if (_ls && _ls.length > 0) {
$.each(_ls, function(index, item) {
// 父icon
var _p_icon = $("#" + $(item).attr("pid")).children().eq(options.expandColumn).find(".treetable-expander");
if (_p_icon.hasClass(options.expanderExpandedClass)) {
$(item).css("display", "table");
}
});
}
}
}
});
}
// 刷新数据
target.refresh = function(parms) {
if(parms){
target.lastAjaxParams=parms;
}
initServer(target.lastAjaxParams);
}
// 添加数据刷新表格
target.appendData = function(data) {
// 下边的操作主要是为了查询时让一些没有根节点的节点显示
$.each(data, function(i, item) {
var _data = target.data_obj["id_" + item[options.code]];
var _p_data = target.data_obj["id_" + item[options.parentCode]];
var _c_list = target.data_list["_n_" + item[options.parentCode]];
var row_id = ""; //行id
var p_id = ""; //父行id
var _lv = 1; //如果没有父就是1默认显示
var tr; //要添加行的对象
if (_data && _data.row_id && _data.row_id != "") {
row_id = _data.row_id; // 如果已经存在了,就直接引用原来的
}
if (_p_data) {
p_id = _p_data.row_id;
if (row_id == "") {
var _tmp = 0
if (_c_list && _c_list.length > 0) {
_tmp = _c_list.length;
}
row_id = _p_data.row_id + "_" + _tmp;
}
_lv = _p_data.lv + 1; //如果有父
// 绘制行
tr = renderRow(item, false, _lv, row_id, p_id);
var _p_icon = $("#" + _p_data.row_id).children().eq(options.expandColumn).find(".treetable-expander");
var _isExpanded = _p_icon.hasClass(options.expanderExpandedClass);
var _isCollapsed = _p_icon.hasClass(options.expanderCollapsedClass);
// 父节点有没有展开收缩按钮
if (_isExpanded || _isCollapsed) {
// 父节点展开状态显示新加行
if (_isExpanded) {
tr.css("display", "table");
}
} else {
// 父节点没有展开收缩按钮则添加
_p_icon.addClass(options.expanderCollapsedClass);
}
if (_data) {
$("#" + _data.row_id).before(tr);
$("#" + _data.row_id).remove();
} else {
// 计算父的同级下一行
var _tmp_ls = _p_data.row_id.split("_");
var _p_next = _p_data.row_id.substring(0, _p_data.row_id.length - 1) + (parseInt(_tmp_ls[_tmp_ls.length - 1]) + 1);
// 画上
$("#" + _p_next).before(tr);
}
} else {
tr = renderRow(item, false, _lv, row_id, p_id);
if (_data) {
$("#" + _data.row_id).before(tr);
$("#" + _data.row_id).remove();
} else {
// 画上
var tbody = target.find("tbody");
tbody.append(tr);
}
}
item.isShow = true;
// 缓存并格式化数据
formatData([item]);
});
registerExpanderEvent();
registerRowClickEvent();
initHiddenColumns();
}
// 展开/折叠指定的行
target.toggleRow=function(id) {
var _rowData = target.data_obj["id_" + id];
var $row_expander = $("#"+_rowData.row_id).find(".treetable-expander");
$row_expander.trigger("click");
}
// 展开指定的行
target.expandRow=function(id) {
var _rowData = target.data_obj["id_" + id];
var $row_expander = $("#"+_rowData.row_id).find(".treetable-expander");
var _isCollapsed = $row_expander.hasClass(target.options.expanderCollapsedClass);
if (_isCollapsed) {
$row_expander.trigger("click");
}
}
// 折叠 指定的行
target.collapseRow=function(id) {
var _rowData = target.data_obj["id_" + id];
var $row_expander = $("#"+_rowData.row_id).find(".treetable-expander");
var _isExpanded = $row_expander.hasClass(target.options.expanderExpandedClass);
if (_isExpanded) {
$row_expander.trigger("click");
}
}
// 展开所有的行
target.expandAll=function() {
target.find("tbody").find("tr").find(".treetable-expander").each(function(i,n){
var _isCollapsed = $(n).hasClass(options.expanderCollapsedClass);
if (_isCollapsed) {
$(n).trigger("click");
}
})
}
// 折叠所有的行
target.collapseAll=function() {
target.find("tbody").find("tr").find(".treetable-expander").each(function(i,n){
var _isExpanded = $(n).hasClass(options.expanderExpandedClass);
if (_isExpanded) {
$(n).trigger("click");
}
})
}
// 显示指定列
target.showColumn=function(field,flag) {
var _index = $.inArray(field, target.hiddenColumns);
if (_index > -1) {
target.hiddenColumns.splice(_index, 1);
}
target.find("."+field+"_cls").show();
//是否更新列选项状态
if(flag&&options.showColumns){
var $input = $(".bootstrap-tree-table .treetable-bars .columns label").find("input[value='"+field+"']")
$input.prop("checked", 'checked');
}
}
// 隐藏指定列
target.hideColumn=function(field,flag) {
target.hiddenColumns.push(field);
target.find("."+field+"_cls").hide();
//是否更新列选项状态
if(flag&&options.showColumns){
var $input = $(".bootstrap-tree-table .treetable-bars .columns label").find("input[value='"+field+"']")
$input.prop("checked", '');
}
}
// snow 解析数据,支持多层级访问
var getItemField = function (item, field) {
var value = item;
if (typeof field !== 'string' || item.hasOwnProperty(field)) {
return item[field];
}
var props = field.split('.');
for (var p in props) {
value = value && value[props[p]];
}
return value;
};
// snow 发起对目标(target)函数的调用
var calculateObjectValue = function (self, name, args, defaultValue) {
var func = name;
if (typeof name === 'string') {
var names = name.split('.');
if (names.length > 1) {
func = window;
$.each(names, function (i, f) {
func = func[f];
});
} else {
func = window[name];
}
}
if (typeof func === 'object') {
return func;
}
if (typeof func === 'function') {
return func.apply(self, args);
}
if (!func && typeof name === 'string' && sprintf.apply(this, [name].concat(args))) {
return sprintf.apply(this, [name].concat(args));
}
return defaultValue;
};
// 初始化
init();
return target;
};
// 组件方法封装........
$.fn.bootstrapTreeTable.methods = {
// 为了兼容bootstrap-table的写法统一返回数组这里返回了表格显示列的数据
getSelections: function(target, data) {
// 所有被选中的记录input
var _ipt = target.find("tbody").find("tr").find("input[name='select_item']:checked");
var chk_value = [];
// 如果是radio
if (_ipt.attr("type") == "radio") {
var _data = target.data_obj["id_" + _ipt.val()];
chk_value.push(_data);
} else {
_ipt.each(function(_i, _item) {
var _data = target.data_obj["id_" + $(_item).val()];
chk_value.push(_data);
});
}
return chk_value;
},
// 刷新记录
refresh: function(target, parms) {
if (parms) {
target.refresh(parms);
} else {
target.refresh();
}
},
// 添加数据到表格
appendData: function(target, data) {
if (data) {
target.appendData(data);
}
},
// 展开/折叠指定的行
toggleRow: function(target, id) {
target.toggleRow(id);
},
// 展开指定的行
expandRow: function(target, id) {
target.expandRow(id);
},
// 折叠 指定的行
collapseRow: function(target, id) {
target.collapseRow(id);
},
// 展开所有的行
expandAll: function(target) {
target.expandAll();
},
// 折叠所有的行
collapseAll: function(target) {
target.collapseAll();
},
// 显示指定列
showColumn: function(target,field) {
target.showColumn(field,true);
},
// 隐藏指定列
hideColumn: function(target,field) {
target.hideColumn(field,true);
}
// 组件的其他方法也可以进行类似封装........
};
$.fn.bootstrapTreeTable.defaults = {
code: 'code', // 选取记录返回的值,用于设置父子关系
parentCode: 'parentCode', // 用于设置父子关系
rootIdValue: null, // 设置根节点id值----可指定根节点默认为null,"",0,"0"
data: null, // 构造table的数据集合
type: "GET", // 请求数据的ajax类型
url: null, // 请求数据的ajax的url
ajaxParams: {}, // 请求数据的ajax的data属性
expandColumn: 0, // 在哪一列上面显示展开按钮
expandAll: false, // 是否全部展开
expandFirst: true, // 是否默认第一级展开--expandAll为false时生效
striped: false, // 是否各行渐变色
bordered: true, // 是否显示边框
hover: true, // 是否鼠标悬停
condensed: false, // 是否紧缩表格
columns: [], // 列
toolbar: null, // 顶部工具条
height: 0, // 表格高度
showTitle: true, // 是否采用title属性显示字段内容被formatter格式化的字段不会显示
showSearch: true, // 是否显示检索信息
showColumns: true, // 是否显示内容列下拉框
showRefresh: true, // 是否显示刷新按钮
expanderExpandedClass: 'glyphicon glyphicon-chevron-down', // 展开的按钮的图标
expanderCollapsedClass: 'glyphicon glyphicon-chevron-right', // 缩起的按钮的图标
responseHandler: function(res) {
return false;
},
onLoadSuccess: function(res) {
return false;
}
};
})(jQuery);

View File

@ -0,0 +1,304 @@
/*!
* Cropper.js v1.5.7
* https://fengyuanchen.github.io/cropperjs
*
* Copyright 2015-present Chen Fengyuan
* Released under the MIT license
*
* Date: 2020-05-23T05:22:57.283Z
*/
.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;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
/*!
* Cropper.js v1.5.7
* https://fengyuanchen.github.io/cropperjs
*
* Copyright 2015-present Chen Fengyuan
* Released under the MIT license
*
* Date: 2020-05-23T05:22:57.283Z
*/.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-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}

File diff suppressed because one or more lines are too long

View File

@ -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;
};
}));

File diff suppressed because one or more lines are too long

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,86 @@
/*
* Bootstrap Duallistbox - v3.0.7
* 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%;
}

View File

@ -0,0 +1,841 @@
/*
* Bootstrap Duallistbox - v3.0.7
* 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
*/
;(function ($, window, document, undefined) {
// Create the defaults once
var pluginName = 'bootstrapDualListbox',
defaults = {
bootstrap2Compatible: false,
filterTextClear: 'show all',
filterPlaceHolder: 'Filter',
moveSelectedLabel: 'Move selected',
moveAllLabel: 'Move all',
removeSelectedLabel: 'Remove selected',
removeAllLabel: 'Remove all',
moveOnSelect: true, // true/false (forced true on androids, see the comment later)
moveOnDoubleClick: true, // true/false (forced false on androids, cause moveOnSelect is forced to true)
preserveSelectionOnMove: false, // 'all' / 'moved' / false
selectedListLabel: false, // 'string', false
nonSelectedListLabel: false, // 'string', false
helperSelectNamePostfix: '_helper', // 'string_of_postfix' / false
selectorMinimalHeight: 100,
showFilterInputs: true, // whether to show filter inputs
nonSelectedFilter: '', // string, filter the non selected options
selectedFilter: '', // string, filter the selected options
infoText: 'Showing all {0}', // text when all options are visible / false for no info text
infoTextFiltered: '<span class="label label-warning">Filtered</span> {0} from {1}', // when not all of the options are visible due to the filter
infoTextEmpty: 'Empty list', // when there are no options present in the list
filterOnValues: false, // filter by selector's values, boolean
sortByInputOrder: false,
eventMoveOverride: false, // boolean, allows user to unbind default event behaviour and run their own instead
eventMoveAllOverride: false, // boolean, allows user to unbind default event behaviour and run their own instead
eventRemoveOverride: false, // boolean, allows user to unbind default event behaviour and run their own instead
eventRemoveAllOverride: false // boolean, allows user to unbind default event behaviour and run their own instead
},
// Selections are invisible on android if the containing select is styled with CSS
// http://code.google.com/p/android/issues/detail?id=16922
isBuggyAndroid = /android/i.test(navigator.userAgent.toLowerCase());
// The actual plugin constructor
function BootstrapDualListbox(element, options) {
this.element = $(element);
// jQuery has an extend method which merges the contents of two or
// more objects, storing the result in the first object. The first object
// is generally empty as we don't want to alter the default options for
// future instances of the plugin
this.settings = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}
function triggerChangeEvent(dualListbox) {
dualListbox.element.trigger('change');
}
function updateSelectionStates(dualListbox) {
dualListbox.element.find('option').each(function(index, item) {
var $item = $(item);
if (typeof($item.data('original-index')) === 'undefined') {
$item.data('original-index', dualListbox.elementCount++);
}
if (typeof($item.data('_selected')) === 'undefined') {
$item.data('_selected', false);
}
});
}
function changeSelectionState(dualListbox, original_index, selected) {
dualListbox.element.find('option').each(function(index, item) {
var $item = $(item);
if ($item.data('original-index') === original_index) {
$item.prop('selected', selected);
if(selected){
$item.attr('data-sortindex', dualListbox.sortIndex);
dualListbox.sortIndex++;
} else {
$item.removeAttr('data-sortindex');
}
}
});
}
function formatString(s, args) {
return s.replace(/\{(\d+)\}/g, function(match, number) {
return typeof args[number] !== 'undefined' ? args[number] : match;
});
}
function refreshInfo(dualListbox) {
if (!dualListbox.settings.infoText) {
return;
}
var visible1 = dualListbox.elements.select1.find('option').length,
visible2 = dualListbox.elements.select2.find('option').length,
all1 = dualListbox.element.find('option').length - dualListbox.selectedElements,
all2 = dualListbox.selectedElements,
content = '';
if (all1 === 0) {
content = dualListbox.settings.infoTextEmpty;
} else if (visible1 === all1) {
content = formatString(dualListbox.settings.infoText, [visible1, all1]);
} else {
content = formatString(dualListbox.settings.infoTextFiltered, [visible1, all1]);
}
dualListbox.elements.info1.html(content);
dualListbox.elements.box1.toggleClass('filtered', !(visible1 === all1 || all1 === 0));
if (all2 === 0) {
content = dualListbox.settings.infoTextEmpty;
} else if (visible2 === all2) {
content = formatString(dualListbox.settings.infoText, [visible2, all2]);
} else {
content = formatString(dualListbox.settings.infoTextFiltered, [visible2, all2]);
}
dualListbox.elements.info2.html(content);
dualListbox.elements.box2.toggleClass('filtered', !(visible2 === all2 || all2 === 0));
}
function refreshSelects(dualListbox) {
dualListbox.selectedElements = 0;
dualListbox.elements.select1.empty();
dualListbox.elements.select2.empty();
dualListbox.element.find('option').each(function(index, item) {
var $item = $(item);
if ($item.prop('selected')) {
dualListbox.selectedElements++;
dualListbox.elements.select2.append($item.clone(true).prop('selected', $item.data('_selected')));
} else {
dualListbox.elements.select1.append($item.clone(true).prop('selected', $item.data('_selected')));
}
});
if (dualListbox.settings.showFilterInputs) {
filter(dualListbox, 1);
filter(dualListbox, 2);
}
refreshInfo(dualListbox);
}
function filter(dualListbox, selectIndex) {
if (!dualListbox.settings.showFilterInputs) {
return;
}
saveSelections(dualListbox, selectIndex);
dualListbox.elements['select'+selectIndex].empty().scrollTop(0);
var regex = new RegExp($.trim(dualListbox.elements['filterInput'+selectIndex].val()), 'gi'),
allOptions = dualListbox.element.find('option'),
options = dualListbox.element;
if (selectIndex === 1) {
options = allOptions.not(':selected');
} else {
options = options.find('option:selected');
}
options.each(function(index, item) {
var $item = $(item),
isFiltered = true;
if (item.text.match(regex) || (dualListbox.settings.filterOnValues && $item.attr('value').match(regex) ) ) {
isFiltered = false;
dualListbox.elements['select'+selectIndex].append($item.clone(true).prop('selected', $item.data('_selected')));
}
allOptions.eq($item.data('original-index')).data('filtered'+selectIndex, isFiltered);
});
refreshInfo(dualListbox);
}
function saveSelections(dualListbox, selectIndex) {
var options = dualListbox.element.find('option');
dualListbox.elements['select'+selectIndex].find('option').each(function(index, item) {
var $item = $(item);
options.eq($item.data('original-index')).data('_selected', $item.prop('selected'));
});
}
function sortOptionsByInputOrder(select){
var selectopt = select.children('option');
selectopt.sort(function(a,b){
var an = parseInt(a.getAttribute('data-sortindex')),
bn = parseInt(b.getAttribute('data-sortindex'));
if(an > bn) {
return 1;
}
if(an < bn) {
return -1;
}
return 0;
});
selectopt.detach().appendTo(select);
}
function sortOptions(select) {
select.find('option').sort(function(a, b) {
return ($(a).data('original-index') > $(b).data('original-index')) ? 1 : -1;
}).appendTo(select);
}
function clearSelections(dualListbox) {
dualListbox.elements.select1.find('option').each(function() {
dualListbox.element.find('option').data('_selected', false);
});
}
function move(dualListbox) {
if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
saveSelections(dualListbox, 2);
} else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
}
dualListbox.elements.select1.find('option:selected').each(function(index, item) {
var $item = $(item);
if (!$item.data('filtered1')) {
changeSelectionState(dualListbox, $item.data('original-index'), true);
}
});
refreshSelects(dualListbox);
triggerChangeEvent(dualListbox);
if(dualListbox.settings.sortByInputOrder){
sortOptionsByInputOrder(dualListbox.elements.select2);
} else {
sortOptions(dualListbox.elements.select2);
}
}
function remove(dualListbox) {
if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
saveSelections(dualListbox, 2);
} else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 2);
}
dualListbox.elements.select2.find('option:selected').each(function(index, item) {
var $item = $(item);
if (!$item.data('filtered2')) {
changeSelectionState(dualListbox, $item.data('original-index'), false);
}
});
refreshSelects(dualListbox);
triggerChangeEvent(dualListbox);
sortOptions(dualListbox.elements.select1);
if(dualListbox.settings.sortByInputOrder){
sortOptionsByInputOrder(dualListbox.elements.select2);
}
}
function moveAll(dualListbox) {
if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
saveSelections(dualListbox, 2);
} else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
}
dualListbox.element.find('option').each(function(index, item) {
var $item = $(item);
if (!$item.data('filtered1')) {
$item.prop('selected', true);
$item.attr('data-sortindex', dualListbox.sortIndex);
dualListbox.sortIndex++;
}
});
refreshSelects(dualListbox);
triggerChangeEvent(dualListbox);
}
function removeAll(dualListbox) {
if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 1);
saveSelections(dualListbox, 2);
} else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
saveSelections(dualListbox, 2);
}
dualListbox.element.find('option').each(function(index, item) {
var $item = $(item);
if (!$item.data('filtered2')) {
$item.prop('selected', false);
$item.removeAttr('data-sortindex');
}
});
refreshSelects(dualListbox);
triggerChangeEvent(dualListbox);
}
function bindEvents(dualListbox) {
dualListbox.elements.form.submit(function(e) {
if (dualListbox.elements.filterInput1.is(':focus')) {
e.preventDefault();
dualListbox.elements.filterInput1.focusout();
} else if (dualListbox.elements.filterInput2.is(':focus')) {
e.preventDefault();
dualListbox.elements.filterInput2.focusout();
}
});
dualListbox.element.on('bootstrapDualListbox.refresh', function(e, mustClearSelections){
dualListbox.refresh(mustClearSelections);
});
dualListbox.elements.filterClear1.on('click', function() {
dualListbox.setNonSelectedFilter('', true);
});
dualListbox.elements.filterClear2.on('click', function() {
dualListbox.setSelectedFilter('', true);
});
if (dualListbox.settings.eventMoveOverride === false) {
dualListbox.elements.moveButton.on('click', function() {
move(dualListbox);
});
}
if (dualListbox.settings.eventMoveAllOverride === false) {
dualListbox.elements.moveAllButton.on('click', function() {
moveAll(dualListbox);
});
}
if (dualListbox.settings.eventRemoveOverride === false) {
dualListbox.elements.removeButton.on('click', function() {
remove(dualListbox);
});
}
if (dualListbox.settings.eventRemoveAllOverride === false) {
dualListbox.elements.removeAllButton.on('click', function() {
removeAll(dualListbox);
});
}
dualListbox.elements.filterInput1.on('change keyup', function() {
filter(dualListbox, 1);
});
dualListbox.elements.filterInput2.on('change keyup', function() {
filter(dualListbox, 2);
});
}
BootstrapDualListbox.prototype = {
init: function () {
// Add the custom HTML template
this.container = $('' +
'<div class="bootstrap-duallistbox-container">' +
' <div class="box1">' +
' <label></label>' +
' <span class="info-container">' +
' <span class="info"></span>' +
' <button type="button" class="btn clear1 pull-right"></button>' +
' </span>' +
' <input class="filter" type="text">' +
' <div class="btn-group buttons">' +
' <button type="button" class="btn moveall">' +
' <i></i>' +
' <i></i>' +
' </button>' +
' <button type="button" class="btn move">' +
' <i></i>' +
' </button>' +
' </div>' +
' <select multiple="multiple"></select>' +
' </div>' +
' <div class="box2">' +
' <label></label>' +
' <span class="info-container">' +
' <span class="info"></span>' +
' <button type="button" class="btn clear2 pull-right"></button>' +
' </span>' +
' <input class="filter" type="text">' +
' <div class="btn-group buttons">' +
' <button type="button" class="btn remove">' +
' <i></i>' +
' </button>' +
' <button type="button" class="btn removeall">' +
' <i></i>' +
' <i></i>' +
' </button>' +
' </div>' +
' <select multiple="multiple"></select>' +
' </div>' +
'</div>')
.insertBefore(this.element);
// Cache the inner elements
this.elements = {
originalSelect: this.element,
box1: $('.box1', this.container),
box2: $('.box2', this.container),
filterInput1: $('.box1 .filter', this.container),
filterInput2: $('.box2 .filter', this.container),
filterClear1: $('.box1 .clear1', this.container),
filterClear2: $('.box2 .clear2', this.container),
label1: $('.box1 > label', this.container),
label2: $('.box2 > label', this.container),
info1: $('.box1 .info', this.container),
info2: $('.box2 .info', this.container),
select1: $('.box1 select', this.container),
select2: $('.box2 select', this.container),
moveButton: $('.box1 .move', this.container),
removeButton: $('.box2 .remove', this.container),
moveAllButton: $('.box1 .moveall', this.container),
removeAllButton: $('.box2 .removeall', this.container),
form: $($('.box1 .filter', this.container)[0].form)
};
// Set select IDs
this.originalSelectName = this.element.attr('name') || '';
var select1Id = 'bootstrap-duallistbox-nonselected-list_' + this.originalSelectName,
select2Id = 'bootstrap-duallistbox-selected-list_' + this.originalSelectName;
this.elements.select1.attr('id', select1Id);
this.elements.select2.attr('id', select2Id);
this.elements.label1.attr('for', select1Id);
this.elements.label2.attr('for', select2Id);
// Apply all settings
this.selectedElements = 0;
this.sortIndex = 0;
this.elementCount = 0;
this.setBootstrap2Compatible(this.settings.bootstrap2Compatible);
this.setFilterTextClear(this.settings.filterTextClear);
this.setFilterPlaceHolder(this.settings.filterPlaceHolder);
this.setMoveSelectedLabel(this.settings.moveSelectedLabel);
this.setMoveAllLabel(this.settings.moveAllLabel);
this.setRemoveSelectedLabel(this.settings.removeSelectedLabel);
this.setRemoveAllLabel(this.settings.removeAllLabel);
this.setMoveOnSelect(this.settings.moveOnSelect);
this.setMoveOnDoubleClick(this.settings.moveOnDoubleClick);
this.setPreserveSelectionOnMove(this.settings.preserveSelectionOnMove);
this.setSelectedListLabel(this.settings.selectedListLabel);
this.setNonSelectedListLabel(this.settings.nonSelectedListLabel);
this.setHelperSelectNamePostfix(this.settings.helperSelectNamePostfix);
this.setSelectOrMinimalHeight(this.settings.selectorMinimalHeight);
updateSelectionStates(this);
this.setShowFilterInputs(this.settings.showFilterInputs);
this.setNonSelectedFilter(this.settings.nonSelectedFilter);
this.setSelectedFilter(this.settings.selectedFilter);
this.setInfoText(this.settings.infoText);
this.setInfoTextFiltered(this.settings.infoTextFiltered);
this.setInfoTextEmpty(this.settings.infoTextEmpty);
this.setFilterOnValues(this.settings.filterOnValues);
this.setSortByInputOrder(this.settings.sortByInputOrder);
this.setEventMoveOverride(this.settings.eventMoveOverride);
this.setEventMoveAllOverride(this.settings.eventMoveAllOverride);
this.setEventRemoveOverride(this.settings.eventRemoveOverride);
this.setEventRemoveAllOverride(this.settings.eventRemoveAllOverride);
// Hide the original select
this.element.hide();
bindEvents(this);
refreshSelects(this);
return this.element;
},
setBootstrap2Compatible: function(value, refresh) {
this.settings.bootstrap2Compatible = value;
if (value) {
this.container.removeClass('row').addClass('row-fluid bs2compatible');
this.container.find('.box1, .box2').removeClass('col-md-6').addClass('span6');
this.container.find('.clear1, .clear2').removeClass('btn-white btn-xs').addClass('btn-mini');
this.container.find('input, select').removeClass('form-control');
this.container.find('.btn').removeClass('btn-white');
this.container.find('.moveall > i, .move > i').removeClass('glyphicon glyphicon-arrow-right').addClass('icon-arrow-right');
this.container.find('.removeall > i, .remove > i').removeClass('glyphicon glyphicon-arrow-left').addClass('icon-arrow-left');
} else {
this.container.removeClass('row-fluid bs2compatible').addClass('row');
this.container.find('.box1, .box2').removeClass('span6').addClass('col-md-6');
this.container.find('.clear1, .clear2').removeClass('btn-mini').addClass('btn-white btn-xs');
this.container.find('input, select').addClass('form-control');
this.container.find('.btn').addClass('btn-white');
this.container.find('.moveall > i, .move > i').removeClass('icon-arrow-right').addClass('glyphicon glyphicon-arrow-right');
this.container.find('.removeall > i, .remove > i').removeClass('icon-arrow-left').addClass('glyphicon glyphicon-arrow-left');
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setFilterTextClear: function(value, refresh) {
this.settings.filterTextClear = value;
this.elements.filterClear1.html(value);
this.elements.filterClear2.html(value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setFilterPlaceHolder: function(value, refresh) {
this.settings.filterPlaceHolder = value;
this.elements.filterInput1.attr('placeholder', value);
this.elements.filterInput2.attr('placeholder', value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setMoveSelectedLabel: function(value, refresh) {
this.settings.moveSelectedLabel = value;
this.elements.moveButton.attr('title', value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setMoveAllLabel: function(value, refresh) {
this.settings.moveAllLabel = value;
this.elements.moveAllButton.attr('title', value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setRemoveSelectedLabel: function(value, refresh) {
this.settings.removeSelectedLabel = value;
this.elements.removeButton.attr('title', value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setRemoveAllLabel: function(value, refresh) {
this.settings.removeAllLabel = value;
this.elements.removeAllButton.attr('title', value);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setMoveOnSelect: function(value, refresh) {
if (isBuggyAndroid) {
value = true;
}
this.settings.moveOnSelect = value;
if (this.settings.moveOnSelect) {
this.container.addClass('moveonselect');
var self = this;
this.elements.select1.on('change', function() {
move(self);
});
this.elements.select2.on('change', function() {
remove(self);
});
} else {
this.container.removeClass('moveonselect');
this.elements.select1.off('change');
this.elements.select2.off('change');
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setMoveOnDoubleClick: function(value, refresh) {
if (isBuggyAndroid) {
value = false;
}
this.settings.moveOnDoubleClick = value;
if (this.settings.moveOnDoubleClick) {
this.container.addClass('moveondoubleclick');
var self = this;
this.elements.select1.on('dblclick', function() {
move(self);
});
this.elements.select2.on('dblclick', function() {
remove(self);
});
} else {
this.container.removeClass('moveondoubleclick');
this.elements.select1.off('dblclick');
this.elements.select2.off('dblclick');
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setPreserveSelectionOnMove: function(value, refresh) {
// We are forcing to move on select and disabling preserveSelectionOnMove on Android
if (isBuggyAndroid) {
value = false;
}
this.settings.preserveSelectionOnMove = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setSelectedListLabel: function(value, refresh) {
this.settings.selectedListLabel = value;
if (value) {
this.elements.label2.show().html(value);
} else {
this.elements.label2.hide().html(value);
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setNonSelectedListLabel: function(value, refresh) {
this.settings.nonSelectedListLabel = value;
if (value) {
this.elements.label1.show().html(value);
} else {
this.elements.label1.hide().html(value);
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setHelperSelectNamePostfix: function(value, refresh) {
this.settings.helperSelectNamePostfix = value;
if (value) {
this.elements.select1.attr('name', this.originalSelectName + value + '1');
this.elements.select2.attr('name', this.originalSelectName + value + '2');
} else {
this.elements.select1.removeAttr('name');
this.elements.select2.removeAttr('name');
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setSelectOrMinimalHeight: function(value, refresh) {
this.settings.selectorMinimalHeight = value;
var height = this.element.height();
if (this.element.height() < value) {
height = value;
}
this.elements.select1.height(height);
this.elements.select2.height(height);
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setShowFilterInputs: function(value, refresh) {
if (!value) {
this.setNonSelectedFilter('');
this.setSelectedFilter('');
refreshSelects(this);
this.elements.filterInput1.hide();
this.elements.filterInput2.hide();
} else {
this.elements.filterInput1.show();
this.elements.filterInput2.show();
}
this.settings.showFilterInputs = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setNonSelectedFilter: function(value, refresh) {
if (this.settings.showFilterInputs) {
this.settings.nonSelectedFilter = value;
this.elements.filterInput1.val(value);
if (refresh) {
refreshSelects(this);
}
return this.element;
}
},
setSelectedFilter: function(value, refresh) {
if (this.settings.showFilterInputs) {
this.settings.selectedFilter = value;
this.elements.filterInput2.val(value);
if (refresh) {
refreshSelects(this);
}
return this.element;
}
},
setInfoText: function(value, refresh) {
this.settings.infoText = value;
if (value) {
this.elements.info1.show();
this.elements.info2.show();
} else {
this.elements.info1.hide();
this.elements.info2.hide();
}
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setInfoTextFiltered: function(value, refresh) {
this.settings.infoTextFiltered = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setInfoTextEmpty: function(value, refresh) {
this.settings.infoTextEmpty = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setFilterOnValues: function(value, refresh) {
this.settings.filterOnValues = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setSortByInputOrder: function(value, refresh){
this.settings.sortByInputOrder = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setEventMoveOverride: function(value, refresh) {
this.settings.eventMoveOverride = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setEventMoveAllOverride: function(value, refresh) {
this.settings.eventMoveAllOverride = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setEventRemoveOverride: function(value, refresh) {
this.settings.eventRemoveOverride = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
setEventRemoveAllOverride: function(value, refresh) {
this.settings.eventRemoveAllOverride = value;
if (refresh) {
refreshSelects(this);
}
return this.element;
},
getContainer: function() {
return this.container;
},
refresh: function(mustClearSelections) {
updateSelectionStates(this);
if (!mustClearSelections) {
saveSelections(this, 1);
saveSelections(this, 2);
} else {
clearSelections(this);
}
refreshSelects(this);
},
destroy: function() {
this.container.remove();
this.element.show();
$.data(this, 'plugin_' + pluginName, null);
return this.element;
}
};
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[ pluginName ] = function (options) {
var args = arguments;
// Is the first parameter an object (options), or was omitted, instantiate a new instance of the plugin.
if (options === undefined || typeof options === 'object') {
return this.each(function () {
// If this is not a select
if (!$(this).is('select')) {
$(this).find('select').each(function(index, item) {
// For each nested select, instantiate the Dual List Box
$(item).bootstrapDualListbox(options);
});
} else if (!$.data(this, 'plugin_' + pluginName)) {
// Only allow the plugin to be instantiated once so we check that the element has no plugin instantiation yet
// if it has no instance, create a new one, pass options to our plugin constructor,
// and store the plugin instance in the elements jQuery data object.
$.data(this, 'plugin_' + pluginName, new BootstrapDualListbox(this, options));
}
});
// If the first parameter is a string and it doesn't start with an underscore or "contains" the `init`-function,
// treat this as a call to a public method.
} else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
// Cache the method call to make it possible to return a value
var returns;
this.each(function () {
var instance = $.data(this, 'plugin_' + pluginName);
// Tests that there's already a plugin-instance and checks that the requested public method exists
if (instance instanceof BootstrapDualListbox && typeof instance[options] === 'function') {
// Call the method of our plugin instance, and pass it the supplied arguments.
returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
}
});
// If the earlier cached method gives a value back return the value,
// otherwise return this to preserve chainability.
return returns !== undefined ? returns : this;
}
};
})(jQuery, window, document);

View File

@ -0,0 +1 @@
.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%}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,315 @@
/* The MIT License
Copyright (c) 2011 by Michael Zinsmaier and nergal.dev
Copyright (c) 2012 by Thomas Ritou
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.
*/
/*
____________________________________________________
what it is:
____________________________________________________
curvedLines is a plugin for flot, that tries to display lines in a smoother way.
The plugin is based on nergal.dev's work https://code.google.com/p/flot/issues/detail?id=226
and further extended with a mode that forces the min/max points of the curves to be on the
points. Both modes are achieved through adding of more data points
=> 1) with large data sets you may get trouble
=> 2) if you want to display the points too, you have to plot them as 2nd data series over the lines
&& 3) consecutive x data points are not allowed to have the same value
This is version 0.5 of curvedLines so it will probably not work in every case. However
the basic form of use descirbed next works (:
Feel free to further improve the code
____________________________________________________
how to use it:
____________________________________________________
var d1 = [[5,5],[7,3],[9,12]];
var options = { series: { curvedLines: { active: true }}};
$.plot($("#placeholder"), [{data = d1, lines: { show: true}, curvedLines: {apply: true}}], options);
_____________________________________________________
options:
_____________________________________________________
active: bool true => plugin can be used
apply: bool true => series will be drawn as curved line
fit: bool true => forces the max,mins of the curve to be on the datapoints
curvePointFactor int defines how many "virtual" points are used per "real" data point to
emulate the curvedLines (points total = real points * curvePointFactor)
fitPointDist: int defines the x axis distance of the additional two points that are used
to enforce the min max condition.
+ line options (since v0.5 curved lines use flots line implementation for drawing
=> line options like fill, show ... are supported out of the box)
*/
/*
* v0.1 initial commit
* v0.15 negative values should work now (outcommented a negative -> 0 hook hope it does no harm)
* v0.2 added fill option (thanks to monemihir) and multi axis support (thanks to soewono effendi)
* v0.3 improved saddle handling and added basic handling of Dates
* v0.4 rewritten fill option (thomas ritou) mostly from original flot code (now fill between points rather than to graph bottom), corrected fill Opacity bug
* v0.5 rewritten instead of implementing a own draw function CurvedLines is now based on the processDatapoints flot hook (credits go to thomas ritou).
* This change breakes existing code however CurvedLines are now just many tiny straight lines to flot and therefore all flot lines options (like gradient fill,
* shadow) are now supported out of the box
* v0.6 flot 0.8 compatibility and some bug fixes
*/
(function($) {
var options = {
series : {
curvedLines : {
active : false,
apply: false,
fit : false,
curvePointFactor : 20,
fitPointDist : undefined
}
}
};
function init(plot) {
plot.hooks.processOptions.push(processOptions);
//if the plugin is active register processDatapoints method
function processOptions(plot, options) {
if (options.series.curvedLines.active) {
plot.hooks.processDatapoints.unshift(processDatapoints);
}
}
//only if the plugin is active
function processDatapoints(plot, series, datapoints) {
var nrPoints = datapoints.points.length / datapoints.pointsize;
var EPSILON = 0.5; //pretty large epsilon but save
if (series.curvedLines.apply == true && series.originSeries === undefined && nrPoints > (1 + EPSILON)) {
if (series.lines.fill) {
var pointsTop = calculateCurvePoints(datapoints, series.curvedLines, 1)
,pointsBottom = calculateCurvePoints(datapoints, series.curvedLines, 2); //flot makes sure for us that we've got a second y point if fill is true !
//Merge top and bottom curve
datapoints.pointsize = 3;
datapoints.points = [];
var j = 0;
var k = 0;
var i = 0;
var ps = 2;
while (i < pointsTop.length || j < pointsBottom.length) {
if (pointsTop[i] == pointsBottom[j]) {
datapoints.points[k] = pointsTop[i];
datapoints.points[k + 1] = pointsTop[i + 1];
datapoints.points[k + 2] = pointsBottom[j + 1];
j += ps;
i += ps;
} else if (pointsTop[i] < pointsBottom[j]) {
datapoints.points[k] = pointsTop[i];
datapoints.points[k + 1] = pointsTop[i + 1];
datapoints.points[k + 2] = k > 0 ? datapoints.points[k-1] : null;
i += ps;
} else {
datapoints.points[k] = pointsBottom[j];
datapoints.points[k + 1] = k > 1 ? datapoints.points[k-2] : null;
datapoints.points[k + 2] = pointsBottom[j + 1];
j += ps;
}
k += 3;
}
} else if (series.lines.lineWidth > 0) {
datapoints.points = calculateCurvePoints(datapoints, series.curvedLines, 1);
datapoints.pointsize = 2;
}
}
}
//no real idea whats going on here code mainly from https://code.google.com/p/flot/issues/detail?id=226
//if fit option is selected additional datapoints get inserted before the curve calculations in nergal.dev s code.
function calculateCurvePoints(datapoints, curvedLinesOptions, yPos) {
var points = datapoints.points, ps = datapoints.pointsize;
var num = curvedLinesOptions.curvePointFactor * (points.length / ps);
var xdata = new Array;
var ydata = new Array;
var curX = -1;
var curY = -1;
var j = 0;
if (curvedLinesOptions.fit) {
//insert a point before and after the "real" data point to force the line
//to have a max,min at the data point.
var fpDist;
if(typeof curvedLinesOptions.fitPointDist == 'undefined') {
//estimate it
var minX = points[0];
var maxX = points[points.length-ps];
fpDist = (maxX - minX) / (500 * 100); //x range / (estimated pixel length of placeholder * factor)
} else {
//use user defined value
fpDist = curvedLinesOptions.fitPointDist;
}
for (var i = 0; i < points.length; i += ps) {
var frontX;
var backX;
curX = i;
curY = i + yPos;
//add point X s
frontX = points[curX] - fpDist;
backX = points[curX] + fpDist;
var factor = 2;
while (frontX == points[curX] || backX == points[curX]) {
//inside the ulp
frontX = points[curX] - (fpDist * factor);
backX = points[curX] + (fpDist * factor);
factor++;
}
//add curve points
xdata[j] = frontX;
ydata[j] = points[curY];
j++;
xdata[j] = points[curX];
ydata[j] = points[curY];
j++;
xdata[j] = backX;
ydata[j] = points[curY];
j++;
}
} else {
//just use the datapoints
for (var i = 0; i < points.length; i += ps) {
curX = i;
curY = i + yPos;
xdata[j] = points[curX];
ydata[j] = points[curY];
j++;
}
}
var n = xdata.length;
var y2 = new Array();
var delta = new Array();
y2[0] = 0;
y2[n - 1] = 0;
delta[0] = 0;
for (var i = 1; i < n - 1; ++i) {
var d = (xdata[i + 1] - xdata[i - 1]);
if (d == 0) {
//point before current point and after current point need some space in between
return [];
}
var s = (xdata[i] - xdata[i - 1]) / d;
var p = s * y2[i - 1] + 2;
y2[i] = (s - 1) / p;
delta[i] = (ydata[i + 1] - ydata[i]) / (xdata[i + 1] - xdata[i]) - (ydata[i] - ydata[i - 1]) / (xdata[i] - xdata[i - 1]);
delta[i] = (6 * delta[i] / (xdata[i + 1] - xdata[i - 1]) - s * delta[i - 1]) / p;
}
for (var j = n - 2; j >= 0; --j) {
y2[j] = y2[j] * y2[j + 1] + delta[j];
}
// xmax - xmin / #points
var step = (xdata[n - 1] - xdata[0]) / (num - 1);
var xnew = new Array;
var ynew = new Array;
var result = new Array;
xnew[0] = xdata[0];
ynew[0] = ydata[0];
result.push(xnew[0]);
result.push(ynew[0]);
for ( j = 1; j < num; ++j) {
//new x point (sampling point for the created curve)
xnew[j] = xnew[0] + j * step;
var max = n - 1;
var min = 0;
while (max - min > 1) {
var k = Math.round((max + min) / 2);
if (xdata[k] > xnew[j]) {
max = k;
} else {
min = k;
}
}
//found point one to the left and one to the right of generated new point
var h = (xdata[max] - xdata[min]);
if (h == 0) {
//similar to above two points from original x data need some space between them
return [];
}
var a = (xdata[max] - xnew[j]) / h;
var b = (xnew[j] - xdata[min]) / h;
ynew[j] = a * ydata[min] + b * ydata[max] + ((a * a * a - a) * y2[min] + (b * b * b - b) * y2[max]) * (h * h) / 6;
result.push(xnew[j]);
result.push(ynew[j]);
}
return result;
}
}//end init
$.plot.plugins.push({
init : init,
options : options,
name : 'curvedLines',
version : '0.5'
});
})(jQuery);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,750 @@
/*
Flot plugin for rendering pie charts. The plugin assumes the data is
coming is as a single data value for each series, and each of those
values is a positive value or zero (negative numbers don't make
any sense and will cause strange effects). The data values do
NOT need to be passed in as percentage values because it
internally calculates the total and percentages.
* Created by Brian Medendorp, June 2009
* Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars
* Changes:
2009-10-22: lineJoin set to round
2009-10-23: IE full circle fix, donut
2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera
2009-11-17: Added IE hover capability submitted by Anthony Aragues
2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well)
Available options are:
series: {
pie: {
show: true/false
radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
offset: {
top: integer value to move the pie up or down
left: integer value to move the pie left or right, or 'auto'
},
stroke: {
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
width: integer pixel width of the stroke
},
label: {
show: true/false, or 'auto'
formatter: a user-defined function that modifies the text/style of the label text
radius: 0-1 for percentage of fullsize, or a specified pixel length
background: {
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
opacity: 0-1
},
threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
},
combine: {
threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
label: any text value of what the combined slice should be labeled
}
highlight: {
opacity: 0-1
}
}
}
More detail and specific examples can be found in the included HTML file.
*/
(function ($)
{
function init(plot) // this is the "body" of the plugin
{
var canvas = null;
var target = null;
var maxRadius = null;
var centerLeft = null;
var centerTop = null;
var total = 0;
var redraw = true;
var redrawAttempts = 10;
var shrink = 0.95;
var legendWidth = 0;
var processed = false;
var raw = false;
// interactive variables
var highlights = [];
// add hook to determine if pie plugin in enabled, and then perform necessary operations
plot.hooks.processOptions.push(checkPieEnabled);
plot.hooks.bindEvents.push(bindEvents);
// check to see if the pie plugin is enabled
function checkPieEnabled(plot, options)
{
if (options.series.pie.show)
{
//disable grid
options.grid.show = false;
// set labels.show
if (options.series.pie.label.show=='auto')
if (options.legend.show)
options.series.pie.label.show = false;
else
options.series.pie.label.show = true;
// set radius
if (options.series.pie.radius=='auto')
if (options.series.pie.label.show)
options.series.pie.radius = 3/4;
else
options.series.pie.radius = 1;
// ensure sane tilt
if (options.series.pie.tilt>1)
options.series.pie.tilt=1;
if (options.series.pie.tilt<0)
options.series.pie.tilt=0;
// add processData hook to do transformations on the data
plot.hooks.processDatapoints.push(processDatapoints);
plot.hooks.drawOverlay.push(drawOverlay);
// add draw hook
plot.hooks.draw.push(draw);
}
}
// bind hoverable events
function bindEvents(plot, eventHolder)
{
var options = plot.getOptions();
if (options.series.pie.show && options.grid.hoverable)
eventHolder.unbind('mousemove').mousemove(onMouseMove);
if (options.series.pie.show && options.grid.clickable)
eventHolder.unbind('click').click(onClick);
}
// debugging function that prints out an object
function alertObject(obj)
{
var msg = '';
function traverse(obj, depth)
{
if (!depth)
depth = 0;
for (var i = 0; i < obj.length; ++i)
{
for (var j=0; j<depth; j++)
msg += '\t';
if( typeof obj[i] == "object")
{ // its an object
msg += ''+i+':\n';
traverse(obj[i], depth+1);
}
else
{ // its a value
msg += ''+i+': '+obj[i]+'\n';
}
}
}
traverse(obj);
alert(msg);
}
function calcTotal(data)
{
for (var i = 0; i < data.length; ++i)
{
var item = parseFloat(data[i].data[0][1]);
if (item)
total += item;
}
}
function processDatapoints(plot, series, data, datapoints)
{
if (!processed)
{
processed = true;
canvas = plot.getCanvas();
target = $(canvas).parent();
options = plot.getOptions();
plot.setData(combine(plot.getData()));
}
}
function setupPie()
{
legendWidth = target.children().filter('.legend').children().width();
// calculate maximum radius and center point
maxRadius = Math.min(canvas.width,(canvas.height/options.series.pie.tilt))/2;
centerTop = (canvas.height/2)+options.series.pie.offset.top;
centerLeft = (canvas.width/2);
if (options.series.pie.offset.left=='auto')
if (options.legend.position.match('w'))
centerLeft += legendWidth/2;
else
centerLeft -= legendWidth/2;
else
centerLeft += options.series.pie.offset.left;
if (centerLeft<maxRadius)
centerLeft = maxRadius;
else if (centerLeft>canvas.width-maxRadius)
centerLeft = canvas.width-maxRadius;
}
function fixData(data)
{
for (var i = 0; i < data.length; ++i)
{
if (typeof(data[i].data)=='number')
data[i].data = [[1,data[i].data]];
else if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')
{
if (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')
data[i].label = data[i].data.label; // fix weirdness coming from flot
data[i].data = [[1,0]];
}
}
return data;
}
function combine(data)
{
data = fixData(data);
calcTotal(data);
var combined = 0;
var numCombined = 0;
var color = options.series.pie.combine.color;
var newdata = [];
for (var i = 0; i < data.length; ++i)
{
// make sure its a number
data[i].data[0][1] = parseFloat(data[i].data[0][1]);
if (!data[i].data[0][1])
data[i].data[0][1] = 0;
if (data[i].data[0][1]/total<=options.series.pie.combine.threshold)
{
combined += data[i].data[0][1];
numCombined++;
if (!color)
color = data[i].color;
}
else
{
newdata.push({
data: [[1,data[i].data[0][1]]],
color: data[i].color,
label: data[i].label,
angle: (data[i].data[0][1]*(Math.PI*2))/total,
percent: (data[i].data[0][1]/total*100)
});
}
}
if (numCombined>0)
newdata.push({
data: [[1,combined]],
color: color,
label: options.series.pie.combine.label,
angle: (combined*(Math.PI*2))/total,
percent: (combined/total*100)
});
return newdata;
}
function draw(plot, newCtx)
{
if (!target) return; // if no series were passed
ctx = newCtx;
setupPie();
var slices = plot.getData();
var attempts = 0;
while (redraw && attempts<redrawAttempts)
{
redraw = false;
if (attempts>0)
maxRadius *= shrink;
attempts += 1;
clear();
if (options.series.pie.tilt<=0.8)
drawShadow();
drawPie();
}
if (attempts >= redrawAttempts) {
clear();
target.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>');
}
if ( plot.setSeries && plot.insertLegend )
{
plot.setSeries(slices);
plot.insertLegend();
}
// we're actually done at this point, just defining internal functions at this point
function clear()
{
ctx.clearRect(0,0,canvas.width,canvas.height);
target.children().filter('.pieLabel, .pieLabelBackground').remove();
}
function drawShadow()
{
var shadowLeft = 5;
var shadowTop = 15;
var edge = 10;
var alpha = 0.02;
// set radius
if (options.series.pie.radius>1)
var radius = options.series.pie.radius;
else
var radius = maxRadius * options.series.pie.radius;
if (radius>=(canvas.width/2)-shadowLeft || radius*options.series.pie.tilt>=(canvas.height/2)-shadowTop || radius<=edge)
return; // shadow would be outside canvas, so don't draw it
ctx.save();
ctx.translate(shadowLeft,shadowTop);
ctx.globalAlpha = alpha;
ctx.fillStyle = '#000';
// center and rotate to starting position
ctx.translate(centerLeft,centerTop);
ctx.scale(1, options.series.pie.tilt);
//radius -= edge;
for (var i=1; i<=edge; i++)
{
ctx.beginPath();
ctx.arc(0,0,radius,0,Math.PI*2,false);
ctx.fill();
radius -= i;
}
ctx.restore();
}
function drawPie()
{
startAngle = Math.PI*options.series.pie.startAngle;
// set radius
if (options.series.pie.radius>1)
var radius = options.series.pie.radius;
else
var radius = maxRadius * options.series.pie.radius;
// center and rotate to starting position
ctx.save();
ctx.translate(centerLeft,centerTop);
ctx.scale(1, options.series.pie.tilt);
//ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
// draw slices
ctx.save();
var currentAngle = startAngle;
for (var i = 0; i < slices.length; ++i)
{
slices[i].startAngle = currentAngle;
drawSlice(slices[i].angle, slices[i].color, true);
}
ctx.restore();
// draw slice outlines
ctx.save();
ctx.lineWidth = options.series.pie.stroke.width;
currentAngle = startAngle;
for (var i = 0; i < slices.length; ++i)
drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
ctx.restore();
// draw donut hole
drawDonutHole(ctx);
// draw labels
if (options.series.pie.label.show)
drawLabels();
// restore to original state
ctx.restore();
function drawSlice(angle, color, fill)
{
if (angle<=0)
return;
if (fill)
ctx.fillStyle = color;
else
{
ctx.strokeStyle = color;
ctx.lineJoin = 'round';
}
ctx.beginPath();
if (Math.abs(angle - Math.PI*2) > 0.000000001)
ctx.moveTo(0,0); // Center of the pie
else if ($.browser.msie)
angle -= 0.0001;
//ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera
ctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);
ctx.closePath();
//ctx.rotate(angle); // This doesn't work properly in Opera
currentAngle += angle;
if (fill)
ctx.fill();
else
ctx.stroke();
}
function drawLabels()
{
var currentAngle = startAngle;
// set radius
if (options.series.pie.label.radius>1)
var radius = options.series.pie.label.radius;
else
var radius = maxRadius * options.series.pie.label.radius;
for (var i = 0; i < slices.length; ++i)
{
if (slices[i].percent >= options.series.pie.label.threshold*100)
drawLabel(slices[i], currentAngle, i);
currentAngle += slices[i].angle;
}
function drawLabel(slice, startAngle, index)
{
if (slice.data[0][1]==0)
return;
// format label text
var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;
if (lf)
text = lf(slice.label, slice);
else
text = slice.label;
if (plf)
text = plf(text, slice);
var halfAngle = ((startAngle+slice.angle) + startAngle)/2;
var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
var html = '<span class="pieLabel" id="pieLabel'+index+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px;">' + text + "</span>";
target.append(html);
var label = target.children('#pieLabel'+index);
var labelTop = (y - label.height()/2);
var labelLeft = (x - label.width()/2);
label.css('top', labelTop);
label.css('left', labelLeft);
// check to make sure that the label is not outside the canvas
if (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0)
redraw = true;
if (options.series.pie.label.background.opacity != 0) {
// put in the transparent background separately to avoid blended labels and label boxes
var c = options.series.pie.label.background.color;
if (c == null) {
c = slice.color;
}
var pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';
$('<div class="pieLabelBackground" style="position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').insertBefore(label).css('opacity', options.series.pie.label.background.opacity);
}
} // end individual label function
} // end drawLabels function
} // end drawPie function
} // end draw function
// Placed here because it needs to be accessed from multiple locations
function drawDonutHole(layer)
{
// draw donut hole
if(options.series.pie.innerRadius > 0)
{
// subtract the center
layer.save();
innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
layer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color
layer.beginPath();
layer.fillStyle = options.series.pie.stroke.color;
layer.arc(0,0,innerRadius,0,Math.PI*2,false);
layer.fill();
layer.closePath();
layer.restore();
// add inner stroke
layer.save();
layer.beginPath();
layer.strokeStyle = options.series.pie.stroke.color;
layer.arc(0,0,innerRadius,0,Math.PI*2,false);
layer.stroke();
layer.closePath();
layer.restore();
// TODO: add extra shadow inside hole (with a mask) if the pie is tilted.
}
}
//-- Additional Interactive related functions --
function isPointInPoly(poly, pt)
{
for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
&& (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
&& (c = !c);
return c;
}
function findNearbySlice(mouseX, mouseY)
{
var slices = plot.getData(),
options = plot.getOptions(),
radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
for (var i = 0; i < slices.length; ++i)
{
var s = slices[i];
if(s.pie.show)
{
ctx.save();
ctx.beginPath();
ctx.moveTo(0,0); // Center of the pie
//ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here.
ctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false);
ctx.closePath();
x = mouseX-centerLeft;
y = mouseY-centerTop;
if(ctx.isPointInPath)
{
if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop))
{
//alert('found slice!');
ctx.restore();
return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
}
}
else
{
// excanvas for IE doesn;t support isPointInPath, this is a workaround.
p1X = (radius * Math.cos(s.startAngle));
p1Y = (radius * Math.sin(s.startAngle));
p2X = (radius * Math.cos(s.startAngle+(s.angle/4)));
p2Y = (radius * Math.sin(s.startAngle+(s.angle/4)));
p3X = (radius * Math.cos(s.startAngle+(s.angle/2)));
p3Y = (radius * Math.sin(s.startAngle+(s.angle/2)));
p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5)));
p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5)));
p5X = (radius * Math.cos(s.startAngle+s.angle));
p5Y = (radius * Math.sin(s.startAngle+s.angle));
arrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];
arrPoint = [x,y];
// TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?
if(isPointInPoly(arrPoly, arrPoint))
{
ctx.restore();
return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
}
}
ctx.restore();
}
}
return null;
}
function onMouseMove(e)
{
triggerClickHoverEvent('plothover', e);
}
function onClick(e)
{
triggerClickHoverEvent('plotclick', e);
}
// trigger click or hover event (they send the same parameters so we share their code)
function triggerClickHoverEvent(eventname, e)
{
var offset = plot.offset(),
canvasX = parseInt(e.pageX - offset.left),
canvasY = parseInt(e.pageY - offset.top),
item = findNearbySlice(canvasX, canvasY);
if (options.grid.autoHighlight)
{
// clear auto-highlights
for (var i = 0; i < highlights.length; ++i)
{
var h = highlights[i];
if (h.auto == eventname && !(item && h.series == item.series))
unhighlight(h.series);
}
}
// highlight the slice
if (item)
highlight(item.series, eventname);
// trigger any hover bind events
var pos = { pageX: e.pageX, pageY: e.pageY };
target.trigger(eventname, [ pos, item ]);
}
function highlight(s, auto)
{
if (typeof s == "number")
s = series[s];
var i = indexOfHighlight(s);
if (i == -1)
{
highlights.push({ series: s, auto: auto });
plot.triggerRedrawOverlay();
}
else if (!auto)
highlights[i].auto = false;
}
function unhighlight(s)
{
if (s == null)
{
highlights = [];
plot.triggerRedrawOverlay();
}
if (typeof s == "number")
s = series[s];
var i = indexOfHighlight(s);
if (i != -1)
{
highlights.splice(i, 1);
plot.triggerRedrawOverlay();
}
}
function indexOfHighlight(s)
{
for (var i = 0; i < highlights.length; ++i)
{
var h = highlights[i];
if (h.series == s)
return i;
}
return -1;
}
function drawOverlay(plot, octx)
{
//alert(options.series.pie.radius);
var options = plot.getOptions();
//alert(options.series.pie.radius);
var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
octx.save();
octx.translate(centerLeft, centerTop);
octx.scale(1, options.series.pie.tilt);
for (i = 0; i < highlights.length; ++i)
drawHighlight(highlights[i].series);
drawDonutHole(octx);
octx.restore();
function drawHighlight(series)
{
if (series.angle < 0) return;
//octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();
octx.fillStyle = "rgba(255, 255, 255, "+options.series.pie.highlight.opacity+")"; // this is temporary until we have access to parseColor
octx.beginPath();
if (Math.abs(series.angle - Math.PI*2) > 0.000000001)
octx.moveTo(0,0); // Center of the pie
octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);
octx.closePath();
octx.fill();
}
}
} // end init (plugin body)
// define pie specific options and their default values
var options = {
series: {
pie: {
show: false,
radius: 'auto', // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)
innerRadius:0, /* for donut */
startAngle: 3/2,
tilt: 1,
offset: {
top: 0,
left: 'auto'
},
stroke: {
color: '#FFF',
width: 1
},
label: {
show: 'auto',
formatter: function(label, slice){
return '<div style="font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';">'+label+'<br/>'+Math.round(slice.percent)+'%</div>';
}, // formatter function
radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
background: {
color: null,
opacity: 0
},
threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow)
},
combine: {
threshold: -1, // percentage at which to combine little slices into one larger slice
color: null, // color to give the new slice (auto-generated if null)
label: 'Other' // label to give the new slice
},
highlight: {
//color: '#FFF', // will add this functionality once parseColor is available
opacity: 0.5
}
}
}
};
$.plot.plugins.push({
init: init,
options: options,
name: "pie",
version: "1.0"
});
})(jQuery);

Some files were not shown because too many files have changed in this diff Show More