@pisell/pisellos 2.2.190 → 2.2.192

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  2. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +2 -1
  3. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -7
  4. package/dist/modules/Cart/utils/cartProduct.js +13 -2
  5. package/dist/modules/Order/index.d.ts +1 -3
  6. package/dist/modules/Order/index.js +69 -95
  7. package/dist/modules/Order/types.d.ts +9 -6
  8. package/dist/modules/Order/utils.d.ts +9 -2
  9. package/dist/modules/Order/utils.js +36 -13
  10. package/dist/modules/SalesSummary/types.d.ts +3 -1
  11. package/dist/modules/SalesSummary/utils.js +7 -3
  12. package/dist/server/modules/order/index.d.ts +60 -7
  13. package/dist/server/modules/order/index.js +670 -178
  14. package/dist/server/modules/order/types.d.ts +0 -2
  15. package/dist/server/modules/products/index.d.ts +33 -6
  16. package/dist/server/modules/products/index.js +528 -231
  17. package/dist/solution/BaseSales/index.js +13 -7
  18. package/dist/solution/BaseSales/types.d.ts +8 -5
  19. package/dist/solution/BaseSales/types.js +2 -3
  20. package/dist/solution/BaseSales/utils/cartPromotion.js +7 -7
  21. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  22. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +16 -13
  23. package/dist/solution/BaseSales/utils.d.ts +1 -1
  24. package/dist/solution/BaseSales/utils.js +22 -19
  25. package/dist/solution/BookingByStep/index.d.ts +1 -1
  26. package/dist/solution/BookingTicket/index.d.ts +1 -1
  27. package/dist/solution/ScanOrder/index.js +7 -5
  28. package/dist/solution/ScanOrder/types.d.ts +8 -5
  29. package/dist/solution/ScanOrder/types.js +2 -3
  30. package/dist/solution/ScanOrder/utils.d.ts +1 -1
  31. package/dist/solution/ScanOrder/utils.js +26 -23
  32. package/dist/solution/VenueBooking/index.js +5 -3
  33. package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  34. package/lib/model/strategy/adapter/promotion/index.js +0 -49
  35. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +2 -1
  36. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
  37. package/lib/modules/Cart/utils/cartProduct.js +9 -2
  38. package/lib/modules/Order/index.d.ts +1 -3
  39. package/lib/modules/Order/index.js +45 -58
  40. package/lib/modules/Order/types.d.ts +9 -6
  41. package/lib/modules/Order/utils.d.ts +9 -2
  42. package/lib/modules/Order/utils.js +41 -10
  43. package/lib/modules/SalesSummary/types.d.ts +3 -1
  44. package/lib/modules/SalesSummary/utils.js +5 -3
  45. package/lib/server/modules/order/index.d.ts +60 -7
  46. package/lib/server/modules/order/index.js +350 -40
  47. package/lib/server/modules/order/types.d.ts +0 -2
  48. package/lib/server/modules/products/index.d.ts +33 -6
  49. package/lib/server/modules/products/index.js +159 -30
  50. package/lib/solution/BaseSales/index.js +14 -5
  51. package/lib/solution/BaseSales/types.d.ts +8 -5
  52. package/lib/solution/BaseSales/utils/cartPromotion.js +6 -6
  53. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  54. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +21 -14
  55. package/lib/solution/BaseSales/utils.d.ts +1 -1
  56. package/lib/solution/BaseSales/utils.js +11 -7
  57. package/lib/solution/BookingByStep/index.d.ts +1 -1
  58. package/lib/solution/BookingTicket/index.d.ts +1 -1
  59. package/lib/solution/ScanOrder/index.js +4 -4
  60. package/lib/solution/ScanOrder/types.d.ts +8 -5
  61. package/lib/solution/ScanOrder/utils.d.ts +1 -1
  62. package/lib/solution/ScanOrder/utils.js +12 -8
  63. package/lib/solution/VenueBooking/index.js +2 -2
  64. package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  65. package/package.json +1 -1
  66. package/dist/solution/Checkout/appointmentDemo.json +0 -1
  67. package/lib/solution/Checkout/appointmentDemo.json +0 -1
@@ -37,9 +37,10 @@ import { applyDetailValueToProducts, applyPriceDataToProducts, applyI18nToProduc
37
37
  * IndexDB 存储名称
38
38
  */
39
39
  var INDEXDB_STORE_NAME = 'products';
40
-
41
40
  /** 商品同步防抖时间(毫秒) */
42
41
  var PRODUCT_SYNC_DEBOUNCE_MS = 10000;
42
+ /** silentRefresh 最小间隔,避免 preload 后立即全量重拉 */
43
+ var PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS = 30000;
43
44
 
44
45
  /**
45
46
  * Products 模块 - 用于获取和管理完整的商品详细数据
@@ -80,6 +81,12 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
80
81
  _defineProperty(_assertThisInitialized(_this), "productDataSource", void 0);
81
82
  _defineProperty(_assertThisInitialized(_this), "pendingSyncMessages", []);
82
83
  _defineProperty(_assertThisInitialized(_this), "syncTimer", void 0);
84
+ /** 最近一次 SSE 全量拉取完成时间 */
85
+ _defineProperty(_assertThisInitialized(_this), "lastServerFullFetchAtMs", 0);
86
+ /** 最近一次 preload 完成时间(含 IndexDB 命中) */
87
+ _defineProperty(_assertThisInitialized(_this), "lastPreloadCompletedAtMs", 0);
88
+ /** IndexDB 写入串行队列,避免快照与 patch 并发交错 */
89
+ _defineProperty(_assertThisInitialized(_this), "productIndexDBSaveQueue", Promise.resolve());
83
90
  return _this;
84
91
  }
85
92
  _createClass(ProductsModule, [{
@@ -1117,17 +1124,18 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1117
1124
  duration: "".concat(Math.round(performance.now() - t0), "ms")
1118
1125
  });
1119
1126
  _context9.next = 15;
1120
- return this.saveProductsToIndexDB(list);
1127
+ return this.replaceProductsSnapshotInIndexDB(list, 'loadProductsByServer');
1121
1128
  case 15:
1122
- _context9.next = 17;
1129
+ this.lastServerFullFetchAtMs = Date.now();
1130
+ _context9.next = 18;
1123
1131
  return this.core.effects.emit(ProductsHooks.onProductsLoaded, list);
1124
- case 17:
1132
+ case 18:
1125
1133
  perfMark('loadProductsByServer', performance.now() - t0, {
1126
1134
  count: list.length
1127
1135
  });
1128
1136
  return _context9.abrupt("return", list);
1129
- case 21:
1130
- _context9.prev = 21;
1137
+ case 22:
1138
+ _context9.prev = 22;
1131
1139
  _context9.t0 = _context9["catch"](5);
1132
1140
  duration = Math.round(performance.now() - t0);
1133
1141
  errorMessage = _context9.t0 instanceof Error ? _context9.t0.message : String(_context9.t0);
@@ -1137,11 +1145,11 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1137
1145
  error: errorMessage
1138
1146
  });
1139
1147
  return _context9.abrupt("return", []);
1140
- case 28:
1148
+ case 29:
1141
1149
  case "end":
1142
1150
  return _context9.stop();
1143
1151
  }
1144
- }, _callee9, this, [[5, 21]]);
1152
+ }, _callee9, this, [[5, 22]]);
1145
1153
  }));
1146
1154
  function loadProductsByServer() {
1147
1155
  return _loadProductsByServer.apply(this, arguments);
@@ -1242,17 +1250,18 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1242
1250
  case 2:
1243
1251
  productList = _context11.sent;
1244
1252
  if (!(productList.length > 0)) {
1245
- _context11.next = 8;
1253
+ _context11.next = 9;
1246
1254
  break;
1247
1255
  }
1248
1256
  _context11.next = 6;
1249
- return this.saveProductsToIndexDB(productList);
1257
+ return this.replaceProductsSnapshotInIndexDB(productList, 'loadProductsByServerHttp');
1250
1258
  case 6:
1251
- _context11.next = 8;
1259
+ this.lastServerFullFetchAtMs = Date.now();
1260
+ _context11.next = 9;
1252
1261
  return this.core.effects.emit(ProductsHooks.onProductsLoaded, productList);
1253
- case 8:
1254
- return _context11.abrupt("return", productList);
1255
1262
  case 9:
1263
+ return _context11.abrupt("return", productList);
1264
+ case 10:
1256
1265
  case "end":
1257
1266
  return _context11.stop();
1258
1267
  }
@@ -1606,64 +1615,243 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1606
1615
  return loadProductsFromIndexDB;
1607
1616
  }()
1608
1617
  /**
1609
- * 保存商品数据到 IndexDB(平铺存储)
1610
- * @private
1618
+ * 串行执行商品 IndexDB 写入,避免快照替换与增量 patch 并发交错。
1619
+ *
1620
+ * @example
1621
+ * await this.runInProductIndexDBSaveQueue(async () => {
1622
+ * await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, products)
1623
+ * })
1611
1624
  */
1612
1625
  )
1613
1626
  }, {
1614
- key: "saveProductsToIndexDB",
1627
+ key: "runInProductIndexDBSaveQueue",
1615
1628
  value: (function () {
1616
- var _saveProductsToIndexDB = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee18(products) {
1617
- var t0, errorMessage;
1629
+ var _runInProductIndexDBSaveQueue = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee18(task) {
1630
+ var queuedTask;
1618
1631
  return _regeneratorRuntime().wrap(function _callee18$(_context18) {
1619
1632
  while (1) switch (_context18.prev = _context18.next) {
1633
+ case 0:
1634
+ queuedTask = this.productIndexDBSaveQueue.then(task, task);
1635
+ this.productIndexDBSaveQueue = queuedTask.then(function () {
1636
+ return undefined;
1637
+ }, function () {
1638
+ return undefined;
1639
+ });
1640
+ return _context18.abrupt("return", queuedTask);
1641
+ case 3:
1642
+ case "end":
1643
+ return _context18.stop();
1644
+ }
1645
+ }, _callee18, this);
1646
+ }));
1647
+ function runInProductIndexDBSaveQueue(_x19) {
1648
+ return _runInProductIndexDBSaveQueue.apply(this, arguments);
1649
+ }
1650
+ return runInProductIndexDBSaveQueue;
1651
+ }()
1652
+ /**
1653
+ * 全量快照写入 IndexDB:clear + bulkUpdate,仅用于 SSE/HTTP 全量拉取。
1654
+ *
1655
+ * @example
1656
+ * await this.replaceProductsSnapshotInIndexDB(list, 'loadProductsByServer')
1657
+ */
1658
+ )
1659
+ }, {
1660
+ key: "replaceProductsSnapshotInIndexDB",
1661
+ value: (function () {
1662
+ var _replaceProductsSnapshotInIndexDB = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee20(products, source) {
1663
+ var _this6 = this;
1664
+ var errorMessage;
1665
+ return _regeneratorRuntime().wrap(function _callee20$(_context20) {
1666
+ while (1) switch (_context20.prev = _context20.next) {
1620
1667
  case 0:
1621
1668
  if (this.dbManager) {
1622
- _context18.next = 3;
1669
+ _context20.next = 3;
1623
1670
  break;
1624
1671
  }
1625
- this.logWarning('saveProductsToIndexDB: dbManager 不可用');
1626
- return _context18.abrupt("return");
1672
+ this.logWarning('replaceProductsSnapshotInIndexDB: dbManager 不可用');
1673
+ return _context20.abrupt("return");
1627
1674
  case 3:
1628
- this.logInfo('开始保存商品数据到 IndexDB', {
1629
- productCount: products.length
1630
- });
1631
- _context18.prev = 4;
1632
- t0 = performance.now();
1633
- _context18.next = 8;
1634
- return this.dbManager.clear(INDEXDB_STORE_NAME);
1675
+ _context20.prev = 3;
1676
+ _context20.next = 6;
1677
+ return this.runInProductIndexDBSaveQueue( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee19() {
1678
+ var t0;
1679
+ return _regeneratorRuntime().wrap(function _callee19$(_context19) {
1680
+ while (1) switch (_context19.prev = _context19.next) {
1681
+ case 0:
1682
+ _this6.logInfo('replaceProductsSnapshotInIndexDB 开始', {
1683
+ source: source,
1684
+ productCount: products.length
1685
+ });
1686
+ t0 = performance.now();
1687
+ _context19.next = 4;
1688
+ return _this6.dbManager.clear(INDEXDB_STORE_NAME);
1689
+ case 4:
1690
+ if (!(products.length > 0)) {
1691
+ _context19.next = 7;
1692
+ break;
1693
+ }
1694
+ _context19.next = 7;
1695
+ return _this6.dbManager.bulkUpdate(INDEXDB_STORE_NAME, products);
1696
+ case 7:
1697
+ perfMark('replaceProductsSnapshotInIndexDB', performance.now() - t0, {
1698
+ count: products.length
1699
+ });
1700
+ _this6.logInfo('replaceProductsSnapshotInIndexDB 完成', {
1701
+ source: source,
1702
+ productCount: products.length
1703
+ });
1704
+ case 9:
1705
+ case "end":
1706
+ return _context19.stop();
1707
+ }
1708
+ }, _callee19);
1709
+ })));
1710
+ case 6:
1711
+ _context20.next = 12;
1712
+ break;
1635
1713
  case 8:
1636
- _context18.next = 10;
1637
- return this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, products);
1638
- case 10:
1639
- perfMark('saveProductsToIndexDB', performance.now() - t0, {
1640
- count: products.length
1714
+ _context20.prev = 8;
1715
+ _context20.t0 = _context20["catch"](3);
1716
+ errorMessage = _context20.t0 instanceof Error ? _context20.t0.message : String(_context20.t0);
1717
+ this.logError('全量保存商品到 IndexDB 失败', {
1718
+ source: source,
1719
+ productCount: products.length,
1720
+ error: errorMessage
1641
1721
  });
1642
- console.log("[Products] \u5DF2\u5C06 ".concat(products.length, " \u4E2A\u5546\u54C1\u5E73\u94FA\u4FDD\u5B58\u5230 IndexDB"));
1643
- this.logInfo('商品数据已保存到 IndexDB', {
1644
- productCount: products.length
1722
+ case 12:
1723
+ case "end":
1724
+ return _context20.stop();
1725
+ }
1726
+ }, _callee20, this, [[3, 8]]);
1727
+ }));
1728
+ function replaceProductsSnapshotInIndexDB(_x20, _x21) {
1729
+ return _replaceProductsSnapshotInIndexDB.apply(this, arguments);
1730
+ }
1731
+ return replaceProductsSnapshotInIndexDB;
1732
+ }()
1733
+ /**
1734
+ * 增量 upsert 商品到 IndexDB,不清空表;用于 pubsub 批次合并后的变更商品。
1735
+ *
1736
+ * @example
1737
+ * await this.patchProductsInIndexDB(changedProducts, 'pubsub.processProductSyncMessages', mergeActions)
1738
+ */
1739
+ )
1740
+ }, {
1741
+ key: "patchProductsInIndexDB",
1742
+ value: (function () {
1743
+ var _patchProductsInIndexDB = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee22(products, source) {
1744
+ var _this7 = this;
1745
+ var mergeActions,
1746
+ validProducts,
1747
+ errorMessage,
1748
+ _args22 = arguments;
1749
+ return _regeneratorRuntime().wrap(function _callee22$(_context22) {
1750
+ while (1) switch (_context22.prev = _context22.next) {
1751
+ case 0:
1752
+ mergeActions = _args22.length > 2 && _args22[2] !== undefined ? _args22[2] : {};
1753
+ if (!(!this.dbManager || products.length === 0)) {
1754
+ _context22.next = 3;
1755
+ break;
1756
+ }
1757
+ return _context22.abrupt("return");
1758
+ case 3:
1759
+ validProducts = products.filter(function (p) {
1760
+ return (p === null || p === void 0 ? void 0 : p.id) !== undefined && (p === null || p === void 0 ? void 0 : p.id) !== null;
1645
1761
  });
1646
- _context18.next = 20;
1762
+ if (!(validProducts.length === 0)) {
1763
+ _context22.next = 6;
1764
+ break;
1765
+ }
1766
+ return _context22.abrupt("return");
1767
+ case 6:
1768
+ _context22.prev = 6;
1769
+ _context22.next = 9;
1770
+ return this.runInProductIndexDBSaveQueue( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee21() {
1771
+ var t0, _iterator10, _step10, product;
1772
+ return _regeneratorRuntime().wrap(function _callee21$(_context21) {
1773
+ while (1) switch (_context21.prev = _context21.next) {
1774
+ case 0:
1775
+ _this7.logInfo('patchProductsInIndexDB 开始', {
1776
+ source: source,
1777
+ count: validProducts.length
1778
+ });
1779
+ t0 = performance.now();
1780
+ if (!(typeof _this7.dbManager.bulkUpdate === 'function')) {
1781
+ _context21.next = 7;
1782
+ break;
1783
+ }
1784
+ _context21.next = 5;
1785
+ return _this7.dbManager.bulkUpdate(INDEXDB_STORE_NAME, validProducts);
1786
+ case 5:
1787
+ _context21.next = 25;
1788
+ break;
1789
+ case 7:
1790
+ if (!(typeof _this7.dbManager.update === 'function')) {
1791
+ _context21.next = 25;
1792
+ break;
1793
+ }
1794
+ _iterator10 = _createForOfIteratorHelper(validProducts);
1795
+ _context21.prev = 9;
1796
+ _iterator10.s();
1797
+ case 11:
1798
+ if ((_step10 = _iterator10.n()).done) {
1799
+ _context21.next = 17;
1800
+ break;
1801
+ }
1802
+ product = _step10.value;
1803
+ _context21.next = 15;
1804
+ return _this7.dbManager.update(INDEXDB_STORE_NAME, product);
1805
+ case 15:
1806
+ _context21.next = 11;
1807
+ break;
1808
+ case 17:
1809
+ _context21.next = 22;
1810
+ break;
1811
+ case 19:
1812
+ _context21.prev = 19;
1813
+ _context21.t0 = _context21["catch"](9);
1814
+ _iterator10.e(_context21.t0);
1815
+ case 22:
1816
+ _context21.prev = 22;
1817
+ _iterator10.f();
1818
+ return _context21.finish(22);
1819
+ case 25:
1820
+ perfMark('patchProductsInIndexDB', performance.now() - t0, {
1821
+ count: validProducts.length
1822
+ });
1823
+ _this7.logInfo('patchProductsInIndexDB 完成', {
1824
+ source: source,
1825
+ count: validProducts.length
1826
+ });
1827
+ case 27:
1828
+ case "end":
1829
+ return _context21.stop();
1830
+ }
1831
+ }, _callee21, null, [[9, 19, 22, 25]]);
1832
+ })));
1833
+ case 9:
1834
+ _context22.next = 15;
1647
1835
  break;
1648
- case 15:
1649
- _context18.prev = 15;
1650
- _context18.t0 = _context18["catch"](4);
1651
- errorMessage = _context18.t0 instanceof Error ? _context18.t0.message : String(_context18.t0);
1652
- console.error('[Products] 保存数据到 IndexDB 失败:', _context18.t0);
1653
- this.logError('保存数据到 IndexDB 失败', {
1654
- productCount: products.length,
1655
- error: errorMessage
1836
+ case 11:
1837
+ _context22.prev = 11;
1838
+ _context22.t0 = _context22["catch"](6);
1839
+ errorMessage = _context22.t0 instanceof Error ? _context22.t0.message : String(_context22.t0);
1840
+ this.logError('增量保存商品到 IndexDB 失败', {
1841
+ source: source,
1842
+ error: errorMessage,
1843
+ productCount: validProducts.length
1656
1844
  });
1657
- case 20:
1845
+ case 15:
1658
1846
  case "end":
1659
- return _context18.stop();
1847
+ return _context22.stop();
1660
1848
  }
1661
- }, _callee18, this, [[4, 15]]);
1849
+ }, _callee22, this, [[6, 11]]);
1662
1850
  }));
1663
- function saveProductsToIndexDB(_x19) {
1664
- return _saveProductsToIndexDB.apply(this, arguments);
1851
+ function patchProductsInIndexDB(_x22, _x23) {
1852
+ return _patchProductsInIndexDB.apply(this, arguments);
1665
1853
  }
1666
- return saveProductsToIndexDB;
1854
+ return patchProductsInIndexDB;
1667
1855
  }()
1668
1856
  /**
1669
1857
  * 同步更新商品 Map 缓存
@@ -1676,17 +1864,17 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1676
1864
  value: function syncProductsMap() {
1677
1865
  var t0 = performance.now();
1678
1866
  this.store.map.clear();
1679
- var _iterator10 = _createForOfIteratorHelper(this.store.list),
1680
- _step10;
1867
+ var _iterator11 = _createForOfIteratorHelper(this.store.list),
1868
+ _step11;
1681
1869
  try {
1682
- for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
1683
- var product = _step10.value;
1870
+ for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
1871
+ var product = _step11.value;
1684
1872
  this.store.map.set(product.id, product);
1685
1873
  }
1686
1874
  } catch (err) {
1687
- _iterator10.e(err);
1875
+ _iterator11.e(err);
1688
1876
  } finally {
1689
- _iterator10.f();
1877
+ _iterator11.f();
1690
1878
  }
1691
1879
  perfMark('syncProductsMap', performance.now() - t0, {
1692
1880
  count: this.store.map.size
@@ -1700,26 +1888,26 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1700
1888
  }, {
1701
1889
  key: "preload",
1702
1890
  value: (function () {
1703
- var _preload = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee19() {
1891
+ var _preload = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee23() {
1704
1892
  var _products$length3;
1705
1893
  var tTotal, _cachedData$length, tIndexDB, cachedData, tSync, errorMessage, tServer, products, _tSync;
1706
- return _regeneratorRuntime().wrap(function _callee19$(_context19) {
1707
- while (1) switch (_context19.prev = _context19.next) {
1894
+ return _regeneratorRuntime().wrap(function _callee23$(_context23) {
1895
+ while (1) switch (_context23.prev = _context23.next) {
1708
1896
  case 0:
1709
1897
  console.log('[Products] 开始预加载数据...');
1710
1898
  tTotal = performance.now();
1711
1899
  this.logInfo('开始预加载数据');
1712
- _context19.prev = 3;
1900
+ _context23.prev = 3;
1713
1901
  tIndexDB = performance.now();
1714
- _context19.next = 7;
1902
+ _context23.next = 7;
1715
1903
  return this.loadProductsFromIndexDB();
1716
1904
  case 7:
1717
- cachedData = _context19.sent;
1905
+ cachedData = _context23.sent;
1718
1906
  perfMark('preload.loadFromIndexDB', performance.now() - tIndexDB, {
1719
1907
  count: (_cachedData$length = cachedData === null || cachedData === void 0 ? void 0 : cachedData.length) !== null && _cachedData$length !== void 0 ? _cachedData$length : 0
1720
1908
  });
1721
1909
  if (!(cachedData && cachedData.length > 0)) {
1722
- _context19.next = 19;
1910
+ _context23.next = 20;
1723
1911
  break;
1724
1912
  }
1725
1913
  console.log("[Products] \u4ECE IndexDB \u52A0\u8F7D\u4E86 ".concat(cachedData.length, " \u4E2A\u5546\u54C1"));
@@ -1740,26 +1928,27 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1740
1928
  duration: "".concat(Math.round(performance.now() - tTotal), "ms"),
1741
1929
  source: 'IndexDB'
1742
1930
  });
1743
- return _context19.abrupt("return");
1744
- case 19:
1931
+ this.lastPreloadCompletedAtMs = Date.now();
1932
+ return _context23.abrupt("return");
1933
+ case 20:
1745
1934
  console.log('[Products] IndexDB 中没有缓存数据,从服务器加载...');
1746
1935
  this.logInfo('IndexDB 中没有缓存数据,准备从服务器加载');
1747
- _context19.next = 28;
1936
+ _context23.next = 29;
1748
1937
  break;
1749
- case 23:
1750
- _context19.prev = 23;
1751
- _context19.t0 = _context19["catch"](3);
1752
- errorMessage = _context19.t0 instanceof Error ? _context19.t0.message : String(_context19.t0);
1753
- console.warn('[Products] 从 IndexDB 加载数据失败:', _context19.t0);
1938
+ case 24:
1939
+ _context23.prev = 24;
1940
+ _context23.t0 = _context23["catch"](3);
1941
+ errorMessage = _context23.t0 instanceof Error ? _context23.t0.message : String(_context23.t0);
1942
+ console.warn('[Products] 从 IndexDB 加载数据失败:', _context23.t0);
1754
1943
  this.logWarning('从 IndexDB 加载数据失败,准备从服务器加载', {
1755
1944
  error: errorMessage
1756
1945
  });
1757
- case 28:
1946
+ case 29:
1758
1947
  tServer = performance.now();
1759
- _context19.next = 31;
1948
+ _context23.next = 32;
1760
1949
  return this.loadProductsByServer();
1761
- case 31:
1762
- products = _context19.sent;
1950
+ case 32:
1951
+ products = _context23.sent;
1763
1952
  perfMark('preload.loadFromServer', performance.now() - tServer, {
1764
1953
  count: (_products$length3 = products === null || products === void 0 ? void 0 : products.length) !== null && _products$length3 !== void 0 ? _products$length3 : 0
1765
1954
  });
@@ -1781,6 +1970,7 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1781
1970
  duration: "".concat(Math.round(performance.now() - tTotal), "ms"),
1782
1971
  source: 'Server'
1783
1972
  });
1973
+ this.lastPreloadCompletedAtMs = Date.now();
1784
1974
  } else {
1785
1975
  perfMark('preload(empty)', performance.now() - tTotal, {
1786
1976
  source: 'empty'
@@ -1789,11 +1979,11 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1789
1979
  duration: "".concat(Math.round(performance.now() - tTotal), "ms")
1790
1980
  });
1791
1981
  }
1792
- case 34:
1982
+ case 35:
1793
1983
  case "end":
1794
- return _context19.stop();
1984
+ return _context23.stop();
1795
1985
  }
1796
- }, _callee19, this, [[3, 23]]);
1986
+ }, _callee23, this, [[3, 24]]);
1797
1987
  }));
1798
1988
  function preload() {
1799
1989
  return _preload.apply(this, arguments);
@@ -1828,7 +2018,7 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1828
2018
  }, {
1829
2019
  key: "setupProductSync",
1830
2020
  value: function setupProductSync() {
1831
- var _this6 = this;
2021
+ var _this8 = this;
1832
2022
  if (!this.productDataSource) {
1833
2023
  this.logWarning('setupProductSync: ProductDataSource 不可用,跳过同步初始化');
1834
2024
  return;
@@ -1838,20 +2028,20 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1838
2028
  var data = (message === null || message === void 0 ? void 0 : message.data) || message;
1839
2029
  if (!data) return;
1840
2030
  console.log("[ProductsModule] \u6536\u5230\u540C\u6B65\u6D88\u606F [".concat(channelKey, "]:"), data);
1841
- _this6.logInfo('收到同步消息', {
2031
+ _this8.logInfo('收到同步消息', {
1842
2032
  channelKey: channelKey,
1843
2033
  action: data.action,
1844
2034
  id: data.id,
1845
2035
  action_filed: data.action_filed
1846
2036
  });
1847
- _this6.pendingSyncMessages.push(_objectSpread(_objectSpread({}, data), {}, {
2037
+ _this8.pendingSyncMessages.push(_objectSpread(_objectSpread({}, data), {}, {
1848
2038
  _channelKey: channelKey
1849
2039
  }));
1850
- if (_this6.syncTimer) {
1851
- clearTimeout(_this6.syncTimer);
2040
+ if (_this8.syncTimer) {
2041
+ clearTimeout(_this8.syncTimer);
1852
2042
  }
1853
- _this6.syncTimer = setTimeout(function () {
1854
- _this6.processProductSyncMessages();
2043
+ _this8.syncTimer = setTimeout(function () {
2044
+ _this8.processProductSyncMessages();
1855
2045
  }, PRODUCT_SYNC_DEBOUNCE_MS);
1856
2046
  };
1857
2047
  };
@@ -1859,7 +2049,7 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1859
2049
  pubsub: {
1860
2050
  callback: function callback(res) {
1861
2051
  console.log('sse_products_callback', res);
1862
- _this6.logInfo('sse_products_callback: 收到同步消息', {
2052
+ _this8.logInfo('sse_products_callback: 收到同步消息', {
1863
2053
  data: res === null || res === void 0 ? void 0 : res.data
1864
2054
  });
1865
2055
  if (!(res !== null && res !== void 0 && res.data)) return;
@@ -1869,7 +2059,7 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1869
2059
  }
1870
2060
  }
1871
2061
  }).catch(function (err) {
1872
- _this6.logError('setupProductSync: DataSource run 出错', {
2062
+ _this8.logError('setupProductSync: DataSource run 出错', {
1873
2063
  error: err instanceof Error ? err.message : String(err)
1874
2064
  });
1875
2065
  });
@@ -1897,18 +2087,18 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1897
2087
  }, {
1898
2088
  key: "processProductSyncMessages",
1899
2089
  value: (function () {
1900
- var _processProductSyncMessages = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee20() {
1901
- var messages, deleteIds, bodyUpdates, sseRefreshIds, priceRefreshIds, shouldClearPriceCache, _iterator11, _step11, msg, channelKey, _msg$relation_product, _msg$change_types, _msg$ids2, _msg$ids, ids, bodyId, _bodyId, _msg$relation_product2, _msg$relation_product3, uniqueDeleteIds, uniqueSSEIds, uniquePriceIds, freshProducts, allChangedIds, hasChanges, errorMessage;
1902
- return _regeneratorRuntime().wrap(function _callee20$(_context20) {
1903
- while (1) switch (_context20.prev = _context20.next) {
2090
+ var _processProductSyncMessages = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee24() {
2091
+ var messages, deleteIds, bodyUpdates, sseRefreshIds, priceRefreshIds, shouldClearPriceCache, _iterator12, _step12, msg, channelKey, _msg$relation_product, _msg$change_types, _msg$ids2, _msg$ids, ids, bodyId, _bodyId, _msg$relation_product2, _msg$relation_product3, uniqueDeleteIds, uniqueSSEIds, uniquePriceIds, patchProductMap, patchMergeActions, storeMutated, bodyResult, _iterator13, _step13, product, freshProducts, mergeResult, _iterator14, _step14, _product, patchProducts, allChangedIds, hasChanges, errorMessage;
2092
+ return _regeneratorRuntime().wrap(function _callee24$(_context24) {
2093
+ while (1) switch (_context24.prev = _context24.next) {
1904
2094
  case 0:
1905
2095
  messages = _toConsumableArray(this.pendingSyncMessages);
1906
2096
  this.pendingSyncMessages = [];
1907
2097
  if (!(messages.length === 0)) {
1908
- _context20.next = 4;
2098
+ _context24.next = 4;
1909
2099
  break;
1910
2100
  }
1911
- return _context20.abrupt("return");
2101
+ return _context24.abrupt("return");
1912
2102
  case 4:
1913
2103
  this.logInfo('processProductSyncMessages: 开始处理', {
1914
2104
  count: messages.length
@@ -1918,18 +2108,18 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1918
2108
  sseRefreshIds = [];
1919
2109
  priceRefreshIds = [];
1920
2110
  shouldClearPriceCache = false;
1921
- _iterator11 = _createForOfIteratorHelper(messages);
1922
- _context20.prev = 11;
1923
- _iterator11.s();
2111
+ _iterator12 = _createForOfIteratorHelper(messages);
2112
+ _context24.prev = 11;
2113
+ _iterator12.s();
1924
2114
  case 13:
1925
- if ((_step11 = _iterator11.n()).done) {
1926
- _context20.next = 36;
2115
+ if ((_step12 = _iterator12.n()).done) {
2116
+ _context24.next = 36;
1927
2117
  break;
1928
2118
  }
1929
- msg = _step11.value;
2119
+ msg = _step12.value;
1930
2120
  channelKey = msg._channelKey || msg.module || 'product';
1931
2121
  if (!(channelKey === 'product')) {
1932
- _context20.next = 33;
2122
+ _context24.next = 33;
1933
2123
  break;
1934
2124
  }
1935
2125
  if ((_msg$relation_product = msg.relation_product_ids) !== null && _msg$relation_product !== void 0 && _msg$relation_product.length) {
@@ -1937,14 +2127,14 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1937
2127
  }
1938
2128
  // 1. 删除场景:operation === 'delete' 或 action === 'delete'
1939
2129
  if (!(msg.operation === 'delete' || msg.action === 'delete')) {
1940
- _context20.next = 21;
2130
+ _context24.next = 21;
1941
2131
  break;
1942
2132
  }
1943
2133
  if ((_msg$ids = msg.ids) !== null && _msg$ids !== void 0 && _msg$ids.length) deleteIds.push.apply(deleteIds, _toConsumableArray(msg.ids));else if (msg.id) deleteIds.push(msg.id);
1944
- return _context20.abrupt("continue", 34);
2134
+ return _context24.abrupt("continue", 34);
1945
2135
  case 21:
1946
2136
  if (!((_msg$change_types = msg.change_types) !== null && _msg$change_types !== void 0 && _msg$change_types.includes('price'))) {
1947
- _context20.next = 26;
2137
+ _context24.next = 26;
1948
2138
  break;
1949
2139
  }
1950
2140
  ids = msg.ids || (msg.id ? [msg.id] : []);
@@ -1953,15 +2143,15 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1953
2143
  bodyId = msg.body.id;
1954
2144
  if (bodyId) bodyUpdates.set(bodyId, msg.body);
1955
2145
  }
1956
- return _context20.abrupt("continue", 34);
2146
+ return _context24.abrupt("continue", 34);
1957
2147
  case 26:
1958
2148
  if (!msg.body) {
1959
- _context20.next = 30;
2149
+ _context24.next = 30;
1960
2150
  break;
1961
2151
  }
1962
2152
  _bodyId = msg.body.id || msg.id;
1963
2153
  if (_bodyId) bodyUpdates.set(_bodyId, msg.body);
1964
- return _context20.abrupt("continue", 34);
2154
+ return _context24.abrupt("continue", 34);
1965
2155
  case 30:
1966
2156
  // 4. 其他情况(有 ids 无 body 无 change_types)→ SSE 拉取
1967
2157
  if ((_msg$ids2 = msg.ids) !== null && _msg$ids2 !== void 0 && _msg$ids2.length) {
@@ -1969,7 +2159,7 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1969
2159
  } else if (msg.id) {
1970
2160
  sseRefreshIds.push(msg.id);
1971
2161
  }
1972
- _context20.next = 34;
2162
+ _context24.next = 34;
1973
2163
  break;
1974
2164
  case 33:
1975
2165
  if (channelKey === 'product_quotation') {
@@ -1984,57 +2174,111 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
1984
2174
  }
1985
2175
  }
1986
2176
  case 34:
1987
- _context20.next = 13;
2177
+ _context24.next = 13;
1988
2178
  break;
1989
2179
  case 36:
1990
- _context20.next = 41;
2180
+ _context24.next = 41;
1991
2181
  break;
1992
2182
  case 38:
1993
- _context20.prev = 38;
1994
- _context20.t0 = _context20["catch"](11);
1995
- _iterator11.e(_context20.t0);
2183
+ _context24.prev = 38;
2184
+ _context24.t0 = _context24["catch"](11);
2185
+ _iterator12.e(_context24.t0);
1996
2186
  case 41:
1997
- _context20.prev = 41;
1998
- _iterator11.f();
1999
- return _context20.finish(41);
2187
+ _context24.prev = 41;
2188
+ _iterator12.f();
2189
+ return _context24.finish(41);
2000
2190
  case 44:
2001
2191
  uniqueDeleteIds = _toConsumableArray(new Set(deleteIds));
2002
2192
  uniqueSSEIds = _toConsumableArray(new Set(sseRefreshIds));
2003
2193
  uniquePriceIds = _toConsumableArray(new Set(priceRefreshIds)); // 1. 处理删除
2004
2194
  if (!(uniqueDeleteIds.length > 0)) {
2005
- _context20.next = 50;
2195
+ _context24.next = 50;
2006
2196
  break;
2007
2197
  }
2008
- _context20.next = 50;
2198
+ _context24.next = 50;
2009
2199
  return this.removeProductsByIds(uniqueDeleteIds);
2010
2200
  case 50:
2201
+ /** 本批次待 patch 的商品(按 id 去重,SSE 覆盖 body) */
2202
+ patchProductMap = new Map();
2203
+ patchMergeActions = {};
2204
+ storeMutated = uniqueDeleteIds.length > 0; // 2. 处理 body 直接覆盖(仅内存,IndexDB 批次末统一 patch)
2011
2205
  if (!(bodyUpdates.size > 0)) {
2012
- _context20.next = 53;
2206
+ _context24.next = 60;
2013
2207
  break;
2014
2208
  }
2015
- _context20.next = 53;
2016
- return this.applyBodyUpdatesToStore(bodyUpdates);
2017
- case 53:
2209
+ _context24.next = 56;
2210
+ return this.applyBodyUpdatesToStore(bodyUpdates, {
2211
+ skipIndexDB: true,
2212
+ skipEmit: true
2213
+ });
2214
+ case 56:
2215
+ bodyResult = _context24.sent;
2216
+ _iterator13 = _createForOfIteratorHelper(bodyResult.changedProducts);
2217
+ try {
2218
+ for (_iterator13.s(); !(_step13 = _iterator13.n()).done;) {
2219
+ product = _step13.value;
2220
+ patchProductMap.set(product.id, product);
2221
+ patchMergeActions[product.id] = bodyResult.mergeActions[product.id];
2222
+ }
2223
+ } catch (err) {
2224
+ _iterator13.e(err);
2225
+ } finally {
2226
+ _iterator13.f();
2227
+ }
2228
+ storeMutated = true;
2229
+ case 60:
2230
+ // 3. 处理 SSE 增量拉取(仅内存,IndexDB 批次末统一 patch)
2231
+ freshProducts = [];
2018
2232
  if (!(uniqueSSEIds.length > 0)) {
2019
- _context20.next = 61;
2233
+ _context24.next = 73;
2020
2234
  break;
2021
2235
  }
2022
- _context20.next = 56;
2236
+ _context24.next = 64;
2023
2237
  return this.fetchProductsBySSE(uniqueSSEIds);
2024
- case 56:
2025
- freshProducts = _context20.sent;
2238
+ case 64:
2239
+ freshProducts = _context24.sent;
2026
2240
  if (!(freshProducts.length > 0)) {
2027
- _context20.next = 60;
2241
+ _context24.next = 72;
2028
2242
  break;
2029
2243
  }
2030
- _context20.next = 60;
2031
- return this.mergeProductsToStore(freshProducts);
2032
- case 60:
2244
+ _context24.next = 68;
2245
+ return this.mergeProductsToStore(freshProducts, {
2246
+ skipIndexDB: true,
2247
+ skipEmit: true
2248
+ });
2249
+ case 68:
2250
+ mergeResult = _context24.sent;
2251
+ _iterator14 = _createForOfIteratorHelper(mergeResult.changedProducts);
2252
+ try {
2253
+ for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) {
2254
+ _product = _step14.value;
2255
+ patchProductMap.set(_product.id, _product);
2256
+ patchMergeActions[_product.id] = mergeResult.mergeActions[_product.id];
2257
+ }
2258
+ } catch (err) {
2259
+ _iterator14.e(err);
2260
+ } finally {
2261
+ _iterator14.f();
2262
+ }
2263
+ storeMutated = true;
2264
+ case 72:
2033
2265
  this.logInfo('processProductSyncMessages: SSE 增量更新完成123', {
2034
2266
  requestedCount: uniqueSSEIds.length,
2035
2267
  receivedCount: freshProducts.length
2036
2268
  });
2037
- case 61:
2269
+ case 73:
2270
+ patchProducts = _toConsumableArray(patchProductMap.values());
2271
+ if (!(patchProducts.length > 0)) {
2272
+ _context24.next = 77;
2273
+ break;
2274
+ }
2275
+ _context24.next = 77;
2276
+ return this.patchProductsInIndexDB(patchProducts, 'pubsub.processProductSyncMessages', patchMergeActions);
2277
+ case 77:
2278
+ if (storeMutated) {
2279
+ this.core.effects.emit(ProductsHooks.onProductsChanged, this.store.list);
2280
+ }
2281
+
2038
2282
  // 收集所有非 delete 的变更 IDs(body + SSE + price),用于增量更新价格缓存
2039
2283
  allChangedIds = _toConsumableArray(new Set([].concat(_toConsumableArray(Array.from(bodyUpdates.keys())), _toConsumableArray(uniqueSSEIds), _toConsumableArray(uniquePriceIds))));
2040
2284
  this.logInfo('processProductSyncMessages: 处理完成123', {
@@ -2047,41 +2291,41 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
2047
2291
  });
2048
2292
  hasChanges = uniqueDeleteIds.length > 0 || allChangedIds.length > 0 || shouldClearPriceCache;
2049
2293
  if (hasChanges) {
2050
- _context20.next = 67;
2294
+ _context24.next = 84;
2051
2295
  break;
2052
2296
  }
2053
2297
  this.logInfo('processProductSyncMessages: 没有变更,不触发 onProductsSyncCompleted');
2054
- return _context20.abrupt("return");
2055
- case 67:
2298
+ return _context24.abrupt("return");
2299
+ case 84:
2056
2300
  if (!shouldClearPriceCache) {
2057
- _context20.next = 78;
2301
+ _context24.next = 95;
2058
2302
  break;
2059
2303
  }
2060
- _context20.prev = 68;
2061
- _context20.next = 71;
2304
+ _context24.prev = 85;
2305
+ _context24.next = 88;
2062
2306
  return this.refreshQuotationPriceBridge();
2063
- case 71:
2064
- _context20.next = 77;
2307
+ case 88:
2308
+ _context24.next = 94;
2065
2309
  break;
2066
- case 73:
2067
- _context20.prev = 73;
2068
- _context20.t1 = _context20["catch"](68);
2069
- errorMessage = _context20.t1 instanceof Error ? _context20.t1.message : String(_context20.t1);
2310
+ case 90:
2311
+ _context24.prev = 90;
2312
+ _context24.t1 = _context24["catch"](85);
2313
+ errorMessage = _context24.t1 instanceof Error ? _context24.t1.message : String(_context24.t1);
2070
2314
  this.logError('报价单桥接刷新失败,将继续清理价格缓存', {
2071
2315
  error: errorMessage
2072
2316
  });
2073
- case 77:
2317
+ case 94:
2074
2318
  this.clearPriceCache();
2075
- case 78:
2076
- _context20.next = 80;
2319
+ case 95:
2320
+ _context24.next = 97;
2077
2321
  return this.core.effects.emit(ProductsHooks.onProductsSyncCompleted, {
2078
2322
  changedIds: allChangedIds
2079
2323
  });
2080
- case 80:
2324
+ case 97:
2081
2325
  case "end":
2082
- return _context20.stop();
2326
+ return _context24.stop();
2083
2327
  }
2084
- }, _callee20, this, [[11, 38, 41, 44], [68, 73]]);
2328
+ }, _callee24, this, [[11, 38, 41, 44], [85, 90]]);
2085
2329
  }));
2086
2330
  function processProductSyncMessages() {
2087
2331
  return _processProductSyncMessages.apply(this, arguments);
@@ -2096,25 +2340,25 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
2096
2340
  }, {
2097
2341
  key: "fetchProductsBySSE",
2098
2342
  value: (function () {
2099
- var _fetchProductsBySSE = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee21(ids) {
2343
+ var _fetchProductsBySSE = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee25(ids) {
2100
2344
  var t0, productList, list, errorMessage;
2101
- return _regeneratorRuntime().wrap(function _callee21$(_context21) {
2102
- while (1) switch (_context21.prev = _context21.next) {
2345
+ return _regeneratorRuntime().wrap(function _callee25$(_context25) {
2346
+ while (1) switch (_context25.prev = _context25.next) {
2103
2347
  case 0:
2104
2348
  if (this.productDataSource) {
2105
- _context21.next = 3;
2349
+ _context25.next = 3;
2106
2350
  break;
2107
2351
  }
2108
2352
  this.logWarning('fetchProductsBySSE: ProductDataSource 不可用');
2109
- return _context21.abrupt("return", []);
2353
+ return _context25.abrupt("return", []);
2110
2354
  case 3:
2111
2355
  this.logInfo('fetchProductsBySSE: 开始', {
2112
2356
  ids: ids,
2113
2357
  count: ids.length
2114
2358
  });
2115
2359
  t0 = performance.now();
2116
- _context21.prev = 5;
2117
- _context21.next = 8;
2360
+ _context25.prev = 5;
2361
+ _context25.next = 8;
2118
2362
  return this.productDataSource.run({
2119
2363
  sse: {
2120
2364
  query: {
@@ -2124,7 +2368,7 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
2124
2368
  }
2125
2369
  });
2126
2370
  case 8:
2127
- productList = _context21.sent;
2371
+ productList = _context25.sent;
2128
2372
  list = productList || [];
2129
2373
  perfMark('fetchProductsBySSE', performance.now() - t0, {
2130
2374
  count: list.length
@@ -2134,23 +2378,23 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
2134
2378
  receivedCount: list.length,
2135
2379
  duration: "".concat(Math.round(performance.now() - t0), "ms")
2136
2380
  });
2137
- return _context21.abrupt("return", list);
2381
+ return _context25.abrupt("return", list);
2138
2382
  case 15:
2139
- _context21.prev = 15;
2140
- _context21.t0 = _context21["catch"](5);
2141
- errorMessage = _context21.t0 instanceof Error ? _context21.t0.message : String(_context21.t0);
2383
+ _context25.prev = 15;
2384
+ _context25.t0 = _context25["catch"](5);
2385
+ errorMessage = _context25.t0 instanceof Error ? _context25.t0.message : String(_context25.t0);
2142
2386
  this.logError('fetchProductsBySSE: 失败', {
2143
2387
  ids: ids,
2144
2388
  error: errorMessage
2145
2389
  });
2146
- return _context21.abrupt("return", []);
2390
+ return _context25.abrupt("return", []);
2147
2391
  case 20:
2148
2392
  case "end":
2149
- return _context21.stop();
2393
+ return _context25.stop();
2150
2394
  }
2151
- }, _callee21, this, [[5, 15]]);
2395
+ }, _callee25, this, [[5, 15]]);
2152
2396
  }));
2153
- function fetchProductsBySSE(_x20) {
2397
+ function fetchProductsBySSE(_x24) {
2154
2398
  return _fetchProductsBySSE.apply(this, arguments);
2155
2399
  }
2156
2400
  return fetchProductsBySSE;
@@ -2158,63 +2402,84 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
2158
2402
  /**
2159
2403
  * 将 body 完整数据直接覆盖到本地 store(不调用报价单接口)
2160
2404
  * 已存在的 → 直接替换;不存在的 → 追加
2161
- * 同时更新 Map 缓存、IndexDB,触发 onProductsChanged
2162
- * 价格缓存由 processProductSyncMessages 末尾统一清除
2405
+ *
2406
+ * @example
2407
+ * await this.applyBodyUpdatesToStore(bodyUpdates, { skipIndexDB: true })
2163
2408
  */
2164
2409
  )
2165
2410
  }, {
2166
2411
  key: "applyBodyUpdatesToStore",
2167
2412
  value: (function () {
2168
- var _applyBodyUpdatesToStore = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee22(bodyUpdates) {
2169
- var updatedCount, newCount, appliedIds, _iterator12, _step12, _step12$value, id, body;
2170
- return _regeneratorRuntime().wrap(function _callee22$(_context22) {
2171
- while (1) switch (_context22.prev = _context22.next) {
2413
+ var _applyBodyUpdatesToStore = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee26(bodyUpdates, options) {
2414
+ var changedProductIds, updatedCount, newCount, appliedIds, mergeActions, changedProducts, _iterator15, _step15, _step15$value, id, body;
2415
+ return _regeneratorRuntime().wrap(function _callee26$(_context26) {
2416
+ while (1) switch (_context26.prev = _context26.next) {
2172
2417
  case 0:
2418
+ changedProductIds = _toConsumableArray(bodyUpdates.keys());
2173
2419
  this.logInfo('applyBodyUpdatesToStore: 开始', {
2174
2420
  count: bodyUpdates.size
2175
2421
  });
2176
2422
  updatedCount = 0;
2177
2423
  newCount = 0;
2178
2424
  appliedIds = new Set();
2425
+ mergeActions = {};
2426
+ changedProducts = [];
2179
2427
  this.store.list = this.store.list.map(function (p) {
2180
2428
  if (bodyUpdates.has(p.id)) {
2181
2429
  updatedCount++;
2182
2430
  appliedIds.add(p.id);
2183
- return bodyUpdates.get(p.id);
2431
+ mergeActions[p.id] = 'update';
2432
+ var next = bodyUpdates.get(p.id);
2433
+ changedProducts.push(next);
2434
+ return next;
2184
2435
  }
2185
2436
  return p;
2186
2437
  });
2187
- _iterator12 = _createForOfIteratorHelper(bodyUpdates);
2438
+ _iterator15 = _createForOfIteratorHelper(bodyUpdates);
2188
2439
  try {
2189
- for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
2190
- _step12$value = _slicedToArray(_step12.value, 2), id = _step12$value[0], body = _step12$value[1];
2440
+ for (_iterator15.s(); !(_step15 = _iterator15.n()).done;) {
2441
+ _step15$value = _slicedToArray(_step15.value, 2), id = _step15$value[0], body = _step15$value[1];
2191
2442
  if (!appliedIds.has(id)) {
2192
2443
  this.store.list.push(body);
2193
2444
  newCount++;
2445
+ mergeActions[id] = 'insert';
2446
+ changedProducts.push(body);
2194
2447
  }
2195
2448
  }
2196
2449
  } catch (err) {
2197
- _iterator12.e(err);
2450
+ _iterator15.e(err);
2198
2451
  } finally {
2199
- _iterator12.f();
2452
+ _iterator15.f();
2200
2453
  }
2201
2454
  this.syncProductsMap();
2202
- _context22.next = 10;
2203
- return this.saveProductsToIndexDB(this.store.list);
2204
- case 10:
2205
- this.core.effects.emit(ProductsHooks.onProductsChanged, this.store.list);
2455
+ if (options !== null && options !== void 0 && options.skipIndexDB) {
2456
+ _context26.next = 14;
2457
+ break;
2458
+ }
2459
+ _context26.next = 14;
2460
+ return this.patchProductsInIndexDB(changedProducts, 'pubsub.bodyUpdate', mergeActions);
2461
+ case 14:
2462
+ if (!(options !== null && options !== void 0 && options.skipEmit)) {
2463
+ this.core.effects.emit(ProductsHooks.onProductsChanged, this.store.list);
2464
+ }
2206
2465
  this.logInfo('applyBodyUpdatesToStore: 完成', {
2207
2466
  updatedCount: updatedCount,
2208
2467
  newCount: newCount,
2209
2468
  totalCount: this.store.list.length
2210
2469
  });
2211
- case 12:
2470
+ return _context26.abrupt("return", {
2471
+ changedProducts: changedProducts,
2472
+ mergeActions: mergeActions,
2473
+ updatedCount: updatedCount,
2474
+ newCount: newCount
2475
+ });
2476
+ case 17:
2212
2477
  case "end":
2213
- return _context22.stop();
2478
+ return _context26.stop();
2214
2479
  }
2215
- }, _callee22, this);
2480
+ }, _callee26, this);
2216
2481
  }));
2217
- function applyBodyUpdatesToStore(_x21) {
2482
+ function applyBodyUpdatesToStore(_x25, _x26) {
2218
2483
  return _applyBodyUpdatesToStore.apply(this, arguments);
2219
2484
  }
2220
2485
  return applyBodyUpdatesToStore;
@@ -2222,68 +2487,91 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
2222
2487
  /**
2223
2488
  * 将增量拉取的商品合并到 store
2224
2489
  * 已存在的 → 替换;新的 → 追加
2225
- * 同时更新 store.map、IndexDB,触发 onProductsChanged
2490
+ *
2491
+ * @example
2492
+ * await this.mergeProductsToStore(freshProducts, { skipIndexDB: true })
2226
2493
  */
2227
2494
  )
2228
2495
  }, {
2229
2496
  key: "mergeProductsToStore",
2230
2497
  value: (function () {
2231
- var _mergeProductsToStore = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee23(freshProducts) {
2232
- var freshMap, _iterator13, _step13, p, updatedList, newCount, _iterator14, _step14, _p2, updatedCount;
2233
- return _regeneratorRuntime().wrap(function _callee23$(_context23) {
2234
- while (1) switch (_context23.prev = _context23.next) {
2498
+ var _mergeProductsToStore = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee27(freshProducts, options) {
2499
+ var freshMap, _iterator16, _step16, p, mergeActions, changedProducts, updatedList, newCount, _iterator17, _step17, _p2, updatedCount, changedProductIds;
2500
+ return _regeneratorRuntime().wrap(function _callee27$(_context27) {
2501
+ while (1) switch (_context27.prev = _context27.next) {
2235
2502
  case 0:
2236
2503
  freshMap = new Map();
2237
- _iterator13 = _createForOfIteratorHelper(freshProducts);
2504
+ _iterator16 = _createForOfIteratorHelper(freshProducts);
2238
2505
  try {
2239
- for (_iterator13.s(); !(_step13 = _iterator13.n()).done;) {
2240
- p = _step13.value;
2506
+ for (_iterator16.s(); !(_step16 = _iterator16.n()).done;) {
2507
+ p = _step16.value;
2241
2508
  freshMap.set(p.id, p);
2242
2509
  }
2243
2510
  } catch (err) {
2244
- _iterator13.e(err);
2511
+ _iterator16.e(err);
2245
2512
  } finally {
2246
- _iterator13.f();
2513
+ _iterator16.f();
2247
2514
  }
2515
+ mergeActions = {};
2516
+ changedProducts = [];
2248
2517
  updatedList = this.store.list.map(function (p) {
2249
2518
  if (freshMap.has(p.id)) {
2250
2519
  var fresh = freshMap.get(p.id);
2251
2520
  freshMap.delete(p.id);
2521
+ mergeActions[p.id] = 'update';
2522
+ changedProducts.push(fresh);
2252
2523
  return fresh;
2253
2524
  }
2254
2525
  return p;
2255
2526
  }); // freshMap 中剩余的是新商品(create 场景)
2256
2527
  newCount = freshMap.size;
2257
- _iterator14 = _createForOfIteratorHelper(freshMap.values());
2528
+ _iterator17 = _createForOfIteratorHelper(freshMap.values());
2258
2529
  try {
2259
- for (_iterator14.s(); !(_step14 = _iterator14.n()).done;) {
2260
- _p2 = _step14.value;
2530
+ for (_iterator17.s(); !(_step17 = _iterator17.n()).done;) {
2531
+ _p2 = _step17.value;
2261
2532
  updatedList.push(_p2);
2533
+ mergeActions[_p2.id] = 'insert';
2534
+ changedProducts.push(_p2);
2262
2535
  }
2263
2536
  } catch (err) {
2264
- _iterator14.e(err);
2537
+ _iterator17.e(err);
2265
2538
  } finally {
2266
- _iterator14.f();
2539
+ _iterator17.f();
2267
2540
  }
2268
2541
  updatedCount = freshProducts.length - newCount;
2542
+ changedProductIds = freshProducts.map(function (p) {
2543
+ return p.id;
2544
+ });
2269
2545
  this.store.list = updatedList;
2270
2546
  this.syncProductsMap();
2271
- _context23.next = 12;
2272
- return this.saveProductsToIndexDB(this.store.list);
2273
- case 12:
2547
+ if (options !== null && options !== void 0 && options.skipIndexDB) {
2548
+ _context27.next = 16;
2549
+ break;
2550
+ }
2551
+ _context27.next = 16;
2552
+ return this.patchProductsInIndexDB(changedProducts, 'pubsub.mergeProductsToStore', mergeActions);
2553
+ case 16:
2554
+ if (!(options !== null && options !== void 0 && options.skipEmit)) {
2555
+ this.core.effects.emit(ProductsHooks.onProductsChanged, this.store.list);
2556
+ }
2274
2557
  this.logInfo('mergeProductsToStore: 合并完成', {
2275
2558
  updatedCount: updatedCount,
2276
2559
  newCount: newCount,
2277
2560
  totalCount: this.store.list.length
2278
2561
  });
2279
- this.core.effects.emit(ProductsHooks.onProductsChanged, this.store.list);
2280
- case 14:
2562
+ return _context27.abrupt("return", {
2563
+ changedProducts: changedProducts,
2564
+ mergeActions: mergeActions,
2565
+ updatedCount: updatedCount,
2566
+ newCount: newCount
2567
+ });
2568
+ case 19:
2281
2569
  case "end":
2282
- return _context23.stop();
2570
+ return _context27.stop();
2283
2571
  }
2284
- }, _callee23, this);
2572
+ }, _callee27, this);
2285
2573
  }));
2286
- function mergeProductsToStore(_x22) {
2574
+ function mergeProductsToStore(_x27, _x28) {
2287
2575
  return _mergeProductsToStore.apply(this, arguments);
2288
2576
  }
2289
2577
  return mergeProductsToStore;
@@ -2297,56 +2585,65 @@ export var ProductsModule = /*#__PURE__*/function (_BaseModule) {
2297
2585
  }, {
2298
2586
  key: "silentRefresh",
2299
2587
  value: (function () {
2300
- var _silentRefresh = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee24() {
2301
- var t0, products, errorMessage;
2302
- return _regeneratorRuntime().wrap(function _callee24$(_context24) {
2303
- while (1) switch (_context24.prev = _context24.next) {
2588
+ var _silentRefresh = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee28() {
2589
+ var t0, now, elapsedSincePreload, elapsedSinceFullFetch, products, errorMessage;
2590
+ return _regeneratorRuntime().wrap(function _callee28$(_context28) {
2591
+ while (1) switch (_context28.prev = _context28.next) {
2304
2592
  case 0:
2305
2593
  t0 = performance.now();
2594
+ now = Date.now();
2595
+ elapsedSincePreload = now - this.lastPreloadCompletedAtMs;
2596
+ elapsedSinceFullFetch = now - this.lastServerFullFetchAtMs;
2597
+ if (!(this.lastPreloadCompletedAtMs > 0 && elapsedSincePreload < PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS || this.lastServerFullFetchAtMs > 0 && elapsedSinceFullFetch < PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS)) {
2598
+ _context28.next = 6;
2599
+ break;
2600
+ }
2601
+ return _context28.abrupt("return", this.store.list);
2602
+ case 6:
2306
2603
  this.logInfo('silentRefresh 开始');
2307
- _context24.prev = 2;
2308
- _context24.next = 5;
2604
+ _context28.prev = 7;
2605
+ _context28.next = 10;
2309
2606
  return this.loadProductsByServer();
2310
- case 5:
2311
- products = _context24.sent;
2607
+ case 10:
2608
+ products = _context28.sent;
2312
2609
  if (!(products && products.length > 0)) {
2313
- _context24.next = 16;
2610
+ _context28.next = 21;
2314
2611
  break;
2315
2612
  }
2316
2613
  this.store.list = products;
2317
2614
  this.syncProductsMap();
2318
2615
  this.clearPriceCache();
2319
2616
  this.core.effects.emit(ProductsHooks.onProductsChanged, this.store.list);
2320
- _context24.next = 13;
2617
+ _context28.next = 18;
2321
2618
  return this.core.effects.emit(ProductsHooks.onProductsSyncCompleted, null);
2322
- case 13:
2619
+ case 18:
2323
2620
  this.logInfo('silentRefresh 完成', {
2324
2621
  productCount: products.length,
2325
2622
  duration: "".concat(Math.round(performance.now() - t0), "ms")
2326
2623
  });
2327
- _context24.next = 17;
2624
+ _context28.next = 22;
2328
2625
  break;
2329
- case 16:
2626
+ case 21:
2330
2627
  this.logWarning('silentRefresh: 服务器未返回数据');
2331
- case 17:
2628
+ case 22:
2332
2629
  perfMark('silentRefresh', performance.now() - t0, {
2333
2630
  count: this.store.list.length
2334
2631
  });
2335
- return _context24.abrupt("return", this.store.list);
2336
- case 21:
2337
- _context24.prev = 21;
2338
- _context24.t0 = _context24["catch"](2);
2339
- errorMessage = _context24.t0 instanceof Error ? _context24.t0.message : String(_context24.t0);
2632
+ return _context28.abrupt("return", this.store.list);
2633
+ case 26:
2634
+ _context28.prev = 26;
2635
+ _context28.t0 = _context28["catch"](7);
2636
+ errorMessage = _context28.t0 instanceof Error ? _context28.t0.message : String(_context28.t0);
2340
2637
  this.logError('silentRefresh 失败', {
2341
2638
  duration: "".concat(Math.round(performance.now() - t0), "ms"),
2342
2639
  error: errorMessage
2343
2640
  });
2344
- return _context24.abrupt("return", this.store.list);
2345
- case 26:
2641
+ return _context28.abrupt("return", this.store.list);
2642
+ case 31:
2346
2643
  case "end":
2347
- return _context24.stop();
2644
+ return _context28.stop();
2348
2645
  }
2349
- }, _callee24, this, [[2, 21]]);
2646
+ }, _callee28, this, [[7, 26]]);
2350
2647
  }));
2351
2648
  function silentRefresh() {
2352
2649
  return _silentRefresh.apply(this, arguments);