@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.
- package/dist/core/index.js +10 -6
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -3
- package/dist/model/strategy/adapter/promotion/evaluator.js +3 -2
- package/dist/model/strategy/adapter/walletPass/evaluator.js +7 -5
- package/dist/model/strategy/adapter/walletPass/example.js +26 -3
- package/dist/model/strategy/adapter/walletPass/index.js +5 -5
- package/dist/model/strategy/adapter/walletPass/type.d.ts +0 -3
- package/dist/model/strategy/adapter/walletPass/utils.d.ts +0 -26
- package/dist/model/strategy/adapter/walletPass/utils.js +24 -96
- package/dist/model/strategy/strategy-example.js +19 -5
- package/dist/modules/BaseModule.d.ts +2 -2
- package/dist/modules/BaseModule.js +12 -14
- package/dist/modules/BookingContext/index.d.ts +48 -0
- package/dist/modules/BookingContext/index.js +566 -0
- package/dist/modules/BookingContext/types.d.ts +102 -0
- package/dist/modules/BookingContext/types.js +51 -0
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +302 -0
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +149 -0
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +249 -0
- package/dist/modules/BookingContext/utils/flexible.d.ts +28 -0
- package/dist/modules/BookingContext/utils/flexible.js +56 -0
- package/dist/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
- package/dist/modules/BookingContext/utils/formatResourceList.js +38 -0
- package/dist/modules/BookingContext/utils/index.d.ts +11 -0
- package/dist/modules/BookingContext/utils/index.js +11 -0
- package/dist/modules/BookingContext/utils/noResource.d.ts +13 -0
- package/dist/modules/BookingContext/utils/noResource.js +77 -0
- package/dist/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
- package/dist/modules/BookingContext/utils/orderLineDisplay.js +36 -0
- package/dist/modules/BookingContext/utils/productExtend.d.ts +72 -0
- package/dist/modules/BookingContext/utils/productExtend.js +339 -0
- package/dist/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
- package/dist/modules/BookingContext/utils/resourceErrors.js +74 -0
- package/dist/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
- package/dist/modules/BookingContext/utils/resourceSelection.js +24 -0
- package/dist/modules/BookingContext/utils/resources.d.ts +80 -0
- package/dist/modules/BookingContext/utils/resources.js +486 -0
- package/dist/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
- package/dist/modules/BookingContext/utils/serviceTimes.js +151 -0
- package/dist/modules/BookingContext/utils/timeSlices.d.ts +42 -0
- package/dist/modules/BookingContext/utils/timeSlices.js +100 -0
- package/dist/modules/Cart/index.js +3 -0
- package/dist/modules/Cart/utils/cartProduct.js +27 -5
- package/dist/modules/Cart/utils/cartResource.js +0 -2
- package/dist/modules/Cart/utils/changePrice.js +11 -11
- package/dist/modules/Customer/index.d.ts +20 -0
- package/dist/modules/Customer/index.js +172 -83
- package/dist/modules/Customer/types.d.ts +2 -0
- package/dist/modules/Date/index.js +5 -1
- package/dist/modules/Discount/index.d.ts +2 -2
- package/dist/modules/Discount/index.js +43 -30
- package/dist/modules/Discount/types.d.ts +1 -1
- package/dist/modules/OpenData/index.d.ts +8 -0
- package/dist/modules/OpenData/index.js +38 -16
- package/dist/modules/Order/index.d.ts +449 -24
- package/dist/modules/Order/index.js +5460 -574
- package/dist/modules/Order/types.d.ts +693 -88
- package/dist/modules/Order/types.js +68 -1
- package/dist/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
- package/dist/modules/Order/utils/bundleDiscountHydration.js +144 -0
- package/dist/modules/Order/utils/manualProductDiscount.d.ts +106 -0
- package/dist/modules/Order/utils/manualProductDiscount.js +210 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.js +405 -0
- package/dist/modules/Order/utils.d.ts +167 -18
- package/dist/modules/Order/utils.js +960 -165
- package/dist/modules/Payment/index.d.ts +10 -9
- package/dist/modules/Payment/index.js +573 -746
- package/dist/modules/Payment/types.d.ts +44 -24
- package/dist/modules/Payment/utils.d.ts +1 -1
- package/dist/modules/Payment/utils.js +4 -3
- package/dist/modules/Payment/walletpass.d.ts +0 -2
- package/dist/modules/Payment/walletpass.js +49 -33
- package/dist/modules/Product/types.d.ts +29 -7
- package/dist/modules/ProductList/index.d.ts +17 -13
- package/dist/modules/ProductList/index.js +182 -81
- package/dist/modules/ProductList/types.d.ts +16 -0
- package/dist/modules/Quotation/index.d.ts +22 -2
- package/dist/modules/Quotation/index.js +108 -42
- package/dist/modules/Quotation/types.d.ts +19 -0
- package/dist/modules/ResourcePlanner/index.d.ts +24 -0
- package/dist/modules/ResourcePlanner/index.js +181 -0
- package/dist/modules/ResourcePlanner/planner.d.ts +14 -0
- package/dist/modules/ResourcePlanner/planner.js +1069 -0
- package/dist/modules/ResourcePlanner/types.d.ts +227 -0
- package/dist/modules/ResourcePlanner/types.js +1 -0
- package/dist/modules/Rules/index.d.ts +8 -10
- package/dist/modules/Rules/index.js +324 -513
- package/dist/modules/Rules/types.d.ts +14 -3
- package/dist/modules/SalesSummary/index.d.ts +23 -26
- package/dist/modules/SalesSummary/index.js +152 -46
- package/dist/modules/SalesSummary/types.d.ts +9 -1
- package/dist/modules/SalesSummary/utils.d.ts +3 -22
- package/dist/modules/SalesSummary/utils.js +804 -165
- package/dist/modules/Schedule/getDateIsInSchedule.js +14 -12
- package/dist/modules/Schedule/index.d.ts +18 -5
- package/dist/modules/Schedule/index.js +79 -24
- package/dist/modules/Schedule/types.d.ts +2 -0
- package/dist/modules/Schedule/utils.js +1 -0
- package/dist/modules/Step/index.js +1 -0
- package/dist/modules/Summary/index.js +4 -3
- package/dist/modules/Summary/utils.js +22 -43
- package/dist/modules/SurchargeList/index.d.ts +18 -0
- package/dist/modules/SurchargeList/index.js +185 -0
- package/dist/modules/SurchargeList/types.d.ts +15 -0
- package/dist/modules/SurchargeList/types.js +1 -0
- package/dist/modules/index.d.ts +3 -0
- package/dist/modules/index.js +4 -1
- package/dist/plugins/app.d.ts +2 -0
- package/dist/plugins/request.d.ts +1 -0
- package/dist/plugins/request.js +4 -1
- package/dist/plugins/window.js +6 -2
- package/dist/server/index.d.ts +462 -8
- package/dist/server/index.js +6168 -680
- package/dist/server/modules/floor-plan/index.d.ts +39 -0
- package/dist/server/modules/floor-plan/index.js +595 -0
- package/dist/server/modules/floor-plan/types.d.ts +43 -0
- package/dist/server/modules/floor-plan/types.js +13 -0
- package/dist/server/modules/index.d.ts +7 -2
- package/dist/server/modules/index.js +6 -0
- package/dist/server/modules/menu/index.js +41 -32
- package/dist/server/modules/order/index.d.ts +207 -14
- package/dist/server/modules/order/index.js +2328 -379
- package/dist/server/modules/order/types.d.ts +76 -5
- package/dist/server/modules/order/types.js +14 -1
- package/dist/server/modules/order/utils/filterBookings.d.ts +7 -1
- package/dist/server/modules/order/utils/filterBookings.js +118 -11
- package/dist/server/modules/order/utils/filterOrders.js +242 -14
- package/dist/server/modules/payment/index.d.ts +28 -0
- package/dist/server/modules/payment/index.js +305 -0
- package/dist/server/modules/payment/types.d.ts +9 -0
- package/dist/server/modules/payment/types.js +1 -0
- package/dist/server/modules/products/index.d.ts +105 -14
- package/dist/server/modules/products/index.js +1416 -521
- package/dist/server/modules/products/types.d.ts +34 -1
- package/dist/server/modules/products/types.js +4 -0
- package/dist/server/modules/quotation/index.d.ts +39 -0
- package/dist/server/modules/quotation/index.js +298 -77
- package/dist/server/modules/resource/index.d.ts +2 -3
- package/dist/server/modules/resource/index.js +109 -86
- package/dist/server/modules/schedule/index.d.ts +6 -4
- package/dist/server/modules/schedule/index.js +145 -106
- package/dist/server/test.json +713 -0
- package/dist/server/types.d.ts +2 -0
- package/dist/server/utils/product.js +3 -2
- package/dist/server/utils/small-ticket.d.ts +71 -0
- package/dist/server/utils/small-ticket.js +963 -0
- package/dist/solution/BaseSales/index.d.ts +378 -0
- package/dist/solution/BaseSales/index.js +4009 -0
- package/dist/solution/BaseSales/types.d.ts +394 -0
- package/dist/solution/BaseSales/types.js +40 -0
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
- package/dist/solution/BaseSales/utils/cartPromotion.js +1450 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +144 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +157 -0
- package/dist/solution/BaseSales/utils/quotationPrice.d.ts +18 -0
- package/dist/solution/BaseSales/utils/quotationPrice.js +250 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +63 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +218 -0
- package/dist/solution/BaseSales/utils.d.ts +40 -0
- package/dist/solution/BaseSales/utils.js +263 -0
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingByStep/index.js +60 -11
- package/dist/solution/BookingByStep/utils/capacity.js +11 -1
- package/dist/solution/BookingByStep/utils/resources.js +3 -1
- package/dist/solution/BookingByStep/utils/timeslots.js +43 -2
- package/dist/solution/BookingTicket/index.d.ts +393 -24
- package/dist/solution/BookingTicket/index.js +2508 -443
- package/dist/solution/BookingTicket/types.d.ts +191 -6
- package/dist/solution/BookingTicket/types.js +83 -10
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
- package/dist/solution/BookingTicket/utils/addProductDecision.js +346 -0
- package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
- package/dist/solution/BookingTicket/utils/addTimeAvailability.js +95 -0
- package/dist/solution/BookingTicket/utils/bookingStatus.d.ts +77 -0
- package/dist/solution/BookingTicket/utils/bookingStatus.js +136 -0
- package/dist/solution/BookingTicket/utils/cartView.d.ts +29 -0
- package/dist/solution/BookingTicket/utils/cartView.js +209 -0
- package/dist/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/dist/solution/BookingTicket/utils/exampleData.js +183 -0
- package/dist/solution/BookingTicket/utils/orderCustomer.d.ts +4 -0
- package/dist/solution/BookingTicket/utils/orderCustomer.js +31 -0
- package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
- package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.js +438 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +400 -0
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.d.ts +4 -0
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +42 -1
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +56 -0
- package/dist/solution/BookingTicket/utils/scan/handleScan.d.ts +3 -1
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +42 -28
- package/dist/solution/BookingTicket/utils/scan/index.d.ts +5 -0
- package/dist/solution/BookingTicket/utils/scan/index.js +30 -14
- package/dist/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
- package/dist/solution/BookingTicket/utils/scan/scanProductValues.js +150 -0
- package/dist/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
- package/dist/solution/BookingTicket/utils/sessionCatalogStale.js +78 -0
- package/dist/solution/BuyTickets/index.js +12 -9
- package/dist/solution/Checkout/index.d.ts +1 -0
- package/dist/solution/Checkout/index.js +275 -209
- package/dist/solution/Checkout/utils/index.js +20 -8
- package/dist/solution/RegisterAndLogin/config.js +2 -10
- package/dist/solution/RegisterAndLogin/index.js +76 -30
- package/dist/solution/Sales/index.d.ts +50 -5
- package/dist/solution/Sales/index.js +484 -92
- package/dist/solution/Sales/types.d.ts +26 -2
- package/dist/solution/ScanOrder/index.d.ts +27 -21
- package/dist/solution/ScanOrder/index.js +519 -444
- package/dist/solution/ScanOrder/types.d.ts +33 -11
- package/dist/solution/ScanOrder/types.js +4 -5
- package/dist/solution/ScanOrder/utils.d.ts +4 -1
- package/dist/solution/ScanOrder/utils.js +109 -34
- package/dist/solution/ShopDiscount/index.js +18 -19
- package/dist/solution/ShopDiscount/types.d.ts +4 -5
- package/dist/solution/ShopDiscount/utils.d.ts +0 -9
- package/dist/solution/ShopDiscount/utils.js +0 -9
- package/dist/solution/UnifiedBookingSales/index.d.ts +183 -0
- package/dist/solution/UnifiedBookingSales/index.js +1871 -0
- package/dist/solution/UnifiedBookingSales/types.d.ts +143 -0
- package/dist/solution/UnifiedBookingSales/types.js +11 -0
- package/dist/solution/VenueBooking/index.d.ts +32 -51
- package/dist/solution/VenueBooking/index.js +741 -808
- package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
- package/dist/solution/VenueBooking/types.d.ts +1 -3
- package/dist/solution/VenueBooking/types.js +0 -1
- package/dist/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
- package/dist/solution/VenueBooking/utils/dateSummary.js +25 -12
- package/dist/solution/VenueBooking/utils/slotMerge.d.ts +6 -0
- package/dist/solution/VenueBooking/utils/slotMerge.js +9 -3
- package/dist/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
- package/dist/solution/VenueBooking/utils/timeSlot.js +4 -9
- package/dist/solution/index.d.ts +2 -0
- package/dist/solution/index.js +3 -1
- package/dist/types/index.d.ts +12 -2
- package/dist/utils/task.js +18 -15
- package/dist/utils/watch.js +1 -0
- package/lib/apis/picoding.js +0 -2
- package/lib/core/index.js +132 -130
- package/lib/effects/index.js +57 -46
- package/lib/index.d.ts +0 -1
- package/lib/index.js +50 -92
- package/lib/model/index.js +21 -14
- package/lib/model/strategy/adapter/dataVariant/adapter.js +50 -38
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +236 -162
- package/lib/model/strategy/adapter/dataVariant/examples.js +237 -229
- package/lib/model/strategy/adapter/dataVariant/index.js +34 -39
- package/lib/model/strategy/adapter/dataVariant/type.js +28 -57
- package/lib/model/strategy/adapter/index.js +64 -100
- package/lib/model/strategy/adapter/itemRule/adapter.js +144 -156
- package/lib/model/strategy/adapter/itemRule/evaluator.js +48 -36
- package/lib/model/strategy/adapter/itemRule/examples.js +225 -295
- package/lib/model/strategy/adapter/itemRule/index.js +57 -83
- package/lib/model/strategy/adapter/itemRule/type.js +36 -97
- package/lib/model/strategy/adapter/promotion/adapter.js +63 -84
- package/lib/model/strategy/adapter/promotion/evaluator.js +233 -382
- package/lib/model/strategy/adapter/promotion/examples.js +159 -139
- package/lib/model/strategy/adapter/promotion/index.js +0 -1
- package/lib/model/strategy/adapter/promotion/type.js +35 -199
- package/lib/model/strategy/adapter/type.js +16 -4
- package/lib/model/strategy/adapter/walletPass/evaluator.js +152 -180
- package/lib/model/strategy/adapter/walletPass/example.js +190 -217
- package/lib/model/strategy/adapter/walletPass/index.js +51 -75
- package/lib/model/strategy/adapter/walletPass/locales.js +58 -36
- package/lib/model/strategy/adapter/walletPass/type.d.ts +0 -3
- package/lib/model/strategy/adapter/walletPass/type.js +16 -4
- package/lib/model/strategy/adapter/walletPass/utils.d.ts +0 -26
- package/lib/model/strategy/adapter/walletPass/utils.js +383 -676
- package/lib/model/strategy/engine.js +168 -270
- package/lib/model/strategy/index.js +34 -49
- package/lib/model/strategy/strategy-example.js +239 -243
- package/lib/model/strategy/type.js +40 -100
- package/lib/modules/Account/index.js +53 -39
- package/lib/modules/Account/types.js +33 -20
- package/lib/modules/AccountList/index.js +154 -116
- package/lib/modules/AccountList/types.js +31 -30
- package/lib/modules/AccountList/utils.js +30 -18
- package/lib/modules/BaseModule.d.ts +2 -2
- package/lib/modules/BaseModule.js +50 -29
- package/lib/modules/BookingContext/index.d.ts +48 -0
- package/lib/modules/BookingContext/index.js +368 -0
- package/lib/modules/BookingContext/types.d.ts +102 -0
- package/lib/modules/BookingContext/types.js +34 -0
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.d.ts +16 -0
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +298 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +8 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +155 -0
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +76 -0
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +222 -0
- package/lib/modules/BookingContext/utils/flexible.d.ts +28 -0
- package/lib/modules/BookingContext/utils/flexible.js +80 -0
- package/lib/modules/BookingContext/utils/formatResourceList.d.ts +8 -0
- package/lib/modules/BookingContext/utils/formatResourceList.js +50 -0
- package/lib/modules/BookingContext/utils/index.d.ts +11 -0
- package/lib/modules/BookingContext/utils/index.js +43 -0
- package/lib/modules/BookingContext/utils/noResource.d.ts +13 -0
- package/lib/modules/BookingContext/utils/noResource.js +90 -0
- package/lib/modules/BookingContext/utils/orderLineDisplay.d.ts +1 -0
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +56 -0
- package/lib/modules/BookingContext/utils/productExtend.d.ts +72 -0
- package/lib/modules/BookingContext/utils/productExtend.js +283 -0
- package/lib/modules/BookingContext/utils/resourceErrors.d.ts +41 -0
- package/lib/modules/BookingContext/utils/resourceErrors.js +80 -0
- package/lib/modules/BookingContext/utils/resourceSelection.d.ts +7 -0
- package/lib/modules/BookingContext/utils/resourceSelection.js +46 -0
- package/lib/modules/BookingContext/utils/resources.d.ts +80 -0
- package/lib/modules/BookingContext/utils/resources.js +377 -0
- package/lib/modules/BookingContext/utils/serviceTimes.d.ts +55 -0
- package/lib/modules/BookingContext/utils/serviceTimes.js +162 -0
- package/lib/modules/BookingContext/utils/timeSlices.d.ts +42 -0
- package/lib/modules/BookingContext/utils/timeSlices.js +124 -0
- package/lib/modules/Cart/index.js +124 -170
- package/lib/modules/Cart/types.js +51 -46
- package/lib/modules/Cart/utils/cartAccount.js +39 -40
- package/lib/modules/Cart/utils/cartDate.js +61 -56
- package/lib/modules/Cart/utils/cartDiscount.js +33 -28
- package/lib/modules/Cart/utils/cartNote.js +32 -27
- package/lib/modules/Cart/utils/cartProduct.js +261 -309
- package/lib/modules/Cart/utils/cartRelationForms.js +35 -29
- package/lib/modules/Cart/utils/cartResource.js +78 -72
- package/lib/modules/Cart/utils/changePrice.js +59 -31
- package/lib/modules/Cart/utils/index.js +48 -106
- package/lib/modules/Customer/constants.js +34 -13
- package/lib/modules/Customer/index.d.ts +20 -0
- package/lib/modules/Customer/index.js +207 -217
- package/lib/modules/Customer/types.d.ts +2 -0
- package/lib/modules/Customer/types.js +35 -38
- package/lib/modules/Date/index.js +115 -116
- package/lib/modules/Date/types.js +28 -16
- package/lib/modules/Date/utils.js +123 -174
- package/lib/modules/Discount/index.d.ts +2 -2
- package/lib/modules/Discount/index.js +133 -119
- package/lib/modules/Discount/types.d.ts +1 -1
- package/lib/modules/Discount/types.js +31 -9
- package/lib/modules/Guests/index.js +56 -30
- package/lib/modules/Guests/types.js +33 -23
- package/lib/modules/Holder/index.js +189 -209
- package/lib/modules/Holder/types.js +16 -4
- package/lib/modules/Holder/utils.js +49 -20
- package/lib/modules/OpenData/index.d.ts +8 -0
- package/lib/modules/OpenData/index.js +88 -63
- package/lib/modules/OpenData/types.js +16 -4
- package/lib/modules/OpenData/utils.js +78 -44
- package/lib/modules/Order/index.d.ts +449 -24
- package/lib/modules/Order/index.js +4184 -514
- package/lib/modules/Order/types.d.ts +693 -88
- package/lib/modules/Order/types.js +35 -24
- package/lib/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
- package/lib/modules/Order/utils/bundleDiscountHydration.js +139 -0
- package/lib/modules/Order/utils/manualProductDiscount.d.ts +106 -0
- package/lib/modules/Order/utils/manualProductDiscount.js +206 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.js +415 -0
- package/lib/modules/Order/utils.d.ts +167 -18
- package/lib/modules/Order/utils.js +1085 -414
- package/lib/modules/Payment/cash.js +33 -20
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +76 -145
- package/lib/modules/Payment/eftpos.js +30 -16
- package/lib/modules/Payment/index.d.ts +10 -9
- package/lib/modules/Payment/index.js +402 -636
- package/lib/modules/Payment/mx51.js +0 -1
- package/lib/modules/Payment/types.d.ts +44 -24
- package/lib/modules/Payment/types.js +107 -216
- package/lib/modules/Payment/utils.d.ts +1 -1
- package/lib/modules/Payment/utils.js +50 -52
- package/lib/modules/Payment/walletpass.d.ts +0 -2
- package/lib/modules/Payment/walletpass.js +216 -221
- package/lib/modules/Product/index.js +46 -51
- package/lib/modules/Product/types.d.ts +29 -7
- package/lib/modules/Product/types.js +16 -4
- package/lib/modules/Product/utils.js +33 -32
- package/lib/modules/ProductList/index.d.ts +17 -13
- package/lib/modules/ProductList/index.js +161 -120
- package/lib/modules/ProductList/types.d.ts +16 -0
- package/lib/modules/ProductList/types.js +31 -9
- package/lib/modules/Quotation/index.d.ts +22 -2
- package/lib/modules/Quotation/index.js +154 -64
- package/lib/modules/Quotation/types.d.ts +19 -0
- package/lib/modules/Quotation/types.js +16 -4
- package/lib/modules/Resource/index.js +59 -27
- package/lib/modules/Resource/types.js +32 -22
- package/lib/modules/Resource/utils.js +38 -30
- package/lib/modules/ResourcePlanner/index.d.ts +24 -0
- package/lib/modules/ResourcePlanner/index.js +148 -0
- package/lib/modules/ResourcePlanner/planner.d.ts +14 -0
- package/lib/modules/ResourcePlanner/planner.js +933 -0
- package/lib/modules/ResourcePlanner/types.d.ts +227 -0
- package/lib/modules/ResourcePlanner/types.js +17 -0
- package/lib/modules/Rules/index.d.ts +8 -10
- package/lib/modules/Rules/index.js +960 -1440
- package/lib/modules/Rules/types.d.ts +14 -3
- package/lib/modules/Rules/types.js +40 -17
- package/lib/modules/SalesSummary/index.d.ts +23 -26
- package/lib/modules/SalesSummary/index.js +134 -61
- package/lib/modules/SalesSummary/types.d.ts +9 -1
- package/lib/modules/SalesSummary/types.js +16 -4
- package/lib/modules/SalesSummary/utils.d.ts +3 -22
- package/lib/modules/SalesSummary/utils.js +814 -233
- package/lib/modules/ScanOrderLogger/index.js +79 -59
- package/lib/modules/ScanOrderLogger/providers/feishu.js +78 -54
- package/lib/modules/ScanOrderLogger/providers/grafana.js +36 -13
- package/lib/modules/ScanOrderLogger/types.js +16 -4
- package/lib/modules/Schedule/getDateIsInSchedule.js +169 -338
- package/lib/modules/Schedule/index.d.ts +18 -5
- package/lib/modules/Schedule/index.js +153 -104
- package/lib/modules/Schedule/type.js +16 -4
- package/lib/modules/Schedule/types.d.ts +2 -0
- package/lib/modules/Schedule/types.js +16 -4
- package/lib/modules/Schedule/utils.js +291 -433
- package/lib/modules/Step/index.js +52 -40
- package/lib/modules/Step/tyeps.js +16 -4
- package/lib/modules/Summary/index.js +71 -66
- package/lib/modules/Summary/types.js +16 -4
- package/lib/modules/Summary/utils.js +418 -791
- package/lib/modules/SurchargeList/index.d.ts +18 -0
- package/lib/modules/SurchargeList/index.js +109 -0
- package/lib/modules/SurchargeList/types.d.ts +15 -0
- package/lib/modules/SurchargeList/types.js +17 -0
- package/lib/modules/index.d.ts +3 -0
- package/lib/modules/index.js +63 -212
- package/lib/plugins/app.d.ts +2 -0
- package/lib/plugins/app.js +16 -4
- package/lib/plugins/index.js +25 -36
- package/lib/plugins/request.d.ts +1 -0
- package/lib/plugins/request.js +126 -137
- package/lib/plugins/shopStore.js +16 -4
- package/lib/plugins/user.js +16 -4
- package/lib/plugins/window.js +179 -171
- package/lib/server/index.d.ts +462 -8
- package/lib/server/index.js +4520 -1162
- package/lib/server/modules/floor-plan/index.d.ts +39 -0
- package/lib/server/modules/floor-plan/index.js +327 -0
- package/lib/server/modules/floor-plan/types.d.ts +43 -0
- package/lib/server/modules/floor-plan/types.js +34 -0
- package/lib/server/modules/index.d.ts +7 -2
- package/lib/server/modules/index.js +67 -84
- package/lib/server/modules/menu/index.js +122 -146
- package/lib/server/modules/menu/types.js +31 -18
- package/lib/server/modules/order/index.d.ts +207 -14
- package/lib/server/modules/order/index.js +1543 -285
- package/lib/server/modules/order/types.d.ts +76 -5
- package/lib/server/modules/order/types.js +32 -107
- package/lib/server/modules/order/utils/filterBookings.d.ts +7 -1
- package/lib/server/modules/order/utils/filterBookings.js +259 -176
- package/lib/server/modules/order/utils/filterOrders.js +293 -94
- package/lib/server/modules/payment/index.d.ts +28 -0
- package/lib/server/modules/payment/index.js +192 -0
- package/lib/server/modules/payment/types.d.ts +9 -0
- package/lib/server/modules/payment/types.js +17 -0
- package/lib/server/modules/products/index.d.ts +105 -14
- package/lib/server/modules/products/index.js +850 -475
- package/lib/server/modules/products/types.d.ts +34 -1
- package/lib/server/modules/products/types.js +34 -41
- package/lib/server/modules/quotation/index.d.ts +39 -0
- package/lib/server/modules/quotation/index.js +254 -75
- package/lib/server/modules/quotation/types.js +31 -21
- package/lib/server/modules/resource/index.d.ts +2 -3
- package/lib/server/modules/resource/index.js +240 -243
- package/lib/server/modules/resource/types.js +33 -42
- package/lib/server/modules/schedule/index.d.ts +6 -4
- package/lib/server/modules/schedule/index.js +146 -147
- package/lib/server/modules/schedule/types.js +21 -14
- package/lib/server/modules/schedule/utils.js +163 -334
- package/lib/server/test.json +713 -0
- package/lib/server/types.d.ts +2 -0
- package/lib/server/types.js +16 -4
- package/lib/server/utils/index.js +23 -25
- package/lib/server/utils/product.js +140 -197
- package/lib/server/utils/schedule.js +41 -34
- package/lib/server/utils/small-ticket.d.ts +71 -0
- package/lib/server/utils/small-ticket.js +904 -0
- package/lib/server/utils/time.js +49 -40
- package/lib/solution/BaseSales/index.d.ts +378 -0
- package/lib/solution/BaseSales/index.js +2533 -0
- package/lib/solution/BaseSales/types.d.ts +394 -0
- package/lib/solution/BaseSales/types.js +43 -0
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +287 -0
- package/lib/solution/BaseSales/utils/cartPromotion.js +1004 -0
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +144 -0
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +160 -0
- package/lib/solution/BaseSales/utils/quotationPrice.d.ts +18 -0
- package/lib/solution/BaseSales/utils/quotationPrice.js +289 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +63 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +256 -0
- package/lib/solution/BaseSales/utils.d.ts +40 -0
- package/lib/solution/BaseSales/utils.js +244 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1340 -1530
- package/lib/solution/BookingByStep/types.js +99 -40
- package/lib/solution/BookingByStep/utils/capacity.js +160 -192
- package/lib/solution/BookingByStep/utils/products.js +52 -42
- package/lib/solution/BookingByStep/utils/resources.js +330 -527
- package/lib/solution/BookingByStep/utils/stock.js +44 -65
- package/lib/solution/BookingByStep/utils/timeslots.js +131 -129
- package/lib/solution/BookingTicket/index.d.ts +393 -24
- package/lib/solution/BookingTicket/index.js +1374 -184
- package/lib/solution/BookingTicket/types.d.ts +191 -6
- package/lib/solution/BookingTicket/types.js +79 -40
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +117 -0
- package/lib/solution/BookingTicket/utils/addProductDecision.js +318 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +125 -0
- package/lib/solution/BookingTicket/utils/bookingStatus.d.ts +77 -0
- package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -0
- package/lib/solution/BookingTicket/utils/cartView.d.ts +29 -0
- package/lib/solution/BookingTicket/utils/cartView.js +184 -0
- package/lib/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/lib/solution/BookingTicket/utils/exampleData.js +0 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.d.ts +4 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.js +58 -0
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +185 -0
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +254 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +36 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +169 -0
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.d.ts +4 -0
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +97 -64
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +32 -0
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +51 -0
- package/lib/solution/BookingTicket/utils/scan/handleScan.d.ts +3 -1
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +81 -82
- package/lib/solution/BookingTicket/utils/scan/index.d.ts +5 -0
- package/lib/solution/BookingTicket/utils/scan/index.js +109 -91
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +43 -90
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.d.ts +21 -0
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +127 -0
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.d.ts +23 -0
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +85 -0
- package/lib/solution/BuyTickets/index.js +70 -67
- package/lib/solution/BuyTickets/types.js +38 -22
- package/lib/solution/Checkout/index.d.ts +1 -0
- package/lib/solution/Checkout/index.js +1169 -1463
- package/lib/solution/Checkout/types.js +61 -91
- package/lib/solution/Checkout/utils/index.js +156 -228
- package/lib/solution/PlaceOrder/index.js +0 -55
- package/lib/solution/RegisterAndLogin/config.js +462 -503
- package/lib/solution/RegisterAndLogin/index.js +630 -633
- package/lib/solution/RegisterAndLogin/types.js +76 -189
- package/lib/solution/RegisterAndLogin/utils.js +125 -183
- package/lib/solution/Sales/index.d.ts +50 -5
- package/lib/solution/Sales/index.js +498 -238
- package/lib/solution/Sales/types.d.ts +26 -2
- package/lib/solution/Sales/types.js +33 -27
- package/lib/solution/ScanOrder/index.d.ts +27 -21
- package/lib/solution/ScanOrder/index.js +936 -864
- package/lib/solution/ScanOrder/types.d.ts +33 -11
- package/lib/solution/ScanOrder/types.js +34 -34
- package/lib/solution/ScanOrder/utils.d.ts +4 -1
- package/lib/solution/ScanOrder/utils.js +422 -385
- package/lib/solution/ShopDiscount/index.js +233 -235
- package/lib/solution/ShopDiscount/types.d.ts +4 -5
- package/lib/solution/ShopDiscount/types.js +37 -15
- package/lib/solution/ShopDiscount/utils.d.ts +0 -9
- package/lib/solution/ShopDiscount/utils.js +172 -309
- package/lib/solution/UnifiedBookingSales/index.d.ts +183 -0
- package/lib/solution/UnifiedBookingSales/index.js +1076 -0
- package/lib/solution/UnifiedBookingSales/types.d.ts +143 -0
- package/lib/solution/UnifiedBookingSales/types.js +33 -0
- package/lib/solution/VenueBooking/index.d.ts +32 -51
- package/lib/solution/VenueBooking/index.js +1008 -984
- package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
- package/lib/solution/VenueBooking/types.d.ts +1 -3
- package/lib/solution/VenueBooking/types.js +39 -20
- package/lib/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
- package/lib/solution/VenueBooking/utils/dateSummary.js +62 -25
- package/lib/solution/VenueBooking/utils/resource.js +54 -31
- package/lib/solution/VenueBooking/utils/slotMerge.d.ts +6 -0
- package/lib/solution/VenueBooking/utils/slotMerge.js +109 -90
- package/lib/solution/VenueBooking/utils/timeSlot.d.ts +0 -2
- package/lib/solution/VenueBooking/utils/timeSlot.js +133 -138
- package/lib/solution/VenueBooking/utils.js +67 -130
- package/lib/solution/index.d.ts +2 -0
- package/lib/solution/index.js +41 -102
- package/lib/store/createStore.js +29 -32
- package/lib/types/index.d.ts +12 -2
- package/lib/types/index.js +16 -4
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +47 -81
- package/package.json +2 -4
- package/dist/solution/Checkout/appointmentDemo.json +0 -1
- package/dist/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
- package/dist/solution/VenueBooking/utils/smartPricing.js +0 -233
- package/lib/solution/Checkout/appointmentDemo.json +0 -1
- package/lib/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
- package/lib/solution/VenueBooking/utils/smartPricing.js +0 -192
|
@@ -1,94 +1,100 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
4
|
-
|
|
19
|
+
// src/server/modules/products/index.ts
|
|
20
|
+
var products_exports = {};
|
|
21
|
+
__export(products_exports, {
|
|
22
|
+
ProductsModule: () => ProductsModule
|
|
5
23
|
});
|
|
6
|
-
exports
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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) {
|
|
73
|
-
console.
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
156
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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:
|
|
175
|
+
priceDataCount: priceData.length,
|
|
179
176
|
duration: `${duration}ms`
|
|
180
177
|
});
|
|
181
|
-
return
|
|
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
|
|
207
|
-
const
|
|
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(
|
|
220
|
-
|
|
221
|
-
|
|
393
|
+
const updatedProducts = await this.prepareProductsWithPrice(
|
|
394
|
+
schedule_date,
|
|
395
|
+
extraContext,
|
|
396
|
+
{ productIds: changedIds }
|
|
397
|
+
);
|
|
222
398
|
if (updatedProducts.length > 0) {
|
|
223
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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(
|
|
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,
|
|
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
|
|
305
|
-
const isIncremental = targetIds
|
|
306
|
-
this.logInfo(
|
|
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 ?
|
|
309
|
-
targetIdsCount: targetIds
|
|
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
|
-
|
|
317
|
-
|
|
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,
|
|
327
|
-
|
|
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
|
|
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,
|
|
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(
|
|
361
|
-
mode: isIncremental ?
|
|
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(
|
|
543
|
+
await this.core.effects.emit(
|
|
544
|
+
import_types.ProductsHooks.onProductsPriceApplied,
|
|
545
|
+
processedProducts
|
|
546
|
+
);
|
|
368
547
|
}
|
|
369
|
-
(0,
|
|
548
|
+
(0, import_product.perfMark)("prepareProductsWithPrice", performance.now() - tTotal, {
|
|
370
549
|
productCount: products.length,
|
|
371
550
|
formatterCount: this.formatters.length,
|
|
372
|
-
mode: isIncremental ?
|
|
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
|
-
|
|
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(
|
|
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,
|
|
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
|
-
|
|
438
|
-
if (this.
|
|
439
|
-
console.warn(
|
|
670
|
+
registerBuiltinProductFormatters() {
|
|
671
|
+
if (this.isBuiltinFormatterRegistered) {
|
|
672
|
+
console.warn("[ProductsModule] 内置商品格式化器已注册,跳过");
|
|
440
673
|
return;
|
|
441
674
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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
|
-
|
|
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,
|
|
712
|
+
return (0, import_product.applyI18nToProducts)(products, context.locale);
|
|
452
713
|
};
|
|
453
714
|
const detailValueFormatter = (products, context) => {
|
|
454
|
-
return (0,
|
|
715
|
+
return (0, import_product.applyDetailValueToProducts)(products, context);
|
|
455
716
|
};
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
768
|
+
* 清空所有格式化器(包括内置智能定价格式化器)
|
|
769
|
+
* @param keepBuiltin 是否保留内置智能定价格式化器(默认 true)
|
|
493
770
|
*/
|
|
494
771
|
clearFormatters(keepBuiltin = true) {
|
|
495
|
-
if (keepBuiltin && this.
|
|
496
|
-
|
|
497
|
-
this.formatters =
|
|
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.
|
|
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(
|
|
808
|
+
this.logWarning("loadProductsByServer: ProductDataSource 不可用");
|
|
531
809
|
return [];
|
|
532
810
|
}
|
|
533
|
-
this.logInfo(
|
|
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,
|
|
542
|
-
|
|
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.
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
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(
|
|
558
|
-
this.logError(
|
|
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(
|
|
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(
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
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(
|
|
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(
|
|
618
|
-
this.logError(
|
|
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.
|
|
635
|
-
|
|
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,
|
|
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) :
|
|
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(
|
|
676
|
-
|
|
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(
|
|
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(
|
|
1007
|
+
this.productsPriceCache.set(
|
|
1008
|
+
dateKey,
|
|
1009
|
+
cachedProducts.filter((p) => !idSet.has(p.id))
|
|
1010
|
+
);
|
|
698
1011
|
}
|
|
699
|
-
this.core.effects.emit(
|
|
700
|
-
this.logInfo(
|
|
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(
|
|
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(
|
|
718
|
-
this.logInfo(
|
|
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(
|
|
1029
|
+
this.logWarning("refreshProducts: 服务器未返回数据");
|
|
723
1030
|
}
|
|
724
|
-
(0,
|
|
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
|
-
|
|
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(
|
|
749
|
-
this.logError(
|
|
750
|
-
error: errorMessage
|
|
751
|
-
});
|
|
1051
|
+
console.error("[Products] 清空 IndexDB 缓存失败:", error);
|
|
1052
|
+
this.logError("清空 IndexDB 缓存失败", { error: errorMessage });
|
|
752
1053
|
}
|
|
753
1054
|
}
|
|
754
|
-
|
|
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(
|
|
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,
|
|
770
|
-
|
|
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(
|
|
779
|
-
this.logError(
|
|
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
|
-
*
|
|
788
|
-
*
|
|
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
|
|
1101
|
+
async replaceProductsSnapshotInIndexDB(products, source) {
|
|
791
1102
|
if (!this.dbManager) {
|
|
792
|
-
this.logWarning(
|
|
1103
|
+
this.logWarning("replaceProductsSnapshotInIndexDB: dbManager 不可用");
|
|
793
1104
|
return;
|
|
794
1105
|
}
|
|
795
|
-
this.logInfo('开始保存商品数据到 IndexDB', {
|
|
796
|
-
productCount: products.length
|
|
797
|
-
});
|
|
798
1106
|
try {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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
|
-
|
|
811
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
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:
|
|
1200
|
+
source: "IndexDB"
|
|
859
1201
|
});
|
|
860
|
-
this.logInfo(
|
|
1202
|
+
this.logInfo("预加载完成(从 IndexDB)", {
|
|
861
1203
|
productCount: cachedData.length,
|
|
862
1204
|
duration: `${Math.round(performance.now() - tTotal)}ms`,
|
|
863
|
-
source:
|
|
1205
|
+
source: "IndexDB"
|
|
864
1206
|
});
|
|
1207
|
+
this.lastPreloadCompletedAtMs = Date.now();
|
|
865
1208
|
return;
|
|
866
1209
|
}
|
|
867
|
-
|
|
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(
|
|
871
|
-
this.logWarning(
|
|
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,
|
|
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,
|
|
886
|
-
|
|
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:
|
|
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:
|
|
1233
|
+
source: "Server"
|
|
897
1234
|
});
|
|
1235
|
+
this.lastPreloadCompletedAtMs = Date.now();
|
|
898
1236
|
} else {
|
|
899
|
-
(0,
|
|
900
|
-
|
|
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
|
-
|
|
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(
|
|
1254
|
+
this.logWarning("initProductDataSource: ProductDataSource 不可用");
|
|
920
1255
|
return;
|
|
921
1256
|
}
|
|
922
1257
|
this.productDataSource = new ProductDataSourceClass();
|
|
923
|
-
this.logInfo(
|
|
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(
|
|
1267
|
+
this.logWarning("setupProductSync: ProductDataSource 不可用,跳过同步初始化");
|
|
934
1268
|
return;
|
|
935
1269
|
}
|
|
936
|
-
const createHandler = channelKey => message => {
|
|
937
|
-
const data = message
|
|
938
|
-
if (!data)
|
|
939
|
-
|
|
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
|
-
|
|
960
|
-
|
|
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 ||
|
|
1295
|
+
const channelKey = data.module || "product";
|
|
965
1296
|
createHandler(channelKey)(data);
|
|
966
1297
|
}
|
|
967
1298
|
}
|
|
968
|
-
}).catch(err => {
|
|
969
|
-
this.logError(
|
|
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(
|
|
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)
|
|
998
|
-
|
|
999
|
-
|
|
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 ||
|
|
1008
|
-
if (channelKey ===
|
|
1009
|
-
if (msg.relation_product_ids
|
|
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
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
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)
|
|
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)
|
|
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 ===
|
|
1043
|
-
// 报价单变更影响范围大,标记清除全量价格缓存
|
|
1370
|
+
} else if (channelKey === "product_quotation") {
|
|
1044
1371
|
shouldClearPriceCache = true;
|
|
1045
|
-
if (msg.relation_product_ids
|
|
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 ([
|
|
1049
|
-
if (msg.relation_product_ids
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
1419
|
+
this.logInfo("processProductSyncMessages: SSE 增量更新完成123", {
|
|
1075
1420
|
requestedCount: uniqueSSEIds.length,
|
|
1076
1421
|
receivedCount: freshProducts.length
|
|
1077
1422
|
});
|
|
1078
1423
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
1472
|
+
this.logWarning("fetchProductsBySSE: ProductDataSource 不可用");
|
|
1112
1473
|
return [];
|
|
1113
1474
|
}
|
|
1114
|
-
this.logInfo(
|
|
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,
|
|
1130
|
-
|
|
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(
|
|
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
|
-
*
|
|
1152
|
-
*
|
|
1498
|
+
*
|
|
1499
|
+
* @example
|
|
1500
|
+
* await this.applyBodyUpdatesToStore(bodyUpdates, { skipIndexDB: true })
|
|
1153
1501
|
*/
|
|
1154
|
-
async applyBodyUpdatesToStore(bodyUpdates) {
|
|
1155
|
-
|
|
1156
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
1213
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
1236
|
-
await this.core.effects.emit(
|
|
1237
|
-
this.logInfo(
|
|
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(
|
|
1617
|
+
this.logWarning("silentRefresh: 服务器未返回数据");
|
|
1243
1618
|
}
|
|
1244
|
-
(0,
|
|
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(
|
|
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 =
|
|
1637
|
+
this.syncTimer = void 0;
|
|
1265
1638
|
}
|
|
1266
|
-
if (this.productDataSource
|
|
1639
|
+
if ((_a = this.productDataSource) == null ? void 0 : _a.destroy) {
|
|
1267
1640
|
this.productDataSource.destroy();
|
|
1268
1641
|
}
|
|
1269
1642
|
this.pendingSyncMessages = [];
|
|
1270
|
-
this.logInfo(
|
|
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
|
-
|
|
1652
|
+
};
|
|
1653
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1654
|
+
0 && (module.exports = {
|
|
1655
|
+
ProductsModule
|
|
1656
|
+
});
|