feat: 多页面拖拽上传、滚动条精简、UI优化

- 剧本评测/分辨率提升/数字人/角色迁移/图片工作台/去水印/电商:新增外部拖拽文件上传
- 电商:爆款图复刻上传框支持拖拽+大滚动条,短视频/模特图/详情图滚动条精简回退
- 图片工作台:右侧输出面板移至左侧提示词上方,删除局部重绘遮罩/结果框
- 数字人:生成按钮改为「开始生成」
- 局部重绘:编辑遮罩→编辑页面
- 对话框生成器:新增对话/视频模式、模型/速度/深度选择按钮
- 视频时长默认改为5秒
- 工具箱页面空状态logo统一绿底亮色图标
- 多处CSS滚动条和布局优化
This commit is contained in:
OmniAI Developer
2026-06-05 18:01:55 +08:00
parent 8fbb2ec95e
commit 5b87594e36
22 changed files with 1796 additions and 195 deletions
@@ -15,7 +15,7 @@ import {
ThunderboltOutlined,
VideoCameraOutlined,
} from "@ant-design/icons";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState, type DragEvent } from "react";
import { aiGenerationClient } from "../../api/aiGenerationClient";
import { waitForTask } from "../../api/taskSubscription";
import { saveToolTaskState, loadToolTaskState, clearToolTaskState } from "../workbench/toolKeepalive";
@@ -87,6 +87,7 @@ function ResolutionUpscalePage({
const [isProcessing, setIsProcessing] = useState(false);
const [isDownloading, setIsDownloading] = useState(false);
const [isSavingAsset, setIsSavingAsset] = useState(false);
const [isDragging, setIsDragging] = useState(false);
const activeTaskIdRef = useRef(activeTaskId);
activeTaskIdRef.current = activeTaskId;
const keepaliveRestoredRef = useRef(false);
@@ -164,6 +165,24 @@ function ResolutionUpscalePage({
event.currentTarget.value = "";
};
const processDroppedFile = (file: File) => {
if (sourcePreview.startsWith("blob:")) URL.revokeObjectURL(sourcePreview);
setSourceName(file.name);
setSourceFile(file);
setSourceUrl("");
setSourcePreview(URL.createObjectURL(file));
setResultPreview("");
setSourceDimensions(null);
setVideoViewMode("source");
setActiveTaskId("");
setTaskProgress(0);
setStatus(`已导入 ${file.name}`);
};
const handleDragOver = (e: DragEvent<HTMLDivElement>) => { e.preventDefault(); e.stopPropagation(); if (e.dataTransfer.types.includes("Files")) setIsDragging(true); };
const handleDragLeave = (e: DragEvent<HTMLDivElement>) => { e.preventDefault(); e.stopPropagation(); if (e.currentTarget === e.target || !e.currentTarget.contains(e.relatedTarget as Node)) setIsDragging(false); };
const handleDrop = (e: DragEvent<HTMLDivElement>) => { e.preventDefault(); e.stopPropagation(); setIsDragging(false); const file = e.dataTransfer.files[0]; if (file) processDroppedFile(file); };
const handleImportUrl = () => {
const normalizedUrl = sourceUrl.trim();
if (!/^https?:\/\//i.test(normalizedUrl)) {
@@ -405,7 +424,13 @@ function ResolutionUpscalePage({
accept={mode === "image" ? "image/png,image/jpeg,image/webp" : "video/mp4,video/quicktime,video/webm,video/*"}
onChange={handleFileChange}
/>
<div className="image-workbench-upload-shell">
<div
className={`image-workbench-upload-shell${isDragging ? " is-dragging" : ""}`}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
>
{isDragging ? <div className="image-workbench-upload-drop-overlay"><span></span></div> : null}
<button type="button" className="image-workbench-upload" onClick={() => fileInputRef.current?.click()}>
{sourcePreview && mode === "image" ? <img src={sourcePreview} alt="" /> : <FileImageOutlined />}
<strong>{sourceName || (mode === "image" ? "选择图片" : "选择视频")}</strong>
@@ -574,11 +599,13 @@ function ResolutionUpscalePage({
</div>
)
) : (
<button type="button" className="image-workbench-empty image-workbench-empty--button" onClick={() => fileInputRef.current?.click()}>
<ColumnWidthOutlined />
<strong>{mode === "image" ? "拖拽或选择图片" : "拖拽或选择视频"}</strong>
<span>{mode === "image" ? "支持 PNG / JPG / WebP" : "支持 MP4 / MOV / WebM"}</span>
</button>
<div className="studio-canvas-ghost">
<div className="studio-canvas-ghost__icon">
<ThunderboltOutlined />
</div>
<div className="studio-canvas-ghost__title">{mode === "image" ? "拖拽或选择图片" : "拖拽或选择视频"}</div>
<div className="studio-canvas-ghost__hint">{mode === "image" ? "支持 PNG / JPG / WebP" : "支持 MP4 / MOV / WebM"}</div>
</div>
)}
</section>
</main>