feat(snapshot): 进度精度升级 — Float百分比 + MB消息存DB
- schema: progress Int→Float,新增 progressMsg 字段 - PG handler: 百分比保留2位小数(toFixed(2)),不再 Math.floor - orchestrator: 每2秒写DB时同时写 progressMsg (含MB信息) - 前端: 百分比显示 toFixed(1),message 优先读 progressMsg 效果: 113GB库每次轮询进度条和MB数都有变化,不再卡在整数百分比 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9cbc0ba580
commit
8855491637
|
|
@ -30,7 +30,8 @@ model SnapshotDetail {
|
|||
taskId String
|
||||
target String
|
||||
status String @default("PENDING")
|
||||
progress Int @default(0)
|
||||
progress Float @default(0)
|
||||
progressMsg String?
|
||||
fileSize BigInt @default(0)
|
||||
fileName String?
|
||||
error String?
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ export class SnapshotOrchestratorService implements OnModuleInit {
|
|||
const now = Date.now();
|
||||
if (now - lastDbWriteTime >= 2000) {
|
||||
lastDbWriteTime = now;
|
||||
this.repo.updateDetailProgress(taskId, target, percent).catch(() => {});
|
||||
this.repo.updateDetailProgress(taskId, target, percent, msg).catch(() => {});
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ export class PostgresBackupHandler implements BackupHandler {
|
|||
if (readMB > lastReportedMB) {
|
||||
lastReportedMB = readMB;
|
||||
const totalMB = Math.floor(totalSize / (1024 * 1024));
|
||||
const percent = Math.min(99, Math.floor((bytesRead / totalSize) * 100));
|
||||
const percent = Math.min(99, parseFloat(((bytesRead / totalSize) * 100).toFixed(2)));
|
||||
onProgress(percent, `PostgreSQL 备份中... ${readMB}MB / ~${totalMB}MB`);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -79,14 +79,16 @@ export class SnapshotRepository {
|
|||
return this.prisma.snapshotDetail.update({ where: { id: detail.id }, data });
|
||||
}
|
||||
|
||||
async updateDetailProgress(taskId: string, target: string, progress: number) {
|
||||
async updateDetailProgress(taskId: string, target: string, progress: number, progressMsg?: string) {
|
||||
const detail = await this.prisma.snapshotDetail.findFirst({
|
||||
where: { taskId, target },
|
||||
});
|
||||
if (!detail) return;
|
||||
const data: Record<string, unknown> = { progress };
|
||||
if (progressMsg !== undefined) data.progressMsg = progressMsg;
|
||||
return this.prisma.snapshotDetail.update({
|
||||
where: { id: detail.id },
|
||||
data: { progress },
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ export default function SnapshotsPage() {
|
|||
{BACKUP_TARGET_LABELS[p.target] || p.target}
|
||||
</span>
|
||||
<span style={{ color: statusColor(p.status.toUpperCase() as SnapshotStatus) }}>
|
||||
{p.status === 'completed' ? '100%' : p.status === 'failed' ? '失败' : `${p.percent}%`}
|
||||
{p.status === 'completed' ? '100%' : p.status === 'failed' ? '失败' : `${p.percent.toFixed(1)}%`}
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.progressBar}>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export function useSnapshotPolling(taskId: string | null): UseSnapshotPollingRet
|
|||
: d.status === 'COMPLETED'
|
||||
? '完成'
|
||||
: d.status === 'RUNNING'
|
||||
? `备份中... ${d.progress}%`
|
||||
? (d.progressMsg || `备份中... ${d.progress.toFixed(1)}%`)
|
||||
: '等待中',
|
||||
status: statusMap[d.status] || 'pending',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export interface SnapshotDetail {
|
|||
target: BackupTarget;
|
||||
status: SnapshotStatus;
|
||||
progress: number;
|
||||
progressMsg: string | null;
|
||||
fileSize: string;
|
||||
fileName: string | null;
|
||||
error: string | null;
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ export default function SnapshotsPage() {
|
|||
: 'text-blue-500'
|
||||
}
|
||||
>
|
||||
{p.status === 'completed' ? '100%' : p.status === 'failed' ? '失败' : `${p.percent}%`}
|
||||
{p.status === 'completed' ? '100%' : p.status === 'failed' ? '失败' : `${p.percent.toFixed(1)}%`}
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-2 overflow-hidden rounded-full bg-muted">
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export function useSnapshotPolling(taskId: string | null): UseSnapshotPollingRet
|
|||
: d.status === 'COMPLETED'
|
||||
? '完成'
|
||||
: d.status === 'RUNNING'
|
||||
? `备份中... ${d.progress}%`
|
||||
? (d.progressMsg || `备份中... ${d.progress.toFixed(1)}%`)
|
||||
: '等待中',
|
||||
status: statusMap[d.status] || 'pending',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export interface SnapshotDetail {
|
|||
target: BackupTarget;
|
||||
status: SnapshotStatus;
|
||||
progress: number;
|
||||
progressMsg: string | null;
|
||||
fileSize: string;
|
||||
fileName: string | null;
|
||||
error: string | null;
|
||||
|
|
|
|||
Loading…
Reference in New Issue