fix: 测试清单遗留bug批量修复(15条:商品库/消费/团队/设置/消息中心/平台套图/资产库)

- R6 商品图删除不生效: 封面asset移交+绕开prefetch缓存, 前端封面缩图补删除入口
- R48 消息中心长文本与UI框错位: 胶囊单行省略+优先级标签禁压缩
- R70 账单流水筛选: 后端加ledger_type过滤, count随筛选变化, 切筛选重置页码
- R72 月限额改后不刷新: 团队页/消费页自取最新teamSettings, 两页同源
- R83/R86 平台套图提示词框加大+模型胶囊嵌入输入框(复用Pill组件)
- R96 未读角标: 修KeyTextTransform注解过滤触发MySQL 3141致接口500
- R100 工作台记录丢失: 新增GET /api/ai/tasks/workbench/ 同源恢复, 废除localStorage方案
- R104 卖点添加按钮移出输入框, 新建抽屉+编辑态统一
- R106 商品库宽屏锁5列, 10个/页铺满两行
- R108 资产删除改软删+单张删除+回收站二次确认; trash页商品/资产双分区+restore/purge端点
- R109 生成图自动入资产库(person演员立绘除外), 迁移0008存量回填, 移除全部加入资产库入口
- R65 无需改动(22268d6已修, 测旧部署所致)

验证: tsc/build/check/makemigrations --check 通过, 后端测试210/210, perf-probe PASS

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-07-02 11:30:06 +08:00
co-authored by Claude Fable 5
parent 22268d608b
commit aab4d7ea4c
28 changed files with 924 additions and 476 deletions
+26 -4
View File
@@ -541,13 +541,21 @@ export function LibraryPage({ onUpload, onDelete }: { onUpload: (formData: FormD
setReloadFlag((f) => f + 1);
}
// 删除(单 / 批):乐观隐藏 → 并发删 → 刷新计数/列表
// 删除(单 / 批):乐观隐藏 → 并发删 → 刷新计数/列表。后端为回收站软删(R108),可恢复。
async function doDelete() {
const ids = confirmIds || [];
setConfirmIds(null);
if (!ids.length || !onDelete) return;
setDeletingIds((prev) => { const next = new Set(prev); ids.forEach((id) => next.add(id)); return next; });
setSelected(new Set());
// R108:批次弹窗内单张删除 —— 同步从打开中的批次里摘掉;删空则关掉弹窗
setOpenBatch((prev) => {
if (!prev) return prev;
const items = prev.items.filter((a) => !ids.includes(a.id));
if (!items.length) return null;
const cover = items[0].files?.find((f) => f.is_primary)?.preview_url || items[0].files?.[0]?.preview_url || prev.cover;
return { ...prev, items, count: items.length, cover };
});
try {
await Promise.all(ids.map((id) => onDelete(id)));
setReloadFlag((f) => f + 1);
@@ -835,10 +843,24 @@ export function LibraryPage({ onUpload, onDelete }: { onUpload: (formData: FormD
{openBatch.items.map((a, i) => {
const cover = a.files?.find((f) => f.is_primary)?.preview_url || a.files?.[0]?.preview_url || "";
return (
<button className="pack-clip as-btn" type="button" key={a.id} onClick={() => { setOpenBatch(null); setDetail(a); }} title="查看详情">
// R108:图片集内单张悬浮删除 icon(嵌套按钮非法 → 外层改 div[role=button])
<div
className="pack-clip as-btn"
role="button"
tabIndex={0}
key={a.id}
onClick={() => { setOpenBatch(null); setDetail(a); }}
onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setOpenBatch(null); setDetail(a); } }}
title="查看详情"
>
{onDelete && (
<button className="card-del-btn" type="button" title="删除这张图片" onClick={(event) => { event.stopPropagation(); setConfirmIds([a.id]); }}>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18" /><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2" /><path d="M19 6l-1.5 14a2 2 0 01-2 1.8H8.5a2 2 0 01-2-1.8L5 6" /></svg>
</button>
)}
{cover ? <img src={cover} alt={a.name} loading="lazy" /> : <span className="pack-clip-ph ph-frame">无图</span>}
<div className="pack-clip-name mono">第 {i + 1} 张</div>
</button>
</div>
);
})}
</div>
@@ -872,7 +894,7 @@ export function LibraryPage({ onUpload, onDelete }: { onUpload: (formData: FormD
title="删除资产"
subtitle="// DELETE ASSET"
icon={<Trash2 size={16} />}
detail={`确定删除选中的 ${confirmIds?.length || 0} 个资产?该操作不可撤销。`}
detail={`已选中 ${confirmIds?.length || 0} 个资产。删除的图片将回收到垃圾桶,是否需要删除?`}
confirmText="删除"
onCancel={() => setConfirmIds(null)}
onConfirm={doDelete}