'use strict'; const express = require('express'); const multer = require('multer'); const { clearPickBins, getPickBinMeta, getReplenishExportRows, getReplenishList, importPickBins, resolveWarehouseKey, } = require('../services/binReplenishService'); const { sendWorkbookDownload } = require('../services/exportWorkbook'); const router = express.Router(); const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 20 * 1024 * 1024 }, }); const EXPORT_COLUMNS = [ { key: 'skuId', title: '商品编码' }, { key: 'productName', title: '品名' }, { key: 'supplier', title: '供应商' }, { key: 'statusLabel', title: '状态' }, { key: 'pickQty', title: '拣货位库存' }, { key: 'storageQty', title: '存货位库存' }, { key: 'totalQty', title: '现有库存合计' }, { key: 'targetQty', title: '目标拣货位库存' }, { key: 'suggestQty', title: '建议补货量' }, { key: 'avgSale', title: '近15天日销' }, { key: 'pickBinText', title: '拣货位(货位号/数量)' }, { key: 'storageBinText', title: '存货位(前5个/数量)' }, ]; /** GET /api/bin-replenish/list —— 缺货补货监控列表 */ router.get('/list', async (req, res, next) => { try { const payload = await getReplenishList({ warehouse: req.query.warehouse, keyword: req.query.keyword, status: req.query.status, page: req.query.page, pageSize: req.query.pageSize, targetDays: req.query.targetDays, refresh: req.query.refresh, }); res.json({ success: true, data: payload }); } catch (error) { next(error); } }); /** GET /api/bin-replenish/export —— 服务端全量导出 */ router.get('/export', async (req, res, next) => { try { const format = String(req.query.format || 'xlsx').toLowerCase() === 'csv' ? 'csv' : 'xlsx'; const payload = await getReplenishExportRows({ warehouse: req.query.warehouse, keyword: req.query.keyword, status: req.query.status, targetDays: req.query.targetDays, }); const rows = payload.rows.map((row) => ({ ...row, pickBinText: (row.pickBins || []).map((item) => `${item.bin}(${item.qty})`).join('、'), storageBinText: (row.storageBins || []).map((item) => `${item.bin}(${item.qty})`).join('、'), })); sendWorkbookDownload(res, { fileName: `${payload.warehouse.shortName}缺货补货监控_${new Date().toISOString().slice(0, 10)}`, format, sheets: [{ name: '缺货补货监控', header: EXPORT_COLUMNS.map((column) => column.title), rows: rows.map((row) => EXPORT_COLUMNS.map((column) => row[column.key])), }], }); } catch (error) { next(error); } }); /** GET /api/bin-replenish/pick-bins —— 当前仓库的拣货位清单概况 */ router.get('/pick-bins', async (req, res, next) => { try { const meta = await getPickBinMeta(resolveWarehouseKey(req.query.warehouse)); res.json({ success: true, data: meta }); } catch (error) { next(error); } }); /** POST /api/bin-replenish/pick-bins —— 导入拣货位清单(xlsx / xls / csv / txt) */ router.post('/pick-bins', upload.single('file'), async (req, res, next) => { try { if (!req.file || !req.file.buffer) { res.status(400).json({ success: false, message: '请选择要导入的货位清单文件(xlsx / xls / csv)' }); return; } // multer 按 latin1 解析 multipart 文件名,中文会乱码,这里转回 UTF-8 const rawName = req.file.originalname || ''; const fileName = /[\u00c0-\u00ff]/.test(rawName) ? Buffer.from(rawName, 'latin1').toString('utf8') : rawName; const result = await importPickBins({ buffer: req.file.buffer, fileName, warehouseKey: req.body?.warehouse || req.query.warehouse, importedBy: req.user?.username || req.user?.name || null, }); res.json({ success: true, data: result }); } catch (error) { next(error); } }); /** DELETE /api/bin-replenish/pick-bins —— 清除货位清单,回到回退口径 */ router.delete('/pick-bins', async (req, res, next) => { try { const result = await clearPickBins(req.query.warehouse); res.json({ success: true, data: result }); } catch (error) { next(error); } }); /** GET /api/bin-replenish/ping —— 路由存活探针(401 也代表已注册) */ router.get('/ping', (req, res) => { res.json({ success: true, data: { ok: true } }); }); module.exports = router;