This commit is contained in:
2019-03-07 10:24:29 +08:00
parent 6c8c683c31
commit e057d613b9
215 changed files with 70917 additions and 118 deletions

110
apidoc.html Normal file

File diff suppressed because one or more lines are too long

552
apidoc.json Normal file
View File

@@ -0,0 +1,552 @@
{
"servers": [
{
"address": "0.0.0.0:80",
"servlets": [
{
"urlregs": [
"/meta/*"
],
"moduleid": 0,
"name": "",
"comment": "元数据服务",
"mappings": [
{
"url": "/meta/db_plat_list",
"auth": true,
"actionid": 0,
"comment": "数据平台",
"params": [],
"results": [],
"result": "java.util.List<net.tccn.dbq.DbPlat>"
},
{
"url": "/meta/exportsort",
"auth": true,
"actionid": 0,
"comment": "导出字段排序保存",
"params": [
{
"name": "serviceKey",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "items",
"radix": 10,
"type": "java.util.List",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "platToken",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "java.util.List<java.lang.String>"
},
{
"url": "/meta/filter_update",
"auth": true,
"actionid": 0,
"comment": "查询配置修改",
"params": [
{
"name": "serviceKey",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "filters",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "platToken",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "net.tccn.base.JBean"
},
{
"url": "/meta/findMetaTable",
"auth": true,
"actionid": 0,
"comment": "",
"params": [
{
"name": "name",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "token",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "net.tccn.meta.MetaTable"
},
{
"url": "/meta/importsort",
"auth": true,
"actionid": 0,
"comment": "导入字段保存",
"params": [
{
"name": "serviceKey",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "items",
"radix": 10,
"type": "java.util.List",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "platToken",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "java.util.List<java.lang.String>"
},
{
"url": "/meta/itemsort",
"auth": true,
"actionid": 0,
"comment": "字段排序",
"params": [
{
"name": "serviceKey",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "items",
"radix": 10,
"type": "java.lang.String[]",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "platToken",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "[Ljava.lang.String;"
},
{
"url": "/meta/itemupdate",
"auth": true,
"actionid": 0,
"comment": "字段修改",
"params": [
{
"name": "serviceKey",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "items",
"radix": 10,
"type": "java.util.List",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "platToken",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "java.util.List<net.tccn.dbq.Field>"
},
{
"url": "/meta/listcfg",
"auth": false,
"actionid": 0,
"comment": "内容列表配置",
"params": [
{
"name": "key",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "platToken",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "net.tccn.base.JBean"
},
{
"url": "/meta/showsort",
"auth": true,
"actionid": 0,
"comment": "展示字段修改",
"params": [
{
"name": "serviceKey",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "items",
"radix": 10,
"type": "java.util.List",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "platToken",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "java.util.List<java.lang.String>"
},
{
"url": "/meta/tableinfo",
"auth": true,
"actionid": 0,
"comment": "table详情",
"params": [
{
"name": "platToken",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "name",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "net.tccn.base.JBean"
},
{
"url": "/meta/tablelist",
"auth": true,
"actionid": 0,
"comment": "table列表",
"params": [
{
"name": "platToken",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "catalog",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "dbPlatId",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "name",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "net.tccn.base.JBean"
}
]
},
{
"urlregs": [
"/qtask/test",
"/qtask/call",
"/qtask/getSysPlat",
"/qtask/qsave"
],
"moduleid": 0,
"name": "",
"comment": "qtask查询服务",
"mappings": [
{
"url": "/qtask/call",
"auth": true,
"actionid": 0,
"comment": "qtask查询",
"params": [
{
"name": "queryId",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "para",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
},
{
"name": "platToken",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "net.tccn.base.JBean"
},
{
"url": "/qtask/getSysPlat",
"auth": true,
"actionid": 0,
"comment": "",
"params": [
{
"name": "token",
"radix": 10,
"type": "java.lang.String",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "net.tccn.dbq.qtask.SysPlat"
},
{
"url": "/qtask/qsave",
"auth": true,
"actionid": 0,
"comment": "qtask保存",
"params": [
{
"name": "qtask",
"radix": 10,
"type": "net.tccn.dbq.qtask.Qtask",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "net.tccn.base.JBean"
},
{
"url": "/qtask/test",
"auth": true,
"actionid": 0,
"comment": "qtask调试",
"params": [
{
"name": "qtask",
"radix": 10,
"type": "net.tccn.dbq.qtask.Qtask",
"src": "PARAMETER",
"comment": "",
"required": true
}
],
"results": [],
"result": "net.tccn.base.JBean"
}
]
}
]
}
],
"types": {
"net.tccn.dbq.qtask.Qtask": {
"queryId": {
"type": "java.lang.String",
"primary": false,
"updatable": true
},
"name": {
"type": "java.lang.String",
"primary": false,
"updatable": true
},
"remark": {
"type": "java.lang.String",
"primary": false,
"updatable": true
},
"sql": {
"type": "java.lang.String",
"primary": false,
"updatable": true
},
"para": {
"type": "java.lang.String",
"primary": false,
"updatable": true
},
"cate": {
"type": "java.lang.String",
"primary": false,
"updatable": true
},
"sysPlatId": {
"type": "java.lang.Integer",
"primary": false,
"updatable": true
},
"platId": {
"type": "java.lang.Integer",
"primary": false,
"updatable": true
},
"catalog": {
"type": "java.lang.String",
"primary": false,
"updatable": true
},
"status": {
"type": "java.lang.Integer",
"primary": false,
"updatable": true
},
"attr": {
"type": "java.util.HashMap",
"primary": false,
"updatable": true
},
"_id": {
"type": "java.lang.String",
"primary": false,
"updatable": true
},
"_key": {
"type": "java.lang.String",
"primary": false,
"updatable": true
},
"_shows": {
"type": "java.util.Set<java.lang.String>",
"primary": false,
"updatable": true
},
"_order": {
"type": "java.util.Map",
"primary": false,
"updatable": true
},
"fieldName": {
"type": "java.util.function.Function<java.lang.String, java.lang.String>",
"primary": false,
"updatable": true
},
"arangoSource": {
"type": "net.tccn.base.arango.ArangoSource",
"primary": false,
"updatable": true
},
"db": {
"type": "com.arangodb.ArangoDatabase",
"primary": false,
"updatable": true
},
"collection": {
"type": "com.arangodb.ArangoCollection",
"primary": false,
"updatable": true
}
}
}
}

25
conf/application.xml Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<application port="5001">
<resources>
<properties load="config.txt"></properties>
</resources>
<server protocol="HTTP" host="0.0.0.0" port="80" root="root">
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
</request>
<response>
<addheader name="X-Node" value="system.property.APP_NODE" />
</response>
<resource-servlet>
</resource-servlet>
<rest autoload="true" base="net.tccn.service.BaseServlet"/>
<services autoload="true"/>
<servlets autoload="true"/>
</server>
</application>

26
conf/config.txt Normal file
View File

@@ -0,0 +1,26 @@
#--------------- FTP --------------
ftp.host=192.168.202.11
ftp.port=21
ftp.user=ftptest
ftp.passwd=123
ftp.verdict.url_file_path=verdict_url
ftp.verdict.app_file_path=verdict_app
#apk文件存放目录 /home/ftptest/apk
ftp.verdict.apk_dir=C:\\Users\\eversec\\Documents\\WXWork\\1688854143550524\\Cache\\File\\2018-12\\02
#--------------- xml-rpc、kafak --------------
rpc.url=http://192.168.205.147:8888
kafak.servers=192.168.202.11:9092
#app研判发送地址
kafak.topic.app_verdict=static_task_virus_topic
#app研判结果监听
kafak.topic.app_verdict_result=static_task_virus_result_topic
#--------------- arango --------------
arango.host=120.24.230.60
arango.port=8529
arango.user=root
arango.passwd=abc123
arango.database=db_dev

24
conf/logging.properties Normal file
View File

@@ -0,0 +1,24 @@
#FileHandler/ConsoleHandler
handlers = java.util.logging.ConsoleHandler
############################################################
.level = FINER
java.level = INFO
javax.level = INFO
com.sun.level = INFO
sun.level = INFO
jdk.level = INFO
java.util.logging.FileHandler.level = FINER
#10M
java.util.logging.FileHandler.limit = 10485760
java.util.logging.FileHandler.count = 10000
java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%u.log
java.util.logging.FileHandler.append = true
java.util.logging.ConsoleHandler.level = FINER

14
conf/persistence.xml Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://558cfc37a10ef.sh.cdb.myqcloud.com:3817/demo?autoReconnect=true&amp;characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.user" value="cdb_outerroot"/>
<property name="javax.persistence.jdbc.password" value="l237809796"/>
</properties>
</persistence-unit>
</persistence>

50
pom.xml
View File

@@ -7,13 +7,33 @@
<groupId>net.tccn</groupId>
<artifactId>meta-kit</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<packaging>jar</packaging>
<modules>
<module>qtask</module>
<!--<module>qtask</module>-->
</modules>
<dependencies>
<!-- redkale支持 -->
<dependency>
<groupId>org.redkale</groupId>
<artifactId>redkale</artifactId>
<version>1.9.9</version>
</dependency>
<!-- arangodb支持 -->
<dependency>
<groupId>com.arangodb</groupId>
<artifactId>arangodb-java-driver</artifactId>
<version>5.0.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@@ -31,6 +51,32 @@
<target>8</target>
</configuration>
</plugin>
<!-- 指定到相对路径下-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-artifact</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<type>${project.packaging}</type>
</artifactItem>
</artifactItems>
<outputDirectory>lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

12
qtask/.gitignore vendored
View File

@@ -1,12 +0,0 @@
/target/
.project
.classpath
/.settings/
/.externalToolBuilders/
/bin/
*.iml
.idea/
/.idea/
/out/
/tmp/
/libs/

View File

@@ -1,39 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.tccn</groupId>
<artifactId>meta-kit</artifactId>
<version>1.0</version>
</parent>
<groupId>net.tccn</groupId>
<artifactId>qtask</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,21 +0,0 @@
package net.tccn.base;
import java.util.LinkedHashMap;
/**
* Created by liangxianyou@eversec.cn at 2018/3/12 14:17.
*/
public class Kv<K,V> extends LinkedHashMap {
public static Kv of(){
return new Kv();
}
public static Kv of(Object k, Object v){
return new Kv().set(k,v);
}
public Kv<K, V> set(K k, V v){
put(k, v);
return this;
}
}

View File

@@ -1,16 +0,0 @@
package net.tccn.qtask;
import net.tccn.E;
public class QTaskEs extends QTaskAbs {
public QTaskEs(E e) {
super(e);
}
@Override
public Object execute() {
//find result by es api todo:
return null;
}
}

8
readme.md Normal file
View File

@@ -0,0 +1,8 @@
MetaData
--
1、元数据管理、Db组件、界面展示
---------------------------
2、Excel操作、Mysql操作、ES操作、
---------------------------
3、
---------------------------

167
root/ddl_export.html Normal file
View File

@@ -0,0 +1,167 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>MySql数据库表结构导出</title>
<!-- zui -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/zui/1.8.1/css/zui.min.css">
<link rel="stylesheet" href="res/css/zui-theme.css">
<link rel="stylesheet" href="res/css/red-kit.css">
<style>
.input-group {
margin-bottom: 10px;
}
</style>
</head>
<body>
<div class="container-fixed">
<row>
<div class="col-md-8">
<h3>导出数据库表结构(导出后使用wps打开)</h3>
<form>
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button">jdbc.url</button>
</span>
<input id="url" type="text" class="form-control" placeholder="jdbc:mysql://127.0.0.1:3306" v-model="jdbc.url">
</div>
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button">jdbc.user</button>
</span>
<input id="user" type="text" class="form-control" placeholder="请输入数据库用户" v-model="jdbc.user">
</div>
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button">jdbc.pwd</button>
</span>
<input id="pwd" type="text" class="form-control" placeholder="请输入数据库密码" v-model="jdbc.pwd">
</div>
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button">Database</button>
</span>
<input id="database" type="text" class="form-control" placeholder="请输入Database" v-model="jdbc.database">
</div>
<div class="input-group">
<div class="radio">
<label>
<input type="radio" v-model="cate" value="word" checked> 导出表结构到word
</label>
</div>
<div class="radio">
<label>
<input type="radio" v-model="cate" value="excel"> 导出表结构到excel
</label>
</div>
</div>
<button id="export" data-toggle="button" class="btn btn-primary" data-cate="word" type="button">导出表结构</button>
</form>
</div>
<div class="col-md-4" v-show="logs.total">
<h3>最近使用记录 <small>共 {{logs.total}} 条记录</small></h3>
<table class="table-bordered">
<thead>
<tr>
<th>IP</th>
<th>时间</th>
<th>导出数据类型</th>
</tr>
</thead>
<tbody>
<tr v-for="row in logs.rows">
<td v-text="row.remoteAddr"></td>
<td v-text="timeFmt(new Date(row.time*1), 'yyyy-MM-dd HH:mm:ss')"></td>
<td v-text="row.cate"></td>
</tr>
</tbody>
</table>
</div>
</row>
</div>
<!-- jQuery (ZUI中的Javascript组件依赖于jQuery) -->
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<!-- ZUI Javascript组件 -->
<script src="//cdnjs.cloudflare.com/ajax/libs/zui/1.8.1/js/zui.min.js"></script>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
function getData(key, defaultValue) {
var v = localStorage.getItem(key) || defaultValue || "";
if (typeof(v) == "string" && v.startsWith("{") && v.endsWith("}")) {
v = JSON.parse(v);
} else if (typeof(v) == "string" && v.startsWith("[") && v.endsWith("]")) {
v = JSON.parse(v);
}
return v;
}
var vm = new Vue({
el:".container-fixed",
data:{
jdbc:getData("jdbc", {url: "jdbc:mysql://192.168.202.11:3306/", user: "root"}),
cate: getData("cate", "word"),
logs: {}
},
watch: {
},
methods: {
loadLog: function() {
$.getJSON("/ddl/ddllist",function (json) {
vm.logs = json;
});
},
timeFmt: function (date,fmt){
var o = {
"M+" : date.getMonth()+1, //月份
"d+" : date.getDate(), //日
"H+" : date.getHours(), //小时
"m+" : date.getMinutes(), //分
"s+" : date.getSeconds(), //秒
"q+" : Math.floor((date.getMonth()+3)/3), //季度
"S" : date.getMilliseconds() //毫秒
};
if(/(y+)/.test(fmt))
fmt=fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length));
for(var k in o)
if(new RegExp("("+ k +")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
return fmt;
}
},
mounted: function () {
this.loadLog();
}
});
$("#export").click(function () {
localStorage.setItem("jdbc", JSON.stringify(vm.jdbc));
localStorage.setItem("cate", vm.cate);
$.post("/"+ vm.cate +"/build", {account:JSON.stringify(vm.jdbc)}, function (json) {
console.log(json)
if (json.code == 0) {
location.href = "/"+ vm.cate +"/download";
} else {
alert(json.message);
}
});
});
</script>
</body>
</html>

BIN
root/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

164
root/index.html Normal file
View File

@@ -0,0 +1,164 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MetaKit</title>
<link rel="stylesheet" href="../res/zui/css/zui.min.css">
<link rel="stylesheet" href="../res/css/zui-theme.css">
<link rel="stylesheet" href="../res/css/red-kit.css">
<style>
</style>
</head>
<body id="home">
<div class="container-fluid">
<row>
<div class="col-md-12" id="top">
<ul class="nav nav-tabs">
<!--item in pages-->
<li v-for="item in pages" @click="loadMain(item)" :class="{active:item.name==pageId}">
<a data-tab href="#" v-text="item.name"></a>
</li>
<li class="pull-right" style="padding-top: 10px">
<select v-model="sysPlat" class="form-control" style="border: 0;background-color: #404a53;color: #fff;">
<option v-for="item in sysPlats" :value="item" v-text="item.name"></option>
</select>
</li>
<li class="pull-right" style="padding-top: 10px">
<a style="padding: 6px 15px;border: 0;background-color: #404a53;color: #fff;">
<i class="icon icon-user"></i> root
</a>
</li>
</ul>
</div>
<div id="mainDiv">
<div class="col-md-1" id="left">
<nav class="menu" data-ride="menu">
<ul class="nav nav-primary">
<li class="active show nav-parent" style="width: 100%;">
<a href="javascript:;"><i class="icon icon-tasks"></i> <span v-text="pageId"></span></a>
<ul class="nav">
<!-- item in menus -->
<li v-for="item in menus" @click="loadPage(item)" :class="{active:page.url==item.url}">
<a href="javascript:;"><i :class="['icon', item.icon ? item.icon : 'icon-circle-blank']"></i> <span v-text="item.name"></span></a>
</li>
</ul>
</li>
</ul>
</nav>
</div>
<div class="col-md-11">
<!--<div style="height: 40px;background-color: #fff;"></div>-->
<!-- load main body to here -->
<div id="main"></div>
</div>
</div>
</row>
</div>
<script src="../res/zui/lib/jquery/jquery.js"></script>
<script src="../res/zui/js/zui.js"></script>
<script src="../res/zui/lib/sortable/zui.sortable.js"></script>
<script src="../res/js/red.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var vm = new Vue({
el: ".container-fluid",
data: {
sysPlat: red.getData("sysPlat"),
sysPlats: red.getData("sysPlats"),
pages: [
{name: "DDL", url: "/qtask/ddl.html"},
{name: "MetaData", url: "/meta", nodes: [
/*{url:"/metadata/metatable/list.html", name:"TableList"},*/
{url:"/metadata/metatable/metaTable.html", name:"MetaTable"},
{url:"/metadata/metaLink.html", name:"MetaLink"},
{url:"/metadata/metaService.html", name:"MetaService"},
{url:"/metadata/dataList.html", name:"数据查询"},
]
},
{
name: "QTask", url: "/qtask", nodes: [
{url:"/qtask/list.html", name:"QTask", icon:"icon-beaker"},
{url:"/qtask/debug.html", name:"QTask-Debug", icon:"icon-bug"},
]
},
{
name: "业务平台", url: "/qtask", nodes: [
{url:"/plat/index.html", name:"业务平台", icon:"icon-server"},
{url:"/plat/dev.html", name:"dev", icon:"icon-beaker"},
]
},
{
name: "数据平台", url: "/plat/db.html", nodes: [
{url:"/plat/db.html", name:"数据中心", icon: "icon-database"},
]
},
],
menus: red.getData("menus", [
{url:"/qtask/plat.html", name:"业务平台"},
{url:"/qtask/list.html", name:"QTask"},
{url:"/qtask/debug.html", name:"QT-Debug"},
]),
page: red.getData("page", {url:"/qtask/list.html", name:"QTask"}),
pageId: red.getData("pageId", "QTask")
},
watch: {
page: function () {
//page main chengedup all cache for munus/pageId/page data
red.setData("page", this.page);
red.setData("menus", this.menus);
red.setData("pageId", this.pageId);
},
sysPlat: function (v) {
red.setData("sysPlat", v);
this.loadPage();
}
},
methods: {
loadPage: function (page) {
if (page && this.page.url == page.url) {
return false;
}
page = page || this.page;
this.page = page;
$("#main").load(page.url);
},
loadMain: function (item) {
this.menus = item.nodes || [item];
this.pageId = item.name;
}
},
mounted: function () {
//绑定事件
$('.menu .nav').on('click', 'li:not(.nav-parent) > a', function() {
var $this = $(this);
$('.menu .nav .active').removeClass('active');
$this.closest('li').addClass('active');
$this.closest('.nav-parent').addClass('active');
});
$("#main").load(this.page.url);
//this.loadPage(this.page);
//监听浏览器窗口大小变化
function autoLeftHeight() {
var h = document.documentElement.clientHeight || document.body.clientHeight;
$("#left").attr("style", "height:" + (h - 50) + "px");
$("#main").attr("style", "height:" + (h - 50) + "px; overflow: auto;");
}
autoLeftHeight();
$(window).resize(function () {
autoLeftHeight();
});
}
});
</script>
</body>
</html>

321
root/list.html Normal file
View File

@@ -0,0 +1,321 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>高级查询</title>
<!-- zui -->
<link rel="stylesheet" href="res/zui/css/zui.min.css">
<link rel="stylesheet" href="res/css/zui-theme.css">
<link rel="stylesheet" href="res/css/red-kit.css">
<style>
.item {
padding-top: 10px;
}
.table > thead > tr > th.sort:after{
display: inline-block;
margin-left: 5px;
font-family: ZenIcon;
font-size: 14px;
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
color: #808080;
text-transform: none;
content: '\e6bd';
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.table > thead > tr > th.sort-up:after {
color: #145ccd;
content: '\e6b9';
}
.table > thead > tr > th.sort-down:after {
color: #145ccd;
content: '\e6b8';
}
</style>
</head>
<body>
<div class="container-fixed">
<h3>高级查询 - [测试用例]</h3>
<div class="row">
<div class="col-md-6">
<select class="form-control" v-model="table" style="width: 300px;">
<option v-for="t in tables" :value="t.name">{{t.comment}}&nbsp;&nbsp;&nbsp;[{{t.name}}]</option>
</select>
</div>
<div class="col-md-6">
<div class="input-group pull-left">
<span class="input-group-btn">
<button class="btn btn-default" type="button">添加过滤条件</button>
</span>
<select class="form-control" v-model="addFilter" style="width: 130px;">
<option></option>
<option v-for="f in cfg.filters" :value="f.name" :disabled="f.add">{{f.label}}</option>
</select>
<span class="input-group-btn">
<button @click="findList" class="btn btn-primary" type="button"> 查询</button>
</span>
<span class="input-group-btn" style="padding-left: 10px">
<button @click="exportExcel" class="btn" type="button"> 导出</button>
</span>
</div>
</div>
<div class="col-md-12">
<div class="input-group item" v-for="(x,index) in formFilter">
<span class="input-group-addon" style="width: 130px">{{x.label}}</span>
<select class="form-control" :name="formFilter[index].name + '_cate'" style="width: 100px">
<option v-for="t in x.filterType" :value="t.name">{{t.remark}}</option>
</select>
<span class="input-group-addon fix-border fix-padding"></span>
<input type="text" class="form-control" v-model="para[formFilter[index].name]">
</div>
</div>
<div class="col-md-12" style="padding-top: 10px;overflow:auto;">
<table class="table table-bordered table-hover" style="width: 100%">
<thead>
<tr>
<th v-for="field in cfg.cols"
v-text="field.label"
:class="{'sort':field.order>0, 'sort-up':field.col==order.col && order.desc==1, 'sort-down':field.col==order.col && order.desc!=1}"
@click="sortEvent(field.col)"
>
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in list.rows">
<td v-for="field in cfg.cols" v-title="dealField(row, field.col)" v-text="dealField(row, field.col)"></td>
</tr>
</tbody>
<!--<tfoot>
<tr>
<td :colspan="meta.field_label.length">
<ul class="pager pull-right">
<li class="previous">
<a>{{list.total}}条数据</a>
</li>
<li :class="['previous', {'disabled':limit.pn==1}]">
<a @click="findList(&#45;&#45; limit.pn)" href="javascript:;">«上一页</a>
</li>
<li :class="['next', {'disabled':limit.pn >= limit.total}]">
<a @click="findList(limit.pn = ++limit.pn )" href="javascript:;">»下一页</a>
</li>
</ul>
</td>
</tr>
</tfoot>-->
</table>
</div>
<div>
<ul class="pager pull-right" style="margin: 5px 10px">
<li class="previous">
<a style="border: 0;">共{{list.total}}条数据</a>
</li>
<li :class="['previous', {'disabled':limit.pn==1}]">
<a @click="findList(-- limit.pn)" href="javascript:;">«上一页</a>
</li>
<li :class="['next', {'disabled':limit.pn >= limit.total}]">
<a @click="findList(limit.pn = ++limit.pn )" href="javascript:;">»下一页</a>
</li>
<li class="previous">
<a style="border-bottom: 0;border-right: 0;border-top: 0;">到第<input v-model="limit.pn" style="width: 30px;height: 21px;">/ {{limit.total}}页</a>
</li>
<li class="previous">
<a @click="findList(limit.pn)" href="javascript:;">确定</a>
</li>
</ul>
</div>
</div>
</div>
<script src="res/zui/lib/jquery/jquery.js"></script>
<script src="res/zui/js/zui.js"></script>
<script src="res/zui/lib/sortable/zui.sortable.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var vm = new Vue({
el:".row",
data: {
cfg:{
cols: [],
filters: []
},
tables: [],
table: "",
filters: [],
formFilter: [
],
addFilter: "recompany",
para: {},
list: {},
limit: {pn: 1, ps: 10, total: 0},
order:{col:"", desc:1}
},
watch: {
addFilter: function (v) {
vm.cfg.filters.forEach(function (f) {
if (f.name == v) {
f["add"] = 1;
vm.add = "";
vm.formFilter.push(f);
}
})
},
table: function (v) {
vm.loadCfg();
vm.formFilter = [];
vm.findList();
},
list: function () {
var limit = vm.limit;
var list = vm.list;
var total = parseInt(list.total/limit.ps) + (list.total%limit.ps > 0 ? 1 : 0);
vm.limit["total"] = total;
},
limit: {
handler(a, b) {
},
immediate: true,
deep: true
},
},
methods: {
findList: function (n) {
var data = [];
for (k in vm.para) {
if (vm.para[k] != ''){
var d = {};
d["col"] = k;
d["value"] = vm.para[k];
d["type"] = $("select[name="+ k +"_cate]").val();
data.push(d);
}
}
data.push({col:"status", value: 9, type: "NOTEQUAL"});
var orders = [];
if (vm.order.col) {
orders.push(vm.order);
}
var fBean = {
keyService: vm.table,
filters: data,
orders: orders,
limit: vm.limit
}
$.post("/db/list", {fBean: JSON.stringify(fBean)}, function (json) {
vm.list = json.body;
});
},
exportExcel: function() {
var data = [];
for (k in vm.para) {
if (vm.para[k] != ''){
var d = {};
d["col"] = k;
d["value"] = vm.para[k];
d["type"] = $("select[name="+ k +"_cate]").val();
data.push(d);
}
}
data.push({col:"status", value: 9, type: "NOTEQUAL"});
var fBean = {
keyService: vm.table,
filters: data,
orders: [{col: "status", desc: -1}],
limit:{ps: 5}
}
location.href = "/export/data?fBean=" + JSON.stringify(fBean);
return;
},
loadTables: function() {
$.getJSON("/meta/alltable",function (json) {
vm.tables = json;
if (!vm.table) {
//vm.table = vm.tables[0].name;
vm.table = "basic_platform";
}
});
},
loadCfg: function () {
$.getJSON("/meta/listcfg", {key: vm.table}, function (json) {
vm.cfg = json;
});
},
dealField: function (bean, field) {
var str = "";
if (!bean || !field){
}else if (typeof(field) === 'function'){
str = field(bean);
}else if (field.indexOf("||") > 0){//处理字典数据
var dic_type = field.split("||")[1];
var v = bean[field.split("||")[0]];
str = kvExtDeal(dic_type, v);
}else if (field.indexOf("|") > 0){//处理字典数据
var dic_type = field.split("|")[1];
var v = bean[field.split("|")[0]];
str = v;//kvDeal(dic_type, v);
}
else if (field.indexOf("=") > 0){//处理字典数据
var fun = field.split("=")[1];
var v = bean[field.split("=")[0]];
return v;
//eval("str =$funs."+ fun +"('"+ v +"')");
}
else if (field.indexOf("-") > 0){
var name = field.split("-")[0];
var path = field.split("-")[1];
if (bean[name]){
var href = config.services.issct+"/downLoadFdfs?fileId="+encodeURI(bean[path])+"&filename="+encodeURI(bean[name]);
str = "<a href='"+ href +"' target='_blank'>"+ bean[name] +"</a>";
}
}else if (bean[field] === 0) { //特殊值 "0" 处理
str = "0";
}else if (bean[field] == "unknown") { //特殊值处理
str = "";
}else {
str = bean[field] || "";
}
return str;
},
sortEvent: function (col) {
if(vm.order.col == col){
vm.order.desc = - vm.order.desc
}else{
vm.order.col = col;
vm.order.desc = 1;
}
vm.findList();
}
},
mounted: function () {
this.loadTables();
}
});
</script>
</body>
</html>

511
root/meta.html Normal file
View File

@@ -0,0 +1,511 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- zui -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/zui/1.8.1/css/zui.min.css">
<link rel="stylesheet" href="res/css/zui-theme.css">
<link rel="stylesheet" href="res/css/red-kit.css">
<style>
.row {
margin-top: 10px;
}
.panel-body {
padding: 0;
}
.icon-move{
padding-left: 5px;
}
</style>
</head>
<body>
<div class="container-fixed">
<div class="row">
<div class="col-md-8">
<div class="input-group list-head">
<span class="input-group-btn">
<button class="btn btn-default" type="button">选择业务类型</button>
</span>
<select class="form-control" v-model="table" style="width: 300px;">
<option v-for="t in tables" :value="t.name">{{t.comment}}&nbsp;&nbsp;&nbsp;[{{t.name}}]</option>
</select>
<span class="input-group-btn">
<button @click="status=1" :class="['btn',{'btn-primary':status==1}]" type="button"> 排序</button>
</span>
<span class="input-group-btn">
<button @click="status=2" :class="['btn',{'btn-primary':status==2}]" type="button"> 编辑属性</button>
</span>
<span class="input-group-btn" style="padding-left: 20px">
<button @click="status=5" :class="['btn',{'btn-primary':status==5}]" type="button"> 列表配置</button>
</span>
<span class="input-group-btn">
<button @click="status=6" :class="['btn',{'btn-primary':status==6}]" type="button"> 查询配置</button>
</span>
<span class="input-group-btn" style="padding-left: 20px">
<button @click="status=3" :class="['btn',{'btn-primary':status==3}]" type="button"> 导出配置</button>
</span>
<span class="input-group-btn">
<button @click="status=4" :class="['btn',{'btn-primary':status==4}]" type="button"> 导入配置</button>
</span>
<span class="input-group-btn" style="padding-left: 30px">
<button @click="metaSave()" :class="['btn',{'btn-primary':status!=0}]" type="button"> 保存修改</button>
</span>
</div>
</div>
<div class="col-md-8">
<table class="table-bordered">
<thead>
<tr style="background-color: #f1f1f1">
<td v-show="status==3 || status==4 || status==5"><input type="checkbox"></td>
<th v-show="status==1"></th>
<th>字段名</th>
<th>中文名</th>
<th>数据类型</th>
<th>输入类型</th>
<th>附加属性</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.items">
<td v-show="status==3"><input type="checkbox" v-model="meta.exports" :value="item.name" class="form-control"></td>
<td v-show="status==4"><input type="checkbox" v-model="meta.imports" :value="item.name" class="form-control"></td>
<td v-show="status==5"><input type="checkbox" v-model="meta.shows" :value="item.name" class="form-control"></td>
<td v-show="status==1" class="icon icon-move"></td>
<td v-show="status!=2" v-text="item.name" style="background-color: rgb(235, 235, 228);"></td>
<td v-show="status!=2" v-text="item.label"></td>
<td v-show="status!=2" v-text="item.type"></td>
<td v-show="status!=2" v-text="item.inType"></td>
<td v-show="status!=2" v-text="item.inExt"></td>
<td v-show="status!=2" v-text="item.remark"></td>
<td v-show="status==2">
<input v-model="item" type="hidden">
<input :value="item.name" disabled class="form-control">
<input v-model="item.name" type="hidden">
<input name="name" type="hidden" :value="item.name">
</td>
<td v-show="status==2"><input v-model="item.label" class="form-control"></td>
<td v-show="status==2"><input v-model="item.type" class="form-control"></td>
<td v-show="status==2"><!--<input v-model="item.inType">-->
<select v-model="item.inType" class="form-control" style="width: 130px">
<option></option>
<option v-for="x in inTypes" :value="x">{{x}}</option>
</select>
</td>
<td v-show="status==2"><input v-model="item.inExt" class="form-control"></td>
<td v-show="status==2"><input v-model="item.remark" class="form-control"></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-4" v-show="false">
<table class="table-bordered table-auto">
<thead>
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<th>展示名</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.items">
<td v-show="status!=2" class="icon icon-move"></td>
<td v-show="status!=2" v-text="item.name" style="background-color: rgb(235, 235, 228);"></td>
<td v-show="status!=2" v-text="item.label"></td>
<td v-show="status!=2"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-4" v-show="status==5">
<div class="panel">
<div class="panel-heading">
列表展示的属性
</div>
<div id="show" class="panel-body">
<table class="table-bordered table-auto" style="width: 100%">
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<th>支持排序</th>
</tr>
<tbody>
<tr v-for="(item, index) in meta.shows">
<td class="icon icon-move">
<input name="name" :value="item" type="hidden">
</td>
<td v-text="item" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item)}}</td>
<td v-show="false"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- exports -->
<div class="col-md-4" v-show="status==3">
<div class="panel">
<div class="panel-heading">
导出的属性配置
</div>
<div id="export" class="panel-body">
<table class="table-bordered table-auto" style="width: 100%">
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<!--<th>展示名</th>-->
</tr>
<tbody>
<tr v-for="(item, index) in meta.exports">
<td class="icon icon-move">
<input name="name" :value="item" type="hidden">
</td>
<td v-text="item" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item)}}</td>
<td v-show="false"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- imports -->
<div class="col-md-4" v-show="status==4">
<div class="panel">
<div class="panel-heading">
导入的属性配置
</div>
<div id="import" class="panel-body">
<table class="table-bordered table-auto" style="width: 100%">
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<!--<th>展示名</th>-->
</tr>
<tbody>
<tr v-for="(item, index) in meta.imports">
<td class="icon icon-move">
<input name="name" :value="item" type="hidden">
</td>
<td v-text="item" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item)}}</td>
<td v-show="false"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- findList -->
<div class="col-md-6" v-show="status==6">
<!--<div class="form-group">
<label class="checkbox-inline">
<input type="checkbox"> fdsaf
</label>
</div>-->
<div class="panel">
<div class="panel-heading">
高级查询的属性配置
</div>
<div id="find" class="panel-body" style="overflow:auto;">
<table class="table-bordered table-auto" style="width: 100%">
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<th>支持查询类型</th>
</tr>
<tbody>
<tr v-for="(item, index) in meta.filters">
<td class="icon icon-move">
<input name="name" :value="item.name" type="hidden">
</td>
<td v-text="item.name" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item.name)}}</td>
<td>
<label class="checkbox-inline" v-for="item in filterCate">
<input type="checkbox"> {{item}}
</label>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- jQuery (ZUI中的Javascript组件依赖于jQuery) -->
<script src="res/zui/lib/jquery/jquery.js"></script>
<!-- ZUI Javascript组件 -->
<script src="res/zui/js/zui.js"></script>
<script src="res/zui/lib/sortable/zui.sortable.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!--<script src="https://unpkg.com/axios/dist/axios.min.js"></script>-->
<script>
var vm = new Vue({
el:".row",
data: {
inTypes: ["INPUT", "SELECT_EXT", "INPUT_DT"],
dataTypes: ["bigint(20)","varchar(255)","varchar(64)","varchar(32)","varchar(16)","int(11)", "int(3)","int(2)","datetime"],
filterCate:["EQUAL","NOTEQUAL","LIKE","IN","NOTEQUAL","LIKE","IN"],
tables: [],//所有的业务类型,【测试用】
meta: {
items: [],
shows: [],
exports: [],
imports: []
},//完整的元数据数据,
move: false,
status:0, //页面默认状态
table: "", //页面选择的业务类型
itemSort:[], //待保存的业务属性
oldItems:[], //不被修改的字段属性
itemEdit:{}, //待修改的字段属性
},
watch: {
status : function (v) {
this.canMove(v)
},
table: function (table) {
this.load(table);
},
"meta.items": {
handler: function (nv, ov) {
var itemNv = nv || [];
var itemOv = vm.oldItems || [];
if (itemOv.length == 0) return;
var itemEdit = [];
a:for (var i = 0; i < itemOv.length; i++) {
var attr = ["label", "name", "remark", "type", "inType"];
for (var j = 0; j < attr.length; j++) {
var k = attr[j];
if (itemOv[i][k] != itemNv[i][k]) {
itemEdit.push(itemNv[i]);
continue a;
}
}
}
vm.itemEdit = itemEdit;
},
deep: true
},
"meta.shows": function (v) {
console.log(v.length)
}
},
methods: {
load: function (cate) {
this.status = 0;
$.getJSON("/meta/info?key="+this.table,function (json) {
vm.meta = json;
var oldItems = [];
json.items.forEach(function (item) {
var d = {};
["label", "name", "remark", "type", "inType"].forEach(function (k) {
d[k] = item[k];
});
oldItems.push(d);
});
vm.oldItems = oldItems;
});
/*axios.get("/meta/info?key="+this.table).then(function (json) {
console.log("axios", json)
vm.meta = json.data;
});*/
},
getAllTables: function() {
$.getJSON("/meta/alltable",function (json) {
vm.tables = json;
if (!vm.table) {
//vm.table = vm.tables[0].name;
vm.table = "basic_platform";
}
});
},
canMove: function () {
if (this.status == 1) {
$('#sortableList,table>tbody').sortable({
selector: '.list-group-item, tr',
finish: function(e) {
var rows = e.list;
vm.itemSort = [];
for (var i=0;i<rows.length;i++) {
var item = $(rows[i]).find("input[name='name']").val();
vm.itemSort.push(item);
}
},
// 设置更多选项...
});
}
else if (this.status == 5) {
$('#show>table>tbody').sortable({
selector: 'tr',
finish: function (e) {
var rows = e.list;
var shows = [];
for (var i=0;i<rows.length;i++) {
var item = $(rows[i]).find("input[name='name']").val();
shows.push(item);
}
vm.meta.shows = shows;
}
});
}else if (this.status == 4) {
$('#import>table>tbody').sortable({
selector: 'tr',
finish: function (e) {
var rows = e.list;
var shows = [];
for (var i=0;i<rows.length;i++) {
var item = $(rows[i]).find("input[name='name']").val();
shows.push(item);
}
vm.meta.imports = shows;
}
});
}else if (this.status == 3) {
$('#export>table>tbody').sortable({
selector: 'tr',
finish: function (e) {
var rows = e.list;
var shows = [];
for (var i=0;i<rows.length;i++) {
var item = $(rows[i]).find("input[name='name']").val();
shows.push(item);
}
vm.meta.exports = shows;
}
});
} else {
$('table>tbody').sortable('destroy');
}
},
/**
* 保存元数据变更:
* 1、基础数据排序
* --> 传递元素的顺序,后台对元素顺序重排
* 2、基础数据属性修改
* --> 只提交被修改过的元素及属性数据,后端通过属性名称对应修改,
* 3、导出
* 导出排序
* --> 传递元素的顺序,后台对元素的顺利重排,(同基础元素排序)
* 导出元素加减
* --> 将元素完整传递到后台,进行覆盖保存
* 4、导入
* 导入排序
* 导入元素加减
*
*/
metaSave: function () {
if (vm.status == 1 && vm.itemSort.length > 0) {
$.getJSON("/meta/itemsort", {serviceKey:vm.table, items:JSON.stringify(vm.itemSort)}, function (json) {
console.log(json);
new $.zui.Messager('操作成功', {
type: 'info' // 定义颜色主题
,placement: "bottom-right"
}).show();
//vm.status = 0;
});
}
else if (vm.status == 2 && vm.itemEdit.length > 0) {
$.getJSON("/meta/itemupdate", {serviceKey:vm.table, items:JSON.stringify(vm.itemEdit)}, function (json) {
console.log(json);
//vm.status = 0;
new $.zui.Messager('操作成功', {
type: 'info' // 定义颜色主题
,placement: "bottom-right"
}).show();
vm.itemEdit = [];
});
}
else if (vm.status == 3 || vm.status == 4 || vm.status == 5) {
var urls = {3: "/meta/exportsort", 4: "/meta/importsort", 5: "/meta/showsort"};
var items = {3: vm.meta.exports, 4: vm.meta.imports, 5: vm.meta.shows};
$.getJSON(urls[vm.status], {serviceKey:vm.table, items:JSON.stringify(items[vm.status])}, function (json) {
console.log(json);
//vm.status = 0;
new $.zui.Messager('操作成功', {
type: 'info' // 定义颜色主题
,placement: "bottom-right"
}).show();
});
}
else if (vm.status == 5) {
$.getJSON("/meta/showsort", {serviceKey:vm.table, items:JSON.stringify(vm.meta.shows)}, function (json) {
console.log(json);
//vm.status = 0;
new $.zui.Messager('操作成功', {
type: 'info' // 定义颜色主题
,placement: "bottom-right"
}).show();
});
}
else {
new $.zui.Messager('操作成功', {
type: 'info' // 定义颜色主题
,placement: "bottom-right"
}).show();
}
},
getFieldLabel: function (col) {
for (var i = 0; i < vm.oldItems.length; i++) {
if (vm.oldItems[i].name == col) {
return vm.oldItems[i].label;
}
}
},
},
mounted: function (){
this.getAllTables();
//this.canMove();
/*for (var i = 0; i < 100; i++) {
this.load('record_ip')
}*/
}
});
</script>
</body>
</html>

262
root/metadata/dataList.html Normal file
View File

@@ -0,0 +1,262 @@
<style>
.item {
padding-top: 10px;
}
</style>
<row class="data-list">
<h3>高级查询 - [测试用例]</h3>
<div class="col-md-6">
<select class="form-control" v-model="table" style="width: 300px;">
<option v-for="t in tables" :value="t.name">{{t.comment}}&nbsp;&nbsp;&nbsp;[{{t.name}}]</option>
</select>
</div>
<div class="col-md-6">
<div class="input-group pull-left">
<span class="input-group-btn">
<button class="btn btn-default" type="button">添加过滤条件</button>
</span>
<select class="form-control" v-model="addFilter" style="width: 130px;">
<option v-for="f in cfg.filters" :value="f.name" :disabled="f.checked">{{f.label}}</option>
</select>
<span class="input-group-btn">
<button @click="findList" class="btn btn-primary" type="button"> 查询</button>
</span>
<span class="input-group-btn" style="padding-left: 10px">
<button @click="exportExcel" class="btn" type="button"> 导出</button>
</span>
</div>
</div>
<div class="">
<div class="col-lg-4 col-md-6 col-xs-12" v-for="(x,index) in cfg.filters" v-if="x.checked">
<div class="input-group item">
<span class="input-group-addon" style="width: 130px;">{{x.label}}</span>
<select class="form-control" :name="cfg.filters[index].name + '_cate'" style="width: 100px">
<option v-for="t in x.filterType" :value="t.name">{{t.remark}}</option>
</select>
<span class="input-group-addon fix-border fix-padding"></span>
<input type="text" class="form-control" v-model="para[cfg.filters[index].name]">
<span class="input-group-addon fix-border fix-padding" style="padding: 5px" title="删除过滤条件">
<a href="javascript:;" @click="x.checked = false;"><i class="icon icon-trash"></i></a>
</span>
</div>
</div>
</div>
<div class="col-md-12" style="padding-top: 10px;overflow:auto;">
<table class="table table-bordered table-hover" style="width: 100%">
<thead>
<tr>
<th v-for="field in cfg.cols"
v-text="field.label"
:class="{'sort':field.order>0, 'sort-up':field.col==order.col && order.desc==1, 'sort-down':field.col==order.col && order.desc!=1}"
@click="sortEvent(field.col)"
>
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in list.rows">
<td v-for="field in cfg.cols" v-title="dealField(row, field.col)" v-text="dealField(row, field.col)"></td>
</tr>
</tbody>
</table>
</div>
<div>
<ul class="pager pull-right" style="margin: 5px 10px">
<li class="previous">
<a style="border: 0;">共{{list.total}}条数据</a>
</li>
<li :class="['previous', {'disabled':limit.pn==1}]">
<a @click="findList(-- limit.pn)" href="javascript:;">«上一页</a>
</li>
<li :class="['next', {'disabled':limit.pn >= limit.total}]">
<a @click="findList(limit.pn = ++limit.pn )" href="javascript:;">»下一页</a>
</li>
<li class="previous">
<a style="border-bottom: 0;border-right: 0;border-top: 0;">到第<input v-model="limit.pn" style="width: 30px;height: 21px;">/ {{limit.total}}页</a>
</li>
<li class="previous">
<a @click="findList(limit.pn)" href="javascript:;">确定</a>
</li>
</ul>
</div>
</row>
<script>
var vm = new Vue({
el:".data-list",
data: {
cfg:{
cols: [],
filters: []
},
tables: [],
table: "",
//filters: [],
addFilter: "recompany",
para: {},
list: {rows:[], total:0},
limit: {pn: 1, ps: 10, total: 0},
order:{col:"id", desc:1}
},
watch: {
addFilter: function (v) {
vm.cfg.filters.forEach(function (f) {
if (f.name == v) {
f["checked"] = true;
vm.addFilter = "";
}
})
},
table: function () {
vm.loadCfg();
vm.limit = {pn: 1, ps: 10, total: 0};
vm.order = {col:"id", desc:1};
vm.findList();
},
list: function () {
var limit = vm.limit;
var list = vm.list;
var total = parseInt(list.total/limit.ps) + (list.total%limit.ps > 0 ? 1 : 0);
vm.limit["total"] = total;
}
},
methods: {
findList: function () {
var filters = [];
for (i in vm.cfg.filters) {
var f = vm.cfg.filters[i]
if (f.checked && vm.para[f.name] != '') {
var d = {};
d["col"] = f.name;
d["value"] = vm.para[f.name];
d["type"] = $("select[name=" + f.name + "_cate]").val();
filters.push(d);
}
}
filters.push({col: "status", value: 9, type: "NOTEQUAL"});
var orders = [];
//截取真实字段名,(考虑如果多表关联情况,是否需要加入真实字段名)
if (vm.order.col) {
var end = vm.order.col.indexOf("\|");
if (end < 0) {
end = vm.order.col.indexOf("=")
}
var col = vm.order.col;
if (end > 0) {
col = vm.order.col.substring(0, end);
}
orders.push({col: col, desc: vm.order.desc});
}
var fbean = {
keyService: vm.table,
filters: filters,
orders: orders,
limit: vm.limit
}
red.getJSON("/db/list",{fBean: JSON.stringify(fbean)}, function (json) {
json = json || {rows:[], total:0};
vm.list = json;
})
},
exportExcel: function () {
var data = [];
for (k in vm.para) {
if (vm.para[k] != '') {
var d = {};
d["col"] = k;
d["value"] = vm.para[k];
d["type"] = $("select[name=" + k + "_cate]").val();
data.push(d);
}
}
data.push({col: "status", value: 9, type: "NOTEQUAL"});
var fBean = {
keyService: vm.table,
filters: data,
orders: [{col: "status", desc: -1}],
limit: {ps: 5}
}
location.href = "/export/data?fBean=" + JSON.stringify(fBean) + "&platToken=" + red.getPlatToken() + "&cate=csv";
return;
},
tableList: function () {
red.getJSON("/meta/tablelist",{}, function (json) {
vm.tables = json;
vm.table = vm.tables[0].name;
});
},
loadCfg: function () {
red.getJSON("/meta/listcfg", {key: vm.table, platToken: red.getPlatToken()}, function (json) {
vm.cfg = json;
});
},
dealField: function (bean, field) {
var str = "";
if (!bean || !field) {
} else if (typeof(field) === 'function') {
str = field(bean);
} else if (field.indexOf("||") > 0) {//处理字典数据
var dic_type = field.split("||")[1];
var v = bean[field.split("||")[0]];
str = kvExtDeal(dic_type, v);
} else if (field.indexOf("|") > 0) {//处理字典数据
var dic_type = field.split("|")[1];
var v = bean[field.split("|")[0]];
str = v;//kvDeal(dic_type, v);
}
else if (field.indexOf("=") > 0) {//处理字典数据
var fun = field.split("=")[1];
var v = bean[field.split("=")[0]];
return v;
//eval("str =$funs."+ fun +"('"+ v +"')");
}
else if (field.indexOf("-") > 0) {
var name = field.split("-")[0];
var path = field.split("-")[1];
if (bean[name]) {
var href = config.services.issct + "/downLoadFdfs?fileId=" + encodeURI(bean[path]) + "&filename=" + encodeURI(bean[name]);
str = "<a href='" + href + "' target='_blank'>" + bean[name] + "</a>";
}
} else if (bean[field] === 0) { //特殊值 "0" 处理
str = "0";
} else if (bean[field] == "unknown") { //特殊值处理
str = "";
} else {
str = bean[field] || "";
}
return str;
},
sortEvent: function (col) {
if (vm.order.col == col) {
vm.order.desc = -vm.order.desc
} else {
vm.order.col = col;
vm.order.desc = 1;
}
vm.findList();
}
},
mounted: function () {
this.tableList();
}
});
</script>

View File

@@ -0,0 +1,29 @@
<row class="meta-link">
</row>
<script>
var vm = new Vue({
el: ".meta-link",
data: {
},
watch: {
},
methods: {
},
mounted: function () {
var m = {"a.name": "lxyer", "a.`age`": 11}
console.log(m["a.name"])
console.log("---------")
for (var k in m) {
console.log(k)
}
}
});
</script>

View File

@@ -0,0 +1,614 @@
<row class="meta-service">
<div class="col-md-12" style="padding-top: 10px;">
<div class="input-group list-head">
<!--<span class="input-group-btn">
<button class="btn btn-default" type="button">数据平台</button>
</span>
<select class="form-control" v-model="filter.dbPlatId" style="width: 100px;">
<option></option>
<option v-for="item in dbPlats" :value="item.key">{{item.name}}</option>
</select>-->
<span class="input-group-btn">
<button class="btn btn-default" type="button">选择业务类型</button>
</span>
<select class="form-control" v-model="table" style="width: 180px;">
<option v-for="item in tables" :value="item.name"> {{item.name}}&nbsp;&nbsp;&nbsp;[{{item.comment}}]</option>
</select>
<span class="input-group-btn">
<button @click="status=1" :class="['btn',{'btn-primary':status==1}]" type="button"> 排序</button>
</span>
<span class="input-group-btn">
<button @click="status=2" :class="['btn',{'btn-primary':status==2}]" type="button"> 编辑属性</button>
</span>
<span class="input-group-btn" style="padding-left: 20px">
<button @click="status=5" :class="['btn',{'btn-primary':status==5}]" type="button"> 列表配置</button>
</span>
<span class="input-group-btn">
<button @click="status=6" :class="['btn',{'btn-primary':status==6}]" type="button"> 查询配置</button>
</span>
<span class="input-group-btn" style="padding-left: 20px">
<button @click="status=3" :class="['btn',{'btn-primary':status==3}]" type="button"> 导出配置</button>
</span>
<span class="input-group-btn">
<button @click="status=4" :class="['btn',{'btn-primary':status==4}]" type="button"> 导入配置</button>
</span>
<span class="input-group-btn" style="padding-left: 20px">
<button @click="status=7;dbPlatList();" :class="['btn',{'btn-primary':status==7}]" type="button"> 数据平台</button>
</span>
<!-- fixme: 加入数据平台相关操作, 1、关联数据平台2、表结构入库 -->
<span class="input-group-btn" style="padding-left: 30px">
<button @click="save()" :class="['btn',{'btn-primary':status!=0},{'disabled':status==0}]" type="button"> 保存</button>
</span>
</div>
</div>
<div class="col-md-7">
<table class="table-bordered" style="width: 100%">
<thead>
<tr style="background-color: #f1f1f1">
<td v-show="status==3 || status==4 || status==5 || status==6"><input type="checkbox"></td>
<th v-show="status==1"></th>
<th>字段名</th>
<th>中文名</th>
<th>数据类型</th>
<th>输入类型</th>
<th>附加属性</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.items">
<td v-show="status==3"><input type="checkbox" v-model="meta.exports" :value="item.name" class="form-control"></td>
<td v-show="status==4"><input type="checkbox" v-model="meta.imports" :value="item.name" class="form-control"></td>
<td v-show="status==5"><input type="checkbox" v-model="meta.shows" :value="item.name" class="form-control"></td>
<td v-show="status==6"><input type="checkbox" v-model="filterArr" :value="item.name" class="form-control"></td>
<td v-show="status==1" class="icon icon-move"></td>
<td v-show="status!=2" v-text="item.name" style="background-color: rgb(235, 235, 228);"></td>
<td v-show="status!=2" v-text="item.label"></td>
<td v-show="status!=2" v-text="item.type"></td>
<td v-show="status!=2" v-text="item.inType"></td>
<td v-show="status!=2" v-text="item.inExt"></td>
<td v-show="status!=2" v-text="item.remark"></td>
<td v-show="status==2">
<input v-model="item" type="hidden">
<input :value="item.name" disabled class="form-control">
<input v-model="item.name" type="hidden">
<input name="name" type="hidden" :value="item.name">
</td>
<td v-show="status==2"><input v-model="item.label" class="form-control"></td>
<td v-show="status==2"><input v-model="item.type" class="form-control"></td>
<td v-show="status==2"><!--<input v-model="item.inType">-->
<select v-model="item.inType" class="form-control" style="width: 130px">
<option></option>
<option v-for="x in inTypes" :value="x">{{x}}</option>
</select>
</td>
<td v-show="status==2"><input v-model="item.inExt" class="form-control"></td>
<td v-show="status==2"><input v-model="item.remark" class="form-control"></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-5" v-show="false">
<table class="table-bordered table-auto">
<thead>
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<th>展示名</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.items">
<td v-show="status!=2" class="icon icon-move"></td>
<td v-show="status!=2" v-text="item.name" style="background-color: rgb(235, 235, 228);"></td>
<td v-show="status!=2" v-text="item.label"></td>
<td v-show="status!=2"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-5" v-show="status==5">
<div class="panel">
<div class="panel-heading">列表展示的属性</div>
<div id="show" class="panel-body">
<table class="table-bordered table-auto" style="width: 100%">
<thead>
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<!--<th>支持排序</th>-->
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.shows">
<td class="icon icon-move">
<input name="name" :value="item" type="hidden">
</td>
<td v-text="item" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item)}}</td>
<td v-show="false"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- exports -->
<div class="col-md-5" v-show="status==3">
<div class="panel">
<div class="panel-heading">导出的属性配置</div>
<div id="export" class="panel-body">
<table class="table-bordered table-auto" style="width: 100%">
<thead>
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<!--<th>展示名</th>-->
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.exports">
<td class="icon icon-move">
<input name="name" :value="item" type="hidden">
</td>
<td v-text="item" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item)}}</td>
<td v-show="false"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- imports -->
<div class="col-md-5" v-show="status==4">
<div class="panel">
<div class="panel-heading">
导入的属性配置
</div>
<div id="import" class="panel-body" style="/*padding-top: 10px;*/overflow:auto;">
<table class="table-bordered table-auto" style="width: 100%;height: 100%">
<thead>
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<!--<th>展示名</th>-->
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.imports">
<td class="icon icon-move">
<input name="name" :value="item" type="hidden">
</td>
<td v-text="item" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item)}}</td>
<td v-show="false"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- filters -->
<div class="col-md-5" v-show="status==6">
<div class="panel">
<div class="panel-heading">查询配置</div>
<div id="filter" class="panel-body" style="overflow:auto;">
<table class="table-bordered table-auto" style="width: 100%">
<thead>
<tr style="background-color: #f1f1f1">
<th></th>
<th style="width: 30px">字段名</th>
<th style="width: 30px">中文名</th>
<th style="width: 30px">默认展示</th>
<th>支持查询类型</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in filters">
<td class="icon icon-move">
<input name="name" :value="item.name" type="hidden">
</td>
<td v-text="item.name" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item.name)}}</td>
<td>
<label>
<input type="checkbox" v-model="item.checked" value="1"> 展示
</label>
</td>
<td>
<label class="checkbox-inline" v-for="c in filterCate">
<input type="checkbox" v-model="item.filterType" :value="c"> {{c}}
</label>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- dbPlat -->
<div class="col-lg-5" v-show="status==7 ">
<div class="panel">
<div class="panel-heading">数据平台配置</div>
<div class="panel-body" style="overflow:auto;">
<form>
<div class="form-group">
<label class="col-sm-2">数据平台</label>
<div class="col-md-6">
<input type="hidden" v-model="row.key">
<select v-model="row.dbPlatId" class="form-control">
<option></option>
<option v-for="item in dbPlats" :value="item.key" v-text="item.name"></option>
</select>
</div>
<div class="col-md-4">
<select v-model="row.catalog" class="form-control">
<option></option>
<option v-for="item in catalogs()" :value="item" v-text="item"></option>
</select>
</div>
</div>
</form>
</div>
</div>
</div>
</row>
<script src="res/zui/lib/sortable/zui.sortable.js"></script>
<script>
var vm = new Vue({
el: ".meta-service",
data: {
inTypes: ["INPUT", "SELECT_EXT", "INPUT_DT"],
dataTypes: ["bigint(20)", "varchar(255)", "varchar(64)", "varchar(32)", "varchar(16)", "int(11)", "int(3)", "int(2)", "datetime"],
filterCate: ["EQUAL", "NOTEQUAL", "LIKE", "IN"],
tables: [],//所有的业务类型,【测试用】
meta: {
items: [],
shows: [],
exports: [],
imports: [],
filters: [{name:"", filterType:[""]}]
},//完整的元数据数据,
move: false,
status: 0, //页面默认状态
table: "", //页面选择的业务类型
itemSort: [], //待保存的业务属性
oldItems: [], //不被修改的字段属性
itemEdit: {}, //待修改的字段属性
dbPlats:[],
row: {key: "", platId: "", catalog: ""},
filter: {db: "", catalog: "", name: ""},//tableList 过滤条件
filters:[],//查询配置
filterArr:[]
},
watch: {
status: function (v) {
this.setMove(v)
},
table: function (table) {
this.loadDetail(table);
},
"meta.items": {
handler: function (nv, ov) {
var itemNv = nv || [];
var itemOv = vm.oldItems || [];
if (itemOv.length == 0) return;
var itemEdit = [];
a:for (var i = 0; i < itemOv.length; i++) {
var attr = ["label", "name", "remark", "type", "inType"];
for (var j = 0; j < attr.length; j++) {
var k = attr[j];
if (itemOv[i][k] != itemNv[i][k]) {
itemEdit.push(itemNv[i]);
continue a;
}
}
}
vm.itemEdit = itemEdit;
},
deep: true
},
"meta.shows": function (v) {
//console.log(v.length)
},
tables: function (v) {
if(v.length > 0) {
vm.table = v[0]["name"];
}
},
meta: function (v) {
vm.row = {key:v.key, dbPlatId: v.dbPlatId, catalog: v.catalog};
vm.filters = v.filters;
var filterArr = [];
vm.filters.forEach(function (item) {
filterArr.push(item.name);
})
vm.filterArr = filterArr;
},
filterArr: function (v) {
var filters = [];
vm.filterArr.forEach(function (item) {
var filter;
for (i in vm.filters) {
if (item == vm.filters[i].name) {
filter = vm.filters[i];
}
}
/*vm.meta.filters.forEach(function (x) {
if (item == x.name) {
//filters.push(x);
filter = x;
}
})*/
if (!filter) {
filter = {name: item, filterType:[], checked: 0};
}
filters.push(filter);
});
vm.filters = filters;
}
},
methods: {
loadDetail: function (cate) {
//this.status = 0;
red.getJSON("/meta/tableinfo",{name: cate}, function (json) {
var row = json;
vm.meta = row;
var oldItems = [];
row.items.forEach(function (item) {
var d = {};
["label", "name", "remark", "type", "inType"].forEach(function (k) {
d[k] = item[k];
});
oldItems.push(d);
});
vm.oldItems = oldItems;
});
},
tableList: function () {
red.getJSON("/meta/tablelist",{}, function (json) {
vm.tables = json;
});
},
catalogs: function() {
var dbPlats = this.dbPlats;
for (i in dbPlats) {
if (dbPlats[i].key == this.row.dbPlatId) {
return dbPlats[i]["catalogs"]
}
}
},
setMove: function () {
if (this.status == 1) {
$('#sortableList,table>tbody').sortable({
selector: '.list-group-item, tr',
finish: function (e) {
var rows = e.list;
vm.itemSort = [];
for (var i = 0; i < rows.length; i++) {
var item = $(rows[i]).find("input[name='name']").val();
vm.itemSort.push(item);
}
},
// 设置更多选项...
});
}
else if (this.status == 5) {
$('#show>table>tbody').sortable({
selector: 'tr',
finish: function (e) {
var rows = e.list;
var shows = [];
for (var i = 0; i < rows.length; i++) {
var item = $(rows[i]).find("input[name='name']").val();
shows.push(item);
}
vm.meta.shows = shows;
}
});
} else if (this.status == 4) {
$('#import>table>tbody').sortable({
selector: 'tr',
finish: function (e) {
var rows = e.list;
var shows = [];
for (var i = 0; i < rows.length; i++) {
var item = $(rows[i]).find("input[name='name']").val();
shows.push(item);
}
vm.meta.imports = shows;
}
});
} else if (this.status == 3) {
$('#export>table>tbody').sortable({
selector: 'tr',
finish: function (e) {
var rows = e.list;
var shows = [];
for (var i = 0; i < rows.length; i++) {
var item = $(rows[i]).find("input[name='name']").val();
shows.push(item);
}
vm.meta.exports = shows;
}
});
}
else if (this.status == 6) {
$('#filter>table>tbody').sortable({
selector: 'tr',
finish: function (e) {
var rows = e.list;
var filterArr = [];
for (var i = 0; i < rows.length; i++) {
var item = $(rows[i]).find("input[name='name']").val();
filterArr.push(item);
}
vm.filterArr = filterArr;
}
});
}
else {
$('table>tbody').sortable('destroy');
}
},
/**
* 保存元数据变更:
* 1、基础数据排序
* --> 传递元素的顺序,后台对元素顺序重排
* 2、基础数据属性修改
* --> 只提交被修改过的元素及属性数据,后端通过属性名称对应修改,
* 3、导出
* 导出排序
* --> 传递元素的顺序,后台对元素的顺利重排,(同基础元素排序)
* 导出元素加减
* --> 将元素完整传递到后台,进行覆盖保存
* 4、导入
* 导入排序
* 导入元素加减
* 5、
*
* 7、数据平台
* 记录元数据,存贮的数据平台
*
*/
save: function () {
if (vm.status == 1 && vm.itemSort.length > 0) {
red.post("/meta/itemsort", {
serviceKey: vm.table,
items: JSON.stringify(vm.itemSort)
});
}
else if (vm.status == 2 && vm.itemEdit.length > 0) {
red.post("/meta/itemupdate", {
serviceKey: vm.table,
items: JSON.stringify(vm.itemEdit)
});
}
else if (vm.status == 3 || vm.status == 4 || vm.status == 5) {
var urls = {3: "/meta/exportsort", 4: "/meta/importsort", 5: "/meta/showsort"};
var items = {3: vm.meta.exports, 4: vm.meta.imports, 5: vm.meta.shows};
red.post(urls[vm.status], {
serviceKey: vm.table,
items: JSON.stringify(items[vm.status])
});
}
else if (vm.status == 5) {
red.post("/meta/showsort", {
serviceKey: vm.table,
items: JSON.stringify(vm.meta.shows)
});
}
else if (vm.status == 6) {
console.log(vm.filters);
red.post("/meta/filter_update", {
serviceKey: vm.table,
filters: JSON.stringify(vm.filters)
});
}
else if (vm.status == 7) {
console.log(vm.row);
red.post("/meta/dbplatupdate", vm.row)
}
else {
red.showMsg();
}
},
getFieldLabel: function (col) {
if (!col) {
return "";
}
for (var i = 0; i < vm.oldItems.length; i++) {
if (vm.oldItems[i].name == col) {
return vm.oldItems[i].label;
}
}
}
},
mounted: function (){
//dbPlats 列表初始化
red.dbPlats(function (json) {
vm.dbPlats = json;
});
this.tableList();
/*$(window).keydown(function (event) {
// 监听 Ctrl + Enter 可全屏查看
if (event.ctrlKey && event.keyCode == 13) {
vm.save();
}
});*/
}
});
</script>
<!--
<row class="">
</row>
<script>
var vm = new Vue({
el: ".meta-service",
data: {
},
watch: {
},
methods: {
},
mounted: function () {
var m = {"a.name": "lxyer", "a.`age`": 11}
console.log(m["a.name"])
console.log("-&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;")
for (var k in m) {
console.log(k)
}
}
});
</script>-->

View File

@@ -0,0 +1,110 @@
<style>
.table td, .table th {
padding: 4px;
}
</style>
<row class="metatable-list">
<div class="col-md-12">
<h3 v-text="cfg.title"></h3>
</div>
<div class="col-md-12">
<div class="input-group list-head pull-left">
<span class="input-group-btn">
<button class="btn btn-default" type="button">数据平台</button>
</span>
<select class="form-control" v-model="filter.dbPlatId" style="width: 150px;">
<option></option>
<option v-for="item in dbPlats" :value="item.key">{{item.name}}</option>
</select>
<span class="input-group-btn">
<button class="btn btn-default" type="button">Catalog</button>
</span>
<select class="form-control" v-model="filter.catalog" style="width: 150px;">
<option></option>
<option v-for="item in catalogs()" :value="item" v-text="item"></option>
</select>
<span class="input-group-btn">
<button class="btn btn-default" type="button">表名称</button>
</span>
<input class="form-control" v-model="filter.name" style="width: 100px">
</div>
</div>
<div class="col-md-12" style="padding-top: 10px;overflow:auto;">
<table class="table table-bordered table-hover" style="width: 100%">
<thead>
<tr>
<th v-for="field in cfg.cols" v-text="field.label"></th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="row in list.rows">
<td v-for="field in cfg.cols" v-title="row[field.col]" v-text="row[field.col]"></td>
<td>
</td>
</tr>
</tbody>
</table>
</div>
</row>
<script>
var vm = new Vue({
el: ".metatable-list",
data: {
cfg: {
title: "MetaTable 列表",
cols: [
{col: "name", label: "表名称"},
{col: "comment", label: "注释"},
{col: "dbPlatName", label: "所属数据库"},
{col: "catalog", label: "所属Database"},
{col: "dataCount", label: "数据量"}
],
filters: [],
cates: ["find","update"]
},
dbPlats:[],
list:{rows:[{name:"user", comment:"[用户表]", dataCount: 23}]},
filter: {dbPlatId: "", catalog: "", name: ""},
},
watch: {
filter: {
handler(n, o) {
vm.tableList();
},
immediate: true,
deep: true
}
},
methods: {
catalogs: function () {
var dbPlats = this.dbPlats;
for (i in dbPlats) {
if (dbPlats[i].key == this.filter.dbPlatId) {
return dbPlats[i]["catalogs"]
}
}
},
tableList: function () {
var para = red.putAll({}, vm.filter);
red.getJSON("/meta/tablelist", para, function (json) {
vm.list = {rows: json};
});
},
},
mounted: function () {
//dbPlats 列表初始化
red.dbPlats(function (json) {
vm.dbPlats = json;
});
this.tableList();
}
});
</script>

View File

@@ -0,0 +1,573 @@
<row class="meta-list">
<div class="col-md-12" style="padding-top: 10px;">
<div class="input-group list-head">
<span class="input-group-btn">
<button class="btn btn-default" type="button">选择Table</button>
</span>
<select class="form-control" v-model="table" style="width: 180px;">
<option v-for="item in tables" :value="item.name"> {{item.name}}&nbsp;&nbsp;&nbsp;[{{item.comment}}]</option>
</select>
<span class="input-group-btn">
<button @click="status=2" :class="['btn',{'btn-primary':status==2}]" type="button"> 字段编辑</button>
</span>
<span class="input-group-btn">
<button @click="status=1" :class="['btn',{'btn-primary':status==1}]" type="button"> 排序</button>
</span>
<!--<span class="input-group-btn" style="padding-left: 20px">
<button @click="status=5" :class="['btn',{'btn-primary':status==5}]" type="button"> 列表配置</button>
</span>
<span class="input-group-btn">
<button @click="status=6" :class="['btn',{'btn-primary':status==6}]" type="button"> 查询配置</button>
</span>
<span class="input-group-btn" style="padding-left: 20px">
<button @click="status=3" :class="['btn',{'btn-primary':status==3}]" type="button"> 导出配置</button>
</span>
<span class="input-group-btn">
<button @click="status=4" :class="['btn',{'btn-primary':status==4}]" type="button"> 导入配置</button>
</span>-->
<span class="input-group-btn" style="padding-left: 20px">
<button @click="status=7;" :class="['btn',{'btn-primary':status==7}]" type="button"> 基本属性</button>
</span>
<!-- fixme: 加入数据平台相关操作, 1、关联数据平台2、表结构入库 -->
<span class="input-group-btn" style="padding-left: 30px">
<button @click="save()" :class="['btn',{'btn-primary':status!=0},{'disabled':status==0}]" type="button"> 保存</button>
</span>
</div>
</div>
<div class="col-md-7">
<table class="table-bordered" style="width: 100%">
<thead>
<tr style="background-color: #f1f1f1">
<td v-show="status==3 || status==4 || status==5 || status==6"><input type="checkbox"></td>
<th v-show="status==1"></th>
<th>字段名</th>
<th>中文名</th>
<th>数据类型</th>
<th>输入类型</th>
<th>附加属性</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.items">
<td v-show="status==3"><input type="checkbox" v-model="meta.exports" :value="item.name" class="form-control"></td>
<td v-show="status==4"><input type="checkbox" v-model="meta.imports" :value="item.name" class="form-control"></td>
<td v-show="status==5"><input type="checkbox" v-model="meta.shows" :value="item.name" class="form-control"></td>
<td v-show="status==6"><input type="checkbox" v-model="filterArr" :value="item.name" class="form-control"></td>
<td v-show="status==1" class="icon icon-move"></td>
<td v-show="status!=2" v-text="item.name" style="background-color: rgb(235, 235, 228);"></td>
<td v-show="status!=2" v-text="item.label"></td>
<td v-show="status!=2" v-text="item.type"></td>
<td v-show="status!=2" v-text="item.inType"></td>
<td v-show="status!=2" v-text="item.inExt"></td>
<td v-show="status!=2" v-text="item.remark"></td>
<td v-show="status==2">
<input v-model="item" type="hidden">
<input :value="item.name" disabled class="form-control">
<input v-model="item.name" type="hidden">
<input name="name" type="hidden" :value="item.name">
</td>
<td v-show="status==2"><input v-model="item.label" class="form-control"></td>
<td v-show="status==2"><input v-model="item.type" class="form-control"></td>
<td v-show="status==2"><!--<input v-model="item.inType">-->
<select v-model="item.inType" class="form-control" style="width: 130px">
<option></option>
<option v-for="x in inTypes" :value="x">{{x}}</option>
</select>
</td>
<td v-show="status==2"><input v-model="item.inExt" class="form-control"></td>
<td v-show="status==2"><input v-model="item.remark" class="form-control"></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-5" v-show="false">
<table class="table-bordered table-auto">
<thead>
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<th>展示名</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.items">
<td v-show="status!=2" class="icon icon-move"></td>
<td v-show="status!=2" v-text="item.name" style="background-color: rgb(235, 235, 228);"></td>
<td v-show="status!=2" v-text="item.label"></td>
<td v-show="status!=2"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-5" v-show="status==5">
<div class="panel">
<div class="panel-heading">列表展示的属性</div>
<div id="show" class="panel-body">
<table class="table-bordered table-auto" style="width: 100%">
<thead>
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<!--<th>支持排序</th>-->
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.shows">
<td class="icon icon-move">
<input name="name" :value="item" type="hidden">
</td>
<td v-text="item" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item)}}</td>
<td v-show="false"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- exports -->
<div class="col-md-5" v-show="status==3">
<div class="panel">
<div class="panel-heading">导出的属性配置</div>
<div id="export" class="panel-body">
<table class="table-bordered table-auto" style="width: 100%">
<thead>
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<!--<th>展示名</th>-->
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.exports">
<td class="icon icon-move">
<input name="name" :value="item" type="hidden">
</td>
<td v-text="item" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item)}}</td>
<td v-show="false"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- imports -->
<div class="col-md-5" v-show="status==4">
<div class="panel">
<div class="panel-heading">
导入的属性配置
</div>
<div id="import" class="panel-body" style="/*padding-top: 10px;*/overflow:auto;">
<table class="table-bordered table-auto" style="width: 100%;height: 100%">
<thead>
<tr style="background-color: #f1f1f1">
<th></th>
<th>字段名</th>
<th>中文名</th>
<!--<th>展示名</th>-->
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in meta.imports">
<td class="icon icon-move">
<input name="name" :value="item" type="hidden">
</td>
<td v-text="item" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item)}}</td>
<td v-show="false"><input v-model="item.label" style="width: 100px;"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- filters -->
<div class="col-md-5" v-show="status==6">
<div class="panel">
<div class="panel-heading">查询配置</div>
<div id="filter" class="panel-body" style="overflow:auto;">
<table class="table-bordered table-auto" style="width: 100%">
<thead>
<tr style="background-color: #f1f1f1">
<th></th>
<th style="width: 30px">字段名</th>
<th style="width: 30px">中文名</th>
<th style="width: 30px">默认展示</th>
<th>支持查询类型</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in filters">
<td class="icon icon-move">
<input name="name" :value="item.name" type="hidden">
</td>
<td v-text="item.name" style="background-color: rgb(235, 235, 228);"></td>
<td v-text="">{{getFieldLabel(item.name)}}</td>
<td>
<label>
<input type="checkbox" v-model="item.checked" value="1"> 展示
</label>
</td>
<td>
<label class="checkbox-inline" v-for="c in filterCate">
<input type="checkbox" v-model="item.filterType" :value="c"> {{c}}
</label>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- dbPlat -->
<div class="col-lg-5" v-show="status==7">
<div class="panel">
<div class="panel-heading">数据平台配置</div>
<div class="panel-body" style="overflow:auto;">
<form class="form-horizontal">
<input type="hidden" v-model="row.key">
<div class="form-group">
<label for="name" class="col-md-2">Table名称</label>
<div class="col-md-6 col-sm-10">
<input v-model="row.name" class="form-control" id="name" placeholder="请输入Table名称">
</div>
</div>
<div class="form-group">
<label for="comment" class="col-md-2">Table标题</label>
<div class="col-md-6 col-sm-10">
<input v-model="row.comment" class="form-control" id="comment" placeholder="请输入 Table标题">
</div>
</div>
<div class="form-group">
<label class="col-md-2">数据平台</label>
<div class="col-md-6">
<select v-model="row.dbPlatId" class="form-control">
<option></option>
<option v-for="item in dbPlats" :value="item.key" v-text="item.name"></option>
</select>
</div>
<div class="col-md-4">
<select v-model="row.catalog" class="form-control">
<option></option>
<option v-for="item in catalogs()" :value="item" v-text="item"></option>
</select>
</div>
</div>
</form>
</div>
</div>
</div>
</row>
<script src="res/zui/lib/sortable/zui.sortable.js"></script>
<script>
var vm = new Vue({
el: ".meta-list",
data: {
inTypes: ["INPUT", "SELECT_EXT", "INPUT_DT"],
dataTypes: ["bigint(20)", "varchar(255)", "varchar(64)", "varchar(32)", "varchar(16)", "int(11)", "int(3)", "int(2)", "datetime"],
filterCate: ["EQUAL", "NOTEQUAL", "LIKE", "IN"],
tables: [],//所有的业务类型,【测试用】
meta: {
items: [],
shows: [],
exports: [],
imports: [],
filters: [{name:"", filterType:[""]}]
},//完整的元数据数据,
move: false,
status: 0, //页面默认状态
table: "", //页面选择的业务类型
itemSort: [], //待保存的业务属性
oldItems: [], //不被修改的字段属性
itemEdit: {}, //待修改的字段属性
dbPlats:[],
row: {key: "", platId: "", dbPlatId:"", catalog: "", name:"", comment:""},
filter: {db: "", catalog: "", name: ""},//tableList 过滤条件
filters:[],//查询配置
filterArr:[]
},
watch: {
status: function (v) {
this.setMove(v)
},
table: function (table) {
this.loadDetail(table);
},
"meta.items": {
handler: function (nv, ov) {
var itemNv = nv || [];
var itemOv = vm.oldItems || [];
if (itemOv.length == 0) return;
var itemEdit = [];
a:for (var i = 0; i < itemOv.length; i++) {
var attr = ["label", "name", "remark", "type", "inType","inExt"];
for (var j = 0; j < attr.length; j++) {
var k = attr[j];
if (itemOv[i][k] != itemNv[i][k]) {
itemEdit.push(itemNv[i]);
continue a;
}
}
}
vm.itemEdit = itemEdit;
},
deep: true
},
"meta.shows": function (v) {
//console.log(v.length)
},
tables: function (v) {
if(v.length > 0) {
vm.table = v[0]["name"];
}
},
meta: function (v) {
vm.row = {key:v.key, dbPlatId: v.dbPlatId, catalog: v.catalog, name:v.name, comment:v.comment};
/*vm.filters = v.filters;
var filterArr = [];
vm.filters.forEach(function (item) {
filterArr.push(item.name);
})
vm.filterArr = filterArr;*/
},
},
methods: {
loadDetail: function (cate) {
//this.status = 0;
red.getJSON("/meta/tableinfo",{name: cate}, function (json) {
var row = json;
vm.meta = row;
var oldItems = [];
row.items.forEach(function (item) {
var d = {};
["label", "name", "remark", "type", "inType"].forEach(function (k) {
d[k] = item[k];
});
oldItems.push(d);
});
vm.oldItems = oldItems;
});
},
tableList: function () {
red.getJSON("/meta/tablelist",{}, function (json) {
vm.tables = json;
});
},
catalogs: function() {
var dbPlats = this.dbPlats;
for (i in dbPlats) {
if (dbPlats[i].key == this.row.dbPlatId) {
return dbPlats[i]["catalogs"]
}
}
},
setMove: function () {
if (this.status == 1) {
$('#sortableList,table>tbody').sortable({
selector: '.list-group-item, tr',
finish: function (e) {
var rows = e.list;
vm.itemSort = [];
for (var i = 0; i < rows.length; i++) {
var item = $(rows[i]).find("input[name='name']").val();
vm.itemSort.push(item);
}
},
// 设置更多选项...
});
}
else if (this.status == 5) {
$('#show>table>tbody').sortable({
selector: 'tr',
finish: function (e) {
var rows = e.list;
var shows = [];
for (var i = 0; i < rows.length; i++) {
var item = $(rows[i]).find("input[name='name']").val();
shows.push(item);
}
vm.meta.shows = shows;
}
});
} else if (this.status == 4) {
$('#import>table>tbody').sortable({
selector: 'tr',
finish: function (e) {
var rows = e.list;
var shows = [];
for (var i = 0; i < rows.length; i++) {
var item = $(rows[i]).find("input[name='name']").val();
shows.push(item);
}
vm.meta.imports = shows;
}
});
} else if (this.status == 3) {
$('#export>table>tbody').sortable({
selector: 'tr',
finish: function (e) {
var rows = e.list;
var shows = [];
for (var i = 0; i < rows.length; i++) {
var item = $(rows[i]).find("input[name='name']").val();
shows.push(item);
}
vm.meta.exports = shows;
}
});
}
else if (this.status == 6) {
$('#filter>table>tbody').sortable({
selector: 'tr',
finish: function (e) {
var rows = e.list;
var filterArr = [];
for (var i = 0; i < rows.length; i++) {
var item = $(rows[i]).find("input[name='name']").val();
filterArr.push(item);
}
vm.filterArr = filterArr;
}
});
}
else {
$('table>tbody').sortable('destroy');
}
},
/**
* 保存元数据变更:
* 1、基础数据排序
* --> 传递元素的顺序,后台对元素顺序重排
* 2、基础数据属性修改
* --> 只提交被修改过的元素及属性数据,后端通过属性名称对应修改,
* 3、导出
* 导出排序
* --> 传递元素的顺序,后台对元素的顺利重排,(同基础元素排序)
* 导出元素加减
* --> 将元素完整传递到后台,进行覆盖保存
* 4、导入
* 导入排序
* 导入元素加减
* 5、
*
* 7、数据平台
* 记录元数据,存贮的数据平台
*
*/
save: function () {
if (vm.status == 1 && vm.itemSort.length > 0) {
red.post("/meta/itemsort", {
serviceKey: vm.table,
items: JSON.stringify(vm.itemSort)
});
}
else if (vm.status == 2 && vm.itemEdit.length > 0) {
red.post("/meta/itemupdate", {
serviceKey: vm.table,
items: JSON.stringify(vm.itemEdit)
});
}
else if (vm.status == 3 || vm.status == 4 || vm.status == 5) {
var urls = {3: "/meta/exportsort", 4: "/meta/importsort", 5: "/meta/showsort"};
var items = {3: vm.meta.exports, 4: vm.meta.imports, 5: vm.meta.shows};
red.post(urls[vm.status], {
serviceKey: vm.table,
items: JSON.stringify(items[vm.status])
});
}
else if (vm.status == 5) {
red.post("/meta/showsort", {
serviceKey: vm.table,
items: JSON.stringify(vm.meta.shows)
});
}
else if (vm.status == 6) {
console.log(vm.filters);
red.post("/meta/filter_update", {
serviceKey: vm.table,
filters: JSON.stringify(vm.filters)
});
}
else if (vm.status == 7) {
console.log(vm.row);
red.post("/meta/dbplatupdate", {metaTable: JSON.stringify(vm.row)})
}
else {
red.showMsg();
}
},
getFieldLabel: function (col) {
if (!col) {
return "";
}
for (var i = 0; i < vm.oldItems.length; i++) {
if (vm.oldItems[i].name == col) {
return vm.oldItems[i].label;
}
}
}
},
mounted: function (){
//dbPlats 列表初始化
red.dbPlats(function (json) {
vm.dbPlats = json;
});
this.tableList();
/*$(window).keydown(function (event) {
// 监听 Ctrl + Enter 可全屏查看
if (event.ctrlKey && event.keyCode == 13) {
vm.save();
}
});*/
}
});
</script>
<!--
todo:
MetaData
1、Excel导入
2、操作数据库表
3、关联数据库表
-->

229
root/plat/db.html Normal file
View File

@@ -0,0 +1,229 @@
<row class="plat">
<!-- head -->
<div class="col-md-11">
<h3 v-text="cfg.title"></h3>
</div>
<div class="col-md-1">
<div class="input-group pull-right" style="padding-top: 10px">
<span class="input-group-btn">
<button @click="edit({})" class="btn btn-primary" type="button"> 新增数据平台 </button>
</span>
</div>
</div>
<div class="col-md-12">
<table class="table table-bordered table-hover" style="width: 100%">
<thead>
<tr>
<th v-for="field in cfg.cols" v-text="field.label"></th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="item in list.rows">
<td v-for="field in cfg.cols"
:title="field.title ? field.title(item[field.col]) : ''"
v-html="field.fmt ? field.fmt(item[field.col]) : item[field.col]">
</td>
<td>
<a @click="edit(item)" href="javascript:;">编辑</a> |
<a @click="update({status:1}, item)" v-show="item.status != 1" href="javascript:;">启用</a>
<a @click="update({status:0}, item)" v-show="item.status == 1" href="javascript:;">不启用</a> |
<a @click="update({status:-1}, item)" href="javascript:;">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
<!-- edit.modal -->
<div class="modal fade" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">关闭</span></button>
<h4 class="modal-title">数据中心 - [编辑]</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group">
<label for="queryId" class="col-sm-2">平台名称</label>
<div class="col-md-6 col-sm-10">
<input v-model="row.name" class="form-control" id="queryId" placeholder="请输入 平台名称">
</div>
</div>
<div class="form-group">
<label for="url" class="col-sm-2">连接URL</label>
<div class="col-md-6">
<input v-model="row.url" class="form-control" id="url" placeholder="请输入 连接URL">
</div>
</div>
<div class="form-group">
<label for="user" class="col-sm-2">连接账号</label>
<div class="col-md-2">
<input v-model="row.user" class="form-control" id="user" placeholder="用户">
</div>
<div class="col-md-2">
<input v-model="row.pwd" class="form-control" id="pwd" placeholder="连接密码">
</div>
<div class="col-md-2">
<a @click="loadCatalogs" class="btn" href="javascript:;">获取catalogs</a>
</div>
</div>
<div class="form-group">
<label class="col-sm-2">Catalogs</label>
<div class="col-md-6">
<label v-for="item in catalogs" class="checkbox-inline">
<input type="checkbox" v-model="row.catalogs" :value="item"> <span v-text="item"></span>
</label>
</div>
</div>
<div class="form-group">
<label for="remark" class="col-sm-2">备注</label>
<div class="col-md-6 col-sm-10">
<input v-model="row.remark" class="form-control" id="remark" placeholder="请输入 备注">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button @click="save(row)" type="button" class="btn btn-primary">确定</button>
</div>
</div>
</div>
</div>
</row>
<script>
var vm = new Vue({
el: ".plat",
data: {
cfg: {
title: "数据中心 管理",
cols: [
{col: "_id", label: "ID"},
{col: "name", label: "数据平台名称"},
{col: "url", label: "数据平台连接地址"},
{col: "user", label: "用户"},
{col: "remark", label: "备注"},
{col: "pulse", label: "状态", fmt: function (v) {
if (!v) return "";
if (v.status == 0) {
return '<span class="label label-success">连接正常</span>';
}
if (v.status == -1) {
return '<span class="label label-danger">连接失败';
}
},title: function (v) {
if (!v) return "";
if (v.status == 0 && v.time) {
return "最后检测时间:" + red.timeFmt(new Date(v.time), "HH:mm:ss");
}
if (v.status == -1 && v.time) {
return "最后检测时间:" + red.timeFmt(new Date(v.time), "HH:mm:ss");
}
return "";
}},
{col: "status", label: "是否启用", fmt: function (v) {
return {"0":"未启用", "1":"启用", "-1":"删除"}[v] || "";
}},
],
filters: []
},
list: {rows:[], total: 0},
row: {},
catalogs: ["a", "b", "c"]
},
watch: {
},
methods: {
findList: function () {
var para = {
doc:"db_plat",
shows: JSON.stringify(["_id", "name", "url", "user", "pwd", "catalogs", "remark", "status"])
};
red.getJSON("/meta/find", para, function (json) {
for (var i=0; i<json.rows.length; i++) {
json.rows[i]["pulse"] = "";
}
vm.list = json;
})
},
update: function (kv, row) {
red.post("/meta/save", {
_id: row._id,
doc: JSON.stringify(kv)
}, function (json) {
red.showMsg();
red.putAll(row, kv);
vm.findList();
});
},
edit: function (row) {
row["catalogs"] = row["catalogs"] || [];
vm.row = row;
this.loadCatalogs();
$('#myModal').modal({moveable: true});
},
save: function (row) {
red.post("/meta/save", {
_id: row._id || "db_plat",
doc: JSON.stringify(row)
}, function (json) {
red.showMsg();
$('#myModal').modal('hide');
vm.findList();
});
},
loadCatalogs: function () {
vm.catalogs = [];
red.post("/_db/catalogs", {
url: this.row.url,
user: this.row.user,
pwd: this.row.pwd
}, function (json) {
vm.catalogs = json;
});
},
dbPulse: function (row) {
row["check"] = true;
$.getJSON("/_db/pulse", {
dbPlatId: row._id
}, function (json) {
row["pulse"] = json.body;
row["check"] = false;
});
}
},
mounted: function () {
this.findList();
function pulse() {
vm.list.rows.forEach(function (row) {
if (row.status == 1 && !row["check"]) {
vm.dbPulse(row);
}
});
}
//心跳检查
setTimeout(function () {
pulse();
}, 500);
setInterval(function () {
pulse();
}, 30000)
}
});
</script>

5
root/plat/dev.html Normal file
View File

@@ -0,0 +1,5 @@
<row class="dev">
<div style="width: 13%;height: 80px;background-color: #fff;">
sdaf
</div>
</row>

144
root/plat/index.html Normal file
View File

@@ -0,0 +1,144 @@
<row class="plat">
<!-- head -->
<div class="col-md-11">
<h3 v-text="cfg.title"></h3>
</div>
<div class="col-md-1">
<div class="input-group pull-right" style="padding-top: 10px">
<span class="input-group-btn">
<button @click="edit({})" class="btn btn-primary" type="button"> 新增业务平台 </button>
</span>
</div>
</div>
<div class="col-md-12">
<table class="table table-bordered table-hover" style="width: 100%">
<thead>
<tr>
<th v-for="field in cfg.cols" v-text="field.label"></th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="item in list.rows">
<td v-for="field in cfg.cols" v-title="item[field.col]" v-text="field.fmt ? field.fmt(item[field.col]) : item[field.col]"></td>
<td>
<a @click="edit(item)" href="javascript:;">编辑</a> |
<a @click="update({status:1}, item)" v-show="item.status != 1" href="javascript:;">启用</a>
<a @click="update({status:0}, item)" v-show="item.status == 1" href="javascript:;">不启用</a> |
<a @click="update({status:-1}, item)" href="javascript:;">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
<!-- edit.modal -->
<div class="modal fade" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">关闭</span></button>
<h4 class="modal-title">业务平台 - [编辑]</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group">
<label for="queryId" class="col-md-2">平台名称</label>
<div class="col-md-8">
<input v-model="row.name" class="form-control" id="queryId" placeholder="请输入 平台名称">
</div>
</div>
<div class="form-group">
<label for="token" class="col-md-2">平台 Token</label>
<div class="col-md-8 col-sm-10">
<input v-model="row.token" class="form-control" id="token" placeholder="请输入 Token">
</div>
</div>
<div class="form-group">
<label for="remark" class="col-md-2">备注</label>
<div class="col-md-8 col-sm-10">
<input v-model="row.remark" class="form-control" id="remark" placeholder="请输入 备注">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button @click="save(row)" type="button" class="btn btn-primary">确定</button>
</div>
</div>
</div>
</div>
</row>
<script>
var vm = new Vue({
el: ".plat",
data: {
cfg: {
title: "业务平台 管理",
cols: [
{col: "_id", label: "ID"},
{col: "name", label: "业务名称"},
{col: "token", label: "Token"},
{col: "remark", label: "说明"},
{col: "status", label: "状态", fmt: function (v) {
return {"0":"未启用", "1":"启用", "-1":"删除"}[v] || "";
}},
],
filters: []
},
list: {rows:[], total: 0},
row: {}
},
watch: {
},
methods: {
findList: function () {
var para = {
doc:"sys_plat",
shows: JSON.stringify(["_id", "_key", "name", "token","remark", "status"]),
filter: JSON.stringify([{col:"status",type:"!=",value:-1}]),
};
red.getJSON("/meta/find", para, function (json) {
vm.list = json;
red.setData("sysPlats", json.rows);
})
},
update: function (kv, row) {
red.post("/meta/save", {
_id: row._id,
doc: JSON.stringify(kv)
}, function (json) {
red.showMsg();
red.putAll(row, kv);
vm.findList();
});
},
edit: function (row) {
vm.row = row;
console.log(this.row);
$('#myModal').modal({moveable: true});
},
save: function (row) {
red.post("/meta/save", {
_id: row._id || "sys_plat",
doc: JSON.stringify(row)
}, function (json) {
red.showMsg();
$('#myModal').modal('hide');
vm.findList();
});
}
},
mounted: function () {
this.findList();
}
});
</script>

24
root/qtask/abc.html Normal file
View File

@@ -0,0 +1,24 @@
<div id="abc">
{{cfg.title}}
<button @click="abc">asf</button>
<button @click="abc">openDia</button>
</div>
<script>
var vm = new Vue({
el: "#abc",
data: {
cfg: {
title: "12"
}
},
methods: {
abc: function () {
console.log("abc");
}
}
});
</script>

143
root/qtask/ddl.html Normal file
View File

@@ -0,0 +1,143 @@
<row class="ddl">
<div class="col-md-6">
<h3>导出数据库表结构(导出后使用wps打开)</h3>
<form>
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button">jdbc.url</button>
</span>
<input id="url" type="text" class="form-control" placeholder="jdbc:mysql://127.0.0.1:3306" v-model="jdbc.url">
</div>
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button">jdbc.user</button>
</span>
<input id="user" type="text" class="form-control" placeholder="请输入数据库用户" v-model="jdbc.user">
</div>
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button">jdbc.pwd</button>
</span>
<input id="pwd" type="text" class="form-control" placeholder="请输入数据库密码" v-model="jdbc.pwd">
</div>
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button">Database</button>
</span>
<input id="database" type="text" class="form-control" placeholder="请输入Database" v-model="jdbc.database">
</div>
<div class="input-group">
<div class="radio">
<label>
<input type="radio" v-model="cate" value="word" checked> 导出表结构到word
</label>
</div>
<div class="radio">
<label>
<input type="radio" v-model="cate" value="excel"> 导出表结构到excel
</label>
</div>
</div>
<button id="export" data-toggle="button" class="btn btn-primary" data-cate="word" type="button">导出表结构</button>
</form>
</div>
<div class="col-md-6" v-show="logs.total">
<h3>最近使用记录 <small>共 {{logs.total}} 条记录</small></h3>
<table class="table-bordered" style="width: 100%">
<thead>
<tr>
<th>IP</th>
<th>最后时间</th>
<th>最后导出数据类型</th>
<th>导出总次数</th>
</tr>
</thead>
<tbody>
<tr v-for="row in logs.rows">
<td v-text="row.remoteAddr"></td>
<td v-text="timeFmt(new Date(row.time*1), 'yyyy-MM-dd HH:mm:ss')"></td>
<td v-text="row.cate"></td>
<td v-text="row.total"></td>
</tr>
<tr style="background-color: #eee">
<td>合计总人数</td>
<td>{{logs.userTotal}}</td>
<td>合计总次数</td>
<td>{{logs.total}}</td>
</tr>
</tbody>
</table>
</div>
</row>
<script>
function getData(key, defaultValue) {
var v = localStorage.getItem(key) || defaultValue || "";
if (typeof(v) == "string" && v.startsWith("{") && v.endsWith("}")) {
v = JSON.parse(v);
} else if (typeof(v) == "string" && v.startsWith("[") && v.endsWith("]")) {
v = JSON.parse(v);
}
return v;
}
var vm = new Vue({
el:".ddl",
data:{
jdbc:getData("jdbc", {url: "jdbc:mysql://192.168.202.11:3306/", user: "root"}),
cate: getData("cate", "word"),
logs: {}
},
watch: {
},
methods: {
loadLog: function() {
$.getJSON("/ddl/logrank",function (json) {
vm.logs = json;
});
},
timeFmt: function (date,fmt){
var o = {
"M+" : date.getMonth()+1, //月份
"d+" : date.getDate(), //日
"H+" : date.getHours(), //小时
"m+" : date.getMinutes(), //分
"s+" : date.getSeconds(), //秒
"q+" : Math.floor((date.getMonth()+3)/3), //季度
"S" : date.getMilliseconds() //毫秒
};
if(/(y+)/.test(fmt))
fmt=fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length));
for(var k in o)
if(new RegExp("("+ k +")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
return fmt;
}
},
mounted: function () {
this.loadLog();
}
});
$("#export").click(function () {
localStorage.setItem("jdbc", JSON.stringify(vm.jdbc));
localStorage.setItem("cate", vm.cate);
$.post("/"+ vm.cate +"/build", {account:JSON.stringify(vm.jdbc)}, function (json) {
console.log(json)
if (json.code == 0) {
location.href = "/"+ vm.cate +"/download";
} else {
alert(json.message);
}
});
});
</script>

131
root/qtask/debug.html Normal file
View File

@@ -0,0 +1,131 @@
<row class="qtask-debug">
<div class="col-md-12">
<h3>QTask - [测试用例]</h3>
</div>
<div class="col-md-6">
<div class="input-group">
<span class="input-group-btn">
<a href="javascript:;" class="btn" type="button"> 选择QTask任务</a>
</span>
<select class="form-control" v-model="row">
<option v-for="item in qtasks" :value="item" v-text="item.name"></option>
</select>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2">查询ID</label>
<div class="col-md-6 col-sm-10" v-text="row.queryId" style="padding-top: 5px"></div>
</div>
<div class="form-group">
<label class="col-sm-2">业务名称</label>
<div class="col-md-6 col-sm-10" v-text="row.name" style="padding-top: 5px"></div>
</div>
<div class="form-group">
<label class="col-sm-2">说明</label>
<div class="col-md-6 col-sm-10" v-text="row.remark" style="padding-top: 5px"></div>
</div>
<div class="form-group" style="margin-bottom: 0">
<label for="sql" class="col-md-2">SQL</label>
<div class="col-md-10">
<textarea v-model="row.sql" class="form-control layui-code" rows="10" id="sql" placeholder="请输入 SQL (支持jfinal-enjoy模板语法)" > </textarea>
</div>
</div>
<div class="form-group">
<label for="para" class="col-sm-2">查询参数</label>
<div class="col-md-6 col-sm-10">
<input v-model="row.para" class="form-control" id="para" placeholder="请输入 默认查询参数格式: {k:v}">
</div>
</div>
<div class="form-group">
<label for="para" class="col-sm-2">数据平台</label>
<div class="col-md-6">
<select v-model="row.platId" class="form-control">
<option></option>
<option v-for="item in dbPlats" :value="item.key" v-text="item.name"></option>
</select>
</div>
<div class="col-md-4">
<select v-model="row.catalog" class="form-control">
<option></option>
<option v-for="item in catalogs()" :value="item" v-text="item"></option>
</select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button @click="query(row)" type="button" class="btn btn-primary">RUN</button>
</div>
</div>
<div class="col-md-6">
<h5>查询结果:</h5>
<pre class="layui-code" v-show="result" v-text="result"></pre>
</div>
</row>
<script src="http://www.1216.top/res/layui/layui.js"></script>
<script>
var vm = new Vue({
el: ".qtask-debug",
data: {
qtasks: [],
row: {},
list: {rows:[], total: 0},
dbPlats: [],
result: ""
},
watch: {
qtask: function () {
console.log(this.qtask)
},
"row.key": function () {
//vm.query();
}
},
methods: {
catalogs: function () {
var dbPlats = this.dbPlats;
for (i in dbPlats) {
if (dbPlats[i].key == this.row.platId) {
return dbPlats[i]["catalogs"]
}
}
},
query: function () {
vm.result = "";
red.post("/qtask/test", {qtask: JSON.stringify(vm.row)}, function (json) {
vm.result = json;
red.showMsg({msg: "查询成功"});
});
}
},
mounted: function () {
//qtask 列表初始化
var para = {
pn:1,
ps:120,
doc:"qtask",
clazz:"net.tccn.common.qtask.Qtask",
filter: JSON.stringify([{col:"status",type:"==",value:1},{col:"sysPlatId",type:"==",value:red.getPlatId()}])
};
red.getJSON("/meta/find", para, function (json) {
vm.qtasks = json.rows;
vm.row = vm.qtasks[0];
});
//dbPlats 列表初始化
red.dbPlats(function (json) {
vm.dbPlats = json;
});
setTimeout(function () {
layui.use('code', function(){ //加载code模块
layui.code({title:"",about: false, height: "500"}); //引用code方法
});
}, 200)
}
});
</script>

237
root/qtask/list.html Normal file
View File

@@ -0,0 +1,237 @@
<row class="qtask-list">
<div class="col-md-12">
<h3 v-text="cfg.title"></h3>
</div>
<div class="col-md-12 ">
<!--<div class="col-md-2" style="padding-left: 0">
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button">选择业务平台</button>
</span>
<select class="form-control">
<option>sdfa</option>
<option>sadf</option>
</select>
</div>
</div>-->
<div class="input-group pull-right">
<button @click="openDia({})" class="btn btn-primary" type="button"> 添加QTask</button>
<!--<button @click="openDia({})" class="btn btn-primary" type="button" style="margin-left: 5px"> 添加QTask</button>-->
</div>
</div>
<div class="col-md-12" style="padding-top: 10px;overflow:auto;">
<table class="table table-bordered table-hover" style="width: 100%">
<thead>
<tr>
<th v-for="field in cfg.cols" v-text="field.label"></th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="row in list.rows">
<td v-for="field in cfg.cols" v-title="row[field.col]" v-text="row[field.col]"></td>
<td v-text="dealStatus(row.status)"></td>
<td>
<a @click="openDia(row)" href="javascript:;">编辑</a>|
<a @click="row['status']=1;qsave(row);" v-show="row.status != 1" href="javascript:;">启用</a>
<a @click="row['status']=0;qsave(row);" v-show="row.status == 1" href="javascript:;">不启用</a> |
<a @click="row['status']=-1;comfirmDel(row);" href="javascript:;">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
<!-- modal-tpl -->
<div class="col-md-12">
<!-- 对话框触发按钮 -->
<!-- 对话框HTML -->
<div class="modal fade" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">关闭</span></button>
<h4 class="modal-title">QTask - [编辑]</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group">
<label for="queryId" class="col-sm-2">查询ID</label>
<div class="col-md-6 col-sm-10">
<input v-model="row.queryId" :readonly="row.key" class="form-control" id="queryId" placeholder="请输入queryId">
</div>
</div>
<div class="form-group">
<label for="name" class="col-sm-2">业务名称</label>
<div class="col-md-6 col-sm-10">
<input v-model="row.name" class="form-control" id="name" placeholder="请输入 业务名称">
</div>
</div>
<div class="form-group">
<label for="para" class="col-sm-2">任务类型</label>
<div class="col-md-6">
<select v-model="row.cate" class="form-control">
<option v-for="item in cfg.cates" :value="item" v-text="item"></option>
</select>
</div>
</div>
<div class="form-group">
<label for="name" class="col-sm-2">说明</label>
<div class="col-md-6 col-sm-10">
<input v-model="row.remark" class="form-control" id="remark" placeholder="请输入 说明">
</div>
</div>
<div class="form-group" style="margin-bottom: 0">
<label for="sql" class="col-md-2">SQL</label>
<div class="col-md-10">
<textarea v-model="row.sql" class="form-control layui-code" rows="10" id="sql" placeholder="请输入 SQL (支持jfinal-enjoy模板语法)" > </textarea>
</div>
</div>
<div class="form-group">
<label for="para" class="col-sm-2">默认查询参数</label>
<div class="col-sm-10">
<input v-model="row.para" class="form-control" id="para" placeholder="请输入 默认查询参数格式: {k:v}">
</div>
</div>
<div class="form-group">
<label for="para" class="col-sm-2">数据平台</label>
<div class="col-md-6">
<select v-model="row.platId" class="form-control">
<option></option>
<option v-for="item in dbPlats" :value="item.key" v-text="item.name"></option>
</select>
</div>
<div class="col-md-4">
<select v-model="row.catalog" class="form-control">
<option></option>
<option v-for="item in catalogs()" :value="item" v-text="item"></option>
</select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button @click="qsave(row)" type="button" class="btn btn-primary">确定</button>
</div>
</div>
</div>
</div>
<!-- 小对话框 -->
<!--<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#mySmModal">小对话框</button>-->
<div class="modal fade" id="mySmModal">
<div class="modal-dialog modal-sm">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">关闭</span></button>
<h4 class="modal-title">确认删除数据吗?</h4>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button @click="qsave(row);$('#mySmModal').modal('hide');" type="button" class="btn btn-primary">确定</button>
</div>
</div>
</div>
</div>
</row>
<script src="http://www.1216.top/res/layui/layui.js"></script>
<script>
var vm = new Vue({
el: ".qtask-list",
data: {
sysPlat: red.getData("sysPlat"),
cfg: {
title: "QTask 管理",
cols: [
{col: "queryId", label: "查询id",},
{col: "name", label: "业务名称",},
{col: "remark", label: "说明"}
],
filters: [],
cates: ["find","update"]
},
list: {rows:[], total: 0},
row: {},
dbPlats: [],
sysPlats: [{name: "工控系统"}]
},
watch: {
},
methods: {
loadList: function () {
var para = {
pn:1,
ps:120,
doc:"qtask",
clazz:"net.tccn.common.qtask.Qtask",
filter: JSON.stringify([{col:"status",type:"!=",value:-1},{col:"sysPlatId",type:"==",value:this.sysPlat._key}])
};
red.getJSON("/meta/find", para, function (json) {
vm.list = json;
});
},
openDia: function (row) {
vm.row = row;
$('#myModal').modal({moveable: true});
if (this.dbPlats.length == 0) {
var para = {
doc:"db_plat",
clazz:"net.tccn.common.qtask.DbPlat",
};
red.getJSON("/meta/find", para, function (json) {
vm.dbPlats = json.rows;
});
}
},
qsave: function (row) {
row = row || vm.row;
if (!row["sysPlatId"]) {//设置平台id
row["sysPlatId"] = red.getPlatId();
}
red.post("/qtask/qsave", {qtask: JSON.stringify(row)}, function (json) {
vm.row = {};
$('#myModal').modal('hide');
vm.loadList();
red.showMsg();
});
},
dealStatus: function (n) {
var arr = {"0":"未启用", "1":"启用", "-1":"删除",}
return arr[n+""] || "";
},
comfirmDel: function (row) {
vm.row = row;
$('#mySmModal').modal({});
},
abc: function () {
$(".container-fixed").load("abc.html");
},
catalogs: function () {
var dbPlats = this.dbPlats;
for (i in dbPlats) {
if (dbPlats[i].key == this.row.platId) {
return dbPlats[i]["catalogs"]
}
}
}
},
mounted: function () {
this.loadList();
setTimeout(function () {
layui.use('code', function(){ //加载code模块
layui.code(/*{skin: 'notepad'}*/); //引用code方法
});
}, 500)
}
});
</script>

137
root/res/css/red-kit.css Normal file
View File

@@ -0,0 +1,137 @@
body {
/*background: url("../img/bg.jpg") no-repeat;*/
}
/*.navbar-inverse {
background-color: #65487a;
border-color: #9361b8;
}
.navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus {
background-color: #996fb8;
}*/
.container-fluid {
padding-left: 0px;
}
#home {
/*background-color: #fff;*/
/*margin: 20px auto;
padding-bottom: 20px;*/
/*min-height: 500px;*/
}
#top {
background-color: #404a53;
padding: 0 10px;
margin: 0px;
height: 45px;
}
#top a {
color: #ddd;
}
#top .nav-tabs{
border-bottom:0;
}
.nav-tabs>li>a{
border: 0;
}
.nav-tabs>li.active>a, .nav-tabs>li.active>a:focus, .nav-tabs>li.active>a:hover, .nav-tabs>li>a:hover {
background-color: #404a53;
color: #fff;
border: 0;
border-bottom: 2px solid #607d8b;
}
#left {
background-color: #404a53; /*padding-bottom: 0px; margin-bottom: 0px;*/
}
#main {
}
#left.col-md-1 {
padding: 0 2px;
width: 10.63333333%;
}
#mainDiv .col-md-11 {
width: 89.36666667%;
/*background-color: #fff;*/
}
#left .nav {
background-color: #404a53;
}
#left .menu > .nav > li > .nav > li > a {
border:0;
border-bottom: 1px solid #495158;
color: #eee;
}
#left .menu > .nav > li > .nav > li>a:hover {
background-color: #404a53;
border:0;
border-bottom: 1px solid #495158;
color: #fff;
}
#left .menu > .nav > li > .nav > li.active > a:hover {
background-color: rgba(255,255,255,.2);/*#607D8B;*/
color: #fff;
}
#left .menu > .nav > li > .nav > li.active a,#left .menu > .nav > li > .nav > li a:hover{
background-color: rgba(255,255,255,.2);/*#607D8B;*/
border-left: 2px solid #77cb99;
color: #fff;
}
.list-head {
padding-bottom: 10px;
}
.meta-list .col-md-5 .panel-body {
padding: 0px;
}
table td,th{
white-space:nowrap;
overflow:hidden;
text-overflow: ellipsis;
max-width: 200px;
}
th{
background-color: #f1f1f1;
}
/*ddl-page*/
.ddl .input-group {
margin-bottom: 10px;
}
/*.data-list 元数据测试用例页面*/
.data-list .table > thead > tr > th.sort:after{
display: inline-block;
margin-left: 5px;
font-family: ZenIcon;
font-size: 14px;
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
color: #808080;
text-transform: none;
content: '\e6bd';
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.data-list .table > thead > tr > th.sort:hover{
cursor:pointer;
}
.data-list .table > thead > tr > th.sort-up:after {
color: #145ccd;
content: '\e6b9';
}
.data-list .table > thead > tr > th.sort-down:after {
color: #145ccd;
content: '\e6b8';
}

File diff suppressed because it is too large Load Diff

1310
root/res/css/zui-theme.css Normal file

File diff suppressed because it is too large Load Diff

BIN
root/res/img/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

141
root/res/js/red.js Normal file
View File

@@ -0,0 +1,141 @@
var red = {
showMsg: function(option) {
var defOption = {msg: "操作成功", type:"info", placement: "bottom-right"};
option = option || defOption;
for (var k in defOption) {
option[k] = option[k] || defOption[k]
}
new $.zui.Messager(option.msg, {
type: option.type // 定义颜色主题
,placement: option.placement
}).show();
},
getData: function(key, defaultValue) {
var v = localStorage.getItem(key) || defaultValue || "";
if (typeof(v) == "string" && v.startsWith("{") && v.endsWith("}")) {
v = JSON.parse(v);
} else if (typeof(v) == "string" && v.startsWith("[") && v.endsWith("]")) {
v = JSON.parse(v);
}
return v;
},
setData: function(key, value) {
var v = value;
if (typeof(v) == "object") {
v = JSON.stringify(value);
}
localStorage.setItem(key, v);
},
getPlatId: function() {
var plat = red.getData("sysPlat") || {};
return plat["_key"];
},
getPlatToken: function() {
var plat = red.getData("sysPlat") || {};
return plat["token"];
},
getJSON: function (url, para, callback) {
para["platToken"] = red.getPlatToken();
$.getJSON(url, para, function (json) {
json = json || {};
red.loginCheck(json);
var data = json;
if (json.code == -1) {
red.showMsg({type:"error", msg: json.message});
return;
}
if (json.code == 0) {
data = json.body;
}
callback(data);
});
},
post: function(url, para, callback) {
para["platToken"] = red.getPlatToken();
$.post(url, para, function (json) {
red.loginCheck(json);
if (json.code == -1) {
red.showMsg({msg: json.message, type: "error"});
return;
}
if (callback) {
callback(json.code == 0 ? json.body : json);
} else {
red.showMsg();
}
});
},
//TODO: 提取统一查询、请求,失败提示
//QTASK find list
qtaskCall: function (para, callback) {
/*$.p$.post("/db/list", {fBean: JSON.stringify(fBean)}, function (json) {
vm.list = json.body;
});*/
$.getJSON("/qtask/call", para, function (json) {
callback(json);
});
},
//db find
dbQuery: function (para, callback) {
$.getJSON("/db/list", para, function (json) {
red.loginCheck(json);
if (json.code == -1) {
console.log("json.code == -1")
}
callback(json);
});
},
dbPlats: function(callBack) {
red.getJSON("/meta/db_plat_list", {}, function (json) {
callBack(json);
});
},
putAll: function(t, s) {
t = t || {};
s = s || {};
for (var k in s) {
t[k] = s[k];
}
return t;
},
timeFmt: function (date,fmt){
fmt = fmt || "yyyy-MM-dd HH:mm:ss";
var o = {
"M+" : date.getMonth()+1, //月份
"d+" : date.getDate(), //日
"H+" : date.getHours(), //小时
"m+" : date.getMinutes(), //分
"s+" : date.getSeconds(), //秒
"q+" : Math.floor((date.getMonth()+3)/3), //季度
"S" : date.getMilliseconds() //毫秒
};
if(/(y+)/.test(fmt))
fmt=fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length));
for(var k in o)
if(new RegExp("("+ k +")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
return fmt;
},
loginCheck: function (json) {
if (json && json["code"] == -2) {
red.showMsg({type:"error", placement: "center", msg: "登陆过期,请前往登陆"});
setTimeout(function () {
location.href = "/user/login.html";
}, 2000);
}
}
}

File diff suppressed because it is too large Load Diff

6
root/res/zui/css/zui-theme.min.css vendored Normal file

File diff suppressed because one or more lines are too long

8714
root/res/zui/css/zui.css Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6
root/res/zui/css/zui.lite.min.css vendored Normal file

File diff suppressed because one or more lines are too long

6
root/res/zui/css/zui.min.css vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Binary file not shown.

6451
root/res/zui/js/zui.js Normal file

File diff suppressed because it is too large Load Diff

3439
root/res/zui/js/zui.lite.js Normal file

File diff suppressed because it is too large Load Diff

15
root/res/zui/js/zui.lite.min.js vendored Normal file

File diff suppressed because one or more lines are too long

16
root/res/zui/js/zui.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,243 @@
/*!
* ZUI: 数组辅助方法 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
/* ========================================================================
* ZUI: array.js
* Array Polyfill.
* http://zui.sexy
* ========================================================================
* Copyright (c) 2014-2016 cnezsoft.com; Licensed MIT
* ======================================================================== */
// Some polyfills copy from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
(function() {
'use strict';
var STR_FUNCTION = 'function';
/**
* Calls a function for each element in the array.
*/
if(!Array.prototype.forEach) {
Array.prototype.forEach = function(fun /*, thisp*/ ) {
var len = this.length;
if(typeof fun != STR_FUNCTION)
throw new TypeError();
var thisp = arguments[1];
for(var i = 0; i < len; i++) {
if(i in this) {
fun.call(thisp, this[i], i, this);
}
}
};
}
/**
* Judge an object is an real array
*/
if(!Array.isArray) {
Array.isArray = function(obj) {
return Object.toString.call(obj) === '[object Array]';
};
}
/**
* Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found.
*/
if(!Array.prototype.lastIndexOf) {
Array.prototype.lastIndexOf = function(elt /*, from*/ ) {
var len = this.length;
var from = Number(arguments[1]);
if(isNaN(from)) {
from = len - 1;
} else {
from = (from < 0) ? Math.ceil(from) : Math.floor(from);
if(from < 0)
from += len;
else if(from >= len)
from = len - 1;
}
for(; from > -1; from--) {
if(from in this &&
this[from] === elt)
return from;
}
return -1;
};
}
/**
* Returns true if every element in this array satisfies the provided testing function.
*/
if(!Array.prototype.every) {
Array.prototype.every = function(fun /*, thisp*/ ) {
var len = this.length;
if(typeof fun != STR_FUNCTION)
throw new TypeError();
var thisp = arguments[1];
for(var i = 0; i < len; i++) {
if(i in this &&
!fun.call(thisp, this[i], i, this))
return false;
}
return true;
};
}
/**
* Creates a new array with all of the elements of this array for which the provided filtering function returns true.
*/
if(!Array.prototype.filter) {
Array.prototype.filter = function(fun /*, thisp*/ ) {
var len = this.length;
if(typeof fun != STR_FUNCTION)
throw new TypeError();
var res = [];
var thisp = arguments[1];
for(var i = 0; i < len; i++) {
if(i in this) {
var val = this[i]; // in case fun mutates this
if(fun.call(thisp, val, i, this))
res.push(val);
}
}
return res;
};
}
/**
* Returns the first (least) index of an element within the array equal to the specified value, or -1 if none is found.
*/
if(!Array.prototype.indexOf) {
Array.prototype.indexOf = function(elt /*, from*/ ) {
var len = this.length;
var from = Number(arguments[1]) || 0;
from = (from < 0) ? Math.ceil(from) : Math.floor(from);
if(from < 0)
from += len;
for(; from < len; from++) {
if(from in this &&
this[from] === elt)
return from;
}
return -1;
};
}
/**
* Creates a new array with the results of calling a provided function on every element in this array.
*/
if(!Array.prototype.map) {
Array.prototype.map = function(fun /*, thisp*/ ) {
var len = this.length;
if(typeof fun != STR_FUNCTION)
throw new TypeError();
var res = new Array(len);
var thisp = arguments[1];
for(var i = 0; i < len; i++) {
if(i in this)
res[i] = fun.call(thisp, this[i], i, this);
}
return res;
};
}
/**
* Creates a new array with the results match the condistions
* @param {plain object or function} conditions
* @param {array} result
* @return {array}
*/
if(!Array.prototype.where) {
Array.prototype.where = function(conditions, result) {
result = result || [];
var cdt, ok, objVal;
this.forEach(function(val) {
ok = true;
for(var key in conditions) {
cdt = conditions[key];
if(typeof cdt === STR_FUNCTION) {
ok = cdt(val);
} else {
objVal = val[key];
ok = (objVal && objVal === cdt);
}
if(!ok) break;
}
if(ok) result.push(val);
});
return result;
};
}
/**
* Return a object contains grouped result as object key
* @param {string} key
* @return {Object}
*/
if(!Array.prototype.groupBy) {
Array.prototype.groupBy = function(key) {
var result = {};
this.forEach(function(val) {
var keyName = val[key];
if(!keyName) {
keyName = 'unkown';
}
if(!result[keyName]) {
result[keyName] = [];
}
result[keyName].push(val);
});
return result;
};
}
/**
* Returns true if at least one element in this array satisfies the provided testing conditions.
* @param {function or plain object} conditions
* @return {Boolean}
*/
if(!Array.prototype.has) {
Array.prototype.has = function(conditions) {
var result = false,
cdt, ok, objVal;
this.forEach(function(val) {
ok = true;
for(var key in conditions) {
cdt = conditions[key];
if(typeof cdt === STR_FUNCTION) {
ok = cdt(val);
} else {
objVal = val[key];
ok = (objVal && objVal === cdt);
}
if(!ok) break;
}
if(ok) {
result = true;
return false;
}
});
return result;
};
}
}());

View File

@@ -0,0 +1,7 @@
/*!
* ZUI: 数组辅助方法 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
!function(){"use strict";var r="function";Array.prototype.forEach||(Array.prototype.forEach=function(t){var o=this.length;if(typeof t!=r)throw new TypeError;for(var e=arguments[1],i=0;i<o;i++)i in this&&t.call(e,this[i],i,this)}),Array.isArray||(Array.isArray=function(r){return"[object Array]"===Object.toString.call(r)}),Array.prototype.lastIndexOf||(Array.prototype.lastIndexOf=function(r){var t=this.length,o=Number(arguments[1]);for(isNaN(o)?o=t-1:(o=o<0?Math.ceil(o):Math.floor(o),o<0?o+=t:o>=t&&(o=t-1));o>-1;o--)if(o in this&&this[o]===r)return o;return-1}),Array.prototype.every||(Array.prototype.every=function(t){var o=this.length;if(typeof t!=r)throw new TypeError;for(var e=arguments[1],i=0;i<o;i++)if(i in this&&!t.call(e,this[i],i,this))return!1;return!0}),Array.prototype.filter||(Array.prototype.filter=function(t){var o=this.length;if(typeof t!=r)throw new TypeError;for(var e=[],i=arguments[1],n=0;n<o;n++)if(n in this){var a=this[n];t.call(i,a,n,this)&&e.push(a)}return e}),Array.prototype.indexOf||(Array.prototype.indexOf=function(r){var t=this.length,o=Number(arguments[1])||0;for(o=o<0?Math.ceil(o):Math.floor(o),o<0&&(o+=t);o<t;o++)if(o in this&&this[o]===r)return o;return-1}),Array.prototype.map||(Array.prototype.map=function(t){var o=this.length;if(typeof t!=r)throw new TypeError;for(var e=new Array(o),i=arguments[1],n=0;n<o;n++)n in this&&(e[n]=t.call(i,this[n],n,this));return e}),Array.prototype.where||(Array.prototype.where=function(t,o){o=o||[];var e,i,n;return this.forEach(function(a){i=!0;for(var y in t)if(e=t[y],typeof e===r?i=e(a):(n=a[y],i=n&&n===e),!i)break;i&&o.push(a)}),o}),Array.prototype.groupBy||(Array.prototype.groupBy=function(r){var t={};return this.forEach(function(o){var e=o[r];e||(e="unkown"),t[e]||(t[e]=[]),t[e].push(o)}),t}),Array.prototype.has||(Array.prototype.has=function(t){var o,e,i,n=!1;return this.forEach(function(a){e=!0;for(var y in t)if(o=t[y],typeof o===r?e=o(a):(i=a[y],e=i&&i===o),!e)break;if(e)return n=!0,!1}),n})}();

View File

@@ -0,0 +1,104 @@
/*!
* ZUI: 看板 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
.board-item {
padding: 6px 10px;
margin-bottom: 5px;
background: #fff;
border: 1px solid #ddd;
-webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, .05);
box-shadow: 0 1px 0 rgba(0, 0, 0, .05);
-webkit-transition: all .4s cubic-bezier(.175, .885, .32, 1);
-o-transition: all .4s cubic-bezier(.175, .885, .32, 1);
transition: all .4s cubic-bezier(.175, .885, .32, 1);
}
.board-item:hover {
-webkit-box-shadow: 0 1px 1 rgba(0, 0, 0, .1);
box-shadow: 0 1px 1 rgba(0, 0, 0, .1);
}
.board-item.board-item-empty {
display: none;
color: #808080;
border-style: dashed;
}
.board-item.board-item-shadow {
display: none;
padding: 0;
background: #ddd;
border: none;
border-color: #ddd;
-webkit-box-shadow: inset 0 0 4px rgba(0, 0, 0, .1);
box-shadow: inset 0 0 4px rgba(0, 0, 0, .1);
-webkit-transition: all .4s cubic-bezier(.175, .885, .32, 1);
-o-transition: all .4s cubic-bezier(.175, .885, .32, 1);
transition: all .4s cubic-bezier(.175, .885, .32, 1);
}
.board-item.drag-shadow {
width: 250px;
cursor: move;
background-color: #fff;
border-color: #c4c4c4;
-webkit-box-shadow: 1px 1px 15px rgba(0, 0, 0, .25);
box-shadow: 1px 1px 15px rgba(0, 0, 0, .25);
opacity: .9;
}
.board-item.drag-from {
background-color: #ebf2f9;
}
.board-list .board-item:last-child {
margin-bottom: 0;
}
.board {
float: left;
width: 250px;
margin-right: 10px;
}
.board.drop-in-empty .board-item-empty {
height: 0;
padding: 0;
margin: 0;
overflow: hidden;
border: transparent;
}
.board:last-child {
margin-right: 0;
}
.board > .panel-body {
padding: 5px;
background: #f1f1f1;
}
.boards:before,
.boards:after {
/* 1 */
display: table;
content: " ";
/* 2 */
}
.boards:after {
clear: both;
}
.boards.dragging .board.drop-in {
border-color: #c4c4c4;
-webkit-box-shadow: 1px 1px 15px rgba(0, 0, 0, .25);
box-shadow: 1px 1px 15px rgba(0, 0, 0, .25);
}
.boards.dragging .board.drop-in .board-item-shadow {
display: block;
}
.boards.dragging .board .board-item.board-item-empty {
display: block;
}
.boards.dragging .board-item.disable-drop {
display: none;
}
.boards.drop-in .board-item.drag-from {
height: 0;
padding: 0;
margin: 0;
overflow: hidden;
border: transparent;
}

View File

@@ -0,0 +1,128 @@
/*!
* ZUI: 看板 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
/* ========================================================================
* ZUI: boards.js
* http://zui.sexy
* ========================================================================
* Copyright (c) 2014-2016 cnezsoft.com; Licensed MIT
* ======================================================================== */
(function($) {
'use strict';
if(!$.fn.droppable) throw new Error('Droppable requires for boards');
var Boards = function(element, options) {
this.$ = $(element);
this.options = this.getOptions(options);
this.getLang();
this.init();
};
Boards.DEFAULTS = {
// lang: null,
langs: {
'zh_cn': {
append2end: '移动到末尾'
},
'zh_tw': {
append2end: '移动到末尾'
},
'en': {
append2end: 'Move to the end.'
}
}
}; // default options
Boards.prototype.getOptions = function(options) {
options = $.extend({lang: $.zui.clientLang()}, Boards.DEFAULTS, this.$.data(), options);
return options;
};
Boards.prototype.getLang = function() {
var options = this.options;
this.lang = options.langs[options.lang] || options.langs[Boards.DEFAULTS.lang];
};
Boards.prototype.init = function() {
var idSeed = 1;
var lang = this.lang;
this.$.find('.board-item:not(".disable-drop"), .board:not(".disable-drop")').each(function() {
var $this = $(this);
if($this.attr('id')) {
$this.attr('data-id', $this.attr('id'));
} else if(!$this.attr('data-id')) {
$this.attr('data-id', 'board' + (idSeed++));
}
if($this.hasClass('board')) {
$this.find('.board-list').append('<div class="board-item board-item-empty"><i class="icon-plus"></i> {append2end}</div>'.format(lang))
.append('<div class="board-item board-item-shadow"></div>'.format(lang));
}
});
this.bind();
};
Boards.prototype.bind = function(items) {
var $boards = this.$,
setting = this.options;
$boards.droppable($.extend({
before: setting.before,
target: '.board-item:not(".disable-drop, .board-item-shadow")',
flex: true,
selector: '.board-item:not(".disable-drop, .board-item-shadow")',
start: function(e) {
$boards.addClass('dragging').find('.board-item-shadow').height(e.element.outerHeight());
},
drag: function(e) {
$boards.find('.board.drop-in-empty').removeClass('drop-in-empty');
if(e.isIn) {
var board = e.target.closest('.board').addClass('drop-in');
var shadow = board.find('.board-item-shadow');
var target = e.target;
$boards.addClass('drop-in').find('.board.drop-in').not(board).removeClass('drop-in');
shadow.insertBefore(target);
board.toggleClass('drop-in-empty', target.hasClass('board-item-empty'));
}
},
drop: function(e) {
if(e.isNew) {
var result;
if($.isFunction(setting['drop'])) {
result = setting['drop'](e);
}
if(result !== false) e.element.insertBefore(e.target);
}
},
finish: function() {
$boards.removeClass('dragging').removeClass('drop-in').find('.board.drop-in').removeClass('drop-in');
}
}, setting.droppable));
};
$.fn.boards = function(option) {
return this.each(function() {
var $this = $(this);
var data = $this.data('zui.boards');
var options = typeof option == 'object' && option;
if(!data) $this.data('zui.boards', (data = new Boards(this, options)));
if(typeof option == 'string') data[option]();
});
};
$.fn.boards.Constructor = Boards;
}(jQuery));

View File

@@ -0,0 +1,6 @@
/*!
* ZUI: 看板 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/.board-item{padding:6px 10px;margin-bottom:5px;background:#fff;border:1px solid #ddd;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.05);box-shadow:0 1px 0 rgba(0,0,0,.05);-webkit-transition:all .4s cubic-bezier(.175,.885,.32,1);-o-transition:all .4s cubic-bezier(.175,.885,.32,1);transition:all .4s cubic-bezier(.175,.885,.32,1)}.board-item:hover{-webkit-box-shadow:0 1px 1 rgba(0,0,0,.1);box-shadow:0 1px 1 rgba(0,0,0,.1)}.board-item.board-item-empty{display:none;color:grey;border-style:dashed}.board-item.board-item-shadow{display:none;padding:0;background:#ddd;border:none;border-color:#ddd;-webkit-box-shadow:inset 0 0 4px rgba(0,0,0,.1);box-shadow:inset 0 0 4px rgba(0,0,0,.1);-webkit-transition:all .4s cubic-bezier(.175,.885,.32,1);-o-transition:all .4s cubic-bezier(.175,.885,.32,1);transition:all .4s cubic-bezier(.175,.885,.32,1)}.board-item.drag-shadow{width:250px;cursor:move;background-color:#fff;border-color:#c4c4c4;-webkit-box-shadow:1px 1px 15px rgba(0,0,0,.25);box-shadow:1px 1px 15px rgba(0,0,0,.25);opacity:.9}.board-item.drag-from{background-color:#ebf2f9}.board-list .board-item:last-child{margin-bottom:0}.board{float:left;width:250px;margin-right:10px}.board.drop-in-empty .board-item-empty{height:0;padding:0;margin:0;overflow:hidden;border:transparent}.board:last-child{margin-right:0}.board>.panel-body{padding:5px;background:#f1f1f1}.boards:after,.boards:before{display:table;content:" "}.boards:after{clear:both}.boards.dragging .board.drop-in{border-color:#c4c4c4;-webkit-box-shadow:1px 1px 15px rgba(0,0,0,.25);box-shadow:1px 1px 15px rgba(0,0,0,.25)}.boards.dragging .board.drop-in .board-item-shadow{display:block}.boards.dragging .board .board-item.board-item-empty{display:block}.boards.dragging .board-item.disable-drop{display:none}.boards.drop-in .board-item.drag-from{height:0;padding:0;margin:0;overflow:hidden;border:transparent}

View File

@@ -0,0 +1,7 @@
/*!
* ZUI: 看板 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
!function(t){"use strict";if(!t.fn.droppable)throw new Error("Droppable requires for boards");var o=function(o,a){this.$=t(o),this.options=this.getOptions(a),this.getLang(),this.init()};o.DEFAULTS={langs:{zh_cn:{append2end:"移动到末尾"},zh_tw:{append2end:"移动到末尾"},en:{append2end:"Move to the end."}}},o.prototype.getOptions=function(a){return a=t.extend({lang:t.zui.clientLang()},o.DEFAULTS,this.$.data(),a)},o.prototype.getLang=function(){var t=this.options;this.lang=t.langs[t.lang]||t.langs[o.DEFAULTS.lang]},o.prototype.init=function(){var o=1,a=this.lang;this.$.find('.board-item:not(".disable-drop"), .board:not(".disable-drop")').each(function(){var i=t(this);i.attr("id")?i.attr("data-id",i.attr("id")):i.attr("data-id")||i.attr("data-id","board"+o++),i.hasClass("board")&&i.find(".board-list").append('<div class="board-item board-item-empty"><i class="icon-plus"></i> {append2end}</div>'.format(a)).append('<div class="board-item board-item-shadow"></div>'.format(a))}),this.bind()},o.prototype.bind=function(o){var a=this.$,i=this.options;a.droppable(t.extend({before:i.before,target:'.board-item:not(".disable-drop, .board-item-shadow")',flex:!0,selector:'.board-item:not(".disable-drop, .board-item-shadow")',start:function(t){a.addClass("dragging").find(".board-item-shadow").height(t.element.outerHeight())},drag:function(t){if(a.find(".board.drop-in-empty").removeClass("drop-in-empty"),t.isIn){var o=t.target.closest(".board").addClass("drop-in"),i=o.find(".board-item-shadow"),e=t.target;a.addClass("drop-in").find(".board.drop-in").not(o).removeClass("drop-in"),i.insertBefore(e),o.toggleClass("drop-in-empty",e.hasClass("board-item-empty"))}},drop:function(o){if(o.isNew){var a;t.isFunction(i.drop)&&(a=i.drop(o)),a!==!1&&o.element.insertBefore(o.target)}},finish:function(){a.removeClass("dragging").removeClass("drop-in").find(".board.drop-in").removeClass("drop-in")}},i.droppable))},t.fn.boards=function(a){return this.each(function(){var i=t(this),e=i.data("zui.boards"),n="object"==typeof a&&a;e||i.data("zui.boards",e=new o(this,n)),"string"==typeof a&&e[a]()})},t.fn.boards.Constructor=o}(jQuery);

View File

@@ -0,0 +1,3 @@
.bootbox.modal .modal-dialog {
width: 400px;
}

847
root/res/zui/lib/bootbox/bootbox.js vendored Normal file
View File

@@ -0,0 +1,847 @@
/* ========================================================================
* Bootbox: bootbox.js [v4.4.0]
* http://bootboxjs.com/
*
* ZUI: The file has been changed in ZUI. It will not keep update with the
* official version in the future.
* http://zui.sexy
* ========================================================================
* http://bootboxjs.com/license.txt
* Improvement in ZUI:
* 1. Determine client language and apply setting automatically.
* 2. Changed button position.
* ======================================================================== */
/*! bootbox.js v4.4.0 http://bootboxjs.com/license.txt */
// @see https://github.com/makeusabrew/bootbox/issues/180
// @see https://github.com/makeusabrew/bootbox/issues/186
(function(root, factory) {
'use strict';
if(typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["jquery"], factory);
} else if(typeof exports === "object") {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory(require("jquery"));
} else {
// Browser globals (root is window)
root.bootbox = factory(root.jQuery);
}
}(this, function init($, undefined) {
'use strict';
// the base DOM structure needed to create a modal
var templates = {
dialog: "<div class='bootbox modal' tabindex='-1' role='dialog'>" +
"<div class='modal-dialog'>" +
"<div class='modal-content'>" +
"<div class='modal-body'><div class='bootbox-body'></div></div>" +
"</div>" +
"</div>" +
"</div>",
header: "<div class='modal-header'>" +
"<h4 class='modal-title'></h4>" +
"</div>",
footer: "<div class='modal-footer'></div>",
closeButton: "<button type='button' class='bootbox-close-button close' data-dismiss='modal' aria-hidden='true'>&times;</button>",
form: "<form class='bootbox-form'></form>",
inputs: {
text: "<input class='bootbox-input bootbox-input-text form-control' autocomplete=off type=text />",
textarea: "<textarea class='bootbox-input bootbox-input-textarea form-control'></textarea>",
email: "<input class='bootbox-input bootbox-input-email form-control' autocomplete='off' type='email' />",
select: "<select class='bootbox-input bootbox-input-select form-control'></select>",
checkbox: "<div class='checkbox'><label><input class='bootbox-input bootbox-input-checkbox' type='checkbox' /></label></div>",
date: "<input class='bootbox-input bootbox-input-date form-control' autocomplete=off type='date' />",
time: "<input class='bootbox-input bootbox-input-time form-control' autocomplete=off type='time' />",
number: "<input class='bootbox-input bootbox-input-number form-control' autocomplete=off type='number' />",
password: "<input class='bootbox-input bootbox-input-password form-control' autocomplete='off' type='password' />"
}
};
var defaults = {
// default language
locale: $.zui && $.zui.clientLang ? $.zui.clientLang() : 'zh_cn',
// show backdrop or not. Default to static so user has to interact with dialog
backdrop: "static",
// animate the modal in/out
animate: true,
// additional class string applied to the top level dialog
className: null,
// whether or not to include a close button
closeButton: true,
// show the dialog immediately by default
show: true,
// dialog container
container: "body"
};
// our public object; augmented after our private API
var exports = {};
/**
* @private
*/
function _t(key) {
var locale = locales[defaults.locale];
return locale ? locale[key] : locales.en[key];
}
function processCallback(e, dialog, callback) {
e.stopPropagation();
e.preventDefault();
// by default we assume a callback will get rid of the dialog,
// although it is given the opportunity to override this
// so, if the callback can be invoked and it *explicitly returns false*
// then we'll set a flag to keep the dialog active...
var preserveDialog = $.isFunction(callback) && callback.call(dialog, e) === false;
// ... otherwise we'll bin it
if(!preserveDialog) {
dialog.modal("hide");
}
}
function getKeyLength(obj) {
// @TODO defer to Object.keys(x).length if available?
var k, t = 0;
for(k in obj) {
t++;
}
return t;
}
function each(collection, iterator) {
var index = 0;
$.each(collection, function(key, value) {
iterator(key, value, index++);
});
}
function sanitize(options) {
var buttons;
var total;
if(typeof options !== "object") {
throw new Error("Please supply an object of options");
}
if(!options.message) {
throw new Error("Please specify a message");
}
// make sure any supplied options take precedence over defaults
options = $.extend({}, defaults, options);
if(!options.buttons) {
options.buttons = {};
}
buttons = options.buttons;
total = getKeyLength(buttons);
each(buttons, function(key, button, index) {
if($.isFunction(button)) {
// short form, assume value is our callback. Since button
// isn't an object it isn't a reference either so re-assign it
button = buttons[key] = {
callback: button
};
}
// before any further checks make sure by now button is the correct type
if($.type(button) !== "object") {
throw new Error("button with key " + key + " must be an object");
}
if(!button.label) {
// the lack of an explicit label means we'll assume the key is good enough
button.label = key;
}
if(!button.className) {
if((total === 2 && (key === 'ok' || key === 'confirm')) || total === 1) {
// always add a primary to the main option in a two-button dialog
button.className = "btn-primary";
} else {
button.className = "btn-default";
}
}
});
return options;
}
/**
* map a flexible set of arguments into a single returned object
* if args.length is already one just return it, otherwise
* use the properties argument to map the unnamed args to
* object properties
* so in the latter case:
* mapArguments(["foo", $.noop], ["message", "callback"])
* -> { message: "foo", callback: $.noop }
*/
function mapArguments(args, properties) {
var argn = args.length;
var options = {};
if(argn < 1 || argn > 2) {
throw new Error("Invalid argument length");
}
if(argn === 2 || typeof args[0] === "string") {
options[properties[0]] = args[0];
options[properties[1]] = args[1];
} else {
options = args[0];
}
return options;
}
/**
* merge a set of default dialog options with user supplied arguments
*/
function mergeArguments(defaults, args, properties) {
return $.extend(
// deep merge
true,
// ensure the target is an empty, unreferenced object
{},
// the base options object for this type of dialog (often just buttons)
defaults,
// args could be an object or array; if it's an array properties will
// map it to a proper options object
mapArguments(
args,
properties
)
);
}
/**
* this entry-level method makes heavy use of composition to take a simple
* range of inputs and return valid options suitable for passing to bootbox.dialog
*/
function mergeDialogOptions(className, labels, properties, args) {
// build up a base set of dialog properties
var baseOptions = {
className: "bootbox-" + className,
buttons: createLabels.apply(null, labels)
};
// ensure the buttons properties generated, *after* merging
// with user args are still valid against the supplied labels
return validateButtons(
// merge the generated base properties with user supplied arguments
mergeArguments(
baseOptions,
args,
// if args.length > 1, properties specify how each arg maps to an object key
properties
),
labels
);
}
/**
* from a given list of arguments return a suitable object of button labels
* all this does is normalise the given labels and translate them where possible
* e.g. "ok", "confirm" -> { ok: "OK, cancel: "Annuleren" }
*/
function createLabels() {
var buttons = {};
for(var i = 0, j = arguments.length; i < j; i++) {
var argument = arguments[i];
var key = argument.toLowerCase();
var value = argument.toUpperCase();
buttons[key] = {
label: _t(value)
};
}
return buttons;
}
function validateButtons(options, buttons) {
var allowedButtons = {};
each(buttons, function(key, value) {
allowedButtons[value] = true;
});
each(options.buttons, function(key) {
if(allowedButtons[key] === undefined) {
throw new Error("button key " + key + " is not allowed (options are " + buttons.join("\n") + ")");
}
});
return options;
}
exports.alert = function() {
var options;
options = mergeDialogOptions("alert", ["ok"], ["message", "callback"], arguments);
if(options.callback && !$.isFunction(options.callback)) {
throw new Error("alert requires callback property to be a function when provided");
}
/**
* overrides
*/
options.buttons.ok.callback = options.onEscape = function() {
if($.isFunction(options.callback)) {
return options.callback.call(this);
}
return true;
};
return exports.dialog(options);
};
exports.confirm = function() {
var options;
// ZUI change begin
options = mergeDialogOptions("confirm", ["confirm", "cancel"], ["message", "callback"], arguments);
// OLD WAY: options = mergeDialogOptions("confirm", ["cancel", "confirm"], ["message", "callback"], arguments);
// ZUI change end
/**
* overrides; undo anything the user tried to set they shouldn't have
*/
options.buttons.cancel.callback = options.onEscape = function() {
return options.callback.call(this, false);
};
options.buttons.confirm.callback = function() {
return options.callback.call(this, true);
};
// confirm specific validation
if(!$.isFunction(options.callback)) {
throw new Error("confirm requires a callback");
}
return exports.dialog(options);
};
exports.prompt = function() {
var options;
var defaults;
var dialog;
var form;
var input;
var shouldShow;
var inputOptions;
// we have to create our form first otherwise
// its value is undefined when gearing up our options
// @TODO this could be solved by allowing message to
// be a function instead...
form = $(templates.form);
// prompt defaults are more complex than others in that
// users can override more defaults
// @TODO I don't like that prompt has to do a lot of heavy
// lifting which mergeDialogOptions can *almost* support already
// just because of 'value' and 'inputType' - can we refactor?
defaults = {
className: "bootbox-prompt",
buttons: createLabels("cancel", "confirm"),
value: "",
inputType: "text"
};
options = validateButtons(
// ZUI change begin
mergeArguments(defaults, arguments, ["title", "callback"]), ["confirm", "cancel"]
// OLD WAY: mergeArguments(defaults, arguments, ["title", "callback"]), ["cancel", "confirm"]arguments);
// ZUI change end
);
// capture the user's show value; we always set this to false before
// spawning the dialog to give us a chance to attach some handlers to
// it, but we need to make sure we respect a preference not to show it
shouldShow = (options.show === undefined) ? true : options.show;
/**
* overrides; undo anything the user tried to set they shouldn't have
*/
options.message = form;
options.buttons.cancel.callback = options.onEscape = function() {
return options.callback.call(this, null);
};
options.buttons.confirm.callback = function() {
var value;
switch(options.inputType) {
case "text":
case "textarea":
case "email":
case "select":
case "date":
case "time":
case "number":
case "password":
value = input.val();
break;
case "checkbox":
var checkedItems = input.find("input:checked");
// we assume that checkboxes are always multiple,
// hence we default to an empty array
value = [];
each(checkedItems, function(_, item) {
value.push($(item).val());
});
break;
}
return options.callback.call(this, value);
};
options.show = false;
// prompt specific validation
if(!options.title) {
throw new Error("prompt requires a title");
}
if(!$.isFunction(options.callback)) {
throw new Error("prompt requires a callback");
}
if(!templates.inputs[options.inputType]) {
throw new Error("invalid prompt type");
}
// create the input based on the supplied type
input = $(templates.inputs[options.inputType]);
switch(options.inputType) {
case "text":
case "textarea":
case "email":
case "date":
case "time":
case "number":
case "password":
input.val(options.value);
break;
case "select":
var groups = {};
inputOptions = options.inputOptions || [];
if(!$.isArray(inputOptions)) {
throw new Error("Please pass an array of input options");
}
if(!inputOptions.length) {
throw new Error("prompt with select requires options");
}
each(inputOptions, function(_, option) {
// assume the element to attach to is the input...
var elem = input;
if(option.value === undefined || option.text === undefined) {
throw new Error("given options in wrong format");
}
// ... but override that element if this option sits in a group
if(option.group) {
// initialise group if necessary
if(!groups[option.group]) {
groups[option.group] = $("<optgroup/>").attr("label", option.group);
}
elem = groups[option.group];
}
elem.append("<option value='" + option.value + "'>" + option.text + "</option>");
});
each(groups, function(_, group) {
input.append(group);
});
// safe to set a select's value as per a normal input
input.val(options.value);
break;
case "checkbox":
var values = $.isArray(options.value) ? options.value : [options.value];
inputOptions = options.inputOptions || [];
if(!inputOptions.length) {
throw new Error("prompt with checkbox requires options");
}
if(!inputOptions[0].value || !inputOptions[0].text) {
throw new Error("given options in wrong format");
}
// checkboxes have to nest within a containing element, so
// they break the rules a bit and we end up re-assigning
// our 'input' element to this container instead
input = $("<div/>");
each(inputOptions, function(_, option) {
var checkbox = $(templates.inputs[options.inputType]);
checkbox.find("input").attr("value", option.value);
checkbox.find("label").append(option.text);
// we've ensured values is an array so we can always iterate over it
each(values, function(_, value) {
if(value === option.value) {
checkbox.find("input").prop("checked", true);
}
});
input.append(checkbox);
});
break;
}
// @TODO provide an attributes option instead
// and simply map that as keys: vals
if(options.placeholder) {
input.attr("placeholder", options.placeholder);
}
if(options.pattern) {
input.attr("pattern", options.pattern);
}
if(options.maxlength) {
input.attr("maxlength", options.maxlength);
}
// now place it in our form
form.append(input);
form.on("submit", function(e) {
e.preventDefault();
// Fix for SammyJS (or similar JS routing library) hijacking the form post.
e.stopPropagation();
// @TODO can we actually click *the* button object instead?
// e.g. buttons.confirm.click() or similar
dialog.find(".btn-primary").click();
});
dialog = exports.dialog(options);
// clear the existing handler focusing the submit button...
dialog.off("shown.zui.modal");
// ...and replace it with one focusing our input, if possible
dialog.on("shown.zui.modal", function() {
// need the closure here since input isn't
// an object otherwise
input.focus();
});
if(shouldShow === true) {
dialog.modal("show");
}
return dialog;
};
exports.dialog = function(options) {
options = sanitize(options);
var dialog = $(templates.dialog);
var innerDialog = dialog.find(".modal-dialog");
var body = dialog.find(".modal-body");
var buttons = options.buttons;
var buttonStr = "";
var callbacks = {
onEscape: options.onEscape
};
if($.fn.modal === undefined) {
throw new Error(
"$.fn.modal is not defined; please double check you have included " +
"the Bootstrap JavaScript library. See http://getbootstrap.com/javascript/ " +
"for more details."
);
}
each(buttons, function(key, button) {
// @TODO I don't like this string appending to itself; bit dirty. Needs reworking
// can we just build up button elements instead? slower but neater. Then button
// can just become a template too
buttonStr += "<button data-bb-handler='" + key + "' type='button' class='btn " + button.className + "'>" + button.label + "</button>";
callbacks[key] = button.callback;
});
body.find(".bootbox-body").html(options.message);
if(options.animate === true) {
dialog.addClass("fade");
}
if(options.className) {
dialog.addClass(options.className);
}
if(options.size === "large") {
innerDialog.addClass("modal-lg");
} else if(options.size === "small") {
innerDialog.addClass("modal-sm");
}
if(options.title) {
body.before(templates.header);
}
if(options.closeButton) {
var closeButton = $(templates.closeButton);
if(options.title) {
dialog.find(".modal-header").prepend(closeButton);
} else {
closeButton.css("margin-top", "-10px").prependTo(body);
}
}
if(options.title) {
dialog.find(".modal-title").html(options.title);
}
if(buttonStr.length) {
body.after(templates.footer);
dialog.find(".modal-footer").html(buttonStr);
}
/**
* Bootstrap event listeners; used handle extra
* setup & teardown required after the underlying
* modal has performed certain actions
*/
dialog.on("hidden.zui.modal", function(e) {
// ensure we don't accidentally intercept hidden events triggered
// by children of the current dialog. We shouldn't anymore now BS
// namespaces its events; but still worth doing
if(e.target === this) {
dialog.remove();
}
});
/*
dialog.on("show.zui.modal", function() {
// sadly this doesn't work; show is called *just* before
// the backdrop is added so we'd need a setTimeout hack or
// otherwise... leaving in as would be nice
if (options.backdrop) {
dialog.next(".modal-backdrop").addClass("bootbox-backdrop");
}
});
*/
dialog.on("shown.zui.modal", function() {
dialog.find(".btn-primary:first").focus();
});
/**
* Bootbox event listeners; experimental and may not last
* just an attempt to decouple some behaviours from their
* respective triggers
*/
if(options.backdrop !== "static") {
// A boolean true/false according to the Bootstrap docs
// should show a dialog the user can dismiss by clicking on
// the background.
// We always only ever pass static/false to the actual
// $.modal function because with `true` we can't trap
// this event (the .modal-backdrop swallows it)
// However, we still want to sort of respect true
// and invoke the escape mechanism instead
dialog.on("click.dismiss.zui.modal", function(e) {
// @NOTE: the target varies in >= 3.3.x releases since the modal backdrop
// moved *inside* the outer dialog rather than *alongside* it
if(dialog.children(".modal-backdrop").length) {
e.currentTarget = dialog.children(".modal-backdrop").get(0);
}
if(e.target !== e.currentTarget) {
return;
}
dialog.trigger("escape.close.bb");
});
}
dialog.on("escape.close.bb", function(e) {
if(callbacks.onEscape) {
processCallback(e, dialog, callbacks.onEscape);
}
});
/**
* Standard jQuery event listeners; used to handle user
* interaction with our dialog
*/
dialog.on("click", ".modal-footer button", function(e) {
var callbackKey = $(this).data("bb-handler");
processCallback(e, dialog, callbacks[callbackKey]);
});
dialog.on("click", ".bootbox-close-button", function(e) {
// onEscape might be falsy but that's fine; the fact is
// if the user has managed to click the close button we
// have to close the dialog, callback or not
processCallback(e, dialog, callbacks.onEscape);
});
dialog.on("keyup", function(e) {
if(e.which === 27) {
dialog.trigger("escape.close.bb");
}
});
// the remainder of this method simply deals with adding our
// dialogent to the DOM, augmenting it with Bootstrap's modal
// functionality and then giving the resulting object back
// to our caller
$(options.container).append(dialog);
dialog.modal({
backdrop: options.backdrop ? "static" : false,
keyboard: false,
show: false
});
if(options.show) {
dialog.modal("show");
}
// @TODO should we return the raw element here or should
// we wrap it in an object on which we can expose some neater
// methods, e.g. var d = bootbox.alert(); d.hide(); instead
// of d.modal("hide");
/*
function BBDialog(elem) {
this.elem = elem;
}
BBDialog.prototype = {
hide: function() {
return this.elem.modal("hide");
},
show: function() {
return this.elem.modal("show");
}
};
*/
return dialog;
};
exports.setDefaults = function() {
var values = {};
if(arguments.length === 2) {
// allow passing of single key/value...
values[arguments[0]] = arguments[1];
} else {
// ... and as an object too
values = arguments[0];
}
$.extend(defaults, values);
};
exports.hideAll = function() {
$(".bootbox").modal("hide");
return exports;
};
/**
* standard locales. Please add more according to ISO 639-1 standard. Multiple language variants are
* unlikely to be required. If this gets too large it can be split out into separate JS files.
*/
var locales = {
en: {
OK: "OK",
CANCEL: "Cancel",
CONFIRM: "OK"
},
zh_cn: {
OK: "确认",
CANCEL: "取消",
CONFIRM: "确认"
},
zh_tw: {
OK: "確認",
CANCEL: "取消",
CONFIRM: "確認"
}
};
exports.addLocale = function(name, values) {
$.each(["OK", "CANCEL", "CONFIRM"], function(_, v) {
if(!values[v]) {
throw new Error("Please supply a translation for '" + v + "'");
}
});
locales[name] = {
OK: values.OK,
CANCEL: values.CANCEL,
CONFIRM: values.CONFIRM
};
return exports;
};
exports.removeLocale = function(name) {
delete locales[name];
return exports;
};
exports.setLocale = function(name) {
return exports.setDefaults("locale", name);
};
exports.init = function(_$) {
return init(_$ || $);
};
return exports;
}));

View File

@@ -0,0 +1 @@
.bootbox.modal .modal-dialog{width:400px}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,156 @@
/*!
* ZUI: 日历 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
.calendar {
margin-bottom: 20px;
}
.calendar > header {
margin-bottom: 10px;
}
.calendar > header .btn-toolbar > .btn-group {
margin-right: 10px;
}
.calendar > header .calendar-caption {
line-height: 30px;
}
.calendar .table {
margin-bottom: 0;
table-layout: fixed;
}
.calendar .table > thead > tr > th,
.calendar .table > tbody > tr > td {
width: 14.28571428571429%;
padding: 0;
}
.calendar .table > thead > tr > th {
color: #808080;
text-align: center;
background-color: #fff;
}
.calendar .weekends-empty .table > thead > tr > th,
.calendar .weekends-empty .table > tbody > tr > td {
width: 20%;
}
.calendar .weekends-empty .table > thead > tr > th.weekend-head,
.calendar .weekends-empty .table > tbody > tr > td.weekend-day {
width: 40px;
min-width: 40px;
}
.calendar .day {
opacity: .7;
}
.calendar .day > .heading {
padding: 2px 5px;
text-align: right;
}
.calendar .day > .heading > .month {
padding: 1px 2px;
color: #fff;
background-color: #b3b3b3;
border-radius: 3px;
}
.calendar .day > .content {
height: 100%;
min-height: 70px;
}
.calendar .cell-day {
background-color: #f1f1f1;
}
.calendar .cell-day.past > .day > .content {
opacity: .7;
}
.calendar .cell-day.current-month {
background: none;
}
.calendar .cell-day.current-month > .day {
opacity: 1;
}
.calendar .cell-day.current {
background-color: #fff0d5;
-webkit-box-shadow: inset 1px 1px 0 #808080, inset -1px -1px 0 #808080;
box-shadow: inset 1px 1px 0 #808080, inset -1px -1px 0 #808080;
}
.calendar .cell-day.current > .day > .content {
padding: 0;
}
.calendar .cell-day.current > .day > .heading {
background-color: rgba(0, 0, 0, .1);
}
.calendar .cell-day.drop-to {
background-color: #fff0d5;
opacity: 1;
}
.calendar .event {
padding: 1px 5px;
margin: 0 1px 1px;
color: #fff;
cursor: pointer;
background-color: #3280fc;
opacity: .95;
-webkit-transition: all .4s cubic-bezier(.175, .885, .32, 1);
-o-transition: all .4s cubic-bezier(.175, .885, .32, 1);
transition: all .4s cubic-bezier(.175, .885, .32, 1);
}
a.calendar .event:hover {
background-color: #0462f7;
}
.calendar .event:hover {
opacity: 1;
}
.calendar .event.drag-shadow {
cursor: move;
}
.calendar .event.drag-from {
opacity: .25;
}
.calendar .event.color-red {
color: #fff;
background-color: #ea644a;
}
a.calendar .event.color-red:hover {
background-color: #e53d1c;
}
.calendar .event.color-green {
color: #fff;
background-color: #38b03f;
}
a.calendar .event.color-green:hover {
background-color: #2c8931;
}
.calendar .event.color-yellow {
color: #fff;
background-color: #f1a325;
}
a.calendar .event.color-yellow:hover {
background-color: #d5890e;
}
.calendar .event.color-blue {
color: #fff;
background-color: #03b8cf;
}
a.calendar .event.color-blue:hover {
background-color: #028b9d;
}
.calendar .event.color-brown {
color: #fff;
background-color: #bd7b46;
}
a.calendar .event.color-brown:hover {
background-color: #996337;
}
.calendar .event.color-purple {
color: #fff;
background-color: #8666b8;
}
a.calendar .event.color-purple:hover {
background-color: #6c4aa1;
}
.calendar.limit-event-title .event {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

View File

@@ -0,0 +1,705 @@
/*!
* ZUI: 日历 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
/* ========================================================================
* ZUI: calendar.js
* http://zui.sexy
* ========================================================================
* Copyright (c) 2014 cnezsoft.com; Licensed MIT
* ======================================================================== */
(function($, window) {
'use strict';
var NAME = 'zui.calendar';
var NUMBER_TYPE_NAME = 'number';
var STRING_TYPE_NAME = 'string';
var UNDEFINED_TYPE_NAME = 'undefined';
var presetColors = {
"primary": 1,
"green": 2,
"red": 3,
"blue": 4,
"yellow": 5,
"brown": 6,
"purple": 7
};
var getNearbyLastWeekDay = function(date, lastWeek) {
lastWeek = lastWeek || 1;
var d = date.clone();
while(d.getDay() != lastWeek) {
d.addDays(-1);
}
d.clearTime();
return d;
},
getFirstDayOfMonth = function(date) {
var d = date.clone();
d.setDate(1);
return d;
},
calculateDays = function(start, end) {
var s = start.clone().clearTime();
var e = end.clone().clearTime();
return Math.round((e.getTime() - s.getTime()) / Date.ONEDAY_TICKS) + 1;
},
everyDayTo = function(start, end, callback) {
var a = start.clone();
var i = 0;
while(a <= end) {
callback(a.clone(), i++);
a.addDays(1);
}
};
var Calendar = function(element, options) {
this.name = NAME;
this.$ = $(element);
this.id = this.$.attr('id') || (NAME + $.zui.uuid());
this.$.attr('id', this.id);
this.storeName = NAME + '.' + this.id;
this.getOptions(options);
this.getLang();
this.data = this.options.data;
this.addCalendars(this.data.calendars);
this.addEvents(this.data.events);
this.sortEvents();
this.storeData = $.zui.store.pageGet(this.storeName, {
date: 'today',
view: 'month'
});
this.date = this.options.startDate || 'today';
this.view = this.options.startView || 'month';
this.$.toggleClass('limit-event-title', options.limitEventTitle);
if(this.options.withHeader) {
var $header = this.$.children('.calender-header');
if(!$header.length) {
$header = $('<header><div class="btn-toolbar"><div class="btn-group"><button type="button" class="btn btn-today">{today}</button></div><div class="btn-group"><button type="button" class="btn btn-prev"><i class="icon-chevron-left"></i></button><button type="button" class="btn btn-next"><i class="icon-chevron-right"></i></button></div><div class="btn-group"><span class="calendar-caption"></span></div></div></header>'.format(this.lang));
this.$.append($header);
}
this.$caption = $header.find('.calendar-caption');
this.$todayBtn = $header.find('.btn-today');
this.$header = $header;
}
var $views = this.$.children('.calendar-views');
if(!$views.length) {
$views = $('<div class="calendar-views"></div>');
this.$.append($views);
}
this.$views = $views;
this.$monthView = $views.children('.calendar-view.month');
this.display();
this.bindEvents();
};
// default options
Calendar.DEFAULTS = {
langs: {
zh_cn: {
weekNames: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
monthNames: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
today: '今天',
year: '{0}年',
month: '{0}月',
yearMonth: '{0}年{1}月'
},
zh_tw: {
weekNames: ['週一', '週二', '週三', '週四', '週五', '週六', '週日'],
monthNames: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
today: '今天',
year: '{0}年',
month: '{0}月',
yearMonth: '{0}年{1}月'
},
en: {
weekNames: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
monthNames: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'June', 'July', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
today: 'Today',
year: '{0}',
month: '{0}',
yearMonth: '{2}, {0}'
}
},
data: {
calendars: {
defaultCal: {
color: '#229F24'
}
},
events: []
},
// startView: "month", // default view when load complete
// startDate: 'today', // default date when load complete
limitEventTitle: true,
storage: true,
withHeader: true,
dragThenDrop: true, // drag an event and drop at another day,
// hideEmptyWeekends: false // Auto hide empty weekends
};
// Sort events by start datetime
Calendar.prototype.sortEvents = function() {
var events = this.events;
if(!$.isArray(events)) {
events = [];
}
events.sort(function(a, b) {
return a.start < b.start ? 1 : (a.start > b.start ? (-1) : 0);
});
this.events = events;
};
Calendar.prototype.bindEvents = function() {
var $e = this.$,
self = this;
$e.on('click', '.btn-today', function() {
self.date = new Date();
self.display();
self.callEvent('clickTodayBtn');
}).on('click', '.btn-next', function() {
if(self.view === 'month') {
self.date.addMonths(1);
}
self.display();
self.callEvent('clickNextBtn');
}).on('click', '.btn-prev', function() {
if(self.view === 'month') {
self.date.addMonths(-1);
}
self.display();
self.callEvent('clickPrevBtn');
}).on('click', '.event', function(event) {
self.callEvent('clickEvent', {
element: this,
event: $(this).data('event'),
events: self.events
});
event.stopPropagation();
}).on('click', '.cell-day', function() {
self.callEvent('clickCell', {
element: this,
view: self.view,
date: new Date($(this).children('.day').attr('data-date')),
events: self.events
});
});
};
Calendar.prototype.addCalendars = function(calendars, silence) {
var that = this;
if(!that.calendars) that.calendars = {};
if($.isPlainObject(calendars)) {
calendars = [calendars];
}
$.each(calendars, function(index, cal) {
if(!silence && !that.callEvent('beforeAddCalendars', {
newCalendar: cal,
data: that.data
})) {
return;
}
if(!cal.color) cal.color = 'primary';
if(!presetColors[cal.color.toLowerCase()]) {
var c = new $.zui.Color(cal.color);
cal.textColor = c.contrast().hexStr();
} else {
cal.presetColor = true;
}
that.calendars[cal.name] = cal;
});
if(!silence) {
that.display();
that.callEvent('addCalendars', {
newCalendars: calendars,
data: that.data
});
}
};
Calendar.prototype.addEvents = function(events, silence) {
var that = this;
if(!that.events) that.events = [];
if($.isPlainObject(events)) {
events = [events];
}
$.each(events, function(index, e) {
if(!silence && !that.callEvent('beforeAddEvent', {
newEvent: e,
data: that.data
})) {
return;
}
var startType = typeof e.start;
var endType = typeof e.end;
if(startType === NUMBER_TYPE_NAME || startType === STRING_TYPE_NAME) {
e.start = new Date(e.start);
}
if(endType === NUMBER_TYPE_NAME || endType === STRING_TYPE_NAME) {
e.end = new Date(e.end);
}
if(typeof e.id === UNDEFINED_TYPE_NAME) {
e.id = $.zui.uuid();
}
if(e.allDay) {
e.start.clearTime();
e.end.clearTime().addDays(1).addMilliseconds(-1);
}
e.days = calculateDays(e.start, e.end);
that.events.push(e);
});
if(!silence) {
that.sortEvents();
that.display();
that.callEvent('addEvents', {
newEvents: events,
data: that.data
});
}
};
Calendar.prototype.getEvent = function(id) {
var events = this.events;
for(var i = 0; i < events.length; i++) {
if(events[i].id == id) {
return events[i];
}
}
return null;
};
Calendar.prototype.updateEvents = function(events) {
var eventsParams = {
data: this.data,
changes: []
},
that = this;
if($.isPlainObject(events)) {
events = [events];
}
var event, chgs, eventParam;
$.each(events, function(index, changes) {
event = changes.event;
chgs = changes.changes;
eventParam = {
event: event,
changes: []
};
if(typeof event === STRING_TYPE_NAME) {
event = that.getEvent(event);
}
if(event) {
if($.isPlainObject(chgs)) {
chgs = [chgs];
}
$.each(changes, function(idx, chge) {
if(that.callEvent('beforeChange', {
event: event,
change: chge.change,
to: chge.to,
from: event[chge.change]
})) {
eventParam.changes.push($.extend(true, {}, chge, {
from: event[chge.change]
}));
event[chge.change] = chge.to;
}
});
}
eventsParams.changes.push(eventParam);
});
that.sortEvents();
that.display();
that.callEvent('change', eventsParams);
};
Calendar.prototype.removeEvents = function(events) {
if(!$.isArray(events)) {
events = [events];
}
var id, event, idx, evts = this.events,
that = this,
removedEvents = [];
$.each(events, function(index, value) {
id = $.isPlainObject(value) ? value.id : value;
idx = -1;
for(var i = 0; i < evts.length; i++) {
if(evts[i].id == id) {
idx = i;
event = evts[i];
break;
}
}
if(idx >= 0 && that.callEvent('beforeRemoveEvent', {
event: event,
eventId: id,
data: that.data
})) {
evts.splice(idx, 1);
removedEvents.push(event);
}
});
that.sortEvents();
that.display();
that.callEvent('removeEvents', {
removedEvents: removedEvents,
data: that.data
});
};
Calendar.prototype.getOptions = function(options) {
this.options = $.extend({}, Calendar.DEFAULTS, this.$.data(), options);
};
Calendar.prototype.getLang = function() {
this.lang = this.options.langs[this.options.lang || ($.zui && $.zui.clientLang ? $.zui.clientLang() : 'zh-cn')];
};
Calendar.prototype.display = function(view, date) {
var that = this;
var viewType = typeof view;
var dateType = typeof date;
if(viewType === UNDEFINED_TYPE_NAME) {
view = that.view;
} else {
that.view = view;
}
if(dateType === UNDEFINED_TYPE_NAME) {
date = that.date;
} else {
that.date = date;
}
if(date === 'today') {
date = new Date();
that.date = date;
}
if(typeof date === STRING_TYPE_NAME) {
date = new Date(date);
that.date = date;
}
if(that.options.storage) {
$.zui.store.pageSet(that.storeName, {
date: date,
view: view
});
}
var eventPramas = {
view: view,
date: date
};
if(that.callEvent('beforeDisplay', eventPramas)) {
switch(view) {
case 'month':
that.displayMonth(date);
break;
}
that.callEvent('display', eventPramas);
}
};
Calendar.prototype.displayMonth = function(date) {
var that = this;
date = date || that.date;
var options = that.options,
lang = that.lang,
i,
$views = that.$views,
$e = that.$;
var $view = that.$monthView;
if(!$view.length) {
$view = $('<div class="calendar-view month"><table class="table table-bordered"><thead><tr class="week-head"></tr></thead><tbody class="month-days"></tbody></table></div>');
var $weekHead = $view.find('.week-head'),
$monthDays = $view.find('.month-days'),
$tr;
for(i = 0; i < 7; i++) {
$('<th>' + lang.weekNames[i] + '</th>').toggleClass('weekend-head', i >= 5).appendTo($weekHead);
}
for(i = 0; i < 6; i++) {
$tr = $('<tr class="week-days"></tr>');
for(var j = 0; j < 7; j++) {
$('<td class="cell-day"><div class="day"><div class="heading"><span class="month"></span> <span class="number"></span></div><div class="content"><div class="events"></div></div></div></td>').toggleClass('weekend-day', j >= 5).appendTo($tr);
}
$monthDays.append($tr);
}
$views.append($view);
that.$monthView = $view;
}
var $weeks = $view.find('.week-days'),
$days = $view.find('.day'),
firstDayOfMonth = getFirstDayOfMonth(date),
// lastDayOfMonth = getLastDayOfMonth(date),
$week,
$day,
$cell,
year,
day,
month,
today = new Date();
var firstDay = getNearbyLastWeekDay(firstDayOfMonth),
thisYear = date.getFullYear(),
thisMonth = date.getMonth(),
todayMonth = today.getMonth(),
todayYear = today.getFullYear(),
todayDate = today.getDate();
var lastDay = firstDay.clone().addDays(6 * 7).addMilliseconds(-1),
printDate = firstDay.clone().addDays(1).addMilliseconds(-1);
var events = that.getEvents(firstDay, lastDay),
calendars = that.calendars,
printDateId, isFirstDayOfWeek, $event, cal, $dayEvents;
var isEmptyWeekends = true;
$weeks.each(function(weekIdx) {
$week = $(this);
$week.find('.day').each(function(dayIndex) {
isFirstDayOfWeek = dayIndex === 0;
$day = $(this);
$cell = $day.closest('.cell-day');
year = printDate.getFullYear();
day = printDate.getDate();
month = printDate.getMonth();
printDateId = printDate.toDateString();
$day.attr('data-date', printDateId);
$day.find('.heading > .number').text(day);
$day.find('.heading > .month')
.toggle((weekIdx === 0 && dayIndex === 0) || day === 1)
.text(((month === 0 && day === 1) ? (lang.year.format(year) + ' ') : '') + lang.monthNames[month]);
$cell.toggleClass('current-month', month === thisMonth);
$cell.toggleClass('current', (day === todayDate && month === todayMonth && year === todayYear));
$cell.toggleClass('past', printDate < today);
$cell.toggleClass('future', printDate > today);
$dayEvents = $day.find('.events').empty();
var dayEvents = events[printDateId];
if(dayEvents) {
var eventsMap = dayEvents.events,
stripCount = 0,
e;
for(i = 0; i <= dayEvents.maxPos; ++i) {
e = eventsMap[i];
if(!e || (e.placeholder && !isFirstDayOfWeek)) {
stripCount++;
continue;
}
if (isEmptyWeekends && dayIndex >= 5) {
isEmptyWeekends = false;
}
$event = $('<div data-id="' + e.id + '" class="event" title="' + e.desc + '"><span class="time">' + e.start.format('hh:mm') + '</span> <span class="title">' + e.title + '</span></div>');
$event.find('.time').toggle(!e.allDay);
$event.data('event', e);
$event.attr('data-days', e.days);
if(e.calendar) {
cal = calendars[e.calendar];
if(cal) {
if(cal.presetColor) {
$event.addClass('color-' + cal.color);
} else {
$event.css({
'background-color': cal.color,
color: cal.textColor
});
}
}
}
if(e.days) {
if(!e.placeholder) {
$event.css('width', Math.min(7 - dayIndex, e.days) + '00%');
} else if(isFirstDayOfWeek) {
$event.css('width', Math.min(7, e.days - e.holderPos) + '00%');
}
}
if(stripCount > 0) {
$event.css('margin-top', stripCount * 22);
stripCount = 0;
}
$dayEvents.append($event);
}
}
printDate.addDays(1);
});
});
if (options.hideEmptyWeekends) {
$view.toggleClass('weekends-empty', isEmptyWeekends);
}
if(options.withHeader) {
that.$caption.text(lang.yearMonth.format(thisYear, thisMonth + 1, lang.monthNames[thisMonth]));
that.$todayBtn.toggleClass('disabled', thisMonth === todayMonth && thisYear === todayYear);
}
if(options.dragThenDrop) {
if(!$.fn.droppable) {
return console.error('Calendar dragThenDrop option requires droppable.js');
}
if(!$view.data('zui.droppable')) {
$view.droppable($.extend({
target: '.cell-day',
selector: '.event',
flex: true,
start: function() {
that.$.addClass('event-dragging');
},
drop: function(e) {
var et = e.element.data('event'),
newDate = e.target.children('.day').attr('data-date');
if(!et || !newDate) return;
var startDate = et.start.clone();
if(startDate.toDateString() != newDate) {
newDate = new Date(newDate);
newDate.setHours(startDate.getHours());
newDate.setMinutes(startDate.getMinutes());
newDate.setSeconds(startDate.getSeconds());
if(that.callEvent('beforeChange', {
event: et,
change: 'start',
to: newDate
})) {
var oldEnd = et.end.clone();
et.end.addMilliseconds(et.end.getTime() - startDate.getTime());
et.start = newDate;
that.display();
that.callEvent('change', {
data: that.data,
changes: [{
event: et,
changes: [{
change: 'start',
from: startDate,
to: et.start
}, {
change: 'end',
from: oldEnd,
to: et.end
}]
}]
});
}
}
},
finish: function() {
that.$.removeClass('event-dragging');
}
}, ($.isPlainObject(options.dragThenDrop)) ? options.dragThenDrop : null));
}
}
};
Calendar.prototype.getEvents = function(start, end) {
var events = {};
var calendars = this.calendars;
var addEventToDay = function(day, event, position) {
var dayId = day.toDateString();
var dayEvents = events[dayId];
if(!dayEvents) {
dayEvents = {
maxPos: -1,
events: {}
};
}
if(typeof position === 'undefined') {
for(var i = 0; i < 100; ++i) {
if(!dayEvents.events[i]) {
position = i;
break;
}
}
}
dayEvents.maxPos = Math.max(position, dayEvents.maxPos);
dayEvents.events[position] = event;
events[dayId] = dayEvents;
return position;
};
$.each(this.events, function(index, e) {
if(e.start >= start && e.start <= end) {
var position = addEventToDay(e.start, e);
if(e.days > 1) {
var placeholder = $.extend({
placeholder: true
}, e);
everyDayTo(e.start.clone().addDays(1), e.end, function(thisDay, i) {
addEventToDay(thisDay.clone(), $.extend({
holderPos: i
}, placeholder), position);
});
}
}
});
return events;
};
Calendar.prototype.callEvent = function(name, params) {
var result = this.$.callEvent(name + '.' + NAME, params, this);
return !(result.result !== undefined && (!result.result));
};
$.fn.calendar = function(option) {
return this.each(function() {
var $this = $(this);
var data = $this.data(NAME);
var options = typeof option == 'object' && option;
if(!data) $this.data(NAME, (data = new Calendar(this, options)));
if(typeof option == STRING_TYPE_NAME) data[option]();
});
};
$.fn.calendar.Constructor = Calendar;
}(jQuery, window));

View File

@@ -0,0 +1,6 @@
/*!
* ZUI: 日历 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/.calendar{margin-bottom:20px}.calendar>header{margin-bottom:10px}.calendar>header .btn-toolbar>.btn-group{margin-right:10px}.calendar>header .calendar-caption{line-height:30px}.calendar .table{margin-bottom:0;table-layout:fixed}.calendar .table>tbody>tr>td,.calendar .table>thead>tr>th{width:14.28571428571429%;padding:0}.calendar .table>thead>tr>th{color:grey;text-align:center;background-color:#fff}.calendar .weekends-empty .table>tbody>tr>td,.calendar .weekends-empty .table>thead>tr>th{width:20%}.calendar .weekends-empty .table>tbody>tr>td.weekend-day,.calendar .weekends-empty .table>thead>tr>th.weekend-head{width:40px;min-width:40px}.calendar .day{opacity:.7}.calendar .day>.heading{padding:2px 5px;text-align:right}.calendar .day>.heading>.month{padding:1px 2px;color:#fff;background-color:#b3b3b3;border-radius:3px}.calendar .day>.content{height:100%;min-height:70px}.calendar .cell-day{background-color:#f1f1f1}.calendar .cell-day.past>.day>.content{opacity:.7}.calendar .cell-day.current-month{background:0 0}.calendar .cell-day.current-month>.day{opacity:1}.calendar .cell-day.current{background-color:#fff0d5;-webkit-box-shadow:inset 1px 1px 0 grey,inset -1px -1px 0 grey;box-shadow:inset 1px 1px 0 grey,inset -1px -1px 0 grey}.calendar .cell-day.current>.day>.content{padding:0}.calendar .cell-day.current>.day>.heading{background-color:rgba(0,0,0,.1)}.calendar .cell-day.drop-to{background-color:#fff0d5;opacity:1}.calendar .event{padding:1px 5px;margin:0 1px 1px;color:#fff;cursor:pointer;background-color:#3280fc;opacity:.95;-webkit-transition:all .4s cubic-bezier(.175,.885,.32,1);-o-transition:all .4s cubic-bezier(.175,.885,.32,1);transition:all .4s cubic-bezier(.175,.885,.32,1)}a.calendar .event:hover{background-color:#0462f7}.calendar .event:hover{opacity:1}.calendar .event.drag-shadow{cursor:move}.calendar .event.drag-from{opacity:.25}.calendar .event.color-red{color:#fff;background-color:#ea644a}a.calendar .event.color-red:hover{background-color:#e53d1c}.calendar .event.color-green{color:#fff;background-color:#38b03f}a.calendar .event.color-green:hover{background-color:#2c8931}.calendar .event.color-yellow{color:#fff;background-color:#f1a325}a.calendar .event.color-yellow:hover{background-color:#d5890e}.calendar .event.color-blue{color:#fff;background-color:#03b8cf}a.calendar .event.color-blue:hover{background-color:#028b9d}.calendar .event.color-brown{color:#fff;background-color:#bd7b46}a.calendar .event.color-brown:hover{background-color:#996337}.calendar .event.color-purple{color:#fff;background-color:#8666b8}a.calendar .event.color-purple:hover{background-color:#6c4aa1}.calendar.limit-event-title .event{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

14
root/res/zui/lib/chart/zui.chart.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,436 @@
/*!
* Chosen, a Select Box Enhancer for jQuery and Prototype
* by Patrick Filler for Harvest, http://getharvest.com
*
* Copyright (c) 2011-2016 Harvest http://getharvest.com
* MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
*/
.chosen-container {
position: relative;
display: inline-block;
font-size: 13px;
vertical-align: middle;
zoom: 1;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
*display: inline;
}
.chosen-container .chosen-drop {
position: absolute;
top: 100%;
left: -9999px;
z-index: 1010;
width: 100%;
background: #fff;
border: 1px solid #cbcbcb;
border: 1px solid rgba(0, 0, 0, .15);
border-top: 0;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
}
.chosen-container .chosen-drop.chosen-drop-size-limited {
border-top: 1px solid rgba(0, 0, 0, .15);
}
.chosen-container.chosen-with-drop .chosen-drop {
left: 0;
}
.chosen-container a {
cursor: pointer;
}
.chosen-container.chosen-up .chosen-drop {
top: inherit;
bottom: 100%;
margin-top: auto;
margin-bottom: -1px;
border-radius: 2px 2px 0 0;
-webkit-box-shadow: 0 -3px 5px rgba(0, 0, 0, .175);
box-shadow: 0 -3px 5px rgba(0, 0, 0, .175);
}
.chosen-container-single .chosen-single {
display: block;
width: 100%;
height: 32px;
padding: 5px 8px;
overflow: hidden;
line-height: 1.53846154;
color: #222;
text-decoration: none;
white-space: nowrap;
vertical-align: middle;
background-color: #fff;
-webkit-background-clip: padding-box;
background-clip: padding-box;
border: 1px solid #ccc;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
}
.chosen-container-single .chosen-default {
color: #808080;
}
.chosen-container-single .chosen-single > span {
display: block;
margin-right: 26px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.chosen-container-single .chosen-single-with-deselect span {
margin-right: 38px;
}
.chosen-container-single .chosen-single abbr {
position: absolute;
top: 7px;
right: 24px;
display: block;
width: 20px;
height: 20px;
font-size: 19.5px;
font-weight: bold;
line-height: 14px;
color: #000;
text-align: center;
text-shadow: 0 1px 0 #fff;
filter: alpha(opacity=20);
opacity: .2;
}
.chosen-container-single .chosen-single abbr:before {
content: '×';
}
.chosen-container-single .chosen-single abbr:hover,
.chosen-container-single .chosen-single abbr:focus {
color: #000;
text-decoration: none;
cursor: pointer;
filter: alpha(opacity=50);
opacity: .5;
}
.chosen-container-single .chosen-single div {
position: absolute;
top: 0;
right: 0;
display: block;
height: 100%;
padding: 5px 8px;
}
.chosen-container-single .chosen-single div b {
display: inline-block;
width: 0;
height: 0;
margin-bottom: 2px;
margin-left: 2px;
vertical-align: middle;
border-top: 4px dashed;
border-top: 4px solid \9;
border-right: 4px solid transparent;
border-left: 4px solid transparent;
}
.chosen-container-single .chosen-search {
position: relative;
z-index: 1010;
padding: 3px 4px;
margin: 0;
white-space: nowrap;
}
.chosen-container-single .chosen-search input[type="text"] {
width: 100%;
height: 27px;
padding: 2px 26px 2px 8px;
margin: 1px 0;
font-size: 12px;
line-height: 1.5;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 4px;
outline: 0;
}
.chosen-container-single .chosen-search input[type="text"]:focus {
border-color: #145ccd;
}
.chosen-container-single .chosen-search:before {
position: absolute;
top: 10px;
right: 10px;
display: block;
font-family: ZenIcon;
font-size: 14px;
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
color: #808080;
text-transform: none;
content: '\e603';
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.chosen-container-single .chosen-drop {
margin-top: -1px;
-webkit-background-clip: padding-box;
background-clip: padding-box;
border-radius: 0 0 4px 4px;
}
.chosen-container-single.chosen-container-single-nosearch .chosen-search {
position: absolute;
left: -9999px;
}
.chosen-container .chosen-results {
position: relative;
max-height: 240px;
padding: 0;
margin: 0;
overflow-x: hidden;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.chosen-container .chosen-results li {
display: none;
padding: 5px 10px;
margin: 0;
line-height: 15px;
list-style: none;
-webkit-transition: background-color .2s cubic-bezier(.175, .885, .32, 1);
-o-transition: background-color .2s cubic-bezier(.175, .885, .32, 1);
transition: background-color .2s cubic-bezier(.175, .885, .32, 1);
-webkit-touch-callout: none;
}
.chosen-container .chosen-results li.active-result {
display: list-item;
cursor: pointer;
}
.chosen-container .chosen-results li.disabled-result {
display: list-item;
color: #ccc;
cursor: default;
}
.chosen-container .chosen-results li.highlighted {
color: #fff;
background-color: #3280fc;
}
.chosen-container .chosen-results li.no-results {
display: list-item;
background: #f4f4f4;
}
.chosen-container .chosen-results li.group-result {
display: list-item;
font-weight: bold;
cursor: default;
}
.chosen-container .chosen-results li.group-option {
padding-left: 15px;
}
.chosen-container .chosen-results li em {
font-style: normal;
text-decoration: underline;
}
.chosen-container-multi .chosen-choices {
position: relative;
width: 100%;
min-height: 32px;
min-height: 30px \0;
padding: 0;
margin: 0;
overflow: hidden;
cursor: text;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
}
.chosen-container-multi .chosen-choices:before,
.chosen-container-multi .chosen-choices:after {
/* 1 */
display: table;
content: " ";
/* 2 */
}
.chosen-container-multi .chosen-choices:after {
clear: both;
}
.chosen-container-multi .chosen-choices li {
display: block;
float: left;
padding: 0 6px;
margin: 5px 0 0 6px;
list-style: none;
}
.chosen-container-multi .chosen-choices li.search-field {
padding: 0;
margin-bottom: 4px;
white-space: nowrap;
}
.chosen-container-multi .chosen-choices li.search-field input[type="text"] {
height: 20px;
font-size: 100%;
color: #808080;
background: transparent !important;
border: 0 !important;
border-radius: 0;
outline: 0;
-webkit-box-shadow: none;
box-shadow: none;
}
.chosen-container-multi .chosen-choices li.search-field .default {
color: #999;
}
.chosen-container-multi .chosen-choices li.search-field:before {
position: absolute;
right: 8px;
bottom: 8px;
display: block;
font-family: ZenIcon;
font-size: 14px;
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
color: #808080;
text-transform: none;
content: '\e603';
opacity: 0;
-webkit-transition: opacity .2s cubic-bezier(.175, .885, .32, 1);
-o-transition: opacity .2s cubic-bezier(.175, .885, .32, 1);
transition: opacity .2s cubic-bezier(.175, .885, .32, 1);
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.chosen-container-multi .chosen-choices li.search-choice {
position: relative;
padding: 3px 20px 3px 5px;
line-height: 12px;
cursor: default;
background-color: #f1f1f1;
-webkit-background-clip: padding-box;
background-clip: padding-box;
border: 1px solid #ddd;
border-radius: 3px;
-webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, .05);
box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, .05);
-webkit-transition: all .4s cubic-bezier(.175, .885, .32, 1);
-o-transition: all .4s cubic-bezier(.175, .885, .32, 1);
transition: all .4s cubic-bezier(.175, .885, .32, 1);
}
.chosen-container-multi .chosen-choices li.search-choice:hover {
background-color: #fff;
border-color: #c4c4c4;
-webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, .1);
box-shadow: 0 1px 0 rgba(0, 0, 0, .1);
}
.chosen-container-multi .chosen-choices li.search-choice .search-choice-close {
position: absolute;
top: 0;
right: 0;
display: block;
width: 20px;
height: 20px;
font-size: 15.6px;
font-weight: bold;
line-height: 14px;
color: #000;
text-align: center;
text-shadow: 0 1px 0 #fff;
filter: alpha(opacity=20);
opacity: .2;
}
.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:before {
content: '×';
}
.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover,
.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
filter: alpha(opacity=50);
opacity: .5;
}
.chosen-container-multi .chosen-choices li.search-choice-disabled {
padding-right: 5px;
color: #666;
background-color: #e4e4e4;
border: 1px solid #ccc;
}
.chosen-container-multi .chosen-choices li.search-choice-focus {
background: #d4d4d4;
}
.chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close {
background-position: -42px -10px;
}
.chosen-container-multi .chosen-results {
padding: 5px 0;
margin: 0;
}
.chosen-container-multi .chosen-drop .result-selected {
display: list-item;
color: #ccc;
cursor: default;
}
.chosen-container-active .chosen-single {
border-color: #145ccd;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(20, 92, 205, .6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(20, 92, 205, .6);
}
.chosen-container-active.chosen-with-drop .chosen-single {
border: 1px solid #cbcbcb;
border: 1px solid rgba(0, 0, 0, .15);
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
}
.chosen-container-active.chosen-with-drop .chosen-single div {
background: transparent;
border-left: none;
}
.chosen-container-active.chosen-with-drop .chosen-single div b {
content: "";
border-top: 0 dotted;
border-bottom: 4px solid;
}
.chosen-container-active.chosen-with-drop.chosen-up .chosen-single {
border-top-left-radius: 0;
border-top-right-radius: 0;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
}
.chosen-container-active .chosen-choices {
border-color: #145ccd;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(20, 92, 205, .6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(20, 92, 205, .6);
}
.chosen-container-active .chosen-choices li.search-field input[type="text"] {
color: #111 !important;
}
.chosen-container-active .chosen-choices li.search-field:before {
opacity: 1;
}
.chosen-disabled {
cursor: default;
opacity: .5 !important;
}
.chosen-disabled .chosen-single {
cursor: default;
}
.chosen-disabled .chosen-choices .search-choice .search-choice-close {
cursor: default;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

11
root/res/zui/lib/chosen/chosen.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,27 @@
/*!
* ZUI: 图标选择器 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
.chosen-container.chosen-icons .chosen-results {
padding: 5px;
}
.chosen-container.chosen-icons .chosen-results li {
border-radius: 4px;
}
.chosen-container.chosen-icons .chosen-results li.group-result {
padding: 5px 0;
font-size: 12px;
color: #666;
border-radius: 0;
}
.chosen-container.chosen-icons .chosen-results li.group-option {
display: inline-block;
width: 30px;
padding: 8px;
font-size: 14px;
line-height: 14px;
text-align: center;
}

View File

@@ -0,0 +1,160 @@
/*!
* ZUI: 图标选择器 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
/* ========================================================================
* ZUI: chosen.icons.js
* http://zui.sexy
* ========================================================================
* Copyright (c) 2014 cnezsoft.com; Licensed MIT
* ======================================================================== */
+ function($) {
'use strict';
var ChosenIcons = function(element, options) {
this.$ = $(element);
this.options = this.getOptions(options);
this.lang = ChosenIcons.LANGS[this.options.lang];
this.id = 'chosen-icons-' + parseInt(Math.random() * 10000000000 + 1);
this.init();
};
ChosenIcons.DEFAULTS = {
optional: true,
lang: 'zh_cn',
icons: {
common: ['heart', 'user', 'group', 'list-ul', 'th', 'th-large', 'star', 'star-empty', 'search', 'envelope', 'dashboard', 'sitemap', 'umbrella', 'lightbulb', 'envelope-alt', 'cog', 'ok', 'remove', 'home', 'time', 'flag', 'flag-alt', 'flag-checkered', 'qrcode', 'tag', 'tags', 'book', 'bookmark', 'bookmark-empty', 'print', 'camera', 'picture', 'globe', 'map-marker', 'edit', 'edit-sign', 'play', 'stop', 'plus-sign', 'minus-sign', 'remove-sign', 'ok-sign', 'check-sign', 'question-sign', 'info-sign', 'exclamation-sign', 'plus', 'plus-sign', 'minus', 'minus-sign', 'asterisk', 'calendar', 'calendar-empty', 'comment', 'comment-alt', 'comments', 'comments-alt', 'folder-close', 'folder-open', 'folder-close-alt', 'folder-open-alt', 'thumbs-up', 'thumbs-down', 'pushpin', 'building', 'phone', 'rss', 'rss-sign', 'bullhorn', 'bell', 'bell-alt', 'certificate', 'wrench', 'tasks', 'cloud', 'beaker', 'magic', 'smile', 'frown', 'meh', 'code', 'location-arrow'],
web: ['share', 'pencil', 'trash', 'file-alt', 'file', 'file-text', 'download-alt', 'upload-alt', 'inbox', 'repeat', 'refresh', 'lock', 'check', 'check-empty', 'eye-open', 'eye-close', 'key', 'signin', 'signout', 'external-link', 'external-link-sign', 'link', 'reorder', 'quote-left', 'quote-right', 'spinner', 'reply', 'question', 'info', 'archive', 'collapse', 'collapse-top'],
editor: ['table', 'copy', 'save', 'list-ol', 'paste', 'keyboard', 'paper-clip', 'crop', 'unlink', 'sort-by-alphabet', 'sort-by-alphabet-alt', 'sort-by-attributes', 'sort-by-attributes-alt', 'sort-by-order', 'sort-by-order-alt'],
directional: ['chevron-left', 'chevron-right', 'chevron-down', 'chevron-up', 'arrow-left', 'arrow-right', 'arrow-down', 'arrow-up', 'hand-right', 'hand-left', 'hand-up', 'hand-down', 'circle-arrow-left', 'circle-arrow-right', 'circle-arrow-up', 'circle-arrow-down', 'double-angle-left', 'double-angle-right', 'double-angle-down', 'double-angle-up', 'angle-left', 'angle-right', 'angle-down', 'angle-up', 'long-arrow-left', 'long-arrow-right', 'long-arrow-down', 'long-arrow-up', 'caret-left', 'caret-right', 'caret-down', 'caret-up'],
other: ['desktop', 'laptop', 'tablet', 'mobile', 'building', 'firefox', 'ie', 'opera', 'qq', 'lemon', 'sign-blank', 'circle', 'circle-blank', 'terminal', 'html5', 'android', 'apple', 'windows', 'weibo', 'wechat', 'renren', 'bug', 'moon', 'sun']
}
};
ChosenIcons.LANGS = {};
ChosenIcons.LANGS['zh_cn'] = {
emptyIcon: '[没有图标]',
commonIcons: '常用图标',
webIcons: 'Web 图标',
editorIcons: '编辑器图标',
directionalIcons: '箭头总汇',
otherIcons: '其他图标',
};
ChosenIcons.LANGS['en'] = {
emptyIcon: '[No Icon]',
commonIcons: 'Common Icons',
webIcons: 'Web Icons',
editorIcons: 'Editor Icons',
directionalIcons: 'Directional Icons',
otherIcons: 'Other Icons'
};
ChosenIcons.LANGS['zh_tw'] = {
emptyIcon: '[沒有圖標]',
commonIcons: '常用圖標',
webIcons: 'Web 圖標',
editorIcons: '編輯器圖標',
directionalIcons: '箭頭總匯',
otherIcons: '其他圖標'
};
ChosenIcons.prototype.getOptions = function(options) {
options = $.extend(true, {
placeholder_text: ' ',
disable_search: true,
width: '100%',
inherit_select_classes: true
}, ChosenIcons.DEFAULTS, this.$.data(), options);
return options;
};
ChosenIcons.prototype.init = function() {
var that = this;
var $this = this.$.addClass('chosen-icons').addClass(this.id).removeClass('form-control');
$this.empty();
if(this.options.optional) {
$this.append(this.getOptionHtml());
}
var lang = this.lang;
var iconsHtml = [];
$.each(this.options.icons, function(name, icons) {
iconsHtml.push(that.getgroupHtml(name, icons));
});
$this.append(iconsHtml.join(''));
$this.chosen(this.options);
var chosenSelector = '.chosen-container.' + this.id;
$this.on('chosen:showing_dropdown', function() {
$(chosenSelector + ' .chosen-results .group-option').each(function() {
var $this = $(this).addClass('icon');
var text = $(this).text();
$this.html('<i class="icon-' + text + '" title="' + text + '"></i>');
});
}).change(function() {
var span = $(chosenSelector + ' .chosen-single > span');
var text = $(this).val();
if(text && text.length > 0) {
span.html('<i class="' + text + '"></i> &nbsp; <span class="text-muted">' + text.substr(5).replace(/-/g, ' ') + '</span>');
}
else {
span.html('<span class="text-muted">' + lang.emptyIcon + '</span>');
}
});
var val = $this.data('value');
if(val) {
$this.val(val).change();
}
}
ChosenIcons.prototype.getgroupHtml = function(name, icons) {
icons = icons || this.options.icons[name]
var iconsHtml = [],
that = this;
$.each(icons, function(i, icon) {
iconsHtml.push(that.getOptionHtml(icon));
});
return '<optgroup label="' + this.lang[name + 'Icons'] + '">' + iconsHtml.join('') + '</optgroup>';
}
ChosenIcons.prototype.getOptionHtml = function(value) {
var name = value;
if(value && value.length > 0) {
value = 'icon-' + value;
} else {
value = '';
name = this.lang.emptyIcon;
}
return '<option value="' + value + '">' + name + '</option>';
}
$.fn.chosenIcons = function(option) {
return this.each(function() {
var $this = $(this);
var data = $this.data('zui.chosenIcons');
var options = typeof option == 'object' && option;
if(!data) $this.data('zui.chosenIcons', (data = new ChosenIcons(this, options)));
if(typeof option == 'string') data[option]();
})
};
$.fn.chosenIcons.Constructor = ChosenIcons;
}(jQuery);

View File

@@ -0,0 +1,6 @@
/*!
* ZUI: 图标选择器 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/.chosen-container.chosen-icons .chosen-results{padding:5px}.chosen-container.chosen-icons .chosen-results li{border-radius:4px}.chosen-container.chosen-icons .chosen-results li.group-result{padding:5px 0;font-size:12px;color:#666;border-radius:0}.chosen-container.chosen-icons .chosen-results li.group-option{display:inline-block;width:30px;padding:8px;font-size:14px;line-height:14px;text-align:center}

View File

@@ -0,0 +1,7 @@
/*!
* ZUI: 图标选择器 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
+function(o){"use strict";var e=function(t,n){this.$=o(t),this.options=this.getOptions(n),this.lang=e.LANGS[this.options.lang],this.id="chosen-icons-"+parseInt(1e10*Math.random()+1),this.init()};e.DEFAULTS={optional:!0,lang:"zh_cn",icons:{common:["heart","user","group","list-ul","th","th-large","star","star-empty","search","envelope","dashboard","sitemap","umbrella","lightbulb","envelope-alt","cog","ok","remove","home","time","flag","flag-alt","flag-checkered","qrcode","tag","tags","book","bookmark","bookmark-empty","print","camera","picture","globe","map-marker","edit","edit-sign","play","stop","plus-sign","minus-sign","remove-sign","ok-sign","check-sign","question-sign","info-sign","exclamation-sign","plus","plus-sign","minus","minus-sign","asterisk","calendar","calendar-empty","comment","comment-alt","comments","comments-alt","folder-close","folder-open","folder-close-alt","folder-open-alt","thumbs-up","thumbs-down","pushpin","building","phone","rss","rss-sign","bullhorn","bell","bell-alt","certificate","wrench","tasks","cloud","beaker","magic","smile","frown","meh","code","location-arrow"],web:["share","pencil","trash","file-alt","file","file-text","download-alt","upload-alt","inbox","repeat","refresh","lock","check","check-empty","eye-open","eye-close","key","signin","signout","external-link","external-link-sign","link","reorder","quote-left","quote-right","spinner","reply","question","info","archive","collapse","collapse-top"],editor:["table","copy","save","list-ol","paste","keyboard","paper-clip","crop","unlink","sort-by-alphabet","sort-by-alphabet-alt","sort-by-attributes","sort-by-attributes-alt","sort-by-order","sort-by-order-alt"],directional:["chevron-left","chevron-right","chevron-down","chevron-up","arrow-left","arrow-right","arrow-down","arrow-up","hand-right","hand-left","hand-up","hand-down","circle-arrow-left","circle-arrow-right","circle-arrow-up","circle-arrow-down","double-angle-left","double-angle-right","double-angle-down","double-angle-up","angle-left","angle-right","angle-down","angle-up","long-arrow-left","long-arrow-right","long-arrow-down","long-arrow-up","caret-left","caret-right","caret-down","caret-up"],other:["desktop","laptop","tablet","mobile","building","firefox","ie","opera","qq","lemon","sign-blank","circle","circle-blank","terminal","html5","android","apple","windows","weibo","wechat","renren","bug","moon","sun"]}},e.LANGS={},e.LANGS.zh_cn={emptyIcon:"[没有图标]",commonIcons:"常用图标",webIcons:"Web 图标",editorIcons:"编辑器图标",directionalIcons:"箭头总汇",otherIcons:"其他图标"},e.LANGS.en={emptyIcon:"[No Icon]",commonIcons:"Common Icons",webIcons:"Web Icons",editorIcons:"Editor Icons",directionalIcons:"Directional Icons",otherIcons:"Other Icons"},e.LANGS.zh_tw={emptyIcon:"[沒有圖標]",commonIcons:"常用圖標",webIcons:"Web 圖標",editorIcons:"編輯器圖標",directionalIcons:"箭頭總匯",otherIcons:"其他圖標"},e.prototype.getOptions=function(t){return t=o.extend(!0,{placeholder_text:" ",disable_search:!0,width:"100%",inherit_select_classes:!0},e.DEFAULTS,this.$.data(),t)},e.prototype.init=function(){var e=this,t=this.$.addClass("chosen-icons").addClass(this.id).removeClass("form-control");t.empty(),this.options.optional&&t.append(this.getOptionHtml());var n=this.lang,s=[];o.each(this.options.icons,function(o,t){s.push(e.getgroupHtml(o,t))}),t.append(s.join("")),t.chosen(this.options);var i=".chosen-container."+this.id;t.on("chosen:showing_dropdown",function(){o(i+" .chosen-results .group-option").each(function(){var e=o(this).addClass("icon"),t=o(this).text();e.html('<i class="icon-'+t+'" title="'+t+'"></i>')})}).change(function(){var e=o(i+" .chosen-single > span"),t=o(this).val();t&&t.length>0?e.html('<i class="'+t+'"></i> &nbsp; <span class="text-muted">'+t.substr(5).replace(/-/g," ")+"</span>"):e.html('<span class="text-muted">'+n.emptyIcon+"</span>")});var r=t.data("value");r&&t.val(r).change()},e.prototype.getgroupHtml=function(e,t){t=t||this.options.icons[e];var n=[],s=this;return o.each(t,function(o,e){n.push(s.getOptionHtml(e))}),'<optgroup label="'+this.lang[e+"Icons"]+'">'+n.join("")+"</optgroup>"},e.prototype.getOptionHtml=function(o){var e=o;return o&&o.length>0?o="icon-"+o:(o="",e=this.lang.emptyIcon),'<option value="'+o+'">'+e+"</option>"},o.fn.chosenIcons=function(t){return this.each(function(){var n=o(this),s=n.data("zui.chosenIcons"),i="object"==typeof t&&t;s||n.data("zui.chosenIcons",s=new e(this,i)),"string"==typeof t&&s[t]()})},o.fn.chosenIcons.Constructor=e}(jQuery);

View File

@@ -0,0 +1,745 @@
/*!
* clipboard.js v1.5.5
* https://zenorocha.github.io/clipboard.js
*
* Licensed MIT © Zeno Rocha
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Clipboard = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var matches = require('matches-selector')
module.exports = function (element, selector, checkYoSelf) {
var parent = checkYoSelf ? element : element.parentNode
while (parent && parent !== document) {
if (matches(parent, selector)) return parent;
parent = parent.parentNode
}
}
},{"matches-selector":2}],2:[function(require,module,exports){
/**
* Element prototype.
*/
var proto = Element.prototype;
/**
* Vendor function.
*/
var vendor = proto.matchesSelector
|| proto.webkitMatchesSelector
|| proto.mozMatchesSelector
|| proto.msMatchesSelector
|| proto.oMatchesSelector;
/**
* Expose `match()`.
*/
module.exports = match;
/**
* Match `el` to `selector`.
*
* @param {Element} el
* @param {String} selector
* @return {Boolean}
* @api public
*/
function match(el, selector) {
if (vendor) return vendor.call(el, selector);
var nodes = el.parentNode.querySelectorAll(selector);
for (var i = 0; i < nodes.length; ++i) {
if (nodes[i] == el) return true;
}
return false;
}
},{}],3:[function(require,module,exports){
var closest = require('closest');
/**
* Delegates event to a selector.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function delegate(element, selector, type, callback) {
var listenerFn = listener.apply(this, arguments);
element.addEventListener(type, listenerFn);
return {
destroy: function() {
element.removeEventListener(type, listenerFn);
}
}
}
/**
* Finds closest match and invokes callback.
*
* @param {Element} element
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Function}
*/
function listener(element, selector, type, callback) {
return function(e) {
e.delegateTarget = closest(e.target, selector, true);
if (e.delegateTarget) {
callback.call(element, e);
}
}
}
module.exports = delegate;
},{"closest":1}],4:[function(require,module,exports){
/**
* Check if argument is a HTML element.
*
* @param {Object} value
* @return {Boolean}
*/
exports.node = function(value) {
return value !== undefined
&& value instanceof HTMLElement
&& value.nodeType === 1;
};
/**
* Check if argument is a list of HTML elements.
*
* @param {Object} value
* @return {Boolean}
*/
exports.nodeList = function(value) {
var type = Object.prototype.toString.call(value);
return value !== undefined
&& (type === '[object NodeList]' || type === '[object HTMLCollection]')
&& ('length' in value)
&& (value.length === 0 || exports.node(value[0]));
};
/**
* Check if argument is a string.
*
* @param {Object} value
* @return {Boolean}
*/
exports.string = function(value) {
return typeof value === 'string'
|| value instanceof String;
};
/**
* Check if argument is a function.
*
* @param {Object} value
* @return {Boolean}
*/
exports.function = function(value) {
var type = Object.prototype.toString.call(value);
return type === '[object Function]';
};
},{}],5:[function(require,module,exports){
var is = require('./is');
var delegate = require('delegate');
/**
* Validates all params and calls the right
* listener function based on its target type.
*
* @param {String|HTMLElement|HTMLCollection|NodeList} target
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listen(target, type, callback) {
if (!target && !type && !callback) {
throw new Error('Missing required arguments');
}
if (!is.string(type)) {
throw new TypeError('Second argument must be a String');
}
if (!is.function(callback)) {
throw new TypeError('Third argument must be a Function');
}
if (is.node(target)) {
return listenNode(target, type, callback);
}
else if (is.nodeList(target)) {
return listenNodeList(target, type, callback);
}
else if (is.string(target)) {
return listenSelector(target, type, callback);
}
else {
throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');
}
}
/**
* Adds an event listener to a HTML element
* and returns a remove listener function.
*
* @param {HTMLElement} node
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenNode(node, type, callback) {
node.addEventListener(type, callback);
return {
destroy: function() {
node.removeEventListener(type, callback);
}
}
}
/**
* Add an event listener to a list of HTML elements
* and returns a remove listener function.
*
* @param {NodeList|HTMLCollection} nodeList
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenNodeList(nodeList, type, callback) {
Array.prototype.forEach.call(nodeList, function(node) {
node.addEventListener(type, callback);
});
return {
destroy: function() {
Array.prototype.forEach.call(nodeList, function(node) {
node.removeEventListener(type, callback);
});
}
}
}
/**
* Add an event listener to a selector
* and returns a remove listener function.
*
* @param {String} selector
* @param {String} type
* @param {Function} callback
* @return {Object}
*/
function listenSelector(selector, type, callback) {
return delegate(document.body, selector, type, callback);
}
module.exports = listen;
},{"./is":4,"delegate":3}],6:[function(require,module,exports){
function select(element) {
var selectedText;
if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
element.focus();
element.setSelectionRange(0, element.value.length);
selectedText = element.value;
}
else {
if (element.hasAttribute('contenteditable')) {
element.focus();
}
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
selectedText = selection.toString();
}
return selectedText;
}
module.exports = select;
},{}],7:[function(require,module,exports){
function E () {
// Keep this empty so it's easier to inherit from
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
}
E.prototype = {
on: function (name, callback, ctx) {
var e = this.e || (this.e = {});
(e[name] || (e[name] = [])).push({
fn: callback,
ctx: ctx
});
return this;
},
once: function (name, callback, ctx) {
var self = this;
function listener () {
self.off(name, listener);
callback.apply(ctx, arguments);
};
listener._ = callback
return this.on(name, listener, ctx);
},
emit: function (name) {
var data = [].slice.call(arguments, 1);
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
var i = 0;
var len = evtArr.length;
for (i; i < len; i++) {
evtArr[i].fn.apply(evtArr[i].ctx, data);
}
return this;
},
off: function (name, callback) {
var e = this.e || (this.e = {});
var evts = e[name];
var liveEvents = [];
if (evts && callback) {
for (var i = 0, len = evts.length; i < len; i++) {
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
liveEvents.push(evts[i]);
}
}
// Remove event from queue to prevent memory leak
// Suggested by https://github.com/lazd
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
(liveEvents.length)
? e[name] = liveEvents
: delete e[name];
return this;
}
};
module.exports = E;
},{}],8:[function(require,module,exports){
'use strict';
exports.__esModule = true;
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _select = require('select');
var _select2 = _interopRequireDefault(_select);
/**
* Inner class which performs selection from either `text` or `target`
* properties and then executes copy or cut operations.
*/
var ClipboardAction = (function () {
/**
* @param {Object} options
*/
function ClipboardAction(options) {
_classCallCheck(this, ClipboardAction);
this.resolveOptions(options);
this.initSelection();
}
/**
* Defines base properties passed from constructor.
* @param {Object} options
*/
ClipboardAction.prototype.resolveOptions = function resolveOptions() {
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
this.action = options.action;
this.emitter = options.emitter;
this.target = options.target;
this.text = options.text;
this.trigger = options.trigger;
this.selectedText = '';
};
/**
* Decides which selection strategy is going to be applied based
* on the existence of `text` and `target` properties.
*/
ClipboardAction.prototype.initSelection = function initSelection() {
if (this.text && this.target) {
throw new Error('Multiple attributes declared, use either "target" or "text"');
} else if (this.text) {
this.selectFake();
} else if (this.target) {
this.selectTarget();
} else {
throw new Error('Missing required attributes, use either "target" or "text"');
}
};
/**
* Creates a fake textarea element, sets its value from `text` property,
* and makes a selection on it.
*/
ClipboardAction.prototype.selectFake = function selectFake() {
var _this = this;
this.removeFake();
this.fakeHandler = document.body.addEventListener('click', function () {
return _this.removeFake();
});
this.fakeElem = document.createElement('textarea');
this.fakeElem.style.position = 'absolute';
this.fakeElem.style.left = '-9999px';
this.fakeElem.style.top = (window.pageYOffset || document.documentElement.scrollTop) + 'px';
this.fakeElem.setAttribute('readonly', '');
this.fakeElem.value = this.text;
document.body.appendChild(this.fakeElem);
this.selectedText = _select2['default'](this.fakeElem);
this.copyText();
};
/**
* Only removes the fake element after another click event, that way
* a user can hit `Ctrl+C` to copy because selection still exists.
*/
ClipboardAction.prototype.removeFake = function removeFake() {
if (this.fakeHandler) {
document.body.removeEventListener('click');
this.fakeHandler = null;
}
if (this.fakeElem) {
document.body.removeChild(this.fakeElem);
this.fakeElem = null;
}
};
/**
* Selects the content from element passed on `target` property.
*/
ClipboardAction.prototype.selectTarget = function selectTarget() {
this.selectedText = _select2['default'](this.target);
this.copyText();
};
/**
* Executes the copy operation based on the current selection.
*/
ClipboardAction.prototype.copyText = function copyText() {
var succeeded = undefined;
try {
succeeded = document.execCommand(this.action);
} catch (err) {
succeeded = false;
}
this.handleResult(succeeded);
};
/**
* Fires an event based on the copy operation result.
* @param {Boolean} succeeded
*/
ClipboardAction.prototype.handleResult = function handleResult(succeeded) {
if (succeeded) {
this.emitter.emit('success', {
action: this.action,
text: this.selectedText,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
});
} else {
this.emitter.emit('error', {
action: this.action,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
});
}
};
/**
* Removes current selection and focus from `target` element.
*/
ClipboardAction.prototype.clearSelection = function clearSelection() {
if (this.target) {
this.target.blur();
}
window.getSelection().removeAllRanges();
};
/**
* Sets the `action` to be performed which can be either 'copy' or 'cut'.
* @param {String} action
*/
/**
* Destroy lifecycle.
*/
ClipboardAction.prototype.destroy = function destroy() {
this.removeFake();
};
_createClass(ClipboardAction, [{
key: 'action',
set: function set() {
var action = arguments.length <= 0 || arguments[0] === undefined ? 'copy' : arguments[0];
this._action = action;
if (this._action !== 'copy' && this._action !== 'cut') {
throw new Error('Invalid "action" value, use either "copy" or "cut"');
}
},
/**
* Gets the `action` property.
* @return {String}
*/
get: function get() {
return this._action;
}
/**
* Sets the `target` property using an element
* that will be have its content copied.
* @param {Element} target
*/
}, {
key: 'target',
set: function set(target) {
if (target !== undefined) {
if (target && typeof target === 'object' && target.nodeType === 1) {
this._target = target;
} else {
throw new Error('Invalid "target" value, use a valid Element');
}
}
},
/**
* Gets the `target` property.
* @return {String|HTMLElement}
*/
get: function get() {
return this._target;
}
}]);
return ClipboardAction;
})();
exports['default'] = ClipboardAction;
module.exports = exports['default'];
},{"select":6}],9:[function(require,module,exports){
'use strict';
exports.__esModule = true;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _clipboardAction = require('./clipboard-action');
var _clipboardAction2 = _interopRequireDefault(_clipboardAction);
var _tinyEmitter = require('tiny-emitter');
var _tinyEmitter2 = _interopRequireDefault(_tinyEmitter);
var _goodListener = require('good-listener');
var _goodListener2 = _interopRequireDefault(_goodListener);
/**
* Base class which takes one or more elements, adds event listeners to them,
* and instantiates a new `ClipboardAction` on each click.
*/
var Clipboard = (function (_Emitter) {
_inherits(Clipboard, _Emitter);
/**
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
* @param {Object} options
*/
function Clipboard(trigger, options) {
_classCallCheck(this, Clipboard);
_Emitter.call(this);
this.resolveOptions(options);
this.listenClick(trigger);
}
/**
* Helper function to retrieve attribute value.
* @param {String} suffix
* @param {Element} element
*/
/**
* Defines if attributes would be resolved using internal setter functions
* or custom functions that were passed in the constructor.
* @param {Object} options
*/
Clipboard.prototype.resolveOptions = function resolveOptions() {
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
this.action = typeof options.action === 'function' ? options.action : this.defaultAction;
this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;
this.text = typeof options.text === 'function' ? options.text : this.defaultText;
};
/**
* Adds a click event listener to the passed trigger.
* @param {String|HTMLElement|HTMLCollection|NodeList} trigger
*/
Clipboard.prototype.listenClick = function listenClick(trigger) {
var _this = this;
this.listener = _goodListener2['default'](trigger, 'click', function (e) {
return _this.onClick(e);
});
};
/**
* Defines a new `ClipboardAction` on each click event.
* @param {Event} e
*/
Clipboard.prototype.onClick = function onClick(e) {
var trigger = e.delegateTarget || e.currentTarget;
if (this.clipboardAction) {
this.clipboardAction = null;
}
this.clipboardAction = new _clipboardAction2['default']({
action: this.action(trigger),
target: this.target(trigger),
text: this.text(trigger),
trigger: trigger,
emitter: this
});
};
/**
* Default `action` lookup function.
* @param {Element} trigger
*/
Clipboard.prototype.defaultAction = function defaultAction(trigger) {
return getAttributeValue('action', trigger);
};
/**
* Default `target` lookup function.
* @param {Element} trigger
*/
Clipboard.prototype.defaultTarget = function defaultTarget(trigger) {
var selector = getAttributeValue('target', trigger);
if (selector) {
return document.querySelector(selector);
}
};
/**
* Default `text` lookup function.
* @param {Element} trigger
*/
Clipboard.prototype.defaultText = function defaultText(trigger) {
return getAttributeValue('text', trigger);
};
/**
* Destroy lifecycle.
*/
Clipboard.prototype.destroy = function destroy() {
this.listener.destroy();
if (this.clipboardAction) {
this.clipboardAction.destroy();
this.clipboardAction = null;
}
};
return Clipboard;
})(_tinyEmitter2['default']);
function getAttributeValue(suffix, element) {
var attribute = 'data-clipboard-' + suffix;
if (!element.hasAttribute(attribute)) {
return;
}
return element.getAttribute(attribute);
}
exports['default'] = Clipboard;
module.exports = exports['default'];
},{"./clipboard-action":8,"good-listener":5,"tiny-emitter":7}]},{},[9])(9)
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,71 @@
/*!
* ZUI: 颜色选择器 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
.colorpicker .dropdown-menu {
min-width: 0;
padding: 2px;
}
.colorpicker .dropdown-menu > li {
display: block;
float: left;
padding: 2px;
}
.colorpicker .dropdown-menu > li > a {
position: relative;
display: block;
width: 100%;
height: 100%;
padding: 0;
font-family: ZenIcon;
font-size: 14px;
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
text-align: center;
text-transform: none;
border: 1px solid transparent;
border-radius: 4px;
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.colorpicker .dropdown-menu > li > a:before {
position: absolute;
top: 50%;
display: block;
width: 100%;
height: 20px;
margin-top: -8px;
}
.colorpicker .dropdown-menu > li > a:hover {
border-color: #333;
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
}
.colorpicker .dropdown-menu > li > a.active:before {
content: '\e60d';
}
.colorpicker .dropdown-menu > li > a.empty {
color: #666;
background: #f2f2f2;
}
.colorpicker .dropdown-menu > li > a.empty:before {
content: '\d7';
}
.colorpicker .btn {
text-shadow: none;
}
.colorpicker .btn .cp-title {
display: inline-block;
margin-right: 5px;
}
.colorpicker.btn-wrapper {
position: relative;
display: inline-block;
}

View File

@@ -0,0 +1,230 @@
/*!
* ZUI: 颜色选择器 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
/* ========================================================================
* ZUI: ColorPicker.js [1.5.0+]
* http://zui.sexy
* ========================================================================
* Copyright (c) 2016 cnezsoft.com; Licensed MIT
* ======================================================================== */
(function($) {
'use strict';
var name = 'zui.colorPicker'; // modal name
var TEAMPLATE = '<div class="colorpicker"><button type="button" class="btn dropdown-toggle" data-toggle="dropdown"><span class="cp-title"></span><i class="ic"></i></button><ul class="dropdown-menu clearfix"></ul></div>';
var LANG = {
zh_cn: {
errorTip: "不是有效的颜色值"
},
zh_tw: {
errorTip: "不是有效的顏色值"
},
en: {
errorTip: "Not a valid color value"
}
};
// The ColorPicker modal class
var ColorPicker = function(element, options) {
this.name = name;
this.$ = $(element);
this.getOptions(options);
this.init();
};
// default options
ColorPicker.DEFAULTS = {
colors: ['#00BCD4', '#388E3C', '#3280fc', '#3F51B5', '#9C27B0', '#795548', '#F57C00', '#F44336', '#E91E63'],
pullMenuRight: true,
wrapper: 'btn-wrapper',
tileSize: 30,
lineCount: 5,
optional: true,
tooltip: 'top',
icon: 'caret-down',
// btnTip: 'Tool tip in button'
};
ColorPicker.prototype.init = function() {
var options = this.options,
that = this;
this.$picker = $(TEAMPLATE).addClass(options.wrapper);
this.$picker.find('.cp-title').toggle(options.title !== undefined).text(options.title);
this.$menu = this.$picker.find('.dropdown-menu').toggleClass('pull-right', options.pullMenuRight);
this.$btn = this.$picker.find('.btn.dropdown-toggle');
this.$btn.find('.ic').addClass('icon-' + options.icon);
if(options.btnTip) {
this.$picker.attr('data-toggle', 'tooltip').tooltip({title: options.btnTip, placement: options.tooltip, container: 'body'});
}
this.$.attr('data-provide', null).after(this.$picker);
// init colors
this.colors = {};
$.each(this.options.colors, function(idx, rawColor) {
if($.zui.Color.isColor(rawColor)) {
var color = new $.zui.Color(rawColor);
that.colors[color.toCssStr()] = color;
}
});
this.updateColors();
var that = this;
this.$picker.on('click', '.cp-tile', function() {
that.setValue($(this).data('color'));
});
var $input = this.$;
var setInputColor = function() {
var val = $input.val();
var isColor = $.zui.Color.isColor(val);
$input.parent().toggleClass('has-error', !isColor && !(options.optional && val === ''));
if(isColor) {
that.setValue(val, true);
} else {
if(options.optional && val === '') {
$input.tooltip('hide');
} else if(!$input.is(':focus')) {
$input.tooltip('show', options.errorTip);
}
}
}
if($input.is('input:not([type=hidden])')) {
if(options.tooltip) {
$input.attr('data-toggle', 'tooltip').tooltip({trigger: 'manual', placement: options.tooltip, tipClass: 'tooltip-danger', container: 'body'});
}
$input.on('keyup paste input change', setInputColor);
} else {
$input.appendTo(this.$picker);
}
setInputColor();
};
ColorPicker.prototype.addColor = function(color) {
if(!(color instanceof $.zui.Color)) {
color = new $.zui.Color(color);
}
var hex = color.toCssStr(),
options = this.options;
if(!this.colors[hex]) {
this.colors[hex] = color;
}
var $a = $('<a href="###" class="cp-tile"></a>', {
titile: color
}).data('color', color).css({
'color': color.contrast().toCssStr(),
'background': hex,
'border-color': color.luma() > 0.43 ? '#ccc' : 'transparent'
}).attr('data-color', hex);
this.$menu.append($('<li/>').css({width: options.tileSize, height: options.tileSize}).append($a));
if(options.optional) {
this.$menu.find('.cp-tile.empty').parent().detach().appendTo(this.$menu);
}
};
ColorPicker.prototype.updateColors = function(colors) {
var $picker = this.$picker,
$menu = this.$menu.empty(),
options = this.options,
colors = colors || this.colors,
that = this;
var bestLineCount = 0;
$.each(colors, function(idx, color) {
that.addColor(color);
bestLineCount++;
});
if(options.optional) {
var $li = $('<li><a class="cp-tile empty" href="###"></a></li>').css({width: options.tileSize, height: options.tileSize});
this.$menu.append($li);
bestLineCount++;
}
$menu.css('width', Math.min(bestLineCount, options.lineCount) * options.tileSize + 6);
};
ColorPicker.prototype.setValue = function(color, notSetInput) {
var options = this.options;
this.$menu.find('.cp-tile.active').removeClass('active');
var hex = '';
if(color) {
var c = new $.zui.Color(color);
hex = c.toCssStr().toLowerCase();
this.$btn.css({
background: hex,
color: c.contrast().toCssStr(),
borderColor: c.luma() > 0.43 ? '#ccc' : hex
});
if(!this.colors[hex]) {
this.addColor(c);
}
if(!notSetInput && this.$.val().toLowerCase() !== hex) {
this.$.val(hex).trigger('change');
}
this.$menu.find('.cp-tile[data-color="' + hex + '"]').addClass('active');
this.$.tooltip('hide');
this.$.trigger('colorchange', c);
} else {
this.$btn.attr('style', null);
if(!notSetInput && this.$.val() !== '') {
this.$.val(hex).trigger('change');
}
if(options.optional) {
this.$.tooltip('hide');
}
this.$menu.find('.cp-tile.empty').addClass('active');
this.$.trigger('colorchange', null);
}
if(options.updateBorder) {
$(options.updateBorder).css('border-color', hex);
}
if(options.updateBackground) {
$(options.updateBackground).css('background-color', hex);
}
if(options.updateColor) {
$(options.updateText).css('color', hex);
}
if(options.updateText) {
$(options.updateText).text(hex);
}
};
// Get and init options
ColorPicker.prototype.getOptions = function(options) {
var thisOptions = $.extend({}, ColorPicker.DEFAULTS, this.$.data(), options);
if(typeof thisOptions.colors === 'string') thisOptions.colors = thisOptions.colors.split(',');
var lang = (thisOptions.lang || $.zui.clientLang()).toLowerCase();
if(!thisOptions.errorTip) {
thisOptions.errorTip = LANG[lang].errorTip;
}
if(!$.fn.tooltip) thisOptions.btnTip = false;
this.options = thisOptions;
};
// Extense jquery element
$.fn.colorPicker = function(option) {
return this.each(function() {
var $this = $(this);
var data = $this.data(name);
var options = typeof option == 'object' && option;
if(!data) $this.data(name, (data = new ColorPicker(this, options)));
if(typeof option == 'string') data[option]();
});
};
$.fn.colorPicker.Constructor = ColorPicker;
// Auto call colorPicker after document load complete
$(function() {
$('[data-provide="colorpicker"]').colorPicker();
});
}(jQuery));

View File

@@ -0,0 +1,6 @@
/*!
* ZUI: 颜色选择器 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/.colorpicker .dropdown-menu{min-width:0;padding:2px}.colorpicker .dropdown-menu>li{display:block;float:left;padding:2px}.colorpicker .dropdown-menu>li>a{position:relative;display:block;width:100%;height:100%;padding:0;font-family:ZenIcon;font-size:14px;font-style:normal;font-weight:400;font-variant:normal;line-height:1;text-align:center;text-transform:none;border:1px solid transparent;border-radius:4px;speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.colorpicker .dropdown-menu>li>a:before{position:absolute;top:50%;display:block;width:100%;height:20px;margin-top:-8px}.colorpicker .dropdown-menu>li>a:hover{border-color:#333;-webkit-box-shadow:0 1px 4px rgba(0,0,0,.25);box-shadow:0 1px 4px rgba(0,0,0,.25)}.colorpicker .dropdown-menu>li>a.active:before{content:'\e60d'}.colorpicker .dropdown-menu>li>a.empty{color:#666;background:#f2f2f2}.colorpicker .dropdown-menu>li>a.empty:before{content:'\d7'}.colorpicker .btn{text-shadow:none}.colorpicker .btn .cp-title{display:inline-block;margin-right:5px}.colorpicker.btn-wrapper{position:relative;display:inline-block}

View File

@@ -0,0 +1,7 @@
/*!
* ZUI: 颜色选择器 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
!function(t){"use strict";var o="zui.colorPicker",i='<div class="colorpicker"><button type="button" class="btn dropdown-toggle" data-toggle="dropdown"><span class="cp-title"></span><i class="ic"></i></button><ul class="dropdown-menu clearfix"></ul></div>',e={zh_cn:{errorTip:"不是有效的颜色值"},zh_tw:{errorTip:"不是有效的顏色值"},en:{errorTip:"Not a valid color value"}},r=function(i,e){this.name=o,this.$=t(i),this.getOptions(e),this.init()};r.DEFAULTS={colors:["#00BCD4","#388E3C","#3280fc","#3F51B5","#9C27B0","#795548","#F57C00","#F44336","#E91E63"],pullMenuRight:!0,wrapper:"btn-wrapper",tileSize:30,lineCount:5,optional:!0,tooltip:"top",icon:"caret-down"},r.prototype.init=function(){var o=this.options,e=this;this.$picker=t(i).addClass(o.wrapper),this.$picker.find(".cp-title").toggle(void 0!==o.title).text(o.title),this.$menu=this.$picker.find(".dropdown-menu").toggleClass("pull-right",o.pullMenuRight),this.$btn=this.$picker.find(".btn.dropdown-toggle"),this.$btn.find(".ic").addClass("icon-"+o.icon),o.btnTip&&this.$picker.attr("data-toggle","tooltip").tooltip({title:o.btnTip,placement:o.tooltip,container:"body"}),this.$.attr("data-provide",null).after(this.$picker),this.colors={},t.each(this.options.colors,function(o,i){if(t.zui.Color.isColor(i)){var r=new t.zui.Color(i);e.colors[r.toCssStr()]=r}}),this.updateColors();var e=this;this.$picker.on("click",".cp-tile",function(){e.setValue(t(this).data("color"))});var r=this.$,s=function(){var i=r.val(),s=t.zui.Color.isColor(i);r.parent().toggleClass("has-error",!(s||o.optional&&""===i)),s?e.setValue(i,!0):o.optional&&""===i?r.tooltip("hide"):r.is(":focus")||r.tooltip("show",o.errorTip)};r.is("input:not([type=hidden])")?(o.tooltip&&r.attr("data-toggle","tooltip").tooltip({trigger:"manual",placement:o.tooltip,tipClass:"tooltip-danger",container:"body"}),r.on("keyup paste input change",s)):r.appendTo(this.$picker),s()},r.prototype.addColor=function(o){o instanceof t.zui.Color||(o=new t.zui.Color(o));var i=o.toCssStr(),e=this.options;this.colors[i]||(this.colors[i]=o);var r=t('<a href="###" class="cp-tile"></a>',{titile:o}).data("color",o).css({color:o.contrast().toCssStr(),background:i,"border-color":o.luma()>.43?"#ccc":"transparent"}).attr("data-color",i);this.$menu.append(t("<li/>").css({width:e.tileSize,height:e.tileSize}).append(r)),e.optional&&this.$menu.find(".cp-tile.empty").parent().detach().appendTo(this.$menu)},r.prototype.updateColors=function(o){var i=(this.$picker,this.$menu.empty()),e=this.options,o=o||this.colors,r=this,s=0;if(t.each(o,function(t,o){r.addColor(o),s++}),e.optional){var a=t('<li><a class="cp-tile empty" href="###"></a></li>').css({width:e.tileSize,height:e.tileSize});this.$menu.append(a),s++}i.css("width",Math.min(s,e.lineCount)*e.tileSize+6)},r.prototype.setValue=function(o,i){var e=this.options;this.$menu.find(".cp-tile.active").removeClass("active");var r="";if(o){var s=new t.zui.Color(o);r=s.toCssStr().toLowerCase(),this.$btn.css({background:r,color:s.contrast().toCssStr(),borderColor:s.luma()>.43?"#ccc":r}),this.colors[r]||this.addColor(s),i||this.$.val().toLowerCase()===r||this.$.val(r).trigger("change"),this.$menu.find('.cp-tile[data-color="'+r+'"]').addClass("active"),this.$.tooltip("hide"),this.$.trigger("colorchange",s)}else this.$btn.attr("style",null),i||""===this.$.val()||this.$.val(r).trigger("change"),e.optional&&this.$.tooltip("hide"),this.$menu.find(".cp-tile.empty").addClass("active"),this.$.trigger("colorchange",null);e.updateBorder&&t(e.updateBorder).css("border-color",r),e.updateBackground&&t(e.updateBackground).css("background-color",r),e.updateColor&&t(e.updateText).css("color",r),e.updateText&&t(e.updateText).text(r)},r.prototype.getOptions=function(o){var i=t.extend({},r.DEFAULTS,this.$.data(),o);"string"==typeof i.colors&&(i.colors=i.colors.split(","));var s=(i.lang||t.zui.clientLang()).toLowerCase();i.errorTip||(i.errorTip=e[s].errorTip),t.fn.tooltip||(i.btnTip=!1),this.options=i},t.fn.colorPicker=function(i){return this.each(function(){var e=t(this),s=e.data(o),a="object"==typeof i&&i;s||e.data(o,s=new r(this,a)),"string"==typeof i&&s[i]()})},t.fn.colorPicker.Constructor=r,t(function(){t('[data-provide="colorpicker"]').colorPicker()})}(jQuery);

View File

@@ -0,0 +1,72 @@
/*!
* ZUI: JS配色表 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
/*!
* ZUI: Generated from less code - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
(function($) {
'use strict';
var nextColorIndex = 0;
var presetColors = ['primary', 'red', 'yellow', 'green', 'blue', 'purple', 'brown', 'dark'];
var colorset = {
primary: '#3280fc',
secondary: '#145ccd',
pale: '#ebf2f9',
fore: '#353535',
back: '#fff',
grayDarker: '#222222',
grayDark: '#333333',
gray: '#808080',
grayLight: '#dddddd',
grayLighter: '#e5e5e5',
grayPale: '#f1f1f1',
white: '#fff',
black: '#000',
red: '#ea644a',
yellow: '#f1a325',
green: '#38b03f',
blue: '#03b8cf',
purple: '#8666b8',
brown: '#bd7b46',
greenPale: '#ddf4df',
yellowPale: '#fff0d5',
redPale: '#ffe5e0',
bluePale: '#ddf3f5',
brownPale: '#f7ebe1',
purplePale: '#f5eeff',
light: '#fff',
dark: '#353535',
success: '#38b03f',
warning: '#f1a325',
danger: '#ea644a',
info: '#03b8cf',
important: '#bd7b46',
special: '#8666b8',
successPale: '#ddf4df',
warningPale: '#fff0d5',
dangerPale: '#ffe5e0',
infoPale: '#ddf3f5',
importantPale: '#f7ebe1',
specialPale: '#f5eeff'
};
colorset.get = function(colorName) {
if(typeof colorName === 'undefined' || colorName === 'random') {
colorName = presetColors[(nextColorIndex++) % presetColors.length];
}
var color = colorset[colorName] ? colorset[colorName] : colorName;
return $.zui.Color ? new $.zui.Color(color) : color;
}
$.zui({colorset: colorset});
if($.zui.Color) $.extend($.zui.Color, colorset);
}(jQuery));

View File

@@ -0,0 +1,13 @@
/*!
* ZUI: JS配色表 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
/*!
* ZUI: Generated from less code - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
!function(e){"use strict";var f=0,r=["primary","red","yellow","green","blue","purple","brown","dark"],a={primary:"#3280fc",secondary:"#145ccd",pale:"#ebf2f9",fore:"#353535",back:"#fff",grayDarker:"#222222",grayDark:"#333333",gray:"#808080",grayLight:"#dddddd",grayLighter:"#e5e5e5",grayPale:"#f1f1f1",white:"#fff",black:"#000",red:"#ea644a",yellow:"#f1a325",green:"#38b03f",blue:"#03b8cf",purple:"#8666b8",brown:"#bd7b46",greenPale:"#ddf4df",yellowPale:"#fff0d5",redPale:"#ffe5e0",bluePale:"#ddf3f5",brownPale:"#f7ebe1",purplePale:"#f5eeff",light:"#fff",dark:"#353535",success:"#38b03f",warning:"#f1a325",danger:"#ea644a",info:"#03b8cf",important:"#bd7b46",special:"#8666b8",successPale:"#ddf4df",warningPale:"#fff0d5",dangerPale:"#ffe5e0",infoPale:"#ddf3f5",importantPale:"#f7ebe1",specialPale:"#f5eeff"};a.get=function(l){"undefined"!=typeof l&&"random"!==l||(l=r[f++%r.length]);var d=a[l]?a[l]:l;return e.zui.Color?new e.zui.Color(d):d},e.zui({colorset:a}),e.zui.Color&&e.extend(e.zui.Color,a)}(jQuery);

View File

@@ -0,0 +1,288 @@
/*!
* ZUI: 仪表盘 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
.dashboard {
position: relative;
}
.dashboard .panel {
position: relative;
}
.dashboard .panel-actions {
position: absolute;
top: 0;
right: 0;
}
.dashboard .panel-actions .dropdown-menu {
min-width: 80px;
}
.dashboard .panel-actions .dropdown-menu > li > a {
padding: 3px 10px;
}
.dashboard .panel-actions > a,
.dashboard .panel-actions > .dropdown > a {
color: #808080;
text-decoration: none !important;
}
.dashboard .panel-actions > a,
.dashboard .panel-actions > .btn,
.dashboard .panel-actions > .dropdown {
display: block;
float: left;
}
.dashboard .panel-actions > a,
.dashboard .panel-actions > .btn,
.dashboard .panel-actions > .dropdown > a,
.dashboard .panel-actions > .dropdown > .btn {
display: block;
min-width: 28px;
height: 31px;
padding: 0 3px;
line-height: 30px;
text-align: center;
filter: alpha(opacity=70);
border: none;
border-radius: 0;
opacity: .7;
}
.dashboard .panel-actions > a:hover,
.dashboard .panel-actions > .dropdown > a:hover {
background-color: rgba(0, 0, 0, .1);
}
.dashboard .panel-heading {
height: 32px;
padding: 6px 60px 6px 6px;
font-weight: bold;
text-overflow: ellipsis;
white-space: nowrap;
}
.dashboard .panel-heading > .icon {
filter: alpha(opacity=70);
opacity: .7;
}
.dashboard .panel-heading:hover > .panel-actions > .btn,
.dashboard .panel-heading:hover > .panel-actions > .dropdown > .btn,
.dashboard .panel-heading:hover > .panel-actions > .dropdown > a,
.dashboard .panel-heading:hover > .panel-actions > a {
filter: alpha(opacity=100);
opacity: 1;
}
.dashboard .panel-body {
position: absolute;
top: 32px;
right: 0;
bottom: 0;
left: 0;
padding: 10px;
overflow: auto;
}
.dashboard .panel-body.no-padding {
padding: 0;
}
.dashboard .panel-body > :last-child {
margin: 0;
}
.dashboard .panel-body > .list-group .list-group-item {
border-right: none;
border-left: none;
border-radius: 0;
}
.dashboard .panel-body > .list-group .list-group-item:first-child {
border-top: none;
}
.dashboard.dashboard-draggable .panel-heading {
cursor: move;
}
.dashboard .panel-dragging {
color: #fff;
background: rgba(0, 0, 0, .1);
border: 1px solid #fff;
-webkit-box-shadow: none!important;
box-shadow: none!important;
}
.dashboard .panel-dragging > * {
filter: alpha(opacity=10);
opacity: .1;
}
.dashboard .panel-dragging-shadow {
position: absolute;
cursor: move;
background: rgba(255, 255, 255, .5);
border: 2px solid rgba(255, 255, 255, .9);
-webkit-box-shadow: 1px 5px 15px rgba(0, 0, 0, .5) !important;
box-shadow: 1px 5px 15px rgba(0, 0, 0, .5) !important;
}
.dashboard .panel-dragging-shadow > * {
filter: alpha(opacity=70);
opacity: .7;
}
.dashboard .panel-dragging-shadow.circle {
overflow: hidden;
border-radius: 50%;
-webkit-transition: width .2s, height .2s;
-o-transition: width .2s, height .2s;
transition: width .2s, height .2s;
}
.dashboard .panel-dragging-shadow.circle .panel-actions {
display: none;
}
.dashboard .dragging-col-holder {
display: none;
}
.dashboard.dashboard-holding .dragging-col-holder {
display: block;
}
.dashboard.dashboard-holding .dragging-col {
display: none;
}
.dashboard .resize-handle {
position: absolute;
top: 0;
right: 4px;
bottom: 20px;
width: 12px;
cursor: e-resize;
filter: alpha(opacity=0);
border-radius: 4px;
opacity: 0;
-webkit-transition: opacity .4s cubic-bezier(.175, .885, .32, 1);
-o-transition: opacity .4s cubic-bezier(.175, .885, .32, 1);
transition: opacity .4s cubic-bezier(.175, .885, .32, 1);
}
.dashboard .resize-handle > .icon {
position: absolute;
top: 50%;
left: 0;
display: block;
width: 20px;
height: 20px;
margin-top: -10px;
line-height: 20px;
color: #3280fc;
text-align: center;
background-color: rgba(50, 128, 252, .2);
-webkit-transition: left .4s cubic-bezier(.175, .885, .32, 1), top .4s cubic-bezier(.175, .885, .32, 1);
-o-transition: left .4s cubic-bezier(.175, .885, .32, 1), top .4s cubic-bezier(.175, .885, .32, 1);
transition: left .4s cubic-bezier(.175, .885, .32, 1), top .4s cubic-bezier(.175, .885, .32, 1);
}
.dashboard .resize-handle:hover {
background-color: rgba(50, 128, 252, .12);
filter: alpha(opacity=100);
opacity: 1;
}
.dashboard .resize-handle:hover > .icon {
left: -4px;
}
.dashboard .resize-handle.resize-vertical {
top: auto;
right: 10px;
bottom: 14px;
left: 10px;
width: auto;
height: 12px;
cursor: n-resize;
}
.dashboard .resize-handle.resize-vertical > .icon {
top: 0;
left: 50%;
margin-top: 0;
margin-left: -10px;
}
.dashboard .resize-handle.resize-vertical:hover {
background-color: rgba(50, 128, 252, .12);
filter: alpha(opacity=100);
opacity: 1;
}
.dashboard .resize-handle.resize-vertical:hover > .icon {
top: -4px;
}
.dashboard .resizing {
-webkit-transition: width .2s cubic-bezier(.175, .885, .32, 1);
-o-transition: width .2s cubic-bezier(.175, .885, .32, 1);
transition: width .2s cubic-bezier(.175, .885, .32, 1);
}
.dashboard .resizing-v .resize-vertical {
opacity: 1;
}
.dashboard .resizing-v .resize-vertical > .icon {
top: -4px;
}
.dashboard .resizing-h .resize-horizontal {
opacity: 1;
}
.dashboard .resizing-h .resize-horizontal > .icon {
left: -4px;
}
.dashboard .resizing .resize-handle {
background-color: rgba(50, 128, 252, .12);
}
.dashboard .panel-body:after,
.dashboard .panel-body:before {
display: block;
visibility: hidden;
content: ' ';
opacity: 0;
-webkit-transition: visibility .2s, opacity .2s;
-o-transition: visibility .2s, opacity .2s;
transition: visibility .2s, opacity .2s;
}
.dashboard .panel-body:before {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #fff;
}
.dashboard .panel-body:after {
position: absolute;
top: 50%;
left: 50%;
width: 40px;
height: 40px;
margin-top: -20px;
margin-left: -20px;
font-family: ZenIcon;
font-size: 14px;
font-size: 28px;
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
line-height: 40px;
text-align: center;
text-transform: none;
content: '\e97c';
-webkit-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
animation: spin 2s infinite linear;
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.dashboard .panel-loading > .panel-body {
overflow: hidden;
}
.dashboard .panel-loading > .panel-body:before,
.dashboard .panel-loading > .panel-body:after {
visibility: visible;
opacity: .5;
}
.dashboard-inverse {
background-color: #3280fc;
}
.dashboard-inverse .panel {
-webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, .15);
box-shadow: 0 1px 5px rgba(0, 0, 0, .15);
}
.dashboard-inverse .panel-dragging {
background: rgba(0, 0, 0, .3);
}
.dashboard-inverse .panel-dragging-shadow {
-webkit-box-shadow: 1px 2px 15px rgba(0, 0, 0, .5) !important;
box-shadow: 1px 2px 15px rgba(0, 0, 0, .5) !important;
}

View File

@@ -0,0 +1,529 @@
/*!
* ZUI: 仪表盘 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
/* ========================================================================
* ZUI: dashboard.js
* http://zui.sexy
* ========================================================================
* Copyright (c) 2014-2016 cnezsoft.com; Licensed MIT
* ======================================================================== */
(function($, Math, undefined) {
'use strict';
var dashboardMessager = $.zui.Messager ? new $.zui.Messager({placement: 'top', time: 1500, close: 0, scale: false, fade: false}) : 0;
var Dashboard = function(element, options) {
this.$ = $(element);
this.options = this.getOptions(options);
this.draggable = this.$.hasClass('dashboard-draggable') || this.options.draggable;
this.init();
};
Dashboard.DEFAULTS = {
minHeight: 100,
height: 360,
shadowType: 'normal',
sensitive: false,
circleShadowSize: 100,
onlyRefreshBody: true,
resizable: true, // 'vertical', 'horizontal'
resizeMessage: false
};
Dashboard.prototype.getOptions = function(options) {
options = $.extend({}, Dashboard.DEFAULTS, this.$.data(), options);
return options;
};
Dashboard.prototype.handleRemoveEvent = function() {
var afterPanelRemoved = this.options.afterPanelRemoved;
var tip = this.options.panelRemovingTip;
this.$.on('click', '.remove-panel', function() {
var panel = $(this).closest('.panel');
var name = panel.data('name') || panel.find('.panel-heading').text().replace('\n', '').replace(/(^\s*)|(\s*$)/g, '');
var index = panel.attr('data-id');
if(tip === undefined || tip === false || confirm(tip.format(name))) {
panel.parent().remove();
if(afterPanelRemoved && $.isFunction(afterPanelRemoved)) {
afterPanelRemoved(index);
}
}
});
};
Dashboard.prototype.handleRefreshEvent = function() {
var that = this;
var onlyRefreshBody = this.options.onlyRefreshBody;
this.$.on('click', '.refresh-panel', function() {
var panel = $(this).closest('.panel');
that.refresh(panel, onlyRefreshBody);
});
};
Dashboard.prototype.handleDraggable = function() {
var dashboard = this.$;
var options = this.options;
var circleShadow = options.shadowType === 'circle';
var circleSize = options.circleShadowSize;
var halfCircleSize = circleSize / 2;
var afterOrdered = options.afterOrdered;
this.$.addClass('dashboard-draggable');
this.$.on('mousedown', '.panel-actions, .drag-disabled', function(event) {
event.stopPropagation();
});
var pColClass;
this.$.on('mousedown', '.panel-heading, .panel-drag-handler', function(event) {
var panel = $(this).closest('.panel');
var pCol = panel.parent();
var row = panel.closest('.row');
var dPanel = panel.clone().addClass('panel-dragging-shadow');
var pos = panel.offset();
var dPos = dashboard.offset();
var dColShadow = row.find('.dragging-col-holder');
var sWidth = panel.width(),
sHeight = panel.height(),
sX1, sY1, sX2, sY2, moveFn, dropCol, dropBefore, nextDropCol;
if(!dColShadow.length) {
dColShadow = $('<div class="dragging-col-holder"><div class="panel"></div></div>').removeClass('dragging-col').appendTo(row);
}
if(pColClass) dColShadow.removeClass(pColClass);
dColShadow.addClass(pColClass = pCol.attr('class'));
dColShadow.insertBefore(pCol).find('.panel').replaceWith(panel.clone().addClass('panel-dragging panel-dragging-holder'));
dashboard.addClass('dashboard-dragging');
panel.addClass('panel-dragging').parent().addClass('dragging-col');
dPanel.css({
left: pos.left - dPos.left,
top: pos.top - dPos.top,
width: sWidth,
height: sHeight
}).appendTo(dashboard).data('mouseOffset', {
x: event.pageX - pos.left + dPos.left,
y: event.pageY - pos.top + dPos.top
});
if(circleShadow) {
dPanel.addClass('circle');
setTimeout(function() {
dPanel.css({
left: event.pageX - dPos.left - halfCircleSize,
top: event.pageY - dPos.top - halfCircleSize,
width: circleSize,
height: circleSize
}).data('mouseOffset', {
x: dPos.left + halfCircleSize,
y: dPos.top + halfCircleSize
});
}, 100);
}
$(document).on('mousemove', mouseMove).on('mouseup', mouseUp);
event.preventDefault();
function mouseMove(event) {
// console.log('......................');
var offset = dPanel.data('mouseOffset');
sX1 = event.pageX - offset.x;
sY1 = event.pageY - offset.y;
sX2 = sX1 + sWidth;
sY2 = sY1 + sHeight;
dPanel.css({
left: sX1,
top: sY1
});
row.find('.dragging-in').removeClass('dragging-in');
dropBefore = false;
dropCol = null;
var area = 0,
thisArea;
row.children(':not(.dragging-col)').each(function() {
var col = $(this);
if(col.hasClass('dragging-col-holder')) {
dropBefore = (!options.sensitive) || (area < 100);
return true;
}
var p = col.children('.panel');
var pP = p.offset(),
pW = p.width(),
pH = p.height();
var pX = pP.left,
pY = pP.top;
if(options.sensitive) {
pX -= dPos.left;
pY -= dPos.top;
thisArea = getIntersectArea(sX1, sY1, sX2, sY2, pX, pY, pX + pW, pY + pH);
if(thisArea > 100 && thisArea > area && thisArea > Math.min(getRectArea(sX1, sY1, sX2, sY2), getRectArea(pX, pY, pX + pW, pY + pH)) / 3) {
area = thisArea;
dropCol = col;
}
} else {
var mX = event.pageX,
mY = event.pageY;
if(mX > pX && mY > pY && mX < (pX + pW) && mY < (pY + pH)) {
dropCol = col;
return false;
}
}
});
if(dropCol) {
if(moveFn) clearTimeout(moveFn);
nextDropCol = dropCol;
moveFn = setTimeout(movePanel, 50);
}
event.preventDefault();
}
function movePanel() {
if(nextDropCol) {
nextDropCol.addClass('dragging-in');
if(dropBefore) dColShadow.insertAfter(nextDropCol);
else dColShadow.insertBefore(nextDropCol);
dashboard.addClass('dashboard-holding');
moveFn = null;
nextDropCol = null;
}
}
function mouseUp(event) {
if(moveFn) clearTimeout(moveFn);
var oldOrder = panel.data('order');
panel.parent().insertAfter(dColShadow);
var newOrder = 0;
var newOrders = {};
row.children(':not(.dragging-col-holder)').each(function() {
var p = $(this).children('.panel');
p.data('order', ++newOrder);
newOrders[p.data('id') || p.attr('id')] = newOrder;
p.parent().attr('data-order', newOrder);
});
if(oldOrder != newOrders[panel.data('id') || panel.attr('id')]) {
row.data('orders', newOrders);
if(afterOrdered && $.isFunction(afterOrdered)) {
afterOrdered(newOrders);
}
}
dPanel.remove();
dashboard.removeClass('dashboard-holding');
dashboard.find('.dragging-col').removeClass('dragging-col');
dashboard.find('.panel-dragging').removeClass('panel-dragging');
row.find('.dragging-in').removeClass('dragging-in');
dashboard.removeClass('dashboard-dragging');
$(document).off('mousemove', mouseMove).off('mouseup', mouseUp);
event.preventDefault();
}
});
};
Dashboard.prototype.handlePanelPadding = function() {
this.$.find('.panel-body > table, .panel-body > .list-group').parent().addClass('no-padding');
};
Dashboard.prototype.updatePanelHeight = function() {
var that = this;
var defaultHeight = that.options.height;
var minHeight = that.options.minHeight;
var sizeConfig = {};
if(that.id && $.zui.store) {
sizeConfig = $.zui.store.pageGet('zui.dashboard.' + that.id + '.sizeConfig', sizeConfig);
}
this.$.children('.row').each(function() {
var $row = $(this);
var rowWidth = $row.width();
var rows = [], row = [], calWidth = 0;
$row.children(':not(.dragging-col-holder)').each(function() {
var $col = $(this);
var colWidth = $col.width();
if(calWidth + colWidth > rowWidth) {
if(row.length) rows.push(row);
row = [$col];
calWidth = colWidth;
} else {
calWidth += colWidth;
row.push($col);
}
});
if(row.length) rows.push(row);
if(rows.length) {
$.each(rows, function(rowId) {
row = rows[rowId];
var bestHeight = 0;
var panels = [];
var setNewHeight = false;
$.each(row, function(colId) {
var $col = row[colId].data('row-id', rowId);
var $panel = $col.children('.panel:first');
panels.push($panel);
if(setNewHeight) return;
var newHeight = $panel.data('newHeight');
if(newHeight) {
$panel.data('newHeight', null).data('height', newHeight);
bestHeight = Math.max(minHeight, newHeight);
setNewHeight = true;
} else {
var panelHeight = $panel.data('height') || sizeConfig[$panel.data('id')];
if(panelHeight) bestHeight = Math.max(bestHeight, panelHeight);
}
});
if(!bestHeight) {
bestHeight = defaultHeight;
}
$.each(panels, function(idx) {
var $panel = panels[idx].css('height', bestHeight);
sizeConfig[$panel.data('id')] = $panel.data('height');
});
});
}
});
if(that.id && $.zui.store) {
$.zui.store.pageSet('zui.dashboard.' + that.id + '.sizeConfig', sizeConfig);
}
return sizeConfig;
};
Dashboard.prototype.handleResizeEvent = function() {
var that = this;
var options = that.options;
var resizable = options.resizable;
var onResize = options.onResize;
var minHeight = options.minHeight;
var resizeMessage = options.resizeMessage;
var messagerAvaliable = resizeMessage && dashboardMessager;
that.$.on('mousedown', '.resize-handle', function(e) {
var $handle = $(this);
var isVertical = $handle.hasClass('resize-vertical');
var $col = $handle.parent()
.addClass('resizing')
.toggleClass('resizing-v', isVertical)
.toggleClass('resizing-h', !isVertical);
var $row = $col.closest('.row');
var $panel = $col.children('.panel');
var startX = e.pageX, startY = e.pageY;
var startWidth = $col.width(), startHeight = $panel.height();
var rowWidth = $row.width();
var oldGrid = Math.round(12*startWidth/rowWidth);
var lastGrid = oldGrid;
if(!isVertical) $col.attr('data-grid', oldGrid);
var mouseMove = function(event) {
if(isVertical) {
$panel.css('height', Math.max(minHeight, startHeight + (event.pageY - startY)));
}
else {
var x = event.pageX;
var grid = Math.max(1, Math.min(12, Math.round(12 * (startWidth + (x - startX)) / rowWidth)));
if(lastGrid != grid) {
$col.attr('data-grid', grid).css('width', (100*grid/12) + '%');
if(messagerAvaliable) dashboardMessager[dashboardMessager.isShow ? 'update' : 'show'](Math.round(100*grid/12) + '% (' + grid + '/12)');
lastGrid = grid;
}
}
event.preventDefault();
event.stopPropagation();
};
var mouseUp = function(event) {
$col.removeClass('resizing resizing-v resizing-h');
if(isVertical) {
var newHeight = Math.max(minHeight, startHeight + (event.pageY - startY));
if(newHeight !== startHeight)
{
if($.isFunction(onResize))
{
var revert = function() {
$panel.css('height', startHeight).data('height', startHeight);
that.updatePanelHeight();
};
var result = onResize({type: 'vertical', id: $panel.data('id'), element: $col, old: startHeight, height: newHeight, revert: revert});
if(result === false) revert();
}
$panel.css('height', newHeight).data('newHeight', newHeight);;
}
} else {
var lastGrid = $col.attr('data-grid');
if(oldGrid != lastGrid) {
if($.isFunction(onResize)) {
var revert = function() {
$col.attr('data-grid', oldGrid).css('width', null);
that.updatePanelHeight();
};
var result = onResize({type: 'horizontal', id: $panel.data('id'), element: $col, old: oldGrid, grid: lastGrid, revert: revert});
if(result === false) revert();
else if(result !== true) {
if(messagerAvaliable) dashboardMessager.show(Math.round(100*lastGrid/12) + '% (' + lastGrid + '/12)');
}
}
}
}
that.updatePanelHeight();
$('body').off('mousemove.resize', mouseMove).off('mouseup.resize', mouseUp);
event.preventDefault();
event.stopPropagation();
};
$('body').on('mousemove.resize', mouseMove).on('mouseup.resize', mouseUp);
e.preventDefault();
e.stopPropagation();
});
var $col = that.$.children('.row').children(':not(.dragging-col-holder)');
if(resizable === true || resizable === 'horizontal')
{
$col.append('<div class="resize-handle resize-horizontal"><i class="icon icon-resize-h"></i></div>');
}
if(resizable === true || resizable === 'vertical')
{
$col.append('<div class="resize-handle resize-vertical"><i class="icon icon-resize-v"></i></div>');
}
};
Dashboard.prototype.refresh = function($panel, onlyRefreshBody) {
if(onlyRefreshBody === undefined) onlyRefreshBody = this.options.onlyRefreshBody;
var afterRefresh = this.options.afterRefresh;
$panel = $($panel);
var url = $panel.data('url');
if(!url) return;
$panel.addClass('panel-loading').find('.panel-heading .icon-refresh,.panel-heading .icon-repeat').addClass('icon-spin');
$.ajax({
url: url,
dataType: 'html'
}).done(function(data) {
var $data = $(data);
if($data.hasClass('panel')) {
$panel.empty().append($data.children());
} else if(onlyRefreshBody) {
$panel.find('.panel-body').empty().html(data);
} else {
$panel.html(data);
}
if($.isFunction(afterRefresh)) {
afterRefresh.call(this, {
result: true,
data: data,
$panel: $panel
});
}
}).fail(function() {
$panel.addClass('panel-error');
if($.isFunction(afterRefresh)) {
afterRefresh.call(this, {
result: false,
$panel: $panel
});
}
}).always(function() {
$panel.removeClass('panel-loading');
$panel.find('.panel-heading .icon-refresh,.panel-heading .icon-repeat').removeClass('icon-spin');
});
};
function getRectArea(x1, y1, x2, y2) {
return Math.abs((x2 - x1) * (y2 - y1));
}
function isPointInner(x, y, x1, y1, x2, y2) {
return x >= x1 && x <= x2 && y >= y1 && y <= y2;
}
function getIntersectArea(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) {
var x1 = Math.max(ax1, bx1),
y1 = Math.max(ay1, by1),
x2 = Math.min(ax2, bx2),
y2 = Math.min(ay2, by2);
if(isPointInner(x1, y1, ax1, ay1, ax2, ay2) && isPointInner(x2, y2, ax1, ay1, ax2, ay2) && isPointInner(x1, y1, bx1, by1, bx2, by2) && isPointInner(x2, y2, bx1, by1, bx2, by2)) {
return getRectArea(x1, y1, x2, y2);
}
return 0;
}
Dashboard.prototype.init = function() {
var options = this.options, that = this;
that.id = options.id ? options.id : that.$.attr('id');
if(options.data) {
var $row = $('<div class="row"/>');
$.each(options.data, function(idx, config) {
var $col = $('<div class="col-sm-' + (config.colWidth || 4) + '"/>');
if(config.colAttrs) $col.attr(config.colAttrs);
var $panel = $('<div class="panel" data-id="' + (config.id || $.zui.uuid()) + '"/>');
if(config.panelAttrs) $panel.attr(config.panelAttrs);
if(config.height !== undefined) $panel.data('height', config.height);
if(config.content !== undefined) {
if($.isFunction(config.content)) {
var content = config.content($panel);
if(content !== true) {
$panel.html(content);
}
} else {
$panel.html(config.content);
}
}
$row.append($col.append($panel.data('url', config.url)));
});
that.$.append($row);
}
that.updatePanelHeight();
that.handlePanelPadding();
that.handleRemoveEvent();
that.handleRefreshEvent();
if(options.resizable) that.handleResizeEvent();
if(that.draggable) that.handleDraggable();
var orderSeed = 0;
that.$.find('.panel').each(function() {
var $this = $(this);
$this.data('order', ++orderSeed);
if(!$this.attr('id')) {
$this.attr('id', 'panel' + orderSeed);
}
if(!$this.attr('data-id')) {
$this.attr('data-id', orderSeed);
}
that.refresh($this, options.onlyRefreshBody);
});
that.$.find('[data-toggle="tooltip"]').tooltip({container: 'body'});
};
$.fn.dashboard = function(option) {
return this.each(function() {
var $this = $(this);
var data = $this.data('zui.dashboard');
var options = typeof option == 'object' && option;
if(!data) $this.data('zui.dashboard', (data = new Dashboard(this, options)));
if(typeof option == 'string') data[option]();
});
};
$.fn.dashboard.Constructor = Dashboard;
}(jQuery, Math, undefined));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,272 @@
/*!
* ZUI: 数据表格② - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
.datagrid-container {
position: relative;
overflow: hidden;
background-color: #f1f1f1;
border: 1px solid #ddd;
}
.datagrid-cells {
position: absolute;
top: 0;
left: 0;
overflow: visible;
}
.datagrid-cell {
position: absolute;
padding: 8px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background-color: #fff;
border: 1px solid #ddd;
-webkit-transition: .4s cubic-bezier(.175, .885, .32, 1);
-o-transition: .4s cubic-bezier(.175, .885, .32, 1);
transition: .4s cubic-bezier(.175, .885, .32, 1);
-webkit-transition-property: background, outline;
-o-transition-property: background, outline;
transition-property: background, outline;
}
.datagrid-cell.datagrid-cell-index {
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
color: #808080;
text-align: right;
background-color: #f1f1f1;
}
.datagrid-cell.datagrid-cell-head {
background-color: #f1f1f1;
}
.datagrid-cell-span {
z-index: 10;
}
.datagrid-row {
position: absolute;
width: 100%;
background-color: #fff;
-webkit-transition: .4s cubic-bezier(.175, .885, .32, 1);
-o-transition: .4s cubic-bezier(.175, .885, .32, 1);
transition: .4s cubic-bezier(.175, .885, .32, 1);
-webkit-transition-property: background, outline;
-o-transition-property: background, outline;
transition-property: background, outline;
}
.datagrid-row-head {
font-weight: bold;
color: #808080;
background-color: #f1f1f1;
}
.datagrid-fixed.datagrid-row {
z-index: 35;
}
.datagrid-fixed.datagrid-cell {
z-index: 30;
}
.datagrid-fixed-edge-top {
-webkit-box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .125), 0 1px 0 rgba(0, 0, 0, .25);
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, .125), 0 1px 0 rgba(0, 0, 0, .25);
}
.datagrid-fixed-edge-bottom {
-webkit-box-shadow: 0 -2px 5px 0 rgba(0, 0, 0, .125), 0 -1px 0 rgba(0, 0, 0, .25);
box-shadow: 0 -2px 5px 0 rgba(0, 0, 0, .125), 0 -1px 0 rgba(0, 0, 0, .25);
}
.datagrid-fixed-edge-left {
-webkit-box-shadow: -1px 0 0 rgba(0, 0, 0, .25) inset;
box-shadow: -1px 0 0 rgba(0, 0, 0, .25) inset;
}
.datagrid-fixed-edge-right {
-webkit-box-shadow: 1px 0 0 rgba(0, 0, 0, .25) inset;
box-shadow: 1px 0 0 rgba(0, 0, 0, .25) inset;
}
.datagrid-row-cell.active .datagrid-cell {
background-color: #fff0d5;
}
.datagrid-row-cell.active .datagrid-cell.datagrid-cell-index {
background-color: #ffe7bc;
}
.datagrid-hover-row .datagrid-row-cell:hover {
z-index: 20;
}
.datagrid-hover-row .datagrid-row-cell:hover .datagrid-cell {
background-color: #ebf2f9;
}
.datagrid-hover-row .datagrid-row-cell:hover.datagrid-fixed {
z-index: 38;
}
.datagrid-hover-row .datagrid-row-cell:hover > .datagrid-cell-index {
background-color: #ddd;
}
.datagrid-hover-row .datagrid-row-cell:hover.active .datagrid-cell {
background-color: #ffe1ac;
}
.datagrid-hover-row .datagrid-row-cell:hover.active .datagrid-cell-index {
background-color: #ffda98;
}
.datagrid-hover-row.datagrid-hover-shadow .datagrid-row-cell:hover {
-webkit-box-shadow: 0 1px 3px 2px rgba(0, 0, 0, .05), 0 0 2px 1px rgba(0, 0, 0, .075);
box-shadow: 0 1px 3px 2px rgba(0, 0, 0, .05), 0 0 2px 1px rgba(0, 0, 0, .075);
}
.datagrid-hover-cell .datagrid-row-cell .datagrid-cell-cell:hover {
z-index: 40;
background-color: #fff;
outline: 1px solid #808080;
outline-offset: -1px;
}
.datagrid-hover-cell .datagrid-row-cell .datagrid-cell-cell.datagrid-fixed:hover,
.datagrid-hover-cell .datagrid-row-cell.datagrid-fixed .datagrid-cell-cell:hover {
z-index: 42;
}
.datagrid-hover-cell.datagrid-hover-shadow .datagrid-row-cell .datagrid-cell:hover {
-webkit-box-shadow: 0 1px 3px 3px rgba(0, 0, 0, .075), 0 0 2px rgba(0, 0, 0, .1);
box-shadow: 0 1px 3px 3px rgba(0, 0, 0, .075), 0 0 2px rgba(0, 0, 0, .1);
}
.datagrid-hover-col .datagrid-cell.hover {
background-color: #ebf2f9;
}
.datagrid-hover-col .datagrid-cell-head.hover,
.datagrid-hover-col .datagrid-cell-index.hover {
background-color: #ddd;
}
.datagrid-hover-col .datagrid-row-cell.active .datagrid-cell.hover {
background-color: #d7e5f3;
}
.datagrid-scrollbar {
position: absolute;
right: 0;
bottom: 0;
z-index: 50;
opacity: 0;
-webkit-transition: 2.5s cubic-bezier(.175, .885, .32, 1);
-o-transition: 2.5s cubic-bezier(.175, .885, .32, 1);
transition: 2.5s cubic-bezier(.175, .885, .32, 1);
-webkit-transition-property: background, opacity;
-o-transition-property: background, opacity;
transition-property: background, opacity;
}
.datagrid-scrollbar.scrolling,
.datagrid-container:hover .datagrid-scrollbar {
opacity: 1;
}
.datagrid-scrollbar > .bar {
position: absolute;
min-width: 10px;
background-color: #ddd;
background-color: rgba(0, 0, 0, .25);
}
.datagrid-scrollbar.scrolling,
.datagrid-scrollbar:hover {
background-color: rgba(0, 0, 0, .075);
}
.datagrid-scrollbar.scrolling > .bar,
.datagrid-scrollbar:hover > .bar {
position: absolute;
background-color: #808080;
background-color: rgba(0, 0, 0, .5);
}
.datagrid-scrollbar-h {
left: 0;
height: 10px;
}
.datagrid-scrollbar-h > .bar {
top: 0!important;
bottom: 0!important;
min-width: 20px;
}
.datagrid-scrollbar-v {
top: 0;
width: 10px;
}
.datagrid-scrollbar-v > .bar {
right: 0!important;
left: 0!important;
min-height: 20px;
}
.datagrid-messager {
position: absolute;
top: 0;
right: 0;
left: 0;
z-index: 60;
padding: 5px 10px;
text-align: center;
}
.datagrid-messager > .close {
position: absolute;
top: 0;
right: 0;
display: block;
width: 30px;
height: 30px;
padding-bottom: 5px;
line-height: 20px;
text-align: center;
}
.datagrid-messager > .close:hover {
background-color: rgba(0, 0, 0, .1);
}
.datagrid-loading {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 61;
background-color: rgba(255, 255, 255, .6);
}
.datagrid-loading > .content {
position: relative;
top: 50%;
display: block;
height: 50px;
margin-top: -25px;
text-align: center;
}
.datagrid-loading > .content > .icon {
color: #3280fc;
}
.datagrid-col-sortable {
padding-right: 20px;
cursor: pointer;
}
.datagrid-sorter {
position: absolute;
top: 3px;
right: 0;
bottom: 0;
width: 20px;
line-height: 30px;
text-align: center;
}
.datagrid-sort-down > .icon-sort:before {
color: #3280fc;
content: '\e6b8';
}
.datagrid-sort-up > .icon-sort:before {
color: #3280fc;
content: '\e6b9';
}
.datagrid-borderless .datagrid-container {
border-color: transparent;
}
.datagrid-borderless .datagrid-cell {
border-right-color: transparent;
border-left-color: transparent;
}
.datagrid-borderless .datagrid-fixed-edge-left {
-webkit-box-shadow: -1px 0 0 rgba(0, 0, 0, .1) inset;
box-shadow: -1px 0 0 rgba(0, 0, 0, .1) inset;
}
.datagrid-borderless .datagrid-fixed-edge-right {
-webkit-box-shadow: 1px 0 0 rgba(0, 0, 0, .1) inset;
box-shadow: 1px 0 0 rgba(0, 0, 0, .1) inset;
}
.datagrid-borderless .datagrid-row-cell:not(:hover) .datagrid-cell.datagrid-cell-index {
background-color: #fff;
}
.datagrid-striped .datagrid-cells > .datagrid-row-cell:nth-child(odd) .datagrid-cell-cell {
background-color: #f9f9f9;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,200 @@
/*!
* ZUI: 数据表格 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
.datatable-head,
.datatable-rows {
display: table;
width: 100%;
table-layout: fixed;
}
.datatable {
margin-bottom: 20px;
}
.datatable > .datatable-head {
-webkit-transition: -webkit-box-shadow .2s;
-o-transition: box-shadow .2s;
transition: -webkit-box-shadow .2s;
transition: box-shadow .2s;
transition: box-shadow .2s, -webkit-box-shadow .2s;
}
.datatable .table {
margin: 0;
table-layout: fixed;
}
.datatable .table > tbody > tr > td,
.datatable .table > thead > tr > th {
min-width: 20px;
}
.datatable .table > tbody > tr > td.check-btn,
.datatable .table > thead > tr > th.check-btn {
width: 30px;
color: #9b9b9b;
text-align: center;
cursor: pointer;
}
.datatable .table > tbody > tr.hover > td.check-btn,
.datatable .table > tbody > tr.active > td.check-btn,
.datatable .table > thead > tr > th.check-btn:hover,
.datatable .table > tbody > tr > td.check-btn:hover,
.datatable .table > thead > tr > th.check-btn.checked,
.datatable .table > tbody > tr > td.check-btn.checked {
color: #4f4f4f;
}
.datatable .table > thead > tr > th.check-btn.checked > .icon-check-empty:before,
.datatable .table > tbody > tr > td.check-btn.checked > .icon-check-empty:before,
.datatable .table > tbody > tr.active > td.check-btn > .icon-check-empty:before {
content: '\e642';
}
.datatable .table > thead > tr > th.col-hover {
background-color: #e2e2e2;
}
.datatable .table > tbody > tr > td.col-hover,
.datatable .table > tbody > tr.hover > td {
background-color: #ebf2f9;
}
.datatable .table > tbody > tr.active.hover td {
background-color: #ffdea2;
}
.datatable.head-fixed > .datatable-head {
position: fixed;
z-index: 1030;
-webkit-box-shadow: 0 1px 4px 0 rgba(0, 0, 0, .15);
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, .15);
}
.datatable.sortable .datatable-head-span .table > thead > tr > th {
overflow: hidden;
white-space: nowrap;
cursor: pointer;
}
.datatable.sortable .datatable-head-span .table > thead > tr > th.text-center {
padding-right: 0;
padding-left: 0;
}
.datatable.sortable .datatable-head-span .table > thead > tr > th:after {
display: inline-block;
margin-left: 5px;
font-family: ZenIcon;
font-size: 14px;
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
color: #808080;
text-transform: none;
content: '\e6bd';
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.datatable.sortable .datatable-head-span .table > thead > tr > th.sort-down:after {
color: #145ccd;
content: '\e6b8';
}
.datatable.sortable .datatable-head-span .table > thead > tr > th.sort-up:after {
color: #145ccd;
content: '\e6b9';
}
.datatable.sortable .datatable-head-span .table > thead > tr > th.check-btn:after,
.datatable.sortable .datatable-head-span .table > thead > tr > th.sort-disabled:after {
display: none;
}
.datatable.sortable .datatable-head-span .table > thead > tr > th.sort-disabled {
cursor: default;
}
.datatable-wrapper {
position: relative;
}
.datatable-span {
display: table-cell;
vertical-align: top;
}
.datatable-span.flexarea {
overflow: hidden;
}
.datatable-span.flexarea.datatable-head-span.dragging {
cursor: move !important;
}
.datatable-span.flexarea .table {
position: relative;
top: 0;
left: 0;
}
.datatable-span.flexarea .scrolled-shadow {
position: absolute;
top: 0;
bottom: 0;
display: none;
width: 20px;
-webkit-box-shadow: 0 0 10px rgba(0, 0, 0, .15);
box-shadow: 0 0 10px rgba(0, 0, 0, .15);
opacity: 0;
-webkit-transition: all .4s cubic-bezier(.175, .885, .32, 1);
-o-transition: all .4s cubic-bezier(.175, .885, .32, 1);
transition: all .4s cubic-bezier(.175, .885, .32, 1);
}
.datatable-span.flexarea .scrolled-in-shadow {
left: -30px;
}
.datatable-span.flexarea .scrolled-out-shadow {
right: -30px;
}
.datatable > .scroll-wrapper {
position: relative;
width: 100%;
}
.datatable .scroll-slide {
position: absolute;
right: -1px;
bottom: 0;
left: -1px;
display: none;
height: 11px;
background: #e5e5e5;
background: rgba(128, 128, 128, .1);
border: 1px solid #e5e5e5;
border-bottom: none;
opacity: 0;
-webkit-transition: opacity .5s, background .3s;
-o-transition: opacity .5s, background .3s;
transition: opacity .5s, background .3s;
}
.datatable .scroll-slide > .bar {
position: absolute;
top: 0;
left: 0;
min-width: 50px;
height: 10px;
cursor: move;
background-color: #a6a6a6;
}
.datatable .scroll-slide:hover > .bar {
background-color: #808080;
}
.datatable .scroll-slide.scroll-pos-out {
bottom: -14px;
height: 15px;
}
.datatable .scroll-slide.scroll-pos-out > .bar {
height: 14px;
}
.datatable.show-scroll-slide:hover .scroll-slide,
.datatable.show-scroll-slide.scrolling .scroll-slide,
.datatable.show-scroll-slide:hover .scrolled-shadow,
.datatable.show-scroll-slide.scrolling .scrolled-shadow {
opacity: 1;
}
.datatable.show-scroll-slide .scroll-slide,
.datatable.show-scroll-slide .scrolled-shadow {
display: block;
}
.datatable.show-scroll-slide.scrolled-in .scrolled-in-shadow {
left: -20px;
}
.datatable.show-scroll-slide.scrolled-out .scrolled-out-shadow {
right: -20px;
}

View File

@@ -0,0 +1,948 @@
/*!
* ZUI: 数据表格 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
/* ========================================================================
* ZUI: datatable.js
* http://zui.sexy
* ========================================================================
* Copyright (c) 2014-2016 cnezsoft.com; Licensed MIT
* ======================================================================== */
(function($) {
'use strict';
var name = 'zui.datatable';
var store = $.zui.store;
/**
* Datatable class
*
* @param object element DOM element or jquery element
* @param object options Datatable options
*/
var DataTable = function(element, options) {
this.name = name;
this.$ = $(element);
this.isTable = (this.$[0].tagName === 'TABLE');
this.firstShow = true;
if(this.isTable) {
this.$table = this.$;
this.id = 'datatable-' + (this.$.attr('id') || $.zui.uuid());
} else {
this.$datatable = this.$.addClass('datatable');
if(this.$.attr('id')) {
this.id = this.$.attr('id');
} else {
this.id = 'datatable-' + $.zui.uuid();
this.$.attr('id', this.id);
}
}
this.getOptions(options);
this.load();
this.callEvent('ready');
};
// default options
DataTable.DEFAULTS = {
// Check options
checkable: false, // added check icon to the head of rows
checkByClickRow: true, // change check status by click anywhere on a row
checkedClass: 'active', // apply CSS class to an checked row
checkboxName: null,
selectable: true,
// Sort options
sortable: false, // enable sorter
// storage
storage: true, // enable storage
// fixed header of columns
fixedHeader: false, // fixed header
fixedHeaderOffset: 0, // set top offset of header when fixed
fixedLeftWidth: '30%', // set left width after first render
fixedRightWidth: '30%', // set right width after first render
flexHeadDrag: true, // scroll flexarea by drag header
scrollPos: 'in', // scroll bar position: 'out' | 'in'
// hover effection
rowHover: true, // apply hover effection to row
colHover: true, // apply hover effection to head
hoverClass: 'hover',
colHoverClass: 'col-hover',
// Fix cell height
fixCellHeight: true,
// Merge rows
mergeRows: false, // Merge rows
// custom columns size
// customizable: false, // enable customizable
minColWidth: 20, // min width of columns
minFixedLeftWidth: 200, // min left width
minFixedRightWidth: 200, // min right width
minFlexAreaWidth: 200 // min flexarea width
};
// Get options
DataTable.prototype.getOptions = function(options) {
var $e = this.$;
options = $.extend({}, DataTable.DEFAULTS, this.$.data(), options);
options.tableClass = options.tableClass || '';
options.tableClass = ' ' + options.tableClass + ' table-datatable';
$.each(['bordered', 'condensed', 'striped', 'condensed', 'fixed'], function(idx, cls) {
cls = 'table-' + cls;
if($e.hasClass(cls)) options.tableClass += ' ' + cls;
});
if($e.hasClass('table-hover') || options.rowHover) {
options.tableClass += ' table-hover';
}
if(!options.checkable || !$.fn.selectable) options.selectable = false;
this.options = options;
};
// Load data form options or table dom
DataTable.prototype.load = function(data) {
var options = this.options,
cols;
if($.isFunction(data)) {
data = data(this.data, this);
data.keepSort = true;
} else if($.isPlainObject(data)) {
this.data = data;
} else if(typeof data === 'string') {
var $table = $(data);
if($table.length) {
this.$table = $table.first();
this.$table.data(name, this);
this.isTable = true;
}
data = null;
} else {
data = options.data;
}
if(!data) {
if(this.isTable) {
data = {
cols: [],
rows: []
};
cols = data.cols;
var rows = data.rows,
i,
$th, $tr, $td, row, $t = this.$table,
colSpan;
$t.children('thead').children('tr:first').children('th').each(function() {
$th = $(this);
cols.push($.extend({
text: $th.html(),
flex: false || $th.hasClass('flex-col'),
width: 'auto',
cssClass: $th.attr('class'),
css: $th.attr('style'),
type: 'string',
ignore: $th.hasClass('ignore'),
sort: !$th.hasClass('sort-disabled'),
mergeRows: $th.attr('merge-rows')
}, $th.data()));
});
$t.children('tbody').children('tr').each(function() {
$tr = $(this);
row = $.extend({
data: [],
checked: false,
cssClass: $tr.attr('class'),
css: $tr.attr('style'),
id: $tr.attr('id')
}, $tr.data());
$tr.children('td').each(function() {
$td = $(this);
colSpan = $td.attr('colspan') || 1;
row.data.push($.extend({
cssClass: $td.attr('class'),
css: $td.attr('style'),
text: $td.html(),
colSpan: colSpan,
title: $td.attr('title')
}, $td.data()));
if(colSpan > 1) {
for(i = 1; i < colSpan; i++) {
row.data.push({
empty: true
});
}
}
});
rows.push(row);
});
var $tfoot = $t.children('tfoot');
if($tfoot.length) {
data.footer = $('<table class="table' + options.tableClass + '"></table>').append($tfoot);
}
} else {
throw new Error('No data avaliable!');
}
}
data.flexStart = -1;
data.flexEnd = -1;
cols = data.cols;
data.colsLength = cols.length;
for(var i = 0; i < data.colsLength; ++i) {
var col = cols[i];
if(col.flex) {
if(data.flexStart < 0) {
data.flexStart = i;
}
data.flexEnd = i;
}
}
if(data.flexStart === 0 && data.flexEnd === data.colsLength) {
data.flexStart = -1;
data.flexEnd = -1;
}
data.flexArea = data.flexStart >= 0;
data.fixedRight = data.flexEnd >= 0 && data.flexEnd < (data.colsLength - 1);
data.fixedLeft = data.flexStart > 0;
if(data.flexStart < 0 && data.flexEnd < 0) {
data.fixedLeft = true;
data.flexStart = data.colsLength;
data.flexEnd = data.colsLength;
}
this.data = data;
this.callEvent('afterLoad', {
data: data
});
this.render();
};
// Render datatable
DataTable.prototype.render = function() {
var that = this;
var $datatable = that.$datatable || (that.isTable ? $('<div class="datatable" id="' + that.id + '"/>') : that.$datatable),
options = that.options,
data = that.data,
cols = that.data.cols,
rows = that.data.rows;
var checkable = options.checkable,
$left,
i,
$right,
$flex,
dataRowSpan = '<div class="datatable-rows-span datatable-span"><div class="datatable-wrapper"><table class="table"></table></div></div>',
dataHeadSpan = '<div class="datatable-head-span datatable-span"><div class="datatable-wrapper"><table class="table"><thead></thead></table></div></div>';
$datatable.children('.datatable-head, .datatable-rows, .scroll-wrapper').remove();
// Set css class to datatable by options
$datatable.toggleClass('sortable', options.sortable);
// $datatable.toggleClass('customizable', options.customizable);
// Head
var $head = $('<div class="datatable-head"/>'),
$tr,
$th,
col;
$left = $('<tr class="datatable-row datatable-row-left"/>');
$right = $('<tr class="datatable-row datatable-row-right"/>');
$flex = $('<tr class="datatable-row datatable-row-flex"/>');
for(i = 0; i < cols.length; i++) {
col = cols[i];
$tr = i < data.flexStart ? $left : ((i >= data.flexStart && i <= data.flexEnd) ? $flex : $right);
if(i === 0 && checkable) {
$tr.append('<th data-index="check" class="check-all check-btn"><i class="icon-check-empty"></i></th>');
}
if(col.ignore) continue;
$th = $('<th class="datatable-head-cell"/>');
// set sort class
$th.toggleClass('sort-down', col.sort === 'down')
.toggleClass('sort-up', col.sort === 'up')
.toggleClass('sort-disabled', col.sort === false);
$th.addClass(col.cssClass)
.addClass(col.colClass)
.html(col.text)
.attr({
'data-index': i,
'data-type': col.type,
style: col.css
}).css('width', col.width);
$tr.append($th);
}
var $headSpan;
if(data.fixedLeft) {
$headSpan = $(dataHeadSpan);
$headSpan.addClass('fixed-left')
// .find('.datatable-wrapper')
// .append('<div class="size-handle size-handle-head size-handle-left"></div>')
.find('table')
.addClass(options.tableClass)
.find('thead').append($left);
$head.append($headSpan);
}
if(data.flexArea) {
$headSpan = $(dataHeadSpan);
$headSpan.addClass('flexarea')
.find('.datatable-wrapper')
.append('<div class="scrolled-shadow scrolled-in-shadow"></div><div class="scrolled-shadow scrolled-out-shadow"></div>')
.find('table')
.addClass(options.tableClass)
.find('thead').append($flex);
$head.append($headSpan);
}
if(data.fixedRight) {
$headSpan = $(dataHeadSpan);
$headSpan.addClass('fixed-right')
// .find('.datatable-wrapper')
// .append('<div class="size-handle size-handle-head size-handle-right"></div>')
.find('table')
.addClass(options.tableClass)
.find('thead').append($right);
$head.append($headSpan);
}
$datatable.append($head);
// Rows
var $rows = $('<div class="datatable-rows">');
var $leftRow,
$flexRow,
$rightRow,
// $tr,
$td,
$cTd,
row,
rowLen = rows.length,
rowCol,
rowColLen;
$left = $('<tbody/>');
$right = $('<tbody/>');
$flex = $('<tbody/>');
for(var r = 0; r < rowLen; ++r) {
row = rows[r];
// format row
if(typeof row.id === 'undefined') {
row.id = r;
}
row.index = r;
$leftRow = $('<tr class="datatable-row"/>');
$leftRow.addClass(row.cssClass)
.toggleClass(options.checkedClass, !!row.checked)
.attr({
'data-index': r,
'data-id': row.id
});
$flexRow = $leftRow.clone().addClass('datatable-row-flex');
$rightRow = $leftRow.clone().addClass('datatable-row-right');
$leftRow.addClass('datatable-row-left');
rowColLen = row.data.length;
for(i = 0; i < rowColLen; ++i) {
rowCol = row.data[i];
if(i > 0 && rowCol.empty) {
continue;
}
$tr = i < data.flexStart ? $leftRow : ((i >= data.flexStart && i <= data.flexEnd) ? $flexRow : $rightRow);
if(i === 0 && checkable) {
$cTd = $('<td data-index="check" class="check-row check-btn"><i class="icon-check-empty"></i></td>');
if(options.checkboxName) {
$cTd.append('<input class="hide" type="checkbox" name="' + options.checkboxName + '" value="' + row.id + '">');
}
$tr.append($cTd);
}
if(cols[i].ignore) continue;
// format row column
if(!$.isPlainObject(rowCol)) {
rowCol = {
text: rowCol,
row: r,
index: i
};
} else {
rowCol.row = r;
rowCol.index = i;
}
row.data[i] = rowCol;
$td = $('<td class="datatable-cell"/>');
$td.html(rowCol.text)
.addClass(rowCol.cssClass)
.addClass(cols[i].colClass)
.attr('colspan', rowCol.colSpan)
.attr({
'data-row': r,
'data-index': i,
'data-flex': false,
'data-type': cols[i].type,
style: rowCol.css,
title: rowCol.title || ''
}).css('width', cols[i].width);
$tr.append($td);
}
$left.append($leftRow);
$flex.append($flexRow);
$right.append($rightRow);
}
var $rowSpan;
if(data.fixedLeft) {
$rowSpan = $(dataRowSpan);
$rowSpan.addClass('fixed-left')
.find('table')
.addClass(options.tableClass)
.append($left);
$rows.append($rowSpan);
}
if(data.flexArea) {
$rowSpan = $(dataRowSpan);
$rowSpan.addClass('flexarea')
.find('.datatable-wrapper')
.append('<div class="scrolled-shadow scrolled-in-shadow"></div><div class="scrolled-shadow scrolled-out-shadow"></div>')
.find('table')
.addClass(options.tableClass)
.append($flex);
$rows.append($rowSpan);
}
if(data.fixedRight) {
$rowSpan = $(dataRowSpan);
$rowSpan.addClass('fixed-right')
.find('table')
.addClass(options.tableClass)
.append($right);
$rows.append($rowSpan);
}
$datatable.append($rows);
if(data.flexArea) {
$datatable.append('<div class="scroll-wrapper"><div class="scroll-slide scroll-pos-' + options.scrollPos + '"><div class="bar"></div></div></div>');
}
var $oldFooter = $datatable.children('.datatable-footer').detach();
if(data.footer) {
$datatable.append($('<div class="datatable-footer"/>').append(data.footer));
data.footer = null;
} else if($oldFooter.length) {
$datatable.append($oldFooter);
}
that.$datatable = $datatable.data(name, that);
if(that.isTable && that.firstShow) {
that.$table.attr('data-datatable-id', this.id).hide().after($datatable);
that.firstShow = false;
}
that.bindEvents();
that.refreshSize();
that.callEvent('render');
};
// Bind global events
DataTable.prototype.bindEvents = function() {
var that = this,
data = this.data,
options = this.options,
$datatable = this.$datatable;
var $dataSpans = that.$dataSpans = $datatable.children('.datatable-head, .datatable-rows').find('.datatable-span');
var $rowsSpans = that.$rowsSpans = $datatable.children('.datatable-rows').children('.datatable-rows-span');
var $headSpans = that.$headSpans = $datatable.children('.datatable-head').children('.datatable-head-span');
var $cells = that.$cells = $dataSpans.find('.datatable-head-cell,.datatable-cell');
var $dataCells = that.$dataCells = $cells.filter('.datatable-cell');
that.$headCells = $cells.filter('.datatable-head-cell');
var $rows = that.$rows = that.$rowsSpans.find('.datatable-row');
// handle row hover events
if(options.rowHover) {
var hoverClass = options.hoverClass;
$rowsSpans.on('mouseenter', '.datatable-cell', function() {
$dataCells.filter('.' + hoverClass).removeClass(hoverClass);
$rows.filter('.' + hoverClass).removeClass(hoverClass);
$rows.filter('[data-index="' + $(this).addClass(hoverClass).data('row') + '"]').addClass(hoverClass);
}).on('mouseleave', '.datatable-cell', function() {
$dataCells.filter('.' + hoverClass).removeClass(hoverClass);
$rows.filter('.' + hoverClass).removeClass(hoverClass);
});
}
// handle col hover events
if(options.colHover) {
var colHoverClass = options.colHoverClass;
$headSpans.on('mouseenter', '.datatable-head-cell', function() {
$cells.filter('.' + colHoverClass).removeClass(colHoverClass);
$cells.filter('[data-index="' + $(this).data('index') + '"]').addClass(colHoverClass);
}).on('mouseleave', '.datatable-head-cell', function() {
$cells.filter('.' + colHoverClass).removeClass(colHoverClass);
});
}
// handle srcoll for flex area
if(data.flexArea) {
var $scrollbar = $datatable.find('.scroll-slide'),
// $flexArea = $datatable.find('.datatable-span.flexarea .table'),
$flexArea = $datatable.find('.datatable-span.flexarea'),
$fixedLeft = $datatable.find('.datatable-span.fixed-left'),
// $flexTable = $datatable.find('.datatable-rows-span.flexarea .table');
$flexTable = $datatable.find('.datatable-span.flexarea .table-datatable');
var $bar = $scrollbar.children('.bar'),
flexWidth,
scrollWidth,
tableWidth,
lastBarLeft,
barLeft,
scrollOffsetStoreName = that.id + '_' + 'scrollOffset',
firtScroll,
left;
that.width = $datatable.width();
$datatable.resize(function() {
that.width = $datatable.width();
});
var srollTable = function(offset, silence) {
barLeft = Math.max(0, Math.min(flexWidth - scrollWidth, offset));
if(!silence) {
$datatable.addClass('scrolling');
}
$bar.css('left', barLeft);
left = 0 - Math.floor((tableWidth - flexWidth) * barLeft / (flexWidth - scrollWidth));
$flexTable.css('left', left);
lastBarLeft = barLeft;
$datatable.toggleClass('scrolled-in', barLeft > 2)
.toggleClass('scrolled-out', barLeft < flexWidth - scrollWidth - 2);
if(options.storage) store.pageSet(scrollOffsetStoreName, barLeft);
};
var resizeScrollbar = function() {
flexWidth = $flexArea.width();
$scrollbar.width(flexWidth).css('left', $fixedLeft.width());
tableWidth = 0;
tableWidth = $flexTable.width();
scrollWidth = Math.floor((flexWidth * flexWidth) / tableWidth);
$bar.css('width', scrollWidth);
$flexTable.css('min-width', flexWidth);
$datatable.toggleClass('show-scroll-slide', tableWidth > flexWidth);
if(!firtScroll && flexWidth !== scrollWidth) {
firtScroll = true;
srollTable(store.pageGet(scrollOffsetStoreName, 0), true); // todo: unused?
}
if($datatable.hasClass('size-changing')) {
srollTable(barLeft, true);
}
};
// $scrollbar.resize(resizeScrollbar); // todo: unuseful?
$flexArea.resize(resizeScrollbar);
if(options.storage) resizeScrollbar();
var dragOptions = {
move: false,
stopPropagation: true,
drag: function(e) {
srollTable($bar.position().left + e.smallOffset.x * (e.element.hasClass('bar') ? 1 : -1));
},
finish: function() {
$datatable.removeClass('scrolling');
}
};
if($.fn.draggable) {
$bar.draggable(dragOptions);
if(options.flexHeadDrag) {
$datatable.find('.datatable-head-span.flexarea').draggable(dragOptions);
}
} else {
console.error('DataTable requires draggable.js to improve UI.');
}
$scrollbar.mousedown(function(event) {
var x = event.pageX - $scrollbar.offset().left;
srollTable(x - (scrollWidth / 2));
});
}
// handle row check events
if(options.checkable) {
var checkedStatusStoreName = that.id + '_checkedStatus',
checkedClass = options.checkedClass,
rowId;
var syncChecks = function() {
var $checkRows = $rowsSpans.first().find('.datatable-row');
var $checkedRows = $checkRows.filter('.' + checkedClass);
if(options.checkboxName) $checkRows.find('.check-row input:checkbox').prop('checked', false);
var checkedStatus = {
checkedAll: $checkRows.length === $checkedRows.length && $checkedRows.length > 0,
checks: $checkedRows.map(function() {
rowId = $(this).data('id');
if(options.checkboxName) {
$(this).find('.check-row input:checkbox').prop('checked', true);
}
return rowId;
}).toArray()
};
that.checks = checkedStatus;
$.each(data.rows, function(index, value) {
value.checked = ($.inArray(value.id, checkedStatus.checks) > -1);
});
$headSpans.find('.check-all').toggleClass('checked', !!checkedStatus.checkedAll);
if(options.storage) store.pageSet(checkedStatusStoreName, checkedStatus);
that.callEvent('checksChanged', {
checks: checkedStatus
});
};
var toggleRowClass = function(ele, toggle) {
var $tr = $(ele).closest('tr');
if(toggle === undefined) toggle = !$tr.hasClass(checkedClass);
$rows.filter('[data-index="' + $tr.data('index') + '"]').toggleClass(checkedClass, !!toggle);
};
var checkEventPrefix = 'click.zui.datatable.check';
if(options.selectable) {
var selectableOptions = {
selector: '.datatable-rows .datatable-row',
trigger: '.datatable-rows',
start: function(e) {
var $checkRow = $(e.target).closest('.check-row, .check-btn');
if($checkRow.length) {
if($checkRow.is('.check-row')) {
toggleRowClass($checkRow);
syncChecks();
}
return false;
}
},
rangeFunc: function(range, targetRange) {
return Math.max(range.top, targetRange.top) < Math.min(range.top + range.height, targetRange.top + targetRange.height);
},
select: function(e) {
toggleRowClass(e.target, true);
},
unselect: function(e) {
toggleRowClass(e.target, false);
},
finish: function(e) {
syncChecks();
}
};
if($.isPlainObject(options.selectable)) {
$.extend(selectableOptions, options.selectable);
}
this.$datatable.selectable(selectableOptions);
} else {
this.$rowsSpans.off(checkEventPrefix).on(checkEventPrefix + 'row', options.checkByClickRow ? 'tr' : '.check-row', function() {
toggleRowClass(this);
syncChecks();
});
}
this.$datatable.off(checkEventPrefix).on('click.zui.datatable.check', '.check-all', function() {
$rows.toggleClass(checkedClass, $(this).toggleClass('checked').hasClass('checked'));
syncChecks();
}).on(checkEventPrefix + '.none', '.check-none', function() {
$rows.toggleClass(checkedClass, false);
syncChecks();
}).on(checkEventPrefix + '.inverse', '.check-inverse', function() {
$rows.toggleClass(checkedClass);
syncChecks();
});
if(options.storage) {
var checkedStatus = store.pageGet(checkedStatusStoreName);
if(checkedStatus) {
$headSpans.find('.check-all').toggleClass('checked', checkedStatus.checkedAll);
if(checkedStatus.checkedAll) {
$rows.addClass(checkedClass);
} else {
$rows.removeClass(checkedClass);
$.each(checkedStatus.checks, function(index, ele) {
$rows.filter('[data-id="' + ele + '"]').addClass(checkedClass);
});
}
if(checkedStatus.checks.length) {
syncChecks();
}
}
}
}
// fixed header
if(options.fixedHeader) {
var offsetTop,
height,
scrollTop,
$dataTableHead = $datatable.children('.datatable-head'),
navbarHeight = options.fixedHeaderOffset || $('.navbar.navbar-fixed-top').height() || 0;
var handleScroll = function() {
offsetTop = $datatable.offset().top;
scrollTop = $(window).scrollTop();
height = $datatable.height();
$datatable.toggleClass('head-fixed', (scrollTop + navbarHeight) > offsetTop && (scrollTop + navbarHeight) < (offsetTop + height));
if($datatable.hasClass('head-fixed')) {
$dataTableHead.css({
width: $datatable.width(),
top: navbarHeight
});
} else {
$dataTableHead.attr('style', '');
}
};
$(window).scroll(handleScroll);
handleScroll();
}
// handle sort
if(options.sortable) {
$headSpans.on('click', 'th:not(.sort-disabled, .check-btn)', function() {
if($datatable.hasClass('size-changing')) return;
that.sortTable($(this));
});
if(options.storage) that.sortTable();
} else if(options.mergeRows) {
this.mergeRows();
}
};
DataTable.prototype.mergeRows = function() {
var $cells = this.$rowsSpans.find('.datatable-cell');
var cols = this.data.cols;
for(var i = 0; i < cols.length; i++) {
var col = cols[i];
if(col.mergeRows) {
var $cs = $cells.filter('[data-index="' + i + '"]');
if($cs.length > 1) {
var $lastCell, rowspan;
$cs.each(function() {
var $cell = $(this);
if($lastCell) {
if($cell.html() === $lastCell.html()) {
rowspan = $lastCell.attr('rowspan') || 1;
if(typeof rowspan !== 'number') {
rowspan = parseInt(rowspan);
if(isNaN(rowspan)) rowspan = 1;
}
$lastCell.attr('rowspan', rowspan + 1).css('vertical-align', 'middle');
$cell.remove();
} else {
$lastCell = $cell;
}
} else {
$lastCell = $cell;
}
});
}
}
}
};
// Sort table
DataTable.prototype.sortTable = function($th) {
var store = $.zui.store,
options = this.options;
var sorterStoreName = this.id + '_datatableSorter';
var sorter = options.storage ? store.pageGet(sorterStoreName) : null;
// sort-down: desc
// sort-up: asc
if(!$th) {
if(sorter) {
$th = this.$headCells.filter('[data-index="' + sorter.index + '"]').addClass('sort-' + (sorter.type === 'up' ? 'down' : 'up'));
} else {
$th = this.$headCells.filter('.sort-up, .sort-down').first();
}
}
if(!$th.length) {
return;
}
var data = this.data;
var cols = data.cols,
rows = data.rows,
$headCells = this.$headCells,
sortUp,
type,
index;
sortUp = !$th.hasClass('sort-up');
if(data.keepSort) sortUp = !sortUp;
data.keepSort = null;
$headCells.removeClass('sort-up sort-down');
$th.addClass(sortUp ? 'sort-up' : 'sort-down');
index = $th.data('index');
$.each(cols, function(idx, col) {
if(idx != index && (col.sort === 'up' || col.sort === 'down')) {
col.sort = true;
} else if(idx == index) {
col.sort = sortUp ? 'up' : 'down';
type = col.type;
}
});
var valA, valB, result, $dataRows = this.$dataCells.filter('[data-index="' + index + '"]');
rows.sort(function(cellA, cellB) {
cellA = cellA.data[index];
cellB = cellB.data[index];
valA = $dataRows.filter('[data-row="' + cellA.row + '"]').text();
valB = $dataRows.filter('[data-row="' + cellB.row + '"]').text();
if(type === 'number') {
valA = parseFloat(valA);
valB = parseFloat(valB);
} else if(type === 'date') {
valA = Date.parse(valA);
valB = Date.parse(valB);
} else {
valA = valA.toLowerCase();
valB = valB.toLowerCase();
}
result = valA < valB ? 1 : (valA > valB ? -1 : 0);
if(sortUp) {
result = result * (-1);
}
return result;
});
var $rows = this.$rows,
lastRows = [],
$row, $lastRow, $r;
$.each(rows, function(idx, row) {
$row = $rows.filter('[data-index="' + row.index + '"]');
$row.each(function(rIdx) {
$r = $(this);
$lastRow = lastRows[rIdx];
if($lastRow) {
$lastRow.after($r);
} else {
$r.parent().prepend($r);
}
lastRows[rIdx] = $r;
});
});
sorter = {
index: index,
type: sortUp ? 'up' : 'down'
};
// save sort with local storage
if(options.storage) store.pageSet(sorterStoreName, sorter);
this.callEvent('sort', {
sorter: sorter
});
};
// Refresh size
DataTable.prototype.refreshSize = function() {
var $datatable = this.$datatable,
options = this.options,
rows = this.data.rows,
cols = this.data.cols,
i;
$datatable.find('.datatable-span.fixed-left').css('width', options.fixedLeftWidth);
$datatable.find('.datatable-span.fixed-right').css('width', options.fixedRightWidth);
if(options.fixCellHeight) {
var findMaxHeight = function($cells) {
var mx = 0,
$cell, rowSpan;
$cells.css('height', 'auto');
$cells.each(function() {
$cell = $(this);
rowSpan = $cell.attr('rowspan');
if(!rowSpan || rowSpan == 1) mx = Math.max(mx, $cell.outerHeight());
});
return mx;
};
var $dataCells = this.$dataCells,
$cells = this.$cells,
$headCells = this.$headCells;
// set height of head cells
var headMaxHeight = findMaxHeight($headCells);
$headCells.css('min-height', headMaxHeight).css('height', headMaxHeight);
// set height of data cells
var $rowCells;
for(i = 0; i < rows.length; ++i) {
$rowCells = $dataCells.filter('[data-row="' + i + '"]');
var rowMaxHeight = findMaxHeight($rowCells);
$rowCells.css('min-height', rowMaxHeight).css('height', rowMaxHeight);
}
}
};
// Call event
DataTable.prototype.callEvent = function(name, params) {
var result = this.$.callEvent(name + '.' + this.name, params, this).result;
return !(result !== undefined && (!result));
};
$.fn.datatable = function(option, newData) {
return this.each(function() {
var $this = $(this);
var data = $this.data(name);
var options = typeof option == 'object' && option;
if(!data) $this.data(name, (data = new DataTable(this, options)));
if(typeof option == 'string') {
if(option === 'load' && $.isPlainObject(newData) && (newData.keepSort === undefined || newData.keepSort === null)) newData.keepSort = true;
data[option](newData);
}
});
};
$.fn.datatable.Constructor = DataTable;
}(jQuery));

View File

@@ -0,0 +1,6 @@
/*!
* ZUI: 数据表格 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/.datatable-head,.datatable-rows{display:table;width:100%;table-layout:fixed}.datatable{margin-bottom:20px}.datatable>.datatable-head{-webkit-transition:-webkit-box-shadow .2s;-o-transition:box-shadow .2s;transition:-webkit-box-shadow .2s;transition:box-shadow .2s;transition:box-shadow .2s,-webkit-box-shadow .2s}.datatable .table{margin:0;table-layout:fixed}.datatable .table>tbody>tr>td,.datatable .table>thead>tr>th{min-width:20px}.datatable .table>tbody>tr>td.check-btn,.datatable .table>thead>tr>th.check-btn{width:30px;color:#9b9b9b;text-align:center;cursor:pointer}.datatable .table>tbody>tr.active>td.check-btn,.datatable .table>tbody>tr.hover>td.check-btn,.datatable .table>tbody>tr>td.check-btn.checked,.datatable .table>tbody>tr>td.check-btn:hover,.datatable .table>thead>tr>th.check-btn.checked,.datatable .table>thead>tr>th.check-btn:hover{color:#4f4f4f}.datatable .table>tbody>tr.active>td.check-btn>.icon-check-empty:before,.datatable .table>tbody>tr>td.check-btn.checked>.icon-check-empty:before,.datatable .table>thead>tr>th.check-btn.checked>.icon-check-empty:before{content:'\e642'}.datatable .table>thead>tr>th.col-hover{background-color:#e2e2e2}.datatable .table>tbody>tr.hover>td,.datatable .table>tbody>tr>td.col-hover{background-color:#ebf2f9}.datatable .table>tbody>tr.active.hover td{background-color:#ffdea2}.datatable.head-fixed>.datatable-head{position:fixed;z-index:1030;-webkit-box-shadow:0 1px 4px 0 rgba(0,0,0,.15);box-shadow:0 1px 4px 0 rgba(0,0,0,.15)}.datatable.sortable .datatable-head-span .table>thead>tr>th{overflow:hidden;white-space:nowrap;cursor:pointer}.datatable.sortable .datatable-head-span .table>thead>tr>th.text-center{padding-right:0;padding-left:0}.datatable.sortable .datatable-head-span .table>thead>tr>th:after{display:inline-block;margin-left:5px;font-family:ZenIcon;font-size:14px;font-style:normal;font-weight:400;font-variant:normal;line-height:1;color:grey;text-transform:none;content:'\e6bd';speak:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.datatable.sortable .datatable-head-span .table>thead>tr>th.sort-down:after{color:#145ccd;content:'\e6b8'}.datatable.sortable .datatable-head-span .table>thead>tr>th.sort-up:after{color:#145ccd;content:'\e6b9'}.datatable.sortable .datatable-head-span .table>thead>tr>th.check-btn:after,.datatable.sortable .datatable-head-span .table>thead>tr>th.sort-disabled:after{display:none}.datatable.sortable .datatable-head-span .table>thead>tr>th.sort-disabled{cursor:default}.datatable-wrapper{position:relative}.datatable-span{display:table-cell;vertical-align:top}.datatable-span.flexarea{overflow:hidden}.datatable-span.flexarea.datatable-head-span.dragging{cursor:move!important}.datatable-span.flexarea .table{position:relative;top:0;left:0}.datatable-span.flexarea .scrolled-shadow{position:absolute;top:0;bottom:0;display:none;width:20px;-webkit-box-shadow:0 0 10px rgba(0,0,0,.15);box-shadow:0 0 10px rgba(0,0,0,.15);opacity:0;-webkit-transition:all .4s cubic-bezier(.175,.885,.32,1);-o-transition:all .4s cubic-bezier(.175,.885,.32,1);transition:all .4s cubic-bezier(.175,.885,.32,1)}.datatable-span.flexarea .scrolled-in-shadow{left:-30px}.datatable-span.flexarea .scrolled-out-shadow{right:-30px}.datatable>.scroll-wrapper{position:relative;width:100%}.datatable .scroll-slide{position:absolute;right:-1px;bottom:0;left:-1px;display:none;height:11px;background:#e5e5e5;background:rgba(128,128,128,.1);border:1px solid #e5e5e5;border-bottom:none;opacity:0;-webkit-transition:opacity .5s,background .3s;-o-transition:opacity .5s,background .3s;transition:opacity .5s,background .3s}.datatable .scroll-slide>.bar{position:absolute;top:0;left:0;min-width:50px;height:10px;cursor:move;background-color:#a6a6a6}.datatable .scroll-slide:hover>.bar{background-color:grey}.datatable .scroll-slide.scroll-pos-out{bottom:-14px;height:15px}.datatable .scroll-slide.scroll-pos-out>.bar{height:14px}.datatable.show-scroll-slide.scrolling .scroll-slide,.datatable.show-scroll-slide.scrolling .scrolled-shadow,.datatable.show-scroll-slide:hover .scroll-slide,.datatable.show-scroll-slide:hover .scrolled-shadow{opacity:1}.datatable.show-scroll-slide .scroll-slide,.datatable.show-scroll-slide .scrolled-shadow{display:block}.datatable.show-scroll-slide.scrolled-in .scrolled-in-shadow{left:-20px}.datatable.show-scroll-slide.scrolled-out .scrolled-out-shadow{right:-20px}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,239 @@
/*!
* Datetimepicker for Bootstrap
* Copyright 2012 Stefan Petre
* Licensed under the Apache License v2.0
*/
.datetimepicker {
padding: 4px;
margin-top: 1px;
white-space: normal;
border-radius: 4px;
direction: ltr;
}
.datetimepicker.datetimepicker-rtl {
direction: rtl;
}
.datetimepicker.datetimepicker-rtl table tr td span {
float: right;
}
.datetimepicker > div {
display: none;
}
.datetimepicker.minutes div.datetimepicker-minutes {
display: block;
}
.datetimepicker.hours div.datetimepicker-hours {
display: block;
}
.datetimepicker.days div.datetimepicker-days {
display: block;
}
.datetimepicker.months div.datetimepicker-months {
display: block;
}
.datetimepicker.years div.datetimepicker-years {
display: block;
}
.datetimepicker table {
margin: 0;
}
.datetimepicker table tr td.minute:hover {
cursor: pointer;
background: #eee;
}
.datetimepicker table tr td.hour:hover {
cursor: pointer;
background: #eee;
}
.datetimepicker table tr td.day:hover {
cursor: pointer;
background: #eee;
}
.datetimepicker table tr td span {
display: block;
float: left;
width: 23%;
height: 54px;
margin: 1%;
line-height: 54px;
cursor: pointer;
border-radius: 4px;
}
.datetimepicker table tr td span:hover {
background: #eee;
}
.datetimepicker table tr td span.old {
color: #999;
}
.datetimepicker .datetimepicker-hours span {
height: 26px;
line-height: 26px;
}
.datetimepicker .datetimepicker-minutes span {
height: 26px;
line-height: 26px;
}
.datetimepicker th.switch {
width: 145px;
}
.datetimepicker-inline {
width: 220px;
}
.datetimepicker-dropdown,
.datetimepicker-dropdown-left {
top: 0;
left: 0;
}
[class*="datetimepicker-dropdown"]:before {
position: absolute;
display: inline-block;
content: '';
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-bottom-color: rgba(0, 0, 0, .2);
border-left: 7px solid transparent;
}
[class*="datetimepicker-dropdown"]:after {
position: absolute;
display: inline-block;
content: '';
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-left: 6px solid transparent;
}
[class*="datetimepicker-dropdown-top"]:before {
display: inline-block;
content: '';
border-top: 7px solid #ccc;
border-top-color: rgba(0, 0, 0, .2);
border-right: 7px solid transparent;
border-bottom: 0;
border-left: 7px solid transparent;
}
[class*="datetimepicker-dropdown-top"]:after {
display: inline-block;
content: '';
border-top: 6px solid #fff;
border-right: 6px solid transparent;
border-bottom: 0;
border-left: 6px solid transparent;
}
.datetimepicker-dropdown-bottom-left:before {
top: -7px;
right: 6px;
}
.datetimepicker-dropdown-bottom-left:after {
top: -6px;
right: 7px;
}
.datetimepicker-dropdown-bottom-right:before {
top: -7px;
left: 6px;
}
.datetimepicker-dropdown-bottom-right:after {
top: -6px;
left: 7px;
}
.datetimepicker-dropdown-top-left:before {
right: 6px;
bottom: -7px;
}
.datetimepicker-dropdown-top-left:after {
right: 7px;
bottom: -6px;
}
.datetimepicker-dropdown-top-right:before {
bottom: -7px;
left: 6px;
}
.datetimepicker-dropdown-top-right:after {
bottom: -6px;
left: 7px;
}
.datetimepicker td,
.datetimepicker th {
width: 22px;
height: 20px;
padding: 3px 0;
text-align: center;
border: none;
border-radius: 4px;
}
.table-striped .datetimepicker td,
.table-striped .datetimepicker th {
background-color: transparent;
}
.datetimepicker td.old,
.datetimepicker td.new {
color: #999;
}
.datetimepicker td.disabled,
.datetimepicker td.disabled:hover {
color: #999;
cursor: default;
background: none;
}
.datetimepicker td.day.today {
color: #fff;
background-color: #f1a325;
border-color: #f1a325;
border-color: rgba(0, 0, 0, .1) rgba(0, 0, 0, .1) rgba(0, 0, 0, .25);
}
.datetimepicker td.day.active {
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
background-color: #3280fc;
border-color: #0462f7;
border-color: rgba(0, 0, 0, .1) rgba(0, 0, 0, .1) rgba(0, 0, 0, .25);
}
.datetimepicker td.day.active:hover {
background-color: #0462f7;
}
.datetimepicker td.day.today:hover,
.datetimepicker td.day.today.active:hover {
background-color: #d5890e;
}
.datetimepicker .datetimepicker-hours td span.hour_am,
.datetimepicker .datetimepicker-hours td span.hour_pm {
width: 14.6%;
}
.datetimepicker .datetimepicker-hours fieldset legend,
.datetimepicker .datetimepicker-minutes fieldset legend {
margin-bottom: inherit;
line-height: 30px;
}
.datetimepicker td span.disabled,
.datetimepicker td span.disabled:hover {
color: #999;
cursor: default;
background: none;
}
.datetimepicker td span.active,
.datetimepicker td span.active:hover,
.datetimepicker td span.active.disabled,
.datetimepicker td span.active.disabled:hover {
color: #fff;
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
background-color: #3280fc;
border-color: #0462f7;
border-color: rgba(0, 0, 0, .1) rgba(0, 0, 0, .1) rgba(0, 0, 0, .25);
}
.datetimepicker thead tr:first-child th,
.datetimepicker tfoot tr:first-child th {
cursor: pointer;
}
.datetimepicker thead tr:first-child th:hover,
.datetimepicker tfoot tr:first-child th:hover {
background: #eee;
}
.input-group.date > .input-group-addon {
border-left: none;
}
.input-append.date .add-on i,
.input-prepend.date .add-on i,
.input-group.date .input-group-addon span {
width: 14px;
height: 14px;
cursor: pointer;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
/*!
* Datetimepicker for Bootstrap
* Copyright 2012 Stefan Petre
* Licensed under the Apache License v2.0
*/.datetimepicker{padding:4px;margin-top:1px;white-space:normal;border-radius:4px;direction:ltr}.datetimepicker.datetimepicker-rtl{direction:rtl}.datetimepicker.datetimepicker-rtl table tr td span{float:right}.datetimepicker>div{display:none}.datetimepicker.minutes div.datetimepicker-minutes{display:block}.datetimepicker.hours div.datetimepicker-hours{display:block}.datetimepicker.days div.datetimepicker-days{display:block}.datetimepicker.months div.datetimepicker-months{display:block}.datetimepicker.years div.datetimepicker-years{display:block}.datetimepicker table{margin:0}.datetimepicker table tr td.minute:hover{cursor:pointer;background:#eee}.datetimepicker table tr td.hour:hover{cursor:pointer;background:#eee}.datetimepicker table tr td.day:hover{cursor:pointer;background:#eee}.datetimepicker table tr td span{display:block;float:left;width:23%;height:54px;margin:1%;line-height:54px;cursor:pointer;border-radius:4px}.datetimepicker table tr td span:hover{background:#eee}.datetimepicker table tr td span.old{color:#999}.datetimepicker .datetimepicker-hours span{height:26px;line-height:26px}.datetimepicker .datetimepicker-minutes span{height:26px;line-height:26px}.datetimepicker th.switch{width:145px}.datetimepicker-inline{width:220px}.datetimepicker-dropdown,.datetimepicker-dropdown-left{top:0;left:0}[class*=datetimepicker-dropdown]:before{position:absolute;display:inline-block;content:'';border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);border-left:7px solid transparent}[class*=datetimepicker-dropdown]:after{position:absolute;display:inline-block;content:'';border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent}[class*=datetimepicker-dropdown-top]:before{display:inline-block;content:'';border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);border-right:7px solid transparent;border-bottom:0;border-left:7px solid transparent}[class*=datetimepicker-dropdown-top]:after{display:inline-block;content:'';border-top:6px solid #fff;border-right:6px solid transparent;border-bottom:0;border-left:6px solid transparent}.datetimepicker-dropdown-bottom-left:before{top:-7px;right:6px}.datetimepicker-dropdown-bottom-left:after{top:-6px;right:7px}.datetimepicker-dropdown-bottom-right:before{top:-7px;left:6px}.datetimepicker-dropdown-bottom-right:after{top:-6px;left:7px}.datetimepicker-dropdown-top-left:before{right:6px;bottom:-7px}.datetimepicker-dropdown-top-left:after{right:7px;bottom:-6px}.datetimepicker-dropdown-top-right:before{bottom:-7px;left:6px}.datetimepicker-dropdown-top-right:after{bottom:-6px;left:7px}.datetimepicker td,.datetimepicker th{width:22px;height:20px;padding:3px 0;text-align:center;border:none;border-radius:4px}.table-striped .datetimepicker td,.table-striped .datetimepicker th{background-color:transparent}.datetimepicker td.new,.datetimepicker td.old{color:#999}.datetimepicker td.disabled,.datetimepicker td.disabled:hover{color:#999;cursor:default;background:0 0}.datetimepicker td.day.today{color:#fff;background-color:#f1a325;border-color:#f1a325;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}.datetimepicker td.day.active{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#3280fc;border-color:#0462f7;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}.datetimepicker td.day.active:hover{background-color:#0462f7}.datetimepicker td.day.today.active:hover,.datetimepicker td.day.today:hover{background-color:#d5890e}.datetimepicker .datetimepicker-hours td span.hour_am,.datetimepicker .datetimepicker-hours td span.hour_pm{width:14.6%}.datetimepicker .datetimepicker-hours fieldset legend,.datetimepicker .datetimepicker-minutes fieldset legend{margin-bottom:inherit;line-height:30px}.datetimepicker td span.disabled,.datetimepicker td span.disabled:hover{color:#999;cursor:default;background:0 0}.datetimepicker td span.active,.datetimepicker td span.active.disabled,.datetimepicker td span.active.disabled:hover,.datetimepicker td span.active:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#3280fc;border-color:#0462f7;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}.datetimepicker tfoot tr:first-child th,.datetimepicker thead tr:first-child th{cursor:pointer}.datetimepicker tfoot tr:first-child th:hover,.datetimepicker thead tr:first-child th:hover{background:#eee}.input-group.date>.input-group-addon{border-left:none}.input-append.date .add-on i,.input-group.date .input-group-addon span,.input-prepend.date .add-on i{width:14px;height:14px;cursor:pointer}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,179 @@
/* ========================================================================
* jQuery Hotkeys Plugin
* Based upon the plugin by Tzury Bar Yochay:
* https://github.com/tzuryby/jquery.hotkeys
*
* ZUI: The file has been changed in ZUI. It will not keep update with the
* official version in the future.
* http://zui.sexy
* ========================================================================
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* Original idea by:
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
* ======================================================================== */
/*!
* jQuery Hotkeys Plugin
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Based upon the plugin by Tzury Bar Yochay:
* http://github.com/tzuryby/hotkeys
*
* Original idea by:
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
*/
(function(jQuery) {
jQuery.hotkeys = {
version: "0.8",
specialKeys: {
8: "backspace",
9: "tab",
13: "return",
16: "shift",
17: "ctrl",
18: "alt",
19: "pause",
20: "capslock",
27: "esc",
32: "space",
33: "pageup",
34: "pagedown",
35: "end",
36: "home",
37: "left",
38: "up",
39: "right",
40: "down",
45: "insert",
46: "del",
96: "0",
97: "1",
98: "2",
99: "3",
100: "4",
101: "5",
102: "6",
103: "7",
104: "8",
105: "9",
106: "*",
107: "+",
109: "-",
110: ".",
111: "/",
112: "f1",
113: "f2",
114: "f3",
115: "f4",
116: "f5",
117: "f6",
118: "f7",
119: "f8",
120: "f9",
121: "f10",
122: "f11",
123: "f12",
144: "numlock",
145: "scroll",
191: "/",
224: "meta"
},
shiftNums: {
"`": "~",
"1": "!",
"2": "@",
"3": "#",
"4": "$",
"5": "%",
"6": "^",
"7": "&",
"8": "*",
"9": "(",
"0": ")",
"-": "_",
"=": "+",
";": ": ",
"'": "\"",
",": "<",
".": ">",
"/": "?",
"\\": "|"
}
};
function keyHandler(handleObj) {
// Only care when a possible input has been specified
if(typeof handleObj.data !== "string") {
return;
}
var origHandler = handleObj.handler,
keys = handleObj.data.toLowerCase().split(" ");
handleObj.handler = function(event) {
// Don't fire in text-accepting inputs that we didn't directly bind to
if(this !== event.target && (/textarea|select/i.test(event.target.nodeName) ||
event.target.type === "text")) {
return;
}
// Keypress represents characters, not special keys
var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[event.which],
character = String.fromCharCode(event.which).toLowerCase(),
key, modif = "",
possible = {};
// check combinations (alt|ctrl|shift+anything)
if(event.altKey && special !== "alt") {
modif += "alt+";
}
if(event.ctrlKey && special !== "ctrl") {
modif += "ctrl+";
}
// TODO: Need to make sure this works consistently across platforms
if(event.metaKey && !event.ctrlKey && special !== "meta") {
modif += "meta+";
}
if(event.shiftKey && special !== "shift") {
modif += "shift+";
}
if(special) {
possible[modif + special] = true;
} else {
possible[modif + character] = true;
possible[modif + jQuery.hotkeys.shiftNums[character]] = true;
// "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
if(modif === "shift+") {
possible[jQuery.hotkeys.shiftNums[character]] = true;
}
}
for(var i = 0, l = keys.length; i < l; i++) {
if(possible[keys[i]]) {
return origHandler.apply(this, arguments);
}
}
};
}
jQuery.each(["keydown", "keyup", "keypress"], function() {
jQuery.event.special[this] = {
add: keyHandler
};
});
})(jQuery);

12
root/res/zui/lib/hotkey/hotkey.min.js vendored Normal file
View File

@@ -0,0 +1,12 @@
/*!
* jQuery Hotkeys Plugin
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Based upon the plugin by Tzury Bar Yochay:
* http://github.com/tzuryby/hotkeys
*
* Original idea by:
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
*/
!function(e){function t(t){if("string"==typeof t.data){var s=t.handler,a=t.data.toLowerCase().split(" ");t.handler=function(t){if(this===t.target||!/textarea|select/i.test(t.target.nodeName)&&"text"!==t.target.type){var r="keypress"!==t.type&&e.hotkeys.specialKeys[t.which],f=String.fromCharCode(t.which).toLowerCase(),i="",h={};t.altKey&&"alt"!==r&&(i+="alt+"),t.ctrlKey&&"ctrl"!==r&&(i+="ctrl+"),t.metaKey&&!t.ctrlKey&&"meta"!==r&&(i+="meta+"),t.shiftKey&&"shift"!==r&&(i+="shift+"),r?h[i+r]=!0:(h[i+f]=!0,h[i+e.hotkeys.shiftNums[f]]=!0,"shift+"===i&&(h[e.hotkeys.shiftNums[f]]=!0));for(var o=0,c=a.length;o<c;o++)if(h[a[o]])return s.apply(this,arguments)}}}}e.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",191:"/",224:"meta"},shiftNums:{"`":"~",1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(",0:")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"}},e.each(["keydown","keyup","keypress"],function(){e.event.special[this]={add:t}})}(jQuery);

File diff suppressed because one or more lines are too long

8
root/res/zui/lib/ieonly/html5shiv.js vendored Normal file
View File

@@ -0,0 +1,8 @@
/*
HTML5 Shiv v3.7.0 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/[\w\-]+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}</style>";
c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||
"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:"3.7.0",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);
if(g)return a.createDocumentFragment();for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);

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