Add big fish settlement actions and publish feedback

This commit is contained in:
2026-04-26 21:28:02 +08:00
parent 09d3fe59b3
commit c81305f2e6
11 changed files with 326 additions and 15 deletions

View File

@@ -170,4 +170,35 @@ describe('BigFishResultView', () => {
fireEvent.click(screen.getByRole('button', { name: '知道了' }));
expect(onDismissError).toHaveBeenCalledTimes(1);
});
test('shows published state and prevents duplicate publish clicks', () => {
const onExecuteAction = vi.fn();
render(
<BigFishResultView
session={{
...createSession(),
stage: 'published',
publishReady: true,
assetCoverage: {
levelMainImageReadyCount: 1,
levelMotionReadyCount: 2,
backgroundReady: true,
requiredLevelCount: 1,
publishReady: true,
blockers: [],
},
}}
onBack={() => {}}
onExecuteAction={onExecuteAction}
onStartTestRun={() => {}}
/>,
);
const publishedButton = screen.getByRole('button', { name: '已发布' });
expect((publishedButton as HTMLButtonElement).disabled).toBe(true);
expect(screen.getAllByText('已发布').length).toBeGreaterThan(0);
fireEvent.click(publishedButton);
expect(onExecuteAction).not.toHaveBeenCalled();
});
});

View File

@@ -7,7 +7,7 @@ import {
Sparkles,
Waves,
} from 'lucide-react';
import { useMemo, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import type {
BigFishAssetSlotResponse,
@@ -338,6 +338,7 @@ export function BigFishResultView({
}: 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);
@@ -345,6 +346,8 @@ export function BigFishResultView({
() => session.assetCoverage.blockers.filter(Boolean),
[session.assetCoverage.blockers],
);
const isPublished = session.stage === 'published';
const canClickPublish = !isPublished && !isBusy;
const studioPreviewUrl = useMemo(() => {
if (!studioTarget) {
return null;
@@ -352,6 +355,12 @@ export function BigFishResultView({
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">
@@ -388,14 +397,23 @@ export function BigFishResultView({
</button>
<button
type="button"
disabled={isBusy}
disabled={!canClickPublish}
onClick={() => {
setIsPublishSubmitting(true);
onExecuteAction({ action: 'big_fish_publish_game' });
}}
className="inline-flex items-center gap-2 rounded-full bg-cyan-200 px-4 py-2 text-sm font-bold text-slate-950 disabled:opacity-45"
>
<CheckCircle2 className="h-4 w-4" />
{isPublishSubmitting && isBusy && !isPublished ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<CheckCircle2 className="h-4 w-4" />
)}
{isPublished
? '已发布'
: isPublishSubmitting && isBusy
? '发布中'
: '发布'}
</button>
</div>
</div>
@@ -487,7 +505,11 @@ export function BigFishResultView({
{session.assetCoverage.backgroundReady ? '已完成' : '待生成'}
</div>
</div>
{blockers.length > 0 ? (
{isPublished ? (
<div className="mt-3 text-sm font-semibold text-emerald-600">
</div>
) : blockers.length > 0 ? (
<div className="mt-3 space-y-1 text-xs leading-5 text-amber-700">
{blockers.slice(0, 4).map((blocker) => (
<div key={blocker}>{blocker}</div>