diff --git a/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedAiWhiteBackgroundPanel.test.tsx b/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedAiWhiteBackgroundPanel.test.tsx index c8a93a0c..a7bfe342 100644 --- a/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedAiWhiteBackgroundPanel.test.tsx +++ b/furniture-3d-system/src/app/intake/non-integrated/NonIntegratedAiWhiteBackgroundPanel.test.tsx @@ -76,6 +76,9 @@ describe("NonIntegratedAiWhiteBackgroundPanel", () => { targetBarcode="BAR-001" targetLabel="BAR-001 / 批次1" targetColor="胡桃木色" + skuTargetColor="胡桃木色" + inlineTargetColor="" + onInlineTargetColorChange={() => {}} targetHasOriginalImages sourceMode="self" selectedSourceBarcode="" @@ -349,6 +352,9 @@ describe("NonIntegratedAiWhiteBackgroundPanel", () => { targetBarcode="BAR-002" targetLabel="BAR-002 / 批次1" targetColor="浅橡木色" + skuTargetColor="浅橡木色" + inlineTargetColor="" + onInlineTargetColorChange={() => {}} targetHasOriginalImages={false} sourceMode="borrow" selectedSourceBarcode="BAR-001" @@ -404,4 +410,79 @@ describe("NonIntegratedAiWhiteBackgroundPanel", () => { expect(screen.queryByText("BAR-001 · 胡桃木色")).not.toBeInTheDocument(); expect(screen.queryByTitle("测试产品一")).not.toBeInTheDocument(); }); + + it("renders a color input when the SKU has no real finish (A 方案)", () => { + const onInlineTargetColorChange = jest.fn(); + renderPanel({ + targetColor: "", + skuTargetColor: "未配置花色", + inlineTargetColor: "", + onInlineTargetColorChange, + }); + + fireEvent.click(screen.getByTestId("ai-white-background-settings-source")); + + const input = screen.getByTestId( + "ai-white-background-inline-target-color", + ); + expect(input).toBeInTheDocument(); + expect(input).toHaveAttribute( + "placeholder", + expect.stringContaining("本次生图颜色"), + ); + expect( + screen.getByText(/该条码未配置花色|借源生图必须指定目标颜色/), + ).toBeInTheDocument(); + }); + + it("shows the borrow-source color warning when borrowing without a target color (B 方案)", () => { + renderPanel({ + targetColor: "", + skuTargetColor: "未配置花色", + inlineTargetColor: "", + sourceMode: "borrow", + targetHasOriginalImages: false, + selectedSourceBarcode: "BAR-001", + sourceBarcodeOptions: [ + { + key: "BAR-001", + skuItemId: "sku-1", + barcode: "BAR-001", + label: "测试产品一", + secondaryLabel: "胡桃木色", + batchNo: 1, + hasOriginalImages: true, + generatedWhiteBackgroundCount: 3, + productPhotoSlotFiles: {} as never, + aiSourceSlotFiles: {} as never, + availableProductPhotoSlotCount: 6, + availableAiSourceSlotCount: 6, + files: [], + }, + ], + availableSourceViewCount: 1, + sourceReadyByView: buildViewRecord((viewKey) => viewKey === "front"), + }); + + fireEvent.click(screen.getByTestId("ai-white-background-settings-source")); + + expect( + screen.getByText(/借源生图必须指定目标颜色/), + ).toBeInTheDocument(); + }); + + it("keeps the readonly finish field when the SKU has a real color", () => { + renderPanel({ + targetColor: "胡桃木色", + skuTargetColor: "胡桃木色", + inlineTargetColor: "", + }); + + fireEvent.click(screen.getByTestId("ai-white-background-settings-source")); + + expect( + screen.queryByTestId("ai-white-background-inline-target-color"), + ).not.toBeInTheDocument(); + expect(screen.getByText("胡桃木色")).toBeInTheDocument(); + }); }); diff --git a/furniture-3d-system/src/app/intake/non-integrated/workspaces/ai-white-background/NonIntegratedAiWhiteBackgroundPanel.tsx b/furniture-3d-system/src/app/intake/non-integrated/workspaces/ai-white-background/NonIntegratedAiWhiteBackgroundPanel.tsx index 2e7864f9..1cc75043 100644 --- a/furniture-3d-system/src/app/intake/non-integrated/workspaces/ai-white-background/NonIntegratedAiWhiteBackgroundPanel.tsx +++ b/furniture-3d-system/src/app/intake/non-integrated/workspaces/ai-white-background/NonIntegratedAiWhiteBackgroundPanel.tsx @@ -45,6 +45,9 @@ type NonIntegratedAiWhiteBackgroundPanelProps = { targetBarcode: string; targetLabel: string; targetColor: string; + skuTargetColor: string; + inlineTargetColor: string; + onInlineTargetColorChange: (value: string) => void; targetHasOriginalImages: boolean; sourceMode: "self" | "borrow"; selectedSourceBarcode: string; @@ -727,6 +730,9 @@ function AiWhiteBackgroundPartGroupEditor({ export default function NonIntegratedAiWhiteBackgroundPanel({ targetColor, + skuTargetColor, + inlineTargetColor, + onInlineTargetColorChange, sourceMode, selectedSourceBarcode, sourceBarcodeOptions, @@ -769,6 +775,19 @@ export default function NonIntegratedAiWhiteBackgroundPanel({ useState(null); const [refinementPrompt, setRefinementPrompt] = useState(""); + // 花色来源判断:SKU 自带真实色 vs 占位符 vs 用户手动输入 + const trimmedSkuTargetColor = (skuTargetColor ?? "").trim(); + const skuHasRealColor = (() => { + if (!trimmedSkuTargetColor) return false; + const compact = trimmedSkuTargetColor.replace(/\s+/g, ""); + return !["未配置花色", "未配置颜色", "缺少花色/颜色信息", "不改色/选择目标花色"] + .some((p) => p.replace(/\s+/g, "") === compact); + })(); + // 当 SKU 无真实色时,展示输入框让用户填写本次生图颜色 + const showInlineColorInput = !skuHasRealColor; + const isBorrowWithoutColor = + sourceMode === "borrow" && !targetColor.trim(); + const generatedViewOptions = useMemo( () => AI_WHITE_BACKGROUND_VIEW_KEYS.filter((viewKey) => @@ -868,11 +887,11 @@ export default function NonIntegratedAiWhiteBackgroundPanel({ data-testid="ai-white-background-panel" className="flex h-full min-h-0 flex-col overflow-hidden rounded-[8px] bg-[#f1f4f5] text-[#2d3335]" > -
+
{AI_WHITE_BACKGROUND_VIEW_KEYS.map((viewKey) => { const generatedFile = generatedFiles[viewKey]; @@ -1046,20 +1065,20 @@ export default function NonIntegratedAiWhiteBackgroundPanel({ data-testid="ai-white-background-control-card" className="flex min-h-0 flex-col overflow-hidden rounded-[8px] bg-white shadow-[0_4px_16px_rgba(45,51,53,0.055)] ring-1 ring-[#adb3b5]/12" > -
+
-

+

生成设置

-
- +
+ {getPartGroupingSourceLabel(partGroupingSource)} @@ -1069,28 +1088,62 @@ export default function NonIntegratedAiWhiteBackgroundPanel({
-
-
+
+
setSettingsSectionExpanded("source", isExpanded) } > -
- +
+ {showInlineColorInput ? ( +
+ + + onInlineTargetColorChange(event.currentTarget.value) + } + placeholder="输入本次生图颜色,如:白色 / 原木色 / 胡桃色" + maxLength={60} + className={cn( + "h-10 w-full rounded-[6px] bg-white px-3 text-[13px] font-bold text-[#2d3335] outline-none ring-1 transition focus:ring-2", + isBorrowWithoutColor + ? "ring-[#c47a3a]/55 focus:ring-[#c47a3a]" + : "ring-[#adb3b5]/22 focus:ring-[#47646b]/45", + )} + /> + {isBorrowWithoutColor ? ( +

+ 借源生图必须指定目标颜色,否则会跟随源条码原图色调。 +

+ ) : ( +

+ 该条码未配置花色,请填写本次想生成的颜色。 +

+ )} +
+ ) : ( + + )} {sourceMode === "borrow" ? (
-