264 lines
8.2 KiB
JavaScript
264 lines
8.2 KiB
JavaScript
// 委外在制库存查询
|
|
(() => {
|
|
let wipStockList = [];
|
|
let currentPage = 1;
|
|
const pageSize = 20;
|
|
|
|
Router.register('/outsourcing-mgmt/wip-stock', async () => {
|
|
const html = `
|
|
<style>
|
|
#wip-stock-page .page-header {
|
|
padding: 20px;
|
|
background: var(--surface);
|
|
border-bottom: 1px solid var(--border);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
#wip-stock-page .content-area {
|
|
flex: 1;
|
|
padding: 20px;
|
|
overflow: hidden;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
#wip-stock-page .table-wrapper {
|
|
flex: 1;
|
|
overflow: auto;
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: 12px;
|
|
}
|
|
|
|
#wip-stock-page table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin: 0;
|
|
}
|
|
|
|
#wip-stock-page thead {
|
|
background: var(--border);
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 10;
|
|
}
|
|
|
|
#wip-stock-page th {
|
|
padding: 8px 12px;
|
|
text-align: left;
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
border-bottom: 2px solid var(--border);
|
|
font-size: 14px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
#wip-stock-page td {
|
|
padding: 8px 12px;
|
|
border-bottom: 1px solid var(--border);
|
|
color: var(--text);
|
|
font-size: 14px;
|
|
}
|
|
|
|
#wip-stock-page tbody tr:hover {
|
|
background: var(--hover);
|
|
}
|
|
|
|
#wip-stock-page .summary-card {
|
|
background: linear-gradient(135deg, var(--primary) 0%, var(--info) 100%);
|
|
color: white;
|
|
padding: 20px;
|
|
border-radius: 12px;
|
|
margin-bottom: 20px;
|
|
display: flex;
|
|
justify-content: space-around;
|
|
align-items: center;
|
|
}
|
|
|
|
#wip-stock-page .summary-item {
|
|
text-align: center;
|
|
}
|
|
|
|
#wip-stock-page .summary-item .label {
|
|
font-size: 14px;
|
|
opacity: 0.9;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
#wip-stock-page .summary-item .value {
|
|
font-size: 32px;
|
|
font-weight: bold;
|
|
}
|
|
</style>
|
|
|
|
<div id="wip-stock-page">
|
|
<div class="page-header">
|
|
<h1 style="margin: 0; font-size: 24px;">委外在制库存</h1>
|
|
<p style="margin: 8px 0 0 0; color: var(--text-2); font-size: 14px;">
|
|
显示已发给外协厂但尚未完工入库的物料库存
|
|
</p>
|
|
</div>
|
|
|
|
<div class="content-area">
|
|
<div class="summary-card">
|
|
<div class="summary-item">
|
|
<div class="label">物料种类</div>
|
|
<div class="value" id="material-count">0</div>
|
|
</div>
|
|
<div class="summary-item">
|
|
<div class="label">在制总数量</div>
|
|
<div class="value" id="total-wip-qty">0</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="filter-section" style="padding: 20px; display: flex; gap: 15px; align-items: center;">
|
|
<input type="text" id="search-keyword" class="input" placeholder="搜索委外工单号或物料" style="flex: 1; max-width: 400px;" />
|
|
<button class="btn btn-secondary" onclick="OutsourcingWipStock.search()">搜索</button>
|
|
<button class="btn btn-secondary" onclick="OutsourcingWipStock.resetSearch()">重置</button>
|
|
<button class="btn btn-primary" onclick="OutsourcingWipStock.loadList()">刷新</button>
|
|
</div>
|
|
|
|
<div class="table-wrapper">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>委外工单号</th>
|
|
<th>物料编码</th>
|
|
<th>物料名称</th>
|
|
<th>在制数量</th>
|
|
<th>单位</th>
|
|
<th>更新时间</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="wip-stock-list">
|
|
<tr><td colspan="6" class="text-center">加载中...</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="pagination" id="pagination" style="padding: 20px; display: flex; justify-content: center; gap: 8px;"></div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
setTimeout(() => {
|
|
document.getElementById('search-keyword')?.addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter') search();
|
|
});
|
|
loadList();
|
|
}, 0);
|
|
|
|
return html;
|
|
});
|
|
|
|
async function loadList() {
|
|
try {
|
|
const res = await API.get('/api/outsourcing-wip-stock');
|
|
wipStockList = res.list || [];
|
|
updateSummary();
|
|
renderList();
|
|
} catch (e) {
|
|
console.error('加载委外在制库存失败:', e);
|
|
document.getElementById('wip-stock-list').innerHTML = '<tr><td colspan="6" class="text-center" style="color: var(--danger);">加载失败</td></tr>';
|
|
}
|
|
}
|
|
|
|
function updateSummary() {
|
|
const materialCount = wipStockList.length;
|
|
const totalWipQty = wipStockList.reduce((sum, item) => sum + (item.wip_qty || 0), 0);
|
|
|
|
const materialCountEl = document.getElementById('material-count');
|
|
const totalWipQtyEl = document.getElementById('total-wip-qty');
|
|
|
|
if (materialCountEl) materialCountEl.textContent = materialCount;
|
|
if (totalWipQtyEl) totalWipQtyEl.textContent = totalWipQty;
|
|
}
|
|
|
|
function renderList() {
|
|
const tbody = document.getElementById('wip-stock-list');
|
|
const keyword = (document.getElementById('search-keyword')?.value || '').toLowerCase();
|
|
|
|
let filtered = wipStockList;
|
|
if (keyword) {
|
|
filtered = wipStockList.filter(item =>
|
|
(item.outsourcing_order_no || '').toLowerCase().includes(keyword) ||
|
|
(item.material_code || '').toLowerCase().includes(keyword) ||
|
|
(item.material_name || '').toLowerCase().includes(keyword)
|
|
);
|
|
}
|
|
|
|
const totalPages = Math.ceil(filtered.length / pageSize);
|
|
const start = (currentPage - 1) * pageSize;
|
|
const pageData = filtered.slice(start, start + pageSize);
|
|
|
|
if (pageData.length === 0) {
|
|
tbody.innerHTML = '<tr><td colspan="6" class="text-center">暂无在制库存</td></tr>';
|
|
} else {
|
|
tbody.innerHTML = pageData.map(item => `
|
|
<tr>
|
|
<td><span style="font-family: monospace; font-size: 12px;">${escapeHtml(item.outsourcing_order_no || '')}</span></td>
|
|
<td>${escapeHtml(item.material_code || '')}</td>
|
|
<td>${escapeHtml(item.material_name || '')}</td>
|
|
<td style="font-weight: 600; color: var(--warning);">${item.wip_qty || 0}</td>
|
|
<td>${escapeHtml(item.unit || 'pcs')}</td>
|
|
<td>${formatTime(item.updated_at)}</td>
|
|
</tr>
|
|
`).join('');
|
|
}
|
|
|
|
renderPagination(totalPages);
|
|
}
|
|
|
|
function renderPagination(totalPages) {
|
|
const container = document.getElementById('pagination');
|
|
if (totalPages <= 1) {
|
|
container.innerHTML = '';
|
|
return;
|
|
}
|
|
|
|
let html = '';
|
|
html += `<button class="btn btn-sm btn-secondary" ${currentPage <= 1 ? 'disabled' : ''} onclick="OutsourcingWipStock.goPage(${currentPage - 1})">上一页</button>`;
|
|
html += `<span style="padding: 0 12px; line-height: 32px;">第 ${currentPage} / ${totalPages} 页</span>`;
|
|
html += `<button class="btn btn-sm btn-secondary" ${currentPage >= totalPages ? 'disabled' : ''} onclick="OutsourcingWipStock.goPage(${currentPage + 1})">下一页</button>`;
|
|
container.innerHTML = html;
|
|
}
|
|
|
|
function search() {
|
|
currentPage = 1;
|
|
renderList();
|
|
}
|
|
|
|
function resetSearch() {
|
|
document.getElementById('search-keyword').value = '';
|
|
currentPage = 1;
|
|
renderList();
|
|
}
|
|
|
|
function goPage(page) {
|
|
currentPage = page;
|
|
renderList();
|
|
}
|
|
|
|
function formatTime(ts) {
|
|
if (!ts) return '-';
|
|
try {
|
|
const d = new Date(ts);
|
|
return d.toLocaleString('zh-CN', { hour12: false });
|
|
} catch {
|
|
return ts;
|
|
}
|
|
}
|
|
|
|
function escapeHtml(str) {
|
|
if (!str) return '';
|
|
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
}
|
|
|
|
window.OutsourcingWipStock = {
|
|
search,
|
|
resetSearch,
|
|
goPage,
|
|
loadList
|
|
};
|
|
})();
|