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:
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user