页面样式优化

This commit is contained in:
sjy
2026-07-24 11:29:04 +08:00
parent a445198ecb
commit 0e20981383
7 changed files with 393 additions and 164 deletions
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -28,7 +28,7 @@
}
})();
</script>
<script type="module" crossorigin src="/assets/index-5mDsoYNB.js"></script>
<script type="module" crossorigin src="/assets/index-CVSmzRXM.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Bsz_Xon-.css">
</head>
<body>
@@ -119,16 +119,7 @@ const NotificationPopup: React.FC = () => {
position: 'relative',
overflow: 'hidden',
}}>
<div style={{
position: 'absolute',
right: -50,
top: -50,
width: 200,
height: 200,
borderRadius: '50%',
background: 'radial-gradient(circle, rgba(255,255,255,0.15) 0%, transparent 60%)',
filter: 'blur(30px)',
}} />
{/* Top row: type badge + close */}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
@@ -136,7 +127,7 @@ const NotificationPopup: React.FC = () => {
{tc.icon} {tc.label}
</Tag>
<button
onClick={handleClose}
onClick={(e) => { e.stopPropagation(); handleClose(); }}
style={{
width: 28, height: 28, borderRadius: '50%',
background: 'rgba(255,255,255,0.1)',
+298 -88
View File
@@ -29,6 +29,7 @@ import {
CloseCircleOutlined,
EditOutlined,
RocketOutlined,
LayoutOutlined,
CaretRightOutlined,
CaretDownOutlined,
VideoCameraOutlined,
@@ -288,16 +289,20 @@ const PortalOptionGroup: React.FC<PortalOptionGroupProps> = ({ group, groupName,
borderRadius: 8,
cursor: "pointer",
userSelect: "none",
transition: "all 0.2s",
background: selected ? "rgba(99,102,241,0.08)" : "#f8f9fc",
border: expanded ? "1px solid #6366f1" : "1px solid #e2e8f0",
transition: "background 0.2s, border-color 0.2s",
background: "#ffffffff",
border: "1px solid #e2e8f0",
minWidth: 70,
whiteSpace: "nowrap",
flexShrink: 0,
}}
>
<Typography.Text
style={{
fontSize: 12,
color: selected ? "#6366f1" : "#64748b",
fontWeight: selected ? 500 : 400,
fontSize: 13,
color: "#374151",
fontWeight: 500,
lineHeight: "18px",
}}
>
{selected || group.name}
@@ -642,13 +647,14 @@ const GeneratePage: React.FC = () => {
// Video params for step 2
const [videoDuration, setVideoDuration] = useState(5);
const [videoAspectRatio, setVideoAspectRatio] = useState<AspectRatio>("16:9");
const [videoAspectRatio, setVideoAspectRatio] = useState<AspectRatio>("9:16");
const [videoResolution, setVideoResolution] = useState<Resolution>("720p");
const [videoEngines, setVideoEngines] = useState<any[]>([]);
const [imageEngines, setImageEngines] = useState<any[]>([]);
const [selectedEngineId, setSelectedEngineId] = useState("");
const [includeMediaReferences, setIncludeMediaReferences] = useState(false);
const [expandedEngine, setExpandedEngine] = useState<string | null>(null);
const [showVideoSettingsModal, setShowVideoSettingsModal] = useState(false);
const [engineOptions, setEngineOptions] = useState<{
ratios: string[];
resolutions: string[];
@@ -856,7 +862,7 @@ const GeneratePage: React.FC = () => {
calculateCredits().then((data: any) => {
setCreditCalculationData(data);
})
if (!showImageSettingsModal) return;
if (!showImageSettingsModal && !showVideoSettingsModal) return;
const handleClickOutside = (e: MouseEvent) => {
const target = e.target as HTMLElement;
if (
@@ -864,11 +870,12 @@ const GeneratePage: React.FC = () => {
!target.closest(".image-settings-trigger")
) {
setShowImageSettingsModal(false);
setShowVideoSettingsModal(false);
}
};
document.addEventListener("click", handleClickOutside);
return () => document.removeEventListener("click", handleClickOutside);
}, [showImageSettingsModal]);
}, [showImageSettingsModal, showVideoSettingsModal]);
const getReferenceUsage = (items?: MediaReference[]) => {
@@ -1141,6 +1148,13 @@ const GeneratePage: React.FC = () => {
// console.log(numericValue);
// 更新状态(使用转换后的数字值)
setMediaType(numericValue);
// 切换媒体类型后,默认选择第一个可用引擎
const engines = numericValue === "image" ? imageEngines : videoEngines;
const filteredEngines = engines.filter((item: any) => item.supportsUniversalReference !== false);
if (filteredEngines.length > 0) {
handleGenerationEngineChange(filteredEngines[0].id);
}
};
useEffect(() => {
@@ -1271,8 +1285,23 @@ const GeneratePage: React.FC = () => {
if (mediaType === 'image') {
const sizes = engine.supportedSizes || {};
setSupportedSizes(sizes);
const resolution = Object.keys(sizes)[0] || '2K';
const ratio = Object.keys(sizes[resolution] || {})[0] || '1:1';
const resolutionKeys = Object.keys(sizes);
const resolutionOpts = resolutionKeys.map((key) => ({
value: key,
label: key,
}));
setResolutionOptions(resolutionOpts);
const resolution = resolutionKeys.includes(selectedResolution) ? selectedResolution : resolutionKeys[0] || '2K';
const ratioKeys = Object.keys(sizes[resolution] || {});
const ratioOpts = ratioKeys.map((key) => ({
value: key,
label: key,
}));
setRatioOptions(ratioOpts);
const ratio = ratioKeys.includes(selectedRatio) ? selectedRatio : ratioKeys[0] || '1:1';
setSelectedResolution(resolution);
setSelectedRatio(ratio);
const pixelSize = sizes[resolution]?.[ratio] || '';
@@ -2417,7 +2446,7 @@ const GeneratePage: React.FC = () => {
}
}}
rows={3}
placeholder="上传参考素材只用做模型理解,不参与生成)、输入文字,自由组合图、文多元素。输入 @ 可引用参考内容..."
placeholder="上传参考素材后(手动开启是否参与最终生成,如不开启则只用做模型理解)、输入文字,自由组合图、文多元素。输入 @ 可引用参考内容..."
maxLength={500}
variant="borderless"
autoSize={{ minRows: 2, maxRows: 6 }}
@@ -2560,12 +2589,12 @@ const GeneratePage: React.FC = () => {
>
<PortalDropdown
label="引擎"
value={(mediaType === "image" ? imageEngines : videoEngines).find((item: any) => item.id === selectedEngineId)?.name || "选择引擎"}
options={(mediaType === "image" ? imageEngines : videoEngines).map((item: any) => item.name)}
value={(mediaType === "image" ? imageEngines : videoEngines).filter((item: any) => item.supportsUniversalReference !== false).find((item: any) => item.id === selectedEngineId)?.name || "选择引擎"}
options={(mediaType === "image" ? imageEngines : videoEngines).filter((item: any) => item.supportsUniversalReference !== false).map((item: any) => item.name)}
expanded={expandedEngine === "engine"}
onToggle={() => setExpandedEngine(expandedEngine === "engine" ? null : "engine")}
onSelect={(value) => {
const engine = (mediaType === "image" ? imageEngines : videoEngines).find((item: any) => item.name === value);
const engine = (mediaType === "image" ? imageEngines : videoEngines).filter((item: any) => item.supportsUniversalReference !== false).find((item: any) => item.name === value);
if (engine) {
handleGenerationEngineChange(engine.id);
}
@@ -2575,34 +2604,228 @@ const GeneratePage: React.FC = () => {
/>
{mediaType !== "image" && (
<>
<PortalDropdown
label="时长"
value={`${videoDuration}`}
options={durationOptions}
suffix="秒"
expanded={expandedEngine === "duration"}
onToggle={handleDurationToggle}
onSelect={handleDurationSelect}
onClose={handleDurationClose}
/>
<PortalDropdown
label="比例"
value={videoAspectRatio as string}
options={engineOptions.ratios}
expanded={expandedEngine === "aspectRatio"}
onToggle={() => setExpandedEngine(expandedEngine === "aspectRatio" ? null : "aspectRatio")}
onSelect={(value) => { setVideoAspectRatio(value as AspectRatio); setExpandedEngine(null); }}
onClose={() => setExpandedEngine(null)}
/>
<PortalDropdown
label="分辨率"
value={videoResolution as string}
options={engineOptions.resolutions}
expanded={expandedEngine === "resolution"}
onToggle={() => setExpandedEngine(expandedEngine === "resolution" ? null : "resolution")}
onSelect={(value) => { setVideoResolution(value as Resolution); setExpandedEngine(null); }}
onClose={() => setExpandedEngine(null)}
/>
<div style={{ flex: 1, position: 'relative', display: 'inline-block' }}>
<button
onClick={() => {
setShowVideoSettingsModal(!showVideoSettingsModal);
setExpandedEngine(null);
}}
className="image-settings-trigger"
style={{
width: '100%',
padding: '4px 12px',
height: 34,
borderRadius: 10,
border: '1px solid rgba(99, 102, 241, 0.15)',
backgroundColor: 'rgba(255,255,255,0.7)',
cursor: 'pointer',
display: 'inline-flex',
alignItems: 'center',
gap: 6,
transition: 'all 0.2s',
}}
>
<LayoutOutlined style={{ fontSize: 14, color: '#6366f1' }} />
<span style={{
fontSize: 14,
fontWeight: 500,
color: '#64748b',
}}>
{videoAspectRatio} · {videoDuration}s · {videoResolution}
</span>
</button>
{showVideoSettingsModal && (
<div
className="image-settings-popover"
style={{
position: 'absolute',
bottom: 'calc(100% + 8px)',
left: -160,
width: 350,
backgroundColor: '#fff',
borderRadius: 16,
boxShadow: '0 10px 40px rgba(0,0,0,0.15)',
padding: 16,
border: 'none',
zIndex: 9999,
}}
onClick={(e) => e.stopPropagation()}
>
<div style={{ marginBottom: 16 }}>
<span style={{
display: 'block',
marginBottom: 8,
fontSize: 12,
fontWeight: 500,
color: '#666666',
}}>
</span>
<div style={{
display: 'flex',
flexWrap: 'wrap',
gap: 4,
}}>
{engineOptions.ratios.map((ratio) => (
<button
key={ratio}
onClick={() => setVideoAspectRatio(ratio as AspectRatio)}
style={{
flex: '0 0 calc(14.28% - 4px)',
minWidth: 44,
height: 52,
borderRadius: 6,
border: videoAspectRatio === ratio
? '2px solid #6366f1'
: '1px solid #e5e7eb',
backgroundColor: videoAspectRatio === ratio
? '#fff'
: '#f9fafb',
cursor: 'pointer',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
transition: 'all 0.2s',
}}
>
<div style={{
width: 18,
height: 18,
border: `2px solid ${videoAspectRatio === ratio ? '#6366f1' : '#9ca3af'}`,
borderRadius: 2,
marginBottom: 2,
}} />
<span style={{
fontSize: 9,
color: videoAspectRatio === ratio
? '#6366f1'
: '#6b7280',
fontWeight: videoAspectRatio === ratio ? 600 : 400,
}}>
{ratio}
</span>
</button>
))}
</div>
</div>
<div style={{ marginBottom: 16 }}>
<span style={{
display: 'block',
marginBottom: 8,
fontSize: 12,
fontWeight: 500,
color: '#666666',
}}>
</span>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<div style={{ flex: 1, position: 'relative', height: 24, display: 'flex', alignItems: 'center' }}>
<div style={{
position: 'absolute',
top: '50%',
left: 0,
right: 0,
height: 6,
borderRadius: 3,
background: '#e5e7eb',
transform: 'translateY(-50%)',
}} />
<div style={{
position: 'absolute',
top: '50%',
left: 0,
height: 6,
borderRadius: 3,
background: '#6366f1',
width: `${((videoDuration - Math.min(...engineOptions.durations)) / (Math.max(...engineOptions.durations) - Math.min(...engineOptions.durations))) * 100}%`,
transform: 'translateY(-50%)',
}} />
<input
type="range"
min={Math.min(...engineOptions.durations)}
max={Math.max(...engineOptions.durations)}
value={videoDuration}
onChange={(e) => setVideoDuration(Number(e.target.value))}
style={{
position: 'relative',
width: '100%',
height: 24,
borderRadius: 3,
background: 'transparent',
outline: 'none',
appearance: 'none',
cursor: 'pointer',
zIndex: 1,
}}
/>
</div>
<div style={{
display: 'flex',
alignItems: 'center',
gap: 4,
padding: '4px 12px',
backgroundColor: '#f1f5f9',
borderRadius: 6,
}}>
<span style={{ fontSize: 14, fontWeight: 600, color: '#64748b' }}>
{videoDuration}
</span>
<span style={{ fontSize: 12, color: '#9ca3af' }}></span>
</div>
</div>
</div>
<div>
<span style={{
display: 'block',
marginBottom: 8,
fontSize: 12,
fontWeight: 500,
color: '#666666',
}}>
</span>
<div style={{ display: 'flex', gap: 6 }}>
{engineOptions.resolutions.map((resolution) => (
<button
key={resolution}
onClick={() => setVideoResolution(resolution as Resolution)}
style={{
flex: 1,
height: 42,
borderRadius: 8,
border: videoResolution === resolution
? '2px solid #6366f1'
: '1px solid #e5e7eb',
backgroundColor: videoResolution === resolution
? '#6366f1'
: '#f9fafb',
cursor: 'pointer',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
transition: 'all 0.2s',
}}
>
<span style={{
fontSize: 12,
fontWeight: 600,
color: videoResolution === resolution
? '#fff'
: '#4b5563',
}}>
{resolution}
</span>
</button>
))}
</div>
</div>
</div>
)}
</div>
{currentOptionGroups.map((group, gi) => {
const isExpanded = expandedGroup === group.name;
const selected = selectedOptions[group.name];
@@ -2622,63 +2845,50 @@ const GeneratePage: React.FC = () => {
</>
)}
{mediaType == "image" && (
<div
style={{ position: "relative", display: "inline-block" }}
>
<div style={{ flex: 1, position: 'relative', display: 'inline-block' }}>
<button
onClick={() =>
setShowImageSettingsModal(!showImageSettingsModal)
}
onClick={() => {
setShowImageSettingsModal(!showImageSettingsModal);
setExpandedEngine(null);
}}
className="image-settings-trigger"
style={{
minWidth: 200,
padding: "0px 14px",
height: 32,
borderRadius: 8,
border: "1px solid #e2e8f0",
backgroundColor: "#fff",
cursor: "pointer",
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: 10,
transition: "all 0.2s",
width: '100%',
padding: '4px 12px',
height: 34,
borderRadius: 10,
border: '1px solid rgba(99, 102, 241, 0.15)',
backgroundColor: 'rgba(255,255,255,0.7)',
cursor: 'pointer',
display: 'inline-flex',
alignItems: 'center',
gap: 6,
transition: 'all 0.2s',
}}
>
<div style={{ textAlign: "left" }}>
<Typography.Text
style={{
fontSize: 13,
fontWeight: 500,
color: "#000000ff",
}}
>
{selectedRatio === "auto" ? "智能" : selectedRatio}
</Typography.Text>
<Typography.Text
style={{ fontSize: 11, color: "#000000ff" }}
>
{selectedResolution === "1K" ? "标清" : selectedResolution === "2K" ? "高清" : `${selectedResolution}`} | {width}×{height}
</Typography.Text>
</div>
<CaretDownOutlined
style={{ fontSize: 14, color: "#000000ff" }}
/>
<LayoutOutlined style={{ fontSize: 14, color: '#6366f1' }} />
<span style={{
fontSize: 14,
fontWeight: 500,
color: '#64748b',
}}>
{selectedRatio === "auto" ? "智能" : selectedRatio} · {selectedResolution} · {width}×{height}
</span>
</button>
{showImageSettingsModal && (
<div
className="image-settings-popover"
style={{
position: "absolute",
bottom: "calc(100% + 8px)",
left: 0,
width: 520,
backgroundColor: "#fff",
borderRadius: 12,
boxShadow: "0 8px 32px rgba(0,0,0,0.12)",
position: 'absolute',
bottom: 'calc(100% + 8px)',
left: -160,
width: 350,
backgroundColor: '#fff',
borderRadius: 16,
boxShadow: '0 10px 40px rgba(0,0,0,0.15)',
padding: 16,
border: "1px solid rgba(231, 234, 240, 0.8)",
border: 'none',
zIndex: 9999,
}}
onClick={(e) => e.stopPropagation()}
+20 -18
View File
@@ -87,7 +87,7 @@ const GenerateConver: React.FC = () => {
const [videoEngines, setVideoEngines] = useState<any[]>([]);
const [engineId, setEngineId] = useState('');
const [videoDuration, setVideoDuration] = useState(5);
const [videoAspectRatio, setVideoAspectRatio] = useState('16:9');
const [videoAspectRatio, setVideoAspectRatio] = useState('9:16');
const [videoResolution, setVideoResolution] = useState('480p');
const [showEngineModal, setShowEngineModal] = useState(false);
const [showVideoSettingsModal, setShowVideoSettingsModal] = useState(false);
@@ -120,7 +120,7 @@ const GenerateConver: React.FC = () => {
if (engines.length > 0) {
const first = engines[0];
setEngineId(first.id);
setVideoAspectRatio(first.supportedRatios?.[0] || '16:9');
setVideoAspectRatio(first.supportedRatios?.includes('9:16') ? '9:16' : first.supportedRatios?.[0] || '9:16');
setVideoResolution(first.supportedResolutions?.[0] || '480p');
setVideoDuration(first.supportedDurations?.[0] || 5);
}
@@ -128,6 +128,18 @@ const GenerateConver: React.FC = () => {
calculateCredits().then((rules: any) => setCreditRules(Array.isArray(rules) ? rules : [])).catch(() => setCreditRules([]));
}, []);
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
const target = e.target as HTMLElement;
if (!target.closest('.image-settings-popover') && !target.closest('.image-settings-trigger')) {
setShowEngineModal(false);
setShowVideoSettingsModal(false);
}
};
document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}, []);
const selectedEngine = videoEngines.find((item: any) => item.id === engineId);
const selectedEngineSupportsImage = !imageUrl || supportsReferenceImage(selectedEngine);
const estimatedCredits = (() => {
@@ -1129,12 +1141,12 @@ const GenerateConver: React.FC = () => {
{/* 原视频产品名称 */}
<div style={{ marginBottom: 16 }}>
<p style={{ margin: 0, fontSize: 13, fontWeight: 500, color: '#475569', marginBottom: 8 }}>
</p>
<Input
value={originalProductName}
onChange={(e) => setOriginalProductName(e.target.value)}
placeholder="请输入原视频产品名称"
placeholder="请输入原产品名称"
style={{
borderRadius: 10,
height: 40,
@@ -1195,7 +1207,7 @@ const GenerateConver: React.FC = () => {
</div>
</div>
<div style={{ marginBottom:16, display: 'grid', gap: 10 }}>
<div style={{ marginBottom: 16, display: 'grid', gap: 10 }}>
<p style={{ margin: 0, fontSize: 13, fontWeight: 600, color: '#475569' }}></p>
<div style={{ width: '100%', display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>
<div style={{ flex: 1, position: 'relative', display: 'inline-block' }}>
@@ -1580,24 +1592,14 @@ const GenerateConver: React.FC = () => {
>
<span style={{ color: '#ffffffff', marginLeft: 8, fontSize: 13 }}>
:{(estimatedCredits + optimizeHoldCredits)}
</span>
</Button>
</Tooltip>
<div style={{textAlign:'center'}}>
<span style={{ color: '#000000ff', marginLeft: 8, fontSize: 13 }}>
:{estimatedCredits}
</span>
<span style={{ color: '#000000ff', marginLeft: 8, fontSize: 13 }}>
+
</span>
<span style={{ color: '#000000ff', marginLeft: 8, fontSize: 13 }}>
:{optimizeHoldCredits}
</span>
</div>
</div>
+46 -20
View File
@@ -47,7 +47,7 @@ function RemoveInfo() {
const [videoEngines, setVideoEngines] = useState<any[]>([]);
const [engineId, setEngineId] = useState('');
const [videoDuration, setVideoDuration] = useState(5);
const [videoAspectRatio, setVideoAspectRatio] = useState('16:9');
const [videoAspectRatio, setVideoAspectRatio] = useState('9:16');
const [videoResolution, setVideoResolution] = useState('480p');
const [showEngineModal, setShowEngineModal] = useState(false);
const [showVideoSettingsModal, setShowVideoSettingsModal] = useState(false);
@@ -79,7 +79,7 @@ function RemoveInfo() {
if (engines.length > 0) {
const first = engines[0];
setEngineId(first.id);
setVideoAspectRatio(first.supportedRatios?.[0] || '16:9');
setVideoAspectRatio(first.supportedRatios?.includes('9:16') ? '9:16' : first.supportedRatios?.[0] || '9:16');
setVideoResolution(first.supportedResolutions?.[0] || '480p');
setVideoDuration(first.supportedDurations?.[0] || 5);
}
@@ -195,6 +195,18 @@ function RemoveInfo() {
};
}, [refreshPageData]);
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
const target = e.target as HTMLElement;
if (!target.closest('.image-settings-popover') && !target.closest('.image-settings-trigger')) {
setShowEngineModal(false);
setShowVideoSettingsModal(false);
}
};
document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}, []);
useEffect(() => {
const processing = taskDetail?.analysisStatus === 'processing';
if (!processing || !creatID) {
@@ -207,8 +219,6 @@ function RemoveInfo() {
}
if (!analysisStartedAtRef.current) analysisStartedAtRef.current = Date.now();
const elapsed = Date.now() - analysisStartedAtRef.current;
const delay = elapsed < 60_000 ? 3_000 : (elapsed < 600_000 ? 10_000 : 30_000);
const poll = async () => {
if (document.visibilityState !== 'visible') return;
@@ -220,11 +230,26 @@ function RemoveInfo() {
}
};
analysisPollingRef.current = window.setTimeout(() => void poll(), delay);
const scheduleNextPoll = () => {
if (!analysisPollingRef.current) return;
const elapsed = Date.now() - (analysisStartedAtRef.current || Date.now());
const delay = elapsed < 60_000 ? 3_000 : (elapsed < 600_000 ? 10_000 : 30_000);
analysisPollingRef.current = window.setTimeout(async () => {
await poll();
scheduleNextPoll();
}, delay);
};
analysisPollingRef.current = window.setTimeout(async () => {
await poll();
scheduleNextPoll();
}, 3_000);
const handleVisibility = () => {
if (document.visibilityState === 'visible') void poll();
};
document.addEventListener('visibilitychange', handleVisibility);
return () => {
if (analysisPollingRef.current) {
window.clearTimeout(analysisPollingRef.current);
@@ -356,7 +381,16 @@ function RemoveInfo() {
//
// }
} catch (err: any) {
message.error(err?.message || '创建失败,请重试');
let errorMsg = '';
if (err instanceof Error) {
try {
const errorData = JSON.parse(err.message);
errorMsg = errorData.detail || err.message;
} catch {
errorMsg = err.message;
}
}
message.error(errorMsg || '创建失败,请重试');
} finally {
setLoading(false);
}
@@ -878,7 +912,7 @@ function RemoveInfo() {
<Button
type="default"
onClick={handleOpenTrimModal}
disabled={!videoUrl || splitLoading}
disabled={!videoUrl || splitLoading || taskDetail?.analysisStatus === 'processing'}
style={{
flex: 1,
height: 52,
@@ -911,7 +945,7 @@ function RemoveInfo() {
<Button
type="primary"
loading={autoSplitLoading}
disabled={autoSplitLoading}
disabled={autoSplitLoading || taskDetail?.analysisStatus === 'processing'}
style={{
flex: 1,
height: 52,
@@ -1551,21 +1585,13 @@ function RemoveInfo() {
>
{loading ? '生成中...' : '手动生成'}
<span style={{ color: '#ffffffff', marginLeft: 8, fontSize: 13 }}>
:{(estimatedCredits + optimizeHoldCredits)}
</span>
</Button>
</Tooltip>
</div>
<div style={{ textAlign: 'center' }}>
<span style={{ color: '#000000ff', marginLeft: 8, fontSize: 13 }}>
:{estimatedCredits}
</span>
<span style={{ color: '#000000ff', marginLeft: 8, fontSize: 13 }}>
+
</span>
<span style={{ color: '#000000ff', marginLeft: 8, fontSize: 13 }}>
:{optimizeHoldCredits}
</span>
</div>
</div>
</Drawer>
+19 -19
View File
@@ -1,5 +1,5 @@
import { useEffect, useState, useRef, useCallback } from 'react';
import { Button, Modal, Input, Table, Upload, Popconfirm, Tag, Space, message } from 'antd';
import { Button, Modal, Input, Table, Upload, Popconfirm, Tag, Space, App } from 'antd';
import { FileTextOutlined, CloudUploadOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
@@ -13,6 +13,7 @@ const renderStatus = (status: string) => {
};
export default function VideoFrameExtractor() {
const { message } = App.useApp();
const navigate = useNavigate();
const [videoUrl, setVideoUrl] = useState<string>('');
@@ -32,7 +33,7 @@ export default function VideoFrameExtractor() {
const canvasRef = useRef<HTMLCanvasElement>(null);
const cleanupResources = useCallback(() => {
if (videoUrl) {
if (videoUrl && videoUrl.startsWith('blob:')) {
URL.revokeObjectURL(videoUrl);
}
setVideoUrl('');
@@ -112,24 +113,23 @@ export default function VideoFrameExtractor() {
idempotency_key: `shot_${Date.now()}`,
};
createShotReplication(params).then((res) => {
// message.success('任务创建成功');
getShotReplicationList(1, 20, searchKeyword).then((res) => {
// console.log('获取列表成功', res.items[0].id);
message.loading('创建中...', 3);
setTimeout(() => {
navigate(`/removelens/${res.items[0].id}/removeinfo`);
}, 3000);
// setTableData(res.items || []);
})
})
const createRes = await createShotReplication(params);
const listRes = await getShotReplicationList(1, 20, searchKeyword);
message.loading('创建中...', 3);
setTimeout(() => {
navigate(`/removelens/${listRes.items[0].id}/removeinfo`);
}, 3000);
cleanupResources();
} catch (err) {
message.error('任务创建失败,请重试');
} catch (err: any) {
let errorMsg = '';
if (err instanceof Error) {
errorMsg = err.message;
} else if (typeof err === 'string') {
errorMsg = err;
}
message.error(errorMsg || '任务创建失败,请重试');
} finally {
setLoading(false);
}