V1.2
1、新增服务器资源添加 (新增数据表pp_task_server) 2、新增远程服务器任务执行 3、删除邮件通知功能(pp_task删除两个有关字段)
This commit is contained in:
21
README.md
21
README.md
@@ -10,3 +10,24 @@ PPGo_Job
|
|||||||
3、修改config 配置数据库
|
3、修改config 配置数据库
|
||||||
4、运行 go build
|
4、运行 go build
|
||||||
5、运行 ./run.sh start|stop
|
5、运行 ./run.sh start|stop
|
||||||
|
|
||||||
|
前台访问:http://your_host:8080
|
||||||
|
用户名:admin 密码:123456
|
||||||
|
|
||||||
|
升级日志
|
||||||
|
----
|
||||||
|
v1.0
|
||||||
|
1、初始版本 本地任务的调取和执行
|
||||||
|
2、定时任务执行日志
|
||||||
|
3、定时任务执行时间
|
||||||
|
----
|
||||||
|
v1.1
|
||||||
|
1、优化界面
|
||||||
|
2、优化列表的登录
|
||||||
|
3、增加初始化任务
|
||||||
|
----
|
||||||
|
v1.2
|
||||||
|
1、新增服务器资源添加 (新增数据表pp_task_server)
|
||||||
|
2、新增远程服务器任务执行
|
||||||
|
3、删除邮件通知功能(pp_task删除两个有关字段)
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ httpport = 8080
|
|||||||
runmode = dev
|
runmode = dev
|
||||||
|
|
||||||
# 允许同时运行的任务数
|
# 允许同时运行的任务数
|
||||||
jobs.pool = 10
|
jobs.pool = 1000
|
||||||
|
|
||||||
# 站点名称
|
# 站点名称
|
||||||
site.name = 定时任务管理器
|
site.name = 定时任务管理器
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/george518/PPGo_Job/models"
|
"github.com/george518/PPGo_Job/models"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupController struct {
|
type GroupController struct {
|
||||||
@@ -39,6 +40,7 @@ func (this *GroupController) Add() {
|
|||||||
group.GroupName = strings.TrimSpace(this.GetString("group_name"))
|
group.GroupName = strings.TrimSpace(this.GetString("group_name"))
|
||||||
group.UserId = this.userId
|
group.UserId = this.userId
|
||||||
group.Description = strings.TrimSpace(this.GetString("description"))
|
group.Description = strings.TrimSpace(this.GetString("description"))
|
||||||
|
group.CreateTime = time.Now().Unix()
|
||||||
|
|
||||||
_, err := models.TaskGroupAdd(group)
|
_, err := models.TaskGroupAdd(group)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
135
controllers/server.go
Normal file
135
controllers/server.go
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* @Author: haodaquan
|
||||||
|
* @Date: 2017-08-16 10:27:40
|
||||||
|
* @Last Modified by: haodaquan
|
||||||
|
* @Last Modified time: 2017-08-16 09:17:22
|
||||||
|
*/
|
||||||
|
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/astaxie/beego"
|
||||||
|
"github.com/george518/PPGo_Job/libs"
|
||||||
|
"github.com/george518/PPGo_Job/models"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerController struct {
|
||||||
|
BaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ServerController) List() {
|
||||||
|
page, _ := this.GetInt("page")
|
||||||
|
if page < 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
result, count := models.TaskServerGetList(page, this.pageSize)
|
||||||
|
list := make([]map[string]interface{}, len(result))
|
||||||
|
for k, v := range result {
|
||||||
|
row := make(map[string]interface{})
|
||||||
|
row["id"] = v.Id
|
||||||
|
if(v.Type==0){
|
||||||
|
row["type"] = "密码"
|
||||||
|
}else {
|
||||||
|
row["type"] = "密钥"
|
||||||
|
}
|
||||||
|
row["server_name"] = v.ServerName
|
||||||
|
row["server_ip"] = v.ServerIp
|
||||||
|
row["detail"] = v.Detail
|
||||||
|
row["port"] = v.Port
|
||||||
|
row["create_time"] = beego.Date(time.Unix(v.CreateTime, 0), "Y-m-d H:i:s")
|
||||||
|
list[k] = row
|
||||||
|
}
|
||||||
|
this.Data["pageTitle"] = "服务器列表"
|
||||||
|
this.Data["list"] = list
|
||||||
|
this.Data["pageBar"] = libs.NewPager(page, int(count), this.pageSize, beego.URLFor("ServerController.List"), true).ToString()
|
||||||
|
this.display()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ServerController) Add() {
|
||||||
|
if this.isPost() {
|
||||||
|
server := new(models.TaskServer)
|
||||||
|
server.ServerName = strings.TrimSpace(this.GetString("server_name"))
|
||||||
|
server.ServerIp = strings.TrimSpace(this.GetString("server_ip"))
|
||||||
|
server.Port,_= strconv.Atoi(this.GetString("port"))
|
||||||
|
server.Type,_ = strconv.Atoi(this.GetString("type"))
|
||||||
|
server.PrivateKeySrc = strings.TrimSpace(this.GetString("private_key_src"))
|
||||||
|
server.PublicKeySrc = strings.TrimSpace(this.GetString("public_key_src"))
|
||||||
|
server.Password = strings.TrimSpace(this.GetString("password"))
|
||||||
|
server.Detail = strings.TrimSpace(this.GetString("detail"))
|
||||||
|
server.CreateTime = time.Now().Unix()
|
||||||
|
server.UpdateTime = time.Now().Unix()
|
||||||
|
server.Status = 0
|
||||||
|
_, err := models.TaskServerAdd(server)
|
||||||
|
if err != nil {
|
||||||
|
this.ajaxMsg(err.Error(), MSG_ERR)
|
||||||
|
}
|
||||||
|
this.ajaxMsg("", MSG_OK)
|
||||||
|
}
|
||||||
|
this.Data["pageTitle"] = "添加服务器"
|
||||||
|
this.display()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ServerController) Edit() {
|
||||||
|
id, _ := this.GetInt("id")
|
||||||
|
server, err := models.TaskServerGetById(id)
|
||||||
|
if err != nil {
|
||||||
|
this.showMsg(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if this.isPost() {
|
||||||
|
server.ServerName = strings.TrimSpace(this.GetString("server_name"))
|
||||||
|
server.ServerIp = strings.TrimSpace(this.GetString("server_ip"))
|
||||||
|
server.Port,_ = strconv.Atoi(this.GetString("port"))
|
||||||
|
server.Type,_ = strconv.Atoi(this.GetString("type"))
|
||||||
|
server.Id,_ = strconv.Atoi(this.GetString("id"))
|
||||||
|
server.PrivateKeySrc = strings.TrimSpace(this.GetString("private_key_src"))
|
||||||
|
server.PublicKeySrc = strings.TrimSpace(this.GetString("public_key_src"))
|
||||||
|
server.Password = strings.TrimSpace(this.GetString("password"))
|
||||||
|
server.Detail = strings.TrimSpace(this.GetString("detail"))
|
||||||
|
server.UpdateTime = time.Now().Unix()
|
||||||
|
server.Status = 0
|
||||||
|
err := server.Update()
|
||||||
|
if err != nil {
|
||||||
|
this.ajaxMsg(err.Error(), MSG_ERR)
|
||||||
|
}
|
||||||
|
this.ajaxMsg("", MSG_OK)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["pageTitle"] = "编辑服务器"
|
||||||
|
this.Data["server"] = server
|
||||||
|
this.display()
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO删除更新
|
||||||
|
func (this *ServerController) Batch() {
|
||||||
|
action := this.GetString("action")
|
||||||
|
ids := this.GetStrings("ids")
|
||||||
|
if len(ids) < 1 {
|
||||||
|
this.ajaxMsg("请选择要操作的项目", MSG_ERR)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range ids {
|
||||||
|
id, _ := strconv.Atoi(v)
|
||||||
|
if id < 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch action {
|
||||||
|
case "delete":
|
||||||
|
//查询服务器是否被占用
|
||||||
|
filters := make([]interface{}, 0)
|
||||||
|
filters = append(filters, "server_id", id)
|
||||||
|
_, count := models.TaskGetList(1, 1000, filters...)
|
||||||
|
if count > 0 {
|
||||||
|
this.ajaxMsg("请先解除该服务器的任务占用", MSG_ERR)
|
||||||
|
}else{
|
||||||
|
models.TaskServerDelById(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ajaxMsg("", MSG_OK)
|
||||||
|
}
|
||||||
@@ -43,12 +43,23 @@ func (this *TaskController) List() {
|
|||||||
result, count := models.TaskGetList(page, this.pageSize, filters...)
|
result, count := models.TaskGetList(page, this.pageSize, filters...)
|
||||||
|
|
||||||
list := make([]map[string]interface{}, len(result))
|
list := make([]map[string]interface{}, len(result))
|
||||||
|
|
||||||
|
|
||||||
// 分组列表
|
// 分组列表
|
||||||
groups, _ := models.TaskGroupGetList(1, 100)
|
groups, _ := models.TaskGroupGetList(1, 100)
|
||||||
groups_map := make(map[int]string)
|
groups_map := make(map[int]string)
|
||||||
for _, gname := range groups {
|
for _, gname := range groups {
|
||||||
groups_map[gname.Id] = gname.GroupName
|
groups_map[gname.Id] = gname.GroupName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//服务器列表
|
||||||
|
servers, _ := models.TaskServerGetList(1, 100)
|
||||||
|
|
||||||
|
server_map := make(map[int]string)
|
||||||
|
for _, sname := range servers {
|
||||||
|
server_map[sname.Id] = sname.ServerName
|
||||||
|
}
|
||||||
|
server_map[0] = "本地"
|
||||||
for k, v := range result {
|
for k, v := range result {
|
||||||
row := make(map[string]interface{})
|
row := make(map[string]interface{})
|
||||||
row["id"] = v.Id
|
row["id"] = v.Id
|
||||||
@@ -58,6 +69,7 @@ func (this *TaskController) List() {
|
|||||||
row["description"] = v.Description
|
row["description"] = v.Description
|
||||||
row["group_id"] = v.GroupId
|
row["group_id"] = v.GroupId
|
||||||
row["group_name"] = groups_map[v.GroupId]
|
row["group_name"] = groups_map[v.GroupId]
|
||||||
|
row["server_name"] = server_map[v.ServerId]
|
||||||
row["is_odd"] = k % 2
|
row["is_odd"] = k % 2
|
||||||
|
|
||||||
e := jobs.GetEntryById(v.Id)
|
e := jobs.GetEntryById(v.Id)
|
||||||
@@ -81,6 +93,7 @@ func (this *TaskController) List() {
|
|||||||
}
|
}
|
||||||
list[k] = row
|
list[k] = row
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Data["pageTitle"] = "任务列表"
|
this.Data["pageTitle"] = "任务列表"
|
||||||
this.Data["list"] = list
|
this.Data["list"] = list
|
||||||
this.Data["groups"] = groups
|
this.Data["groups"] = groups
|
||||||
@@ -99,26 +112,11 @@ func (this *TaskController) Add() {
|
|||||||
task.TaskName = strings.TrimSpace(this.GetString("task_name"))
|
task.TaskName = strings.TrimSpace(this.GetString("task_name"))
|
||||||
task.Description = strings.TrimSpace(this.GetString("description"))
|
task.Description = strings.TrimSpace(this.GetString("description"))
|
||||||
task.Concurrent, _ = this.GetInt("concurrent")
|
task.Concurrent, _ = this.GetInt("concurrent")
|
||||||
|
task.ServerId, _ = this.GetInt("server_id")
|
||||||
task.CronSpec = strings.TrimSpace(this.GetString("cron_spec"))
|
task.CronSpec = strings.TrimSpace(this.GetString("cron_spec"))
|
||||||
task.Command = strings.TrimSpace(this.GetString("command"))
|
task.Command = strings.TrimSpace(this.GetString("command"))
|
||||||
task.Notify, _ = this.GetInt("notify")
|
|
||||||
task.Timeout, _ = this.GetInt("timeout")
|
task.Timeout, _ = this.GetInt("timeout")
|
||||||
|
|
||||||
notifyEmail := strings.TrimSpace(this.GetString("notify_email"))
|
|
||||||
if notifyEmail != "" {
|
|
||||||
emailList := make([]string, 0)
|
|
||||||
tmp := strings.Split(notifyEmail, "\n")
|
|
||||||
for _, v := range tmp {
|
|
||||||
v = strings.TrimSpace(v)
|
|
||||||
if !libs.IsEmail([]byte(v)) {
|
|
||||||
this.ajaxMsg("无效的Email地址:"+v, MSG_ERR)
|
|
||||||
} else {
|
|
||||||
emailList = append(emailList, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
task.NotifyEmail = strings.Join(emailList, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
if task.TaskName == "" || task.CronSpec == "" || task.Command == "" {
|
if task.TaskName == "" || task.CronSpec == "" || task.Command == "" {
|
||||||
this.ajaxMsg("请填写完整信息", MSG_ERR)
|
this.ajaxMsg("请填写完整信息", MSG_ERR)
|
||||||
}
|
}
|
||||||
@@ -135,6 +133,9 @@ func (this *TaskController) Add() {
|
|||||||
// 分组列表
|
// 分组列表
|
||||||
groups, _ := models.TaskGroupGetList(1, 100)
|
groups, _ := models.TaskGroupGetList(1, 100)
|
||||||
this.Data["groups"] = groups
|
this.Data["groups"] = groups
|
||||||
|
//服务器分组
|
||||||
|
servers, _ := models.TaskServerGetList(1, 100)
|
||||||
|
this.Data["servers"] = servers
|
||||||
this.Data["pageTitle"] = "添加任务"
|
this.Data["pageTitle"] = "添加任务"
|
||||||
this.display()
|
this.display()
|
||||||
}
|
}
|
||||||
@@ -153,26 +154,10 @@ func (this *TaskController) Edit() {
|
|||||||
task.Description = strings.TrimSpace(this.GetString("description"))
|
task.Description = strings.TrimSpace(this.GetString("description"))
|
||||||
task.GroupId, _ = this.GetInt("group_id")
|
task.GroupId, _ = this.GetInt("group_id")
|
||||||
task.Concurrent, _ = this.GetInt("concurrent")
|
task.Concurrent, _ = this.GetInt("concurrent")
|
||||||
|
task.ServerId, _ = this.GetInt("server_id")
|
||||||
task.CronSpec = strings.TrimSpace(this.GetString("cron_spec"))
|
task.CronSpec = strings.TrimSpace(this.GetString("cron_spec"))
|
||||||
task.Command = strings.TrimSpace(this.GetString("command"))
|
task.Command = strings.TrimSpace(this.GetString("command"))
|
||||||
task.Notify, _ = this.GetInt("notify")
|
|
||||||
task.Timeout, _ = this.GetInt("timeout")
|
task.Timeout, _ = this.GetInt("timeout")
|
||||||
|
|
||||||
notifyEmail := strings.TrimSpace(this.GetString("notify_email"))
|
|
||||||
if notifyEmail != "" {
|
|
||||||
tmp := strings.Split(notifyEmail, "\n")
|
|
||||||
emailList := make([]string, 0, len(tmp))
|
|
||||||
for _, v := range tmp {
|
|
||||||
v = strings.TrimSpace(v)
|
|
||||||
if !libs.IsEmail([]byte(v)) {
|
|
||||||
this.ajaxMsg("无效的Email地址:"+v, MSG_ERR)
|
|
||||||
} else {
|
|
||||||
emailList = append(emailList, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
task.NotifyEmail = strings.Join(emailList, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
if task.TaskName == "" || task.CronSpec == "" || task.Command == "" {
|
if task.TaskName == "" || task.CronSpec == "" || task.Command == "" {
|
||||||
this.ajaxMsg("请填写完整信息", MSG_ERR)
|
this.ajaxMsg("请填写完整信息", MSG_ERR)
|
||||||
}
|
}
|
||||||
@@ -189,6 +174,10 @@ func (this *TaskController) Edit() {
|
|||||||
// 分组列表
|
// 分组列表
|
||||||
groups, _ := models.TaskGroupGetList(1, 100)
|
groups, _ := models.TaskGroupGetList(1, 100)
|
||||||
this.Data["groups"] = groups
|
this.Data["groups"] = groups
|
||||||
|
//服务器分组
|
||||||
|
servers, _ := models.TaskServerGetList(1, 100)
|
||||||
|
this.Data["servers"] = servers
|
||||||
|
|
||||||
this.Data["task"] = task
|
this.Data["task"] = task
|
||||||
this.Data["pageTitle"] = "编辑任务"
|
this.Data["pageTitle"] = "编辑任务"
|
||||||
this.display()
|
this.display()
|
||||||
|
|||||||
34
info.log
Normal file
34
info.log
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
nohup: ./PPGo_Job: No such file or directory
|
||||||
|
[ORM]2017/08/16 09:38:35 -[Queries/default] - [ OK / db.QueryRow / 20.4ms] - [SELECT COUNT(*) FROM `pp_task` T0 WHERE T0.`status` = ? ] - `1`
|
||||||
|
[ORM]2017/08/16 09:38:35 -[Queries/default] - [ OK / db.Query / 0.8ms] - [SELECT T0.`id`, T0.`user_id`, T0.`group_id`, T0.`task_name`, T0.`task_type`, T0.`description`, T0.`cron_spec`, T0.`concurrent`, T0.`command`, T0.`status`, T0.`notify`, T0.`notify_email`, T0.`timeout`, T0.`execute_times`, T0.`prev_time`, T0.`create_time` FROM `pp_task` T0 WHERE T0.`status` = ? ORDER BY T0.`id` DESC LIMIT 1000000] - `1`
|
||||||
|
2017/08/16 09:38:35 [1;34m[I] [asm_amd64.s:2197] http server Running on http://:8080[0m
|
||||||
|
2017/08/16 09:38:40 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 1.098433ms| match|[44m GET [0m /login r:/login[0m
|
||||||
|
2017/08/16 09:38:40 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 405.271µs| match|[44m GET [0m /static/login/style.css[0m
|
||||||
|
2017/08/16 09:38:40 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 4.183452ms| match|[44m GET [0m /static/bootstrap/css/bootstrap.min.css[0m
|
||||||
|
2017/08/16 09:38:40 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 5.848598ms| match|[44m GET [0m /static/js/jquery-1.11.1.min.js[0m
|
||||||
|
2017/08/16 09:38:40 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 7.361263ms| match|[44m GET [0m /static/bootstrap/js/bootstrap.js[0m
|
||||||
|
2017/08/16 09:38:40 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 1.723698ms| match|[44m GET [0m /static/login/background.jpg[0m
|
||||||
|
2017/08/16 09:38:40 [1;44m[D] [server.go:2568] | 127.0.0.1|[43m 404 [0m| 329.057µs| nomatch|[44m GET [0m /static/img/favicon.png[0m
|
||||||
|
[ORM]2017/08/16 09:38:42 -[Queries/default] - [ OK / db.Query / 9.1ms] - [SELECT T0.`id`, T0.`user_name`, T0.`password`, T0.`salt`, T0.`email`, T0.`last_login`, T0.`last_ip`, T0.`status` FROM `pp_user` T0 WHERE T0.`user_name` = ? LIMIT 1] - `admin`
|
||||||
|
[ORM]2017/08/16 09:38:42 -[Queries/default] - [ OK / db.Exec / 4.3ms] - [UPDATE `pp_user` SET `user_name` = ?, `password` = ?, `salt` = ?, `email` = ?, `last_login` = ?, `last_ip` = ?, `status` = ? WHERE `id` = ?] - `admin`, `abfcf6dcedfb4b5b1505d41a8b4c77e8`, `aYk4Q1P83v`, `haodaquan@shoplinq.cn`, `1502847522`, `[`, `0`, `1`
|
||||||
|
[ORM]2017/08/16 09:38:42 -[Queries/default] - [ OK / db.Query / 0.5ms] - [SELECT T0.`id`, T0.`user_name`, T0.`password`, T0.`salt`, T0.`email`, T0.`last_login`, T0.`last_ip`, T0.`status` FROM `pp_user` T0 WHERE T0.`id` = ? LIMIT 1] - `1`
|
||||||
|
[ORM]2017/08/16 09:38:42 -[Queries/default] - [ OK / db.QueryRow / 0.7ms] - [SELECT COUNT(*) FROM `pp_task` T0 ]
|
||||||
|
[ORM]2017/08/16 09:38:42 -[Queries/default] - [ OK / db.Query / 1.0ms] - [SELECT T0.`id`, T0.`user_id`, T0.`group_id`, T0.`task_name`, T0.`task_type`, T0.`description`, T0.`cron_spec`, T0.`concurrent`, T0.`command`, T0.`status`, T0.`notify`, T0.`notify_email`, T0.`timeout`, T0.`execute_times`, T0.`prev_time`, T0.`create_time` FROM `pp_task` T0 ORDER BY T0.`id` DESC LIMIT 20]
|
||||||
|
[ORM]2017/08/16 09:38:42 -[Queries/default] - [ OK / db.QueryRow / 3.6ms] - [SELECT COUNT(*) FROM `pp_task_group` T0 ]
|
||||||
|
[ORM]2017/08/16 09:38:42 -[Queries/default] - [ OK / db.Query / 1.5ms] - [SELECT T0.`id`, T0.`user_id`, T0.`group_name`, T0.`description`, T0.`create_time` FROM `pp_task_group` T0 ORDER BY T0.`id` DESC LIMIT 100]
|
||||||
|
2017/08/16 09:38:42 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 10.55596ms| match|[44m GET [0m /task/list r:/task/list/*[0m
|
||||||
|
2017/08/16 09:38:42 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 1.173247ms| match|[44m GET [0m /static/css/dermaorange.css[0m
|
||||||
|
2017/08/16 09:38:42 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 628.292µs| match|[44m GET [0m /static/css/dermadefault.css[0m
|
||||||
|
2017/08/16 09:38:42 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 1.808048ms| match|[44m GET [0m /static/css/style.css[0m
|
||||||
|
2017/08/16 09:38:42 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 1.171345ms| match|[44m GET [0m /static/css/templatecss.css[0m
|
||||||
|
2017/08/16 09:38:42 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 2.631179ms| match|[44m GET [0m /static/css/dermagreen.css[0m
|
||||||
|
2017/08/16 09:38:42 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 2.248771ms| match|[44m GET [0m /static/js/jquery.cookie.js[0m
|
||||||
|
2017/08/16 09:38:42 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 809.603µs| match|[44m GET [0m /static/bootstrap/js/bootstrap.min.js[0m
|
||||||
|
2017/08/16 09:38:42 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 367.119µs| match|[44m GET [0m /static/bootstrap/fonts/glyphicons-halflings-regular.woff2[0m
|
||||||
|
[ORM]2017/08/16 09:38:42 -[Queries/default] - [ OK / db.Query / 0.4ms] - [SELECT T0.`id`, T0.`user_name`, T0.`password`, T0.`salt`, T0.`email`, T0.`last_login`, T0.`last_ip`, T0.`status` FROM `pp_user` T0 WHERE T0.`id` = ? LIMIT 1] - `1`
|
||||||
|
2017/08/16 09:38:42 [1;44m[D] [server.go:2568] | 127.0.0.1|[43m 404 [0m| 278.275µs| nomatch|[44m GET [0m /favicon.ico[0m
|
||||||
|
[ORM]2017/08/16 09:38:47 -[Queries/default] - [ OK / db.Query / 1.8ms] - [SELECT T0.`id`, T0.`user_name`, T0.`password`, T0.`salt`, T0.`email`, T0.`last_login`, T0.`last_ip`, T0.`status` FROM `pp_user` T0 WHERE T0.`id` = ? LIMIT 1] - `1`
|
||||||
|
[ORM]2017/08/16 09:38:47 -[Queries/default] - [ OK / db.QueryRow / 0.1ms] - [SELECT COUNT(*) FROM `pp_task_group` T0 ]
|
||||||
|
[ORM]2017/08/16 09:38:47 -[Queries/default] - [ OK / db.Query / 0.2ms] - [SELECT T0.`id`, T0.`user_id`, T0.`group_name`, T0.`description`, T0.`create_time` FROM `pp_task_group` T0 ORDER BY T0.`id` DESC LIMIT 20]
|
||||||
|
2017/08/16 09:38:47 [1;44m[D] [server.go:2568] | 127.0.0.1|[42m 200 [0m| 4.738919ms| match|[44m GET [0m /group/list r:/group/list/*[0m
|
||||||
|
[ORM]2017/08/16 09:38:47 -[Queries/default] - [ OK / db.Query / 0.6ms] - [SELECT T0.`id`, T0.`user_name`, T0.`password`, T0.`salt`, T0.`email`, T0.`last_login`, T0.`last_ip`, T0.`status` FROM `pp_user` T0 WHERE T0.`id` = ? LIMIT 1] - `1`
|
||||||
182
jobs/job.go
182
jobs/job.go
@@ -11,40 +11,16 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/george518/PPGo_Job/mail"
|
|
||||||
"github.com/george518/PPGo_Job/models"
|
"github.com/george518/PPGo_Job/models"
|
||||||
"html/template"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
"io/ioutil"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
var mailTpl *template.Template
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
mailTpl, _ = template.New("mail_tpl").Parse(`
|
|
||||||
你好 {{.username}},<br/>
|
|
||||||
|
|
||||||
<p>以下是任务执行结果:</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
任务ID:{{.task_id}}<br/>
|
|
||||||
任务名称:{{.task_name}}<br/>
|
|
||||||
执行时间:{{.start_time}}<br />
|
|
||||||
执行耗时:{{.process_time}}秒<br />
|
|
||||||
执行状态:{{.status}}
|
|
||||||
</p>
|
|
||||||
<p>-------------以下是任务执行输出-------------</p>
|
|
||||||
<p>{{.output}}</p>
|
|
||||||
<p>
|
|
||||||
--------------------------------------------<br />
|
|
||||||
本邮件由系统自动发出,请勿回复<br />
|
|
||||||
如果要取消邮件通知,请登录到系统进行设置<br />
|
|
||||||
</p>
|
|
||||||
`)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type Job struct {
|
type Job struct {
|
||||||
id int // 任务ID
|
id int // 任务ID
|
||||||
@@ -56,14 +32,24 @@ type Job struct {
|
|||||||
Concurrent bool // 同一个任务是否允许并行执行
|
Concurrent bool // 同一个任务是否允许并行执行
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func NewJobFromTask(task *models.Task) (*Job, error) {
|
func NewJobFromTask(task *models.Task) (*Job, error) {
|
||||||
if task.Id < 1 {
|
if task.Id < 1 {
|
||||||
return nil, fmt.Errorf("ToJob: 缺少id")
|
return nil, fmt.Errorf("ToJob: 缺少id")
|
||||||
}
|
}
|
||||||
job := NewCommandJob(task.Id, task.TaskName, task.Command)
|
//本地程序执行
|
||||||
job.task = task
|
if(task.ServerId==0) {
|
||||||
job.Concurrent = task.Concurrent == 1
|
job := NewCommandJob(task.Id, task.TaskName, task.Command)
|
||||||
return job, nil
|
job.task = task
|
||||||
|
job.Concurrent = task.Concurrent == 1
|
||||||
|
return job, nil
|
||||||
|
}else{
|
||||||
|
server, _ := models.TaskServerGetById(task.ServerId)
|
||||||
|
job := RemoteCommandJob(task.Id, task.TaskName, task.Command,server)
|
||||||
|
job.task = task
|
||||||
|
job.Concurrent = task.Concurrent == 1
|
||||||
|
return job, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCommandJob(id int, name string, command string) *Job {
|
func NewCommandJob(id int, name string, command string) *Job {
|
||||||
@@ -85,6 +71,66 @@ func NewCommandJob(id int, name string, command string) *Job {
|
|||||||
}
|
}
|
||||||
return job
|
return job
|
||||||
}
|
}
|
||||||
|
//远程执行任务
|
||||||
|
func RemoteCommandJob(id int,name string,command string,servers *models.TaskServer) *Job {
|
||||||
|
job := &Job{
|
||||||
|
id: id,
|
||||||
|
name: name,
|
||||||
|
}
|
||||||
|
job.runFunc = func(timeout time.Duration) (string, string, error, bool) {
|
||||||
|
|
||||||
|
key, err := ioutil.ReadFile(servers.PrivateKeySrc)
|
||||||
|
if err != nil {
|
||||||
|
return "","",err,false
|
||||||
|
}
|
||||||
|
// Create the Signer for this private key.
|
||||||
|
signer, err := ssh.ParsePrivateKey(key)
|
||||||
|
if err != nil {
|
||||||
|
return "","",err,false
|
||||||
|
}
|
||||||
|
addr := fmt.Sprintf("%s:%d", servers.ServerIp, servers.Port)
|
||||||
|
config := &ssh.ClientConfig{
|
||||||
|
User: "root",
|
||||||
|
Auth: []ssh.AuthMethod{
|
||||||
|
// Use the PublicKeys method for remote authentication.
|
||||||
|
ssh.PublicKeys(signer),
|
||||||
|
},
|
||||||
|
//HostKeyCallback: ssh.FixedHostKey(hostKey),
|
||||||
|
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// Connect to the remote server and perform the SSH handshake.47.93.220.5
|
||||||
|
client, err := ssh.Dial("tcp", addr, config)
|
||||||
|
if err != nil {
|
||||||
|
return "","",err,false
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err := client.NewSession()
|
||||||
|
if err != nil {
|
||||||
|
return "","",err,false
|
||||||
|
}
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
// Once a Session is created, you can execute a single command on
|
||||||
|
// the remote side using the Run method.
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
var c bytes.Buffer
|
||||||
|
session.Stdout = &b
|
||||||
|
session.Stderr = &c
|
||||||
|
|
||||||
|
//session.Output(command)
|
||||||
|
if err := session.Run(command); err != nil {
|
||||||
|
return "","",err,false
|
||||||
|
}
|
||||||
|
isTimeout := false
|
||||||
|
return b.String(), c.String(), err, isTimeout
|
||||||
|
}
|
||||||
|
return job
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func (j *Job) Status() int {
|
func (j *Job) Status() int {
|
||||||
return j.status
|
return j.status
|
||||||
@@ -159,41 +205,41 @@ func (j *Job) Run() {
|
|||||||
j.task.Update("PrevTime", "ExecuteTimes")
|
j.task.Update("PrevTime", "ExecuteTimes")
|
||||||
|
|
||||||
// 发送邮件通知
|
// 发送邮件通知
|
||||||
if (j.task.Notify == 1 && err != nil) || j.task.Notify == 2 {
|
//if (j.task.Notify == 1 && err != nil) || j.task.Notify == 2 {
|
||||||
user, uerr := models.UserGetById(j.task.UserId)
|
// user, uerr := models.UserGetById(j.task.UserId)
|
||||||
if uerr != nil {
|
// if uerr != nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
var title string
|
// var title string
|
||||||
|
//
|
||||||
data := make(map[string]interface{})
|
// data := make(map[string]interface{})
|
||||||
data["task_id"] = j.task.Id
|
// data["task_id"] = j.task.Id
|
||||||
data["username"] = user.UserName
|
// data["username"] = user.UserName
|
||||||
data["task_name"] = j.task.TaskName
|
// data["task_name"] = j.task.TaskName
|
||||||
data["start_time"] = beego.Date(t, "Y-m-d H:i:s")
|
// data["start_time"] = beego.Date(t, "Y-m-d H:i:s")
|
||||||
data["process_time"] = float64(ut) / 1000
|
// data["process_time"] = float64(ut) / 1000
|
||||||
data["output"] = cmdOut
|
// data["output"] = cmdOut
|
||||||
|
//
|
||||||
if isTimeout {
|
// if isTimeout {
|
||||||
title = fmt.Sprintf("任务执行结果通知 #%d: %s", j.task.Id, "超时")
|
// title = fmt.Sprintf("任务执行结果通知 #%d: %s", j.task.Id, "超时")
|
||||||
data["status"] = fmt.Sprintf("超时(%d秒)", int(timeout/time.Second))
|
// data["status"] = fmt.Sprintf("超时(%d秒)", int(timeout/time.Second))
|
||||||
} else if err != nil {
|
// } else if err != nil {
|
||||||
title = fmt.Sprintf("任务执行结果通知 #%d: %s", j.task.Id, "失败")
|
// title = fmt.Sprintf("任务执行结果通知 #%d: %s", j.task.Id, "失败")
|
||||||
data["status"] = "失败(" + err.Error() + ")"
|
// data["status"] = "失败(" + err.Error() + ")"
|
||||||
} else {
|
// } else {
|
||||||
title = fmt.Sprintf("任务执行结果通知 #%d: %s", j.task.Id, "成功")
|
// title = fmt.Sprintf("任务执行结果通知 #%d: %s", j.task.Id, "成功")
|
||||||
data["status"] = "成功"
|
// data["status"] = "成功"
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
content := new(bytes.Buffer)
|
// content := new(bytes.Buffer)
|
||||||
mailTpl.Execute(content, data)
|
// mailTpl.Execute(content, data)
|
||||||
ccList := make([]string, 0)
|
// ccList := make([]string, 0)
|
||||||
if j.task.NotifyEmail != "" {
|
// if j.task.NotifyEmail != "" {
|
||||||
ccList = strings.Split(j.task.NotifyEmail, "\n")
|
// ccList = strings.Split(j.task.NotifyEmail, "\n")
|
||||||
}
|
// }
|
||||||
if !mail.SendMail(user.Email, user.UserName, title, content.String(), ccList) {
|
// if !mail.SendMail(user.Email, user.UserName, title, content.String(), ccList) {
|
||||||
beego.Error("发送邮件超时:", user.Email)
|
// beego.Error("发送邮件超时:", user.Email)
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|||||||
67
mail/mail.go
67
mail/mail.go
@@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Author: haodaquan
|
|
||||||
* @Date: 2017-06-21 13:06:28
|
|
||||||
* @Last Modified by: haodaquan
|
|
||||||
* @Last Modified time: 2017-06-21 13:06:33
|
|
||||||
*/
|
|
||||||
|
|
||||||
package mail
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/astaxie/beego"
|
|
||||||
"github.com/astaxie/beego/utils"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
sendCh chan *utils.Email
|
|
||||||
config string
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
queueSize, _ := beego.AppConfig.Int("mail.queue_size")
|
|
||||||
host := beego.AppConfig.String("mail.host")
|
|
||||||
port, _ := beego.AppConfig.Int("mail.port")
|
|
||||||
username := beego.AppConfig.String("mail.user")
|
|
||||||
password := beego.AppConfig.String("mail.password")
|
|
||||||
from := beego.AppConfig.String("mail.from")
|
|
||||||
if port == 0 {
|
|
||||||
port = 25
|
|
||||||
}
|
|
||||||
|
|
||||||
config = fmt.Sprintf(`{"username":"%s","password":"%s","host":"%s","port":%d,"from":"%s"}`, username, password, host, port, from)
|
|
||||||
|
|
||||||
sendCh = make(chan *utils.Email, queueSize)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case m, ok := <-sendCh:
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := m.Send(); err != nil {
|
|
||||||
beego.Error("SendMail:", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func SendMail(address, name, subject, content string, cc []string) bool {
|
|
||||||
mail := utils.NewEMail(config)
|
|
||||||
mail.To = []string{address}
|
|
||||||
mail.Subject = subject
|
|
||||||
mail.HTML = content
|
|
||||||
if len(cc) > 0 {
|
|
||||||
mail.Cc = cc
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case sendCh <- mail:
|
|
||||||
return true
|
|
||||||
case <-time.After(time.Second * 3):
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1
main.go
1
main.go
@@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
_ "github.com/george518/PPGo_Job/mail"
|
|
||||||
"github.com/george518/PPGo_Job/models"
|
"github.com/george518/PPGo_Job/models"
|
||||||
_ "github.com/george518/PPGo_Job/routers"
|
_ "github.com/george518/PPGo_Job/routers"
|
||||||
"github.com/george518/PPGo_Job/jobs"
|
"github.com/george518/PPGo_Job/jobs"
|
||||||
|
|||||||
@@ -30,9 +30,7 @@ func Init() {
|
|||||||
dsn = dsn + "&loc=" + url.QueryEscape(timezone)
|
dsn = dsn + "&loc=" + url.QueryEscape(timezone)
|
||||||
}
|
}
|
||||||
orm.RegisterDataBase("default", "mysql", dsn)
|
orm.RegisterDataBase("default", "mysql", dsn)
|
||||||
|
orm.RegisterModel(new(User), new(Task), new(TaskGroup), new(TaskLog),new(TaskServer))
|
||||||
// orm.RegisterModel(new(User), new(Task), new(TaskGroup), new(TaskLog))
|
|
||||||
orm.RegisterModel(new(User), new(Task), new(TaskGroup), new(TaskLog))
|
|
||||||
|
|
||||||
if beego.AppConfig.String("runmode") == "dev" {
|
if beego.AppConfig.String("runmode") == "dev" {
|
||||||
orm.Debug = true
|
orm.Debug = true
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const (
|
|||||||
type Task struct {
|
type Task struct {
|
||||||
Id int
|
Id int
|
||||||
UserId int
|
UserId int
|
||||||
|
ServerId int
|
||||||
GroupId int
|
GroupId int
|
||||||
TaskName string
|
TaskName string
|
||||||
TaskType int
|
TaskType int
|
||||||
@@ -30,8 +31,6 @@ type Task struct {
|
|||||||
Concurrent int
|
Concurrent int
|
||||||
Command string
|
Command string
|
||||||
Status int
|
Status int
|
||||||
Notify int
|
|
||||||
NotifyEmail string
|
|
||||||
Timeout int
|
Timeout int
|
||||||
ExecuteTimes int
|
ExecuteTimes int
|
||||||
PrevTime int64
|
PrevTime int64
|
||||||
|
|||||||
@@ -60,9 +60,7 @@ func TaskGroupDelById(id int) error {
|
|||||||
|
|
||||||
func TaskGroupGetList(page, pageSize int) ([]*TaskGroup, int64) {
|
func TaskGroupGetList(page, pageSize int) ([]*TaskGroup, int64) {
|
||||||
offset := (page - 1) * pageSize
|
offset := (page - 1) * pageSize
|
||||||
|
|
||||||
list := make([]*TaskGroup, 0)
|
list := make([]*TaskGroup, 0)
|
||||||
|
|
||||||
query := orm.NewOrm().QueryTable(TableName("task_group"))
|
query := orm.NewOrm().QueryTable(TableName("task_group"))
|
||||||
total, _ := query.Count()
|
total, _ := query.Count()
|
||||||
query.OrderBy("-id").Limit(pageSize, offset).All(&list)
|
query.OrderBy("-id").Limit(pageSize, offset).All(&list)
|
||||||
|
|||||||
87
models/task_server.go
Normal file
87
models/task_server.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* @Author: haodaquan
|
||||||
|
* @Date: 2017-08-16 12:22:37
|
||||||
|
* @Last Modified by: haodaquan
|
||||||
|
* @Last Modified time: 2017-08-16 12:22:55
|
||||||
|
*/
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/astaxie/beego/orm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TaskServer struct {
|
||||||
|
Id int
|
||||||
|
ServerName string
|
||||||
|
ServerIp string
|
||||||
|
Port int
|
||||||
|
Password string
|
||||||
|
PrivateKeySrc string
|
||||||
|
PublicKeySrc string
|
||||||
|
Type int
|
||||||
|
Detail string
|
||||||
|
CreateTime int64
|
||||||
|
UpdateTime int64
|
||||||
|
Status int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TaskServer) TableName() string {
|
||||||
|
return TableName("task_server")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TaskServer) Update(fields ...string) error {
|
||||||
|
if t.ServerName == "" {
|
||||||
|
return fmt.Errorf("服务器名不能为空")
|
||||||
|
}
|
||||||
|
if t.ServerIp == "" {
|
||||||
|
return fmt.Errorf("服务器IP不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Type == 0 && t.Password == "" {
|
||||||
|
return fmt.Errorf("服务器密码不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Type == 1 && t.PrivateKeySrc == "" {
|
||||||
|
return fmt.Errorf("私钥不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := orm.NewOrm().Update(t, fields...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TaskServerAdd(obj *TaskServer) (int64, error) {
|
||||||
|
if obj.ServerName == "" {
|
||||||
|
return 0, fmt.Errorf("服务器名不能为空")
|
||||||
|
}
|
||||||
|
return orm.NewOrm().Insert(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TaskServerGetById(id int) (*TaskServer, error) {
|
||||||
|
obj := &TaskServer{
|
||||||
|
Id: id,
|
||||||
|
}
|
||||||
|
err := orm.NewOrm().Read(obj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TaskServerDelById(id int) error {
|
||||||
|
_, err := orm.NewOrm().QueryTable(TableName("task_server")).Filter("id", id).Delete()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TaskServerGetList(page, pageSize int) ([]*TaskServer, int64) {
|
||||||
|
offset := (page - 1) * pageSize
|
||||||
|
list := make([]*TaskServer, 0)
|
||||||
|
query := orm.NewOrm().QueryTable(TableName("task_server"))
|
||||||
|
total, _ := query.Count()
|
||||||
|
query.OrderBy("-id").Limit(pageSize, offset).All(&list)
|
||||||
|
|
||||||
|
return list, total
|
||||||
|
}
|
||||||
46
ppgo_job.sql
46
ppgo_job.sql
File diff suppressed because one or more lines are too long
@@ -14,4 +14,5 @@ func init() {
|
|||||||
beego.Router("/help", &controllers.HelpController{}, "*:Index")
|
beego.Router("/help", &controllers.HelpController{}, "*:Index")
|
||||||
beego.AutoRouter(&controllers.TaskController{})
|
beego.AutoRouter(&controllers.TaskController{})
|
||||||
beego.AutoRouter(&controllers.GroupController{})
|
beego.AutoRouter(&controllers.GroupController{})
|
||||||
|
beego.AutoRouter(&controllers.ServerController{})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<div class="content-list">
|
<div class="content-list">
|
||||||
<form action="{{urlfor "GroupController.Add"}}" method="post" class="form-horizontal">
|
<form action="{{urlfor "GroupController.Add"}}" method="post" class="form-horizontal">
|
||||||
<div class="form-group" style="margin-top: 15px">
|
<div class="form-group" style="margin-top: 15px">
|
||||||
<label class="col-sm-3 control-label" for="group_name">组名</label>
|
<label class="col-sm-3 control-label" for="group_name">分类名称</label>
|
||||||
<div class="col-sm-3" >
|
<div class="col-sm-3" >
|
||||||
<input type="text" class="form-control input-sm" placeholder="" name="group_name" value="" required />
|
<input type="text" class="form-control input-sm" placeholder="" name="group_name" value="" required />
|
||||||
</div>
|
</div>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group" style="margin-top: 15px">
|
<div class="form-group" style="margin-top: 15px">
|
||||||
<label class="col-sm-3 control-label" for="description">任务说明</label>
|
<label class="col-sm-3 control-label" for="description">分类说明</label>
|
||||||
<div class="col-sm-5" >
|
<div class="col-sm-5" >
|
||||||
<textarea name="description" class="form-control" id="description" rows="3"></textarea>
|
<textarea name="description" class="form-control" id="description" rows="3"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<div class="content-list">
|
<div class="content-list">
|
||||||
<form action="{{urlfor "GroupController.Edit"}}" method="post" class="form-horizontal">
|
<form action="{{urlfor "GroupController.Edit"}}" method="post" class="form-horizontal">
|
||||||
<div class="form-group" style="margin-top: 15px">
|
<div class="form-group" style="margin-top: 15px">
|
||||||
<label class="col-sm-3 control-label" for="group_name">组名</label>
|
<label class="col-sm-3 control-label" for="group_name">分类名称</label>
|
||||||
<div class="col-sm-3" >
|
<div class="col-sm-3" >
|
||||||
<input type="text" class="form-control input-sm" placeholder="" name="group_name" value="{{.group.GroupName}}" required />
|
<input type="text" class="form-control input-sm" placeholder="" name="group_name" value="{{.group.GroupName}}" required />
|
||||||
</div>
|
</div>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group" style="margin-top: 15px">
|
<div class="form-group" style="margin-top: 15px">
|
||||||
<label class="col-sm-3 control-label" for="description">任务说明</label>
|
<label class="col-sm-3 control-label" for="description">分类说明</label>
|
||||||
<div class="col-sm-5" >
|
<div class="col-sm-5" >
|
||||||
<textarea name="description" class="form-control" id="description" rows="3">{{.group.Description}}</textarea>
|
<textarea name="description" class="form-control" id="description" rows="3">{{.group.Description}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<div class="search-box row">
|
<div class="search-box row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<div class="btn-group pull-left" role="group" aria-label="...">
|
<div class="btn-group pull-left" role="group" aria-label="...">
|
||||||
<a href='{{urlfor "GroupController.Add"}}' class="btn btn-primary"><span class="glyphicon glyphicon-plus"></span> 新增分组</a>
|
<a href='{{urlfor "GroupController.Add"}}' class="btn btn-primary"><span class="glyphicon glyphicon-plus"></span> 新增分类</a>
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<span class="glyphicon glyphicon-edit"></span> 批量操作
|
<span class="glyphicon glyphicon-edit"></span> 批量操作
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><input type="checkbox" name="all_check" /></td>
|
<td><input type="checkbox" name="all_check" /></td>
|
||||||
<td>ID</td>
|
<td>ID</td>
|
||||||
<td width="20%">分组名称</td>
|
<td width="20%">分类名称</td>
|
||||||
<td>描述</td>
|
<td>描述</td>
|
||||||
<td width="25%">操作</td>
|
<td width="25%">操作</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
<div class="collapse navbar-collapse">
|
<div class="collapse navbar-collapse">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li class="li-border">
|
<li class="li-border">
|
||||||
<a class="mystyle-color" href="#" style="font-size: 20px">渠道定时任务管理后台 <span style="font-size: 12px">V1.1</span></a>
|
<a class="mystyle-color" href="#" style="font-size: 20px">定时任务管理后台 <span style="font-size: 12px">V1.2</span></a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -129,7 +129,6 @@
|
|||||||
<span class="sub-title">任务分类</span>
|
<span class="sub-title">任务分类</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li {{if eq .curRoute "help.index"}}class="active"{{end}}>
|
<li {{if eq .curRoute "help.index"}}class="active"{{end}}>
|
||||||
<div class="showtitle" style="width:100px;">
|
<div class="showtitle" style="width:100px;">
|
||||||
使用帮助
|
使用帮助
|
||||||
@@ -143,6 +142,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="subNavBox">
|
||||||
|
<div class="sBox">
|
||||||
|
<div class="subNav sublist-down">
|
||||||
|
<span class="title-icon glyphicon glyphicon-chevron-down"></span>
|
||||||
|
<span class="sublist-title">资源管理</span>
|
||||||
|
</div>
|
||||||
|
<ul class="navContent" >
|
||||||
|
|
||||||
|
<li {{if eq .menuTag "server"}}class="active"{{end}}>
|
||||||
|
<div class="showtitle" style="width:100px;">
|
||||||
|
服务器
|
||||||
|
</div>
|
||||||
|
<a href="/server/list">
|
||||||
|
<span class="sublist-icon glyphicon glyphicon-hdd"></span>
|
||||||
|
<span class="sub-title">服务器</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="subNavBox">
|
<div class="subNavBox">
|
||||||
<div class="sBox">
|
<div class="sBox">
|
||||||
<div class="subNav sublist-down">
|
<div class="subNav sublist-down">
|
||||||
|
|||||||
149
views/server/add.html
Normal file
149
views/server/add.html
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
<!-- 新增服务器 -->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="info-center">
|
||||||
|
<!--title-->
|
||||||
|
<div class="info-center">
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="pull-left">
|
||||||
|
<h4>{{.pageTitle}}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="pull-right">
|
||||||
|
<!-- <button type="button" class="btn btn-mystyle btn-sm refresh">刷新</button>
|
||||||
|
<button type="button" class="btn btn-mystyle btn-sm reback">返回</button> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!--content-list-->
|
||||||
|
<div class="content-list">
|
||||||
|
<form action="{{urlfor "ServerController.Add"}}" method="post" class="form-horizontal">
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="server_name">服务器名</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="server_name" value="" required />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="server_ip">服务器IP</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="server_ip" value="" required />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="port">服务器ssh端口</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="port" value="" required />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="type">验证类型</label>
|
||||||
|
<div class="col-sm-6" >
|
||||||
|
<label class="radio-inline">
|
||||||
|
<input type="radio" name="type" value="0" > 密码
|
||||||
|
</label>
|
||||||
|
<label class="radio-inline">
|
||||||
|
<input type="radio" name="type" value="1" checked > 密钥
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group hide" style="margin-top: 15px" id="password">
|
||||||
|
<label class="col-sm-3 control-label" for="password">服务器密码</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="password" value="" readonly />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group " style="margin-top: 15px" id="private_key_src">
|
||||||
|
<label class="col-sm-3 control-label" for="private_key_src">私钥地址</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="private_key_src" value="/Users/haodaquan/.ssh/pp_rsa" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group " style="margin-top: 15px" id="public_key_src">
|
||||||
|
<label class="col-sm-3 control-label" for="public_key_src">公钥地址</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="public_key_src" value="/Users/haodaquan/.ssh/pp_rsa.pub" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
<i style="font-size: 12px">公钥和私钥地址请在本地服务器生成,命令:ssh-keygen -t rsa -f pp_rsa</i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="detail">说明</label>
|
||||||
|
<div class="col-sm-5" >
|
||||||
|
<textarea name="detail" class="form-control" id="detail" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<div class="modal-footer" style="text-align:center">
|
||||||
|
<button type="submit" class="btn btn-primary submit_attr_button">保存</button>
|
||||||
|
<button type="button" class="btn btn-default reback">返回</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
$("form").submit(function () {
|
||||||
|
// $(".alert").hide();
|
||||||
|
$("button[type='submit']").attr('disabled', true);
|
||||||
|
$.post('{{urlfor "ServerController.Add"}}', $(this).serialize(), function (out) {
|
||||||
|
if (out.status == 0) {
|
||||||
|
window.location.href = '{{urlfor "ServerController.List"}}';
|
||||||
|
} else {
|
||||||
|
alert_message(out.msg,"alert-danger","alert-success");
|
||||||
|
$("button[type='submit']").attr('disabled', false);
|
||||||
|
}
|
||||||
|
}, "json");
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$("input[name='type']").click(function () {
|
||||||
|
if ($(this).val() > 0) {
|
||||||
|
$("#password").addClass('hide');
|
||||||
|
$("#public_key_src").removeClass('hide');
|
||||||
|
$("#private_key_src").removeClass('hide');
|
||||||
|
} else {
|
||||||
|
$("#password").removeClass('hide');
|
||||||
|
$("#public_key_src").addClass('hide');
|
||||||
|
$("#private_key_src").addClass('hide');
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
150
views/server/edit.html
Normal file
150
views/server/edit.html
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
<!-- 新增服务器 -->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="info-center">
|
||||||
|
<!--title-->
|
||||||
|
<div class="info-center">
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="pull-left">
|
||||||
|
<h4>{{.pageTitle}}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="pull-right">
|
||||||
|
<!-- <button type="button" class="btn btn-mystyle btn-sm refresh">刷新</button>
|
||||||
|
<button type="button" class="btn btn-mystyle btn-sm reback">返回</button> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!--content-list-->
|
||||||
|
<div class="content-list">
|
||||||
|
<form action="{{urlfor "ServerController.Edit"}}" method="post" class="form-horizontal">
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="server_name">服务器名</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="server_name" value="{{.server.ServerName}}" required />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="server_ip">服务器IP</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="server_ip" value="{{.server.ServerIp}}" required />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="port">服务器ssh端口</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="port" value="{{.server.Port}}" required />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="type">验证类型</label>
|
||||||
|
<div class="col-sm-6" >
|
||||||
|
<label class="radio-inline">
|
||||||
|
<input type="radio" name="type" value="0" {{if eq .server.Type 0}}checked{{end}}> 密码
|
||||||
|
</label>
|
||||||
|
<label class="radio-inline">
|
||||||
|
<input type="radio" name="type" value="1" {{if eq .server.Type 1}}checked{{end}}> 密钥
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group {{if eq .server.Type 1}}hide{{end}}" style="margin-top: 15px" id="password">
|
||||||
|
<label class="col-sm-3 control-label" for="password">服务器密码</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="password" value="{{.server.Password}}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group {{if eq .server.Type 0}}hide{{end}}" style="margin-top: 15px" id="private_key_src">
|
||||||
|
<label class="col-sm-3 control-label" for="private_key_src">私钥地址</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="private_key_src" value="{{.server.PrivateKeySrc}}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group {{if eq .server.Type 0}}hide{{end}}" style="margin-top: 15px" id="public_key_src">
|
||||||
|
<label class="col-sm-3 control-label" for="public_key_src">公钥地址</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<input type="text" class="form-control input-sm" placeholder="" name="public_key_src" value="{{.server.PublicKeySrc}}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="detail">说明</label>
|
||||||
|
<div class="col-sm-5" >
|
||||||
|
<textarea name="detail" class="form-control" id="detail" rows="3">{{.server.Detail}}</textarea>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<div class="modal-footer" style="text-align:center">
|
||||||
|
<input type="hidden" name="id" value="{{.server.Id}}" />
|
||||||
|
<button type="submit" class="btn btn-primary submit_attr_button">保存</button>
|
||||||
|
<button type="button" class="btn btn-default reback">返回</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
$("form").submit(function () {
|
||||||
|
// $(".alert").hide();
|
||||||
|
$("button[type='submit']").attr('disabled', true);
|
||||||
|
$.post('{{urlfor "ServerController.Edit"}}', $(this).serialize(), function (out) {
|
||||||
|
if (out.status == 0) {
|
||||||
|
window.location.href = '{{urlfor "ServerController.List"}}';
|
||||||
|
} else {
|
||||||
|
alert_message(out.msg,"alert-danger","alert-success");
|
||||||
|
$("button[type='submit']").attr('disabled', false);
|
||||||
|
}
|
||||||
|
}, "json");
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$("input[name='type']").click(function () {
|
||||||
|
if ($(this).val() > 0) {
|
||||||
|
$("#password").addClass('hide');
|
||||||
|
$("#public_key_src").removeClass('hide');
|
||||||
|
$("#private_key_src").removeClass('hide');
|
||||||
|
} else {
|
||||||
|
$("#password").removeClass('hide');
|
||||||
|
$("#public_key_src").addClass('hide');
|
||||||
|
$("#private_key_src").addClass('hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
121
views/server/list.html
Normal file
121
views/server/list.html
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
<!-- 分组列表 -->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="info-center">
|
||||||
|
<!--title-->
|
||||||
|
<div class="info-center">
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="pull-left">
|
||||||
|
<h4>{{.pageTitle}}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="pull-right">
|
||||||
|
<!-- <button type="button" class="btn btn-mystyle btn-sm refresh">刷新</button>
|
||||||
|
<button type="button" class="btn btn-mystyle btn-sm reback">返回</button> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
<!--content-list-->
|
||||||
|
<div class="content-list">
|
||||||
|
<div class="search-box row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="btn-group pull-left" role="group" aria-label="...">
|
||||||
|
<a href='{{urlfor "ServerController.Add"}}' class="btn btn-primary"><span class="glyphicon glyphicon-plus"></span> 新增服务器</a>
|
||||||
|
<div class="btn-group" role="server">
|
||||||
|
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="glyphicon glyphicon-edit"></span> 批量操作
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="javascript:;" onclick="javascript:batch('delete');"><span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span> 删除</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class=" btn-large pull-right" >
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
<div class="table-margin">
|
||||||
|
<form id="form-list" method="post" action="">
|
||||||
|
<table class="table table-bordered table-header">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td><input type="checkbox" name="all_check" /></td>
|
||||||
|
<td>ID</td>
|
||||||
|
<td width="20%">服务器名称</td>
|
||||||
|
<td width="">IP地址</td>
|
||||||
|
<td width="">端口号</td>
|
||||||
|
<td width="">验证类型</td>
|
||||||
|
<td width="20%">备注</td>
|
||||||
|
<td width="">创建时间</td>
|
||||||
|
<td width="10%">操作</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range $k,$v := .list}}
|
||||||
|
<tr>
|
||||||
|
<td class="chk"><input type="checkbox" name="ids" value="{{$v.id}}" /></td>
|
||||||
|
<td class="center">{{$v.id}}</td>
|
||||||
|
<td>{{$v.server_name}}</td>
|
||||||
|
<td>{{$v.server_ip}}</td>
|
||||||
|
<td>{{$v.port}}</td>
|
||||||
|
<td>{{$v.type}}</td>
|
||||||
|
<td>{{$v.detail}}</td>
|
||||||
|
<td>{{$v.create_time}}</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
|
||||||
|
<a class="btn btn-info btn-xs" href="{{urlfor "ServerController.Edit"}}?id={{$v.id}}">
|
||||||
|
<span class="glyphicon glyphicon-file" aria-hidden="true"></span> 编辑
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="9">
|
||||||
|
<div class="pull-right">
|
||||||
|
{{str2html .pageBar}}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function batch(action) {
|
||||||
|
if ($("input[name='ids']:checked").size() < 1) {
|
||||||
|
alert_message("请选择要操作的任务","alert-danger","alert-success");
|
||||||
|
} else {
|
||||||
|
if(action=='delete'){
|
||||||
|
if(!confirm("确定要删除所选吗?")) return;
|
||||||
|
}
|
||||||
|
var url = "{{urlfor "ServerController.Batch"}}";
|
||||||
|
$.post(url + "?action=" + action, $("#form-list").serialize(), function(out) {
|
||||||
|
if (out.status != 0) {
|
||||||
|
alert_message(out.msg,"alert-danger","alert-success");
|
||||||
|
} else {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}, "json");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//点击行换色
|
||||||
|
$('tbody tr').click(function(){
|
||||||
|
$(this).addClass("warning").siblings().removeClass("warning");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -55,6 +55,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="server_id">服务器</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<select name="server_id" class="form-control">
|
||||||
|
<option value="0">本地服务器</option>
|
||||||
|
{{range $ks, $vs := .servers}}
|
||||||
|
<option value="{{$vs.Id}}">{{$vs.ServerName}}</option>
|
||||||
|
{{end}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group" style="margin-top: 15px">
|
<div class="form-group" style="margin-top: 15px">
|
||||||
<label class="col-sm-3 control-label" for="concurrent">是否单例</label>
|
<label class="col-sm-3 control-label" for="concurrent">是否单例</label>
|
||||||
<div class="col-sm-3" >
|
<div class="col-sm-3" >
|
||||||
@@ -100,35 +115,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group" style="margin-top: 15px">
|
|
||||||
<label class="col-sm-3 control-label" for="notify">邮件通知</label>
|
|
||||||
<div class="col-sm-6" >
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" name="notify" value="0" checked readonly> 不通知
|
|
||||||
</label>
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" name="notify" value="1" > 执行失败通知
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" name="notify" value="2" > 执行结束通知
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-3" style="padding-top:5px;">
|
|
||||||
<i style="font-size: 12px;color: red">暂不支持</i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group notify_email hide" style="margin-top: 15px">
|
|
||||||
<label class="col-sm-3 control-label" for="notify_email">通知邮件抄送人</label>
|
|
||||||
<div class="col-sm-5" >
|
|
||||||
<textarea name="notify_email" class="form-control" id="notify_email" rows="3"></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-4" style="padding-top:5px;">
|
|
||||||
每行一个email地址,如果不需要抄送给其他人请留空
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<div class="modal-footer" style="text-align:center">
|
<div class="modal-footer" style="text-align:center">
|
||||||
<button type="submit" class="btn btn-primary submit_attr_button">保存</button>
|
<button type="submit" class="btn btn-primary submit_attr_button">保存</button>
|
||||||
@@ -141,28 +127,17 @@
|
|||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
$("form").submit(function () {
|
$("form").submit(function () {
|
||||||
// $(".alert").hide();
|
|
||||||
$("button[type='submit']").attr('disabled', true);
|
$("button[type='submit']").attr('disabled', true);
|
||||||
$.post('{{urlfor "TaskController.Add"}}', $(this).serialize(), function (out) {
|
$.post('{{urlfor "TaskController.Add"}}', $(this).serialize(), function (out) {
|
||||||
if (out.status == 0) {
|
if (out.status == 0) {
|
||||||
window.location.href = '{{urlfor "TaskController.List"}}';
|
window.location.href = '{{urlfor "TaskController.List"}}';
|
||||||
} else {
|
} else {
|
||||||
alert_message(out.msg,"alert-danger","alert-success");
|
alert_message(out.msg,"alert-danger","alert-success");
|
||||||
// $(".alert").text(out.msg);
|
|
||||||
// $(".alert").show();
|
|
||||||
$("button[type='submit']").attr('disabled', false);
|
$("button[type='submit']").attr('disabled', false);
|
||||||
}
|
}
|
||||||
}, "json");
|
}, "json");
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
$("input[name='notify']").click(function () {
|
|
||||||
// alert("暂不启用");
|
|
||||||
// return;
|
|
||||||
if ($(this).val() > 0) {
|
|
||||||
$('.notify_email').removeClass('hide');
|
|
||||||
} else {
|
|
||||||
$('.notify_email').addClass('hide');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -56,6 +56,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 15px">
|
||||||
|
<label class="col-sm-3 control-label" for="server_id">服务器</label>
|
||||||
|
<div class="col-sm-3" >
|
||||||
|
<select name="server_id" class="form-control">
|
||||||
|
<option value="0">本地服务器</option>
|
||||||
|
{{range $ks, $vs := .servers}}
|
||||||
|
<option value="{{$vs.Id}}" {{if eq $vs.Id $.task.ServerId}}selected{{end}}>{{$vs.ServerName}}</option>
|
||||||
|
{{end}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6" style="padding-top:5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group" style="margin-top: 15px">
|
<div class="form-group" style="margin-top: 15px">
|
||||||
<label class="col-sm-3 control-label" for="concurrent">是否单例</label>
|
<label class="col-sm-3 control-label" for="concurrent">是否单例</label>
|
||||||
<div class="col-sm-3" >
|
<div class="col-sm-3" >
|
||||||
@@ -102,35 +117,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group" style="margin-top: 15px">
|
|
||||||
<label class="col-sm-3 control-label" for="concurrent">邮件通知</label>
|
|
||||||
<div class="col-sm-6" >
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" name="notify" value="0" {{if eq .task.Notify 0}}checked{{end}}> 不通知
|
|
||||||
</label>
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" name="notify" value="1" {{if eq .task.Notify 1}}checked{{end}}> 执行失败通知
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label class="radio-inline">
|
|
||||||
<input type="radio" name="notify" value="2" {{if eq .task.Notify 2}}checked{{end}}> 执行结束通知
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-3" style="padding-top:5px;">
|
|
||||||
<i style="font-size: 12px;color: red">暂不支持</i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group notify_email {{if eq .task.Notify 0}}hide{{end}}" style="margin-top: 15px">
|
|
||||||
<label class="col-sm-3 control-label" for="task_name">通知邮件抄送人</label>
|
|
||||||
<div class="col-sm-5" >
|
|
||||||
<textarea name="notify_email" class="form-control" id="notify_email" rows="3">{{.task.NotifyEmail}}</textarea>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-4" style="padding-top:5px;">
|
|
||||||
每行一个email地址,如果不需要抄送给其他人请留空
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<input type="hidden" name="id" value="{{.task.Id}}" />
|
<input type="hidden" name="id" value="{{.task.Id}}" />
|
||||||
<div class="modal-footer" style="text-align:center">
|
<div class="modal-footer" style="text-align:center">
|
||||||
@@ -155,13 +141,5 @@ $(function () {
|
|||||||
}, "json");
|
}, "json");
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
$("input[name='notify']").click(function () {
|
|
||||||
if ($(this).val() > 0) {
|
|
||||||
$('.notify_email').removeClass('hide');
|
|
||||||
} else {
|
|
||||||
$('.notify_email').addClass('hide');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -60,7 +60,8 @@
|
|||||||
<td><input type="checkbox" name="all_check" /></td>
|
<td><input type="checkbox" name="all_check" /></td>
|
||||||
<td>ID</td>
|
<td>ID</td>
|
||||||
<td width="20%">任务名称</td>
|
<td width="20%">任务名称</td>
|
||||||
<td>时间表达式</td>
|
<td>服务器</td>
|
||||||
|
|
||||||
<td>任务说明</td>
|
<td>任务说明</td>
|
||||||
<td>上次执行时间</td>
|
<td>上次执行时间</td>
|
||||||
<td>下次执行时间</td>
|
<td>下次执行时间</td>
|
||||||
@@ -80,7 +81,8 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{$v.group_name}}-{{$v.name}}
|
{{$v.group_name}}-{{$v.name}}
|
||||||
</td>
|
</td>
|
||||||
<td> {{$v.cron_spec}} </td>
|
<td> {{$v.server_name}} </td>
|
||||||
|
|
||||||
<td> {{$v.description}} </td>
|
<td> {{$v.description}} </td>
|
||||||
<td> {{$v.prev_time}} </td>
|
<td> {{$v.prev_time}} </td>
|
||||||
<td> {{$v.next_time}} </td>
|
<td> {{$v.next_time}} </td>
|
||||||
@@ -110,7 +112,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="9">
|
<td colspan="8">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
{{str2html .pageBar}}
|
{{str2html .pageBar}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user