feat(canvas): 画布工作区 - 整合侧栏与风格预设并修复提示词回填

选择性整合 #547,保留主分支节点与工具条设计。新增默认折叠的节点、资产、任务和历史面板,风格与预设保留在节点内,移除重复入口。

补齐工具权限、提示词解析、资源引用保护及数据库迁移,修复提示词清空和连续编辑后的生成配置同步。

验证:前端全量 1925 项测试、构建、类型检查及 lint 通过;后端 go test ./... 通过。真实模型、PostgreSQL 实库与登录态页面验收仍待进行。

Refs #547

Co-authored-by: bensharp <bensharp@qq.com>
This commit is contained in:
ddCat
2026-09-20 16:40:08 +08:00
parent 0ea9f7d94b
commit 9148ceab66
66 changed files with 6127 additions and 97 deletions

View File

@@ -1,7 +1,7 @@
import { useEffect, useLayoutEffect, useRef, useState, type ReactNode, type RefObject } from "react";
import { App, Button, Dropdown, Input, Modal, Tag, Tooltip } from "antd";
import type { MenuProps } from "antd";
import { Camera, Check, ChevronDown, ChevronRight, Ellipsis, Images, Plus, SlidersHorizontal, UserRound } from "lucide-react";
import { Camera, Check, ChevronDown, ChevronRight, Ellipsis, Grid3x3, Images, Plus, SlidersHorizontal, UserRound } from "lucide-react";
import { canvasDockStyle } from "@/lib/canvas/canvas-aceternity-style";
import { ASSET_CATEGORY_OPTIONS } from "@/lib/asset-category";
@@ -62,6 +62,7 @@ type CanvasNodeToolbarProps = {
onToggleFreeResize: (node: CanvasNodeData) => void;
onToggleLocked: (node: CanvasNodeData) => void;
onDelete: (node: CanvasNodeData) => void;
onNineGrid: (node: CanvasNodeData, toolId: number, label: string, icon: string) => void;
workspaceMode?: CanvasWorkspaceMode;
};
@@ -127,6 +128,7 @@ export function CanvasNodeToolbar({
onToggleFreeResize,
onToggleLocked,
onDelete,
onNineGrid,
workspaceMode = "professional",
}: CanvasNodeToolbarProps) {
const [openMenuId, setOpenMenuId] = useState<string | null>(null);
@@ -229,7 +231,7 @@ export function CanvasNodeToolbar({
}
copyText(prompt, "提示词已复制");
};
const imageTools = buildImageToolbarTools(node, { onUpload, onToggleFreeResize, onAnnotate, onAnnotationEdit, onTextEdit, onMaskEdit, onRemoveBackground, onLayerDecomposition, onEmotion, onPortraitTexture, onCrop, onUpscale, onSuperResolve, onAngle, onLighting, onPanorama, onViewImage, onCopyPrompt: copyImagePrompt, onReversePrompt });
const imageTools = buildImageToolbarTools(node, { onUpload, onToggleFreeResize, onAnnotate, onAnnotationEdit, onTextEdit, onMaskEdit, onRemoveBackground, onLayerDecomposition, onEmotion, onPortraitTexture, onCrop, onUpscale, onSuperResolve, onAngle, onLighting, onPanorama, onViewImage, onCopyPrompt: copyImagePrompt, onReversePrompt, onNineGrid });
// 构建 ToolContext——供注册表解析工具
const nodeHoverHandlers = {
@@ -292,6 +294,7 @@ export function CanvasNodeToolbar({
const viewpointLightingTools = compact ? [] : [...inGroup("viewpoint"), ...inGroup("lighting")];
const panoramaTools = compact ? [] : inGroup("panorama");
const processTools = compact ? [...inGroup("portrait"), ...inGroup("viewpoint"), ...inGroup("lighting"), ...inGroup("panorama"), ...inGroup("process")] : inGroup("process");
const nineGridTools = compact ? [] : inGroup("nine_grid");
const workspaceTools = narrow ? [] : inGroup("workspace");
const utilityTools = inGroup("utility");
const moreTools = [...(narrow ? [...primary.slice(1), ...inGroup("workspace")] : []), ...inGroup("more")];
@@ -324,6 +327,7 @@ export function CanvasNodeToolbar({
style={{ ...dockStyle, border: 0 }}
>
{primaryTools.map((tool) => <NodeDockToolButton key={tool.id} tool={tool} />)}
{nineGridTools.length ? <NodeDockMenuButton menuId="nine-grid" label="九宫格" icon={<Grid3x3 className="size-3.5" />} tools={nineGridTools} openMenuId={openMenuId} onOpenChange={handleMenuOpenChange} /> : null}
{panoramaTools.map((tool) => <NodeDockToolButton key={tool.id} tool={tool} />)}
{portraitTools.length ? <NodeDockMenuButton menuId="portrait" label="人像调整" icon={<UserRound className="size-3.5" />} tools={portraitTools} openMenuId={openMenuId} onOpenChange={handleMenuOpenChange} /> : null}
{viewpointLightingTools.length ? <NodeDockMenuButton menuId="viewpoint-lighting" label="视角" icon={<Camera className="size-3.5" />} tools={viewpointLightingTools} openMenuId={openMenuId} onOpenChange={handleMenuOpenChange} /> : null}