refactor: 收口作品架删除确认模型
This commit is contained in:
@@ -412,6 +412,7 @@ import {
|
||||
hasPuzzleRuntimeUrlStateValue,
|
||||
normalizeCreationUrlValue,
|
||||
} from './platformCreationUrlStateModel';
|
||||
import { resolvePlatformCreationWorkDeleteConfirmationModel } from './platformCreationWorkDeleteFlow';
|
||||
import {
|
||||
buildPlatformErrorDialogDismissKey,
|
||||
buildPlatformTaskCompletionDialogDismissKey,
|
||||
@@ -10212,12 +10213,16 @@ export function PlatformEntryFlowShellImpl({
|
||||
return;
|
||||
}
|
||||
|
||||
const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'rpg-library',
|
||||
entry,
|
||||
});
|
||||
requestDeleteCreationWork({
|
||||
id: entry.profileId,
|
||||
title: entry.worldName,
|
||||
detail: '删除后会从你的作品列表和公开广场中移除。',
|
||||
id: deleteModel.id,
|
||||
title: deleteModel.title,
|
||||
detail: deleteModel.detail,
|
||||
run: () => {
|
||||
setDeletingCreationWorkId(entry.profileId);
|
||||
setDeletingCreationWorkId(deleteModel.id);
|
||||
platformBootstrap.setPlatformError(null);
|
||||
|
||||
void deleteRpgEntryWorldProfile(entry.profileId)
|
||||
@@ -10245,21 +10250,17 @@ export function PlatformEntryFlowShellImpl({
|
||||
if (deletingCreationWorkId) {
|
||||
return;
|
||||
}
|
||||
const noticeKeys = collectDraftNoticeKeys('rpg', [
|
||||
work.workId,
|
||||
work.sessionId,
|
||||
work.profileId,
|
||||
]);
|
||||
const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'rpg',
|
||||
work,
|
||||
});
|
||||
|
||||
requestDeleteCreationWork({
|
||||
id: work.workId,
|
||||
title: work.title,
|
||||
detail:
|
||||
work.status === 'published'
|
||||
? '删除后会从你的作品列表和公开广场中移除。'
|
||||
: '删除后会从你的作品列表中移除。',
|
||||
id: deleteModel.id,
|
||||
title: deleteModel.title,
|
||||
detail: deleteModel.detail,
|
||||
run: () => {
|
||||
setDeletingCreationWorkId(work.workId);
|
||||
setDeletingCreationWorkId(deleteModel.id);
|
||||
platformBootstrap.setPlatformError(null);
|
||||
|
||||
const deleteTask =
|
||||
@@ -10282,7 +10283,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
|
||||
void deleteTask
|
||||
.then(async () => {
|
||||
markDraftNoticeSeen(noticeKeys);
|
||||
markDraftNoticeSeen(deleteModel.noticeKeys);
|
||||
await platformBootstrap.refreshPublishedGallery().catch(() => []);
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -10309,25 +10310,22 @@ export function PlatformEntryFlowShellImpl({
|
||||
if (deletingCreationWorkId) {
|
||||
return;
|
||||
}
|
||||
const noticeKeys = collectDraftNoticeKeys('big-fish', [
|
||||
work.workId,
|
||||
work.sourceSessionId,
|
||||
]);
|
||||
const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'big-fish',
|
||||
work,
|
||||
});
|
||||
|
||||
requestDeleteCreationWork({
|
||||
id: work.workId,
|
||||
title: work.title,
|
||||
detail:
|
||||
work.status === 'published'
|
||||
? '删除后会从你的作品列表和公开广场中移除。'
|
||||
: '删除后会从你的作品列表中移除。',
|
||||
id: deleteModel.id,
|
||||
title: deleteModel.title,
|
||||
detail: deleteModel.detail,
|
||||
run: () => {
|
||||
setDeletingCreationWorkId(work.workId);
|
||||
setDeletingCreationWorkId(deleteModel.id);
|
||||
setBigFishError(null);
|
||||
|
||||
void deleteBigFishWork(work.sourceSessionId)
|
||||
.then(async (response) => {
|
||||
markDraftNoticeSeen(noticeKeys);
|
||||
markDraftNoticeSeen(deleteModel.noticeKeys);
|
||||
setBigFishWorks(response.items);
|
||||
await refreshBigFishGallery().catch(() => []);
|
||||
})
|
||||
@@ -10357,31 +10355,22 @@ export function PlatformEntryFlowShellImpl({
|
||||
if (deletingCreationWorkId) {
|
||||
return;
|
||||
}
|
||||
const noticeKeys = collectDraftNoticeKeys('puzzle', [
|
||||
work.workId,
|
||||
work.profileId,
|
||||
work.sourceSessionId,
|
||||
buildPuzzleResultWorkId(work.sourceSessionId),
|
||||
buildPuzzleResultProfileId(work.sourceSessionId),
|
||||
]);
|
||||
|
||||
const displayName =
|
||||
work.workTitle?.trim() || work.levelName.trim() || '未命名拼图';
|
||||
const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'puzzle',
|
||||
work,
|
||||
});
|
||||
requestDeleteCreationWork({
|
||||
id: work.workId,
|
||||
title: displayName,
|
||||
detail:
|
||||
work.publicationStatus === 'published'
|
||||
? '删除后会从你的作品列表和公开广场中移除。'
|
||||
: '删除后会从你的作品列表中移除。',
|
||||
id: deleteModel.id,
|
||||
title: deleteModel.title,
|
||||
detail: deleteModel.detail,
|
||||
run: () => {
|
||||
setDeletingCreationWorkId(work.workId);
|
||||
setDeletingCreationWorkId(deleteModel.id);
|
||||
setPuzzleFormDraftPayload(null);
|
||||
setPuzzleError(null);
|
||||
|
||||
void deletePuzzleWork(work.profileId)
|
||||
.then((response) => {
|
||||
markDraftNoticeSeen(noticeKeys);
|
||||
markDraftNoticeSeen(deleteModel.noticeKeys);
|
||||
setPuzzleWorks(response.items);
|
||||
void refreshPuzzleGallery();
|
||||
})
|
||||
@@ -10411,27 +10400,23 @@ export function PlatformEntryFlowShellImpl({
|
||||
if (deletingCreationWorkId) {
|
||||
return;
|
||||
}
|
||||
const noticeKeys = collectDraftNoticeKeys('match3d', [
|
||||
work.workId,
|
||||
work.profileId,
|
||||
work.sourceSessionId,
|
||||
]);
|
||||
const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'match3d',
|
||||
work,
|
||||
});
|
||||
|
||||
requestDeleteCreationWork({
|
||||
id: work.workId,
|
||||
title: work.gameName,
|
||||
detail:
|
||||
work.publicationStatus === 'published'
|
||||
? '删除后会从你的作品列表和公开广场中移除。'
|
||||
: '删除后会从你的作品列表中移除。',
|
||||
id: deleteModel.id,
|
||||
title: deleteModel.title,
|
||||
detail: deleteModel.detail,
|
||||
run: () => {
|
||||
setDeletingCreationWorkId(work.workId);
|
||||
setDeletingCreationWorkId(deleteModel.id);
|
||||
setMatch3DFormDraftPayload(null);
|
||||
setMatch3DError(null);
|
||||
|
||||
void deleteMatch3DWork(work.profileId)
|
||||
.then((response) => {
|
||||
markDraftNoticeSeen(noticeKeys);
|
||||
markDraftNoticeSeen(deleteModel.noticeKeys);
|
||||
setMatch3DWorks(mapMatch3DWorksForRuntimeUi(response.items));
|
||||
void refreshMatch3DGallery();
|
||||
})
|
||||
@@ -10462,26 +10447,22 @@ export function PlatformEntryFlowShellImpl({
|
||||
if (deletingCreationWorkId) {
|
||||
return;
|
||||
}
|
||||
const noticeKeys = collectDraftNoticeKeys('square-hole', [
|
||||
work.workId,
|
||||
work.profileId,
|
||||
work.sourceSessionId,
|
||||
]);
|
||||
const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'square-hole',
|
||||
work,
|
||||
});
|
||||
|
||||
requestDeleteCreationWork({
|
||||
id: work.workId,
|
||||
title: work.gameName,
|
||||
detail:
|
||||
work.publicationStatus === 'published'
|
||||
? '删除后会从你的作品列表和公开广场中移除。'
|
||||
: '删除后会从你的作品列表中移除。',
|
||||
id: deleteModel.id,
|
||||
title: deleteModel.title,
|
||||
detail: deleteModel.detail,
|
||||
run: () => {
|
||||
setDeletingCreationWorkId(work.workId);
|
||||
setDeletingCreationWorkId(deleteModel.id);
|
||||
setSquareHoleError(null);
|
||||
|
||||
void deleteSquareHoleWork(work.profileId)
|
||||
.then((response) => {
|
||||
markDraftNoticeSeen(noticeKeys);
|
||||
markDraftNoticeSeen(deleteModel.noticeKeys);
|
||||
setSquareHoleWorks(response.items);
|
||||
void refreshSquareHoleGallery();
|
||||
})
|
||||
@@ -10511,24 +10492,22 @@ export function PlatformEntryFlowShellImpl({
|
||||
if (deletingCreationWorkId) {
|
||||
return;
|
||||
}
|
||||
const noticeKeys = collectDraftNoticeKeys('visual-novel', [
|
||||
work.profileId,
|
||||
]);
|
||||
const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'visual-novel',
|
||||
work,
|
||||
});
|
||||
|
||||
requestDeleteCreationWork({
|
||||
id: work.profileId,
|
||||
title: work.title || '未命名视觉小说',
|
||||
detail:
|
||||
work.publishStatus === 'published'
|
||||
? '删除后会从你的作品列表和公开广场中移除。'
|
||||
: '删除后会从你的作品列表中移除。',
|
||||
id: deleteModel.id,
|
||||
title: deleteModel.title,
|
||||
detail: deleteModel.detail,
|
||||
run: () => {
|
||||
setDeletingCreationWorkId(work.profileId);
|
||||
setDeletingCreationWorkId(deleteModel.id);
|
||||
setVisualNovelError(null);
|
||||
|
||||
void deleteVisualNovelWork(work.profileId)
|
||||
.then(async (response) => {
|
||||
markDraftNoticeSeen(noticeKeys);
|
||||
markDraftNoticeSeen(deleteModel.noticeKeys);
|
||||
setVisualNovelWorks(response.works);
|
||||
await refreshVisualNovelGallery();
|
||||
})
|
||||
@@ -10558,26 +10537,22 @@ export function PlatformEntryFlowShellImpl({
|
||||
if (deletingCreationWorkId) {
|
||||
return;
|
||||
}
|
||||
const noticeKeys = collectDraftNoticeKeys('baby-object-match', [
|
||||
work.profileId,
|
||||
work.draftId,
|
||||
]);
|
||||
const displayName = work.workTitle.trim() || work.templateName;
|
||||
const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'baby-object-match',
|
||||
work,
|
||||
});
|
||||
|
||||
requestDeleteCreationWork({
|
||||
id: work.profileId,
|
||||
title: displayName,
|
||||
detail:
|
||||
work.publicationStatus === 'published'
|
||||
? '删除后会从你的作品列表和寓教于乐板块中移除。'
|
||||
: '删除后会从你的作品列表中移除。',
|
||||
id: deleteModel.id,
|
||||
title: deleteModel.title,
|
||||
detail: deleteModel.detail,
|
||||
run: () => {
|
||||
setDeletingCreationWorkId(work.profileId);
|
||||
setDeletingCreationWorkId(deleteModel.id);
|
||||
setBabyObjectMatchError(null);
|
||||
|
||||
void deleteLocalBabyObjectMatchDraft(work.profileId)
|
||||
.then((nextDrafts) => {
|
||||
markDraftNoticeSeen(noticeKeys);
|
||||
markDraftNoticeSeen(deleteModel.noticeKeys);
|
||||
setBabyObjectMatchDrafts(nextDrafts);
|
||||
setBabyObjectMatchDraft((current) =>
|
||||
current?.profileId === work.profileId ? null : current,
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary';
|
||||
import type { CustomWorldWorkSummary } from '../../../packages/shared/src/contracts/customWorldWorkSummary';
|
||||
import type { BabyObjectMatchDraft } from '../../../packages/shared/src/contracts/edutainmentBabyObject';
|
||||
import type { Match3DWorkSummary } from '../../../packages/shared/src/contracts/match3dWorks';
|
||||
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
|
||||
import type { SquareHoleWorkSummary } from '../../../packages/shared/src/contracts/squareHoleWorks';
|
||||
import type { VisualNovelWorkSummary } from '../../../packages/shared/src/contracts/visualNovel';
|
||||
import { resolvePlatformCreationWorkDeleteConfirmationModel } from './platformCreationWorkDeleteFlow';
|
||||
|
||||
describe('platformCreationWorkDeleteFlow', () => {
|
||||
test('resolves RPG library delete confirmation without draft notice keys', () => {
|
||||
expect(
|
||||
resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'rpg-library',
|
||||
entry: {
|
||||
profileId: 'rpg-profile',
|
||||
worldName: '潮雾列岛',
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
id: 'rpg-profile',
|
||||
title: '潮雾列岛',
|
||||
detail: '删除后会从你的作品列表和公开广场中移除。',
|
||||
noticeKeys: [],
|
||||
});
|
||||
});
|
||||
|
||||
test('resolves RPG work delete detail and notice keys by work status', () => {
|
||||
expect(
|
||||
resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'rpg',
|
||||
work: buildRpgWork(),
|
||||
}),
|
||||
).toEqual({
|
||||
id: 'rpg-work',
|
||||
title: 'RPG 草稿',
|
||||
detail: '删除后会从你的作品列表中移除。',
|
||||
noticeKeys: ['rpg:rpg-work', 'rpg:rpg-session', 'rpg:rpg-profile'],
|
||||
});
|
||||
|
||||
expect(
|
||||
resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'rpg',
|
||||
work: buildRpgWork({ status: 'published' }),
|
||||
}).detail,
|
||||
).toBe('删除后会从你的作品列表和公开广场中移除。');
|
||||
});
|
||||
|
||||
test('resolves mini game delete models with shared public and private detail copy', () => {
|
||||
expect(
|
||||
resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'big-fish',
|
||||
work: buildBigFishWork({ status: 'published' }),
|
||||
}),
|
||||
).toMatchObject({
|
||||
id: 'big-fish-work',
|
||||
title: '大鱼作品',
|
||||
detail: '删除后会从你的作品列表和公开广场中移除。',
|
||||
noticeKeys: ['big-fish:big-fish-work', 'big-fish:big-fish-session'],
|
||||
});
|
||||
|
||||
expect(
|
||||
resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'match3d',
|
||||
work: buildMatch3DWork(),
|
||||
}).detail,
|
||||
).toBe('删除后会从你的作品列表中移除。');
|
||||
expect(
|
||||
resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'square-hole',
|
||||
work: buildSquareHoleWork({ publicationStatus: 'published' }),
|
||||
}).noticeKeys,
|
||||
).toEqual([
|
||||
'square-hole:square-hole-work',
|
||||
'square-hole:square-hole-profile',
|
||||
'square-hole:square-hole-session',
|
||||
]);
|
||||
});
|
||||
|
||||
test('resolves puzzle title fallback and stable result notice keys', () => {
|
||||
expect(
|
||||
resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'puzzle',
|
||||
work: buildPuzzleWork({
|
||||
workTitle: ' ',
|
||||
levelName: ' 雾港第一关 ',
|
||||
sourceSessionId: 'puzzle-session-ocean',
|
||||
}),
|
||||
}),
|
||||
).toEqual({
|
||||
id: 'puzzle-work',
|
||||
title: '雾港第一关',
|
||||
detail: '删除后会从你的作品列表中移除。',
|
||||
noticeKeys: [
|
||||
'puzzle:puzzle-work',
|
||||
'puzzle:puzzle-profile',
|
||||
'puzzle:puzzle-session-ocean',
|
||||
'puzzle:puzzle-work-ocean',
|
||||
'puzzle:puzzle-profile-ocean',
|
||||
],
|
||||
});
|
||||
|
||||
expect(
|
||||
resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'puzzle',
|
||||
work: buildPuzzleWork({ workTitle: '', levelName: ' ' }),
|
||||
}).title,
|
||||
).toBe('未命名拼图');
|
||||
});
|
||||
|
||||
test('resolves visual novel and baby object match special delete copy', () => {
|
||||
expect(
|
||||
resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'visual-novel',
|
||||
work: buildVisualNovelWork({ title: '', publishStatus: 'published' }),
|
||||
}),
|
||||
).toEqual({
|
||||
id: 'visual-novel-profile',
|
||||
title: '未命名视觉小说',
|
||||
detail: '删除后会从你的作品列表和公开广场中移除。',
|
||||
noticeKeys: ['visual-novel:visual-novel-profile'],
|
||||
});
|
||||
|
||||
expect(
|
||||
resolvePlatformCreationWorkDeleteConfirmationModel({
|
||||
kind: 'baby-object-match',
|
||||
work: buildBabyObjectMatchDraft({
|
||||
workTitle: ' ',
|
||||
publicationStatus: 'published',
|
||||
}),
|
||||
}),
|
||||
).toEqual({
|
||||
id: 'baby-profile',
|
||||
title: '宝贝识物',
|
||||
detail: '删除后会从你的作品列表和寓教于乐板块中移除。',
|
||||
noticeKeys: [
|
||||
'baby-object-match:baby-profile',
|
||||
'baby-object-match:baby-draft',
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function buildRpgWork(
|
||||
overrides: Partial<CustomWorldWorkSummary> = {},
|
||||
): CustomWorldWorkSummary {
|
||||
return {
|
||||
workId: 'rpg-work',
|
||||
sourceType: 'agent_session',
|
||||
status: 'draft',
|
||||
title: 'RPG 草稿',
|
||||
subtitle: '待完善',
|
||||
summary: 'RPG 摘要。',
|
||||
coverImageSrc: null,
|
||||
updatedAt: '2026-06-04T00:00:00.000Z',
|
||||
publishedAt: null,
|
||||
stage: 'draft',
|
||||
stageLabel: '草稿',
|
||||
playableNpcCount: 1,
|
||||
landmarkCount: 1,
|
||||
sessionId: 'rpg-session',
|
||||
profileId: 'rpg-profile',
|
||||
canResume: true,
|
||||
canEnterWorld: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function buildBigFishWork(
|
||||
overrides: Partial<BigFishWorkSummary> = {},
|
||||
): BigFishWorkSummary {
|
||||
return {
|
||||
workId: 'big-fish-work',
|
||||
sourceSessionId: 'big-fish-session',
|
||||
ownerUserId: 'user-1',
|
||||
authorDisplayName: '玩家',
|
||||
title: '大鱼作品',
|
||||
subtitle: '大鱼吃小鱼',
|
||||
summary: '大鱼摘要。',
|
||||
coverImageSrc: null,
|
||||
status: 'draft',
|
||||
updatedAt: '2026-06-04T00:00:00.000Z',
|
||||
publishedAt: null,
|
||||
publishReady: false,
|
||||
levelCount: 1,
|
||||
levelMainImageReadyCount: 0,
|
||||
levelMotionReadyCount: 0,
|
||||
backgroundReady: true,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function buildPuzzleWork(
|
||||
overrides: Partial<PuzzleWorkSummary> = {},
|
||||
): PuzzleWorkSummary {
|
||||
return {
|
||||
workId: 'puzzle-work',
|
||||
profileId: 'puzzle-profile',
|
||||
ownerUserId: 'user-1',
|
||||
sourceSessionId: 'puzzle-session',
|
||||
authorDisplayName: '玩家',
|
||||
workTitle: '拼图作品',
|
||||
workDescription: '拼图摘要。',
|
||||
levelName: '拼图第一关',
|
||||
summary: '拼图摘要。',
|
||||
themeTags: [],
|
||||
coverImageSrc: null,
|
||||
coverAssetId: null,
|
||||
publicationStatus: 'draft',
|
||||
updatedAt: '2026-06-04T00:00:00.000Z',
|
||||
publishedAt: null,
|
||||
playCount: 0,
|
||||
remixCount: 0,
|
||||
likeCount: 0,
|
||||
publishReady: false,
|
||||
levels: [],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function buildMatch3DWork(
|
||||
overrides: Partial<Match3DWorkSummary> = {},
|
||||
): Match3DWorkSummary {
|
||||
return {
|
||||
workId: 'match3d-work',
|
||||
profileId: 'match3d-profile',
|
||||
ownerUserId: 'user-1',
|
||||
sourceSessionId: 'match3d-session',
|
||||
gameName: '抓大鹅作品',
|
||||
themeText: '糖果厨房',
|
||||
summary: '抓大鹅摘要。',
|
||||
tags: [],
|
||||
coverImageSrc: null,
|
||||
referenceImageSrc: null,
|
||||
clearCount: 12,
|
||||
difficulty: 4,
|
||||
publicationStatus: 'draft',
|
||||
playCount: 0,
|
||||
updatedAt: '2026-06-04T00:00:00.000Z',
|
||||
publishedAt: null,
|
||||
publishReady: false,
|
||||
generatedItemAssets: [],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function buildSquareHoleWork(
|
||||
overrides: Partial<SquareHoleWorkSummary> = {},
|
||||
): SquareHoleWorkSummary {
|
||||
return {
|
||||
workId: 'square-hole-work',
|
||||
profileId: 'square-hole-profile',
|
||||
ownerUserId: 'user-1',
|
||||
sourceSessionId: 'square-hole-session',
|
||||
gameName: '方洞作品',
|
||||
themeText: '图形',
|
||||
twistRule: '反直觉',
|
||||
summary: '方洞摘要。',
|
||||
tags: [],
|
||||
coverImageSrc: null,
|
||||
backgroundPrompt: '背景',
|
||||
backgroundImageSrc: null,
|
||||
shapeOptions: [],
|
||||
holeOptions: [],
|
||||
shapeCount: 8,
|
||||
difficulty: 4,
|
||||
publicationStatus: 'draft',
|
||||
playCount: 0,
|
||||
updatedAt: '2026-06-04T00:00:00.000Z',
|
||||
publishedAt: null,
|
||||
publishReady: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function buildVisualNovelWork(
|
||||
overrides: Partial<VisualNovelWorkSummary> = {},
|
||||
): VisualNovelWorkSummary {
|
||||
return {
|
||||
runtimeKind: 'visual-novel',
|
||||
profileId: 'visual-novel-profile',
|
||||
ownerUserId: 'user-1',
|
||||
title: '视觉小说作品',
|
||||
description: '视觉小说摘要。',
|
||||
coverImageSrc: null,
|
||||
tags: [],
|
||||
publishStatus: 'draft',
|
||||
publishReady: false,
|
||||
playCount: 0,
|
||||
updatedAt: '2026-06-04T00:00:00.000Z',
|
||||
publishedAt: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function buildBabyObjectMatchDraft(
|
||||
overrides: Partial<BabyObjectMatchDraft> = {},
|
||||
): BabyObjectMatchDraft {
|
||||
return {
|
||||
draftId: 'baby-draft',
|
||||
profileId: 'baby-profile',
|
||||
templateId: 'baby-object-match',
|
||||
templateName: '宝贝识物',
|
||||
workTitle: '宝贝识物作品',
|
||||
workDescription: '宝贝识物摘要。',
|
||||
itemNames: ['苹果', '香蕉'],
|
||||
itemAssets: [
|
||||
{
|
||||
itemId: 'apple',
|
||||
itemName: '苹果',
|
||||
imageSrc: '/apple.png',
|
||||
assetObjectId: null,
|
||||
generationProvider: 'placeholder',
|
||||
prompt: '苹果',
|
||||
},
|
||||
{
|
||||
itemId: 'banana',
|
||||
itemName: '香蕉',
|
||||
imageSrc: '/banana.png',
|
||||
assetObjectId: null,
|
||||
generationProvider: 'placeholder',
|
||||
prompt: '香蕉',
|
||||
},
|
||||
],
|
||||
themeTags: [],
|
||||
publicationStatus: 'draft',
|
||||
createdAt: '2026-06-04T00:00:00.000Z',
|
||||
updatedAt: '2026-06-04T00:00:00.000Z',
|
||||
publishedAt: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
288
src/components/platform-entry/platformCreationWorkDeleteFlow.ts
Normal file
288
src/components/platform-entry/platformCreationWorkDeleteFlow.ts
Normal file
@@ -0,0 +1,288 @@
|
||||
import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary';
|
||||
import type { CustomWorldWorkSummary } from '../../../packages/shared/src/contracts/customWorldWorkSummary';
|
||||
import type { BabyObjectMatchDraft } from '../../../packages/shared/src/contracts/edutainmentBabyObject';
|
||||
import type { Match3DWorkSummary } from '../../../packages/shared/src/contracts/match3dWorks';
|
||||
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
|
||||
import type { CustomWorldLibraryEntry } from '../../../packages/shared/src/contracts/runtime';
|
||||
import type { SquareHoleWorkSummary } from '../../../packages/shared/src/contracts/squareHoleWorks';
|
||||
import type { VisualNovelWorkSummary } from '../../../packages/shared/src/contracts/visualNovel';
|
||||
import {
|
||||
buildPuzzleResultProfileId,
|
||||
buildPuzzleResultWorkId,
|
||||
collectDraftNoticeKeys,
|
||||
} from './platformDraftGenerationShelfModel';
|
||||
|
||||
const PRIVATE_WORK_DELETE_DETAIL = '删除后会从你的作品列表中移除。';
|
||||
const PUBLIC_GALLERY_DELETE_DETAIL = '删除后会从你的作品列表和公开广场中移除。';
|
||||
const EDUTAINMENT_PUBLIC_DELETE_DETAIL =
|
||||
'删除后会从你的作品列表和寓教于乐板块中移除。';
|
||||
|
||||
export type PlatformCreationWorkDeleteConfirmationModel = {
|
||||
id: string;
|
||||
title: string;
|
||||
detail: string;
|
||||
noticeKeys: string[];
|
||||
};
|
||||
|
||||
export type PlatformCreationWorkDeleteInput =
|
||||
| {
|
||||
kind: 'rpg-library';
|
||||
entry: Pick<CustomWorldLibraryEntry<unknown>, 'profileId' | 'worldName'>;
|
||||
}
|
||||
| {
|
||||
kind: 'rpg';
|
||||
work: Pick<
|
||||
CustomWorldWorkSummary,
|
||||
'workId' | 'title' | 'status' | 'sessionId' | 'profileId'
|
||||
>;
|
||||
}
|
||||
| {
|
||||
kind: 'big-fish';
|
||||
work: Pick<
|
||||
BigFishWorkSummary,
|
||||
'workId' | 'title' | 'status' | 'sourceSessionId'
|
||||
>;
|
||||
}
|
||||
| {
|
||||
kind: 'puzzle';
|
||||
work: Pick<
|
||||
PuzzleWorkSummary,
|
||||
| 'workId'
|
||||
| 'profileId'
|
||||
| 'sourceSessionId'
|
||||
| 'workTitle'
|
||||
| 'levelName'
|
||||
| 'publicationStatus'
|
||||
>;
|
||||
}
|
||||
| {
|
||||
kind: 'match3d';
|
||||
work: Pick<
|
||||
Match3DWorkSummary,
|
||||
| 'workId'
|
||||
| 'profileId'
|
||||
| 'sourceSessionId'
|
||||
| 'gameName'
|
||||
| 'publicationStatus'
|
||||
>;
|
||||
}
|
||||
| {
|
||||
kind: 'square-hole';
|
||||
work: Pick<
|
||||
SquareHoleWorkSummary,
|
||||
| 'workId'
|
||||
| 'profileId'
|
||||
| 'sourceSessionId'
|
||||
| 'gameName'
|
||||
| 'publicationStatus'
|
||||
>;
|
||||
}
|
||||
| {
|
||||
kind: 'visual-novel';
|
||||
work: Pick<
|
||||
VisualNovelWorkSummary,
|
||||
'profileId' | 'title' | 'publishStatus'
|
||||
>;
|
||||
}
|
||||
| {
|
||||
kind: 'baby-object-match';
|
||||
work: Pick<
|
||||
BabyObjectMatchDraft,
|
||||
| 'profileId'
|
||||
| 'draftId'
|
||||
| 'workTitle'
|
||||
| 'templateName'
|
||||
| 'publicationStatus'
|
||||
>;
|
||||
};
|
||||
|
||||
export function resolvePlatformCreationWorkDeleteConfirmationModel(
|
||||
input: PlatformCreationWorkDeleteInput,
|
||||
): PlatformCreationWorkDeleteConfirmationModel {
|
||||
switch (input.kind) {
|
||||
case 'rpg-library':
|
||||
return resolveRpgLibraryDeleteConfirmationModel(input.entry);
|
||||
case 'rpg':
|
||||
return resolveRpgWorkDeleteConfirmationModel(input.work);
|
||||
case 'big-fish':
|
||||
return resolveBigFishWorkDeleteConfirmationModel(input.work);
|
||||
case 'puzzle':
|
||||
return resolvePuzzleWorkDeleteConfirmationModel(input.work);
|
||||
case 'match3d':
|
||||
return resolveMatch3DWorkDeleteConfirmationModel(input.work);
|
||||
case 'square-hole':
|
||||
return resolveSquareHoleWorkDeleteConfirmationModel(input.work);
|
||||
case 'visual-novel':
|
||||
return resolveVisualNovelWorkDeleteConfirmationModel(input.work);
|
||||
case 'baby-object-match':
|
||||
return resolveBabyObjectMatchDeleteConfirmationModel(input.work);
|
||||
default: {
|
||||
const exhaustive: never = input;
|
||||
return exhaustive;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveStatusDeleteDetail(
|
||||
status: string,
|
||||
publishedDetail = PUBLIC_GALLERY_DELETE_DETAIL,
|
||||
) {
|
||||
return status === 'published' ? publishedDetail : PRIVATE_WORK_DELETE_DETAIL;
|
||||
}
|
||||
|
||||
function resolveTrimmedTitle(
|
||||
value: string | null | undefined,
|
||||
fallback: string,
|
||||
) {
|
||||
const trimmedValue = value?.trim();
|
||||
return trimmedValue || fallback;
|
||||
}
|
||||
|
||||
function resolveRpgLibraryDeleteConfirmationModel(
|
||||
entry: Pick<CustomWorldLibraryEntry<unknown>, 'profileId' | 'worldName'>,
|
||||
): PlatformCreationWorkDeleteConfirmationModel {
|
||||
return {
|
||||
id: entry.profileId,
|
||||
title: entry.worldName,
|
||||
detail: PUBLIC_GALLERY_DELETE_DETAIL,
|
||||
noticeKeys: [],
|
||||
};
|
||||
}
|
||||
|
||||
function resolveRpgWorkDeleteConfirmationModel(
|
||||
work: Pick<
|
||||
CustomWorldWorkSummary,
|
||||
'workId' | 'title' | 'status' | 'sessionId' | 'profileId'
|
||||
>,
|
||||
): PlatformCreationWorkDeleteConfirmationModel {
|
||||
return {
|
||||
id: work.workId,
|
||||
title: work.title,
|
||||
detail: resolveStatusDeleteDetail(work.status),
|
||||
noticeKeys: collectDraftNoticeKeys('rpg', [
|
||||
work.workId,
|
||||
work.sessionId,
|
||||
work.profileId,
|
||||
]),
|
||||
};
|
||||
}
|
||||
|
||||
function resolveBigFishWorkDeleteConfirmationModel(
|
||||
work: Pick<
|
||||
BigFishWorkSummary,
|
||||
'workId' | 'title' | 'status' | 'sourceSessionId'
|
||||
>,
|
||||
): PlatformCreationWorkDeleteConfirmationModel {
|
||||
return {
|
||||
id: work.workId,
|
||||
title: work.title,
|
||||
detail: resolveStatusDeleteDetail(work.status),
|
||||
noticeKeys: collectDraftNoticeKeys('big-fish', [
|
||||
work.workId,
|
||||
work.sourceSessionId,
|
||||
]),
|
||||
};
|
||||
}
|
||||
|
||||
function resolvePuzzleWorkDeleteConfirmationModel(
|
||||
work: Pick<
|
||||
PuzzleWorkSummary,
|
||||
| 'workId'
|
||||
| 'profileId'
|
||||
| 'sourceSessionId'
|
||||
| 'workTitle'
|
||||
| 'levelName'
|
||||
| 'publicationStatus'
|
||||
>,
|
||||
): PlatformCreationWorkDeleteConfirmationModel {
|
||||
return {
|
||||
id: work.workId,
|
||||
title: resolveTrimmedTitle(
|
||||
work.workTitle,
|
||||
resolveTrimmedTitle(work.levelName, '未命名拼图'),
|
||||
),
|
||||
detail: resolveStatusDeleteDetail(work.publicationStatus),
|
||||
noticeKeys: collectDraftNoticeKeys('puzzle', [
|
||||
work.workId,
|
||||
work.profileId,
|
||||
work.sourceSessionId,
|
||||
buildPuzzleResultWorkId(work.sourceSessionId),
|
||||
buildPuzzleResultProfileId(work.sourceSessionId),
|
||||
]),
|
||||
};
|
||||
}
|
||||
|
||||
function resolveMatch3DWorkDeleteConfirmationModel(
|
||||
work: Pick<
|
||||
Match3DWorkSummary,
|
||||
| 'workId'
|
||||
| 'profileId'
|
||||
| 'sourceSessionId'
|
||||
| 'gameName'
|
||||
| 'publicationStatus'
|
||||
>,
|
||||
): PlatformCreationWorkDeleteConfirmationModel {
|
||||
return {
|
||||
id: work.workId,
|
||||
title: work.gameName,
|
||||
detail: resolveStatusDeleteDetail(work.publicationStatus),
|
||||
noticeKeys: collectDraftNoticeKeys('match3d', [
|
||||
work.workId,
|
||||
work.profileId,
|
||||
work.sourceSessionId,
|
||||
]),
|
||||
};
|
||||
}
|
||||
|
||||
function resolveSquareHoleWorkDeleteConfirmationModel(
|
||||
work: Pick<
|
||||
SquareHoleWorkSummary,
|
||||
| 'workId'
|
||||
| 'profileId'
|
||||
| 'sourceSessionId'
|
||||
| 'gameName'
|
||||
| 'publicationStatus'
|
||||
>,
|
||||
): PlatformCreationWorkDeleteConfirmationModel {
|
||||
return {
|
||||
id: work.workId,
|
||||
title: work.gameName,
|
||||
detail: resolveStatusDeleteDetail(work.publicationStatus),
|
||||
noticeKeys: collectDraftNoticeKeys('square-hole', [
|
||||
work.workId,
|
||||
work.profileId,
|
||||
work.sourceSessionId,
|
||||
]),
|
||||
};
|
||||
}
|
||||
|
||||
function resolveVisualNovelWorkDeleteConfirmationModel(
|
||||
work: Pick<VisualNovelWorkSummary, 'profileId' | 'title' | 'publishStatus'>,
|
||||
): PlatformCreationWorkDeleteConfirmationModel {
|
||||
return {
|
||||
id: work.profileId,
|
||||
title: work.title || '未命名视觉小说',
|
||||
detail: resolveStatusDeleteDetail(work.publishStatus),
|
||||
noticeKeys: collectDraftNoticeKeys('visual-novel', [work.profileId]),
|
||||
};
|
||||
}
|
||||
|
||||
function resolveBabyObjectMatchDeleteConfirmationModel(
|
||||
work: Pick<
|
||||
BabyObjectMatchDraft,
|
||||
'profileId' | 'draftId' | 'workTitle' | 'templateName' | 'publicationStatus'
|
||||
>,
|
||||
): PlatformCreationWorkDeleteConfirmationModel {
|
||||
return {
|
||||
id: work.profileId,
|
||||
title: resolveTrimmedTitle(work.workTitle, work.templateName),
|
||||
detail: resolveStatusDeleteDetail(
|
||||
work.publicationStatus,
|
||||
EDUTAINMENT_PUBLIC_DELETE_DETAIL,
|
||||
),
|
||||
noticeKeys: collectDraftNoticeKeys('baby-object-match', [
|
||||
work.profileId,
|
||||
work.draftId,
|
||||
]),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user