'use strict'; const express = require('express'); const { getMkhBomList, getMkhBomDetail, listMkhBomExportRows, clearMkhBomCache, } = require('../services/mkhBomService'); const { getMkhReplenishAlertAdminConfig, resetMkhReplenishAlertState, saveMkhReplenishAlertConfig, } = require('../services/mkhReplenishAlertSettings'); const { checkMkhReplenishAlerts } = require('../jobs/mkhReplenishAlertJob'); const { saveYydNotificationCenterConfig, } = require('../services/yydNotificationCenterSettings'); const router = express.Router(); function sendError(res, error, fallback) { const status = Number(error?.statusCode) || 500; console.error('[MkhBom]', { message: error?.message || fallback, code: error?.code || null, status, }); res.status(status).json({ success: false, error: error.message || fallback }); } function buildSyncQuery(query = {}) { return { ...query, live: '1', fresh: '1' }; } // MKH-BOM 资料列表(模块化组合商品 + 配件汇总) router.get('/list', async (req, res) => { try { res.set('Cache-Control', 'no-store'); res.json({ success: true, data: await getMkhBomList(req.query || {}) }); } catch (error) { sendError(res, error, '加载 MKH-BOM 资料列表失败'); } }); // 单个 MKH 组合商品的 BOM 配件明细(打印用) router.get('/detail', async (req, res) => { try { const skuId = req.query?.skuId || req.query?.comboSkuId; res.set('Cache-Control', 'no-store'); res.json({ success: true, data: await getMkhBomDetail(skuId) }); } catch (error) { sendError(res, error, '加载 MKH-BOM 明细失败'); } }); // 导出:当前筛选条件下的全部数据(不分页) // mode=products(默认)→ 商品清单;mode=components → 配件明细摊平 router.get('/export', async (req, res) => { try { res.json({ success: true, data: await listMkhBomExportRows(req.query || {}) }); } catch (error) { sendError(res, error, '导出 MKH-BOM 资料失败'); } }); // 补货预警推送设置(接收人 / 开关 / 推送范围) router.get('/alert-config', async (req, res) => { try { res.json({ success: true, data: await getMkhReplenishAlertAdminConfig() }); } catch (error) { sendError(res, error, '加载补货预警推送设置失败'); } }); // 保存补货预警推送设置 router.put('/alert-config', async (req, res) => { try { const data = await saveMkhReplenishAlertConfig(req.body || {}); res.json({ success: true, data }); } catch (error) { sendError(res, error, '保存补货预警推送设置失败'); } }); // 立即检查并推送(dryRun: 只预览不发送;force: 忽略「只推新增」推全量;reset: 先清空已推送记录) router.post('/alert-check', async (req, res) => { try { const body = req.body || {}; if (body.reset === true) await resetMkhReplenishAlertState(); const result = await checkMkhReplenishAlerts({ dryRun: body.dryRun === true, force: body.force === true, }); res.json({ success: true, data: result }); } catch (error) { sendError(res, error, '执行补货预警推送失败'); } }); // 保存统一通知中心凭据(补货预警的推送通道) router.put('/notification-center', async (req, res) => { try { await saveYydNotificationCenterConfig(req.body || {}); res.json({ success: true, data: await getMkhReplenishAlertAdminConfig() }); } catch (error) { sendError(res, error, '保存统一通知中心配置失败'); } }); // 手动同步:先清空本页服务端缓存(BOM / 补货索引 / 加工单 / 待发货 / 配件库存 / 仓位), // 再在同一次请求中直连副本库读取新快照。这样不会被同步前尚未完成的旧列表请求覆盖。 router.post('/sync', async (req, res) => { try { const cache = clearMkhBomCache(); // fresh=1 是真正重读库存 / 加工单 / 待发货数据的协议。 // 只清缓存再传 live=1 会落到旧快照,导致按钮显示“同步成功”却数值不变。 const snapshot = await getMkhBomList(buildSyncQuery(req.body?.query)); res.set('Cache-Control', 'no-store'); res.json({ success: true, data: { cache, snapshot } }); } catch (error) { sendError(res, error, '同步 MKH-BOM 数据失败'); } }); module.exports = router; module.exports._private = { buildSyncQuery };