import { ArrowLeft, Loader2, Send } from 'lucide-react'; import { useMemo, useState } from 'react'; import type { PuzzleClearImageAsset, PuzzleClearSessionResponse, PuzzleClearWorkspaceCreateRequest, } from '../../../packages/shared/src/contracts/puzzleClear'; import { puzzleClearClient } from '../../services/puzzle-clear/puzzleClearClient'; import { readPuzzleReferenceImageAsDataUrl } from '../../services/puzzleReferenceImage'; import { CreativeImageInputPanel } from '../common/CreativeImageInputPanel'; type PuzzleClearWorkspaceProps = { isBusy?: boolean; error?: string | null; onBack: () => void; onSubmitted: ( result: PuzzleClearSessionResponse, payload: PuzzleClearWorkspaceCreateRequest, ) => void; }; type PuzzleClearWorkspaceFormState = { workTitle: string; workDescription: string; themePrompt: string; boardBackgroundPrompt: string; boardBackgroundAsset: PuzzleClearImageAsset | null; boardBackgroundImageSrc: string; generateBoardBackground: boolean; }; const DEFAULT_FORM_STATE: PuzzleClearWorkspaceFormState = { workTitle: '', workDescription: '', themePrompt: '', boardBackgroundPrompt: '', boardBackgroundAsset: null, boardBackgroundImageSrc: '', generateBoardBackground: true, }; function buildLocalBoardBackgroundAsset( imageSrc: string, prompt: string, ): PuzzleClearImageAsset { return { assetId: `local-board-background-${Date.now()}`, imageSrc, imageObjectKey: '', assetObjectId: '', generationProvider: 'local-upload', prompt, width: 0, height: 0, }; } export function PuzzleClearWorkspace({ isBusy = false, error = null, onBack, onSubmitted, }: PuzzleClearWorkspaceProps) { const [formState, setFormState] = useState(DEFAULT_FORM_STATE); const [localError, setLocalError] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const hasBoardBackgroundInput = useMemo( () => formState.generateBoardBackground || Boolean(formState.boardBackgroundAsset || formState.boardBackgroundImageSrc), [ formState.boardBackgroundAsset, formState.boardBackgroundImageSrc, formState.generateBoardBackground, ], ); const canSubmit = useMemo( () => Boolean( formState.workTitle.trim() && formState.themePrompt.trim() && hasBoardBackgroundInput, ), [formState.themePrompt, formState.workTitle, hasBoardBackgroundInput], ); const handleSubmit = async () => { if (!canSubmit || isSubmitting || isBusy) { setLocalError('请先补全输入。'); return; } setIsSubmitting(true); setLocalError(null); try { const boardBackgroundAsset = formState.boardBackgroundAsset ?? (formState.boardBackgroundImageSrc ? buildLocalBoardBackgroundAsset( formState.boardBackgroundImageSrc, formState.boardBackgroundPrompt.trim() || formState.themePrompt.trim(), ) : null); const payload: PuzzleClearWorkspaceCreateRequest = { templateId: 'puzzle-clear', workTitle: formState.workTitle.trim(), workDescription: formState.workDescription.trim(), themePrompt: formState.themePrompt.trim(), boardBackgroundPrompt: formState.boardBackgroundPrompt.trim(), generateBoardBackground: formState.generateBoardBackground, boardBackgroundAsset, }; const response = await puzzleClearClient.createSession(payload); onSubmitted(response, payload); } catch (caughtError) { setLocalError( caughtError instanceof Error ? caughtError.message : '创建草稿失败。', ); } finally { setIsSubmitting(false); } }; return (
{ event.preventDefault(); void handleSubmit(); }} className="platform-remap-surface mx-auto flex h-full min-h-0 w-full max-w-5xl flex-col px-3 pb-3 pt-3 sm:px-4 sm:pt-4" >