Files
ppgo_job/controller/admin.go
T
lmk 610b85e3a5 refactor: 从 Beego 迁移到 GoFrame v2
- 替换 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/
2026-07-09 11:06:12 +08:00

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": ""},
})
}