fix: v0.10.2 — admin重新编辑隐藏/frozen防负数/进度条刷新保持/navigate修正
- admin资产页视频详情隐藏「重新编辑」按钮(hideReEdit prop)
- 团管重新编辑跳转修正:navigate('/') → navigate('/app')
- _release_freeze 防止 frozen_amount 变负数
- 生成进度条用 sessionStorage 持久化,刷新页面后从之前位置继续
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ef2212e345
commit
699a390f45
@ -320,7 +320,10 @@ def _release_freeze(record):
|
||||
frozen = record.frozen_amount
|
||||
with transaction.atomic():
|
||||
locked_team = Team.objects.select_for_update().get(pk=team.pk)
|
||||
locked_team.frozen_amount = F('frozen_amount') - frozen
|
||||
# 防止 frozen_amount 变负
|
||||
actual_release = min(frozen, locked_team.frozen_amount)
|
||||
if actual_release > 0:
|
||||
locked_team.frozen_amount = F('frozen_amount') - actual_release
|
||||
locked_team.total_seconds_used = F('total_seconds_used') - record.seconds_consumed
|
||||
locked_team.save(update_fields=['frozen_amount', 'total_seconds_used'])
|
||||
record.frozen_amount = 0
|
||||
|
||||
@ -13,13 +13,14 @@ interface Props {
|
||||
onReEdit?: (id: string) => void;
|
||||
onRegenerate?: (id: string) => void;
|
||||
onDelete?: (id: string) => void;
|
||||
hideReEdit?: boolean;
|
||||
onPrev?: () => void;
|
||||
onNext?: () => void;
|
||||
hasPrev?: boolean;
|
||||
hasNext?: boolean;
|
||||
}
|
||||
|
||||
export function VideoDetailModal({ task, onClose, onReEdit, onRegenerate, onDelete, onPrev, onNext, hasPrev, hasNext }: Props) {
|
||||
export function VideoDetailModal({ task, onClose, onReEdit, onRegenerate, onDelete, onPrev, onNext, hasPrev, hasNext, hideReEdit }: Props) {
|
||||
const navigate = useNavigate();
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const videoContainerRef = useRef<HTMLDivElement>(null);
|
||||
@ -230,7 +231,7 @@ export function VideoDetailModal({ task, onClose, onReEdit, onRegenerate, onDele
|
||||
}
|
||||
}
|
||||
onClose();
|
||||
navigate('/');
|
||||
navigate('/app');
|
||||
}
|
||||
};
|
||||
|
||||
@ -497,7 +498,7 @@ export function VideoDetailModal({ task, onClose, onReEdit, onRegenerate, onDele
|
||||
</div>
|
||||
|
||||
{/* Re-edit button above info bar */}
|
||||
<div style={{ padding: '0 20px 12px', borderBottom: '1px solid rgba(255,255,255,0.08)' }}>
|
||||
{!hideReEdit && <div style={{ padding: '0 20px 12px', borderBottom: '1px solid rgba(255,255,255,0.08)' }}>
|
||||
<button className={styles.cardBtn} onClick={handleReEdit} style={{ width: '100%', justifyContent: 'center' }}>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
|
||||
@ -505,7 +506,7 @@ export function VideoDetailModal({ task, onClose, onReEdit, onRegenerate, onDele
|
||||
</svg>
|
||||
重新编辑
|
||||
</button>
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
{/* Fixed bottom: info bar + actions card */}
|
||||
<div className={styles.infoPanelBottom}>
|
||||
|
||||
@ -229,6 +229,7 @@ export function AdminAssetsPage() {
|
||||
<VideoDetailModal
|
||||
task={detailTask}
|
||||
onClose={() => setDetailTask(null)}
|
||||
hideReEdit
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -75,7 +75,7 @@ function backendToFrontend(bt: BackendTask): GenerationTask {
|
||||
duration: bt.duration as GenerationTask['duration'],
|
||||
references,
|
||||
status: mapStatus(bt.status),
|
||||
progress: mapProgress(bt.status),
|
||||
progress: bt.status === 'processing' ? Number(sessionStorage.getItem(`progress_${bt.task_id}`) || mapProgress(bt.status)) : mapProgress(bt.status),
|
||||
resultUrl: bt.result_url || undefined,
|
||||
errorMessage: mapErrorMessage(bt.error_message),
|
||||
createdAt: new Date(bt.created_at).getTime(),
|
||||
@ -105,7 +105,9 @@ function ensureSmoothProgress() {
|
||||
if (t.status !== 'generating') return t;
|
||||
// Decelerate: fast at start, slow near end
|
||||
const increment = t.progress < 30 ? 2 : t.progress < 60 ? 1 : 0.5;
|
||||
return { ...t, progress: Math.min(t.progress + increment, 95) };
|
||||
const newProgress = Math.min(t.progress + increment, 95);
|
||||
if (t.taskId) sessionStorage.setItem(`progress_${t.taskId}`, String(newProgress));
|
||||
return { ...t, progress: newProgress };
|
||||
}),
|
||||
}));
|
||||
}, 2000);
|
||||
@ -146,6 +148,7 @@ function startPolling(taskId: string, frontendId: string) {
|
||||
|
||||
if (newStatus === 'completed' || newStatus === 'failed') {
|
||||
pollTimers.delete(frontendId);
|
||||
sessionStorage.removeItem(`progress_${taskId}`);
|
||||
if (newStatus === 'completed') {
|
||||
useAuthStore.getState().fetchUserInfo();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user