fix(design): surface incomplete creation plans
This commit is contained in:
@@ -70,7 +70,12 @@ function canonicalCreatorPrompt(workspace: DesignWorkspace): string {
|
||||
const values = workspace.form.specification.values;
|
||||
return values.content.concept?.trim()
|
||||
|| values.content.narrative?.trim()
|
||||
|| '';
|
||||
|| [
|
||||
...values.content.subjects.map((subject) => subject.description.trim()),
|
||||
values.content.action?.trim(),
|
||||
values.content.environment?.trim(),
|
||||
values.content.emotional_tone?.trim(),
|
||||
].filter((value): value is string => Boolean(value)).join(',');
|
||||
}
|
||||
|
||||
function Stepper({
|
||||
@@ -141,7 +146,7 @@ export function YouthCreationCard({
|
||||
const [replaceIndex, setReplaceIndex] = useState<number | null>(null);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
const [medium, setMedium] = useState(values.intent.media ?? 'image');
|
||||
const [aspectRatio, setAspectRatio] = useState(values.output.aspect_ratio ?? '1:1');
|
||||
const [aspectRatio, setAspectRatio] = useState(values.output.aspect_ratio ?? '');
|
||||
const [duration, setDuration] = useState(values.video.total_duration_seconds ?? 6);
|
||||
const [variantCount, setVariantCount] = useState(values.output.variant_count ?? 1);
|
||||
const promptRef = useRef<HTMLTextAreaElement>(null);
|
||||
@@ -155,7 +160,7 @@ export function YouthCreationCard({
|
||||
|
||||
useEffect(() => {
|
||||
setMedium(values.intent.media ?? 'image');
|
||||
setAspectRatio(values.output.aspect_ratio ?? '1:1');
|
||||
setAspectRatio(values.output.aspect_ratio ?? '');
|
||||
setDuration(values.video.total_duration_seconds ?? 6);
|
||||
setVariantCount(values.output.variant_count ?? 1);
|
||||
}, [
|
||||
@@ -602,6 +607,7 @@ export function YouthCreationCard({
|
||||
], () => setAspectRatio(next));
|
||||
}}
|
||||
>
|
||||
<option value="" disabled>请选择</option>
|
||||
{ASPECT_RATIOS.map((item) => <option key={item.value} value={item.value}>{item.label}</option>)}
|
||||
</Select>
|
||||
</label>
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import type { DesignWorkspace } from '../../../shared/image-workspace';
|
||||
|
||||
function hasCreatorPrompt(workspace: DesignWorkspace): boolean {
|
||||
function hasCreatorMeaning(workspace: DesignWorkspace): boolean {
|
||||
const values = workspace.form.specification.values;
|
||||
return Boolean(values.content.concept?.trim() || values.content.narrative?.trim());
|
||||
return Boolean(
|
||||
values.content.concept?.trim()
|
||||
|| values.content.narrative?.trim()
|
||||
|| values.content.action?.trim()
|
||||
|| values.content.environment?.trim()
|
||||
|| values.content.emotional_tone?.trim()
|
||||
|| values.content.subjects.some((subject) => subject.description.trim())
|
||||
|| values.content.exact_content.some((item) => item.text.trim())
|
||||
|| values.references.length > 0,
|
||||
);
|
||||
}
|
||||
|
||||
export function hasActiveCreationPlan(workspace: DesignWorkspace): boolean {
|
||||
if (workspace.form.activeQuotes.some((quote) => quote.status === 'offered')) return true;
|
||||
if (!hasCreatorPrompt(workspace) && workspace.form.specification.values.references.length === 0) return false;
|
||||
if (!hasCreatorMeaning(workspace)) return false;
|
||||
const latestTaskRevision = workspace.tasks.reduce(
|
||||
(latest, task) => Math.max(latest, task.specificationRevision),
|
||||
-1,
|
||||
|
||||
@@ -192,6 +192,40 @@ describe('AI Design Canvas page', () => {
|
||||
expect(screen.queryByTestId('image-workspace-works-rail')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows an incomplete meaningful plan and does not invent a selected aspect ratio', async () => {
|
||||
const form = designFormFixture();
|
||||
form.specification.values.content.concept = null;
|
||||
form.specification.values.content.action = '一只狗和一只猫在草地上互相扑咬玩闹';
|
||||
form.specification.values.output.aspect_ratio = null;
|
||||
form.specification.values.output.orientation = 'portrait';
|
||||
const { actions } = prepareWorkspace({ form });
|
||||
useImageWorkspaceStore.setState({
|
||||
quoteBlockers: [{
|
||||
code: 'aspect_ratio_required',
|
||||
message: 'Choose an aspect ratio before requesting a production quote.',
|
||||
severity: 'blocker',
|
||||
path: 'output.aspect_ratio',
|
||||
}],
|
||||
});
|
||||
|
||||
render(<ImageCanvas />);
|
||||
|
||||
expect(screen.getByRole('heading', { name: '制作方案' })).toBeInTheDocument();
|
||||
expect(screen.getByText('先选择作品形状。')).toBeInTheDocument();
|
||||
expect(screen.getByRole('combobox', { name: '画幅' })).toHaveValue('');
|
||||
expect(screen.getByRole('button', { name: '准备制作方案' })).toBeDisabled();
|
||||
|
||||
fireEvent.change(screen.getByRole('combobox', { name: '画幅' }), {
|
||||
target: { value: '9:16' },
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(actions.applyFieldOperations).toHaveBeenCalledWith([
|
||||
{ kind: 'set', path: 'output.aspect_ratio', value: '9:16' },
|
||||
{ kind: 'set', path: 'output.orientation', value: 'portrait' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('opens project navigation as a left sheet on compact layouts', () => {
|
||||
prepareWorkspace();
|
||||
render(<ImageCanvas />);
|
||||
|
||||
Reference in New Issue
Block a user