@pisell/pisellos 0.0.569 → 0.10.2
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/index.js +9 -0
- 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 +17 -92
- package/dist/model/strategy/strategy-example.js +19 -5
- package/dist/modules/BaseModule.d.ts +1 -1
- package/dist/modules/BaseModule.js +8 -10
- package/dist/modules/Cart/index.js +3 -0
- package/dist/modules/Cart/utils/cartProduct.js +1 -0
- package/dist/modules/Cart/utils/cartResource.js +0 -2
- package/dist/modules/Cart/utils/changePrice.js +9 -16
- package/dist/modules/Date/index.js +5 -1
- package/dist/modules/Discount/index.d.ts +0 -1
- package/dist/modules/Discount/index.js +7 -22
- package/dist/modules/Discount/types.d.ts +0 -1
- package/dist/modules/OpenData/index.js +2 -0
- package/dist/modules/Order/index.js +70 -40
- package/dist/modules/Payment/index.js +162 -97
- package/dist/modules/Payment/types.d.ts +4 -8
- package/dist/modules/Payment/walletpass.d.ts +0 -2
- package/dist/modules/Payment/walletpass.js +5 -4
- package/dist/modules/ProductList/index.d.ts +1 -1
- package/dist/modules/ProductList/index.js +3 -12
- package/dist/modules/ProductList/types.d.ts +0 -1
- package/dist/modules/Rules/index.js +126 -427
- package/dist/modules/SalesSummary/utils.js +1 -2
- package/dist/modules/Schedule/getDateIsInSchedule.js +0 -5
- package/dist/modules/Schedule/index.js +1 -0
- package/dist/modules/Schedule/utils.js +1 -0
- package/dist/modules/Step/index.js +1 -0
- package/dist/modules/Summary/utils.js +22 -43
- package/dist/plugins/request.js +4 -1
- package/dist/plugins/window.js +6 -2
- package/dist/server/index.js +129 -97
- package/dist/server/modules/menu/index.js +41 -32
- package/dist/server/modules/order/index.js +4 -2
- package/dist/server/modules/products/index.js +42 -24
- package/dist/server/modules/quotation/index.js +38 -29
- package/dist/server/modules/resource/index.js +4 -3
- package/dist/server/modules/schedule/index.js +35 -27
- package/dist/server/utils/product.js +1 -0
- package/dist/solution/BaseSales/index.js +41 -38
- 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 +1 -1
- package/dist/solution/BookingTicket/index.js +2 -0
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +7 -6
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +31 -25
- package/dist/solution/BookingTicket/utils/scan/index.js +10 -6
- package/dist/solution/BuyTickets/index.js +12 -9
- package/dist/solution/Checkout/index.js +252 -177
- package/dist/solution/Checkout/utils/index.js +16 -4
- package/dist/solution/RegisterAndLogin/index.js +76 -30
- package/dist/solution/ScanOrder/index.js +60 -50
- package/dist/solution/ShopDiscount/index.js +14 -15
- 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/VenueBooking/index.d.ts +3 -31
- package/dist/solution/VenueBooking/index.js +496 -651
- 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/timeSlot.d.ts +0 -2
- package/dist/solution/VenueBooking/utils/timeSlot.js +4 -9
- package/dist/types/index.d.ts +1 -1
- 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 +231 -381
- package/lib/model/strategy/adapter/promotion/examples.js +159 -139
- package/lib/model/strategy/adapter/promotion/index.js +49 -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 -678
- 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 +1 -1
- package/lib/modules/BaseModule.js +46 -25
- package/lib/modules/BookingContext/index.js +136 -158
- package/lib/modules/BookingContext/types.js +32 -46
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +143 -131
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +82 -75
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +150 -170
- package/lib/modules/BookingContext/utils/flexible.js +55 -38
- package/lib/modules/BookingContext/utils/formatResourceList.js +34 -19
- package/lib/modules/BookingContext/utils/index.js +41 -124
- package/lib/modules/BookingContext/utils/noResource.js +70 -58
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +41 -14
- package/lib/modules/BookingContext/utils/productExtend.js +155 -202
- package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
- package/lib/modules/BookingContext/utils/resourceSelection.js +41 -19
- package/lib/modules/BookingContext/utils/resources.js +167 -209
- package/lib/modules/BookingContext/utils/serviceTimes.js +116 -115
- package/lib/modules/BookingContext/utils/timeSlices.js +80 -70
- 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 +251 -321
- 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 +50 -28
- package/lib/modules/Cart/utils/index.js +48 -106
- package/lib/modules/Customer/constants.js +34 -13
- package/lib/modules/Customer/index.js +169 -232
- 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 +0 -1
- package/lib/modules/Discount/index.js +128 -130
- package/lib/modules/Discount/types.d.ts +0 -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.js +76 -69
- package/lib/modules/OpenData/types.js +16 -4
- package/lib/modules/OpenData/utils.js +78 -44
- package/lib/modules/Order/index.js +1909 -1572
- package/lib/modules/Order/types.js +35 -78
- package/lib/modules/Order/utils/bundleDiscountHydration.js +74 -41
- package/lib/modules/Order/utils/manualProductDiscount.js +123 -124
- package/lib/modules/Order/utils/orderCollectionIdentity.js +210 -148
- package/lib/modules/Order/utils.js +634 -799
- 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.js +378 -518
- package/lib/modules/Payment/mx51.js +0 -1
- package/lib/modules/Payment/types.d.ts +4 -8
- package/lib/modules/Payment/types.js +107 -216
- package/lib/modules/Payment/utils.js +48 -51
- package/lib/modules/Payment/walletpass.d.ts +0 -2
- package/lib/modules/Payment/walletpass.js +211 -226
- package/lib/modules/Product/index.js +46 -51
- package/lib/modules/Product/types.js +16 -4
- package/lib/modules/Product/utils.js +33 -32
- package/lib/modules/ProductList/index.d.ts +1 -1
- package/lib/modules/ProductList/index.js +117 -117
- package/lib/modules/ProductList/types.d.ts +0 -1
- package/lib/modules/ProductList/types.js +31 -9
- package/lib/modules/Quotation/index.js +100 -66
- 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.js +61 -60
- package/lib/modules/ResourcePlanner/planner.js +384 -346
- package/lib/modules/ResourcePlanner/types.js +16 -4
- package/lib/modules/Rules/index.js +903 -1475
- package/lib/modules/Rules/types.js +40 -17
- package/lib/modules/SalesSummary/index.js +90 -85
- package/lib/modules/SalesSummary/types.js +16 -4
- package/lib/modules/SalesSummary/utils.js +427 -351
- 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 +163 -339
- package/lib/modules/Schedule/index.js +114 -100
- package/lib/modules/Schedule/type.js +16 -4
- 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.js +60 -46
- package/lib/modules/SurchargeList/types.js +16 -4
- package/lib/modules/index.js +63 -245
- package/lib/plugins/app.js +16 -4
- package/lib/plugins/index.js +25 -36
- 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.js +2337 -2675
- package/lib/server/modules/floor-plan/index.js +123 -102
- package/lib/server/modules/floor-plan/types.js +30 -15
- package/lib/server/modules/index.js +68 -106
- package/lib/server/modules/menu/index.js +122 -146
- package/lib/server/modules/menu/types.js +31 -18
- package/lib/server/modules/order/index.js +642 -567
- package/lib/server/modules/order/types.js +32 -117
- package/lib/server/modules/order/utils/filterBookings.js +194 -219
- package/lib/server/modules/order/utils/filterOrders.js +92 -118
- package/lib/server/modules/payment/index.js +83 -59
- package/lib/server/modules/payment/types.js +16 -4
- package/lib/server/modules/products/index.js +459 -575
- package/lib/server/modules/products/types.js +34 -44
- package/lib/server/modules/quotation/index.js +172 -137
- package/lib/server/modules/quotation/types.js +31 -21
- package/lib/server/modules/resource/index.js +184 -213
- package/lib/server/modules/resource/types.js +33 -42
- package/lib/server/modules/schedule/index.js +123 -135
- package/lib/server/modules/schedule/types.js +21 -14
- package/lib/server/modules/schedule/utils.js +163 -334
- package/lib/server/types.js +16 -4
- package/lib/server/utils/index.js +23 -25
- package/lib/server/utils/product.js +139 -196
- package/lib/server/utils/schedule.js +41 -34
- package/lib/server/utils/small-ticket.js +456 -478
- package/lib/server/utils/time.js +49 -40
- package/lib/solution/BaseSales/index.js +1016 -850
- package/lib/solution/BaseSales/types.js +37 -41
- package/lib/solution/BaseSales/utils/cartPromotion.js +460 -611
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +105 -85
- package/lib/solution/BaseSales/utils/quotationPrice.js +114 -56
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +143 -102
- package/lib/solution/BaseSales/utils.js +140 -155
- 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 +1 -1
- package/lib/solution/BookingTicket/index.js +459 -543
- package/lib/solution/BookingTicket/types.js +77 -99
- package/lib/solution/BookingTicket/utils/addProductDecision.js +184 -219
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +89 -58
- package/lib/solution/BookingTicket/utils/bookingStatus.js +78 -107
- package/lib/solution/BookingTicket/utils/cartView.js +94 -110
- package/lib/solution/BookingTicket/utils/exampleData.js +0 -185
- package/lib/solution/BookingTicket/utils/orderCustomer.js +41 -18
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +86 -219
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +93 -144
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +91 -79
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +41 -54
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +81 -84
- package/lib/solution/BookingTicket/utils/scan/index.js +104 -98
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +43 -90
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +64 -52
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +58 -56
- package/lib/solution/BuyTickets/index.js +70 -67
- package/lib/solution/BuyTickets/types.js +38 -22
- package/lib/solution/Checkout/index.js +1158 -1451
- 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 +460 -493
- 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.js +320 -317
- package/lib/solution/Sales/types.js +33 -27
- package/lib/solution/ScanOrder/index.js +862 -831
- package/lib/solution/ScanOrder/types.js +34 -33
- package/lib/solution/ScanOrder/utils.js +371 -406
- 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.js +405 -379
- package/lib/solution/UnifiedBookingSales/types.js +31 -12
- package/lib/solution/VenueBooking/index.d.ts +3 -31
- package/lib/solution/VenueBooking/index.js +916 -967
- 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.js +107 -94
- 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.js +41 -124
- package/lib/store/createStore.js +29 -32
- package/lib/types/index.d.ts +1 -1
- 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/VenueBooking/utils/smartPricing.d.ts +0 -70
- package/dist/solution/VenueBooking/utils/smartPricing.js +0 -233
- package/lib/solution/VenueBooking/utils/smartPricing.d.ts +0 -70
- package/lib/solution/VenueBooking/utils/smartPricing.js +0 -192
|
@@ -1,173 +1,39 @@
|
|
|
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/solution/BookingTicket/utils/resolveBestAddTimePlan.ts
|
|
20
|
+
var resolveBestAddTimePlan_exports = {};
|
|
21
|
+
__export(resolveBestAddTimePlan_exports, {
|
|
22
|
+
ADD_TIME_UNIT_MINUTES: () => ADD_TIME_UNIT_MINUTES,
|
|
23
|
+
buildAddTimeCandidates: () => buildAddTimeCandidates,
|
|
24
|
+
resolveBestAddTimePlan: () => resolveBestAddTimePlan
|
|
5
25
|
});
|
|
6
|
-
exports
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 计算指定加时时长下的最优购买方案。
|
|
11
|
-
*
|
|
12
|
-
* 输入的商品结构来自旧版 booking addTimeModal 的加时商品配置映射:
|
|
13
|
-
* - `minMinutes`:该商品第一次可选择的最小时长。
|
|
14
|
-
* - `maxMinutes`:单次购买该商品可覆盖的最大时长。
|
|
15
|
-
* - `unitMinutes`:超过最小时长后,每次递增的时长切片。
|
|
16
|
-
* - `price`:每个 `unitMinutes` 切片的价格。
|
|
17
|
-
* - `unlimited`:固定价格商品,可覆盖任意目标时长。
|
|
18
|
-
*
|
|
19
|
-
* 算法流程:
|
|
20
|
-
*
|
|
21
|
-
* ```
|
|
22
|
-
* products
|
|
23
|
-
* |
|
|
24
|
-
* v
|
|
25
|
-
* 将每个普通商品展开成有限候选档位
|
|
26
|
-
* 商品 A: min=30, max=60, unit=10, price=10
|
|
27
|
-
* => 30m/$30, 40m/$40, 50m/$50, 60m/$60
|
|
28
|
-
* |
|
|
29
|
-
* v
|
|
30
|
-
* 单独加入 unlimited 候选
|
|
31
|
-
* unlimited 商品 => targetMinutes / 固定商品价格
|
|
32
|
-
* |
|
|
33
|
-
* v
|
|
34
|
-
* 按 covered minutes 做动态规划
|
|
35
|
-
* dp[minutes] = 正好覆盖 `minutes` 时的最低价候选组合
|
|
36
|
-
* |
|
|
37
|
-
* v
|
|
38
|
-
* 从所有 dp[minutes >= targetMinutes] 中挑选最优方案
|
|
39
|
-
* ```
|
|
40
|
-
*
|
|
41
|
-
* 候选档位生成刻意对齐旧版 addTimeModal:
|
|
42
|
-
* `totalPrice = minutes / unitMinutes * price`.
|
|
43
|
-
* 例如 `minMinutes=30`、`unitMinutes=10`、`price=10` 时:
|
|
44
|
-
* - 30 分钟 => 30 / 10 * 10 = 30
|
|
45
|
-
* - 60 分钟 => 60 / 10 * 10 = 60
|
|
46
|
-
*
|
|
47
|
-
* 目标时长不要求精确命中某个档位,只需要覆盖即可。例如目标是 51 分钟时,
|
|
48
|
-
* 60 分钟档位可以作为候选。动态规划也允许跨商品组合,例如商品 A 的 30m
|
|
49
|
-
* 加上商品 B 的 30m。最终方案按以下优先级比较:
|
|
50
|
-
* 1. 总价更低;
|
|
51
|
-
* 2. 超出时长更少,即 `coveredMinutes - targetMinutes` 更小;
|
|
52
|
-
* 3. 结果行数更少,让购买方案尽量简单。
|
|
53
|
-
*
|
|
54
|
-
* 典型匹配示例:
|
|
55
|
-
*
|
|
56
|
-
* 示例 1:精确命中,直接选择更便宜的商品。
|
|
57
|
-
* ```
|
|
58
|
-
* target = 30
|
|
59
|
-
* 商品 A: min=30, max=30, unit=30, price=10 => 30m/$10
|
|
60
|
-
* 商品 B: min=30, max=30, unit=30, price=8 => 30m/$8
|
|
61
|
-
* 结果:选择商品 B,coveredMinutes=30,totalPrice=8
|
|
62
|
-
* ```
|
|
63
|
-
*
|
|
64
|
-
* 示例 2:目标时长落在两个档位之间,向上选择可覆盖的档位。
|
|
65
|
-
* ```
|
|
66
|
-
* target = 51
|
|
67
|
-
* 商品 A: min=30, max=120, unit=10, price=10
|
|
68
|
-
* 候选:30m/$30, 40m/$40, 50m/$50, 60m/$60 ...
|
|
69
|
-
* 结果:50m 不足以覆盖 51m,因此选择 60m/$60
|
|
70
|
-
* ```
|
|
71
|
-
*
|
|
72
|
-
* 示例 3:不同商品都能覆盖同一目标时长,比较最终价格。
|
|
73
|
-
* ```
|
|
74
|
-
* target = 51
|
|
75
|
-
* 商品 A: min=30, max=120, unit=10, price=10 => 60m/$60
|
|
76
|
-
* 商品 B: min=30, max=120, unit=30, price=25 => 60m/$50
|
|
77
|
-
* 结果:两个方案都覆盖 60m,但商品 B 更便宜,所以选择商品 B
|
|
78
|
-
* ```
|
|
79
|
-
*
|
|
80
|
-
* 示例 4:允许跨商品组合,组合价更低时会选择组合。
|
|
81
|
-
* ```
|
|
82
|
-
* target = 90
|
|
83
|
-
* 商品 A: min=30, max=30, unit=30, price=5 => 30m/$5
|
|
84
|
-
* 商品 B: min=60, max=60, unit=60, price=8 => 60m/$8
|
|
85
|
-
* 商品 C: min=90, max=90, unit=90, price=20 => 90m/$20
|
|
86
|
-
* 结果:商品 A + 商品 B = 90m/$13,比商品 C 更便宜
|
|
87
|
-
* ```
|
|
88
|
-
*
|
|
89
|
-
* 示例 5:允许重复购买同一个候选档位。
|
|
90
|
-
* ```
|
|
91
|
-
* target = 90
|
|
92
|
-
* 商品 A: min=30, max=30, unit=30, price=5 => 30m/$5
|
|
93
|
-
* 结果:购买 3 份商品 A,coveredMinutes=90,totalPrice=15,
|
|
94
|
-
* lines 中会合并为一行:product_add_schedule_time=30,num=3
|
|
95
|
-
* ```
|
|
96
|
-
*
|
|
97
|
-
* 示例 6:unlimited 可以覆盖任意目标时长,并参与价格比较。
|
|
98
|
-
* ```
|
|
99
|
-
* target = 180
|
|
100
|
-
* 商品 A: min=30, max=120, unit=30, price=10
|
|
101
|
-
* 商品 B: unlimited=true, price=35
|
|
102
|
-
* 普通商品可以组合成 180m,例如 120m + 60m,总价 $60
|
|
103
|
-
* unlimited 商品固定 $35
|
|
104
|
-
* 结果:选择 unlimited 商品,coveredMinutes=180,totalPrice=35
|
|
105
|
-
* ```
|
|
106
|
-
*
|
|
107
|
-
* 示例 7:unlimited 不一定优先,普通商品更便宜时选择普通商品。
|
|
108
|
-
* ```
|
|
109
|
-
* target = 60
|
|
110
|
-
* 商品 A: min=30, max=60, unit=30, price=10 => 60m/$20
|
|
111
|
-
* 商品 B: unlimited=true, price=50
|
|
112
|
-
* 结果:选择商品 A 的 60m 档位
|
|
113
|
-
* ```
|
|
114
|
-
*
|
|
115
|
-
* 示例 8:价格相同,优先选择超出时长更少的方案。
|
|
116
|
-
* ```
|
|
117
|
-
* target = 51
|
|
118
|
-
* 商品 A: 60m/$20
|
|
119
|
-
* 商品 B: 90m/$20
|
|
120
|
-
* 结果:选择 60m,因为 overage=9,小于 90m 的 overage=39
|
|
121
|
-
* ```
|
|
122
|
-
*
|
|
123
|
-
* 示例 9:价格和覆盖时长都相同,优先选择结果行数更少的方案。
|
|
124
|
-
* ```
|
|
125
|
-
* target = 60
|
|
126
|
-
* 商品 A: 60m/$20
|
|
127
|
-
* 商品 B: 30m/$10
|
|
128
|
-
* 商品 C: 30m/$10
|
|
129
|
-
* 结果:商品 A 单行方案和 B+C 两行方案价格、时长相同,选择商品 A
|
|
130
|
-
* ```
|
|
131
|
-
*
|
|
132
|
-
* 示例 10:没有任何有效商品时返回 `NO_PRODUCTS`。
|
|
133
|
-
* ```
|
|
134
|
-
* target = 30
|
|
135
|
-
* products = []
|
|
136
|
-
* 结果:available=false,unavailableReason='NO_PRODUCTS'
|
|
137
|
-
* ```
|
|
138
|
-
*
|
|
139
|
-
* 示例 11:有商品但没有可用候选时返回 `NO_COVERAGE`。
|
|
140
|
-
* ```
|
|
141
|
-
* target = 30
|
|
142
|
-
* 商品 A: price=0,或 minMinutes 缺失/无效
|
|
143
|
-
* 结果:available=false,unavailableReason='NO_COVERAGE'
|
|
144
|
-
* ```
|
|
145
|
-
*
|
|
146
|
-
* 示例 12:目标时长小于等于 0 时无需购买。
|
|
147
|
-
* ```
|
|
148
|
-
* target = 0
|
|
149
|
-
* 结果:available=true,coveredMinutes=0,totalPrice=0,lines=[]
|
|
150
|
-
* ```
|
|
151
|
-
*
|
|
152
|
-
* 搜索边界:
|
|
153
|
-
* 有限档位只需要搜索到 `targetMinutes + maxFiniteCandidateMinutes`。
|
|
154
|
-
* 这里的 `maxFiniteCandidateMinutes` 是所有普通候选档位里的最大时长。
|
|
155
|
-
* 例如目标是 51 分钟,最大普通档位是 120 分钟,则只搜索到 171 分钟。
|
|
156
|
-
* 如果某个组合覆盖了 180 分钟,那么移除其中任意一个普通档位后,剩余时长
|
|
157
|
-
* 仍然有机会覆盖 51 分钟,而且价格一定不会更高,所以 180 分钟这个组合不
|
|
158
|
-
* 可能是最优解。
|
|
159
|
-
*/
|
|
160
|
-
|
|
161
|
-
const ADD_TIME_UNIT_MINUTES = exports.ADD_TIME_UNIT_MINUTES = [10, 15, 20, 30, 45, 60];
|
|
162
|
-
const toPositiveNumber = value => {
|
|
26
|
+
module.exports = __toCommonJS(resolveBestAddTimePlan_exports);
|
|
27
|
+
var ADD_TIME_UNIT_MINUTES = [10, 15, 20, 30, 45, 60];
|
|
28
|
+
var toPositiveNumber = (value) => {
|
|
163
29
|
const n = Number(value);
|
|
164
30
|
return Number.isFinite(n) && n > 0 ? n : null;
|
|
165
31
|
};
|
|
166
|
-
|
|
32
|
+
var normalizeTargetMinutes = (minutes) => {
|
|
167
33
|
const n = Number(minutes);
|
|
168
34
|
return Number.isFinite(n) ? Math.max(0, Math.ceil(n)) : 0;
|
|
169
35
|
};
|
|
170
|
-
|
|
36
|
+
var gcd = (a, b) => {
|
|
171
37
|
let x = Math.abs(a);
|
|
172
38
|
let y = Math.abs(b);
|
|
173
39
|
while (y !== 0) {
|
|
@@ -177,28 +43,26 @@ const gcd = (a, b) => {
|
|
|
177
43
|
}
|
|
178
44
|
return x;
|
|
179
45
|
};
|
|
180
|
-
|
|
181
|
-
return candidates.reduce(
|
|
46
|
+
var getDpStepMinutes = (candidates) => {
|
|
47
|
+
return candidates.reduce(
|
|
48
|
+
(current, candidate) => gcd(current, candidate.product_add_schedule_time),
|
|
49
|
+
0
|
|
50
|
+
) || 1;
|
|
182
51
|
};
|
|
183
|
-
|
|
184
|
-
if (!left)
|
|
185
|
-
|
|
186
|
-
// 第一优先级:总价更低。例:同样覆盖 60 分钟,$50 优先于 $60。
|
|
52
|
+
var comparePlans = (left, right) => {
|
|
53
|
+
if (!left)
|
|
54
|
+
return right;
|
|
187
55
|
if (right.totalPrice !== left.totalPrice) {
|
|
188
56
|
return right.totalPrice < left.totalPrice ? right : left;
|
|
189
57
|
}
|
|
190
|
-
|
|
191
|
-
// 第二优先级:价格相同时,选择超出目标更少的方案。例:target=51 时,60m 优先于 90m。
|
|
192
58
|
const leftOverage = left.coveredMinutes - left.targetMinutes;
|
|
193
59
|
const rightOverage = right.coveredMinutes - right.targetMinutes;
|
|
194
60
|
if (rightOverage !== leftOverage) {
|
|
195
61
|
return rightOverage < leftOverage ? right : left;
|
|
196
62
|
}
|
|
197
|
-
|
|
198
|
-
// 第三优先级:价格和超出时长都相同时,选择购买行数更少的方案,减少下单复杂度。
|
|
199
63
|
return right.lines.length < left.lines.length ? right : left;
|
|
200
64
|
};
|
|
201
|
-
|
|
65
|
+
var toPlanLine = (candidate) => ({
|
|
202
66
|
product_id: candidate.product_id,
|
|
203
67
|
product_title: candidate.product_title,
|
|
204
68
|
product_add_schedule_time: Number.isFinite(candidate.product_add_schedule_time) ? candidate.product_add_schedule_time : 0,
|
|
@@ -206,11 +70,10 @@ const toPlanLine = candidate => ({
|
|
|
206
70
|
price: candidate.price,
|
|
207
71
|
_originalProduct: candidate._originalProduct
|
|
208
72
|
});
|
|
209
|
-
|
|
210
|
-
const map = new Map();
|
|
73
|
+
var mergePlanLines = (candidates) => {
|
|
74
|
+
const map = /* @__PURE__ */ new Map();
|
|
211
75
|
for (const candidate of candidates) {
|
|
212
|
-
|
|
213
|
-
const key = `${candidate.product_id}-${candidate.product_add_schedule_time}-${candidate.unlimited ? 'u' : 'n'}`;
|
|
76
|
+
const key = `${candidate.product_id}-${candidate.product_add_schedule_time}-${candidate.unlimited ? "u" : "n"}`;
|
|
214
77
|
const existing = map.get(key);
|
|
215
78
|
if (existing) {
|
|
216
79
|
existing.num += candidate.num;
|
|
@@ -220,13 +83,17 @@ const mergePlanLines = candidates => {
|
|
|
220
83
|
}
|
|
221
84
|
return Array.from(map.values());
|
|
222
85
|
};
|
|
223
|
-
|
|
224
|
-
|
|
86
|
+
var sumPlanLineMinutes = (lines) => lines.reduce(
|
|
87
|
+
(total, line) => total + line.product_add_schedule_time * line.num,
|
|
88
|
+
0
|
|
89
|
+
);
|
|
90
|
+
var restoreDpCandidates = (dp, finiteCandidates, index) => {
|
|
225
91
|
const candidates = [];
|
|
226
92
|
let currentIndex = index;
|
|
227
93
|
while (currentIndex > 0) {
|
|
228
94
|
const current = dp[currentIndex];
|
|
229
|
-
if (!current || current.candidateIndex < 0)
|
|
95
|
+
if (!current || current.candidateIndex < 0)
|
|
96
|
+
break;
|
|
230
97
|
candidates.push(finiteCandidates[current.candidateIndex]);
|
|
231
98
|
currentIndex = current.prevIndex;
|
|
232
99
|
}
|
|
@@ -235,11 +102,10 @@ const restoreDpCandidates = (dp, finiteCandidates, index) => {
|
|
|
235
102
|
function buildAddTimeCandidates(products) {
|
|
236
103
|
const candidates = [];
|
|
237
104
|
for (const product of products) {
|
|
238
|
-
// 价格无效的商品无法参与比价,直接跳过,避免生成 0 元或 NaN 候选。
|
|
239
105
|
const price = toPositiveNumber(product.price);
|
|
240
|
-
if (price == null)
|
|
106
|
+
if (price == null)
|
|
107
|
+
continue;
|
|
241
108
|
if (product.unlimited) {
|
|
242
|
-
// unlimited 是固定价商品,可覆盖任意目标时长;这里先用 Infinity 标记,最终按 targetMinutes 输出。
|
|
243
109
|
candidates.push({
|
|
244
110
|
product_id: product.id,
|
|
245
111
|
product_title: product.title,
|
|
@@ -252,18 +118,12 @@ function buildAddTimeCandidates(products) {
|
|
|
252
118
|
});
|
|
253
119
|
continue;
|
|
254
120
|
}
|
|
255
|
-
|
|
256
|
-
// 普通商品必须有有效的起购时长,否则无法知道第一档应该从哪里开始。
|
|
257
121
|
const minMinutes = toPositiveNumber(product.minMinutes);
|
|
258
|
-
if (minMinutes == null)
|
|
259
|
-
|
|
260
|
-
// 旧版配置中 max/unit 可能缺失:缺失时退化为只有 minMinutes 这一档。
|
|
122
|
+
if (minMinutes == null)
|
|
123
|
+
continue;
|
|
261
124
|
const maxMinutes = toPositiveNumber(product.maxMinutes) ?? minMinutes;
|
|
262
125
|
const unitMinutes = toPositiveNumber(product.unitMinutes) ?? minMinutes;
|
|
263
|
-
// 当 maxMinutes 小于 minMinutes 时,至少保留 minMinutes 这一档,避免错误配置导致无候选。
|
|
264
126
|
const safeMax = Math.max(minMinutes, maxMinutes);
|
|
265
|
-
|
|
266
|
-
// 将一个商品展开为多个可购买档位。例:min=30,max=60,unit=10 => 30/40/50/60 四个候选。
|
|
267
127
|
for (let minutes = minMinutes; minutes <= safeMax; minutes += unitMinutes) {
|
|
268
128
|
candidates.push({
|
|
269
129
|
product_id: product.id,
|
|
@@ -279,10 +139,8 @@ function buildAddTimeCandidates(products) {
|
|
|
279
139
|
return candidates;
|
|
280
140
|
}
|
|
281
141
|
function resolveBestAddTimePlan(products, targetMinutes) {
|
|
282
|
-
// 目标时长按分钟向上取整,避免 50.2 分钟被当成 50 分钟而覆盖不足。
|
|
283
142
|
const normalizedTarget = normalizeTargetMinutes(targetMinutes);
|
|
284
143
|
if (normalizedTarget <= 0) {
|
|
285
|
-
// 目标时长为 0 或负数时表示无需加时,直接返回 0 元可用方案。
|
|
286
144
|
return {
|
|
287
145
|
available: true,
|
|
288
146
|
targetMinutes: 0,
|
|
@@ -294,7 +152,7 @@ function resolveBestAddTimePlan(products, targetMinutes) {
|
|
|
294
152
|
if (!products.length) {
|
|
295
153
|
return {
|
|
296
154
|
available: false,
|
|
297
|
-
unavailableReason:
|
|
155
|
+
unavailableReason: "NO_PRODUCTS",
|
|
298
156
|
targetMinutes: normalizedTarget,
|
|
299
157
|
coveredMinutes: 0,
|
|
300
158
|
totalPrice: 0,
|
|
@@ -302,19 +160,23 @@ function resolveBestAddTimePlan(products, targetMinutes) {
|
|
|
302
160
|
};
|
|
303
161
|
}
|
|
304
162
|
const candidates = buildAddTimeCandidates(products);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const maxFiniteMinutes = Math.max(
|
|
163
|
+
const finiteCandidates = candidates.filter(
|
|
164
|
+
(item) => Number.isFinite(item.product_add_schedule_time)
|
|
165
|
+
);
|
|
166
|
+
const unlimitedCandidates = candidates.filter((item) => item.unlimited);
|
|
167
|
+
const maxFiniteMinutes = Math.max(
|
|
168
|
+
0,
|
|
169
|
+
...finiteCandidates.map((item) => item.product_add_schedule_time)
|
|
170
|
+
);
|
|
310
171
|
const searchLimit = normalizedTarget + maxFiniteMinutes;
|
|
311
172
|
let best = null;
|
|
312
173
|
for (const unlimited of unlimitedCandidates) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
174
|
+
const lines = [
|
|
175
|
+
toPlanLine({
|
|
176
|
+
...unlimited,
|
|
177
|
+
product_add_schedule_time: normalizedTarget
|
|
178
|
+
})
|
|
179
|
+
];
|
|
318
180
|
best = comparePlans(best, {
|
|
319
181
|
available: true,
|
|
320
182
|
targetMinutes: normalizedTarget,
|
|
@@ -327,9 +189,9 @@ function resolveBestAddTimePlan(products, targetMinutes) {
|
|
|
327
189
|
const stepMinutes = getDpStepMinutes(finiteCandidates);
|
|
328
190
|
const searchLimitIndex = Math.ceil(searchLimit / stepMinutes);
|
|
329
191
|
const targetIndex = Math.ceil(normalizedTarget / stepMinutes);
|
|
330
|
-
const finiteCandidateSteps = finiteCandidates.map(
|
|
331
|
-
|
|
332
|
-
|
|
192
|
+
const finiteCandidateSteps = finiteCandidates.map(
|
|
193
|
+
(candidate) => candidate.product_add_schedule_time / stepMinutes
|
|
194
|
+
);
|
|
333
195
|
const dp = [];
|
|
334
196
|
dp[0] = {
|
|
335
197
|
price: 0,
|
|
@@ -339,18 +201,16 @@ function resolveBestAddTimePlan(products, targetMinutes) {
|
|
|
339
201
|
};
|
|
340
202
|
for (let index = 0; index <= searchLimitIndex; index += 1) {
|
|
341
203
|
const current = dp[index];
|
|
342
|
-
|
|
343
|
-
|
|
204
|
+
if (!current)
|
|
205
|
+
continue;
|
|
344
206
|
for (let candidateIndex = 0; candidateIndex < finiteCandidates.length; candidateIndex += 1) {
|
|
345
|
-
// 尝试在当前组合后再买一个候选档位,形成新的覆盖时长。
|
|
346
207
|
const nextIndex = index + finiteCandidateSteps[candidateIndex];
|
|
347
|
-
if (nextIndex > searchLimitIndex)
|
|
208
|
+
if (nextIndex > searchLimitIndex)
|
|
209
|
+
continue;
|
|
348
210
|
const candidate = finiteCandidates[candidateIndex];
|
|
349
211
|
const nextPrice = current.price + candidate.totalPrice;
|
|
350
212
|
const nextItemCount = current.itemCount + 1;
|
|
351
213
|
const prev = dp[nextIndex];
|
|
352
|
-
|
|
353
|
-
// 更新 dp[nextIndex]:价格更低则替换;价格相同则用更少档位,便于后续输出更简单的方案。
|
|
354
214
|
if (!prev || nextPrice < prev.price || nextPrice === prev.price && nextItemCount < prev.itemCount) {
|
|
355
215
|
dp[nextIndex] = {
|
|
356
216
|
price: nextPrice,
|
|
@@ -361,12 +221,13 @@ function resolveBestAddTimePlan(products, targetMinutes) {
|
|
|
361
221
|
}
|
|
362
222
|
}
|
|
363
223
|
}
|
|
364
|
-
|
|
365
|
-
// 目标不要求精确命中:从 target 到 searchLimit 的所有可达方案里选最优。
|
|
366
224
|
for (let index = targetIndex; index <= searchLimitIndex; index += 1) {
|
|
367
225
|
const current = dp[index];
|
|
368
|
-
if (!current)
|
|
369
|
-
|
|
226
|
+
if (!current)
|
|
227
|
+
continue;
|
|
228
|
+
const lines = mergePlanLines(
|
|
229
|
+
restoreDpCandidates(dp, finiteCandidates, index)
|
|
230
|
+
);
|
|
370
231
|
best = comparePlans(best, {
|
|
371
232
|
available: true,
|
|
372
233
|
targetMinutes: normalizedTarget,
|
|
@@ -378,10 +239,16 @@ function resolveBestAddTimePlan(products, targetMinutes) {
|
|
|
378
239
|
}
|
|
379
240
|
return best ?? {
|
|
380
241
|
available: false,
|
|
381
|
-
unavailableReason:
|
|
242
|
+
unavailableReason: "NO_COVERAGE",
|
|
382
243
|
targetMinutes: normalizedTarget,
|
|
383
244
|
coveredMinutes: 0,
|
|
384
245
|
totalPrice: 0,
|
|
385
246
|
lines: []
|
|
386
247
|
};
|
|
387
|
-
}
|
|
248
|
+
}
|
|
249
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
250
|
+
0 && (module.exports = {
|
|
251
|
+
ADD_TIME_UNIT_MINUTES,
|
|
252
|
+
buildAddTimeCandidates,
|
|
253
|
+
resolveBestAddTimePlan
|
|
254
|
+
});
|