112 lines
5.6 KiB
HTML
112 lines
5.6 KiB
HTML
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>订单池 - 智能排产系统</title>
|
|||
|
|
<link rel="stylesheet" href="../css/common.css">
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<div id="app">
|
|||
|
|
<header class="header" id="header"></header>
|
|||
|
|
<div class="body">
|
|||
|
|
<aside class="sidebar" id="sidebar"></aside>
|
|||
|
|
<main class="main">
|
|||
|
|
<h1 class="page-title">订单池</h1>
|
|||
|
|
<div class="toolbar">
|
|||
|
|
<button class="btn btn-primary" id="batchScheduleBtn" onclick="batchSchedule()" disabled>批量排产</button>
|
|||
|
|
<button class="btn" onclick="markRush()">标记加急</button>
|
|||
|
|
<div class="search-box"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg><input id="searchInput" placeholder="搜索" oninput="render()"></div>
|
|||
|
|
</div>
|
|||
|
|
<div class="tabs">
|
|||
|
|
<div class="tab active" data-status="CONFIRMED" onclick="switchTab(this)">待排产</div>
|
|||
|
|
<div class="tab" data-status="SCHEDULED" onclick="switchTab(this)">已排产</div>
|
|||
|
|
<div class="tab" data-status="IN_PRODUCTION" onclick="switchTab(this)">生产中</div>
|
|||
|
|
<div class="tab" data-status="COMPLETED" onclick="switchTab(this)">已完成</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="card">
|
|||
|
|
<div class="card-body table-wrap">
|
|||
|
|
<table id="poolTable">
|
|||
|
|
<thead><tr><th><input type="checkbox" id="checkAll" onclick="toggleAll()"></th><th>订单号</th><th>客户</th><th>产品/数量</th><th>交期</th><th>优先级</th><th>状态</th><th>操作</th></tr></thead>
|
|||
|
|
<tbody></tbody>
|
|||
|
|
</table>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</main>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<script src="../js/data.js"></script>
|
|||
|
|
<script src="../js/common.js"></script>
|
|||
|
|
<script>
|
|||
|
|
initPage('order-pool');
|
|||
|
|
let currentStatus = 'CONFIRMED';
|
|||
|
|
let selectedIds = [];
|
|||
|
|
function switchTab(el) {
|
|||
|
|
$$('.tab').forEach(t => t.classList.remove('active'));
|
|||
|
|
el.classList.add('active');
|
|||
|
|
currentStatus = el.dataset.status;
|
|||
|
|
selectedIds = [];
|
|||
|
|
document.getElementById('checkAll').checked = false;
|
|||
|
|
render();
|
|||
|
|
}
|
|||
|
|
function render() {
|
|||
|
|
const kw = document.getElementById('searchInput').value.toLowerCase();
|
|||
|
|
let rows = apsData.salesOrders.filter(o => {
|
|||
|
|
if (currentStatus === 'SCHEDULED') {
|
|||
|
|
if (o.status !== 'CONFIRMED') return false;
|
|||
|
|
return apsData.productionOrders.some(po => po.salesOrderId == o.id);
|
|||
|
|
}
|
|||
|
|
return o.status === currentStatus;
|
|||
|
|
}).filter(o => {
|
|||
|
|
const text = (o.orderNo + ' ' + o.customerName + ' ' + o.items.map(i => i.productName).join(' ')).toLowerCase();
|
|||
|
|
return !kw || text.includes(kw);
|
|||
|
|
});
|
|||
|
|
rows.sort((a, b) => a.priority - b.priority || a.deliveryDate.localeCompare(b.deliveryDate));
|
|||
|
|
const tbody = document.querySelector('#poolTable tbody');
|
|||
|
|
tbody.innerHTML = rows.map(o => {
|
|||
|
|
const item = o.items[0];
|
|||
|
|
const scheduled = apsData.productionOrders.some(po => po.salesOrderId == o.id);
|
|||
|
|
return `<tr>
|
|||
|
|
<td><input type="checkbox" class="row-check" value="${o.id}" ${selectedIds.includes(o.id) ? 'checked' : ''} onchange="toggleRow(${o.id})"></td>
|
|||
|
|
<td>${o.orderNo}</td>
|
|||
|
|
<td>${o.customerName} ${o.isRush ? '<span class="badge badge-danger">加急</span>' : ''}</td>
|
|||
|
|
<td>${item.productName} × ${item.quantity}</td>
|
|||
|
|
<td>${o.deliveryDate}</td>
|
|||
|
|
<td>${o.priority}</td>
|
|||
|
|
<td>${scheduled ? '<span class="badge badge-primary">已排产</span>' : statusBadge(o.status, { CONFIRMED:'default', IN_PRODUCTION:'warning', COMPLETED:'success', CANCELLED:'danger' })}</td>
|
|||
|
|
<td class="actions">
|
|||
|
|
${!scheduled && o.status === 'CONFIRMED' ? `<button class="btn btn-sm btn-primary" onclick="scheduleOne(${o.id})">排产</button>` : ''}
|
|||
|
|
${!o.isRush && o.status !== 'COMPLETED' && o.status !== 'CANCELLED' ? `<button class="btn btn-sm" onclick="setRush(${o.id})">加急</button>` : ''}
|
|||
|
|
</td>
|
|||
|
|
</tr>`;
|
|||
|
|
}).join('') || '<tr><td colspan="8" class="text-center text-muted">无数据</td></tr>';
|
|||
|
|
document.getElementById('batchScheduleBtn').disabled = !selectedIds.length;
|
|||
|
|
}
|
|||
|
|
function toggleRow(id) {
|
|||
|
|
if (selectedIds.includes(id)) selectedIds = selectedIds.filter(x => x !== id);
|
|||
|
|
else selectedIds.push(id);
|
|||
|
|
render();
|
|||
|
|
}
|
|||
|
|
function toggleAll() {
|
|||
|
|
const checked = document.getElementById('checkAll').checked;
|
|||
|
|
const visible = [];
|
|||
|
|
$$('.row-check').forEach(cb => visible.push(Number(cb.value)));
|
|||
|
|
selectedIds = checked ? visible : [];
|
|||
|
|
render();
|
|||
|
|
}
|
|||
|
|
function scheduleOne(id) { location.href = `scheduling.html?orderIds=${id}`; }
|
|||
|
|
function batchSchedule() { location.href = `scheduling.html?orderIds=${selectedIds.join(',')}`; }
|
|||
|
|
function setRush(id) {
|
|||
|
|
const o = findById(apsData.salesOrders, id); o.isRush = true; o.priority = 1; o.rushStrategy = apsData.scheduleParams.rushStrategy;
|
|||
|
|
apsData.$utils.save(apsData); showToast('已标记加急', `订单 ${o.orderNo} 优先级已设为最高`); render();
|
|||
|
|
}
|
|||
|
|
function markRush() {
|
|||
|
|
if (!selectedIds.length) return showToast('提示', '请先勾选订单', 'warning');
|
|||
|
|
selectedIds.forEach(id => { const o = findById(apsData.salesOrders, id); o.isRush = true; o.priority = 1; });
|
|||
|
|
apsData.$utils.save(apsData); showToast('已批量加急', '所选订单已标记加急'); render();
|
|||
|
|
}
|
|||
|
|
render();
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|