852 lines
20 KiB
Markdown
852 lines
20 KiB
Markdown
# 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
|
||
|
||
可安装设备列表:设备池在线设备(标记 `pool`)+ 本机 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)。
|
||
设备池管理、远程看屏、adb 终端等集中在"工具"页(页内子分栏)。
|
||
|
||
### GET /api/devices/pool
|
||
|
||
设备池清单(SQLite devices 表),含实时在线状态。**权限**:`devices`。
|
||
|
||
**响应**:
|
||
```json
|
||
{"ok": true, "devices": [
|
||
{"serial": "100.100.10.20:5555", "name": "", "model": "22120RN86C",
|
||
"enabled": true, "online": true, "note": "", "created_at": "2026-08-17 11:10"}
|
||
]}
|
||
```
|
||
|
||
### POST /api/devices/pool/add
|
||
|
||
添加/更新设备(upsert)。**权限**:`devices`。
|
||
**请求**(JSON):`{"serial": "100.100.10.20:5555", "name": "备注", "note": ""}`
|
||
IP:5555 设备添加后立即尝试 adb connect,并后台采集型号(getprop ro.product.model)。
|
||
|
||
### POST /api/devices/pool/toggle
|
||
|
||
启用/停用设备(停用后不参与任务调度)。**权限**:`devices`。
|
||
**请求**(JSON):`{"serial": "...", "enabled": false}`
|
||
|
||
### POST /api/devices/pool/remove
|
||
|
||
从设备池删除(不再参与调度,不影响设备本身)。**权限**:`devices`。
|
||
**请求**(JSON):`{"serial": "..."}`
|
||
|
||
### POST /api/devices/pool/reconnect
|
||
|
||
一键重连:并发 adb connect 池内全部 IP:5555 设备(后台执行),完成后自动批量刷新型号。**权限**:`devices`。
|
||
|
||
### POST /api/devices/pool/refresh_models
|
||
|
||
批量采集池内在线设备的型号(后台执行)。**权限**:`devices`。
|
||
|
||
### GET /api/screen/stream
|
||
|
||
远程看屏:MJPEG 实时画面流(`multipart/x-mixed-replace`)。**权限**:`devices`。
|
||
|
||
`?serial=xxx` 指定设备;浏览器 `<img src>` 直接渲染,客户端断开自动停止。数据源 u2(atx-agent minicap,约 3-6 帧/秒)。
|
||
|
||
### GET /api/screen/thumb
|
||
|
||
大屏缩略图:单张 JPEG(360px 宽,质量 55)。**权限**:`devices`。
|
||
|
||
`?serial=xxx` 指定设备。监控大屏按设备每 ~2.5s 轮询一帧(页面不可见时暂停);
|
||
一次性请求(非流),与任务并发安全(与任务截图同走 u2 minicap)。
|
||
|
||
### GET /wall
|
||
|
||
监控大屏页面(全屏深色控制室风格,登录后可访问):设备卡片网格(缩略图/型号/
|
||
状态/当前动作/进度)、顶部统计与时钟;状态每 5s 刷新、缩略图每 2.5s 轮询。
|
||
20 台设备整体开销约 0.2 核 CPU + 100KB/s 带宽,普通电脑无压力。
|
||
|
||
### POST /api/screen/tap
|
||
|
||
点击设备屏幕。**权限**:`devices`。
|
||
**请求**(JSON):`{"serial": "...", "x": 360, "y": 800}`(设备原生分辨率坐标)
|
||
|
||
### POST /api/screen/swipe
|
||
|
||
滑动。**请求**(JSON):`{"serial": "...", "x1": 360, "y1": 1200, "x2": 360, "y2": 600, "duration": 0.2}`
|
||
|
||
### POST /api/screen/key
|
||
|
||
按键。**请求**(JSON):`{"serial": "...", "key": "back"}`。
|
||
支持:back/home/recent/menu/power/volume_up/volume_down/enter/delete/search/camera
|
||
|
||
### POST /api/screen/text
|
||
|
||
输入文字(需焦点在输入框)。**请求**(JSON):`{"serial": "...", "text": "你好"}`
|
||
|
||
### POST /api/device/screen_all
|
||
|
||
批量亮屏/息屏(并发)。**权限**:`devices`。
|
||
|
||
**请求**(JSON):
|
||
```json
|
||
{"mode": "on", "serials": ["100.100.10.11:5555"]}
|
||
```
|
||
`serials` 可选:指定设备(离线自动过滤);不带则作用于全部在线设备。息屏会中断运行中的任务,前端有确认提示。
|
||
|
||
### GET /api/adb/devices
|
||
|
||
维护终端设备列表:本地 adb 已连接(含 offline)+ 设备池已配置设备(标记 `pool`)。
|
||
供终端设备选择器使用——选中后前端自动附加 `-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)——会断开共享的 adb transport,导致全部设备连接重建。
|
||
|
||
**响应**:
|
||
```json
|
||
{"ok": true, "stdout": "...", "stderr": "", "code": 0}
|
||
```
|
||
|
||
---
|
||
|
||
## 14. 步骤测试(仅管理员可触发,需"设备控制"权限)
|
||
|
||
### POST /api/steps/test
|
||
|
||
在指定设备上单步试执行(步骤编辑器"测试此步骤"按钮),验证选择器是否命中。
|
||
只读连接(adb connect + u2),与运行中任务互不干扰。
|
||
|
||
**请求**(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。
|
||
|
||
---
|
||
|
||
## 15. Tailscale 管理(仅管理员)
|
||
|
||
工具页"Tailscale 管理"子分栏,调用 Tailscale 官方 API v2。所有接口仅管理员可用。
|
||
前置:`.env` 配置 `TAILSCALE_API_KEY`(Settings → API Access Tokens)与
|
||
`TAILSCALE_TAILNET`(tailnet 名,个人账号一般为邮箱前缀);未配置返回 502 并附提示。
|
||
设备 IP 由 tailnet 分配,API 不可修改,列表只读展示。
|
||
|
||
### GET /api/tailscale/status
|
||
|
||
配置状态检查。
|
||
|
||
**响应**:
|
||
```json
|
||
{"ok": true, "configured": false, "hint": "TAILSCALE_API_KEY(...);TAILSCALE_TAILNET(...)"}
|
||
```
|
||
|
||
### GET /api/tailscale/devices
|
||
|
||
列出 tailnet 全部设备。
|
||
|
||
**响应**:
|
||
```json
|
||
{"ok": true, "devices": [
|
||
{"id": "d1", "name": "dev-a", "hostname": "dev-a", "os": "linux",
|
||
"addresses": ["100.100.10.11"], "authorized": true,
|
||
"key_expiry_disabled": false, "online": true, "last_seen": "...", "tags": []}
|
||
]}
|
||
```
|
||
|
||
### POST /api/tailscale/devices/:device_id
|
||
|
||
更新设备(按传入字段分发到 Tailscale 专属端点,`POST /device/{id}` 本身是 405):
|
||
`name` → `/name` 显示名;`authorized` → `/authorized` 授权开关;
|
||
`key_expiry_disabled` → `/key`(true=密钥永不过期,即关闭设备密钥验证,恢复后按原定过期时间执行)。
|
||
|
||
**请求**(JSON):
|
||
```json
|
||
{"key_expiry_disabled": true}
|
||
```
|
||
|
||
### POST /api/tailscale/devices/:device_id/ip
|
||
|
||
设置设备的 Tailscale IPv4 地址(未公开端点,实测可用)。
|
||
|
||
**请求**(JSON):
|
||
```json
|
||
{"ipv4": "100.100.10.16"}
|
||
```
|
||
|
||
⚠ 改 IP 会断开设备当前 tailscale 会话;平台设备池 serial 随之变化,需同步更新设备池/分组/任务目标。
|
||
|
||
### DELETE /api/tailscale/devices/:device_id
|
||
|
||
从 tailnet 移除设备(下次上线需重新授权)。
|
||
|
||
### POST /api/tailscale/authkey
|
||
|
||
生成设备接入 auth key(key 只返回一次)。
|
||
|
||
**请求**(JSON):
|
||
```json
|
||
{"description": "新设备接入", "reusable": false, "ephemeral": false,
|
||
"preauthorized": true, "expiry_seconds": 3600}
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{"ok": true, "key": "tskey-auth-...", "id": "k1", "expires": "2026-08-11T01:00:00Z"}
|
||
```
|
||
|
||
---
|
||
|
||
## 16. 工具(仅管理员)
|
||
|
||
工具页(剪贴板注入 / 应用版本管理 / 设备池管理)接口,均仅管理员可用。
|
||
|
||
### POST /api/tools/clipboard/set
|
||
|
||
剪贴板注入:把指定文字写入一台或多台设备的剪贴板。
|
||
|
||
**请求**(JSON):
|
||
```json
|
||
{"serials": ["100.100.10.11:5555", "0123456789ABCDEF"], "text": "要注入的文字"}
|
||
```
|
||
设备来源与维护终端一致(本地 adb 含 USB + 设备池)。
|
||
实现:u2 `jsonrpc.setClipboard`(实测 `cmd clipboard` 在 MIUI 上不存在),支持中文/引号/换行;
|
||
IP 设备先 adb connect(已连接跳过,绝不 disconnect),USB 设备首次自动推送 atx-agent。
|
||
|
||
**响应**:
|
||
```json
|
||
{"ok": true, "results": {"100.100.10.11:5555": {"ok": true, "msg": "已注入"}},
|
||
"ok_count": 1, "fail_count": 0, "error": null}
|
||
```
|
||
|
||
### POST /api/tools/appver
|
||
|
||
应用版本管理:查询所有设备上指定包名的安装情况与版本号(并发 10 台)。
|
||
|
||
**请求**(JSON):
|
||
```json
|
||
{"pkg": "com.ss.android.ugc.aweme"}
|
||
```
|
||
|
||
**响应**:
|
||
```json
|
||
{"ok": true, "total": 8, "fail": 0,
|
||
"results": {"100.100.10.11:5555": {"installed": true, "version_name": "28.5.0", "version_code": "280500"}}}
|
||
```
|
||
未安装返回 `installed: false`;查询失败的设备带 `error` 字段。
|