Files
吉鑫升andClaude Opus 4.7 d339db4799 feat: 公开定时任务页面、Word 导出、定时任务实时刷新与技能详情重构
- 新增 /public/scheduled-tasks/:taskId 公开只读访问页与对应的
  /api/public/scheduled-tasks 后端路由(无需登录)
- 新增对话整体 / 单条消息 / Markdown 工件 "另存为 Word (.docx)" 能力
- 定时任务列表与运行列表在任务执行中自动轮询刷新,并新增"正在执行"标记
- 定时任务运行消息接口在事件存储为空时回退到 LangGraph checkpoint,
  让正在执行的任务也能立即看到提示词与流式输出
- 技能详情对话框由折叠面板改为 Tab 切换(Detail / SKILL.md),
  并支持 Rendered / Raw 切换、一键复制
- config.yaml 增加 database (MySQL) 与 checkpointer (SQLite) 配置块

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 17:04:58 +08:00

279 lines
7.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 公开定时任务 API
本文档描述用于对接外部系统的**公开只读**定时任务接口,以及配套的公开网页入口。所有 `/api/public/*` 接口都**无需登录**,可以直接调用。
> ⚠️ 任何接入这套接口的系统需要确认:暴露 task / run 列表与正文是符合贵方业务安全要求的。如果不希望全员可见,请走带鉴权的 `/api/scheduled-tasks/*`。
---
## 1. 基础信息
| 项 | 值 |
|---|---|
| 网关基址(开发) | `http://localhost:8001` |
| 网关基址(生产) | 部署到 Nginx 后通常是 `https://<你的域名>` |
| 公开 API 前缀 | `/api/public/scheduled-tasks` |
| 鉴权 | **无需**鉴权(白名单在 `auth_middleware._PUBLIC_PATH_PREFIXES`) |
| 编码 | 请求 / 响应均为 UTF-8,响应类型 `application/json`(下载除外) |
| 错误响应 | 标准 FastAPI 错误体 `{"detail": "..."}`;HTTP 状态码 `404 / 400 / 500` 等 |
公开网页页面:
```
#/public/scheduled-tasks/<task_id>
```
例如 `https://<你的域名>/#/public/scheduled-tasks/8f1d8b9c-...`。
左侧列出该任务所有执行记录,默认打开第一条;右侧默认渲染 Markdown 正文,点击 Tab 可以查看“结果文件”或“元数据”,点击左侧任意记录右侧内容会跟随切换。
---
## 2. 接口列表
### 2.1 列出全部定时任务
```
GET /api/public/scheduled-tasks
```
**Query 参数**
| 名称 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
| `search` | string | 否 | — | 任务名模糊匹配(不区分大小写) |
| `limit` | int | 否 | 200 | 单页数量,1–500 |
| `offset` | int | 否 | 0 | 偏移量,配合 `limit` 分页 |
**响应**
```json
{
"total": 12,
"limit": 200,
"offset": 0,
"tasks": [
{
"task_id": "8f1d8b9c-...",
"name": "每日舆情简报",
"schedule_text": "每天 09:00",
"cron_expr": "0 9 * * *",
"timezone": "Asia/Shanghai",
"enabled": true,
"next_run_at": "2026-05-21T01:00:00+00:00",
"last_run_at": "2026-05-20T01:00:12+00:00",
"last_status": "succeeded",
"published": true
}
]
}
```
> 已脱敏:`user_id`、`creator_email`、`prompt`、`scheduler_thread_id`、`execution_context` 等私有字段不会出现在公开响应里。
### 2.2 获取单个任务元数据
```
GET /api/public/scheduled-tasks/{task_id}
```
**响应**:与上面 `tasks[]` 的元素结构一致;任务不存在返回 `404`。
### 2.3 列出某任务的所有执行记录
```
GET /api/public/scheduled-tasks/{task_id}/runs
```
**Query 参数**
| 名称 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
| `limit` | int | 否 | 50 | 最近执行数量,1–200 |
**响应**
```json
{
"task": { "task_id": "...", "name": "...", "schedule_text": "...", "timezone": "...", "enabled": true },
"total": 7,
"runs": [
{
"id": "run-uuid-...",
"task_id": "8f1d8b9c-...",
"scheduled_for": "2026-05-20T01:00:00+00:00",
"started_at": "2026-05-20T01:00:01+00:00",
"finished_at": "2026-05-20T01:00:12+00:00",
"status": "succeeded",
"error": null,
"retry_count": 0,
"result": {
"title": "2026-05-20 舆情简报",
"content": "# 简报\n\n...",
"format": "markdown",
"files": [
{ "index": 0, "name": "report.md", "mime_type": "text/markdown", "kind": "markdown", "size": 4321 }
],
"created_at": "2026-05-20T01:00:12+00:00"
}
}
]
}
```
> 已脱敏:返回的 `files[]` 不包含服务器绝对路径;客户端通过下标 `index` 调用文件接口。
### 2.4 获取单条执行记录
```
GET /api/public/scheduled-tasks/runs/{run_id}
```
返回单条 run 数据(结构同 2.3 中的 `runs[]` 元素)。
### 2.5 获取单个结果文件的内容(可预览文本直接内联)
```
GET /api/public/scheduled-tasks/runs/{run_id}/files/{file_index}
```
`file_index` 来自 `run.result.files[].index`。
**响应**
```json
{
"index": 0,
"name": "report.md",
"mime_type": "text/markdown",
"kind": "markdown",
"size": 4321,
"previewable": true,
"content": "# 简报\n\n..."
}
```
二进制文件 `previewable=false`、`content=null`,请走 2.6 下载。
### 2.6 下载单个结果文件
```
GET /api/public/scheduled-tasks/runs/{run_id}/files/{file_index}/download
```
返回原始文件二进制流,附带 `Content-Disposition: attachment` 头部。
### 2.7 打包下载整个执行结果
```
GET /api/public/scheduled-tasks/runs/{run_id}/download
```
- 如果该 run **没有附加文件**:直接返回 `result.md`(UTF-8 BOM)。
- 如果有 ≥ 1 个附加文件:返回 ZIP,里面包含:
- `result.md` — 标题 + 正文 Markdown
- 每个生成文件原样
---
## 3. 调用示例
### curl
```bash
# 列出全部任务
curl -s "https://<domain>/api/public/scheduled-tasks?limit=50"
# 查看任务的执行记录
curl -s "https://<domain>/api/public/scheduled-tasks/<task_id>/runs"
# 下载某次执行
curl -L -o report.zip \
"https://<domain>/api/public/scheduled-tasks/runs/<run_id>/download"
```
### Python
```python
import requests
base = "https://<domain>/api/public/scheduled-tasks"
tasks = requests.get(f"{base}", params={"limit": 100, "search": "舆情"}).json()
for task in tasks["tasks"]:
runs = requests.get(f"{base}/{task['task_id']}/runs", params={"limit": 5}).json()
for run in runs["runs"]:
if run.get("result"):
print(task["name"], run["id"], run["result"]["title"])
print(run["result"]["content"][:200])
```
### 直接嵌入 iframe
```html
<iframe src="https://<domain>/#/public/scheduled-tasks/<task_id>"
style="width:100%;height:800px;border:0"></iframe>
```
---
## 4. 状态码
| 状态码 | 含义 |
|---|---|
| 200 | 成功 |
| 400 | 参数错误(如 `limit` 超出范围) |
| 404 | 任务 / 执行 / 文件 不存在 |
| 5xx | 网关 / 后台错误 |
---
## 5. 字段映射快查
### `task` 字段
| 字段 | 类型 | 说明 |
|---|---|---|
| `task_id` | string | 任务 ID |
| `name` | string | 任务名 |
| `schedule_text` | string | 人类可读的执行计划 |
| `cron_expr` | string | 规范化的 cron 表达式 |
| `timezone` | string | 时区 |
| `enabled` | bool | 是否启用 |
| `next_run_at` | string &#124; null | 下次执行时间(ISO 8601) |
| `last_run_at` | string &#124; null | 上次执行时间 |
| `last_status` | string &#124; null | 上次执行状态(`succeeded` / `failed` / `running` / `pending` / `…`) |
| `published` | bool | 是否被发布到广场 |
### `run` 字段
| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | string | 执行 ID |
| `task_id` | string | 所属任务 ID |
| `scheduled_for` | string | 原定执行时间 |
| `started_at` | string &#124; null | 实际开始时间 |
| `finished_at` | string &#124; null | 完成 / 失败时间 |
| `status` | string | `pending` / `running` / `succeeded` / `failed` |
| `error` | string &#124; null | 失败描述 |
| `retry_count` | int &#124; null | 重试次数 |
| `result` | object &#124; null | 执行结果(见下) |
### `result` 字段
| 字段 | 类型 | 说明 |
|---|---|---|
| `title` | string | 结果标题 |
| `content` | string | 主体 Markdown / 文本 |
| `format` | string | `markdown` / `text` / `json` / `mixed` |
| `files[]` | array | 附加文件元数据,含 `index / name / mime_type / kind / size` |
| `created_at` | string | 结果生成时间 |
---
## 6. 实现位置
- 路由实现:[`app/gateway/routers/public_scheduled_tasks.py`](../app/gateway/routers/public_scheduled_tasks.py)
- 公开 URL 白名单:[`app/gateway/auth_middleware.py`](../app/gateway/auth_middleware.py) 中的 `_PUBLIC_PATH_PREFIXES`
- 前端公开页面:[`frontend-web/src/pages/PublicScheduledTaskPage.tsx`](../../../frontend-web/src/pages/PublicScheduledTaskPage.tsx)
- 路由注册:[`frontend-web/src/App.tsx`](../../../frontend-web/src/App.tsx) `/#/public/scheduled-tasks/:taskId`