接入草稿生成原生通知

平台壳生成完成和失败收口消费 notification.showLocal

新增 HostBridge 草稿通知 payload 与去重模型测试

迁移生成状态纯函数以通过组件 Fast Refresh 约束

更新原生壳方案、HostBridge 协议和共享决策记录
This commit is contained in:
2026-06-18 07:10:01 +08:00
parent e8c2e8d532
commit cdcbaf4cee
8 changed files with 258 additions and 70 deletions
@@ -176,7 +176,6 @@ import {
streamCreativeAgentMessage,
streamCreativeDraftEdit,
} from '../../services/creative-agent';
import { getExternalGenerationQueueOverview } from '../../services/external-generation';
import {
readCustomWorldAgentUiState,
shouldRestoreCustomWorldAgentUiState,
@@ -190,6 +189,8 @@ import {
regenerateBabyObjectMatchDraftAssets,
saveBabyObjectMatchDraft,
} from '../../services/edutainment-baby-object';
import { getExternalGenerationQueueOverview } from '../../services/external-generation';
import { showHostLocalNotification } from '../../services/host-bridge/hostBridge';
import {
jumpHopClient,
type JumpHopGalleryCardResponse,
@@ -224,7 +225,6 @@ import {
buildSquareHoleGenerationAnchorEntries,
buildWoodenFishGenerationAnchorEntries,
createMiniGameDraftGenerationState,
type MiniGameDraftGenerationKind,
type MiniGameDraftGenerationState,
resolveMiniGameDraftGenerationStartedAtMs,
} from '../../services/miniGameDraftGenerationProgress';
@@ -240,7 +240,6 @@ import {
buildSquareHolePublicWorkCode,
buildVisualNovelPublicWorkCode,
buildWoodenFishPublicWorkCode,
isSamePuzzleClearPublicWorkCode,
isSamePuzzlePublicWorkCode,
} from '../../services/publicWorkCode';
import {
@@ -356,8 +355,8 @@ import {
publishVisualNovelWork,
updateVisualNovelWork,
} from '../../services/visual-novel-works';
import { requestGenerationResultSubscribePermission } from '../../services/wechatMiniProgramSubscribe';
import { postWechatMiniProgramShareTarget } from '../../services/wechatMiniProgramShareTarget';
import { requestGenerationResultSubscribePermission } from '../../services/wechatMiniProgramSubscribe';
import {
woodenFishClient,
type WoodenFishGalleryCardResponse,
@@ -373,7 +372,6 @@ import { PlatformAcknowledgeStatusDialog } from '../common/PlatformAcknowledgeSt
import { PlatformActionButton } from '../common/PlatformActionButton';
import { PlatformDangerConfirmDialog } from '../common/PlatformDangerConfirmDialog';
import { PlatformFieldLabel } from '../common/PlatformFieldLabel';
import { PlatformStatusMessage } from '../common/PlatformStatusMessage';
import { PlatformSubpanel } from '../common/PlatformSubpanel';
import { PublishShareModal } from '../common/PublishShareModal';
import type { PublishShareModalPayload } from '../common/publishShareModalModel';
@@ -393,7 +391,6 @@ import {
isBigFishGalleryEntry,
isEdutainmentGalleryEntry,
isJumpHopGalleryEntry,
isPuzzleClearGalleryEntry,
isPuzzleGalleryEntry,
mapPuzzleClearWorkToPlatformGalleryCard,
type PlatformPublicGalleryCard,
@@ -459,7 +456,6 @@ import {
resolveWoodenFishCreationUrlRestoreStage,
} from './platformCreationUrlStateModel';
import { resolvePlatformCreationWorkDeleteConfirmationModel } from './platformCreationWorkDeleteFlow';
import { buildExternalGenerationQueueStatus } from './platformExternalGenerationQueueStatusModel';
import {
buildPlatformErrorDialogDismissKey,
buildPlatformTaskCompletionDialogDismissKey,
@@ -474,6 +470,10 @@ import {
resolveActivePlatformDialog,
resolvePlatformErrorDialog,
} from './platformDialogStateModel';
import {
type DraftGenerationPointNotice,
PlatformDraftGenerationPointNoticeDialog,
} from './PlatformDraftGenerationPointNoticeDialog';
import {
buildCreationWorkShelfRuntimeState,
buildDraftCompletionDialogSource,
@@ -511,10 +511,6 @@ import {
canExposePublicWork,
EDUTAINMENT_HIDDEN_MESSAGE,
} from './platformEdutainmentVisibility';
import {
PlatformDraftGenerationPointNoticeDialog,
type DraftGenerationPointNotice,
} from './PlatformDraftGenerationPointNoticeDialog';
import { PlatformEntryCreationTypeModal } from './PlatformEntryCreationTypeModal';
import type { PlatformCreationTypeId } from './platformEntryCreationTypes';
import {
@@ -543,8 +539,16 @@ import type {
} from './platformEntryTypes';
import { PlatformEntryWorldDetailView } from './PlatformEntryWorldDetailView';
import { PlatformErrorDialog } from './PlatformErrorDialog';
import { buildExternalGenerationQueueStatus } from './platformExternalGenerationQueueStatusModel';
import { PlatformFeedbackView } from './PlatformFeedbackView';
import { resolvePlatformGenerationProgressTickDecision } from './platformGenerationProgressTickModel';
import {
buildPlatformHostDraftFailureNotification,
buildPlatformHostDraftNotificationResetKeys,
buildPlatformHostDraftReadyNotification,
type PlatformHostDraftNotification,
sendPlatformHostDraftNotificationOnce,
} from './platformHostNotificationModel';
import {
buildMatch3DProfileFromSession,
hasMatch3DRuntimeAsset,
@@ -570,6 +574,7 @@ import {
rebaseMiniGameDraftBackgroundCompileTaskForDisplay,
rebaseMiniGameDraftGenerationStateForDisplay,
resolveFinishedMiniGameDraftGenerationState,
resolveMiniGameGenerationViewBusy,
} from './platformMiniGameDraftGenerationStateModel';
import {
buildJumpHopDraftActionPayload,
@@ -655,7 +660,6 @@ import {
buildPuzzleResultWorkId,
} from './platformPuzzleIdentityModel';
import { mergePuzzleServiceRuntimeState } from './platformPuzzleRuntimeStateModel';
import { buildPlatformRecommendedEntries } from './platformRecommendation';
import {
type PlatformPuzzleRuntimeAuthMode,
resolvePlatformRecommendRuntimeAuthPlan,
@@ -691,38 +695,6 @@ type PuzzleBackgroundCompileTask = {
error: string | null;
};
type MiniGameGenerationProgressTickStateMap = Partial<
Record<MiniGameDraftGenerationKind, MiniGameDraftGenerationState | null>
>;
export function resolveMiniGameGenerationProgressTickState(
selectionStage: SelectionStage,
states: MiniGameGenerationProgressTickStateMap,
) {
const stageKindMap: Partial<
Record<SelectionStage, MiniGameDraftGenerationKind>
> = {
'puzzle-generating': 'puzzle',
'big-fish-generating': 'big-fish',
'square-hole-generating': 'square-hole',
'match3d-generating': 'match3d',
'baby-object-match-generating': 'baby-object-match',
'jump-hop-generating': 'jump-hop',
'puzzle-clear-generating': 'puzzle-clear',
'wooden-fish-generating': 'wooden-fish',
};
const kind = stageKindMap[selectionStage];
return kind ? (states[kind] ?? null) : null;
}
export function resolveMiniGameGenerationViewBusy(
isBusy: boolean,
state: MiniGameDraftGenerationState | null | undefined,
) {
return isBusy || isMiniGameDraftGenerating(state ?? null);
}
function isExternalGenerationQueueStage(selectionStage: SelectionStage) {
return (
selectionStage === 'puzzle-generating' ||
@@ -913,7 +885,6 @@ const PUZZLE_DRAFT_GENERATION_POINT_COST = 2;
const PUZZLE_BACKGROUND_ACTION_POLL_INTERVAL_MS = 3000;
const PUZZLE_BACKGROUND_ACTION_MAX_POLL_ATTEMPTS = 160;
const MATCH3D_DRAFT_GENERATION_POINT_COST = 10;
const BARK_BATTLE_DRAFT_GENERATION_POINT_COST = 3;
function isPuzzleBackgroundAction(payload: PuzzleAgentActionRequest) {
return (
@@ -2027,6 +1998,9 @@ export function PlatformEntryFlowShellImpl({
const profileWalletLocalDeltaRef = useRef(0);
const lastProfileDashboardSnapshotRef =
useRef<ProfileDashboardSummary | null>(null);
const sentPlatformHostDraftNotificationKeysRef = useRef<Set<string>>(
new Set(),
);
const [
pendingPlatformTaskCompletionDialog,
setPendingPlatformTaskCompletionDialog,
@@ -2043,6 +2017,34 @@ export function PlatformEntryFlowShellImpl({
);
const handledPuzzleRuntimeUrlStateKeyRef = useRef<string | null>(null);
const sendPlatformHostDraftNotification = useCallback(
(notification: PlatformHostDraftNotification | null) => {
if (!notification) {
return;
}
sendPlatformHostDraftNotificationOnce(
sentPlatformHostDraftNotificationKeysRef.current,
notification,
showHostLocalNotification,
);
},
[],
);
const resetPlatformHostDraftNotifications = useCallback(
(kind: CreationWorkShelfKind, ids: Array<string | null | undefined>) => {
const sentKeys = sentPlatformHostDraftNotificationKeysRef.current;
for (const key of buildPlatformHostDraftNotificationResetKeys(
kind,
ids,
)) {
sentKeys.delete(key);
}
},
[],
);
useEffect(() => {
selectionStageRef.current = selectionStage;
}, [selectionStage]);
@@ -2173,12 +2175,14 @@ export function PlatformEntryFlowShellImpl({
(kind: CreationWorkShelfKind, ids: Array<string | null | undefined>) => {
setPendingPlatformTaskCompletionDialog(null);
setPendingPlatformTaskFailureDialog(null);
resetPlatformHostDraftNotifications(kind, ids);
updateDraftGenerationNotices(
collectDraftNoticeKeys(kind, ids),
'generating',
);
},
[
resetPlatformHostDraftNotifications,
setPendingPlatformTaskCompletionDialog,
setPendingPlatformTaskFailureDialog,
updateDraftGenerationNotices,
@@ -2198,6 +2202,9 @@ export function PlatformEntryFlowShellImpl({
);
setProfileTaskRefreshKey((current) => current + 1);
const completedAtMs = Date.now();
sendPlatformHostDraftNotification(
buildPlatformHostDraftReadyNotification(kind, ids),
);
setPendingPlatformTaskCompletionDialog({
key: `${kind}:${collectDraftNoticeKeys(kind, ids).join('|')}:${completedAtMs}`,
source: buildDraftCompletionDialogSource(kind, ids),
@@ -2206,6 +2213,7 @@ export function PlatformEntryFlowShellImpl({
});
},
[
sendPlatformHostDraftNotification,
setPendingPlatformTaskCompletionDialog,
setPendingPlatformTaskFailureDialog,
updateDraftGenerationNotices,
@@ -2224,6 +2232,13 @@ export function PlatformEntryFlowShellImpl({
const normalizedErrorMessage = errorMessage?.trim();
if (normalizedErrorMessage && showFailureDialog) {
const failedAtMs = Date.now();
sendPlatformHostDraftNotification(
buildPlatformHostDraftFailureNotification(
kind,
ids,
normalizedErrorMessage,
),
);
setPendingPlatformTaskFailureDialog({
key: `draft-failure:${kind}:${noticeKeys.join('|')}:${failedAtMs}`,
source: buildDraftCompletionDialogSource(kind, ids),
@@ -2233,6 +2248,7 @@ export function PlatformEntryFlowShellImpl({
}
},
[
sendPlatformHostDraftNotification,
setPendingPlatformTaskCompletionDialog,
setPendingPlatformTaskFailureDialog,
updateDraftGenerationNotices,
@@ -14356,25 +14372,6 @@ export function PlatformEntryFlowShellImpl({
openPublicWorkDetail(matchedEntry.detail);
};
const tryOpenPuzzleClearGalleryEntry = async () => {
const entries =
puzzleClearGalleryEntries.length > 0
? puzzleClearGalleryEntries
: await refreshPuzzleClearGallery();
const matchedEntry = entries.find((entry) => {
const detailEntry = mapPuzzleClearWorkToPlatformGalleryCard(entry);
return (
canExposePublicWork(detailEntry) &&
isSamePuzzleClearPublicWorkCode(normalizedKeyword, entry.profileId)
);
});
if (!matchedEntry) {
throw new Error('未找到拼消消作品。');
}
await openPuzzleClearPublicWorkDetail(matchedEntry.profileId);
};
const tryOpenMatch3DGalleryEntry = async () => {
const entries =
match3dGalleryEntries.length > 0