fix(admin-web): 批量下载完成后直接触发浏览器另存为对话框

- 创建任务后自动轮询等待完成
- 完成后使用 <a download> 触发浏览器下载对话框
- 按钮显示打包进度
- 打包期间禁用按钮防止重复点击

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-02-05 23:59:04 -08:00
parent 15019206c8
commit 8b7872d205
1 changed files with 86 additions and 18 deletions

View File

@ -139,9 +139,42 @@ export default function ContractsPage() {
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 () => {
setBatchDownloading(true);
setBatchProgress(0);
try {
toast.info('正在准备批量下载,请稍候...');
const result = await contractService.createBatchDownload({
filters: {
signedAfter: filters.signedAfter || undefined,
@ -151,15 +184,30 @@ export default function ContractsPage() {
},
});
toast.success(`批量下载任务已创建,任务号: ${result.taskNo}`);
// 轮询等待任务完成
const downloadUrl = await pollTaskUntilComplete(result.taskNo);
// 保存当前时间作为最后下载时间
const now = new Date().toISOString();
localStorage.setItem('contract_last_download_time', now);
setLastDownloadTime(now);
if (downloadUrl) {
// 创建隐藏的 a 标签触发浏览器下载(会弹出另存为对话框)
const link = document.createElement('a');
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) {
console.error('创建批量下载任务失败:', error);
toast.error('创建批量下载任务失败');
console.error('批量下载失败:', error);
toast.error('批量下载失败,请重试');
} finally {
setBatchDownloading(false);
setBatchProgress(0);
}
};
@ -170,7 +218,12 @@ export default function ContractsPage() {
return;
}
setBatchDownloading(true);
setBatchProgress(0);
try {
toast.info('正在准备增量下载,请稍候...');
const result = await contractService.createBatchDownload({
filters: {
signedAfter: lastDownloadTime,
@ -179,15 +232,30 @@ export default function ContractsPage() {
},
});
toast.success(`增量下载任务已创建,任务号: ${result.taskNo}`);
// 轮询等待任务完成
const downloadUrl = await pollTaskUntilComplete(result.taskNo);
// 更新最后下载时间
const now = new Date().toISOString();
localStorage.setItem('contract_last_download_time', now);
setLastDownloadTime(now);
if (downloadUrl) {
// 创建隐藏的 a 标签触发浏览器下载(会弹出另存为对话框)
const link = document.createElement('a');
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) {
console.error('创建增量下载任务失败:', error);
toast.error('创建增量下载任务失败');
console.error('增量下载失败:', error);
toast.error('增量下载失败,请重试');
} finally {
setBatchDownloading(false);
setBatchProgress(0);
}
};
@ -295,11 +363,11 @@ export default function ContractsPage() {
</div>
<div className={styles.contracts__actions}>
<Button variant="primary" onClick={handleBatchDownload}>
ZIP
<Button variant="primary" onClick={handleBatchDownload} disabled={batchDownloading}>
{batchDownloading ? `打包中 ${batchProgress}%...` : '批量下载 ZIP'}
</Button>
{lastDownloadTime && (
<Button variant="outline" onClick={handleIncrementalDownload}>
<Button variant="outline" onClick={handleIncrementalDownload} disabled={batchDownloading}>
: {new Date(lastDownloadTime).toLocaleString('zh-CN')}
</Button>
)}