- 替换 Beego 框架为 GoFrame v2 - 重构项目结构: controller/service/dao/middleware 分层 - 替换自定义 crons 包为 gcron - 模板从 views/ 迁移到 resource/template/ - 配置从 conf/app.conf 迁移到 config.yml - 数据库从 MySQL 切换为 SQLite (modernc.org/sqlite) - 移除 agent/ 远程执行器(待后续迁移) - 移除 crons/ 自定义定时器包 - 静态资源整理到 resource/static/
508 lines
16 KiB
Go
508 lines
16 KiB
Go
package controller
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"ppgo_job/consts"
|
|
"ppgo_job/dao"
|
|
"ppgo_job/model/entity"
|
|
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
"github.com/gogf/gf/v2/net/ghttp"
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
)
|
|
|
|
// ==================== 服务器管理 ====================
|
|
|
|
// ServerAdd 新增服务器页面
|
|
func ServerAdd(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
groups, _, _ := dao.ServerGroup.GetList(ctx, 1, 1000, "status", 1)
|
|
sg := make(map[int]string)
|
|
for _, g := range groups {
|
|
sg[g.Id] = g.GroupName
|
|
}
|
|
display(r, "server/add.html", g.Map{
|
|
"pageTitle": "新增服务器",
|
|
"serverGroup": sg,
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
// ServerEdit 编辑服务器页面
|
|
func ServerEdit(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
server, err := dao.TaskServer.GetById(ctx, id)
|
|
if err != nil || server == nil {
|
|
ajaxMsg(r, "服务器不存在", consts.MsgErr)
|
|
return
|
|
}
|
|
groups, _, _ := dao.ServerGroup.GetList(ctx, 1, 1000, "status", 1)
|
|
sg := make(map[int]string)
|
|
for _, g := range groups {
|
|
sg[g.Id] = g.GroupName
|
|
}
|
|
display(r, "server/edit.html", g.Map{
|
|
"pageTitle": "编辑服务器",
|
|
"server": gconv.Map(server),
|
|
"serverGroup": sg,
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
// ServerAjaxSave 保存服务器
|
|
// ServerCopy 复制服务器页面
|
|
func ServerCopy(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
server, _ := dao.TaskServer.GetById(ctx, id)
|
|
if server == nil {
|
|
ajaxMsg(r, "服务器不存在", consts.MsgErr)
|
|
return
|
|
}
|
|
groups, _, _ := dao.ServerGroup.GetList(ctx, 1, 1000, "status", 1)
|
|
sg := make(map[int]string)
|
|
for _, g := range groups {
|
|
sg[g.Id] = g.GroupName
|
|
}
|
|
r.Response.WriteTpl("server/copy.html", g.Map{
|
|
"pageTitle": "复制服务器",
|
|
"server": gconv.Map(server),
|
|
"serverGroup": sg,
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
func ServerAjaxSave(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
groupId := r.Get("group_id", 0).Int()
|
|
serverName := r.Get("server_name").String()
|
|
serverIp := r.Get("server_ip").String()
|
|
port := r.Get("port", 22).Int()
|
|
serverAccount := r.Get("server_account").String()
|
|
password := r.Get("password").String()
|
|
connType := r.Get("connection_type", 0).Int()
|
|
authType := r.Get("type", 0).Int()
|
|
privateKeySrc := r.Get("private_key_src").String()
|
|
detail := r.Get("detail").String()
|
|
|
|
if serverName == "" || serverIp == "" || serverAccount == "" {
|
|
ajaxMsg(r, "服务器名称、IP、账号不能为空", consts.MsgErr)
|
|
return
|
|
}
|
|
|
|
now := time.Now().Unix()
|
|
|
|
if id > 0 {
|
|
srv, _ := dao.TaskServer.GetById(ctx, id)
|
|
if srv == nil { ajaxMsg(r, "服务器不存在", consts.MsgErr); return }
|
|
if password != "" { srv.Password = password }
|
|
if privateKeySrc != "" { srv.PrivateKeySrc = privateKeySrc }
|
|
srv.GroupId = groupId; srv.ServerName = serverName; srv.ServerIp = serverIp
|
|
srv.Port = port; srv.ServerAccount = serverAccount
|
|
srv.ConnectionType = connType; srv.Type = authType; srv.Detail = detail
|
|
srv.UpdateTime = now
|
|
_ = dao.TaskServer.Update(ctx, srv)
|
|
ajaxMsg(r, "更新成功", consts.MsgOK)
|
|
} else {
|
|
_, err := dao.TaskServer.Insert(ctx, &entity.TaskServer{
|
|
GroupId: groupId, ServerName: serverName, ServerIp: serverIp,
|
|
Port: port, ServerAccount: serverAccount, Password: password,
|
|
ConnectionType: connType, Type: authType,
|
|
PrivateKeySrc: privateKeySrc, Detail: detail,
|
|
CreateTime: now, UpdateTime: now, Status: 0,
|
|
})
|
|
if err != nil { ajaxMsg(r, "添加失败: "+err.Error(), consts.MsgErr); return }
|
|
ajaxMsg(r, "添加成功", consts.MsgOK)
|
|
}
|
|
}
|
|
|
|
// ServerAjaxDel 删除服务器
|
|
func ServerAjaxDel(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
if id <= 0 { ajaxMsg(r, "参数错误", consts.MsgErr); return }
|
|
_ = dao.TaskServer.Delete(ctx, id)
|
|
ajaxMsg(r, "删除成功", consts.MsgOK)
|
|
}
|
|
|
|
// ServerAjaxTest 测试服务器连接
|
|
func ServerAjaxTest(r *ghttp.Request) {
|
|
// 暂不实现实际测试,返回成功
|
|
ajaxMsg(r, "连接测试功能暂未实现", consts.MsgOK)
|
|
}
|
|
|
|
// ServerGetByGroupId 按分组获取服务器列表
|
|
func ServerGetByGroupId(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
groupId := r.Get("groupId", 0).Int()
|
|
list, _, _ := dao.TaskServer.GetList(ctx, 1, 1000, "group_id", groupId)
|
|
r.Response.WriteJson(list)
|
|
}
|
|
|
|
// ServerApiSave Agent注册/更新API
|
|
func ServerApiSave(r *ghttp.Request) {
|
|
ajaxMsg(r, "Agent API 待完善", consts.MsgOK)
|
|
}
|
|
|
|
// ServerApiStatus Agent更新状态API
|
|
func ServerApiStatus(r *ghttp.Request) {
|
|
ajaxMsg(r, "Agent API 待完善", consts.MsgOK)
|
|
}
|
|
|
|
// ServerApiGet Agent获取信息API
|
|
func ServerApiGet(r *ghttp.Request) {
|
|
r.Response.WriteJson(g.Map{"status": 0, "message": "ok"})
|
|
}
|
|
|
|
// ==================== 任务分组 ====================
|
|
|
|
// GroupAdd 新增任务分组页面
|
|
func GroupAdd(r *ghttp.Request) {
|
|
display(r, "group/add.html", g.Map{
|
|
"pageTitle": "新增任务分组",
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
// GroupEdit 编辑任务分组页面
|
|
func GroupEdit(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
group, _ := dao.Group.GetById(ctx, id)
|
|
if group == nil { ajaxMsg(r, "分组不存在", consts.MsgErr); return }
|
|
display(r, "group/edit.html", g.Map{
|
|
"pageTitle": "编辑任务分组",
|
|
"group": gconv.Map(group),
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
// GroupAjaxSave 保存任务分组
|
|
func GroupAjaxSave(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
groupName := r.Get("group_name").String()
|
|
description := r.Get("description").String()
|
|
if groupName == "" { ajaxMsg(r, "分组名称不能为空", consts.MsgErr); return }
|
|
|
|
now := time.Now().Unix()
|
|
if id > 0 {
|
|
g, _ := dao.Group.GetById(ctx, id)
|
|
if g == nil { ajaxMsg(r, "分组不存在", consts.MsgErr); return }
|
|
g.GroupName = groupName; g.Description = description; g.UpdateTime = now
|
|
_ = dao.Group.Update(ctx, g)
|
|
ajaxMsg(r, "更新成功", consts.MsgOK)
|
|
} else {
|
|
_, err := dao.Group.Insert(ctx, &entity.Group{
|
|
GroupName: groupName, Description: description,
|
|
CreateTime: now, UpdateTime: now, Status: 1,
|
|
})
|
|
if err != nil { ajaxMsg(r, "添加失败: "+err.Error(), consts.MsgErr); return }
|
|
ajaxMsg(r, "添加成功", consts.MsgOK)
|
|
}
|
|
}
|
|
|
|
// GroupAjaxDel 删除任务分组
|
|
func GroupAjaxDel(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
if id <= 0 { ajaxMsg(r, "参数错误", consts.MsgErr); return }
|
|
_ = dao.Task.ResetGroupId(ctx, id)
|
|
_ = dao.Group.Delete(ctx, id)
|
|
ajaxMsg(r, "删除成功", consts.MsgOK)
|
|
}
|
|
|
|
// ==================== 资源分组 ====================
|
|
|
|
func ServerGroupAdd(r *ghttp.Request) {
|
|
display(r, "servergroup/add.html", g.Map{
|
|
"pageTitle": "新增资源分组",
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
func ServerGroupEdit(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
sg, _ := dao.ServerGroup.GetById(ctx, id)
|
|
if sg == nil { ajaxMsg(r, "分组不存在", consts.MsgErr); return }
|
|
display(r, "servergroup/edit.html", g.Map{
|
|
"pageTitle": "编辑资源分组",
|
|
"serverGroup": gconv.Map(sg),
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
func ServerGroupAjaxSave(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
groupName := r.Get("group_name").String()
|
|
description := r.Get("description").String()
|
|
if groupName == "" { ajaxMsg(r, "分组名称不能为空", consts.MsgErr); return }
|
|
|
|
now := time.Now().Unix()
|
|
if id > 0 {
|
|
sg, _ := dao.ServerGroup.GetById(ctx, id)
|
|
if sg == nil { ajaxMsg(r, "分组不存在", consts.MsgErr); return }
|
|
sg.GroupName = groupName; sg.Description = description; sg.UpdateTime = now
|
|
_ = dao.ServerGroup.Update(ctx, sg)
|
|
ajaxMsg(r, "更新成功", consts.MsgOK)
|
|
} else {
|
|
_, err := dao.ServerGroup.Insert(ctx, &entity.ServerGroup{
|
|
GroupName: groupName, Description: description,
|
|
CreateTime: now, UpdateTime: now, Status: 1,
|
|
})
|
|
if err != nil { ajaxMsg(r, "添加失败: "+err.Error(), consts.MsgErr); return }
|
|
ajaxMsg(r, "添加成功", consts.MsgOK)
|
|
}
|
|
}
|
|
|
|
func ServerGroupAjaxDel(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
if id <= 0 { ajaxMsg(r, "参数错误", consts.MsgErr); return }
|
|
_ = dao.ServerGroup.Delete(ctx, id)
|
|
ajaxMsg(r, "删除成功", consts.MsgOK)
|
|
}
|
|
|
|
// ==================== 禁用命令 ====================
|
|
|
|
func BanAdd(r *ghttp.Request) {
|
|
display(r, "ban/add.html", g.Map{
|
|
"pageTitle": "新增禁用命令",
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
func BanEdit(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
ban, _ := dao.Ban.GetById(ctx, id)
|
|
if ban == nil { ajaxMsg(r, "记录不存在", consts.MsgErr); return }
|
|
display(r, "ban/edit.html", g.Map{
|
|
"pageTitle": "编辑禁用命令",
|
|
"ban": gconv.Map(ban),
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
func BanAjaxSave(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
code := r.Get("code").String()
|
|
if code == "" { ajaxMsg(r, "命令关键字不能为空", consts.MsgErr); return }
|
|
|
|
now := time.Now().Unix()
|
|
if id > 0 {
|
|
b, _ := dao.Ban.GetById(ctx, id)
|
|
if b == nil { ajaxMsg(r, "记录不存在", consts.MsgErr); return }
|
|
b.Code = code; b.UpdateTime = now
|
|
_ = dao.Ban.Update(ctx, b)
|
|
ajaxMsg(r, "更新成功", consts.MsgOK)
|
|
} else {
|
|
_, err := dao.Ban.Insert(ctx, &entity.Ban{Code: code, CreateTime: now, UpdateTime: now, Status: 1})
|
|
if err != nil { ajaxMsg(r, "添加失败: "+err.Error(), consts.MsgErr); return }
|
|
ajaxMsg(r, "添加成功", consts.MsgOK)
|
|
}
|
|
}
|
|
|
|
func BanAjaxDel(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
if id <= 0 { ajaxMsg(r, "参数错误", consts.MsgErr); return }
|
|
_ = dao.Ban.Delete(ctx, id)
|
|
ajaxMsg(r, "删除成功", consts.MsgOK)
|
|
}
|
|
|
|
// ==================== 通知模板 ====================
|
|
|
|
func NotifyTplList(r *ghttp.Request) {
|
|
display(r, "notifytpl/list.html", g.Map{
|
|
"pageTitle": "通知模板",
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
func NotifyTplTable(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
page := r.Get("page", 1).Int()
|
|
limit := r.Get("limit", 20).Int()
|
|
list, total, err := dao.NotifyTpl.GetList(ctx, page, limit)
|
|
if err != nil { ajaxList(r, "查询失败", consts.MsgErr, 0, nil); return }
|
|
rows := make([]g.Map, 0)
|
|
for _, v := range list {
|
|
tplTypeText := ""
|
|
switch v.TplType {
|
|
case consts.NotifyTypeEmail: tplTypeText = "邮件"
|
|
case consts.NotifyTypeSMS: tplTypeText = "短信"
|
|
case consts.NotifyTypeDingtalk: tplTypeText = "钉钉"
|
|
case consts.NotifyTypeWechat: tplTypeText = "微信"
|
|
}
|
|
statusText := "正常"
|
|
if v.Status == 0 { statusText = "禁用" }
|
|
ct := ""; ut := ""
|
|
if v.CreateTime > 0 { ct = time.Unix(v.CreateTime, 0).Format("2006-01-02 15:04:05") }
|
|
if v.UpdateTime > 0 { ut = time.Unix(v.UpdateTime, 0).Format("2006-01-02 15:04:05") }
|
|
rows = append(rows, g.Map{"id":v.Id,"type":v.Type,"tpl_name":v.TplName,"tpl_type_text":tplTypeText,"create_time":ct,"update_time":ut,"status_text":statusText})
|
|
}
|
|
ajaxList(r, "成功", 0, total, rows)
|
|
}
|
|
|
|
func NotifyTplAdd(r *ghttp.Request) {
|
|
display(r, "notifytpl/add.html", g.Map{
|
|
"pageTitle": "新增通知模板",
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
func NotifyTplEdit(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
tpl, _ := dao.NotifyTpl.GetById(ctx, id)
|
|
if tpl == nil { ajaxMsg(r, "模板不存在", consts.MsgErr); return }
|
|
display(r, "notifytpl/edit.html", g.Map{
|
|
"pageTitle": "编辑通知模板",
|
|
"notifyTpl": gconv.Map(tpl),
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|
|
|
|
func NotifyTplAjaxSave(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
tplName := r.Get("tpl_name").String()
|
|
tplType := r.Get("tpl_type", 0).Int()
|
|
title := r.Get("title").String()
|
|
content := r.Get("content").String()
|
|
tp := r.Get("type").String()
|
|
if tp == "" { tp = "default" }
|
|
|
|
if tplName == "" { ajaxMsg(r, "模板名称不能为空", consts.MsgErr); return }
|
|
|
|
now := time.Now().Unix()
|
|
if id > 0 {
|
|
t, _ := dao.NotifyTpl.GetById(ctx, id)
|
|
if t == nil { ajaxMsg(r, "模板不存在", consts.MsgErr); return }
|
|
t.TplName = tplName; t.TplType = tplType; t.Title = title
|
|
t.Content = content; t.Type = tp; t.UpdateTime = now
|
|
_ = dao.NotifyTpl.Update(ctx, t)
|
|
ajaxMsg(r, "更新成功", consts.MsgOK)
|
|
} else {
|
|
_, err := dao.NotifyTpl.Insert(ctx, &entity.NotifyTpl{
|
|
TplName: tplName, TplType: tplType, Title: title,
|
|
Content: content, Type: tp,
|
|
CreateTime: now, UpdateTime: now, Status: 1,
|
|
})
|
|
if err != nil { ajaxMsg(r, "添加失败: "+err.Error(), consts.MsgErr); return }
|
|
ajaxMsg(r, "添加成功", consts.MsgOK)
|
|
}
|
|
}
|
|
|
|
func NotifyTplAjaxDel(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
if id <= 0 { ajaxMsg(r, "参数错误", consts.MsgErr); return }
|
|
_ = dao.NotifyTpl.Delete(ctx, id)
|
|
ajaxMsg(r, "删除成功", consts.MsgOK)
|
|
}
|
|
|
|
func NotifyTplAjaxByType(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
notifyType := r.Get("notify_type", 0).Int()
|
|
tpl, _ := dao.NotifyTpl.GetByTplType(ctx, notifyType, "system")
|
|
if tpl == nil {
|
|
tpl, _ = dao.NotifyTpl.GetByTplType(ctx, notifyType, "default")
|
|
}
|
|
if tpl == nil {
|
|
r.Response.WriteJson(g.Map{
|
|
"code": 0,
|
|
"data": make([]g.Map, 0),
|
|
})
|
|
return
|
|
}
|
|
r.Response.WriteJson(g.Map{
|
|
"code": 0,
|
|
"data": []g.Map{
|
|
{
|
|
"id": tpl.Id,
|
|
"tpl_name": tpl.TplName,
|
|
"title": tpl.Title,
|
|
"content": tpl.Content,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
// ==================== 任务日志详情 ====================
|
|
|
|
func TaskLogDetail(r *ghttp.Request) {
|
|
ctx := r.GetCtx()
|
|
id := r.Get("id", 0).Int()
|
|
log, _ := dao.TaskLog.GetById(ctx, id)
|
|
if log == nil { ajaxMsg(r, "日志不存在", consts.MsgErr); return }
|
|
|
|
// 构建 taskLog map(模板使用下划线命名,与实体 json tag 不同)
|
|
taskLog := g.Map{
|
|
"id": log.Id,
|
|
"task_id": log.TaskId,
|
|
"server_id": log.ServerId,
|
|
"server_name": log.ServerName,
|
|
"status": log.Status,
|
|
"process_time": log.ProcessTime,
|
|
"output": log.Output,
|
|
"error": log.Error,
|
|
"start_time": time.Unix(log.CreateTime, 0).Format("2006-01-02 15:04:05"),
|
|
"output_size": fmt.Sprintf("%d 字节", len(log.Output)),
|
|
}
|
|
|
|
// 加载关联的任务
|
|
task, _ := dao.Task.GetById(ctx, log.TaskId)
|
|
if task == nil {
|
|
display(r, "tasklog/detail.html", g.Map{
|
|
"pageTitle": "日志详情",
|
|
"taskLog": taskLog,
|
|
"task": g.Map{},
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
return
|
|
}
|
|
|
|
st := "运行中"
|
|
if task.Status == -1 { st = "已删除" } else if task.Status == 0 { st = "已暂停" } else if task.Status == 2 { st = "待审核" } else if task.Status == 3 { st = "审核失败" }
|
|
groupName := ""
|
|
if g, _ := dao.Group.GetById(ctx, task.GroupId); g != nil { groupName = g.GroupName }
|
|
serverName := "本地服务器"
|
|
if task.ServerIds != "" && task.ServerIds != "0" {
|
|
if s, _ := dao.TaskServer.GetById(ctx, gconv.Int(task.ServerIds)); s != nil { serverName = s.ServerName }
|
|
}
|
|
notifyTplName := ""
|
|
if task.IsNotify == 1 && task.NotifyTplId > 0 {
|
|
if t, _ := dao.NotifyTpl.GetById(ctx, task.NotifyTplId); t != nil { notifyTplName = t.TplName }
|
|
}
|
|
createName := ""; updateName := ""
|
|
if a, _ := dao.Admin.GetById(ctx, task.CreateId); a != nil { createName = a.RealName }
|
|
if a, _ := dao.Admin.GetById(ctx, task.UpdateId); a != nil { updateName = a.RealName }
|
|
ct := ""; ut := ""
|
|
if task.CreateTime > 0 { ct = time.Unix(task.CreateTime, 0).Format("2006-01-02 15:04:05") }
|
|
if task.UpdateTime > 0 { ut = time.Unix(task.UpdateTime, 0).Format("2006-01-02 15:04:05") }
|
|
|
|
display(r, "tasklog/detail.html", g.Map{
|
|
"pageTitle": "日志详情",
|
|
"task": task,
|
|
"taskLog": taskLog,
|
|
"TextStatus": st,
|
|
"GroupName": groupName,
|
|
"serverName": serverName,
|
|
"NotifyTplName": notifyTplName,
|
|
"CreateName": createName,
|
|
"UpdateName": updateName,
|
|
"CreateTime": ct,
|
|
"UpdateTime": ut,
|
|
"flash": g.Map{"error": ""},
|
|
})
|
|
}
|