将个人中心邀请弹窗奖励说明迁移到共享状态提示组件 将大鱼吃小鱼结果页 hero 摘要标签迁移到共享胶囊标签组件 补充充值商品卡购买胶囊暂不抽共享组件的收口文档与团队决策
652 lines
21 KiB
TypeScript
652 lines
21 KiB
TypeScript
import {
|
|
ArrowLeft,
|
|
CheckCircle2,
|
|
ImagePlus,
|
|
Loader2,
|
|
Play,
|
|
Sparkles,
|
|
Waves,
|
|
} from 'lucide-react';
|
|
import { useEffect, useMemo, useState } from 'react';
|
|
|
|
import type {
|
|
BigFishAssetSlotResponse,
|
|
BigFishGameDraftResponse,
|
|
BigFishLevelBlueprintResponse,
|
|
BigFishSessionSnapshotResponse,
|
|
ExecuteBigFishActionRequest,
|
|
} from '../../../packages/shared/src/contracts/bigFish';
|
|
import { PlatformActionButton } from '../common/PlatformActionButton';
|
|
import { PlatformEmptyState } from '../common/PlatformEmptyState';
|
|
import { PlatformFieldLabel } from '../common/PlatformFieldLabel';
|
|
import { PlatformIconBadge } from '../common/PlatformIconBadge';
|
|
import { PlatformIconButton } from '../common/PlatformIconButton';
|
|
import { PlatformMediaFrame } from '../common/PlatformMediaFrame';
|
|
import { PlatformPillBadge } from '../common/PlatformPillBadge';
|
|
import { PlatformStatusMessage } from '../common/PlatformStatusMessage';
|
|
import { PlatformSubpanel } from '../common/PlatformSubpanel';
|
|
import { UnifiedConfirmDialog } from '../common/UnifiedConfirmDialog';
|
|
|
|
type BigFishAssetStudioTarget =
|
|
| {
|
|
kind: 'level_main_image';
|
|
level: BigFishLevelBlueprintResponse;
|
|
}
|
|
| {
|
|
kind: 'level_motion';
|
|
level: BigFishLevelBlueprintResponse;
|
|
motionKey: 'idle_float' | 'move_swim';
|
|
}
|
|
| {
|
|
kind: 'stage_background';
|
|
};
|
|
|
|
type BigFishResultViewProps = {
|
|
session: BigFishSessionSnapshotResponse;
|
|
isBusy?: boolean;
|
|
error?: string | null;
|
|
onBack: () => void;
|
|
onDismissError?: () => void;
|
|
onExecuteAction: (payload: ExecuteBigFishActionRequest) => void;
|
|
onStartTestRun: () => void;
|
|
};
|
|
|
|
function findAssetSlot(
|
|
slots: BigFishAssetSlotResponse[],
|
|
assetKind: string,
|
|
level?: number,
|
|
motionKey?: string,
|
|
) {
|
|
return slots.find((slot) => {
|
|
if (slot.assetKind !== assetKind) {
|
|
return false;
|
|
}
|
|
if (level !== undefined && slot.level !== level) {
|
|
return false;
|
|
}
|
|
if (motionKey !== undefined && slot.motionKey !== motionKey) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
function assetReadyLabel(slot: BigFishAssetSlotResponse | undefined) {
|
|
if (slot?.status !== 'ready') {
|
|
return '待生成';
|
|
}
|
|
return isBigFishPlaceholderAsset(slot) ? '占位已生成' : '已生成';
|
|
}
|
|
|
|
function buildLevelAssetPreview(slot: BigFishAssetSlotResponse | undefined) {
|
|
if (slot?.assetUrl) {
|
|
return slot.assetUrl;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function isBigFishPlaceholderAsset(slot: BigFishAssetSlotResponse | undefined) {
|
|
return Boolean(slot?.assetUrl?.includes('/generated-big-fish/'));
|
|
}
|
|
|
|
function buildStudioAssetPreview(
|
|
slots: BigFishAssetSlotResponse[],
|
|
target: BigFishAssetStudioTarget,
|
|
) {
|
|
if (target.kind === 'stage_background') {
|
|
return buildLevelAssetPreview(findAssetSlot(slots, 'stage_background'));
|
|
}
|
|
if (target.kind === 'level_main_image') {
|
|
return buildLevelAssetPreview(
|
|
findAssetSlot(slots, 'level_main_image', target.level.level),
|
|
);
|
|
}
|
|
return buildLevelAssetPreview(
|
|
findAssetSlot(slots, 'level_motion', target.level.level, target.motionKey),
|
|
);
|
|
}
|
|
|
|
function BigFishAssetStudioModal({
|
|
draft,
|
|
target,
|
|
previewUrl,
|
|
isBusy,
|
|
onClose,
|
|
onExecuteAction,
|
|
}: {
|
|
draft: BigFishGameDraftResponse;
|
|
target: BigFishAssetStudioTarget;
|
|
previewUrl?: string | null;
|
|
isBusy: boolean;
|
|
onClose: () => void;
|
|
onExecuteAction: (payload: ExecuteBigFishActionRequest) => void;
|
|
}) {
|
|
const title =
|
|
target.kind === 'stage_background'
|
|
? '场地背景工坊'
|
|
: target.kind === 'level_main_image'
|
|
? `Lv.${target.level.level} 主图工坊`
|
|
: `Lv.${target.level.level} 动作工坊`;
|
|
const prompt =
|
|
target.kind === 'stage_background'
|
|
? draft.background.backgroundPromptSeed
|
|
: target.kind === 'level_main_image'
|
|
? target.level.visualDescription || target.level.visualPromptSeed
|
|
: target.motionKey === 'move_swim'
|
|
? target.level.moveMotionDescription || target.level.motionPromptSeed
|
|
: target.level.idleMotionDescription || target.level.motionPromptSeed;
|
|
|
|
const execute = () => {
|
|
if (target.kind === 'stage_background') {
|
|
onExecuteAction({ action: 'big_fish_generate_stage_background' });
|
|
return;
|
|
}
|
|
|
|
if (target.kind === 'level_main_image') {
|
|
onExecuteAction({
|
|
action: 'big_fish_generate_level_main_image',
|
|
level: target.level.level,
|
|
});
|
|
return;
|
|
}
|
|
|
|
onExecuteAction({
|
|
action: 'big_fish_generate_level_motion',
|
|
level: target.level.level,
|
|
motionKey: target.motionKey,
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div className="platform-overlay fixed inset-0 z-[95] flex items-end justify-center p-3 backdrop-blur-sm sm:items-center sm:p-4">
|
|
<div className="platform-modal-shell w-full max-w-xl overflow-hidden rounded-[1.8rem]">
|
|
<div className="border-b border-[var(--platform-subpanel-border)] px-4 py-4">
|
|
<div className="text-lg font-black text-[var(--platform-text-strong)]">
|
|
{title}
|
|
</div>
|
|
<div className="mt-1 text-sm text-[var(--platform-text-base)]">
|
|
{target.kind === 'stage_background'
|
|
? draft.background.theme
|
|
: target.level.textDescription || target.level.oneLineFantasy}
|
|
</div>
|
|
</div>
|
|
<div className="space-y-4 px-4 py-4">
|
|
<PlatformSubpanel as="div" surface="flat">
|
|
<PlatformFieldLabel variant="section">PROMPT</PlatformFieldLabel>
|
|
<div className="mt-2 text-sm leading-6 text-[var(--platform-text-strong)]">
|
|
{prompt}
|
|
</div>
|
|
</PlatformSubpanel>
|
|
<PlatformMediaFrame
|
|
src={previewUrl}
|
|
alt={title}
|
|
fallbackLabel="AI 资产候选预览"
|
|
aspect="wide"
|
|
surface="none"
|
|
className="rounded-[1.4rem] border border-dashed border-cyan-300/50 bg-cyan-50/40"
|
|
fallbackClassName="tracking-normal text-[var(--platform-text-base)]"
|
|
/>
|
|
</div>
|
|
<div className="flex justify-end gap-2 border-t border-[var(--platform-subpanel-border)] px-4 py-4">
|
|
<PlatformActionButton
|
|
onClick={onClose}
|
|
disabled={isBusy}
|
|
tone="ghost"
|
|
shape="pill"
|
|
size="xs"
|
|
>
|
|
关闭
|
|
</PlatformActionButton>
|
|
<PlatformActionButton
|
|
onClick={execute}
|
|
disabled={isBusy}
|
|
shape="pill"
|
|
size="xs"
|
|
className="gap-2"
|
|
>
|
|
{isBusy ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
|
|
生成并应用正式图
|
|
</PlatformActionButton>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function BigFishLevelCard({
|
|
level,
|
|
slots,
|
|
isBusy,
|
|
onOpenStudio,
|
|
}: {
|
|
level: BigFishLevelBlueprintResponse;
|
|
slots: BigFishAssetSlotResponse[];
|
|
isBusy: boolean;
|
|
onOpenStudio: (target: BigFishAssetStudioTarget) => void;
|
|
}) {
|
|
const mainImageSlot = findAssetSlot(slots, 'level_main_image', level.level);
|
|
const idleSlot = findAssetSlot(
|
|
slots,
|
|
'level_motion',
|
|
level.level,
|
|
'idle_float',
|
|
);
|
|
const moveSlot = findAssetSlot(
|
|
slots,
|
|
'level_motion',
|
|
level.level,
|
|
'move_swim',
|
|
);
|
|
const previewUrl = buildLevelAssetPreview(mainImageSlot);
|
|
|
|
return (
|
|
<PlatformSubpanel
|
|
as="article"
|
|
surface="flat"
|
|
radius="xl"
|
|
padding="none"
|
|
className="overflow-hidden bg-white/78"
|
|
>
|
|
<div className="flex gap-3 p-3">
|
|
<PlatformMediaFrame
|
|
src={previewUrl}
|
|
alt={level.name}
|
|
fallbackLabel="关卡主图"
|
|
fallbackContent={<Waves className="h-8 w-8 text-cyan-100/72" />}
|
|
aspect="square"
|
|
surface="none"
|
|
className="h-24 w-24 shrink-0 rounded-[1.15rem] bg-[radial-gradient(circle_at_center,rgba(34,211,238,0.28),transparent_68%),linear-gradient(145deg,rgba(8,47,73,0.88),rgba(15,23,42,0.94))] text-white"
|
|
/>
|
|
<div className="min-w-0 flex-1">
|
|
<div className="flex items-start justify-between gap-2">
|
|
<div>
|
|
<div className="text-xs font-black tracking-[0.18em] text-cyan-700">
|
|
LV.{level.level}
|
|
</div>
|
|
<div className="mt-1 text-lg font-black text-[var(--platform-text-strong)]">
|
|
{level.name}
|
|
</div>
|
|
</div>
|
|
{level.isFinalLevel ? (
|
|
<PlatformPillBadge
|
|
tone="warning"
|
|
size="xs"
|
|
className="px-2 py-1 text-xs font-bold"
|
|
>
|
|
终局
|
|
</PlatformPillBadge>
|
|
) : null}
|
|
</div>
|
|
<div className="mt-2 line-clamp-2 text-sm leading-5 text-[var(--platform-text-base)]">
|
|
{level.oneLineFantasy}
|
|
</div>
|
|
<div className="mt-3 flex flex-wrap gap-2">
|
|
<PlatformPillBadge tone="muted" size="xxs">
|
|
猎物 {level.preyWindow.join('/') || '-'}
|
|
</PlatformPillBadge>
|
|
<PlatformPillBadge tone="muted" size="xxs">
|
|
威胁 {level.threatWindow.join('/') || '-'}
|
|
</PlatformPillBadge>
|
|
<PlatformPillBadge tone="muted" size="xxs">
|
|
主图 {assetReadyLabel(mainImageSlot)}
|
|
</PlatformPillBadge>
|
|
<PlatformPillBadge tone="muted" size="xxs">
|
|
动作{' '}
|
|
{[assetReadyLabel(idleSlot), assetReadyLabel(moveSlot)].join('/')}
|
|
</PlatformPillBadge>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="grid grid-cols-3 gap-2 border-t border-[var(--platform-subpanel-border)] p-3">
|
|
<PlatformActionButton
|
|
disabled={isBusy}
|
|
onClick={() => {
|
|
onOpenStudio({ kind: 'level_main_image', level });
|
|
}}
|
|
shape="pill"
|
|
size="xs"
|
|
className="px-3"
|
|
>
|
|
主图
|
|
</PlatformActionButton>
|
|
<PlatformActionButton
|
|
disabled={isBusy}
|
|
onClick={() => {
|
|
onOpenStudio({
|
|
kind: 'level_motion',
|
|
level,
|
|
motionKey: 'idle_float',
|
|
});
|
|
}}
|
|
tone="ghost"
|
|
shape="pill"
|
|
size="xs"
|
|
className="px-3"
|
|
>
|
|
待机
|
|
</PlatformActionButton>
|
|
<PlatformActionButton
|
|
disabled={isBusy}
|
|
onClick={() => {
|
|
onOpenStudio({
|
|
kind: 'level_motion',
|
|
level,
|
|
motionKey: 'move_swim',
|
|
});
|
|
}}
|
|
tone="ghost"
|
|
shape="pill"
|
|
size="xs"
|
|
className="px-3"
|
|
>
|
|
移动
|
|
</PlatformActionButton>
|
|
</div>
|
|
</PlatformSubpanel>
|
|
);
|
|
}
|
|
|
|
export function BigFishResultView({
|
|
session,
|
|
isBusy = false,
|
|
error = null,
|
|
onBack,
|
|
onDismissError,
|
|
onExecuteAction,
|
|
onStartTestRun,
|
|
}: BigFishResultViewProps) {
|
|
const [studioTarget, setStudioTarget] =
|
|
useState<BigFishAssetStudioTarget | null>(null);
|
|
const [isPublishSubmitting, setIsPublishSubmitting] = useState(false);
|
|
const draft = session.draft;
|
|
const backgroundSlot = findAssetSlot(session.assetSlots, 'stage_background');
|
|
const backgroundPreviewUrl = buildLevelAssetPreview(backgroundSlot);
|
|
const blockers = useMemo(
|
|
() => session.assetCoverage.blockers.filter(Boolean),
|
|
[session.assetCoverage.blockers],
|
|
);
|
|
const isPublished = session.stage === 'published';
|
|
const canClickPublish = !isPublished && !isBusy;
|
|
const studioPreviewUrl = useMemo(() => {
|
|
if (!studioTarget) {
|
|
return null;
|
|
}
|
|
return buildStudioAssetPreview(session.assetSlots, studioTarget);
|
|
}, [session.assetSlots, studioTarget]);
|
|
|
|
useEffect(() => {
|
|
if (!isBusy || isPublished || error) {
|
|
setIsPublishSubmitting(false);
|
|
}
|
|
}, [error, isBusy, isPublished]);
|
|
|
|
if (!draft) {
|
|
return (
|
|
<div className="flex h-full items-center justify-center">
|
|
<PlatformEmptyState
|
|
surface="subpanel"
|
|
size="compact"
|
|
tone="base"
|
|
>
|
|
还没有可编辑的玩法草稿
|
|
</PlatformEmptyState>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="platform-remap-surface mx-auto flex h-full min-h-0 w-full max-w-6xl flex-col gap-3 overflow-hidden px-1 sm:px-0">
|
|
<div className="platform-result-hero relative overflow-hidden rounded-[1.8rem] border border-cyan-100/16 bg-[radial-gradient(circle_at_top_left,rgba(45,212,191,0.2),transparent_32%),linear-gradient(135deg,rgba(8,47,73,0.98),rgba(15,23,42,0.98))] px-4 py-4 text-white sm:px-5">
|
|
<div className="flex items-start justify-between gap-3">
|
|
<PlatformIconButton
|
|
onClick={onBack}
|
|
disabled={isBusy}
|
|
label="返回"
|
|
title="返回"
|
|
variant="darkMini"
|
|
className="h-10 w-10 !border-white/16 !bg-white/10 !text-white/84 backdrop-blur hover:!bg-white/16 hover:!text-white"
|
|
icon={<ArrowLeft className="h-4 w-4" />}
|
|
/>
|
|
<div className="flex gap-2">
|
|
<PlatformActionButton
|
|
disabled={isBusy}
|
|
onClick={() => {
|
|
onStartTestRun();
|
|
}}
|
|
surface="editorDark"
|
|
tone="secondary"
|
|
shape="pill"
|
|
className="!border-white/16 !bg-white/12 !text-white hover:!bg-white/18"
|
|
>
|
|
<Play className="h-4 w-4" />
|
|
测试
|
|
</PlatformActionButton>
|
|
<PlatformActionButton
|
|
disabled={!canClickPublish}
|
|
onClick={() => {
|
|
setIsPublishSubmitting(true);
|
|
onExecuteAction({ action: 'big_fish_publish_game' });
|
|
}}
|
|
surface="editorDark"
|
|
tone="primary"
|
|
shape="pill"
|
|
className="!border-cyan-200/70 !bg-cyan-200 !text-slate-950 hover:!bg-cyan-100"
|
|
>
|
|
{isPublishSubmitting && isBusy && !isPublished ? (
|
|
<Loader2 className="h-4 w-4 animate-spin" />
|
|
) : (
|
|
<CheckCircle2 className="h-4 w-4" />
|
|
)}
|
|
{isPublished
|
|
? '已发布'
|
|
: isPublishSubmitting && isBusy
|
|
? '发布中'
|
|
: '发布'}
|
|
</PlatformActionButton>
|
|
</div>
|
|
</div>
|
|
<div className="mt-6">
|
|
<div className="text-2xl font-black leading-tight sm:text-3xl">
|
|
{draft.title}
|
|
</div>
|
|
<div className="mt-2 max-w-2xl text-sm leading-6 text-cyan-50/76">
|
|
{draft.subtitle}
|
|
</div>
|
|
</div>
|
|
<div className="mt-4 flex flex-wrap gap-2 text-xs text-cyan-50/78">
|
|
<PlatformPillBadge
|
|
tone="lightOverlay"
|
|
className="border-transparent bg-white/10"
|
|
>
|
|
{draft.coreFun}
|
|
</PlatformPillBadge>
|
|
<PlatformPillBadge
|
|
tone="lightOverlay"
|
|
className="border-transparent bg-white/10"
|
|
>
|
|
{draft.ecologyTheme}
|
|
</PlatformPillBadge>
|
|
<PlatformPillBadge
|
|
tone="lightOverlay"
|
|
className="border-transparent bg-white/10"
|
|
>
|
|
{draft.runtimeParams.levelCount} 级
|
|
</PlatformPillBadge>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid min-h-0 flex-1 gap-3 overflow-hidden lg:grid-cols-[minmax(0,1fr)_18rem]">
|
|
<div className="min-h-0 overflow-y-auto pr-1">
|
|
<div className="grid gap-3 sm:grid-cols-2">
|
|
{draft.levels.map((level) => (
|
|
<BigFishLevelCard
|
|
key={level.level}
|
|
level={level}
|
|
slots={session.assetSlots}
|
|
isBusy={isBusy}
|
|
onOpenStudio={setStudioTarget}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<aside className="min-h-0 space-y-3 overflow-y-auto">
|
|
<PlatformSubpanel
|
|
as="section"
|
|
surface="flat"
|
|
radius="xl"
|
|
className="bg-[var(--platform-subpanel-fill)]"
|
|
>
|
|
<div className="flex items-center justify-between gap-2">
|
|
<div>
|
|
<div className="text-sm font-black text-[var(--platform-text-strong)]">
|
|
场地背景
|
|
</div>
|
|
<div className="mt-1 text-xs text-[var(--platform-text-soft)]">
|
|
{assetReadyLabel(backgroundSlot)}
|
|
</div>
|
|
</div>
|
|
<ImagePlus className="h-5 w-5 text-cyan-600" />
|
|
</div>
|
|
<PlatformMediaFrame
|
|
src={backgroundPreviewUrl}
|
|
alt={`${draft.background.theme} 场地背景`}
|
|
fallbackLabel="场地背景"
|
|
fallbackContent={<span className="sr-only">场地背景</span>}
|
|
aspect="portrait"
|
|
surface="none"
|
|
className="mt-3 rounded-[1.2rem] bg-[radial-gradient(circle_at_center,rgba(34,211,238,0.2),transparent_62%),linear-gradient(180deg,rgba(8,47,73,0.88),rgba(15,23,42,0.94))]"
|
|
/>
|
|
<PlatformActionButton
|
|
disabled={isBusy}
|
|
onClick={() => {
|
|
setStudioTarget({ kind: 'stage_background' });
|
|
}}
|
|
shape="pill"
|
|
size="xs"
|
|
fullWidth
|
|
className="mt-3 gap-2"
|
|
>
|
|
<Sparkles className="h-4 w-4" />
|
|
生成背景
|
|
</PlatformActionButton>
|
|
</PlatformSubpanel>
|
|
|
|
<PlatformSubpanel
|
|
as="section"
|
|
surface="flat"
|
|
radius="xl"
|
|
className="bg-[var(--platform-subpanel-fill)]"
|
|
>
|
|
<div className="text-sm font-black text-[var(--platform-text-strong)]">
|
|
发布校验
|
|
</div>
|
|
<div className="mt-3 space-y-2 text-sm text-[var(--platform-text-base)]">
|
|
<div>
|
|
主图 {session.assetCoverage.levelMainImageReadyCount}/
|
|
{session.assetCoverage.requiredLevelCount}
|
|
</div>
|
|
<div>
|
|
动作 {session.assetCoverage.levelMotionReadyCount}/
|
|
{session.assetCoverage.requiredLevelCount * 2}
|
|
</div>
|
|
<div>
|
|
背景{' '}
|
|
{session.assetCoverage.backgroundReady ? '已完成' : '待生成'}
|
|
</div>
|
|
</div>
|
|
{isPublished ? (
|
|
<div className="mt-3">
|
|
<PlatformPillBadge tone="success" size="sm">
|
|
已发布
|
|
</PlatformPillBadge>
|
|
</div>
|
|
) : blockers.length > 0 ? (
|
|
<PlatformStatusMessage
|
|
tone="warning"
|
|
surface="platform"
|
|
size="xs"
|
|
className="mt-3 space-y-1 leading-5"
|
|
>
|
|
{blockers.slice(0, 4).map((blocker) => (
|
|
<div key={blocker}>{blocker}</div>
|
|
))}
|
|
</PlatformStatusMessage>
|
|
) : (
|
|
<div className="mt-3">
|
|
<PlatformPillBadge tone="success" size="sm">
|
|
已达到发布条件
|
|
</PlatformPillBadge>
|
|
</div>
|
|
)}
|
|
</PlatformSubpanel>
|
|
</aside>
|
|
</div>
|
|
|
|
{studioTarget ? (
|
|
<BigFishAssetStudioModal
|
|
draft={draft}
|
|
target={studioTarget}
|
|
previewUrl={studioPreviewUrl}
|
|
isBusy={isBusy}
|
|
onClose={() => {
|
|
setStudioTarget(null);
|
|
}}
|
|
onExecuteAction={(payload) => {
|
|
onExecuteAction(payload);
|
|
setStudioTarget(null);
|
|
}}
|
|
/>
|
|
) : null}
|
|
|
|
{error ? (
|
|
<BigFishResultErrorModal
|
|
message={error}
|
|
onClose={() => {
|
|
onDismissError?.();
|
|
}}
|
|
/>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function BigFishResultErrorModal({
|
|
message,
|
|
onClose,
|
|
}: {
|
|
message: string;
|
|
onClose: () => void;
|
|
}) {
|
|
return (
|
|
<UnifiedConfirmDialog
|
|
open
|
|
title="发布失败"
|
|
onClose={onClose}
|
|
closeOnBackdrop={false}
|
|
showCloseButton={false}
|
|
confirmLabel="知道了"
|
|
confirmClassName="w-full justify-center border-slate-950 bg-slate-950 text-white"
|
|
size="sm"
|
|
zIndexClassName="z-[160]"
|
|
overlayClassName="bg-slate-950/58"
|
|
panelClassName="border-red-100/80 bg-white text-slate-950 shadow-2xl"
|
|
footerClassName="border-t-0 px-5 pb-5 pt-0"
|
|
>
|
|
<div className="flex items-start gap-3">
|
|
<PlatformIconBadge
|
|
icon={<Waves className="h-4 w-4" />}
|
|
label="发布失败提示"
|
|
tone="danger"
|
|
className="mt-0.5"
|
|
/>
|
|
<div className="min-w-0 flex-1 text-sm leading-6 text-slate-600">
|
|
{message}
|
|
</div>
|
|
</div>
|
|
</UnifiedConfirmDialog>
|
|
);
|
|
}
|
|
|
|
export default BigFishResultView;
|