feat(发布计划): 改按名字发(文件名 名字_日期_编号)+ 账号管理整页下线 + 自动切号一轮发完

发布计划不再绑设备、不再依赖账号台账:上传文件名 `名字_日期_编号`(标题行
`标题 || 正文_名字_日期_编号`),运行时读本机当前抖音昵称取计划;靠循环块
「一轮把本机待发的号跑完」自动切号,一直发到发完。

· 解析/配对换键:右锚定认名字(不许含下划线、不许纯数字 —— 不合法直接拒收并说清原因),
  删掉三处"手机号必须命中台账"的校验,加索引 ix_video_plan_name_date(启动时补建)
· 新步骤三个:读本机账号名字 / 切换账号(**按名字点控件**、切完回读校验、遇登录页停本设备)/
  循环本机待发的号(试过不回头、跑一轮没进展就换号、停止·超时·上限三个干净出口)
· 发布骨架改 18 步:读名字 → 校验账号(cmp_source=account_target)→ 推送(**推送前重读昵称核对**)
  → 抖音流程 → 标记结果;push_release 的 account 默认 name
· 账号管理整页下线:删 core/ledger.py(serial_of 迁到 core/device_pool.py)、6 个 /api/ledger*、
  「账号」页与 ledger.js、设备池「账号」列、设备端账号块;发布计划升为一级页签;
  device_account 表与 42 行历史数据保留、仍在备份清单内(**停用不等于删数据**)
· 人工入口「按名字找设备」:新增 core/account_probe.py(只读探测、跳过在跑任务的设备)
  + POST /api/video_plan/push_by_account,没设备登着的号逐条报出来;
  推送时把"实际是谁发的"写进 posted_serial / posted_device_name
· 通知:新增 task.account.switch_failed / task.account.need_login
· schema v12(posted_*)/ v13(device.cur_account_name / cur_name_at)
· 文档同步:TASK_DEV / API / DATA_MODEL / ARCHITECTURE / NOTIFY / DEVICE_AGENT / DEPLOY /
  DEVELOPMENT / README / .env.example(两个抖音控件选择器抓一次填 .env)
· 新增 scripts/tests/:6 套用例 + run_all.py(临时库 + 假设备,不碰真实数据、不连真机)
This commit is contained in:
2026-10-12 09:02:40 +08:00
parent 75bee21ffb
commit beda0f3779
37 changed files with 2615 additions and 1747 deletions
+3 -48
View File
@@ -216,51 +216,6 @@ adb -s <serial> shell am start -n <pkg>/.InfoActivity \
要求:全屏大字、再次调用可覆盖内容、`close` 可关闭、不驻留前台。
#### 5.2.1 本机账号台账(`accounts_b64`,可选 extras — **需要设备端配合实现**)
平台在**打开**身份页时会顺带把这台设备在「账号」页登记的抖音账号推过去
(`--es close 1` 时**不带**)。**中文必须 base64**(同 §5.1:adb shell 直传中文会变形):
```bash
adb -s <serial> shell am start -n <pkg>/.InfoActivity \
--es name "A03" --es serial "192.168.20.63:5555" --es server "http://192.168.20.220:18050" \
--es ip "192.168.20.63" \
--es accounts_b64 "<base64(UTF-8 JSON)>"
```
解码:**标准 base64**(不是 URL-safe)+ UTF-8。JSON 结构(字段名的设备端解析按名取,多余字段忽略):
```json
{"v":1,"total":4,"shown":4,"truncated":false,
"note":"设备『A03』登记 4 个号",
"accounts":[
{"name":"AA建材王总","douyin_id":"66057500463","device_name":"A03","device_no":"A03",
"sim_in_device":true,"can_post_video":true}]}
```
| 字段 | 说明 |
|------|------|
| `v` | 本块格式版本(当前 **1**)。解不出来时用它区分"格式变了"与"平台没给" |
| `total` / `shown` / `truncated` | 该设备在台账里的总数 / 本次带了几条 / 是否被截断 |
| `accounts[].name` | 账号名称(台账的「账号名称」列) |
| `accounts[].douyin_id` | **抖音号(纯号)**,如 `35377983067` |
| `accounts[].sim_in_device` / `can_post_video` | 卡在机内 / 可发视频(布尔) |
| `accounts[].phone` | **默认不推**(大字页是机器旁的公开屏幕,手机号不宜默认上屏)。需要时平台请求体传 `{"include_phone":true}` |
**设备端要做的**(当前版本忽略该 extra,行为与旧版逐字一致):
1. 读 `accounts_b64` → base64 解码 → `JSONObject`
2. 在身份页上按 `name` / `douyin_id` 渲染一个列表(建议 1~3 行简短列表,最多显示 `shown` 条)
3. `truncated=true` 时提示"还有更多,见平台账号页"
**约定与边界**(平台侧实现见 `web/device_agent_api.py` 的 `_encode_accounts`):
- **没有这个 extra = 这台设备在台账里没有账号**(不是"平台忘了给")——设备端保持原样显示即可,
不要显示空列表
- 超预算时平台**按整条丢**(`shown` 变小 + `truncated=true`),**绝不按字节切**(切了就是坏 JSON);
台账过大时可能**整个 extra 不发**(平台响应体里 `warn` 会说明原因)
- 台账读取失败时同样**不发**这个 extra —— 台账故障不影响"显示身份"这个动作
### 5.3 扫码配置(设备端已实现)
平台「设备池」里点某台设备的「**二维码**」→ 生成一张二维码 → 手机上的 Agent 点
@@ -294,9 +249,9 @@ adb -s <serial> shell am start -n <pkg>/.ConfigActivity \
## 6. 版本与兼容
- **§5.2.1 的 `accounts_b64` 是"加字段"= 小版本**:`agent_api_version` **仍是 1**,
设备端忽略它时行为必须与旧版逐字一致(只是大字页少一块内容)。也**不**走
`bootstrap`:身份页由平台用 adb 推,加进 bootstrap 没人用还会让契约多一处要同步。
- 身份页 extras(`name`/`ip`/`serial`/`server`/`close`)是**平台单向下发**:设备端多收/少收
都不影响旧行为。(2026-10-12:账号台账下线,原先顺带下发的 `accounts_b64` 已不再发送 ——
设备端收到"没有这个 extra"时照旧只显示身份信息即可。)
- `agent_api_version`(当前 **1**)在每次 `bootstrap` 响应里返回
- **设备端**:启动时对比自己实现的版本,不一致要在日志里明确记下来(不要静默)
- **平台端**: