Files
auto_control/doc/API.md
T

670 lines
14 KiB
Markdown
Raw 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 接口文档
`platform-tools` Web 后台提供 JSON API,所有接口需登录后访问(Flask-Login session 认证)。
**Base URL**:`http://localhost:18050`
**认证方式**:Cookie Session(先 POST `/login` 获取 session cookie,后续请求带上)
**通用响应格式**:
```json
{"ok": true, "data": "..."}
{"ok": false, "error": "错误信息"}
```
---
**权限模型**(v2 起):
- 所有接口需登录;**查看类 GET 接口**(状态/列表/截图)所有登录用户可用
- **写操作按权限位授权**(管理员拥有全部权限):
| 权限位 | 中文 | 覆盖接口 |
|--------|------|---------|
| `tasks` | 任务管理 | 任务/自定义动作/分组的增删改、启停、立即执行 |
| `devices` | 设备控制 | 停止设备、释放占用、清除异常、前台扫描、元素抓取 |
| `apks` | 应用管理 | APK 上传、安装、删除 |
| `logs` | 日志查看 | `GET /api/logs` |
- **用户管理接口仅管理员可用**(普通用户即使被授予业务权限也无法访问)
- 无权限访问返回 `403 {"ok": false, "error": "无权限执行此操作..."}`
- 当前用户权限查询:`GET /api/me`
---
## 1. 认证
### POST /login
用户登录。
**请求**(form-data):
| 参数 | 类型 | 说明 |
|------|------|------|
| username | string | 用户名 |
| password | string | 密码 |
**响应**:成功重定向到 `/`,失败返回登录页(含 error 信息)。
### GET /logout
登出,重定向到登录页。
---
## 2. 页面路由
### GET /
单页应用首页(需登录)。响应头设置 `Cache-Control: no-store` 防止缓存。
### GET /login
登录页面(GET)。
---
## 3. 设备状态
### GET /api/status
获取设备池 + Worker 综合状态(带 5 秒缓存)。
**响应**:
```json
{
"ok": true,
"server_time": 1700000000.0,
"fg_scanning": false,
"fg_last_scan": 1700000000.0,
"devices": [
{
"serial": "192.168.1.100:5555",
"model": "Pixel 6",
"device_name": "测试机1",
"present": true,
"ready": true,
"stf_occupied": false,
"owner": "",
"worker_status": "idle",
"foreground_app": "空闲",
"progress": {"done": 5, "total": 80, "unit": "视频", "action_counts": {"like": 3}},
"current_action": "观看视频 6",
"last_error": "",
"running_job": "",
"task_job": "",
"attempt": 0
}
]
}
```
**worker_status 取值**:`idle` / `connecting` / `running` / `done` / `error` / `failed` / `released`
(权限:设备控制)
手动触发前台 App 扫描(后台异步执行,不打扰设备)。
**响应**:
```json
{"ok": true, "msg": "扫描已启动"}
{"ok": false, "error": "已有扫描在进行中"}
```
### GET /api/devices
返回所有在线设备 serial 列表(供分组表单勾选用)。
**响应**:
```json
{"ok": true, "devices": ["192.168.1.100:5555", "192.168.1.101:5555"]}
```
### GET /api/device/screenshot
获取设备当前画面截图(PNG)。
**参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| serial | string | 设备 serial |
| t | int | 时间戳(避免缓存,前端自动加) |
**响应**:成功返回 `image/png`,失败返回 JSON 错误。
> 用 `adb exec-out screencap -p`,只读操作,任务运行中调用安全。
---
## 4. 任务类型
### GET /api/task_types
返回所有已注册任务类型。
**响应**:
```json
{
"ok": true,
"task_types": [
{
"task_type": "douyin_nurture",
"name": "抖音养号",
"description": "自动观看抖音视频...",
"default_params": {"watch_count": 80, "...": "..."}
},
{
"task_type": "generic_steps",
"name": "通用步骤",
"description": "通过步骤编辑器编排...",
"default_params": {"steps": [...]}
}
]
}
```
### GET /api/actions
返回指定任务类型支持的专属操作。
**参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| task_type | string | 任务类型 |
**响应**:
```json
{
"ok": true,
"actions": [
{"action_type": "like", "name": "点赞", "description": "...", "default_params": {"rate": 0.3}}
]
}
```
---
## 5. 任务计划 CRUD
### GET /api/jobs
列出所有任务计划。
**响应**:
```json
{
"ok": true,
"jobs": [{"id": "abc123", "name": "抖音养号", "task_type": "douyin_nurture",
"next_run": "2026-08-12 09:00", "...": "..."}],
"task_types": [...]
}
```
`next_run`:下次真正执行时间(已按运行窗口跳过窗口外触发点,格式 `YYYY-MM-DD HH:MM`);手动任务/已停用为 `null`。
(权限:任务管理)
创建任务计划。
**请求**(JSON):
```json
{
"name": "抖音养号",
"task_type": "douyin_nurture",
"target": {"mode": "all"},
"params": {"watch_count": 50, "actions": {"like": {"params": {"rate": 0.5}}}},
"schedule": {"mode": "cron", "cron": "0 */2 * * *"},
"retry": {"max_attempts": 3, "delay": 60},
"enabled": true
}
```
**响应**:
```json
{"ok": true, "msg": "任务已创建", "job": {"id": "abc123", "...": "..."}}
```
`schedule` 字段格式:
| 字段 | 说明 |
|------|------|
| `mode` | `once` 手动 / `cron` 定时启动 / `cron_stop` 定时启动+停止 |
| `cron` | 标准 5 段 cron:`分 时 日 月 周`(周 `0`/`7`=周日);如 `0 */2 * * *` 每 2 小时整点 |
| `stop_cron` | (cron_stop 必填)到点停止本任务 worker |
| `window` | 可选,运行窗口 `{"start": "21:00", "end": "09:00"}`(每天重复,支持跨午夜)。窗口外定时触发和手动执行(`POST /api/jobs/:id/run`)均不启动,手动执行返回错误提示 |
(权限:任务管理)
更新任务计划。只需传要更新的字段。
**请求**(JSON):
```json
{"params": {"watch_count": 100}}
```
**响应**:
```json
{"ok": true, "msg": "任务已更新", "job": {"...": "..."}}
```
(权限:任务管理)
删除任务计划。
**响应**:
```json
{"ok": true, "msg": "任务已删除"}
```
(权限:任务管理)
立即执行任务(异步,不阻塞)。
**响应**:
```json
{"ok": true, "msg": "任务 抖音养号 已触发"}
```
(权限:任务管理)
启用/停用任务。
**请求**(JSON):
```json
{"enabled": false}
```
**响应**:
```json
{"ok": true, "msg": "任务已停用"}
```
---
## 6. 设备分组
### GET /api/groups
列出所有分组。
**响应**:
```json
{
"ok": true,
"groups": [
{"name": "A组", "serials": ["192.168.1.100:5555"], "description": "测试组"}
]
}
```
(权限:任务管理)
创建分组。
**请求**(JSON):
```json
{"name": "A组", "serials": ["192.168.1.100:5555"], "description": "测试组"}
```
(权限:任务管理)
更新分组。
**请求**(JSON):
```json
{"serials": ["192.168.1.100:5555", "192.168.1.101:5555"], "description": "更新描述"}
```
(权限:任务管理)
删除分组。
---
## 7. 运行控制
(权限:设备控制)
停止单台设备的 worker(并阻止后续重试)。
**请求**(JSON):
```json
{"serial": "192.168.1.100:5555"}
```
**响应**:
```json
{"ok": true, "msg": "已发送停止信号给 192.168.1.100:5555"}
```
(权限:设备控制)
停止所有运行中的 worker。
**响应**:
```json
{"ok": true, "stopped": ["192.168.1.100:5555", "192.168.1.101:5555"]}
```
(权限:设备控制)
释放当前账户占用的所有 STF 设备(清理用)。
**响应**:
```json
{"ok": true, "released": ["192.168.1.100:5555"]}
```
---
## 8. 用户管理
(仅管理员)
列出所有用户。
**响应**:
```json
{"ok": true, "users": [{"id": 1, "username": "admin", "is_admin": true}]}
```
(仅管理员)
创建用户。
**请求**(JSON):
```json
{"username": "user1", "password": "pass123", "is_admin": false}
```
(仅管理员)
更新用户(修改密码/管理员权限)。
**请求**(JSON):
```json
{"password": "newpass", "is_admin": true}
```
(仅管理员)
删除用户(不能删除 admin 和当前登录用户)。
---
## 9. 日志
(权限:日志查看)
查看日志文件内容。
**参数**:
| 参数 | 类型 | 默认 | 说明 |
|------|------|------|------|
| file | string | `core.log` | 日志文件名 |
| lines | int | 300 | 返回最后 N 行 |
**可选文件**:`core.log` / `task.log` / `web.log` / `action.log`
**响应**:
```json
{
"ok": true,
"content": "2026-08-08 10:00:00 [INFO] [core.worker] ...",
"file": "core.log",
"files": {"core": "core.log", "task": "task.log", "web": "web.log", "action": "action.log"}
}
```
---
## 10. 自定义动作
### GET /api/custom_actions
列出所有自定义动作(步骤打包)。
(权限:任务管理)
创建自定义动作。
**请求**(JSON):
```json
{"name": "登录流程", "icon": "📦", "steps": [{"type": "click", "...": "..."}]}
```
(权限:任务管理)
更新自定义动作。
(权限:任务管理)
删除自定义动作。
---
## 11. 元素抓取(uiauto2)
### GET /api/uiauto/status
探测 uiauto2 本地服务是否运行。
**响应**:
```json
{"ok": true, "running": true}
```
(权限:设备控制)
获取 uiauto2 已连接的设备列表。
**响应**:
```json
{"ok": true, "devices": [{"serial": "192.168.1.100:5555", "model": "Pixel 6"}]}
```
(权限:设备控制)
通过 uiauto2 获取设备截图(JPEG)。
**参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| serial | string | 设备 serial |
**响应**:成功返回 `image/jpeg`,失败返回 JSON 错误。
(权限:设备控制)
获取设备 UI 元素树。
**参数**:
| 参数 | 类型 | 说明 |
|------|------|------|
| serial | string | 设备 serial |
**响应**:
```json
{
"ok": true,
"elements": [
{
"depth": 0,
"name": "android.widget.FrameLayout",
"resource_id": "",
"text": "",
"description": "",
"class": "android.widget.FrameLayout",
"bounds": "[0,0][1080,2400]",
"suggested": {"type": "xpath", "value": "//*"}
}
]
}
```
---
## 12. 应用管理(APK)
### GET /api/apks
列出所有已上传的 APK。
**响应**:
```json
{
"ok": true,
"apks": [
{
"id": "abc123",
"display_name": "抖音",
"package_name": "com.ss.android.ugc.aweme",
"version_name": "25.0.0",
"version_code": 2500,
"size": 104857600,
"upload_time": "2026-08-08 10:00:00"
}
]
}
```
(权限:应用管理)
上传 APK 文件(自动解析包名/版本/应用名)。
**请求**(multipart/form-data):
| 字段 | 类型 | 说明 |
|------|------|------|
| file | file | APK 文件 |
**响应**:
```json
{"ok": true, "apk": {"...": "..."}, "msg": "上传成功: 抖音"}
```
(权限:应用管理)
删除 APK 文件和记录。
(权限:应用管理)
批量安装 APK 到指定设备。
**请求**(JSON):
```json
{"apk_id": "abc123", "serials": ["192.168.1.100:5555", "192.168.1.101:5555"]}
```
**响应**:
```json
{"ok": true, "msg": "开始安装 抖音 到 2 台设备"}
```
### GET /api/apks/install/devices
可安装设备列表:STF 在线设备池 + 本机 adb 设备(**含 USB 有线连接**,serial 无冒号标记 `usb`)。
安装弹窗用此列表,USB 设备安装时跳过 adb connect 直接安装。
**响应**:
```json
{"ok": true, "devices": [
{"serial": "100.100.10.11:5555", "model": "22120RN86C", "source": "stf"},
{"serial": "ZY322ABCDEF", "model": "", "source": "usb"}
]}
```
### GET /api/apks/install/status
获取安装任务实时状态。
**响应**:
```json
{
"ok": true,
"status": {
"apk_name": "抖音",
"finished": false,
"total": 2,
"success": 1,
"failed": 0,
"skipped": 0,
"installing": 1,
"pending": 0,
"items": {
"192.168.1.100:5555": {"name": "Pixel 6", "status": "success", "msg": "安装成功(已验证)"},
"192.168.1.101:5555": {"name": "Pixel 7", "status": "installing", "msg": "正在安装..."}
}
}
}
```
---
## 13. 维护(仅管理员)
维护页两个接口都**仅管理员可用**(普通用户即使有业务权限也访问不了,返回 403)。
### POST /api/stf/restart
一键重启 STF Docker 容器。通过 SSH 到部署机执行 `docker restart`,随后轮询 STF API 确认恢复。
- 目标与容器名:`STF_SSH_TARGET`(默认 `[email protected]`)、`STF_DOCKER_CONTAINER`(默认 `stf`)环境变量配置
- 前置条件:本机可免密 SSH 到部署机
- **有任务在运行时返回 409 拒绝执行**(STF 重启会重置设备占用状态)
- 失败返回 502(SSH 不可达/容器名错误);执行超时返回 408
**响应**:
```json
{"ok": true, "msg": "STF 容器已重启", "detail": "stf: Up 3 seconds", "api_alive": true}
```
### GET /api/adb/devices
维护终端设备列表:本地 adb 已连接(含 offline)+ STF 在线设备池(标记 `stf`)。
供终端设备选择器使用——选中后前端自动附加 `-s <serial>`。
**响应**:
```json
{"ok": true, "devices": [
{"serial": "100.100.10.11:5555", "state": "device"},
{"serial": "100.100.10.13:5555", "state": "offline"},
{"serial": "100.100.10.12:5555", "state": "stf"}
]}
```
### POST /api/adb/cmd
adb 远程终端:用平台 adb 二进制执行任意 adb 命令(20s 超时)。
**请求**(JSON):
```json
{"cmd": "adb -s 100.100.10.11:5555 shell ls /sdcard"}
```
(开头的 `adb` 前缀可省略)
**安全红线**:包含 `kill-server` / `disconnect` 的命令直接拒绝(400)——会断开 STF provider 共享的 adb transport,导致全部设备被 STF 误判离线。
**响应**:
```json
{"ok": true, "stdout": "...", "stderr": "", "code": 0}
```
---
## 14. 步骤测试(仅管理员可触发,需"设备控制"权限)
### POST /api/steps/test
在指定设备上单步试执行(步骤编辑器"测试此步骤"按钮),验证选择器是否命中。
只读连接(adb connect + u2),不占用/释放 STF,与运行中任务互不干扰。
**请求**(JSON):
```json
{
"serial": "100.100.10.11:5555",
"step": {"type": "click", "label": "测试", "params": {"selector_type": "xpath", "selector_value": "//*[@resource-id=\"x\"]"}}
}
```
**响应**:
```json
{"ok": true, "msg": "步骤已执行(测试)", "result": "命中"}
```
`result`:`命中` / `未找到` / `已执行`(无选择器命中语义的步骤)。
无"设备控制"权限返回 403。