修复历史记录批量下载的bug

This commit is contained in:
2026-08-02 09:38:48 +08:00
parent 9516078b1d
commit 17b7cd27b9
3 changed files with 279 additions and 147 deletions

View File

@@ -16,59 +16,153 @@ function onHistoryStatusChange() {
loadHistoryWithDate(1);
}
// 批量下载历史记录
// 统一的批量下载:勾选时下载选中记录,未勾选时按筛选条件下载全部匹配记录
async function batchDownloadHistory() {
// 同步当前筛选条件
const configNameInput = document.getElementById('history-config-name');
if (configNameInput) {
historyConfigName = configNameInput.value.trim();
}
historyStatus = document.getElementById('history-status-filter').value;
historyStartDate = document.getElementById('history-start-date').value;
historyEndDate = document.getElementById('history-end-date').value;
const checkboxes = document.querySelectorAll('.history-checkbox:checked');
if (checkboxes.length === 0) {
alert('请至少选择一条记录');
const hasSelection = checkboxes.length > 0;
if (hasSelection) {
// 模式1下载勾选的记录
const ids = Array.from(checkboxes).map(cb => parseInt(cb.value));
const failedCount = Array.from(checkboxes).filter(cb => cb.dataset.status !== '1').length;
const successCount = checkboxes.length - failedCount;
if (successCount === 0) {
alert('选中的记录都是生成失败的,无法下载');
return;
}
if (failedCount > 0) {
if (!confirm(`选中的 ${checkboxes.length} 条记录中有 ${failedCount} 条是生成失败的,无法下载。\n是否打包下载成功的 ${successCount} 条?`)) {
return;
}
} else {
if (!confirm(`确定要下载选中的 ${successCount} 条报表吗?`)) {
return;
}
}
try {
const response = await fetch('/api/download/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: ids })
});
await handleDownloadResponse(response);
} catch (error) {
alert('下载失败: ' + error.message);
}
} else {
// 模式2按筛选条件下载全部匹配的成功记录
const filterDescParts = [];
if (historyConfigName) filterDescParts.push(`配置名称含"${historyConfigName}"`);
if (historyStartDate) filterDescParts.push(`开始日期 ${historyStartDate}`);
if (historyEndDate) filterDescParts.push(`结束日期 ${historyEndDate}`);
const filterDesc = filterDescParts.length > 0 ? filterDescParts.join('') : '全部记录';
// 查询匹配数量
let matchCount = 0;
let dateRange = '';
try {
const countResponse = await fetch('/api/download/batch-filter-count', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
config_name: historyConfigName,
start_date: historyStartDate,
end_date: historyEndDate
})
});
const countResult = await countResponse.json();
if (countResult.success) {
matchCount = countResult.data.total || 0;
if (countResult.data.min_date && countResult.data.max_date) {
dateRange = `\n报表日期范围: ${countResult.data.min_date}${countResult.data.max_date}`;
}
}
} catch (e) {
console.error('查询导出数量失败:', e);
}
if (matchCount === 0) {
alert(`没有符合条件的成功记录可导出。\n筛选条件: ${filterDesc}`);
return;
}
if (!confirm(`未选中任何记录,将按当前筛选条件导出全部匹配的成功记录。\n\n筛选条件: ${filterDesc}\n匹配记录数: ${matchCount}${dateRange}\n\n注意: 仅导出生成成功的报表。\n是否继续?`)) {
return;
}
try {
const response = await fetch('/api/download/batch-filter', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
config_name: historyConfigName,
start_date: historyStartDate,
end_date: historyEndDate,
status: historyStatus
})
});
await handleDownloadResponse(response);
} catch (error) {
alert('下载失败: ' + error.message);
}
}
}
// 处理下载响应(两种模式共用)
async function handleDownloadResponse(response) {
if (!response.ok) {
try {
const result = await response.json();
alert('下载失败: ' + (result.message || '未知错误'));
} catch (e) {
alert('下载失败: 服务器返回错误');
}
return;
}
const ids = Array.from(checkboxes).map(cb => parseInt(cb.value));
// 检查是否有生成失败的记录
const failedCount = Array.from(checkboxes).filter(cb => cb.dataset.status !== '1').length;
const successCount = checkboxes.length - failedCount;
if (successCount === 0) {
alert('选中的记录都是生成失败的,无法下载');
return;
}
if (failedCount > 0) {
if (!confirm(`选中的 ${checkboxes.length} 条记录中有 ${failedCount} 条是生成失败的,无法下载。\n是否打包下载成功的 ${successCount} 条?`)) {
return;
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
const timestamp = new Date().toISOString().slice(0, 19).replace(/[-T:]/g, '');
a.download = `批量下载_${timestamp}.zip`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
// 显示统计信息(如果有)
const totalMatched = response.headers.get('X-Total-Matched');
const filesZipped = response.headers.get('X-Files-Zipped');
const filesMissing = response.headers.get('X-Files-Missing');
const skippedFailed = response.headers.get('X-Skipped-Failed');
if (totalMatched && filesZipped) {
const missing = filesMissing ? parseInt(filesMissing) : 0;
const skipped = skippedFailed ? parseInt(skippedFailed) : 0;
let msg = `下载完成!\n`;
msg += `匹配记录: ${totalMatched}\n`;
msg += `成功打包: ${filesZipped} 个文件`;
if (missing > 0) {
msg += `\n缺失文件: ${filesMissing} 个(历史文件可能已被清理)`;
}
}
try {
const response = await fetch('/api/download/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: ids })
});
if (response.ok) {
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
const timestamp = new Date().toISOString().slice(0, 19).replace(/[-T:]/g, '');
a.download = `批量下载_${timestamp}.zip`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
} else {
try {
const result = await response.json();
alert('下载失败: ' + (result.message || '未知错误'));
} catch (e) {
alert('下载失败: 服务器返回错误');
}
if (skipped > 0) {
msg += `\n跳过失败记录: ${skipped}`;
}
if (missing > 0 || skipped > 0) {
alert(msg);
}
} catch (error) {
alert('下载失败: ' + error.message);
}
}
@@ -375,69 +469,5 @@ async function batchDeleteHistory() {
}
}
// 批量导出当前筛选条件下的所有记录(与搜索条件同步)
async function batchDownloadFilteredHistory() {
// 同步当前筛选条件
const configNameInput = document.getElementById('history-config-name');
if (configNameInput) {
historyConfigName = configNameInput.value.trim();
}
historyStatus = document.getElementById('history-status-filter').value;
historyStartDate = document.getElementById('history-start-date').value;
historyEndDate = document.getElementById('history-end-date').value;
// 构建筛选条件描述
const filterDescParts = [];
if (historyStatus) {
filterDescParts.push(historyStatus === '1' ? '成功' : '失败');
}
if (historyConfigName) {
filterDescParts.push(`配置名称含"${historyConfigName}"`);
}
if (historyStartDate) {
filterDescParts.push(`开始日期 ${historyStartDate}`);
}
if (historyEndDate) {
filterDescParts.push(`结束日期 ${historyEndDate}`);
}
const filterDesc = filterDescParts.length > 0 ? filterDescParts.join('') : '全部记录';
if (!confirm(`将导出符合当前筛选条件的所有成功记录(${filterDesc})。\n注意:仅导出生成成功的报表。\n是否继续?`)) {
return;
}
try {
const response = await fetch('/api/download/batch-filter', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
config_name: historyConfigName,
start_date: historyStartDate,
end_date: historyEndDate,
status: historyStatus
})
});
if (response.ok) {
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
const timestamp = new Date().toISOString().slice(0, 19).replace(/[-T:]/g, '');
a.download = `批量导出_${timestamp}.zip`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
} else {
try {
const result = await response.json();
alert('导出失败: ' + (result.message || '未知错误'));
} catch (e) {
alert('导出失败: 服务器返回错误');
}
}
} catch (error) {
alert('导出失败: ' + error.message);
}
}
// 批量导出当前筛选条件下的所有记录 - 已合并到 batchDownloadHistory 函数
// 该函数已被移除,功能整合到统一的 batchDownloadHistory 中