feat: 首页增加工具箱功能区、剧本评测可视化展示;重构剧本评分页面UI

- 首页新增工具箱功能区(ToolboxSection),展示四大AI工具卡片
- 首页剧本功能区替换为六维柱状图可视化(ScriptReviewVisual)
- 剧本评分页面(ScriptTokensPage)全面重构为新版UI布局
- 左侧面板:上传区、AI识别信息、历史评测(持久化)、操作按钮
- 右侧:剧本输入区、评测结果Hero、六维柱状图、亮点/扣分点、优化建议表格
- 历史评测支持localStorage持久化,按时间倒序排列
This commit is contained in:
OmniAI Developer
2026-06-02 18:58:13 +08:00
parent c13bf800cc
commit 05e4f5b4b3
17 changed files with 3510 additions and 504 deletions
+233
View File
@@ -0,0 +1,233 @@
import { ToolOutlined } from "@ant-design/icons";
import type { WebViewKey, WebImageWorkbenchTool } from "../../types";
import toolImageBefore from "../../assets/toolbox/牛仔.png";
import toolImageAfter from "../../assets/toolbox/西装.png";
import watermarkBefore from "../../assets/toolbox/去水印前.png";
import watermarkAfter from "../../assets/toolbox/去水印后.png";
interface ToolboxSectionProps {
onSelectView: (view: WebViewKey) => void;
onOpenImageTool?: (tool: WebImageWorkbenchTool) => void;
}
const TOOLS = [
{
key: "image-studio",
icon: "🎨",
name: "图片工作室",
desc: "图片二次加工,调色裁剪特效风格迁移",
},
{
key: "lens-lab",
icon: "📷",
name: "镜头实验室",
desc: "多视角镜头生成,不同角度与姿势",
},
{
key: "digital-human",
icon: "🧑",
name: "一键数字人",
desc: "上传图片和音频,生成数字人视频",
},
{
key: "watermark-removal",
icon: "✨",
name: "去除水印",
desc: "AI智能识别去除图片视频水印",
},
];
const CARDS = [
{
key: "image-studio",
title: "图片工作室",
tag: "图片加工",
icon: "🎨",
features: ["二次加工", "调色", "裁剪", "风格迁移"],
targetView: "imageWorkbench" as WebViewKey,
render: () => (
<div className="toolbox-card1-content">
<div className="toolbox-card1-side toolbox-card1-left">
<div className="toolbox-card1-img">
<img src={toolImageBefore} alt="图片加工前" />
</div>
<div className="toolbox-card1-label"></div>
</div>
<div className="toolbox-card1-divider" />
<div className="toolbox-card1-side toolbox-card1-right">
<div className="toolbox-card1-img">
<img src={toolImageAfter} alt="图片加工后" />
</div>
<div className="toolbox-card1-label"></div>
</div>
</div>
),
},
{
key: "lens-lab",
title: "镜头实验室",
tag: "多视角",
icon: "📷",
features: ["正面", "45°侧", "俯拍", "仰拍", "背面"],
targetView: "imageWorkbench" as WebViewKey,
render: () => (
<div className="toolbox-card2-content">
{["正面", "45°侧", "俯拍", "仰拍", "背面"].map((angle) => (
<div key={angle} className="toolbox-card2-frame">
<div className="toolbox-card2-product" />
<div className="toolbox-card2-shadow" />
<div className="toolbox-card2-angle-label">{angle}</div>
</div>
))}
</div>
),
},
{
key: "digital-human",
title: "一键数字人",
tag: "视频生成",
icon: "🧑",
features: ["上传人像", "匹配音频", "唇形同步", "生成视频"],
targetView: "digitalHuman" as WebViewKey,
render: () => (
<div className="toolbox-card3-content">
<div className="toolbox-card3-side toolbox-card3-left">
<div className="toolbox-card3-portrait">
<div className="toolbox-card3-portrait-mark">STATIC</div>
</div>
<div className="toolbox-card3-label"></div>
</div>
<div className="toolbox-card3-divider" />
<div className="toolbox-card3-transform"></div>
<div className="toolbox-card3-side toolbox-card3-right">
<div className="toolbox-card3-portrait">
<div className="toolbox-card3-glow-ring" />
<div className="toolbox-card3-lipsync">
<span /><span /><span /><span /><span />
</div>
<div className="toolbox-card3-gesture" />
<div className="toolbox-card3-live">LIVE</div>
</div>
<div className="toolbox-card3-label"></div>
</div>
</div>
),
},
{
key: "watermark-removal",
title: "去除水印",
tag: "AI清除",
icon: "✨",
features: ["智能识别", "精准去除", "无损画质"],
targetView: "watermarkRemoval" as WebViewKey,
render: () => (
<div className="toolbox-card4-content">
<div className="toolbox-card4-side toolbox-card4-left">
<div className="toolbox-card4-img">
<img src={watermarkBefore} alt="去水印前" />
</div>
<div className="toolbox-card4-label"></div>
</div>
<div className="toolbox-card4-divider" />
<div className="toolbox-card4-side toolbox-card4-right">
<div className="toolbox-card4-img">
<img src={watermarkAfter} alt="去水印后" />
</div>
<div className="toolbox-card4-label"></div>
</div>
</div>
),
},
];
function ToolboxSection({ onSelectView, onOpenImageTool }: ToolboxSectionProps) {
const handleCardClick = (targetView: WebViewKey) => {
onSelectView(targetView);
};
return (
<section className="omni-home__toolbox-page" aria-label="OmniAI 工具箱">
<div className="omni-home__toolbox-shell">
{/* Left Panel */}
<aside className="omni-home__toolbox-left">
<div className="omni-home__toolbox-brand">
<div className="omni-home__toolbox-brand-icon">
<ToolOutlined />
</div>
<div className="omni-home__toolbox-brand-text"></div>
</div>
<div className="omni-home__toolbox-title">
<br />
</div>
<div className="omni-home__toolbox-subtitle">
AI工具覆盖图片加工
</div>
<div className="omni-home__toolbox-list">
{TOOLS.map((tool) => (
<div
key={tool.key}
className="omni-home__toolbox-item"
onClick={() => {
const card = CARDS.find((c) => c.key === tool.key);
if (card) handleCardClick(card.targetView);
}}
>
<div className="omni-home__toolbox-item-icon">{tool.icon}</div>
<div className="omni-home__toolbox-item-info">
<div className="omni-home__toolbox-item-name">{tool.name}</div>
<div className="omni-home__toolbox-item-desc">{tool.desc}</div>
</div>
</div>
))}
</div>
<div className="omni-home__toolbox-workflow">
<div className="omni-home__toolbox-workflow-label"></div>
<div className="omni-home__toolbox-workflow-steps">
<span className="omni-home__toolbox-workflow-step"></span>
<span className="omni-home__toolbox-workflow-arrow"></span>
<span className="omni-home__toolbox-workflow-step"></span>
<span className="omni-home__toolbox-workflow-arrow"></span>
<span className="omni-home__toolbox-workflow-step">AI处理</span>
<span className="omni-home__toolbox-workflow-arrow"></span>
<span className="omni-home__toolbox-workflow-step"></span>
</div>
</div>
</aside>
{/* Grid Area */}
<div className="omni-home__toolbox-grid">
{CARDS.map((card) => (
<div
key={card.key}
className="omni-home__toolbox-card"
onClick={() => handleCardClick(card.targetView)}
>
<div className="omni-home__toolbox-card-header">
<div className="omni-home__toolbox-card-header-left">
<div className="omni-home__toolbox-card-icon">{card.icon}</div>
<div className="omni-home__toolbox-card-title">{card.title}</div>
</div>
<div className="omni-home__toolbox-card-tag">{card.tag}</div>
</div>
<div className="omni-home__toolbox-card-content">
{card.render()}
</div>
<div className="omni-home__toolbox-card-footer">
{card.features.map((feat, i) => (
<span key={feat}>
{i > 0 && <span className="omni-home__toolbox-card-feat-sep">|</span>}
<span className="omni-home__toolbox-card-feat">{feat}</span>
</span>
))}
</div>
</div>
))}
</div>
</div>
</section>
);
}
export default ToolboxSection;