diff --git a/components/canvas/AiWashWorkspace.tsx b/components/canvas/AiWashWorkspace.tsx
index d0dba9979..4af410e5f 100644
--- a/components/canvas/AiWashWorkspace.tsx
+++ b/components/canvas/AiWashWorkspace.tsx
@@ -1284,14 +1284,14 @@ export function AiWashWorkspace({
) : (
-
+
选择本地图后即可开始 {config.modeLabel || "AI洗图"}
diff --git a/components/canvas/nodes/ImageNode.tsx b/components/canvas/nodes/ImageNode.tsx
index 89049be1e..962825fd0 100644
--- a/components/canvas/nodes/ImageNode.tsx
+++ b/components/canvas/nodes/ImageNode.tsx
@@ -1201,6 +1201,14 @@ export function ImageNode({
imageNodeMoreEnabled &&
(hasHoverImageMorePrimaryActions || hasHoverImageMoreSecondaryActions);
const hasSelectedImageMorePrimaryActions =
+ imageBoxCutoutEnabled ||
+ imageLocalEditEnabled ||
+ imageRemoveWatermarkEnabled ||
+ imageResizeEnabled ||
+ imageMultiAngleEnabled ||
+ imageGenerate3dModelEnabled ||
+ imageGenerate3dWorldEnabled ||
+ imageLayerSplitEnabled ||
imageExtendEnabled ||
imageCropEnabled ||
imageAdjustEnabled ||
@@ -1208,22 +1216,14 @@ export function ImageNode({
imagePromptRegenerateEnabled ||
imageNoteEnabled;
const hasSelectedImageMoreMenu =
- imageNodeMoreEnabled &&
- (hasSelectedImageMorePrimaryActions || imageDeleteEnabled);
+ hasSelectedImageMorePrimaryActions ||
+ (imageNodeMoreEnabled && imageDeleteEnabled);
const hasSelectedImagePrimaryToolbarActions =
imagePickObjectEnabled ||
imageEnhanceEnabled ||
imageRemoveBackgroundEnabled ||
- imageBoxCutoutEnabled ||
- imageLocalEditEnabled ||
- imageRemoveWatermarkEnabled ||
- imageResizeEnabled ||
imageTextEditEnabled ||
- imageMultiAngleEnabled ||
- imageGenerate3dModelEnabled ||
- imageGenerate3dWorldEnabled ||
- imageAiWashQuickEnabled ||
- imageLayerSplitEnabled;
+ imageAiWashQuickEnabled;
const hasSelectedImageSecondaryToolbarActions =
hasSelectedImageMoreMenu || imageDownloadEnabled;
const contentScale = useMemo(
@@ -4294,7 +4294,7 @@ export function ImageNode({
const rect = containerRef.current.getBoundingClientRect();
const toolbarWidth = Math.max(
280,
- (toolbarSize.width || 980) * FLOATING_TOOLBAR_SCALE
+ (toolbarSize.width || 640) * FLOATING_TOOLBAR_SCALE
);
const toolbarHeight = Math.max(
42,
@@ -4302,12 +4302,12 @@ export function ImageNode({
);
const titleSafeHeight = 34;
const gap = 12;
- const { viewportPadding, maxTop, safeLeft, safeRight } =
+ const { viewportPadding, maxTop, safeBottom, safeLeft, safeRight } =
getFloatingViewportBounds(toolbarHeight);
- let top = rect.top - toolbarHeight - titleSafeHeight - gap;
- if (top < viewportPadding) {
- top = rect.bottom + gap;
+ let top = rect.bottom + gap;
+ if (top + toolbarHeight > safeBottom) {
+ top = rect.top - toolbarHeight - titleSafeHeight - gap;
}
top = Math.min(Math.max(top, viewportPadding), maxTop);
@@ -4332,36 +4332,31 @@ export function ImageNode({
return { top: 0, left: 0, maxWidth: 480 };
};
- const getAiWashQuickPanelPosition = (
- anchor: { top: number; left: number; maxWidth: number }
- ) => {
- if (typeof window === "undefined") {
- return { top: 0, left: 0, width: 360, maxHeight: 520 };
+ const getAiWashQuickPanelPosition = () => {
+ if (!containerRef.current || typeof window === "undefined") {
+ return { top: 0, left: 0, width: 286, maxHeight: 430 };
}
- const panelWidth = 360;
- const panelHeight = 540;
- const gap = 10;
- const toolbarHeight = Math.max(
- 42,
- (toolbarSize.height || 60) * FLOATING_TOOLBAR_SCALE
- );
+ const rect = containerRef.current.getBoundingClientRect();
+ const panelWidth = 286;
+ const panelHeight = 430;
+ const gap = 12;
const { viewportPadding, safeBottom, safeLeft, safeRight, maxTop } =
getFloatingViewportBounds(panelHeight);
const width = Math.min(panelWidth, Math.max(260, safeRight - safeLeft));
- let top = anchor.top + toolbarHeight + gap;
+ let left = rect.right + gap;
+ if (left + width > safeRight) {
+ left = rect.left - width - gap;
+ }
+ left = Math.min(Math.max(left, safeLeft), Math.max(safeLeft, safeRight - width));
+
+ let top = rect.top;
if (top + panelHeight > safeBottom) {
- top = anchor.top - panelHeight - gap;
+ top = rect.bottom - panelHeight;
}
top = Math.min(Math.max(top, viewportPadding), maxTop);
- const preferredLeft = anchor.left;
- const left = Math.min(
- Math.max(preferredLeft, safeLeft),
- Math.max(safeLeft, safeRight - width)
- );
-
return {
top,
left,
@@ -7457,7 +7452,7 @@ export function ImageNode({
const cropPanelPosition = getCropPanelPosition();
const imageAdjustPanelPosition = getImageAdjustPanelPosition();
const toolbarPosition = getToolbarPosition();
- const aiWashQuickPanelPosition = getAiWashQuickPanelPosition(toolbarPosition);
+ const aiWashQuickPanelPosition = getAiWashQuickPanelPosition();
const boxCutoutToolbarPosition = getBoxCutoutToolbarPosition();
const flipRotatePanelPosition = getFlipRotatePanelPosition();
const anglePanelPosition = getAnglePanelPosition();
@@ -8653,7 +8648,7 @@ export function ImageNode({
typeof document !== "undefined" &&
createPortal(
event.stopPropagation()}
onMouseDown={(event) => event.stopPropagation()}
@@ -8667,93 +8662,80 @@ export function ImageNode({
scrollbarWidth: "thin",
}}
>
-
-
-
+
+
+
-
+
{aiWashQuickModeLabel}
-
- 选中图片快捷洗图
-
{aiWashConfigLoading ? (
-
-
+
+
正在加载 AI洗图 配置...
) : null}
-
-
-
-
-
- 渲染目标
+
+
+
+
+
+ 目标
-
+
{getAiWashStatusLabel(aiWashQuickStatus)}
-
- {aiWashQuickPresets.map((preset) => {
- const isActive = selectedAiWashQuickPreset?.id === preset.id;
- return (
-
- );
- })}
-
+
+ {selectedAiWashQuickPreset?.description ? (
+
+ {selectedAiWashQuickPreset.description}
+
+ ) : null}
-
-
参数设置
+
+
+ 参数
+
{shouldShowAiWashQuickModelSelector ? (
-
+
@@ -8761,7 +8743,7 @@ export function ImageNode({
onValueChange={setAiWashQuickModelId}
value={selectedAiWashQuickModel?.id || aiWashQuickModelId}
>
-
+
@@ -8787,7 +8769,7 @@ export function ImageNode({
{selectedAiWashQuickModel
- ? `当前模型:${selectedAiWashQuickModel.displayName} · ${
+ ? `${selectedAiWashQuickModel.displayName} · ${
selectedAiWashQuickModel.unitCost > 0
? `${selectedAiWashQuickModel.unitCost} 积分/张`
: "未设置积分"
@@ -8798,15 +8780,15 @@ export function ImageNode({
) : selectedAiWashQuickModel ? (
-
- 管理员已锁定模型:{selectedAiWashQuickModel.displayName}
+
+ {selectedAiWashQuickModel.displayName}
{selectedAiWashQuickModel.unitCost > 0
? ` · ${selectedAiWashQuickModel.unitCost} 积分/张`
: ""}
) : null}
-
+
{aiWashQuickControls.map((control) => {
const selectedIndex =
aiWashQuickLevels[control.id] ?? control.defaultLevel;
@@ -8816,14 +8798,14 @@ export function ImageNode({
null;
return (
-
-
+
+
{control.label}
-
+
{activeLevel?.label || selectedIndex + 1}
@@ -8839,8 +8821,8 @@ export function ImageNode({
}
rangeClassName="bg-slate-950 dark:bg-white"
step={1}
- thumbClassName="h-3.5 w-3.5 border border-slate-300 bg-white shadow-[0_0_0_3px_rgba(15,23,42,0.06)]"
- trackClassName="h-1.5 bg-slate-200 dark:bg-white/14"
+ thumbClassName="h-3 w-3 border border-slate-300 bg-white shadow-[0_0_0_3px_rgba(15,23,42,0.06)]"
+ trackClassName="h-1 bg-slate-200 dark:bg-white/14"
value={[selectedIndex]}
/>
@@ -8849,14 +8831,8 @@ export function ImageNode({
- {aiWashQuickPrompt ? (
-
- {aiWashQuickPrompt}
-
- ) : null}
-