feat(collect): persist product status snapshots

This commit is contained in:
chengma
2026-07-18 16:34:37 +08:00
parent b4250f36f8
commit 0cf23db403
11 changed files with 464 additions and 12 deletions
+81 -3
View File
@@ -11,7 +11,7 @@ from dataclasses import dataclass
from datetime import datetime
from typing import Iterable, Optional
from . import appconfig
from . import appconfig, product_status
from .config import make_slug
@@ -30,6 +30,7 @@ FAILURE_STEP_LABELS = {
"open_product": "打开商品页",
"wait_ready": "页面就绪",
"read_title": "读标题",
"read_product_status": "读取商品状态",
"read_cover": "读封面",
"download_cover": "下载封面",
"db_write": "写库",
@@ -135,6 +136,9 @@ class Task:
account_name: Optional[str]
alias: str
item_id: str
product_status: Optional[str]
product_status_note: Optional[str]
product_status_at: Optional[str]
old_title: Optional[str]
old_cover_path: Optional[str]
new_title: Optional[str]
@@ -232,6 +236,9 @@ CREATE TABLE IF NOT EXISTS tasks (
account_name TEXT,
alias TEXT NOT NULL,
item_id TEXT NOT NULL,
product_status TEXT,
product_status_note TEXT,
product_status_at TEXT,
old_title TEXT,
old_cover_path TEXT,
new_title TEXT,
@@ -485,6 +492,7 @@ def init_db(path=None, conn=None) -> None:
_ensure_batch_delete_columns(database)
_ensure_task_image_task_columns(database)
_ensure_task_cover_reset_columns(database)
_ensure_task_product_status_columns(database)
_ensure_image_studio_project_suite_columns(database)
_ensure_image_studio_project_draft_columns(database)
_ensure_image_studio_job_recovery_columns(database)
@@ -516,6 +524,16 @@ def _ensure_task_cover_reset_columns(database):
database.execute("ALTER TABLE tasks ADD COLUMN cover_reset_at TEXT")
def _ensure_task_product_status_columns(database):
columns = {row["name"] for row in database.execute("PRAGMA table_info(tasks)").fetchall()}
if "product_status" not in columns:
database.execute("ALTER TABLE tasks ADD COLUMN product_status TEXT")
if "product_status_note" not in columns:
database.execute("ALTER TABLE tasks ADD COLUMN product_status_note TEXT")
if "product_status_at" not in columns:
database.execute("ALTER TABLE tasks ADD COLUMN product_status_at TEXT")
def _ensure_image_studio_project_suite_columns(database):
columns = {
row["name"]
@@ -1021,8 +1039,53 @@ def clear_image_task(task_id, path=None, conn=None) -> None:
)
def set_collected(task_id, old_title, old_cover_path, path=None, conn=None) -> None:
def set_product_status(
task_id,
product_status_value,
product_status_note=None,
product_status_at=None,
path=None,
conn=None,
) -> None:
"""Persist a status snapshot without changing the collection lifecycle."""
now = _now()
detected_at = product_status_at or now
with _connection(conn, path) as database:
with database:
database.execute(
"""
UPDATE tasks
SET product_status = ?,
product_status_note = ?,
product_status_at = ?,
updated_at = ?
WHERE id = ?
""",
(
product_status.normalize_status(product_status_value),
str(product_status_note or "")[:2000] or None,
detected_at,
now,
int(task_id),
),
)
def set_collected(
task_id,
old_title,
old_cover_path,
path=None,
conn=None,
*,
product_status_value=None,
product_status_note=None,
product_status_at=None,
) -> None:
now = _now()
has_status_snapshot = product_status_value is not None
detected_at = product_status_at or now
with _connection(conn, path) as database:
with database:
database.execute(
@@ -1035,10 +1098,25 @@ def set_collected(task_id, old_title, old_cover_path, path=None, conn=None) -> N
last_error = NULL,
collect_attempts = collect_attempts + 1,
collected_at = ?,
product_status = CASE WHEN ? THEN ? ELSE product_status END,
product_status_note = CASE WHEN ? THEN ? ELSE product_status_note END,
product_status_at = CASE WHEN ? THEN ? ELSE product_status_at END,
updated_at = ?
WHERE id = ?
""",
(old_title, old_cover_path, now, now, int(task_id)),
(
old_title,
old_cover_path,
now,
int(has_status_snapshot),
product_status.normalize_status(product_status_value),
int(has_status_snapshot),
str(product_status_note or "")[:2000] or None,
int(has_status_snapshot),
detected_at,
now,
int(task_id),
),
)