瀏覽代碼

基于xxl-job点评内部定制版本

xueli.xue 9 年之前
父節點
當前提交
e7ff48304e
共有 100 個文件被更改,包括 20643 次插入0 次删除
  1. 11 0
      branch-dianping/dianping-job/README.md
  2. 87 0
      branch-dianping/dianping-job/dianping-job-client-demo/pom.xml
  3. 38 0
      branch-dianping/dianping-job/dianping-job-client-demo/src/main/java/com/dianping/job/service/handler/DemoJobHandler.java
  4. 15 0
      branch-dianping/dianping-job/dianping-job-client-demo/src/main/resources/applicationcontext-base.xml
  5. 10 0
      branch-dianping/dianping-job/dianping-job-client-demo/src/main/resources/log4j.properties
  6. 35 0
      branch-dianping/dianping-job/dianping-job-client-demo/src/main/webapp/WEB-INF/web.xml
  7. 1 0
      branch-dianping/dianping-job/dianping-job-client-demo/src/main/webapp/index.html
  8. 83 0
      branch-dianping/dianping-job/dianping-job-client/pom.xml
  9. 140 0
      branch-dianping/dianping-job/dianping-job-client/src/main/java/com/dianping/job/client/handler/HandlerRepository.java
  10. 46 0
      branch-dianping/dianping-job/dianping-job-client/src/main/java/com/dianping/job/client/handler/IJobHandler.java
  11. 61 0
      branch-dianping/dianping-job/dianping-job-client/src/main/java/com/dianping/job/client/netcom/http/DianpingJobServlet.java
  12. 59 0
      branch-dianping/dianping-job/dianping-job-client/src/main/java/com/dianping/job/client/util/HttpUtil.java
  13. 174 0
      branch-dianping/dianping-job/dianping-job-web/pom.xml
  14. 180 0
      branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/controller/IndexController.java
  15. 79 0
      branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/core/model/DianpingJobLog.java
  16. 50 0
      branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/core/model/ReturnT.java
  17. 199 0
      branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/core/util/DynamicSchedulerUtil.java
  18. 11 0
      branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/service/ITriggerService.java
  19. 21 0
      branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/service/impl/TriggerServiceImpl.java
  20. 137 0
      branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/service/job/HttpJobBean.java
  21. 33 0
      branch-dianping/dianping-job/dianping-job-web/src/main/resources/applicationcontext-base.xml
  22. 42 0
      branch-dianping/dianping-job/dianping-job-web/src/main/resources/applicationcontext-database.xml
  23. 25 0
      branch-dianping/dianping-job/dianping-job-web/src/main/resources/applicationcontext-trigger-db.xml
  24. 32 0
      branch-dianping/dianping-job/dianping-job-web/src/main/resources/applicationcontext-trigger-local.xml
  25. 38 0
      branch-dianping/dianping-job/dianping-job-web/src/main/resources/applicationcontext-tx.xml
  26. 10 0
      branch-dianping/dianping-job/dianping-job-web/src/main/resources/freemarker.properties
  27. 4 0
      branch-dianping/dianping-job/dianping-job-web/src/main/resources/jdbc.properties
  28. 10 0
      branch-dianping/dianping-job/dianping-job-web/src/main/resources/log4j.properties
  29. 25 0
      branch-dianping/dianping-job/dianping-job-web/src/main/resources/quartz.properties
  30. 52 0
      branch-dianping/dianping-job/dianping-job-web/src/main/resources/springmvc-context.xml
  31. 1 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/500.html
  32. 39 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/template/common/common.exception.ftl
  33. 240 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/template/common/common.macro.ftl
  34. 1 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/template/common/common.result.ftl
  35. 76 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/template/job/help.ftl
  36. 195 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/template/job/index.ftl
  37. 63 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/web.xml
  38. 1 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/css/bootstrap.css.map
  39. 5 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/css/bootstrap.min.css
  40. 二進制
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/fonts/glyphicons-halflings-regular.eot
  41. 288 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/fonts/glyphicons-halflings-regular.svg
  42. 二進制
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/fonts/glyphicons-halflings-regular.ttf
  43. 二進制
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/fonts/glyphicons-halflings-regular.woff
  44. 二進制
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/fonts/glyphicons-halflings-regular.woff2
  45. 7 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/js/bootstrap.min.js
  46. 7 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/dist/css/AdminLTE.min.css
  47. 1 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/dist/css/skins/_all-skins.min.css
  48. 13 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/dist/js/app.min.js
  49. 210 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/dist/js/pages/dashboard.js
  50. 274 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/dist/js/pages/dashboard2.js
  51. 372 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/dataTables.bootstrap.css
  52. 206 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/dataTables.bootstrap.js
  53. 8 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/dataTables.bootstrap.min.js
  54. 二進制
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/images/sort_asc.png
  55. 二進制
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/images/sort_asc_disabled.png
  56. 二進制
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/images/sort_both.png
  57. 二進制
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/images/sort_desc.png
  58. 二進制
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/images/sort_desc_disabled.png
  59. 455 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/jquery.dataTables.css
  60. 14951 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/jquery.dataTables.js
  61. 1 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/jquery.dataTables.min.css
  62. 160 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/jquery.dataTables.min.js
  63. 416 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/jquery.dataTables_themeroller.css
  64. 841 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/fastclick/fastclick.js
  65. 1 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/fastclick/fastclick.min.js
  66. 4 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/jQuery/jQuery-2.1.4.min.js
  67. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/az.js
  68. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/bg.js
  69. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/ca.js
  70. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/cs.js
  71. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/da.js
  72. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/de.js
  73. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/en.js
  74. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/es.js
  75. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/et.js
  76. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/eu.js
  77. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/fa.js
  78. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/fi.js
  79. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/fr.js
  80. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/gl.js
  81. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/he.js
  82. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/hi.js
  83. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/hr.js
  84. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/hu.js
  85. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/id.js
  86. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/is.js
  87. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/it.js
  88. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/ko.js
  89. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/lt.js
  90. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/lv.js
  91. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/mk.js
  92. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/nb.js
  93. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/nl.js
  94. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/pl.js
  95. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/pt-BR.js
  96. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/pt.js
  97. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/ro.js
  98. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/ru.js
  99. 3 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/sk.js
  100. 0 0
      branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/sr.js

+ 11 - 0
branch-dianping/dianping-job/README.md

@@ -0,0 +1,11 @@
+## dianping-job[任务调度平台]
+	
+	分层: 调度和任务拆分, 支持动态扩充, 管理任务
+		1. 调度模块:dianping-job-web, 维护任务的调度信息,负责定时/周期性的发出调度请求.
+		2. 任务模块:dianping-job-client, 具体的任务逻辑,负责接收调度模块的调度请求,执行任务逻辑.
+		3. 通讯模块:dianping-job-client, 负责调度模块和任务模块之间的通讯.
+		
+	说明:
+		1. 调度模块集群部署[HA].
+		2. 任务串行执行.
+		3. 记录调度日系.

+ 87 - 0
branch-dianping/dianping-job/dianping-job-client-demo/pom.xml

@@ -0,0 +1,87 @@
+<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>
+	<parent>
+		<groupId>com.dianping</groupId>
+		<artifactId>dianping-job</artifactId>
+		<version>0.0.1-SNAPSHOT</version>
+	</parent>
+	<artifactId>dianping-job-client-demo</artifactId>
+	<packaging>war</packaging>
+	<name>dianping-job-client-demo</name>
+	<url>http://maven.apache.org</url>
+
+	<properties>
+		<spring.version>3.2.14.RELEASE</spring.version>
+	</properties>
+
+	<dependencies>
+		<!-- springframe start -->
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-webmvc</artifactId>
+			<version>${spring.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-context-support</artifactId>
+			<version>${spring.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-orm</artifactId>
+			<version>${spring.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-test</artifactId>
+			<version>${spring.version}</version>
+		</dependency>
+		<!-- springframe end -->
+		<!-- aspectjweaver (support spring aop) -->
+		<dependency>
+			<groupId>org.aspectj</groupId>
+			<artifactId>aspectjweaver</artifactId>
+			<version>1.8.7</version>
+		</dependency>
+		
+		<!-- slf4j -->
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-log4j12</artifactId>
+			<version>1.7.5</version>
+		</dependency>
+		
+		<!-- dianping-job-client -->
+		<dependency>
+			<groupId>com.dianping</groupId>
+			<artifactId>dianping-job-client</artifactId>
+			<version>1.0.1-SNAPSHOT</version>
+		</dependency>
+		
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.1</version>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+					<encoding>UTF8</encoding>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-war-plugin</artifactId>
+				<version>2.2</version>
+				<configuration>
+					<archiveClasses>true</archiveClasses>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+</project>

+ 38 - 0
branch-dianping/dianping-job/dianping-job-client-demo/src/main/java/com/dianping/job/service/handler/DemoJobHandler.java

@@ -0,0 +1,38 @@
+package com.dianping.job.service.handler;
+
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import com.dianping.job.client.handler.HandlerRepository;
+import com.dianping.job.client.handler.IJobHandler;
+
+/**
+ * demo job handler
+ * @author xuxueli 2015-12-19 19:43:36
+ */
+@Service
+public class DemoJobHandler extends IJobHandler {
+	private static transient Logger logger = LoggerFactory.getLogger(DemoJobHandler.class);
+	
+	public DemoJobHandler() {
+		HandlerRepository.regist(DemoJobHandler.class.getName(), this);
+	}
+	
+	@Override
+	public JobHandleStatus handle(Map<String, String> param) throws Exception {
+		logger.info(" ... param:{}", param);
+		TimeUnit.SECONDS.sleep(new Random().nextInt(5));
+		return JobHandleStatus.SUCCESS;
+	}
+	
+	public static void main(String[] args) {
+		System.out.println(DemoJobHandler.class.getName());
+		System.out.println(DemoJobHandler.class);
+	}
+	
+}

+ 15 - 0
branch-dianping/dianping-job/dianping-job-client-demo/src/main/resources/applicationcontext-base.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+           http://www.springframework.org/schema/context
+           http://www.springframework.org/schema/context/spring-context-3.0.xsd
+           http://www.springframework.org/schema/util 
+           http://www.springframework.org/schema/util/spring-util.xsd">
+
+	<context:annotation-config />
+	<context:component-scan base-package="com.dianping.job.service" />
+
+</beans>

+ 10 - 0
branch-dianping/dianping-job/dianping-job-client-demo/src/main/resources/log4j.properties

@@ -0,0 +1,10 @@
+log4j.rootLogger=info,console
+
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d - dianping-job-client-demo - %p [%c] - <%m>%n
+
+log4j.appender.logFile=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.logFile.File=${catalina.base}/logs/dianping-job-client-demo.log
+log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
+log4j.appender.logFile.layout.ConversionPattern=%d - dianping-job-client-demo - %p [%c] - <%m>%n

+ 35 - 0
branch-dianping/dianping-job/dianping-job-client-demo/src/main/webapp/WEB-INF/web.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+	id="WebApp_ID" version="2.5">
+
+	<context-param>
+		<param-name>contextConfigLocation</param-name>
+		<param-value>classpath*:applicationcontext-*.xml</param-value>
+	</context-param>
+
+	<listener>
+		<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
+	</listener>
+	<listener>
+		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+	</listener>
+	
+	<!-- Dianping Job Servlet -->
+	<servlet>
+		<servlet-name>DianpingJobServlet</servlet-name>
+		<servlet-class>com.dianping.job.client.netcom.http.DianpingJobServlet</servlet-class>
+		<load-on-startup>1</load-on-startup>
+	</servlet>
+	<servlet-mapping>
+		<servlet-name>DianpingJobServlet</servlet-name>
+		<url-pattern>/dianpingJobServlet</url-pattern>
+	</servlet-mapping>
+	
+	<display-name>clock-job-web</display-name>
+	<welcome-file-list>
+		<welcome-file>index.html</welcome-file>
+	</welcome-file-list>
+	
+</web-app>

+ 1 - 0
branch-dianping/dianping-job/dianping-job-client-demo/src/main/webapp/index.html

@@ -0,0 +1 @@
+200

+ 83 - 0
branch-dianping/dianping-job/dianping-job-client/pom.xml

@@ -0,0 +1,83 @@
+<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>
+	<parent>
+		<groupId>com.dianping</groupId>
+		<artifactId>dianping-job</artifactId>
+		<version>0.0.1-SNAPSHOT</version>
+	</parent>
+	<artifactId>dianping-job-client</artifactId>
+	<version>1.0.1-SNAPSHOT</version>
+	<name>dianping-job-client</name>
+	<url>http://maven.apache.org</url>
+
+	<dependencies>
+
+		<!-- servlet -->
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>2.5</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet.jsp</groupId>
+			<artifactId>jsp-api</artifactId>
+			<version>2.1</version>
+			<scope>provided</scope>
+		</dependency>
+				
+		<!-- slf4j -->
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-log4j12</artifactId>
+			<version>1.7.5</version>
+		</dependency>
+
+		<!-- jackson -->
+		<dependency>
+			<groupId>org.codehaus.jackson</groupId>
+			<artifactId>jackson-mapper-asl</artifactId>
+			<version>1.9.13</version>
+		</dependency>
+		
+		<!-- httpclient -->
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
+			<version>4.3.6</version>
+		</dependency>
+		
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.1</version>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+					<encoding>UTF8</encoding>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+	<profiles>
+		<profile>
+			<id>jdk-1.6</id>
+			<activation>
+				<activeByDefault>true</activeByDefault>
+				<jdk>1.6</jdk>
+			</activation>
+			<properties>
+				<maven.compiler.source>1.6</maven.compiler.source>
+				<maven.compiler.target>1.6</maven.compiler.target>
+				<maven.compiler.compilerVersion>1.6</maven.compiler.compilerVersion>
+			</properties>
+		</profile>
+	</profiles>
+
+</project>

+ 140 - 0
branch-dianping/dianping-job/dianping-job-client/src/main/java/com/dianping/job/client/handler/HandlerRepository.java

@@ -0,0 +1,140 @@
+package com.dianping.job.client.handler;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.dianping.job.client.handler.IJobHandler.JobHandleStatus;
+import com.dianping.job.client.handler.IJobHandler.JobTriggerStatus;
+
+/**
+ * handler repository
+ * @author xuxueli 2015-12-19 19:28:44
+ */
+public class HandlerRepository {
+	private static Logger logger = LoggerFactory.getLogger(HandlerRepository.class);
+	
+	public static final String triggerUuid = "triggerUuid";
+	public static final String handleName = "handleName";
+
+	// handler class map
+	private static ConcurrentHashMap<String, IJobHandler> handlerClassMap = new ConcurrentHashMap<String, IJobHandler>();
+	// handler thread map
+	private static ConcurrentHashMap<String, HandlerThread> handlerTreadMap = new ConcurrentHashMap<String, HandlerThread>();
+	// handler date queue map
+	private static ConcurrentHashMap<String, LinkedBlockingQueue<Map<String, String>>> handlerDataQueueMap = new ConcurrentHashMap<String, LinkedBlockingQueue<Map<String, String>>>();
+	
+	// regist handler
+	public static void regist(String handleName, IJobHandler handler){
+		handlerClassMap.put(handleName, handler);
+		LinkedBlockingQueue<Map<String, String>> handlerDateQueue = new LinkedBlockingQueue<Map<String, String>>();
+		handlerDataQueueMap.put(handleName, handlerDateQueue);
+		HandlerThread handlerThread = new HandlerThread(handleName);
+		handlerThread.start();
+		handlerTreadMap.put(handleName, handlerThread);
+		logger.info(">>>>>>>>>>> dianping-job regist handler success, handleName:{}, handler:{}, handlerDateQueue:{}, handlerThread:{}", 
+				new Object[]{handleName, handler, handlerDateQueue, handlerThread});
+	}
+	
+	// create handler thread
+	static class HandlerThread extends Thread{
+		private String _handleName;
+		public HandlerThread(String _handleName) {
+			this._handleName = _handleName;
+		}
+		public boolean isValid = true;
+		public void stopThread(){
+			isValid = false;
+		}
+		@Override
+		public void run() {
+			while (isValid) {
+				LinkedBlockingQueue<Map<String, String>> handlerDateQueue = handlerDataQueueMap.get(_handleName);
+				Map<String, String> handlerDate = handlerDateQueue.poll();
+				if (handlerDate!=null) {
+					JobHandleStatus jobHandleStatus = null;
+					String jobHandleDetail = null;
+					try {
+						IJobHandler handler = handlerClassMap.get(_handleName);
+						jobHandleStatus = handler.handle(handlerDate);
+					} catch (Exception e) {
+						e.printStackTrace();
+						jobHandleStatus = JobHandleStatus.FAIL;
+						StringWriter out = new StringWriter();
+						e.printStackTrace(new PrintWriter(out));
+						jobHandleDetail = out.toString();
+					}
+					String _triggerUuid = handlerDate.get(triggerUuid);
+					logger.info("<<<<<<<<<<< dianping-job thread handle, _triggerUuid:{}, _handleName:{}, jobHandleStatus:{}, jobHandleDetail:{}, thread:{}", 
+							new Object[]{_triggerUuid, _handleName, jobHandleStatus, jobHandleDetail, this});
+				} else {
+					try {
+						TimeUnit.SECONDS.sleep(3);
+					} catch (InterruptedException e) {
+						e.printStackTrace();
+					}
+				}
+			}
+		}
+	}
+	
+	// handler push to queue
+	public static String pushHandleQueue(String triggerUuid, String handleName, Map<String, String> _param) {
+		JobTriggerStatus _triggerStatus = JobTriggerStatus.FAIL;
+		String _triggerDetailLog = null;
+		
+		try {
+			if (handleName!=null && handleName.trim().length()>0) {
+				IJobHandler handler = handlerClassMap.get(handleName);
+				if (handler != null) {
+					// push data to handler queue
+					LinkedBlockingQueue<Map<String, String>> handlerDateQueue = handlerDataQueueMap.get(handleName);
+					if (handlerDateQueue == null) {
+						handlerDateQueue = new LinkedBlockingQueue<Map<String, String>>();
+						handlerDataQueueMap.put(handleName, handlerDateQueue);
+						logger.info(">>>>>>>>>>> dianping-job handler lazy fresh handlerDateQueue, handleName:{}, handler:{}, handlerDateQueue:{}", 
+								new Object[]{handleName, handler, handlerDateQueue});
+					}
+					handlerDateQueue.offer(_param);
+					// check handler thread
+					HandlerThread handlerThreadOld = handlerTreadMap.get(handleName);
+					if (!handlerThreadOld.isAlive()) {
+						handlerThreadOld.stopThread();
+						HandlerThread handlerThread = new HandlerThread(handleName);
+						handlerThread.start();
+						handlerTreadMap.put(handleName, handlerThread);
+						logger.info(">>>>>>>>>>> dianping-job handler lazy fresh thread, handleName:{}, handler:{}, handlerThread:{}", 
+								new Object[]{handleName, handler, handlerThread});
+					}
+					_triggerStatus = JobTriggerStatus.SUCCESS;
+				}
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			_triggerStatus = JobTriggerStatus.FAIL;
+			StringWriter out = new StringWriter();
+			e.printStackTrace(new PrintWriter(out));
+			_triggerDetailLog = out.toString();
+		}
+		logger.info(">>>>>>>>>>> dianping-job pushHandleQueue, triggerUuid:{}, handleName, _triggerStatus:{}, _triggerDetailLog", 
+				new Object[]{triggerUuid, handleName, _triggerStatus, _triggerDetailLog});
+		
+		String responseBody = _triggerStatus.name();
+		if (JobTriggerStatus.SUCCESS != _triggerStatus) {
+			responseBody += "#" + _triggerDetailLog;
+		}
+		return responseBody;
+		/**
+		 * trigger-log : 
+		 * 		trigger side : store trigger-info >> trigger request >> update trigger-response-status
+		 * 		job side : handler trigger >> update trigger-result
+		 */
+	}
+	
+}

+ 46 - 0
branch-dianping/dianping-job/dianping-job-client/src/main/java/com/dianping/job/client/handler/IJobHandler.java

@@ -0,0 +1,46 @@
+package com.dianping.job.client.handler;
+
+import java.util.Map;
+
+/**
+ * remote job handler
+ * @author xuxueli 2015-12-19 19:06:38
+ */
+public abstract class IJobHandler extends HandlerRepository{
+	
+	/**
+	 * job handler <br><br>
+	 * the return Object will be and stored
+	 * @param param
+	 * @return 
+	 * @throws Exception
+	 */
+	public abstract JobHandleStatus handle(Map<String, String> param) throws Exception;
+	
+	public enum JobHandleStatus{
+		/**
+		 * handle success
+		 */
+		SUCCESS, 
+		/**
+		 * handle fail
+		 */
+		FAIL, 
+		/**
+		 * handle not found
+		 */
+		NOT_FOUND;
+	}
+	
+	public enum JobTriggerStatus{
+		/**
+		 * trigger success
+		 */
+		SUCCESS, 
+		/**
+		 * trigger fail
+		 */
+		FAIL;
+	}
+	
+}

+ 61 - 0
branch-dianping/dianping-job/dianping-job-client/src/main/java/com/dianping/job/client/netcom/http/DianpingJobServlet.java

@@ -0,0 +1,61 @@
+package com.dianping.job.client.netcom.http;
+
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.dianping.job.client.handler.HandlerRepository;
+
+/**
+ * remote job client on http
+ * @author xuxueli 2015-12-19 18:36:47
+ */
+public class DianpingJobServlet extends HttpServlet {
+	private static final long serialVersionUID = 1L;
+
+    /**
+     * Default constructor. 
+     */
+    public DianpingJobServlet() {
+        // TODO Auto-generated constructor stub
+    }
+    
+	/**
+	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
+	 */
+	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+		request.setCharacterEncoding("UTF-8");
+		response.setCharacterEncoding("UTF-8");
+		
+		Map<String, String> _param = new HashMap<String, String>();
+		if (request.getParameterMap()!=null && request.getParameterMap().size()>0) {
+			for (Object paramKey : request.getParameterMap().keySet()) {
+				if (paramKey!=null) {
+					String paramKeyStr = paramKey.toString();
+					_param.put(paramKeyStr, request.getParameter(paramKeyStr));
+				}
+			}
+		}
+		String _triggerUuid = _param.get(HandlerRepository.triggerUuid);
+		String _handleName = _param.get(HandlerRepository.handleName);
+		
+		String resp = HandlerRepository.pushHandleQueue(_triggerUuid, _handleName, _param);
+		response.getWriter().append(resp);
+		return;
+	}
+
+	/**
+	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
+	 */
+	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+		// TODO Auto-generated method stub
+		doGet(request, response);
+	}
+
+}

+ 59 - 0
branch-dianping/dianping-job/dianping-job-client/src/main/java/com/dianping/job/client/util/HttpUtil.java

@@ -0,0 +1,59 @@
+package com.dianping.job.client.util;
+
+import java.io.IOException;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+/**
+ * http util to send hex data
+ * @author xuxueli
+ * @version  2015-11-28 15:30:59
+ */
+public class HttpUtil {
+
+	public static String sendHex(String reqURL, String queryString) {
+
+		String responseContent = null;
+		if (queryString != null && !queryString.equals("")) {
+			reqURL = reqURL + "?data=" + queryString;
+		}
+
+		HttpGet httpGet = new HttpGet(reqURL);
+		CloseableHttpClient httpClient = HttpClients.createDefault();
+		try {
+			RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(3000).setConnectTimeout(3000).build();
+			httpGet.setConfig(requestConfig);
+			
+			HttpResponse response = httpClient.execute(httpGet);
+			
+			HttpEntity entity = response.getEntity();
+			if (null != entity) {
+				responseContent = EntityUtils.toString(entity, "UTF-8");
+				EntityUtils.consume(entity);
+				if (responseContent!=null) {
+					responseContent = responseContent.trim();
+				}
+			}
+		} catch (ClientProtocolException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		} finally {
+			httpGet.releaseConnection();
+			try {
+				httpClient.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+		return responseContent;
+	}
+
+}

+ 174 - 0
branch-dianping/dianping-job/dianping-job-web/pom.xml

@@ -0,0 +1,174 @@
+<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>
+	<parent>
+		<groupId>com.dianping</groupId>
+		<artifactId>dianping-job</artifactId>
+		<version>0.0.1-SNAPSHOT</version>
+	</parent>
+	<artifactId>dianping-job-web</artifactId>
+	<version>1.0.1-SNAPSHOT</version>
+	<packaging>war</packaging>
+    <name>dianping-job-web</name>
+    <url>http://maven.apache.org</url>
+
+	<properties>
+		<spring.version>3.2.14.RELEASE</spring.version>
+	</properties>
+
+	<dependencies>
+		<!-- springframe start -->
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-webmvc</artifactId>
+			<version>${spring.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-context-support</artifactId>
+			<version>${spring.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-orm</artifactId>
+			<version>${spring.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-test</artifactId>
+			<version>${spring.version}</version>
+		</dependency>
+		<!-- springframe end -->
+		<!-- aspectjweaver (support spring aop) -->
+		<dependency>
+			<groupId>org.aspectj</groupId>
+			<artifactId>aspectjweaver</artifactId>
+			<version>1.8.7</version>
+		</dependency>
+		<!-- jackson (support spring json) -->
+		<dependency>
+			<groupId>org.codehaus.jackson</groupId>
+			<artifactId>jackson-mapper-asl</artifactId>
+			<version>1.9.13</version>
+		</dependency>
+
+		<!-- slf4j -->
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-log4j12</artifactId>
+			<version>1.7.5</version>
+		</dependency>
+
+		<!-- freemarker -->
+		<dependency>
+			<groupId>org.freemarker</groupId>
+			<artifactId>freemarker</artifactId>
+			<version>2.3.20</version>
+		</dependency>
+
+		<!-- commons-beanutils -->
+		<dependency>
+			<groupId>commons-beanutils</groupId>
+			<artifactId>commons-beanutils</artifactId>
+			<version>1.9.2</version>
+		</dependency>
+		<!-- commons-lang -->
+		<dependency>
+			<groupId>commons-lang</groupId>
+			<artifactId>commons-lang</artifactId>
+			<version>2.6</version>
+		</dependency>
+
+		<!-- servlet -->
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>2.5</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet.jsp</groupId>
+			<artifactId>jsp-api</artifactId>
+			<version>2.1</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<!-- junit -->
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.11</version>
+			<scope>test</scope>
+		</dependency>
+
+		<!-- c3p0 -->
+		<dependency>
+			<groupId>c3p0</groupId>
+			<artifactId>c3p0</artifactId>
+			<version>0.9.1.2</version>
+		</dependency>
+		<!-- mybatis-spring -->
+		<dependency>
+			<groupId>org.mybatis</groupId>
+			<artifactId>mybatis-spring</artifactId>
+			<version>1.2.2</version>
+		</dependency>
+		<dependency>
+			<groupId>org.mybatis</groupId>
+			<artifactId>mybatis</artifactId>
+			<version>3.2.8</version>
+		</dependency>
+		<!-- mysql-connector -->
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+			<version>5.1.29</version>
+		</dependency>
+
+		<!-- quartz :quartz-2.2.1/c3p0-0.9.1.1/slf4j-api-1.6.6 -->
+		<dependency>
+			<groupId>org.quartz-scheduler</groupId>
+			<artifactId>quartz</artifactId>
+			<version>2.2.1</version>
+		</dependency>
+		
+		<!-- httpclient -->
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
+			<version>4.3.6</version>
+		</dependency>
+		
+		<!-- dianping-job-client -->
+		<dependency>
+			<groupId>com.dianping</groupId>
+			<artifactId>dianping-job-client</artifactId>
+			<version>1.0.1-SNAPSHOT</version>
+		</dependency>
+
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.1</version>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+					<encoding>UTF8</encoding>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-war-plugin</artifactId>
+				<version>2.2</version>
+				<configuration>
+					<archiveClasses>true</archiveClasses>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+</project>

+ 180 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/controller/IndexController.java

@@ -0,0 +1,180 @@
+package com.dianping.job.controller;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang.StringUtils;
+import org.quartz.CronExpression;
+import org.quartz.Job;
+import org.quartz.SchedulerException;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.dianping.job.client.handler.HandlerRepository;
+import com.dianping.job.core.model.ReturnT;
+import com.dianping.job.core.util.DynamicSchedulerUtil;
+import com.dianping.job.service.job.HttpJobBean;
+
+/**
+ * index controller
+ * @author xuxueli 2015-12-19 16:13:16
+ */
+@Controller
+public class IndexController {
+
+	
+	@RequestMapping("")
+	public String index(Model model) {
+		List<Map<String, Object>> jobList = DynamicSchedulerUtil.getJobList();
+		model.addAttribute("jobList", jobList);
+		return "job/index";
+	}
+	
+	@RequestMapping("/help")
+	public String help(Model model) {
+		return "job/help";
+	}
+	
+	@RequestMapping("/job/add")
+	@ResponseBody
+	public ReturnT<String> add(HttpServletRequest request) {
+		String triggerKeyName = null;
+		String cronExpression = null;
+		Map<String, Object> jobData = new HashMap<String, Object>();
+		
+		try {
+			request.setCharacterEncoding("utf-8");
+		} catch (UnsupportedEncodingException e1) {
+			e1.printStackTrace();
+		}
+		@SuppressWarnings("unchecked")
+		Set<Map.Entry<String, String[]>> paramSet = request.getParameterMap().entrySet();
+		for (Entry<String, String[]> param : paramSet) {
+			if (param.getKey().equals("triggerKeyName")) {
+				triggerKeyName = param.getValue()[0];
+			} else if (param.getKey().equals("cronExpression")) {
+				cronExpression = param.getValue()[0];
+			} else {
+				jobData.put(param.getKey(), param.getValue().length>0?param.getValue()[0]:param.getValue());
+			}
+		}
+		
+		// triggerKeyName
+		if (StringUtils.isBlank(triggerKeyName)) {
+			return new ReturnT<String>(500, "请输入“任务key”");
+		}
+		
+		// cronExpression
+		if (StringUtils.isBlank(cronExpression)) {
+			return new ReturnT<String>(500, "请输入“任务corn”");
+		}
+		if (!CronExpression.isValidExpression(cronExpression)) {
+			return new ReturnT<String>(500, "“任务corn”不合法");
+		}
+		
+		// jobData
+		if (jobData.get(DynamicSchedulerUtil.job_desc)==null || jobData.get(DynamicSchedulerUtil.job_desc).toString().trim().length()==0) {
+			return new ReturnT<String>(500, "请输入“任务描述”");
+		}
+		if (jobData.get(DynamicSchedulerUtil.job_url)==null || jobData.get(DynamicSchedulerUtil.job_url).toString().trim().length()==0) {
+			return new ReturnT<String>(500, "请输入“任务URL”");
+		}
+		if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) {
+			return new ReturnT<String>(500, "请输入“任务handler”");
+		}
+		
+		// jobClass
+		Class<? extends Job> jobClass = HttpJobBean.class;
+		
+		try {
+			boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, jobData);
+			if (!result) {
+				return new ReturnT<String>(500, "任务ID重复,请更换确认");
+			}
+			return ReturnT.SUCCESS;
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+		}
+		return ReturnT.FAIL;
+	}
+	
+	@RequestMapping("/job/reschedule")
+	@ResponseBody
+	public ReturnT<String> reschedule(String triggerKeyName, String cronExpression) {
+		// triggerKeyName
+		if (StringUtils.isBlank(triggerKeyName)) {
+			return new ReturnT<String>(500, "请输入“任务key”");
+		}
+		// cronExpression
+		if (StringUtils.isBlank(cronExpression)) {
+			return new ReturnT<String>(500, "请输入“任务corn”");
+		}
+		if (!CronExpression.isValidExpression(cronExpression)) {
+			return new ReturnT<String>(500, "“任务corn”不合法");
+		}
+		try {
+			DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression);
+			return ReturnT.SUCCESS;
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+		}
+		return ReturnT.FAIL;
+	}
+	
+	@RequestMapping("/job/remove")
+	@ResponseBody
+	public ReturnT<String> remove(String triggerKeyName) {
+		try {
+			DynamicSchedulerUtil.removeJob(triggerKeyName);
+			return ReturnT.SUCCESS;
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+			return ReturnT.FAIL;
+		}
+	}
+	
+	@RequestMapping("/job/pause")
+	@ResponseBody
+	public ReturnT<String> pause(String triggerKeyName) {
+		try {
+			DynamicSchedulerUtil.pauseJob(triggerKeyName);
+			return ReturnT.SUCCESS;
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+			return ReturnT.FAIL;
+		}
+	}
+	
+	@RequestMapping("/job/resume")
+	@ResponseBody
+	public ReturnT<String> resume(String triggerKeyName) {
+		try {
+			DynamicSchedulerUtil.resumeJob(triggerKeyName);
+			return ReturnT.SUCCESS;
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+			return ReturnT.FAIL;
+		}
+	}
+	
+	@RequestMapping("/job/trigger")
+	@ResponseBody
+	public ReturnT<String> triggerJob(String triggerKeyName) {
+		try {
+			DynamicSchedulerUtil.triggerJob(triggerKeyName);
+			return ReturnT.SUCCESS;
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+			return ReturnT.FAIL;
+		}
+	}
+	
+}

+ 79 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/core/model/DianpingJobLog.java

@@ -0,0 +1,79 @@
+package com.dianping.job.core.model;
+
+import java.util.Date;
+
+/**
+ * dianping job log, used to track trigger process
+ * @author xuxueli  2015-12-19 23:19:09
+ */
+public class DianpingJobLog {
+	
+	private String jobTriggerUuid;
+	private String jobHandleName;
+	// trigger info
+	private Date triggerTime;
+	private String triggerStatus;
+	private String triggerDetailLog;
+	// handle info
+	private Date handleTime;
+	private String handleStatus;
+	private String handleDetailLog;
+	
+	public String getJobTriggerUuid() {
+		return jobTriggerUuid;
+	}
+	public void setJobTriggerUuid(String jobTriggerUuid) {
+		this.jobTriggerUuid = jobTriggerUuid;
+	}
+	public String getJobHandleName() {
+		return jobHandleName;
+	}
+	public void setJobHandleName(String jobHandleName) {
+		this.jobHandleName = jobHandleName;
+	}
+	public Date getTriggerTime() {
+		return triggerTime;
+	}
+	public void setTriggerTime(Date triggerTime) {
+		this.triggerTime = triggerTime;
+	}
+	public String getTriggerStatus() {
+		return triggerStatus;
+	}
+	public void setTriggerStatus(String triggerStatus) {
+		this.triggerStatus = triggerStatus;
+	}
+	public String getTriggerDetailLog() {
+		return triggerDetailLog;
+	}
+	public void setTriggerDetailLog(String triggerDetailLog) {
+		this.triggerDetailLog = triggerDetailLog;
+	}
+	public Date getHandleTime() {
+		return handleTime;
+	}
+	public void setHandleTime(Date handleTime) {
+		this.handleTime = handleTime;
+	}
+	public String getHandleStatus() {
+		return handleStatus;
+	}
+	public void setHandleStatus(String handleStatus) {
+		this.handleStatus = handleStatus;
+	}
+	public String getHandleDetailLog() {
+		return handleDetailLog;
+	}
+	public void setHandleDetailLog(String handleDetailLog) {
+		this.handleDetailLog = handleDetailLog;
+	}
+	
+	@Override
+	public String toString() {
+		return "DianpingJobLog [jobTriggerUuid=" + jobTriggerUuid + ", jobHandleName=" + jobHandleName
+				+ ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus + ", triggerDetailLog="
+				+ triggerDetailLog + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus
+				+ ", handleDetailLog=" + handleDetailLog + "]";
+	}
+	
+}

+ 50 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/core/model/ReturnT.java

@@ -0,0 +1,50 @@
+package com.dianping.job.core.model;
+
+/**
+ * common return
+ * @author xuxueli 2015-12-4 16:32:31
+ * @param <T>
+ */
+public class ReturnT<T> {
+	public static final ReturnT<String> SUCCESS = new ReturnT<String>(null);
+	public static final ReturnT<String> FAIL = new ReturnT<String>(500, null);
+	
+	private int code;
+	private String msg;
+	private T content;
+	
+	public ReturnT(int code, String msg) {
+		this.code = code;
+		this.msg = msg;
+	}
+	public ReturnT(T content) {
+		this.code = 200;
+		this.content = content;
+	}
+	
+	public int getCode() {
+		return code;
+	}
+	public void setCode(int code) {
+		this.code = code;
+	}
+	public String getMsg() {
+		return msg;
+	}
+	public void setMsg(String msg) {
+		this.msg = msg;
+	}
+	public T getContent() {
+		return content;
+	}
+	public void setContent(T content) {
+		this.content = content;
+	}
+
+	@Override
+	public String toString() {
+		return "ReturnT [code=" + code + ", msg=" + msg + ", content="
+				+ content + "]";
+	}
+
+}

+ 199 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/core/util/DynamicSchedulerUtil.java

@@ -0,0 +1,199 @@
+package com.dianping.job.core.util;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.quartz.CronScheduleBuilder;
+import org.quartz.CronTrigger;
+import org.quartz.Job;
+import org.quartz.JobBuilder;
+import org.quartz.JobDataMap;
+import org.quartz.JobDetail;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.Trigger.TriggerState;
+import org.quartz.TriggerBuilder;
+import org.quartz.TriggerKey;
+import org.quartz.impl.matchers.GroupMatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.Assert;
+
+/**
+ * base quartz scheduler util
+ * @author xuxueli 2015-12-19 16:13:53
+ */
+public final class DynamicSchedulerUtil implements InitializingBean {
+    private static final Logger logger = LoggerFactory.getLogger(DynamicSchedulerUtil.class);
+    
+    // Scheduler
+    private static Scheduler scheduler;
+    public static void setScheduler(Scheduler scheduler) {
+		DynamicSchedulerUtil.scheduler = scheduler;
+	}
+
+	@Override
+    public void afterPropertiesSet() throws Exception {
+        Assert.notNull(scheduler, "quartz scheduler is null");
+        logger.info(">>>>>>>>> init quartz scheduler success.[{}]", scheduler);
+    }
+	
+	// getJobKeys
+	public static List<Map<String, Object>> getJobList(){
+		List<Map<String, Object>> jobList = new ArrayList<Map<String,Object>>();
+		
+		try {
+			if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) {
+				return null;
+			}
+			String groupName = scheduler.getJobGroupNames().get(0);
+			Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
+			if (jobKeys!=null && jobKeys.size()>0) {
+				for (JobKey jobKey : jobKeys) {
+			        TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP);
+			        Trigger trigger = scheduler.getTrigger(triggerKey);
+			        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
+			        TriggerState triggerState = scheduler.getTriggerState(triggerKey);
+			        Map<String, Object> jobMap = new HashMap<String, Object>();
+			        jobMap.put("TriggerKey", triggerKey);
+			        jobMap.put("Trigger", trigger);
+			        jobMap.put("JobDetail", jobDetail);
+			        jobMap.put("TriggerState", triggerState);
+			        jobList.add(jobMap);
+				}
+			}
+			
+		} catch (SchedulerException e) {
+			e.printStackTrace();
+			return null;
+		}
+		return jobList;
+	}
+
+	public static final String job_desc = "job_desc";
+	public static final String job_url = "job_url";
+	// addJob 新增
+    public static boolean addJob(String triggerKeyName, String cronExpression, Class<? extends Job> jobClass, Map<String, Object> jobData) throws SchedulerException {
+    	// TriggerKey : name + group
+    	String group = Scheduler.DEFAULT_GROUP;
+        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
+        
+        // TriggerKey valid if_exists
+        if (scheduler.checkExists(triggerKey)) {
+            Trigger trigger = scheduler.getTrigger(triggerKey);
+            logger.info(">>>>>>>>> Already exist trigger [" + trigger + "] by key [" + triggerKey + "] in Scheduler");
+            return false;
+        }
+        
+        // CronTrigger : TriggerKey + cronExpression
+        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
+        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
+
+        // JobDetail : jobClass
+        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(triggerKeyName, group).build();
+        if (jobData!=null && jobData.size() > 0) {
+        	JobDataMap jobDataMap = jobDetail.getJobDataMap();
+        	jobDataMap.putAll(jobData);	// JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
+		}
+        
+        // schedule : jobDetail + cronTrigger
+        Date date = scheduler.scheduleJob(jobDetail, cronTrigger);
+
+        logger.info(">>>>>>>>>>> addJob success, jobDetail:{}, cronTrigger:{}, date:{}", jobDetail, cronTrigger, date);
+        return true;
+    }
+    
+    // reschedule 重置cron
+    public static boolean rescheduleJob(String triggerKeyName, String cronExpression) throws SchedulerException {
+        // TriggerKey : name + group
+    	String group = Scheduler.DEFAULT_GROUP;
+        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
+        
+        boolean result = false;
+        if (scheduler.checkExists(triggerKey)) {
+            // CronTrigger : TriggerKey + cronExpression
+            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
+            CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
+            
+            Date date = scheduler.rescheduleJob(triggerKey, cronTrigger);
+            result = true;
+            logger.info(">>>>>>>>>>> resumeJob success, triggerKey:{}, cronExpression:{}, date:{}", triggerKey, cronExpression, date);
+        } else {
+        	logger.info(">>>>>>>>>>> resumeJob fail, triggerKey:{}, cronExpression:{}", triggerKey, cronExpression);
+        }
+        return result;
+    }
+    
+    // unscheduleJob 删除
+    public static boolean removeJob(String triggerKeyName) throws SchedulerException {
+    	// TriggerKey : name + group
+    	String group = Scheduler.DEFAULT_GROUP;
+        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
+        
+        boolean result = false;
+        if (scheduler.checkExists(triggerKey)) {
+            result = scheduler.unscheduleJob(triggerKey);
+        }
+        logger.info(">>>>>>>>>>> removeJob, triggerKey:{}, result [{}]", triggerKey, result);
+        return result;
+    }
+
+    // Pause 暂停
+    public static boolean pauseJob(String triggerKeyName) throws SchedulerException {
+    	// TriggerKey : name + group
+    	String group = Scheduler.DEFAULT_GROUP;
+        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
+        
+        boolean result = false;
+        if (scheduler.checkExists(triggerKey)) {
+            scheduler.pauseTrigger(triggerKey);
+            result = true;
+            logger.info(">>>>>>>>>>> pauseJob success, triggerKey:{}", triggerKey);
+        } else {
+        	logger.info(">>>>>>>>>>> pauseJob fail, triggerKey:{}", triggerKey);
+        }
+        return result;
+    }
+    
+    // resume 重启 
+    public static boolean resumeJob(String triggerKeyName) throws SchedulerException {
+        // TriggerKey : name + group
+    	String group = Scheduler.DEFAULT_GROUP;
+        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
+        
+        boolean result = false;
+        if (scheduler.checkExists(triggerKey)) {
+            scheduler.resumeTrigger(triggerKey);
+            result = true;
+            logger.info(">>>>>>>>>>> resumeJob success, triggerKey:{}", triggerKey);
+        } else {
+        	logger.info(">>>>>>>>>>> resumeJob fail, triggerKey:{}", triggerKey);
+        }
+        return result;
+    }
+    
+    // run 执行一次 
+    public static boolean triggerJob(String triggerKeyName) throws SchedulerException {
+        // TriggerKey : name + group
+    	String group = Scheduler.DEFAULT_GROUP;
+        JobKey jobKey = JobKey.jobKey(triggerKeyName, group);
+        
+        boolean result = false;
+        if (scheduler.checkExists(jobKey)) {
+            scheduler.triggerJob(jobKey);
+            result = true;
+            logger.info(">>>>>>>>>>> runJob success, jobKey:{}", jobKey);
+        } else {
+        	logger.info(">>>>>>>>>>> runJob fail, jobKey:{}", jobKey);
+        }
+        return result;
+    }
+
+}

+ 11 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/service/ITriggerService.java

@@ -0,0 +1,11 @@
+package com.dianping.job.service;
+
+/**
+ * local trigger, only exists in local jvm
+ * @author xuxueli 2015-12-17 17:29:23
+ */
+public interface ITriggerService {
+	
+	public void beat();
+	
+}

+ 21 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/service/impl/TriggerServiceImpl.java

@@ -0,0 +1,21 @@
+package com.dianping.job.service.impl;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import com.dianping.job.service.ITriggerService;
+
+/**
+ * local trigger, only exists in local jvm
+ * @author xuxueli 2015-12-17 17:31:24
+ */
+@Service("triggerService")
+public class TriggerServiceImpl implements ITriggerService {
+	private static transient Logger logger = LoggerFactory.getLogger(TriggerServiceImpl.class);
+	
+	public void beat() {
+		logger.info(">>>>>>>>>>> dianping-clock beat success.");
+	}
+	
+}

+ 137 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/java/com/dianping/job/service/job/HttpJobBean.java

@@ -0,0 +1,137 @@
+package com.dianping.job.service.job;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.quartz.QuartzJobBean;
+
+import com.dianping.job.client.handler.HandlerRepository;
+import com.dianping.job.client.handler.IJobHandler.JobTriggerStatus;
+import com.dianping.job.core.model.DianpingJobLog;
+import com.dianping.job.core.util.DynamicSchedulerUtil;
+
+/**
+ * http job bean
+ * @author xuxueli 2015-12-17 18:20:34
+ */
+public class HttpJobBean extends QuartzJobBean {
+	private static Logger logger = LoggerFactory.getLogger(HttpJobBean.class);
+
+	@Override
+	protected void executeInternal(JobExecutionContext context)
+			throws JobExecutionException {
+		
+		String triggerKey = context.getTrigger().getKey().getName();
+		String triggerGroup = context.getTrigger().getKey().getGroup();
+		Map<String, Object> jobDataMap = context.getMergedJobDataMap().getWrappedMap();
+		
+		// jobDataMap 2 params
+		Map<String, String> params = new HashMap<String, String>();
+		if (jobDataMap!=null && jobDataMap.size()>0) {
+			for (Entry<String, Object> item : jobDataMap.entrySet()) {
+				params.put(item.getKey(), String.valueOf(item.getValue()));
+			}
+		}
+		
+		String job_url = params.get(DynamicSchedulerUtil.job_url);
+		triggerPost(job_url, params);
+		
+		logger.info(">>>>>>>>>>> dianping-clock run :jobId:{}, group:{}, jobDataMap:{}", 
+				new Object[]{triggerKey, triggerGroup, jobDataMap});
+    }
+	
+	public static void triggerPost(String reqURL, Map<String, String> params){
+		// save log
+		DianpingJobLog jobLog = new DianpingJobLog();
+		jobLog.setJobTriggerUuid(UUID.randomUUID().toString());
+		jobLog.setJobHandleName(params.get(HandlerRepository.handleName));
+		jobLog.setTriggerTime(new Date());
+		logger.info(">>>>>>>>>>> dianping-clock trigger start :jobLog:{}", jobLog);
+		
+		// post
+		String responseContent = null;
+		HttpPost httpPost = new HttpPost(reqURL);
+		CloseableHttpClient httpClient = HttpClients.createDefault();
+		try{
+			if (params != null && !params.isEmpty()) {
+				List<NameValuePair> formParams = new ArrayList<NameValuePair>();
+				for(Map.Entry<String,String> entry : params.entrySet()){
+					formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
+				}
+				httpPost.setEntity(new UrlEncodedFormEntity(formParams, "UTF-8"));
+			}
+			RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();
+			httpPost.setConfig(requestConfig);
+			
+			HttpResponse response = httpClient.execute(httpPost);
+			HttpEntity entity = response.getEntity();
+			if (null != entity) {
+				responseContent = EntityUtils.toString(entity, "UTF-8");
+				EntityUtils.consume(entity);
+			}
+			logger.info(">>>>>>>>>>> dianping-clock trigger ing :jobLog:{}, response:{}, responseContent:{}", jobLog, response, responseContent);
+		} catch (Exception e) {
+			e.printStackTrace();
+			
+			StringWriter out = new StringWriter();
+			e.printStackTrace(new PrintWriter(out));
+			responseContent = out.toString();
+		} finally{
+			httpPost.releaseConnection();
+			try {
+				httpClient.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			
+			// update trigger status
+			if (responseContent!=null && responseContent.equals(JobTriggerStatus.SUCCESS.name())) {
+				jobLog.setTriggerStatus(JobTriggerStatus.SUCCESS.name());
+			} else {
+				jobLog.setTriggerStatus(JobTriggerStatus.FAIL.name());
+			}
+			jobLog.setTriggerDetailLog(responseContent);
+			if (jobLog.getTriggerDetailLog()!=null && jobLog.getTriggerDetailLog().length()>1000) {
+				jobLog.setTriggerDetailLog(jobLog.getTriggerDetailLog().substring(0, 1000));
+			}
+			
+			logger.info(">>>>>>>>>>> dianping-clock trigger end :jobLog:{}", jobLog);
+		}
+		
+	}
+	
+	public static void main(String[] args) {
+		String url = "http://localhost:8080/dianping-job-client-demo/dianpingJobServlet";
+		
+		for (int i = 0; i < 3; i++) {
+			Map<String, String> params = new HashMap<String, String>();
+			params.put(HandlerRepository.handleName, "com.dianping.job.service.handler.DemoJobHandler");
+			params.put(HandlerRepository.triggerUuid, i+"");
+			params.put("key", i+"");
+			
+			triggerPost(url, params);
+		}
+	}
+}

+ 33 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/resources/applicationcontext-base.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+           http://www.springframework.org/schema/context
+           http://www.springframework.org/schema/context/spring-context-3.0.xsd
+           http://www.springframework.org/schema/util 
+           http://www.springframework.org/schema/util/spring-util.xsd">
+
+	<context:annotation-config />
+	<context:component-scan base-package="com.dianping.job.service" />
+
+	<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
+		<property name="templateLoaderPath" value="/WEB-INF/template/" />
+		<property name="freemarkerSettings">
+			<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
+				<property name="location" value="classpath:freemarker.properties" />
+			</bean>
+		</property>
+	</bean>
+
+	<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+		<property name="fileEncoding" value="utf-8" />
+		<property name="locations">
+			<list>
+				<value>classpath*:jdbc.properties</value>
+			</list>
+		</property>
+	</bean>
+
+</beans>

+ 42 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/resources/applicationcontext-database.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
+	xsi:schemaLocation="
+		http://www.springframework.org/schema/beans 
+		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
+		http://www.springframework.org/schema/context 
+		http://www.springframework.org/schema/context/spring-context-3.0.xsd 
+		http://www.springframework.org/schema/aop 
+		http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
+		http://www.springframework.org/schema/tx 
+		http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
+		
+	<context:annotation-config />
+	<context:component-scan base-package="com.xxl.service.impl, com.xxl.dao.impl" />
+
+	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"  destroy-method="close">  
+	    <property name="driverClass" value="${c3p0.driverClass}" />  
+	    <property name="jdbcUrl" value="${c3p0.url}" />  
+	    <property name="user" value="${c3p0.user}" />  
+	    <property name="password" value="${c3p0.password}" />  
+	    <property name="initialPoolSize" value="3" />  
+	    <property name="minPoolSize" value="2" />  
+	    <property name="maxPoolSize" value="10" />  
+	    <property name="maxIdleTime" value="60" />
+	    <property name="acquireRetryDelay" value="1000" />
+	    <property name="acquireRetryAttempts" value="10" />
+	    <property name="preferredTestQuery" value="SELECT 1" />
+	</bean>
+	
+	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
+		<property name="dataSource" ref="dataSource" />
+		<property name="mapperLocations" value="classpath*:com/xxl/core/model/mapper/*.xml"/>
+	</bean>
+    
+    <!-- scope must be "prototype" when junit -->
+    <bean id="sqlSessionTemplate"  class="org.mybatis.spring.SqlSessionTemplate" scope="prototype">  
+          <constructor-arg index="0" ref="sqlSessionFactory" />  
+    </bean> 
+	
+</beans>

+ 25 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/resources/applicationcontext-trigger-db.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+           http://www.springframework.org/schema/context
+           http://www.springframework.org/schema/context/spring-context-3.0.xsd
+           http://www.springframework.org/schema/util 
+           http://www.springframework.org/schema/util/spring-util.xsd">
+
+	<bean id="quartzScheduler" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
+		<property name="dataSource" ref="dataSource" />
+        <property name="autoStartup" value="true" />
+		<property name="applicationContextSchedulerContextKey"  value="applicationContextKey" /> 
+        <property name="configLocation" value="classpath:quartz.properties"/>
+	</bean>
+	
+	<!-- 协同-调度器 -->
+	<bean id="dynamicSchedulerUtil" class="com.dianping.job.core.util.DynamicSchedulerUtil">
+		<!-- (轻易不要变更“调度器名称”, 任务创建时会绑定该“调度器名称”) -->
+        <property name="scheduler" ref="quartzScheduler"/>
+    </bean>
+
+</beans>

+ 32 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/resources/applicationcontext-trigger-local.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+           http://www.springframework.org/schema/context
+           http://www.springframework.org/schema/context/spring-context-3.0.xsd
+           http://www.springframework.org/schema/util 
+           http://www.springframework.org/schema/util/spring-util.xsd">
+
+	<bean id="beatJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
+		<property name="targetObject" ref="triggerService" />
+		<property name="targetMethod" value="beat" />
+		<property name="concurrent" value="false" />
+	</bean>
+	
+	<bean id="beatTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
+		<property name="jobDetail" ref="beatJobDetail" />
+		<property name="cronExpression" value="0/10 * * * * ? *" />
+	</bean>
+	
+	<!-- 进程-调度器 -->
+	<bean name="jvmQuertz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
+		<property name="triggers">
+			<list>
+				<!-- <ref bean="beatTrigger" /> -->
+			</list>
+		</property>
+	</bean>
+
+</beans>

+ 38 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/resources/applicationcontext-tx.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
+	xsi:schemaLocation="
+		http://www.springframework.org/schema/beans 
+		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
+		http://www.springframework.org/schema/context 
+		http://www.springframework.org/schema/context/spring-context-3.0.xsd 
+		http://www.springframework.org/schema/aop 
+		http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
+		http://www.springframework.org/schema/tx 
+		http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
+
+	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
+		<property name="dataSource" ref="dataSource" />
+	</bean>
+      
+	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
+	
+	<tx:advice id="txAdvice" transaction-manager="transactionManager">
+		<tx:attributes>
+			<tx:method name="detail*" propagation="SUPPORTS" />
+			<tx:method name="visit*" propagation="SUPPORTS" />
+			<tx:method name="get*" propagation="SUPPORTS" />
+			<tx:method name="find*" propagation="SUPPORTS" />
+			<tx:method name="check*" propagation="SUPPORTS" />
+			<tx:method name="list*" propagation="SUPPORTS" />
+			<tx:method name="*" propagation="REQUIRED" rollback-for="exception" />
+		</tx:attributes>
+	</tx:advice>
+
+	<aop:config>
+		<aop:pointcut id="txoperation" expression="execution(* com.xxl.service.imp.*.*(..))" />
+		<aop:advisor pointcut-ref="txoperation" advice-ref="txAdvice" />
+	</aop:config>
+	
+</beans>

+ 10 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/resources/freemarker.properties

@@ -0,0 +1,10 @@
+template_update_delay=0
+default_encoding=UTF-8
+output_encoding=UTF-8
+locale=zh_CN
+number_format=0.##########
+date_format=yyyy-MM-dd
+time_format=HH:mm:ss
+datetime_format=yyyy-MM-dd HH:mm:s
+classic_compatible=true
+template_exception_handler=ignore

+ 4 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/resources/jdbc.properties

@@ -0,0 +1,4 @@
+c3p0.driverClass=com.mysql.jdbc.Driver
+c3p0.url=jdbc:mysql://localhost:3306/test?Unicode=true&amp;characterEncoding=UTF-8
+c3p0.user=root
+c3p0.password=root_pwd

+ 10 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/resources/log4j.properties

@@ -0,0 +1,10 @@
+log4j.rootLogger=info,console,logFile
+
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d - dianping-job-web - %p [%c] - <%m>%n
+
+log4j.appender.logFile=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.logFile.File=${catalina.base}/logs/dianping-job-web.log
+log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
+log4j.appender.logFile.layout.ConversionPattern=%d - dianping-job-web - %p [%c] - <%m>%n

+ 25 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/resources/quartz.properties

@@ -0,0 +1,25 @@
+# Default Properties file for use by StdSchedulerFactory
+# to create a Quartz Scheduler Instance, if a different
+# properties file is not explicitly specified.
+#
+
+org.quartz.scheduler.instanceName: DefaultQuartzScheduler
+org.quartz.scheduler.rmi.export: false
+org.quartz.scheduler.rmi.proxy: false
+org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
+
+org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
+org.quartz.threadPool.threadCount: 10
+org.quartz.threadPool.threadPriority: 5
+org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
+
+org.quartz.jobStore.misfireThreshold: 60000
+
+#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
+
+# for cluster
+org.quartz.jobStore.tablePrefix = WED_qrtz_
+org.quartz.scheduler.instanceId: AUTO
+org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
+org.quartz.jobStore.isClustered: true
+org.quartz.jobStore.clusterCheckinInterval: 1000

+ 52 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/resources/springmvc-context.xml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?> 
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:aop="http://www.springframework.org/schema/aop" 
+    xmlns:context="http://www.springframework.org/schema/context" 
+    xmlns:p="http://www.springframework.org/schema/p" 
+    xmlns:tx="http://www.springframework.org/schema/tx"
+    xmlns:mvc="http://www.springframework.org/schema/mvc"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="  
+		http://www.springframework.org/schema/beans 
+		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
+		http://www.springframework.org/schema/context 
+		http://www.springframework.org/schema/context/spring-context-3.0.xsd 
+		http://www.springframework.org/schema/aop 
+		http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
+		http://www.springframework.org/schema/tx 
+		http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
+		http://www.springframework.org/schema/mvc
+		http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
+
+	<mvc:annotation-driven /> 
+	<context:component-scan base-package="com.dianping.job.controller" />
+	
+	<mvc:resources mapping="/favicon.ico" location="/favicon.ico" />
+	<mvc:resources mapping="/static/**" location="/static/" />
+	<mvc:resources mapping="/**/*.html" location="/" />
+	
+	<bean id="viewResolver"	class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
+		<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
+		<property name="prefix" value="" />
+		<property name="suffix" value=".ftl" />
+		<property name="contentType" value="text/html;charset=UTF-8" />
+		<property name="exposeSpringMacroHelpers" value="true" />
+		<property name="exposeRequestAttributes" value="true" />
+		<property name="exposeSessionAttributes" value="true" />
+		<property name="requestContextAttribute" value="request" />
+		<property name="cache" value="true" />
+		<property name="order" value="0" />
+	</bean>
+	
+	<!--
+	// 自定义拦截器,支持SSO登陆拦截 
+	<mvc:interceptors>
+		<mvc:interceptor>
+			<mvc:mapping path="/**"/>
+			<bean class="com.xxl.controller.interceptor.PermissionInterceptor"/>
+		</mvc:interceptor>
+	</mvc:interceptors>
+ 	<bean id="exceptionResolver" class="com.xxl.controller.resolver.WebExceptionResolver" /> 
+ 	-->
+	
+</beans>

+ 1 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/500.html

@@ -0,0 +1 @@
+500

+ 39 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/template/common/common.exception.ftl

@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<meta charset="UTF-8">
+	<title>应用程序异常 (500)</title> 
+    <style type="text/css"> 
+        body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
+        div.dialog {
+            width: 80%;
+            padding: 1em 4em;
+            margin: 4em auto 0 auto;
+            border: 1px solid #ccc;
+            border-right-color: #999;
+            border-bottom-color: #999;
+        }
+        h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
+    </style>
+    
+</head> 
+</head>
+<body> 
+
+	<div class="dialog"> 
+	    <h1>应用程序异常</h1> 
+	    <p>抱歉!您访问的页面出现异常,请稍后重试或联系管理员。</p> 
+	    <p><a href="javascript:showErr();">详 情</a> 
+		<a href="javascript:window.location.href='${request.contextPath}'">返 回</a> 
+	    </p> 
+	    <div style="display:none;text-align: left;" id="err">${exceptionMsg}</div>
+	</div>
+  
+<script type="text/javascript">
+function showErr(){
+	document.getElementById("err").style.display = "";
+}
+</script>
+
+</body>
+</html>

+ 240 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/template/common/common.macro.ftl

@@ -0,0 +1,240 @@
+<#macro commonStyle>
+
+	<meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <!-- Tell the browser to be responsive to screen width -->
+    <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
+    <!-- Bootstrap 3.3.5 -->
+    <link rel="stylesheet" href="${request.contextPath}/static/adminlte/bootstrap/css/bootstrap.min.css">
+    <!-- Font Awesome -->
+    <!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> -->
+    <link rel="stylesheet" href="${request.contextPath}/static/plugins/font-awesome-4.3.0/css/font-awesome.min.css">
+    <!-- Ionicons -->
+    <!-- <link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css"> -->
+    <link rel="stylesheet" href="${request.contextPath}/static/plugins/ionicons-2.0.1/css/ionicons.min.css">
+    <!-- Theme style -->
+    <link rel="stylesheet" href="${request.contextPath}/static/adminlte/dist/css/AdminLTE.min.css">
+    <!-- AdminLTE Skins. Choose a skin from the css/skins folder instead of downloading all of them to reduce the load. -->
+    <link rel="stylesheet" href="${request.contextPath}/static/adminlte/dist/css/skins/_all-skins.min.css">
+      
+	<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
+    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
+    <!--[if lt IE 9]>
+    <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
+    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+    <![endif]-->
+  
+	<!-- scrollup -->
+	<link rel="stylesheet" href="${request.contextPath}/static/plugins/scrollup/image.css">
+</#macro>
+
+<#macro commonScript>
+	<!-- jQuery 2.1.4 -->
+	<script src="${request.contextPath}/static/adminlte/plugins/jQuery/jQuery-2.1.4.min.js"></script>
+	<!-- Bootstrap 3.3.5 -->
+	<script src="${request.contextPath}/static/adminlte/bootstrap/js/bootstrap.min.js"></script>
+	<!-- FastClick -->
+	<script src="${request.contextPath}/static/adminlte/plugins/fastclick/fastclick.js"></script>
+	<!-- AdminLTE App -->
+	<script src="${request.contextPath}/static/adminlte/dist/js/app.min.js"></script>
+
+    <!-- scrollup -->
+    <script src="${request.contextPath}/static/plugins/scrollup/jquery.scrollUp.min.js"></script>
+    <script src="${request.contextPath}/static/js/common.1.js"></script>
+</#macro>
+
+<#macro commonHeader>
+	<header class="main-header">
+		<a href="${request.contextPath}/" class="logo">
+			<span class="logo-mini"><b>X</b>XL</span>
+			<span class="logo-lg"><b>任务调度</b>中心</span>
+		</a>
+		<nav class="navbar navbar-static-top" role="navigation">
+			<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button"><span class="sr-only">切换导航</span></a>
+			<div class="navbar-custom-menu"></div>
+		</nav>
+	</header>
+</#macro>
+
+<#macro commonLeft>
+	<!-- Left side column. contains the logo and sidebar -->
+	<aside class="main-sidebar">
+		<!-- sidebar: style can be found in sidebar.less -->
+		<section class="sidebar">
+			<!-- sidebar menu: : style can be found in sidebar.less -->
+			<ul class="sidebar-menu">
+				<li class="header">常用模块</li>
+				<li class="nav-click" ><a href="${request.contextPath}//"><i class="fa fa-circle-o text-red"></i> <span>调度中心</span></a></li>
+				<li class="nav-click" ><a href="${request.contextPath}/help"><i class="fa fa-circle-o text-yellow"></i><span>使用教程</span></a></li>
+			</ul>
+		</section>
+		<!-- /.sidebar -->
+	</aside>
+</#macro>
+
+<#macro commonControl >
+	<!-- Control Sidebar -->
+	<aside class="control-sidebar control-sidebar-dark">
+		<!-- Create the tabs -->
+		<ul class="nav nav-tabs nav-justified control-sidebar-tabs">
+			<li class="active"><a href="#control-sidebar-home-tab" data-toggle="tab"><i class="fa fa-home"></i></a></li>
+			<li><a href="#control-sidebar-settings-tab" data-toggle="tab"><i class="fa fa-gears"></i></a></li>
+		</ul>
+		<!-- Tab panes -->
+		<div class="tab-content">
+			<!-- Home tab content -->
+			<div class="tab-pane active" id="control-sidebar-home-tab">
+				<h3 class="control-sidebar-heading">近期活动</h3>
+				<ul class="control-sidebar-menu">
+					<li>
+						<a href="javascript::;">
+							<i class="menu-icon fa fa-birthday-cake bg-red"></i>
+							<div class="menu-info">
+								<h4 class="control-sidebar-subheading">张三今天过生日</h4>
+								<p>2015-09-10</p>
+							</div>
+						</a>
+					</li>
+					<li>
+						<a href="javascript::;"> 
+							<i class="menu-icon fa fa-user bg-yellow"></i>
+							<div class="menu-info">
+								<h4 class="control-sidebar-subheading">Frodo 更新了资料</h4>
+								<p>更新手机号码 +1(800)555-1234</p>
+							</div>
+						</a>
+					</li>
+					<li>
+						<a href="javascript::;"> 
+							<i class="menu-icon fa fa-envelope-o bg-light-blue"></i>
+							<div class="menu-info">
+								<h4 class="control-sidebar-subheading">Nora 加入邮件列表</h4>
+								<p>nora@example.com</p>
+							</div>
+						</a>
+					</li>
+					<li>
+						<a href="javascript::;">
+						<i class="menu-icon fa fa-file-code-o bg-green"></i>
+						<div class="menu-info">
+							<h4 class="control-sidebar-subheading">001号定时作业调度</h4>
+							<p>5秒前执行</p>
+						</div>
+						</a>
+					</li>
+				</ul>
+				<!-- /.control-sidebar-menu -->
+			</div>
+			<!-- /.tab-pane -->
+
+			<!-- Settings tab content -->
+			<div class="tab-pane" id="control-sidebar-settings-tab">
+				<form method="post">
+					<h3 class="control-sidebar-heading">个人设置</h3>
+					<div class="form-group">
+						<label class="control-sidebar-subheading"> 左侧菜单自适应
+							<input type="checkbox" class="pull-right" checked>
+						</label>
+						<p>左侧菜单栏样式自适应</p>
+					</div>
+					<!-- /.form-group -->
+
+				</form>
+			</div>
+			<!-- /.tab-pane -->
+		</div>
+	</aside>
+	<!-- /.control-sidebar -->
+	<!-- Add the sidebar's background. This div must be placed immediately after the control sidebar -->
+	<div class="control-sidebar-bg"></div>
+</#macro>
+
+<#macro commonFooter >
+	<footer class="main-footer">
+		<div class="pull-right hidden-xs">
+			<b>Version</b> 1.0
+		</div>
+		<strong>Copyright &copy; 2015-2015 &nbsp;
+			<a href="https://github.com/xuxueli/xxl-job" target="_blank" >github</a>&nbsp;
+			<a href="http://www.cnblogs.com/xuxueli/p/5021979.html" target="_blank" >cnblog</a>.
+		</strong> All rights reserved.
+	</footer>
+</#macro>
+
+<#macro comAlert >
+	<!-- ComAlert.模态框Modal -->
+	<div class="modal fade" id="ComAlert" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+		<div class="modal-dialog">
+			<div class="modal-content">
+				<!--	<div class="modal-header"><h4 class="modal-title"><strong>提示:</strong></h4></div>	-->
+	         	<div class="modal-body"><div class="alert alert-success"></div></div>
+	         	<div class="modal-footer">
+	         		<div class="text-center" >
+	            		<button type="button" class="btn btn-default ok" data-dismiss="modal" >确认</button>
+	            	</div>
+	         	</div>
+			</div>
+		</div>
+	</div>
+	<!-- ComConfirm.模态框Modal -->
+	<div class="modal fade" id="ComConfirm" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+		<div class="modal-dialog">
+			<div class="modal-content">
+	         	<div class="modal-body"><div class="alert alert-success"></div></div>
+	         	<div class="modal-footer">
+	         		<div class="text-center" >
+	            		<button type="button" class="btn btn-primary ok" data-dismiss="modal" >确认</button>
+	            		<button type="button" class="btn btn-default cancel" data-dismiss="modal" >取消</button>
+	            	</div>
+	         	</div>
+			</div>
+		</div>
+	</div>
+	<script>
+		// 通用提示
+		var ComAlert = {
+			show:function(type, msg, callback){
+				// 弹框初始
+				if (type == 1) {
+					$('#ComAlert .alert').attr('class', 'alert alert-success');
+				} else {
+					$('#ComAlert .alert').attr('class', 'alert alert-warning');
+				}
+				$('#ComAlert .alert').html(msg);
+				$('#ComAlert').modal('show');
+				
+				$('#ComAlert .ok').click(function(){
+					$('#ComAlert').modal('hide');
+					if(typeof callback == 'function') {
+						callback();
+					}
+				});
+				
+				// $("#ComAlert").on('hide.bs.modal', function () {	});	// 监听关闭
+			}
+		};
+		// 通用确认弹框
+		var ComConfirm = {
+			show:function(msg, callback){
+				// 弹框初始
+				$('#ComConfirm .alert').attr('class', 'alert alert-warning');
+				$('#ComConfirm .alert').html(msg);
+				$('#ComConfirm').modal('show');
+				
+				$('#ComConfirm .ok').unbind("click");	// 解绑陈旧事件
+				$('#ComConfirm .ok').click(function(){
+					$('#ComConfirm').modal('hide');
+					if(typeof callback == 'function') {
+						callback();
+						return;
+					}
+				});
+				
+				$('#ComConfirm .cancel').click(function(){
+					$('#ComConfirm').modal('hide');
+					return;
+				});
+			}
+		};
+	</script>
+</#macro>

+ 1 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/template/common/common.result.ftl

@@ -0,0 +1 @@
+${result?if_exists}

+ 76 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/template/job/help.ftl

@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+  	<title>调度中心</title>
+  	<#import "/common/common.macro.ftl" as netCommon>
+	<@netCommon.commonStyle />
+</head>
+<body class="hold-transition skin-blue sidebar-mini">
+<div class="wrapper">
+	<!-- header -->
+	<@netCommon.commonHeader />
+	<!-- left -->
+	<@netCommon.commonLeft />
+	
+	<!-- Content Wrapper. Contains page content -->
+	<div class="content-wrapper">
+		<!-- Content Header (Page header) -->
+		<section class="content-header">
+			<h1>使用教程<small>调度管理平台</small></h1>
+			<ol class="breadcrumb">
+				<li><a><i class="fa fa-dashboard"></i>调度中心</a></li>
+				<li class="active">使用教程</li>
+			</ol>
+		</section>
+
+		<!-- Main content -->
+		<section class="content">
+			<div class="callout callout-info">
+				<h4>简介:DIANPING_CLOCK</h4>
+				<p>基于quartz封装实现的的集群任务调度管理平台.</p>
+				<p></p>
+            </div>
+            <div class="callout callout-default">
+				<h4>特点:</h4>
+				<p>1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手.</p>
+				<p>2、动态:支持动态修改任务状态,动态暂停/恢复任务,即时生效.</p>
+				<p>3、集群:任务信息持久化到mysql中,支持Job服务器集群(高可用),一个任务只会在其中一台服务器上执行.</p>
+            </div>
+            
+            <div class="callout callout-default">
+				<h4>分层模型:</h4>
+				<p>1、基础:基于quartz封装底层调度层,通过CORN自定义任务执行周期,最终执行自定义JobBean的execute方法,如需多个任务,需要开发多个JobBean实现.</p>
+				<p>2、分层:上述基础调度模型存在一定局限,调度层和任务层耦合,当新任务上线势必影响任务的正常调度,因此规划将调度系统分层为:调度层 + 任务层 + 通讯层.</p>
+				<p>
+				 	<div class="row">
+				      	<div class="col-xs-offset-1 col-xs-11">
+				      		<p>》调度模块:维护任务的调度信息,负责定时/周期性的发出调度请求.</p>
+							<p>》任务模块:具体的任务逻辑,负责接收调度模块的调度请求,执行任务逻辑.</p>
+							<p>》通讯模块:负责调度模块和任务模块之间的通讯.</p>
+							<p>(总而言之,一条完整任务由 “调度信息” 和 “任务信息” 组成.)</p>
+				      	</div>      
+			   		</div>
+				</p>
+            </div>
+            
+            <div class="callout callout-default">
+				<h4>调度属性解析 : 发出HTTP调度请求</h4>
+				<p>1、调度Key【必填】:调度信息的全局唯一标识.</p>
+				<p>2、调度Corn【必填】:调度执行的时间表达式.</p>
+				<p>3、调度描述【必填】:调度的简述.</p>
+				<p>4、调度URL【必填】:调度执行时发出HTTP请求的目标URL地址.</p>
+				<p>5、+args【选填】:调度执行时发出HTTP请求的附带的POST参数.</p>
+            </div>
+		</section>
+		<!-- /.content -->
+	</div>
+	<!-- /.content-wrapper -->
+	
+	<!-- footer -->
+	<@netCommon.commonFooter />
+	<!-- control -->
+	<@netCommon.commonControl />
+</div>
+<@netCommon.commonScript />
+</body>
+</html>

+ 195 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/template/job/index.ftl

@@ -0,0 +1,195 @@
+<!DOCTYPE html>
+<html>
+<head>
+  	<title>调度中心</title>
+  	<#import "/common/common.macro.ftl" as netCommon>
+	<@netCommon.commonStyle />
+	<!-- DataTables -->
+  	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
+  
+</head>
+<body class="hold-transition skin-blue sidebar-mini">
+<div class="wrapper">
+	<!-- header -->
+	<@netCommon.commonHeader />
+	<!-- left -->
+	<@netCommon.commonLeft />
+	
+	<!-- Content Wrapper. Contains page content -->
+	<div class="content-wrapper">
+		<!-- Content Header (Page header) -->
+		<section class="content-header">
+			<h1>调度中心<small>调度管理</small></h1>
+			<ol class="breadcrumb">
+				<li><a><i class="fa fa-dashboard"></i>调度中心</a></li>
+				<li class="active">调度管理</li>
+			</ol>
+		</section>
+		
+		<!-- Main content -->
+	    <section class="content">
+			<div class="row">
+				<div class="col-xs-12">
+					<div class="box">
+			            <div class="box-header">
+			            	<h3 class="box-title">调度列表</h3>
+			            	<button class="btn btn-info btn-xs add" type="button">+新增任务</button>
+			            </div>
+			            <div class="box-body">
+			              	<table id="job_list" class="table table-bordered table-striped">
+				                <thead>
+					            	<tr>
+					                	<th>调度key</th>
+					                  	<th>cron</th>
+					                  	<!--<th>类路径</th>-->
+					                  	<th>参数</th>
+					                  	<th>状态</th>
+					                  	<th>操作</th>
+					                </tr>
+				                </thead>
+				                <tbody>
+			                		<#if jobList?exists && jobList?size gt 0>
+									<#list jobList as item>
+									<tr>
+					            		<td>${item['TriggerKey'].name}</td>
+					                  	<td>${item['Trigger'].cronExpression}</td>
+					                  	<!--<td>${item['JobDetail'].jobClass}</td>-->
+					                  	<td>
+					                  		<#assign jobDataMap = item['JobDetail'].jobDataMap />
+					                  		<#if jobDataMap?exists && jobDataMap?keys?size gt 0>
+					                  			<#list jobDataMap?keys as key>
+					                  				${key}	=	${jobDataMap[key]}	<br>
+					                  			</#list>
+					                  		</#if>
+					                  	</td>
+					                  	<td state="${item['TriggerState']}" >
+					                  		<#if item['TriggerState'] == 'NORMAL'>
+					                  			<button class="btn btn-block btn-success" type="button">运行ing</button>
+					                  		<#elseif item['TriggerState'] == 'PAUSED'>
+					                  			<button class="btn btn-block btn-warning" type="button">暂停ing</button>
+					                  		<#else>
+					                  			<button class="btn btn-block" type="button">${item['TriggerState']}</button>
+					                  		</#if>
+					                  	</td>
+					                  	<td>
+											<p name="${item['TriggerKey'].name}" group="${item['TriggerKey'].group}" 
+												cronExpression="${item['Trigger'].cronExpression}" jobClassName="${item['JobDetail'].jobClass}" jobDesc="${job_desc?if_exists}" >
+												<#if item['TriggerState'] == 'NORMAL'>
+													<button class="btn btn-info btn-xs job_operate" type="job_pause" type="button">暂停</button>
+												<#elseif item['TriggerState'] == 'PAUSED'>
+													<button class="btn btn-info btn-xs job_operate" type="job_resume" type="button">恢复</button>
+												</#if>
+												<button class="btn btn-info btn-xs job_operate" type="job_trigger" type="button">执行一次</button>
+											  	<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>
+												<button class="btn btn-info btn-xs update" type="button">更新corn</button>
+											</p>
+					                  	</td>
+					                </tr>
+									</#list>
+									</#if>
+				                </tbody>
+				                <tfoot>
+					            	<tr>
+					                  	<th>调度key</th>
+					                  	<th>cron</th>
+					                  	<!--<th>类路径</th>-->
+					                  	<th>参数</th>
+					                  	<th>状态</th>
+					                  	<th>操作</th>
+					                </tr>
+				                </tfoot>
+							</table>
+						</div>
+					</div>
+				</div>
+			</div>
+	    </section>
+	</div>
+	
+	<!-- footer -->
+	<@netCommon.commonFooter />
+	<!-- control -->
+	<@netCommon.commonControl />
+</div>
+
+<!-- job新增.模态框 -->
+<div class="modal fade" id="addModal" tabindex="-1" role="dialog"  aria-hidden="true">
+	<div class="modal-dialog">
+		<div class="modal-content">
+			<div class="modal-header">
+            	<h4 class="modal-title" >新增调度信息</h4>
+         	</div>
+         	<div class="modal-body">
+				<form class="form-horizontal form" role="form" >
+					<div class="form-group">
+						<label for="firstname" class="col-sm-3 control-label">任务Key</label>
+						<div class="col-sm-9"><input type="text" class="form-control" name="triggerKeyName" placeholder="请输入任务Key" minlength="4" maxlength="100" ></div>
+					</div>
+					<div class="form-group">
+						<label for="lastname" class="col-sm-3 control-label">任务Corn</label>
+						<div class="col-sm-9"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn[允许修改]" maxlength="100" ></div>
+					</div>
+					<div class="form-group">
+						<label for="lastname" class="col-sm-3 control-label">任务描述</label>
+						<div class="col-sm-9"><input type="text" class="form-control" name="job_desc" placeholder="请输入任务描述[不支持修改]" maxlength="200" ></div>
+					</div>
+					<div class="form-group">
+						<label for="lastname" class="col-sm-3 control-label">任务URL</label>
+						<div class="col-sm-9"><input type="text" class="form-control" name="job_url" placeholder="请输入任务URL[不支持修改]" maxlength="200" ></div>
+					</div>
+					<div class="form-group">
+						<label for="lastname" class="col-sm-3 control-label">任务handler</label>
+						<div class="col-sm-9"><input type="text" class="form-control" name="handleName" placeholder="请输入任务handler[不支持修改]" maxlength="200" ></div>
+					</div>
+					<div class="form-group">
+						<div class="col-sm-offset-3 col-sm-9">
+							<button type="submit" class="btn btn-primary"  >保存</button>
+							<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
+							<button type="button" class="btn btn-info pull-right addParam">+ arg</button>
+						</div>
+					</div>
+				</form>
+         	</div>
+		</div>
+	</div>
+</div>
+
+<!-- 更新.模态框 -->
+<div class="modal fade" id="updateModal" tabindex="-1" role="dialog"  aria-hidden="true">
+	<div class="modal-dialog">
+		<div class="modal-content">
+			<div class="modal-header">
+            	<h4 class="modal-title" >更新corn</h4>
+         	</div>
+         	<div class="modal-body">
+				<form class="form-horizontal form" role="form" >
+					<div class="form-group">
+						<label for="firstname" class="col-sm-2 control-label">任务Key</label>
+						<div class="col-sm-10"><input type="text" class="form-control" name="triggerKeyName" placeholder="请输入任务Key" minlength="4" maxlength="100" readonly ></div>
+					</div>
+					<div class="form-group">
+						<label for="lastname" class="col-sm-2 control-label">任务Corn</label>
+						<div class="col-sm-10"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn" maxlength="100" ></div>
+					</div>
+					<div class="form-group">
+						<div class="col-sm-offset-2 col-sm-10">
+							<button type="submit" class="btn btn-primary"  >保存</button>
+							<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
+						</div>
+					</div>
+				</form>
+         	</div>
+		</div>
+	</div>
+</div>
+
+<@netCommon.commonScript />
+<@netCommon.comAlert />
+<!-- DataTables -->
+<script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>
+<script src="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.min.js"></script>
+<script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
+<script>var base_url = '${request.contextPath}';</script>
+<script src="${request.contextPath}/static/js/job.index.1.js"></script>
+</body>
+</html>

+ 63 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/WEB-INF/web.xml

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+	id="WebApp_ID" version="2.5">
+	<display-name>dianping-job-web</display-name>
+
+	<context-param>
+		<param-name>contextConfigLocation</param-name>
+		<param-value>classpath*:applicationcontext-*.xml</param-value>
+	</context-param>
+
+	<listener>
+		<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
+	</listener>
+	<listener>
+		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+	</listener>
+
+	<filter>
+		<filter-name>encodingFilter</filter-name>
+		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
+		<init-param>
+			<param-name>encoding</param-name>
+			<param-value>UTF-8</param-value>
+		</init-param>
+		<init-param>
+			<param-name>forceEncoding</param-name>
+			<param-value>true</param-value>
+		</init-param>
+	</filter>
+	<filter-mapping>
+		<filter-name>encodingFilter</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
+
+	<servlet>
+		<servlet-name>springmvc</servlet-name>
+		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+		<init-param>
+			<param-name>contextConfigLocation</param-name>
+			<param-value>classpath*:springmvc-context.xml</param-value>
+		</init-param>
+		<load-on-startup>1</load-on-startup>
+	</servlet>
+	<servlet-mapping>
+		<servlet-name>springmvc</servlet-name>
+		<url-pattern>/</url-pattern>
+	</servlet-mapping>
+
+	<welcome-file-list>
+		<welcome-file>index.html</welcome-file>
+	</welcome-file-list>
+	<error-page>
+		<error-code>404</error-code>
+		<location>/500.html</location>
+	</error-page>
+	<error-page>
+		<error-code>500</error-code>
+		<location>/500.html</location>
+	</error-page>
+
+</web-app>

文件差異過大導致無法顯示
+ 1 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/css/bootstrap.css.map


文件差異過大導致無法顯示
+ 5 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/css/bootstrap.min.css


二進制
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/fonts/glyphicons-halflings-regular.eot


文件差異過大導致無法顯示
+ 288 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/fonts/glyphicons-halflings-regular.svg


二進制
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/fonts/glyphicons-halflings-regular.ttf


二進制
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/fonts/glyphicons-halflings-regular.woff


二進制
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/fonts/glyphicons-halflings-regular.woff2


文件差異過大導致無法顯示
+ 7 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/bootstrap/js/bootstrap.min.js


文件差異過大導致無法顯示
+ 7 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/dist/css/AdminLTE.min.css


文件差異過大導致無法顯示
+ 1 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/dist/css/skins/_all-skins.min.css


文件差異過大導致無法顯示
+ 13 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/dist/js/app.min.js


+ 210 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/dist/js/pages/dashboard.js

@@ -0,0 +1,210 @@
+/*
+ * Author: Abdullah A Almsaeed
+ * Date: 4 Jan 2014
+ * Description:
+ *      This is a demo file used only for the main dashboard (index.html)
+ **/
+
+$(function () {
+
+  "use strict";
+
+  //Make the dashboard widgets sortable Using jquery UI
+  $(".connectedSortable").sortable({
+    placeholder: "sort-highlight",
+    connectWith: ".connectedSortable",
+    handle: ".box-header, .nav-tabs",
+    forcePlaceholderSize: true,
+    zIndex: 999999
+  });
+  $(".connectedSortable .box-header, .connectedSortable .nav-tabs-custom").css("cursor", "move");
+
+  //jQuery UI sortable for the todo list
+  $(".todo-list").sortable({
+    placeholder: "sort-highlight",
+    handle: ".handle",
+    forcePlaceholderSize: true,
+    zIndex: 999999
+  });
+
+  //bootstrap WYSIHTML5 - text editor
+  $(".textarea").wysihtml5();
+
+  $('.daterange').daterangepicker({
+    ranges: {
+      'Today': [moment(), moment()],
+      'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
+      'Last 7 Days': [moment().subtract(6, 'days'), moment()],
+      'Last 30 Days': [moment().subtract(29, 'days'), moment()],
+      'This Month': [moment().startOf('month'), moment().endOf('month')],
+      'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
+    },
+    startDate: moment().subtract(29, 'days'),
+    endDate: moment()
+  }, function (start, end) {
+    window.alert("You chose: " + start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY'));
+  });
+
+  /* jQueryKnob */
+  $(".knob").knob();
+
+  //jvectormap data
+  var visitorsData = {
+    "US": 398, //USA
+    "SA": 400, //Saudi Arabia
+    "CA": 1000, //Canada
+    "DE": 500, //Germany
+    "FR": 760, //France
+    "CN": 300, //China
+    "AU": 700, //Australia
+    "BR": 600, //Brazil
+    "IN": 800, //India
+    "GB": 320, //Great Britain
+    "RU": 3000 //Russia
+  };
+  //World map by jvectormap
+  $('#world-map').vectorMap({
+    map: 'world_mill_en',
+    backgroundColor: "transparent",
+    regionStyle: {
+      initial: {
+        fill: '#e4e4e4',
+        "fill-opacity": 1,
+        stroke: 'none',
+        "stroke-width": 0,
+        "stroke-opacity": 1
+      }
+    },
+    series: {
+      regions: [{
+        values: visitorsData,
+        scale: ["#92c1dc", "#ebf4f9"],
+        normalizeFunction: 'polynomial'
+      }]
+    },
+    onRegionLabelShow: function (e, el, code) {
+      if (typeof visitorsData[code] != "undefined")
+        el.html(el.html() + ': ' + visitorsData[code] + ' new visitors');
+    }
+  });
+
+  //Sparkline charts
+  var myvalues = [1000, 1200, 920, 927, 931, 1027, 819, 930, 1021];
+  $('#sparkline-1').sparkline(myvalues, {
+    type: 'line',
+    lineColor: '#92c1dc',
+    fillColor: "#ebf4f9",
+    height: '50',
+    width: '80'
+  });
+  myvalues = [515, 519, 520, 522, 652, 810, 370, 627, 319, 630, 921];
+  $('#sparkline-2').sparkline(myvalues, {
+    type: 'line',
+    lineColor: '#92c1dc',
+    fillColor: "#ebf4f9",
+    height: '50',
+    width: '80'
+  });
+  myvalues = [15, 19, 20, 22, 33, 27, 31, 27, 19, 30, 21];
+  $('#sparkline-3').sparkline(myvalues, {
+    type: 'line',
+    lineColor: '#92c1dc',
+    fillColor: "#ebf4f9",
+    height: '50',
+    width: '80'
+  });
+
+  //The Calender
+  $("#calendar").datepicker();
+
+  //SLIMSCROLL FOR CHAT WIDGET
+  $('#chat-box').slimScroll({
+    height: '250px'
+  });
+
+  /* Morris.js Charts */
+  // Sales chart
+  var area = new Morris.Area({
+    element: 'revenue-chart',
+    resize: true,
+    data: [
+      {y: '2011 Q1', item1: 2666, item2: 2666},
+      {y: '2011 Q2', item1: 2778, item2: 2294},
+      {y: '2011 Q3', item1: 4912, item2: 1969},
+      {y: '2011 Q4', item1: 3767, item2: 3597},
+      {y: '2012 Q1', item1: 6810, item2: 1914},
+      {y: '2012 Q2', item1: 5670, item2: 4293},
+      {y: '2012 Q3', item1: 4820, item2: 3795},
+      {y: '2012 Q4', item1: 15073, item2: 5967},
+      {y: '2013 Q1', item1: 10687, item2: 4460},
+      {y: '2013 Q2', item1: 8432, item2: 5713}
+    ],
+    xkey: 'y',
+    ykeys: ['item1', 'item2'],
+    labels: ['Item 1', 'Item 2'],
+    lineColors: ['#a0d0e0', '#3c8dbc'],
+    hideHover: 'auto'
+  });
+  var line = new Morris.Line({
+    element: 'line-chart',
+    resize: true,
+    data: [
+      {y: '2011 Q1', item1: 2666},
+      {y: '2011 Q2', item1: 2778},
+      {y: '2011 Q3', item1: 4912},
+      {y: '2011 Q4', item1: 3767},
+      {y: '2012 Q1', item1: 6810},
+      {y: '2012 Q2', item1: 5670},
+      {y: '2012 Q3', item1: 4820},
+      {y: '2012 Q4', item1: 15073},
+      {y: '2013 Q1', item1: 10687},
+      {y: '2013 Q2', item1: 8432}
+    ],
+    xkey: 'y',
+    ykeys: ['item1'],
+    labels: ['Item 1'],
+    lineColors: ['#efefef'],
+    lineWidth: 2,
+    hideHover: 'auto',
+    gridTextColor: "#fff",
+    gridStrokeWidth: 0.4,
+    pointSize: 4,
+    pointStrokeColors: ["#efefef"],
+    gridLineColor: "#efefef",
+    gridTextFamily: "Open Sans",
+    gridTextSize: 10
+  });
+
+  //Donut Chart
+  var donut = new Morris.Donut({
+    element: 'sales-chart',
+    resize: true,
+    colors: ["#3c8dbc", "#f56954", "#00a65a"],
+    data: [
+      {label: "Download Sales", value: 12},
+      {label: "In-Store Sales", value: 30},
+      {label: "Mail-Order Sales", value: 20}
+    ],
+    hideHover: 'auto'
+  });
+
+  //Fix for charts under tabs
+  $('.box ul.nav a').on('shown.bs.tab', function () {
+    area.redraw();
+    donut.redraw();
+    line.redraw();
+  });
+
+  /* The todo list plugin */
+  $(".todo-list").todolist({
+    onCheck: function (ele) {
+      window.console.log("The element has been checked");
+      return ele;
+    },
+    onUncheck: function (ele) {
+      window.console.log("The element has been unchecked");
+      return ele;
+    }
+  });
+
+});

+ 274 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/dist/js/pages/dashboard2.js

@@ -0,0 +1,274 @@
+$(function () {
+
+  'use strict';
+
+  /* ChartJS
+   * -------
+   * Here we will create a few charts using ChartJS
+   */
+
+  //-----------------------
+  //- MONTHLY SALES CHART -
+  //-----------------------
+
+  // Get context with jQuery - using jQuery's .get() method.
+  var salesChartCanvas = $("#salesChart").get(0).getContext("2d");
+  // This will get the first returned node in the jQuery collection.
+  var salesChart = new Chart(salesChartCanvas);
+
+  var salesChartData = {
+    labels: ["January", "February", "March", "April", "May", "June", "July"],
+    datasets: [
+      {
+        label: "Electronics",
+        fillColor: "rgb(210, 214, 222)",
+        strokeColor: "rgb(210, 214, 222)",
+        pointColor: "rgb(210, 214, 222)",
+        pointStrokeColor: "#c1c7d1",
+        pointHighlightFill: "#fff",
+        pointHighlightStroke: "rgb(220,220,220)",
+        data: [65, 59, 80, 81, 56, 55, 40]
+      },
+      {
+        label: "Digital Goods",
+        fillColor: "rgba(60,141,188,0.9)",
+        strokeColor: "rgba(60,141,188,0.8)",
+        pointColor: "#3b8bba",
+        pointStrokeColor: "rgba(60,141,188,1)",
+        pointHighlightFill: "#fff",
+        pointHighlightStroke: "rgba(60,141,188,1)",
+        data: [28, 48, 40, 19, 86, 27, 90]
+      }
+    ]
+  };
+
+  var salesChartOptions = {
+    //Boolean - If we should show the scale at all
+    showScale: true,
+    //Boolean - Whether grid lines are shown across the chart
+    scaleShowGridLines: false,
+    //String - Colour of the grid lines
+    scaleGridLineColor: "rgba(0,0,0,.05)",
+    //Number - Width of the grid lines
+    scaleGridLineWidth: 1,
+    //Boolean - Whether to show horizontal lines (except X axis)
+    scaleShowHorizontalLines: true,
+    //Boolean - Whether to show vertical lines (except Y axis)
+    scaleShowVerticalLines: true,
+    //Boolean - Whether the line is curved between points
+    bezierCurve: true,
+    //Number - Tension of the bezier curve between points
+    bezierCurveTension: 0.3,
+    //Boolean - Whether to show a dot for each point
+    pointDot: false,
+    //Number - Radius of each point dot in pixels
+    pointDotRadius: 4,
+    //Number - Pixel width of point dot stroke
+    pointDotStrokeWidth: 1,
+    //Number - amount extra to add to the radius to cater for hit detection outside the drawn point
+    pointHitDetectionRadius: 20,
+    //Boolean - Whether to show a stroke for datasets
+    datasetStroke: true,
+    //Number - Pixel width of dataset stroke
+    datasetStrokeWidth: 2,
+    //Boolean - Whether to fill the dataset with a color
+    datasetFill: true,
+    //String - A legend template
+    legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].lineColor%>\"></span><%=datasets[i].label%></li><%}%></ul>",
+    //Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
+    maintainAspectRatio: true,
+    //Boolean - whether to make the chart responsive to window resizing
+    responsive: true
+  };
+
+  //Create the line chart
+  salesChart.Line(salesChartData, salesChartOptions);
+
+  //---------------------------
+  //- END MONTHLY SALES CHART -
+  //---------------------------
+
+  //-------------
+  //- PIE CHART -
+  //-------------
+  // Get context with jQuery - using jQuery's .get() method.
+  var pieChartCanvas = $("#pieChart").get(0).getContext("2d");
+  var pieChart = new Chart(pieChartCanvas);
+  var PieData = [
+    {
+      value: 700,
+      color: "#f56954",
+      highlight: "#f56954",
+      label: "Chrome"
+    },
+    {
+      value: 500,
+      color: "#00a65a",
+      highlight: "#00a65a",
+      label: "IE"
+    },
+    {
+      value: 400,
+      color: "#f39c12",
+      highlight: "#f39c12",
+      label: "FireFox"
+    },
+    {
+      value: 600,
+      color: "#00c0ef",
+      highlight: "#00c0ef",
+      label: "Safari"
+    },
+    {
+      value: 300,
+      color: "#3c8dbc",
+      highlight: "#3c8dbc",
+      label: "Opera"
+    },
+    {
+      value: 100,
+      color: "#d2d6de",
+      highlight: "#d2d6de",
+      label: "Navigator"
+    }
+  ];
+  var pieOptions = {
+    //Boolean - Whether we should show a stroke on each segment
+    segmentShowStroke: true,
+    //String - The colour of each segment stroke
+    segmentStrokeColor: "#fff",
+    //Number - The width of each segment stroke
+    segmentStrokeWidth: 1,
+    //Number - The percentage of the chart that we cut out of the middle
+    percentageInnerCutout: 50, // This is 0 for Pie charts
+    //Number - Amount of animation steps
+    animationSteps: 100,
+    //String - Animation easing effect
+    animationEasing: "easeOutBounce",
+    //Boolean - Whether we animate the rotation of the Doughnut
+    animateRotate: true,
+    //Boolean - Whether we animate scaling the Doughnut from the centre
+    animateScale: false,
+    //Boolean - whether to make the chart responsive to window resizing
+    responsive: true,
+    // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
+    maintainAspectRatio: false,
+    //String - A legend template
+    legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>",
+    //String - A tooltip template
+    tooltipTemplate: "<%=value %> <%=label%> users"
+  };
+  //Create pie or douhnut chart
+  // You can switch between pie and douhnut using the method below.
+  pieChart.Doughnut(PieData, pieOptions);
+  //-----------------
+  //- END PIE CHART -
+  //-----------------
+
+  /* jVector Maps
+   * ------------
+   * Create a world map with markers
+   */
+  $('#world-map-markers').vectorMap({
+    map: 'world_mill_en',
+    normalizeFunction: 'polynomial',
+    hoverOpacity: 0.7,
+    hoverColor: false,
+    backgroundColor: 'transparent',
+    regionStyle: {
+      initial: {
+        fill: 'rgba(210, 214, 222, 1)',
+        "fill-opacity": 1,
+        stroke: 'none',
+        "stroke-width": 0,
+        "stroke-opacity": 1
+      },
+      hover: {
+        "fill-opacity": 0.7,
+        cursor: 'pointer'
+      },
+      selected: {
+        fill: 'yellow'
+      },
+      selectedHover: {}
+    },
+    markerStyle: {
+      initial: {
+        fill: '#00a65a',
+        stroke: '#111'
+      }
+    },
+    markers: [
+      {latLng: [41.90, 12.45], name: 'Vatican City'},
+      {latLng: [43.73, 7.41], name: 'Monaco'},
+      {latLng: [-0.52, 166.93], name: 'Nauru'},
+      {latLng: [-8.51, 179.21], name: 'Tuvalu'},
+      {latLng: [43.93, 12.46], name: 'San Marino'},
+      {latLng: [47.14, 9.52], name: 'Liechtenstein'},
+      {latLng: [7.11, 171.06], name: 'Marshall Islands'},
+      {latLng: [17.3, -62.73], name: 'Saint Kitts and Nevis'},
+      {latLng: [3.2, 73.22], name: 'Maldives'},
+      {latLng: [35.88, 14.5], name: 'Malta'},
+      {latLng: [12.05, -61.75], name: 'Grenada'},
+      {latLng: [13.16, -61.23], name: 'Saint Vincent and the Grenadines'},
+      {latLng: [13.16, -59.55], name: 'Barbados'},
+      {latLng: [17.11, -61.85], name: 'Antigua and Barbuda'},
+      {latLng: [-4.61, 55.45], name: 'Seychelles'},
+      {latLng: [7.35, 134.46], name: 'Palau'},
+      {latLng: [42.5, 1.51], name: 'Andorra'},
+      {latLng: [14.01, -60.98], name: 'Saint Lucia'},
+      {latLng: [6.91, 158.18], name: 'Federated States of Micronesia'},
+      {latLng: [1.3, 103.8], name: 'Singapore'},
+      {latLng: [1.46, 173.03], name: 'Kiribati'},
+      {latLng: [-21.13, -175.2], name: 'Tonga'},
+      {latLng: [15.3, -61.38], name: 'Dominica'},
+      {latLng: [-20.2, 57.5], name: 'Mauritius'},
+      {latLng: [26.02, 50.55], name: 'Bahrain'},
+      {latLng: [0.33, 6.73], name: 'São Tomé and Príncipe'}
+    ]
+  });
+
+  /* SPARKLINE CHARTS
+   * ----------------
+   * Create a inline charts with spark line
+   */
+
+  //-----------------
+  //- SPARKLINE BAR -
+  //-----------------
+  $('.sparkbar').each(function () {
+    var $this = $(this);
+    $this.sparkline('html', {
+      type: 'bar',
+      height: $this.data('height') ? $this.data('height') : '30',
+      barColor: $this.data('color')
+    });
+  });
+
+  //-----------------
+  //- SPARKLINE PIE -
+  //-----------------
+  $('.sparkpie').each(function () {
+    var $this = $(this);
+    $this.sparkline('html', {
+      type: 'pie',
+      height: $this.data('height') ? $this.data('height') : '90',
+      sliceColors: $this.data('color')
+    });
+  });
+
+  //------------------
+  //- SPARKLINE LINE -
+  //------------------
+  $('.sparkline').each(function () {
+    var $this = $(this);
+    $this.sparkline('html', {
+      type: 'line',
+      height: $this.data('height') ? $this.data('height') : '90',
+      width: '100%',
+      lineColor: $this.data('linecolor'),
+      fillColor: $this.data('fillcolor'),
+      spotColor: $this.data('spotcolor')
+    });
+  });
+});

+ 372 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/dataTables.bootstrap.css

@@ -0,0 +1,372 @@
+div.dataTables_length label {
+	font-weight: normal;
+	text-align: left;
+	white-space: nowrap;
+}
+
+div.dataTables_length select {
+	width: 75px;
+	display: inline-block;
+}
+
+div.dataTables_filter {
+	text-align: right;
+}
+
+div.dataTables_filter label {
+	font-weight: normal;
+	white-space: nowrap;
+	text-align: left;
+}
+
+div.dataTables_filter input {
+	margin-left: 0.5em;
+	display: inline-block;
+	width: auto;
+}
+
+div.dataTables_info {
+	padding-top: 8px;
+	white-space: nowrap;
+}
+
+div.dataTables_paginate {
+	margin: 0;
+	white-space: nowrap;
+	text-align: right;
+}
+
+div.dataTables_paginate ul.pagination {
+	margin: 2px 0;
+	white-space: nowrap;
+}
+
+@media screen and (max-width: 767px) {
+	div.dataTables_wrapper > div.row > div,
+	div.dataTables_length,
+	div.dataTables_filter,
+	div.dataTables_info,
+	div.dataTables_paginate {
+		text-align: center;
+	}
+
+	div.DTTT {
+		margin-bottom: 0.5em;
+	}
+}
+
+
+table.dataTable td,
+table.dataTable th {
+	-webkit-box-sizing: content-box;
+	-moz-box-sizing: content-box;
+	box-sizing: content-box;
+}
+
+
+table.dataTable {
+	clear: both;
+	margin-top: 6px !important;
+	margin-bottom: 6px !important;
+	max-width: none !important;
+}
+
+table.dataTable thead .sorting,
+table.dataTable thead .sorting_asc,
+table.dataTable thead .sorting_desc,
+table.dataTable thead .sorting_asc_disabled,
+table.dataTable thead .sorting_desc_disabled {
+	cursor: pointer;
+	position: relative;
+}
+
+table.dataTable thead .sorting:after,
+table.dataTable thead .sorting_asc:after,
+table.dataTable thead .sorting_desc:after {
+	position: absolute;
+	top: 8px;
+	right: 8px;
+	display: block;
+	font-family: 'Glyphicons Halflings';
+	opacity: 0.5;
+}
+table.dataTable thead .sorting:after {
+	opacity: 0.2;
+	content: "\e150"; /* sort */
+}
+table.dataTable thead .sorting_asc:after {
+	content: "\e155"; /* sort-by-attributes */
+}
+table.dataTable thead .sorting_desc:after {
+	content: "\e156"; /* sort-by-attributes-alt */
+}
+div.dataTables_scrollBody table.dataTable thead .sorting:after,
+div.dataTables_scrollBody table.dataTable thead .sorting_asc:after,
+div.dataTables_scrollBody table.dataTable thead .sorting_desc:after {
+	display: none;
+}
+
+table.dataTable thead .sorting_asc_disabled:after,
+table.dataTable thead .sorting_desc_disabled:after {
+	color: #eee;
+}
+
+table.dataTable thead > tr > th {
+	padding-right: 30px;
+}
+
+table.dataTable th:active {
+	outline: none;
+}
+
+
+/* Condensed */
+table.dataTable.table-condensed thead > tr > th {
+	padding-right: 20px;
+}
+
+table.dataTable.table-condensed thead .sorting:after,
+table.dataTable.table-condensed thead .sorting_asc:after,
+table.dataTable.table-condensed thead .sorting_desc:after {
+	top: 6px;
+	right: 6px;
+}
+
+/* Scrolling */
+div.dataTables_scrollHead table {
+	margin-bottom: 0 !important;
+	border-bottom-left-radius: 0;
+	border-bottom-right-radius: 0;
+}
+
+div.dataTables_scrollHead table thead tr:last-child th:first-child,
+div.dataTables_scrollHead table thead tr:last-child td:first-child {
+	border-bottom-left-radius: 0 !important;
+	border-bottom-right-radius: 0 !important;
+}
+
+div.dataTables_scrollBody table {
+	border-top: none;
+	margin-top: 0 !important;
+	margin-bottom: 0 !important;
+}
+
+div.dataTables_scrollBody tbody tr:first-child th,
+div.dataTables_scrollBody tbody tr:first-child td {
+	border-top: none;
+}
+
+div.dataTables_scrollFoot table {
+	margin-top: 0 !important;
+	border-top: none;
+}
+
+/* Frustratingly the border-collapse:collapse used by Bootstrap makes the column
+   width calculations when using scrolling impossible to align columns. We have
+   to use separate
+ */
+table.table-bordered.dataTable {
+	border-collapse: separate !important;
+}
+table.table-bordered thead th,
+table.table-bordered thead td {
+	border-left-width: 0;
+	border-top-width: 0;
+}
+table.table-bordered tbody th,
+table.table-bordered tbody td {
+	border-left-width: 0;
+	border-bottom-width: 0;
+}
+table.table-bordered tfoot th,
+table.table-bordered tfoot td {
+    border-left-width: 0;
+    border-bottom-width: 0;
+}
+table.table-bordered th:last-child,
+table.table-bordered td:last-child {
+	border-right-width: 0;
+}
+div.dataTables_scrollHead table.table-bordered {
+	border-bottom-width: 0;
+}
+
+
+
+
+/*
+ * TableTools styles
+ */
+.table.dataTable tbody tr.active td,
+.table.dataTable tbody tr.active th {
+	background-color: #08C;
+	color: white;
+}
+
+.table.dataTable tbody tr.active:hover td,
+.table.dataTable tbody tr.active:hover th {
+	background-color: #0075b0 !important;
+}
+
+.table.dataTable tbody tr.active th > a,
+.table.dataTable tbody tr.active td > a {
+	color: white;
+}
+
+.table-striped.dataTable tbody tr.active:nth-child(odd) td,
+.table-striped.dataTable tbody tr.active:nth-child(odd) th {
+	background-color: #017ebc;
+}
+
+table.DTTT_selectable tbody tr {
+	cursor: pointer;
+}
+
+div.DTTT .btn:hover {
+	text-decoration: none !important;
+}
+
+ul.DTTT_dropdown.dropdown-menu {
+  z-index: 2003;
+}
+
+ul.DTTT_dropdown.dropdown-menu a {
+	color: #333 !important; /* needed only when demo_page.css is included */
+}
+
+ul.DTTT_dropdown.dropdown-menu li {
+	position: relative;
+}
+
+ul.DTTT_dropdown.dropdown-menu li:hover a {
+	background-color: #0088cc;
+	color: white !important;
+}
+
+div.DTTT_collection_background {
+	z-index: 2002;	
+}
+
+/* TableTools information display */
+div.DTTT_print_info {
+	position: fixed;
+	top: 50%;
+	left: 50%;
+	width: 400px;
+	height: 150px;
+	margin-left: -200px;
+	margin-top: -75px;
+	text-align: center;
+	color: #333;
+	padding: 10px 30px;
+	opacity: 0.95;
+
+	background-color: white;
+	border: 1px solid rgba(0, 0, 0, 0.2);
+	border-radius: 6px;
+	
+	-webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.5);
+	        box-shadow: 0 3px 7px rgba(0, 0, 0, 0.5);
+}
+
+div.DTTT_print_info h6 {
+	font-weight: normal;
+	font-size: 28px;
+	line-height: 28px;
+	margin: 1em;
+}
+
+div.DTTT_print_info p {
+	font-size: 14px;
+	line-height: 20px;
+}
+
+div.dataTables_processing {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    width: 100%;
+    height: 60px;
+    margin-left: -50%;
+    margin-top: -25px;
+    padding-top: 20px;
+    padding-bottom: 20px;
+    text-align: center;
+    font-size: 1.2em;
+    background-color: white;
+    background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));
+    background: -webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
+    background: -moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
+    background: -ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
+    background: -o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
+    background: linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
+}
+
+
+
+/*
+ * FixedColumns styles
+ */
+div.DTFC_LeftHeadWrapper table,
+div.DTFC_LeftFootWrapper table,
+div.DTFC_RightHeadWrapper table,
+div.DTFC_RightFootWrapper table,
+table.DTFC_Cloned tr.even {
+    background-color: white;
+    margin-bottom: 0;
+}
+ 
+div.DTFC_RightHeadWrapper table ,
+div.DTFC_LeftHeadWrapper table {
+	border-bottom: none !important;
+    margin-bottom: 0 !important;
+    border-top-right-radius: 0 !important;
+    border-bottom-left-radius: 0 !important;
+    border-bottom-right-radius: 0 !important;
+}
+ 
+div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child,
+div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child,
+div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child,
+div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child {
+    border-bottom-left-radius: 0 !important;
+    border-bottom-right-radius: 0 !important;
+}
+ 
+div.DTFC_RightBodyWrapper table,
+div.DTFC_LeftBodyWrapper table {
+    border-top: none;
+    margin: 0 !important;
+}
+ 
+div.DTFC_RightBodyWrapper tbody tr:first-child th,
+div.DTFC_RightBodyWrapper tbody tr:first-child td,
+div.DTFC_LeftBodyWrapper tbody tr:first-child th,
+div.DTFC_LeftBodyWrapper tbody tr:first-child td {
+    border-top: none;
+}
+ 
+div.DTFC_RightFootWrapper table,
+div.DTFC_LeftFootWrapper table {
+    border-top: none;
+    margin-top: 0 !important;
+}
+
+
+div.DTFC_LeftBodyWrapper table.dataTable thead .sorting:after,
+div.DTFC_LeftBodyWrapper table.dataTable thead .sorting_asc:after,
+div.DTFC_LeftBodyWrapper table.dataTable thead .sorting_desc:after,
+div.DTFC_RightBodyWrapper table.dataTable thead .sorting:after,
+div.DTFC_RightBodyWrapper table.dataTable thead .sorting_asc:after,
+div.DTFC_RightBodyWrapper table.dataTable thead .sorting_desc:after {
+	display: none;
+}
+
+
+/*
+ * FixedHeader styles
+ */
+div.FixedHeader_Cloned table {
+	margin: 0 !important
+}
+

+ 206 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/dataTables.bootstrap.js

@@ -0,0 +1,206 @@
+/*! DataTables Bootstrap 3 integration
+ * ©2011-2014 SpryMedia Ltd - datatables.net/license
+ */
+
+/**
+ * DataTables integration for Bootstrap 3. This requires Bootstrap 3 and
+ * DataTables 1.10 or newer.
+ *
+ * This file sets the defaults and adds options to DataTables to style its
+ * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap
+ * for further information.
+ */
+(function(window, document, undefined){
+
+var factory = function( $, DataTable ) {
+"use strict";
+
+
+/* Set the defaults for DataTables initialisation */
+$.extend( true, DataTable.defaults, {
+	dom:
+		"<'row'<'col-sm-6'l><'col-sm-6'f>>" +
+		"<'row'<'col-sm-12'tr>>" +
+		"<'row'<'col-sm-5'i><'col-sm-7'p>>",
+	renderer: 'bootstrap'
+} );
+
+
+/* Default class modification */
+$.extend( DataTable.ext.classes, {
+	sWrapper:      "dataTables_wrapper form-inline dt-bootstrap",
+	sFilterInput:  "form-control input-sm",
+	sLengthSelect: "form-control input-sm"
+} );
+
+
+/* Bootstrap paging button renderer */
+DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {
+	var api     = new DataTable.Api( settings );
+	var classes = settings.oClasses;
+	var lang    = settings.oLanguage.oPaginate;
+	var btnDisplay, btnClass, counter=0;
+
+	var attach = function( container, buttons ) {
+		var i, ien, node, button;
+		var clickHandler = function ( e ) {
+			e.preventDefault();
+			if ( !$(e.currentTarget).hasClass('disabled') ) {
+				api.page( e.data.action ).draw( false );
+			}
+		};
+
+		for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
+			button = buttons[i];
+
+			if ( $.isArray( button ) ) {
+				attach( container, button );
+			}
+			else {
+				btnDisplay = '';
+				btnClass = '';
+
+				switch ( button ) {
+					case 'ellipsis':
+						btnDisplay = '&hellip;';
+						btnClass = 'disabled';
+						break;
+
+					case 'first':
+						btnDisplay = lang.sFirst;
+						btnClass = button + (page > 0 ?
+							'' : ' disabled');
+						break;
+
+					case 'previous':
+						btnDisplay = lang.sPrevious;
+						btnClass = button + (page > 0 ?
+							'' : ' disabled');
+						break;
+
+					case 'next':
+						btnDisplay = lang.sNext;
+						btnClass = button + (page < pages-1 ?
+							'' : ' disabled');
+						break;
+
+					case 'last':
+						btnDisplay = lang.sLast;
+						btnClass = button + (page < pages-1 ?
+							'' : ' disabled');
+						break;
+
+					default:
+						btnDisplay = button + 1;
+						btnClass = page === button ?
+							'active' : '';
+						break;
+				}
+
+				if ( btnDisplay ) {
+					node = $('<li>', {
+							'class': classes.sPageButton+' '+btnClass,
+							'id': idx === 0 && typeof button === 'string' ?
+								settings.sTableId +'_'+ button :
+								null
+						} )
+						.append( $('<a>', {
+								'href': '#',
+								'aria-controls': settings.sTableId,
+								'data-dt-idx': counter,
+								'tabindex': settings.iTabIndex
+							} )
+							.html( btnDisplay )
+						)
+						.appendTo( container );
+
+					settings.oApi._fnBindAction(
+						node, {action: button}, clickHandler
+					);
+
+					counter++;
+				}
+			}
+		}
+	};
+
+	// IE9 throws an 'unknown error' if document.activeElement is used
+	// inside an iframe or frame. 
+	var activeEl;
+
+	try {
+		// Because this approach is destroying and recreating the paging
+		// elements, focus is lost on the select button which is bad for
+		// accessibility. So we want to restore focus once the draw has
+		// completed
+		activeEl = $(document.activeElement).data('dt-idx');
+	}
+	catch (e) {}
+
+	attach(
+		$(host).empty().html('<ul class="pagination"/>').children('ul'),
+		buttons
+	);
+
+	if ( activeEl ) {
+		$(host).find( '[data-dt-idx='+activeEl+']' ).focus();
+	}
+};
+
+
+/*
+ * TableTools Bootstrap compatibility
+ * Required TableTools 2.1+
+ */
+if ( DataTable.TableTools ) {
+	// Set the classes that TableTools uses to something suitable for Bootstrap
+	$.extend( true, DataTable.TableTools.classes, {
+		"container": "DTTT btn-group",
+		"buttons": {
+			"normal": "btn btn-default",
+			"disabled": "disabled"
+		},
+		"collection": {
+			"container": "DTTT_dropdown dropdown-menu",
+			"buttons": {
+				"normal": "",
+				"disabled": "disabled"
+			}
+		},
+		"print": {
+			"info": "DTTT_print_info"
+		},
+		"select": {
+			"row": "active"
+		}
+	} );
+
+	// Have the collection use a bootstrap compatible drop down
+	$.extend( true, DataTable.TableTools.DEFAULTS.oTags, {
+		"collection": {
+			"container": "ul",
+			"button": "li",
+			"liner": "a"
+		}
+	} );
+}
+
+}; // /factory
+
+
+// Define as an AMD module if possible
+if ( typeof define === 'function' && define.amd ) {
+	define( ['jquery', 'datatables'], factory );
+}
+else if ( typeof exports === 'object' ) {
+    // Node/CommonJS
+    factory( require('jquery'), require('datatables') );
+}
+else if ( jQuery ) {
+	// Otherwise simply initialise as normal, stopping multiple evaluation
+	factory( jQuery, jQuery.fn.dataTable );
+}
+
+
+})(window, document);
+

文件差異過大導致無法顯示
+ 8 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/dataTables.bootstrap.min.js


二進制
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/images/sort_asc.png


二進制
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/images/sort_asc_disabled.png


二進制
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/images/sort_both.png


二進制
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/images/sort_desc.png


二進制
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/images/sort_desc_disabled.png


+ 455 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/jquery.dataTables.css

@@ -0,0 +1,455 @@
+/*
+ * Table styles
+ */
+table.dataTable {
+  width: 100%;
+  margin: 0 auto;
+  clear: both;
+  border-collapse: separate;
+  border-spacing: 0;
+  /*
+   * Header and footer styles
+   */
+  /*
+   * Body styles
+   */
+}
+table.dataTable thead th,
+table.dataTable tfoot th {
+  font-weight: bold;
+}
+table.dataTable thead th,
+table.dataTable thead td {
+  padding: 10px 18px;
+  border-bottom: 1px solid #111;
+}
+table.dataTable thead th:active,
+table.dataTable thead td:active {
+  outline: none;
+}
+table.dataTable tfoot th,
+table.dataTable tfoot td {
+  padding: 10px 18px 6px 18px;
+  border-top: 1px solid #111;
+}
+table.dataTable thead .sorting,
+table.dataTable thead .sorting_asc,
+table.dataTable thead .sorting_desc {
+  cursor: pointer;
+  *cursor: hand;
+}
+table.dataTable thead .sorting,
+table.dataTable thead .sorting_asc,
+table.dataTable thead .sorting_desc,
+table.dataTable thead .sorting_asc_disabled,
+table.dataTable thead .sorting_desc_disabled {
+  background-repeat: no-repeat;
+  background-position: center right;
+}
+table.dataTable thead .sorting {
+  background-image: url("images/sort_both.png");
+}
+table.dataTable thead .sorting_asc {
+  background-image: url("images/sort_asc.png");
+}
+table.dataTable thead .sorting_desc {
+  background-image: url("images/sort_desc.png");
+}
+table.dataTable thead .sorting_asc_disabled {
+  background-image: url("images/sort_asc_disabled.png");
+}
+table.dataTable thead .sorting_desc_disabled {
+  background-image: url("images/sort_desc_disabled.png");
+}
+table.dataTable tbody tr {
+  background-color: #ffffff;
+}
+table.dataTable tbody tr.selected {
+  background-color: #B0BED9;
+}
+table.dataTable tbody th,
+table.dataTable tbody td {
+  padding: 8px 10px;
+}
+table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
+  border-top: 1px solid #ddd;
+}
+table.dataTable.row-border tbody tr:first-child th,
+table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
+table.dataTable.display tbody tr:first-child td {
+  border-top: none;
+}
+table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
+  border-top: 1px solid #ddd;
+  border-right: 1px solid #ddd;
+}
+table.dataTable.cell-border tbody tr th:first-child,
+table.dataTable.cell-border tbody tr td:first-child {
+  border-left: 1px solid #ddd;
+}
+table.dataTable.cell-border tbody tr:first-child th,
+table.dataTable.cell-border tbody tr:first-child td {
+  border-top: none;
+}
+table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
+  background-color: #f9f9f9;
+}
+table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
+  background-color: #abb9d3;
+}
+table.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {
+  background-color: whitesmoke;
+}
+table.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {
+  background-color: #a9b7d1;
+}
+table.dataTable.order-column tbody tr > .sorting_1,
+table.dataTable.order-column tbody tr > .sorting_2,
+table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
+table.dataTable.display tbody tr > .sorting_2,
+table.dataTable.display tbody tr > .sorting_3 {
+  background-color: #f9f9f9;
+}
+table.dataTable.order-column tbody tr.selected > .sorting_1,
+table.dataTable.order-column tbody tr.selected > .sorting_2,
+table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
+table.dataTable.display tbody tr.selected > .sorting_2,
+table.dataTable.display tbody tr.selected > .sorting_3 {
+  background-color: #acbad4;
+}
+table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
+  background-color: #f1f1f1;
+}
+table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
+  background-color: #f3f3f3;
+}
+table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
+  background-color: whitesmoke;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
+  background-color: #a6b3cd;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
+  background-color: #a7b5ce;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
+  background-color: #a9b6d0;
+}
+table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
+  background-color: #f9f9f9;
+}
+table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
+  background-color: #fbfbfb;
+}
+table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
+  background-color: #fdfdfd;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
+  background-color: #acbad4;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
+  background-color: #adbbd6;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
+  background-color: #afbdd8;
+}
+table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {
+  background-color: #eaeaea;
+}
+table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {
+  background-color: #ebebeb;
+}
+table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {
+  background-color: #eeeeee;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {
+  background-color: #a1aec7;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {
+  background-color: #a2afc8;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {
+  background-color: #a4b2cb;
+}
+table.dataTable.no-footer {
+  border-bottom: 1px solid #111;
+}
+table.dataTable.nowrap th, table.dataTable.nowrap td {
+  white-space: nowrap;
+}
+table.dataTable.compact thead th,
+table.dataTable.compact thead td {
+  padding: 4px 17px 4px 4px;
+}
+table.dataTable.compact tfoot th,
+table.dataTable.compact tfoot td {
+  padding: 4px;
+}
+table.dataTable.compact tbody th,
+table.dataTable.compact tbody td {
+  padding: 4px;
+}
+table.dataTable th.dt-left,
+table.dataTable td.dt-left {
+  text-align: left;
+}
+table.dataTable th.dt-center,
+table.dataTable td.dt-center,
+table.dataTable td.dataTables_empty {
+  text-align: center;
+}
+table.dataTable th.dt-right,
+table.dataTable td.dt-right {
+  text-align: right;
+}
+table.dataTable th.dt-justify,
+table.dataTable td.dt-justify {
+  text-align: justify;
+}
+table.dataTable th.dt-nowrap,
+table.dataTable td.dt-nowrap {
+  white-space: nowrap;
+}
+table.dataTable thead th.dt-head-left,
+table.dataTable thead td.dt-head-left,
+table.dataTable tfoot th.dt-head-left,
+table.dataTable tfoot td.dt-head-left {
+  text-align: left;
+}
+table.dataTable thead th.dt-head-center,
+table.dataTable thead td.dt-head-center,
+table.dataTable tfoot th.dt-head-center,
+table.dataTable tfoot td.dt-head-center {
+  text-align: center;
+}
+table.dataTable thead th.dt-head-right,
+table.dataTable thead td.dt-head-right,
+table.dataTable tfoot th.dt-head-right,
+table.dataTable tfoot td.dt-head-right {
+  text-align: right;
+}
+table.dataTable thead th.dt-head-justify,
+table.dataTable thead td.dt-head-justify,
+table.dataTable tfoot th.dt-head-justify,
+table.dataTable tfoot td.dt-head-justify {
+  text-align: justify;
+}
+table.dataTable thead th.dt-head-nowrap,
+table.dataTable thead td.dt-head-nowrap,
+table.dataTable tfoot th.dt-head-nowrap,
+table.dataTable tfoot td.dt-head-nowrap {
+  white-space: nowrap;
+}
+table.dataTable tbody th.dt-body-left,
+table.dataTable tbody td.dt-body-left {
+  text-align: left;
+}
+table.dataTable tbody th.dt-body-center,
+table.dataTable tbody td.dt-body-center {
+  text-align: center;
+}
+table.dataTable tbody th.dt-body-right,
+table.dataTable tbody td.dt-body-right {
+  text-align: right;
+}
+table.dataTable tbody th.dt-body-justify,
+table.dataTable tbody td.dt-body-justify {
+  text-align: justify;
+}
+table.dataTable tbody th.dt-body-nowrap,
+table.dataTable tbody td.dt-body-nowrap {
+  white-space: nowrap;
+}
+
+table.dataTable,
+table.dataTable th,
+table.dataTable td {
+  -webkit-box-sizing: content-box;
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+
+/*
+ * Control feature layout
+ */
+.dataTables_wrapper {
+  position: relative;
+  clear: both;
+  *zoom: 1;
+  zoom: 1;
+}
+.dataTables_wrapper .dataTables_length {
+  float: left;
+}
+.dataTables_wrapper .dataTables_filter {
+  float: right;
+  text-align: right;
+}
+.dataTables_wrapper .dataTables_filter input {
+  margin-left: 0.5em;
+}
+.dataTables_wrapper .dataTables_info {
+  clear: both;
+  float: left;
+  padding-top: 0.755em;
+}
+.dataTables_wrapper .dataTables_paginate {
+  float: right;
+  text-align: right;
+  padding-top: 0.25em;
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button {
+  box-sizing: border-box;
+  display: inline-block;
+  min-width: 1.5em;
+  padding: 0.5em 1em;
+  margin-left: 2px;
+  text-align: center;
+  text-decoration: none !important;
+  cursor: pointer;
+  *cursor: hand;
+  color: #333 !important;
+  border: 1px solid transparent;
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
+  color: #333 !important;
+  border: 1px solid #cacaca;
+  background-color: white;
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));
+  /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);
+  /* Chrome10+,Safari5.1+ */
+  background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);
+  /* FF3.6+ */
+  background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);
+  /* IE10+ */
+  background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);
+  /* Opera 11.10+ */
+  background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);
+  /* W3C */
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {
+  cursor: default;
+  color: #666 !important;
+  border: 1px solid transparent;
+  background: transparent;
+  box-shadow: none;
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button:hover {
+  color: white !important;
+  border: 1px solid #111;
+  background-color: #585858;
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));
+  /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top, #585858 0%, #111 100%);
+  /* Chrome10+,Safari5.1+ */
+  background: -moz-linear-gradient(top, #585858 0%, #111 100%);
+  /* FF3.6+ */
+  background: -ms-linear-gradient(top, #585858 0%, #111 100%);
+  /* IE10+ */
+  background: -o-linear-gradient(top, #585858 0%, #111 100%);
+  /* Opera 11.10+ */
+  background: linear-gradient(to bottom, #585858 0%, #111 100%);
+  /* W3C */
+}
+.dataTables_wrapper .dataTables_paginate .paginate_button:active {
+  outline: none;
+  background-color: #2b2b2b;
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));
+  /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
+  /* Chrome10+,Safari5.1+ */
+  background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
+  /* FF3.6+ */
+  background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
+  /* IE10+ */
+  background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
+  /* Opera 11.10+ */
+  background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);
+  /* W3C */
+  box-shadow: inset 0 0 3px #111;
+}
+.dataTables_wrapper .dataTables_paginate .ellipsis {
+  padding: 0 1em;
+}
+.dataTables_wrapper .dataTables_processing {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  width: 100%;
+  height: 40px;
+  margin-left: -50%;
+  margin-top: -25px;
+  padding-top: 20px;
+  text-align: center;
+  font-size: 1.2em;
+  background-color: white;
+  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));
+  /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* Chrome10+,Safari5.1+ */
+  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* FF3.6+ */
+  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* IE10+ */
+  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* Opera 11.10+ */
+  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* W3C */
+}
+.dataTables_wrapper .dataTables_length,
+.dataTables_wrapper .dataTables_filter,
+.dataTables_wrapper .dataTables_info,
+.dataTables_wrapper .dataTables_processing,
+.dataTables_wrapper .dataTables_paginate {
+  color: #333;
+}
+.dataTables_wrapper .dataTables_scroll {
+  clear: both;
+}
+.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {
+  *margin-top: -1px;
+  -webkit-overflow-scrolling: touch;
+}
+.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,
+.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {
+  height: 0;
+  overflow: hidden;
+  margin: 0 !important;
+  padding: 0 !important;
+}
+.dataTables_wrapper.no-footer .dataTables_scrollBody {
+  border-bottom: 1px solid #111;
+}
+.dataTables_wrapper.no-footer div.dataTables_scrollHead table,
+.dataTables_wrapper.no-footer div.dataTables_scrollBody table {
+  border-bottom: none;
+}
+.dataTables_wrapper:after {
+  visibility: hidden;
+  display: block;
+  content: "";
+  clear: both;
+  height: 0;
+}
+
+@media screen and (max-width: 767px) {
+  .dataTables_wrapper .dataTables_info,
+  .dataTables_wrapper .dataTables_paginate {
+    float: none;
+    text-align: center;
+  }
+  .dataTables_wrapper .dataTables_paginate {
+    margin-top: 0.5em;
+  }
+}
+@media screen and (max-width: 640px) {
+  .dataTables_wrapper .dataTables_length,
+  .dataTables_wrapper .dataTables_filter {
+    float: none;
+    text-align: center;
+  }
+  .dataTables_wrapper .dataTables_filter {
+    margin-top: 0.5em;
+  }
+}

文件差異過大導致無法顯示
+ 14951 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/jquery.dataTables.js


文件差異過大導致無法顯示
+ 1 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/jquery.dataTables.min.css


文件差異過大導致無法顯示
+ 160 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/jquery.dataTables.min.js


+ 416 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/datatables/jquery.dataTables_themeroller.css

@@ -0,0 +1,416 @@
+/*
+ * Table styles
+ */
+table.dataTable {
+  width: 100%;
+  margin: 0 auto;
+  clear: both;
+  border-collapse: separate;
+  border-spacing: 0;
+  /*
+   * Header and footer styles
+   */
+  /*
+   * Body styles
+   */
+}
+table.dataTable thead th,
+table.dataTable thead td,
+table.dataTable tfoot th,
+table.dataTable tfoot td {
+  padding: 4px 10px;
+}
+table.dataTable thead th,
+table.dataTable tfoot th {
+  font-weight: bold;
+}
+table.dataTable thead th:active,
+table.dataTable thead td:active {
+  outline: none;
+}
+table.dataTable thead .sorting_asc,
+table.dataTable thead .sorting_desc,
+table.dataTable thead .sorting {
+  cursor: pointer;
+  *cursor: hand;
+}
+table.dataTable thead th div.DataTables_sort_wrapper {
+  position: relative;
+  padding-right: 10px;
+}
+table.dataTable thead th div.DataTables_sort_wrapper span {
+  position: absolute;
+  top: 50%;
+  margin-top: -8px;
+  right: -5px;
+}
+table.dataTable thead th.ui-state-default {
+  border-right-width: 0;
+}
+table.dataTable thead th.ui-state-default:last-child {
+  border-right-width: 1px;
+}
+table.dataTable tbody tr {
+  background-color: #ffffff;
+}
+table.dataTable tbody tr.selected {
+  background-color: #B0BED9;
+}
+table.dataTable tbody th,
+table.dataTable tbody td {
+  padding: 8px 10px;
+}
+table.dataTable th.center,
+table.dataTable td.center,
+table.dataTable td.dataTables_empty {
+  text-align: center;
+}
+table.dataTable th.right,
+table.dataTable td.right {
+  text-align: right;
+}
+table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
+  border-top: 1px solid #ddd;
+}
+table.dataTable.row-border tbody tr:first-child th,
+table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
+table.dataTable.display tbody tr:first-child td {
+  border-top: none;
+}
+table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
+  border-top: 1px solid #ddd;
+  border-right: 1px solid #ddd;
+}
+table.dataTable.cell-border tbody tr th:first-child,
+table.dataTable.cell-border tbody tr td:first-child {
+  border-left: 1px solid #ddd;
+}
+table.dataTable.cell-border tbody tr:first-child th,
+table.dataTable.cell-border tbody tr:first-child td {
+  border-top: none;
+}
+table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
+  background-color: #f9f9f9;
+}
+table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
+  background-color: #abb9d3;
+}
+table.dataTable.hover tbody tr:hover,
+table.dataTable.hover tbody tr.odd:hover,
+table.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover,
+table.dataTable.display tbody tr.odd:hover,
+table.dataTable.display tbody tr.even:hover {
+  background-color: whitesmoke;
+}
+table.dataTable.hover tbody tr:hover.selected,
+table.dataTable.hover tbody tr.odd:hover.selected,
+table.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected,
+table.dataTable.display tbody tr.odd:hover.selected,
+table.dataTable.display tbody tr.even:hover.selected {
+  background-color: #a9b7d1;
+}
+table.dataTable.order-column tbody tr > .sorting_1,
+table.dataTable.order-column tbody tr > .sorting_2,
+table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
+table.dataTable.display tbody tr > .sorting_2,
+table.dataTable.display tbody tr > .sorting_3 {
+  background-color: #f9f9f9;
+}
+table.dataTable.order-column tbody tr.selected > .sorting_1,
+table.dataTable.order-column tbody tr.selected > .sorting_2,
+table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
+table.dataTable.display tbody tr.selected > .sorting_2,
+table.dataTable.display tbody tr.selected > .sorting_3 {
+  background-color: #acbad4;
+}
+table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
+  background-color: #f1f1f1;
+}
+table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
+  background-color: #f3f3f3;
+}
+table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
+  background-color: whitesmoke;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
+  background-color: #a6b3cd;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
+  background-color: #a7b5ce;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
+  background-color: #a9b6d0;
+}
+table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
+  background-color: #f9f9f9;
+}
+table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
+  background-color: #fbfbfb;
+}
+table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
+  background-color: #fdfdfd;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
+  background-color: #acbad4;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
+  background-color: #adbbd6;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
+  background-color: #afbdd8;
+}
+table.dataTable.display tbody tr:hover > .sorting_1,
+table.dataTable.display tbody tr.odd:hover > .sorting_1,
+table.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1,
+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1,
+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 {
+  background-color: #eaeaea;
+}
+table.dataTable.display tbody tr:hover > .sorting_2,
+table.dataTable.display tbody tr.odd:hover > .sorting_2,
+table.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2,
+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2,
+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 {
+  background-color: #ebebeb;
+}
+table.dataTable.display tbody tr:hover > .sorting_3,
+table.dataTable.display tbody tr.odd:hover > .sorting_3,
+table.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3,
+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3,
+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 {
+  background-color: #eeeeee;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_1,
+table.dataTable.display tbody tr.odd:hover.selected > .sorting_1,
+table.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1,
+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1,
+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 {
+  background-color: #a1aec7;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_2,
+table.dataTable.display tbody tr.odd:hover.selected > .sorting_2,
+table.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2,
+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2,
+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 {
+  background-color: #a2afc8;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_3,
+table.dataTable.display tbody tr.odd:hover.selected > .sorting_3,
+table.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3,
+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3,
+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 {
+  background-color: #a4b2cb;
+}
+table.dataTable.nowrap th, table.dataTable.nowrap td {
+  white-space: nowrap;
+}
+table.dataTable.compact thead th,
+table.dataTable.compact thead td {
+  padding: 5px 9px;
+}
+table.dataTable.compact tfoot th,
+table.dataTable.compact tfoot td {
+  padding: 5px 9px 3px 9px;
+}
+table.dataTable.compact tbody th,
+table.dataTable.compact tbody td {
+  padding: 4px 5px;
+}
+table.dataTable th.dt-left,
+table.dataTable td.dt-left {
+  text-align: left;
+}
+table.dataTable th.dt-center,
+table.dataTable td.dt-center,
+table.dataTable td.dataTables_empty {
+  text-align: center;
+}
+table.dataTable th.dt-right,
+table.dataTable td.dt-right {
+  text-align: right;
+}
+table.dataTable th.dt-justify,
+table.dataTable td.dt-justify {
+  text-align: justify;
+}
+table.dataTable th.dt-nowrap,
+table.dataTable td.dt-nowrap {
+  white-space: nowrap;
+}
+table.dataTable thead th.dt-head-left,
+table.dataTable thead td.dt-head-left,
+table.dataTable tfoot th.dt-head-left,
+table.dataTable tfoot td.dt-head-left {
+  text-align: left;
+}
+table.dataTable thead th.dt-head-center,
+table.dataTable thead td.dt-head-center,
+table.dataTable tfoot th.dt-head-center,
+table.dataTable tfoot td.dt-head-center {
+  text-align: center;
+}
+table.dataTable thead th.dt-head-right,
+table.dataTable thead td.dt-head-right,
+table.dataTable tfoot th.dt-head-right,
+table.dataTable tfoot td.dt-head-right {
+  text-align: right;
+}
+table.dataTable thead th.dt-head-justify,
+table.dataTable thead td.dt-head-justify,
+table.dataTable tfoot th.dt-head-justify,
+table.dataTable tfoot td.dt-head-justify {
+  text-align: justify;
+}
+table.dataTable thead th.dt-head-nowrap,
+table.dataTable thead td.dt-head-nowrap,
+table.dataTable tfoot th.dt-head-nowrap,
+table.dataTable tfoot td.dt-head-nowrap {
+  white-space: nowrap;
+}
+table.dataTable tbody th.dt-body-left,
+table.dataTable tbody td.dt-body-left {
+  text-align: left;
+}
+table.dataTable tbody th.dt-body-center,
+table.dataTable tbody td.dt-body-center {
+  text-align: center;
+}
+table.dataTable tbody th.dt-body-right,
+table.dataTable tbody td.dt-body-right {
+  text-align: right;
+}
+table.dataTable tbody th.dt-body-justify,
+table.dataTable tbody td.dt-body-justify {
+  text-align: justify;
+}
+table.dataTable tbody th.dt-body-nowrap,
+table.dataTable tbody td.dt-body-nowrap {
+  white-space: nowrap;
+}
+
+table.dataTable,
+table.dataTable th,
+table.dataTable td {
+  -webkit-box-sizing: content-box;
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+
+/*
+ * Control feature layout
+ */
+.dataTables_wrapper {
+  position: relative;
+  clear: both;
+  *zoom: 1;
+  zoom: 1;
+}
+.dataTables_wrapper .dataTables_length {
+  float: left;
+}
+.dataTables_wrapper .dataTables_filter {
+  float: right;
+  text-align: right;
+}
+.dataTables_wrapper .dataTables_filter input {
+  margin-left: 0.5em;
+}
+.dataTables_wrapper .dataTables_info {
+  clear: both;
+  float: left;
+  padding-top: 0.55em;
+}
+.dataTables_wrapper .dataTables_paginate {
+  float: right;
+  text-align: right;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button {
+  box-sizing: border-box;
+  display: inline-block;
+  min-width: 1.5em;
+  padding: 0.5em;
+  margin-left: 2px;
+  text-align: center;
+  text-decoration: none !important;
+  cursor: pointer;
+  *cursor: hand;
+  color: #333 !important;
+  border: 1px solid transparent;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button:active {
+  outline: none;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button:first-child {
+  border-top-left-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button:last-child {
+  border-top-right-radius: 3px;
+  border-bottom-right-radius: 3px;
+}
+.dataTables_wrapper .dataTables_processing {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  width: 100%;
+  height: 40px;
+  margin-left: -50%;
+  margin-top: -25px;
+  padding-top: 20px;
+  text-align: center;
+  font-size: 1.2em;
+  background-color: white;
+  background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));
+  /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* Chrome10+,Safari5.1+ */
+  background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* FF3.6+ */
+  background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* IE10+ */
+  background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* Opera 11.10+ */
+  background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+  /* W3C */
+}
+.dataTables_wrapper .dataTables_length,
+.dataTables_wrapper .dataTables_filter,
+.dataTables_wrapper .dataTables_info,
+.dataTables_wrapper .dataTables_processing,
+.dataTables_wrapper .dataTables_paginate {
+  color: #333;
+}
+.dataTables_wrapper .dataTables_scroll {
+  clear: both;
+}
+.dataTables_wrapper .dataTables_scrollBody {
+  *margin-top: -1px;
+  -webkit-overflow-scrolling: touch;
+}
+.dataTables_wrapper .ui-widget-header {
+  font-weight: normal;
+}
+.dataTables_wrapper .ui-toolbar {
+  padding: 8px;
+}
+.dataTables_wrapper:after {
+  visibility: hidden;
+  display: block;
+  content: "";
+  clear: both;
+  height: 0;
+}
+
+@media screen and (max-width: 767px) {
+  .dataTables_wrapper .dataTables_length,
+  .dataTables_wrapper .dataTables_filter,
+  .dataTables_wrapper .dataTables_info,
+  .dataTables_wrapper .dataTables_paginate {
+    float: none;
+    text-align: center;
+  }
+  .dataTables_wrapper .dataTables_filter,
+  .dataTables_wrapper .dataTables_paginate {
+    margin-top: 0.5em;
+  }
+}

+ 841 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/fastclick/fastclick.js

@@ -0,0 +1,841 @@
+;(function () {
+	'use strict';
+
+	/**
+	 * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
+	 *
+	 * @codingstandard ftlabs-jsv2
+	 * @copyright The Financial Times Limited [All Rights Reserved]
+	 * @license MIT License (see LICENSE.txt)
+	 */
+
+	/*jslint browser:true, node:true*/
+	/*global define, Event, Node*/
+
+
+	/**
+	 * Instantiate fast-clicking listeners on the specified layer.
+	 *
+	 * @constructor
+	 * @param {Element} layer The layer to listen on
+	 * @param {Object} [options={}] The options to override the defaults
+	 */
+	function FastClick(layer, options) {
+		var oldOnClick;
+
+		options = options || {};
+
+		/**
+		 * Whether a click is currently being tracked.
+		 *
+		 * @type boolean
+		 */
+		this.trackingClick = false;
+
+
+		/**
+		 * Timestamp for when click tracking started.
+		 *
+		 * @type number
+		 */
+		this.trackingClickStart = 0;
+
+
+		/**
+		 * The element being tracked for a click.
+		 *
+		 * @type EventTarget
+		 */
+		this.targetElement = null;
+
+
+		/**
+		 * X-coordinate of touch start event.
+		 *
+		 * @type number
+		 */
+		this.touchStartX = 0;
+
+
+		/**
+		 * Y-coordinate of touch start event.
+		 *
+		 * @type number
+		 */
+		this.touchStartY = 0;
+
+
+		/**
+		 * ID of the last touch, retrieved from Touch.identifier.
+		 *
+		 * @type number
+		 */
+		this.lastTouchIdentifier = 0;
+
+
+		/**
+		 * Touchmove boundary, beyond which a click will be cancelled.
+		 *
+		 * @type number
+		 */
+		this.touchBoundary = options.touchBoundary || 10;
+
+
+		/**
+		 * The FastClick layer.
+		 *
+		 * @type Element
+		 */
+		this.layer = layer;
+
+		/**
+		 * The minimum time between tap(touchstart and touchend) events
+		 *
+		 * @type number
+		 */
+		this.tapDelay = options.tapDelay || 200;
+
+		/**
+		 * The maximum time for a tap
+		 *
+		 * @type number
+		 */
+		this.tapTimeout = options.tapTimeout || 700;
+
+		if (FastClick.notNeeded(layer)) {
+			return;
+		}
+
+		// Some old versions of Android don't have Function.prototype.bind
+		function bind(method, context) {
+			return function() { return method.apply(context, arguments); };
+		}
+
+
+		var methods = ['onMouse', 'onClick', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel'];
+		var context = this;
+		for (var i = 0, l = methods.length; i < l; i++) {
+			context[methods[i]] = bind(context[methods[i]], context);
+		}
+
+		// Set up event handlers as required
+		if (deviceIsAndroid) {
+			layer.addEventListener('mouseover', this.onMouse, true);
+			layer.addEventListener('mousedown', this.onMouse, true);
+			layer.addEventListener('mouseup', this.onMouse, true);
+		}
+
+		layer.addEventListener('click', this.onClick, true);
+		layer.addEventListener('touchstart', this.onTouchStart, false);
+		layer.addEventListener('touchmove', this.onTouchMove, false);
+		layer.addEventListener('touchend', this.onTouchEnd, false);
+		layer.addEventListener('touchcancel', this.onTouchCancel, false);
+
+		// Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
+		// which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick
+		// layer when they are cancelled.
+		if (!Event.prototype.stopImmediatePropagation) {
+			layer.removeEventListener = function(type, callback, capture) {
+				var rmv = Node.prototype.removeEventListener;
+				if (type === 'click') {
+					rmv.call(layer, type, callback.hijacked || callback, capture);
+				} else {
+					rmv.call(layer, type, callback, capture);
+				}
+			};
+
+			layer.addEventListener = function(type, callback, capture) {
+				var adv = Node.prototype.addEventListener;
+				if (type === 'click') {
+					adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
+						if (!event.propagationStopped) {
+							callback(event);
+						}
+					}), capture);
+				} else {
+					adv.call(layer, type, callback, capture);
+				}
+			};
+		}
+
+		// If a handler is already declared in the element's onclick attribute, it will be fired before
+		// FastClick's onClick handler. Fix this by pulling out the user-defined handler function and
+		// adding it as listener.
+		if (typeof layer.onclick === 'function') {
+
+			// Android browser on at least 3.2 requires a new reference to the function in layer.onclick
+			// - the old one won't work if passed to addEventListener directly.
+			oldOnClick = layer.onclick;
+			layer.addEventListener('click', function(event) {
+				oldOnClick(event);
+			}, false);
+			layer.onclick = null;
+		}
+	}
+
+	/**
+	* Windows Phone 8.1 fakes user agent string to look like Android and iPhone.
+	*
+	* @type boolean
+	*/
+	var deviceIsWindowsPhone = navigator.userAgent.indexOf("Windows Phone") >= 0;
+
+	/**
+	 * Android requires exceptions.
+	 *
+	 * @type boolean
+	 */
+	var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0 && !deviceIsWindowsPhone;
+
+
+	/**
+	 * iOS requires exceptions.
+	 *
+	 * @type boolean
+	 */
+	var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent) && !deviceIsWindowsPhone;
+
+
+	/**
+	 * iOS 4 requires an exception for select elements.
+	 *
+	 * @type boolean
+	 */
+	var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);
+
+
+	/**
+	 * iOS 6.0-7.* requires the target element to be manually derived
+	 *
+	 * @type boolean
+	 */
+	var deviceIsIOSWithBadTarget = deviceIsIOS && (/OS [6-7]_\d/).test(navigator.userAgent);
+
+	/**
+	 * BlackBerry requires exceptions.
+	 *
+	 * @type boolean
+	 */
+	var deviceIsBlackBerry10 = navigator.userAgent.indexOf('BB10') > 0;
+
+	/**
+	 * Determine whether a given element requires a native click.
+	 *
+	 * @param {EventTarget|Element} target Target DOM element
+	 * @returns {boolean} Returns true if the element needs a native click
+	 */
+	FastClick.prototype.needsClick = function(target) {
+		switch (target.nodeName.toLowerCase()) {
+
+		// Don't send a synthetic click to disabled inputs (issue #62)
+		case 'button':
+		case 'select':
+		case 'textarea':
+			if (target.disabled) {
+				return true;
+			}
+
+			break;
+		case 'input':
+
+			// File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
+			if ((deviceIsIOS && target.type === 'file') || target.disabled) {
+				return true;
+			}
+
+			break;
+		case 'label':
+		case 'iframe': // iOS8 homescreen apps can prevent events bubbling into frames
+		case 'video':
+			return true;
+		}
+
+		return (/\bneedsclick\b/).test(target.className);
+	};
+
+
+	/**
+	 * Determine whether a given element requires a call to focus to simulate click into element.
+	 *
+	 * @param {EventTarget|Element} target Target DOM element
+	 * @returns {boolean} Returns true if the element requires a call to focus to simulate native click.
+	 */
+	FastClick.prototype.needsFocus = function(target) {
+		switch (target.nodeName.toLowerCase()) {
+		case 'textarea':
+			return true;
+		case 'select':
+			return !deviceIsAndroid;
+		case 'input':
+			switch (target.type) {
+			case 'button':
+			case 'checkbox':
+			case 'file':
+			case 'image':
+			case 'radio':
+			case 'submit':
+				return false;
+			}
+
+			// No point in attempting to focus disabled inputs
+			return !target.disabled && !target.readOnly;
+		default:
+			return (/\bneedsfocus\b/).test(target.className);
+		}
+	};
+
+
+	/**
+	 * Send a click event to the specified element.
+	 *
+	 * @param {EventTarget|Element} targetElement
+	 * @param {Event} event
+	 */
+	FastClick.prototype.sendClick = function(targetElement, event) {
+		var clickEvent, touch;
+
+		// On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
+		if (document.activeElement && document.activeElement !== targetElement) {
+			document.activeElement.blur();
+		}
+
+		touch = event.changedTouches[0];
+
+		// Synthesise a click event, with an extra attribute so it can be tracked
+		clickEvent = document.createEvent('MouseEvents');
+		clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
+		clickEvent.forwardedTouchEvent = true;
+		targetElement.dispatchEvent(clickEvent);
+	};
+
+	FastClick.prototype.determineEventType = function(targetElement) {
+
+		//Issue #159: Android Chrome Select Box does not open with a synthetic click event
+		if (deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {
+			return 'mousedown';
+		}
+
+		return 'click';
+	};
+
+
+	/**
+	 * @param {EventTarget|Element} targetElement
+	 */
+	FastClick.prototype.focus = function(targetElement) {
+		var length;
+
+		// Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
+		if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month') {
+			length = targetElement.value.length;
+			targetElement.setSelectionRange(length, length);
+		} else {
+			targetElement.focus();
+		}
+	};
+
+
+	/**
+	 * Check whether the given target element is a child of a scrollable layer and if so, set a flag on it.
+	 *
+	 * @param {EventTarget|Element} targetElement
+	 */
+	FastClick.prototype.updateScrollParent = function(targetElement) {
+		var scrollParent, parentElement;
+
+		scrollParent = targetElement.fastClickScrollParent;
+
+		// Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the
+		// target element was moved to another parent.
+		if (!scrollParent || !scrollParent.contains(targetElement)) {
+			parentElement = targetElement;
+			do {
+				if (parentElement.scrollHeight > parentElement.offsetHeight) {
+					scrollParent = parentElement;
+					targetElement.fastClickScrollParent = parentElement;
+					break;
+				}
+
+				parentElement = parentElement.parentElement;
+			} while (parentElement);
+		}
+
+		// Always update the scroll top tracker if possible.
+		if (scrollParent) {
+			scrollParent.fastClickLastScrollTop = scrollParent.scrollTop;
+		}
+	};
+
+
+	/**
+	 * @param {EventTarget} targetElement
+	 * @returns {Element|EventTarget}
+	 */
+	FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {
+
+		// On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
+		if (eventTarget.nodeType === Node.TEXT_NODE) {
+			return eventTarget.parentNode;
+		}
+
+		return eventTarget;
+	};
+
+
+	/**
+	 * On touch start, record the position and scroll offset.
+	 *
+	 * @param {Event} event
+	 * @returns {boolean}
+	 */
+	FastClick.prototype.onTouchStart = function(event) {
+		var targetElement, touch, selection;
+
+		// Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
+		if (event.targetTouches.length > 1) {
+			return true;
+		}
+
+		targetElement = this.getTargetElementFromEventTarget(event.target);
+		touch = event.targetTouches[0];
+
+		if (deviceIsIOS) {
+
+			// Only trusted events will deselect text on iOS (issue #49)
+			selection = window.getSelection();
+			if (selection.rangeCount && !selection.isCollapsed) {
+				return true;
+			}
+
+			if (!deviceIsIOS4) {
+
+				// Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23):
+				// when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched
+				// with the same identifier as the touch event that previously triggered the click that triggered the alert.
+				// Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an
+				// immediately preceeding touch event (issue #52), so this fix is unavailable on that platform.
+				// Issue 120: touch.identifier is 0 when Chrome dev tools 'Emulate touch events' is set with an iOS device UA string,
+				// which causes all touch events to be ignored. As this block only applies to iOS, and iOS identifiers are always long,
+				// random integers, it's safe to to continue if the identifier is 0 here.
+				if (touch.identifier && touch.identifier === this.lastTouchIdentifier) {
+					event.preventDefault();
+					return false;
+				}
+
+				this.lastTouchIdentifier = touch.identifier;
+
+				// If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
+				// 1) the user does a fling scroll on the scrollable layer
+				// 2) the user stops the fling scroll with another tap
+				// then the event.target of the last 'touchend' event will be the element that was under the user's finger
+				// when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
+				// is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
+				this.updateScrollParent(targetElement);
+			}
+		}
+
+		this.trackingClick = true;
+		this.trackingClickStart = event.timeStamp;
+		this.targetElement = targetElement;
+
+		this.touchStartX = touch.pageX;
+		this.touchStartY = touch.pageY;
+
+		// Prevent phantom clicks on fast double-tap (issue #36)
+		if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
+			event.preventDefault();
+		}
+
+		return true;
+	};
+
+
+	/**
+	 * Based on a touchmove event object, check whether the touch has moved past a boundary since it started.
+	 *
+	 * @param {Event} event
+	 * @returns {boolean}
+	 */
+	FastClick.prototype.touchHasMoved = function(event) {
+		var touch = event.changedTouches[0], boundary = this.touchBoundary;
+
+		if (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) {
+			return true;
+		}
+
+		return false;
+	};
+
+
+	/**
+	 * Update the last position.
+	 *
+	 * @param {Event} event
+	 * @returns {boolean}
+	 */
+	FastClick.prototype.onTouchMove = function(event) {
+		if (!this.trackingClick) {
+			return true;
+		}
+
+		// If the touch has moved, cancel the click tracking
+		if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {
+			this.trackingClick = false;
+			this.targetElement = null;
+		}
+
+		return true;
+	};
+
+
+	/**
+	 * Attempt to find the labelled control for the given label element.
+	 *
+	 * @param {EventTarget|HTMLLabelElement} labelElement
+	 * @returns {Element|null}
+	 */
+	FastClick.prototype.findControl = function(labelElement) {
+
+		// Fast path for newer browsers supporting the HTML5 control attribute
+		if (labelElement.control !== undefined) {
+			return labelElement.control;
+		}
+
+		// All browsers under test that support touch events also support the HTML5 htmlFor attribute
+		if (labelElement.htmlFor) {
+			return document.getElementById(labelElement.htmlFor);
+		}
+
+		// If no for attribute exists, attempt to retrieve the first labellable descendant element
+		// the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label
+		return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea');
+	};
+
+
+	/**
+	 * On touch end, determine whether to send a click event at once.
+	 *
+	 * @param {Event} event
+	 * @returns {boolean}
+	 */
+	FastClick.prototype.onTouchEnd = function(event) {
+		var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
+
+		if (!this.trackingClick) {
+			return true;
+		}
+
+		// Prevent phantom clicks on fast double-tap (issue #36)
+		if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
+			this.cancelNextClick = true;
+			return true;
+		}
+
+		if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) {
+			return true;
+		}
+
+		// Reset to prevent wrong click cancel on input (issue #156).
+		this.cancelNextClick = false;
+
+		this.lastClickTime = event.timeStamp;
+
+		trackingClickStart = this.trackingClickStart;
+		this.trackingClick = false;
+		this.trackingClickStart = 0;
+
+		// On some iOS devices, the targetElement supplied with the event is invalid if the layer
+		// is performing a transition or scroll, and has to be re-detected manually. Note that
+		// for this to function correctly, it must be called *after* the event target is checked!
+		// See issue #57; also filed as rdar://13048589 .
+		if (deviceIsIOSWithBadTarget) {
+			touch = event.changedTouches[0];
+
+			// In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null
+			targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;
+			targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
+		}
+
+		targetTagName = targetElement.tagName.toLowerCase();
+		if (targetTagName === 'label') {
+			forElement = this.findControl(targetElement);
+			if (forElement) {
+				this.focus(targetElement);
+				if (deviceIsAndroid) {
+					return false;
+				}
+
+				targetElement = forElement;
+			}
+		} else if (this.needsFocus(targetElement)) {
+
+			// Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.
+			// Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37).
+			if ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) {
+				this.targetElement = null;
+				return false;
+			}
+
+			this.focus(targetElement);
+			this.sendClick(targetElement, event);
+
+			// Select elements need the event to go through on iOS 4, otherwise the selector menu won't open.
+			// Also this breaks opening selects when VoiceOver is active on iOS6, iOS7 (and possibly others)
+			if (!deviceIsIOS || targetTagName !== 'select') {
+				this.targetElement = null;
+				event.preventDefault();
+			}
+
+			return false;
+		}
+
+		if (deviceIsIOS && !deviceIsIOS4) {
+
+			// Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
+			// and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
+			scrollParent = targetElement.fastClickScrollParent;
+			if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
+				return true;
+			}
+		}
+
+		// Prevent the actual click from going though - unless the target node is marked as requiring
+		// real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
+		if (!this.needsClick(targetElement)) {
+			event.preventDefault();
+			this.sendClick(targetElement, event);
+		}
+
+		return false;
+	};
+
+
+	/**
+	 * On touch cancel, stop tracking the click.
+	 *
+	 * @returns {void}
+	 */
+	FastClick.prototype.onTouchCancel = function() {
+		this.trackingClick = false;
+		this.targetElement = null;
+	};
+
+
+	/**
+	 * Determine mouse events which should be permitted.
+	 *
+	 * @param {Event} event
+	 * @returns {boolean}
+	 */
+	FastClick.prototype.onMouse = function(event) {
+
+		// If a target element was never set (because a touch event was never fired) allow the event
+		if (!this.targetElement) {
+			return true;
+		}
+
+		if (event.forwardedTouchEvent) {
+			return true;
+		}
+
+		// Programmatically generated events targeting a specific element should be permitted
+		if (!event.cancelable) {
+			return true;
+		}
+
+		// Derive and check the target element to see whether the mouse event needs to be permitted;
+		// unless explicitly enabled, prevent non-touch click events from triggering actions,
+		// to prevent ghost/doubleclicks.
+		if (!this.needsClick(this.targetElement) || this.cancelNextClick) {
+
+			// Prevent any user-added listeners declared on FastClick element from being fired.
+			if (event.stopImmediatePropagation) {
+				event.stopImmediatePropagation();
+			} else {
+
+				// Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
+				event.propagationStopped = true;
+			}
+
+			// Cancel the event
+			event.stopPropagation();
+			event.preventDefault();
+
+			return false;
+		}
+
+		// If the mouse event is permitted, return true for the action to go through.
+		return true;
+	};
+
+
+	/**
+	 * On actual clicks, determine whether this is a touch-generated click, a click action occurring
+	 * naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or
+	 * an actual click which should be permitted.
+	 *
+	 * @param {Event} event
+	 * @returns {boolean}
+	 */
+	FastClick.prototype.onClick = function(event) {
+		var permitted;
+
+		// It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
+		if (this.trackingClick) {
+			this.targetElement = null;
+			this.trackingClick = false;
+			return true;
+		}
+
+		// Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
+		if (event.target.type === 'submit' && event.detail === 0) {
+			return true;
+		}
+
+		permitted = this.onMouse(event);
+
+		// Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through.
+		if (!permitted) {
+			this.targetElement = null;
+		}
+
+		// If clicks are permitted, return true for the action to go through.
+		return permitted;
+	};
+
+
+	/**
+	 * Remove all FastClick's event listeners.
+	 *
+	 * @returns {void}
+	 */
+	FastClick.prototype.destroy = function() {
+		var layer = this.layer;
+
+		if (deviceIsAndroid) {
+			layer.removeEventListener('mouseover', this.onMouse, true);
+			layer.removeEventListener('mousedown', this.onMouse, true);
+			layer.removeEventListener('mouseup', this.onMouse, true);
+		}
+
+		layer.removeEventListener('click', this.onClick, true);
+		layer.removeEventListener('touchstart', this.onTouchStart, false);
+		layer.removeEventListener('touchmove', this.onTouchMove, false);
+		layer.removeEventListener('touchend', this.onTouchEnd, false);
+		layer.removeEventListener('touchcancel', this.onTouchCancel, false);
+	};
+
+
+	/**
+	 * Check whether FastClick is needed.
+	 *
+	 * @param {Element} layer The layer to listen on
+	 */
+	FastClick.notNeeded = function(layer) {
+		var metaViewport;
+		var chromeVersion;
+		var blackberryVersion;
+		var firefoxVersion;
+
+		// Devices that don't support touch don't need FastClick
+		if (typeof window.ontouchstart === 'undefined') {
+			return true;
+		}
+
+		// Chrome version - zero for other browsers
+		chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
+
+		if (chromeVersion) {
+
+			if (deviceIsAndroid) {
+				metaViewport = document.querySelector('meta[name=viewport]');
+
+				if (metaViewport) {
+					// Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
+					if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
+						return true;
+					}
+					// Chrome 32 and above with width=device-width or less don't need FastClick
+					if (chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) {
+						return true;
+					}
+				}
+
+			// Chrome desktop doesn't need FastClick (issue #15)
+			} else {
+				return true;
+			}
+		}
+
+		if (deviceIsBlackBerry10) {
+			blackberryVersion = navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/);
+
+			// BlackBerry 10.3+ does not require Fastclick library.
+			// https://github.com/ftlabs/fastclick/issues/251
+			if (blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3) {
+				metaViewport = document.querySelector('meta[name=viewport]');
+
+				if (metaViewport) {
+					// user-scalable=no eliminates click delay.
+					if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
+						return true;
+					}
+					// width=device-width (or less than device-width) eliminates click delay.
+					if (document.documentElement.scrollWidth <= window.outerWidth) {
+						return true;
+					}
+				}
+			}
+		}
+
+		// IE10 with -ms-touch-action: none or manipulation, which disables double-tap-to-zoom (issue #97)
+		if (layer.style.msTouchAction === 'none' || layer.style.touchAction === 'manipulation') {
+			return true;
+		}
+
+		// Firefox version - zero for other browsers
+		firefoxVersion = +(/Firefox\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
+
+		if (firefoxVersion >= 27) {
+			// Firefox 27+ does not have tap delay if the content is not zoomable - https://bugzilla.mozilla.org/show_bug.cgi?id=922896
+
+			metaViewport = document.querySelector('meta[name=viewport]');
+			if (metaViewport && (metaViewport.content.indexOf('user-scalable=no') !== -1 || document.documentElement.scrollWidth <= window.outerWidth)) {
+				return true;
+			}
+		}
+
+		// IE11: prefixed -ms-touch-action is no longer supported and it's recomended to use non-prefixed version
+		// http://msdn.microsoft.com/en-us/library/windows/apps/Hh767313.aspx
+		if (layer.style.touchAction === 'none' || layer.style.touchAction === 'manipulation') {
+			return true;
+		}
+
+		return false;
+	};
+
+
+	/**
+	 * Factory method for creating a FastClick object
+	 *
+	 * @param {Element} layer The layer to listen on
+	 * @param {Object} [options={}] The options to override the defaults
+	 */
+	FastClick.attach = function(layer, options) {
+		return new FastClick(layer, options);
+	};
+
+
+	if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
+
+		// AMD. Register as an anonymous module.
+		define(function() {
+			return FastClick;
+		});
+	} else if (typeof module !== 'undefined' && module.exports) {
+		module.exports = FastClick.attach;
+		module.exports.FastClick = FastClick;
+	} else {
+		window.FastClick = FastClick;
+	}
+}());

文件差異過大導致無法顯示
+ 1 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/fastclick/fastclick.min.js


文件差異過大導致無法顯示
+ 4 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/jQuery/jQuery-2.1.4.min.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/az.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/bg.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/ca.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/cs.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/da.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/de.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/en.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/es.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/et.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/eu.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/fa.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/fi.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/fr.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/gl.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/he.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/hi.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/hr.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/hu.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/id.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/is.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/it.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/ko.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/lt.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/lv.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/mk.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/nb.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/nl.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/pl.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/pt-BR.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/pt.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/ro.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/ru.js


文件差異過大導致無法顯示
+ 3 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/sk.js


+ 0 - 0
branch-dianping/dianping-job/dianping-job-web/src/main/webapp/static/adminlte/plugins/select2/i18n/sr.js


部分文件因文件數量過多而無法顯示