236 lines
7.7 KiB
JavaScript
Executable File
236 lines
7.7 KiB
JavaScript
Executable File
Router.register('/shipments/summary', async () => {
|
|
setTimeout(async () => {
|
|
const queryBtn = document.getElementById('summary-query-btn');
|
|
const exportBtn = document.getElementById('summary-export-btn');
|
|
const startDateInput = document.getElementById('start-date');
|
|
const endDateInput = document.getElementById('end-date');
|
|
const resultDiv = document.getElementById('summary-result');
|
|
|
|
// 设置默认日期为当前月份
|
|
const now = new Date();
|
|
const firstDay = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0);
|
|
|
|
if (startDateInput) {
|
|
startDateInput.value = firstDay.toISOString().split('T')[0];
|
|
}
|
|
if (endDateInput) {
|
|
endDateInput.value = lastDay.toISOString().split('T')[0];
|
|
}
|
|
|
|
const performQuery = async () => {
|
|
const startDate = startDateInput?.value;
|
|
const endDate = endDateInput?.value;
|
|
|
|
if (!startDate || !endDate) {
|
|
resultDiv.innerHTML = '<div class="error">请选择开始和结束日期</div>';
|
|
return;
|
|
}
|
|
|
|
try {
|
|
resultDiv.innerHTML = '<div>查询中...</div>';
|
|
|
|
const res = await fetch(`/api/shipments/summary?start=${encodeURIComponent(startDate)}&end=${encodeURIComponent(endDate)}`, {
|
|
credentials: 'include'
|
|
});
|
|
const data = await res.json();
|
|
|
|
if (data.records && data.records.length > 0) {
|
|
const totalQty = data.records.reduce((sum, r) => sum + (r.qty || 0), 0);
|
|
|
|
const tableRows = data.records.map(record => `
|
|
<tr>
|
|
<td>${record.date}</td>
|
|
<td>${record.qty}</td>
|
|
<td>${record.receiver || '-'}</td>
|
|
<td>${record.ts || '-'}</td>
|
|
</tr>
|
|
`).join('');
|
|
|
|
resultDiv.innerHTML = `
|
|
<div style="margin-bottom:16px;padding:12px;background:var(--surface);border:1px solid var(--border);border-radius:8px">
|
|
<div style="display:flex;align-items:center;gap:16px">
|
|
<div>
|
|
<div style="color:var(--text-2);font-size:14px">查询时间段</div>
|
|
<div style="font-weight:600;margin-top:4px">${startDate} 至 ${endDate}</div>
|
|
</div>
|
|
<div style="margin-left:auto">
|
|
<div style="color:var(--text-2);font-size:14px">总出货数量</div>
|
|
<div style="font-weight:600;font-size:24px;color:var(--primary);margin-top:4px">${totalQty}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="max-height:60vh;overflow-y:auto;overflow-x:auto;border:1px solid var(--border);border-radius:8px;background:var(--surface)">
|
|
<table class="table" style="margin:0">
|
|
<thead style="position:sticky;top:0;z-index:1;background:var(--surface)">
|
|
<tr>
|
|
<th>发货日期</th>
|
|
<th>数量</th>
|
|
<th>收货方</th>
|
|
<th>录入时间</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
${tableRows}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
`;
|
|
} else {
|
|
resultDiv.innerHTML = `
|
|
<div class="result-card error">
|
|
<div class="result-title">未找到记录</div>
|
|
<div class="result-item">该时间段内没有发货记录</div>
|
|
</div>
|
|
`;
|
|
}
|
|
} catch (e) {
|
|
resultDiv.innerHTML = `<div class="error">查询失败:${e.message}</div>`;
|
|
}
|
|
};
|
|
|
|
const performExport = async () => {
|
|
const startDate = startDateInput?.value;
|
|
const endDate = endDateInput?.value;
|
|
|
|
if (!startDate || !endDate) {
|
|
alert('请选择开始和结束日期');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
exportBtn.disabled = true;
|
|
exportBtn.textContent = '导出中...';
|
|
|
|
const url = `/api/shipments/export?start=${encodeURIComponent(startDate)}&end=${encodeURIComponent(endDate)}`;
|
|
|
|
// 使用 fetch 下载文件
|
|
const res = await fetch(url, {
|
|
credentials: 'include'
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const error = await res.json();
|
|
throw new Error(error.error || '导出失败');
|
|
}
|
|
|
|
// 获取文件名
|
|
const contentDisposition = res.headers.get('Content-Disposition');
|
|
let filename = `发货记录_${startDate}_至_${endDate}.xlsx`;
|
|
if (contentDisposition) {
|
|
const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(contentDisposition);
|
|
if (matches && matches[1]) {
|
|
filename = matches[1].replace(/['"]/g, '');
|
|
}
|
|
}
|
|
|
|
// 下载文件
|
|
const blob = await res.blob();
|
|
const downloadUrl = window.URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = downloadUrl;
|
|
a.download = filename;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
window.URL.revokeObjectURL(downloadUrl);
|
|
document.body.removeChild(a);
|
|
|
|
alert('导出成功!');
|
|
} catch (e) {
|
|
alert('导出失败:' + e.message);
|
|
} finally {
|
|
exportBtn.disabled = false;
|
|
exportBtn.textContent = '导出Excel';
|
|
}
|
|
};
|
|
|
|
queryBtn?.addEventListener('click', performQuery);
|
|
exportBtn?.addEventListener('click', performExport);
|
|
|
|
// 自动执行一次查询
|
|
performQuery();
|
|
}, 0);
|
|
|
|
return `
|
|
<style>
|
|
#shipment-summary-page {
|
|
padding: 20px;
|
|
background: var(--bg);
|
|
}
|
|
#shipment-summary-page .page-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
}
|
|
#shipment-summary-page h1 {
|
|
margin: 0;
|
|
font-size: 24px;
|
|
color: var(--text);
|
|
}
|
|
#shipment-summary-page .content-area {
|
|
background: var(--surface);
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
#shipment-summary-page .query-section {
|
|
padding: 20px;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
#shipment-summary-page .result-section {
|
|
padding: 20px;
|
|
}
|
|
#shipment-summary-page .date-row {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
@media (max-width: 768px) {
|
|
#shipment-summary-page .date-row {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<div id="shipment-summary-page">
|
|
<div class="page-header">
|
|
<h1>发货汇总信息查询</h1>
|
|
</div>
|
|
|
|
<div class="content-area">
|
|
<div class="query-section">
|
|
<div class="date-row">
|
|
<div class="field">
|
|
<label>开始日期</label>
|
|
<input
|
|
id="start-date"
|
|
type="date"
|
|
class="input"
|
|
/>
|
|
</div>
|
|
<div class="field">
|
|
<label>结束日期</label>
|
|
<input
|
|
id="end-date"
|
|
type="date"
|
|
class="input"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="actions" style="display:flex;gap:12px">
|
|
<button class="btn btn-primary" id="summary-query-btn">查询</button>
|
|
<button class="btn" id="summary-export-btn" style="background:#10b981;color:white">导出Excel</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="result-section">
|
|
<div id="summary-result"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
});
|