const Export = (() => {
async function render() {
setTimeout(bindEvents, 0);
return `
📤 数据导出
`;
}
function bindEvents() {
const typeSelect = document.getElementById('export-type');
const excelBtn = document.getElementById('export-excel');
const pdfBtn = document.getElementById('export-pdf');
// 类型改变时更新预览
if (typeSelect) {
typeSelect.addEventListener('change', updatePreview);
// 初始加载预览
updatePreview();
}
// Excel导出
if (excelBtn) {
excelBtn.addEventListener('click', async () => {
const type = typeSelect.value;
await exportData(type, 'excel');
});
}
// PDF导出
if (pdfBtn) {
pdfBtn.addEventListener('click', async () => {
const type = typeSelect.value;
await exportData(type, 'pdf');
});
}
}
async function updatePreview() {
const type = document.getElementById('export-type').value;
const preview = document.getElementById('export-preview');
try {
preview.innerHTML = '加载中...
';
let data;
switch(type) {
case 'stats':
data = await API.listStats();
renderStatsPreview(data.list || []);
break;
case 'mac':
data = await API.listMac();
renderMacPreview(data.list || []);
break;
case 'repairs':
data = await API.listRepairs();
renderRepairsPreview(data.list || []);
break;
case 'defects':
data = await API.listDefects();
renderDefectsPreview(data.list || []);
break;
case 'shipments':
data = await API.listShipments();
renderShipmentsPreview(data.list || []);
break;
case 'devices':
data = await API.devices();
renderDevicesPreview(data.list || []);
break;
case 'environment':
data = await API.environment();
renderEnvironmentPreview(data);
break;
case 'personnel':
data = await API.personnel();
renderPersonnelPreview(data.list || []);
break;
case 'qa':
data = await API.qa();
renderQaPreview(data.list || []);
break;
case 'production':
data = await API.production();
renderProductionPreview(data.list || []);
break;
}
} catch (e) {
preview.innerHTML = '加载失败
';
}
}
function renderStatsPreview(list) {
const preview = document.getElementById('export-preview');
if (list.length === 0) {
preview.innerHTML = '暂无数据
';
return;
}
preview.innerHTML = `
| 直通良品数 |
良品数 |
不良品数 |
时间 |
${list.slice(0, 50).map(item => `
| ${item.fpy_good || 0} |
${item.good} |
${item.bad} |
${new Date(item.ts).toLocaleString('zh-CN')} |
`).join('')}
${list.length > 50 ? `仅显示前50条,导出时将包含全部 ${list.length} 条数据
` : ''}
`;
}
function renderMacPreview(list) {
const preview = document.getElementById('export-preview');
if (list.length === 0) {
preview.innerHTML = '暂无数据
';
return;
}
preview.innerHTML = `
| MAC地址 |
批次号 |
时间 |
${list.slice(0, 50).map(item => `
| ${item.mac} |
${item.batch} |
${new Date(item.ts).toLocaleString('zh-CN')} |
`).join('')}
${list.length > 50 ? `仅显示前50条,导出时将包含全部 ${list.length} 条数据
` : ''}
`;
}
function renderRepairsPreview(list) {
const preview = document.getElementById('export-preview');
if (list.length === 0) {
preview.innerHTML = '暂无数据
';
return;
}
preview.innerHTML = `
| 返修数量 |
备注 |
时间 |
${list.slice(0, 50).map(item => `
| ${item.qty} |
${item.note || '无'} |
${new Date(item.ts).toLocaleString('zh-CN')} |
`).join('')}
${list.length > 50 ? `仅显示前50条,导出时将包含全部 ${list.length} 条数据
` : ''}
`;
}
function renderDefectsPreview(list) {
const preview = document.getElementById('export-preview');
if (list.length === 0) {
preview.innerHTML = '暂无数据
';
return;
}
preview.innerHTML = `
| MAC地址 |
批次号 |
时间 |
${list.slice(0, 50).map(item => `
| ${item.mac} |
${item.batch} |
${new Date(item.ts).toLocaleString('zh-CN')} |
`).join('')}
${list.length > 50 ? `仅显示前50条,导出时将包含全部 ${list.length} 条数据
` : ''}
`;
}
function renderShipmentsPreview(list) {
const preview = document.getElementById('export-preview');
if (list.length === 0) {
preview.innerHTML = '暂无数据
';
return;
}
preview.innerHTML = `
| 日期 |
数量 |
收货方 |
时间 |
${list.slice(0, 50).map(item => `
| ${item.date} |
${item.qty} |
${item.receiver} |
${new Date(item.ts).toLocaleString('zh-CN')} |
`).join('')}
${list.length > 50 ? `仅显示前50条,导出时将包含全部 ${list.length} 条数据
` : ''}
`;
}
function renderDevicesPreview(list) {
const preview = document.getElementById('export-preview');
if (list.length === 0) {
preview.innerHTML = '暂无数据
';
return;
}
preview.innerHTML = `
| 设备名称 |
状态 |
${list.map(item => `
| ${item.name} |
${item.status} |
`).join('')}
`;
}
function renderEnvironmentPreview(data) {
const preview = document.getElementById('export-preview');
preview.innerHTML = `
| 参数 |
值 |
| 温度 |
${data.temp || '—'} |
| 湿度 |
${data.hum || '—'} |
`;
}
function renderPersonnelPreview(list) {
const preview = document.getElementById('export-preview');
if (list.length === 0) {
preview.innerHTML = '暂无数据
';
return;
}
preview.innerHTML = `
| 姓名 |
角色 |
${list.map(item => `
| ${item.name} |
${item.role || '—'} |
`).join('')}
`;
}
function renderQaPreview(list) {
const preview = document.getElementById('export-preview');
if (list.length === 0) {
preview.innerHTML = '暂无数据
';
return;
}
preview.innerHTML = `
| 标题 |
日期 |
${list.map(item => `
| ${item.title} |
${item.date} |
`).join('')}
`;
}
function renderProductionPreview(list) {
const preview = document.getElementById('export-preview');
if (list.length === 0) {
preview.innerHTML = '暂无数据
';
return;
}
preview.innerHTML = `
| 批次 |
时长 |
${list.map(item => `
| ${item.batch} |
${item.duration} |
`).join('')}
`;
}
async function exportData(type, format) {
const statusEl = document.getElementById('export-status');
try {
statusEl.style.display = 'block';
statusEl.style.background = 'rgba(79,140,255,0.1)';
statusEl.style.color = 'var(--primary)';
statusEl.textContent = `正在导出${format.toUpperCase()}...`;
// 调用导出API并下载文件
const endpoint = format === 'excel' ? '/api/export/excel' : '/api/export/pdf';
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include',
body: JSON.stringify({ type })
});
if (!response.ok) {
throw new Error('导出失败');
}
// 获取文件名
const contentDisposition = response.headers.get('Content-Disposition');
let filename = `export_${type}_${Date.now()}.${format === 'excel' ? 'xlsx' : 'pdf'}`;
if (contentDisposition) {
const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
if (filenameMatch && filenameMatch[1]) {
filename = filenameMatch[1].replace(/['"]/g, '');
}
}
// 下载文件
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
statusEl.style.background = 'rgba(34,197,94,0.1)';
statusEl.style.color = 'var(--success)';
statusEl.textContent = `✓ ${format.toUpperCase()}导出成功!文件已下载`;
setTimeout(() => {
statusEl.style.display = 'none';
}, 3000);
} catch (e) {
statusEl.style.background = 'rgba(239,68,68,0.1)';
statusEl.style.color = 'var(--danger)';
statusEl.textContent = `✗ 导出失败: ${e.message}`;
}
}
Router.register('/export', render);
})();