@pisell/pisellos 0.0.568 → 0.10.1

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 (588) hide show
  1. package/dist/core/index.js +10 -6
  2. package/dist/index.d.ts +0 -1
  3. package/dist/index.js +0 -3
  4. package/dist/model/strategy/adapter/promotion/evaluator.js +3 -2
  5. package/dist/model/strategy/adapter/walletPass/evaluator.js +7 -5
  6. package/dist/model/strategy/adapter/walletPass/example.js +26 -3
  7. package/dist/model/strategy/adapter/walletPass/index.js +5 -5
  8. package/dist/model/strategy/adapter/walletPass/type.d.ts +0 -3
  9. package/dist/model/strategy/adapter/walletPass/utils.d.ts +0 -26
  10. package/dist/model/strategy/adapter/walletPass/utils.js +24 -96
  11. package/dist/model/strategy/strategy-example.js +19 -5
  12. package/dist/modules/BaseModule.d.ts +2 -2
  13. package/dist/modules/BaseModule.js +12 -14
  14. package/dist/modules/BookingContext/index.d.ts +48 -0
  15. package/dist/modules/BookingContext/index.js +566 -0
  16. package/dist/modules/BookingContext/types.d.ts +102 -0
  17. package/dist/modules/BookingContext/types.js +51 -0
  18. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  19. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +302 -0
  20. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  21. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +149 -0
  22. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
  23. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +249 -0
  24. package/dist/modules/BookingContext/utils/flexible.d.ts +28 -0
  25. package/dist/modules/BookingContext/utils/flexible.js +56 -0
  26. package/dist/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  27. package/dist/modules/BookingContext/utils/formatResourceList.js +38 -0
  28. package/dist/modules/BookingContext/utils/index.d.ts +11 -0
  29. package/dist/modules/BookingContext/utils/index.js +11 -0
  30. package/dist/modules/BookingContext/utils/noResource.d.ts +13 -0
  31. package/dist/modules/BookingContext/utils/noResource.js +77 -0
  32. package/dist/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
  33. package/dist/modules/BookingContext/utils/orderLineDisplay.js +36 -0
  34. package/dist/modules/BookingContext/utils/productExtend.d.ts +72 -0
  35. package/dist/modules/BookingContext/utils/productExtend.js +339 -0
  36. package/dist/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  37. package/dist/modules/BookingContext/utils/resourceErrors.js +74 -0
  38. package/dist/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  39. package/dist/modules/BookingContext/utils/resourceSelection.js +24 -0
  40. package/dist/modules/BookingContext/utils/resources.d.ts +80 -0
  41. package/dist/modules/BookingContext/utils/resources.js +486 -0
  42. package/dist/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  43. package/dist/modules/BookingContext/utils/serviceTimes.js +151 -0
  44. package/dist/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  45. package/dist/modules/BookingContext/utils/timeSlices.js +100 -0
  46. package/dist/modules/Cart/index.js +3 -0
  47. package/dist/modules/Cart/utils/cartProduct.js +27 -5
  48. package/dist/modules/Cart/utils/cartResource.js +0 -2
  49. package/dist/modules/Cart/utils/changePrice.js +11 -11
  50. package/dist/modules/Customer/index.d.ts +20 -0
  51. package/dist/modules/Customer/index.js +172 -83
  52. package/dist/modules/Customer/types.d.ts +2 -0
  53. package/dist/modules/Date/index.js +5 -1
  54. package/dist/modules/Discount/index.d.ts +2 -2
  55. package/dist/modules/Discount/index.js +43 -30
  56. package/dist/modules/Discount/types.d.ts +1 -1
  57. package/dist/modules/OpenData/index.d.ts +8 -0
  58. package/dist/modules/OpenData/index.js +38 -16
  59. package/dist/modules/Order/index.d.ts +449 -24
  60. package/dist/modules/Order/index.js +5460 -574
  61. package/dist/modules/Order/types.d.ts +693 -88
  62. package/dist/modules/Order/types.js +68 -1
  63. package/dist/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  64. package/dist/modules/Order/utils/bundleDiscountHydration.js +144 -0
  65. package/dist/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  66. package/dist/modules/Order/utils/manualProductDiscount.js +210 -0
  67. package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
  68. package/dist/modules/Order/utils/orderCollectionIdentity.js +405 -0
  69. package/dist/modules/Order/utils.d.ts +167 -18
  70. package/dist/modules/Order/utils.js +960 -165
  71. package/dist/modules/Payment/index.d.ts +10 -9
  72. package/dist/modules/Payment/index.js +573 -746
  73. package/dist/modules/Payment/types.d.ts +44 -24
  74. package/dist/modules/Payment/utils.d.ts +1 -1
  75. package/dist/modules/Payment/utils.js +4 -3
  76. package/dist/modules/Payment/walletpass.d.ts +0 -2
  77. package/dist/modules/Payment/walletpass.js +49 -33
  78. package/dist/modules/Product/types.d.ts +29 -7
  79. package/dist/modules/ProductList/index.d.ts +17 -13
  80. package/dist/modules/ProductList/index.js +182 -81
  81. package/dist/modules/ProductList/types.d.ts +16 -0
  82. package/dist/modules/Quotation/index.d.ts +22 -2
  83. package/dist/modules/Quotation/index.js +108 -42
  84. package/dist/modules/Quotation/types.d.ts +19 -0
  85. package/dist/modules/ResourcePlanner/index.d.ts +24 -0
  86. package/dist/modules/ResourcePlanner/index.js +181 -0
  87. package/dist/modules/ResourcePlanner/planner.d.ts +14 -0
  88. package/dist/modules/ResourcePlanner/planner.js +1069 -0
  89. package/dist/modules/ResourcePlanner/types.d.ts +227 -0
  90. package/dist/modules/ResourcePlanner/types.js +1 -0
  91. package/dist/modules/Rules/index.d.ts +8 -10
  92. package/dist/modules/Rules/index.js +324 -513
  93. package/dist/modules/Rules/types.d.ts +14 -3
  94. package/dist/modules/SalesSummary/index.d.ts +23 -26
  95. package/dist/modules/SalesSummary/index.js +152 -46
  96. package/dist/modules/SalesSummary/types.d.ts +9 -1
  97. package/dist/modules/SalesSummary/utils.d.ts +3 -22
  98. package/dist/modules/SalesSummary/utils.js +804 -165
  99. package/dist/modules/Schedule/getDateIsInSchedule.js +14 -12
  100. package/dist/modules/Schedule/index.d.ts +18 -5
  101. package/dist/modules/Schedule/index.js +79 -24
  102. package/dist/modules/Schedule/types.d.ts +2 -0
  103. package/dist/modules/Schedule/utils.js +1 -0
  104. package/dist/modules/Step/index.js +1 -0
  105. package/dist/modules/Summary/index.js +4 -3
  106. package/dist/modules/Summary/utils.js +22 -43
  107. package/dist/modules/SurchargeList/index.d.ts +18 -0
  108. package/dist/modules/SurchargeList/index.js +185 -0
  109. package/dist/modules/SurchargeList/types.d.ts +15 -0
  110. package/dist/modules/SurchargeList/types.js +1 -0
  111. package/dist/modules/index.d.ts +3 -0
  112. package/dist/modules/index.js +4 -1
  113. package/dist/plugins/app.d.ts +2 -0
  114. package/dist/plugins/request.d.ts +1 -0
  115. package/dist/plugins/request.js +4 -1
  116. package/dist/plugins/window.js +6 -2
  117. package/dist/server/index.d.ts +462 -8
  118. package/dist/server/index.js +6168 -680
  119. package/dist/server/modules/floor-plan/index.d.ts +39 -0
  120. package/dist/server/modules/floor-plan/index.js +595 -0
  121. package/dist/server/modules/floor-plan/types.d.ts +43 -0
  122. package/dist/server/modules/floor-plan/types.js +13 -0
  123. package/dist/server/modules/index.d.ts +7 -2
  124. package/dist/server/modules/index.js +6 -0
  125. package/dist/server/modules/menu/index.js +41 -32
  126. package/dist/server/modules/order/index.d.ts +207 -14
  127. package/dist/server/modules/order/index.js +2328 -379
  128. package/dist/server/modules/order/types.d.ts +76 -5
  129. package/dist/server/modules/order/types.js +14 -1
  130. package/dist/server/modules/order/utils/filterBookings.d.ts +7 -1
  131. package/dist/server/modules/order/utils/filterBookings.js +118 -11
  132. package/dist/server/modules/order/utils/filterOrders.js +242 -14
  133. package/dist/server/modules/payment/index.d.ts +28 -0
  134. package/dist/server/modules/payment/index.js +305 -0
  135. package/dist/server/modules/payment/types.d.ts +9 -0
  136. package/dist/server/modules/payment/types.js +1 -0
  137. package/dist/server/modules/products/index.d.ts +105 -14
  138. package/dist/server/modules/products/index.js +1416 -521
  139. package/dist/server/modules/products/types.d.ts +34 -1
  140. package/dist/server/modules/products/types.js +4 -0
  141. package/dist/server/modules/quotation/index.d.ts +39 -0
  142. package/dist/server/modules/quotation/index.js +298 -77
  143. package/dist/server/modules/resource/index.d.ts +2 -3
  144. package/dist/server/modules/resource/index.js +109 -86
  145. package/dist/server/modules/schedule/index.d.ts +6 -4
  146. package/dist/server/modules/schedule/index.js +145 -106
  147. package/dist/server/test.json +713 -0
  148. package/dist/server/types.d.ts +2 -0
  149. package/dist/server/utils/product.js +3 -2
  150. package/dist/server/utils/small-ticket.d.ts +71 -0
  151. package/dist/server/utils/small-ticket.js +963 -0
  152. package/dist/solution/BaseSales/index.d.ts +378 -0
  153. package/dist/solution/BaseSales/index.js +4009 -0
  154. package/dist/solution/BaseSales/types.d.ts +394 -0
  155. package/dist/solution/BaseSales/types.js +40 -0
  156. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
  157. package/dist/solution/BaseSales/utils/cartPromotion.js +1450 -0
  158. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +144 -0
  159. package/dist/solution/BaseSales/utils/parseSalesResponse.js +157 -0
  160. package/dist/solution/BaseSales/utils/quotationPrice.d.ts +18 -0
  161. package/dist/solution/BaseSales/utils/quotationPrice.js +250 -0
  162. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +63 -0
  163. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +218 -0
  164. package/dist/solution/BaseSales/utils.d.ts +40 -0
  165. package/dist/solution/BaseSales/utils.js +263 -0
  166. package/dist/solution/BookingByStep/index.d.ts +1 -1
  167. package/dist/solution/BookingByStep/index.js +60 -11
  168. package/dist/solution/BookingByStep/utils/capacity.js +11 -1
  169. package/dist/solution/BookingByStep/utils/resources.js +3 -1
  170. package/dist/solution/BookingByStep/utils/timeslots.js +43 -2
  171. package/dist/solution/BookingTicket/index.d.ts +393 -24
  172. package/dist/solution/BookingTicket/index.js +2508 -443
  173. package/dist/solution/BookingTicket/types.d.ts +191 -6
  174. package/dist/solution/BookingTicket/types.js +83 -10
  175. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
  176. package/dist/solution/BookingTicket/utils/addProductDecision.js +346 -0
  177. package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
  178. package/dist/solution/BookingTicket/utils/addTimeAvailability.js +95 -0
  179. package/dist/solution/BookingTicket/utils/bookingStatus.d.ts +77 -0
  180. package/dist/solution/BookingTicket/utils/bookingStatus.js +136 -0
  181. package/dist/solution/BookingTicket/utils/cartView.d.ts +29 -0
  182. package/dist/solution/BookingTicket/utils/cartView.js +209 -0
  183. package/dist/solution/BookingTicket/utils/exampleData.d.ts +123 -0
  184. package/dist/solution/BookingTicket/utils/exampleData.js +183 -0
  185. package/dist/solution/BookingTicket/utils/orderCustomer.d.ts +4 -0
  186. package/dist/solution/BookingTicket/utils/orderCustomer.js +31 -0
  187. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
  188. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.js +438 -0
  189. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
  190. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +400 -0
  191. package/dist/solution/BookingTicket/utils/scan/cloudSearch.d.ts +4 -0
  192. package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +42 -1
  193. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
  194. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +56 -0
  195. package/dist/solution/BookingTicket/utils/scan/handleScan.d.ts +3 -1
  196. package/dist/solution/BookingTicket/utils/scan/handleScan.js +42 -28
  197. package/dist/solution/BookingTicket/utils/scan/index.d.ts +5 -0
  198. package/dist/solution/BookingTicket/utils/scan/index.js +30 -14
  199. package/dist/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
  200. package/dist/solution/BookingTicket/utils/scan/scanProductValues.js +150 -0
  201. package/dist/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
  202. package/dist/solution/BookingTicket/utils/sessionCatalogStale.js +78 -0
  203. package/dist/solution/BuyTickets/index.js +12 -9
  204. package/dist/solution/Checkout/index.d.ts +1 -0
  205. package/dist/solution/Checkout/index.js +275 -209
  206. package/dist/solution/Checkout/utils/index.js +20 -8
  207. package/dist/solution/RegisterAndLogin/config.js +2 -10
  208. package/dist/solution/RegisterAndLogin/index.js +76 -30
  209. package/dist/solution/Sales/index.d.ts +50 -5
  210. package/dist/solution/Sales/index.js +484 -92
  211. package/dist/solution/Sales/types.d.ts +26 -2
  212. package/dist/solution/ScanOrder/index.d.ts +27 -21
  213. package/dist/solution/ScanOrder/index.js +519 -444
  214. package/dist/solution/ScanOrder/types.d.ts +33 -11
  215. package/dist/solution/ScanOrder/types.js +4 -5
  216. package/dist/solution/ScanOrder/utils.d.ts +4 -1
  217. package/dist/solution/ScanOrder/utils.js +109 -34
  218. package/dist/solution/ShopDiscount/index.js +18 -19
  219. package/dist/solution/ShopDiscount/types.d.ts +4 -5
  220. package/dist/solution/ShopDiscount/utils.d.ts +0 -9
  221. package/dist/solution/ShopDiscount/utils.js +0 -9
  222. package/dist/solution/UnifiedBookingSales/index.d.ts +183 -0
  223. package/dist/solution/UnifiedBookingSales/index.js +1871 -0
  224. package/dist/solution/UnifiedBookingSales/types.d.ts +143 -0
  225. package/dist/solution/UnifiedBookingSales/types.js +11 -0
  226. package/dist/solution/VenueBooking/index.d.ts +32 -51
  227. package/dist/solution/VenueBooking/index.js +741 -808
  228. package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  229. package/dist/solution/VenueBooking/types.d.ts +1 -3
  230. package/dist/solution/VenueBooking/types.js +0 -1
  231. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
  232. package/dist/solution/VenueBooking/utils/dateSummary.js +25 -12
  233. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +6 -0
  234. package/dist/solution/VenueBooking/utils/slotMerge.js +9 -3
  235. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
  236. package/dist/solution/VenueBooking/utils/timeSlot.js +4 -9
  237. package/dist/solution/index.d.ts +2 -0
  238. package/dist/solution/index.js +3 -1
  239. package/dist/types/index.d.ts +12 -2
  240. package/dist/utils/task.js +18 -15
  241. package/dist/utils/watch.js +1 -0
  242. package/lib/apis/picoding.js +0 -2
  243. package/lib/core/index.js +132 -130
  244. package/lib/effects/index.js +57 -46
  245. package/lib/index.d.ts +0 -1
  246. package/lib/index.js +50 -92
  247. package/lib/model/index.js +21 -14
  248. package/lib/model/strategy/adapter/dataVariant/adapter.js +50 -38
  249. package/lib/model/strategy/adapter/dataVariant/evaluator.js +236 -162
  250. package/lib/model/strategy/adapter/dataVariant/examples.js +237 -229
  251. package/lib/model/strategy/adapter/dataVariant/index.js +34 -39
  252. package/lib/model/strategy/adapter/dataVariant/type.js +28 -57
  253. package/lib/model/strategy/adapter/index.js +64 -100
  254. package/lib/model/strategy/adapter/itemRule/adapter.js +144 -156
  255. package/lib/model/strategy/adapter/itemRule/evaluator.js +48 -36
  256. package/lib/model/strategy/adapter/itemRule/examples.js +225 -295
  257. package/lib/model/strategy/adapter/itemRule/index.js +57 -83
  258. package/lib/model/strategy/adapter/itemRule/type.js +36 -97
  259. package/lib/model/strategy/adapter/promotion/adapter.js +63 -84
  260. package/lib/model/strategy/adapter/promotion/evaluator.js +233 -382
  261. package/lib/model/strategy/adapter/promotion/examples.js +159 -139
  262. package/lib/model/strategy/adapter/promotion/index.js +0 -1
  263. package/lib/model/strategy/adapter/promotion/type.js +35 -199
  264. package/lib/model/strategy/adapter/type.js +16 -4
  265. package/lib/model/strategy/adapter/walletPass/evaluator.js +152 -180
  266. package/lib/model/strategy/adapter/walletPass/example.js +190 -217
  267. package/lib/model/strategy/adapter/walletPass/index.js +51 -75
  268. package/lib/model/strategy/adapter/walletPass/locales.js +58 -36
  269. package/lib/model/strategy/adapter/walletPass/type.d.ts +0 -3
  270. package/lib/model/strategy/adapter/walletPass/type.js +16 -4
  271. package/lib/model/strategy/adapter/walletPass/utils.d.ts +0 -26
  272. package/lib/model/strategy/adapter/walletPass/utils.js +383 -676
  273. package/lib/model/strategy/engine.js +168 -270
  274. package/lib/model/strategy/index.js +34 -49
  275. package/lib/model/strategy/strategy-example.js +239 -243
  276. package/lib/model/strategy/type.js +40 -100
  277. package/lib/modules/Account/index.js +53 -39
  278. package/lib/modules/Account/types.js +33 -20
  279. package/lib/modules/AccountList/index.js +154 -116
  280. package/lib/modules/AccountList/types.js +31 -30
  281. package/lib/modules/AccountList/utils.js +30 -18
  282. package/lib/modules/BaseModule.d.ts +2 -2
  283. package/lib/modules/BaseModule.js +50 -29
  284. package/lib/modules/BookingContext/index.d.ts +48 -0
  285. package/lib/modules/BookingContext/index.js +368 -0
  286. package/lib/modules/BookingContext/types.d.ts +102 -0
  287. package/lib/modules/BookingContext/types.js +34 -0
  288. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
  289. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +298 -0
  290. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
  291. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +155 -0
  292. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
  293. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +222 -0
  294. package/lib/modules/BookingContext/utils/flexible.d.ts +28 -0
  295. package/lib/modules/BookingContext/utils/flexible.js +80 -0
  296. package/lib/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
  297. package/lib/modules/BookingContext/utils/formatResourceList.js +50 -0
  298. package/lib/modules/BookingContext/utils/index.d.ts +11 -0
  299. package/lib/modules/BookingContext/utils/index.js +43 -0
  300. package/lib/modules/BookingContext/utils/noResource.d.ts +13 -0
  301. package/lib/modules/BookingContext/utils/noResource.js +90 -0
  302. package/lib/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
  303. package/lib/modules/BookingContext/utils/orderLineDisplay.js +56 -0
  304. package/lib/modules/BookingContext/utils/productExtend.d.ts +72 -0
  305. package/lib/modules/BookingContext/utils/productExtend.js +283 -0
  306. package/lib/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
  307. package/lib/modules/BookingContext/utils/resourceErrors.js +80 -0
  308. package/lib/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
  309. package/lib/modules/BookingContext/utils/resourceSelection.js +46 -0
  310. package/lib/modules/BookingContext/utils/resources.d.ts +80 -0
  311. package/lib/modules/BookingContext/utils/resources.js +377 -0
  312. package/lib/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
  313. package/lib/modules/BookingContext/utils/serviceTimes.js +162 -0
  314. package/lib/modules/BookingContext/utils/timeSlices.d.ts +42 -0
  315. package/lib/modules/BookingContext/utils/timeSlices.js +124 -0
  316. package/lib/modules/Cart/index.js +124 -170
  317. package/lib/modules/Cart/types.js +51 -46
  318. package/lib/modules/Cart/utils/cartAccount.js +39 -40
  319. package/lib/modules/Cart/utils/cartDate.js +61 -56
  320. package/lib/modules/Cart/utils/cartDiscount.js +33 -28
  321. package/lib/modules/Cart/utils/cartNote.js +32 -27
  322. package/lib/modules/Cart/utils/cartProduct.js +261 -309
  323. package/lib/modules/Cart/utils/cartRelationForms.js +35 -29
  324. package/lib/modules/Cart/utils/cartResource.js +78 -72
  325. package/lib/modules/Cart/utils/changePrice.js +59 -31
  326. package/lib/modules/Cart/utils/index.js +48 -106
  327. package/lib/modules/Customer/constants.js +34 -13
  328. package/lib/modules/Customer/index.d.ts +20 -0
  329. package/lib/modules/Customer/index.js +207 -217
  330. package/lib/modules/Customer/types.d.ts +2 -0
  331. package/lib/modules/Customer/types.js +35 -38
  332. package/lib/modules/Date/index.js +115 -116
  333. package/lib/modules/Date/types.js +28 -16
  334. package/lib/modules/Date/utils.js +123 -174
  335. package/lib/modules/Discount/index.d.ts +2 -2
  336. package/lib/modules/Discount/index.js +133 -119
  337. package/lib/modules/Discount/types.d.ts +1 -1
  338. package/lib/modules/Discount/types.js +31 -9
  339. package/lib/modules/Guests/index.js +56 -30
  340. package/lib/modules/Guests/types.js +33 -23
  341. package/lib/modules/Holder/index.js +189 -209
  342. package/lib/modules/Holder/types.js +16 -4
  343. package/lib/modules/Holder/utils.js +49 -20
  344. package/lib/modules/OpenData/index.d.ts +8 -0
  345. package/lib/modules/OpenData/index.js +88 -63
  346. package/lib/modules/OpenData/types.js +16 -4
  347. package/lib/modules/OpenData/utils.js +78 -44
  348. package/lib/modules/Order/index.d.ts +449 -24
  349. package/lib/modules/Order/index.js +4184 -514
  350. package/lib/modules/Order/types.d.ts +693 -88
  351. package/lib/modules/Order/types.js +35 -24
  352. package/lib/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  353. package/lib/modules/Order/utils/bundleDiscountHydration.js +139 -0
  354. package/lib/modules/Order/utils/manualProductDiscount.d.ts +106 -0
  355. package/lib/modules/Order/utils/manualProductDiscount.js +206 -0
  356. package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
  357. package/lib/modules/Order/utils/orderCollectionIdentity.js +415 -0
  358. package/lib/modules/Order/utils.d.ts +167 -18
  359. package/lib/modules/Order/utils.js +1085 -414
  360. package/lib/modules/Payment/cash.js +33 -20
  361. package/lib/modules/Payment/cashRecommendationAlgorithm.js +76 -145
  362. package/lib/modules/Payment/eftpos.js +30 -16
  363. package/lib/modules/Payment/index.d.ts +10 -9
  364. package/lib/modules/Payment/index.js +402 -636
  365. package/lib/modules/Payment/mx51.js +0 -1
  366. package/lib/modules/Payment/types.d.ts +44 -24
  367. package/lib/modules/Payment/types.js +107 -216
  368. package/lib/modules/Payment/utils.d.ts +1 -1
  369. package/lib/modules/Payment/utils.js +50 -52
  370. package/lib/modules/Payment/walletpass.d.ts +0 -2
  371. package/lib/modules/Payment/walletpass.js +216 -221
  372. package/lib/modules/Product/index.js +46 -51
  373. package/lib/modules/Product/types.d.ts +29 -7
  374. package/lib/modules/Product/types.js +16 -4
  375. package/lib/modules/Product/utils.js +33 -32
  376. package/lib/modules/ProductList/index.d.ts +17 -13
  377. package/lib/modules/ProductList/index.js +161 -120
  378. package/lib/modules/ProductList/types.d.ts +16 -0
  379. package/lib/modules/ProductList/types.js +31 -9
  380. package/lib/modules/Quotation/index.d.ts +22 -2
  381. package/lib/modules/Quotation/index.js +154 -64
  382. package/lib/modules/Quotation/types.d.ts +19 -0
  383. package/lib/modules/Quotation/types.js +16 -4
  384. package/lib/modules/Resource/index.js +59 -27
  385. package/lib/modules/Resource/types.js +32 -22
  386. package/lib/modules/Resource/utils.js +38 -30
  387. package/lib/modules/ResourcePlanner/index.d.ts +24 -0
  388. package/lib/modules/ResourcePlanner/index.js +148 -0
  389. package/lib/modules/ResourcePlanner/planner.d.ts +14 -0
  390. package/lib/modules/ResourcePlanner/planner.js +933 -0
  391. package/lib/modules/ResourcePlanner/types.d.ts +227 -0
  392. package/lib/modules/ResourcePlanner/types.js +17 -0
  393. package/lib/modules/Rules/index.d.ts +8 -10
  394. package/lib/modules/Rules/index.js +960 -1440
  395. package/lib/modules/Rules/types.d.ts +14 -3
  396. package/lib/modules/Rules/types.js +40 -17
  397. package/lib/modules/SalesSummary/index.d.ts +23 -26
  398. package/lib/modules/SalesSummary/index.js +134 -61
  399. package/lib/modules/SalesSummary/types.d.ts +9 -1
  400. package/lib/modules/SalesSummary/types.js +16 -4
  401. package/lib/modules/SalesSummary/utils.d.ts +3 -22
  402. package/lib/modules/SalesSummary/utils.js +814 -233
  403. package/lib/modules/ScanOrderLogger/index.js +79 -59
  404. package/lib/modules/ScanOrderLogger/providers/feishu.js +78 -54
  405. package/lib/modules/ScanOrderLogger/providers/grafana.js +36 -13
  406. package/lib/modules/ScanOrderLogger/types.js +16 -4
  407. package/lib/modules/Schedule/getDateIsInSchedule.js +169 -338
  408. package/lib/modules/Schedule/index.d.ts +18 -5
  409. package/lib/modules/Schedule/index.js +153 -104
  410. package/lib/modules/Schedule/type.js +16 -4
  411. package/lib/modules/Schedule/types.d.ts +2 -0
  412. package/lib/modules/Schedule/types.js +16 -4
  413. package/lib/modules/Schedule/utils.js +291 -433
  414. package/lib/modules/Step/index.js +52 -40
  415. package/lib/modules/Step/tyeps.js +16 -4
  416. package/lib/modules/Summary/index.js +71 -66
  417. package/lib/modules/Summary/types.js +16 -4
  418. package/lib/modules/Summary/utils.js +418 -791
  419. package/lib/modules/SurchargeList/index.d.ts +18 -0
  420. package/lib/modules/SurchargeList/index.js +109 -0
  421. package/lib/modules/SurchargeList/types.d.ts +15 -0
  422. package/lib/modules/SurchargeList/types.js +17 -0
  423. package/lib/modules/index.d.ts +3 -0
  424. package/lib/modules/index.js +63 -212
  425. package/lib/plugins/app.d.ts +2 -0
  426. package/lib/plugins/app.js +16 -4
  427. package/lib/plugins/index.js +25 -36
  428. package/lib/plugins/request.d.ts +1 -0
  429. package/lib/plugins/request.js +126 -137
  430. package/lib/plugins/shopStore.js +16 -4
  431. package/lib/plugins/user.js +16 -4
  432. package/lib/plugins/window.js +179 -171
  433. package/lib/server/index.d.ts +462 -8
  434. package/lib/server/index.js +4520 -1162
  435. package/lib/server/modules/floor-plan/index.d.ts +39 -0
  436. package/lib/server/modules/floor-plan/index.js +327 -0
  437. package/lib/server/modules/floor-plan/types.d.ts +43 -0
  438. package/lib/server/modules/floor-plan/types.js +34 -0
  439. package/lib/server/modules/index.d.ts +7 -2
  440. package/lib/server/modules/index.js +67 -84
  441. package/lib/server/modules/menu/index.js +122 -146
  442. package/lib/server/modules/menu/types.js +31 -18
  443. package/lib/server/modules/order/index.d.ts +207 -14
  444. package/lib/server/modules/order/index.js +1543 -285
  445. package/lib/server/modules/order/types.d.ts +76 -5
  446. package/lib/server/modules/order/types.js +32 -107
  447. package/lib/server/modules/order/utils/filterBookings.d.ts +7 -1
  448. package/lib/server/modules/order/utils/filterBookings.js +259 -176
  449. package/lib/server/modules/order/utils/filterOrders.js +293 -94
  450. package/lib/server/modules/payment/index.d.ts +28 -0
  451. package/lib/server/modules/payment/index.js +192 -0
  452. package/lib/server/modules/payment/types.d.ts +9 -0
  453. package/lib/server/modules/payment/types.js +17 -0
  454. package/lib/server/modules/products/index.d.ts +105 -14
  455. package/lib/server/modules/products/index.js +850 -475
  456. package/lib/server/modules/products/types.d.ts +34 -1
  457. package/lib/server/modules/products/types.js +34 -41
  458. package/lib/server/modules/quotation/index.d.ts +39 -0
  459. package/lib/server/modules/quotation/index.js +254 -75
  460. package/lib/server/modules/quotation/types.js +31 -21
  461. package/lib/server/modules/resource/index.d.ts +2 -3
  462. package/lib/server/modules/resource/index.js +240 -243
  463. package/lib/server/modules/resource/types.js +33 -42
  464. package/lib/server/modules/schedule/index.d.ts +6 -4
  465. package/lib/server/modules/schedule/index.js +146 -147
  466. package/lib/server/modules/schedule/types.js +21 -14
  467. package/lib/server/modules/schedule/utils.js +163 -334
  468. package/lib/server/test.json +713 -0
  469. package/lib/server/types.d.ts +2 -0
  470. package/lib/server/types.js +16 -4
  471. package/lib/server/utils/index.js +23 -25
  472. package/lib/server/utils/product.js +140 -197
  473. package/lib/server/utils/schedule.js +41 -34
  474. package/lib/server/utils/small-ticket.d.ts +71 -0
  475. package/lib/server/utils/small-ticket.js +904 -0
  476. package/lib/server/utils/time.js +49 -40
  477. package/lib/solution/BaseSales/index.d.ts +378 -0
  478. package/lib/solution/BaseSales/index.js +2533 -0
  479. package/lib/solution/BaseSales/types.d.ts +394 -0
  480. package/lib/solution/BaseSales/types.js +43 -0
  481. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
  482. package/lib/solution/BaseSales/utils/cartPromotion.js +1004 -0
  483. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +144 -0
  484. package/lib/solution/BaseSales/utils/parseSalesResponse.js +160 -0
  485. package/lib/solution/BaseSales/utils/quotationPrice.d.ts +18 -0
  486. package/lib/solution/BaseSales/utils/quotationPrice.js +289 -0
  487. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +63 -0
  488. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +256 -0
  489. package/lib/solution/BaseSales/utils.d.ts +40 -0
  490. package/lib/solution/BaseSales/utils.js +244 -0
  491. package/lib/solution/BookingByStep/index.d.ts +1 -1
  492. package/lib/solution/BookingByStep/index.js +1340 -1530
  493. package/lib/solution/BookingByStep/types.js +99 -40
  494. package/lib/solution/BookingByStep/utils/capacity.js +160 -192
  495. package/lib/solution/BookingByStep/utils/products.js +52 -42
  496. package/lib/solution/BookingByStep/utils/resources.js +330 -527
  497. package/lib/solution/BookingByStep/utils/stock.js +44 -65
  498. package/lib/solution/BookingByStep/utils/timeslots.js +131 -129
  499. package/lib/solution/BookingTicket/index.d.ts +393 -24
  500. package/lib/solution/BookingTicket/index.js +1374 -184
  501. package/lib/solution/BookingTicket/types.d.ts +191 -6
  502. package/lib/solution/BookingTicket/types.js +79 -40
  503. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
  504. package/lib/solution/BookingTicket/utils/addProductDecision.js +318 -0
  505. package/lib/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
  506. package/lib/solution/BookingTicket/utils/addTimeAvailability.js +125 -0
  507. package/lib/solution/BookingTicket/utils/bookingStatus.d.ts +77 -0
  508. package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -0
  509. package/lib/solution/BookingTicket/utils/cartView.d.ts +29 -0
  510. package/lib/solution/BookingTicket/utils/cartView.js +184 -0
  511. package/lib/solution/BookingTicket/utils/exampleData.d.ts +123 -0
  512. package/lib/solution/BookingTicket/utils/exampleData.js +0 -0
  513. package/lib/solution/BookingTicket/utils/orderCustomer.d.ts +4 -0
  514. package/lib/solution/BookingTicket/utils/orderCustomer.js +58 -0
  515. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
  516. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +254 -0
  517. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
  518. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +169 -0
  519. package/lib/solution/BookingTicket/utils/scan/cloudSearch.d.ts +4 -0
  520. package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +97 -64
  521. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
  522. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +51 -0
  523. package/lib/solution/BookingTicket/utils/scan/handleScan.d.ts +3 -1
  524. package/lib/solution/BookingTicket/utils/scan/handleScan.js +81 -82
  525. package/lib/solution/BookingTicket/utils/scan/index.d.ts +5 -0
  526. package/lib/solution/BookingTicket/utils/scan/index.js +109 -91
  527. package/lib/solution/BookingTicket/utils/scan/scanCache.js +43 -90
  528. package/lib/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
  529. package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +127 -0
  530. package/lib/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
  531. package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +85 -0
  532. package/lib/solution/BuyTickets/index.js +70 -67
  533. package/lib/solution/BuyTickets/types.js +38 -22
  534. package/lib/solution/Checkout/index.d.ts +1 -0
  535. package/lib/solution/Checkout/index.js +1169 -1463
  536. package/lib/solution/Checkout/types.js +61 -91
  537. package/lib/solution/Checkout/utils/index.js +156 -228
  538. package/lib/solution/PlaceOrder/index.js +0 -55
  539. package/lib/solution/RegisterAndLogin/config.js +462 -503
  540. package/lib/solution/RegisterAndLogin/index.js +630 -633
  541. package/lib/solution/RegisterAndLogin/types.js +76 -189
  542. package/lib/solution/RegisterAndLogin/utils.js +125 -183
  543. package/lib/solution/Sales/index.d.ts +50 -5
  544. package/lib/solution/Sales/index.js +498 -238
  545. package/lib/solution/Sales/types.d.ts +26 -2
  546. package/lib/solution/Sales/types.js +33 -27
  547. package/lib/solution/ScanOrder/index.d.ts +27 -21
  548. package/lib/solution/ScanOrder/index.js +936 -864
  549. package/lib/solution/ScanOrder/types.d.ts +33 -11
  550. package/lib/solution/ScanOrder/types.js +34 -34
  551. package/lib/solution/ScanOrder/utils.d.ts +4 -1
  552. package/lib/solution/ScanOrder/utils.js +422 -385
  553. package/lib/solution/ShopDiscount/index.js +233 -235
  554. package/lib/solution/ShopDiscount/types.d.ts +4 -5
  555. package/lib/solution/ShopDiscount/types.js +37 -15
  556. package/lib/solution/ShopDiscount/utils.d.ts +0 -9
  557. package/lib/solution/ShopDiscount/utils.js +172 -309
  558. package/lib/solution/UnifiedBookingSales/index.d.ts +183 -0
  559. package/lib/solution/UnifiedBookingSales/index.js +1076 -0
  560. package/lib/solution/UnifiedBookingSales/types.d.ts +143 -0
  561. package/lib/solution/UnifiedBookingSales/types.js +33 -0
  562. package/lib/solution/VenueBooking/index.d.ts +32 -51
  563. package/lib/solution/VenueBooking/index.js +1008 -984
  564. package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  565. package/lib/solution/VenueBooking/types.d.ts +1 -3
  566. package/lib/solution/VenueBooking/types.js +39 -20
  567. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
  568. package/lib/solution/VenueBooking/utils/dateSummary.js +62 -25
  569. package/lib/solution/VenueBooking/utils/resource.js +54 -31
  570. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +6 -0
  571. package/lib/solution/VenueBooking/utils/slotMerge.js +109 -90
  572. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
  573. package/lib/solution/VenueBooking/utils/timeSlot.js +133 -138
  574. package/lib/solution/VenueBooking/utils.js +67 -130
  575. package/lib/solution/index.d.ts +2 -0
  576. package/lib/solution/index.js +41 -102
  577. package/lib/store/createStore.js +29 -32
  578. package/lib/types/index.d.ts +12 -2
  579. package/lib/types/index.js +16 -4
  580. package/lib/utils/task.js +36 -36
  581. package/lib/utils/watch.js +47 -81
  582. package/package.json +2 -4
  583. package/dist/solution/Checkout/appointmentDemo.json +0 -1
  584. package/dist/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
  585. package/dist/solution/VenueBooking/utils/smartPricing.js +0 -233
  586. package/lib/solution/Checkout/appointmentDemo.json +0 -1
  587. package/lib/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
  588. package/lib/solution/VenueBooking/utils/smartPricing.js +0 -192
@@ -1,94 +1,100 @@
1
- "use strict";
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
2
18
 
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
19
+ // src/server/modules/products/index.ts
20
+ var products_exports = {};
21
+ __export(products_exports, {
22
+ ProductsModule: () => ProductsModule
5
23
  });
6
- exports.ProductsModule = void 0;
7
- var _BaseModule = require("../../../modules/BaseModule");
8
- var _plugins = require("../../../plugins");
9
- var _types = require("./types");
10
- var _product = require("../../utils/product");
11
- /**
12
- * IndexDB 存储名称
13
- */
14
- const INDEXDB_STORE_NAME = 'products';
15
-
16
- /** 商品同步防抖时间(毫秒) */
17
- const PRODUCT_SYNC_DEBOUNCE_MS = 10_000;
18
-
19
- /**
20
- * Products 模块 - 用于获取和管理完整的商品详细数据
21
- * 相比 ProductList 模块,Products 会获取所有详细信息并缓存
22
- */
23
- class ProductsModule extends _BaseModule.BaseModule {
24
- defaultName = 'products';
25
- defaultVersion = '1.0.0';
26
- store;
27
- request;
28
- dbManager; // IndexDBManager 实例
29
- logger; // LoggerManager 实例
30
- otherParams = {};
31
-
32
- // 商品价格缓存:Map<日期, 应用了价格的商品列表>
33
- productsPriceCache = new Map();
34
-
35
- // 缓存配置
36
- CACHE_MAX_DAYS = 7; // 最多缓存7天
37
-
38
- // 商品格式化器列表
39
- formatters = [];
40
-
41
- // 是否已注册内置价格格式化器
42
- isPriceFormatterRegistered = false;
43
-
44
- // ---- 商品数据同步相关 ----
45
- productDataSource;
46
- pendingSyncMessages = [];
47
- syncTimer;
24
+ module.exports = __toCommonJS(products_exports);
25
+ var import_BaseModule = require("../../../modules/BaseModule");
26
+ var import_Quotation = require("../../../modules/Quotation");
27
+ var import_types = require("./types");
28
+ var import_product = require("../../utils/product");
29
+ var INDEXDB_STORE_NAME = "products";
30
+ var PRODUCT_SYNC_DEBOUNCE_MS = 1e4;
31
+ var PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS = 3e4;
32
+ var ProductsModule = class extends import_BaseModule.BaseModule {
48
33
  constructor(name, version) {
49
34
  super(name, version);
35
+ this.defaultName = "products";
36
+ this.defaultVersion = "1.0.0";
37
+ // LoggerManager 实例
38
+ this.otherParams = {};
39
+ // 商品价格缓存:Map<日期, 应用了价格的商品列表>
40
+ this.productsPriceCache = /* @__PURE__ */ new Map();
41
+ // 缓存配置
42
+ this.CACHE_MAX_DAYS = 7;
43
+ // 最多缓存7天
44
+ // 商品格式化器列表
45
+ this.formatters = [];
46
+ // 是否已注册内置商品格式化器
47
+ this.isBuiltinFormatterRegistered = false;
48
+ // 旧报价单格式化器默认关闭,仅显式开启时作为兼容兜底注册
49
+ this.isLegacyPriceFormatterEnabled = false;
50
+ this.quotationBridgeLoadedKey = "";
51
+ this.quotationScheduleCache = /* @__PURE__ */ new Map();
52
+ this.quotationScheduleCacheSource = null;
53
+ this.quotationScheduleCacheLoaded = false;
54
+ this.pendingSyncMessages = [];
55
+ /** 最近一次 SSE 全量拉取完成时间 */
56
+ this.lastServerFullFetchAtMs = 0;
57
+ /** 最近一次 preload 完成时间(含 IndexDB 命中) */
58
+ this.lastPreloadCompletedAtMs = 0;
59
+ /** IndexDB 写入串行队列,避免快照与 patch 并发交错 */
60
+ this.productIndexDBSaveQueue = Promise.resolve();
61
+ /** 最近一次智能定价评估提取的 schedule 变价时间点(HH:mm),供 Server 订阅定时刷新使用 */
62
+ this.lastScheduleTimePoints = [];
50
63
  }
51
64
  async initialize(core, options) {
65
+ var _a;
52
66
  this.core = core;
53
67
  this.store = options.store;
54
68
  this.otherParams = options.otherParams || {};
55
- if (Array.isArray(options.initialState?.list)) {
69
+ if (Array.isArray((_a = options.initialState) == null ? void 0 : _a.list)) {
56
70
  this.store.list = options.initialState.list;
57
- // 同步更新 Map 缓存
58
71
  this.syncProductsMap();
59
- this.core.effects.emit(_types.ProductsHooks.onProductsChanged, this.store.list);
72
+ this.core.effects.emit(import_types.ProductsHooks.onProductsChanged, this.store.list);
60
73
  } else {
61
74
  this.store.list = [];
62
- this.store.map = new Map();
75
+ this.store.map = /* @__PURE__ */ new Map();
63
76
  }
64
- this.request = core.getPlugin('request');
65
-
66
- // 获取并存储 dbManager 和 logger
67
- const appPlugin = core.getPlugin('app');
77
+ this.request = core.getPlugin("request");
78
+ const appPlugin = core.getPlugin("app");
68
79
  if (appPlugin) {
69
80
  const app = appPlugin.getApp();
70
81
  this.dbManager = app.dbManager;
71
82
  this.logger = app.logger;
72
- if (this.dbManager) {} else {
73
- console.warn('[Products] IndexDB Manager 未找到');
83
+ if (this.dbManager) {
84
+ console.log("[Products] IndexDB Manager 已初始化");
85
+ } else {
86
+ console.warn("[Products] IndexDB Manager 未找到");
74
87
  }
75
88
  }
76
-
77
- // 注册内置的价格格式化器(作为第一个格式化器)
78
- this.registerBuiltinPriceFormatter();
79
-
80
- // 初始化 ProductDataSource 实例
89
+ this.registerBuiltinProductFormatters();
81
90
  this.initProductDataSource();
82
-
83
- // 初始化商品数据同步(pubsub 订阅)
84
91
  this.setupProductSync();
85
- this.logInfo('模块初始化完成', {
92
+ this.logInfo("模块初始化完成", {
86
93
  hasDbManager: !!this.dbManager,
87
94
  hasLogger: !!this.logger,
88
95
  initialProductCount: this.store.list.length
89
96
  });
90
97
  }
91
-
92
98
  /**
93
99
  * 记录信息日志
94
100
  * @param title 日志标题
@@ -98,16 +104,14 @@ class ProductsModule extends _BaseModule.BaseModule {
98
104
  try {
99
105
  if (this.logger) {
100
106
  this.logger.addLog({
101
- type: 'info',
107
+ type: "info",
102
108
  title: `[ProductsModule] ${title}`,
103
109
  metadata: metadata || {}
104
110
  });
105
111
  }
106
112
  } catch {
107
- // 日志记录失败不影响主流程
108
113
  }
109
114
  }
110
-
111
115
  /**
112
116
  * 记录警告日志
113
117
  * @param title 日志标题
@@ -117,16 +121,14 @@ class ProductsModule extends _BaseModule.BaseModule {
117
121
  try {
118
122
  if (this.logger) {
119
123
  this.logger.addLog({
120
- type: 'warning',
124
+ type: "warning",
121
125
  title: `[ProductsModule] ${title}`,
122
126
  metadata: metadata || {}
123
127
  });
124
128
  }
125
129
  } catch {
126
- // 日志记录失败不影响主流程
127
130
  }
128
131
  }
129
-
130
132
  /**
131
133
  * 记录错误日志
132
134
  * @param title 日志标题
@@ -136,53 +138,48 @@ class ProductsModule extends _BaseModule.BaseModule {
136
138
  try {
137
139
  if (this.logger) {
138
140
  this.logger.addLog({
139
- type: 'error',
141
+ type: "error",
140
142
  title: `[ProductsModule] ${title}`,
141
143
  metadata: metadata || {}
142
144
  });
143
145
  }
144
146
  } catch {
145
- // 日志记录失败不影响主流程
146
147
  }
147
148
  }
148
-
149
149
  /**
150
150
  * 加载商品价格(原始方法,不带缓存)
151
151
  * @private
152
152
  */
153
153
  async loadProductsPrice({
154
154
  ids = [],
155
- customer_id,
156
- schedule_date
155
+ schedule_date,
156
+ schedule_datetime,
157
+ customer_id
157
158
  }) {
158
- this.logInfo('开始加载商品价格', {
159
+ this.logInfo("开始加载商品价格", {
159
160
  productCount: ids.length,
160
161
  schedule_date,
162
+ schedule_datetime,
161
163
  customer_id
162
164
  });
163
165
  const startTime = Date.now();
166
+ const datetime = schedule_datetime || schedule_date;
164
167
  try {
165
- const productsData = await this.request.post(`/product/query/price`, {
166
- ids,
167
- customer_id,
168
- schedule_date
169
- }, {
170
- cache: {
171
- mode: _plugins.RequestModeENUM.REMOTE_LOCAL,
172
- type: "memory"
173
- }
174
- });
168
+ await this.ensureQuotationBridgeReady(customer_id);
169
+ const idSet = new Set(ids);
170
+ const products = this.getProductsRef().filter((product) => idSet.has(product.id));
171
+ const priceData = products.map((product) => this.buildPriceDataFromQuotation(product, datetime, customer_id));
175
172
  const duration = Date.now() - startTime;
176
- this.logInfo('加载商品价格成功', {
173
+ this.logInfo("加载商品价格成功", {
177
174
  productCount: ids.length,
178
- priceDataCount: productsData.data?.length ?? 0,
175
+ priceDataCount: priceData.length,
179
176
  duration: `${duration}ms`
180
177
  });
181
- return productsData.data;
178
+ return priceData;
182
179
  } catch (error) {
183
180
  const duration = Date.now() - startTime;
184
181
  const errorMessage = error instanceof Error ? error.message : String(error);
185
- this.logError('加载商品价格失败', {
182
+ this.logError("加载商品价格失败", {
186
183
  productCount: ids.length,
187
184
  duration: `${duration}ms`,
188
185
  error: errorMessage
@@ -190,7 +187,182 @@ class ProductsModule extends _BaseModule.BaseModule {
190
187
  return [];
191
188
  }
192
189
  }
193
-
190
+ /**
191
+ * 设置报价单价格桥接器。
192
+ * Server 层负责传入完整 schedule 模块,Products 只负责把报价单计算结果转成价格响应形状。
193
+ */
194
+ async setupQuotationPriceBridge(params) {
195
+ var _a;
196
+ if (!this.core) {
197
+ this.logWarning("setupQuotationPriceBridge: core 尚未初始化");
198
+ return;
199
+ }
200
+ const channel = params.channel || ((_a = this.otherParams) == null ? void 0 : _a.channel);
201
+ this.quotationBridgeChannel = channel;
202
+ if (!this.quotationPriceBridge) {
203
+ const quotation = new import_Quotation.QuotationModule(`${this.name}_quotation_price_bridge`);
204
+ await quotation.initialize(this.core, {});
205
+ this.quotationPriceBridge = quotation;
206
+ }
207
+ if (params.scheduleModule) {
208
+ if (this.quotationScheduleCacheSource !== params.scheduleModule) {
209
+ this.quotationScheduleCache.clear();
210
+ this.quotationScheduleCacheLoaded = false;
211
+ this.quotationScheduleCacheSource = params.scheduleModule;
212
+ }
213
+ this.quotationPriceBridge.setScheduleResolver((id) => {
214
+ var _a2, _b, _c, _d, _e, _f;
215
+ const scheduleId = String(id);
216
+ if (this.quotationScheduleCache.has(scheduleId)) {
217
+ return this.quotationScheduleCache.get(scheduleId);
218
+ }
219
+ if (!this.quotationScheduleCacheLoaded) {
220
+ const scheduleList = ((_b = (_a2 = params.scheduleModule).getScheduleList) == null ? void 0 : _b.call(_a2)) || [];
221
+ for (const schedule of scheduleList) {
222
+ this.quotationScheduleCache.set(String(schedule.id), schedule);
223
+ }
224
+ this.quotationScheduleCacheLoaded = true;
225
+ }
226
+ if (this.quotationScheduleCache.has(scheduleId)) {
227
+ return this.quotationScheduleCache.get(scheduleId);
228
+ }
229
+ const schedules = ((_d = (_c = params.scheduleModule).getScheduleListByIds) == null ? void 0 : _d.call(_c, [id])) || ((_f = (_e = params.scheduleModule).getScheduleByIds) == null ? void 0 : _f.call(_e, [id])) || [];
230
+ if (schedules[0])
231
+ this.quotationScheduleCache.set(scheduleId, schedules[0]);
232
+ return schedules[0];
233
+ });
234
+ }
235
+ await this.refreshQuotationPriceBridge({ customer_id: params.customer_id });
236
+ }
237
+ /**
238
+ * 刷新桥接器内的报价单列表。
239
+ */
240
+ async refreshQuotationPriceBridge(params) {
241
+ if (!this.quotationPriceBridge)
242
+ return;
243
+ const refreshKey = this.getQuotationBridgeScopeKey();
244
+ if (this.quotationBridgeRefreshPromise && this.quotationBridgeRefreshKey === refreshKey) {
245
+ await this.quotationBridgeRefreshPromise;
246
+ return;
247
+ }
248
+ if (this.quotationBridgeRefreshPromise) {
249
+ await this.quotationBridgeRefreshPromise;
250
+ }
251
+ this.quotationBridgeRefreshKey = refreshKey;
252
+ this.quotationBridgeRefreshPromise = this.quotationPriceBridge.loadQuotations({
253
+ channel: this.quotationBridgeChannel
254
+ }).then(() => {
255
+ this.quotationBridgeLoadedKey = refreshKey;
256
+ }).finally(() => {
257
+ this.quotationBridgeRefreshPromise = void 0;
258
+ this.quotationBridgeRefreshKey = void 0;
259
+ });
260
+ await this.quotationBridgeRefreshPromise;
261
+ }
262
+ async ensureQuotationBridgeReady(customerId) {
263
+ var _a;
264
+ if (!this.quotationPriceBridge) {
265
+ await this.setupQuotationPriceBridge({
266
+ channel: (_a = this.otherParams) == null ? void 0 : _a.channel,
267
+ customer_id: customerId
268
+ });
269
+ return;
270
+ }
271
+ if (this.quotationBridgeRefreshPromise) {
272
+ await this.quotationBridgeRefreshPromise;
273
+ }
274
+ if (this.getQuotationBridgeScopeKey() !== this.quotationBridgeLoadedKey) {
275
+ await this.refreshQuotationPriceBridge({ customer_id: customerId });
276
+ }
277
+ }
278
+ getQuotationBridgeScopeKey() {
279
+ return this.quotationBridgeChannel || "";
280
+ }
281
+ getQuotedPrice(params) {
282
+ var _a;
283
+ const quotation = this.quotationPriceBridge;
284
+ if (!quotation)
285
+ return null;
286
+ const query = {
287
+ productId: params.productId,
288
+ variantId: params.variantId,
289
+ datetime: params.datetime,
290
+ customer_id: params.customerId
291
+ };
292
+ if (typeof quotation.getQuotationMatchForProduct === "function") {
293
+ return ((_a = quotation.getQuotationMatchForProduct(query)) == null ? void 0 : _a.price) ?? null;
294
+ }
295
+ if (typeof quotation.getPriceForProduct === "function") {
296
+ return quotation.getPriceForProduct(query);
297
+ }
298
+ return null;
299
+ }
300
+ buildPriceDataFromQuotation(product, datetime, customerId) {
301
+ const quotedPrice = this.getQuotedPrice({
302
+ productId: product.id,
303
+ datetime,
304
+ customerId
305
+ });
306
+ const productPrice = quotedPrice ?? product.price;
307
+ const productBasePrice = quotedPrice ?? product.base_price ?? product.price ?? 0;
308
+ return {
309
+ id: product.id,
310
+ price: String(productPrice ?? 0),
311
+ base_price: String(productBasePrice),
312
+ variant: this.buildVariantPriceData(product, datetime, customerId),
313
+ bundle_group: this.buildBundleGroupPriceData(product, datetime, customerId)
314
+ };
315
+ }
316
+ buildVariantPriceData(product, datetime, customerId) {
317
+ if (!Array.isArray(product.variant))
318
+ return [];
319
+ return product.variant.map((variant) => {
320
+ const quotedPrice = this.getQuotedPrice({
321
+ productId: product.id,
322
+ variantId: Number(variant.id),
323
+ datetime,
324
+ customerId
325
+ });
326
+ const price = quotedPrice ?? variant.price ?? product.price ?? 0;
327
+ const basePrice = quotedPrice ?? variant.base_price ?? variant.price ?? product.base_price ?? product.price ?? 0;
328
+ return {
329
+ id: Number(variant.id),
330
+ product_id: Number(variant.product_id ?? product.id),
331
+ base_price: Number(basePrice),
332
+ price: Number(price)
333
+ };
334
+ });
335
+ }
336
+ buildBundleGroupPriceData(product, datetime, customerId) {
337
+ if (!Array.isArray(product.bundle_group))
338
+ return [];
339
+ return product.bundle_group.map((group) => ({
340
+ id: Number(group.id),
341
+ bundle_item: (group.bundle_item || []).map((item) => {
342
+ const bundleProductId = Number(item.bundle_product_id);
343
+ const bundleVariantId = Number(item.bundle_variant_id || 0);
344
+ const quotedPrice = this.getQuotedPrice({
345
+ productId: bundleProductId,
346
+ variantId: bundleVariantId,
347
+ datetime,
348
+ customerId
349
+ });
350
+ const price = quotedPrice ?? item.price ?? 0;
351
+ const basePrice = quotedPrice ?? item.base_price ?? item.price ?? 0;
352
+ return {
353
+ id: Number(item.id),
354
+ product_id: Number(item.product_id ?? product.id),
355
+ group_id: Number(item.group_id ?? group.id),
356
+ bundle_product_id: bundleProductId,
357
+ bundle_variant_id: bundleVariantId,
358
+ price: Number(price),
359
+ base_price: basePrice,
360
+ price_type: item.price_type,
361
+ price_type_ext: item.price_type_ext
362
+ };
363
+ })
364
+ }));
365
+ }
194
366
  /**
195
367
  * 获取应用了价格的商品列表(带缓存)
196
368
  * 使用日期作为缓存 key,同一天的商品价格会被缓存
@@ -199,29 +371,32 @@ class ProductsModule extends _BaseModule.BaseModule {
199
371
  * @param extraContext 额外的上下文数据(可选,由 Server 层传入)
200
372
  * @param options 可选参数
201
373
  * @param options.changedIds 变更的商品 IDs,非空时仅对这些商品增量执行 prepare 并更新缓存
374
+ * @param options.productIds 指定商品 IDs,仅对这些商品执行价格计算;不传则处理全量
202
375
  * @returns 应用了价格的商品列表
203
376
  */
204
377
  async getProductsWithPrice(schedule_date, extraContext, options) {
378
+ var _a;
205
379
  const t0 = performance.now();
206
- const cacheKey = schedule_date;
207
- const changedIds = options?.changedIds;
380
+ const scopedProductIds = this.normalizeProductIds(options == null ? void 0 : options.productIds);
381
+ const cacheKey = this.getProductsPriceCacheKey(schedule_date, extraContext, scopedProductIds);
382
+ const scopedProductIdSet = scopedProductIds ? new Set(scopedProductIds) : void 0;
383
+ const changedIds = scopedProductIdSet ? (_a = options == null ? void 0 : options.changedIds) == null ? void 0 : _a.filter((id) => scopedProductIdSet.has(id)) : options == null ? void 0 : options.changedIds;
208
384
  if (this.productsPriceCache.has(cacheKey)) {
209
385
  const cachedProducts = this.productsPriceCache.get(cacheKey);
210
-
211
- // 有变更的商品 → 增量 prepare 后 merge 回缓存
212
386
  if (changedIds && changedIds.length > 0) {
213
- this.logInfo('商品价格缓存命中,增量更新变更商品', {
387
+ this.logInfo("商品价格缓存命中,增量更新变更商品", {
214
388
  cacheKey,
215
389
  changedIds,
216
390
  cachedProductCount: cachedProducts.length
217
391
  });
218
392
  try {
219
- const updatedProducts = await this.prepareProductsWithPrice(schedule_date, extraContext, {
220
- productIds: changedIds
221
- });
393
+ const updatedProducts = await this.prepareProductsWithPrice(
394
+ schedule_date,
395
+ extraContext,
396
+ { productIds: changedIds }
397
+ );
222
398
  if (updatedProducts.length > 0) {
223
- // merge:用更新结果替换缓存中对应的商品,新增的追加
224
- const updatedMap = new Map(updatedProducts.map(p => [p.id, p]));
399
+ const updatedMap = new Map(updatedProducts.map((p) => [p.id, p]));
225
400
  const mergedCache = [];
226
401
  for (const p of cachedProducts) {
227
402
  if (updatedMap.has(p.id)) {
@@ -231,17 +406,16 @@ class ProductsModule extends _BaseModule.BaseModule {
231
406
  mergedCache.push(p);
232
407
  }
233
408
  }
234
- // 剩余的是新增商品(create 场景)
235
409
  for (const p of updatedMap.values()) {
236
410
  mergedCache.push(p);
237
411
  }
238
412
  this.productsPriceCache.set(cacheKey, mergedCache);
239
- this.logInfo('增量更新完成', {
413
+ this.logInfo("增量更新完成", {
240
414
  cacheKey,
241
415
  changedCount: updatedProducts.length,
242
416
  totalCount: mergedCache.length
243
417
  });
244
- (0, _product.perfMark)('getProductsWithPrice(incrementalUpdate)', performance.now() - t0, {
418
+ (0, import_product.perfMark)("getProductsWithPrice(incrementalUpdate)", performance.now() - t0, {
245
419
  cacheKey,
246
420
  changedCount: changedIds.length,
247
421
  count: mergedCache.length
@@ -250,46 +424,50 @@ class ProductsModule extends _BaseModule.BaseModule {
250
424
  }
251
425
  } catch (error) {
252
426
  const errorMessage = error instanceof Error ? error.message : String(error);
253
- this.logError('增量更新失败,返回现有缓存', {
427
+ this.logError("增量更新失败,返回现有缓存", {
254
428
  cacheKey,
255
429
  changedIds,
256
430
  error: errorMessage
257
431
  });
258
432
  }
259
- (0, _product.perfMark)('getProductsWithPrice(incrementalUpdate)', performance.now() - t0, {
433
+ (0, import_product.perfMark)("getProductsWithPrice(incrementalUpdate)", performance.now() - t0, {
260
434
  cacheKey,
261
435
  changedCount: changedIds.length,
262
436
  count: cachedProducts.length
263
437
  });
264
438
  return cachedProducts;
265
439
  }
266
- (0, _product.perfMark)('getProductsWithPrice(cacheHit)', performance.now() - t0, {
440
+ (0, import_product.perfMark)("getProductsWithPrice(cacheHit)", performance.now() - t0, {
267
441
  cacheKey,
268
442
  count: cachedProducts.length
269
443
  });
270
- this.logInfo('商品价格缓存命中', {
444
+ this.logInfo("商品价格缓存命中", {
271
445
  cacheKey,
272
446
  productCount: cachedProducts.length
273
447
  });
274
448
  return cachedProducts;
275
449
  }
276
- this.logInfo('商品价格缓存未命中,准备获取', {
277
- cacheKey
450
+ this.logInfo("商品价格缓存未命中,准备获取", {
451
+ cacheKey,
452
+ scopedProductCount: scopedProductIds == null ? void 0 : scopedProductIds.length
278
453
  });
279
- const result = await this.prepareProductsWithPrice(schedule_date, extraContext);
454
+ const result = await this.prepareProductsWithPrice(
455
+ schedule_date,
456
+ extraContext,
457
+ scopedProductIds ? { productIds: scopedProductIds } : void 0
458
+ );
280
459
  this.productsPriceCache.set(cacheKey, result);
281
- this.logInfo('商品价格已缓存', {
460
+ this.logInfo("商品价格已缓存", {
282
461
  cacheKey,
283
462
  productCount: result.length
284
463
  });
285
464
  this.cleanExpiredPriceCache();
286
- (0, _product.perfMark)('getProductsWithPrice(cacheMiss)', performance.now() - t0, {
465
+ (0, import_product.perfMark)("getProductsWithPrice(cacheMiss)", performance.now() - t0, {
287
466
  cacheKey,
288
467
  count: result.length
289
468
  });
290
469
  return result;
291
470
  }
292
-
293
471
  /**
294
472
  * 准备带价格的商品数据(通过格式化器流程处理)
295
473
  * @param schedule_date 日期
@@ -300,22 +478,21 @@ class ProductsModule extends _BaseModule.BaseModule {
300
478
  * @private
301
479
  */
302
480
  async prepareProductsWithPrice(schedule_date, extraContext, options) {
481
+ var _a, _b, _c, _d;
303
482
  const tTotal = performance.now();
304
- const targetIds = options?.productIds;
305
- const isIncremental = targetIds && targetIds.length > 0;
306
- this.logInfo('prepareProductsWithPrice 开始处理', {
483
+ const targetIds = options == null ? void 0 : options.productIds;
484
+ const isIncremental = Array.isArray(targetIds);
485
+ this.logInfo("prepareProductsWithPrice 开始处理", {
307
486
  schedule_date,
308
- mode: isIncremental ? 'incremental' : 'full',
309
- targetIdsCount: targetIds?.length
487
+ mode: isIncremental ? "incremental" : "full",
488
+ targetIdsCount: targetIds == null ? void 0 : targetIds.length
310
489
  });
311
490
  try {
312
- // 1. 获取商品列表:指定 IDs 时从 store 取子集,否则取全量
313
491
  let products;
314
492
  let ids;
315
493
  if (isIncremental) {
316
- const idSet = new Set(targetIds);
317
- products = this.getProductsRef().filter(p => idSet.has(p.id));
318
- ids = products.map(p => p.id);
494
+ products = this.getProductsRefByIds(targetIds);
495
+ ids = products.map((p) => p.id);
319
496
  } else {
320
497
  products = this.getProductsRef();
321
498
  const tIds = performance.now();
@@ -323,65 +500,123 @@ class ProductsModule extends _BaseModule.BaseModule {
323
500
  for (let i = 0; i < products.length; i++) {
324
501
  ids[i] = products[i].id;
325
502
  }
326
- (0, _product.perfMark)('prepareProducts.extractIds', performance.now() - tIds, {
327
- count: ids.length
503
+ (0, import_product.perfMark)("prepareProducts.extractIds", performance.now() - tIds, { count: ids.length });
504
+ }
505
+ this.logInfo("获取到商品列表", { productCount: products.length });
506
+ let priceData = [];
507
+ if (this.isLegacyPriceFormatterEnabled) {
508
+ const tPrice = performance.now();
509
+ priceData = await this.loadProductsPrice({
510
+ ids,
511
+ schedule_date,
512
+ schedule_datetime: extraContext == null ? void 0 : extraContext.schedule_datetime,
513
+ customer_id: extraContext == null ? void 0 : extraContext.customer_id
328
514
  });
515
+ (0, import_product.perfMark)("prepareProducts.loadPrice", performance.now() - tPrice, { count: ids.length });
516
+ this.logInfo("获取商品报价单价格成功", { priceDataCount: (priceData == null ? void 0 : priceData.length) ?? 0 });
329
517
  }
330
- this.logInfo('获取到商品列表', {
331
- productCount: products.length
332
- });
333
-
334
- // 2. 获取价格数据(网络请求)
335
- const tPrice = performance.now();
336
- const priceData = await this.loadProductsPrice({
337
- ids,
338
- schedule_date
339
- });
340
- (0, _product.perfMark)('prepareProducts.loadPrice', performance.now() - tPrice, {
341
- count: ids.length
342
- });
343
- this.logInfo('获取商品报价单价格成功', {
344
- priceDataCount: priceData?.length ?? 0
345
- });
346
518
  const context = {
347
519
  schedule_date,
520
+ schedule_datetime: extraContext == null ? void 0 : extraContext.schedule_datetime,
521
+ customer_id: extraContext == null ? void 0 : extraContext.customer_id,
348
522
  priceData,
349
- locale: this.core?.context?.locale,
523
+ locale: (_b = (_a = this.core) == null ? void 0 : _a.context) == null ? void 0 : _b.locale,
524
+ dataVariantEvaluator: (extraContext == null ? void 0 : extraContext.dataVariantEvaluator) || ((_d = (_c = this.core) == null ? void 0 : _c.context) == null ? void 0 : _d.dataVariantEvaluator),
525
+ menuList: (extraContext == null ? void 0 : extraContext.menuList) || [],
526
+ scheduleList: (extraContext == null ? void 0 : extraContext.scheduleList) || [],
527
+ strategy_context: extraContext == null ? void 0 : extraContext.strategy_context,
350
528
  ...extraContext
351
529
  };
352
-
353
- // 3. 通过格式化器流程处理商品
354
530
  const tFormat = performance.now();
355
531
  const processedProducts = await this.applyFormatters(products, context);
356
- (0, _product.perfMark)('prepareProducts.applyFormatters', performance.now() - tFormat, {
532
+ (0, import_product.perfMark)("prepareProducts.applyFormatters", performance.now() - tFormat, {
357
533
  count: products.length,
358
534
  formatterCount: this.formatters.length
359
535
  });
360
- this.logInfo('prepareProductsWithPrice 处理完成', {
361
- mode: isIncremental ? 'incremental' : 'full',
536
+ this.logInfo("prepareProductsWithPrice 处理完成", {
537
+ mode: isIncremental ? "incremental" : "full",
362
538
  originalProductCount: products.length,
363
539
  processedProductCount: processedProducts.length,
364
540
  formatterCount: this.formatters.length
365
541
  });
366
542
  if (!isIncremental) {
367
- await this.core.effects.emit(_types.ProductsHooks.onProductsPriceApplied, processedProducts);
543
+ await this.core.effects.emit(
544
+ import_types.ProductsHooks.onProductsPriceApplied,
545
+ processedProducts
546
+ );
368
547
  }
369
- (0, _product.perfMark)('prepareProductsWithPrice', performance.now() - tTotal, {
548
+ (0, import_product.perfMark)("prepareProductsWithPrice", performance.now() - tTotal, {
370
549
  productCount: products.length,
371
550
  formatterCount: this.formatters.length,
372
- mode: isIncremental ? 'incremental' : 'full'
551
+ mode: isIncremental ? "incremental" : "full"
373
552
  });
374
553
  return processedProducts;
375
554
  } catch (err) {
376
555
  const errorMessage = err instanceof Error ? err.message : String(err);
377
- this.logError('prepareProductsWithPrice 处理失败', {
556
+ console.log(`[ProductsModule] 🌐 ERROR`, err);
557
+ this.logError("prepareProductsWithPrice 处理失败", {
378
558
  schedule_date,
379
559
  error: errorMessage
380
560
  });
381
561
  }
382
562
  return [];
383
563
  }
384
-
564
+ getProductsPriceCacheKey(schedule_date, extraContext, productIds) {
565
+ const datetime = (extraContext == null ? void 0 : extraContext.schedule_datetime) || schedule_date;
566
+ const productScope = productIds ? `:products:${productIds.join(",")}` : "";
567
+ const strategyScope = this.stringifyStable((extraContext == null ? void 0 : extraContext.strategy_context) || {});
568
+ return `${datetime}:customer:${(extraContext == null ? void 0 : extraContext.customer_id) ?? ""}:strategy:${strategyScope}${productScope}`;
569
+ }
570
+ /**
571
+ * 稳定序列化策略上下文,避免对象 key 顺序不同导致缓存 key 抖动。
572
+ */
573
+ stringifyStable(value) {
574
+ if (value == null)
575
+ return "";
576
+ if (Array.isArray(value))
577
+ return `[${value.map((item) => this.stringifyStable(item)).join(",")}]`;
578
+ if (typeof value === "object") {
579
+ return `{${Object.keys(value).sort().map((key) => `${key}:${this.stringifyStable(value[key])}`).join(",")}}`;
580
+ }
581
+ return String(value);
582
+ }
583
+ normalizeProductIds(productIds) {
584
+ if (!Array.isArray(productIds))
585
+ return void 0;
586
+ return Array.from(new Set(
587
+ productIds.map((id) => Number(id)).filter((id) => Number.isFinite(id))
588
+ )).sort((a, b) => a - b);
589
+ }
590
+ /**
591
+ * 按轻量范围返回商品 ID,不做 structuredClone。
592
+ */
593
+ getProductIdsByScope(scope) {
594
+ const productIds = this.normalizeProductIds(scope.productIds) || [];
595
+ const collectionIds = this.normalizeProductIds(scope.collectionIds) || [];
596
+ if (scope.isAllProducts) {
597
+ return this.getProductsRef().map((product) => product.id);
598
+ }
599
+ if (productIds.length === 0 && collectionIds.length === 0)
600
+ return [];
601
+ const result = /* @__PURE__ */ new Set();
602
+ for (const id of productIds) {
603
+ if (this.store.map.has(id))
604
+ result.add(id);
605
+ }
606
+ if (collectionIds.length === 0)
607
+ return Array.from(result);
608
+ const collectionIdSet = new Set(collectionIds);
609
+ for (const product of this.getProductsRef()) {
610
+ if (result.has(product.id))
611
+ continue;
612
+ if (!Array.isArray(product.collection))
613
+ continue;
614
+ const isInCollection = product.collection.some((collection) => collectionIdSet.has(collection.id));
615
+ if (isInCollection)
616
+ result.add(product.id);
617
+ }
618
+ return Array.from(result);
619
+ }
385
620
  /**
386
621
  * 应用所有已注册的格式化器
387
622
  * @param products 商品列表
@@ -392,13 +627,11 @@ class ProductsModule extends _BaseModule.BaseModule {
392
627
  async applyFormatters(products, context) {
393
628
  let result = products;
394
629
  if (this.formatters.length === 0) {
395
- console.warn('[ProductsModule] ⚠️ 没有注册任何格式化器');
396
- this.logWarning('没有注册任何格式化器', {
397
- productCount: products.length
398
- });
630
+ console.warn("[ProductsModule] ⚠️ 没有注册任何格式化器");
631
+ this.logWarning("没有注册任何格式化器", { productCount: products.length });
399
632
  return result;
400
633
  }
401
- this.logInfo('开始应用格式化器', {
634
+ this.logInfo("开始应用格式化器", {
402
635
  productCount: products.length,
403
636
  formatterCount: this.formatters.length
404
637
  });
@@ -407,7 +640,7 @@ class ProductsModule extends _BaseModule.BaseModule {
407
640
  try {
408
641
  const tF = performance.now();
409
642
  result = await formatter(result, context);
410
- (0, _product.perfMark)(`applyFormatters[${i}]`, performance.now() - tF, {
643
+ (0, import_product.perfMark)(`applyFormatters[${i}]`, performance.now() - tF, {
411
644
  index: i,
412
645
  total: this.formatters.length,
413
646
  productCount: result.length
@@ -422,48 +655,93 @@ class ProductsModule extends _BaseModule.BaseModule {
422
655
  });
423
656
  }
424
657
  }
425
- this.logInfo('所有格式化器已应用', {
658
+ this.logInfo("所有格式化器已应用", {
426
659
  formatterCount: this.formatters.length,
427
660
  resultProductCount: result.length
428
661
  });
429
662
  return result;
430
663
  }
431
-
432
664
  /**
433
- * 注册内置的价格格式化器
434
- * 这个格式化器负责将价格数据应用到商品上
665
+ * 注册内置商品格式化器。
666
+ *
667
+ * 智能定价默认替代报价单逻辑;报价单 formatter 仅在 enableLegacyPriceFormatter=true 时启用。
435
668
  * @private
436
669
  */
437
- registerBuiltinPriceFormatter() {
438
- if (this.isPriceFormatterRegistered) {
439
- console.warn('[ProductsModule] 内置价格格式化器已注册,跳过');
670
+ registerBuiltinProductFormatters() {
671
+ if (this.isBuiltinFormatterRegistered) {
672
+ console.warn("[ProductsModule] 内置商品格式化器已注册,跳过");
440
673
  return;
441
674
  }
442
-
443
- // 创建价格格式化器
444
- const priceFormatter = (products, context) => {
675
+ this.isLegacyPriceFormatterEnabled = this.shouldEnableLegacyPriceFormatter();
676
+ const dataVariantFormatter = (products, context) => {
677
+ var _a, _b;
678
+ const evaluator = context.dataVariantEvaluator || ((_b = (_a = this.core) == null ? void 0 : _a.context) == null ? void 0 : _b.dataVariantEvaluator);
679
+ if (!evaluator || typeof evaluator.resolveProducts !== "function") {
680
+ this.lastScheduleTimePoints = [];
681
+ this.logWarning("智能定价评估器未注入,跳过 DataVariant 格式化", {
682
+ productCount: products.length
683
+ });
684
+ return products;
685
+ }
686
+ const strategyContext = context.strategy_context || {};
687
+ const businessData = {
688
+ products,
689
+ scheduleDateTime: context.schedule_datetime || context.schedule_date,
690
+ scheduleList: context.scheduleList || [],
691
+ menuList: context.menuList || [],
692
+ customerId: context.customer_id,
693
+ channel: strategyContext.channel,
694
+ orderType: strategyContext.orderType || strategyContext.order_type,
695
+ businessCode: strategyContext.business_code ?? strategyContext.businessCode,
696
+ availableWalletIds: strategyContext.available_wallet_ids,
697
+ custom: strategyContext
698
+ };
699
+ const result = evaluator.resolveProducts(businessData);
700
+ this.lastScheduleTimePoints = Array.isArray(result == null ? void 0 : result.scheduleTimePoints) ? [...result.scheduleTimePoints] : [];
701
+ return Array.isArray(result == null ? void 0 : result.products) ? result.products : products;
702
+ };
703
+ const legacyPriceFormatter = (products, context) => {
445
704
  if (!context.priceData || context.priceData.length === 0) {
705
+ console.log("[ProductsModule] 💰 没有价格数据,跳过 legacy 报价单价格应用");
446
706
  return products;
447
707
  }
448
- return (0, _product.applyPriceDataToProducts)(products, context.priceData);
708
+ console.log(`[ProductsModule] 💰 应用 legacy 报价单价格到 ${products.length} 个商品`);
709
+ return (0, import_product.applyPriceDataToProducts)(products, context.priceData);
449
710
  };
450
711
  const i18nFormatter = (products, context) => {
451
- return (0, _product.applyI18nToProducts)(products, context.locale);
712
+ return (0, import_product.applyI18nToProducts)(products, context.locale);
452
713
  };
453
714
  const detailValueFormatter = (products, context) => {
454
- return (0, _product.applyDetailValueToProducts)(products, context);
715
+ return (0, import_product.applyDetailValueToProducts)(products, context);
455
716
  };
456
-
457
- // 将价格格式化器注册为第一个格式化器
458
- this.formatters.unshift(priceFormatter);
717
+ if (this.isLegacyPriceFormatterEnabled) {
718
+ this.formatters.push(legacyPriceFormatter);
719
+ }
720
+ this.formatters.push(dataVariantFormatter);
459
721
  this.formatters.push(i18nFormatter);
460
722
  this.formatters.push(detailValueFormatter);
461
- this.isPriceFormatterRegistered = true;
723
+ this.isBuiltinFormatterRegistered = true;
724
+ console.log("[ProductsModule] ✅ 内置商品格式化器已注册(智能定价优先)");
725
+ }
726
+ /**
727
+ * 是否启用旧报价单价格 formatter。
728
+ *
729
+ * 默认关闭,避免报价单逻辑覆盖智能定价结果。
730
+ */
731
+ shouldEnableLegacyPriceFormatter() {
732
+ var _a, _b, _c;
733
+ return ((_a = this.otherParams) == null ? void 0 : _a.enableLegacyPriceFormatter) === true || ((_c = (_b = this.core) == null ? void 0 : _b.context) == null ? void 0 : _c.enableLegacyPriceFormatter) === true;
734
+ }
735
+ /**
736
+ * 返回最近一次 prepareProductsWithPrice / DataVariant 评估提取的变价时间点(HH:mm)。
737
+ * 供 OS Server 商品 query 订阅定时刷新使用。
738
+ */
739
+ getLastScheduleTimePoints() {
740
+ return [...this.lastScheduleTimePoints];
462
741
  }
463
-
464
742
  /**
465
743
  * 注册商品格式化器
466
- * 格式化器会按注册顺序依次执行(内置价格格式化器始终是第一个)
744
+ * 格式化器会按注册顺序依次执行;legacy 启用时先兜底报价,再由智能定价覆盖。
467
745
  * @param formatter 格式化函数
468
746
  * @param prepend 是否插入到队列开头(默认 false,追加到末尾)
469
747
  * @example
@@ -478,29 +756,29 @@ class ProductsModule extends _BaseModule.BaseModule {
478
756
  */
479
757
  registerFormatter(formatter, prepend = false) {
480
758
  if (prepend) {
481
- // 插入到价格格式化器之后(索引 1 的位置)
482
- const insertIndex = this.isPriceFormatterRegistered ? 1 : 0;
759
+ const insertIndex = this.isBuiltinFormatterRegistered ? this.isLegacyPriceFormatterEnabled ? 2 : 1 : 0;
483
760
  this.formatters.splice(insertIndex, 0, formatter);
761
+ console.log(`[ProductsModule] 📌 已在位置 ${insertIndex + 1} 插入格式化器,当前共 ${this.formatters.length} 个`);
484
762
  } else {
485
- // 追加到末尾
486
763
  this.formatters.push(formatter);
764
+ console.log(`[ProductsModule] 📌 已注册格式化器,当前共 ${this.formatters.length} 个`);
487
765
  }
488
766
  }
489
-
490
767
  /**
491
- * 清空所有格式化器(包括内置价格格式化器)
492
- * @param keepBuiltin 是否保留内置价格格式化器(默认 true)
768
+ * 清空所有格式化器(包括内置智能定价格式化器)
769
+ * @param keepBuiltin 是否保留内置智能定价格式化器(默认 true)
493
770
  */
494
771
  clearFormatters(keepBuiltin = true) {
495
- if (keepBuiltin && this.isPriceFormatterRegistered) {
496
- // 只保留第一个格式化器(内置价格格式化器)
497
- this.formatters = [this.formatters[0]];
772
+ if (keepBuiltin && this.isBuiltinFormatterRegistered) {
773
+ const builtinCount = this.isLegacyPriceFormatterEnabled ? 2 : 1;
774
+ this.formatters = this.formatters.slice(0, builtinCount);
775
+ console.log("[ProductsModule] 🧹 已清空自定义格式化器,保留内置智能定价格式化器");
498
776
  } else {
499
777
  this.formatters = [];
500
- this.isPriceFormatterRegistered = false;
778
+ this.isBuiltinFormatterRegistered = false;
779
+ console.log("[ProductsModule] 🧹 已清空所有格式化器");
501
780
  }
502
781
  }
503
-
504
782
  /**
505
783
  * 清理过期的价格缓存
506
784
  * 当缓存数量超过限制时,删除最老的缓存
@@ -511,64 +789,59 @@ class ProductsModule extends _BaseModule.BaseModule {
511
789
  const keys = Array.from(this.productsPriceCache.keys());
512
790
  const oldestKey = keys[0];
513
791
  this.productsPriceCache.delete(oldestKey);
792
+ console.log(`[ProductsModule] 🧹 清理过期商品价格缓存: ${oldestKey}`);
514
793
  }
515
794
  }
516
-
517
795
  /**
518
796
  * 清空商品价格缓存
519
797
  * 可用于手动刷新价格数据
520
798
  */
521
799
  clearPriceCache() {
522
800
  this.productsPriceCache.clear();
801
+ console.log("[ProductsModule] 🗑️ 商品价格缓存已清空");
523
802
  }
524
-
525
803
  /**
526
804
  * 通过 ProductDataSource SSE 加载完整商品列表
527
805
  */
528
806
  async loadProductsByServer() {
529
807
  if (!this.productDataSource) {
530
- this.logWarning('loadProductsByServer: ProductDataSource 不可用');
808
+ this.logWarning("loadProductsByServer: ProductDataSource 不可用");
531
809
  return [];
532
810
  }
533
- this.logInfo('开始通过 DataSource SSE 加载商品列表');
811
+ this.logInfo("开始通过 DataSource SSE 加载商品列表");
534
812
  const t0 = performance.now();
535
813
  try {
536
814
  const tSSE = performance.now();
537
- const productList = await this.productDataSource.run({
538
- sse: {}
539
- });
815
+ const productList = await this.productDataSource.run({ sse: {} });
540
816
  const list = productList || [];
541
- (0, _product.perfMark)('loadProductsByServer.SSE', performance.now() - tSSE, {
542
- count: list.length
543
- });
544
- this.logInfo('通过 DataSource SSE 加载商品列表成功', {
817
+ (0, import_product.perfMark)("loadProductsByServer.SSE", performance.now() - tSSE, { count: list.length });
818
+ this.logInfo("通过 DataSource SSE 加载商品列表成功", {
545
819
  productCount: list.length,
546
820
  duration: `${Math.round(performance.now() - t0)}ms`
547
821
  });
548
- await this.saveProductsToIndexDB(list);
549
- await this.core.effects.emit(_types.ProductsHooks.onProductsLoaded, list);
550
- (0, _product.perfMark)('loadProductsByServer', performance.now() - t0, {
551
- count: list.length
552
- });
822
+ await this.replaceProductsSnapshotInIndexDB(list, "loadProductsByServer");
823
+ this.lastServerFullFetchAtMs = Date.now();
824
+ await this.core.effects.emit(import_types.ProductsHooks.onProductsLoaded, list);
825
+ (0, import_product.perfMark)("loadProductsByServer", performance.now() - t0, { count: list.length });
553
826
  return list;
554
827
  } catch (error) {
555
828
  const duration = Math.round(performance.now() - t0);
556
829
  const errorMessage = error instanceof Error ? error.message : String(error);
557
- console.error('[Products] 加载商品数据失败:', error);
558
- this.logError('通过 DataSource SSE 加载商品列表失败', {
830
+ console.error("[Products] 加载商品数据失败:", error);
831
+ this.logError("通过 DataSource SSE 加载商品列表失败", {
559
832
  duration: `${duration}ms`,
560
833
  error: errorMessage
561
834
  });
562
835
  return [];
563
836
  }
564
837
  }
565
-
566
838
  /**
567
839
  * 纯请求方法:通过 HTTP 接口获取商品列表(无副作用,不触发事件、不写 IndexDB)
568
840
  * @param params 查询参数
569
841
  * @returns 商品列表
570
842
  */
571
843
  async fetchProductsByHttp(params) {
844
+ var _a, _b;
572
845
  const {
573
846
  category_ids = [],
574
847
  product_ids = [],
@@ -576,7 +849,7 @@ class ProductsModule extends _BaseModule.BaseModule {
576
849
  customer_id,
577
850
  cacheId
578
851
  } = params || {};
579
- this.logInfo('fetchProductsByHttp: 开始请求', {
852
+ this.logInfo("fetchProductsByHttp: 开始请求", {
580
853
  categoryIdsCount: category_ids.length,
581
854
  productIdsCount: product_ids.length,
582
855
  collectionCount: Array.isArray(collection) ? collection.length : collection ? 1 : 0,
@@ -584,29 +857,46 @@ class ProductsModule extends _BaseModule.BaseModule {
584
857
  });
585
858
  const startTime = Date.now();
586
859
  try {
587
- const productsData = await this.request.post(`/product/query`, {
588
- open_bundle: 1,
589
- exclude_extension_type: ['product_party', 'product_event', 'product_series_event', 'product_package_ticket', 'ticket', 'event_item'],
590
- force_ignore_cache_flag: 1,
591
- with: ['category', 'collection', 'resourceRelation', 'bundleGroup.bundleItem', 'optionGroup.optionItem', 'variantGroup.variantItem'],
592
- open_deposit: 1,
593
- is_append_product_description: 1,
594
- with_count: ['bundleGroup', 'optionGroup'],
595
- with_category_tree: 1,
596
- status: 'published',
597
- num: 500,
598
- skip: 1,
599
- category_ids,
600
- ids: product_ids,
601
- collection,
602
- front_end_cache_id: cacheId,
603
- application_code: this.otherParams?.channel
604
- }, {
605
- cache: undefined
606
- });
607
- const productList = productsData?.data?.list || [];
860
+ const productsData = await this.request.post(
861
+ `/product/query`,
862
+ {
863
+ open_bundle: 1,
864
+ exclude_extension_type: [
865
+ "product_party",
866
+ "product_event",
867
+ "product_series_event",
868
+ "product_package_ticket",
869
+ "ticket",
870
+ "event_item"
871
+ ],
872
+ force_ignore_cache_flag: 1,
873
+ with: [
874
+ "category",
875
+ "collection",
876
+ "resourceRelation",
877
+ "bundleGroup.bundleItem",
878
+ "optionGroup.optionItem",
879
+ "variantGroup.variantItem",
880
+ "dataVariants"
881
+ ],
882
+ open_deposit: 1,
883
+ is_append_product_description: 1,
884
+ with_count: ["bundleGroup", "optionGroup"],
885
+ with_category_tree: 1,
886
+ status: "published",
887
+ num: 500,
888
+ skip: 1,
889
+ category_ids,
890
+ ids: product_ids,
891
+ collection,
892
+ front_end_cache_id: cacheId,
893
+ application_code: (_a = this.otherParams) == null ? void 0 : _a.channel
894
+ },
895
+ { cache: void 0 }
896
+ );
897
+ const productList = ((_b = productsData == null ? void 0 : productsData.data) == null ? void 0 : _b.list) || [];
608
898
  const duration = Date.now() - startTime;
609
- this.logInfo('fetchProductsByHttp: 请求成功', {
899
+ this.logInfo("fetchProductsByHttp: 请求成功", {
610
900
  productCount: productList.length,
611
901
  duration: `${duration}ms`
612
902
  });
@@ -614,15 +904,14 @@ class ProductsModule extends _BaseModule.BaseModule {
614
904
  } catch (error) {
615
905
  const duration = Date.now() - startTime;
616
906
  const errorMessage = error instanceof Error ? error.message : String(error);
617
- console.error('[Products] fetchProductsByHttp 失败:', error);
618
- this.logError('fetchProductsByHttp: 请求失败', {
907
+ console.error("[Products] fetchProductsByHttp 失败:", error);
908
+ this.logError("fetchProductsByHttp: 请求失败", {
619
909
  duration: `${duration}ms`,
620
910
  error: errorMessage
621
911
  });
622
912
  return [];
623
913
  }
624
914
  }
625
-
626
915
  /**
627
916
  * 加载完整商品列表通过接口(包含所有详细数据)
628
917
  * 包含副作用:保存到 IndexDB + 触发 onProductsLoaded 事件
@@ -631,24 +920,41 @@ class ProductsModule extends _BaseModule.BaseModule {
631
920
  async loadProductsByServerHttp(params) {
632
921
  const productList = await this.fetchProductsByHttp(params);
633
922
  if (productList.length > 0) {
634
- await this.saveProductsToIndexDB(productList);
635
- await this.core.effects.emit(_types.ProductsHooks.onProductsLoaded, productList);
923
+ await this.replaceProductsSnapshotInIndexDB(productList, "loadProductsByServerHttp");
924
+ this.lastServerFullFetchAtMs = Date.now();
925
+ await this.core.effects.emit(import_types.ProductsHooks.onProductsLoaded, productList);
636
926
  }
637
927
  return productList;
638
928
  }
639
-
640
929
  /**
641
930
  * 获取商品列表(深拷贝,供外部安全使用)
642
931
  */
643
932
  async getProducts() {
644
933
  const t0 = performance.now();
645
934
  const result = structuredClone(this.store.list);
646
- (0, _product.perfMark)('ProductsModule.getProducts(structuredClone)', performance.now() - t0, {
647
- count: result.length
648
- });
935
+ (0, import_product.perfMark)("ProductsModule.getProducts(structuredClone)", performance.now() - t0, { count: result.length });
649
936
  return result;
650
937
  }
651
-
938
+ /**
939
+ * 批量获取商品轻量快照,供订单详情等响应补齐展示协议字段。
940
+ */
941
+ async getProductSnapshotsByIds(ids) {
942
+ const snapshots = {};
943
+ const seen = /* @__PURE__ */ new Set();
944
+ for (const id of ids) {
945
+ if (!Number.isFinite(id) || seen.has(id))
946
+ continue;
947
+ seen.add(id);
948
+ const product = this.store.map.get(id);
949
+ if (!product)
950
+ continue;
951
+ snapshots[String(id)] = {
952
+ cover: product.cover,
953
+ holder_config: product.holder_config
954
+ };
955
+ }
956
+ return snapshots;
957
+ }
652
958
  /**
653
959
  * 内部获取商品列表的直接引用(无拷贝)
654
960
  * 仅供内部 formatter 流程使用,因为 formatter 会创建新对象
@@ -656,27 +962,34 @@ class ProductsModule extends _BaseModule.BaseModule {
656
962
  getProductsRef() {
657
963
  return this.store.list;
658
964
  }
659
-
965
+ /**
966
+ * 按 ID 从 Map 取商品引用,供内部 formatter 流程使用。
967
+ */
968
+ getProductsRefByIds(ids) {
969
+ const products = [];
970
+ for (const id of ids) {
971
+ const product = this.store.map.get(id);
972
+ if (product)
973
+ products.push(product);
974
+ }
975
+ return products;
976
+ }
660
977
  /**
661
978
  * 根据ID获取单个商品(从内存缓存)
662
979
  * 使用 Map 快速查询,时间复杂度 O(1)
663
980
  */
664
981
  async getProductById(id) {
665
982
  const product = this.store.map.get(id);
666
- return product ? structuredClone(product) : undefined;
983
+ return product ? structuredClone(product) : void 0;
667
984
  }
668
-
669
985
  /**
670
986
  * 根据 ID 列表删除商品(用于 pubsub 同步删除场景)
671
987
  * 同时更新 store.list、store.map、IndexDB 和价格缓存
672
988
  */
673
989
  async removeProductsByIds(ids) {
674
990
  const idSet = new Set(ids);
675
- this.logInfo('removeProductsByIds', {
676
- ids,
677
- count: ids.length
678
- });
679
- this.store.list = this.store.list.filter(p => !idSet.has(p.id));
991
+ this.logInfo("removeProductsByIds", { ids, count: ids.length });
992
+ this.store.list = this.store.list.filter((p) => !idSet.has(p.id));
680
993
  for (const id of ids) {
681
994
  this.store.map.delete(id);
682
995
  }
@@ -687,134 +1000,166 @@ class ProductsModule extends _BaseModule.BaseModule {
687
1000
  }
688
1001
  } catch (error) {
689
1002
  const errorMessage = error instanceof Error ? error.message : String(error);
690
- this.logError('removeProductsByIds: IndexDB 删除失败', {
691
- ids,
692
- error: errorMessage
693
- });
1003
+ this.logError("removeProductsByIds: IndexDB 删除失败", { ids, error: errorMessage });
694
1004
  }
695
1005
  }
696
1006
  for (const [dateKey, cachedProducts] of this.productsPriceCache.entries()) {
697
- this.productsPriceCache.set(dateKey, cachedProducts.filter(p => !idSet.has(p.id)));
1007
+ this.productsPriceCache.set(
1008
+ dateKey,
1009
+ cachedProducts.filter((p) => !idSet.has(p.id))
1010
+ );
698
1011
  }
699
- this.core.effects.emit(_types.ProductsHooks.onProductsChanged, this.store.list);
700
- this.logInfo('removeProductsByIds 完成', {
701
- remaining: this.store.list.length
702
- });
1012
+ this.core.effects.emit(import_types.ProductsHooks.onProductsChanged, this.store.list);
1013
+ this.logInfo("removeProductsByIds 完成", { remaining: this.store.list.length });
703
1014
  }
704
-
705
1015
  /**
706
1016
  * 重新从服务器加载全量商品列表并更新本地 store
707
1017
  * 用于 pubsub 同步 create / update / batch_update 场景
708
1018
  */
709
1019
  async refreshProducts() {
710
1020
  const tTotal = performance.now();
711
- this.logInfo('refreshProducts 开始');
1021
+ this.logInfo("refreshProducts 开始");
712
1022
  const products = await this.loadProductsByServer();
713
1023
  if (products && products.length > 0) {
714
- // 服务器返回的数据已经是全新的,无需 cloneDeep
715
1024
  this.store.list = products;
716
1025
  this.syncProductsMap();
717
- this.core.effects.emit(_types.ProductsHooks.onProductsChanged, this.store.list);
718
- this.logInfo('refreshProducts 完成', {
719
- productCount: products.length
720
- });
1026
+ this.core.effects.emit(import_types.ProductsHooks.onProductsChanged, this.store.list);
1027
+ this.logInfo("refreshProducts 完成", { productCount: products.length });
721
1028
  } else {
722
- this.logWarning('refreshProducts: 服务器未返回数据');
1029
+ this.logWarning("refreshProducts: 服务器未返回数据");
723
1030
  }
724
- (0, _product.perfMark)('refreshProducts', performance.now() - tTotal, {
725
- count: this.store.list.length
726
- });
1031
+ (0, import_product.perfMark)("refreshProducts", performance.now() - tTotal, { count: this.store.list.length });
727
1032
  return this.store.list;
728
1033
  }
729
-
730
1034
  /**
731
1035
  * 清空缓存
732
1036
  */
733
1037
  async clear() {
734
- this.logInfo('开始清空缓存', {
1038
+ this.logInfo("开始清空缓存", {
735
1039
  currentProductCount: this.store.list.length,
736
1040
  priceCacheCount: this.productsPriceCache.size
737
1041
  });
738
1042
  this.store.list = [];
739
1043
  this.store.map.clear();
740
-
741
- // 同时清空 IndexDB 中的所有数据(包括商品和元数据)
742
1044
  if (this.dbManager) {
743
1045
  try {
744
1046
  await this.dbManager.clear(INDEXDB_STORE_NAME);
745
- this.logInfo('IndexDB 缓存已清空');
1047
+ console.log("[Products] IndexDB 缓存已清空");
1048
+ this.logInfo("IndexDB 缓存已清空");
746
1049
  } catch (error) {
747
1050
  const errorMessage = error instanceof Error ? error.message : String(error);
748
- console.error('[Products] 清空 IndexDB 缓存失败:', error);
749
- this.logError('清空 IndexDB 缓存失败', {
750
- error: errorMessage
751
- });
1051
+ console.error("[Products] 清空 IndexDB 缓存失败:", error);
1052
+ this.logError("清空 IndexDB 缓存失败", { error: errorMessage });
752
1053
  }
753
1054
  }
754
- this.logInfo('缓存清空完成');
1055
+ console.log("[Products] 缓存已清空");
1056
+ this.logInfo("缓存清空完成");
755
1057
  }
756
-
757
1058
  /**
758
1059
  * 从 IndexDB 加载商品数据
759
1060
  * @private
760
1061
  */
761
1062
  async loadProductsFromIndexDB() {
762
1063
  if (!this.dbManager) {
763
- this.logWarning('loadProductsFromIndexDB: dbManager 不可用');
1064
+ this.logWarning("loadProductsFromIndexDB: dbManager 不可用");
764
1065
  return [];
765
1066
  }
766
1067
  try {
767
1068
  const t0 = performance.now();
768
1069
  const products = await this.dbManager.getAll(INDEXDB_STORE_NAME);
769
- (0, _product.perfMark)('loadProductsFromIndexDB', performance.now() - t0, {
770
- count: products?.length ?? 0
771
- });
772
- this.logInfo('从 IndexDB 加载商品数据', {
773
- productCount: products?.length ?? 0
1070
+ (0, import_product.perfMark)("loadProductsFromIndexDB", performance.now() - t0, { count: (products == null ? void 0 : products.length) ?? 0 });
1071
+ this.logInfo("从 IndexDB 加载商品数据", {
1072
+ productCount: (products == null ? void 0 : products.length) ?? 0
774
1073
  });
775
1074
  return products || [];
776
1075
  } catch (error) {
777
1076
  const errorMessage = error instanceof Error ? error.message : String(error);
778
- console.error('[Products] 从 IndexDB 读取数据失败:', error);
779
- this.logError('从 IndexDB 读取数据失败', {
780
- error: errorMessage
781
- });
1077
+ console.error("[Products] 从 IndexDB 读取数据失败:", error);
1078
+ this.logError("从 IndexDB 读取数据失败", { error: errorMessage });
782
1079
  return [];
783
1080
  }
784
1081
  }
785
-
786
1082
  /**
787
- * 保存商品数据到 IndexDB(平铺存储)
788
- * @private
1083
+ * 串行执行商品 IndexDB 写入,避免快照替换与增量 patch 并发交错。
1084
+ *
1085
+ * @example
1086
+ * await this.runInProductIndexDBSaveQueue(async () => {
1087
+ * await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, products)
1088
+ * })
1089
+ */
1090
+ async runInProductIndexDBSaveQueue(task) {
1091
+ const queuedTask = this.productIndexDBSaveQueue.then(task, task);
1092
+ this.productIndexDBSaveQueue = queuedTask.then(() => void 0, () => void 0);
1093
+ return queuedTask;
1094
+ }
1095
+ /**
1096
+ * 全量快照写入 IndexDB:clear + bulkUpdate,仅用于 SSE/HTTP 全量拉取。
1097
+ *
1098
+ * @example
1099
+ * await this.replaceProductsSnapshotInIndexDB(list, 'loadProductsByServer')
789
1100
  */
790
- async saveProductsToIndexDB(products) {
1101
+ async replaceProductsSnapshotInIndexDB(products, source) {
791
1102
  if (!this.dbManager) {
792
- this.logWarning('saveProductsToIndexDB: dbManager 不可用');
1103
+ this.logWarning("replaceProductsSnapshotInIndexDB: dbManager 不可用");
793
1104
  return;
794
1105
  }
795
- this.logInfo('开始保存商品数据到 IndexDB', {
796
- productCount: products.length
797
- });
798
1106
  try {
799
- const t0 = performance.now();
800
- await this.dbManager.clear(INDEXDB_STORE_NAME);
801
- await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, products);
802
- (0, _product.perfMark)('saveProductsToIndexDB', performance.now() - t0, {
803
- count: products.length
804
- });
805
- this.logInfo('商品数据已保存到 IndexDB', {
806
- productCount: products.length
1107
+ await this.runInProductIndexDBSaveQueue(async () => {
1108
+ this.logInfo("replaceProductsSnapshotInIndexDB 开始", { source, productCount: products.length });
1109
+ const t0 = performance.now();
1110
+ await this.dbManager.clear(INDEXDB_STORE_NAME);
1111
+ if (products.length > 0) {
1112
+ await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, products);
1113
+ }
1114
+ (0, import_product.perfMark)("replaceProductsSnapshotInIndexDB", performance.now() - t0, { count: products.length });
1115
+ this.logInfo("replaceProductsSnapshotInIndexDB 完成", { source, productCount: products.length });
807
1116
  });
808
1117
  } catch (error) {
809
1118
  const errorMessage = error instanceof Error ? error.message : String(error);
810
- console.error('[Products] 保存数据到 IndexDB 失败:', error);
811
- this.logError('保存数据到 IndexDB 失败', {
1119
+ this.logError("全量保存商品到 IndexDB 失败", {
1120
+ source,
812
1121
  productCount: products.length,
813
1122
  error: errorMessage
814
1123
  });
815
1124
  }
816
1125
  }
817
-
1126
+ /**
1127
+ * 增量 upsert 商品到 IndexDB,不清空表;用于 pubsub 批次合并后的变更商品。
1128
+ *
1129
+ * @example
1130
+ * await this.patchProductsInIndexDB(changedProducts, 'pubsub.processProductSyncMessages', mergeActions)
1131
+ */
1132
+ async patchProductsInIndexDB(products, source, mergeActions = {}) {
1133
+ if (!this.dbManager || products.length === 0) {
1134
+ return;
1135
+ }
1136
+ const validProducts = products.filter((p) => (p == null ? void 0 : p.id) !== void 0 && (p == null ? void 0 : p.id) !== null);
1137
+ if (validProducts.length === 0) {
1138
+ return;
1139
+ }
1140
+ try {
1141
+ await this.runInProductIndexDBSaveQueue(async () => {
1142
+ this.logInfo("patchProductsInIndexDB 开始", { source, count: validProducts.length });
1143
+ const t0 = performance.now();
1144
+ if (typeof this.dbManager.bulkUpdate === "function") {
1145
+ await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, validProducts);
1146
+ } else if (typeof this.dbManager.update === "function") {
1147
+ for (const product of validProducts) {
1148
+ await this.dbManager.update(INDEXDB_STORE_NAME, product);
1149
+ }
1150
+ }
1151
+ (0, import_product.perfMark)("patchProductsInIndexDB", performance.now() - t0, { count: validProducts.length });
1152
+ this.logInfo("patchProductsInIndexDB 完成", { source, count: validProducts.length });
1153
+ });
1154
+ } catch (error) {
1155
+ const errorMessage = error instanceof Error ? error.message : String(error);
1156
+ this.logError("增量保存商品到 IndexDB 失败", {
1157
+ source,
1158
+ error: errorMessage,
1159
+ productCount: validProducts.length
1160
+ });
1161
+ }
1162
+ }
818
1163
  /**
819
1164
  * 同步更新商品 Map 缓存
820
1165
  * 将 list 中的商品同步到 map,以 id 为 key
@@ -826,103 +1171,92 @@ class ProductsModule extends _BaseModule.BaseModule {
826
1171
  for (const product of this.store.list) {
827
1172
  this.store.map.set(product.id, product);
828
1173
  }
829
- (0, _product.perfMark)('syncProductsMap', performance.now() - t0, {
830
- count: this.store.map.size
831
- });
1174
+ (0, import_product.perfMark)("syncProductsMap", performance.now() - t0, { count: this.store.map.size });
832
1175
  }
833
-
834
1176
  /**
835
1177
  * 预加载模块数据(统一接口)
836
1178
  * 在模块注册后自动调用
837
1179
  */
838
1180
  async preload() {
1181
+ console.log("[Products] 开始预加载数据...");
839
1182
  const tTotal = performance.now();
840
- this.logInfo('开始预加载数据');
1183
+ this.logInfo("开始预加载数据");
841
1184
  try {
842
1185
  const tIndexDB = performance.now();
843
1186
  const cachedData = await this.loadProductsFromIndexDB();
844
- (0, _product.perfMark)('preload.loadFromIndexDB', performance.now() - tIndexDB, {
845
- count: cachedData?.length ?? 0
846
- });
1187
+ (0, import_product.perfMark)("preload.loadFromIndexDB", performance.now() - tIndexDB, { count: (cachedData == null ? void 0 : cachedData.length) ?? 0 });
847
1188
  if (cachedData && cachedData.length > 0) {
848
- // IndexDB 反序列化的数据已经是全新的,无需 cloneDeep
1189
+ console.log(`[Products] 从 IndexDB 加载了 ${cachedData.length} 个商品`);
849
1190
  this.store.list = cachedData;
850
1191
  const tSync = performance.now();
851
1192
  this.syncProductsMap();
852
- (0, _product.perfMark)('preload.syncProductsMap', performance.now() - tSync, {
853
- count: cachedData.length
854
- });
855
- this.core.effects.emit(_types.ProductsHooks.onProductsChanged, this.store.list);
856
- (0, _product.perfMark)('preload(IndexDB)', performance.now() - tTotal, {
1193
+ (0, import_product.perfMark)("preload.syncProductsMap", performance.now() - tSync, { count: cachedData.length });
1194
+ this.core.effects.emit(
1195
+ import_types.ProductsHooks.onProductsChanged,
1196
+ this.store.list
1197
+ );
1198
+ (0, import_product.perfMark)("preload(IndexDB)", performance.now() - tTotal, {
857
1199
  count: cachedData.length,
858
- source: 'IndexDB'
1200
+ source: "IndexDB"
859
1201
  });
860
- this.logInfo('预加载完成(从 IndexDB)', {
1202
+ this.logInfo("预加载完成(从 IndexDB)", {
861
1203
  productCount: cachedData.length,
862
1204
  duration: `${Math.round(performance.now() - tTotal)}ms`,
863
- source: 'IndexDB'
1205
+ source: "IndexDB"
864
1206
  });
1207
+ this.lastPreloadCompletedAtMs = Date.now();
865
1208
  return;
866
1209
  }
867
- this.logInfo('IndexDB 中没有缓存数据,准备从服务器加载');
1210
+ console.log("[Products] IndexDB 中没有缓存数据,从服务器加载...");
1211
+ this.logInfo("IndexDB 中没有缓存数据,准备从服务器加载");
868
1212
  } catch (error) {
869
1213
  const errorMessage = error instanceof Error ? error.message : String(error);
870
- console.warn('[Products] 从 IndexDB 加载数据失败:', error);
871
- this.logWarning('从 IndexDB 加载数据失败,准备从服务器加载', {
872
- error: errorMessage
873
- });
1214
+ console.warn("[Products] 从 IndexDB 加载数据失败:", error);
1215
+ this.logWarning("从 IndexDB 加载数据失败,准备从服务器加载", { error: errorMessage });
874
1216
  }
875
1217
  const tServer = performance.now();
876
1218
  const products = await this.loadProductsByServer();
877
- (0, _product.perfMark)('preload.loadFromServer', performance.now() - tServer, {
878
- count: products?.length ?? 0
879
- });
1219
+ (0, import_product.perfMark)("preload.loadFromServer", performance.now() - tServer, { count: (products == null ? void 0 : products.length) ?? 0 });
880
1220
  if (products && products.length > 0) {
881
- // 服务器返回的数据已经是全新的,无需 cloneDeep
882
1221
  this.store.list = products;
883
1222
  const tSync = performance.now();
884
1223
  this.syncProductsMap();
885
- (0, _product.perfMark)('preload.syncProductsMap', performance.now() - tSync, {
886
- count: products.length
887
- });
888
- this.core.effects.emit(_types.ProductsHooks.onProductsChanged, this.store.list);
889
- (0, _product.perfMark)('preload(Server)', performance.now() - tTotal, {
1224
+ (0, import_product.perfMark)("preload.syncProductsMap", performance.now() - tSync, { count: products.length });
1225
+ this.core.effects.emit(import_types.ProductsHooks.onProductsChanged, this.store.list);
1226
+ (0, import_product.perfMark)("preload(Server)", performance.now() - tTotal, {
890
1227
  count: products.length,
891
- source: 'Server'
1228
+ source: "Server"
892
1229
  });
893
- this.logInfo('预加载完成(从服务器)', {
1230
+ this.logInfo("预加载完成(从服务器)", {
894
1231
  productCount: products.length,
895
1232
  duration: `${Math.round(performance.now() - tTotal)}ms`,
896
- source: 'Server'
1233
+ source: "Server"
897
1234
  });
1235
+ this.lastPreloadCompletedAtMs = Date.now();
898
1236
  } else {
899
- (0, _product.perfMark)('preload(empty)', performance.now() - tTotal, {
900
- source: 'empty'
901
- });
902
- this.logWarning('预加载完成但未获取到数据', {
1237
+ (0, import_product.perfMark)("preload(empty)", performance.now() - tTotal, { source: "empty" });
1238
+ this.logWarning("预加载完成但未获取到数据", {
903
1239
  duration: `${Math.round(performance.now() - tTotal)}ms`
904
1240
  });
905
1241
  }
906
1242
  }
907
-
908
1243
  // =============================================
909
1244
  // 商品数据同步(pubsub)
910
1245
  // =============================================
911
-
912
1246
  /**
913
1247
  * 初始化 ProductDataSource 实例
914
1248
  * 与 pubsub 订阅和数据获取分开,仅负责创建实例
915
1249
  */
916
1250
  initProductDataSource() {
917
- const ProductDataSourceClass = this.core.serverOptions?.All_DATA_SOURCES?.ProductDataSource;
1251
+ var _a, _b;
1252
+ const ProductDataSourceClass = (_b = (_a = this.core.serverOptions) == null ? void 0 : _a.All_DATA_SOURCES) == null ? void 0 : _b.ProductDataSource;
918
1253
  if (!ProductDataSourceClass) {
919
- this.logWarning('initProductDataSource: ProductDataSource 不可用');
1254
+ this.logWarning("initProductDataSource: ProductDataSource 不可用");
920
1255
  return;
921
1256
  }
922
1257
  this.productDataSource = new ProductDataSourceClass();
923
- this.logInfo('ProductDataSource 实例已创建');
1258
+ this.logInfo("ProductDataSource 实例已创建");
924
1259
  }
925
-
926
1260
  /**
927
1261
  * 初始化 pubsub 订阅,监听管理后台商品变更
928
1262
  * 仅负责订阅 product / product_quotation 频道,消息通过防抖合并后批量处理
@@ -930,22 +1264,21 @@ class ProductsModule extends _BaseModule.BaseModule {
930
1264
  */
931
1265
  setupProductSync() {
932
1266
  if (!this.productDataSource) {
933
- this.logWarning('setupProductSync: ProductDataSource 不可用,跳过同步初始化');
1267
+ this.logWarning("setupProductSync: ProductDataSource 不可用,跳过同步初始化");
934
1268
  return;
935
1269
  }
936
- const createHandler = channelKey => message => {
937
- const data = message?.data || message;
938
- if (!data) return;
939
- this.logInfo('收到同步消息', {
1270
+ const createHandler = (channelKey) => (message) => {
1271
+ const data = (message == null ? void 0 : message.data) || message;
1272
+ if (!data)
1273
+ return;
1274
+ console.log(`[ProductsModule] 收到同步消息 [${channelKey}]:`, data);
1275
+ this.logInfo("收到同步消息", {
940
1276
  channelKey,
941
1277
  action: data.action,
942
1278
  id: data.id,
943
1279
  action_filed: data.action_filed
944
1280
  });
945
- this.pendingSyncMessages.push({
946
- ...data,
947
- _channelKey: channelKey
948
- });
1281
+ this.pendingSyncMessages.push({ ...data, _channelKey: channelKey });
949
1282
  if (this.syncTimer) {
950
1283
  clearTimeout(this.syncTimer);
951
1284
  }
@@ -955,24 +1288,21 @@ class ProductsModule extends _BaseModule.BaseModule {
955
1288
  };
956
1289
  this.productDataSource.run({
957
1290
  pubsub: {
958
- callback: res => {
959
- this.logInfo('sse_products_callback: 收到同步消息', {
960
- data: res?.data
961
- });
962
- if (!res?.data) return;
1291
+ callback: (res) => {
1292
+ if (!(res == null ? void 0 : res.data))
1293
+ return;
963
1294
  const data = res.data;
964
- const channelKey = data.module || 'product';
1295
+ const channelKey = data.module || "product";
965
1296
  createHandler(channelKey)(data);
966
1297
  }
967
1298
  }
968
- }).catch(err => {
969
- this.logError('setupProductSync: DataSource run 出错', {
1299
+ }).catch((err) => {
1300
+ this.logError("setupProductSync: DataSource run 出错", {
970
1301
  error: err instanceof Error ? err.message : String(err)
971
1302
  });
972
1303
  });
973
- this.logInfo('setupProductSync: pubsub 订阅已建立');
1304
+ this.logInfo("setupProductSync: pubsub 订阅已建立");
974
1305
  }
975
-
976
1306
  /**
977
1307
  * 处理防抖后的同步消息批次
978
1308
  *
@@ -992,94 +1322,122 @@ class ProductsModule extends _BaseModule.BaseModule {
992
1322
  * Server 层监听该事件后对变更商品增量执行 prepareProductsWithPrice 并更新缓存
993
1323
  */
994
1324
  async processProductSyncMessages() {
1325
+ var _a, _b, _c, _d, _e, _f, _g;
995
1326
  const messages = [...this.pendingSyncMessages];
996
1327
  this.pendingSyncMessages = [];
997
- if (messages.length === 0) return;
998
- this.logInfo('processProductSyncMessages: 开始处理', {
999
- count: messages.length
1000
- });
1328
+ if (messages.length === 0)
1329
+ return;
1330
+ this.logInfo("processProductSyncMessages: 开始处理", { count: messages.length });
1001
1331
  const deleteIds = [];
1002
- const bodyUpdates = new Map();
1332
+ const bodyUpdates = /* @__PURE__ */ new Map();
1003
1333
  const sseRefreshIds = [];
1004
1334
  const priceRefreshIds = [];
1005
1335
  let shouldClearPriceCache = false;
1006
1336
  for (const msg of messages) {
1007
- const channelKey = msg._channelKey || msg.module || 'product';
1008
- if (channelKey === 'product') {
1009
- if (msg.relation_product_ids?.length) {
1337
+ const channelKey = msg._channelKey || msg.module || "product";
1338
+ if (channelKey === "product") {
1339
+ if ((_a = msg.relation_product_ids) == null ? void 0 : _a.length) {
1010
1340
  sseRefreshIds.push(...msg.relation_product_ids);
1011
1341
  }
1012
- // 1. 删除场景:operation === 'delete' 或 action === 'delete'
1013
- if (msg.operation === 'delete' || msg.action === 'delete') {
1014
- if (msg.ids?.length) deleteIds.push(...msg.ids);else if (msg.id) deleteIds.push(msg.id);
1342
+ if (msg.operation === "delete" || msg.action === "delete") {
1343
+ if ((_b = msg.ids) == null ? void 0 : _b.length)
1344
+ deleteIds.push(...msg.ids);
1345
+ else if (msg.id)
1346
+ deleteIds.push(msg.id);
1015
1347
  continue;
1016
1348
  }
1017
-
1018
- // 2. change_types 包含 price → 仅收集需要刷新价格的 IDs(不走 SSE 拉取)
1019
- if (msg.change_types?.includes('price')) {
1349
+ if ((_c = msg.change_types) == null ? void 0 : _c.includes("price")) {
1020
1350
  const ids = msg.ids || (msg.id ? [msg.id] : []);
1021
1351
  priceRefreshIds.push(...ids);
1022
1352
  if (msg.body) {
1023
1353
  const bodyId = msg.body.id;
1024
- if (bodyId) bodyUpdates.set(bodyId, msg.body);
1354
+ if (bodyId)
1355
+ bodyUpdates.set(bodyId, msg.body);
1025
1356
  }
1026
1357
  continue;
1027
1358
  }
1028
-
1029
- // 3. 有 body → 完整数据直接覆盖本地
1030
1359
  if (msg.body) {
1031
1360
  const bodyId = msg.body.id || msg.id;
1032
- if (bodyId) bodyUpdates.set(bodyId, msg.body);
1361
+ if (bodyId)
1362
+ bodyUpdates.set(bodyId, msg.body);
1033
1363
  continue;
1034
1364
  }
1035
-
1036
- // 4. 其他情况(有 ids 无 body 无 change_types)→ SSE 拉取
1037
- if (msg.ids?.length) {
1365
+ if ((_d = msg.ids) == null ? void 0 : _d.length) {
1038
1366
  sseRefreshIds.push(...msg.ids);
1039
1367
  } else if (msg.id) {
1040
1368
  sseRefreshIds.push(msg.id);
1041
1369
  }
1042
- } else if (channelKey === 'product_quotation') {
1043
- // 报价单变更影响范围大,标记清除全量价格缓存
1370
+ } else if (channelKey === "product_quotation") {
1044
1371
  shouldClearPriceCache = true;
1045
- if (msg.relation_product_ids?.length) {
1372
+ if ((_e = msg.relation_product_ids) == null ? void 0 : _e.length) {
1046
1373
  sseRefreshIds.push(...msg.relation_product_ids);
1047
1374
  }
1048
- } else if (['product_collection', 'product_category'].includes(channelKey)) {
1049
- if (msg.relation_product_ids?.length) {
1375
+ } else if (["product_collection", "product_category"].includes(channelKey)) {
1376
+ if ((_f = msg.relation_product_ids) == null ? void 0 : _f.length) {
1050
1377
  sseRefreshIds.push(...msg.relation_product_ids);
1051
1378
  }
1379
+ } else if (["product_data_variant"].includes(channelKey)) {
1380
+ if ((_g = msg.product_ids) == null ? void 0 : _g.length) {
1381
+ sseRefreshIds.push(...msg.product_ids);
1382
+ }
1052
1383
  }
1053
1384
  }
1054
1385
  const uniqueDeleteIds = [...new Set(deleteIds)];
1055
1386
  const uniqueSSEIds = [...new Set(sseRefreshIds)];
1056
1387
  const uniquePriceIds = [...new Set(priceRefreshIds)];
1057
-
1058
- // 1. 处理删除
1059
1388
  if (uniqueDeleteIds.length > 0) {
1060
1389
  await this.removeProductsByIds(uniqueDeleteIds);
1061
1390
  }
1062
-
1063
- // 2. 处理 body 直接覆盖(store.list 更新,价格缓存不清除)
1391
+ const patchProductMap = /* @__PURE__ */ new Map();
1392
+ const patchMergeActions = {};
1393
+ let storeMutated = uniqueDeleteIds.length > 0;
1064
1394
  if (bodyUpdates.size > 0) {
1065
- await this.applyBodyUpdatesToStore(bodyUpdates);
1395
+ const bodyResult = await this.applyBodyUpdatesToStore(bodyUpdates, {
1396
+ skipIndexDB: true,
1397
+ skipEmit: true
1398
+ });
1399
+ for (const product of bodyResult.changedProducts) {
1400
+ patchProductMap.set(product.id, product);
1401
+ patchMergeActions[product.id] = bodyResult.mergeActions[product.id];
1402
+ }
1403
+ storeMutated = true;
1066
1404
  }
1067
-
1068
- // 3. 处理 SSE 增量拉取(store.list 更新,价格缓存不清除)
1405
+ let freshProducts = [];
1069
1406
  if (uniqueSSEIds.length > 0) {
1070
- const freshProducts = await this.fetchProductsBySSE(uniqueSSEIds);
1407
+ freshProducts = await this.fetchProductsBySSE(uniqueSSEIds);
1071
1408
  if (freshProducts.length > 0) {
1072
- await this.mergeProductsToStore(freshProducts);
1409
+ const mergeResult = await this.mergeProductsToStore(freshProducts, {
1410
+ skipIndexDB: true,
1411
+ skipEmit: true
1412
+ });
1413
+ for (const product of mergeResult.changedProducts) {
1414
+ patchProductMap.set(product.id, product);
1415
+ patchMergeActions[product.id] = mergeResult.mergeActions[product.id];
1416
+ }
1417
+ storeMutated = true;
1073
1418
  }
1074
- this.logInfo('processProductSyncMessages: SSE 增量更新完成123', {
1419
+ this.logInfo("processProductSyncMessages: SSE 增量更新完成123", {
1075
1420
  requestedCount: uniqueSSEIds.length,
1076
1421
  receivedCount: freshProducts.length
1077
1422
  });
1078
1423
  }
1079
-
1080
- // 收集所有非 delete 的变更 IDs(body + SSE + price),用于增量更新价格缓存
1081
- const allChangedIds = [...new Set([...Array.from(bodyUpdates.keys()), ...uniqueSSEIds, ...uniquePriceIds])];
1082
- this.logInfo('processProductSyncMessages: 处理完成123', {
1424
+ const patchProducts = [...patchProductMap.values()];
1425
+ if (patchProducts.length > 0) {
1426
+ await this.patchProductsInIndexDB(
1427
+ patchProducts,
1428
+ "pubsub.processProductSyncMessages",
1429
+ patchMergeActions
1430
+ );
1431
+ }
1432
+ if (storeMutated) {
1433
+ this.core.effects.emit(import_types.ProductsHooks.onProductsChanged, this.store.list);
1434
+ }
1435
+ const allChangedIds = [.../* @__PURE__ */ new Set([
1436
+ ...Array.from(bodyUpdates.keys()),
1437
+ ...uniqueSSEIds,
1438
+ ...uniquePriceIds
1439
+ ])];
1440
+ this.logInfo("processProductSyncMessages: 处理完成123", {
1083
1441
  deleteCount: uniqueDeleteIds.length,
1084
1442
  bodyUpdateCount: bodyUpdates.size,
1085
1443
  sseRefreshCount: uniqueSSEIds.length,
@@ -1089,47 +1447,40 @@ class ProductsModule extends _BaseModule.BaseModule {
1089
1447
  });
1090
1448
  const hasChanges = uniqueDeleteIds.length > 0 || allChangedIds.length > 0 || shouldClearPriceCache;
1091
1449
  if (!hasChanges) {
1092
- this.logInfo('processProductSyncMessages: 没有变更,不触发 onProductsSyncCompleted');
1450
+ this.logInfo("processProductSyncMessages: 没有变更,不触发 onProductsSyncCompleted");
1093
1451
  return;
1094
1452
  }
1095
-
1096
- // 报价单变更 → 清除全量价格缓存,后续走全量重建
1097
1453
  if (shouldClearPriceCache) {
1454
+ try {
1455
+ await this.refreshQuotationPriceBridge();
1456
+ } catch (error) {
1457
+ const errorMessage = error instanceof Error ? error.message : String(error);
1458
+ this.logError("报价单桥接刷新失败,将继续清理价格缓存", { error: errorMessage });
1459
+ }
1098
1460
  this.clearPriceCache();
1099
1461
  }
1100
- await this.core.effects.emit(_types.ProductsHooks.onProductsSyncCompleted, {
1462
+ await this.core.effects.emit(import_types.ProductsHooks.onProductsSyncCompleted, {
1101
1463
  changedIds: allChangedIds
1102
1464
  });
1103
1465
  }
1104
-
1105
1466
  /**
1106
1467
  * 通过 SSE 按 ids 增量拉取商品数据
1107
1468
  * 请求 GET /shop/core/stream?type=product&ids={ids}
1108
1469
  */
1109
1470
  async fetchProductsBySSE(ids) {
1110
1471
  if (!this.productDataSource) {
1111
- this.logWarning('fetchProductsBySSE: ProductDataSource 不可用');
1472
+ this.logWarning("fetchProductsBySSE: ProductDataSource 不可用");
1112
1473
  return [];
1113
1474
  }
1114
- this.logInfo('fetchProductsBySSE: 开始', {
1115
- ids,
1116
- count: ids.length
1117
- });
1475
+ this.logInfo("fetchProductsBySSE: 开始", { ids, count: ids.length });
1118
1476
  const t0 = performance.now();
1119
1477
  try {
1120
1478
  const productList = await this.productDataSource.run({
1121
- sse: {
1122
- query: {
1123
- type: 'product',
1124
- ids
1125
- }
1126
- }
1479
+ sse: { query: { type: "product", ids } }
1127
1480
  });
1128
1481
  const list = productList || [];
1129
- (0, _product.perfMark)('fetchProductsBySSE', performance.now() - t0, {
1130
- count: list.length
1131
- });
1132
- this.logInfo('fetchProductsBySSE: 成功', {
1482
+ (0, import_product.perfMark)("fetchProductsBySSE", performance.now() - t0, { count: list.length });
1483
+ this.logInfo("fetchProductsBySSE: 成功", {
1133
1484
  requestedCount: ids.length,
1134
1485
  receivedCount: list.length,
1135
1486
  duration: `${Math.round(performance.now() - t0)}ms`
@@ -1137,32 +1488,33 @@ class ProductsModule extends _BaseModule.BaseModule {
1137
1488
  return list;
1138
1489
  } catch (error) {
1139
1490
  const errorMessage = error instanceof Error ? error.message : String(error);
1140
- this.logError('fetchProductsBySSE: 失败', {
1141
- ids,
1142
- error: errorMessage
1143
- });
1491
+ this.logError("fetchProductsBySSE: 失败", { ids, error: errorMessage });
1144
1492
  return [];
1145
1493
  }
1146
1494
  }
1147
-
1148
1495
  /**
1149
1496
  * 将 body 完整数据直接覆盖到本地 store(不调用报价单接口)
1150
1497
  * 已存在的 → 直接替换;不存在的 → 追加
1151
- * 同时更新 Map 缓存、IndexDB,触发 onProductsChanged
1152
- * 价格缓存由 processProductSyncMessages 末尾统一清除
1498
+ *
1499
+ * @example
1500
+ * await this.applyBodyUpdatesToStore(bodyUpdates, { skipIndexDB: true })
1153
1501
  */
1154
- async applyBodyUpdatesToStore(bodyUpdates) {
1155
- this.logInfo('applyBodyUpdatesToStore: 开始', {
1156
- count: bodyUpdates.size
1157
- });
1502
+ async applyBodyUpdatesToStore(bodyUpdates, options) {
1503
+ const changedProductIds = [...bodyUpdates.keys()];
1504
+ this.logInfo("applyBodyUpdatesToStore: 开始", { count: bodyUpdates.size });
1158
1505
  let updatedCount = 0;
1159
1506
  let newCount = 0;
1160
- const appliedIds = new Set();
1161
- this.store.list = this.store.list.map(p => {
1507
+ const appliedIds = /* @__PURE__ */ new Set();
1508
+ const mergeActions = {};
1509
+ const changedProducts = [];
1510
+ this.store.list = this.store.list.map((p) => {
1162
1511
  if (bodyUpdates.has(p.id)) {
1163
1512
  updatedCount++;
1164
1513
  appliedIds.add(p.id);
1165
- return bodyUpdates.get(p.id);
1514
+ mergeActions[p.id] = "update";
1515
+ const next = bodyUpdates.get(p.id);
1516
+ changedProducts.push(next);
1517
+ return next;
1166
1518
  }
1167
1519
  return p;
1168
1520
  });
@@ -1170,54 +1522,71 @@ class ProductsModule extends _BaseModule.BaseModule {
1170
1522
  if (!appliedIds.has(id)) {
1171
1523
  this.store.list.push(body);
1172
1524
  newCount++;
1525
+ mergeActions[id] = "insert";
1526
+ changedProducts.push(body);
1173
1527
  }
1174
1528
  }
1175
1529
  this.syncProductsMap();
1176
- await this.saveProductsToIndexDB(this.store.list);
1177
- this.core.effects.emit(_types.ProductsHooks.onProductsChanged, this.store.list);
1178
- this.logInfo('applyBodyUpdatesToStore: 完成', {
1530
+ if (!(options == null ? void 0 : options.skipIndexDB)) {
1531
+ await this.patchProductsInIndexDB(changedProducts, "pubsub.bodyUpdate", mergeActions);
1532
+ }
1533
+ if (!(options == null ? void 0 : options.skipEmit)) {
1534
+ this.core.effects.emit(import_types.ProductsHooks.onProductsChanged, this.store.list);
1535
+ }
1536
+ this.logInfo("applyBodyUpdatesToStore: 完成", {
1179
1537
  updatedCount,
1180
1538
  newCount,
1181
1539
  totalCount: this.store.list.length
1182
1540
  });
1541
+ return { changedProducts, mergeActions, updatedCount, newCount };
1183
1542
  }
1184
-
1185
1543
  /**
1186
1544
  * 将增量拉取的商品合并到 store
1187
1545
  * 已存在的 → 替换;新的 → 追加
1188
- * 同时更新 store.map、IndexDB,触发 onProductsChanged
1546
+ *
1547
+ * @example
1548
+ * await this.mergeProductsToStore(freshProducts, { skipIndexDB: true })
1189
1549
  */
1190
- async mergeProductsToStore(freshProducts) {
1191
- const freshMap = new Map();
1550
+ async mergeProductsToStore(freshProducts, options) {
1551
+ const freshMap = /* @__PURE__ */ new Map();
1192
1552
  for (const p of freshProducts) {
1193
1553
  freshMap.set(p.id, p);
1194
1554
  }
1195
- const updatedList = this.store.list.map(p => {
1555
+ const mergeActions = {};
1556
+ const changedProducts = [];
1557
+ const updatedList = this.store.list.map((p) => {
1196
1558
  if (freshMap.has(p.id)) {
1197
1559
  const fresh = freshMap.get(p.id);
1198
1560
  freshMap.delete(p.id);
1561
+ mergeActions[p.id] = "update";
1562
+ changedProducts.push(fresh);
1199
1563
  return fresh;
1200
1564
  }
1201
1565
  return p;
1202
1566
  });
1203
-
1204
- // freshMap 中剩余的是新商品(create 场景)
1205
1567
  const newCount = freshMap.size;
1206
1568
  for (const p of freshMap.values()) {
1207
1569
  updatedList.push(p);
1570
+ mergeActions[p.id] = "insert";
1571
+ changedProducts.push(p);
1208
1572
  }
1209
1573
  const updatedCount = freshProducts.length - newCount;
1574
+ const changedProductIds = freshProducts.map((p) => p.id);
1210
1575
  this.store.list = updatedList;
1211
1576
  this.syncProductsMap();
1212
- await this.saveProductsToIndexDB(this.store.list);
1213
- this.logInfo('mergeProductsToStore: 合并完成', {
1577
+ if (!(options == null ? void 0 : options.skipIndexDB)) {
1578
+ await this.patchProductsInIndexDB(changedProducts, "pubsub.mergeProductsToStore", mergeActions);
1579
+ }
1580
+ if (!(options == null ? void 0 : options.skipEmit)) {
1581
+ this.core.effects.emit(import_types.ProductsHooks.onProductsChanged, this.store.list);
1582
+ }
1583
+ this.logInfo("mergeProductsToStore: 合并完成", {
1214
1584
  updatedCount,
1215
1585
  newCount,
1216
1586
  totalCount: this.store.list.length
1217
1587
  });
1218
- this.core.effects.emit(_types.ProductsHooks.onProductsChanged, this.store.list);
1588
+ return { changedProducts, mergeActions, updatedCount, newCount };
1219
1589
  }
1220
-
1221
1590
  /**
1222
1591
  * 静默全量刷新:后台重新拉取全量 SSE 数据并更新本地
1223
1592
  * 拿到完整数据后一次性替换 store,清除价格缓存,触发 onProductsSyncCompleted
@@ -1225,51 +1594,54 @@ class ProductsModule extends _BaseModule.BaseModule {
1225
1594
  */
1226
1595
  async silentRefresh() {
1227
1596
  const t0 = performance.now();
1228
- this.logInfo('silentRefresh 开始');
1597
+ const now = Date.now();
1598
+ const elapsedSincePreload = now - this.lastPreloadCompletedAtMs;
1599
+ const elapsedSinceFullFetch = now - this.lastServerFullFetchAtMs;
1600
+ if (this.lastPreloadCompletedAtMs > 0 && elapsedSincePreload < PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS || this.lastServerFullFetchAtMs > 0 && elapsedSinceFullFetch < PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS) {
1601
+ return this.store.list;
1602
+ }
1603
+ this.logInfo("silentRefresh 开始");
1229
1604
  try {
1230
1605
  const products = await this.loadProductsByServer();
1231
1606
  if (products && products.length > 0) {
1232
1607
  this.store.list = products;
1233
1608
  this.syncProductsMap();
1234
1609
  this.clearPriceCache();
1235
- this.core.effects.emit(_types.ProductsHooks.onProductsChanged, this.store.list);
1236
- await this.core.effects.emit(_types.ProductsHooks.onProductsSyncCompleted, null);
1237
- this.logInfo('silentRefresh 完成', {
1610
+ this.core.effects.emit(import_types.ProductsHooks.onProductsChanged, this.store.list);
1611
+ await this.core.effects.emit(import_types.ProductsHooks.onProductsSyncCompleted, null);
1612
+ this.logInfo("silentRefresh 完成", {
1238
1613
  productCount: products.length,
1239
1614
  duration: `${Math.round(performance.now() - t0)}ms`
1240
1615
  });
1241
1616
  } else {
1242
- this.logWarning('silentRefresh: 服务器未返回数据');
1617
+ this.logWarning("silentRefresh: 服务器未返回数据");
1243
1618
  }
1244
- (0, _product.perfMark)('silentRefresh', performance.now() - t0, {
1245
- count: this.store.list.length
1246
- });
1619
+ (0, import_product.perfMark)("silentRefresh", performance.now() - t0, { count: this.store.list.length });
1247
1620
  return this.store.list;
1248
1621
  } catch (error) {
1249
1622
  const errorMessage = error instanceof Error ? error.message : String(error);
1250
- this.logError('silentRefresh 失败', {
1623
+ this.logError("silentRefresh 失败", {
1251
1624
  duration: `${Math.round(performance.now() - t0)}ms`,
1252
1625
  error: errorMessage
1253
1626
  });
1254
1627
  return this.store.list;
1255
1628
  }
1256
1629
  }
1257
-
1258
1630
  /**
1259
1631
  * 销毁同步资源(取消 pubsub 订阅、清除定时器)
1260
1632
  */
1261
1633
  destroyProductSync() {
1634
+ var _a;
1262
1635
  if (this.syncTimer) {
1263
1636
  clearTimeout(this.syncTimer);
1264
- this.syncTimer = undefined;
1637
+ this.syncTimer = void 0;
1265
1638
  }
1266
- if (this.productDataSource?.destroy) {
1639
+ if ((_a = this.productDataSource) == null ? void 0 : _a.destroy) {
1267
1640
  this.productDataSource.destroy();
1268
1641
  }
1269
1642
  this.pendingSyncMessages = [];
1270
- this.logInfo('destroyProductSync: 同步资源已销毁');
1643
+ this.logInfo("destroyProductSync: 同步资源已销毁");
1271
1644
  }
1272
-
1273
1645
  /**
1274
1646
  * 获取模块的路由定义
1275
1647
  * Products 模块暂不提供路由,由 Server 层统一处理
@@ -1277,5 +1649,8 @@ class ProductsModule extends _BaseModule.BaseModule {
1277
1649
  getRoutes() {
1278
1650
  return [];
1279
1651
  }
1280
- }
1281
- exports.ProductsModule = ProductsModule;
1652
+ };
1653
+ // Annotate the CommonJS export names for ESM import in node:
1654
+ 0 && (module.exports = {
1655
+ ProductsModule
1656
+ });