<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>总订单完成状况</title>
<style>
:root{
--bg:#f5faff;
--panel:#fff;
--border:#cce7ff;
--primary:#3ca9ff;
--primary-dark:#0077e6;
--primary-light:#e6f4ff;
--text:#003366;
--text-light:#0077e6;
--shadow:rgba(60,169,255,.12);
}
body{margin:0;background:var(--bg);font-family:"Segoe UI",Arial,"PingFang SC","Microsoft YaHei",sans-serif}
.status-container{max-width:98%;margin:22px auto;background:var(--panel);border:1px solid var(--border);padding:22px 18px 30px 18px;border-radius:12px;box-shadow:0 6px 30px var(--shadow);position:relative}
.status-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:18px;background:var(--bg)}
.status-header h3{color:var(--text-light);letter-spacing:2px}
.status-header .btns{display:flex;gap:12px}
.btn{padding:7px 18px;border:none;border-radius:4px;font-size:15px;cursor:pointer;background:var(--primary);color:#fff;transition:background .2s}
.btn:hover{background:var(--primary-dark)}
.btn.modify{background:var(--primary-light);color:var(--text)}
.btn.modify:hover{background:var(--primary-dark);color:#fff}
.search-box{display:flex;align-items:center;gap:8px}
.search-box input{height:32px;border:1px solid var(--primary);border-radius:4px;padding:0 10px;font-size:14px;background:#fff;color:var(--text)}
table{width:100%;border-collapse:collapse;font-size:14px;color:var(--text)}
thead{background-color:var(--primary-light);color:var(--text)}
th,td{border:1px solid var(--border);padding:9px 7px;text-align:center}
th{background:var(--primary-light);color:var(--text)}
tr:nth-child(even){background:var(--bg)}
.tag{border-radius:10px;padding:2px 10px;font-size:13px;display:inline-block}
.tag-success{background:#d0ffd0;color:#006100}
.tag-danger{background:#ffecec;color:#c00000;cursor:pointer}
td:last-child{white-space:nowrap;min-width:120px}
/* 弹窗 */
.modal-mask{position:fixed;left:0;top:0;width:100%;height:100%;background:rgba(0,119,230,.2);z-index:999;display:none}
.modal{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);background:#fff;min-width:360px;border-radius:8px;box-shadow:0 8px 32px rgba(60,169,255,.15);padding:22px;z-index:1000;display:none}
.modal-title{font-weight:bold;font-size:1.18rem;color:var(--primary-dark);margin-bottom:19px}
.modal-form-row{margin-bottom:13px;display:flex;align-items:center}
.modal-form-row label{width:86px;color:var(--text-light);font-size:14px}
.modal-form-row input,.modal-form-row select{flex:1;height:28px;padding:0 7px;border:1px solid var(--primary);border-radius:4px;background:var(--bg);color:var(--text)}
.modal-btns{text-align:right;margin-top:18px}
.modal-btns .btn{margin-left:12px;background:var(--primary)}
/* 分页 */
.pager-box{display:flex;align-items:center;gap:8px;position:absolute;right:22px;bottom:-80px;background:var(--primary-light);padding:6px 10px;border-radius:6px;box-shadow:0 2px 8px var(--shadow);font-size:14px;color:var(--text-light)}
.pager-label input{width:46px;height:24px;text-align:center;border:1px solid var(--primary);border-radius:4px;margin:0 4px;background:#fff;color:var(--text-light)}
</style>
</head>
<body>
<div class="status-container">
<div class="status-header">
<h3>总订单完成状况</h3>
<div class="btns">
<div class="search-box">
<input type="text" id="searchInput" placeholder="订单编号、产品名称...关键词查询">
<button class="btn" onclick="searchOrders()">查询</button>
</div>
<button class="btn" onclick="openAddModal()">增加</button>
</div>
</div>
<table>
<thead>
<tr>
<th>序号</th><th>销售类型</th><th>订单编号</th><th>产品编号</th><th>产品名称</th>
<th>订单数量</th><th>GTM要求交期</th><th>订单评审出货日期</th>
<th>电子料齐套</th><th>组装料齐套</th>
<th>SMT累计出货</th><th>SMT欠订单数</th><th>SMT工厂</th>
<th>组装累计出货</th><th>组装欠订单数</th><th>组装工厂</th>
<th>结单状况</th><th>备注</th><th>操作</th>
</tr>
</thead>
<tbody id="orderTableBody"><tr><td colspan="19">加载中...</td></tbody>
</table>
<div id="pagerBox" class="pager-box">
<button class="btn" id="btnPrev" onclick="prevPage()">上一页</button>
<label class="pager-label">
第<input type="number" id="pageInput" min="1" max="1" value="1"
onkeydown="if(event.key==='Enter') jumpToPage()">页 / 共<span id="totalPages">1</span>页
</label>
<button class="btn" id="btnNext" onclick="nextPage()">下一页</button>
<button class="btn modify" onclick="jumpToPage()">跳转</button>
</div>
</div>
<!-- 订单弹窗 -->
<div class="modal-mask" id="modalMask"></div>
<div class="modal" id="modalBox">
<div class="modal-title" id="modalTitle">新增订单</div>
<form id="modalForm">
<div class="modal-form-row"><label>销售类型</label><input name="saleType" required></div>
<div class="modal-form-row"><label>订单编号</label><input name="orderNo" required></div>
<div class="modal-form-row"><label>产品编号</label><input name="productNo" required></div>
<div class="modal-form-row"><label>产品名称</label><input name="productName" required></div>
<div class="modal-form-row"><label>订单数量</label><input type="number" name="orderQuantity" required></div>
<div class="modal-form-row"><label>GTM交期</label><input type="date" name="gtmDueDate"></div>
<div class="modal-form-row"><label>评审出货日期</label><input type="date" name="reviewShipDate"></div>
<div class="modal-form-row"><label>电子料齐套</label>
<select name="materialElectronic"><option value="1">齐套</option><option value="0">未齐套</option></select></div>
<div class="modal-form-row"><label>组装料齐套</label>
<select name="materialAssembly"><option value="1">齐套</option><option value="0">未齐套</option></select></div>
<div class="modal-form-row"><label>SMT累计出货</label><input type="number" name="smtShippedQty"></div>
<div class="modal-form-row"><label>SMT欠订单数</label><input type="number" name="smtOwedQty"></div>
<div class="modal-form-row"><label>SMT工厂</label><input name="smtFactory"></div>
<div class="modal-form-row"><label>组装累计出货</label><input type="number" name="assemblyShippedQty"></div>
<div class="modal-form-row"><label>组装欠订单数</label><input type="number" name="assemblyOwedQty"></div>
<div class="modal-form-row"><label>组装工厂</label><input name="assemblyFactory"></div>
<div class="modal-form-row"><label>接单状况</label><input name="receiveStatus"></div>
<div class="modal-form-row"><label>备注</label><input name="remark"></div>
<div class="modal-btns">
<button type="button" class="btn" onclick="closeModal()">取消</button>
<button type="submit" class="btn modify" id="modalSubmitBtn">保存</button>
</div>
</form>
</div>
<!-- 通用 BOM 详情弹窗 -->
<div class="modal-mask" id="bomModalMask"></div>
<div class="modal" id="bomModalBox">
<div class="modal-title" id="bomModalTitle">BOM 齐套详情</div>
<form id="bomModalForm">
<input type="hidden" id="bomType">
<input type="hidden" id="bomOrderNo">
<div class="modal-form-row">
<label>BOM 版本</label>
<select id="bomVersionSelect" required></select>
</div>
<!-- 物料编码 -->
<div class="modal-form-row">
<label>物料编码</label>
<input type="text" id="materialCode" required placeholder="请输入物料编码">
</div>
<!-- 物料名称 -->
<div class="modal-form-row">
<label>物料名称</label>
<input type="text" id="materialName" required placeholder="如:贴片电阻">
</div>
<!-- 规格 -->
<div class="modal-form-row">
<label>规格</label>
<input type="text" id="specification" placeholder="如:0603 1KΩ ±1%">
</div>
<!-- 技术参数 -->
<div class="modal-form-row">
<label>技术参数</label>
<input type="text" id="technicalParam" placeholder="如:阻值范围/温度系数">
</div>
<!-- 参数值 -->
<div class="modal-form-row">
<label>参数值</label>
<input type="text" id="paramValue" placeholder="如:1KΩ/±100ppm/℃">
</div>
<!-- 用量 -->
<div class="modal-form-row">
<label>用量</label>
<input type="number" id="quantity" required min="1" placeholder="单个产品所需数量">
</div>
<!-- 制造商 -->
<div class="modal-form-row">
<label>制造商</label>
<input type="number" id="manufacturerSelect" required min="1" placeholder="单个产品所需数量">
</div>
<!-- 制造商料号 -->
<div class="modal-form-row">
<label>制造商料号</label>
<input type="text" id="mpn" required placeholder="如:RC0603FR-071KL">
</div>
<div class="modal-btns">
<button type="button" class="btn" onclick="closeBomModal()">取消</button>
<button type="submit" class="btn modify">保存</button>
</div>
</form>
</div>
<!-- 电子料齐套弹窗 -->
<div class="modal-mask" id="eBomModalMask"></div>
<div class="modal" id="eBomModalBox">
<div class="modal-title">电子料齐套详情</div>
<form id="eBomModalForm">
<div class="modal-form-row"><label>订单编号</label><input id="eBomOrderNo" readonly></div>
<div class="modal-form-row"><label>BOM版本</label><select id="eBomVersionSelect" required></select></div>
<div class="modal-form-row"><label>订单数量</label><input type="number" id="eBomOrderQty" min="1" required></div>
<div class="modal-btns">
<button type="button" class="btn" onclick="closeEBomModal()">取消</button>
<button type="submit" class="btn modify">保存</button>
</div>
</form>
</div>
<script>
let editingId = null, allOrders = [], currentPage = 1, totalPages = 1;
const eBomQtyCache = {}; // 已录入电子料齐套数量缓存
async function request(url, method='GET', body=null){
const res = await fetch(url, {
method,
headers: body ? {'Content-Type':'application/json'} : {},
body: body ? JSON.stringify(body) : undefined
});
return res.json();
}
async function loadOrders(keyword, page){
const tbody=document.getElementById('orderTableBody');
tbody.innerHTML='<tr><td colspan="19">加载中...</td></tr>';
try{
let url=`/api/orders?page=${page}&size=10`;
if(keyword) url+=`&keyword=${encodeURIComponent(keyword)}`;
const data=await request(url);
allOrders=data.records;
renderOrders(data.records);
currentPage=data.current; totalPages=data.pages;
updatePager();
}catch(e){ tbody.innerHTML='<tr><td colspan="19">加载失败</td></tr>'; }
}
function renderOrders(data){
const tbody=document.getElementById('orderTableBody');
if(!data.length){ tbody.innerHTML='<tr><td colspan="19">暂无数据</td></tr>'; return; }
tbody.innerHTML=data.map(r=>`
<tr>
<td>${r.id}</td><td>${r.saleType||'-'}</td><td>${r.orderNo||'-'}</td><td>${r.productNo||'-'}</td><td>${r.productName||'-'}</td>
<td>${r.orderQuantity??'-'}</td><td>${r.gtmDueDate||'-'}</td><td>${r.reviewShipDate||'-'}</td>
<!-- 电子料齐套列:未齐套可点击 -->
<td>
<span class="tag ${r.materialElectronic?'tag-success':'tag-danger'}"
style="cursor:${r.materialElectronic?'default':'pointer'}"
onclick="${!r.materialElectronic?`openEBomDetailModal('${r.orderNo}',${r.orderQuantity||0})`:''}">
${r.materialElectronic?'齐套':'未齐套'}
</span>
<button class="btn modify"
style="font-size:12px;padding:2px 8px"
onclick="openEBomDetailTable('${r.orderNo}')">详情</button>
</td>
<!-- 组装料齐套列:保持原状 -->
<td>
<span class="tag ${r.materialAssembly?'tag-success':'tag-danger'}">
${r.materialAssembly?'齐套':'未齐套'}
</span>
<button class="btn modify"
style="font-size:12px;padding:2px 8px"
onclick="openBomDetail('assembly','${r.orderNo}',${r.orderQuantity||0})">
详情
</button>
</td>
<td>${r.smtShippedQty??'-'}</td><td>${r.smtOwedQty??'-'}</td><td>${r.smtFactory||'-'}</td>
<td>${r.assemblyShippedQty??'-'}</td><td>${r.assemblyOwedQty??'-'}</td><td>${r.assemblyFactory||'-'}</td>
<td>${r.receiveStatus||'-'}</td><td>${r.remark||'-'}</td>
<td>
<button class="btn modify" onclick="openEditModal(${r.id})">修改</button>
<button class="btn" style="margin-left:6px;background:#f56c6c" onclick="deleteOrder(${r.id})">删除</button>
</td>
</tr>`).join('');
}
function searchOrders(){loadOrders(document.getElementById('searchInput').value.trim(),1);}
function updatePager(){
const p=document.getElementById('pageInput');
p.max=totalPages; p.value=currentPage;
document.getElementById('totalPages').textContent=totalPages;
document.getElementById('btnPrev').disabled=currentPage<=1;
document.getElementById('btnNext').disabled=currentPage>=totalPages;
}
function jumpToPage(){
const v=parseInt(document.getElementById('pageInput').value,10);
if(v>=1&&v<=totalPages) loadOrders(document.getElementById('searchInput').value.trim(),v);
}
function prevPage(){if(currentPage>1) loadOrders(document.getElementById('searchInput').value.trim(),currentPage-1);}
function nextPage(){if(currentPage<totalPages) loadOrders(document.getElementById('searchInput').value.trim(),currentPage+1);}
/* 订单弹窗 */
function openAddModal(){editingId=null;resetModal('新增订单');}
function openEditModal(id){
editingId=id; const r=allOrders.find(r=>r.id===id);
resetModal('修改订单',r);
}
function resetModal(title,data={}){
document.getElementById('modalTitle').textContent=title;
const f=document.getElementById('modalForm'); f.reset();
for(const k in data) if(f[k]!==undefined) f[k].value=data[k];
document.getElementById('modalMask').style.display='block';
document.getElementById('modalBox').style.display='block';
}
function closeModal(){
document.getElementById('modalMask').style.display='none';
document.getElementById('modalBox').style.display='none';
}
document.getElementById('modalMask').onclick=closeModal;
document.getElementById('modalForm').onsubmit=async e=>{
e.preventDefault();
const fd=new FormData(e.target);
const data=Object.fromEntries(fd);
data.materialElectronic=data.materialElectronic==='1';
data.materialAssembly=data.materialAssembly==='1';
['orderQuantity','smtShippedQty','smtOwedQty','assemblyShippedQty','assemblyOwedQty']
.forEach(k=>{if(data[k])data[k]=Number(data[k]);});
try{
const url=editingId?`/api/orders/${editingId}`:'/api/orders';
const meth=editingId?'PUT':'POST';
await request(url,meth,data);
closeModal(); loadOrders('',currentPage);
}catch{alert('保存失败');}
};
async function deleteOrder(id){
if(!confirm(`确定删除订单 ${id} 吗?`)) return;
try{
await request(`/api/orders/${id}`,'DELETE');
loadOrders(document.getElementById('searchInput').value.trim(),currentPage);
}catch{alert('删除失败');}
}
/* ========= 通用 BOM 弹窗 ========= */
function openBomDetail(type, orderNo, orderQty){
document.getElementById('bomType').value = type; // electronic / assembly
document.getElementById('bomOrderNo').value = orderNo;
document.getElementById('bomModalTitle').textContent =
(type === 'electronic' ? '电子料' : '组装料') + '齐套详情';
/* 拉取或初始化数据 */
fetchBomDetail(type, orderNo).then(data=>{
fillBomModal(data, orderQty);
document.getElementById('bomModalMask').style.display='block';
document.getElementById('bomModalBox').style.display='block';
});
}
async function fetchBomDetail(type, orderNo){
// 调用后端接口,返回 {bomVersion, orderQty, needQty, oweQty}
const res = await request(`/api/bom_detail/${type}/${orderNo}`);
return res || {};
}
function fillBomModal(data, orderQty){
/* 版本下拉 */
const sel=document.getElementById('bomVersionSelect');
sel.innerHTML='';
const versions = JSON.parse(localStorage.getItem('eBomVersions')||'[]');
versions.forEach(v=>{
const opt=document.createElement('option');
opt.value=opt.textContent=v;
if(v===data.bomVersion) opt.selected=true;
sel.appendChild(opt);
});
document.getElementById('bomOrderQty').value = data.orderQty ?? orderQty;
document.getElementById('bomNeedQty').value = data.needQty ?? 0;
document.getElementById('bomOweQty').value = data.oweQty ?? 0;
}
function closeBomModal(){
document.getElementById('bomModalMask').style.display='none';
document.getElementById('bomModalBox').style.display='none';
}
document.getElementById('bomModalMask').onclick = closeBomModal;
/* 保存 */
document.getElementById('bomModalForm').addEventListener('submit', async e=>{
e.preventDefault();
const type = document.getElementById('bomType').value;
const orderNo= document.getElementById('bomOrderNo').value;
const payload = {
bomVersion : document.getElementById('bomVersionSelect').value,
orderQty : Number(document.getElementById('bomOrderQty').value),
needQty : Number(document.getElementById('bomNeedQty').value),
oweQty : Number(document.getElementById('bomOweQty').value)
};
try{
await request(`/api/bom_detail/${type}/${orderNo}`, 'POST', payload);
alert('保存成功');
closeBomModal();
}catch{ alert('保存失败'); }
});
/* 电子料齐套弹窗 */
function openEBomDetailModal(orderNo,orderQty){
document.getElementById('eBomOrderNo').value=orderNo;
const cached=eBomQtyCache[orderNo]||0;
document.getElementById('eBomOrderQty').value=cached;
document.getElementById('eBomOrderQty').min=cached;
const sel=document.getElementById('eBomVersionSelect');
sel.innerHTML='';
const versions=JSON.parse(localStorage.getItem('eBomVersions')||'[]');
if(!versions.length){alert('请先打开“电子料 BOM 明细”页面以同步 BOM 版本数据');return;}
versions.forEach(v=>{
const opt=document.createElement('option');
opt.value=opt.textContent=v;
sel.appendChild(opt);
});
document.getElementById('eBomModalMask').style.display='block';
document.getElementById('eBomModalBox').style.display='block';
}
function closeEBomModal(){
document.getElementById('eBomModalMask').style.display='none';
document.getElementById('eBomModalBox').style.display='none';
}
document.getElementById('eBomModalMask').onclick=closeEBomModal;
document.getElementById('eBomModalForm').addEventListener('submit',async e=>{
e.preventDefault();
const orderNo=document.getElementById('eBomOrderNo').value.trim();
const bomVersion=document.getElementById('eBomVersionSelect').value;
const qty=Number(document.getElementById('eBomOrderQty').value);
const cached=eBomQtyCache[orderNo]||0;
if(qty<cached){alert('订单数量只能增加,不能减少!');return;}
try{
await request('/api/electronic_bom_detail','POST',{orderNo,bomVersion,orderQty:qty});
eBomQtyCache[orderNo]=qty;
alert('保存成功'); closeEBomModal();
}catch{alert('保存失败');}
});
loadOrders('',1);
</script>
</body>
</html>能不能给我当点击未齐套时页面跳转的具体流程,当我单击详情时该怎么实现页面跳转