From edf37d97a7f460dc26c7c59e8adf193f8ca12608 Mon Sep 17 00:00:00 2001 From: kdletters Date: Thu, 11 Jun 2026 00:38:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B6=E5=8F=A3=E5=8D=95=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E5=B7=B2=E8=AF=BB=E7=8A=B6=E6=80=81=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 PlatformAcknowledgeStatusDialog 统一承接单按钮已读状态壳层 迁移大鱼结果页与个人中心支付结果复用共享已读状态弹窗 迁移 RPG 编辑器与平台入口提示链路复用共享已读状态弹窗 迁移自定义世界实体目录阻断提示复用共享已读状态弹窗 补充共享组件测试并更新 PlatformUiKit 收口文档与决策记录 --- .hermes/shared-memory/decision-log.md | 1 + ...】PlatformUiKit弹窗组件收口计划-2026-06-08.md | 1 + src/components/CustomWorldEntityCatalog.tsx | 9 +- .../big-fish-result/BigFishResultView.tsx | 11 +- .../PlatformAcknowledgeStatusDialog.test.tsx | 48 ++++++++ .../PlatformAcknowledgeStatusDialog.tsx | 111 ++++++++++++++++++ .../PlatformEntryFlowShellImpl.tsx | 29 ++--- .../RpgCreationEntityEditorShared.tsx | 15 +-- src/components/rpg-entry/RpgEntryHomeView.tsx | 5 +- 9 files changed, 181 insertions(+), 49 deletions(-) create mode 100644 src/components/common/PlatformAcknowledgeStatusDialog.test.tsx create mode 100644 src/components/common/PlatformAcknowledgeStatusDialog.tsx diff --git a/.hermes/shared-memory/decision-log.md b/.hermes/shared-memory/decision-log.md index 3d7803d4..7306b657 100644 --- a/.hermes/shared-memory/decision-log.md +++ b/.hermes/shared-memory/decision-log.md @@ -41,6 +41,7 @@ - 2026-06-10 追加:`RpgCreationRoleAssetStudioModalImpl.tsx` 的角色形象生成 / 动作草稿生成确认也并入 `PlatformMudPointConfirmDialog`;共享组件通过自定义 title 与补充说明承接工坊语义,工坊页不再单独维护 `UnifiedConfirmDialog` 的标准泥点文案骨架。后续同类“确认消耗泥点 + 补充说明”场景继续优先复用该 Module。 - 2026-06-10 追加:平台危险确认统一收口到 `src/components/common/PlatformDangerConfirmDialog.tsx`;该 Module 专门承接“确认 / 取消 + 危险主动作”的标准骨架,当前已覆盖 `PlatformEntryFlowShellImpl.tsx` 的删除作品确认、`RpgCreationResultViewImpl.tsx` 的重新生成确认和 `CustomWorldEntityCatalog.tsx` 的删除角色 / 批量删除确认。后续删除、覆盖、清空等危险动作优先复用该 Module,不再在业务页重复拼接 `UnifiedConfirmDialog` 的 `showCancel + confirmTone=\"danger\"` 组合。 - 2026-06-10 追加:平台未保存离开确认统一收口到 `src/components/common/PlatformUnsavedLeaveConfirmDialog.tsx`;该 Module 专门承接“继续编辑 + 确认离开”的标准骨架,当前已覆盖 `RpgCreationEntityEditorShared.tsx` 里的关闭未保存修改、生成结果未保存退出和普通结果未保存退出确认。后续同类未保存离开场景优先复用该 Module,不再在业务页重复拼接 `UnifiedConfirmDialog` 的 `showCancel + cancelLabel=\"继续编辑\"` 组合和重复壳层 class。 +- 2026-06-10 追加:平台单按钮已读状态统一收口到 `src/components/common/PlatformAcknowledgeStatusDialog.tsx`;该 Module 专门承接“状态提示 + 知道了”的单按钮确认已读语义,当前已覆盖 `BigFishResultView.tsx` 的发布失败提示、`RpgEntryHomeView.tsx` 的支付结果提示、`RpgCreationEntityEditorShared.tsx` 的编辑器 notice、`PlatformEntryFlowShellImpl.tsx` 的泥点提示 / 作品不可用 / 搜索未命中提示,以及 `CustomWorldEntityCatalog.tsx` 的“无法删除”阻断提示。后续同类 status-dialog 场景优先复用该 Module,不再在业务页重复拼装 `action={{ label: '知道了', onClick: onClose }}`。 - 2026-06-10 追加:RPG 首页个人中心里的统计卡、统计骨架、常用功能入口、设置行和法律信息入口统一抽到 `src/components/platform-entry/PlatformProfilePrimitives.tsx`;这组纯展示原子以后优先通过 props 接收图片资源、点击回调和展示文案,不再继续塞回 `RpgEntryHomeView` 的账户控制逻辑里。新建 `PlatformProfilePrimitives.test.tsx` 作为组件级护栏,页面级布局与法律入口继续由 `RpgEntryHomeView.recharge.test.tsx` 兜底。 - 2026-06-10 追加:RPG 首页个人中心的充值 / 钱包 / 每日任务 / 邀请 / 兑换码等商业与账户控制逻辑统一收口到 `src/components/platform-entry/usePlatformProfileCenterController.ts`;controller 负责账户动作分流、商业状态派生与相关面板控制,`RpgEntryHomeView` 只保留展示、昵称头像编辑、扫码入口和页面级交互编排,不在页面组件里继续堆叠账户控制分支。验证命令:`npm run test -- src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx`、`npm run typecheck`。 - 2026-06-10 追加:RPG 首页个人中心的“玩过 / 可继续”历史弹层统一抽到 `src/components/platform-entry/PlatformProfilePlayedWorksModal.tsx`;`RpgEntryHomeView` 不再内联 `SaveArchiveCard`、`ProfilePlayedWorksModal` 和未连通的 `ProfileSaveArchivesModal`。当前产品语义已经把存档恢复并入“玩过”弹层的“可继续”分区,因此 controller 里的 `ProfilePopupPanel` 也去掉了没有真实入口的 `saveArchives` 分支。验证命令:`npm run test -- src/components/platform-entry/PlatformProfilePlayedWorksModal.test.tsx src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx`、`npm run typecheck`。 diff --git a/docs/technical/【前端架构】PlatformUiKit弹窗组件收口计划-2026-06-08.md b/docs/technical/【前端架构】PlatformUiKit弹窗组件收口计划-2026-06-08.md index 95ca4708..9f85f71e 100644 --- a/docs/technical/【前端架构】PlatformUiKit弹窗组件收口计划-2026-06-08.md +++ b/docs/technical/【前端架构】PlatformUiKit弹窗组件收口计划-2026-06-08.md @@ -246,6 +246,7 @@ 19.3.22. 标准泥点消耗确认弹窗收口到 `src/components/common/PlatformMudPointConfirmDialog.tsx`;组件固定承接“确认消耗泥点 + 消耗 N 泥点”的同形态标题、正文骨架和确认 / 取消动作,业务页只保留点数、补充说明和确认回调。`PuzzleCreationWorkspace.tsx`、`Match3DCreationWorkspace.tsx`、`PuzzleResultView.tsx`、`Match3DResultView.tsx` 以及 `RpgCreationRoleAssetStudioModalImpl.tsx` 已迁移;其中角色形象生成 / 动作草稿生成继续通过自定义 title 和补充说明承接工坊语义,但不再各自拼接 `UnifiedConfirmDialog` 的相同文案和内容结构。后续同类泥点确认优先复用该 Module;像 runtime 道具确认、预计消耗区间确认这类节奏不同的弹层再单独评估是否扩展变体。 19.3.23. 平台危险确认弹窗收口到 `src/components/common/PlatformDangerConfirmDialog.tsx`;组件固定承接“确认 / 取消 + 危险主动作”的标准骨架,并透传忙碌态、遮罩关闭策略、按钮文案和局部面板样式。`PlatformEntryFlowShellImpl.tsx` 的删除作品确认、`RpgCreationResultViewImpl.tsx` 的重新生成确认,以及 `CustomWorldEntityCatalog.tsx` 的删除角色 / 批量删除确认已迁移;业务页继续保留标题、说明文案和确认回调,不再各自拼接 `UnifiedConfirmDialog` 的危险按钮配置。后续删除、覆盖、清空等危险动作优先复用该 Module,再按需要补充更窄的语义 wrapper。 19.3.24. 平台未保存离开确认弹窗收口到 `src/components/common/PlatformUnsavedLeaveConfirmDialog.tsx`;组件固定承接“继续编辑 + 确认离开”的标准骨架,并按 `platform / pixel` 两类确认风格兜底默认遮罩和面板样式。`RpgCreationEntityEditorShared.tsx` 中的关闭未保存修改确认、生成结果未保存退出确认和普通结果未保存退出确认已迁移;业务页只保留标题、确认按钮文案和未保存提示内容,不再各自拼接 `UnifiedConfirmDialog` 的 cancel/confirm 组合和重复壳层 class。 +19.3.25. 平台单按钮已读状态弹窗收口到 `src/components/common/PlatformAcknowledgeStatusDialog.tsx`;组件固定承接“状态提示 + 知道了”这一类单按钮确认已读语义,并透传 action surface / size / fullWidth / class、header、关闭路径和局部 panel 覆写。`BigFishResultView.tsx` 的发布失败提示、`RpgEntryHomeView.tsx` 的支付结果提示、`RpgCreationEntityEditorShared.tsx` 的编辑器 notice、`PlatformEntryFlowShellImpl.tsx` 的泥点提示 / 作品不可用 / 搜索未命中提示,以及 `CustomWorldEntityCatalog.tsx` 的“无法删除”阻断提示已迁移;业务页继续保留 status、标题、说明和关闭回调,不再各自手写 `PlatformStatusDialog` 的 `action={{ label: '知道了', onClick: onClose }}` 结构。 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`。 diff --git a/src/components/CustomWorldEntityCatalog.tsx b/src/components/CustomWorldEntityCatalog.tsx index 3d1af50b..6cf99b3d 100644 --- a/src/components/CustomWorldEntityCatalog.tsx +++ b/src/components/CustomWorldEntityCatalog.tsx @@ -23,6 +23,7 @@ import { type SceneChapterBlueprint, } from '../types'; import { CharacterAnimator } from './CharacterAnimator'; +import { PlatformAcknowledgeStatusDialog } from './common/PlatformAcknowledgeStatusDialog'; import { PlatformActionButton } from './common/PlatformActionButton'; import { PlatformDangerConfirmDialog } from './common/PlatformDangerConfirmDialog'; import { PlatformEmptyState } from './common/PlatformEmptyState'; @@ -30,7 +31,6 @@ import { PlatformMediaFrame } from './common/PlatformMediaFrame'; import { PlatformPillBadge } from './common/PlatformPillBadge'; import { PlatformProgressBar } from './common/PlatformProgressBar'; import { PlatformStatGrid } from './common/PlatformStatGrid'; -import { PlatformStatusDialog } from './common/PlatformStatusDialog'; import { PlatformStatusMessage } from './common/PlatformStatusMessage'; import { PlatformSubpanel } from './common/PlatformSubpanel'; import { PlatformTextField } from './common/PlatformTextField'; @@ -1440,17 +1440,12 @@ export function CustomWorldEntityCatalog({ ) : null} {confirmState?.kind === 'minimum-playable' ? ( - ) : null} diff --git a/src/components/big-fish-result/BigFishResultView.tsx b/src/components/big-fish-result/BigFishResultView.tsx index 6921a9d6..1bc3336e 100644 --- a/src/components/big-fish-result/BigFishResultView.tsx +++ b/src/components/big-fish-result/BigFishResultView.tsx @@ -16,6 +16,7 @@ import type { BigFishSessionSnapshotResponse, ExecuteBigFishActionRequest, } from '../../../packages/shared/src/contracts/bigFish'; +import { PlatformAcknowledgeStatusDialog } from '../common/PlatformAcknowledgeStatusDialog'; import { PlatformActionButton } from '../common/PlatformActionButton'; import { PlatformEmptyState } from '../common/PlatformEmptyState'; import { PlatformFieldLabel } from '../common/PlatformFieldLabel'; @@ -23,7 +24,6 @@ import { PlatformIconBadge } from '../common/PlatformIconBadge'; import { PlatformIconButton } from '../common/PlatformIconButton'; import { PlatformMediaFrame } from '../common/PlatformMediaFrame'; import { PlatformPillBadge } from '../common/PlatformPillBadge'; -import { PlatformStatusDialog } from '../common/PlatformStatusDialog'; import { PlatformStatusMessage } from '../common/PlatformStatusMessage'; import { PlatformSubpanel } from '../common/PlatformSubpanel'; @@ -619,7 +619,7 @@ function BigFishResultErrorModal({ onClose: () => void; }) { return ( - } iconLabel="发布失败提示" iconClassName="mt-0.5 bg-[var(--platform-button-danger-fill)] text-[var(--platform-button-danger-text)]" - action={{ - label: '知道了', - onClick: onClose, - surface: 'platform', - className: 'border-slate-950 bg-slate-950 text-white', - }} + actionClassName="border-slate-950 bg-slate-950 text-white" zIndexClassName="z-[160]" overlayClassName="bg-slate-950/58" panelClassName="border-red-100/80 bg-white text-slate-950 shadow-2xl" diff --git a/src/components/common/PlatformAcknowledgeStatusDialog.test.tsx b/src/components/common/PlatformAcknowledgeStatusDialog.test.tsx new file mode 100644 index 00000000..eb458974 --- /dev/null +++ b/src/components/common/PlatformAcknowledgeStatusDialog.test.tsx @@ -0,0 +1,48 @@ +/* @vitest-environment jsdom */ + +import { fireEvent, render, screen } from '@testing-library/react'; +import { expect, test, vi } from 'vitest'; + +import { PlatformAcknowledgeStatusDialog } from './PlatformAcknowledgeStatusDialog'; + +test('renders a standard acknowledge action and closes through 知道了', () => { + const onClose = vi.fn(); + + render( + , + ); + + const action = screen.getByRole('button', { name: '知道了' }); + + expect(action.className).toContain('platform-button'); + fireEvent.click(action); + expect(onClose).toHaveBeenCalledTimes(1); +}); + +test('supports custom action styling and header notice layout', () => { + render( + {}} + showHeader + showCloseButton + closeOnBackdrop + iconLabel="发布失败提示" + actionClassName="border-slate-950 bg-slate-950 text-white" + />, + ); + + const action = screen.getByRole('button', { name: '知道了' }); + const dialog = screen.getByRole('dialog', { name: '发布失败' }); + + expect(action.className).toContain('border-slate-950'); + expect(action.className).toContain('bg-slate-950'); + expect(dialog.querySelector('[aria-label="发布失败提示"]')).toBeTruthy(); +}); diff --git a/src/components/common/PlatformAcknowledgeStatusDialog.tsx b/src/components/common/PlatformAcknowledgeStatusDialog.tsx new file mode 100644 index 00000000..7f6ff65a --- /dev/null +++ b/src/components/common/PlatformAcknowledgeStatusDialog.tsx @@ -0,0 +1,111 @@ +import type { ReactNode } from 'react'; + +import type { + PlatformActionButtonSize, + PlatformActionButtonSurface, + PlatformActionButtonTone, +} from './platformActionButtonModel'; +import { + PlatformStatusDialog, + type PlatformStatusDialogStatus, +} from './PlatformStatusDialog'; + +type PlatformAcknowledgeStatusDialogProps = { + open?: boolean; + status: PlatformStatusDialogStatus; + title: string; + description?: ReactNode; + children?: ReactNode; + onClose: () => void; + actionLabel?: string; + actionDisabled?: boolean; + actionTone?: PlatformActionButtonTone; + actionSurface?: PlatformActionButtonSurface; + actionSize?: PlatformActionButtonSize; + actionFullWidth?: boolean; + actionClassName?: string; + showHeader?: boolean; + showBodyTitle?: boolean; + showCloseButton?: boolean; + closeOnBackdrop?: boolean; + closeOnEscape?: boolean; + closeLabel?: string; + closeDisabled?: boolean; + zIndexClassName?: string; + overlayClassName?: string; + panelClassName?: string; + bodyClassName?: string; + iconClassName?: string; + icon?: ReactNode; + iconLabel?: string; +}; + +/** + * 平台已读确认状态弹窗。 + * 统一承接“状态提示 + 知道了”这一类单按钮确认已读的弹窗语义。 + */ +export function PlatformAcknowledgeStatusDialog({ + open, + status, + title, + description, + children, + onClose, + actionLabel = '知道了', + actionDisabled = false, + actionTone, + actionSurface = 'platform', + actionSize, + actionFullWidth, + actionClassName, + showHeader, + showBodyTitle, + showCloseButton, + closeOnBackdrop, + closeOnEscape, + closeLabel, + closeDisabled, + zIndexClassName, + overlayClassName, + panelClassName, + bodyClassName, + iconClassName, + icon, + iconLabel, +}: PlatformAcknowledgeStatusDialogProps) { + return ( + + {children} + + ); +} diff --git a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx index a53bb633..e09c25f6 100644 --- a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx +++ b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx @@ -363,10 +363,10 @@ import { } from '../../services/wooden-fish/woodenFishClient'; import type { CustomWorldProfile } from '../../types'; import { useAuthUi } from '../auth/AuthUiContext'; +import { PlatformAcknowledgeStatusDialog } from '../common/PlatformAcknowledgeStatusDialog'; import { PlatformActionButton } from '../common/PlatformActionButton'; import { PlatformDangerConfirmDialog } from '../common/PlatformDangerConfirmDialog'; import { PlatformFieldLabel } from '../common/PlatformFieldLabel'; -import { PlatformStatusDialog } from '../common/PlatformStatusDialog'; import { PlatformStatusMessage } from '../common/PlatformStatusMessage'; import { PlatformSubpanel } from '../common/PlatformSubpanel'; import { PublishShareModal } from '../common/PublishShareModal'; @@ -16997,7 +16997,7 @@ export function PlatformEntryFlowShellImpl({ }} /> ) : null} - setDraftGenerationPointNotice(null), - surface: 'platform', - }} > {draftGenerationPointNotice?.message} - + - {workNotFoundRecoveryDialog?.message} - + - {publicSearchError} - + ) : searchedPublicUser ? ( void; }) { return ( -