feat: 多页面拖拽上传、滚动条精简、UI优化
- 剧本评测/分辨率提升/数字人/角色迁移/图片工作台/去水印/电商:新增外部拖拽文件上传 - 电商:爆款图复刻上传框支持拖拽+大滚动条,短视频/模特图/详情图滚动条精简回退 - 图片工作台:右侧输出面板移至左侧提示词上方,删除局部重绘遮罩/结果框 - 数字人:生成按钮改为「开始生成」 - 局部重绘:编辑遮罩→编辑页面 - 对话框生成器:新增对话/视频模式、模型/速度/深度选择按钮 - 视频时长默认改为5秒 - 工具箱页面空状态logo统一绿底亮色图标 - 多处CSS滚动条和布局优化
This commit is contained in:
@@ -16,7 +16,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 StudioToolLayout from "../../components/StudioToolLayout";
|
||||
import type { WebImageWorkbenchTool, WebViewKey } from "../../types";
|
||||
import { aiGenerationClient } from "../../api/aiGenerationClient";
|
||||
@@ -58,6 +58,7 @@ function CharacterMixPage({
|
||||
const [resultUrl, setResultUrl] = useState<string | null>(null);
|
||||
const abortRef = useRef(false);
|
||||
const taskIdRef = useRef<string | null>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
@@ -233,6 +234,32 @@ function CharacterMixPage({
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragOver = (e: DragEvent) => { e.preventDefault(); if (e.dataTransfer?.types?.includes("Files")) setIsDragging(true); };
|
||||
const handleDragLeave = (e: DragEvent) => { e.preventDefault(); if (!e.currentTarget.contains(e.relatedTarget as Node)) setIsDragging(false); };
|
||||
const handleDrop = (e: DragEvent) => {
|
||||
e.preventDefault();
|
||||
setIsDragging(false);
|
||||
const file = e.dataTransfer?.files?.[0];
|
||||
if (!file) return;
|
||||
if (file.type.startsWith("image/")) {
|
||||
if (characterPreview) URL.revokeObjectURL(characterPreview);
|
||||
setCharacterFile(file.name);
|
||||
setCharacterPreview(URL.createObjectURL(file));
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => { if (typeof reader.result === "string") setCharacterDataUrl(reader.result); };
|
||||
reader.readAsDataURL(file);
|
||||
setNotice(`已选择人物图 ${file.name}`);
|
||||
} else if (file.type.startsWith("video/")) {
|
||||
if (videoPreview) URL.revokeObjectURL(videoPreview);
|
||||
setVideoFile(file.name);
|
||||
setVideoPreview(URL.createObjectURL(file));
|
||||
const reader2 = new FileReader();
|
||||
reader2.onload = () => { if (typeof reader2.result === "string") setVideoDataUrl(reader2.result); };
|
||||
reader2.readAsDataURL(file);
|
||||
setNotice(`已选择参考视频 ${file.name}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="image-workbench-page character-mix-page" aria-label="角色迁移">
|
||||
<header className="image-workbench-topbar">
|
||||
@@ -292,7 +319,17 @@ function CharacterMixPage({
|
||||
<StudioToolLayout
|
||||
noTop
|
||||
leftPanel={
|
||||
<>
|
||||
<div
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
style={{ position: "relative" }}
|
||||
>
|
||||
{isDragging ? (
|
||||
<div style={{ position: "absolute", inset: 0, zIndex: 100, display: "flex", alignItems: "center", justifyContent: "center", background: "rgba(0,0,0,0.55)", border: "2px dashed var(--primary, #4a9eff)", borderRadius: 12, pointerEvents: "none" }}>
|
||||
<span style={{ fontSize: 18, color: "#fff", fontWeight: 600 }}>释放文件以上传</span>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="studio-panel__section">
|
||||
<div className="studio-panel__section-head">
|
||||
<span className="studio-panel__section-title">人物图</span>
|
||||
@@ -370,7 +407,7 @@ function CharacterMixPage({
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
}
|
||||
canvas={
|
||||
isCreating ? (
|
||||
|
||||
Reference in New Issue
Block a user