修复图片编辑复用与元数据回退的小问题

- 修复参考素材标签的空白文本回退显示

- 重构 quick-edit 参数选择逻辑,移除嵌套三元并统一回退

- 抽取生成复用流程的参数回退与缺失素材提示逻辑

- 使用 quick-edit 提交计划中的输出尺寸构建复用时占位符
This commit is contained in:
2026-08-04 17:15:33 +08:00
parent 96b06cc39b
commit 78307de9a1
4 changed files with 101 additions and 44 deletions
@@ -148,6 +148,23 @@ function getDialogDefaultPrompt(mode: GenerateDialogState['mode']) {
return 'AI 生成图片';
}
function resolveOptionalFieldWithFallback<T extends string>(
preferredValue: string | undefined | null,
supportedValues: readonly string[],
fallbackValues: readonly T[],
defaultValue: T,
) {
const normalizedPreferred = preferredValue?.trim() ?? '';
if (supportedValues.includes(normalizedPreferred)) {
return normalizedPreferred as T;
}
return (
fallbackValues.find((fallbackValue) =>
supportedValues.includes(fallbackValue),
) ?? defaultValue
);
}
export type ImageGenerationSubmissionPlan =
| {
kind: 'edit';
@@ -306,17 +323,21 @@ export function buildImageGenerationSubmissionPlan({
sourceLayer.originalHeight,
);
const aspectRatio = supportedAspectRatios.includes(dialog.aspectRatio ?? '')
? dialog.aspectRatio!
: supportedAspectRatios.includes(inferredAspectRatio)
? inferredAspectRatio
: (dimensionOptions.aspectRatios[0] ?? '1:1');
? dialog.aspectRatio!.trim()
: resolveOptionalFieldWithFallback(
inferredAspectRatio,
supportedAspectRatios,
dimensionOptions.aspectRatios,
'1:1',
);
const imageSize = supportedImageSizes.includes(dialog.imageSize ?? '')
? dialog.imageSize!
: supportedImageSizes.includes(inferredImageSize)
? inferredImageSize
: (dimensionOptions.imageSizes.find((size) => size === '1K') ??
dimensionOptions.imageSizes[0] ??
'1K');
: resolveOptionalFieldWithFallback(
inferredImageSize,
supportedImageSizes,
dimensionOptions.imageSizes,
'1K',
);
const outputSize = resolveEditorImageGenerationPixelSize({
model: imageModel,
aspectRatio,
@@ -84,7 +84,7 @@ export function ImageCanvasMetadataModalView({
{reference.title}
</span>
<span>
{reference.label ?? '参考素材'}
{reference.label?.trim() || '参考素材'}
</span>
<span className="image-canvas-editor__metadata-reference-id">
{formatReferenceType(reference.refType)} ·{' '}
@@ -257,6 +257,29 @@ const EDITOR_GENERATION_QUEUE_POLL_INTERVAL_MS = 1600;
const EDITOR_GENERATION_QUEUE_TIMEOUT_MS = 20 * 60 * 1000;
const EDITOR_GENERATION_QUEUE_PROJECT_REFRESH_RETRY_MS = 650;
function getCanvasCompletionPlaceholderSizeFromPlan({
sourceLayer,
outputSize,
}: {
sourceLayer: CanvasLayer;
outputSize: string | null | undefined;
}) {
const match = /^(\d+)x(\d+)$/i.exec(outputSize?.trim() ?? '');
if (!match) {
return {
width: sourceLayer.originalWidth,
height: sourceLayer.originalHeight,
};
}
const width = Number(match[1]);
const height = Number(match[2]);
return {
width: Number.isFinite(width) && width > 0 ? width : sourceLayer.originalWidth,
height:
Number.isFinite(height) && height > 0 ? height : sourceLayer.originalHeight,
};
}
type GenerationSubmissionWorkflowOptions = {
layers: CanvasLayer[];
canvasSize: CanvasSize;
@@ -1899,6 +1922,10 @@ export function useImageCanvasGenerationSubmissionWorkflow({
projectId,
);
}
const quickEditPlaceholderSize = getCanvasCompletionPlaceholderSizeFromPlan({
sourceLayer: submissionPlan.sourceLayer,
outputSize: submissionPlan.editInput.size,
});
const generated = await runEditorGenerationWithWalletRefresh(
editEditorImage({
prompt: submissionPlan.normalizedPrompt,
@@ -1920,12 +1947,10 @@ export function useImageCanvasGenerationSubmissionWorkflow({
buildRightSideCanvasCompletionPlaceholder(
submissionPlan.sourceLayer,
{
width: submissionPlan.sourceLayer.originalWidth,
height: submissionPlan.sourceLayer.originalHeight,
originalWidth:
submissionPlan.sourceLayer.originalWidth,
originalHeight:
submissionPlan.sourceLayer.originalHeight,
width: quickEditPlaceholderSize.width,
height: quickEditPlaceholderSize.height,
originalWidth: quickEditPlaceholderSize.width,
originalHeight: quickEditPlaceholderSize.height,
},
),
},
@@ -115,6 +115,31 @@ import {
type CanvasSize = { width: number; height: number };
function getCanvasGenerationRedrawWarning({
hasParameterFallbacks,
unavailableReferenceCount,
isNormalizedGenerationInputs,
}: {
hasParameterFallbacks: boolean;
unavailableReferenceCount: number;
isNormalizedGenerationInputs: boolean;
}) {
const hasUnavailableReferences = unavailableReferenceCount > 0;
if (hasParameterFallbacks && hasUnavailableReferences) {
return `${CANVAS_GENERATION_PARAMETER_FALLBACK_WARNING} 部分原参考素材不在当前画布或来自面板上传,未恢复,请重新选择。`;
}
if (hasParameterFallbacks) {
return CANVAS_GENERATION_PARAMETER_FALLBACK_WARNING;
}
if (!isNormalizedGenerationInputs && hasUnavailableReferences) {
return '已按旧版数据恢复,部分参数可能使用当前默认值。';
}
if (hasUnavailableReferences) {
return '部分原参考素材不在当前画布或来自面板上传,未恢复,请重新选择。';
}
return null;
}
type CropExpandResizeDragState = {
pointerId: number;
handle: CropExpandResizeHandle;
@@ -1345,18 +1370,13 @@ export function useImageCanvasGenerationWorkflow({
setQuickEditPanel(null);
selectSingleLayer(extractionSource.id);
setActiveTool('select');
if (hasParameterFallbacks && unavailableReferences.length) {
showGenerationWarning(
`${CANVAS_GENERATION_PARAMETER_FALLBACK_WARNING} `,
);
} else if (hasParameterFallbacks) {
showGenerationWarning(
CANVAS_GENERATION_PARAMETER_FALLBACK_WARNING,
);
} else if (unavailableReferences.length) {
showGenerationWarning(
'部分原参考素材不在当前画布或来自面板上传,未恢复,请重新选择。',
);
const redrawWarning = getCanvasGenerationRedrawWarning({
hasParameterFallbacks,
unavailableReferenceCount: unavailableReferences.length,
isNormalizedGenerationInputs,
});
if (redrawWarning) {
showGenerationWarning(redrawWarning);
}
return;
}
@@ -1382,22 +1402,13 @@ export function useImageCanvasGenerationWorkflow({
setQuickEditPanel(null);
selectSingleLayer(null);
setActiveTool(getCanvasToolForGenerationMode(sameSourceDraft.mode));
if (hasParameterFallbacks && unavailableReferences.length) {
showGenerationWarning(
`${CANVAS_GENERATION_PARAMETER_FALLBACK_WARNING} `,
);
} else if (hasParameterFallbacks) {
showGenerationWarning(
CANVAS_GENERATION_PARAMETER_FALLBACK_WARNING,
);
} else if (isNormalizedGenerationInputs && unavailableReferences.length) {
showGenerationWarning(
'部分原参考素材不在当前画布或来自面板上传,未恢复,请重新选择。',
);
} else if (!isNormalizedGenerationInputs) {
showGenerationWarning(
'已按旧版数据恢复,部分参数可能使用当前默认值。',
);
const redrawWarning = getCanvasGenerationRedrawWarning({
hasParameterFallbacks,
unavailableReferenceCount: unavailableReferences.length,
isNormalizedGenerationInputs,
});
if (redrawWarning) {
showGenerationWarning(redrawWarning);
}
return;
}