fix: 修复图片生成切换商品重复批次
This commit is contained in:
@@ -605,6 +605,18 @@ type GenBatch = {
|
||||
pendingIds?: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断本地临时卡与后端恢复卡是否代表同一真实任务组。
|
||||
* 新提交后先有前端 b- 临时 id,随后才回填后端 batch_id;两者在商品切换时会短暂共存,
|
||||
* 必须按真实 batch_id(或任务 id 重叠的提交/恢复交错兜底)合并,不能按前端卡片 id 比较。
|
||||
*/
|
||||
function isSameWorkbenchBatch(left: GenBatch, right: GenBatch): boolean {
|
||||
if (left.backendBatchId && right.backendBatchId && left.backendBatchId === right.backendBatchId) return true;
|
||||
const leftIds = left.pendingIds || [];
|
||||
const rightIds = new Set(right.pendingIds || []);
|
||||
return leftIds.some((id) => rightIds.has(id));
|
||||
}
|
||||
|
||||
/* R100:后端 platform_id(douyin/taobao…) → 前端平台 key(dy/tb…),恢复批次时还原平台分组 */
|
||||
const PLATFORM_KEY_MAP: Record<string, string> = Object.fromEntries(
|
||||
Object.entries(PLATFORM_ID_MAP).map(([key, canonical]) => [canonical, key])
|
||||
@@ -691,6 +703,10 @@ export function ImageWorkbenchPage({
|
||||
const [openMore, setOpenMore] = useState("");
|
||||
// 批次列表:每次生成/重跑追加一条,各自展示;可多批并行 generating
|
||||
const [batches, setBatches] = useState<GenBatch[]>([]);
|
||||
// 商品切换后的后端恢复回调不依赖 batches,避免恢复 effect 因批次状态变化反复触发;
|
||||
// 用 ref 读取最新内存卡,识别仍由首次提交轮询的临时批次。
|
||||
const batchesRef = useRef<GenBatch[]>(batches);
|
||||
batchesRef.current = batches;
|
||||
/* ── 图片创作「对话」(真实体,后端 ImageConversation)──
|
||||
conversations = 左栏会话列表;activeConvId = 当前选中对话(空 = 还没建,首次发送时后端自动开)。
|
||||
activeConvRef 让 startBatch 在不进 deps 的情况下读到最新 active id。 */
|
||||
@@ -1251,10 +1267,19 @@ export function ImageWorkbenchPage({
|
||||
.then((res) => {
|
||||
if (cancelled) return;
|
||||
const next = batchesFromWorkbenchTasks(res.tasks || []);
|
||||
// 竞态保护:拉取在途时用户又提交了新批次(本地 id 以 b- 开头、还在生成中)→ 合并保留,别被整体替换冲掉
|
||||
setBatches((prev) => [...next, ...prev.filter((b) => b.id.startsWith("b-") && b.status === "generating")]);
|
||||
// 竞态保护:拉取在途时用户又提交了新批次(本地 id 以 b- 开头、还在生成中)→ 合并保留,别被整体替换冲掉。
|
||||
// 同时,切走再回来时 next 会带回这张临时卡对应的真实 batch_id:若直接追加,
|
||||
// 页面会出现两张同一任务卡,并对同一 pendingIds 启动两次轮询。
|
||||
const inMemoryGenerating = batchesRef.current.filter((b) => b.id.startsWith("b-") && b.status === "generating");
|
||||
const recoveredToResume = next.filter((b) => !inMemoryGenerating.some((local) => isSameWorkbenchBatch(local, b)));
|
||||
setBatches((prev) => {
|
||||
const localGenerating = prev.filter((b) => b.id.startsWith("b-") && b.status === "generating");
|
||||
const recovered = next.filter((b) => !localGenerating.some((local) => isSameWorkbenchBatch(local, b)));
|
||||
return [...recovered, ...localGenerating];
|
||||
});
|
||||
if (onResume) {
|
||||
for (const b of next) {
|
||||
// 仅恢复当前内存中不存在的批次;已匹配的临时卡仍由首次提交流程继续轮询。
|
||||
for (const b of recoveredToResume) {
|
||||
if (b.status !== "generating" || !(b.pendingIds && b.pendingIds.length)) continue;
|
||||
onResume(mode, b.pendingIds).then((r) => {
|
||||
if (cancelled || !r?.assets) return;
|
||||
|
||||
Reference in New Issue
Block a user