feat: 验收任务周期采集与设备资源接口

- 新增 acceptance-tasks 周期采集、立即采集、断点续采与批次管理
- acceptance-resources 返回 xhs_device_accounts 真实设备清单
- 数据看板服务调整及测试更新
This commit is contained in:
2026-08-28 13:43:53 +08:00
parent a021f2fe60
commit e188c50fab
8 changed files with 819 additions and 47 deletions

View File

@@ -193,6 +193,17 @@ def init_database() -> None:
FOREIGN KEY(task_id) REFERENCES acceptance_tasks(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS acceptance_match_keywords (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id INTEGER NOT NULL,
keyword_order INTEGER NOT NULL,
keyword TEXT NOT NULL,
created_at TEXT NOT NULL,
UNIQUE(task_id, keyword_order),
UNIQUE(task_id, keyword),
FOREIGN KEY(task_id) REFERENCES acceptance_tasks(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS acceptance_feishu_sources (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id INTEGER NOT NULL,
@@ -288,6 +299,34 @@ def init_database() -> None:
CREATE INDEX IF NOT EXISTS idx_acceptance_keyword_runs_task
ON acceptance_keyword_runs(task_id, status);
CREATE TABLE IF NOT EXISTS acceptance_xapi_runs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id INTEGER NOT NULL,
keyword_run_id INTEGER,
batch_id TEXT NOT NULL,
xapi_task_id TEXT NOT NULL UNIQUE,
keyword TEXT,
xhs_account_id TEXT,
device_serial TEXT,
device_label TEXT,
status TEXT,
writeback_status TEXT,
source_base_url TEXT,
base_record_id TEXT,
artifacts_json TEXT,
feishu_result_text TEXT,
feishu_record_json TEXT,
feishu_sync_status TEXT,
feishu_sync_error TEXT,
raw_json TEXT NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
FOREIGN KEY(task_id) REFERENCES acceptance_tasks(id) ON DELETE CASCADE,
FOREIGN KEY(keyword_run_id) REFERENCES acceptance_keyword_runs(id) ON DELETE SET NULL
);
CREATE INDEX IF NOT EXISTS idx_acceptance_xapi_runs_task
ON acceptance_xapi_runs(task_id, status, batch_id);
CREATE TABLE IF NOT EXISTS acceptance_cookie_attempts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id INTEGER NOT NULL,
@@ -321,8 +360,33 @@ def init_database() -> None:
);
CREATE INDEX IF NOT EXISTS idx_acceptance_task_resources
ON acceptance_task_resources(task_id, resource_order);
CREATE TABLE IF NOT EXISTS acceptance_task_secrets (
task_id INTEGER NOT NULL,
secret_type TEXT NOT NULL,
secret_value TEXT NOT NULL,
created_at TEXT NOT NULL,
PRIMARY KEY(task_id, secret_type),
FOREIGN KEY(task_id) REFERENCES acceptance_tasks(id) ON DELETE CASCADE
);
"""
)
acceptance_columns = {
row["name"] for row in conn.execute("PRAGMA table_info(acceptance_tasks)").fetchall()
}
acceptance_migrations = {
"schedule_enabled": "INTEGER NOT NULL DEFAULT 0",
"schedule_weekday": "INTEGER",
"next_run_at": "TEXT",
"last_run_at": "TEXT",
"scheduled_from_task_id": "INTEGER",
"schedule_error": "TEXT",
"trigger_source": "TEXT NOT NULL DEFAULT 'acceptance'",
"cookie_count": "INTEGER NOT NULL DEFAULT 0",
}
for column, definition in acceptance_migrations.items():
if column not in acceptance_columns:
conn.execute(f"ALTER TABLE acceptance_tasks ADD COLUMN {column} {definition}")
# 将旧版本保存在 acceptance_xhs_notes.parsed_json 中的成功结果迁移到
# 全局去重的笔记业务表;任务关联仍由 acceptance_xhs_notes 保留。
legacy_rows = conn.execute(