优化首页内容

This commit is contained in:
georgehao
2019-07-06 17:05:19 +08:00
parent 37fb659c4e
commit 6a30e9265c
49 changed files with 1060 additions and 729 deletions

View File

@@ -1,12 +1,15 @@
PPGo_Job定时任务管理系统 V2.x
PPGo_Job定时任务管理系统
====
![](http://www.haodaquan.com/Uploads/article/2018-07-26/153262059813931.png)
PPGo_Job是一款定时任务可视化的、多人多权限的管理系统采用golang开发安装方便资源消耗少支持大并发可同时管理多台服务器上的定时任务。
##说明
PPGo_Job是一款轻量级定时任务管理系统go语言开发部署超级简单资源消耗少运行稳定。
支持定时任务可视化管理、多人多权限的管理,支持大并发,可同时管理多台服务器上的定时任务。
PPGo_Job从v1.0开源以来,得到众多技术朋友的支持和欢迎,已应用在多个公司的生产环境,同时也
吸收使用者的建议和意见不断改进和优化目前已经上线了20余个版本9个稳定版本生产环境部署完成后才发布新版本
前言PPGo_Job V1.x版本开源两年多了不少朋友的公司都在用反响还不错当然也有好多朋友提了不少合理的意见和建议所以这次干脆重构了一下连UI也重新编码。目前V2.x版本
已经用于生产环境。
码云地址https://gitee.com/georgehao/PPGo_Job
Github地址:https://github.com/george518/PPGo_Job
@@ -14,11 +17,15 @@ Github地址:https://github.com/george518/PPGo_Job
文档地址http://www.haodaquan.com/topics/1###
Wiki:https://github.com/george518/PPGo_Job/wiki
##架构
V1.x版本是一个简单的定时任务管理系统进入V1.0 https://github.com/george518/PPGo_Job/releases/tag/v1.2.1
相对于V1.x版本V2.0新增以下功能和特性:
![](http://www.haodaquan.com/Uploads/editormd/2019-07-06/156240332990478.png)
- 1、全新UI,基于LayUI2.3构建全新页面后端模板手工搭建让操作更加人性化。后台模板地址https://github.com/george518/PP_admin-template
##特性
V2.x新增以下功能和特性
- 1、全新UI,基于LayUI构建全新页面后端模板手工搭建让操作更加人性化。后台模板地址https://github.com/george518/PP_admin-template
- 2、新增权限管理功能根据菜单权限、操作权限和数据权限进行划分方便多用户多权限管理定时任务。
- 3、新增服务器复制功能让服务器资源添加更加方便。
- 4、新增定时任务详情页面将任务相关操作更加集中起来操作。
@@ -29,13 +36,16 @@ V1.x版本是一个简单的定时任务管理系统进入V1.0 https://git
- 9、支持windows系统运行定时系统不歧视windows也要支持。
- 10、提醒信息新增钉钉和微信通知功能并支持编辑通知模版功能。让提醒内容个性化不再死板。
- 11、新增创建、启动、关闭任务的API通过接口的方式控制定时任务猜你喜欢。
- 12、**新增任务执行器agent可以通过sshtelnet或者agent的方式分发任务**
总之管理定时任务使用PPGo_Job吧节省出来的时间或皮或浪随你,哈哈
总之管理定时任务使用PPGo_Job吧节省出来的时间或皮或浪随你。
感觉不错的话,给个星星吧
也可以请我喝水
##支持
----
####1、给项目一个star
####2、请我喝瓶水
![github](https://github.com/george518/PP_blog/blob/master/static/public/images/weixin.png?raw=true "github")
先看效果

View File

@@ -1,8 +0,0 @@
package main
//任务执行器
//
func main() {
}

BIN
agent/agent Executable file

Binary file not shown.

View File

@@ -6,19 +6,18 @@ Version = 1.0.0
LogLevel = ALL
# 执行器配置
# auto-自动起名,或者自己起名
ServerName = agent-10.32.40.165-1564
ServerName = agent-192.168.1.101-1564
# 启动后回写
ServerId = 7
ServerId = 4
# 端口,必须配置!!
TcpPort = 1564
# auto-自动获取
TcpIp = 10.32.40.165
TcpIp = 192.168.1.101
# Ip地址是外网还是内网1-外网0-内网若填写TcpIp则本项配置无意义
IpType = 0
# 添加的执行器属于分组Id默认为1
GroupId = 1
# 以下配置必填地址格式http://yourdomain/server/apisave
RegisterUrl = http://localhost:8081/server/apisave
UpdateStatusUrl = http://localhost:8081/server/apistatus
RegisterUrl = http://localhost:8080/server/apisave
UpdateStatusUrl = http://localhost:8080/server/apistatus

View File

@@ -80,8 +80,8 @@ func ResetCommandJob(id int, serverId int, name string, command string) *Job {
err, isTimeout := runCmdWithTimeout(cmd, timeout)
jobResult = new(JobResult)
jobResult.ErrMsg = libs.GbkAsUtf8(bufErr.String())
jobResult.OutMsg = libs.GbkAsUtf8(bufOut.String())
jobResult.ErrMsg = bufErr.String()
jobResult.OutMsg = bufOut.String()
jobResult.IsOk = true
if err != nil {
jobResult.IsOk = false

15
agent/test/sqls/ts.go Normal file
View File

@@ -0,0 +1,15 @@
/************************************************************
** @Description: ts
** @Author: george hao
** @Date: 2019-07-04 17:23
** @Last Modified by: george hao
** @Last Modified time: 2019-07-04 17:23
*************************************************************/
package main
import "github.com/george518/PPGo_Job/models"
func main() {
models.TaskTotalRunNum()
}

BIN
assets/screenshot/ppgo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

@@ -1,9 +1,9 @@
AppName = PPGo_Job2
HTTPPort = 8081
HTTPPort = 8080
RunMode = dev
SessionOn = true
version= V2.7
version= V2.8
# 允许同时运行的任务数
jobs.pool = 1000
@@ -19,7 +19,7 @@ db.host = 127.0.0.1
db.user = root
db.password = "123456"
db.port = 3306
db.name = cron
db.name = ppgo_job3
db.prefix = pp_
db.timezone = Asia/Shanghai

View File

@@ -13,6 +13,9 @@ import (
"github.com/george518/PPGo_Job/libs"
"github.com/george518/PPGo_Job/models"
"runtime"
"sort"
"strconv"
//"strconv"
"time"
)
@@ -34,9 +37,47 @@ func (self *HomeController) Help() {
}
func (self *HomeController) Start() {
//总任务数量
_, count := models.TaskGetList(1, 10)
self.Data["totalJob"] = count
//日志总量
_, totalLog := models.TaskLogGetList(1, 10)
self.Data["totalLog"] = totalLog
//待审核任务数量
_, totalAuditTask := models.TaskGetList(1, 10, "status", 2)
self.Data["totalAuditTask"] = totalAuditTask
//失败
errorNum, err := models.GetLogNum(-1)
if err != nil {
errorNum = 0
}
self.Data["errorNum"] = errorNum
//成功
successNum, err := models.GetLogNum(0)
if err != nil {
successNum = 0
}
self.Data["successNum"] = successNum
//用户数
_, userNum := models.AdminGetList(1, 10, "status", 1)
self.Data["userNum"] = userNum
//累计运行总次数
n, err := models.TaskTotalRunNum()
if err != nil {
n = 0
}
self.Data["TaskTotalRunNum"] = n
groups_map := serverGroupLists(self.serverGroups, self.userId)
//计算总任务数量
_, count := models.TaskGetList(1, 300)
// 即将执行的任务
entries := jobs.GetEntries(30)
jobList := make([]map[string]interface{}, len(entries))
@@ -53,35 +94,10 @@ func (self *HomeController) Start() {
startJob++
}
// 最近执行的日志
logs, _ := models.TaskLogGetList(1, 20)
recentLogs := make([]map[string]interface{}, len(logs))
failJob := 0 //最近失败的数量
okJob := 0 //最近成功的数量
for k, v := range logs {
task, err := models.TaskGetById(v.TaskId)
taskName := ""
if err == nil {
taskName = task.TaskName
}
row := make(map[string]interface{})
row["task_name"] = taskName
row["id"] = v.Id
row["start_time"] = beego.Date(time.Unix(v.CreateTime, 0), "Y-m-d H:i:s")
row["process_time"] = float64(v.ProcessTime) / 1000
row["ouput_size"] = libs.SizeFormat(float64(len(v.Output)))
row["output"] = beego.Substr(v.Output, 0, 100)
row["status"] = v.Status
recentLogs[k] = row
if v.Status != 0 {
failJob++
} else {
okJob++
}
}
self.Data["recentLogs"] = jobList
// 最近执行失败的日志
logs, _ = models.TaskLogGetList(1, 20, "status__lt", 0)
logs, _ := models.TaskLogGetList(1, 30, "status__lt", 0)
errLogs := make([]map[string]interface{}, len(logs))
for k, v := range logs {
@@ -102,15 +118,61 @@ func (self *HomeController) Start() {
errLogs[k] = row
}
self.Data["errLogs"] = errLogs
self.Data["startJob"] = startJob
self.Data["okJob"] = okJob
self.Data["failJob"] = failJob
self.Data["totalJob"] = count
self.Data["recentLogs"] = recentLogs
// this.Data["errLogs"] = errLogs
self.Data["jobs"] = jobList
//折线图
okRun := models.SumByDays(30, "0")
errRun := models.SumByDays(30, "-1")
expiredRun := models.SumByDays(30, "-2")
days := []string{}
okNum := []int64{}
errNum := []int64{}
expiredNum := []int64{}
type kv struct {
Key string
Value int64
}
//排序
var ss []kv
for k, v := range okRun {
i, _ := strconv.ParseInt(v.(string), 10, 64)
ss = append(ss, kv{k, i})
}
sort.Slice(ss, func(i, j int) bool {
return ss[i].Key < ss[j].Key
})
for _, v := range ss {
days = append(days, v.Key)
okNum = append(okNum, v.Value)
if _, ok := errRun[v.Key]; ok {
i, _ := strconv.ParseInt(errRun[v.Key].(string), 10, 64)
errNum = append(errNum, i)
} else {
errNum = append(errNum, 0)
}
if _, ok := expiredRun[v.Key]; ok {
i, _ := strconv.ParseInt(expiredRun[v.Key].(string), 10, 64)
expiredNum = append(expiredNum, i)
} else {
expiredNum = append(expiredNum, 0)
}
}
self.Data["days"] = days
self.Data["okNum"] = okNum
self.Data["errNum"] = errNum
self.Data["expiredNum"] = expiredNum
self.Data["cpuNum"] = runtime.NumCPU()
//系统运行信息

View File

@@ -11,6 +11,8 @@ import (
"strings"
"time"
"fmt"
"strconv"
"github.com/astaxie/beego"
@@ -53,6 +55,7 @@ func (self *ServerGroupController) AjaxSave() {
servergroup_id, _ := self.GetInt("id")
fmt.Println(servergroup_id)
if servergroup_id == 0 {
//新增
servergroup.CreateTime = time.Now().Unix()

View File

@@ -223,7 +223,7 @@ func (self *TaskController) Detail() {
//任务分组
groupName := "默认分组"
if task.GroupId > 0 {
group, err := models.TaskGroupGetById(task.GroupId)
group, err := models.GroupGetById(task.GroupId)
if err == nil {
groupName = group.GroupName
}

View File

@@ -187,7 +187,7 @@ func (self *TaskLogController) Detail() {
//任务分组
groupName := "默认分组"
if task.GroupId > 0 {
group, err := models.TaskGroupGetById(task.GroupId)
group, err := models.GroupGetById(task.GroupId)
if err == nil {
groupName = group.GroupName
}

View File

@@ -192,8 +192,8 @@ func NewCommandJob(id int, serverId int, name string, command string) *Job {
cmd.Start()
err, isTimeout := runCmdWithTimeout(cmd, timeout)
jobresult = new(JobResult)
jobresult.OutMsg = libs.GbkAsUtf8(bufOut.String())
jobresult.ErrMsg = libs.GbkAsUtf8(bufErr.String())
jobresult.OutMsg = bufOut.String()
jobresult.ErrMsg = bufErr.String()
jobresult.IsOk = true
if err != nil {

View File

@@ -79,5 +79,5 @@ func GbkAsUtf8(str string) string {
//任务识别码
func JobKey(taskId, serverId int) int {
return taskId*10000000 + serverId
return taskId*100000 + serverId
}

View File

@@ -21,7 +21,6 @@ func init() {
var StartTime = time.Now().Unix()
models.Init(StartTime)
jobs.InitJobs()
}
func main() {

View File

@@ -9,6 +9,7 @@ package models
import (
"fmt"
"strconv"
"time"
"github.com/astaxie/beego/orm"
@@ -116,3 +117,25 @@ func TaskDel(id int) (int64, error) {
//_, err := orm.NewOrm().QueryTable(TableName("task")).Filter("id", id).Delete()
//return err
}
//运行总次数
func TaskTotalRunNum() (int64, error) {
res := make(orm.Params)
_, err := orm.NewOrm().Raw("select sum(execute_times) as num,task_name from pp_task").RowsToMap(&res, "num", "task_name")
if err != nil {
return 0, err
}
for k, _ := range res {
i64, err := strconv.ParseInt(k, 10, 64)
if err != nil {
return 0, err
}
return i64, nil
}
return 0, nil
}

View File

@@ -71,8 +71,22 @@ func TaskLogDelByTaskId(taskId int) (int64, error) {
return orm.NewOrm().QueryTable(TableName("task_log")).Filter("task_id", taskId).Delete()
}
// func GetTodaySuccessNum() (num, error) {
// o := orm.NewOrm()
// var r RawSeter
// r = o.Raw("SELECT COUNT(*) AS num WHERE create_time>=? AND status<0", "")
// }
func GetLogNum(status int) (int64, error) {
return orm.NewOrm().QueryTable(TableName("task_log")).Filter("status", status).Count()
}
type SumDays struct {
Day string
Sum int
}
func SumByDays(limit int, status string) orm.Params {
res := make(orm.Params)
_, err := orm.NewOrm().Raw("SELECT FROM_UNIXTIME(create_time,'%Y-%m-%d') days,COUNT(id) count FROM pp_task_log WHERE status in(?) GROUP BY days ORDER BY days DESC limit ?;",
status, limit).RowsToMap(&res, "days", "count")
if err != nil {
return nil
}
return res
}

View File

@@ -331,15 +331,15 @@ ALTER TABLE `pp_task_server` ADD `connection_type` TINYINT(1) NOT NULL DEFAULT '
COMMIT;
BEGIN;
ALTER TABLE `ppgo_job2`.`pp_task` CHANGE COLUMN `server_id` `server_ids` varchar(200) NOT NULL DEFAULT '0' COMMENT '服务器id字符串英文都好隔开';
ALTER TABLE `pp_task` CHANGE COLUMN `server_id` `server_ids` varchar(200) NOT NULL DEFAULT '0' COMMENT '服务器id字符串英文都好隔开';
COMMIT;
BEGIN;
ALTER TABLE `ppgo_job2`.`pp_task_log` ADD COLUMN `server_id` int(11) NOT NULL DEFAULT '-1' COMMENT '服务器ID-1异常' AFTER `task_id`, CHANGE COLUMN `output` `output` mediumtext NOT NULL COMMENT '任务输出' AFTER `server_id`, CHANGE COLUMN `error` `error` text NOT NULL COMMENT '错误信息' AFTER `output`, CHANGE COLUMN `status` `status` tinyint(4) NOT NULL COMMENT '状态' AFTER `error`, CHANGE COLUMN `process_time` `process_time` int(11) NOT NULL DEFAULT '0' COMMENT '消耗时间/毫秒' AFTER `status`, CHANGE COLUMN `create_time` `create_time` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间' AFTER `process_time`;
ALTER TABLE `ppgo_job2`.`pp_task_log` ADD COLUMN `server_name` varchar(60) NOT NULL DEFAULT '\"\"' COMMENT '服务器名称' AFTER `server_id`, CHANGE COLUMN `output` `output` mediumtext NOT NULL COMMENT '任务输出' AFTER `server_name`, CHANGE COLUMN `error` `error` text NOT NULL COMMENT '错误信息' AFTER `output`, CHANGE COLUMN `status` `status` tinyint(4) NOT NULL COMMENT '状态' AFTER `error`, CHANGE COLUMN `process_time` `process_time` int(11) NOT NULL DEFAULT '0' COMMENT '消耗时间/毫秒' AFTER `status`, CHANGE COLUMN `create_time` `create_time` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间' AFTER `process_time`;
ALTER TABLE `pp_task_log` ADD COLUMN `server_id` int(11) NOT NULL DEFAULT '-1' COMMENT '服务器ID-1异常' AFTER `task_id`, CHANGE COLUMN `output` `output` mediumtext NOT NULL COMMENT '任务输出' AFTER `server_id`, CHANGE COLUMN `error` `error` text NOT NULL COMMENT '错误信息' AFTER `output`, CHANGE COLUMN `status` `status` tinyint(4) NOT NULL COMMENT '状态' AFTER `error`, CHANGE COLUMN `process_time` `process_time` int(11) NOT NULL DEFAULT '0' COMMENT '消耗时间/毫秒' AFTER `status`, CHANGE COLUMN `create_time` `create_time` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间' AFTER `process_time`;
ALTER TABLE `pp_task_log` ADD COLUMN `server_name` varchar(60) NOT NULL DEFAULT '\"\"' COMMENT '服务器名称' AFTER `server_id`, CHANGE COLUMN `output` `output` mediumtext NOT NULL COMMENT '任务输出' AFTER `server_name`, CHANGE COLUMN `error` `error` text NOT NULL COMMENT '错误信息' AFTER `output`, CHANGE COLUMN `status` `status` tinyint(4) NOT NULL COMMENT '状态' AFTER `error`, CHANGE COLUMN `process_time` `process_time` int(11) NOT NULL DEFAULT '0' COMMENT '消耗时间/毫秒' AFTER `status`, CHANGE COLUMN `create_time` `create_time` int(11) UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间' AFTER `process_time`;
COMMIT;
BEGIN;
ALTER TABLE `ppgo_job2`.`pp_task` CHANGE COLUMN `is_notify` ` is_notify` tinyint(1) UNSIGNED NOT NULL DEFAULT '0' COMMENT '0-不通知1-通知', ADD COLUMN `server_type` tinyint(1) UNSIGNED NOT NULL DEFAULT '1' COMMENT '执行策略0-同时执行1-轮询执行' AFTER `update_id`;
ALTER TABLE `pp_task` CHANGE COLUMN `is_notify` `is_notify` tinyint(1) UNSIGNED NOT NULL DEFAULT '0' COMMENT '0-不通知1-通知', ADD COLUMN `server_type` tinyint(1) UNSIGNED NOT NULL DEFAULT '1' COMMENT '执行策略0-同时执行1-轮询执行' AFTER `update_id`;
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

13
static/echarts/echarts.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
/** layui-v2.4.3 MIT License By https://www.layui.com */
/** layui-v2.4.3 MIT License By https://www.layui.com */
html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 274 KiB

After

Width:  |  Height:  |  Size: 274 KiB

View File

@@ -1,2 +1,2 @@
/** layui-v2.4.3 MIT License By https://www.layui.com */
/** layui-v2.4.3 MIT License By https://www.layui.com */
;layui.define("jquery",function(e){"use strict";var i=layui.$,n=(layui.hint(),layui.device(),{config:{},set:function(e){var n=this;return n.config=i.extend({},n.config,e),n},on:function(e,i){return layui.onevent.call(this,t,e,i)}}),t="carousel",a="layui-this",l=">*[carousel-item]>*",o="layui-carousel-left",r="layui-carousel-right",d="layui-carousel-prev",s="layui-carousel-next",u="layui-carousel-arrow",c="layui-carousel-ind",m=function(e){var t=this;t.config=i.extend({},t.config,n.config,e),t.render()};m.prototype.config={width:"600px",height:"280px",full:!1,arrow:"hover",indicator:"inside",autoplay:!0,interval:3e3,anim:"",trigger:"click",index:0},m.prototype.render=function(){var e=this,n=e.config;n.elem=i(n.elem),n.elem[0]&&(e.elemItem=n.elem.find(l),n.index<0&&(n.index=0),n.index>=e.elemItem.length&&(n.index=e.elemItem.length-1),n.interval<800&&(n.interval=800),n.full?n.elem.css({position:"fixed",width:"100%",height:"100%",zIndex:9999}):n.elem.css({width:n.width,height:n.height}),n.elem.attr("lay-anim",n.anim),e.elemItem.eq(n.index).addClass(a),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},m.prototype.reload=function(e){var n=this;clearInterval(n.timer),n.config=i.extend({},n.config,e),n.render()},m.prototype.prevIndex=function(){var e=this,i=e.config,n=i.index-1;return n<0&&(n=e.elemItem.length-1),n},m.prototype.nextIndex=function(){var e=this,i=e.config,n=i.index+1;return n>=e.elemItem.length&&(n=0),n},m.prototype.addIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index+e,n.index>=i.elemItem.length&&(n.index=0)},m.prototype.subIndex=function(e){var i=this,n=i.config;e=e||1,n.index=n.index-e,n.index<0&&(n.index=i.elemItem.length-1)},m.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(e.timer=setInterval(function(){e.slide()},i.interval))},m.prototype.arrow=function(){var e=this,n=e.config,t=i(['<button class="layui-icon '+u+'" lay-type="sub">'+("updown"===n.anim?"&#xe619;":"&#xe603;")+"</button>",'<button class="layui-icon '+u+'" lay-type="add">'+("updown"===n.anim?"&#xe61a;":"&#xe602;")+"</button>"].join(""));n.elem.attr("lay-arrow",n.arrow),n.elem.find("."+u)[0]&&n.elem.find("."+u).remove(),n.elem.append(t),t.on("click",function(){var n=i(this),t=n.attr("lay-type");e.slide(t)})},m.prototype.indicator=function(){var e=this,n=e.config,t=e.elemInd=i(['<div class="'+c+'"><ul>',function(){var i=[];return layui.each(e.elemItem,function(e){i.push("<li"+(n.index===e?' class="layui-this"':"")+"></li>")}),i.join("")}(),"</ul></div>"].join(""));n.elem.attr("lay-indicator",n.indicator),n.elem.find("."+c)[0]&&n.elem.find("."+c).remove(),n.elem.append(t),"updown"===n.anim&&t.css("margin-top",-(t.height()/2)),t.find("li").on("hover"===n.trigger?"mouseover":n.trigger,function(){var t=i(this),a=t.index();a>n.index?e.slide("add",a-n.index):a<n.index&&e.slide("sub",n.index-a)})},m.prototype.slide=function(e,i){var n=this,l=n.elemItem,u=n.config,c=u.index,m=u.elem.attr("lay-filter");n.haveSlide||("sub"===e?(n.subIndex(i),l.eq(u.index).addClass(d),setTimeout(function(){l.eq(c).addClass(r),l.eq(u.index).addClass(r)},50)):(n.addIndex(i),l.eq(u.index).addClass(s),setTimeout(function(){l.eq(c).addClass(o),l.eq(u.index).addClass(o)},50)),setTimeout(function(){l.removeClass(a+" "+d+" "+s+" "+o+" "+r),l.eq(u.index).addClass(a),n.haveSlide=!1},300),n.elemInd.find("li").eq(u.index).addClass(a).siblings().removeClass(a),n.haveSlide=!0,layui.event.call(this,t,"change("+m+")",{index:u.index,prevIndex:c,item:l.eq(u.index)}))},m.prototype.events=function(){var e=this,i=e.config;i.elem.data("haveEvents")||(i.elem.on("mouseenter",function(){clearInterval(e.timer)}).on("mouseleave",function(){e.autoplay()}),i.elem.data("haveEvents",!0))},n.render=function(e){var i=new m(e);return i},e(t,n)});

View File

@@ -1,2 +1,2 @@
/** layui-v2.4.3 MIT License By https://www.layui.com */
/** layui-v2.4.3 MIT License By https://www.layui.com */
;layui.define("jquery",function(e){"use strict";var a=layui.$,l="http://www.layui.com/doc/modules/code.html";e("code",function(e){var t=[];e=e||{},e.elem=a(e.elem||".layui-code"),e.about=!("about"in e)||e.about,e.elem.each(function(){t.push(this)}),layui.each(t.reverse(),function(t,i){var c=a(i),o=c.html();(c.attr("lay-encode")||e.encode)&&(o=o.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#39;").replace(/"/g,"&quot;")),c.html('<ol class="layui-code-ol"><li>'+o.replace(/[\r\t\n]+/g,"</li><li>")+"</li></ol>"),c.find(">.layui-code-h3")[0]||c.prepend('<h3 class="layui-code-h3">'+(c.attr("lay-title")||e.title||"code")+(e.about?'<a href="'+l+'" target="_blank">layui.code</a>':"")+"</h3>");var d=c.find(">.layui-code-ol");c.addClass("layui-box layui-code-view"),(c.attr("lay-skin")||e.skin)&&c.addClass("layui-code-"+(c.attr("lay-skin")||e.skin)),(d.find("li").length/100|0)>0&&d.css("margin-left",(d.find("li").length/100|0)+"px"),(c.attr("lay-height")||e.height)&&d.css("max-height",c.attr("lay-height")||e.height)})})}).addcss("modules/code.css","skincodecss");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
/** layui-v2.4.3 MIT License By https://www.layui.com */
/** layui-v2.4.3 MIT License By https://www.layui.com */
;layui.define("jquery",function(e){"use strict";var l=layui.$,o=function(e){},t='<i class="layui-anim layui-anim-rotate layui-anim-loop layui-icon ">&#xe63e;</i>';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!("isAuto"in e)||e.isAuto,v=e.end||"没有更多了",y=e.scrollElem&&e.scrollElem!==document,d="<cite>加载更多</cite>",h=l('<div class="layui-flow-more"><a href="javascript:;">'+d+"</a></div>");f.find(".layui-flow-more")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(m.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var m=e.attr("lay-src");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",m).removeAttr("lay-src"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;s<t.lazyimg.elem.length;s++){var v=t.lazyimg.elem.eq(s),y=a?function(){return v.offset().top-n.offset().top+m}():v.offset().top;if(c(v,f),i=s,y>u)break}};if(f(),!o){var m;n.on("scroll",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e("flow",new o)});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
/** layui-v2.4.3 MIT License By https://www.layui.com */
/** layui-v2.4.3 MIT License By https://www.layui.com */
;layui.define(function(e){"use strict";var a=document,t="getElementById",n="getElementsByTagName",i="laypage",r="layui-disabled",u=function(e){var a=this;a.config=e||{},a.config.index=++s.index,a.render(!0)};u.prototype.type=function(){var e=this.config;if("object"==typeof e.elem)return void 0===e.elem.length?2:3},u.prototype.view=function(){var e=this,a=e.config,t=a.groups="groups"in a?0|a.groups:5;a.layout="object"==typeof a.layout?a.layout:["prev","page","next"],a.count=0|a.count,a.curr=0|a.curr||1,a.limits="object"==typeof a.limits?a.limits:[10,20,30,40,50],a.limit=0|a.limit||10,a.pages=Math.ceil(a.count/a.limit)||1,a.curr>a.pages&&(a.curr=a.pages),t<0?t=1:t>a.pages&&(t=a.pages),a.prev="prev"in a?a.prev:"&#x4E0A;&#x4E00;&#x9875;",a.next="next"in a?a.next:"&#x4E0B;&#x4E00;&#x9875;";var n=a.pages>t?Math.ceil((a.curr+(t>1?1:0))/(t>0?t:1)):1,i={prev:function(){return a.prev?'<a href="javascript:;" class="layui-laypage-prev'+(1==a.curr?" "+r:"")+'" data-page="'+(a.curr-1)+'">'+a.prev+"</a>":""}(),page:function(){var e=[];if(a.count<1)return"";n>1&&a.first!==!1&&0!==t&&e.push('<a href="javascript:;" class="layui-laypage-first" data-page="1" title="&#x9996;&#x9875;">'+(a.first||1)+"</a>");var i=Math.floor((t-1)/2),r=n>1?a.curr-i:1,u=n>1?function(){var e=a.curr+(t-i-1);return e>a.pages?a.pages:e}():t;for(u-r<t-1&&(r=u-t+1),a.first!==!1&&r>2&&e.push('<span class="layui-laypage-spr">&#x2026;</span>');r<=u;r++)r===a.curr?e.push('<span class="layui-laypage-curr"><em class="layui-laypage-em" '+(/^#/.test(a.theme)?'style="background-color:'+a.theme+';"':"")+"></em><em>"+r+"</em></span>"):e.push('<a href="javascript:;" data-page="'+r+'">'+r+"</a>");return a.pages>t&&a.pages>u&&a.last!==!1&&(u+1<a.pages&&e.push('<span class="layui-laypage-spr">&#x2026;</span>'),0!==t&&e.push('<a href="javascript:;" class="layui-laypage-last" title="&#x5C3E;&#x9875;" data-page="'+a.pages+'">'+(a.last||a.pages)+"</a>")),e.join("")}(),next:function(){return a.next?'<a href="javascript:;" class="layui-laypage-next'+(a.curr==a.pages?" "+r:"")+'" data-page="'+(a.curr+1)+'">'+a.next+"</a>":""}(),count:'<span class="layui-laypage-count"> '+a.count+" 条</span>",limit:function(){var e=['<span class="layui-laypage-limits"><select lay-ignore>'];return layui.each(a.limits,function(t,n){e.push('<option value="'+n+'"'+(n===a.limit?"selected":"")+">"+n+" 条/页</option>")}),e.join("")+"</select></span>"}(),refresh:['<a href="javascript:;" data-page="'+a.curr+'" class="layui-laypage-refresh">','<i class="layui-icon layui-icon-refresh"></i>',"</a>"].join(""),skip:function(){return['<span class="layui-laypage-skip">&#x5230;&#x7B2C;','<input type="text" min="1" value="'+a.curr+'" class="layui-input">','&#x9875;<button type="button" class="layui-laypage-btn">&#x786e;&#x5b9a;</button>',"</span>"].join("")}()};return['<div class="layui-box layui-laypage layui-laypage-'+(a.theme?/^#/.test(a.theme)?"molv":a.theme:"default")+'" id="layui-laypage-'+a.index+'">',function(){var e=[];return layui.each(a.layout,function(a,t){i[t]&&e.push(i[t])}),e.join("")}(),"</div>"].join("")},u.prototype.jump=function(e,a){if(e){var t=this,i=t.config,r=e.children,u=e[n]("button")[0],l=e[n]("input")[0],p=e[n]("select")[0],c=function(){var e=0|l.value.replace(/\s|\D/g,"");e&&(i.curr=e,t.render())};if(a)return c();for(var o=0,y=r.length;o<y;o++)"a"===r[o].nodeName.toLowerCase()&&s.on(r[o],"click",function(){var e=0|this.getAttribute("data-page");e<1||e>i.pages||(i.curr=e,t.render())});p&&s.on(p,"change",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),u&&s.on(u,"click",function(){c()})}},u.prototype.skip=function(e){if(e){var a=this,t=e[n]("input")[0];t&&s.on(t,"keyup",function(t){var n=this.value,i=t.keyCode;/^(37|38|39|40)$/.test(i)||(/\D/.test(n)&&(this.value=n.replace(/\D/,"")),13===i&&a.jump(e,!0))})}},u.prototype.render=function(e){var n=this,i=n.config,r=n.type(),u=n.view();2===r?i.elem&&(i.elem.innerHTML=u):3===r?i.elem.html(u):a[t](i.elem)&&(a[t](i.elem).innerHTML=u),i.jump&&i.jump(i,e);var s=a[t]("layui-laypage-"+i.index);n.jump(s),i.hash&&!e&&(location.hash="!"+i.hash+"="+i.curr),n.skip(s)};var s={render:function(e){var a=new u(e);return a.index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(e,a,t){return e.attachEvent?e.attachEvent("on"+a,function(a){a.target=a.srcElement,t.call(e,a)}):e.addEventListener(a,t,!1),this}};e(i,s)});

View File

@@ -1,2 +1,2 @@
/** layui-v2.4.3 MIT License By https://www.layui.com */
/** layui-v2.4.3 MIT License By https://www.layui.com */
;layui.define(function(e){"use strict";var r={open:"{{",close:"}}"},c={exp:function(e){return new RegExp(e,"g")},query:function(e,c,t){var o=["#([\\s\\S])+?","([^{#}])*?"][e||0];return n((c||"")+r.open+o+r.close+(t||""))},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#39;").replace(/"/g,"&quot;")},error:function(e,r){var c="Laytpl Error";return"object"==typeof console&&console.error(c+e+"\n"+(r||"")),c+e}},n=c.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=n("^"+r.open+"#",""),l=n(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(n(r.open+"#"),r.open+"# ").replace(n(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(n(r.open+"!(.+?)!"+r.close),function(e){return e=e.replace(n("^"+r.open+"!"),"").replace(n("!"+r.close),"").replace(n(r.open+"|"+r.close),function(e){return e.replace(/(.)/g,"\\$1")})}).replace(/(?="|')/g,"\\").replace(c.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(c.query(1),function(e){var c='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(n(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),c='"+_escape_('),c+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,c.escape)}catch(u){return delete o.cache,c.error(u,p)}},t.pt.render=function(e,r){var n,t=this;return e?(n=t.cache?t.cache(e,c.escape):t.parse(t.tpl,e),r?void r(n):n):c.error("no data")};var o=function(e){return"string"!=typeof e?c.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var c in e)r[c]=e[c]},o.v="1.2.0",e("laytpl",o)});

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
/** layui-v2.4.3 MIT License By https://www.layui.com */
/** layui-v2.4.3 MIT License By https://www.layui.com */
;layui.define("jquery",function(e){"use strict";var a=layui.jquery,i={config:{},index:layui.rate?layui.rate.index+1e4:0,set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,a){return layui.onevent.call(this,n,e,a)}},l=function(){var e=this,a=e.config;return{setvalue:function(a){e.setvalue.call(e,a)},config:a}},n="rate",t="layui-rate",o="layui-icon-rate",s="layui-icon-rate-solid",u="layui-icon-rate-half",r="layui-icon-rate-solid layui-icon-rate-half",c="layui-icon-rate-solid layui-icon-rate",f="layui-icon-rate layui-icon-rate-half",v=function(e){var l=this;l.index=++i.index,l.config=a.extend({},l.config,i.config,e),l.render()};v.prototype.config={length:5,text:!1,readonly:!1,half:!1,value:0,theme:""},v.prototype.render=function(){var e=this,i=e.config,l=i.theme?'style="color: '+i.theme+';"':"";i.elem=a(i.elem),parseInt(i.value)!==i.value&&(i.half||(i.value=Math.ceil(i.value)-i.value<.5?Math.ceil(i.value):Math.floor(i.value)));for(var n='<ul class="layui-rate" '+(i.readonly?"readonly":"")+">",u=1;u<=i.length;u++){var r='<li class="layui-inline"><i class="layui-icon '+(u>Math.floor(i.value)?o:s)+'" '+l+"></i></li>";i.half&&parseInt(i.value)!==i.value&&u==Math.ceil(i.value)?n=n+'<li><i class="layui-icon layui-icon-rate-half" '+l+"></i></li>":n+=r}n+="</ul>"+(i.text?'<span class="layui-inline">'+i.value+"星":"")+"</span>";var c=i.elem,f=c.next("."+t);f[0]&&f.remove(),e.elemTemp=a(n),i.span=e.elemTemp.next("span"),i.setText&&i.setText(i.value),c.html(e.elemTemp),c.addClass("layui-inline"),i.readonly||e.action()},v.prototype.setvalue=function(e){var a=this,i=a.config;i.value=e,a.render()},v.prototype.action=function(){var e=this,i=e.config,l=e.elemTemp,n=l.find("i").width();l.children("li").each(function(e){var t=e+1,v=a(this);v.on("click",function(e){if(i.value=t,i.half){var o=e.pageX-a(this).offset().left;o<=n/2&&(i.value=i.value-.5)}i.text&&l.next("span").text(i.value+"星"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),v.on("mousemove",function(e){if(l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+t+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half){var c=e.pageX-a(this).offset().left;c<=n/2&&v.children("i").addClass(u).removeClass(s)}}),v.on("mouseleave",function(){l.find("i").each(function(){a(this).addClass(o).removeClass(r)}),l.find("i:lt("+Math.floor(i.value)+")").each(function(){a(this).addClass(s).removeClass(f)}),i.half&&parseInt(i.value)!==i.value&&l.children("li:eq("+Math.floor(i.value)+")").children("i").addClass(u).removeClass(c)})})},v.prototype.events=function(){var e=this;e.config},i.render=function(e){var a=new v(e);return l.call(a)},e(n,i)});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
/** layui-v2.4.3 MIT License By https://www.layui.com */
/** layui-v2.4.3 MIT License By https://www.layui.com */
;layui.define("jquery",function(e){"use strict";var o=layui.$,a=layui.hint(),i="layui-tree-enter",r=function(e){this.options=e},t={arrow:["&#xe623;","&#xe625;"],checkbox:["&#xe626;","&#xe627;"],radio:["&#xe62b;","&#xe62a;"],branch:["&#xe622;","&#xe624;"],leaf:"&#xe621;"};r.prototype.init=function(e){var o=this;e.addClass("layui-box layui-tree"),o.options.skin&&e.addClass("layui-tree-skin-"+o.options.skin),o.tree(e),o.on(e)},r.prototype.tree=function(e,a){var i=this,r=i.options,n=a||r.nodes;layui.each(n,function(a,n){var l=n.children&&n.children.length>0,c=o('<ul class="'+(n.spread?"layui-show":"")+'"></ul>'),s=o(["<li "+(n.spread?'data-spread="'+n.spread+'"':"")+">",function(){return l?'<i class="layui-icon layui-tree-spread">'+(n.spread?t.arrow[1]:t.arrow[0])+"</i>":""}(),function(){return r.check?'<i class="layui-icon layui-tree-check">'+("checkbox"===r.check?t.checkbox[0]:"radio"===r.check?t.radio[0]:"")+"</i>":""}(),function(){return'<a href="'+(n.href||"javascript:;")+'" '+(r.target&&n.href?'target="'+r.target+'"':"")+">"+('<i class="layui-icon layui-tree-'+(l?"branch":"leaf")+'">'+(l?n.spread?t.branch[1]:t.branch[0]:t.leaf)+"</i>")+("<cite>"+(n.name||"未命名")+"</cite></a>")}(),"</li>"].join(""));l&&(s.append(c),i.tree(c,n.children)),e.append(s),"function"==typeof r.click&&i.click(s,n),i.spread(s,n),r.drag&&i.drag(s,n)})},r.prototype.click=function(e,o){var a=this,i=a.options;e.children("a").on("click",function(e){layui.stope(e),i.click(o)})},r.prototype.spread=function(e,o){var a=this,i=(a.options,e.children(".layui-tree-spread")),r=e.children("ul"),n=e.children("a"),l=function(){e.data("spread")?(e.data("spread",null),r.removeClass("layui-show"),i.html(t.arrow[0]),n.find(".layui-icon").html(t.branch[0])):(e.data("spread",!0),r.addClass("layui-show"),i.html(t.arrow[1]),n.find(".layui-icon").html(t.branch[1]))};r[0]&&(i.on("click",l),n.on("dblclick",l))},r.prototype.on=function(e){var a=this,r=a.options,t="layui-tree-drag";e.find("i").on("selectstart",function(e){return!1}),r.drag&&o(document).on("mousemove",function(e){var i=a.move;if(i.from){var r=(i.to,o('<div class="layui-box '+t+'"></div>'));e.preventDefault(),o("."+t)[0]||o("body").append(r);var n=o("."+t)[0]?o("."+t):r;n.addClass("layui-show").html(i.from.elem.children("a").html()),n.css({left:e.pageX+10,top:e.pageY+10})}}).on("mouseup",function(){var e=a.move;e.from&&(e.from.elem.children("a").removeClass(i),e.to&&e.to.elem.children("a").removeClass(i),a.move={},o("."+t).remove())})},r.prototype.move={},r.prototype.drag=function(e,a){var r=this,t=(r.options,e.children("a")),n=function(){var t=o(this),n=r.move;n.from&&(n.to={item:a,elem:e},t.addClass(i))};t.on("mousedown",function(){var o=r.move;o.from={item:a,elem:e}}),t.on("mouseenter",n).on("mousemove",n).on("mouseleave",function(){var e=o(this),a=r.move;a.from&&(delete a.to,e.removeClass(i))})},e("tree",function(e){var i=new r(e=e||{}),t=o(e.elem);return t[0]?void i.init(t):a.error("layui.tree 没有找到"+e.elem+"元素")})});

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
/** layui-v2.4.3 MIT License By https://www.layui.com */
/** layui-v2.4.3 MIT License By https://www.layui.com */
;layui.define("jquery",function(t){"use strict";var e=layui.$,i={fixbar:function(t){var i,a,n="layui-fixbar",r="layui-fixbar-top",o=e(document),l=e("body");t=e.extend({showHeight:200},t),t.bar1=t.bar1===!0?"&#xe606;":t.bar1,t.bar2=t.bar2===!0?"&#xe607;":t.bar2,t.bgcolor=t.bgcolor?"background-color:"+t.bgcolor:"";var c=[t.bar1,t.bar2,"&#xe604;"],g=e(['<ul class="'+n+'">',t.bar1?'<li class="layui-icon" lay-type="bar1" style="'+t.bgcolor+'">'+c[0]+"</li>":"",t.bar2?'<li class="layui-icon" lay-type="bar2" style="'+t.bgcolor+'">'+c[1]+"</li>":"",'<li class="layui-icon '+r+'" lay-type="top" style="'+t.bgcolor+'">'+c[2]+"</li>","</ul>"].join("")),s=g.find("."+r),u=function(){var e=o.scrollTop();e>=t.showHeight?i||(s.show(),i=1):i&&(s.hide(),i=0)};e("."+n)[0]||("object"==typeof t.css&&g.css(t.css),l.append(g),u(),g.find("li").on("click",function(){var i=e(this),a=i.attr("lay-type");"top"===a&&e("html,body").animate({scrollTop:0},200),t.click&&t.click.call(this,a)}),o.on("scroll",function(){clearTimeout(a),a=setTimeout(function(){u()},100)}))},countdown:function(t,e,i){var a=this,n="function"==typeof e,r=new Date(t).getTime(),o=new Date(!e||n?(new Date).getTime():e).getTime(),l=r-o,c=[Math.floor(l/864e5),Math.floor(l/36e5)%24,Math.floor(l/6e4)%60,Math.floor(l/1e3)%60];n&&(i=e);var g=setTimeout(function(){a.countdown(t,o+1e3,i)},1e3);return i&&i(l>0?c:[0,0,0,0],e,g),l<=0&&clearTimeout(g),g},timeAgo:function(t,e){var i=this,a=[[],[]],n=(new Date).getTime()-new Date(t).getTime();return n>6912e5?(n=new Date(t),a[0][0]=i.digit(n.getFullYear(),4),a[0][1]=i.digit(n.getMonth()+1),a[0][2]=i.digit(n.getDate()),e||(a[1][0]=i.digit(n.getHours()),a[1][1]=i.digit(n.getMinutes()),a[1][2]=i.digit(n.getSeconds())),a[0].join("-")+" "+a[1].join(":")):n>=864e5?(n/1e3/60/60/24|0)+"天前":n>=36e5?(n/1e3/60/60|0)+"小时前":n>=12e4?(n/1e3/60|0)+"分钟前":n<0?"未来":"刚刚"},digit:function(t,e){var i="";t=String(t),e=e||2;for(var a=t.length;a<e;a++)i+="0";return t<Math.pow(10,e)?i+(0|t):t},toDateString:function(t,e){var i=this,a=new Date(t||new Date),n=[i.digit(a.getFullYear(),4),i.digit(a.getMonth()+1),i.digit(a.getDate())],r=[i.digit(a.getHours()),i.digit(a.getMinutes()),i.digit(a.getSeconds())];return e=e||"yyyy-MM-dd HH:mm:ss",e.replace(/yyyy/g,n[0]).replace(/MM/g,n[1]).replace(/dd/g,n[2]).replace(/HH/g,r[0]).replace(/mm/g,r[1]).replace(/ss/g,r[2])},escape:function(t){return String(t||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#39;").replace(/"/g,"&quot;")}};!function(t,e,i){"$:nomunge";function a(){n=e[l](function(){r.each(function(){var e=t(this),i=e.width(),a=e.height(),n=t.data(this,g);(i!==n.w||a!==n.h)&&e.trigger(c,[n.w=i,n.h=a])}),a()},o[s])}var n,r=t([]),o=t.resize=t.extend(t.resize,{}),l="setTimeout",c="resize",g=c+"-special-event",s="delay",u="throttleWindow";o[s]=250,o[u]=!0,t.event.special[c]={setup:function(){if(!o[u]&&this[l])return!1;var e=t(this);r=r.add(e),t.data(this,g,{w:e.width(),h:e.height()}),1===r.length&&a()},teardown:function(){if(!o[u]&&this[l])return!1;var e=t(this);r=r.not(e),e.removeData(g),r.length||clearTimeout(n)},add:function(e){function a(e,a,r){var o=t(this),l=t.data(this,g)||{};l.w=a!==i?a:o.width(),l.h=r!==i?r:o.height(),n.apply(this,arguments)}if(!o[u]&&this[l])return!1;var n;return t.isFunction(e)?(n=e,a):(n=e.handler,void(e.handler=a))}}}(e,window),t("util",i)});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +1,10 @@
<div class="layui-row ml20" >
<style>
.info-box {
height: 85px;
background-color: white;
background-color: #ecf0f5;
height: 60px;
background-color: #f2f2f2;
border: 1px solid #f2f2f2;
}
@@ -14,34 +15,40 @@
border-bottom-left-radius: 2px;
display: block;
float: left;
height: 85px;
width: 85px;
height: 60px;
width: 60px;
text-align: center;
font-size: 45px;
line-height: 85px;
background: rgba(0, 0, 0, 0.2);
font-size: 40px;
line-height: 60px;
/*background: rgba(0, 0, 0, 0.2);*/
background-color:#efefef !important;
}
.info-box .info-box-content {
padding: 5px 10px;
margin-left: 85px;
padding: 1px 5px;
margin-left: 60px;
}
.info-box-content .info-box-text{
font-size: 18px;
width: 100%;
font-size: 16px;
width: 80%;
display: block;
text-align: center;
color: #999;
margin: 10px auto;
color: #888;
margin: 3px auto;
}
.info-box-content .info-box-number{
font-size: 24px;
font-size: 20px;
width: 100%;
display: block;
text-align: center;
}
.inner-icon{
font-size:24px;
color: #efefef !important;
}
</style>
<div class="layui-row">
@@ -51,153 +58,347 @@
<div class="layui-row layui-col-space15">
<div class="layui-col-md3">
<div class="info-box">
<span class="info-box-icon" style="background-color:#00a65a !important;color:white;"><i class="fa fa-check" aria-hidden="true"></i></span>
{{/*<span class="info-box-icon" style="background-color:#f39c12 !important;color:white;"><i class="fa fa-hourglass" aria-hidden="true"></i></span>*/}}
<span class="fa-stack fa-lg info-box-icon" >
<i class="fa fa-circle fa-stack-1x" style="color:#fff !important;">
<i class="fa fa-hourglass fa-inverse fa-stack-1x inner-icon" ></i>
</i>
</span>
<div class="info-box-content">
<span class="info-box-text">最近执行成功</span>
<span class="info-box-number">{{.okJob}}</span>
</div>
</div>
</div>
<div class="layui-col-md3">
<div class="info-box">
<span class="info-box-icon" style="background-color:#dd4b39 !important;color:white;"><i class="fa fa-exclamation" aria-hidden="true"></i></span>
<div class="info-box-content">
<span class="info-box-text">最近执行失败</span>
<span class="info-box-number">{{.failJob}}</span>
</div>
</div>
</div>
<div class="layui-col-md3">
<div class="info-box">
<span class="info-box-icon" style="background-color:#f39c12 !important;color:white;"><i class="fa fa-hourglass" aria-hidden="true"></i></span>
<div class="info-box-content">
<span class="info-box-text">即将执行的任务</span>
<span class="info-box-text">即将执行的任务</span>
<span class="info-box-number">{{.startJob}}</span>
</div>
</div>
</div>
<div class="layui-col-md3">
<div class="info-box">
<span class="info-box-icon" style="background-color:#00c0ef !important;color:white;"><i class="fa fa-database" aria-hidden="true"></i></span>
<span class="fa-stack fa-lg info-box-icon" >
<i class="fa fa-circle fa-stack-1x" style="color:#fff !important;">
<i class="fa fa-question fa-inverse fa-stack-1x inner-icon" ></i>
</i>
</span>
<div class="info-box-content">
<span class="info-box-text">待审核任务数量</span>
<span class="info-box-number">{{.totalAuditTask}}</span>
</div>
</div>
</div>
<div class="layui-col-md3">
<div class="info-box">
<span class="fa-stack fa-lg info-box-icon" >
<i class="fa fa-circle fa-stack-1x" style="color:#fff !important;">
<i class="fa fa-check fa-inverse fa-stack-1x inner-icon" ></i>
</i>
</span>
<div class="info-box-content">
<span class="info-box-text">近期执行成功</span>
<span class="info-box-number">{{.successNum}}</span>
</div>
</div>
</div>
<div class="layui-col-md3">
<div class="info-box">
<span class="fa-stack fa-lg info-box-icon" >
<i class="fa fa-circle fa-stack-1x" style="color:#fff !important;">
<i class="fa fa-exclamation fa-inverse fa-stack-1x inner-icon" ></i>
</i>
</span>
<div class="info-box-content">
<span class="info-box-text">近期执行失败</span>
<span class="info-box-number">{{.errorNum}}</span>
</div>
</div>
</div>
<div class="layui-col-md3">
<div class="info-box">
<span class="fa-stack fa-lg info-box-icon" >
<i class="fa fa-circle fa-stack-1x" style="color:#fff !important;">
<i class="fa fa-user fa-inverse fa-stack-1x inner-icon" ></i>
</i>
</span>
<div class="info-box-content">
<span class="info-box-text">当前用户总数</span>
<span class="info-box-number">{{.userNum}}</span>
</div>
</div>
</div>
<div class="layui-col-md3">
<div class="info-box">
<span class="fa-stack fa-lg info-box-icon" >
<i class="fa fa-circle fa-stack-1x" style="color:#fff !important;">
<i class="fa fa-tasks fa-inverse fa-stack-1x inner-icon" ></i>
</i>
</span>
<div class="info-box-content">
<span class="info-box-text">定时任务总数量</span>
<span class="info-box-number">{{.totalJob}}</span>
</div>
</div>
</div>
<div class="layui-col-md3">
<div class="info-box">
<span class="fa-stack fa-lg info-box-icon" >
<i class="fa fa-circle fa-stack-1x" style="color:#fff !important;">
<i class="fa fa-calculator fa-inverse fa-stack-1x inner-icon" ></i>
</i>
</span>
<div class="info-box-content">
<span class="info-box-text">累计运行次数</span>
<span class="info-box-number">{{.TaskTotalRunNum}}</span>
</div>
</div>
</div>
<div class="layui-col-md3">
<div class="info-box">
<span class="fa-stack fa-lg info-box-icon" >
<i class="fa fa-circle fa-stack-1x" style="color:#fff !important;">
<i class="fa fa-sticky-note fa-inverse fa-stack-1x inner-icon" ></i>
</i>
</span>
<div class="info-box-content">
<span class="info-box-text">当前日志总量</span>
<span class="info-box-number">{{.totalLog}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="layui-col-md4">
<div class="layui-card">
<div class="layui-card-header">最近执行的任务</div>
<div class="layui-card-body" style="height: 465px; padding-bottom: 10px; overflow: auto">
<table class="layui-table" lay-size="sm">
<colgroup>
<col width="50">
<col >
<col >
<col>
</colgroup>
<thead>
<tr>
<th>序号</th>
<th>任务名称</th>
<th>开始时间</th>
<th>执行结果</th>
</tr>
</thead>
<tbody>
{{range $k, $v := .recentLogs}}
<tr>
<td>{{$k}}</td>
<td><a href="{{urlfor "TaskLogController.Detail" "id" $v.id}}" class="news-item-title">
{{$v.task_name}} # {{$v.id}}
</a></td>
<td>{{$v.start_time}}</td>
<td>{{if eq $v.status 0}}
正常
{{else if eq $v.status -1}}
<span style="color:red">异常</span>
{{else}}
<span style="color:red">超时</span>
{{end}}</td>
</tr>
{{else}}
<tr>
<td colspan="3">暂无信息</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
</div>
<div class="layui-col-md4">
<div class="layui-card" style="background: #fff">
<div class="layui-card-header">即将执行的任务</div>
<div class="layui-card-body" style="height: 465px; padding-bottom: 10px; overflow: auto">
<table class="layui-table" lay-size="sm">
<colgroup>
<col>
<col>
</colgroup>
<thead>
<tr>
<th>任务名称</th>
<th>执行时间</th>
</tr>
</thead>
<tbody>
{{range $k, $v := .jobs}}
<tr>
<td><a href="{{urlfor "TaskController.Logs" "id" $v.task_id}}" class="news-item-title">{{$v.task_name}}-{{$v.task_group}} # {{$v.task_id}}</a></td>
<td>{{$v.next_time}}</td>
</tr>
{{else}}
<tr>
<td colspan="2">暂无信息</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
</div>
<div class="layui-col-md4">
<div class="layui-card" style="background: #fff">
<div class="layui-card-header">系统概况</div>
<div class="layui-card-body" style="height: 465px; padding-bottom: 10px; overflow: auto">
<table class="layui-table" lay-size="sm">
<colgroup>
<col>
<col>
</colgroup>
<thead>
<tr>
<th>参数</th>
<th></th>
</div>
</div>
<div class="layui-row">
<div class="layui-col-md12">
<div class="layui-card-body">
<div class="layui-tab">
<ul class="layui-tab-title">
<li class="layui-this">系统概况</li>
<li>即将开始的任务</li>
<li>最近失败的任务</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-col-md8" id="charts-box">
{{/*图表*/}}
<div id="main" style=" height: 528px;"></div>
</div>
</tr>
</thead>
<tbody>
{{range $k, $v := .sysInfo}}
<tr>
<td># {{$k}} </td>
<td>{{$v}}</td>
</tr>
{{else}}
<tr>
<td colspan="2">暂无信息</td>
</tr>
{{end}}
</tbody>
</table>
<div class="layui-col-md4" >
{{/*系统概况*/}}
<div class="layui-card" style="background: #fff" id="sys">
<div class="layui-card-header">系统概况</div>
<div class="layui-card-body" style="height: 465px; padding-bottom: 10px; overflow: auto">
<table class="layui-table" lay-size="sm">
<colgroup>
<col>
<col>
</colgroup>
<thead>
<tr>
<th>参数</th>
<th></th>
</tr>
</thead>
<tbody>
{{range $k, $v := .sysInfo}}
<tr>
<td># {{$k}} </td>
<td>{{$v}}</td>
</tr>
{{else}}
<tr>
<td colspan="2">暂无信息</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="layui-tab-item">
<div class="layui-card" style="background: #fff">
<div class="layui-card-header">即将执行的任务</div>
<div class="layui-card-body" style="height: 465px; padding-bottom: 10px; overflow: auto">
<table class="layui-table" lay-size="sm">
<colgroup>
<col>
<col>
</colgroup>
<thead>
<tr>
<th>任务名称</th>
<th>执行时间</th>
</tr>
</thead>
<tbody>
{{range $k, $v := .jobs}}
<tr>
<td><a href="{{urlfor "TaskController.Logs" "id" $v.task_id}}" class="news-item-title">{{$v.task_name}}-{{$v.task_group}} # {{$v.task_id}}</a></td>
<td>{{$v.next_time}}</td>
</tr>
{{else}}
<tr>
<td colspan="2">暂无信息</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
</div>
<div class="layui-tab-item">
{{/*执行失败的任务*/}}
<div class="layui-card">
<div class="layui-card-header">最近执行的任务</div>
<div class="layui-card-body" style="height: 465px; padding-bottom: 10px; overflow: auto">
<table class="layui-table" lay-size="sm">
<colgroup>
<col width="50">
<col >
<col >
<col>
</colgroup>
<thead>
<tr>
<th>序号</th>
<th>任务名称</th>
<th>开始时间</th>
<th>执行结果</th>
</tr>
</thead>
<tbody>
{{range $k, $v := .errLogs}}
<tr>
<td>{{$k}}</td>
<td><a href="javascript:;" onclick="logDetail({{$v.id}});" class="news-item-title">
{{$v.task_name}} # {{$v.id}}
</a></td>
<td>{{$v.start_time}}</td>
<td>{{if eq $v.status 0}}
正常
{{else if eq $v.status -1}}
<span style="color:red">异常</span>
{{else}}
<span style="color:red">超时</span>
{{end}}</td>
</tr>
{{else}}
<tr>
<td colspan="3">暂无信息</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="/static/echarts/echarts.min.js"></script>
<script src="/static/layui/layui.js"></script>
<script>
var $;
//注意:选项卡 依赖 element 模块,否则无法进行功能性操作
layui.use('element', function(){
var element = layui.element;
$ = layui.$;
resizeChartbox();
window.onresize = function(){
resizeChartbox();
}
function resizeChartbox()
{
height = $("#sys").height();
width = $("#charts-box").width();
$("#main").width(width-200);
$("#main").height(height);
}
element.render();
//…
});
function logDetail(id){
window.parent.openTab("/tasklog/detail?id="+id,id+' 日志详情',"admin_log_detail-"+id,'');
}
// 基于准备好的dom初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: '运行概况'
},
tooltip: {
trigger: 'axis'
},
legend: {
data:['任务执行失败','任务执行超时','任务执行成功']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: {{.days}}
},
yAxis: {
type: 'value'
},
series: [
{
name:'任务执行失败',
type:'line',
stack: '总量',
data:{{.errNum}}
},
{
name:'任务执行超时',
type:'line',
stack: '总量',
data:{{.expiredNum}}
},
{
name:'任务执行成功',
type:'line',
stack: '总量',
data:{{.okNum}}
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>

View File

@@ -53,7 +53,7 @@
,url: '/task/table?status=2'
,cols: [[
{checkbox: true, fixed: true},
{field:'id', title: 'ID', align:'center',sort: true, width:100}
{field:'id', title: 'ID', align:'center',sort: true, width:80}
,{field:'task_name',title: '任务名称'}
,{field:'cron_spec',title: '执行时间', width:150}
,{field:'pre_time', width:170,title: '上次执行时间'}

View File

@@ -35,7 +35,7 @@
{{/*<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="status">启|停</a>*/}}
{{/*<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>*/}}
<a class="layui-btn layui-btn-xs " lay-event="detail">详细</a>
{{/*<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="run">测试</a>*/}}
<a class="layui-btn layui-btn-warm layui-btn-xs" lay-event="run">测试</a>
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="log">日志</a>
</script>
</div>
@@ -58,13 +58,13 @@
,url: '/task/table'
,cols: [[
{checkbox: true, fixed: true},
{field:'id', title: 'ID', align:'center', width:100,sort: true}
{field:'id', title: 'ID', align:'center', width:80,sort: true}
,{field:'task_name', title: '任务名称'}
,{field:'cron_spec',title: '时间表达式', width:150}
,{field:'cron_spec',title: '时间表达式', width:100}
,{field:'next_time', width:170,title: '下次执行时间'}
,{field:'pre_time', title: '上次执行时间',width:170,}
,{field:'execute_times', title: '次数',width:100}
,{width:120, align:'center', title:'操作', toolbar: '#bar'}
,{width:180, align:'center', title:'操作', toolbar: '#bar'}
]]
,id: 'listReload'
,page: true