ERP/frontend/js/components/outsourcing-wip-stock.js

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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
window.OutsourcingWipStock = {
search,
resetSearch,
goPage,
loadList
};
})();