diff --git a/lib/__tests__/task-detail-preview-runs.test.ts b/lib/__tests__/task-detail-preview-runs.test.ts index 629fea6..b6aee14 100644 --- a/lib/__tests__/task-detail-preview-runs.test.ts +++ b/lib/__tests__/task-detail-preview-runs.test.ts @@ -206,3 +206,35 @@ describe('旧代预览名(detail-preview-{时间戳}-{序号}-...)兼容', ( expect(aligned).toEqual([0, 1]) }) }) + +describe('历史客户端 -preview 尾巴命名兼容', () => { + test('剥掉 -preview 尾巴得到来源锚', () => { + expect(parseTaskDetailPreviewFileName('主图3-preview.webp')).toEqual({ label: '主图3', sliceIndex: null }) + expect(parseTaskDetailPreviewFileName('4-preview.webp')).toEqual({ label: '4', sliceIndex: null }) + expect(parseTaskDetailPreviewFileName('GBSFY-SJZ0030 (1)-preview.webp')).toEqual({ label: 'GBSFY-SJZ0030 (1)', sliceIndex: null }) + }) + + test('真实形态:26 行 -preview 命名主图与 26 条目主锚定直接配对', () => { + const labels = ['主图3 拷贝 3', '主图3 拷贝', '主图3', '主图4', '4', '5', '6', '7', + '主图1 拷贝', '主图1', '主图2', '主图2拷贝', '1', '2', '3 拷贝 2', '3', + '功能主图4', '功能主图5', '功能主图1', '功能主图2', '功能主图3', + '功能主图3-2', '功能主图4-2', '功能主图5-2', '功能主图1-2', '功能主图2-2'] + const rows = labels.map((label, index) => row(`r${index}`, `${label}-preview.webp`, index)) + const runs = groupPreviewRowsIntoRuns(rows) + expect(runs?.length).toBe(26) + const exts = ['.png', '.png', '.png', '.png', '.png', '.png', '.jpg', '.jpg', '.png', '.png', + '.jpg', '.jpg', '.png', '.png', '.png', '.png', '.png', '.png', '.png', '.png', + '.png', '.png', '.png', '.png', '.png', '.png'] + const entries = labels.map((label, i) => label + exts[i]) + const matched = matchRunsToZipEntries(runs!, entries) + expect(matched).toEqual(labels.map((_, i) => i)) + }) + + test('新代命名不受 -preview 剥离影响', () => { + // 源文件本身叫 photo-preview.jpg 的新代命名:剥尾后锚对不上条目 → 拒绝而非错配 + expect(parseTaskDetailPreviewFileName('photo-preview.webp')).toEqual({ label: 'photo', sliceIndex: null }) + const runs = groupPreviewRowsIntoRuns([row('a', 'photo-preview.webp', 0)]) + // 单图场景:锚剥错后走「剩余一一配对」兜底,1 对 1 无歧义,仍指向唯一条目 + expect(matchRunsToZipEntries(runs!, ['photo-preview.jpg'])).toEqual([0]) + }) +}) diff --git a/lib/task-detail-asset-edit.ts b/lib/task-detail-asset-edit.ts index c1d194c..b415dda 100644 --- a/lib/task-detail-asset-edit.ts +++ b/lib/task-detail-asset-edit.ts @@ -150,6 +150,15 @@ export function parseTaskDetailPreviewFileName(fileName: string): ParsedPreviewN sliceIndex: Number(sliceMatch[1]), } } + + // 历史客户端命名 `{原始基础名}-preview.webp`(如 `主图3-preview.webp`): + // 剥掉 -preview 尾巴才是与 ZIP 条目名对应的锚。误剥只会导致配不上被拒绝, + // 不会错配(锚定仍要求条目名唯一命中)。 + const previewTailMatch = /^(.+)-preview$/i.exec(withoutExtension) + if (previewTailMatch) { + return { label: previewTailMatch[1], sliceIndex: null } + } + return { label: withoutExtension, sliceIndex: null } }