“爆款复刻/拆镜复刻积分不足提示”
This commit is contained in:
+156
-105
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -28,7 +28,7 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script type="module" crossorigin src="/assets/index-nrhXZrQV.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-Dq-lhFsY.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DviWdElm.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
HeartOutlined,
|
||||
CameraOutlined,
|
||||
CalculatorOutlined,
|
||||
CaretDownOutlined,
|
||||
DollarOutlined,
|
||||
FireOutlined,
|
||||
CloudOutlined,
|
||||
@@ -126,6 +127,7 @@ const StorageCard: React.FC<{ data: ResourceCapacityData | null }> = ({ data })
|
||||
<div
|
||||
style={{
|
||||
// marginTop: 12,
|
||||
marginBottom: 12,
|
||||
padding: '0 12px',
|
||||
paddingTop: 6,
|
||||
borderRadius: 10,
|
||||
@@ -906,33 +908,59 @@ const AppLayout: React.FC = () => {
|
||||
|
||||
<div style={{ padding: '16px 16px', flexShrink: 0, paddingTop: 0 }}>
|
||||
<Dropdown menu={{ items: userMenuItems, onClick: handleUserMenuClick }} placement="topRight" arrow>
|
||||
<div style={{
|
||||
<div className="user-card-container" style={{
|
||||
padding: '10px 14px',
|
||||
display: 'flex', alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
gap: 12,
|
||||
// padding: '10px 14px',
|
||||
borderRadius: 14, cursor: 'pointer',
|
||||
transition: 'all 0.25s ease',
|
||||
background: 'linear-gradient(135deg, rgba(248, 250, 252, 0.9) 0%, rgba(241, 245, 249, 0.9) 100%)',
|
||||
boxShadow: '0 2px 12px rgba(0, 0, 0, 0.04)',
|
||||
transition: 'all 0.35s cubic-bezier(0.4,0,0.2,1)',
|
||||
background: 'linear-gradient(135deg, rgba(248, 250, 252, 0.95) 0%, rgba(241, 245, 249, 0.95) 100%)',
|
||||
boxShadow: '0 2px 12px rgba(0, 0, 0, 0.04), inset 0 1px 0 rgba(255,255,255,0.8)',
|
||||
position: 'relative',
|
||||
border: '1px solid rgba(99, 102, 241, 0.15)',
|
||||
animation: 'cardBreath 3s ease-in-out infinite',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = 'linear-gradient(135deg, #ffffff 0%, #f8fafc 100%)';
|
||||
e.currentTarget.style.boxShadow = '0 4px 16px rgba(0, 0, 0, 0.08)';
|
||||
e.currentTarget.style.boxShadow = '0 8px 24px rgba(99, 102, 241, 0.25), inset 0 1px 0 rgba(255,255,255,0.9)';
|
||||
e.currentTarget.style.transform = 'translateY(-3px) scale(1.01)';
|
||||
e.currentTarget.style.borderColor = 'rgba(99, 102, 241, 0.4)';
|
||||
e.currentTarget.style.animation = 'none';
|
||||
e.currentTarget.querySelector('.user-card-arrow')?.classList.add('arrow-hover');
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = 'linear-gradient(135deg, rgba(248, 250, 252, 0.9) 0%, rgba(241, 245, 249, 0.9) 100%)';
|
||||
e.currentTarget.style.boxShadow = '0 2px 12px rgba(0, 0, 0, 0.04)';
|
||||
e.currentTarget.style.background = 'linear-gradient(135deg, rgba(248, 250, 252, 0.95) 0%, rgba(241, 245, 249, 0.95) 100%)';
|
||||
e.currentTarget.style.boxShadow = '0 2px 12px rgba(0, 0, 0, 0.04), inset 0 1px 0 rgba(255,255,255,0.8)';
|
||||
e.currentTarget.style.transform = 'translateY(0) scale(1)';
|
||||
e.currentTarget.style.borderColor = 'rgba(99, 102, 241, 0.15)';
|
||||
e.currentTarget.style.animation = 'cardBreath 3s ease-in-out infinite';
|
||||
e.currentTarget.querySelector('.user-card-arrow')?.classList.remove('arrow-hover');
|
||||
}}
|
||||
>
|
||||
<div className="user-card-glow" style={{
|
||||
position: 'absolute',
|
||||
inset: -4,
|
||||
borderRadius: 18,
|
||||
background: 'linear-gradient(90deg, transparent 0%, rgba(99,102,241,0.15) 25%, rgba(139,92,246,0.15) 50%, rgba(99,102,241,0.15) 75%, transparent 100%)',
|
||||
backgroundSize: '200% 100%',
|
||||
opacity: 0.8,
|
||||
animation: 'borderShimmer 2.5s linear infinite',
|
||||
pointerEvents: 'none',
|
||||
}} />
|
||||
|
||||
<Avatar size={36} icon={<UserOutlined />}
|
||||
style={{
|
||||
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
|
||||
flexShrink: 0,
|
||||
boxShadow: '0 4px 12px rgba(99, 102, 241, 0.3)',
|
||||
transition: 'all 0.35s cubic-bezier(0.4,0,0.2,1)',
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
animation: 'avatarPulse 2s ease-in-out infinite',
|
||||
}} />
|
||||
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
<div style={{ flex: 1, minWidth: 0, position: 'relative', zIndex: 1 }}>
|
||||
<div style={{ color: '#1e293b', fontSize: 16, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', letterSpacing: -0.01 }}>
|
||||
{user?.username}
|
||||
</div>
|
||||
@@ -941,12 +969,74 @@ const AppLayout: React.FC = () => {
|
||||
fontSize: 16,
|
||||
fontWeight: 500,
|
||||
letterSpacing: 0,
|
||||
// background: 'rgba(99, 102, 241, 0.08)',
|
||||
// padding: '2px 8px',
|
||||
borderRadius: 6,
|
||||
display: 'inline-block',
|
||||
animation: 'creditGlow 1.5s ease-in-out infinite',
|
||||
}}>积分: {user?.credits || 0}</div>
|
||||
</div>
|
||||
|
||||
<div className="user-card-arrow" style={{
|
||||
fontSize: 12,
|
||||
color: '#6366f1',
|
||||
flexShrink: 0,
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
}}>
|
||||
<MenuOutlined />
|
||||
</div>
|
||||
|
||||
<style>{`
|
||||
@keyframes arrowFlash {
|
||||
0%, 100% {
|
||||
transform: translateY(0) scale(1);
|
||||
opacity: 0.6;
|
||||
filter: drop-shadow(0 0 4px rgba(99, 102, 241, 0.4));
|
||||
}
|
||||
50% {
|
||||
transform: translateY(4px) scale(1.1);
|
||||
opacity: 1;
|
||||
filter: drop-shadow(0 0 12px rgba(99, 102, 241, 0.7));
|
||||
}
|
||||
}
|
||||
@keyframes creditGlow {
|
||||
0%, 100% {
|
||||
text-shadow: 0 0 0 transparent;
|
||||
}
|
||||
50% {
|
||||
text-shadow: 0 0 15px rgba(99, 102, 241, 0.6), 0 0 30px rgba(99, 102, 241, 0.3);
|
||||
}
|
||||
}
|
||||
@keyframes borderShimmer {
|
||||
0% { background-position: 200% center; }
|
||||
100% { background-position: -200% center; }
|
||||
}
|
||||
@keyframes cardBreath {
|
||||
0%, 100% {
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04), inset 0 1px 0 rgba(255,255,255,0.8);
|
||||
border-color: rgba(99, 102, 241, 0.15);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 4px 20px rgba(99, 102, 241, 0.1), inset 0 1px 0 rgba(255,255,255,0.8);
|
||||
border-color: rgba(99, 102, 241, 0.25);
|
||||
}
|
||||
}
|
||||
@keyframes avatarPulse {
|
||||
0%, 100% {
|
||||
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 6px 20px rgba(99, 102, 241, 0.5);
|
||||
transform: scale(1.02);
|
||||
}
|
||||
}
|
||||
.user-card-arrow.arrow-hover {
|
||||
color: #8b5cf6 !important;
|
||||
transform: rotate(180deg) scale(1.15) !important;
|
||||
animation: none !important;
|
||||
filter: drop-shadow(0 0 15px rgba(139, 92, 246, 0.8)) !important;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
</Dropdown>
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button, Typography, Collapse, Space, Modal, Input, Table, message } from 'antd';
|
||||
import { ArrowLeftOutlined, PlayCircleOutlined, CheckCircleOutlined, EditOutlined, DownloadOutlined, SettingOutlined, LayoutOutlined } from '@ant-design/icons';
|
||||
import { Button, Typography, Collapse, Space, Modal, Input, Table, message, Tooltip } from 'antd';
|
||||
import { ArrowLeftOutlined, PlayCircleOutlined, CheckCircleOutlined, EditOutlined, DownloadOutlined, SettingOutlined, LayoutOutlined, WarningOutlined } from '@ant-design/icons';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { getReplicationList, getReplicationDetail, gettwo, getthree, getfour, getEngine, updateHotOpeningVideoPromptSchema, updateImagePrompt } from '../api/index';
|
||||
import { getReplicationList, getReplicationDetail, gettwo, getthree, getfour, getEngine, updateHotOpeningVideoPromptSchema, updateImagePrompt, calculateCredits } from '../api/index';
|
||||
import { useAuthStore } from '../store/useAuthStore';
|
||||
import VideoPromptSchemaEditor from '../components/VideoPromptSchemaEditor';
|
||||
import { validateVideoPromptSchemaByConfig } from '../utils/videoPromptSchema';
|
||||
import './css/InitialInfo.css';
|
||||
@@ -24,6 +25,7 @@ const buildMediaUrl = (url: string): string => {
|
||||
function InitialInfo() {
|
||||
const navigate = useNavigate();
|
||||
const { creatID } = useParams<{ creatID: string }>();
|
||||
const { user } = useAuthStore();
|
||||
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [promptText, setPromptText] = useState('');
|
||||
@@ -55,6 +57,9 @@ function InitialInfo() {
|
||||
durations: [5, 8, 10, 12, 15],
|
||||
});
|
||||
|
||||
const [creditCalculationData, setCreditCalculationData] = useState<any[]>([]);
|
||||
const [estimatedCredits, setEstimatedCredits] = useState<number>(0);
|
||||
|
||||
// 创作记录表格数据
|
||||
const [tableData, setTableData] = useState<any[]>([]);
|
||||
// 分页状态
|
||||
@@ -222,27 +227,89 @@ function InitialInfo() {
|
||||
useEffect(() => {
|
||||
getEngine()
|
||||
.then((data: any) => {
|
||||
setEnginesele(data.engine || {});
|
||||
// 默认选中第一个视频引擎
|
||||
if (data.engine?.video && data.engine.video.length > 0) {
|
||||
setCountType(data.engine.video[0].id);
|
||||
// 设置默认引擎参数
|
||||
const firstEngine = data.engine.video[0];
|
||||
const filteredVideoEngines = (data.engine?.video || []).filter((engine: any) => engine.supportsUniversalReference !== false);
|
||||
const filteredImageEngines = (data.engine?.image || []).filter((engine: any) => engine.supportsUniversalReference !== false);
|
||||
|
||||
setEnginesele({
|
||||
video: filteredVideoEngines,
|
||||
image: filteredImageEngines,
|
||||
});
|
||||
|
||||
if (filteredVideoEngines.length > 0) {
|
||||
setCountType(filteredVideoEngines[0].id);
|
||||
const firstEngine = filteredVideoEngines[0];
|
||||
setEngineOptions({
|
||||
ratios: firstEngine.supportedRatios || ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9'],
|
||||
resolutions: firstEngine.supportedResolutions || ['480p', '720p', '1080p'],
|
||||
durations: firstEngine.supportedDurations || [5, 8, 10, 12, 15],
|
||||
});
|
||||
}
|
||||
// 默认选中第一个图片引擎
|
||||
if (data.engine?.image && data.engine.image.length > 0) {
|
||||
setImageEngineId(data.engine.image[0].id);
|
||||
if (filteredImageEngines.length > 0) {
|
||||
setImageEngineId(filteredImageEngines[0].id);
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
calculateCredits().then((data: any) => {
|
||||
setCreditCalculationData(data);
|
||||
}).catch(() => {});
|
||||
}, []);
|
||||
|
||||
const calculateEstimatedCredits = () => {
|
||||
let config: any = {};
|
||||
config = creditCalculationData.find((item: any) =>
|
||||
item.modelConfigId === countType &&
|
||||
item.genType === 'video' &&
|
||||
item.resolution === videoResolution
|
||||
);
|
||||
|
||||
if (!config) {
|
||||
config = {
|
||||
perSecondCredits: 2,
|
||||
baseCredits: 60,
|
||||
ratio: 1.3,
|
||||
inputVideoRatio: 1.3,
|
||||
inputVideoBaseCredits: 0,
|
||||
inputVideoPerSecondCredits: 15,
|
||||
inputImageRatio: 1,
|
||||
inputImageBaseCredits: 0,
|
||||
inputImagePerImageCredits: 0.0,
|
||||
};
|
||||
if (videoResolution === '1080p') {
|
||||
config.ratio = 1.3;
|
||||
} else if (videoResolution === '720p') {
|
||||
config.ratio = 1.3;
|
||||
} else if (videoResolution === '480p') {
|
||||
config.ratio = 1.3;
|
||||
}
|
||||
}
|
||||
|
||||
let total = (videoDuration * config.perSecondCredits + config.baseCredits) * config.ratio;
|
||||
|
||||
const inputVideoDuration = taskDetail?.videoGeneration?.inputMedia?.video?.duration || 0;
|
||||
if (inputVideoDuration > 0) {
|
||||
const inputVideoCost = ((config.inputVideoBaseCredits || 0) + (config.inputVideoPerSecondCredits || 0) * inputVideoDuration) * (config.inputVideoRatio || 1);
|
||||
total += inputVideoCost;
|
||||
}
|
||||
|
||||
const inputImageCount = taskDetail?.videoGeneration?.inputMedia?.image?.length || 0;
|
||||
if (inputImageCount > 0) {
|
||||
const inputImageCost = ((config.inputImageBaseCredits || 0) + (config.inputImagePerImageCredits || 0) * inputImageCount) * (config.inputImageRatio || 1);
|
||||
total += inputImageCost;
|
||||
}
|
||||
|
||||
setEstimatedCredits(Number(total.toFixed(2)));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (creditCalculationData.length > 0 && countType) {
|
||||
calculateEstimatedCredits();
|
||||
}
|
||||
}, [creditCalculationData, countType, videoDuration, videoResolution, taskDetail]);
|
||||
|
||||
// 组件卸载时清理定时器
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
@@ -1190,14 +1257,36 @@ function InitialInfo() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{ width: '100%', borderRadius: 10, background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)', border: 'none', height: 36, fontWeight: 500, boxShadow: '0 4px 12px rgba(99, 102, 241, 0.3)' }}
|
||||
onClick={() => { handleNextStep(step.id); }}
|
||||
disabled={step.status !== 'completed'}
|
||||
<Tooltip
|
||||
title={((user?.credits || 0) < estimatedCredits) ? '积分不足,请更换参数/充值积分' : ''}
|
||||
placement="top"
|
||||
>
|
||||
下一步:生成视频提示词
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{
|
||||
width: '100%',
|
||||
borderRadius: 10,
|
||||
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
|
||||
border: 'none',
|
||||
height: 36,
|
||||
fontWeight: 500,
|
||||
boxShadow: '0 4px 12px rgba(99, 102, 241, 0.3)'
|
||||
}}
|
||||
onClick={() => {
|
||||
if ((user?.credits || 0) < estimatedCredits) {
|
||||
message.warning('积分不足,请更换参数/充值积分');
|
||||
return;
|
||||
}
|
||||
handleNextStep(step.id);
|
||||
}}
|
||||
disabled={step.status !== 'completed' || ((user?.credits || 0) < estimatedCredits)}
|
||||
>
|
||||
下一步:生成视频提示词
|
||||
<span style={{ color: '#fff', marginLeft: 8 }}>
|
||||
预估积分:{estimatedCredits}
|
||||
</span>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
{/* 步骤4: 生成视频提示词 */}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button, Typography, Collapse, Space, Modal, Input, Table, message } from 'antd';
|
||||
import { Button, Typography, Collapse, Space, Modal, Input, Table, message, Tooltip } from 'antd';
|
||||
import { ArrowLeftOutlined, PlayCircleOutlined, CheckCircleOutlined, EditOutlined, DownloadOutlined, SettingOutlined, LayoutOutlined } from '@ant-design/icons';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { getShotReplicationList, removeDetail, removeone, removetwo, removethree, removefour, getEngine, updateShotImagePrompt, updateShotVideoPromptSchema } from '../api/index';
|
||||
import { getShotReplicationList, removeDetail, removeone, removetwo, removethree, removefour, getEngine, updateShotImagePrompt, updateShotVideoPromptSchema, calculateCredits } from '../api/index';
|
||||
import { useAuthStore } from '../store/useAuthStore';
|
||||
import VideoPromptSchemaEditor from '../components/VideoPromptSchemaEditor';
|
||||
import { validateVideoPromptSchemaByConfig } from '../utils/videoPromptSchema';
|
||||
import './css/InitialInfo.css';
|
||||
@@ -24,8 +25,11 @@ const buildMediaUrl = (url: string): string => {
|
||||
function InitialInfo() {
|
||||
const navigate = useNavigate();
|
||||
const { creatID } = useParams<{ creatID: string }>();
|
||||
const { user } = useAuthStore();
|
||||
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [creditCalculationData, setCreditCalculationData] = useState<any[]>([]);
|
||||
const [estimatedCredits, setEstimatedCredits] = useState<number>(0);
|
||||
const [promptText, setPromptText] = useState('');
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [currentType, setCurrentType] = useState<string>('image');
|
||||
@@ -128,7 +132,7 @@ function InitialInfo() {
|
||||
// 当apiSteps更新时,逆向遍历找到第一个已完成或失败的步骤并展开
|
||||
useEffect(() => {
|
||||
const completedFailedKeys = new Set<string>();
|
||||
|
||||
|
||||
activeKey.forEach(key => {
|
||||
const step = steps.find(s => String(s.childId) === key);
|
||||
if (step && (step.status === 'completed' || step.status === 'failed')) {
|
||||
@@ -190,12 +194,17 @@ function InitialInfo() {
|
||||
useEffect(() => {
|
||||
getEngine()
|
||||
.then((data: any) => {
|
||||
setEnginesele(data.engine || {});
|
||||
const filteredVideoEngines = (data.engine?.video || []).filter((engine: any) => engine.supportsUniversalReference !== false);
|
||||
const filteredImageEngines = (data.engine?.image || []).filter((engine: any) => engine.supportsUniversalReference !== false);
|
||||
setEnginesele({
|
||||
video: filteredVideoEngines,
|
||||
image: filteredImageEngines,
|
||||
});
|
||||
// 默认选中第一个视频引擎
|
||||
if (data.engine?.video && data.engine.video.length > 0) {
|
||||
setCountType(data.engine.video[0].id);
|
||||
if (filteredVideoEngines.length > 0) {
|
||||
setCountType(filteredVideoEngines[0].id);
|
||||
// 设置默认引擎参数
|
||||
const firstEngine = data.engine.video[0];
|
||||
const firstEngine = filteredVideoEngines[0];
|
||||
setEngineOptions({
|
||||
ratios: firstEngine.supportedRatios || ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9'],
|
||||
resolutions: firstEngine.supportedResolutions || ['480p', '720p', '1080p'],
|
||||
@@ -203,8 +212,8 @@ function InitialInfo() {
|
||||
});
|
||||
}
|
||||
// 默认选中第一个图片引擎
|
||||
if (data.engine?.image && data.engine.image.length > 0) {
|
||||
setImageEngineId(data.engine.image[0].id);
|
||||
if (filteredImageEngines.length > 0) {
|
||||
setImageEngineId(filteredImageEngines[0].id);
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
@@ -275,6 +284,57 @@ function InitialInfo() {
|
||||
}
|
||||
}, [steps]);
|
||||
|
||||
useEffect(() => {
|
||||
calculateCredits().then((data: any) => {
|
||||
setCreditCalculationData(data);
|
||||
}).catch(() => {});
|
||||
}, []);
|
||||
|
||||
const calculateEstimatedCredits = () => {
|
||||
let config: any = {};
|
||||
config = creditCalculationData.find((item: any) =>
|
||||
item.modelConfigId === countType &&
|
||||
item.genType === 'video' &&
|
||||
item.resolution === videoResolution
|
||||
);
|
||||
|
||||
if (!config) {
|
||||
config = {
|
||||
perSecondCredits: 2,
|
||||
baseCredits: 60,
|
||||
ratio: 1.3,
|
||||
inputVideoRatio: 1.3,
|
||||
inputVideoBaseCredits: 0,
|
||||
inputVideoPerSecondCredits: 15,
|
||||
inputImageRatio: 1,
|
||||
inputImageBaseCredits: 0,
|
||||
inputImagePerImageCredits: 0.0,
|
||||
};
|
||||
}
|
||||
|
||||
let total = (videoDuration * config.perSecondCredits + config.baseCredits) * config.ratio;
|
||||
|
||||
const inputVideoDuration = taskDetail?.videoGeneration?.inputMedia?.video?.duration || 0;
|
||||
if (inputVideoDuration > 0) {
|
||||
const inputVideoCost = ((config.inputVideoBaseCredits || 0) + (config.inputVideoPerSecondCredits || 0) * inputVideoDuration) * (config.inputVideoRatio || 1);
|
||||
total += inputVideoCost;
|
||||
}
|
||||
|
||||
const inputImageCount = taskDetail?.videoGeneration?.inputMedia?.image?.length || 0;
|
||||
if (inputImageCount > 0) {
|
||||
const inputImageCost = ((config.inputImageBaseCredits || 0) + (config.inputImagePerImageCredits || 0) * inputImageCount) * (config.inputImageRatio || 1);
|
||||
total += inputImageCost;
|
||||
}
|
||||
|
||||
setEstimatedCredits(Number(total.toFixed(2)));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (creditCalculationData.length > 0 && countType) {
|
||||
calculateEstimatedCredits();
|
||||
}
|
||||
}, [creditCalculationData, countType, videoDuration, videoResolution, taskDetail]);
|
||||
|
||||
const handleOpenModal = (prompt?: any, type?: string, stepId?: string | number, schemaConfigSnapshot?: any) => {
|
||||
setCurrentType(type || 'image');
|
||||
setEditingPromptStepId(stepId ? String(stepId) : '');
|
||||
@@ -1188,14 +1248,36 @@ function InitialInfo() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{ width: '100%', borderRadius: 10, background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)', border: 'none', height: 36, fontWeight: 500, boxShadow: '0 4px 12px rgba(99, 102, 241, 0.3)' }}
|
||||
onClick={() => { handleNextStep(step.id); }}
|
||||
disabled={step.status !== 'completed'}
|
||||
<Tooltip
|
||||
title={((user?.credits || 0) < estimatedCredits) ? '积分不足,请更换参数/充值积分' : ''}
|
||||
placement="top"
|
||||
>
|
||||
下一步:生成视频提示词
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{
|
||||
width: '100%',
|
||||
borderRadius: 10,
|
||||
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
|
||||
border: 'none',
|
||||
height: 36,
|
||||
fontWeight: 500,
|
||||
boxShadow: '0 4px 12px rgba(99, 102, 241, 0.3)'
|
||||
}}
|
||||
onClick={() => {
|
||||
if ((user?.credits || 0) < estimatedCredits) {
|
||||
message.warning('积分不足,请更换参数/充值积分');
|
||||
return;
|
||||
}
|
||||
handleNextStep(step.id);
|
||||
}}
|
||||
disabled={step.status !== 'completed' || ((user?.credits || 0) < estimatedCredits)}
|
||||
>
|
||||
下一步:生成视频提示词
|
||||
<span style={{ color: '#fff', marginLeft: 8 }}>
|
||||
预估积分:{estimatedCredits}
|
||||
</span>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
{/* 步骤4: 生成视频提示词 */}
|
||||
|
||||
Reference in New Issue
Block a user