feat: refine generation workspace experience
This commit is contained in:
@@ -1,4 +1,15 @@
|
||||
import { useEffect, useRef, useState, type ChangeEvent, type KeyboardEvent } from "react";
|
||||
import {
|
||||
BarChartOutlined,
|
||||
CheckCircleFilled,
|
||||
CloseOutlined,
|
||||
CopyOutlined,
|
||||
DownloadOutlined,
|
||||
FileTextOutlined,
|
||||
LoadingOutlined,
|
||||
ThunderboltOutlined,
|
||||
UploadOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { useEffect, useRef, useState, type ChangeEvent, type DragEvent, type KeyboardEvent } from "react";
|
||||
import "../../styles/pages/script-tokens-v5.css";
|
||||
import "../../styles/pages/script-tokens.css";
|
||||
import { evaluateScript } from "../../api/scriptEvalClient";
|
||||
@@ -307,6 +318,7 @@ function ScriptTokensPage() {
|
||||
const [animatedScore, setAnimatedScore] = useState(0);
|
||||
const [activeHistoryIndex, setActiveHistoryIndex] = useState<number>(0);
|
||||
const [history, setHistory] = useState<HistoryEntry[]>(loadHistory);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const scoreFrameRef = useRef<number | null>(null);
|
||||
|
||||
@@ -329,9 +341,7 @@ function ScriptTokensPage() {
|
||||
return () => { if (scoreFrameRef.current) cancelAnimationFrame(scoreFrameRef.current); };
|
||||
}, [result]);
|
||||
|
||||
const handleFileUpload = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
const processUploadedFile = async (file: File) => {
|
||||
const ext = getFileExtension(file.name);
|
||||
const readable = isReadableTextFile(file, ext);
|
||||
setUploadedFile({ name: file.name, size: file.size });
|
||||
@@ -361,6 +371,12 @@ function ScriptTokensPage() {
|
||||
} else {
|
||||
setScript(`[已上传文件:${file.name}]\n\n暂不支持解析 ${ext ? ext.toUpperCase() : "未知"} 格式,请上传常见文本类文件。`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileUpload = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
await processUploadedFile(file);
|
||||
event.target.value = "";
|
||||
};
|
||||
|
||||
@@ -461,6 +477,30 @@ function ScriptTokensPage() {
|
||||
fileInputRef.current?.click();
|
||||
};
|
||||
|
||||
const handleDragOver = (event: DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (event.dataTransfer.types.includes("Files")) {
|
||||
setIsDragging(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragLeave = (event: DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (event.currentTarget === event.target || !event.currentTarget.contains(event.relatedTarget as Node)) {
|
||||
setIsDragging(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrop = (event: DragEvent<HTMLDivElement>) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setIsDragging(false);
|
||||
const file = event.dataTransfer.files[0];
|
||||
if (file) processUploadedFile(file);
|
||||
};
|
||||
|
||||
const grade = result ? getGrade(result.totalScore) : null;
|
||||
const beatPct = result ? (result.totalScore >= 95 ? 97 : result.totalScore >= 88 ? 92 : result.totalScore >= 80 ? 85 : 72) : 0;
|
||||
const compactTitle = uploadedFile?.name?.replace(/\.[^.]+$/, "") ?? "剧本评测";
|
||||
@@ -477,15 +517,32 @@ function ScriptTokensPage() {
|
||||
<div className="script-eval-v5-lp-section">
|
||||
<div className="script-eval-v5-lp-label">上传剧本</div>
|
||||
<div
|
||||
className="script-eval-v5-upload-zone"
|
||||
className={`script-eval-v5-upload-zone${isDragging ? " is-dragging" : ""}`}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
onKeyDown={uploadKeyDown}
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
>
|
||||
{isDragging ? (
|
||||
<div className="script-eval-v5-upload-drop-overlay">
|
||||
<UploadOutlined />
|
||||
<span>释放文件以上传</span>
|
||||
</div>
|
||||
) : null}
|
||||
{uploadedFile ? (
|
||||
<div className="script-eval-v5-upload-done is-show">
|
||||
<ShellIcon name="check-circle" />
|
||||
<button
|
||||
type="button"
|
||||
className="script-eval-v5-upload-delete"
|
||||
onClick={(e) => { e.stopPropagation(); handleReset(); }}
|
||||
aria-label="删除文件"
|
||||
>
|
||||
<CloseOutlined />
|
||||
</button>
|
||||
<CheckCircleFilled />
|
||||
<span className="script-eval-v5-uf-meta">
|
||||
<span className="script-eval-v5-uf-name">{uploadedFile.name}</span>
|
||||
<span className="script-eval-v5-uf-size">{formatFileSize(uploadedFile.size)}</span>
|
||||
|
||||
Reference in New Issue
Block a user