349 lines
13 KiB
JavaScript
349 lines
13 KiB
JavaScript
// 客户订单管理
|
||
(() => {
|
||
Router.register('/plan-mgmt/customer-order', async () => {
|
||
// 先返回 HTML
|
||
const html = `
|
||
<div class="page-header">
|
||
<h1>客户订单管理</h1>
|
||
<div class="page-actions">
|
||
<button id="add-order-btn" class="btn btn-primary">新增订单</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-body">
|
||
<div class="table-container">
|
||
<table class="data-table">
|
||
<thead>
|
||
<tr>
|
||
<th>下单时间</th>
|
||
<th>订单编号</th>
|
||
<th>客户名称</th>
|
||
<th>物料</th>
|
||
<th>订单数量</th>
|
||
<th>单价</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="order-list">
|
||
<tr>
|
||
<td colspan="7" class="text-center">加载中...</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 新增订单弹窗 -->
|
||
<div id="order-modal" class="modal" style="display:none;">
|
||
<div class="modal-content" style="max-width: 900px; max-height: 90vh; overflow-y: auto;">
|
||
<div class="modal-header">
|
||
<h2 id="modal-title">新增订单</h2>
|
||
<button class="modal-close" onclick="window.CustomerOrder.closeModal()">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form id="order-form">
|
||
<!-- 订单基本信息 -->
|
||
<div style="background: var(--surface); padding: 20px; border-radius: 8px; margin-bottom: 20px; border: 1px solid var(--border);">
|
||
<h3 style="margin: 0 0 15px 0; font-size: 16px; color: var(--text); font-weight: 600;">订单基本信息</h3>
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 15px;">
|
||
<div class="field" style="margin: 0;">
|
||
<label>下单时间 <span style="color: var(--danger);">*</span></label>
|
||
<input type="date" id="order-date" class="input" required />
|
||
</div>
|
||
<div class="field" style="margin: 0;">
|
||
<label>订单编号 <span style="color: var(--danger);">*</span></label>
|
||
<input type="text" id="order-no" class="input" placeholder="如:CGDD001695" required />
|
||
</div>
|
||
<div class="field" style="margin: 0;">
|
||
<label>客户名称 <span style="color: var(--danger);">*</span></label>
|
||
<input type="text" id="customer-name" class="input" placeholder="如:易泰勒" required />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 物料列表 -->
|
||
<div style="background: var(--surface); padding: 20px; border-radius: 8px; border: 1px solid var(--border);">
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
|
||
<h3 style="margin: 0; font-size: 16px; color: var(--text); font-weight: 600;">物料清单</h3>
|
||
<button type="button" class="btn btn-primary" onclick="window.CustomerOrder.addMaterialRow()">
|
||
➕ 添加物料
|
||
</button>
|
||
</div>
|
||
|
||
<div id="materials-container">
|
||
<!-- 物料行将动态添加到这里 -->
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-secondary" onclick="window.CustomerOrder.closeModal()">取消</button>
|
||
<button class="btn btn-primary" onclick="window.CustomerOrder.saveOrder()">保存订单</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
// DOM 渲染后初始化
|
||
setTimeout(() => {
|
||
const addBtn = document.getElementById('add-order-btn');
|
||
if (addBtn) {
|
||
addBtn.addEventListener('click', () => {
|
||
openModal();
|
||
});
|
||
}
|
||
loadOrders();
|
||
}, 100);
|
||
|
||
return html;
|
||
});
|
||
|
||
async function loadOrders() {
|
||
try {
|
||
console.log('开始加载订单列表...');
|
||
const res = await fetch('/api/customer-orders');
|
||
console.log('API响应状态:', res.status);
|
||
const data = await res.json();
|
||
console.log('订单数据:', data);
|
||
|
||
const tbody = document.getElementById('order-list');
|
||
if (!tbody) {
|
||
console.error('找不到 order-list 元素');
|
||
return;
|
||
}
|
||
|
||
if (!data.list || data.list.length === 0) {
|
||
tbody.innerHTML = '<tr><td colspan="7" class="text-center">暂无数据</td></tr>';
|
||
return;
|
||
}
|
||
|
||
tbody.innerHTML = data.list.map(order => `
|
||
<tr>
|
||
<td>${order.order_date || '—'}</td>
|
||
<td>${order.order_no || '—'}</td>
|
||
<td>${order.customer_name || '—'}</td>
|
||
<td style="white-space: pre-wrap;">${order.material || '—'}</td>
|
||
<td>${order.quantity || 0}</td>
|
||
<td>${order.unit_price || 0}</td>
|
||
<td>
|
||
<button class="btn-text btn-danger" onclick="window.CustomerOrder.deleteOrder(${order.id})">删除</button>
|
||
</td>
|
||
</tr>
|
||
`).join('');
|
||
console.log('订单列表加载完成');
|
||
} catch (err) {
|
||
console.error('加载订单失败:', err);
|
||
const tbody = document.getElementById('order-list');
|
||
if (tbody) {
|
||
tbody.innerHTML = '<tr><td colspan="7" class="text-center" style="color: red;">加载失败,请刷新重试</td></tr>';
|
||
}
|
||
API.toast('加载订单失败', 'error');
|
||
}
|
||
}
|
||
|
||
let materialRowIndex = 0;
|
||
|
||
function addMaterialRow(material = '', quantity = '', unitPrice = '') {
|
||
const container = document.getElementById('materials-container');
|
||
const index = materialRowIndex++;
|
||
|
||
const row = document.createElement('div');
|
||
row.className = 'material-row';
|
||
row.id = `material-row-${index}`;
|
||
row.style.cssText = 'display: grid; grid-template-columns: 2fr 1fr 1fr auto; gap: 12px; margin-bottom: 12px; padding: 16px; background: var(--surface-2); border-radius: 8px; border: 1px solid var(--border);';
|
||
|
||
row.innerHTML = `
|
||
<div class="field" style="margin: 0;">
|
||
<label>物料名称 <span style="color: var(--danger);">*</span></label>
|
||
<input type="text" class="input material-name" placeholder="如:ETAP05 基站-5.0" value="${material}" required />
|
||
</div>
|
||
<div class="field" style="margin: 0;">
|
||
<label>数量 <span style="color: var(--danger);">*</span></label>
|
||
<input type="number" class="input material-quantity" placeholder="数量" value="${quantity}" min="1" required />
|
||
</div>
|
||
<div class="field" style="margin: 0;">
|
||
<label>单价 <span style="color: var(--danger);">*</span></label>
|
||
<input type="number" class="input material-price" placeholder="单价" value="${unitPrice}" step="0.01" min="0" required />
|
||
</div>
|
||
<div style="display: flex; align-items: flex-end; padding-bottom: 2px;">
|
||
<button type="button" class="btn btn-danger" onclick="window.CustomerOrder.removeMaterialRow(${index})" style="white-space: nowrap;">
|
||
🗑️ 删除
|
||
</button>
|
||
</div>
|
||
`;
|
||
|
||
container.appendChild(row);
|
||
}
|
||
|
||
function removeMaterialRow(index) {
|
||
const row = document.getElementById(`material-row-${index}`);
|
||
if (row) {
|
||
row.remove();
|
||
}
|
||
|
||
// 如果没有物料行了,至少保留一行
|
||
const container = document.getElementById('materials-container');
|
||
if (container.children.length === 0) {
|
||
addMaterialRow();
|
||
}
|
||
}
|
||
|
||
function openModal(order = null) {
|
||
const modal = document.getElementById('order-modal');
|
||
const title = document.getElementById('modal-title');
|
||
|
||
title.textContent = '新增订单';
|
||
document.getElementById('order-form').reset();
|
||
|
||
// 设置默认日期为今天
|
||
const today = new Date().toISOString().split('T')[0];
|
||
document.getElementById('order-date').value = today;
|
||
|
||
// 清空物料列表并添加一行
|
||
const container = document.getElementById('materials-container');
|
||
container.innerHTML = '';
|
||
materialRowIndex = 0;
|
||
addMaterialRow();
|
||
|
||
modal.style.display = 'flex';
|
||
}
|
||
|
||
function closeModal() {
|
||
const modal = document.getElementById('order-modal');
|
||
modal.style.display = 'none';
|
||
document.getElementById('order-form').reset();
|
||
|
||
// 清空物料列表
|
||
const container = document.getElementById('materials-container');
|
||
if (container) {
|
||
container.innerHTML = '';
|
||
}
|
||
materialRowIndex = 0;
|
||
}
|
||
|
||
async function saveOrder() {
|
||
const orderDate = document.getElementById('order-date').value.trim();
|
||
const orderNo = document.getElementById('order-no').value.trim();
|
||
const customerName = document.getElementById('customer-name').value.trim();
|
||
|
||
if (!orderDate || !orderNo || !customerName) {
|
||
API.toast('请填写订单基本信息', 'error');
|
||
return;
|
||
}
|
||
|
||
// 收集所有物料信息
|
||
const materials = [];
|
||
const materialRows = document.querySelectorAll('.material-row');
|
||
|
||
if (materialRows.length === 0) {
|
||
API.toast('请至少添加一个物料', 'error');
|
||
return;
|
||
}
|
||
|
||
for (const row of materialRows) {
|
||
const materialName = row.querySelector('.material-name').value.trim();
|
||
const quantity = parseInt(row.querySelector('.material-quantity').value);
|
||
const unitPrice = parseFloat(row.querySelector('.material-price').value);
|
||
|
||
if (!materialName || !quantity || isNaN(unitPrice)) {
|
||
API.toast('请填写所有物料信息', 'error');
|
||
return;
|
||
}
|
||
|
||
if (quantity <= 0) {
|
||
API.toast('物料数量必须大于0', 'error');
|
||
return;
|
||
}
|
||
|
||
if (unitPrice < 0) {
|
||
API.toast('单价不能为负数', 'error');
|
||
return;
|
||
}
|
||
|
||
materials.push({
|
||
material: materialName,
|
||
quantity: quantity,
|
||
unit_price: unitPrice
|
||
});
|
||
}
|
||
|
||
try {
|
||
// 为每个物料创建一条订单记录
|
||
let successCount = 0;
|
||
for (const mat of materials) {
|
||
const res = await fetch('/api/customer-orders', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
order_date: orderDate,
|
||
order_no: orderNo,
|
||
customer_name: customerName,
|
||
material: mat.material,
|
||
quantity: mat.quantity,
|
||
unit_price: mat.unit_price
|
||
})
|
||
});
|
||
|
||
const data = await res.json();
|
||
|
||
if (res.ok && data.ok) {
|
||
successCount++;
|
||
} else {
|
||
console.error('保存物料失败:', mat.material, data.error);
|
||
}
|
||
}
|
||
|
||
if (successCount === materials.length) {
|
||
API.toast(`订单保存成功,共 ${successCount} 个物料`, 'success');
|
||
closeModal();
|
||
await loadOrders();
|
||
} else if (successCount > 0) {
|
||
API.toast(`部分保存成功(${successCount}/${materials.length})`, 'warning');
|
||
closeModal();
|
||
await loadOrders();
|
||
} else {
|
||
API.toast('保存失败', 'error');
|
||
}
|
||
} catch (err) {
|
||
console.error('保存订单失败:', err);
|
||
API.toast('保存失败', 'error');
|
||
}
|
||
}
|
||
|
||
async function deleteOrder(id) {
|
||
if (!confirm('确定要删除这条订单吗?')) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const res = await fetch(`/api/customer-orders/${id}`, {
|
||
method: 'DELETE'
|
||
});
|
||
|
||
const data = await res.json();
|
||
|
||
if (res.ok && data.ok) {
|
||
API.toast('删除成功', 'success');
|
||
await loadOrders();
|
||
} else {
|
||
API.toast(data.error || '删除失败', 'error');
|
||
}
|
||
} catch (err) {
|
||
console.error('删除订单失败:', err);
|
||
API.toast('删除失败', 'error');
|
||
}
|
||
}
|
||
|
||
// 暴露给全局
|
||
window.CustomerOrder = {
|
||
openModal,
|
||
closeModal,
|
||
saveOrder,
|
||
deleteOrder,
|
||
addMaterialRow,
|
||
removeMaterialRow
|
||
};
|
||
})();
|