PPGo_Job 定时任务管理系统 ==== 一款轻量级定时任务管理系统,基于 **GoFrame v2** 重构。支持 **本机执行** 和 **SSH 远程执行**,部署简单,资源消耗少。 ## 技术栈 - **后端框架:** GoFrame v2 - **数据库:** SQLite(纯 Go 驱动 `modernc.org/sqlite`,无需 CGO) - **定时任务:** GoFrame `gcron` - **前端:** Vue 3 + Element Plus + TypeScript(`frontend/` 目录) - **旧前端(兼容):** LayUI 模板(`resource/template/`) - **远程执行:** SSH(`golang.org/x/crypto/ssh`) ## 快速开始 ```bash # 方式一:一键构建(前端 + 后端) build_frontend.cmd # 方式二:分步构建 # 1. 构建前端(首次或修改前端后需要) cd frontend npm install npm run build cd .. # 2. 编译(纯 Go,不需要 gcc/MinGW) CGO_ENABLED=0 go build -o ppgo_job.exe . # 3. 运行 ./ppgo_job.exe ``` > 首次启动自动在 `./data/ppgo_job.db` 创建 SQLite 数据库、表和默认管理员。 **访问地址:** http://localhost:8082 **新前端:** http://localhost:8082/app/(Vue 3 + Element Plus) **旧前端:** http://localhost:8082/(LayUI,兼容保留) **默认账号:** admin / **密码:** 123456 ## 运行测试 ```bash # 运行所有测试 CGO_ENABLED=0 go test -count=1 ./... # 运行单元测试(libs、consts、dao,无需启动服务器) CGO_ENABLED=0 go test -count=1 ./libs/ ./consts/ ./dao/ # 运行集成测试(自动启动测试服务器,端口 18082) CGO_ENABLED=0 go test -count=1 -timeout=120s -run "TestLogin|TestAuth|TestHome|TestTask|TestServer|TestGroup|TestBan|TestTemplate|TestStatic|TestDatabase|TestCORS" . # 运行特定包测试 CGO_ENABLED=0 go test -v -count=1 ./libs/ ``` > 集成测试覆盖登录、认证拦截、CRUD 操作、模板渲染、静态文件、CORS 头、数据库种子数据等功能。 > 测试使用独立的端口 `:18082`,不会干扰正在运行的开发实例。 --- ## 📖 使用指南 ### 1. 登录 打开浏览器访问 `http://localhost:8082`,输入默认账号 `admin` / `123456` 登录。 > 💡 如果访问时遇到"重定向次数过多",清除浏览器 Cookie 后刷新即可。 --- ### 2. 首页仪表盘 登录后进入系统首页,展示: - **任务概览** — 总任务数、运行中、待审核 - **近期执行统计** — 过去 7 天的成功/失败/超时柱状图 - **即将执行的任务** — 最近将要触发的定时任务 - **系统信息** — 运行时间、内存使用、goroutine 数量 --- ### 3. 任务管理 #### 3.1 新增任务 左侧菜单「任务管理 → 任务列表」→ 点击「新增」按钮。 必填字段: | 字段 | 说明 | 示例 | |------|------|------| | 任务名称 | 有意义的名称 | `数据库备份` | | Cron 表达式 | **6 段格式(含秒)** | `0 0 3 * * *`(每天凌晨 3 点) | | 执行命令 | 要执行的 shell 命令 | `mysqldump -u root db1 > /backup.sql` | | 超时时间 | 超时后自动终止(秒) | `300`(5 分钟) | > ⚠️ **Cron 表达式注意事项:** > 本项目使用 GoFrame `gcron`,Cron 表达式为 **6 段格式**(比标准多一位秒): > > ``` > 秒 分 时 日 月 周 > ``` > > 常用示例: > - `0 */5 * * * *` — 每 5 分钟 > - `0 0 3 * * *` — 每天凌晨 3 点 > - `0 30 9 * * 1-5` — 工作日 9:30 > - `0 0 0 1 * *` — 每月 1 号零点 > > 如果误填了标准 5 段表达式,系统会提示 `invalid pattern` 错误。 可选字段: - **任务分组** — 归类管理 - **执行服务器** — 选择远程服务器(留空 = 本机执行) - **执行方式** — 同时执行(所有服务器一起跑) / 轮询执行(逐台跑) - **允许并发** — 默认不允许(上一个未执行完,下一个不会触发) - **失败通知** — 勾选后可选择通知模板和接收人 #### 3.2 任务列表 列表展示了所有任务,支持: - **按状态筛选** — 下拉框选择运行中/已暂停/待审核/审核失败 - **按分组筛选** — 下拉框选择任务分组 - **按名称搜索** — 输入关键字后点查询 - **表头排序** — 点击 ID 列头切换正序/倒序 - **表格操作按钮:** | 按钮 | 功能 | |------|------| | 🔍 详细 | 查看任务完整信息 | | ✏️ 编辑 | 修改任务参数 | | ▶️ 启动 | 将暂停的任务加入调度 | | ⏸️ 暂停 | 从调度中移除(暂不执行) | | ▶️ 测试 | **立即执行一次**(不依赖 Cron 触发) | | 📋 日志 | 查看该任务的执行记录 | | 📝 复制 | 基于现有任务创建新任务 | | 🗑️ 删除 | 软删除(可在数据库恢复) | #### 3.3 任务审核 超级管理员 `admin` 创建的任务自动进入暂停状态;普通账号创建的任务进入「待审核」状态,需要管理员在「任务管理 → 任务审核」中通过后才能启动。 --- ### 4. 服务器管理 #### 4.1 新增服务器 「服务器管理 → 服务器列表」→ 点击「新增」。 | 字段 | 说明 | 示例 | |------|------|------| | 服务器名称 | 标识名称 | `Web 服务器 01` | | 连接方式 | SSH / Telnet / Agent | SSH | | IP 地址 | 连接 IP | `192.168.1.100` | | 端口 | SSH 默认 22 | `22` | | 账号 | 登录用户名 | `root` | | 密码/密钥 | 密码或私钥内容 | — | > SSH 远程执行已实现,支持密码和密钥认证。创建任务时选择配置好的服务器即可远程执行。 #### 4.2 资源分组 将服务器归类管理。多个服务器可以属于同一个资源组,方便在创建任务时批量选择。 --- ### 5. 系统设置 #### 5.1 任务分组 对任务进行分类,例如:`数据备份`、`日志清理`、`监控脚本`。 #### 5.2 禁用命令 设置禁止执行的关键词。创建/编辑任务时,如果命令包含禁用词(如 `rm -rf`),系统会拒绝保存。 #### 5.3 通知模板 配置任务执行失败时的通知内容。支持变量占位符:`{{task_name}}`、`{{status}}`。 > 邮件通知已实现(`net/smtp`),任务失败时自动发送邮件到通知人。 --- ### 6. 执行日志 「日志管理 → 执行日志」查看所有任务的执行记录。 | 字段 | 说明 | |------|------| | 状态 | ✅ 成功 / ❌ 失败 / ⏰ 超时 | | 耗时 | 执行耗时(毫秒) | | 执行时间 | 触发时间 | | 输出 | 命令的标准输出 | | 错误 | 错误信息(如果有) | 支持按任务 ID 筛选、分页浏览、查看详情和删除。 --- ### 7. 权限管理 #### 7.1 权限因子 系统内置的菜单和功能权限,支持新增/编辑/删除。每个权限对应一个侧边栏菜单项。 权限结构为两级: - **一级菜单** — 如「任务管理」「服务器管理」 - **二级菜单** — 如「任务列表」「任务审核」 #### 7.2 角色管理 创建角色并绑定权限,支持数据权限控制(限制可查看的服务器组和任务组)。 例如创建一个「运维人员」角色,只赋予任务管理和日志查看权限。 #### 7.3 管理员管理 创建系统用户,可关联角色。新增的管理员默认密码 `123456`。 > `admin` 是超级管理员,**不能被禁用**,拥有全部权限。 --- ### 8. 个人资料 右上角用户头像 → 可修改个人资料(姓名、电话、邮箱、钉钉/微信等)及修改密码。 --- ## 注意事项 ### ⚡ Cron 表达式格式 本项目使用 **6 段格式**(含秒),不要使用标准 5 段格式: ``` ✅ 正确: 0 0 3 * * * (每天凌晨 3 点) ❌ 错误: 0 3 * * * (缺少秒字段 → 报错) ✅ 正确: 0 */5 * * * * (每 5 分钟) ``` ### 🔒 端口冲突 如果启动提示 `bind: Only one usage of each socket address`,说明端口 8082 已被占用: ```bash # 查看谁占了端口 netstat -ano | findstr 8082 # 杀掉进程(PID 替换为实际值) taskkill //PID 进程号 //F # 或者修改 config.yml 换个端口 ``` ### 💾 数据库 SQLite 数据库文件在 `./data/ppgo_job.db`,直接复制即可备份。如需重置,删除该文件后重启服务即可自动重建。 --- ## 项目结构 ``` ├── main.go # 入口 ├── config.yml # 配置文件 ├── boot/ # 启动初始化 │ ├── db.go # 数据库目录初始化 │ ├── router.go # 路由注册 + 路由表 │ ├── tplfunc.go # 模板函数(urlfor/date/substr) │ └── init.go # 自动建表 + 种子数据 + 加载调度任务 ├── frontend/ # Vue 3 前端工程 │ ├── src/ # 源码(api/router/stores/views/layout) │ ├── dist/ # 构建产物(Go 静态文件服务) │ ├── vite.config.ts │ └── package.json ├── controller/ # HTTP 控制器 │ ├── base.go # display/ajaxMsg/ajaxList 辅助函数 │ ├── response.go # 统一 JSON 响应格式 │ ├── api.go # Vue 前端专用 API 端点 │ ├── login.go # 登录/登出(Cookie+JWT 双认证) │ ├── home.go # 首页仪表盘 │ ├── task.go # 任务/服务器/分组/日志/CRUD │ ├── admin.go # 服务器/分组/禁用命令/通知模板 CRUD │ ├── system.go # 权限因子/角色/管理员/个人资料 CRUD │ └── spa.go # SPA 静态文件服务 ├── service/ │ └── scheduler/ # 任务调度 + 执行引擎 │ ├── scheduler.go # gcron 调度管理 │ ├── task_runner.go # 命令执行器(本地/远程) │ ├── ssh.go # SSH 远程连接器 │ └── notify.go # 邮件通知实现 ├── dao/ # 数据访问层 ├── model/entity/ # 数据库实体(含字段常量) ├── middleware/ # 认证中间件(Cookie + JWT 双认证) ├── libs/ # 工具函数(密码哈希/JWT/加密) ├── consts/ # 常量定义 └── resource/ ├── template/ # LayUI 模板(旧前端) └── static/ # JS/CSS/字体(旧前端) ``` ## 配置文件(`config.yml`) ```yaml server: address: ":8082" # 监听端口 name: "ppgo_job" logStdout: true # 日志输出到控制台 database: default: type: sqlite # 数据库类型(仅支持 sqlite) name: "./data/ppgo_job.db" jobs: pool: 1000 # 任务并发池大小 site: name: "定时任务管理器" # 站点标题 ``` ## API 接口 ### 新前端 API(`/api/*`,JWT 认证) | 接口 | 方法 | 说明 | |------|------|------| | `/api/login_in` | POST | 登录(返回 JWT token) | | `/api/user_info` | GET | 当前用户信息 + 菜单树 | | `/api/dashboard` | GET | 仪表盘统计数据(含 7 天图表) | | `/api/task/table` | GET | 任务列表(支持 status/group_id/task_name 筛选,field/order 排序) | | `/api/task/save` | POST | 新增/编辑任务 | | `/api/task/start` | POST | 启动任务 | | `/api/task/pause` | POST | 暂停任务 | | `/api/task/del` | POST | 删除任务 | | `/api/task/run` | POST | 立即执行 | | `/api/task/audit` | POST | 审核通过 | | `/api/task/nopass` | POST | 审核不通过 | | `/api/task/add_data` | GET | 新增任务的关联数据(分组/服务器/通知人) | | `/api/task/edit_data` | GET | 编辑任务的数据 | | `/api/task/detail_data` | GET | 任务详情 | | `/api/server/table` | GET | 服务器列表 | | `/api/server/save` | POST | 新增/编辑服务器 | | `/api/server/del` | POST | 删除服务器 | | `/api/group/table` | GET | 任务分组列表 | | `/api/server_group/table` | GET | 资源分组列表 | | `/api/ban/table` | GET | 禁用命令列表 | | `/api/notify_tpl/table` | GET | 通知模板列表 | | `/api/auth/nodes` | GET | 权限树 | | `/api/role/table` | GET | 角色列表 | | `/api/admin/table` | GET | 管理员列表 | | `/api/task_log/table` | GET | 执行日志列表(支持 status/task_id 筛选) | | `/api/profile` | GET | 个人资料 | | `/api/user/save` | POST | 修改个人资料 | ### 旧前端 API(Cookie 认证,兼容保留) | 接口 | 方法 | 说明 | |------|------|------| | `/login_in` | POST | 登录 | | `/task/ajax_save` | POST | 新增/编辑任务 | | `/task/ajax_del` | POST | 删除任务 | | ... | ... | 其他 `ajax_*` 端点同旧版 | 完整路由见 `boot/router.go`。 ## 编译部署 ```bash # 本地运行(含前端构建) build_frontend.cmd # 或分步运行 cd frontend && npm install && npm run build && cd .. CGO_ENABLED=0 go build -o ppgo_job.exe . && ./ppgo_job.exe # 仅编译后端 CGO_ENABLED=0 go build -o ppgo_job.exe . # Linux 交叉编译 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ppgo_job . # Windows 交叉编译 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o ppgo_job.exe . # Mac 交叉编译 CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o ppgo_job . ``` ## 已知限制 - **Telnet/Agent 远程执行** — 已实现 SSH,Telnet 和 Agent 模式尚未支持 - **钉钉/微信通知** — 已实现邮件通知,钉钉和微信待补充 - **Agent API** — 远程 Agent 注册和管理暂未实现 - **旧前端兼容** — LayUI 前端保留但不再维护,新功能仅添加到 Vue 前端 ## License MIT