feat(canvas): rename scene fusion to 批量处理 and add toolbar entry
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-03-05 16:50:21 +08:00
parent 46ce28adad
commit bbad28114b
6 changed files with 43 additions and 22 deletions

View File

@ -826,7 +826,7 @@ export function AdminSettingsClient() {
imageSize: "square" as "square" | "square_hd",
});
// 详情替换配置状态
// 批量处理配置状态
const [sceneFusionConfig, setSceneFusionConfig] = useState({
enabled: true,
defaultPrompt: "将图1的产品替换到图2的场景中,保持图1产品的外观、颜色和细节不变,自然融合到图2的环境中。",
@ -1014,7 +1014,7 @@ export function AdminSettingsClient() {
}
}, [realtimeCanvasConfigData]);
// 加载详情替换配置
// 加载批量处理配置
const { data: sceneFusionConfigData } = useSWR("/api/admin/settings?key=scene_fusion_config", fetcher);
useEffect(() => {
if (sceneFusionConfigData?.setting?.value) {
@ -2102,7 +2102,7 @@ export function AdminSettingsClient() {
}
};
// --- 详情替换配置逻辑 ---
// --- 批量处理配置逻辑 ---
const handleSaveSceneFusionConfig = async () => {
try {
if (!sceneFusionConfig.defaultPrompt.trim()) {
@ -2125,9 +2125,9 @@ export function AdminSettingsClient() {
});
if (!response.ok) throw new Error("保存失败");
toast.success("详情替换配置保存成功");
toast.success("批量处理配置保存成功");
} catch (error) {
toast.error("保存详情替换配置失败");
toast.error("保存批量处理配置失败");
}
};
@ -8630,24 +8630,24 @@ export function AdminSettingsClient() {
</CardContent>
</Card>
{/* 详情替换配置 */}
{/* 批量处理配置 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-xl">
<Sparkles className="h-5 w-5" />
详情替换配置
批量处理配置
</CardTitle>
<CardDescription>
配置详情替换功能的默认提示词和参数。详情替换可将产品图批量融合到多个场景中。
配置批量处理功能的默认提示词和参数。批量处理可将产品图批量融合到多个场景中。
</CardDescription>
</CardHeader>
<CardContent className="space-y-6 pt-6">
{/* 功能开关 */}
<div className="flex items-center justify-between rounded-lg border p-4">
<div className="space-y-0.5">
<Label className="text-base">启用详情替换功能</Label>
<Label className="text-base">启用批量处理功能</Label>
<div className="text-sm text-muted-foreground">
开启后用户可在图片编辑器中使用详情替换功能
开启后用户可在图片编辑器中使用批量处理功能
</div>
</div>
<div className="flex items-center gap-2">
@ -8673,7 +8673,7 @@ export function AdminSettingsClient() {
disabled={!sceneFusionConfig.enabled}
/>
<div className="text-xs text-muted-foreground">
该提示词将作为详情替换的基础指令,用户可以在此基础上添加修改要求
该提示词将作为批量处理的基础指令,用户可以在此基础上添加修改要求
</div>
</div>

View File

@ -25,6 +25,7 @@ import {
Settings,
PenTool,
Box,
Layers,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
@ -60,6 +61,7 @@ import { CanvasWorkspace } from "@/components/canvas";
import { CanvasChatPanel } from "@/components/canvas/CanvasChatPanel";
import { CanvasFileListPanel } from "@/components/canvas/CanvasFileListPanel";
import { ObjectPickerOverlay } from "@/components/canvas/ObjectPickerOverlay";
import { SceneFusionDialog } from "@/components/scene-fusion-dialog";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { cn, fetcher } from "@/lib/utils";
import { Grid2X2 } from "lucide-react";
@ -127,6 +129,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
const [isEditingTitle, setIsEditingTitle] = useState(false);
const [editTitle, setEditTitle] = useState("");
const [isPanelOpen, setIsPanelOpen] = useState(true);
const [sceneFusionDialogOpen, setSceneFusionDialogOpen] = useState(false);
// 面板模式: 'chat' 聊天面板, 'fileList' 文件列表
const [panelMode, setPanelMode] = useState<'chat' | 'fileList'>('chat');
const [viewportWidth, setViewportWidth] = useState(0);
@ -769,6 +772,20 @@ export default function CanvasEditorPage({ params }: PageProps) {
<TooltipContent side="top">平移 (H)</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => setSceneFusionDialogOpen(true)}
className="h-9 w-9 rounded-xl"
>
<Layers className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent side="top">批量处理</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
@ -906,6 +923,10 @@ export default function CanvasEditorPage({ params }: PageProps) {
{/* 7. 物品拾取模式覆盖层 */}
<ObjectPickerOverlay />
<SceneFusionDialog
open={sceneFusionDialogOpen}
onOpenChange={setSceneFusionDialogOpen}
/>
</div>
</TooltipProvider>
);

View File

@ -1192,7 +1192,7 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
'extend': '扩图',
'resize': '调尺',
'angle': '视角',
'scene-fusion': '替换',
'scene-fusion': '批量处理',
'annotate': '标注',
'text-edit': '改字',
'note': '备注',
@ -2006,7 +2006,7 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
/>
)}
{/* 详情替换对话框 */}
{/* 批量处理对话框 */}
<SceneFusionDialog
open={sceneFusionDialogOpen}
onOpenChange={setSceneFusionDialogOpen}

View File

@ -1636,7 +1636,7 @@ export function ImageAnnotator({
<Layers className="h-5 w-5" />
</Button>
</TooltipTrigger>
<TooltipContent>详情替换</TooltipContent>
<TooltipContent>批量处理</TooltipContent>
</Tooltip>
<div className="mx-1 h-7 w-px bg-black/10 dark:bg-white/10" />

View File

@ -53,7 +53,7 @@ export function SceneFusionDialog({ open, onOpenChange }: SceneFusionDialogProps
// 最大自动重试次数
const MAX_AUTO_RETRY = 10;
// 获取详情替换配置(使用公开 API 端点)
// 获取批量处理配置(使用公开 API 端点)
const { data: configData } = useSWR(
open ? "/api/scene-fusion/config" : null,
fetcher
@ -144,7 +144,7 @@ export function SceneFusionDialog({ open, onOpenChange }: SceneFusionDialogProps
// 开始裂变
const startFusion = async () => {
if (config?.enabled === false) {
toast.error("详情替换功能已被管理员禁用");
toast.error("批量处理功能已被管理员禁用");
return;
}
if (!productImage) {
@ -410,7 +410,7 @@ export function SceneFusionDialog({ open, onOpenChange }: SceneFusionDialogProps
<DialogHeader className="px-6 py-4 border-b shrink-0">
<DialogTitle className="flex items-center gap-2">
<Layers className="w-5 h-5 text-primary" />
详情替换
批量处理
</DialogTitle>
<DialogDescription>
上传1张产品图和多张场景图,AI 自动将产品融合到所有场景中。

View File

@ -40,12 +40,12 @@ interface SceneFusionViewProps {
onBack: () => void;
/**
* 可选:从外部(例如图片编辑器当前图片)传入的初始产品图。
* 这样在「详情替换」中就可以自动带入当前正在编辑的图片,
* 这样在「批量处理」中就可以自动带入当前正在编辑的图片,
* 避免用户重复上传。
*/
initialProductImage?: string | null;
/**
* 可选:初始产品名称,便于在进入详情替换时预填文案。
* 可选:初始产品名称,便于在进入批量处理时预填文案。
*/
initialProductName?: string;
}
@ -54,7 +54,7 @@ export function SceneFusionView({ onBack, initialProductImage, initialProductNam
// 最大自动重试次数
const MAX_AUTO_RETRY = 10;
// 获取详情替换配置(使用公开 API 端点)
// 获取批量处理配置(使用公开 API 端点)
const { data: configData } = useSWR(
"/api/scene-fusion/config",
fetcher
@ -222,7 +222,7 @@ export function SceneFusionView({ onBack, initialProductImage, initialProductNam
// 开始裂变
const startFusion = async () => {
if (config?.enabled === false) {
toast.error("详情替换功能已被管理员禁用");
toast.error("批量处理功能已被管理员禁用");
return;
}
if (!productImage) {
@ -613,7 +613,7 @@ export function SceneFusionView({ onBack, initialProductImage, initialProductNam
</Button>
<div className="flex items-center gap-2 font-medium">
<Layers className="w-5 h-5 text-primary" />
详情替换
批量处理
</div>
</div>
<div className="text-sm text-muted-foreground hidden md:block">