Files
ylt_diy/public/static/js/history.js

474 lines
17 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

let historyStartDate = '';
let historyEndDate = '';
let historyStatus = '';
let historyConfigName = '';
let historyPageSize = 10;
// 每页显示条数变化
function onHistoryPageSizeChange() {
historyPageSize = parseInt(document.getElementById('history-page-size').value) || 10;
loadHistoryWithDate(1);
}
// 状态筛选变化
function onHistoryStatusChange() {
historyStatus = document.getElementById('history-status-filter').value;
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');
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) {
showToast('选中的记录都是生成失败的,无法下载');
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) {
showToast('下载失败: ' + 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) {
showToast(`没有符合条件的成功记录可导出。\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) {
showToast('下载失败: ' + error.message);
}
}
}
// 处理下载响应(两种模式共用)
async function handleDownloadResponse(response) {
if (!response.ok) {
try {
const result = await response.json();
showToast('下载失败: ' + (result.message || '未知错误'));
} catch (e) {
showToast('下载失败: 服务器返回错误');
}
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} 个(历史文件可能已被清理)`;
}
if (skipped > 0) {
msg += `\n跳过失败记录: ${skipped}`;
}
if (missing > 0 || skipped > 0) {
showToast(msg);
}
}
}
// 按日期查询
function queryHistoryByDate() {
const startDate = document.getElementById('history-start-date').value;
const endDate = document.getElementById('history-end-date').value;
const configNameInput = document.getElementById('history-config-name');
historyStartDate = startDate;
historyEndDate = endDate;
historyConfigName = configNameInput ? configNameInput.value.trim() : '';
loadHistoryWithDate(1);
}
// 清除筛选
function clearHistoryFilter() {
document.getElementById('history-status-filter').value = '';
document.getElementById('history-start-date').value = '';
document.getElementById('history-end-date').value = '';
const configNameInput = document.getElementById('history-config-name');
if (configNameInput) configNameInput.value = '';
historyStatus = '';
historyStartDate = '';
historyEndDate = '';
historyConfigName = '';
loadHistory(1);
}
// 带日期参数加载历史记录
// 渲染历史记录列表
function renderHistory(list) {
const tbody = document.getElementById('history-list');
if (!list || list.length === 0) {
tbody.innerHTML = '<tr><td colspan="9" class="empty">暂无历史记录</td></tr>';
return;
}
// 解析日期字符串(支持多种格式)
const parseDate = (dateStr) => {
if (!dateStr) return null;
// 尝试匹配 "2026-07-12" 格式
let match = dateStr.match(/(\d{4})-(\d{1,2})-(\d{1,2})/);
if (match) {
return {
year: parseInt(match[1]),
month: parseInt(match[2]),
day: parseInt(match[3])
};
}
// 尝试匹配 "Sun, 12 Jul 2026 00:00:00 GMT" 格式
match = dateStr.match(/(\d{1,2})\s+(\w+)\s+(\d{4})/);
if (match) {
const months = {
'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12
};
return {
year: parseInt(match[3]),
month: months[match[2]] || 1,
day: parseInt(match[1])
};
}
return null;
};
// 解析时间字符串(支持多种格式)
const parseTime = (timeStr) => {
if (!timeStr) return null;
// 尝试匹配 "2026-07-12 08:00:00" 格式
let match = timeStr.match(/(\d{4})-(\d{1,2})-(\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})/);
if (match) {
return {
year: match[1],
month: match[2].padStart(2, '0'),
day: match[3].padStart(2, '0'),
hour: match[4].padStart(2, '0'),
minute: match[5].padStart(2, '0'),
second: match[6].padStart(2, '0')
};
}
// 尝试匹配 "Sun, 12 Jul 2026 08:00:00 GMT" 格式
match = timeStr.match(/(\d{1,2})\s+(\w+)\s+(\d{4})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})/);
if (match) {
const months = {
'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04', 'May': '05', 'Jun': '06',
'Jul': '07', 'Aug': '08', 'Sep': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12'
};
return {
year: match[3],
month: months[match[2]] || '01',
day: match[1].padStart(2, '0'),
hour: match[4].padStart(2, '0'),
minute: match[5].padStart(2, '0'),
second: match[6].padStart(2, '0')
};
}
return null;
};
tbody.innerHTML = list.map(item => {
const statusText = item.status === 1 ? '成功' : '失败';
const statusClass = item.status === 1 ? 'status-success' : 'status-failed';
// 格式化报表日期为中文
let reportDate = '-';
const dateObj = parseDate(item.report_date);
if (dateObj) {
reportDate = `${dateObj.year}${dateObj.month}${dateObj.day}`;
} else if (item.report_date) {
reportDate = item.report_date;
}
// 格式化时间范围
let timeRange = '-';
const startObj = parseTime(item.start_time);
const endObj = parseTime(item.end_time);
if (startObj && endObj) {
const formatTimeObj = (obj) => `${obj.year}-${obj.month}-${obj.day} ${obj.hour}:${obj.minute}:${obj.second}`;
timeRange = `${formatTimeObj(startObj)}${formatTimeObj(endObj)}`;
} else if (item.start_time && item.end_time) {
timeRange = `${item.start_time}${item.end_time}`;
}
const configName = item.config_name || '-';
const splitValue = item.split_name || '-';
const totalOrders = item.total_orders || 0;
const totalDegree = item.total_degree ? parseFloat(item.total_degree).toFixed(3) : '0.000';
return `
<tr>
<td><input type="checkbox" class="history-checkbox" value="${item.id}" data-status="${item.status}" data-name="${configName}"></td>
<td>${reportDate}</td>
<td>${timeRange}</td>
<td>${configName}</td>
<td>${splitValue}</td>
<td>${totalOrders}</td>
<td>${totalDegree}</td>
<td><span class="${statusClass}">${statusText}</span></td>
<td>
${item.status === 1 && item.file_path ?
`<a href="/api/download?path=${encodeURIComponent(item.file_path)}&token=${encodeURIComponent(getToken())}" class="btn btn-sm btn-success">下载</a>` :
'-'}
<button class="btn btn-sm btn-danger" onclick="deleteHistory(${item.id})">删除</button>
</td>
</tr>
`;
}).join('');
}
// 渲染分页控件
function renderPagination(page, total, pageSize) {
const container = document.getElementById('history-pagination');
if (!container) return;
const totalPages = Math.ceil(total / pageSize);
if (totalPages <= 1) {
container.innerHTML = '';
return;
}
let html = '<div class="pagination">';
// 上一页
if (page > 1) {
html += `<button onclick="loadHistoryWithDate(${page - 1})">上一页</button>`;
}
// 页码最多显示7个页码
let startPage = Math.max(1, page - 3);
let endPage = Math.min(totalPages, startPage + 6);
if (endPage - startPage < 6) {
startPage = Math.max(1, endPage - 6);
}
if (startPage > 1) {
html += `<button onclick="loadHistoryWithDate(1)">1</button>`;
if (startPage > 2) {
html += `<span style="padding: 0 5px;">...</span>`;
}
}
for (let i = startPage; i <= endPage; i++) {
if (i === page) {
html += `<button class="active">${i}</button>`;
} else {
html += `<button onclick="loadHistoryWithDate(${i})">${i}</button>`;
}
}
if (endPage < totalPages) {
if (endPage < totalPages - 1) {
html += `<span style="padding: 0 5px;">...</span>`;
}
html += `<button onclick="loadHistoryWithDate(${totalPages})">${totalPages}</button>`;
}
// 下一页
if (page < totalPages) {
html += `<button onclick="loadHistoryWithDate(${page + 1})">下一页</button>`;
}
html += '</div>';
container.innerHTML = html;
}
// 加载历史记录(无日期筛选)
async function loadHistory(page = 1) {
loadHistoryWithDate(page);
}
async function loadHistoryWithDate(page) {
try {
// 同步配置名称搜索框的值(翻页时保留筛选条件)
const configNameInput = document.getElementById('history-config-name');
if (configNameInput) {
historyConfigName = configNameInput.value.trim();
}
let url = `/api/report/history?page=${page}&page_size=${historyPageSize}`;
if (historyStatus) url += `&status=${historyStatus}`;
if (historyStartDate) url += `&start_date=${historyStartDate}`;
if (historyEndDate) url += `&end_date=${historyEndDate}`;
if (historyConfigName) url += `&config_name=${encodeURIComponent(historyConfigName)}`;
const response = await fetch(url);
const result = await response.json();
if (result.success) {
renderHistory(result.data.list);
renderPagination(result.data.page, result.data.total, result.data.page_size);
} else {
showToast('加载失败: ' + (result.error || result.message || '未知错误'));
}
} catch (error) {
showToast('加载失败: ' + error.message);
}
}
// 全选/取消全选历史记录
function toggleSelectAllHistory() {
const selectAllCheckbox = document.getElementById('select-all-history');
const checkboxes = document.querySelectorAll('#history-list input[type="checkbox"]');
checkboxes.forEach(cb => {
cb.checked = selectAllCheckbox.checked;
});
}
// 删除单条历史记录
async function deleteHistory(id) {
if (!confirm('确定要删除这条历史记录吗?对应的报表文件也会被删除。')) {
return;
}
try {
const response = await fetch('/api/report/history/batch-delete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: [id] })
});
const result = await response.json();
if (result.success) {
showToast('删除成功');
loadHistoryWithDate();
} else {
showToast('删除失败: ' + result.message);
}
} catch (error) {
showToast('删除失败: ' + error.message);
}
}
// 批量删除历史记录
async function batchDeleteHistory() {
const checkboxes = document.querySelectorAll('.history-checkbox:checked');
if (checkboxes.length === 0) {
showToast('请至少选择一条记录');
return;
}
if (!confirm(`确定要删除选中的 ${checkboxes.length} 条历史记录吗?对应的报表文件也会被删除。`)) {
return;
}
const ids = Array.from(checkboxes).map(cb => parseInt(cb.value));
try {
const response = await fetch('/api/report/history/batch-delete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: ids })
});
const result = await response.json();
if (result.success) {
showToast(result.message);
loadHistoryWithDate();
} else {
showToast('删除失败: ' + result.message);
}
} catch (error) {
showToast('删除失败: ' + error.message);
}
}
// 批量导出当前筛选条件下的所有记录 - 已合并到 batchDownloadHistory 函数
// 该函数已被移除,功能整合到统一的 batchDownloadHistory 中