收口标准泥点确认弹窗
新增 PlatformMudPointConfirmDialog 统一承接标准泥点消耗确认壳层 迁移拼图与抓大鹅创作工作台复用共享泥点确认弹窗 迁移拼图与抓大鹅结果页素材生成流程复用共享泥点确认弹窗 补充共享组件测试并更新 PlatformUiKit 收口文档与决策记录
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -243,6 +243,7 @@
|
||||
19.3.19. RPG 首页个人中心的支付结果提示、支付确认遮罩与扫码面板继续向共享组件收口:支付结果 / 确认中弹层统一抽到 `src/components/common/PlatformStatusDialog.tsx`,扫码面板统一抽到 `src/components/platform-entry/PlatformProfileQrScannerModal.tsx`;`RpgEntryHomeView` 仅保留支付状态映射、扫码打开关闭和结果写回,不再内联 `RechargePaymentResultModal`、`RechargePaymentConfirmationMask`、`ProfileQrScannerModal`、`BarcodeDetector` 启动逻辑和 profile 弹层壳层参数。组件级验证新增 `src/components/common/PlatformStatusDialog.test.tsx` 与 `src/components/platform-entry/PlatformProfileQrScannerModal.test.tsx`,首页继续复用 `RpgEntryHomeView.recharge.test.tsx` 的支付 / 扫码入口断言。验证命令:`npm run test -- src/components/common/PlatformStatusDialog.test.tsx`、`npm run test -- src/components/platform-entry/PlatformProfileQrScannerModal.test.tsx`、`npm run test -- src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx -t "profile recharge modal jumps to h5 payment on mobile web by default|profile recharge modal posts mini program payment request and reacts to success hash result|profile recharge modal releases submitting state and shows virtual payment failure detail|profile recharge modal eventually shows error text even when hashchange is not dispatched|profile recharge modal resumes virtual payment confirmation when pageshow returns with paid order|profile recharge modal blocks tab navigation while virtual payment confirmation is pending|profile scan action opens camera scanner instead of recharge panel"`、`npm run typecheck`。
|
||||
19.3.20. `PlatformStatusDialog` 继续扩展到 notice 场景:组件新增 header notice 布局、body content、close button、backdrop / Escape 关闭路径以及动作按钮样式透传;`PlatformEntryFlowShellImpl` 里的 `draftGenerationPointNotice` / `workNotFoundRecoveryDialog` 和 `RpgCreationEntityEditorShared.tsx` 里的 `EditorNoticeDialog` 已接入。创作入口泥点不足、作品不可用恢复和 RPG 大编辑器规则阻断提示不再各自维护 `UnifiedConfirmDialog` 壳层,只保留标题、正文、辅助提示和关闭回调。验证命令:`npm run test -- src/components/common/PlatformStatusDialog.test.tsx`、`npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "bark battle form checks mud points before creating a draft|puzzle form checks mud points before creating a draft|match3d form checks mud points before creating a draft|direct missing public work detail shows unified dialog before returning home"`、`npm run test -- src/components/CustomWorldEntityEditorModal.test.tsx -t "可扮演角色至少保留一个背景章节时使用统一提示弹窗|场景连接缺少可连接目标时使用统一提示弹窗|场景保存缺少主角色时使用统一提示弹窗"`、`npm run typecheck`。
|
||||
19.3.21. `PlatformStatusDialog` 继续收口规则阻断和搜索未命中提示:`CustomWorldEntityCatalog.tsx` 的 `minimum-playable` 规则阻断从删除确认分支中拆出,改由独立 `PlatformStatusDialog` 承接;`PlatformEntryFlowShellImpl` 的公开编号搜索弹层拆成“命中用户继续走 `UnifiedModal + PlatformSubpanel`”与“未找到结果改走 `PlatformStatusDialog`”两条分支。业务页不再让规则阻断提示和危险删除确认共用同一套 confirm config,也不再在搜索结果 modal 内同时维护用户信息和错误态两套内容布局。验证命令:`npm run test -- src/components/CustomWorldEntityEditorModal.test.tsx -t "最后一个可扮演角色不可删除时使用平台状态弹窗"`、`npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "searching unmatched public work code shows not-found search result dialog|public code search shows public user summary in shared search result modal and clears it on close"`、`npm run typecheck`。
|
||||
19.3.22. 标准泥点消耗确认弹窗收口到 `src/components/common/PlatformMudPointConfirmDialog.tsx`;组件固定承接“确认消耗泥点 + 消耗 N 泥点”的同形态标题、正文骨架和确认 / 取消动作,业务页只保留点数、补充说明和确认回调。`PuzzleCreationWorkspace.tsx`、`Match3DCreationWorkspace.tsx`、`PuzzleResultView.tsx` 与 `Match3DResultView.tsx` 已先迁移,后续同类泥点确认优先复用该 Module,不再各自拼接 `UnifiedConfirmDialog` 的相同文案和内容结构;`RpgCreationRoleAssetStudioModalImpl` 暂留到后续轮次再并入,避免把不同节奏的工坊弹层适配绑进这一轮。
|
||||
19.3. creative-agent 首页的侧边栏菜单、账号入口、开启新对话、我的创作、首页激励 CTA 和 prompt suggestion 按钮迁移到 `PlatformIconButton` / `PlatformActionButton`;首页继续保留 `creative-agent-home__*` 本地 class 承接透明顶栏、抽屉和品牌化胶囊视觉,不把视觉回收和语义收口绑成一次大改。`Beta` 徽标和历史记录纯文本行暂保留本地实现,等出现更多同构轻量列表行后再评估是否抽新的共享 row primitive。
|
||||
19.4. 大鱼吃小鱼结果页 hero 的返回入口迁移到 `PlatformIconButton variant="darkMini"`,测试 / 发布动作迁移到 `PlatformActionButton surface="editorDark"`;结果页只保留测试运行、发布提交和文案状态语义,不再手写 hero 顶栏按钮壳。
|
||||
19.4.1. 大鱼吃小鱼结果页的发布失败弹层迁移到 `src/components/common/PlatformStatusDialog.tsx`;`PlatformStatusDialog` 补充自定义图标、可访问标签和动作按钮样式透传后,`BigFishResultView` 不再保留 `BigFishResultErrorModal` 内联的 `UnifiedConfirmDialog + PlatformIconBadge` 组合。结果页只保留失败文案和关闭回调,发布失败的状态图标、遮罩、白底面板和“知道了”主动作统一由共享状态弹层承接。验证命令:`npm run test -- src/components/common/PlatformStatusDialog.test.tsx src/components/big-fish-result/BigFishResultView.test.tsx`、`npm run typecheck`。
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user