fix(admin-web): 批量下载完成后直接触发浏览器另存为对话框
- 创建任务后自动轮询等待完成 - 完成后使用 <a download> 触发浏览器下载对话框 - 按钮显示打包进度 - 打包期间禁用按钮防止重复点击 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
15019206c8
commit
8b7872d205
|
|
@ -139,9 +139,42 @@ export default function ContractsPage() {
|
||||||
window.open(downloadUrl, '_blank');
|
window.open(downloadUrl, '_blank');
|
||||||
};
|
};
|
||||||
|
|
||||||
// 批量下载(创建下载任务)
|
// 批量下载状态
|
||||||
|
const [batchDownloading, setBatchDownloading] = useState(false);
|
||||||
|
const [batchProgress, setBatchProgress] = useState(0);
|
||||||
|
|
||||||
|
// 轮询任务状态直到完成
|
||||||
|
const pollTaskUntilComplete = async (taskNo: string): Promise<string | null> => {
|
||||||
|
const maxAttempts = 120; // 最多轮询2分钟
|
||||||
|
for (let i = 0; i < maxAttempts; i++) {
|
||||||
|
try {
|
||||||
|
const status = await contractService.getBatchDownloadStatus(taskNo);
|
||||||
|
setBatchProgress(status.progress);
|
||||||
|
|
||||||
|
if (status.status === 'COMPLETED' && status.resultFileUrl) {
|
||||||
|
return status.resultFileUrl;
|
||||||
|
} else if (status.status === 'FAILED') {
|
||||||
|
throw new Error('任务处理失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待1秒后继续轮询
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('查询任务状态失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error('任务处理超时');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 批量下载(创建下载任务并等待完成后自动下载)
|
||||||
const handleBatchDownload = async () => {
|
const handleBatchDownload = async () => {
|
||||||
|
setBatchDownloading(true);
|
||||||
|
setBatchProgress(0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
toast.info('正在准备批量下载,请稍候...');
|
||||||
|
|
||||||
const result = await contractService.createBatchDownload({
|
const result = await contractService.createBatchDownload({
|
||||||
filters: {
|
filters: {
|
||||||
signedAfter: filters.signedAfter || undefined,
|
signedAfter: filters.signedAfter || undefined,
|
||||||
|
|
@ -151,15 +184,30 @@ export default function ContractsPage() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
toast.success(`批量下载任务已创建,任务号: ${result.taskNo}`);
|
// 轮询等待任务完成
|
||||||
|
const downloadUrl = await pollTaskUntilComplete(result.taskNo);
|
||||||
|
|
||||||
// 保存当前时间作为最后下载时间
|
if (downloadUrl) {
|
||||||
const now = new Date().toISOString();
|
// 创建隐藏的 a 标签触发浏览器下载(会弹出另存为对话框)
|
||||||
localStorage.setItem('contract_last_download_time', now);
|
const link = document.createElement('a');
|
||||||
setLastDownloadTime(now);
|
link.href = downloadUrl;
|
||||||
|
link.download = ''; // 设置 download 属性触发下载
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
toast.success('请选择保存位置');
|
||||||
|
|
||||||
|
// 保存当前时间作为最后下载时间
|
||||||
|
const now = new Date().toISOString();
|
||||||
|
localStorage.setItem('contract_last_download_time', now);
|
||||||
|
setLastDownloadTime(now);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('创建批量下载任务失败:', error);
|
console.error('批量下载失败:', error);
|
||||||
toast.error('创建批量下载任务失败');
|
toast.error('批量下载失败,请重试');
|
||||||
|
} finally {
|
||||||
|
setBatchDownloading(false);
|
||||||
|
setBatchProgress(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -170,7 +218,12 @@ export default function ContractsPage() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setBatchDownloading(true);
|
||||||
|
setBatchProgress(0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
toast.info('正在准备增量下载,请稍候...');
|
||||||
|
|
||||||
const result = await contractService.createBatchDownload({
|
const result = await contractService.createBatchDownload({
|
||||||
filters: {
|
filters: {
|
||||||
signedAfter: lastDownloadTime,
|
signedAfter: lastDownloadTime,
|
||||||
|
|
@ -179,15 +232,30 @@ export default function ContractsPage() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
toast.success(`增量下载任务已创建,任务号: ${result.taskNo}`);
|
// 轮询等待任务完成
|
||||||
|
const downloadUrl = await pollTaskUntilComplete(result.taskNo);
|
||||||
|
|
||||||
// 更新最后下载时间
|
if (downloadUrl) {
|
||||||
const now = new Date().toISOString();
|
// 创建隐藏的 a 标签触发浏览器下载(会弹出另存为对话框)
|
||||||
localStorage.setItem('contract_last_download_time', now);
|
const link = document.createElement('a');
|
||||||
setLastDownloadTime(now);
|
link.href = downloadUrl;
|
||||||
|
link.download = ''; // 设置 download 属性触发下载
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
toast.success('请选择保存位置');
|
||||||
|
|
||||||
|
// 更新最后下载时间
|
||||||
|
const now = new Date().toISOString();
|
||||||
|
localStorage.setItem('contract_last_download_time', now);
|
||||||
|
setLastDownloadTime(now);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('创建增量下载任务失败:', error);
|
console.error('增量下载失败:', error);
|
||||||
toast.error('创建增量下载任务失败');
|
toast.error('增量下载失败,请重试');
|
||||||
|
} finally {
|
||||||
|
setBatchDownloading(false);
|
||||||
|
setBatchProgress(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -295,11 +363,11 @@ export default function ContractsPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.contracts__actions}>
|
<div className={styles.contracts__actions}>
|
||||||
<Button variant="primary" onClick={handleBatchDownload}>
|
<Button variant="primary" onClick={handleBatchDownload} disabled={batchDownloading}>
|
||||||
批量下载 ZIP
|
{batchDownloading ? `打包中 ${batchProgress}%...` : '批量下载 ZIP'}
|
||||||
</Button>
|
</Button>
|
||||||
{lastDownloadTime && (
|
{lastDownloadTime && (
|
||||||
<Button variant="outline" onClick={handleIncrementalDownload}>
|
<Button variant="outline" onClick={handleIncrementalDownload} disabled={batchDownloading}>
|
||||||
增量下载(上次: {new Date(lastDownloadTime).toLocaleString('zh-CN')})
|
增量下载(上次: {new Date(lastDownloadTime).toLocaleString('zh-CN')})
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue