This commit is contained in:
2026-06-15 23:35:52 +08:00
11 changed files with 314 additions and 110 deletions
+25
View File
@@ -0,0 +1,25 @@
/**
* 时间工具 — 北京时间 (Asia/Shanghai, UTC+8)
*
* 后端存储的日期时间均为 UTCnaive datetime),
* 前端统一转换为北京时间展示。
*/
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone'
dayjs.extend(utc)
dayjs.extend(timezone)
const TZ = 'Asia/Shanghai'
/**
* 将 UTC 时间戳格式化为北京时间字符串
* @param {string|Date|null} ts ISO 时间字符串或 Date 对象
* @param {string} fmt dayjs 格式模板,默认 'MM-DD HH:mm'
* @returns {string} 格式化后的北京时间
*/
export function beijing(ts, fmt = 'MM-DD HH:mm') {
if (!ts) return '—'
return dayjs.utc(ts).tz(TZ).format(fmt)
}
+1 -1
View File
@@ -42,7 +42,7 @@
<script setup>
import { ref, onMounted } from 'vue'
import dayjs from 'dayjs'
import { beijing } from '../utils/time.js'
import { listAlerts, acknowledgeAlert } from '../api/index.js'
const alerts = ref([])
+116 -28
View File
@@ -152,7 +152,7 @@
<script setup>
import { ref, onMounted, computed } from 'vue'
import dayjs from 'dayjs'
import { beijing } from '../utils/time.js'
import { getDashboardSummary, getDashboardTasks, getSystemConfig } from '../api/index.js'
const summary = ref({
@@ -170,62 +170,150 @@ const baseUrl = ref(window.location.origin)
const curlScript = computed(() => {
const b = baseUrl.value
return `# AI Agent 执行以下命令注册自己:
return `# TaskPulse 接入指引 — 请 AI Agent 执行以下步骤
你正在被接入 TaskPulse(定时任务监控系统),完成后你将拥有统一的运行状态看板和超时告警能力。请按步骤操作,无需用户额外干预。
## 第 1 步:注册你自己
向 TaskPulse 注册你的 Agent 身份,系统会返回专属 API Key:
curl -X POST ${b}/api/agents \\
-H "Content-Type: application/json" \\
-d '{"name": "my-agent", "description": "我的 AI Agent"}'
-d '{"name": "<你的名字>", "description": "<你的职责描述>"}'
# 保存返回的 api_key,后续汇报用
响应中"api_key"字段即你的凭证,请妥善保存,后续所有请求都需要通过
Authorization: Bearer <api_key> 鉴权。
# 注册定时任务(替换 YOUR_API_KEY):
curl -X POST "${b}/api/tasks?agent_id=<ID>" \\
## 第 2 步:注册定时任务
逐一注册你管理的每一个定时任务,描述清楚执行周期和用途:
curl -X POST "${b}/api/tasks?agent_id=<AGENT_ID>" \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer <API_KEY>" \\
-d '{"name": "任务名称", "cron_expression": "*/5 * * * *", "grace_period": 300}'
如果你有多个任务,推荐使用批量注册接口,一次完成:
curl -X POST ${b}/api/agents/register-with-tasks \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer <YOUR_API_KEY>" \\
-d '{
"name": "data-sync",
"cron_expression": "*/5 * * * *",
"grace_period": 300
"name": "<你的名字>",
"tasks": [
{"name": "sync-data", "cron_expression": "*/5 * * * *"},
{"name": "daily-report", "cron_expression": "0 9 * * *"}
]
}'
# 执行后汇报
## 第 3 步:修改你的代码 — 每次执行后主动汇报
这是最关键的一步。修改你的任务执行逻辑,在每次执行完毕后(无论成功还是失败)主动向 TaskPulse 汇报结果,这样看板才能展示实时状态。
在你的任务执行代码末尾,加上以下逻辑:
# 任务执行成功后立即调用
curl -X POST "${b}/api/tasks/<TASK_ID>/executions" \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer <YOUR_API_KEY>" \\
-d '{
"status": "success",
"duration_ms": 1500,
"log": "任务执行完毕"
}'`
-H "Authorization: Bearer <API_KEY>" \\
-d '{"status": "success", "duration_ms": <耗时毫秒>, "log": "<执行日志>"}'
# 任务执行失败时调用
curl -X POST "${b}/api/tasks/<TASK_ID>/executions" \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer <API_KEY>" \\
-d '{"status": "failed", "duration_ms": <耗时>, "log": "<日志>", "error_message": "<错误信息>"}'
## 第 4 步:保持活跃
定期发送心跳,让系统知道你仍在运行:
curl -X POST ${b}/api/agents/<AGENT_ID>/heartbeat \\
-H "Authorization: Bearer <API_KEY>"
---
完成以上步骤后,前往 TaskPulse 看板(本页面)查看你的运行状态和执行历史。如配置了通知渠道,任务超时未执行时系统会自动告警。`
})
const pythonScript = computed(() => {
const b = baseUrl.value
return `import requests
return `# TaskPulse 接入指引 — 请 AI Agent 执行以下步骤
你正在被接入 TaskPulse(定时任务监控系统),完成后你将拥有统一的运行状态看板和超时告警能力。请按步骤操作,无需用户额外干预。
## 第 1 步:注册你自己
向 TaskPulse 注册你的 Agent 身份,系统会返回专属 API Key:
import requests
BASE = "${b}"
# 1. AI Agent 注册自己
resp = requests.post(f"{BASE}/api/agents", json={
"name": "my-agent",
"description": "我的 AI Agent"
"name": "<你的名字>",
"description": "<你的职责描述>"
})
agent = resp.json()
API_KEY = agent["api_key"] # 保存此 Key
API_KEY = agent["api_key"] # 保存此 Key,后续所有请求通过 Bearer 鉴权
AGENT_ID = agent["id"]
# 2. 注册定时任务
## 第 2 步:注册定时任务
逐一注册你管理的每一个定时任务,描述清楚执行周期和用途:
resp = requests.post(f"{BASE}/api/tasks",
params={"agent_id": AGENT_ID},
headers={"Authorization": f"Bearer {API_KEY}"},
json={"name": "data-sync", "cron_expression": "*/5 * * * *"}
json={"name": "sync-data", "cron_expression": "*/5 * * * *", "grace_period": 300}
)
task = resp.json()
TASK_ID = task["id"]
# 3. 每次执行后汇报
requests.post(f"{BASE}/api/tasks/{TASK_ID}/executions",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"status": "success", "duration_ms": 1500, "log": "done"})`
如果你有多个任务,推荐使用批量注册接口,一次完成:
resp = requests.post(f"{BASE}/api/agents/register-with-tasks",
json={
"name": "<你的名字>",
"tasks": [
{"name": "sync-data", "cron_expression": "*/5 * * * *"},
{"name": "daily-report", "cron_expression": "0 9 * * *"}
]
}
)
## 第 3 步:修改你的代码 — 每次执行后主动汇报
这是最关键的一步。修改你的任务执行逻辑,在每次执行完毕后(无论成功还是失败)主动向 TaskPulse 汇报结果,这样看板才能展示实时状态。
在你的任务执行代码中,加上以下逻辑:
import time
def run_with_reporting(task_func, task_id, api_key):
try:
start = time.time()
result = task_func() # 你的任务逻辑
elapsed = int((time.time() - start) * 1000)
requests.post(f"{BASE}/api/tasks/{task_id}/executions",
headers={"Authorization": f"Bearer {api_key}"},
json={"status": "success", "duration_ms": elapsed, "log": str(result)})
except Exception as e:
requests.post(f"{BASE}/api/tasks/{task_id}/executions",
headers={"Authorization": f"Bearer {api_key}"},
json={"status": "failed", "duration_ms": 0, "error_message": str(e)})
# 使用示例 — 包裹你现有的任务函数:
run_with_reporting(my_task_function, TASK_ID, API_KEY)
## 第 4 步:保持活跃
定期发送心跳,让系统知道你仍在运行:
requests.post(f"{BASE}/api/agents/{AGENT_ID}/heartbeat",
headers={"Authorization": f"Bearer {API_KEY}"})
---
完成以上步骤后,前往 TaskPulse 看板(本页面)查看你的运行状态和执行历史。如配置了通知渠道,任务超时未执行时系统会自动告警。`
})
onMounted(async () => {
+1 -1
View File
@@ -92,7 +92,7 @@
<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import dayjs from 'dayjs'
import { beijing } from '../utils/time.js'
import { getTask, listExecutions } from '../api/index.js'
const route = useRoute()
+7
View File
@@ -197,6 +197,13 @@ onMounted(loadData)
border-bottom: 1px solid var(--border-color);
}
.section-header h3 { font-size: 15px; font-weight: 600; color: #e0e0f0; margin: 0; }
.section-header.collapsible { cursor: pointer; user-select: none; }
.section-header.collapsible:hover { background: rgba(255,255,255,0.02); }
.section-toggle {
display: flex; align-items: center; gap: 6px;
color: var(--text-muted); font-size: 12px;
}
.section-toggle:hover { color: var(--text-secondary); }
/* Search */
.search-bar {