Initial commit: TaskPool React panel
- React frontend with route-level code splitting - Backend rebranded from Baihu to TaskPool - DB brand migration script and local compatibility
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
# 远程执行 (Agents)
|
||||
|
||||
远程执行模块(Agents)是实现分布式、多节点任务管理的关键,允许您在一台主控制面板上协同调度部署在不同区域、不同操作系统的任务。
|
||||
|
||||
## Agents 架构
|
||||
|
||||
- **Agent 节点**:独立运行的小型客户端程序,监听主面板的任务分配。
|
||||
- **通信协议**:基于高效且稳定的消息队列与 WebSocket 协议,确保持久化双向实时通信。
|
||||
- **异构环境**:Agent 完全支持 Linux、Windows 及 macOS。您可以将 Agent 安装在轻量级树莓派、本地闲置电脑甚至异地数据中心。
|
||||
|
||||
## 节点管理
|
||||
|
||||
- **节点注册**:通过唯一的指纹认证,确保存储与数据传输的安全性。
|
||||
- **多状态监控**:
|
||||
- `在线`:节点准备就绪,可以接受任务。
|
||||
- `离线`:失去连接,所有指派的任务将自动进入等待或失败逻辑(取决于具体任务配置)。
|
||||
- `异常`:连接握手失败或版本由于过低暂不支持。
|
||||
|
||||
|
||||
## 指派任务
|
||||
|
||||
1. 在 `定时任务` 编辑页面,将执行器选项从 `本地执行` 切换为特定的 Agent 节点。
|
||||
2. 任务执行完成后,所有的控制台日志将通过加密隧道回传至主面板进行统一存储与检索。
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
layout: false
|
||||
---
|
||||
|
||||
<script setup>
|
||||
import { ApiReference } from '@scalar/api-reference'
|
||||
import '@scalar/api-reference/style.css'
|
||||
</script>
|
||||
|
||||
<div class="scalar-container">
|
||||
<ClientOnly>
|
||||
<ApiReference
|
||||
:configuration="{
|
||||
spec: {
|
||||
url: '/taskpool/swagger.json'
|
||||
},
|
||||
theme: 'alternate',
|
||||
showSidebar: true,
|
||||
servers: [
|
||||
{
|
||||
url: '{protocol}://{host}:{port}/open2api/v1',
|
||||
description: '可编辑的服务器地址',
|
||||
variables: {
|
||||
protocol: { default: 'http', enum: ['http', 'https'] },
|
||||
host: { default: 'localhost' },
|
||||
port: { default: '8052' }
|
||||
}
|
||||
}
|
||||
]
|
||||
}"
|
||||
/>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:root, body, #app {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.scalar-container {
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
/* 覆盖 VitePress 可能存在的样式干扰 */
|
||||
.scalar-container :deep(.scalar-api-reference) {
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,80 @@
|
||||
# 更新日志 ☕
|
||||
|
||||
本页面记录了taskpool的主要版本更新历史。
|
||||
|
||||
## 最近更新概览
|
||||
|
||||
### 2026.07.13 - 日志 ZSTD 压缩、依赖补全与计划任务排序 (v1.1.20)
|
||||
- **日志 ZSTD 压缩升级 (New)**:日志流式压缩机制由 zlib 全面升级至高压缩比的 ZSTD,显著降低磁盘开销与传输带宽;前端集成 `fzstd` 无缝支持新格式解码,并实现了对旧版 zlib 日志的向后兼容;针对小于 128 字节的短日志自动绕过压缩,避免无意义的算力浪费。
|
||||
- **依赖自动补全与交互终端 (New) (#147)**:全新上线依赖分析与自动补全安装 CLI,并提供终端安装向导提示;在定时任务日志界面右下角,现可通过“补全依赖”按钮一键调出内嵌终端进行交互式依赖安装。
|
||||
- **定时任务排序功能 (#148)**:任务列表(大屏与中屏)现已支持点击表头“名称”、“执行时间”(下次执行时间)和“状态”进行排序;同时小屏/移动端顶栏新增了“排序规则”下拉菜单,规则无缝统一。
|
||||
- **全局 ESC 关闭弹窗**:在通用组件 `DialogContent` 内部集成非侵入式 Escape 按键全局捕获,按 ESC 优先退出最顶层弹窗,避免输入框/Monaco等组件焦点占用导致退出失效。
|
||||
- **视图管理与任务优化**:任务列表自定义视图现已可联动保存当前的排序状态并自动还原;为新建任务的日志清理配置默认设置为保留最近 30 条记录,防止磁盘占满;日志详情弹窗增加了最大高度及滚动条优化。
|
||||
- **样式与体验优化**:将“状态”列宽度由 `w-8` 扩大至 `w-14` 消除因加入排序图标导致的文字折行与表头挤压;去除了 Dialog 自动聚焦时产生的窗口边缘白色高亮聚焦线。
|
||||
|
||||
### 2026.06.28 - 全新节点互联功能发布! (v1.1.17)
|
||||
- **节点互联体系 (New)**:新增开放连接(OpenConnect)协议支持,轻松打通并管理多个任务池实例;全新上线同步管理面板,可实时总览所有连接节点的资源开销与各项负载指标;支持了跨节点间的环境变量全量无缝同步(完美保留原始结构与关联 ID);底层路由机制迎来全面升级,完美支持基于穿透隧道的前端互联访问代理。
|
||||
- **终端体验优化**:针对移动端深度优化终端(xterm)交互,禁用移动端点击自动弹出软键盘,支持选中内容后 Ctrl+C 快捷复制,并大幅提升了小屏幕下的滑动流畅性。
|
||||
- **调度器安全**:为 Worker 数量和队列大小添加了边界验证及安全限制,从底层防止高并发场景下出现 OOM 问题。
|
||||
- **UI 体验优化**:修复了大屏模式下环境变量表格删除按钮丢失的问题;MasterView 按钮在小屏幕下支持自适应填满;增加了演示模式下互联角色的操作限制。
|
||||
|
||||
|
||||
### 2026.06.22 - 体验优化与 Bug 修复 (v1.1.16)
|
||||
- **执行历史自适应 (New)**:修复了执行历史列表及日志卡片高度被固定限制在 `520px` 的 Bug,改为通过 `calc(100vh - 190px)` 动态铺满视口,大幅提升大屏及竖屏利用率(#134)。
|
||||
- **通知日志截断 Bug 修复**:修复了任务通知中执行日志在全局被提前硬编码截断导致个性化字数限制失效的 Bug(#133)。
|
||||
- **去颜色性能优化**:将清除 ANSI 控制字符的正则操作移到循环外部只运行一次,降低了多通道投递时的 CPU 占用(#133)。
|
||||
- **机密使用指引**:在机密管理 UI 中增加了醒目的使用指引说明,支持手动关闭并可本地记忆关闭状态防止打扰(#135)。
|
||||
- **数据恢复兼容性**:在导入/恢复备份包时,支持自动检测并迁移旧版本 task 中的环境变量及 tags 数据(#135)。
|
||||
- **其它优化与修复**:支持自定义仓库同步文件夹名称(#132);支持输出当前版本的 `version` 命令;修复了终端 UTF-8 截断引发的乱码缺陷;CI 新增 arm64 构建支持。
|
||||
|
||||
### 2026.06.12 - 调度器与面板资源实时监控
|
||||
- **资源监控大盘 (New)**:新增对面板底层运行资源、调度器并发池(Worker)以及内存堆栈状态的实时高频监控展示。
|
||||
|
||||
### 2026.05.29 - 前端定制与 WebUI 插件化
|
||||
- **自定义 WebUI 支持 (New)**:新增了前端自定义打包与热切换功能。面板系统彻底解耦前后端静态资源,用户可以在“系统设置 - 前端定制”中上传并管理自定义前端资源包,实现深度的主题替换与定制。
|
||||
- **打包工具链整合**:提供了一键构建前端定制包的 `make pack-webui` 快捷命令与规范(自动生成 `uimanifest.json`)。
|
||||
- **动态资源托管**:Go 后端引入动态静态资源拦截机制,可无缝接管系统入口与单页应用渲染,同时向下兼容内置面板。
|
||||
|
||||
|
||||
### 2026.04.16 - 内建脚本助手库 (Built-in SDK)
|
||||
- **内建助手库 (Built-in SDK) (New)**:新增 Python 与 Node.js 的轻量级助手库 `taskpool`。通过环境自动注入机制实现“零配置”通知投递,开发者无需在脚本中显式配置 TOKEN 或 URL。
|
||||
- **环境自动初始化**:新增 `taskpool builtininstall` 命令行工具,支持一键为 `mise` 管理的所有多语言版本同步安装/刷新内建包依赖。
|
||||
- **体验与文档升级**:重构了「脚本调用」UI 指引,简化了集成步骤说明,并统一了全局 UI 字体规范。
|
||||
|
||||
### 2026.04.14 - PWA 支持与推送渠道扩展
|
||||
- **PWA 动态配置 (New)**:支持 Progressive Web App 动态 manifest 配置,应用名称和图标可由后端站点设置实时动态注入。
|
||||
- **VoceChat 推送支持**:新增对 VoceChat 私有化部署推信渠道的支持(基于 Bot API)。
|
||||
- **Bark 增强**:Bark 推送渠道新增“自定义服务器”支持,适配 Bark 私有化部署场景与加密推送。
|
||||
|
||||
### 2026.03.27 - 安全机密管理 (GitHub Secrets 风格)
|
||||
- **安全机密功能 (New)**:引入类似 GitHub Actions 的机密管理机制。支持使用 **AES-GCM** 加密存储敏感变量,数据库不存明文,保障配置安全。
|
||||
- **秘钥内存常驻销毁 (Safe-Unset)**:系统启动从环境变量读取秘钥后会立即执行 `Unset` 操作,确保秘钥仅保留在内存中,不暴露在进程环境内。
|
||||
- **日志自动脱敏**:实时流水日志自动扫描并掩码(Mask)脱敏显示机密内容(`********`),防止执行时通过任务输出泄露机密。
|
||||
- **严格隔离机制**:机密**仅在定时调度任务**时生效,终端命令执行、手动测试、调试等入口物理隔离机密。
|
||||
|
||||
### 2026.03.19 - 仓库同步功能增强
|
||||
- **青龙指令深度兼容**:支持直接粘贴青龙格式的仓库同步指令,自动解析并创建任务。
|
||||
|
||||
### 2026.03.05 - API 文档重构
|
||||
- **OpenAPI 认证体系**:支持站点级 Token 配置与 Basic Auth 保护。
|
||||
- **自定义 UI**:新增设计感十足的全局 **404 页面**。
|
||||
|
||||
### 2026.03.04 - 消息推送系统重构
|
||||
- **原生内置**:全新原生支持企业微信、钉钉、飞书、Telegram、Bark、邮件等十余种主流渠道。
|
||||
- **事件捕获**:接入系统级事件通知自动捕获,告别原有必配外部推送服务的繁琐历史。
|
||||
|
||||
### 2026.02.13 - 任务执行引擎重构
|
||||
- **深度集成 Mise**:支持 Python, Node.js, Go, Rust, PHP 等几乎所有主流语言的动态安装与多版本切换。
|
||||
- **依赖管理**:同步上线跨语言统一依赖管理系统。
|
||||
|
||||
### 2026.02.11 - 安全性增强
|
||||
- **随机密码策略**:首次启动使用随机密码并打印在日志中。
|
||||
- **暴力破解防护**:登录接口增加防暴力破解。
|
||||
- **路径遍历防护**:文件系统操作增加路径穿越锁定。
|
||||
|
||||
### 2026.02.10 - 任务调度重构
|
||||
- **调度性能**:重写了并发控制逻辑,完善了任务队列。
|
||||
- **体验优化**:优化文件树交互体验,支持任务执行实时日志流。
|
||||
|
||||
### 2026.02.06 - 镜像扩展
|
||||
- **Debian 13 支持**:增加对 Debian 13 (Trixie) 镜像支持,整理 Docker 目录结构。
|
||||
@@ -0,0 +1,166 @@
|
||||
# 命令行工具 (CLI)
|
||||
|
||||
taskpool在环境内内置了同名的 `taskpool` 命令行工具。如果您在终端内需要执行系统级别的操作,可以使用这些内置命令。
|
||||
|
||||
## 常用核心指令
|
||||
|
||||
| 命令 | 描述 |
|
||||
| :--- | :--- |
|
||||
| `taskpool server` | 面板启动指令,运行服务端后台进程。 |
|
||||
| `taskpool reposync` | 供定时任务调用,将远程 Git 仓库的高级特性同步到本地目录中。 |
|
||||
| `taskpool resetpwd` | 交互式重置系统 admin 账号密码(密码丢失时可通过进入终端重置)。 |
|
||||
| `taskpool restore <file>` | 使用本地的 .zip 备份压缩包文件,一条命令直接全量恢复系统数据。 |
|
||||
| `taskpool task` | 极速只读与控制台常驻任务管理(支持查询列表、手动触发、查看状态及开关控制)。 |
|
||||
|
||||
---
|
||||
|
||||
## 使用场景示例
|
||||
|
||||
### 1. 密码重置
|
||||
您可以进入 Docker 容器或通过 ssh 连入宿主机控制台:
|
||||
```bash
|
||||
docker exec -it taskpool taskpool resetpwd
|
||||
```
|
||||
然后根据提示,输入新的管理员密码即可重置成功。
|
||||
|
||||
### 2. 手动启动
|
||||
如果是通过手动部署二进制文件,可以使用 `taskpool server` 启动:
|
||||
```bash
|
||||
nohup ./taskpool server > /dev/null 2>&1 &
|
||||
```
|
||||
|
||||
### 3. 数据恢复
|
||||
上传备份后的 ZIP 文件至容器目录:
|
||||
```bash
|
||||
docker exec -it taskpool taskpool restore /app/data/backup-2026xxxx.zip
|
||||
```
|
||||
该操作会全量覆盖现有数据库和脚本文件,请谨慎操作。
|
||||
|
||||
---
|
||||
|
||||
## `reposync` 参数详解
|
||||
|
||||
`taskpool reposync` 是面板核心的同步命令,除了在任务中自动调用外,您也可以通过命令行手动执行。
|
||||
|
||||
### 参数列表
|
||||
|
||||
| 参数名 | 默认值 | 描述 |
|
||||
| :--- | :--- | :--- |
|
||||
| `--source-type` | `git` | 同步源类型,可选 `git`(Git 仓库)或 `url`(文件直链下载)。 |
|
||||
| `--source-url` | | 同步源地址,Git 仓库地址或下载 URL。 |
|
||||
| `--target-path` | | 目标保存路径。支持变量替换(如 `$SCRIPTS_DIR$`)。 |
|
||||
| `--branch` | | Git 分支名。留空时将自动检测远程默认分支(如 `main` 或 `master`)。 |
|
||||
| `--path` | | 稀疏检出(Sparse checkout)的指定路径,或在单文件模式下的相对路径。 |
|
||||
| `--single-file` | `false` | 是否开启单文件模式,仅从 Git 提取指定单个文件。 |
|
||||
| `--proxy` | `none` | Github 加速代理类型,可选 `none`、`ghproxy`、`mirror`、`custom`。 |
|
||||
| `--proxy-url` | | 自定义代理地址,仅在 `--proxy=custom` 时生效。 |
|
||||
| `--auth-token` | | 私有仓库或 API 访问使用的鉴权 Token。 |
|
||||
| `--http-proxy` | | HTTP/HTTPS 代理地址,例如 `http://127.0.0.1:7890`。 |
|
||||
| `--whitelist-paths`| | 白名单路径(逗号或竖线分隔),同步时受保护不被清理的路径。 |
|
||||
| `--blacklist` | | 黑名单关键字(竖线 `\|` 分隔),包含该关键字的文件将会被过滤删除。 |
|
||||
| `--dependence` | | 依赖文件关键字(竖线 `\|` 分隔),这些文件将强制保留。 |
|
||||
| `--extensions` | | 允许的脚本扩展名(竖线 `\|` 分隔,如 `.js\|.py`),后缀不符的文件将被删除。 |
|
||||
| `--task-id` | | 内部任务 ID,用于在同步完成后通知调度器刷新增量任务。 |
|
||||
| `--task-langs` | | 任务配置的语言(JSON格式),用于标记和解析。 |
|
||||
| `--repo-task-id` | | 原始任务 ID。 |
|
||||
| `--task-timeout` | `30` | 同步任务的超时时间,单位为分钟。 |
|
||||
| `--commenttotask` | `false` | 是否启用青龙 (QL) 格式的脚本注释解析(`true`/`false`)。 |
|
||||
|
||||
### 使用示例
|
||||
|
||||
#### 1. 基础 Git 仓库同步
|
||||
将指定仓库克隆或拉取到特定目录:
|
||||
```bash
|
||||
taskpool reposync --source-url https://github.com/example/repo.git --target-path /app/data/scripts/example_repo
|
||||
```
|
||||
|
||||
#### 2. 启用代理的同步
|
||||
针对 Github 仓库使用加速代理,并限定只保留 `.js` 和 `.py` 脚本:
|
||||
```bash
|
||||
taskpool reposync --source-url https://github.com/example/repo.git \
|
||||
--target-path /app/data/scripts/example_repo \
|
||||
--proxy ghproxy \
|
||||
--extensions ".js|.py"
|
||||
```
|
||||
|
||||
#### 3. 稀疏检出 (Sparse Checkout)
|
||||
当仓库庞大时,仅同步特定的子目录或文件:
|
||||
```bash
|
||||
taskpool reposync --source-url https://github.com/example/repo.git \
|
||||
--target-path /app/data/scripts/example_repo \
|
||||
--path "scripts/daily"
|
||||
```
|
||||
|
||||
#### 4. 单文件下载模式
|
||||
如果只需要仓库中的某一个脚本文件:
|
||||
```bash
|
||||
taskpool reposync --source-url https://github.com/example/repo.git \
|
||||
--target-path /app/data/scripts/ \
|
||||
--single-file true \
|
||||
--path "main_script.py"
|
||||
```
|
||||
|
||||
#### 5. 高级过滤与青龙注释解析
|
||||
使用黑名单排除特定脚本,并开启青龙格式注释解析以自动生成定时任务:
|
||||
```bash
|
||||
taskpool reposync --source-url https://github.com/example/repo.git \
|
||||
--target-path /app/data/scripts/example_repo \
|
||||
--blacklist "test|mock" \
|
||||
--dependence "package.json|requirements.txt" \
|
||||
--commenttotask "true"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `taskpool task` 任务管理指令集
|
||||
|
||||
`taskpool task` 是一组专为纯终端操作与自动化脚本调度打造的轻量级任务管理子命令集。它能够绕过繁重的界面操作,直接提供闪电般的本地查询与安全指令下发控制。
|
||||
|
||||
### 支持子命令
|
||||
|
||||
#### 1. 任务列表查询 (`list`)
|
||||
查询并分页展示系统内配置的所有任务概览。
|
||||
```bash
|
||||
# 默认展示前 20 条
|
||||
taskpool task list
|
||||
|
||||
# 指定关键词过滤,并查看第 2 页 (每页展示 10 条)
|
||||
taskpool task list -q "签到" -page 2 -size 10
|
||||
```
|
||||
|
||||
#### 2. 手动立即触发 (`run`)
|
||||
手动向常驻后台服务下发指令,立即异步运行指定的任务。
|
||||
```bash
|
||||
taskpool task run a1b2c3d4
|
||||
```
|
||||
|
||||
#### 3. 任务状态切换 (`enable` / `disable`)
|
||||
快速启用或禁用系统任务。
|
||||
```bash
|
||||
taskpool task enable a1b2c3d4
|
||||
taskpool task disable a1b2c3d4
|
||||
```
|
||||
|
||||
#### 4. 实时执行状态追踪 (`status`)
|
||||
查看指定任务最新一次执行的详细输出日志和最终退出码。
|
||||
```bash
|
||||
# 查看最近一条日志
|
||||
taskpool task status a1b2c3d4
|
||||
|
||||
# 查看指定历史日志条目的完整输出
|
||||
taskpool task status a1b2c3d4 log_123456
|
||||
```
|
||||
|
||||
#### 5. 近期执行历史流水 (`history`)
|
||||
列出某任务最近的多次运行记录(包含耗时、执行时间及状态结果)。
|
||||
```bash
|
||||
taskpool task history a1b2c3d4
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> 所有的 `taskpool task` 子命令均原生支持单独传入 `--help` 参数获取具体的示例和选项清单。例如:`taskpool task list --help`。
|
||||
|
||||
---
|
||||
|
||||
## 其他帮助
|
||||
终端内直接执行 `taskpool` 即可在控制台直接打印内置支持详细说明和命令列表参数。
|
||||
@@ -0,0 +1,90 @@
|
||||
# 系统配置手册
|
||||
|
||||
taskpool支持通过环境变量和配置文件两种核心方式进行系统参数微调。
|
||||
|
||||
## 环境变量配置 (优先级最高)
|
||||
|
||||
环境变量在容器内自动注入,非常适合 CI/CD 和 Docker 混合编排场景。
|
||||
|
||||
### 核心配置项列表
|
||||
|
||||
| 环境变量 | 对应配置 | 说明 | 默认值 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `BH_SERVER_PORT` | server.port | 服务监听端口 | 8052 |
|
||||
| `BH_SERVER_HOST` | server.host | 监听地址 | 0.0.0.0 |
|
||||
| `BH_SERVER_URL_PREFIX` | server.url_prefix | URL 前缀,用于反向代理子路径部署 | - |
|
||||
| `BH_COOKIE_NAME` | server.cookie_name | 全局会话 Cookie 名称 | BHToken |
|
||||
| `BH_DB_TYPE` | database.type | 数据库类型 (sqlite/mysql) | sqlite |
|
||||
| `BH_DB_HOST` | database.host | 数据库实例地址 | localhost |
|
||||
| `BH_DB_PORT` | database.port | 数据库端口 | 3306 |
|
||||
| `BH_DB_USER` | database.user | 数据库用户名 | root |
|
||||
| `BH_DB_PASSWORD` | database.password | 数据库密码 | - |
|
||||
| `BH_DB_NAME` | database.dbname | 数据库库名 | taskpool |
|
||||
| `BH_DB_PATH` | database.path | SQLite 物理文件存储路径 | ./data/taskpool.db |
|
||||
| `BH_DB_DSN` | database.dsn | 数据库 DSN (仅 mysql/postgres, 优先级高。**需对应设置 type**) | - |
|
||||
| `BH_DB_TABLE_PREFIX` | database.table_prefix | 数据库表前缀 | taskpool_ |
|
||||
| `BH_DB_SSL_MODE` | database.ssl_mode | SSL 模式: postgres 支持 disable/require/verify-ca/verify-full; mysql 支持 true/skip-verify | - |
|
||||
| `TASKPOOL_SECRET_KEY` | - | 系统加密秘钥,用于机密变量功能(**注:仅支持环境变量设置,不支持配置文件**) | - |
|
||||
|
||||
---
|
||||
|
||||
## 配置文件挂载 (config.ini)
|
||||
|
||||
如果您希望对系统参数有更细致的控制(而非通过外部注入),可以使用配置文件。
|
||||
|
||||
### 挂载点
|
||||
```yaml
|
||||
volumes:
|
||||
- ./configs:/app/configs
|
||||
```
|
||||
|
||||
### 配置文件示例 (`configs/config.ini`)
|
||||
```ini
|
||||
[server]
|
||||
port = 8052
|
||||
host = 0.0.0.0
|
||||
# 配置 URL 前缀用于反向代理,例如 /taskpool/
|
||||
url_prefix = /taskpool
|
||||
# 全局会话 Cookie 名称
|
||||
cookie_name = BHToken
|
||||
|
||||
[database]
|
||||
type = sqlite
|
||||
path = /app/data/taskpool.db
|
||||
# 数据库连接示例 (Unix Socket / DSN):
|
||||
# 注意:使用 dsn 时,type 必须设为 mysql 或 postgres
|
||||
# dsn = user:password@unix(/var/run/mysqld/mysqld.sock)/dbname?charset=utf8mb4&parseTime=True&loc=Local
|
||||
# dsn = postgres://user:password@localhost:5432/dbname?sslmode=disable
|
||||
table_prefix = taskpool_
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 调度设置说明
|
||||
|
||||
系统采用异步任务队列 + Worker Pool 架构,可在「系统设置 > 调度设置」页面进行配置:
|
||||
|
||||
- **Worker 数量** (默认 4):同时在后端并发运行的任务进程数。
|
||||
- **队列大小** (默认 100):待处理任务队列的最大容量。
|
||||
- **速率间隔** (默认 200 ms):控制两个任务启动之间的最小等待时长。
|
||||
|
||||
---
|
||||
|
||||
## 机密管理 (Secret Management)
|
||||
|
||||
taskpool提供了一套基于 **AES-GCM** 工业级标准的安全机密管理系统,其设计理念参考了 GitHub Actions Secrets。
|
||||
|
||||
### 核心特性
|
||||
|
||||
1. **强加密存储**:所有标记为“机密”的变量在数据库中均以加密密文形式存储。
|
||||
2. **秘钥安全**:通过环境变量 `TASKPOOL_SECRET_KEY` 注入加密秘钥。系统读取秘钥后会立即将其从进程环境变量中销毁(Unset),确保秘钥仅驻留在内存中。
|
||||
3. **日志自动脱敏**:系统会自动扫描任务执行生成的实时日志流。一旦发现机密明文,将自动替换为 `********`,防止敏感信息通过日志泄露。
|
||||
4. **严格权限隔离**:
|
||||
- 机密内容**仅在计划任务由调度器定时执行时**才会注入到环境。
|
||||
- 通过**终端命令**、**测试运行**或**调试运行**调起的临时进程无法获取机密内容,保障核心资产安全。
|
||||
|
||||
### 配置建议
|
||||
|
||||
- 建议在 Docker/Compose 启动项中设置 `TASKPOOL_SECRET_KEY` 为一个复杂的随机字符串。
|
||||
- 不要将该秘钥写入 `config.ini` 或提交到版本控制系统。
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# 数据仪表
|
||||
|
||||
数据仪表提供了taskpool的全局运行状态、任务执行统计及关键指标的可视化展示。
|
||||
|
||||
## 主要功能
|
||||
|
||||
- **总体概览**:实时统计当前面板的总任务数、正在运行的任务数、总脚本数以及 Agent 节点的状态。
|
||||
- **执行状况统计**:通过饼图展示过去 24 小时或 7 天内任务执行的成功、失败及因超时被自动强制终止的比例。
|
||||
- **并发趋势监测**:折线图实时呈现任务并发执行的高峰与低谷,辅助管理员评估物理硬件或云服务器的负载情况。
|
||||
- **资源监控**:实时获取主机 CPU、内存在线占用状态,确保面板在资源充裕的环境下高效运转。
|
||||
|
||||
## 面板布局
|
||||
|
||||
1. **状态卡片**:位于顶部,快速掌握系统规模。
|
||||
2. **执行热力图**:展示不同时段的任务运行频次。
|
||||
3. **系统性能仪表**:直观展示核心硬件利用率。
|
||||
@@ -0,0 +1,181 @@
|
||||
# 快速部署
|
||||
|
||||
项目提供多种基础镜像,默认版本基于 Debian 12,集成了 Python 3.13 与 Node.js 23。
|
||||
|
||||
## 基础镜像选择
|
||||
|
||||
| 标签 (Tag) | 基础镜像 | 说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| `latest` | Debian 12 | **默认推荐**:集成 Python 3.13 与 Node.js 23,开箱即用 |
|
||||
| `latest-debian13` | Debian 13 | 尝鲜版本,基于 Debian Trixie |
|
||||
| `latest-minimal` | Debian 13 | **最小化版**:不预置任何语言环境,仅内置 Mise,适合追求极致纯净的用户 |
|
||||
|
||||
> **提示**:目前默认使用 `latest` 标签。如需切换环境,只需将镜像名后的 `latest` 替换为 `latest-minimal`(极致纯净)或 `latest-debian13` 即可。
|
||||
|
||||
## 环境版本重构说明 (2026.02.13+)
|
||||
|
||||
> **警告**:架构升级破坏性变更
|
||||
>
|
||||
> 本版本(2026.02.13+)对底层运行时环境进行了彻底重构,弃用了原有的静态 Python/Node 环境,转为使用 **Mise** 进行动态版本管理。
|
||||
>
|
||||
> 1. **不再提供 Alpine 镜像**:由于 glibc 兼容性问题,Mise 无法在 Alpine 上完美运行,因此暂时取消 Alpine 镜像支持。
|
||||
> 2. **环境数据不兼容**:如果您是从旧版本升级上来,原有的 Python/Node 环境数据将无法迁移。您需要清空挂载的 `envs/` 目录并让其由新容器自动初始化。
|
||||
|
||||
---
|
||||
|
||||
## 方式一:Docker 运行 (环境变量配置)
|
||||
|
||||
通过环境变量指定配置,简单灵活,适合一般部署。
|
||||
|
||||
### SQLite (默认)
|
||||
```bash
|
||||
docker run -d \
|
||||
--name taskpool \
|
||||
-p 8052:8052 \
|
||||
-v $(pwd)/data:/app/data \
|
||||
-v $(pwd)/envs:/app/envs \
|
||||
-e TZ=Asia/Shanghai \
|
||||
-e BH_SERVER_PORT=8052 \
|
||||
-e BH_SERVER_HOST=0.0.0.0 \
|
||||
-e BH_DB_TYPE=sqlite \
|
||||
-e BH_DB_PATH=/app/data/taskpool.db \
|
||||
-e BH_DB_TABLE_PREFIX=taskpool_ \
|
||||
--restart unless-stopped \
|
||||
ghcr.io/engigu/taskpool:latest
|
||||
```
|
||||
|
||||
### MySQL
|
||||
```bash
|
||||
docker run -d \
|
||||
--name taskpool \
|
||||
-p 8052:8052 \
|
||||
-v $(pwd)/data:/app/data \
|
||||
-v $(pwd)/envs:/app/envs \
|
||||
-e TZ=Asia/Shanghai \
|
||||
-e BH_SERVER_PORT=8052 \
|
||||
-e BH_SERVER_HOST=0.0.0.0 \
|
||||
-e BH_DB_TYPE=mysql \
|
||||
-e BH_DB_HOST=mysql-server \
|
||||
-e BH_DB_PORT=3306 \
|
||||
-e BH_DB_USER=root \
|
||||
-e BH_DB_PASSWORD=your_password \
|
||||
-e BH_DB_NAME=taskpool \
|
||||
-e BH_DB_TABLE_PREFIX=taskpool_ \
|
||||
--restart unless-stopped \
|
||||
ghcr.io/engigu/taskpool:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 方式二:Docker Compose 部署
|
||||
|
||||
推荐的生产环境部署方式。
|
||||
|
||||
### 核心部署模板
|
||||
```yaml
|
||||
services:
|
||||
taskpool:
|
||||
image: ghcr.io/engigu/taskpool:latest
|
||||
container_name: taskpool
|
||||
ports:
|
||||
- "8052:8052"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./envs:/app/envs
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- BH_SERVER_PORT=8052
|
||||
- BH_SERVER_HOST=0.0.0.0
|
||||
- BH_DB_TYPE=sqlite
|
||||
- BH_DB_PATH=/app/data/taskpool.db
|
||||
- BH_DB_TABLE_PREFIX=taskpool_
|
||||
# - BH_SERVER_URL_PREFIX=/taskpool # 可选:配置 URL 前缀用于反向代理
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 方式三:配置文件挂载模式
|
||||
|
||||
通过挂载 `/app/configs/config.ini` 来管理详细配置。
|
||||
|
||||
### 配置文件挂载示例
|
||||
```yaml
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./configs:/app/configs
|
||||
- ./envs:/app/envs
|
||||
```
|
||||
---
|
||||
|
||||
## Docker 启动流程
|
||||
|
||||
容器启动时 `docker-entrypoint.sh` 会自动执行以下关键步骤:
|
||||
|
||||
1. **环境自检**:检查 `/app/data`、`/app/configs`、`/app/envs` 挂载点并创建必要子目录。
|
||||
2. **Mise 同步**:自动将镜像内置的 Mise 核心运行时激活文件同步到持久化挂载目录中,确保容器重启后环境依然可用。
|
||||
3. **运行时激活**:动态注入环境变量,将 `mise shims` 路径加入系统 `PATH`。
|
||||
4. **包管理预设**:自动为 Python 配置清华源 (PIP) 镜像,配置 Node.js 内存限制。
|
||||
5. **主进程启动**:运行 `taskpool server` 开启面板。
|
||||
|
||||
> **提示**:通过持久化挂载 `./envs` 目录,您安装的所有运行时版本和第三方依赖库均会永久保留。
|
||||
|
||||
---
|
||||
|
||||
## 自动更新 Docker 镜像
|
||||
|
||||
如果您希望taskpool能够自动拉取最新镜像并无感更新,推荐使用 **Watchtower**。Watchtower 会定期检查被监控容器的基础镜像,当发现有新版本推送时,它会自动拉取新镜像、使用与原容器完全相同的配置重启容器。
|
||||
|
||||
由于taskpool采用持久化挂载(数据和环境都在外部),因此自动更新不会造成任何数据丢失。
|
||||
|
||||
### 方式一:独立一行命令运行 Watchtower(推荐)
|
||||
|
||||
执行以下命令,Watchtower 将会自动在每天凌晨 3 点自动检查并更新名为 `taskpool` 的容器:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name watchtower \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-e TZ=Asia/Shanghai \
|
||||
-e WATCHTOWER_SCHEDULE="0 0 3 * * *" \
|
||||
-e WATCHTOWER_CLEANUP=true \
|
||||
--restart unless-stopped \
|
||||
containrrr/watchtower \
|
||||
taskpool
|
||||
```
|
||||
|
||||
> **参数说明**:
|
||||
> - 结尾处的 `taskpool` 为指定仅监控更新名为 `taskpool` 的容器。若不加此参数,则会自动更新宿主机上所有的 Docker 容器。
|
||||
> - `WATCHTOWER_CLEANUP=true`:更新成功后自动删除旧版本的废弃镜像,防止存储空间被占满。
|
||||
> - `WATCHTOWER_SCHEDULE`:设置定时检查的 Cron 表达式(秒 分 时 日 月 周)。
|
||||
|
||||
### 方式二:集成到 Docker Compose 中
|
||||
|
||||
您可以直接将 Watchtower 作为附加服务加入现有的 `docker-compose.yml` 中:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
taskpool:
|
||||
image: ghcr.io/engigu/taskpool:latest
|
||||
container_name: taskpool
|
||||
# ... 省略端口、挂载等其他配置 ...
|
||||
|
||||
watchtower:
|
||||
image: containrrr/watchtower
|
||||
container_name: watchtower
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- WATCHTOWER_CLEANUP=true
|
||||
- WATCHTOWER_SCHEDULE="0 0 3 * * *"
|
||||
command: taskpool
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
修改完成后,执行 `docker compose up -d` 生效即可。
|
||||
@@ -0,0 +1,24 @@
|
||||
# 免责声明
|
||||
|
||||
taskpool(TaskPool)及其开发者在提供本项目的同时,默认用户已完全知悉并同意以下条款:
|
||||
|
||||
## 1. 免责保证
|
||||
|
||||
- **无业务逻辑**:本项目仅作为一个轻量级的任务托管与调度平台,不提供、不内置任何具有实际业务逻辑的第三方脚本。
|
||||
- **脚本审核**:用户自行添加或配置的脚本来源、逻辑及潜在的系统影响均由用户自行负责。请勿执行来源不明的恶意脚本,并在执行前仔细阅读并审核其源代码,确保安全性。
|
||||
|
||||
## 2. 软件责任
|
||||
|
||||
- **按“原样”提供**:本项目属于业余开源开发作品,采用 Apache License 2.0 协议发布(需遵守 NOTICE 署名要求)。开发者不保证软件不存在任何 Bug、系统漏洞或逻辑缺陷。
|
||||
- **损失赔偿**:因运行用户自行脚本或使用本系统带来的一切数据泄露、系统损坏、财产损失(如服务器被封、云服务欠费)及相关法律责任,均由使用者本人承担。
|
||||
|
||||
## 3. 授权与使用
|
||||
|
||||
- **合理镜像申请**:由于项目涉及到网络请求和资产调度,请遵循相关的开源协议进行公平、合理的使用。
|
||||
- **禁止非法用途**:严禁将taskpool用于任何违反中华人民共和国法律法规及相关组织政策的行为。
|
||||
|
||||
---
|
||||
|
||||
## 4. 联系我们
|
||||
|
||||
如果您在使用过程中发现任何技术问题,欢迎通过 GitHub [Issues](https://github.com/engigu/taskpool/issues) 反馈。
|
||||
@@ -0,0 +1,19 @@
|
||||
# 变量机密
|
||||
|
||||
变量机密提供了统一的环境变量管理功能,旨在保护敏感数据并提高配置的灵活性,包含环境变量和机密。
|
||||
|
||||
## 环境变量 (Environment Variables)
|
||||
|
||||
- **全局作用域**:一旦在变量机密页面配置成功,所有的 `定时任务` 与 `命令行交互` 在运行期间均会自动注入这些环境变量。
|
||||
- **变量命名规范**:建议使用大写字母加下划线的形式,例如 `DB_PASSWORD` 或 `AUTH_TOKEN`。
|
||||
|
||||
|
||||
## 机密 (Secrets)
|
||||
|
||||
- **字段脱敏**:对于标记为 `Secret` 的变量,面板在浏览列表中将以星号 `*******` 显示,避免在协作或投屏场景下泄露机密信息。
|
||||
- **加密存储**:数据库中的敏感字段均由系统后端进行深度加密,确保存储层的物理安全。
|
||||
- **编辑权限**:某些机密字段可能在编辑后不可见其原始值,仅支持通过覆盖更新的方式进行修改。
|
||||
|
||||
## 注入机制
|
||||
|
||||
- **任务运行时动态挂载**:在启动任务对应的进程前,主进程或 Agent 会将配置好的键值对同步至子进程的 `Environment` 参数中,确保脚本可以直接通过 `os.environ` 或 `process.env` 获取到该配置。
|
||||
@@ -0,0 +1,191 @@
|
||||
# 浏览器示例
|
||||
|
||||
`example/playwright` 提供了一组远程浏览器脚本示例,演示如何连接 **Browserless**。
|
||||
|
||||
> [!NOTE]
|
||||
> 本示例以 Browserless 为主要演示对象。以此类推,您也可以使用其他的浏览器镜像(如原生的 `headless-shell` 或其他的浏览器集群服务)进行部署,只要它们支持 CDP 协议。
|
||||
|
||||
---
|
||||
|
||||
## 部署方式对比
|
||||
|
||||
taskpool强烈建议采用 **单独部署浏览器服务(如 Browserless)** 的方案,而不是在任务池镜像内部安装浏览器。
|
||||
|
||||
### 本地部署 (在任务池容器内安装) 的缺点
|
||||
- **资源争抢**:浏览器是极度的“内存/CPU 杀手”,在同一容器内运行多任务极易导致任务池主进程因 OOM (内存溢出) 而崩溃。
|
||||
- **镜像臃肿**:安装 Chromium 后,原本精简的 Docker 镜像体积会暴增数倍(增加 500MB+),导致拉取和更新缓慢。
|
||||
- **依赖环境复杂**:在精简镜像中安装浏览器常会遇到各种缺失 `.so` 库文件的底层错误,排查极其困难。
|
||||
- **不利于扩展**:无法实现多节点负载均衡,一个容器内的资源始终是有限的。
|
||||
|
||||
### 远程部署 (Browserless) 的优势
|
||||
- **性能隔离**:浏览器的负载波动不会影响taskpool的稳定性。
|
||||
- **开箱即用**:专业的浏览器镜像是针对性优化的,包含所有底层依赖和沙箱安全配置。
|
||||
- **可视化调试**:大多数服务(如 Browserless)支持通过 VNC 同步查看浏览器画面,方便排查脚本逻辑。
|
||||
- **弹性伸缩**:支持多会话、多实例模式,可以应对高并发爬虫需求。
|
||||
|
||||
---
|
||||
|
||||
## 准备工作
|
||||
|
||||
在taskpool中运行浏览器自动化脚本前,需要先配置好对应的 **语言环境** 与 **第三方依赖包**。
|
||||
|
||||
### 1. Node.js 环境 (JavaScript)
|
||||
如果您使用 `playwright.js` 脚本:
|
||||
- **依赖安装**:前往「语言依赖」->「Node.js」,安装 `puppeteer-core`。
|
||||
- **说明**:该脚本使用 `puppeteer-core` 通过 CDP 协议连接远程浏览器,无需安装完整的 puppeteer 及其内置浏览器。
|
||||
|
||||
### 2. Python 环境
|
||||
如果您使用 `playwright.py` 脚本:
|
||||
- **版本推荐**:建议在「语言环境」中安装并使用 **Python 3.11**。
|
||||
> [!TIP]
|
||||
> 建议避开更高版本的 Python(如 3.12+),因为目前部分 Playwright 依赖在极新版本的 Python 环境下可能会遭遇编译或安装失败。
|
||||
- **依赖安装**:前往「语言依赖」->「Python」,安装 `playwright`。
|
||||
|
||||
---
|
||||
|
||||
配置完成后,即可创建定时任务并关联对应的脚本文件。
|
||||
|
||||
## Browserless 连接要点
|
||||
|
||||
如果你当前是通过 Browserless 连接远程浏览器:
|
||||
|
||||
- 不要执行 `playwright install`
|
||||
- 不需要额外下载 Chromium / Firefox / WebKit
|
||||
- 直接使用 `connect_over_cdp` 连接远程浏览器即可
|
||||
|
||||
## 适用场景
|
||||
|
||||
- 验证任务池到 Browserless 的网络连通性
|
||||
- 验证远程浏览器地址和 Token 是否配置正确
|
||||
- 快速测试浏览器自动化脚本是否能正常运行
|
||||
- 快速确认 Node.js / Python 语言环境是否已经配置完成
|
||||
- 作为后续网页自动化脚本的基础模板
|
||||
|
||||
## 推荐部署方式
|
||||
|
||||
建议配合 `browserless/chromium` 一起使用,再由任务池中的脚本连接远程浏览器服务。
|
||||
|
||||
参考 `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
browser:
|
||||
image: ghcr.io/browserless/chromium:latest
|
||||
container_name: browser
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MAX_CONCURRENT_SESSIONS: 5
|
||||
MAX_QUEUE_LENGTH: 20
|
||||
CONNECTION_TIMEOUT: 300000
|
||||
DEFAULT_LAUNCH_ARGS: '["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage"]'
|
||||
TOKEN: your-secret-token
|
||||
ENABLE_DEBUGGER: "false"
|
||||
shm_size: "1gb"
|
||||
mem_limit: 2g
|
||||
cpus: 2
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/healthz"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
taskpool:
|
||||
image: ghcr.io/engigu/taskpool:latest
|
||||
container_name: taskpool
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8052:8052"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./envs:/app/envs
|
||||
environment:
|
||||
- TZ=Asia/Shanghai
|
||||
- BH_SERVER_PORT=8052
|
||||
- BH_SERVER_HOST=0.0.0.0
|
||||
- BH_DB_TYPE=sqlite
|
||||
- BH_DB_PATH=/app/data/taskpool.db
|
||||
- BH_DB_TABLE_PREFIX=taskpool_
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
depends_on:
|
||||
- browser
|
||||
```
|
||||
|
||||
## 使用步骤
|
||||
|
||||
1. 启动 `browser` 和 `taskpool` 服务。
|
||||
2. 在任务池的“语言依赖”中安装对应包。
|
||||
3. 按实际环境修改脚本中的 Browserless 地址和 Token。
|
||||
4. 在任务池中创建任务并运行对应脚本。
|
||||
|
||||
Python 示例的核心写法如下:
|
||||
|
||||
```python
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.connect_over_cdp(
|
||||
"http://browser:3000?token=your-secret-token"
|
||||
)
|
||||
page = browser.new_page()
|
||||
page.goto("https://www.baidu.com")
|
||||
page.screenshot(path="baidu.png")
|
||||
browser.close()
|
||||
```
|
||||
|
||||
## 运行前检查
|
||||
|
||||
- Browserless 服务已经正常启动
|
||||
- 任务池可以访问 Browserless 地址
|
||||
- `TOKEN` 与 Browserless 配置保持一致
|
||||
- 脚本中的地址、端口和协议填写正确
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 报错提示找不到模块
|
||||
|
||||
通常是还没有在“语言依赖”中安装对应包:
|
||||
|
||||
- Node.js 示例需要 `puppeteer-core`
|
||||
- Python 示例需要 `playwright`
|
||||
|
||||
### 2. 为什么没有执行 `playwright install`
|
||||
|
||||
这是预期行为。
|
||||
|
||||
如果你使用的是 Browserless 这类远程浏览器服务,Playwright 只是作为客户端发起连接,不需要在任务池容器里再下载本地浏览器,所以通常不要执行 `playwright install`。
|
||||
|
||||
### 3. 连接不上 Browserless
|
||||
|
||||
请优先检查:
|
||||
|
||||
- Browserless 服务是否正常启动
|
||||
- Token 是否正确
|
||||
- 任务池与 Browserless 是否在同一网络中
|
||||
- 地址是否写成了当前运行环境可访问的地址
|
||||
|
||||
### 4. 页面打开超时
|
||||
|
||||
可以尝试:
|
||||
|
||||
- 换一个更稳定的目标站点
|
||||
- 调大超时时间
|
||||
- 增加 Browserless 容器的 `shm_size`
|
||||
- 检查容器 CPU / 内存是否不足
|
||||
|
||||
### 5. 没有看到截图文件
|
||||
|
||||
请确认:
|
||||
|
||||
- 脚本已经执行成功
|
||||
- 截图保存路径是否正确
|
||||
- 任务工作目录是否符合预期
|
||||
|
||||
## 说明
|
||||
|
||||
这组示例主要用于快速验证任务池与远程浏览器服务之间的连通性,以及对应语言环境是否已经配置完成。
|
||||
@@ -0,0 +1,296 @@
|
||||
# 内置库示例
|
||||
|
||||
taskpool提供了一个名为 `taskpool` 的内建包(Built-in SDK),支持 Python 和 Node.js。通过该内置库,您可以在脚本中实现**消息推送**、**环境变量管理**以及**任务执行控制**等高级功能。
|
||||
|
||||
---
|
||||
|
||||
## 准备工作
|
||||
|
||||
在运行内置库脚本之前,请确保完成了以下步骤:
|
||||
|
||||
### 1. 安装内置包
|
||||
在taskpool的「终端」页面中,或者通过创建临时任务执行以下命令,为面板管理的所有语言环境安装 `taskpool` 包:
|
||||
|
||||
```bash
|
||||
taskpool builtininstall
|
||||
```
|
||||
|
||||
### 2. 配置环境变量
|
||||
根据您需要调用的功能,在定时任务的“环境变量”或“机密”中配置以下对应 Key:
|
||||
|
||||
#### 消息推送所需环境变量
|
||||
- **`BHPKG_NOTIFY_TOKEN`**:进入「消息推送」->「脚本调用说明」页面即可找到。
|
||||
- **`BHPKG_NOTIFY_CHANNEL`**:进入「消息推送」->「渠道列表」页面,查看对应渠道的 **ID**。
|
||||
- **`BHPKG_NOTIFY_URL`** (可选):默认为 `http://localhost:8052/api/v1/notify/send`。如果修改了主服务端口,需要同步修改。
|
||||
|
||||
#### 环境变量管理与定时任务控制所需环境变量
|
||||
- **`BHPKG_OPENAPI_TOKEN`** (或 `OPENAPI_TOKEN`):用于 OpenAPI 接口鉴权,进入「系统设置」->「OpenAPI」页面,生成并复制 Token。
|
||||
- **`BHPKG_OPENAPI_URL`** (或 `OPENAPI_URL`,可选):默认为本地面板 API 地址。若在非标准环境下运行,可手动指定(例如 `http://localhost:8052`)。
|
||||
|
||||
---
|
||||
|
||||
## 消息通知示例
|
||||
|
||||
只需要一行代码即可触发零配置推送。
|
||||
|
||||
::: code-group
|
||||
|
||||
```python [Python]
|
||||
import taskpool
|
||||
|
||||
def main():
|
||||
print("正在尝试发送 Python 内建通知...")
|
||||
try:
|
||||
# 调用内置 notify 函数
|
||||
# 内部会自动使用环境变量进行鉴权和投递
|
||||
response = taskpool.notify(
|
||||
title="Python 任务提醒",
|
||||
text="这是一条来自 Python 示例脚本的通知消息。调用非常简单!"
|
||||
)
|
||||
print("发送请求已处理。")
|
||||
if response:
|
||||
print(f"服务器响应: {response}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"发送过程发生异常: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
```javascript [Node.js]
|
||||
const taskpool = require('taskpool');
|
||||
|
||||
console.log("正在尝试发送 Node.js 内建通知...");
|
||||
|
||||
try {
|
||||
// 简单的一行代码即可完成推送,内置包采用异步非阻塞发送
|
||||
taskpool.notify(
|
||||
"Node.js 任务提醒",
|
||||
"这是一条来自 Node.js 示例脚本的通知消息。无需配置 API 地址或 Token。"
|
||||
);
|
||||
console.log("发送请求已提交。");
|
||||
|
||||
} catch (e) {
|
||||
console.error(`通知失败: ${e.message}`);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 环境变量管理
|
||||
|
||||
内置库支持对面板的环境变量进行增删改查。
|
||||
|
||||
### 支持方法
|
||||
|
||||
* **Python**:
|
||||
- `get_envs()`: 获取所有环境变量列表。
|
||||
- `get_env(name)`: 根据变量名称获取详情。
|
||||
- `add_env(name, value, remark)`: 添加新的环境变量。
|
||||
- `update_env(id, name, value, remark)`: 更新指定 ID 的环境变量值。
|
||||
- `delete_env(id)`: 根据 ID 删除环境变量。
|
||||
* **Node.js**:
|
||||
- `getEnvs()`: 获取所有环境变量列表。
|
||||
- `getEnv(name)`: 根据变量名称获取详情。
|
||||
- `addEnv(name, value, remark)`: 添加新的环境变量。
|
||||
- `updateEnv(id, name, value, remark)`: 更新指定 ID 的环境变量值。
|
||||
- `deleteEnv(id)`: 根据 ID 删除环境变量。
|
||||
|
||||
### 代码示例
|
||||
|
||||
::: code-group
|
||||
|
||||
```python [Python]
|
||||
import taskpool
|
||||
|
||||
def main():
|
||||
print("====== 开始运行 Python 环境变量管理示例 ======")
|
||||
try:
|
||||
# 1. 获取全部环境变量
|
||||
envs = taskpool.get_envs()
|
||||
print(f"当前共有 {len(envs)} 个环境变量")
|
||||
|
||||
# 2. 新增一个临时环境变量
|
||||
new_env_name = "BHPKG_TEST_KEY"
|
||||
new_env_val = "HelloTaskPool"
|
||||
print(f"正在创建环境变量: {new_env_name}...")
|
||||
created_env = taskpool.add_env(
|
||||
name=new_env_name,
|
||||
value=new_env_val,
|
||||
remark="Python SDK 测试自动创建"
|
||||
)
|
||||
print(f"创建成功: ID={created_env.get('id')}, Name={created_env.get('name')}")
|
||||
|
||||
# 3. 查询刚才创建的环境变量详情
|
||||
checked_env = taskpool.get_env(new_env_name)
|
||||
if checked_env:
|
||||
print(f"成功查询到变量: {checked_env.get('name')} = {checked_env.get('value')}")
|
||||
|
||||
# 4. 修改该环境变量的值
|
||||
updated_val = "HelloTaskPool_Updated"
|
||||
print(f"正在修改环境变量的值为: {updated_val}...")
|
||||
updated_env = taskpool.update_env(
|
||||
id=checked_env.get("id"),
|
||||
name=new_env_name,
|
||||
value=updated_val,
|
||||
remark="Python SDK 测试自动更新"
|
||||
)
|
||||
print(f"更新成功: Value={updated_env.get('value')}")
|
||||
|
||||
# 5. 删除该临时环境变量
|
||||
print(f"正在删除临时环境变量: ID={checked_env.get('id')}...")
|
||||
taskpool.delete_env(checked_env.get("id"))
|
||||
print("删除成功!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"环境变量操作失败: {e}")
|
||||
print("提示: 请确保在面板任务设置中正确注入了 OpenAPI Token。")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
```javascript [Node.js]
|
||||
const taskpool = require('taskpool');
|
||||
|
||||
async function main() {
|
||||
console.log("====== 开始运行 Node.js 环境变量管理示例 ======");
|
||||
try {
|
||||
// 1. 获取全部环境变量
|
||||
const envs = await taskpool.getEnvs();
|
||||
console.log(`当前共有 ${envs.length} 个环境变量`);
|
||||
|
||||
// 2. 新增一个临时环境变量
|
||||
const newEnvName = "BHPKG_TEST_KEY_JS";
|
||||
const newEnvVal = "HelloTaskPoolJS";
|
||||
console.log(`正在创建环境变量: ${newEnvName}...`);
|
||||
const createdEnv = await taskpool.addEnv(
|
||||
newEnvName,
|
||||
newEnvVal,
|
||||
"Node.js SDK 测试自动创建"
|
||||
);
|
||||
console.log(`创建成功: ID={createdEnv.id}, Name={createdEnv.name}`);
|
||||
|
||||
// 3. 查询该环境变量
|
||||
const checkedEnv = await taskpool.getEnv(newEnvName);
|
||||
if (checkedEnv) {
|
||||
console.log(`成功查询到变量: ${checkedEnv.name} = ${checkedEnv.value}`);
|
||||
|
||||
// 4. 修改该环境变量的值
|
||||
const updatedVal = "HelloTaskPoolJS_Updated";
|
||||
console.log(`正在修改环境变量的值为: ${updatedVal}...`);
|
||||
const updatedEnv = await taskpool.updateEnv(
|
||||
checkedEnv.id,
|
||||
newEnvName,
|
||||
updatedVal,
|
||||
"Node.js SDK 测试自动更新"
|
||||
);
|
||||
console.log(`更新成功: Value=${updatedEnv.value}`);
|
||||
|
||||
// 5. 删除该临时环境变量
|
||||
console.log(`正在删除临时环境变量: ID={checkedEnv.id}...`);
|
||||
await taskpool.deleteEnv(checkedEnv.id);
|
||||
console.log("删除成功!");
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error(`环境变量操作失败: ${e.message}`);
|
||||
console.log("提示: 请确保在面板任务设置中正确注入了 OpenAPI Token。");
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 定时任务管理与控制
|
||||
|
||||
内置库支持查询面板的任务列表、最近的执行结果以及手动触发特定任务的运行。
|
||||
|
||||
### 支持方法
|
||||
|
||||
* **Python**:
|
||||
- `get_tasks()`: 获取所有定时任务列表。
|
||||
- `execute_task(id)`: 立即触发指定 ID 任务的运行。
|
||||
- `get_last_results()`: 获取最近任务的执行记录。
|
||||
* **Node.js**:
|
||||
- `getTasks()`: 获取所有定时任务列表。
|
||||
- `executeTask(id)`: 立即触发指定 ID 任务的运行。
|
||||
- `getLastResults()`: 获取最近任务的执行记录。
|
||||
|
||||
### 代码示例
|
||||
|
||||
::: code-group
|
||||
|
||||
```python [Python]
|
||||
import taskpool
|
||||
|
||||
def main():
|
||||
print("====== 开始运行 Python 任务管理与执行控制示例 ======")
|
||||
try:
|
||||
# 1. 获取所有任务列表
|
||||
tasks = taskpool.get_tasks()
|
||||
print(f"成功获取到 {len(tasks)} 个定时任务:")
|
||||
for task in tasks[:5]: # 仅打印前5个
|
||||
print(f" - [{task.get('id')}] {task.get('name')} (表达式: {task.get('schedule')}, 备注: {task.get('remark')})")
|
||||
|
||||
# 2. 尝试触发第一个任务的运行
|
||||
if tasks:
|
||||
target_task = tasks[0]
|
||||
print(f"\n尝试手动触发任务运行: [{target_task.get('id')}] {target_task.get('name')}...")
|
||||
taskpool.execute_task(target_task.get("id"))
|
||||
print("执行指令发送成功。")
|
||||
|
||||
# 3. 获取最近的执行结果列表
|
||||
results = taskpool.get_last_results()
|
||||
print(f"\n最近共有 {len(results)} 条任务执行记录。")
|
||||
|
||||
except Exception as e:
|
||||
print(f"任务操作失败: {e}")
|
||||
print("提示: 请确保在面板任务设置中正确注入了 OpenAPI Token。")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
|
||||
```javascript [Node.js]
|
||||
const taskpool = require('taskpool');
|
||||
|
||||
async function main() {
|
||||
console.log("====== 开始运行 Node.js 任务管理与执行控制示例 ======");
|
||||
try {
|
||||
// 1. 获取所有任务列表
|
||||
const tasks = await taskpool.getTasks();
|
||||
console.log(`成功获取到 ${tasks.length} 个定时任务:`);
|
||||
tasks.slice(0, 5).forEach(task => { // 仅展示前5项
|
||||
console.log(` - [${task.id}] ${task.name} (表达式: ${task.schedule || ''}, 备注: ${task.remark || ''})`);
|
||||
});
|
||||
|
||||
// 2. 尝试触发第一个任务的运行
|
||||
if (tasks.length > 0) {
|
||||
const targetTask = tasks[0];
|
||||
console.log(`\n尝试手动触发任务运行: [${targetTask.id}] ${targetTask.name}...`);
|
||||
await taskpool.executeTask(targetTask.id);
|
||||
console.log("执行指令发送成功。");
|
||||
}
|
||||
|
||||
// 3. 获取最近的执行结果列表
|
||||
const results = await taskpool.getLastResults();
|
||||
console.log(`\n最近共有 ${results.length} 条任务执行记录。`);
|
||||
|
||||
} catch (e) {
|
||||
console.error(`任务操作失败: ${e.message}`);
|
||||
console.log("提示: 请确保在面板任务设置中正确注入了 OpenAPI Token。");
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
:::
|
||||
@@ -0,0 +1,27 @@
|
||||
# 脚本示例
|
||||
|
||||
任务池内置了一批可直接参考的脚本示例,适合用来验证运行环境、演示常见用法,或者作为你自己脚本的起点。
|
||||
|
||||
如果你使用 Docker 镜像启动任务池,容器启动后会自动将仓库中的 `example` 目录同步到脚本目录下。通常你可以在脚本目录中看到:
|
||||
|
||||
```text
|
||||
example/
|
||||
```
|
||||
|
||||
使用脚本示例前,建议先完成下面几步:
|
||||
|
||||
1. 确认示例文件已经同步到脚本目录。
|
||||
2. 根据脚本语言,到“语言依赖”页面安装对应依赖包。
|
||||
3. 按实际环境修改脚本中的地址、Token、账号或其他配置。
|
||||
4. 在任务管理中选择对应脚本并运行。
|
||||
|
||||
> [!TIP]
|
||||
> 如果示例脚本依赖第三方包,但你还没有在“语言依赖”中安装,对应任务通常会直接报缺少模块或包。
|
||||
|
||||
## 当前示例
|
||||
|
||||
目前文档已经整理出的示例类型:
|
||||
|
||||
- [浏览器示例](./browser.md)
|
||||
- [内置库示例](./builtin.md)
|
||||
- [Linux 环境依赖示例](./linux-deps.md)
|
||||
@@ -0,0 +1,111 @@
|
||||
# Linux 系统依赖处理
|
||||
|
||||
在使用taskpool时,您可能会在运行某些脚本时遇到缺少底层 Linux 系统级依赖(例如 `apt` 或 `apk` 包)的情况。这篇指南将详细讲解如何优雅、持久地解决这些依赖问题。
|
||||
|
||||
## 背景与痛点
|
||||
|
||||
taskpool通常以 Docker 容器的形式运行。Docker 的文件系统具有以下特性:
|
||||
- **挂载目录(持久化)**:像 `data/` 这样的目录被映射到了宿主机,其中的数据(如脚本、日志、配置文件)在重启或升级镜像时会保留。
|
||||
- **容器层(非持久化)**:容器自身的系统目录(如 `/usr/bin`, `/lib`, `/etc`)是临时层。如果您直接在终端里手动执行 `apt-get install xxx`,虽然当下可以立即使用,**但在容器被销毁重建或更新镜像后,这些刚安装的系统包就会全部丢失。**(注意:仅仅是普通的 `docker restart` 重启容器并不会丢失,只有重建容器时才会重置)
|
||||
|
||||
## 核心解决思路
|
||||
|
||||
为了解决依赖丢失的问题,taskpool提供了一种自动化的解决方案:**利用 `taskpool_startup`(开机触发)类型的定时任务,在面板每次启动时自动执行一段依赖安装脚本。**
|
||||
|
||||
这样,无论您如何更新镜像或重启容器,系统依赖都能在面板核心服务就绪前自动被补充安装,并且对后续的普通脚本任务透明。
|
||||
|
||||
---
|
||||
|
||||
## 具体操作步骤
|
||||
|
||||
### 第一步:编写依赖安装脚本
|
||||
|
||||
首先,在您的脚本目录(通常为 `data/scripts` 下,或者您可以单独建一个 `data/scripts/deps` 目录)创建一个 Shell 脚本,例如 `install_my_deps.sh`。
|
||||
|
||||
由于taskpool的镜像目前均基于 Debian 系统,您可以直接在脚本中使用 `apt` 或 `apt-get` 命令来管理系统依赖。
|
||||
|
||||
**示例 1:安装 Puppeteer (无头浏览器) 的依赖动态库**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 遇到错误即停止执行
|
||||
set -e
|
||||
|
||||
echo "正在检测并安装 Puppeteer 依赖..."
|
||||
|
||||
# 提前 update 索引是非常重要的一步
|
||||
apt-get update
|
||||
apt-get install -y libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2
|
||||
|
||||
echo "Puppeteer 依赖安装完成!"
|
||||
```
|
||||
|
||||
**示例 2:安装 Python/C++ 编译所需的基础工具链**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
apt-get update
|
||||
# 安装 gcc, g++, make 以及 python3 相关的头文件
|
||||
apt-get install -y build-essential python3-dev
|
||||
```
|
||||
|
||||
**示例 3:带 Hash 检查的高阶依赖安装脚本(推荐)**
|
||||
此脚本利用 `/tmp` 目录和脚本自身内容的哈希值,完美匹配 Docker 容器的生命周期,避免在普通重启时无意义地检测。
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# 生成当前脚本的哈希标识
|
||||
SCRIPT_HASH=$(md5sum "$0" | awk '{print $1}')
|
||||
FLAG_FILE="/tmp/deps_installed_${SCRIPT_HASH}"
|
||||
|
||||
# 如果标识文件存在,说明在此容器生命周期内已安装过,且脚本未被修改,直接退出
|
||||
if [ -f "$FLAG_FILE" ]; then
|
||||
echo "系统依赖已就绪,跳过安装。"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "开始安装系统环境依赖..."
|
||||
apt-get update
|
||||
# 假设您需要安装 ffmpeg 和 imagemagick
|
||||
apt-get install -y ffmpeg imagemagick
|
||||
|
||||
# 安装成功后写入标识文件
|
||||
touch "$FLAG_FILE"
|
||||
echo "系统依赖安装完成!"
|
||||
```
|
||||
|
||||
### 第二步:配置开机触发任务
|
||||
|
||||
脚本编写并保存到面板后,接下来只需将其配置为开机任务:
|
||||
|
||||
1. 进入面板的 **「定时任务」** 页面,点击 **「新建任务」**。
|
||||
2. **任务名称**: 填写容易辨识的名称,例如 “安装系统底层依赖”。
|
||||
3. **执行命令**: 输入执行该脚本的命令,例如 `bash deps/install_my_deps.sh` (假设您将脚本放在了 `deps` 文件夹下)。
|
||||
4. **触发类型**: 在下拉菜单中选择 **`taskpool_startup` (开机触发)**。
|
||||
5. **保存** 任务。
|
||||
|
||||
现在,你可以尝试在终端中执行一下该任务验证脚本是否无误。一旦无误,未来每次容器重启,面板都会自动在后台静默执行这个任务,确保环境完备。
|
||||
|
||||
---
|
||||
|
||||
## 官方预设示例:PHP 编译依赖
|
||||
|
||||
为了方便用户参考,我们在项目源码中内置了一个更完善的依赖安装脚本示例。
|
||||
|
||||
通过 `mise` 安装某些 PHP 版本时,系统会尝试从源码编译,这就需要用到 `autoconf`, `bison`, `pkg-config` 等工具。
|
||||
|
||||
如果您在安装 PHP 时遇到 `autoconf not found` 或 `buildconf failed`,可以直接使用项目根目录下的预设示例脚本:
|
||||
- **路径位置**: `example/deps/install_php_env_deps.sh`
|
||||
- **使用方法**: 新建 `taskpool_startup` 触发类型的任务,执行命令填写 `bash example/deps/install_php_env_deps.sh` 即可。
|
||||
|
||||
此示例脚本中还包含了“检测是否已安装再决定是否执行 apt install”的逻辑,您可以查阅其源码作为编写自己依赖脚本的最佳实践参考。
|
||||
|
||||
---
|
||||
|
||||
## 注意事项与进阶建议
|
||||
|
||||
1. **幂等性 (Idempotency)**:开机脚本在每次重启时都会在后台异步执行。像 `apt-get install -y` 这种命令天然是幂等的(如果已安装就不会重新下载),虽然它不会阻塞面板的启动速度,但每次无意义地检查和刷新软件源仍会白白占用开机初期的系统资源。建议您在脚本中先用 `dpkg -l <包名>` 或 `command -v <命令>` 判断依赖是否存在,不存在时再执行安装。
|
||||
- **进阶技巧**:您也可以在依赖安装完成后,向 `/tmp` 目录下写入一个带有当前脚本内容 Hash 值的标识文件(例如 `touch /tmp/deps_installed_$(md5sum "$0" | awk '{print $1}')`)。在脚本开头判断该文件是否存在,若存在则直接退出。由于容器被销毁重建时 `/tmp` 目录和您安装的系统依赖会一并丢失,而在普通的重启中它们又会一并保留,这种方式完美契合了容器的临时层生命周期,能避免反复执行依赖检测逻辑,进一步加速开机任务。
|
||||
2. **网络环境**: Docker 镜像已经**默认将 APT 源替换为了清华源 (TUNA)**,因此在国内网络下执行 `apt-get` 也能获得很快的下载速度,您通常不需要在脚本中再次手动替换源。
|
||||
3. **避免冲突**:请仅安装您脚本运行强依赖的底层库,尽量不要通过 `apt` 安装 Node.js 或 Python 的运行环境,这些高级语言环境应交由面板的 **「编程语言」** (Mise) 模块统一管理。
|
||||
@@ -0,0 +1,43 @@
|
||||
# 访问面板
|
||||
|
||||
部署成功并启动容器后,您只需通过浏览器即可访问taskpool。
|
||||
|
||||
## 默认账号
|
||||
|
||||
- **访问地址**:`http://localhost:8052` (或您配置的宿主机端口)
|
||||
- **用户名**:`admin`
|
||||
- **密码**:首次启动成功后,系统会为管理员账号生成 **12 位随机初始密码** 并打印在容器启动日志中。
|
||||
|
||||
> **如何查找初始密码**:
|
||||
> 运行容器后,在命令行执行:
|
||||
> ```bash
|
||||
> docker logs taskpool | grep "管理员账号创建成功"
|
||||
> ```
|
||||
> 找到包含密码的内容后登录,登录后建议首选操作:**修改管理员密码**。
|
||||
|
||||
---
|
||||
|
||||
## 登录后的首要配置
|
||||
|
||||
### 1. 修改密码
|
||||
在右上角用户头像下拉菜单选择「个人设置」进行账号安全修改。
|
||||
|
||||
### 2. 系统调度设置
|
||||
在「系统设置」>「调度设置」中,可以根据服务器资源微调任务队列的并发数(默认 4)和最大队列大小(默认 100)。
|
||||
|
||||
### 3. 环境与依赖
|
||||
如果您需要执行特定语言或脚本包,请先进入「编程语言」页面确认所需的环境已安装(如已安装 Python3.x 或 Node.js.x)。
|
||||
|
||||
---
|
||||
|
||||
## 面板功能一览
|
||||
|
||||
| 模块 | 说明 |
|
||||
| :--- | :--- |
|
||||
| **仪表盘 (Dashboard)** | 实时监控任务执行动态、容器状态和资源占用频率情况。 |
|
||||
| **定时任务 (Tasks)** | 管理和调度各种 Cron 脚本。 |
|
||||
| **脚本管理 (Scripts)** | 在线编辑、上传项目源代码。 |
|
||||
| **在线终端 (Terminal)** | 直接操作容器环境进行运维和调试。 |
|
||||
| **消息推送 (Notify)** | 配置各类通知渠道。 |
|
||||
| **环境变量 (Environments)** | 管理脚本所需的各种隐私信息、持久配置。 |
|
||||
| **个人设置 (Settings)** | 调整站点 UI 和账号安全信息。 |
|
||||
@@ -0,0 +1,24 @@
|
||||
# 执行历史
|
||||
|
||||
执行历史详细记录了面板中所有任务的运行状态、实时日志及耗时统计。
|
||||
|
||||
## 日志详情
|
||||
|
||||
- **实时日志推流**:即使任务仍在运行,也可以在历史日志详情页实时看到程序的控制台输出(stdout/stderr)。
|
||||
- **历史归档**:系统默认保留最近一段时间的任务运行快照。
|
||||
- **状态统计**:
|
||||
- `SUCCESS`:任务按计划成功运行并返回正常退出代码。
|
||||
- `FAILURE`:脚本运行时报错或程序异常终止。
|
||||
- `TIMEOUT`:任务执行超出了设定的最大运行时间,由系统强制中止并标记为超时。
|
||||
|
||||
## 日志管理
|
||||
|
||||
- **搜索与过滤**:支持通过 `任务名称`、`脚本文件名` 或 `状态` 快速检索历史。
|
||||
- **自动清理策略**:
|
||||
- **最大保留份数**:支持在系统设置中配置每个任务保留的历史日志最大数量。
|
||||
- **日志滚动更新**:当产生新日志且超过最大份数时,最旧的记录将被自动清除,确保存储空间的动态平衡。
|
||||
|
||||
## 执行耗时
|
||||
|
||||
- **精准计时**:精确统计每次任务执行从启动到退出的全周期耗时。
|
||||
- **性能分析**:通过历史耗时数据对比,可辅助用户排查脚本是否出现了性能退化。
|
||||
@@ -0,0 +1,62 @@
|
||||
# 面板互联 (Interconnect)
|
||||
|
||||
面板互联功能允许您将多个面板(taskpool)连接在一起,形成主从(Master-Child)架构的集群。这使得您可以在一个中心化的主面板上集中监控和管理所有的子节点,极大地简化了多面板环境下的运维工作。
|
||||
|
||||
## 核心特性
|
||||
|
||||
- **集中管理**:在主节点上统一查看所有子节点的状态。
|
||||
- **无缝穿越**:主节点可以直接“穿越”到子节点的控制台进行管理,无需反复登录。
|
||||
- **内网穿透**:即使子节点部署在没有公网 IP 的深层内网(如家庭宽带、企业内网),只要主节点具有公网访问能力,子节点也能主动与主节点建立安全的反向穿透隧道,实现主节点对内网子节点的直连管理。
|
||||
- **极致性能**:深度优化了底层连接与通信逻辑,严格控制并优化了协程(Goroutine)数目,确保在海量节点高并发连接下依然保持极低的资源占用和极高的系统稳定性。
|
||||
- **角色互斥**:每个面板只能扮演一种角色(主节点或子节点),避免循环嵌套。
|
||||
|
||||
## 架构说明
|
||||
|
||||
### 主节点 (Master)
|
||||
|
||||
- **功能**:集中监控其他面板的状态,并可无缝穿越到子节点进行管理。
|
||||
- **适用场景**:部署在具有公网 IP 的云服务器上,作为整个集群的控制中心。
|
||||
- **配置操作**:选择作为主节点后,您可以生成专属的连接密钥,并将此密钥提供给子节点用于连接。在主节点的界面上可以添加并管理多个子节点。
|
||||
|
||||
### 子节点 (Child)
|
||||
|
||||
- **功能**:向主节点报告自身的运行状态,并允许主节点穿越到本面板进行管理。
|
||||
- **适用场景**:部署在各种边缘环境,如家庭宽带、企业内网等可能没有公网 IP 的环境中。
|
||||
- **配置操作**:选择作为子节点后,需要填入主节点的地址和由主节点生成的密钥。子节点会主动发起连接,与主节点建立安全的反向穿透隧道。
|
||||
|
||||
## 使用步骤
|
||||
|
||||
1. **确定角色**:首先在您的面板集群中规划好哪台机器作为主节点,哪些机器作为子节点。
|
||||
2. **配置主节点**:
|
||||
- 登录主节点的面板。
|
||||
- 导航至左侧菜单的 **面板互联**。
|
||||
- 选择 **我是主节点 (Master)** 角色。
|
||||
- 复制生成的连接信息或密钥。
|
||||
3. **配置子节点**:
|
||||
- 登录子节点的面板。
|
||||
- 导航至左侧菜单的 **面板互联**。
|
||||
- 选择 **我是子节点 (Child)** 角色。
|
||||
- 填入主节点的地址和刚才复制的密钥。
|
||||
- 保存并连接。
|
||||
4. **统一管理**:
|
||||
- 回到主节点,您将看到刚刚连接上来的子节点列表及其在线状态。
|
||||
- 点击子节点列表中的对应操作按钮,即可实现无缝穿越,直接管理该子节点的资源和任务。
|
||||
|
||||
## 无缝穿越功能 (Seamless Travel)
|
||||
|
||||
无缝穿越是面板互联中最强大的功能之一,它允许您在不离开主节点浏览器界面的情况下,直接接管并操作任何连接的子节点。
|
||||
|
||||
### 穿越特点
|
||||
|
||||
- **免密直连**:只要子节点已经连接到主节点,即可一键穿越,无需再次输入子节点的管理员账号和密码。
|
||||
- **全功能接管**:穿越后,您看到的所有数据(如定时任务、脚本、执行历史、系统状态等)和进行的所有操作(如新建任务、执行脚本)都是针对**该子节点**的。相当于您直接在子节点本地登录。
|
||||
- **内网穿透能力**:得益于底层的反向隧道技术,即使子节点位于无法直接访问的深层内网,穿越依然能够流畅进行,所有的 API 请求都将通过隧道安全转发。
|
||||
|
||||
### 如何退出穿越
|
||||
|
||||
当您处于穿越状态时(即正在管理某个子节点),界面左下方会出现一个醒目的悬浮控制条(**“返回主节点”**)。
|
||||
- 随时点击该按钮即可**退出穿越**。
|
||||
- 退出后,您的视图和操作权限将立即恢复为主节点的本地状态。
|
||||
|
||||
> **注意**:
|
||||
> 请根据实际集群架构分配角色,一旦设定角色,除非重置配置,否则该面板将一直保持此角色。在演示模式下,可能无法修改互联角色。
|
||||
@@ -0,0 +1,23 @@
|
||||
# 项目介绍
|
||||
|
||||
taskpool (TaskPool) 是一款极致轻量、高性能的自动化任务调度平台。采用 Go + Vue3 架构,专注于高性能与低系统开销。
|
||||
|
||||
## 核心亮点
|
||||
|
||||
- **极致性能**:采用 Go 语言开发,在同样的任务执行下,资源占用极低。
|
||||
- **运行时解耦**:深度集成 **Mise** 运行时管理,原生支持 Python、Node.js、Go、Rust、PHP 等所有主流语言环境的动态安装(几乎所有的版本)与统一依赖管理。
|
||||
- **一键部署**:支持 Docker/Docker-Compose 一键部署,开箱即用。
|
||||
- **现代 UI**:基于 Vue3 + TailwindCSS + Shadcn/ui,提供响应式设计与深色/浅色主题。
|
||||
|
||||
|
||||
## 主要特色
|
||||
|
||||
- **轻量级:** docker/compose部署,无需复杂配置,开箱即用
|
||||
- **任务调度:** 支持标准 Cron 表达式,常用时间规则快捷选择。日志不落文件,没有磁盘频繁io的问题
|
||||
- **脚本管理:** 在线代码编辑器,支持文件上传、压缩包解压
|
||||
- **在线终端:** WebSocket 实时终端,命令执行结果实时输出
|
||||
- **消息推送:** 内置强大消息推送与通知引擎,无缝兼容主流渠道,支持系统级事件告警
|
||||
- **环境变量:** 安全存储敏感配置,任务执行时自动注入
|
||||
- **移动端:** 适配移动小屏样式
|
||||
- **远程执行:** 支持远程agent执行任务,展示执行结果
|
||||
- **多语言支持:** 深度集成 Mise,支持几乎所有主流编程语言的动态安装、多版本切换及依赖管理
|
||||
@@ -0,0 +1,74 @@
|
||||
# 语言依赖
|
||||
|
||||
taskpool深度集成了 **Mise** 运行时管理器,这使得它具备多版本语言环境的高灵活性和隔离性。
|
||||
|
||||
## 脚本运行环境
|
||||
|
||||
taskpool原生支持以下脚本的定时执行:
|
||||
- **Python3**, **Node.js**, **Bash** (标准版镜像内置环境)
|
||||
- 通过 **Mise** 扩展:支持几乎所有主流编程语言的动态安装与切换。
|
||||
|
||||
|
||||
> [!TIP]
|
||||
> **Minimal 镜像注意**:如果您使用的是 `minimal` 标签的镜像,系统初始不包含 Python 和 Node.js。您需要进入「编程语言」页面手动点击安装您所需的运行时。
|
||||
|
||||
## 依赖管理支持
|
||||
|
||||
系统内置了高度集成的跨语言依赖管理器,支持自动化安装和管理以下语言的依赖项,并确保在容器内全局可用:
|
||||
|
||||
| 语言 | 包管理器 | 功能说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| **Python** | pip | 自动使用内置虚拟环境,支持清华源 |
|
||||
| **Node.js** | npm | 全局安装模式,自动配置 npmmirror 镜像 |
|
||||
| **Go** | go install | 通过 `go install` 安装二进制工具 |
|
||||
| **Rust** | cargo | 通过 `cargo install` 安装 Rust 依赖 |
|
||||
| **Ruby** | gem | 支持 `gem install` 本地安装 |
|
||||
| **Bun** | bun | 支持 `bun add -g` 全局模式 |
|
||||
| **PHP** | composer | 支持 `composer global require` |
|
||||
| **Deno** | deno | 支持 `deno install -g` |
|
||||
| **.NET** | dotnet | 支持 `dotnet tool install -g` |
|
||||
| **Elixir/Erlang** | mix | 支持 `mix archive.install` |
|
||||
| **Lua** | luarocks | 通过 `luarocks` 管理 Lua 包 |
|
||||
| **Nim** | nimble | 支持 `nimble install` |
|
||||
| **Dart/Flutter** | pub | 支持 `pub global activate` |
|
||||
| **Perl** | cpanm | 简单的 `cpanm` 安装支持 |
|
||||
| **Crystal** | shards | `shards` 项目级别或工具安装 |
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 安装环境
|
||||
进入「编程语言」页面,使用 `mise` 一键安装所需的语言及版本。
|
||||
|
||||
### 2. 依赖管理
|
||||
在已安装列表点击「依赖管理」,输入名称(可选版本)即可自动在对应环境内完成安装。
|
||||
|
||||
### 3. 多版本切换
|
||||
对于复杂的项目,您可以通过面板配置不同的任务版本镜像,系统基于 `mise exec` 实现了完善的环境隔离,不同版本的依赖包互不冲突。
|
||||
|
||||
## 常用工具安装
|
||||
|
||||
如果您需要在面板环境中使用 Ansible 或其他通过 pipx 管理的工具,可以使用以下命令进行快速安装:
|
||||
|
||||
### 安装 Ansible
|
||||
|
||||
taskpool推荐通过 `mise` 结合 `pipx` 安装 Ansible,以保持环境隔离且全局可用:
|
||||
|
||||
```bash
|
||||
# 首先安装 pipx
|
||||
mise use -g pipx@latest
|
||||
|
||||
# 使用 pipx 安装 ansible
|
||||
mise use -g ansible@latest
|
||||
```
|
||||
|
||||
安装完成后,您可以在「脚本管理」或「定时任务」中直接调用 `ansible` 或 `ansible-playbook` 命令。
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 隔离机制说明
|
||||
|
||||
- taskpool通过动态注入 `PATH` 环境和 `mise shims` 将语言环境暴露给系统。
|
||||
- 每个任务在执行前都会根据任务配置自动加载对应的运行时环境变量。
|
||||
- **运行时激活**:自动将 `MISE_DATA_DIR` 等环境变量指向宿主机的持久化挂载目录,确保护持久化可用。
|
||||
@@ -0,0 +1,86 @@
|
||||
# Nginx 反向代理配置
|
||||
|
||||
如果您需要通过域名和 HTTPS 访问taskpool,推荐使用 Nginx 作为反向代理并配置 WebSocket 负载均衡。
|
||||
|
||||
## Nginx 反向代理配置示例
|
||||
|
||||
### 1. 配置映射
|
||||
首先,在 `nginx.conf` 的 `http` 块中添加 WebSocket 升级映射:
|
||||
```nginx
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 服务器配置
|
||||
将 `example.com` 替换为您的域名,并指定宿主机监听端口:
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name example.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
access_log /var/log/nginx/example.access.log;
|
||||
error_log /var/log/nginx/example.error.log warn;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8052; # 指定taskpool宿主机 IP 和端口
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# WebSocket 支持(在线控制台必需)
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
}
|
||||
|
||||
# 自动 HTTP 跳转 HTTPS (可选)
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 子路径部署场景
|
||||
|
||||
如果您是通过 `BH_SERVER_URL_PREFIX=/taskpool` 进行子路径托管,请修改 `location` 参数:
|
||||
```nginx
|
||||
location /taskpool/ {
|
||||
proxy_pass http://127.0.0.1:8052/taskpool/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 验证与发布
|
||||
|
||||
在保存配置文件后,请执行以下命令确保 Nginx 配置正确并重启:
|
||||
```bash
|
||||
# 检查语法
|
||||
nginx -t
|
||||
# 重启服务
|
||||
nginx -s reload
|
||||
```
|
||||
@@ -0,0 +1,132 @@
|
||||
# 消息中心
|
||||
|
||||
消息中心集成了一整套灵活且现代的消息分发引擎,支持多场景自动推送到外部 IM 工具。
|
||||
|
||||
## 消息通道
|
||||
|
||||
- **企业 IM**:支持集成 **企业微信** (WeCom)、**钉钉** (DingTalk)、**飞书** (Lark)。
|
||||
- **个人推送到位**:支持 **Telegram** Bot、**Bark** (支持自建)、**VoceChat** (支持自建) 以及基于 **Wpush** 的推送服务。
|
||||
- **公共渠道**:标准的 **SMTP 邮件** 及 **Webhook** 回调。
|
||||
|
||||
## 事件通知规则
|
||||
|
||||
- **多事件配置**:您可以灵活定义在哪些场景下触发通知,包括但不限于:
|
||||
- **任务失败**:定时任务在 Cron 触发后运行报错。
|
||||
- **任务超时**:任务由于运行过长被系统中止。
|
||||
- **登录安全**:检测到异地登录或多次密码错误。
|
||||
- **服务下线**:Agent 节点掉线提醒。
|
||||
|
||||
## 推送使用路径
|
||||
|
||||
taskpool提供了两种不同层面的通知推送方式,满足从“自动报警”到“程序内自定义推送”的全场景需求。
|
||||
|
||||
---
|
||||
|
||||
### 路径一:任务绑定通知(零代码自动化)
|
||||
|
||||
这是最常用的方式,用于在定时任务执行完成后,根据结果自动发送通知。
|
||||
|
||||
1. **入口**:在 **「定时任务」** 页面,点击任务右侧的 **「编辑」**。
|
||||
2. **配置**:在弹窗底部的 **「通知配置」** 栏目中:
|
||||
- **选择渠道**:指定发送消息的 IM 渠道。
|
||||
- **触发时机**:勾选 `成功时`、`失败时` 或 `超时时`(建议至少勾选失败和超时)。
|
||||
- **附带日志**:开启后可在消息中直接预览报错日志,支持设置截取长度。
|
||||
3. **生效**:保存后,该任务每次运行结束都会按设定的逻辑自动推信。
|
||||
|
||||
---
|
||||
|
||||
### 路径二:脚本手动调用 (内置助手库 - 推荐)
|
||||
|
||||
taskpool提供了一套**零配置**的内建助手库(Built-in SDK),支持 Python 和 Node.js。除了支持极简的消息通知投递外,它还支持管理面板的**环境变量**与**定时任务控制**。
|
||||
|
||||
#### 1. 如何获取配置 Key?
|
||||
在使用助手库前,请确保您已经在任务设置的“环境变量”或“机密”中配置了以下对应 Key:
|
||||
- **消息推送相关**:
|
||||
- `BHPKG_NOTIFY_TOKEN`:进入「消息推送」->「脚本调用说明」标签,可以直接复制此处的 Token。
|
||||
- `BHPKG_NOTIFY_CHANNEL`:进入「消息推送」->「渠道列表」标签,可以查看每个渠道对应的 **ID**。
|
||||
- `BHPKG_NOTIFY_URL` (可选):内置通知 API 的地址。默认为 `http://localhost:8052/api/v1/notify/send`。
|
||||
- **环境与任务管理相关**:
|
||||
- `BHPKG_OPENAPI_TOKEN` (或 `OPENAPI_TOKEN`):OpenAPI 鉴权 Token,在「系统设置」->「OpenAPI」中生成。
|
||||
- `BHPKG_OPENAPI_URL` (可选):默认为本地面板 API 地址。
|
||||
|
||||
#### 2. 环境初始化
|
||||
在开始编写脚本前,您需要在终端执行以下命令,为面板管理的所有语言环境安装 `taskpool` 包:
|
||||
|
||||
```bash
|
||||
taskpool builtininstall
|
||||
```
|
||||
*该操作会将助手库安装到 mise 管理的所有版本中,确保 import 成功。*
|
||||
|
||||
#### 3. 代码示例
|
||||
|
||||
##### Python (同步调用)
|
||||
```python
|
||||
import taskpool
|
||||
|
||||
# 消息通知
|
||||
taskpool.notify("任务标题", "通知正文内容")
|
||||
|
||||
# 环境变量与任务管理(详细用法见内置库示例)
|
||||
envs = taskpool.get_envs()
|
||||
tasks = taskpool.get_tasks()
|
||||
```
|
||||
|
||||
##### Node.js (异步调用)
|
||||
```javascript
|
||||
const taskpool = require('taskpool');
|
||||
|
||||
// 消息通知
|
||||
taskpool.notify("任务标题", "通知正文内容");
|
||||
|
||||
// 环境变量与任务管理(详细用法见内置库示例)
|
||||
(async () => {
|
||||
const envs = await taskpool.getEnvs();
|
||||
const tasks = await taskpool.getTasks();
|
||||
})();
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> 关于环境变量增删改查以及任务触发控制的完整 API 列表与更详尽的代码,请参考 [内置库示例](./examples/builtin.md)。
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 路径三:其他语言/高级调用 (原始 API)
|
||||
> [!IMPORTANT]
|
||||
> 以下示例中的端口均默认为 `8052`。如果您更改了容器内部的服务端口(通过 `BH_SERVER_PORT` 环境配置),请务必在调用时将 `8052` 替换为您的实际端口。
|
||||
|
||||
如果您使用 Shell 或其他尚未提供助手库的语言,可以通过标准 HTTP POST 请求调用。
|
||||
|
||||
#### 1. 快速获取代码
|
||||
进入 **「消息推送」** -> **「脚本调用说明」** 标签,页面会根据您的配置自动生成包含 **通知 Token** 和 **默认渠道 ID** 的完整代码。
|
||||
|
||||
#### 2. 代码参考示例
|
||||
|
||||
##### Shell (Curl)
|
||||
> **注意**:如果更改了容器内部的服务端口,请将 `8052` 替换为实际端口,或直接使用环境变量 `BHPKG_NOTIFY_URL`。
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8052/api/v1/notify/send" \
|
||||
-H "notify-token: 您的_NOTIFY_TOKEN" \
|
||||
-d '{"channel_id":"渠道ID", "title":"标题", "text":"内容"}'
|
||||
```
|
||||
|
||||
##### 基础 Python (requests)
|
||||
```python
|
||||
import requests
|
||||
|
||||
def send_notify(title, content):
|
||||
url = "http://localhost:8052/api/v1/notify/send"
|
||||
headers = { "notify-token": "您的_NOTIFY_TOKEN" }
|
||||
data = {"channel_id": "您的_渠道_ID", "title": title, "text": content}
|
||||
requests.post(url, headers=headers, json=data)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 消息中心管理
|
||||
|
||||
除了配置发送路径,您还可以在消息中心进行以下操作:
|
||||
|
||||
- **发送记录 (审计)**:实时记录每一条通过taskpool发送至外部的消息,方便追溯。
|
||||
- **回执查询**:在 **「消息日志」** 页面查看到每条推送的详细状态,如果发送失败,会提供原始的错误响应代码以供排查。
|
||||
@@ -0,0 +1,388 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import pullStatsData from '../data/pull-stats.json'
|
||||
|
||||
const searchQuery = ref('')
|
||||
const activePoint = ref(null)
|
||||
|
||||
const pullStatsList = computed(() => pullStatsData.stats || [])
|
||||
|
||||
// 格式化时间显示 (北京时间)
|
||||
const formattedUpdateTime = computed(() => {
|
||||
if (!pullStatsData.updatedAt) return '-'
|
||||
const date = new Date(pullStatsData.updatedAt)
|
||||
const y = date.getFullYear()
|
||||
const m = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const d = String(date.getDate()).padStart(2, '0')
|
||||
const hh = String(date.getHours()).padStart(2, '0')
|
||||
const mm = String(date.getMinutes()).padStart(2, '0')
|
||||
const ss = String(date.getSeconds()).padStart(2, '0')
|
||||
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
|
||||
})
|
||||
|
||||
// 辅助函数:解析 SemVer 版本号
|
||||
const parseVersion = (tag) => {
|
||||
const match = tag.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/)
|
||||
if (!match) return { major: 0, minor: 0, patch: 0, suffix: tag }
|
||||
return {
|
||||
major: parseInt(match[1], 10),
|
||||
minor: parseInt(match[2], 10),
|
||||
patch: parseInt(match[3], 10),
|
||||
suffix: match[4] || ''
|
||||
}
|
||||
}
|
||||
|
||||
// 提取最近发布的主语义版本(包含 latest,过滤掉架构),用于折线图趋势展示
|
||||
const chartPoints = computed(() => {
|
||||
const list = [...pullStatsList.value]
|
||||
.filter(item => (/^\d+\.\d+\.\d+$/.test(item.tag) || item.tag === 'latest') && item.downloads !== 0)
|
||||
.sort((a, b) => {
|
||||
if (a.tag === 'latest') return 1
|
||||
if (b.tag === 'latest') return -1
|
||||
const va = parseVersion(a.tag)
|
||||
const vb = parseVersion(b.tag)
|
||||
if (va.major !== vb.major) return va.major - vb.major
|
||||
if (va.minor !== vb.minor) return va.minor - vb.minor
|
||||
return va.patch - vb.patch
|
||||
})
|
||||
.slice(-20) // 展示最近的 20 个正式版本
|
||||
|
||||
if (list.length === 0) return []
|
||||
|
||||
const maxVal = Math.max(...list.map(d => d.downloads)) || 1
|
||||
const width = 600
|
||||
const height = 240
|
||||
const paddingLeft = 45
|
||||
const paddingRight = 25
|
||||
const paddingTop = 20
|
||||
const paddingBottom = 40
|
||||
|
||||
const chartWidth = width - paddingLeft - paddingRight
|
||||
const chartHeight = height - paddingTop - paddingBottom
|
||||
|
||||
return list.map((item, idx) => {
|
||||
const x = paddingLeft + (idx / (list.length - 1)) * chartWidth
|
||||
const y = paddingTop + (1 - item.downloads / maxVal) * chartHeight
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
tag: item.tag,
|
||||
downloads: item.downloads,
|
||||
maxVal,
|
||||
chartHeight,
|
||||
paddingTop,
|
||||
transform: "rotate(15 " + Math.round(x) + " 222)",
|
||||
tooltipLeft: (x - 55) + "px",
|
||||
tooltipTop: (y - 48) + "px"
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const gridLines = computed(() => {
|
||||
if (chartPoints.value.length === 0) return []
|
||||
const maxVal = chartPoints.value[0].maxVal
|
||||
const height = 240
|
||||
const paddingTop = 20
|
||||
const paddingBottom = 40
|
||||
const chartHeight = height - paddingTop - paddingBottom
|
||||
|
||||
const steps = 4
|
||||
const lines = []
|
||||
for (let i = 0; i !== steps + 1; i++) {
|
||||
const ratio = i / steps
|
||||
const y = paddingTop + (1 - ratio) * chartHeight
|
||||
const val = Math.round(ratio * maxVal)
|
||||
lines.push({
|
||||
y,
|
||||
label: Math.max(val, 1000) === val ? (val / 1000).toFixed(1) + 'k' : val.toString()
|
||||
})
|
||||
}
|
||||
return lines
|
||||
})
|
||||
|
||||
const linePath = computed(() => {
|
||||
const pts = chartPoints.value
|
||||
if (pts.length === 0) return ''
|
||||
return pts.reduce((path, pt, idx) => {
|
||||
return path + (idx === 0 ? `M ${pt.x} ${pt.y}` : ` L ${pt.x} ${pt.y}`)
|
||||
}, '')
|
||||
})
|
||||
|
||||
const areaPath = computed(() => {
|
||||
const pts = chartPoints.value
|
||||
if (pts.length === 0) return ''
|
||||
const startX = pts[0].x
|
||||
const endX = pts[pts.length - 1].x
|
||||
const baselineY = 200 // height - paddingBottom
|
||||
return linePath.value + ` L ${endX} ${baselineY} L ${startX} ${baselineY} Z`
|
||||
})
|
||||
|
||||
// 过滤搜索并排序的所有版本(列表显示)
|
||||
const filteredStats = computed(() => {
|
||||
const query = searchQuery.value.trim().toLowerCase()
|
||||
let list = [...pullStatsList.value]
|
||||
if (query) {
|
||||
list = list.filter(item => item.tag.toLowerCase().includes(query))
|
||||
}
|
||||
return list.sort((a, b) => {
|
||||
if (a.tag === 'latest') return -1
|
||||
if (b.tag === 'latest') return 1
|
||||
|
||||
const va = parseVersion(a.tag)
|
||||
const vb = parseVersion(b.tag)
|
||||
|
||||
if (va.major !== vb.major) return vb.major - va.major
|
||||
if (va.minor !== vb.minor) return vb.minor - va.minor
|
||||
if (va.patch !== vb.patch) return vb.patch - va.patch
|
||||
|
||||
if (!va.suffix && vb.suffix) return -1
|
||||
if (va.suffix && !vb.suffix) return 1
|
||||
return vb.suffix.localeCompare(va.suffix)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
# 镜像下载量统计
|
||||
|
||||
本页面展示 GitHub Container Registry 上任务池(`ghcr.io/engigu/taskpool`)各版本镜像的 Pull(下载)数量统计。数据在文档部署时自动更新。
|
||||
|
||||
<div class="update-time-box">
|
||||
<span>数据更新时间:</span>
|
||||
<strong>{{ formattedUpdateTime }}</strong>
|
||||
</div>
|
||||
|
||||
<div class="stats-container">
|
||||
<div class="chart-sectioncard">
|
||||
<h3>主版本下载量趋势折线图</h3>
|
||||
<div class="line-chart-wrapper">
|
||||
<svg viewBox="0 0 600 240" class="trend-svg">
|
||||
<defs>
|
||||
<linearGradient id="chart-grad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="var(--vp-c-brand-1)" stop-opacity="0.25"></stop>
|
||||
<stop offset="100%" stop-color="var(--vp-c-brand-1)" stop-opacity="0.0"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g stroke="var(--vp-c-divider)" stroke-dasharray="3,3" stroke-width="1">
|
||||
<line v-for="grid in gridLines" :key="grid.y" x1="45" :y1="grid.y" x2="575" :y2="grid.y"></line>
|
||||
</g>
|
||||
<g fill="var(--vp-c-text-3)" font-size="11" font-family="var(--vp-font-family-base)" text-anchor="end">
|
||||
<text v-for="grid in gridLines" :key="grid.y" x="38" :y="grid.y + 4">{{ grid.label }}</text>
|
||||
</g>
|
||||
<path :d="areaPath" fill="url(#chart-grad)"></path>
|
||||
<path :d="linePath" fill="none" stroke="var(--vp-c-brand-1)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
<g>
|
||||
<circle
|
||||
v-for="(pt, idx) in chartPoints"
|
||||
:key="idx"
|
||||
:cx="pt.x"
|
||||
:cy="pt.y"
|
||||
r="5"
|
||||
fill="var(--vp-c-bg)"
|
||||
stroke="var(--vp-c-brand-1)"
|
||||
stroke-width="2"
|
||||
class="chart-dot"
|
||||
@mouseenter="activePoint = pt"
|
||||
@mouseleave="activePoint = null"
|
||||
></circle>
|
||||
</g>
|
||||
<g fill="var(--vp-c-text-2)" font-size="11" font-family="var(--vp-font-family-base)" text-anchor="middle">
|
||||
<text
|
||||
v-for="(pt, idx) in chartPoints"
|
||||
:key="idx"
|
||||
:x="pt.x"
|
||||
y="222"
|
||||
:transform="pt.transform"
|
||||
>
|
||||
{{ pt.tag }}
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
<div v-if="activePoint" class="chart-tooltip" :style="{ left: activePoint.tooltipLeft, top: activePoint.tooltipTop }">
|
||||
<span class="tooltip-tag">{{ activePoint.tag }}</span>
|
||||
<span class="tooltip-val">{{ activePoint.downloads.toLocaleString() }} Pulls</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-sectioncard">
|
||||
<div class="table-header-control">
|
||||
<h3>所有版本下载数据</h3>
|
||||
<input type="text" v-model="searchQuery" placeholder="搜索版本标签..." class="search-input" />
|
||||
</div>
|
||||
<div class="table-wrapper">
|
||||
<table class="stats-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>序号</th>
|
||||
<th>版本标签 (Tag)</th>
|
||||
<th style="text-align: right;">下载量 (Pulls)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, idx) in filteredStats" :key="item.tag">
|
||||
<td>{{ idx + 1 }}</td>
|
||||
<td class="tag-name"><code>{{ item.tag }}</code></td>
|
||||
<td style="text-align: right; font-weight: 500;">{{ item.downloads.toLocaleString() }}</td>
|
||||
</tr>
|
||||
<tr v-if="filteredStats.length === 0">
|
||||
<td colspan="3" style="text-align: center; color: var(--vp-c-text-3); padding: 2rem 0;">没有找到匹配的版本</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style scoped>
|
||||
.stats-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.update-time-box {
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-top: -0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.update-time-box strong {
|
||||
color: var(--vp-c-brand-1);
|
||||
font-family: var(--vp-font-family-mono);
|
||||
}
|
||||
|
||||
.chart-sectioncard, .table-sectioncard {
|
||||
background-color: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-border);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chart-sectioncard h3, .table-sectioncard h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.line-chart-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.trend-svg {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.chart-dot {
|
||||
cursor: pointer;
|
||||
transition: r 0.2s, stroke-width 0.2s;
|
||||
}
|
||||
|
||||
.chart-dot:hover {
|
||||
r: 7;
|
||||
stroke-width: 3px;
|
||||
}
|
||||
|
||||
.chart-tooltip {
|
||||
position: absolute;
|
||||
background-color: var(--vp-c-bg-elv);
|
||||
border: 1px solid var(--vp-c-brand-1);
|
||||
border-radius: 4px;
|
||||
padding: 0.35rem 0.6rem;
|
||||
font-size: 0.75rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
box-shadow: var(--vp-shadow-3);
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
min-width: 110px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tooltip-tag {
|
||||
font-weight: 600;
|
||||
font-family: var(--vp-font-family-mono);
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.tooltip-val {
|
||||
color: var(--vp-c-brand-1);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.table-header-control {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.table-header-control h3 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
background-color: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-border);
|
||||
border-radius: 6px;
|
||||
padding: 0.4rem 0.75rem;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-1);
|
||||
outline: none;
|
||||
min-width: 200px;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
border-color: var(--vp-c-brand-1);
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid var(--vp-c-border);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.stats-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.stats-table th, .stats-table td {
|
||||
padding: 0.6rem 0.8rem;
|
||||
font-size: 0.85rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--vp-c-border);
|
||||
}
|
||||
|
||||
.stats-table th {
|
||||
background-color: var(--vp-c-bg-mute);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.stats-table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.tag-name code {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,23 @@
|
||||
# 脚本管理
|
||||
|
||||
脚本管理提供了taskpool的在线文件资源浏览器和编辑器。
|
||||
|
||||
## 资源管理器
|
||||
|
||||
- **目录树视图**:清晰层级化展示位于 `scripts` 目录下的所有子文件夹及文件。
|
||||
- **动态预览**:支持常见的文本文件预览。
|
||||
- **文件操作**:
|
||||
- **创建/重命名**:在浏览器中直接对脚本文件进行管理和修订。
|
||||
- **极速上传**:支持直接在 Web 端上传单文件或进行多选拖拽上传。
|
||||
- **在线解包**:支持一键解压缩 `.zip` 包,大大优化了脚本部署流程。
|
||||
|
||||
## 在线编辑器
|
||||
|
||||
- **语法高亮**:集成了现代代码编辑器,完美支持 JavaScript、Python、Shell、Go、TypeScript 等主流开发语言。
|
||||
- **编辑器增强**:支持常见的代码查找与替换、自动缩进和括号匹配。
|
||||
- **一键保存**:编辑后的内容将实时写入服务器端物理存储,配合 `定时任务` 可快速生效。
|
||||
|
||||
## 权限控制
|
||||
|
||||
- **安全防御**:默认只能在指定的 `scripts` 根路径内进行相关文件操作,防止跨目录读取系统敏感文件。
|
||||
- **文件保护**:系统核心配置文件不可在脚本管理器中直接修改。
|
||||
@@ -0,0 +1,25 @@
|
||||
# 仓库同步 (Repo)
|
||||
|
||||
仓库同步允许taskpool直接以 Git 仓库的形式管理和更新脚本库,极大地方便了脚本的大规模分发与自动化部署。
|
||||
|
||||
## 同步源管理
|
||||
|
||||
- **青龙 (QL) 指令解析**:如果您曾经是青龙面板的用户,您可以直接粘贴类似的 `ql repo <url> <whitelist> <blacklist> <dependence> <branch>` 指令,系统将自动提取各项参数。
|
||||
> [!IMPORTANT]
|
||||
> **依赖管理说明**:由于该面板采用基于 Mise 的多版本语言管理系统,与青龙的全局环境不同,系统 **无法通过 `dependence` 字段自动安装依赖**。用户需要手动前往「语言依赖」页面,或者在终端中自己执行依赖,在对应的运行中安装脚本所需的依赖包。
|
||||
- **Git 源管理**:支持从 **GitHub**, **GitLab**, **Gitee** 等主流代码托管平台同步脚本。
|
||||
- **SSH/Token 访问**:支持私有仓库的访问,可以在环境变量中配置对应的 Git 鉴权秘钥。
|
||||
|
||||
## 扫描与注册规则
|
||||
|
||||
- **自动解析配置**:在同步代码至本地物理磁盘后,面板将深度扫描每个 `.js` 或 `.py` 文件。
|
||||
- **配置探测**:
|
||||
- `new Env('任务名称')`:解析 JavaScript 脚本定义的展示名。
|
||||
- `cron "0 0 * * *"`:自动提取文件头部的 Cron 注释规则。
|
||||
- **白名单/黑名单**:通过正则表达式(Regex)过滤哪些子目录或特定命名的文件需要被注册为定时任务。
|
||||
|
||||
## 增量同步
|
||||
|
||||
- **Git 离线拉取**:支持增量更新,仅下载变更部分,降低带宽压力。
|
||||
- **分支切换**:支持指定任意分支进行同步,方便用户在生产与测试环境间切换脚本源。
|
||||
- **稀疏检出 (Sparse Checkout)**:如果仓库过于庞大,您可以配置仅同步特定的子文件夹以节省存储空间。
|
||||
@@ -0,0 +1,36 @@
|
||||
# 定时任务
|
||||
|
||||
定时任务是taskpool的核心模块,支持对各类多语言脚本、命令进行精细化执行管理。
|
||||
|
||||
## 任务属性
|
||||
|
||||
- **任务名称**:给任务起一个直观的名称,例如 `每日签到任务`。
|
||||
- **Cron 表达式**:支持标准 cron 规则(分、时、日、月、周)。
|
||||
- **脚本路径**:关联到 `scripts` 目录下的具体脚本文件或直接输入 Shell 命令。
|
||||
- **执行终端**:允许选择运行在 `本机` 或是指定的 `远程 Agent` 节点。
|
||||
- **任务超时**:设定单次运行的最大时长,防止僵尸进程占用资源。
|
||||
|
||||
## 管理操作
|
||||
|
||||
- **启动/停止**:手动控制任务的状态,支持一键切换自动调度与临时暂停。
|
||||
- **立即执行**:不等待 Cron 触发,即刻拉起脚本运行。
|
||||
- **查看日志**:直接跳转到与该任务关联的最新执行历史详情。
|
||||
- **批量管理**:支持对选中的多个任务执行批量禁用、启用或删除动作。
|
||||
|
||||
## 交互设计
|
||||
|
||||
- **预设 Cron 规则**:在编辑任务时,提供常用的 `每分钟执行`、`每小时整点` 等预设样式。
|
||||
- **下次触发预测**:实时计算并展示任务下一次执行的北京时间,帮助验证调度逻辑是否符合预期。
|
||||
|
||||
## 特殊任务类型
|
||||
|
||||
除了标准的 Cron 定时触发,taskpool还支持以下特殊触发场景:
|
||||
|
||||
### 开机启动任务 (`taskpool_startup`)
|
||||
|
||||
当您在定时规则(Schedule)中填写 `taskpool_startup` 时,该任务将被标记为**系统启动任务**。
|
||||
- **触发时机**: 面板主进程启动或重启完成后立即执行。
|
||||
- **应用场景**:
|
||||
- 自动挂载磁盘或网络共享。
|
||||
- **环境预热**: 例如安装 PHP 编译依赖(参考 [PHP 编译依赖说明](languages.md#php-环境特别说明))。建议命令: `bash example/deps/install_php_env_deps.sh`
|
||||
- 启动自定义的后台常驻服务。
|
||||
@@ -0,0 +1,15 @@
|
||||
# 终端命令
|
||||
|
||||
终端命令模块(Terminal)允许用户在 Web 端直接与服务器的 Shell 环境进行交互。
|
||||
|
||||
## 实时交互
|
||||
|
||||
- **WebSocket 双工连接**:不仅是单向的命令发送,您可以获得一个可以输入交互(如 `yes/no` 確認、`npm init` 交互等)的伪终端(PTY)。
|
||||
- **实时输出回传**:秒级显示命令的执行结果,支持 ANSI 转义序列以正确渲染终端样式与彩色文本。
|
||||
- **自定义工作目录**:可以选择在哪一个文件夹(如 `scripts` 或系统根目录)下启动终端。
|
||||
|
||||
|
||||
## 常用指令
|
||||
|
||||
- `ls -la`:查看当前目录详细文件列表。
|
||||
- `git status`:在 `scripts` 目录下查看仓库 Git 定位状态。
|
||||
@@ -0,0 +1,62 @@
|
||||
# 功能特性
|
||||
|
||||
taskpool不仅提供基础的脚本执行功能,还集成了众多的实用工具和管理模块。
|
||||
|
||||
## 数据仪表
|
||||
|
||||
- **运行状态概览**:实时展示系统运行状态、任务执行统计及资源消耗。
|
||||
- **动态图表**:通过直观的图表展示任务成功率、并发趋势及系统负载。
|
||||
|
||||
## 定时任务管理
|
||||
|
||||
- **标准 Cron 表达式**:支持高度灵活的调度配置。
|
||||
- **控制台快捷键**:常用规则一键选择。
|
||||
- **手动触发执行**:支持临时执行任务。
|
||||
- **任务超时控制**:通过配置 `timeout` 参数,系统会自动隔离并中止长时间运行的任务。
|
||||
|
||||
## 远程分布式执行 (Agents)
|
||||
|
||||
- **子节点管理**:支持注册多个远程 Agent 节点,实现分布式任务分发。
|
||||
- **跨平台支持**:Agent 可部署在 Linux、Windows、macOS 等不同系统,覆盖异构执行环境。
|
||||
|
||||
## 脚本文件管理
|
||||
|
||||
- **在线代码编辑器**:集成了现代代码编辑器,支持语法高亮和编辑。
|
||||
- **文件树形结构**:直观展示项目内所有文件。
|
||||
- **文件上传与解压**:支持单文件、多文件上传和对 ZIP 压缩包的在线解压。
|
||||
- **文件管理**:支持在线进行创建、重命名、移动和删除操作。
|
||||
|
||||
## 在线终端
|
||||
|
||||
- **WebSocket 实时终端**:支持常用的 Shell 命令。
|
||||
- **命令输出实时推流**:实时查看脚本运行的物理设备输出。
|
||||
|
||||
## 执行日志
|
||||
|
||||
- **任务执行历史**:记录每次运行的状态(成功/失败/超时)。
|
||||
- **执行耗时统计**:自动统计任务耗时,辅助性能优化。
|
||||
- **日志压缩存储**:通过对旧日志进行自动清理和压缩,规避存储空间占用问题。
|
||||
|
||||
## 环境变量管理 (Secret)
|
||||
|
||||
- **机密性管理**:对敏感字段(如脚本 Key、DB 密码)进行脱敏显示和加密存储。
|
||||
- **全局环境隔离**:在不同脚本运行期间动态注入,确保持久化和隔离。
|
||||
|
||||
## 消息推送与系统通知
|
||||
|
||||
- **原生内置分发**:集成了企业微信、钉钉、飞书、Telegram、Bark、邮件等十余种主流渠道。
|
||||
- **多事件灵活通知**:您可以配置「任务失败」、「服务下线」、「登录安全报警」等事件通知条件。
|
||||
- **API 示例**:系统自动生成各种编程语言的一键集成代码片段,方便用户脚本集成。
|
||||
- **消息日志**:详细记录每条推送消息的状态、接收人和尝试发送的日志,方便故障排查。
|
||||
|
||||
## 仓库任务同步
|
||||
|
||||
- **青龙指令兼容**:支持直接粘贴 `ql repo` 指令快速创建同步任务。
|
||||
- **脚本自动注册**:自动扫描同步目录下的脚本文件,解析其中的 `new Env()` 名称和 `cron` 表达式。
|
||||
- **灵活筛选规则**:支持通过正则表达式配置白名单、黑名单,精确控制哪些脚本需要转化为面板任务。
|
||||
- **版本控制集成**:基于 Git 进行增量同步,支持分支切换和稀疏检出(Sparse Checkout)。
|
||||
|
||||
## 系统设置
|
||||
|
||||
- **数据备份与恢复**:支持全量数据的本地导出和一键导入恢复。
|
||||
- **页面设置**:自定义站点标题、标语和分页显示逻辑。
|
||||
@@ -0,0 +1,134 @@
|
||||
# 前端定制 (WebUI)
|
||||
|
||||
taskpool支持完全接管和替换默认系统面板界面。你可以开发自己专属的前端主题,甚至添加自定义的前端交互功能,并打包为独立的 WebUI 资源包上传至系统应用。
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **安全与一致性维护声明**:
|
||||
> 更换前端包后,系统无法自动保障自定义前端的安全性,亦无法确保其与后续更新的后端 API 接口始终保持一致。**自定义前端包的更新、向后兼容维护与漏洞修复需完全由该前端资源提供者(或开发者)负责**。
|
||||
|
||||
---
|
||||
|
||||
## 快速使用
|
||||
|
||||
### 1. 网页端上传与切换
|
||||
1. 进入系统后,点击导航栏的 **系统设置**。
|
||||
2. 切换到 **前端定制** 面板。
|
||||
3. 点击右上角的 **上传前端资源包**,选择你打包好的 `.zip`、`.tar.gz` 或 `.tgz` 格式的前端资源包。
|
||||
4. 上传成功后,列表会显示该包的信息(名称、版本、作者、状态等)。
|
||||
5. 点击操作栏中的 **启用** 按钮,系统将自动重载并切换至你的自定义前端包。
|
||||
|
||||
> [!WARNING]
|
||||
> 自定义前端包若存在 Bug 或打包不完整可能导致界面白屏。如果不慎应用了错误或不兼容的包,请使用下方命令行工具恢复。
|
||||
|
||||
### 2. 命令行 (CLI) 运维
|
||||
当界面因异常白屏无法访问时,可以进入taskpool容器/服务器终端,使用 `taskpool webui` 命令一键管理或恢复:
|
||||
|
||||
- **一键恢复默认内置界面**:
|
||||
```bash
|
||||
taskpool webui reset
|
||||
```
|
||||
- **查看已安装的资源包列表**:
|
||||
```bash
|
||||
taskpool webui list
|
||||
```
|
||||
- **手动切换/启用前端包**:
|
||||
```bash
|
||||
taskpool webui set <包名>
|
||||
```
|
||||
- **删除指定的前端包**:
|
||||
```bash
|
||||
taskpool webui delete <包名>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 开发自定义前端
|
||||
|
||||
taskpool的前端架构是完全解耦的。你可以选择以下两种方式之一来定制专属前端:
|
||||
|
||||
### 方式一:基于现有代码二次开发(推荐)
|
||||
如果你只是想修改部分样式、布局,或者在原有功能基础上增加新特性,最简单的方式是 **Fork `taskpool` 项目**。
|
||||
1. Fork 本项目并克隆代码到本地。
|
||||
2. 直接在项目的 `web/` 目录下,对现有的 Vue3 源码进行修改与定制。
|
||||
3. 修改完成后,利用项目自带的 Makefile 打包命令(见下方说明)一键将你的修改编译为独立的 WebUI 资源包。
|
||||
|
||||
### 方式二:从零开始全新开发
|
||||
如果你想用自己熟悉的技术栈(如 React, Angular,或者是纯静态的 HTML/JS)完全重写整个面板,这也是完全支持的!你只需要按照下方的核心规范进行开发和打包即可。
|
||||
### 1. 核心校验规则
|
||||
taskpool后端提取并启用前端资源时,会执行以下强校验:
|
||||
1. **压缩包根目录下必须包含 `index.html`**:作为单页应用 (SPA) 的静态入口文件。
|
||||
2. **压缩包根目录下必须包含 `uimanifest.json`**:声明该前端包的元数据信息。
|
||||
|
||||
### 2. 配置文件 `uimanifest.json` 规范
|
||||
在前端打包产物的根目录下(与 `index.html` 同级),必须创建一个 `uimanifest.json` 文件。格式示例如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "custom-neon-theme",
|
||||
"version": "1.0.2",
|
||||
"author": "YourName",
|
||||
"description": "taskpool霓虹暗黑风定制前端主题",
|
||||
"min_panel_version": "1.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
*注:`name` 字段不能设置为 `"default"`(default 被保留作为内置前端的系统标识)。*
|
||||
|
||||
### 3. API 请求地址与开发环境代理
|
||||
在独立开发自定义前端时,需要配置请求与后端的通信地址及代理:
|
||||
|
||||
- **后端默认服务地址与端口**:
|
||||
taskpool后端服务默认运行在端口 `8052` 上,本地调试 API 的基础 URL 通常为:
|
||||
`http://127.0.0.1:8052/api/v1`
|
||||
|
||||
- **本地开发环境代理配置(以 Vite 为例)**:
|
||||
为了避免跨域问题(CORS),推荐在前端开发服务器中设置代理。在 `vite.config.ts` 中配置示例如下:
|
||||
```typescript
|
||||
export default defineConfig({
|
||||
server: {
|
||||
proxy: {
|
||||
'/api/v1': {
|
||||
target: 'http://127.0.0.1:8052', // 本地运行的taskpool后端地址
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
- **生产环境线上适配(相对路径)**:
|
||||
前端包部署生效后,与后端处于同端口同域名下。后端会在返回的 `index.html` 的 `<head>` 中自动注入以下配置变量:
|
||||
```html
|
||||
<script>
|
||||
window.__BASE_URL__ = ""; // 部署子路径前缀 (根据实际反代配置)
|
||||
window.__API_VERSION__ = "/api/v1"; // API 接口版本前缀
|
||||
</script>
|
||||
```
|
||||
建议在封装 Axios 或 Fetch 时,直接通过浏览器环境变量拼接相对路径作为 API 地址:
|
||||
```typescript
|
||||
const baseURL = `${window.location.origin}${window.__BASE_URL__ || ''}${window.__API_VERSION__ || '/api/v1'}`;
|
||||
```
|
||||
|
||||
- **接口定义与类型参考**:
|
||||
默认系统中已经定义好了所有的后端 API 接口签名、传参格式以及 TS 类型声明。你在二次开发或自定义前端时,可以直接参考项目源码中的前端接口定义文件: `web/src/api/index.ts`。
|
||||
|
||||
---
|
||||
|
||||
## 打包前端资源包(现成)
|
||||
|
||||
你可以利用taskpool项目自带的 `Makefile` 脚本,在现在的前端页面进行修改,将开发好的前端项目快速编译打包成标准的 `.tar.gz` 前端资源包, 自己使用或者分享使用。
|
||||
|
||||
### 使用 Makefile 打包
|
||||
|
||||
在项目根目录下,运行以下指令(参数必须填写完整):
|
||||
|
||||
```bash
|
||||
make pack-webui NAME=neon-theme VERSION=1.0.2 AUTHOR=MyName DESC="霓虹定制主题包"
|
||||
```
|
||||
|
||||
该指令会自动执行以下步骤:
|
||||
1. 进入 `web/` 目录并安装依赖;
|
||||
2. 编译构建前端静态资源(默认输出到 `web/dist`);
|
||||
3. 在 `web/dist` 中自动按参数生成校验所需的 `uimanifest.json`;
|
||||
4. 将该目录下所有文件使用 `tar` 命令进行 gzip 压缩打包;
|
||||
5. 输出归档文件在项目根目录的 `bin/webui-neon-theme-1.0.2.tar.gz`,此包即可直接在面板中上传安装。
|
||||
Reference in New Issue
Block a user