# 公开定时任务 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/ ``` 例如 `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:///api/public/scheduled-tasks?limit=50" # 查看任务的执行记录 curl -s "https:///api/public/scheduled-tasks//runs" # 下载某次执行 curl -L -o report.zip \ "https:///api/public/scheduled-tasks/runs//download" ``` ### Python ```python import requests base = "https:///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 ``` --- ## 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 | null | 下次执行时间(ISO 8601) | | `last_run_at` | string | null | 上次执行时间 | | `last_status` | string | null | 上次执行状态(`succeeded` / `failed` / `running` / `pending` / `…`) | | `published` | bool | 是否被发布到广场 | ### `run` 字段 | 字段 | 类型 | 说明 | |---|---|---| | `id` | string | 执行 ID | | `task_id` | string | 所属任务 ID | | `scheduled_for` | string | 原定执行时间 | | `started_at` | string | null | 实际开始时间 | | `finished_at` | string | null | 完成 / 失败时间 | | `status` | string | `pending` / `running` / `succeeded` / `failed` | | `error` | string | null | 失败描述 | | `retry_count` | int | null | 重试次数 | | `result` | object | 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`