103 lines
5.9 KiB
HTML
103 lines
5.9 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" onclick="addLineModal()">+ 新增产线</button>
|
||
|
|
<button class="btn" onclick="addWsModal()">+ 新增工位</button>
|
||
|
|
</div>
|
||
|
|
<div id="lineCards"></div>
|
||
|
|
</main>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<script src="../js/data.js"></script>
|
||
|
|
<script src="../js/common.js"></script>
|
||
|
|
<script>
|
||
|
|
initPage('lines');
|
||
|
|
function render() {
|
||
|
|
const container = document.getElementById('lineCards');
|
||
|
|
container.innerHTML = apsData.lines.map(line => {
|
||
|
|
const ws = apsData.workstations.filter(w => w.lineId == line.id).sort((a,b)=>a.sequenceNo-b.sequenceNo);
|
||
|
|
const products = apsData.lineProducts.filter(lp => lp.lineId == line.id).map(lp => {
|
||
|
|
const p = apsData.materials.find(m => m.id == lp.productId);
|
||
|
|
return p ? p.name : '';
|
||
|
|
}).join('、');
|
||
|
|
return `
|
||
|
|
<div class="card">
|
||
|
|
<div class="card-header">${line.name} <span class="text-muted">(${line.code})</span>
|
||
|
|
<span class="badge badge-${line.status==='ACTIVE'?'success':'default'} ml-2">${line.status}</span>
|
||
|
|
<span class="ml-auto text-muted">日产能 ${line.capacityPerDay} | 节拍 ${line.taktTime}min</span>
|
||
|
|
</div>
|
||
|
|
<div class="card-body">
|
||
|
|
<p><strong>可生产产品:</strong>${products || '未配置'}</p>
|
||
|
|
<table>
|
||
|
|
<thead><tr><th>顺序</th><th>工位编码</th><th>工位名称</th><th>工序</th><th>状态</th></tr></thead>
|
||
|
|
<tbody>
|
||
|
|
${ws.map(w => {
|
||
|
|
const ops = apsData.workstationOperations.filter(wo => wo.workstationId == w.id).map(wo => {
|
||
|
|
const op = apsData.operations.find(o => o.id == wo.operationId); return op ? op.name : '';
|
||
|
|
}).join('、');
|
||
|
|
return `<tr><td>${w.sequenceNo}</td><td>${w.code}</td><td>${w.name}</td><td>${ops || '-'}</td><td>${w.status}</td></tr>`;
|
||
|
|
}).join('') || '<tr><td colspan="5" class="text-center text-muted">无工位</td></tr>'}
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
</div>`;
|
||
|
|
}).join('');
|
||
|
|
}
|
||
|
|
function addLineModal() {
|
||
|
|
const wsOpts = apsData.workshops.map(w => `<option value="${w.id}">${w.name}</option>`).join('');
|
||
|
|
openModal('新增产线', `
|
||
|
|
<div class="form-row"><div class="form-group"><label>产线编码</label><input id="l_code"></div><div class="form-group"><label>产线名称</label><input id="l_name"></div></div>
|
||
|
|
<div class="form-row"><div class="form-group"><label>所属车间</label><select id="l_ws">${wsOpts}</select></div><div class="form-group"><label>日产能</label><input id="l_cap" type="number" value="800"></div></div>
|
||
|
|
`, `
|
||
|
|
<button class="btn" onclick="closeModal()">取消</button>
|
||
|
|
<button class="btn btn-primary" onclick="saveLine()">保存</button>
|
||
|
|
`);
|
||
|
|
}
|
||
|
|
function saveLine() {
|
||
|
|
const code = document.getElementById('l_code').value.trim();
|
||
|
|
const name = document.getElementById('l_name').value.trim();
|
||
|
|
if (!code || !name) return showToast('校验失败', '请填写编码和名称', 'error');
|
||
|
|
apsData.lines.push({ id: apsData.$utils.nextId('line'), workshopId: Number(document.getElementById('l_ws').value), code, name, capacityPerDay: Number(document.getElementById('l_cap').value), taktTime: 0.6, efficiencyFactor: 1, status: 'ACTIVE', alternativeLineIds: [] });
|
||
|
|
apsData.$utils.save(apsData); closeModal(); showToast('保存成功'); render();
|
||
|
|
}
|
||
|
|
function addWsModal() {
|
||
|
|
const lineOpts = apsData.lines.map(l => `<option value="${l.id}">${l.name}</option>`).join('');
|
||
|
|
const opOpts = apsData.operations.map(o => `<option value="${o.id}">${o.name}</option>`).join('');
|
||
|
|
openModal('新增工位', `
|
||
|
|
<div class="form-row"><div class="form-group"><label>所属产线</label><select id="ws_line">${lineOpts}</select></div><div class="form-group"><label>顺序号</label><input id="ws_seq" type="number" value="1"></div></div>
|
||
|
|
<div class="form-row"><div class="form-group"><label>工位编码</label><input id="ws_code"></div><div class="form-group"><label>工位名称</label><input id="ws_name"></div></div>
|
||
|
|
<div class="form-row"><div class="form-group"><label>可执行工序</label><select id="ws_op">${opOpts}</select></div></div>
|
||
|
|
`, `
|
||
|
|
<button class="btn" onclick="closeModal()">取消</button>
|
||
|
|
<button class="btn btn-primary" onclick="saveWs()">保存</button>
|
||
|
|
`);
|
||
|
|
}
|
||
|
|
function saveWs() {
|
||
|
|
const code = document.getElementById('ws_code').value.trim();
|
||
|
|
const name = document.getElementById('ws_name').value.trim();
|
||
|
|
if (!code || !name) return showToast('校验失败', '请填写编码和名称', 'error');
|
||
|
|
const lineId = Number(document.getElementById('ws_line').value);
|
||
|
|
const seq = Number(document.getElementById('ws_seq').value);
|
||
|
|
const wsId = apsData.$utils.nextId('workstation');
|
||
|
|
apsData.workstations.push({ id: wsId, lineId, code, name, sequenceNo: seq, status: 'ACTIVE' });
|
||
|
|
apsData.workstationOperations.push({ id: apsData.$utils.nextId('workstationOperation'), workstationId: wsId, operationId: Number(document.getElementById('ws_op').value), setupTime: 20, runTimePerUnit: 0.5, isPrimary: true });
|
||
|
|
apsData.$utils.save(apsData); closeModal(); showToast('保存成功'); render();
|
||
|
|
}
|
||
|
|
render();
|
||
|
|
</script>
|
||
|
|
</body>
|
||
|
|
</html>
|