diff --git a/backend/src/api/mkhBom.js b/backend/src/api/mkhBom.js index afe8956..9614490 100644 --- a/backend/src/api/mkhBom.js +++ b/backend/src/api/mkhBom.js @@ -5,6 +5,7 @@ const { getMkhBomList, getMkhBomDetail, listMkhBomExportRows, + clearMkhBomCache, } = require('../services/mkhBomService'); const { getMkhReplenishAlertAdminConfig, @@ -101,4 +102,14 @@ router.put('/notification-center', async (req, res) => { } }); +// 手动同步:清空本页服务端缓存(BOM / 补货索引 / 加工单 / 待发货 / 配件库存 / 仓位), +// 前端「同步」按钮调用后再拉一次列表即可直连副本库取最新快照 +router.post('/sync', async (_req, res) => { + try { + res.json({ success: true, data: clearMkhBomCache() }); + } catch (error) { + sendError(res, error, '同步 MKH-BOM 数据失败'); + } +}); + module.exports = router; diff --git a/backend/src/api/modularStockMonitor.js b/backend/src/api/modularStockMonitor.js index ce34dd1..6139f06 100644 --- a/backend/src/api/modularStockMonitor.js +++ b/backend/src/api/modularStockMonitor.js @@ -4,6 +4,7 @@ const express = require('express'); const { getModularStockList, getModularStockFilters, + syncModularStock, } = require('../services/modularStockMonitorService'); const router = express.Router(); @@ -36,4 +37,13 @@ router.get('/filters', async (_req, res) => { } }); +// 手动同步:重新取最新监控日,前端「同步」按钮调用后再拉一次列表即拿到最新快照 +router.post('/sync', async (_req, res) => { + try { + res.json({ success: true, data: await syncModularStock() }); + } catch (error) { + sendError(res, error, '同步配件库存监控数据失败'); + } +}); + module.exports = router; diff --git a/backend/src/services/mkhBomService.js b/backend/src/services/mkhBomService.js index ed4a607..d74260b 100644 --- a/backend/src/services/mkhBomService.js +++ b/backend/src/services/mkhBomService.js @@ -1947,8 +1947,37 @@ async function listMkhBomExportRows(query = {}) { }; } +// 手动同步:清空本页全部服务端缓存(BOM / 补货索引 / 加工单 / 待发货 / 配件库存 / 配件仓位)。 +// 页面「同步」按钮调用——清掉后下一次查询直连副本库,拿到的是上游最新快照, +// 而不是 2~15 分钟前的缓存结果。 +// 注意:副本库本身由聚水潭侧同步,应用层无法触发上游拉取,本函数只保证「不读旧缓存」。 +function clearMkhBomCache() { + businessBomCache = null; + officialBomIndexCache = null; + productBomCache = null; + mkhProductCache = null; + replenishIndexCache = null; + workOrderIndexCache = null; + pendingOrderIndexCache = null; + + const cleared = [ + ['officialBomDetailCache', officialBomDetailCache.size], + ['componentLocationCache', componentLocationCache.size], + ['componentStockCache', componentStockCache.size], + ]; + officialBomDetailCache.clear(); + componentLocationCache.clear(); + componentStockCache.clear(); + + return { + syncedAt: new Date().toISOString(), + cleared: cleared.map(([name, entries]) => ({ name, entries })), + }; +} + module.exports = { getMkhBomList, + clearMkhBomCache, getMkhBomDetail, listReplenishAlertRows, listMkhBomExportRows, diff --git a/backend/src/services/modularStockMonitorService.js b/backend/src/services/modularStockMonitorService.js index 5b3d0da..b436771 100644 --- a/backend/src/services/modularStockMonitorService.js +++ b/backend/src/services/modularStockMonitorService.js @@ -445,6 +445,17 @@ async function getModularStockFilters() { }; } +// 手动同步:本页无进程内缓存(每次请求直连副本库),同步动作 = 重新解析监控日并返回, +// 前端据此刷新列表到最新快照。 +// 注意:副本库由聚水潭侧同步,应用层无法触发上游拉取,这里只保证取到最新监控日。 +async function syncModularStock() { + const monitorDate = await resolveMonitorDate(); + return { + syncedAt: new Date().toISOString(), + monitorDate, + }; +} + module.exports = { WAREHOUSE_NAME, WAREHOUSE_WMS_CO_ID, @@ -452,4 +463,5 @@ module.exports = { DEFAULT_SAFETY_DAYS, getModularStockList, getModularStockFilters, + syncModularStock, }; diff --git a/frontend/src/api/mkhBom.js b/frontend/src/api/mkhBom.js index fdd3341..4d61416 100644 --- a/frontend/src/api/mkhBom.js +++ b/frontend/src/api/mkhBom.js @@ -45,3 +45,11 @@ export const saveMkhNotificationCenter = (payload = {}) => request.put( '/api/mkh-bom/notification-center', payload ); + +// 手动同步:清空服务端缓存(BOM / 补货索引 / 加工单 / 待发货 / 配件库存 / 仓位), +// 随后重新拉列表即直连副本库取最新快照,可随时点击 +export const syncMkhBom = () => request.post( + '/api/mkh-bom/sync', + null, + { timeout: LIST_TIMEOUT_MS } +); diff --git a/frontend/src/api/modularStockMonitor.js b/frontend/src/api/modularStockMonitor.js index 19257e7..ec44585 100644 --- a/frontend/src/api/modularStockMonitor.js +++ b/frontend/src/api/modularStockMonitor.js @@ -14,3 +14,10 @@ export const getModularStockFilters = () => request.get( '/api/modular-stock-monitor/filters', { timeout: META_TIMEOUT_MS } ); + +// 手动同步:后端重新取最新监控日,前端随后再拉一次列表即拿到最新快照 +export const syncModularStock = () => request.post( + '/api/modular-stock-monitor/sync', + null, + { timeout: META_TIMEOUT_MS } +); diff --git a/frontend/src/pages/MkhBomData/index.jsx b/frontend/src/pages/MkhBomData/index.jsx index 0fd2e30..33968da 100644 --- a/frontend/src/pages/MkhBomData/index.jsx +++ b/frontend/src/pages/MkhBomData/index.jsx @@ -4,7 +4,7 @@ import { Table, Tooltip, Typography, message, } from 'antd'; import { - BellOutlined, DownloadOutlined, PrinterOutlined, ReloadOutlined, SearchOutlined, + BellOutlined, DownloadOutlined, PrinterOutlined, ReloadOutlined, SearchOutlined, SyncOutlined, } from '@ant-design/icons'; import { SycmPage } from '../../components/Common'; import { @@ -15,6 +15,7 @@ import { saveMkhReplenishAlertConfig, saveMkhNotificationCenter, checkMkhReplenishAlert, + syncMkhBom, } from '../../api/mkhBom'; import { exportTableFile } from '../../utils/tableExport'; import './style.css'; @@ -233,6 +234,7 @@ const MkhBomData = () => { // 导出(当前筛选条件下的全部数据) const [exporting, setExporting] = useState(false); + const [syncing, setSyncing] = useState(false); // 补货预警推送设置 const [alertOpen, setAlertOpen] = useState(false); @@ -718,6 +720,22 @@ const MkhBomData = () => { ); }; + // 手动同步:清掉服务端缓存(BOM / 补货索引 / 加工单 / 待发货 / 配件库存 / 仓位), + // 再拉一次列表即可直连副本库取最新快照;可随时点击,不必等凌晨的定时刷新 + const handleSync = async () => { + setSyncing(true); + try { + await syncMkhBom(); + setDetailCache({}); + await load(); + message.success('已同步最新数据'); + } catch (syncError) { + message.error(syncError?.response?.data?.error || syncError?.message || '同步失败'); + } finally { + setSyncing(false); + } + }; + return (
@@ -772,6 +790,9 @@ const MkhBomData = () => { /> + + + { const [data, setData] = useState({ rows: [], total: 0, page: 1, pageSize: 50, summary: {}, monitorDate: null }); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); + const [syncing, setSyncing] = useState(false); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(50); const [sorter, setSorter] = useState({ field: 'realtimeStock', order: 'DESC' }); @@ -282,6 +283,21 @@ const AccessoryStockPanel = () => { } }; + // 手动同步:后端重新取最新监控日(清服务端缓存)后再拉一次列表, + // 拿到的是副本库当前最新快照;可随时点击,不受 24 点定时任务限制 + const handleSync = async () => { + setSyncing(true); + try { + await syncModularStock(); + await load(); + message.success('已同步最新数据'); + } catch (syncError) { + message.error(syncError?.response?.data?.error || syncError?.message || '同步失败'); + } finally { + setSyncing(false); + } + }; + const summary = data.summary || {}; return ( @@ -327,6 +343,9 @@ const AccessoryStockPanel = () => { + + +