feat: 视频生成使用系统素材时每个额外收取 2 积分
This commit is contained in:
@@ -378,7 +378,14 @@ export function useVideoGeneration({
|
||||
};
|
||||
});
|
||||
}
|
||||
const actualVideoPoints = Math.ceil(totalAudioDuration) * videoMultiplier;
|
||||
const baseVideoPoints = Math.ceil(totalAudioDuration) * videoMultiplier;
|
||||
// 系统素材额外收费:每个空镜使用的系统素材额外 2 积分
|
||||
const systemMaterialCount = shots.filter((s: ScriptShot) => {
|
||||
if (s.type !== 'empty_shot') return false;
|
||||
const matched = materialMatchMap[String(s.id)];
|
||||
return matched && (matched.url.startsWith('http://') || matched.url.startsWith('https://'));
|
||||
}).length;
|
||||
const actualVideoPoints = baseVideoPoints + systemMaterialCount * 2;
|
||||
await pointsApi.consumePoints({
|
||||
points: actualVideoPoints,
|
||||
sourceType: 'video',
|
||||
|
||||
@@ -60,23 +60,6 @@ export default function VideoGeneration() {
|
||||
|
||||
const dubbingAudioDuration = useProjectStore(state => state.dubbingAudioDuration);
|
||||
|
||||
// 视频生成积分:统一用完整配音音频时长作为唯一口径(与后端预检、实际扣费保持一致)
|
||||
const estimatedVideoPoints = useMemo(() => {
|
||||
// 优先使用已保存的配音音频实际时长,确保预估 = 实际扣费
|
||||
if (dubbingAudioDuration && dubbingAudioDuration > 0) {
|
||||
return Math.ceil(dubbingAudioDuration) * videoMultiplier;
|
||||
}
|
||||
// 降级:按分镜 actualDuration 累加(配音后已更新)
|
||||
const totalDur = shots.reduce((sum, shot) => {
|
||||
if (shot.actualDuration && shot.actualDuration > 0) {
|
||||
return sum + shot.actualDuration;
|
||||
}
|
||||
const durStr = typeof shot.duration === 'string' ? shot.duration : '5s';
|
||||
return sum + parseFloat(durStr.replace(/[^0-9.]/g, '') || '0');
|
||||
}, 0);
|
||||
return Math.ceil(totalDur) * videoMultiplier;
|
||||
}, [shots, videoMultiplier, dubbingAudioDuration]);
|
||||
|
||||
const [activeScene, setActiveScene] = useState<number>(1);
|
||||
|
||||
// 控制右侧预览区显示完整视频还是镜头素材
|
||||
@@ -149,6 +132,32 @@ export default function VideoGeneration() {
|
||||
setMaterialMatchMap,
|
||||
} = useEmptyShotMaterials(shots, projectId);
|
||||
|
||||
// 视频生成积分:统一用完整配音音频时长作为唯一口径(与后端预检、实际扣费保持一致)
|
||||
const estimatedVideoPoints = useMemo(() => {
|
||||
// 优先使用已保存的配音音频实际时长,确保预估 = 实际扣费
|
||||
let basePoints = 0;
|
||||
if (dubbingAudioDuration && dubbingAudioDuration > 0) {
|
||||
basePoints = Math.ceil(dubbingAudioDuration) * videoMultiplier;
|
||||
} else {
|
||||
// 降级:按分镜 actualDuration 累加(配音后已更新)
|
||||
const totalDur = shots.reduce((sum, shot) => {
|
||||
if (shot.actualDuration && shot.actualDuration > 0) {
|
||||
return sum + shot.actualDuration;
|
||||
}
|
||||
const durStr = typeof shot.duration === 'string' ? shot.duration : '5s';
|
||||
return sum + parseFloat(durStr.replace(/[^0-9.]/g, '') || '0');
|
||||
}, 0);
|
||||
basePoints = Math.ceil(totalDur) * videoMultiplier;
|
||||
}
|
||||
// 系统素材额外收费:每个空镜使用的系统素材额外 2 积分
|
||||
const systemMaterialCount = shots.filter((s) => {
|
||||
if (s.type !== 'empty_shot') return false;
|
||||
const matched = materialMatchMap[String(s.id)];
|
||||
return matched && (matched.url.startsWith('http://') || matched.url.startsWith('https://'));
|
||||
}).length;
|
||||
return basePoints + systemMaterialCount * 2;
|
||||
}, [shots, videoMultiplier, dubbingAudioDuration, materialMatchMap]);
|
||||
|
||||
// 同步 activeScene 与 shots 数据
|
||||
useEffect(() => {
|
||||
if (shots.length > 0 && !shots.find((s) => Number(s.id) === activeScene)) {
|
||||
|
||||
Reference in New Issue
Block a user