diff --git a/.hermes/shared-memory/decision-log.md b/.hermes/shared-memory/decision-log.md index 0951fdf7..f88f2203 100644 --- a/.hermes/shared-memory/decision-log.md +++ b/.hermes/shared-memory/decision-log.md @@ -37,6 +37,7 @@ - 背景:前端已有 `UnifiedModal` 统一遮罩和无障碍外壳,但业务页面仍反复手写“知道了”“确认 / 取消”“危险确认”的 footer 按钮和关闭禁用逻辑。 - 决策:简单提示、确认 / 取消和危险确认统一使用 `src/components/common/UnifiedConfirmDialog.tsx`;剪贴板复制反馈统一使用 `src/components/common/useCopyFeedback.ts`,可点击复制按钮统一使用 `src/components/common/CopyFeedbackButton.tsx` 承载图标、三态文案、可访问名称、纯图标模式和动作按钮外观入口,作品号 / 用户号等短代码 chip 统一使用 `src/components/common/CopyCodeButton.tsx` 承载代码、三态后缀和默认可访问名称,非按钮复制提示统一使用 `src/components/common/CopyFeedbackMessage.tsx`,白底平台状态提示统一使用 `src/components/common/PlatformStatusMessage.tsx`,无操作空态 / 轻量读取态统一使用 `src/components/common/PlatformEmptyState.tsx`,平台动作按钮统一使用 `src/components/common/PlatformActionButton.tsx` 承载 platform / profile 两类样式族、尺寸、圆角、对齐、宽度和禁用态;认证表单的提交、验证码、第三方登录和邀请码提交按钮使用 `size="lg"` 复用 48px 高度,统一创作工作台、统一创作页壳层、玩法创作工作台、结果页返回按钮和反馈页 header 返回使用 `tone="ghost"`,生成 / 提交 / 发布按钮使用主动作,自定义世界实体目录、RPG 首页作品卡删除、创作中心错误重试和素材槽的小动作使用 `size="xs"` 或 `shape="pill"` 收口,推荐回复和列表内动作使用 `align="start"` 承接左对齐,上传控件等需要 label 语义时使用 `PlatformActionButton asChild="label"`,不把文件输入伪装成普通 button。普通平台图标动作按钮和图标上传 label 统一使用 `src/components/common/PlatformIconButton.tsx` 承载 `platform-icon-button` 外观、可访问名称、默认 `type="button"`、`asChild="label"` 和可选 title;历史图片选择弹窗、RPG 发布检查弹窗、RPG 首页搜索结果清空、creative-agent 侧边栏关闭 / 外观 / 设置入口、creation-agent 参考图移除、敲木鱼结果页新增主题标签入口、拼图结果页标签生成 / 标签新增 / 关卡详情关闭 / 发布弹窗关闭 / 删除关卡入口、视觉小说结果页素材选择 / 音频生成 / 保存草稿 / 运行配置入口,以及抓大鹅结果页标签生成 / 标签新增 / 物品素材删除 / 参考图上传入口已先迁移;图标上传控件必须保留 label + file input 语义。平台 / 个人中心弹窗关闭按钮统一使用 `src/components/common/PlatformModalCloseButton.tsx` 承载 profile / profileCompact / floating / floatingPlain / platformIcon 五类圆形关闭按钮、默认图标和可访问名称;认证入口、邀请码弹窗、抓大鹅结果页弹窗关闭等平台头部关闭按钮使用 `variant="platformIcon"`,不在业务 JSX 中手写 `platform-icon-button` + X 图标。RPG / 拼图 / 抓大鹅 / 跳一跳 / 敲木鱼 / 拼消消 / 宝贝识物 / 方洞 / 汪汪声浪结果页,拼消消 / 宝贝识物 / 视觉小说 / 汪汪声浪创作工作台,发布检查、素材生成面板和自定义世界实体目录中的错误 / 成功 / 信息 / 警告 / 中性提示使用 `PlatformStatusMessage surface="platform"` 复用平台 banner token;个人中心弹窗、账号安全弹窗、认证入口、验证码提示、统一创作工作台和通用创作输入区的错误 / 成功 / 信息 / 警告提示使用 `PlatformStatusMessage surface="profile"` 复用 profile token,不再把 `platform-profile-error` / `platform-profile-success` 或 `platform-banner--danger / success / info / warning / neutral` 作为业务 JSX 接口。`UnifiedModal` 继续作为底层模态窗口 Module。已有弹窗栈内的二级确认使用 `UnifiedConfirmDialog portal={false}` 内嵌到当前层级。特殊确认按钮外观通过 `confirmClassName` 适配,不让业务页重新手写 footer;`UnifiedConfirmDialog` 自身的 footer 按钮也复用 `PlatformActionButton`。带复制状态、渠道按钮、媒体预览或复杂网格的弹窗可以保留专用 Module,但普通确认按钮、普通动作按钮、普通图标动作按钮、复制按钮动作外观、复制状态机、copied / failed 按钮 / toast 分支、基础错误 / 成功提示条、无操作空态和普通弹窗关闭按钮不再直接写进业务页面。运行态 HUD、输入 Composer 发送 / 上传按钮、复制三态图标按钮或需要专用交互禁用语义的图标按钮先保留专用布局,等对应场景验证时再迁移。业务代码中的阻断提示、删除确认和公开作品失效恢复不得继续调用浏览器原生 `window.alert` / `window.confirm`,应由页面壳层或编辑器壳层用 `UnifiedConfirmDialog` 承接。简单确认需要像素风时使用 `UnifiedConfirmDialog variant="pixel"`,不再为同类确认单独维护壳层和按钮。 - 2026-06-10 追加:推荐页运行态卡片底部的点赞 / 分享 / 改造入口,以及创作中心公开作品卡右上角分享入口统一迁移到 `PlatformIconButton`;这类和 swipe / drag 手势耦合的图标动作必须继续保留业务局部 class 与 `onPointerDown` / `onClick` 里的 `stopPropagation`,只把按钮语义、可访问名称和默认 `type="button"` 收口到共享组件,避免图标动作误触推荐卡切换、整卡打开或残留左滑状态。 +- 2026-06-10 追加:标准泥点消耗确认弹窗统一收口到 `src/components/common/PlatformMudPointConfirmDialog.tsx`;该 Module 专门承接“确认消耗泥点 + 消耗 N 泥点”的同形态确认骨架,当前已覆盖 `PuzzleCreationWorkspace.tsx`、`Match3DCreationWorkspace.tsx`、`PuzzleResultView.tsx` 与 `Match3DResultView.tsx`。后续遇到同形态泥点确认时,业务页只传点数、补充说明和确认回调,不再重复拼接 `UnifiedConfirmDialog` 正文;`RpgCreationRoleAssetStudioModalImpl` 这类节奏和内容结构不同的泥点弹层继续单独评估,留作后续轮次处理。 - 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 d676e332..1b937ab6 100644 --- a/docs/technical/【前端架构】PlatformUiKit弹窗组件收口计划-2026-06-08.md +++ b/docs/technical/【前端架构】PlatformUiKit弹窗组件收口计划-2026-06-08.md @@ -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`。 diff --git a/src/components/common/PlatformMudPointConfirmDialog.test.tsx b/src/components/common/PlatformMudPointConfirmDialog.test.tsx new file mode 100644 index 00000000..f9b21200 --- /dev/null +++ b/src/components/common/PlatformMudPointConfirmDialog.test.tsx @@ -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( + , + ); + + 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( + + 本次会覆盖当前待确认素材。 + , + ); + + const dialog = screen.getByRole('dialog', { name: '保存正式素材' }); + + expect(within(dialog).getByText('消耗 7 泥点')).toBeTruthy(); + expect(within(dialog).getByText('本次会覆盖当前待确认素材。')).toBeTruthy(); + expect(screen.queryByRole('button', { name: '关闭' })).toBeNull(); +}); diff --git a/src/components/common/PlatformMudPointConfirmDialog.tsx b/src/components/common/PlatformMudPointConfirmDialog.tsx new file mode 100644 index 00000000..198ead2e --- /dev/null +++ b/src/components/common/PlatformMudPointConfirmDialog.tsx @@ -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 ( + +
+
消耗 {points} 泥点
+ {children} +
+
+ ); +} diff --git a/src/components/match3d-result/Match3DResultView.tsx b/src/components/match3d-result/Match3DResultView.tsx index 979cfcc2..c4f13eb1 100644 --- a/src/components/match3d-result/Match3DResultView.tsx +++ b/src/components/match3d-result/Match3DResultView.tsx @@ -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}泥点 - 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)]" - > -
消耗 {pointsCost} 泥点
-
+ /> ); @@ -2465,24 +2461,20 @@ function Match3DBatchRegenerateItemsPanel({ 重新生成物品素材 · {pointsCost}泥点 - 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)]" - > -
消耗 {pointsCost} 泥点
-
+ /> ); diff --git a/src/components/puzzle-result/PuzzleResultView.tsx b/src/components/puzzle-result/PuzzleResultView.tsx index 3cd86ae7..17067b9d 100644 --- a/src/components/puzzle-result/PuzzleResultView.tsx +++ b/src/components/puzzle-result/PuzzleResultView.tsx @@ -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} - 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)]" - > -
- 消耗 {PUZZLE_IMAGE_GENERATION_POINT_COST} 泥点 -
-
+ /> {isHistoryPickerOpen ? ( - 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)]" - > -
消耗 {mudPointCost} 泥点
-
+ /> ); } diff --git a/src/components/unified-creation/workspaces/PuzzleCreationWorkspace.tsx b/src/components/unified-creation/workspaces/PuzzleCreationWorkspace.tsx index 3e8d6f83..8a760e1c 100644 --- a/src/components/unified-creation/workspaces/PuzzleCreationWorkspace.tsx +++ b/src/components/unified-creation/workspaces/PuzzleCreationWorkspace.tsx @@ -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} - 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)]" - > -
消耗 {mudPointCost} 泥点
-
+ /> ); }