收口标准泥点确认弹窗

新增 PlatformMudPointConfirmDialog 统一承接标准泥点消耗确认壳层
迁移拼图与抓大鹅创作工作台复用共享泥点确认弹窗
迁移拼图与抓大鹅结果页素材生成流程复用共享泥点确认弹窗
补充共享组件测试并更新 PlatformUiKit 收口文档与决策记录
This commit is contained in:
2026-06-10 21:57:49 +08:00
parent a33914aa5a
commit dbfdb9b99b
8 changed files with 138 additions and 41 deletions

View File

@@ -0,0 +1,53 @@
/* @vitest-environment jsdom */
import { fireEvent, render, screen, within } from '@testing-library/react';
import { expect, test, vi } from 'vitest';
import { PlatformMudPointConfirmDialog } from './PlatformMudPointConfirmDialog';
test('renders standard mud point confirmation copy and forwards confirm', () => {
const onClose = vi.fn();
const onConfirm = vi.fn();
render(
<PlatformMudPointConfirmDialog
open
points={8}
onClose={onClose}
onConfirm={onConfirm}
portal={false}
/>,
);
const dialog = screen.getByRole('dialog', { name: '确认消耗泥点' });
expect(within(dialog).getByText('消耗 8 泥点')).toBeTruthy();
fireEvent.click(within(dialog).getByRole('button', { name: '确定' }));
expect(onConfirm).toHaveBeenCalledTimes(1);
});
test('supports extra detail copy and close button override', () => {
const onClose = vi.fn();
render(
<PlatformMudPointConfirmDialog
open
points={7}
title="保存正式素材"
description="角色形象"
onClose={onClose}
onConfirm={vi.fn()}
showCloseButton={false}
portal={false}
>
</PlatformMudPointConfirmDialog>,
);
const dialog = screen.getByRole('dialog', { name: '保存正式素材' });
expect(within(dialog).getByText('消耗 7 泥点')).toBeTruthy();
expect(within(dialog).getByText('本次会覆盖当前待确认素材。')).toBeTruthy();
expect(screen.queryByRole('button', { name: '关闭' })).toBeNull();
});

View File

@@ -0,0 +1,64 @@
import type { ReactNode } from 'react';
import { UnifiedConfirmDialog } from './UnifiedConfirmDialog';
type PlatformMudPointConfirmDialogProps = {
open: boolean;
points: number;
onClose: () => void;
onConfirm: () => void;
confirmDisabled?: boolean;
confirmLabel?: string;
title?: string;
description?: ReactNode;
children?: ReactNode;
showCloseButton?: boolean;
portal?: boolean;
size?: 'sm' | 'md';
overlayClassName?: string;
panelClassName?: string;
};
/**
* 平台泥点消耗确认弹窗。
* 统一承接“确认消耗泥点 + 消耗 N 泥点”的标准确认壳层,业务侧只保留点数与确认动作。
*/
export function PlatformMudPointConfirmDialog({
open,
points,
onClose,
onConfirm,
confirmDisabled = false,
confirmLabel = '确定',
title = '确认消耗泥点',
description,
children,
showCloseButton = true,
portal = true,
size = 'sm',
overlayClassName,
panelClassName,
}: PlatformMudPointConfirmDialogProps) {
return (
<UnifiedConfirmDialog
open={open}
title={title}
description={description}
onClose={onClose}
onConfirm={onConfirm}
confirmLabel={confirmLabel}
confirmDisabled={confirmDisabled}
showCancel
showCloseButton={showCloseButton}
portal={portal}
size={size}
overlayClassName={overlayClassName}
panelClassName={panelClassName}
>
<div className="space-y-2">
<div className="font-semibold"> {points} </div>
{children}
</div>
</UnifiedConfirmDialog>
);
}

View File

@@ -59,6 +59,7 @@ import { PlatformIconButton } from '../common/PlatformIconButton';
import { PlatformMediaFrame } from '../common/PlatformMediaFrame';
import { PlatformMediaTileGrid } from '../common/PlatformMediaTileGrid';
import { PlatformModalCloseButton } from '../common/PlatformModalCloseButton';
import { PlatformMudPointConfirmDialog } from '../common/PlatformMudPointConfirmDialog';
import { PlatformPillBadge } from '../common/PlatformPillBadge';
import { PlatformPillSwitch } from '../common/PlatformPillSwitch';
import { PlatformProgressBar } from '../common/PlatformProgressBar';
@@ -69,7 +70,6 @@ import { PlatformSubpanel } from '../common/PlatformSubpanel';
import { PlatformTagEditor } from '../common/PlatformTagEditor';
import { PlatformTextField } from '../common/PlatformTextField';
import { PlatformUploadPreviewCard } from '../common/PlatformUploadPreviewCard';
import { UnifiedConfirmDialog } from '../common/UnifiedConfirmDialog';
import {
MATCH3D_RUNTIME_BOARD_BASE_CLASS,
MATCH3D_RUNTIME_BOARD_FALLBACK_CLASS,
@@ -2370,24 +2370,20 @@ function Match3DBatchAddItemsPanel({
· {pointsCost}
</PlatformActionButton>
<UnifiedConfirmDialog
<PlatformMudPointConfirmDialog
open={isCostConfirmOpen}
title="确认消耗泥点"
points={pointsCost}
onClose={() => setIsCostConfirmOpen(false)}
onConfirm={() => {
setIsCostConfirmOpen(false);
onSubmit();
}}
confirmLabel="确定"
confirmDisabled={parsedNames.length <= 0 || isGenerating}
showCancel
showCloseButton={false}
portal={false}
overlayClassName="platform-modal-backdrop z-[90]"
panelClassName="platform-remap-surface max-w-xs rounded-[1.35rem] shadow-[0_24px_70px_rgba(15,23,42,0.22)]"
>
<div className="font-semibold"> {pointsCost} </div>
</UnifiedConfirmDialog>
/>
</div>
</Match3DModalShell>
);
@@ -2465,24 +2461,20 @@ function Match3DBatchRegenerateItemsPanel({
· {pointsCost}
</PlatformActionButton>
<UnifiedConfirmDialog
<PlatformMudPointConfirmDialog
open={isCostConfirmOpen}
title="确认消耗泥点"
points={pointsCost}
onClose={() => setIsCostConfirmOpen(false)}
onConfirm={() => {
setIsCostConfirmOpen(false);
onSubmit();
}}
confirmLabel="确定"
confirmDisabled={targetItemNames.length <= 0 || isGenerating}
showCancel
showCloseButton={false}
portal={false}
overlayClassName="platform-modal-backdrop z-[90]"
panelClassName="platform-remap-surface max-w-xs rounded-[1.35rem] shadow-[0_24px_70px_rgba(15,23,42,0.22)]"
>
<div className="font-semibold"> {pointsCost} </div>
</UnifiedConfirmDialog>
/>
</div>
</Match3DModalShell>
);

View File

@@ -28,6 +28,7 @@ import { PlatformFieldLabel } from '../common/PlatformFieldLabel';
import { PlatformIconBadge } from '../common/PlatformIconBadge';
import { PlatformIconButton } from '../common/PlatformIconButton';
import { PlatformMediaFrame } from '../common/PlatformMediaFrame';
import { PlatformMudPointConfirmDialog } from '../common/PlatformMudPointConfirmDialog';
import { PlatformPillBadge } from '../common/PlatformPillBadge';
import { PlatformProgressBar } from '../common/PlatformProgressBar';
import { PlatformSegmentedTabs } from '../common/PlatformSegmentedTabs';
@@ -36,7 +37,6 @@ import { PlatformSubpanel } from '../common/PlatformSubpanel';
import { PlatformTagEditor } from '../common/PlatformTagEditor';
import { PlatformTextField } from '../common/PlatformTextField';
import { PlatformUploadPreviewCard } from '../common/PlatformUploadPreviewCard';
import { UnifiedConfirmDialog } from '../common/UnifiedConfirmDialog';
import PuzzleHistoryAssetPickerDialog from '../unified-creation/shared/PuzzleHistoryAssetPickerDialog';
import {
PUZZLE_IMAGE_MODEL_GPT_IMAGE_2,
@@ -815,22 +815,16 @@ function PuzzleLevelDetailDialog({
) : null}
</div>
<UnifiedConfirmDialog
<PlatformMudPointConfirmDialog
open={isCostConfirmOpen}
title="确认消耗泥点"
points={PUZZLE_IMAGE_GENERATION_POINT_COST}
onClose={() => setIsCostConfirmOpen(false)}
onConfirm={executeGeneration}
confirmLabel="确定"
confirmDisabled={isBusy || generationProgress.isGenerating}
showCancel
portal={false}
overlayClassName="absolute z-20 bg-black/45"
panelClassName="platform-remap-surface rounded-[1.5rem] shadow-[0_24px_80px_rgba(0,0,0,0.45)]"
>
<div className="font-semibold">
{PUZZLE_IMAGE_GENERATION_POINT_COST}
</div>
</UnifiedConfirmDialog>
/>
{isHistoryPickerOpen ? (
<PuzzleHistoryAssetPickerDialog

View File

@@ -14,7 +14,7 @@ import { PlatformSegmentedTabs } from '../../common/PlatformSegmentedTabs';
import { PlatformStatusMessage } from '../../common/PlatformStatusMessage';
import { PlatformSubpanel } from '../../common/PlatformSubpanel';
import { PlatformTextField } from '../../common/PlatformTextField';
import { UnifiedConfirmDialog } from '../../common/UnifiedConfirmDialog';
import { PlatformMudPointConfirmDialog } from '../../common/PlatformMudPointConfirmDialog';
type Match3DCreationWorkspaceProps = {
session: Match3DAgentSessionSnapshot | null;
@@ -351,19 +351,15 @@ export function Match3DCreationWorkspace({
</PlatformActionButton>
</div>
<UnifiedConfirmDialog
<PlatformMudPointConfirmDialog
open={isPointCostConfirmOpen}
title="确认消耗泥点"
points={mudPointCost}
onClose={() => setIsPointCostConfirmOpen(false)}
onConfirm={executeSubmitForm}
confirmLabel="确定"
confirmDisabled={!canSubmit}
showCancel
overlayClassName="platform-modal-backdrop z-[80]"
panelClassName="platform-remap-surface max-w-xs rounded-[1.35rem] shadow-[0_24px_70px_rgba(15,23,42,0.22)]"
>
<div className="font-semibold"> {mudPointCost} </div>
</UnifiedConfirmDialog>
/>
</div>
);
}

View File

@@ -26,7 +26,7 @@ import {
clampSquareImageCropRect,
type SquareImageCropRect,
} from '../../common/squareImageCropModel';
import { UnifiedConfirmDialog } from '../../common/UnifiedConfirmDialog';
import { PlatformMudPointConfirmDialog } from '../../common/PlatformMudPointConfirmDialog';
import PuzzleHistoryAssetPickerDialog from '../shared/PuzzleHistoryAssetPickerDialog';
import {
normalizePuzzleImageModel,
@@ -747,19 +747,15 @@ export function PuzzleCreationWorkspace({
}}
/>
) : null}
<UnifiedConfirmDialog
<PlatformMudPointConfirmDialog
open={isPointCostConfirmOpen}
title="确认消耗泥点"
points={mudPointCost}
onClose={() => setIsPointCostConfirmOpen(false)}
onConfirm={executeSubmitForm}
confirmLabel="确定"
confirmDisabled={!canSubmit}
showCancel
overlayClassName="platform-modal-backdrop z-[80]"
panelClassName="platform-remap-surface max-w-xs rounded-[1.35rem] shadow-[0_24px_70px_rgba(15,23,42,0.22)]"
>
<div className="font-semibold"> {mudPointCost} </div>
</UnifiedConfirmDialog>
/>
</div>
);
}