继续收口平台分段与泥点确认

新增泥点确认状态机共享 hook 并接入拼图与抓大鹅工作台

将首页发现页与个人中心剩余切换条收口到 PlatformSegmentedTabs

统一平台弹窗 header 关闭入口并补齐相关测试

更新前端组件收口文档与团队决策记录
This commit is contained in:
2026-06-11 01:30:13 +08:00
parent 94122583ac
commit 0a4ccdf45c
19 changed files with 511 additions and 242 deletions
@@ -1,5 +1,5 @@
import { Loader2, Sparkles, WandSparkles } from 'lucide-react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type {
CreateMatch3DSessionRequest,
@@ -9,12 +9,13 @@ import type {
} from '../../../../packages/shared/src/contracts/match3dAgent';
import { PlatformActionButton } from '../../common/PlatformActionButton';
import { PlatformFieldLabel } from '../../common/PlatformFieldLabel';
import { PlatformMudPointConfirmDialog } from '../../common/PlatformMudPointConfirmDialog';
import { PlatformPillBadge } from '../../common/PlatformPillBadge';
import { PlatformSegmentedTabs } from '../../common/PlatformSegmentedTabs';
import { PlatformStatusMessage } from '../../common/PlatformStatusMessage';
import { PlatformSubpanel } from '../../common/PlatformSubpanel';
import { PlatformTextField } from '../../common/PlatformTextField';
import { PlatformMudPointConfirmDialog } from '../../common/PlatformMudPointConfirmDialog';
import { useMudPointConfirmController } from '../../common/useMudPointConfirmController';
type Match3DCreationWorkspaceProps = {
session: Match3DAgentSessionSnapshot | null;
@@ -131,7 +132,6 @@ export function Match3DCreationWorkspace({
const [formState, setFormState] = useState<Match3DFormState>(() =>
resolveInitialFormState(session, initialFormPayload),
);
const [isPointCostConfirmOpen, setIsPointCostConfirmOpen] = useState(false);
const appliedInitialFormKeyRef = useRef<string | null>(null);
useEffect(() => {
@@ -143,7 +143,6 @@ export function Match3DCreationWorkspace({
appliedInitialFormKeyRef.current = nextInitialFormKey;
setFormState(resolveInitialFormState(session, initialFormPayload));
setIsPointCostConfirmOpen(false);
}, [initialFormPayload, session]);
const themeText = formState.themeText.trim();
@@ -165,32 +164,40 @@ export function Match3DCreationWorkspace({
[selectedDifficultyOption, themeText],
);
const submitForm = () => {
if (!canSubmit) {
return;
}
setIsPointCostConfirmOpen(true);
};
const executeSubmitForm = () => {
const executeSubmitForm = useCallback(() => {
if (!canSubmit) {
return;
}
if (onCreateFromForm) {
setIsPointCostConfirmOpen(false);
onCreateFromForm(formPayload);
return;
}
if (session) {
setIsPointCostConfirmOpen(false);
onExecuteAction({
action: 'match3d_compile_draft',
generateClickSound: false,
});
}
}, [canSubmit, formPayload, onCreateFromForm, onExecuteAction, session]);
const {
open: isPointCostConfirmOpen,
requestOpen: requestPointCostConfirm,
close: closePointCostConfirm,
confirm: confirmPointCostConfirm,
} = useMudPointConfirmController(executeSubmitForm);
useEffect(() => {
closePointCostConfirm();
}, [closePointCostConfirm, initialFormPayload, session]);
const submitForm = () => {
if (!canSubmit) {
return;
}
requestPointCostConfirm();
};
return (
@@ -354,8 +361,8 @@ export function Match3DCreationWorkspace({
<PlatformMudPointConfirmDialog
open={isPointCostConfirmOpen}
points={mudPointCost}
onClose={() => setIsPointCostConfirmOpen(false)}
onConfirm={executeSubmitForm}
onClose={closePointCostConfirm}
onConfirm={confirmPointCostConfirm}
confirmDisabled={!canSubmit}
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)]"
@@ -1,5 +1,5 @@
import { ArrowLeft } from 'lucide-react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { PuzzleAgentActionRequest } from '../../../../packages/shared/src/contracts/puzzleAgentActions';
import type {
@@ -19,6 +19,7 @@ import {
type CreativeImageInputReferenceImage,
} from '../../common/CreativeImageInputPanel';
import { PlatformActionButton } from '../../common/PlatformActionButton';
import { PlatformMudPointConfirmDialog } from '../../common/PlatformMudPointConfirmDialog';
import { PlatformPillBadge } from '../../common/PlatformPillBadge';
import { SquareImageCropModal } from '../../common/SquareImageCropModal';
import {
@@ -26,7 +27,7 @@ import {
clampSquareImageCropRect,
type SquareImageCropRect,
} from '../../common/squareImageCropModel';
import { PlatformMudPointConfirmDialog } from '../../common/PlatformMudPointConfirmDialog';
import { useMudPointConfirmController } from '../../common/useMudPointConfirmController';
import PuzzleHistoryAssetPickerDialog from '../shared/PuzzleHistoryAssetPickerDialog';
import {
normalizePuzzleImageModel,
@@ -254,7 +255,6 @@ export function PuzzleCreationWorkspace({
);
const [cropState, setCropState] = useState<PuzzleImageCropState | null>(null);
const [isHistoryPickerOpen, setIsHistoryPickerOpen] = useState(false);
const [isPointCostConfirmOpen, setIsPointCostConfirmOpen] = useState(false);
const previousSessionIdRef = useRef<string | null>(
session?.sessionId ?? null,
);
@@ -284,7 +284,6 @@ export function PuzzleCreationWorkspace({
setReferenceImageError(null);
setCropState(null);
setIsHistoryPickerOpen(false);
setIsPointCostConfirmOpen(false);
}, [initialFormPayload, session]);
const pictureDescription = formState.pictureDescription.trim();
@@ -476,6 +475,71 @@ export function PuzzleCreationWorkspace({
setReferenceImageError(null);
};
const executeSubmitForm = useCallback(() => {
if (!canSubmit) {
return;
}
const payloadPictureDescription = formState.aiRedraw
? pictureDescription
: pictureDescription || formState.referenceImageLabel || '上传拼图图片';
const payload = {
seedText: payloadPictureDescription,
workDescription: payloadPictureDescription,
pictureDescription: payloadPictureDescription,
referenceImageSrc: mainReferenceImageSrcForPayload,
referenceImageSrcs: promptReferenceImageSrcsForPayload,
referenceImageAssetObjectId:
formState.referenceImageAssetObjectId || null,
referenceImageAssetObjectIds: promptReferenceAssetObjectIds,
imageModel: formState.imageModel,
aiRedraw: formState.aiRedraw,
};
if (!session && onCreateFromForm) {
onCreateFromForm(payload);
return;
}
onExecuteAction({
action: 'compile_puzzle_draft',
promptText: payloadPictureDescription,
workDescription: payloadPictureDescription,
pictureDescription: payloadPictureDescription,
referenceImageSrc: mainReferenceImageSrcForPayload,
referenceImageSrcs: promptReferenceImageSrcsForPayload,
referenceImageAssetObjectId:
formState.referenceImageAssetObjectId || null,
referenceImageAssetObjectIds: promptReferenceAssetObjectIds,
imageModel: formState.imageModel,
aiRedraw: formState.aiRedraw,
candidateCount: 1,
});
}, [
canSubmit,
formState.aiRedraw,
formState.imageModel,
formState.referenceImageAssetObjectId,
formState.referenceImageLabel,
mainReferenceImageSrcForPayload,
onCreateFromForm,
onExecuteAction,
pictureDescription,
promptReferenceAssetObjectIds,
promptReferenceImageSrcsForPayload,
session,
]);
const {
open: isPointCostConfirmOpen,
requestOpen: requestPointCostConfirm,
close: closePointCostConfirm,
confirm: confirmPointCostConfirm,
} = useMudPointConfirmController(executeSubmitForm);
useEffect(() => {
closePointCostConfirm();
}, [closePointCostConfirm, initialFormPayload, session]);
const updateCropState = (nextCrop: {
x: number;
y: number;
@@ -538,56 +602,12 @@ export function PuzzleCreationWorkspace({
}
if (formState.aiRedraw) {
setIsPointCostConfirmOpen(true);
requestPointCostConfirm();
return;
}
executeSubmitForm();
};
const executeSubmitForm = () => {
if (!canSubmit) {
return;
}
const payloadPictureDescription = formState.aiRedraw
? pictureDescription
: pictureDescription || formState.referenceImageLabel || '上传拼图图片';
const payload = {
seedText: payloadPictureDescription,
workDescription: payloadPictureDescription,
pictureDescription: payloadPictureDescription,
referenceImageSrc: mainReferenceImageSrcForPayload,
referenceImageSrcs: promptReferenceImageSrcsForPayload,
referenceImageAssetObjectId:
formState.referenceImageAssetObjectId || null,
referenceImageAssetObjectIds: promptReferenceAssetObjectIds,
imageModel: formState.imageModel,
aiRedraw: formState.aiRedraw,
};
if (!session && onCreateFromForm) {
setIsPointCostConfirmOpen(false);
onCreateFromForm(payload);
return;
}
setIsPointCostConfirmOpen(false);
onExecuteAction({
action: 'compile_puzzle_draft',
promptText: payloadPictureDescription,
workDescription: payloadPictureDescription,
pictureDescription: payloadPictureDescription,
referenceImageSrc: mainReferenceImageSrcForPayload,
referenceImageSrcs: promptReferenceImageSrcsForPayload,
referenceImageAssetObjectId:
formState.referenceImageAssetObjectId || null,
referenceImageAssetObjectIds: promptReferenceAssetObjectIds,
imageModel: formState.imageModel,
aiRedraw: formState.aiRedraw,
candidateCount: 1,
});
};
const removeReferenceImage = () => {
setFormState((current) => ({
...current,
@@ -750,8 +770,8 @@ export function PuzzleCreationWorkspace({
<PlatformMudPointConfirmDialog
open={isPointCostConfirmOpen}
points={mudPointCost}
onClose={() => setIsPointCostConfirmOpen(false)}
onConfirm={executeSubmitForm}
onClose={closePointCostConfirm}
onConfirm={confirmPointCostConfirm}
confirmDisabled={!canSubmit}
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)]"