feat(canvas): rename scene fusion to 批量处理 and add toolbar entry
This commit is contained in:
parent
46ce28adad
commit
bbad28114b
@ -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>
|
||||
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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" />
|
||||
|
||||
@ -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 自动将产品融合到所有场景中。
|
||||
|
||||
@ -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">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user