'use strict'; const express = require('express'); const multer = require('multer'); const { buildExportColumns, getReturnStockWarningExportRows, getReturnStockWarningList, resolveWarehouse, resolveWarehouseKey, } = require('../services/returnStockWarningService'); const { clearStockWarningImport, importStockWarning, } = require('../services/returnStockWarningImport'); const { sendWorkbookDownload } = require('../services/exportWorkbook'); const router = express.Router(); const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 20 * 1024 * 1024 }, }); const resolveScope = (value) => (['imported', 'replica'].includes(String(value)) ? String(value) : 'all'); /** * GET /api/return-stock-warning/list —— 退货库存预警列表(客退数据监控,按仓库出数) * warehouse: 仓库标识 henlin2 / subei / suining / shandong / henan(缺省 = 横林二仓) */ router.get('/list', async (req, res, next) => { try { const payload = await getReturnStockWarningList({ warehouse: req.query.warehouse, page: req.query.page, pageSize: req.query.pageSize, keyword: req.query.keyword, supplier: req.query.supplier, sortBy: req.query.sortBy, sortOrder: req.query.sortOrder, qtyBasis: req.query.qtyBasis, createdAtBasis: req.query.createdAtBasis, scope: resolveScope(req.query.scope), focusDays: req.query.focusDays, alertDays: req.query.alertDays, warningLevel: req.query.warningLevel, priceFocusMin: req.query.priceFocusMin, priceHighMin: req.query.priceHighMin, priceLevel: req.query.priceLevel, returnLimitDays: req.query.returnLimitDays, refresh: req.query.refresh, }); res.json({ success: true, data: payload }); } catch (error) { next(error); } }); /** GET /api/return-stock-warning/export —— 服务端全量导出(xlsx / csv) */ router.get('/export', async (req, res, next) => { try { const format = String(req.query.format || 'xlsx').toLowerCase() === 'csv' ? 'csv' : 'xlsx'; const keyword = String(req.query.keyword || '').trim(); const warehouse = resolveWarehouse(req.query.warehouse); const rows = await getReturnStockWarningExportRows({ warehouse: req.query.warehouse, keyword, supplier: req.query.supplier, qtyBasis: req.query.qtyBasis, createdAtBasis: req.query.createdAtBasis, scope: resolveScope(req.query.scope), focusDays: req.query.focusDays, alertDays: req.query.alertDays, warningLevel: req.query.warningLevel, priceFocusMin: req.query.priceFocusMin, priceHighMin: req.query.priceHighMin, priceLevel: req.query.priceLevel, returnLimitDays: req.query.returnLimitDays, refresh: req.query.refresh, }); const exportColumns = buildExportColumns(warehouse); sendWorkbookDownload(res, { fileName: `${warehouse.shortName}客退数据监控_${keyword || '全部'}`, format, sheets: [{ name: `${warehouse.shortName}客退数据监控`, header: exportColumns.map((column) => column.title), rows: rows.map((row) => exportColumns.map((column) => row[column.key])), }], }); } catch (error) { next(error); } }); /** POST /api/return-stock-warning/import —— 导入聚水潭「箱及仓位库存」导出文件 */ router.post('/import', 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 importStockWarning({ buffer: req.file.buffer, fileName, importedBy: req.user?.username || req.user?.name || null, // 导入落在哪个仓库下:优先取表单字段,其次 query,最后回落默认仓 warehouseKey: resolveWarehouseKey(req.body?.warehouse || req.query.warehouse), }); res.json({ success: true, data: result }); } catch (error) { next(error); } }); /** DELETE /api/return-stock-warning/import —— 清除当前仓库的导入,回到系统推算口径 */ router.delete('/import', async (req, res, next) => { try { const result = await clearStockWarningImport(resolveWarehouseKey(req.query.warehouse)); res.json({ success: true, data: result }); } catch (error) { next(error); } }); module.exports = router;