feat(发布计划): 标题 + 正文(标题 || 正文 _手机号_日期_编号)+ 发布流程多一步填正文;账号名称全面下线

一、正文(video_plan.body,schema v10→v11)
- 标题 txt 一行里可带正文,用 `||` 分隔(标题/正文都常带下划线,不能再用下划线分列;
  只切第一处,正文里再出现 `||` 原样保留):`标题 || 正文 _手机号_日期_编号`
  正文可省(老文件照收);两种写法(标题在前 / 手机号在前)都能带正文
- 长度:标题 ≤100 字、正文 ≤1000 字,超了**拒收不截断**
- 「待发布」判据从"有没有标题"改成"**标题或正文有没有内容**"(`_sync_content_status` 一处定义,
  改标题/改正文/批量导入三处共用),只给正文的行也照样待发
- 导入配对:同标题补一条新正文**要收下**(不能当重复跳过);已有别的标题仍然拒收(不静默覆盖)

二、发布流程多一步
- 骨架 15 → **17 步**:⑪ 输入文字(计划的标题) → ⑫ 点击正文框 → ⑬ 输入文字(计划的正文) → ⑭ 发布 → ⑮ 标记
- 「输入文字」取值来源集中到 `RELEASE_TEXT_SOURCES`:release_title(_topics) / release_body(_topics) /
  release_title_body(标题+正文,只有一个输入框的抖音版本用);`build_caption(key=…)` 支持三种来源
- 任务编辑器与发布计划就地编辑器的下拉都补齐这 6 档;待抓的空选择器 5 → 6 个(多了正文框)

三、账号名称下线(用户要求:只要抖音号)
- 发布计划:卡片 / 明细表 / 搜索 / 导出 CSV 都不再有账号名称(CSV 改为
  发布日期/设备号/手机号/抖音号/编号/标题/正文/分享链接/发布时间)
- 账号台账:列表列 / 编辑弹窗 / 粘贴导入预览 / 设备维度弹窗 / 导入说明与示例都去掉;
  **粘贴导入忽略这一列**(不报错、不落库),库里的历史值保留(不删列)
- 设备端 Agent 身份页:平台不再下发名称(传空串,**不改 APK 也能生效**,避免老版本解析失败)

四、文档 / 测试
- DATA_MODEL:body 列 + schema 11;API:upload_titles(`||` 语义)、PUT {title,body}、CSV 列、骨架 17 步
- TASK_DEV:骨架 17 步、`input_text` 六个取值来源表、正文长度上限
- ARCHITECTURE:release.js 说明(正文、不显示账号名称)
- 测试(%TEMP% 被系统清理后重建):test_plan_body.py 33 项(解析/取内容/骨架/入库/导入配对)、
  smoke_app_body.py 10 项(整机装配:页面、PUT 改正文、时间线、CSV 表头)—— 全过
This commit is contained in:
2026-10-11 16:36:56 +08:00
parent a800d051ae
commit 6ee089e023
13 changed files with 196 additions and 95 deletions
+3 -2
View File
@@ -16,7 +16,7 @@
| SQLite 回退时的 PRAGMA | `journal_mode=WAL`、`busy_timeout=5000`、`synchronous=NORMAL`(监听器按连接类型守卫,MySQL 连接不会执行) |
| 建表方式 | **唯一真相是模型**:`db.create_all()`(建缺表)+ `_sync_columns()`(补缺列);`SCHEMA_MIGRATIONS` 只作版本账本与数据回填 |
| 库位置 | MySQL:由 `DB_HOST/DB_NAME` 指定;SQLite:`data/users.db` |
| 当前 schema 版本 | `app_meta.schema_version = 10`(迁移清单见 `core/models.py` 的 `SCHEMA_MIGRATIONS`:建表/补列以模型为准,这里只作版本账本) |
| 当前 schema 版本 | `app_meta.schema_version = 11`(迁移清单见 `core/models.py` 的 `SCHEMA_MIGRATIONS`:建表/补列以模型为准,这里只作版本账本) |
**环境与库的绑定**(防混库,见 [DEPLOY.md](DEPLOY.md) §2.2)
@@ -248,7 +248,8 @@
| `device_name` / `nickname` / `douyin_id` / `serial` | String | 账号与设备快照(时间线卡片直接显示,免 join) |
| `release_date` | String(10) index | **`2026-09-12`** 纯日期(等值比较走索引) |
| `seq` / `seq_auto` | Integer / Boolean | 编号从 **1** 起(不用 0 表示"无");`seq_auto`=号是自动分配的 |
| `title` | Text | 文案(标题 txt 配对写入;**空标题不会被发布**) |
| `title` | Text | **标题**(发布页的「标题」框;标题 txt 配对写入) |
| `body` | Text | **正文/文案**(发布页的文案框,可带 `#话题`)—— 标题 txt 一行里用 `||` 分隔:`标题 || 正文 _手机号_日期_编号`;**标题与正文都为空的行不会被发布** |
| `video_file` / `video_name` / `video_size` / `video_sha1` | 各自 | 落盘相对路径 / 原始名 / 大小 / 内容指纹(重复上传判据) |
| `status` | String(16) index | 见下方状态机 |
| `stage` | String(16) | 失败发生在哪一步:`push`/`scan`/`post`/`verify` |