// 期初库存管理 (() => { let stockList = []; let currentPage = 1; const pageSize = 20; let editingId = null; Router.register('/plan-mgmt/initial-stock', async () => { const html = `
物料编码 物料名称 库存数量 单位 最小包装 供应商 备注 更新时间 操作
加载中...
`; setTimeout(() => { document.getElementById('add-stock-btn')?.addEventListener('click', () => openModal()); document.getElementById('import-stock-btn')?.addEventListener('click', () => showImportDialog()); document.getElementById('download-template-btn')?.addEventListener('click', () => downloadTemplate()); document.getElementById('batch-delete-btn')?.addEventListener('click', () => batchDelete()); document.getElementById('search-keyword')?.addEventListener('keypress', (e) => { if (e.key === 'Enter') InitialStock.search(); }); loadList(); }, 100); return html; }); function showImportDialog() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.xlsx,.xls,.csv'; input.onchange = async (e) => { const file = e.target.files[0]; if (!file) return; const formData = new FormData(); formData.append('file', file); try { const overlay = document.getElementById('overlay'); overlay.classList.remove('hidden'); const res = await fetch('/api/initial-stock/import', { method: 'POST', body: formData, credentials: 'include' }); overlay.classList.add('hidden'); const data = await res.json(); if (data.ok) { alert(data.message || '导入成功'); loadList(); } else { alert(data.error || '导入失败'); } } catch (err) { document.getElementById('overlay').classList.add('hidden'); alert('导入失败: ' + err.message); } }; input.click(); } function downloadTemplate() { const headers = ['物料编码', '物料名称', '库存数量', '单位', '最小包装', '供应商', '备注']; const example = ['PCB-001', '主控PCB板', '50', 'pcs', '10', '深圳电子', '']; const csvContent = [headers.join(','), example.join(',')].join('\n'); const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = '期初库存导入模板.csv'; link.click(); } async function loadList() { try { const res = await API.get('/api/initial-stock'); stockList = res.list || []; renderList(); } catch (e) { console.error('加载库存列表失败:', e); document.getElementById('stock-list').innerHTML = '加载失败'; } } function renderList() { const tbody = document.getElementById('stock-list'); const keyword = (document.getElementById('search-keyword')?.value || '').toLowerCase(); let filtered = stockList; if (keyword) { filtered = stockList.filter(item => (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 = '暂无数据'; } else { tbody.innerHTML = pageData.map(item => ` ${escapeHtml(item.material_code || '')} ${escapeHtml(item.material_name || '')} ${item.stock_qty || 0} ${escapeHtml(item.unit || 'pcs')} ${item.min_package || 1} ${escapeHtml(item.supplier || '-')} ${escapeHtml(item.remark || '-')} ${formatTime(item.updated_at)} `).join(''); } renderPagination(totalPages); } function renderPagination(totalPages) { const container = document.getElementById('pagination'); if (totalPages <= 1) { container.innerHTML = ''; return; } let html = ''; html += ``; html += `第 ${currentPage} / ${totalPages} 页`; html += ``; container.innerHTML = html; } function openModal(item = null) { editingId = item?.id || null; document.getElementById('modal-title').textContent = item ? '编辑期初库存' : '新增期初库存'; document.getElementById('material-code').value = item?.material_code || ''; document.getElementById('material-name').value = item?.material_name || ''; document.getElementById('stock-qty').value = item?.stock_qty || 0; document.getElementById('unit').value = item?.unit || 'pcs'; document.getElementById('min-package').value = item?.min_package || 1; document.getElementById('supplier').value = item?.supplier || ''; document.getElementById('remark').value = item?.remark || ''; document.getElementById('stock-modal').style.display = 'flex'; } function closeModal() { document.getElementById('stock-modal').style.display = 'none'; editingId = null; } async function save() { const data = { material_code: document.getElementById('material-code').value.trim(), material_name: document.getElementById('material-name').value.trim(), stock_qty: parseInt(document.getElementById('stock-qty').value) || 0, unit: document.getElementById('unit').value.trim() || 'pcs', min_package: parseInt(document.getElementById('min-package').value) || 1, supplier: document.getElementById('supplier').value.trim(), remark: document.getElementById('remark').value.trim() }; if (!data.material_code || !data.material_name) { alert('请填写物料编码和物料名称'); return; } try { if (editingId) { await API.put(`/api/initial-stock/${editingId}`, data); alert('更新成功'); } else { await API.post('/api/initial-stock', data); alert('创建成功'); } closeModal(); loadList(); } catch (e) { alert(e.message || '操作失败'); } } async function edit(id) { const item = stockList.find(x => x.id === id); if (item) openModal(item); } async function deleteStock(id) { if (!confirm('确定要删除这条库存记录吗?')) return; try { await API.delete(`/api/initial-stock/${id}`); alert('删除成功'); loadList(); } catch (e) { alert(e.message || '删除失败'); } } async function batchDelete() { const checked = document.querySelectorAll('.row-checkbox:checked'); if (checked.length === 0) { alert('请先选择要删除的项'); return; } if (!confirm(`确定要删除选中的 ${checked.length} 条库存记录吗?`)) return; const ids = Array.from(checked).map(cb => parseInt(cb.dataset.id)); try { await API.post('/api/initial-stock/batch-delete', { ids }); alert('批量删除成功'); loadList(); } catch (e) { alert(e.message || '批量删除失败'); } } function toggleSelectAll(checkbox) { document.querySelectorAll('.row-checkbox').forEach(cb => cb.checked = checkbox.checked); } 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, '"'); } window.InitialStock = { search, resetSearch, edit, delete: deleteStock, closeModal, save, toggleSelectAll, goPage }; })();