250 lines
8.9 KiB
JavaScript
250 lines
8.9 KiB
JavaScript
Router.register('/upload/shipments', async () => {
|
||
setTimeout(() => {
|
||
const manualStatus = document.getElementById('ship-manual-status');
|
||
|
||
// 设置默认日期为今天
|
||
const dateInput = document.getElementById('ship-date');
|
||
if (dateInput && !dateInput.value) {
|
||
const today = new Date().toISOString().split('T')[0];
|
||
dateInput.value = today;
|
||
}
|
||
|
||
// 手动录入提交
|
||
const btn = document.getElementById('ship-upload');
|
||
btn?.addEventListener('click', async () => {
|
||
const date = document.getElementById('ship-date').value;
|
||
const qty = parseInt(document.getElementById('ship-qty').value || '0', 10);
|
||
const to = document.getElementById('ship-to').value;
|
||
const platform = document.getElementById('ship-manual-platform').value;
|
||
const boxNo = document.getElementById('ship-box-no').value.trim();
|
||
|
||
// 验证必填字段
|
||
if (!date) {
|
||
manualStatus.textContent = '✗ 请选择发货日期';
|
||
manualStatus.className = 'error';
|
||
return;
|
||
}
|
||
|
||
if (!platform) {
|
||
manualStatus.textContent = '✗ 请选择机种类型';
|
||
manualStatus.className = 'error';
|
||
return;
|
||
}
|
||
|
||
if (!to) {
|
||
manualStatus.textContent = '✗ 请输入接收方';
|
||
manualStatus.className = 'error';
|
||
return;
|
||
}
|
||
|
||
if (qty <= 0) {
|
||
manualStatus.textContent = '✗ 数量必须大于0';
|
||
manualStatus.className = 'error';
|
||
return;
|
||
}
|
||
|
||
try {
|
||
manualStatus.textContent = '提交中...';
|
||
manualStatus.className = '';
|
||
|
||
const payload = { date, qty, to, platform };
|
||
if (boxNo) {
|
||
payload.box_no = boxNo;
|
||
}
|
||
|
||
await API.uploadShipments(payload);
|
||
|
||
const platformName = {pdd: '拼多多', yt: '圆通', tx: '兔喜'}[platform] || platform;
|
||
manualStatus.textContent = `✓ 录入成功!机种:${platformName},数量:${qty}`;
|
||
manualStatus.className = 'success';
|
||
|
||
// 清空表单(保留日期和机种)
|
||
document.getElementById('ship-qty').value = '';
|
||
document.getElementById('ship-to').value = '';
|
||
document.getElementById('ship-box-no').value = '';
|
||
|
||
} catch(e) {
|
||
manualStatus.textContent = '✗ 录入失败:' + (e.message || '未知错误');
|
||
manualStatus.className = 'error';
|
||
}
|
||
});
|
||
|
||
const fileInput = document.getElementById('ship-file');
|
||
const validateBtn = document.getElementById('ship-validate');
|
||
const uploadFileBtn = document.getElementById('ship-upload-file');
|
||
const fileStatus = document.getElementById('ship-file-status');
|
||
|
||
fileInput?.addEventListener('change', () => {
|
||
fileStatus.textContent = '';
|
||
fileStatus.className = '';
|
||
});
|
||
|
||
validateBtn?.addEventListener('click', async () => {
|
||
const file = fileInput?.files?.[0];
|
||
if (!file) {
|
||
fileStatus.textContent = '请先选择文件';
|
||
fileStatus.className = 'error';
|
||
return;
|
||
}
|
||
|
||
const formData = new FormData();
|
||
formData.append('file', file);
|
||
|
||
try {
|
||
const res = await fetch('/api/validate/shipments-file', {
|
||
method: 'POST',
|
||
body: formData,
|
||
credentials: 'include'
|
||
});
|
||
|
||
if (!res.ok) {
|
||
const text = await res.text();
|
||
throw new Error(`HTTP ${res.status}: ${text}`);
|
||
}
|
||
|
||
const data = await res.json();
|
||
|
||
if (data.valid) {
|
||
fileStatus.textContent = '✓ ' + data.message;
|
||
fileStatus.className = 'success';
|
||
} else {
|
||
fileStatus.textContent = '✗ ' + data.message;
|
||
fileStatus.className = 'error';
|
||
}
|
||
} catch (e) {
|
||
fileStatus.textContent = '验证失败:' + e.message;
|
||
fileStatus.className = 'error';
|
||
}
|
||
});
|
||
|
||
uploadFileBtn?.addEventListener('click', async () => {
|
||
const file = fileInput?.files?.[0];
|
||
const platform = document.getElementById('ship-platform')?.value;
|
||
|
||
if (!platform) {
|
||
fileStatus.textContent = '✗ 请选择机种类型';
|
||
fileStatus.className = 'error';
|
||
return;
|
||
}
|
||
|
||
if (!file) {
|
||
fileStatus.textContent = '✗ 请先选择文件';
|
||
fileStatus.className = 'error';
|
||
return;
|
||
}
|
||
|
||
const formData = new FormData();
|
||
formData.append('file', file);
|
||
formData.append('platform', platform);
|
||
|
||
try {
|
||
fileStatus.textContent = '上传中...';
|
||
fileStatus.className = '';
|
||
|
||
const res = await fetch('/api/upload/shipments-file', {
|
||
method: 'POST',
|
||
body: formData,
|
||
credentials: 'include'
|
||
});
|
||
|
||
if (!res.ok) {
|
||
const text = await res.text();
|
||
throw new Error(`HTTP ${res.status}: ${text}`);
|
||
}
|
||
|
||
const data = await res.json();
|
||
|
||
if (data.ok) {
|
||
const platformName = {pdd: '拼多多', yt: '圆通', tx: '兔喜'}[platform] || platform;
|
||
fileStatus.textContent = `✓ 上传成功!机种:${platformName},共导入${data.count}个箱次,${data.total_qty}个SN`;
|
||
fileStatus.className = 'success';
|
||
fileInput.value = '';
|
||
document.getElementById('ship-platform').value = '';
|
||
} else {
|
||
fileStatus.textContent = '✗ ' + (data.error || '上传失败');
|
||
fileStatus.className = 'error';
|
||
}
|
||
} catch (e) {
|
||
fileStatus.textContent = '上传失败:' + e.message;
|
||
fileStatus.className = 'error';
|
||
}
|
||
});
|
||
}, 0);
|
||
return `<div class="card">
|
||
<div style="font-weight:600;margin-bottom:16px">发货记录</div>
|
||
|
||
<div style="margin-bottom:24px;padding-bottom:24px;border-bottom:1px solid var(--border)">
|
||
<div style="font-weight:500;margin-bottom:12px">手动录入</div>
|
||
<div style="font-size:13px;color:var(--text-secondary);margin-bottom:12px">
|
||
用于快速录入发货汇总信息(不含详细SN)
|
||
</div>
|
||
<div class="row">
|
||
<div class="col">
|
||
<div class="field">
|
||
<label>发货日期 <span style="color:var(--danger)">*</span></label>
|
||
<input id="ship-date" type="date" class="input" />
|
||
</div>
|
||
</div>
|
||
<div class="col">
|
||
<div class="field">
|
||
<label>机种类型 <span style="color:var(--danger)">*</span></label>
|
||
<select id="ship-manual-platform" class="input">
|
||
<option value="">请选择机种</option>
|
||
<option value="pdd">拼多多</option>
|
||
<option value="yt">圆通</option>
|
||
<option value="tx">兔喜</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col">
|
||
<div class="field">
|
||
<label>接收方 <span style="color:var(--danger)">*</span></label>
|
||
<input id="ship-to" class="input" placeholder="客户名称" />
|
||
</div>
|
||
</div>
|
||
<div class="col">
|
||
<div class="field">
|
||
<label>数量 <span style="color:var(--danger)">*</span></label>
|
||
<input id="ship-qty" type="number" min="1" class="input" placeholder="发货数量" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="field">
|
||
<label>箱号(可选)</label>
|
||
<input id="ship-box-no" class="input" placeholder="例如:BOX001" />
|
||
</div>
|
||
<div id="ship-manual-status" style="margin:8px 0;font-size:13px"></div>
|
||
<div class="actions"><button class="btn" id="ship-upload">提交录入</button></div>
|
||
</div>
|
||
|
||
<div>
|
||
<div style="font-weight:500;margin-bottom:12px">详细记录批量导入</div>
|
||
<div class="format-requirements">
|
||
<div style="font-weight:500;margin-bottom:4px">文件格式要求:</div>
|
||
<div>• 必需列:出货日期、箱号、SN1、SN2、...、SN20</div>
|
||
<div>• 出货日期列支持合并单元格</div>
|
||
<div>• 支持格式:Excel (.xlsx, .xls) 或 CSV</div>
|
||
</div>
|
||
<div class="field">
|
||
<label>机种类型 <span style="color:var(--danger)">*</span></label>
|
||
<select id="ship-platform" class="input">
|
||
<option value="">请选择机种</option>
|
||
<option value="pdd">拼多多</option>
|
||
<option value="yt">圆通</option>
|
||
<option value="tx">兔喜</option>
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<label>选择文件</label>
|
||
<input type="file" id="ship-file" accept=".xlsx,.xls,.csv" class="input" style="padding:6px" />
|
||
</div>
|
||
<div id="ship-file-status" style="margin:8px 0;font-size:13px"></div>
|
||
<div class="actions">
|
||
<button class="btn" id="ship-validate" style="background:#6c757d">验证文件</button>
|
||
<button class="btn" id="ship-upload-file">导入数据</button>
|
||
</div>
|
||
</div>
|
||
</div>`;
|
||
}); |