feat(product-suite): add original image batch management

This commit is contained in:
chengma
2026-07-14 15:35:59 +08:00
parent 21d2dd5253
commit e86b9189ab
8 changed files with 759 additions and 37 deletions
+78
View File
@@ -575,6 +575,84 @@ def remove_asset_if_unused(asset_id, path=None, conn=None):
return asset
def remove_original_assets_if_unused(project_id, asset_ids, path=None, conn=None):
"""Atomically remove unreferenced original assets from one project.
Local files are intentionally retained. If any requested asset is invalid or
referenced, no asset row is removed.
"""
project_id = int(project_id)
ordered_ids = []
seen = set()
for value in asset_ids or []:
asset_id = int(value)
if asset_id not in seen:
seen.add(asset_id)
ordered_ids.append(asset_id)
if not ordered_ids:
raise db.DbError("请选择要删除的商品原图")
placeholders = ",".join("?" for _ in ordered_ids)
with _connection(conn, path) as database:
with database:
project = get_project(project_id, conn=database)
if project is None:
raise db.DbError("商品套图项目不存在或已删除")
rows = database.execute(
f"""
SELECT * FROM image_studio_assets
WHERE project_id = ? AND kind = ? AND id IN ({placeholders})
""",
[project_id, ASSET_KIND_ORIGINAL, *ordered_ids],
).fetchall()
by_id = {int(row["id"]): row for row in rows}
if set(by_id) != set(ordered_ids):
raise db.DbError("选中的商品原图不存在或不属于当前项目")
referenced_ids = [
asset_id
for asset_id in ordered_ids
if asset_reference_counts(asset_id, conn=database)["total"]
]
if referenced_ids:
raise db.DbError("选中的图片正在被生成任务或终选引用,不能移除")
database.execute(
f"""
DELETE FROM image_studio_assets
WHERE project_id = ? AND kind = ? AND id IN ({placeholders})
""",
[project_id, ASSET_KIND_ORIGINAL, *ordered_ids],
)
remaining_rows = database.execute(
"""
SELECT id FROM image_studio_assets
WHERE project_id = ? AND kind = ?
ORDER BY source_order, id
""",
(project_id, ASSET_KIND_ORIGINAL),
).fetchall()
now = _now()
for source_order, row in enumerate(remaining_rows, 1):
database.execute(
"""
UPDATE image_studio_assets
SET source_order = ?, updated_at = ?
WHERE id = ? AND project_id = ? AND kind = ?
""",
(
source_order,
now,
int(row["id"]),
project_id,
ASSET_KIND_ORIGINAL,
),
)
return [_row_to_dataclass(by_id[asset_id], ImageStudioAsset) for asset_id in ordered_ids]
def sync_original_asset_urls(project_id, image_urls, path=None, conn=None, max_assets=16):
"""Store the read-only Shopee main image URL snapshot as remote-only assets."""