@pisell/pisellos 2.3.74 → 2.3.76
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 +6 -10
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/model/strategy/adapter/walletPass/example.js +3 -26
- package/dist/model/strategy/strategy-example.js +5 -19
- package/dist/modules/Cart/index.js +0 -3
- package/dist/modules/Cart/utils/cartProduct.js +0 -1
- package/dist/modules/Date/index.js +1 -5
- package/dist/modules/Discount/index.js +2 -4
- package/dist/modules/OpenData/index.js +0 -2
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +75 -91
- package/dist/modules/Order/types.d.ts +3 -1
- package/dist/modules/Payment/index.js +97 -162
- package/dist/modules/Rules/index.js +1 -4
- package/dist/modules/Schedule/index.js +0 -1
- package/dist/modules/Schedule/utils.js +0 -1
- package/dist/modules/Step/index.js +0 -1
- package/dist/plugins/request.js +1 -4
- package/dist/plugins/window.js +2 -6
- package/dist/server/index.js +97 -129
- package/dist/server/modules/menu/index.js +32 -41
- package/dist/server/modules/order/index.js +2 -4
- package/dist/server/modules/products/index.js +24 -42
- package/dist/server/modules/quotation/index.js +29 -38
- package/dist/server/modules/resource/index.js +3 -4
- package/dist/server/modules/schedule/index.js +27 -35
- package/dist/server/utils/product.js +0 -1
- package/dist/solution/BaseSales/index.js +100 -72
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +5 -0
- package/dist/solution/BaseSales/utils/cartPromotion.js +15 -6
- package/dist/solution/BookingByStep/index.js +7 -59
- package/dist/solution/BookingByStep/utils/capacity.js +1 -11
- package/dist/solution/BookingByStep/utils/resources.js +1 -3
- package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
- package/dist/solution/BookingTicket/index.js +0 -2
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +6 -7
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
- package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
- package/dist/solution/BuyTickets/index.js +9 -12
- package/dist/solution/Checkout/index.js +177 -252
- package/dist/solution/Checkout/utils/index.js +4 -16
- package/dist/solution/RegisterAndLogin/index.js +30 -76
- package/dist/solution/ScanOrder/index.js +50 -60
- package/dist/solution/ShopDiscount/index.js +2 -7
- package/dist/solution/VenueBooking/index.js +45 -55
- package/dist/utils/task.js +15 -18
- package/dist/utils/watch.js +0 -1
- package/lib/apis/picoding.js +2 -0
- package/lib/core/index.js +134 -134
- package/lib/effects/index.js +46 -57
- package/lib/index.js +82 -49
- package/lib/model/index.js +14 -21
- package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
- package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
- package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
- package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
- package/lib/model/strategy/adapter/index.js +100 -64
- package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
- package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
- package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
- package/lib/model/strategy/adapter/itemRule/index.js +83 -57
- package/lib/model/strategy/adapter/itemRule/type.js +97 -36
- package/lib/model/strategy/adapter/promotion/adapter.js +91 -69
- package/lib/model/strategy/adapter/promotion/evaluator.js +444 -310
- package/lib/model/strategy/adapter/promotion/examples.js +222 -234
- package/lib/model/strategy/adapter/promotion/index.js +1 -0
- package/lib/model/strategy/adapter/promotion/type.js +243 -36
- package/lib/model/strategy/adapter/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -150
- package/lib/model/strategy/adapter/walletPass/example.js +217 -190
- package/lib/model/strategy/adapter/walletPass/index.js +75 -51
- package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
- package/lib/model/strategy/adapter/walletPass/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/utils.js +588 -378
- package/lib/model/strategy/engine.js +270 -168
- package/lib/model/strategy/index.js +49 -34
- package/lib/model/strategy/strategy-example.js +243 -239
- package/lib/model/strategy/type.js +100 -40
- package/lib/modules/Account/index.js +39 -53
- package/lib/modules/Account/types.js +20 -33
- package/lib/modules/AccountList/index.js +116 -154
- package/lib/modules/AccountList/types.js +30 -31
- package/lib/modules/AccountList/utils.js +18 -30
- package/lib/modules/BaseModule.js +23 -42
- package/lib/modules/BookingContext/index.js +158 -136
- package/lib/modules/BookingContext/types.js +46 -32
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +138 -146
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +78 -83
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +170 -150
- package/lib/modules/BookingContext/utils/flexible.js +38 -55
- package/lib/modules/BookingContext/utils/formatResourceList.js +19 -34
- package/lib/modules/BookingContext/utils/index.js +124 -41
- package/lib/modules/BookingContext/utils/noResource.js +58 -70
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +14 -41
- package/lib/modules/BookingContext/utils/productExtend.js +202 -155
- package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
- package/lib/modules/BookingContext/utils/resourceSelection.js +19 -41
- package/lib/modules/BookingContext/utils/resources.js +209 -167
- package/lib/modules/BookingContext/utils/serviceTimes.js +115 -116
- package/lib/modules/BookingContext/utils/timeSlices.js +76 -86
- package/lib/modules/Cart/index.js +170 -124
- package/lib/modules/Cart/types.js +46 -51
- package/lib/modules/Cart/utils/cartAccount.js +40 -39
- package/lib/modules/Cart/utils/cartDate.js +56 -61
- package/lib/modules/Cart/utils/cartDiscount.js +28 -33
- package/lib/modules/Cart/utils/cartNote.js +27 -32
- package/lib/modules/Cart/utils/cartProduct.js +321 -251
- package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
- package/lib/modules/Cart/utils/cartResource.js +70 -78
- package/lib/modules/Cart/utils/changePrice.js +22 -50
- package/lib/modules/Cart/utils/index.js +106 -48
- package/lib/modules/Customer/constants.js +13 -34
- package/lib/modules/Customer/index.js +235 -172
- package/lib/modules/Customer/types.js +38 -35
- package/lib/modules/Date/index.js +116 -115
- package/lib/modules/Date/types.js +16 -28
- package/lib/modules/Date/utils.js +174 -123
- package/lib/modules/Discount/index.js +122 -127
- package/lib/modules/Discount/types.js +9 -31
- package/lib/modules/Guests/index.js +30 -56
- package/lib/modules/Guests/types.js +23 -33
- package/lib/modules/Holder/index.js +209 -189
- package/lib/modules/Holder/types.js +4 -16
- package/lib/modules/Holder/utils.js +20 -49
- package/lib/modules/OpenData/index.js +70 -76
- package/lib/modules/OpenData/types.js +4 -16
- package/lib/modules/OpenData/utils.js +44 -78
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +1733 -2121
- package/lib/modules/Order/payment-utils.js +77 -120
- package/lib/modules/Order/types.d.ts +3 -1
- package/lib/modules/Order/types.js +88 -35
- package/lib/modules/Order/utils/bundleDiscountHydration.js +41 -74
- package/lib/modules/Order/utils/discountProductLineIdentity.js +142 -100
- package/lib/modules/Order/utils/manualProductDiscount.js +124 -123
- package/lib/modules/Order/utils/orderCollectionIdentity.js +184 -244
- package/lib/modules/Order/utils.js +814 -647
- package/lib/modules/Payment/cash.js +20 -33
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
- package/lib/modules/Payment/eftpos.js +16 -30
- package/lib/modules/Payment/index.js +532 -399
- package/lib/modules/Payment/mx51.js +1 -0
- package/lib/modules/Payment/types.js +230 -108
- package/lib/modules/Payment/utils.js +52 -51
- package/lib/modules/Payment/walletpass.js +485 -660
- package/lib/modules/Product/index.js +51 -46
- package/lib/modules/Product/types.js +4 -16
- package/lib/modules/Product/utils.js +32 -33
- package/lib/modules/ProductList/index.js +113 -123
- package/lib/modules/ProductList/types.js +9 -31
- package/lib/modules/Quotation/index.js +81 -118
- package/lib/modules/Quotation/types.js +4 -16
- package/lib/modules/Resource/index.js +27 -59
- package/lib/modules/Resource/types.js +22 -32
- package/lib/modules/Resource/utils.js +30 -38
- package/lib/modules/ResourcePlanner/index.js +25 -23
- package/lib/modules/ResourcePlanner/localClock.js +54 -119
- package/lib/modules/ResourcePlanner/planner.js +589 -770
- package/lib/modules/ResourcePlanner/types.js +10 -29
- package/lib/modules/Rules/index.js +1218 -959
- package/lib/modules/Rules/types.js +17 -40
- package/lib/modules/SalesSummary/index.js +85 -90
- package/lib/modules/SalesSummary/types.js +4 -16
- package/lib/modules/SalesSummary/utils.js +355 -430
- package/lib/modules/ScanOrderLogger/index.js +59 -79
- package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
- package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
- package/lib/modules/ScanOrderLogger/types.js +4 -16
- package/lib/modules/Schedule/getDateIsInSchedule.js +334 -163
- package/lib/modules/Schedule/index.js +100 -114
- package/lib/modules/Schedule/type.js +4 -16
- package/lib/modules/Schedule/types.js +4 -16
- package/lib/modules/Schedule/utils.js +433 -291
- package/lib/modules/Step/index.js +40 -52
- package/lib/modules/Step/tyeps.js +4 -16
- package/lib/modules/Summary/index.js +66 -71
- package/lib/modules/Summary/types.js +4 -16
- package/lib/modules/Summary/utils.js +773 -418
- package/lib/modules/SurchargeList/index.js +46 -60
- package/lib/modules/SurchargeList/types.js +4 -16
- package/lib/modules/index.js +245 -63
- package/lib/plugins/app.js +4 -16
- package/lib/plugins/index.js +36 -25
- package/lib/plugins/request.js +137 -126
- package/lib/plugins/shopStore.js +4 -16
- package/lib/plugins/user.js +4 -16
- package/lib/plugins/window.js +171 -179
- package/lib/server/index.js +3050 -2665
- package/lib/server/modules/floor-plan/index.js +118 -134
- package/lib/server/modules/floor-plan/types.js +15 -30
- package/lib/server/modules/index.js +106 -68
- package/lib/server/modules/menu/index.js +142 -122
- package/lib/server/modules/menu/types.js +18 -31
- package/lib/server/modules/order/index.js +784 -1002
- package/lib/server/modules/order/types.js +122 -33
- package/lib/server/modules/order/utils/filterBookings.js +219 -194
- package/lib/server/modules/order/utils/filterOrders.js +118 -92
- package/lib/server/modules/payment/index.js +59 -83
- package/lib/server/modules/payment/types.js +4 -16
- package/lib/server/modules/products/index.js +583 -471
- package/lib/server/modules/products/types.js +44 -34
- package/lib/server/modules/quotation/index.js +137 -172
- package/lib/server/modules/quotation/types.js +21 -31
- package/lib/server/modules/resource/index.js +220 -186
- package/lib/server/modules/resource/types.js +42 -33
- package/lib/server/modules/schedule/index.js +135 -123
- package/lib/server/modules/schedule/types.js +14 -21
- package/lib/server/modules/schedule/utils.js +334 -163
- package/lib/server/types.js +4 -16
- package/lib/server/utils/index.js +25 -23
- package/lib/server/utils/product.js +196 -139
- package/lib/server/utils/schedule.js +34 -41
- package/lib/server/utils/small-ticket.js +479 -456
- package/lib/server/utils/time.js +40 -49
- package/lib/solution/BaseSales/index.js +1220 -1412
- package/lib/solution/BaseSales/types.js +42 -38
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +5 -0
- package/lib/solution/BaseSales/utils/cartPromotion.js +652 -498
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +85 -105
- package/lib/solution/BaseSales/utils/quotationPrice.js +56 -114
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +108 -145
- package/lib/solution/BaseSales/utils.js +158 -143
- package/lib/solution/BookingByStep/index.js +1527 -1340
- package/lib/solution/BookingByStep/types.js +40 -99
- package/lib/solution/BookingByStep/utils/capacity.js +192 -160
- package/lib/solution/BookingByStep/utils/products.js +42 -52
- package/lib/solution/BookingByStep/utils/resources.js +527 -330
- package/lib/solution/BookingByStep/utils/stock.js +65 -44
- package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
- package/lib/solution/BookingTicket/index.js +607 -522
- package/lib/solution/BookingTicket/types.js +99 -77
- package/lib/solution/BookingTicket/utils/addProductDecision.js +226 -189
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +58 -89
- package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -78
- package/lib/solution/BookingTicket/utils/cartView.js +114 -99
- package/lib/solution/BookingTicket/utils/exampleData.js +185 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.js +18 -41
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +219 -86
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +168 -116
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +79 -91
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +54 -41
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +84 -81
- package/lib/solution/BookingTicket/utils/scan/index.js +98 -104
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +52 -64
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +56 -58
- package/lib/solution/BookingTicket/utils/weighingProductSku.js +34 -48
- package/lib/solution/BuyTickets/index.js +67 -70
- package/lib/solution/BuyTickets/types.js +22 -38
- package/lib/solution/Checkout/index.js +1451 -1158
- package/lib/solution/Checkout/types.js +91 -61
- package/lib/solution/Checkout/utils/index.js +228 -156
- package/lib/solution/PlaceOrder/index.js +55 -0
- package/lib/solution/RegisterAndLogin/config.js +493 -460
- package/lib/solution/RegisterAndLogin/index.js +633 -630
- package/lib/solution/RegisterAndLogin/types.js +189 -76
- package/lib/solution/RegisterAndLogin/utils.js +183 -125
- package/lib/solution/Sales/index.js +328 -324
- package/lib/solution/Sales/types.js +27 -33
- package/lib/solution/ScanOrder/index.js +832 -864
- package/lib/solution/ScanOrder/types.js +33 -34
- package/lib/solution/ScanOrder/utils.js +409 -374
- package/lib/solution/ShopDiscount/index.js +226 -232
- package/lib/solution/ShopDiscount/types.js +15 -37
- package/lib/solution/ShopDiscount/utils.js +300 -172
- package/lib/solution/UnifiedBookingSales/index.js +1035 -1201
- package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.js +99 -159
- package/lib/solution/UnifiedBookingSales/types.js +10 -32
- package/lib/solution/VenueBooking/index.js +811 -879
- package/lib/solution/VenueBooking/types.js +19 -39
- package/lib/solution/VenueBooking/utils/dateSummary.js +27 -56
- package/lib/solution/VenueBooking/utils/resource.js +31 -54
- package/lib/solution/VenueBooking/utils/slotMerge.js +94 -107
- package/lib/solution/VenueBooking/utils/timeSlot.js +132 -132
- package/lib/solution/VenueBooking/utils.js +130 -67
- package/lib/solution/index.js +124 -41
- package/lib/store/createStore.js +32 -29
- package/lib/types/index.js +4 -16
- package/lib/utils/payment-number.js +26 -46
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +81 -47
- package/package.json +2 -1
|
@@ -1,115 +1,84 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
-
|
|
29
|
-
// src/solution/BookingByStep/index.ts
|
|
30
|
-
var BookingByStep_exports = {};
|
|
31
|
-
__export(BookingByStep_exports, {
|
|
32
|
-
BookingByStepImpl: () => BookingByStepImpl
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
33
5
|
});
|
|
34
|
-
|
|
35
|
-
var
|
|
36
|
-
var
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
var
|
|
40
|
-
var
|
|
41
|
-
var
|
|
42
|
-
var
|
|
43
|
-
var
|
|
44
|
-
var
|
|
45
|
-
var
|
|
46
|
-
var
|
|
47
|
-
var
|
|
48
|
-
var
|
|
49
|
-
var
|
|
50
|
-
var
|
|
51
|
-
var
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
6
|
+
exports.BookingByStepImpl = void 0;
|
|
7
|
+
var _BaseModule = require("../../modules/BaseModule");
|
|
8
|
+
var _types = require("./types");
|
|
9
|
+
var _utils = require("../../modules/Cart/utils");
|
|
10
|
+
var _products = require("./utils/products");
|
|
11
|
+
var _resources = require("./utils/resources");
|
|
12
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
13
|
+
var _isSameOrBefore = _interopRequireDefault(require("dayjs/plugin/isSameOrBefore"));
|
|
14
|
+
var _isSameOrAfter = _interopRequireDefault(require("dayjs/plugin/isSameOrAfter"));
|
|
15
|
+
var _utils2 = require("../../modules/Resource/utils");
|
|
16
|
+
var _lodashEs = require("lodash-es");
|
|
17
|
+
var _utils3 = require("../../modules/Schedule/utils");
|
|
18
|
+
var _utils4 = require("../../modules/Date/utils");
|
|
19
|
+
var _utils5 = require("../../modules/Product/utils");
|
|
20
|
+
var _timeslots = require("./utils/timeslots");
|
|
21
|
+
var _changePrice = require("../../modules/Cart/utils/changePrice");
|
|
22
|
+
var _capacity = require("./utils/capacity");
|
|
23
|
+
var _stock = require("./utils/stock");
|
|
24
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
25
|
+
_dayjs.default.extend(_isSameOrBefore.default);
|
|
26
|
+
_dayjs.default.extend(_isSameOrAfter.default);
|
|
27
|
+
class BookingByStepImpl extends _BaseModule.BaseModule {
|
|
28
|
+
defaultName = 'bookingByStep';
|
|
29
|
+
defaultVersion = '1.0.0';
|
|
30
|
+
isSolution = true;
|
|
31
|
+
request;
|
|
32
|
+
window;
|
|
33
|
+
shopStore;
|
|
34
|
+
store;
|
|
35
|
+
otherParams = {};
|
|
36
|
+
cacheId;
|
|
37
|
+
otherData = {}; // 提供给 UI 层的临时数据存储,会进缓存
|
|
38
|
+
platform; // 平台类型,用于判断是 PC / H5
|
|
39
|
+
|
|
64
40
|
async initialize(core, options) {
|
|
65
|
-
var _a, _b, _c, _d, _e;
|
|
66
41
|
this.core = core;
|
|
67
42
|
this.store = options.store || {};
|
|
68
43
|
this.otherParams = options.otherParams || {};
|
|
69
|
-
|
|
70
|
-
this.request = core.getPlugin(
|
|
71
|
-
this.window = core.getPlugin(
|
|
72
|
-
this.shopStore = core.getPlugin(
|
|
44
|
+
// 获取依赖的插件
|
|
45
|
+
this.request = core.getPlugin('request');
|
|
46
|
+
this.window = core.getPlugin('window');
|
|
47
|
+
this.shopStore = core.getPlugin('shopStore');
|
|
73
48
|
if (!this.request) {
|
|
74
|
-
throw new Error(
|
|
49
|
+
throw new Error('bookingByStep解决方案需要 request 插件支持');
|
|
75
50
|
}
|
|
76
51
|
if (!this.shopStore) {
|
|
77
|
-
throw new Error(
|
|
52
|
+
throw new Error('SummaryModule 需要 shopStore 插件支持');
|
|
78
53
|
}
|
|
54
|
+
|
|
55
|
+
// 如果有传 cacheid,默认需要收集上面这些模块里用户操作选中的数据
|
|
56
|
+
// 并且在上面 registerModule 的时候,读取 sessionStroage 里的数据,塞进默认值
|
|
79
57
|
let targetCacheData = {};
|
|
80
|
-
this.cacheId =
|
|
81
|
-
this.platform =
|
|
82
|
-
if (
|
|
58
|
+
this.cacheId = this.otherParams?.cacheId;
|
|
59
|
+
this.platform = this.otherParams?.platform;
|
|
60
|
+
if (this.otherParams?.cacheId) {
|
|
83
61
|
const sessionData = this.window.sessionStorage.getItem(this.name);
|
|
84
62
|
if (sessionData) {
|
|
85
63
|
const data = JSON.parse(sessionData);
|
|
64
|
+
// 匹配 cacheid,如果匹配不到,直接把 sessionData 清掉即可
|
|
65
|
+
// 如果匹配到了,则把 sessionData 里的数据按模块塞到 store 里去
|
|
86
66
|
targetCacheData = data[this.otherParams.cacheId];
|
|
87
|
-
this.otherData =
|
|
67
|
+
this.otherData = data[this.otherParams.cacheId]?.[this.name]?.['otherData'] || {};
|
|
88
68
|
}
|
|
89
69
|
}
|
|
90
|
-
const moduleArr = [
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"cart",
|
|
94
|
-
"schedule",
|
|
95
|
-
"summary",
|
|
96
|
-
"step",
|
|
97
|
-
"products",
|
|
98
|
-
"date",
|
|
99
|
-
"order"
|
|
100
|
-
];
|
|
101
|
-
moduleArr.forEach((step) => {
|
|
102
|
-
var _a2, _b2;
|
|
103
|
-
const targetModule = (0, import_types.createModule)(step, this.name);
|
|
70
|
+
const moduleArr = ['accountList', 'holder', 'cart', 'schedule', 'summary', 'step', 'products', 'date', 'order'];
|
|
71
|
+
moduleArr.forEach(step => {
|
|
72
|
+
const targetModule = (0, _types.createModule)(step, this.name);
|
|
104
73
|
if (targetModule) {
|
|
105
74
|
this.store[step] = targetModule;
|
|
106
75
|
this.core.registerModule(targetModule, {
|
|
107
|
-
initialState: targetCacheData
|
|
76
|
+
initialState: targetCacheData?.[targetModule.name],
|
|
108
77
|
otherParams: {
|
|
109
78
|
...this.otherParams,
|
|
110
79
|
fatherModule: this.name,
|
|
111
|
-
openCache:
|
|
112
|
-
cacheId:
|
|
80
|
+
openCache: this.otherParams?.cacheId ? true : false,
|
|
81
|
+
cacheId: this.otherParams?.cacheId
|
|
113
82
|
}
|
|
114
83
|
});
|
|
115
84
|
} else {
|
|
@@ -129,6 +98,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
129
98
|
step: this.store.step.getCurrentStep()
|
|
130
99
|
};
|
|
131
100
|
}
|
|
101
|
+
|
|
132
102
|
// step: 下一个
|
|
133
103
|
next() {
|
|
134
104
|
this.store.step.nextStep();
|
|
@@ -137,32 +107,38 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
137
107
|
back() {
|
|
138
108
|
this.store.step.prevStep();
|
|
139
109
|
}
|
|
110
|
+
|
|
140
111
|
// 跳转到指定步骤
|
|
141
112
|
gotoStep(index) {
|
|
142
113
|
this.store.step.gotoStep(index);
|
|
143
114
|
}
|
|
115
|
+
|
|
144
116
|
// 获取所有step
|
|
145
117
|
getStepList() {
|
|
146
118
|
return this.store.step.getStepList();
|
|
147
119
|
}
|
|
120
|
+
|
|
148
121
|
/**
|
|
149
122
|
* 添加step
|
|
150
123
|
*/
|
|
151
124
|
addStep(step, key) {
|
|
152
125
|
this.store.step.addStep(step, key);
|
|
153
126
|
}
|
|
127
|
+
|
|
154
128
|
/**
|
|
155
129
|
* 删除step
|
|
156
130
|
*/
|
|
157
131
|
removeStep(key) {
|
|
158
132
|
this.store.step.removeStep(key);
|
|
159
133
|
}
|
|
134
|
+
|
|
160
135
|
/**
|
|
161
136
|
* 更新step
|
|
162
137
|
*/
|
|
163
138
|
updateStep(key, step) {
|
|
164
139
|
this.store.step.updateStep(key, step);
|
|
165
140
|
}
|
|
141
|
+
|
|
166
142
|
/**
|
|
167
143
|
*
|
|
168
144
|
* 加载商品,然后导到商品列表里去
|
|
@@ -193,13 +169,15 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
193
169
|
schedule_date,
|
|
194
170
|
cacheId: this.cacheId
|
|
195
171
|
});
|
|
172
|
+
// 预拉取当天的资源数据
|
|
196
173
|
this.getAvailableDate({
|
|
197
|
-
startDate: schedule_date || (0,
|
|
198
|
-
endDate: schedule_date || (0,
|
|
174
|
+
startDate: schedule_date || (0, _dayjs.default)().format('YYYY-MM-DD'),
|
|
175
|
+
endDate: schedule_date || (0, _dayjs.default)().format('YYYY-MM-DD'),
|
|
199
176
|
products: [...res]
|
|
200
177
|
});
|
|
201
178
|
return res;
|
|
202
179
|
}
|
|
180
|
+
|
|
203
181
|
/**
|
|
204
182
|
* 通过 schedule 来读取商品,适用于 session 类商品
|
|
205
183
|
*
|
|
@@ -220,21 +198,40 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
220
198
|
product_ids = [],
|
|
221
199
|
category_ids = []
|
|
222
200
|
}) {
|
|
223
|
-
var _a;
|
|
224
201
|
const scheduleList = this.store.schedule.getAvailabilityScheduleDateList();
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
202
|
+
// 缓存下这次选择的结果,如果是先选日期再选 duration 类商品,后面用得到
|
|
203
|
+
this.setDateRange([{
|
|
204
|
+
date,
|
|
205
|
+
status: 'available',
|
|
206
|
+
week: '',
|
|
207
|
+
weekNum: 0
|
|
208
|
+
}, {
|
|
209
|
+
date,
|
|
210
|
+
status: 'available',
|
|
211
|
+
week: '',
|
|
212
|
+
weekNum: 0
|
|
213
|
+
}]);
|
|
229
214
|
let newProductIds = [];
|
|
230
|
-
const
|
|
231
|
-
|
|
215
|
+
// const scheduleIds = scheduleList
|
|
216
|
+
// .filter((n) => n.date === date)
|
|
217
|
+
// .flatMap((n) => n.schedule_id)
|
|
218
|
+
// .filter((n) => n !== null && n !== undefined);
|
|
219
|
+
|
|
220
|
+
// 如果外面没传 product_ids,尝试从对应 schedule 里拿 product_ids
|
|
221
|
+
// if (!product_ids?.length) {
|
|
222
|
+
// const schedule = scheduleList.find((n) => n.date === date);
|
|
223
|
+
// if (schedule && schedule.product_ids?.length) {
|
|
224
|
+
// product_ids = schedule.product_ids;
|
|
225
|
+
// }
|
|
226
|
+
// }
|
|
227
|
+
// V2接口修改后,只能从schedule 接口里拿数据,不可以从外面拿,外面给的是装修数据
|
|
228
|
+
const schedule = scheduleList.find(n => n.date === date);
|
|
229
|
+
if (schedule && schedule.product_ids?.length) {
|
|
232
230
|
newProductIds = schedule.product_ids;
|
|
233
231
|
}
|
|
232
|
+
// 尝试去拿schedule 里的 other_product_ids 和 product_ids 拼在一起去重
|
|
234
233
|
const otherProductsIds = this.store.schedule.getOtherProductsIds() || [];
|
|
235
|
-
const allProductIds = [...newProductIds, ...otherProductsIds].filter(
|
|
236
|
-
(n, index, self) => self.indexOf(n) === index
|
|
237
|
-
);
|
|
234
|
+
const allProductIds = [...newProductIds, ...otherProductsIds].filter((n, index, self) => self.indexOf(n) === index);
|
|
238
235
|
const res = await this.loadProducts({
|
|
239
236
|
product_ids: allProductIds,
|
|
240
237
|
category_ids,
|
|
@@ -242,6 +239,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
242
239
|
});
|
|
243
240
|
return res;
|
|
244
241
|
}
|
|
242
|
+
|
|
245
243
|
/**
|
|
246
244
|
* 更新完商品数据、切换日期、或者在较后的流程里登录了,检测当前购物车里是否有商品,如果有,则需要更新购物车里的商品价格
|
|
247
245
|
*
|
|
@@ -249,34 +247,25 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
249
247
|
* @memberof BookingByStepImpl
|
|
250
248
|
*/
|
|
251
249
|
async updateQuotationPriceAndCart(date) {
|
|
252
|
-
var _a;
|
|
253
250
|
const cartItems = this.store.cart.getItems();
|
|
254
251
|
if (cartItems.length) {
|
|
255
|
-
let userPlugin = this.core.getPlugin(
|
|
256
|
-
let customer_id =
|
|
252
|
+
let userPlugin = this.core.getPlugin('user');
|
|
253
|
+
let customer_id = undefined;
|
|
257
254
|
try {
|
|
258
|
-
customer_id =
|
|
255
|
+
customer_id = userPlugin?.get()?.id;
|
|
259
256
|
} catch (error) {
|
|
260
257
|
console.error(error);
|
|
261
258
|
}
|
|
262
259
|
const res = await this.store.products.loadProductsPrice({
|
|
263
|
-
ids: cartItems.map(
|
|
260
|
+
ids: cartItems.map(n => n.id),
|
|
264
261
|
schedule_date: date,
|
|
265
262
|
customer_id
|
|
266
263
|
});
|
|
267
|
-
await (0,
|
|
268
|
-
|
|
269
|
-
res,
|
|
270
|
-
(id) => this.store.products.getProduct(id),
|
|
271
|
-
(params) => this.store.cart.updateItem(params),
|
|
272
|
-
(params) => this.store.cart.updateItemInitInfo(params)
|
|
273
|
-
);
|
|
274
|
-
this.core.effects.emit(
|
|
275
|
-
`${this.store.cart.name}:onUpdateQuotationPrice`,
|
|
276
|
-
{}
|
|
277
|
-
);
|
|
264
|
+
await (0, _changePrice.updateAllCartItemPrice)(cartItems, res, id => this.store.products.getProduct(id), params => this.store.cart.updateItem(params), params => this.store.cart.updateItemInitInfo(params));
|
|
265
|
+
this.core.effects.emit(`${this.store.cart.name}:onUpdateQuotationPrice`, {});
|
|
278
266
|
}
|
|
279
267
|
}
|
|
268
|
+
|
|
280
269
|
/**
|
|
281
270
|
* ui 层提供日期的起始范围,返回一个起始范围内日期的可用情况
|
|
282
271
|
* 适用于先选日期的流程,确定日期是否可用
|
|
@@ -303,36 +292,36 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
303
292
|
channel
|
|
304
293
|
});
|
|
305
294
|
}
|
|
295
|
+
|
|
306
296
|
// 添加单个账户或者 guest
|
|
307
297
|
async addAccount(account, extra) {
|
|
308
|
-
|
|
298
|
+
// 如果是holder类型的需要先做数据转换
|
|
299
|
+
if (extra?.type === 'holder') {
|
|
309
300
|
const accountModules = await this.store.accountList.addHolderAccounts({
|
|
310
301
|
holders: [account],
|
|
311
302
|
customerId: extra.customerId,
|
|
312
|
-
type:
|
|
303
|
+
type: 'unshift'
|
|
313
304
|
});
|
|
314
305
|
return accountModules[0].getAccount();
|
|
315
306
|
}
|
|
316
|
-
const newAccount = await this.store.accountList.addAccount(
|
|
317
|
-
account
|
|
318
|
-
);
|
|
307
|
+
const newAccount = await this.store.accountList.addAccount(account);
|
|
319
308
|
return newAccount.getAccount();
|
|
320
309
|
}
|
|
310
|
+
|
|
321
311
|
// 添加账户或者 guest
|
|
322
312
|
async addAccounts(accounts, extra) {
|
|
323
|
-
|
|
313
|
+
// 如果是holder类型的需要先做数据转换
|
|
314
|
+
if (extra?.type === 'holder') {
|
|
324
315
|
this.store.accountList.addHolderAccounts({
|
|
325
316
|
holders: accounts,
|
|
326
317
|
customerId: extra.customerId,
|
|
327
|
-
type:
|
|
318
|
+
type: 'unshift'
|
|
328
319
|
});
|
|
329
320
|
return;
|
|
330
321
|
}
|
|
331
322
|
const res = [];
|
|
332
323
|
for (const account of accounts) {
|
|
333
|
-
const accountModule = await this.store.accountList.addAccount(
|
|
334
|
-
account
|
|
335
|
-
);
|
|
324
|
+
const accountModule = await this.store.accountList.addAccount(account);
|
|
336
325
|
const accountData = accountModule.getAccount();
|
|
337
326
|
if (accountData) {
|
|
338
327
|
res.push(accountData);
|
|
@@ -340,70 +329,77 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
340
329
|
}
|
|
341
330
|
return res;
|
|
342
331
|
}
|
|
332
|
+
|
|
343
333
|
// 获取所有账户
|
|
344
334
|
async getAccounts() {
|
|
345
335
|
const accounts = this.store.accountList.getAccounts();
|
|
346
|
-
return accounts.map(
|
|
336
|
+
return accounts.map(account => account.getAccount());
|
|
347
337
|
}
|
|
348
338
|
checkHasLoginAccount() {
|
|
349
339
|
const accounts = this.store.accountList.getAccounts();
|
|
350
|
-
return accounts.some(
|
|
340
|
+
return accounts.some(account => account.getLoginStatus());
|
|
351
341
|
}
|
|
352
342
|
setActiveAccount(id) {
|
|
353
343
|
this.store.accountList.setActiveAccount(id);
|
|
354
344
|
}
|
|
355
345
|
getActiveAccount() {
|
|
356
346
|
const activeAccount = this.store.accountList.getActiveAccount();
|
|
357
|
-
const account = activeAccount
|
|
358
|
-
return account === null ?
|
|
347
|
+
const account = activeAccount?.getAccount();
|
|
348
|
+
return account === null ? undefined : account;
|
|
359
349
|
}
|
|
360
350
|
removeAccount(id) {
|
|
361
351
|
this.store.accountList.removeAccount(id);
|
|
352
|
+
// 还需要把对应账号的商品给她删了
|
|
362
353
|
this.clearCartByAccount(id);
|
|
363
354
|
}
|
|
355
|
+
|
|
364
356
|
/**
|
|
365
357
|
* 获取holder类型账户列表
|
|
366
358
|
* @param params
|
|
367
359
|
*/
|
|
368
360
|
async fetchHolderAccountsAsync(params) {
|
|
369
|
-
var _a, _b;
|
|
370
361
|
const cartItems = this.store.cart.getItems();
|
|
371
362
|
if (cartItems.length) {
|
|
372
|
-
let date =
|
|
363
|
+
let date = this.store.date.getDateRange()?.[0]?.date;
|
|
373
364
|
if (!date) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
);
|
|
377
|
-
date =
|
|
365
|
+
// 如果没有日期,则应该是 session 类先选商品的流程,直接从购物车里拿 start_date
|
|
366
|
+
// 不能从购物车里第一个找时间,而是找到购物车里第一个有 start_date 的时间
|
|
367
|
+
const normalProductCartItem = cartItems.find(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
368
|
+
date = normalProductCartItem?.start_date || '';
|
|
378
369
|
}
|
|
379
370
|
this.updateQuotationPriceAndCart(date);
|
|
380
371
|
}
|
|
381
372
|
return this.store.accountList.fetchHolderAccounts(params);
|
|
382
373
|
}
|
|
374
|
+
|
|
383
375
|
/**
|
|
384
376
|
* 获取 holder 表单 map
|
|
385
377
|
*/
|
|
386
378
|
getHolderFormMap() {
|
|
387
379
|
return this.store.holder.getHolderFormMap();
|
|
388
380
|
}
|
|
381
|
+
|
|
389
382
|
/**
|
|
390
383
|
* 登录后或外部触发时,按当前 holderMap 批量刷新所有表单的 records
|
|
391
384
|
*/
|
|
392
385
|
async refreshAllHolderFormRecords(params) {
|
|
393
386
|
return this.store.holder.refreshAllFormRecords({
|
|
394
|
-
customer_id: params
|
|
387
|
+
customer_id: params?.customer_id,
|
|
395
388
|
useCache: false
|
|
396
389
|
});
|
|
397
390
|
}
|
|
391
|
+
|
|
398
392
|
/**
|
|
399
393
|
* 添加表单记录
|
|
400
394
|
*/
|
|
401
395
|
appendFormRecord(params) {
|
|
402
396
|
return this.store.holder.appendFormRecord(params);
|
|
403
397
|
}
|
|
398
|
+
|
|
404
399
|
// 设置日期范围,注入到日期模块中
|
|
405
400
|
async setDateRange(dateRange) {
|
|
406
401
|
this.store.date.setDateRange(dateRange);
|
|
402
|
+
// 日期数据变更后,如果购物车里有数据,需要更新购物车里的报价单的价格
|
|
407
403
|
if (dateRange.length && this.store.cart.getItems().length) {
|
|
408
404
|
this.updateQuotationPriceAndCart(dateRange[0].date);
|
|
409
405
|
}
|
|
@@ -411,6 +407,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
411
407
|
clearDateRange() {
|
|
412
408
|
this.store.date.clearDateRange();
|
|
413
409
|
}
|
|
410
|
+
|
|
414
411
|
// 获取日期模块里选中的日期
|
|
415
412
|
async getDateRange() {
|
|
416
413
|
return this.store.date.getDateRange();
|
|
@@ -418,37 +415,50 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
418
415
|
getCart() {
|
|
419
416
|
return this.store.cart.getItems();
|
|
420
417
|
}
|
|
418
|
+
|
|
421
419
|
// 获取商品/服务的可用日期
|
|
422
420
|
async getAvailableDate(params = {}) {
|
|
423
|
-
|
|
424
|
-
let {
|
|
425
|
-
|
|
426
|
-
startDate
|
|
421
|
+
// 开始日期如果小于今天,直接以今天当做开始日期
|
|
422
|
+
let {
|
|
423
|
+
products,
|
|
424
|
+
startDate,
|
|
425
|
+
endDate,
|
|
426
|
+
type,
|
|
427
|
+
useCache = true
|
|
428
|
+
} = params;
|
|
429
|
+
// 前端传递的 startDate,可能是今天之前的,如果 startDate 小于今天 且 endDate 小于或等于今天,需要把 startDate 置为今天
|
|
430
|
+
if ((0, _dayjs.default)(startDate).isBefore((0, _dayjs.default)(), 'day') && ((0, _dayjs.default)(endDate).isAfter((0, _dayjs.default)(), 'day') || (0, _dayjs.default)(endDate).isSame((0, _dayjs.default)(), 'day'))) {
|
|
431
|
+
startDate = (0, _dayjs.default)().format('YYYY-MM-DD');
|
|
427
432
|
}
|
|
428
|
-
let tempProducts = products || this.store.cart.getItems().map(
|
|
433
|
+
let tempProducts = products || this.store.cart.getItems().map(p => p._productOrigin);
|
|
429
434
|
if (tempProducts.length) {
|
|
430
|
-
tempProducts.forEach(
|
|
431
|
-
if (p
|
|
432
|
-
const scheduleData = this.getScheduleDataByIds(p[
|
|
433
|
-
p[
|
|
435
|
+
tempProducts.forEach(p => {
|
|
436
|
+
if (p?.['schedule.ids']) {
|
|
437
|
+
const scheduleData = this.getScheduleDataByIds(p['schedule.ids']);
|
|
438
|
+
p['_schedule'] = scheduleData;
|
|
434
439
|
}
|
|
435
440
|
});
|
|
436
441
|
}
|
|
442
|
+
// 如果当前打开了某个的商品详情弹窗,则应该默认用这个商品
|
|
437
443
|
if (this.store.currentProduct) {
|
|
438
|
-
tempProducts = [
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}
|
|
443
|
-
];
|
|
444
|
+
tempProducts = [{
|
|
445
|
+
...this.store.currentProduct,
|
|
446
|
+
_schedule: this.store.currentProductMeta?.['schedule']
|
|
447
|
+
}];
|
|
444
448
|
}
|
|
445
449
|
let dateRange = this.store.date.getDateRange();
|
|
446
|
-
const tempStartDate = startDate ||
|
|
447
|
-
const tempEndDate = endDate ||
|
|
450
|
+
const tempStartDate = startDate || dateRange?.[0]?.date;
|
|
451
|
+
const tempEndDate = endDate || dateRange?.[1]?.date || dateRange?.[0]?.date;
|
|
448
452
|
if (!tempProducts.length) {
|
|
449
453
|
return [];
|
|
450
454
|
}
|
|
451
|
-
|
|
455
|
+
|
|
456
|
+
// 在这里需要把能收集到的数据都收集上来,拼装好给 date 模块去查询
|
|
457
|
+
const {
|
|
458
|
+
resourceIds,
|
|
459
|
+
rules,
|
|
460
|
+
resourcesMap
|
|
461
|
+
} = (0, _products.getAvailableProductResources)(tempProducts) || {};
|
|
452
462
|
this.otherParams.currentResourcesMap = resourcesMap;
|
|
453
463
|
const res = await this.store.date.getResourceDates({
|
|
454
464
|
url: params.url,
|
|
@@ -463,6 +473,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
463
473
|
});
|
|
464
474
|
return res;
|
|
465
475
|
}
|
|
476
|
+
|
|
466
477
|
/**
|
|
467
478
|
* 获取购物车汇总信息
|
|
468
479
|
*/
|
|
@@ -471,26 +482,29 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
471
482
|
const summary = await this.store.summary.getSummary(cartItems);
|
|
472
483
|
return summary;
|
|
473
484
|
}
|
|
485
|
+
|
|
474
486
|
/**
|
|
475
487
|
* 获取协议
|
|
476
488
|
*/
|
|
477
489
|
async getProtocol(protocolId) {
|
|
478
490
|
return this.store.summary.getProtocol(protocolId);
|
|
479
491
|
}
|
|
492
|
+
|
|
480
493
|
// 获取可选择的商品、服务列表
|
|
481
494
|
async getProducts() {
|
|
482
495
|
return this.store.products.getProducts();
|
|
483
496
|
}
|
|
497
|
+
|
|
484
498
|
// 如果用户登录
|
|
485
499
|
async setLoginAccount(accountId, accountInfo) {
|
|
486
|
-
var _a, _b;
|
|
487
500
|
const account = this.store.accountList.getAccount(accountId);
|
|
488
501
|
if (account) {
|
|
489
502
|
let stateAccountId = account.getId();
|
|
490
503
|
accountInfo.isLogin = true;
|
|
491
504
|
account.setAccountInfo(accountInfo);
|
|
505
|
+
// 然后去购物车,把原先关联了 holder_id 为 accountId 的商品,替换为 holder_id = accountInfo.id
|
|
492
506
|
const cartItems = this.store.cart.getItems();
|
|
493
|
-
cartItems.forEach(
|
|
507
|
+
cartItems.forEach(item => {
|
|
494
508
|
if (item.holder_id === accountId) {
|
|
495
509
|
this.store.cart.updateItem({
|
|
496
510
|
_id: item._id,
|
|
@@ -500,35 +514,39 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
500
514
|
});
|
|
501
515
|
this.store.accountList.updateAccountListById(stateAccountId, accountInfo);
|
|
502
516
|
if (cartItems.length) {
|
|
503
|
-
let date =
|
|
517
|
+
let date = this.store.date.getDateRange()?.[0]?.date;
|
|
504
518
|
if (!date) {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
);
|
|
508
|
-
date =
|
|
519
|
+
// 如果没有日期,则应该是 session 类先选商品的流程,直接从购物车里拿 start_date
|
|
520
|
+
// 不能从购物车里第一个找时间,而是找到购物车里第一个有 start_date 的时间
|
|
521
|
+
const normalProductCartItem = cartItems.find(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
522
|
+
date = normalProductCartItem?.start_date || '';
|
|
509
523
|
}
|
|
510
524
|
this.updateQuotationPriceAndCart(date);
|
|
525
|
+
|
|
526
|
+
// 登录后刷新 holder 表单
|
|
511
527
|
try {
|
|
512
528
|
const customerId = Number(accountInfo.id);
|
|
513
529
|
await this.refreshAllHolderFormRecords({
|
|
514
530
|
customer_id: customerId
|
|
515
531
|
});
|
|
516
532
|
} catch (error) {
|
|
517
|
-
console.error(
|
|
533
|
+
console.error('[BookingByStep] 登录后刷新 holder 表单失败', error);
|
|
518
534
|
}
|
|
519
535
|
}
|
|
520
536
|
} else {
|
|
521
537
|
throw new Error(`没有找到${accountId}账户`);
|
|
522
538
|
}
|
|
523
539
|
}
|
|
540
|
+
|
|
524
541
|
// 生成购物车的正规数据
|
|
525
|
-
async generateCartData() {
|
|
526
|
-
|
|
542
|
+
async generateCartData() {}
|
|
543
|
+
|
|
527
544
|
// 免费领取商品相关逻辑,上线了来不及加了,先放在这,后面要做到 payment 里面的
|
|
528
545
|
async getFreeProduct(id) {
|
|
529
546
|
const res = await this.request.post(`/pay/order/free-pay/${id}`);
|
|
530
547
|
return res;
|
|
531
548
|
}
|
|
549
|
+
|
|
532
550
|
/**
|
|
533
551
|
* 检查购物车提交订单前是否符合条件
|
|
534
552
|
* @param type 类型 "holder" | "account"
|
|
@@ -540,61 +558,71 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
540
558
|
cartItems: this.store.cart.getItems()
|
|
541
559
|
});
|
|
542
560
|
}
|
|
561
|
+
|
|
543
562
|
// 购物车提交订单
|
|
544
563
|
async submitOrder(extraData) {
|
|
545
|
-
var _a;
|
|
546
564
|
const cartItems = this.store.cart.getItems();
|
|
547
|
-
const newCartItems = (0,
|
|
548
|
-
|
|
549
|
-
|
|
565
|
+
const newCartItems = (0, _lodashEs.cloneDeep)(cartItems);
|
|
566
|
+
// 先整个临时的逻辑,把购物车里所有商品的资源给他格式化一下
|
|
567
|
+
newCartItems.forEach(item => {
|
|
550
568
|
if (item._origin.resources && item._origin.resources.length) {
|
|
551
|
-
item._origin.resources = item._origin.resources.map(
|
|
552
|
-
const newResourcesItem = (0,
|
|
569
|
+
item._origin.resources = item._origin.resources.map(n => {
|
|
570
|
+
const newResourcesItem = (0, _lodashEs.cloneDeep)(n);
|
|
553
571
|
delete newResourcesItem.id;
|
|
554
572
|
delete newResourcesItem.main_field;
|
|
555
573
|
delete newResourcesItem.resourceType;
|
|
556
|
-
return {
|
|
574
|
+
return {
|
|
575
|
+
...newResourcesItem
|
|
576
|
+
};
|
|
557
577
|
});
|
|
558
|
-
const {
|
|
559
|
-
|
|
578
|
+
const {
|
|
579
|
+
currentCapacity,
|
|
580
|
+
formatCapacity
|
|
581
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(item);
|
|
582
|
+
if (!item._origin?.metadata) {
|
|
560
583
|
item._origin.metadata = {};
|
|
561
584
|
}
|
|
562
585
|
item._origin.metadata.capacity = formatCapacity;
|
|
563
586
|
item._origin.number = currentCapacity;
|
|
564
587
|
}
|
|
565
588
|
});
|
|
566
|
-
let type = this.otherParams.isRetailTemplate ?
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
type = "virtual";
|
|
589
|
+
let type = this.otherParams.isRetailTemplate ? 'virtual' : 'appointment_booking';
|
|
590
|
+
// 如果购物车里全都是普通商品,type 也应该为 virtual
|
|
591
|
+
if ((0, _utils5.areAllNormalProducts)(newCartItems.map(n => n._productOrigin))) {
|
|
592
|
+
type = 'virtual';
|
|
571
593
|
}
|
|
572
594
|
return this.store.order.submitOrder({
|
|
573
595
|
query: {
|
|
574
596
|
cartItems: newCartItems,
|
|
575
597
|
type,
|
|
576
598
|
platform: this.platform,
|
|
577
|
-
business_code:
|
|
599
|
+
business_code: this.otherParams?.business_code,
|
|
578
600
|
extraData
|
|
579
601
|
}
|
|
580
602
|
});
|
|
581
603
|
}
|
|
604
|
+
|
|
582
605
|
// 拉起支付模块
|
|
583
|
-
async pay() {
|
|
584
|
-
|
|
606
|
+
async pay() {}
|
|
607
|
+
|
|
585
608
|
// 获取支付信息
|
|
586
|
-
async getPayInfo() {
|
|
587
|
-
|
|
588
|
-
|
|
609
|
+
async getPayInfo() {}
|
|
610
|
+
async setOtherParams(params, {
|
|
611
|
+
cover = false
|
|
612
|
+
} = {}) {
|
|
589
613
|
if (cover) {
|
|
590
614
|
this.otherParams = params;
|
|
591
615
|
} else {
|
|
592
|
-
this.otherParams = {
|
|
616
|
+
this.otherParams = {
|
|
617
|
+
...this.otherParams,
|
|
618
|
+
...params
|
|
619
|
+
};
|
|
593
620
|
}
|
|
594
621
|
}
|
|
595
622
|
async getOtherParams() {
|
|
596
623
|
return this.otherParams;
|
|
597
624
|
}
|
|
625
|
+
|
|
598
626
|
/**
|
|
599
627
|
* 往购物车加商品数据(duration 类、普通商品)
|
|
600
628
|
* 老接口,先不删,怕 UI 有问题,直接桥接到新接口addProductToCart上
|
|
@@ -603,12 +631,15 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
603
631
|
* @memberof BookingByStepImpl
|
|
604
632
|
*/
|
|
605
633
|
storeProduct(productData) {
|
|
634
|
+
// 往购物车加商品数据的时候,默认用当前 activeAccount 填充到 product 的 account 里面
|
|
606
635
|
const activeAccount = this.getActiveAccount();
|
|
636
|
+
// 直接调用 addProductToCart,不传递 date 参数以避免日期检查逻辑
|
|
607
637
|
return this.addProductToCart({
|
|
608
638
|
product: productData,
|
|
609
639
|
account: activeAccount
|
|
610
640
|
});
|
|
611
641
|
}
|
|
642
|
+
|
|
612
643
|
/**
|
|
613
644
|
* 往购物车加商品数据
|
|
614
645
|
*
|
|
@@ -637,20 +668,31 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
637
668
|
rowKey,
|
|
638
669
|
quantity = 1
|
|
639
670
|
} = product || {};
|
|
640
|
-
const productData = {
|
|
641
|
-
|
|
671
|
+
const productData = {
|
|
672
|
+
...origin,
|
|
673
|
+
product_variant_id
|
|
674
|
+
};
|
|
675
|
+
// 保护,如果进来的是 session 商品,则必须要有 date 和时间片,否则不允许添加
|
|
676
|
+
if ((0, _products.isSessionProduct)(productData)) {
|
|
642
677
|
if (!date || !date.startTime || !date.endTime) {
|
|
643
|
-
return {
|
|
678
|
+
return {
|
|
679
|
+
success: false,
|
|
680
|
+
errorCode: 'date_or_time_required'
|
|
681
|
+
};
|
|
644
682
|
}
|
|
645
683
|
}
|
|
684
|
+
|
|
685
|
+
// 库存检测
|
|
646
686
|
const currentCartItems = this.store.cart.getItems();
|
|
647
|
-
const stockCheckResult = (0,
|
|
687
|
+
const stockCheckResult = (0, _stock.checkProductStock)({
|
|
648
688
|
productData,
|
|
649
689
|
product_variant_id,
|
|
650
690
|
quantity,
|
|
651
691
|
bundle,
|
|
652
692
|
currentCartItems
|
|
653
693
|
});
|
|
694
|
+
|
|
695
|
+
// 如果库存检测失败,直接返回
|
|
654
696
|
if (!stockCheckResult.success) {
|
|
655
697
|
return stockCheckResult;
|
|
656
698
|
}
|
|
@@ -663,19 +705,21 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
663
705
|
try {
|
|
664
706
|
this.store.holder.ensureFormByProduct({
|
|
665
707
|
product: productData,
|
|
666
|
-
shop_id:
|
|
708
|
+
shop_id: productData?.shop_id || '',
|
|
667
709
|
useCache: true
|
|
668
710
|
});
|
|
669
711
|
} catch (error) {
|
|
670
|
-
console.error(
|
|
712
|
+
console.error('[BookingByStep] 加载 holder 表单失败', error);
|
|
671
713
|
}
|
|
672
714
|
const flag = this.store.cart.mergeCartItemByRowKey({
|
|
673
715
|
rowKey,
|
|
674
716
|
quantity,
|
|
675
|
-
account: account ||
|
|
717
|
+
account: account || undefined
|
|
676
718
|
});
|
|
677
719
|
if (flag) {
|
|
678
|
-
return {
|
|
720
|
+
return {
|
|
721
|
+
success: true
|
|
722
|
+
};
|
|
679
723
|
}
|
|
680
724
|
const addItemParams = {
|
|
681
725
|
product: productData,
|
|
@@ -689,18 +733,24 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
689
733
|
if (account) {
|
|
690
734
|
addItemParams.account = account;
|
|
691
735
|
}
|
|
692
|
-
this.addProductCheck({
|
|
693
|
-
|
|
736
|
+
this.addProductCheck({
|
|
737
|
+
date
|
|
738
|
+
});
|
|
739
|
+
// 如果 quantity 大于 1,且是预约商品,则进入购物车拆散成多条数据
|
|
740
|
+
if (addItemParams.quantity > 1 && !(0, _utils5.isNormalProduct)(productData)) {
|
|
694
741
|
for (let i = 0; i < addItemParams.quantity; i++) {
|
|
695
|
-
const newAddItemParams = (0,
|
|
742
|
+
const newAddItemParams = (0, _lodashEs.cloneDeep)(addItemParams);
|
|
696
743
|
newAddItemParams.quantity = 1;
|
|
697
744
|
this.store.cart.addItem(newAddItemParams);
|
|
698
745
|
}
|
|
699
746
|
} else {
|
|
700
747
|
this.store.cart.addItem(addItemParams);
|
|
701
748
|
}
|
|
702
|
-
return {
|
|
749
|
+
return {
|
|
750
|
+
success: true
|
|
751
|
+
};
|
|
703
752
|
}
|
|
753
|
+
|
|
704
754
|
/**
|
|
705
755
|
* 添加完购物车以后做的一些检测,比如日期是否在同一天
|
|
706
756
|
*
|
|
@@ -710,28 +760,38 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
710
760
|
addProductCheck({
|
|
711
761
|
date
|
|
712
762
|
}) {
|
|
763
|
+
// 检测,有传递 date,检查购物车里其他商品的 date 是否在同一天,如果不在,清空那些不在同一天的商品
|
|
713
764
|
if (date) {
|
|
714
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
715
|
-
const cartItemsByDate = cartItems.filter(
|
|
716
|
-
(n) => !(0, import_dayjs.default)(n.start_date).isSame((0, import_dayjs.default)(date.startTime), "day")
|
|
717
|
-
);
|
|
765
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
766
|
+
const cartItemsByDate = cartItems.filter(n => !(0, _dayjs.default)(n.start_date).isSame((0, _dayjs.default)(date.startTime), 'day'));
|
|
718
767
|
if (cartItemsByDate.length) {
|
|
719
|
-
cartItemsByDate.forEach(
|
|
768
|
+
cartItemsByDate.forEach(n => {
|
|
720
769
|
this.store.cart.removeItem(n._id);
|
|
721
770
|
});
|
|
722
771
|
}
|
|
772
|
+
// // 如果 date.startTime 和 dateRange 里的 startTime 不一样,需要修正 dateRange
|
|
773
|
+
// const dateRange = this.store.date.getDateRange()
|
|
774
|
+
// if (dateRange?.[0] && !dayjs(dateRange[0].date).isSame(dayjs(date.startTime), 'day')) {
|
|
775
|
+
// this.setDateRange([
|
|
776
|
+
// { date: dayjs(date.startTime).format('YYYY-MM-DD'), status: 'available', week: '', weekNum: 0 },
|
|
777
|
+
// { date: dayjs(date.endTime).format('YYYY-MM-DD'), status: 'available', week: '', weekNum: 0 },
|
|
778
|
+
// ]);
|
|
779
|
+
// }
|
|
723
780
|
}
|
|
724
781
|
}
|
|
725
782
|
beforeUpdateCart(params, targetCartItem) {
|
|
726
783
|
if (params.resources) {
|
|
727
|
-
const {
|
|
728
|
-
|
|
784
|
+
const {
|
|
785
|
+
currentCapacity
|
|
786
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(targetCartItem);
|
|
787
|
+
params.resources = params.resources.map(n => {
|
|
729
788
|
n.capacity = currentCapacity || 1;
|
|
730
|
-
(0,
|
|
789
|
+
(0, _capacity.checkSubResourcesCapacity)(n);
|
|
731
790
|
return n;
|
|
732
791
|
});
|
|
733
792
|
}
|
|
734
793
|
}
|
|
794
|
+
|
|
735
795
|
// 更新购物车
|
|
736
796
|
updateCart(params) {
|
|
737
797
|
const targetCartItem = this.store.cart.getItem(params._id);
|
|
@@ -742,6 +802,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
742
802
|
this.store.cart.updateItem(params);
|
|
743
803
|
this.updateCartCheck(params, targetCartItem);
|
|
744
804
|
}
|
|
805
|
+
|
|
745
806
|
/**
|
|
746
807
|
* 更新购物车以后的一些操作,比如检测资源是否重复,检测资源容量是否足够
|
|
747
808
|
*
|
|
@@ -751,63 +812,59 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
751
812
|
* @memberof BookingByStepImpl
|
|
752
813
|
*/
|
|
753
814
|
updateCartCheck(params, targetCartItem) {
|
|
754
|
-
|
|
815
|
+
// 零售模板不需要检测
|
|
755
816
|
if (this.otherParams.isRetailTemplate) {
|
|
756
817
|
return;
|
|
757
818
|
}
|
|
758
819
|
let currentResourcesCapacityMap = {};
|
|
759
|
-
|
|
820
|
+
params.resources?.forEach(n => {
|
|
760
821
|
currentResourcesCapacityMap[n.id] = n.capacity;
|
|
761
822
|
});
|
|
762
823
|
const allOriginResources = [];
|
|
763
824
|
const dateRange = this.store.date.getDateRange();
|
|
764
|
-
if (dateRange
|
|
765
|
-
dateRange.forEach(
|
|
766
|
-
if (n.resource)
|
|
767
|
-
allOriginResources.push(...n.resource);
|
|
825
|
+
if (dateRange?.length) {
|
|
826
|
+
dateRange.forEach(n => {
|
|
827
|
+
if (n.resource) allOriginResources.push(...n.resource);
|
|
768
828
|
});
|
|
769
829
|
}
|
|
830
|
+
// 如果此时 resources 为空,视作购物车里已经有了 dateRange 数据,此时 dateList 里明确就是那一天的数据
|
|
770
831
|
if (!allOriginResources.length) {
|
|
771
832
|
const dateList = this.store.date.getDateList();
|
|
772
|
-
dateList
|
|
773
|
-
if (n.resource)
|
|
774
|
-
allOriginResources.push(...n.resource);
|
|
833
|
+
dateList?.forEach(n => {
|
|
834
|
+
if (n.resource) allOriginResources.push(...n.resource);
|
|
775
835
|
});
|
|
776
836
|
}
|
|
837
|
+
// 只有在更新资源的时候做这个判断,其他情况下不做处理
|
|
777
838
|
if (params.resources) {
|
|
839
|
+
// 更新购物车后,需要判定购物车里是否存在多个账号选择了相同资源的情况,如果是,且资源是单个预约,则要把选择了相同资源的 product._origin.resources 给去除
|
|
778
840
|
const cartItems = this.store.cart.getItems();
|
|
779
|
-
cartItems.forEach(
|
|
780
|
-
var _a2;
|
|
841
|
+
cartItems.forEach(item => {
|
|
781
842
|
if (item._id !== targetCartItem._id) {
|
|
782
|
-
const {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
843
|
+
const {
|
|
844
|
+
currentCapacity
|
|
845
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(item);
|
|
846
|
+
const resources = item._origin.resources?.filter(m => {
|
|
847
|
+
// 检查当前资源是否与目标资源的任何资源匹配
|
|
848
|
+
// 目标资源,应该只取跟当前 m.form_id 相同的资源
|
|
849
|
+
const sameFormIdResources = (0, _resources.filterResourcesByFormItem)(targetCartItem._origin.resources, m.form_id);
|
|
850
|
+
if (!sameFormIdResources?.length) {
|
|
789
851
|
return true;
|
|
790
852
|
}
|
|
791
|
-
return !sameFormIdResources.some(
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
);
|
|
796
|
-
|
|
797
|
-
currentResourcesCapacityMap[m.id] || 0,
|
|
798
|
-
currentCapacity,
|
|
799
|
-
originResource == null ? void 0 : originResource.capacity
|
|
800
|
-
);
|
|
801
|
-
if (canUse)
|
|
802
|
-
currentResourcesCapacityMap[m.id] += currentCapacity;
|
|
853
|
+
return !sameFormIdResources.some(targetRes => {
|
|
854
|
+
// 如果新更新进来的资源不是单个预约,其实就不需要检测了资源重叠了,但是需要检测资源 capacity 是否足够
|
|
855
|
+
if (targetRes.resourceType !== 'single') {
|
|
856
|
+
const originResource = allOriginResources.find(n => n.id === targetRes.id);
|
|
857
|
+
const canUse = (0, _capacity.checkResourceCanUseByCapacity)(currentResourcesCapacityMap[m.id] || 0, currentCapacity, originResource?.capacity);
|
|
858
|
+
if (canUse) currentResourcesCapacityMap[m.id] += currentCapacity;
|
|
803
859
|
return !canUse;
|
|
804
860
|
}
|
|
805
|
-
if (item.holder_id !==
|
|
806
|
-
return (0,
|
|
861
|
+
if (item.holder_id !== targetCartItem?.holder_id) {
|
|
862
|
+
return (0, _resources.checkTwoResourcesIntersection)(targetRes, m);
|
|
807
863
|
}
|
|
808
864
|
return false;
|
|
809
865
|
});
|
|
810
866
|
});
|
|
867
|
+
// session 类商品应该只调用清空 resource 的方法
|
|
811
868
|
if (item.start_time) {
|
|
812
869
|
const start_time = item.start_time;
|
|
813
870
|
const end_time = item.end_time;
|
|
@@ -817,12 +874,8 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
817
874
|
_id: item._id,
|
|
818
875
|
resources,
|
|
819
876
|
date: {
|
|
820
|
-
startTime: (0,
|
|
821
|
-
|
|
822
|
-
),
|
|
823
|
-
endTime: (0, import_dayjs.default)(`${end_date} ${end_time}`).format(
|
|
824
|
-
"YYYY-MM-DD HH:mm"
|
|
825
|
-
)
|
|
877
|
+
startTime: (0, _dayjs.default)(`${start_date} ${start_time}`).format('YYYY-MM-DD HH:mm'),
|
|
878
|
+
endTime: (0, _dayjs.default)(`${end_date} ${end_time}`).format('YYYY-MM-DD HH:mm')
|
|
826
879
|
}
|
|
827
880
|
});
|
|
828
881
|
} else {
|
|
@@ -835,29 +888,34 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
835
888
|
});
|
|
836
889
|
}
|
|
837
890
|
}
|
|
891
|
+
|
|
838
892
|
// 删除购物车里某个商品
|
|
839
893
|
deleteCart(cartItemId) {
|
|
840
894
|
this.store.cart.removeItem(cartItemId);
|
|
841
895
|
}
|
|
896
|
+
|
|
842
897
|
// 清空购物车
|
|
843
898
|
clearCart() {
|
|
844
899
|
this.store.cart.clear();
|
|
845
900
|
}
|
|
901
|
+
|
|
846
902
|
// 基于账户清空购物车
|
|
847
903
|
clearCartByAccount(account_id) {
|
|
848
904
|
this.store.cart.clearCartByAccount(account_id);
|
|
849
905
|
}
|
|
906
|
+
|
|
850
907
|
/**
|
|
851
908
|
* 批量更新购物车
|
|
852
909
|
*/
|
|
853
910
|
batchUpdateCart(paramsList) {
|
|
854
911
|
const cartItems = [];
|
|
855
|
-
paramsList.forEach(
|
|
912
|
+
paramsList.forEach(params => {
|
|
856
913
|
const cartItem = this.store.cart.formatCartItem(params);
|
|
857
914
|
cartItems.push(cartItem);
|
|
858
915
|
});
|
|
859
916
|
this.store.cart.batchSetItems(cartItems);
|
|
860
917
|
}
|
|
918
|
+
|
|
861
919
|
/**
|
|
862
920
|
* 从购物车中按类别删除信息
|
|
863
921
|
*/
|
|
@@ -867,15 +925,17 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
867
925
|
checkCartItemByType(cartItem, type) {
|
|
868
926
|
return this.store.cart.checkCartItemByType(cartItem, type);
|
|
869
927
|
}
|
|
928
|
+
|
|
870
929
|
/**
|
|
871
930
|
* 检查购物车商品是否符合条件
|
|
872
931
|
* @param type 类型
|
|
873
932
|
* @returns 不符合条件的购物车商品ID列表
|
|
874
933
|
*/
|
|
875
934
|
checkCartItems(type) {
|
|
876
|
-
|
|
935
|
+
// 预约流程中普通商品无需检测这些东西
|
|
936
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
877
937
|
const errorCartItemIds = [];
|
|
878
|
-
cartItems.forEach(
|
|
938
|
+
cartItems.forEach(cartItem => {
|
|
879
939
|
const result = this.store.cart.checkCartItemByType(cartItem, type);
|
|
880
940
|
if (!result) {
|
|
881
941
|
errorCartItemIds.push(cartItem._id);
|
|
@@ -884,129 +944,117 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
884
944
|
return errorCartItemIds;
|
|
885
945
|
}
|
|
886
946
|
destroy() {
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
(_f = this.store.accountList) == null ? void 0 : _f.destroy();
|
|
947
|
+
this.store.cart?.destroy();
|
|
948
|
+
this.store.step?.destroy();
|
|
949
|
+
this.store.products?.destroy();
|
|
950
|
+
this.store.guests?.destroy();
|
|
951
|
+
this.store.date?.destroy();
|
|
952
|
+
this.store.accountList?.destroy();
|
|
894
953
|
this.core.effects.offByModuleDestroy(this.name);
|
|
895
954
|
this.core.unregisterModule(this);
|
|
896
955
|
}
|
|
956
|
+
|
|
897
957
|
// 获取当前购物车内所有关联的资源列表,拼装数据格式
|
|
898
958
|
getResourcesList() {
|
|
899
959
|
const dateRange = this.store.date.getDateRange();
|
|
900
960
|
const resources = [];
|
|
901
|
-
if (dateRange
|
|
902
|
-
dateRange.forEach(
|
|
903
|
-
if (n.resource)
|
|
904
|
-
resources.push(...n.resource);
|
|
961
|
+
if (dateRange?.length) {
|
|
962
|
+
dateRange.forEach(n => {
|
|
963
|
+
if (n.resource) resources.push(...n.resource);
|
|
905
964
|
});
|
|
906
965
|
}
|
|
907
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
966
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
967
|
+
|
|
968
|
+
// 如果此时 resources 为空,视作购物车里已经有了 dateRange 数据,此时 dateList 里明确就是那一天的数据
|
|
908
969
|
if (!resources.length) {
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
);
|
|
914
|
-
resources.push(...dateResources || []);
|
|
970
|
+
// 如果此时购物车里已经有了开始时间,则直接取那天的数据即可
|
|
971
|
+
const firstDateCartItem = cartItems?.find(n => n.start_date);
|
|
972
|
+
if (firstDateCartItem?.start_date) {
|
|
973
|
+
const dateResources = this.store.date.getResourcesListByDate(firstDateCartItem.start_date);
|
|
974
|
+
resources.push(...(dateResources || []));
|
|
915
975
|
} else {
|
|
916
976
|
const dateList = this.store.date.getDateList();
|
|
917
|
-
dateList
|
|
918
|
-
if (n.resource)
|
|
919
|
-
resources.push(...n.resource);
|
|
977
|
+
dateList?.forEach(n => {
|
|
978
|
+
if (n.resource) resources.push(...n.resource);
|
|
920
979
|
});
|
|
921
980
|
}
|
|
922
981
|
}
|
|
923
|
-
const resourcesMap = (0,
|
|
982
|
+
const resourcesMap = (0, _utils2.getResourcesMap)((0, _lodashEs.cloneDeep)(resources));
|
|
924
983
|
const arr = [];
|
|
925
|
-
cartItems.forEach(
|
|
926
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
984
|
+
cartItems.forEach(cartItem => {
|
|
927
985
|
let selectedResources = [];
|
|
928
|
-
const {
|
|
986
|
+
const {
|
|
987
|
+
currentCapacity,
|
|
988
|
+
formatCapacity
|
|
989
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(cartItem);
|
|
929
990
|
cartItem._origin.metadata.capacity = formatCapacity;
|
|
930
991
|
if (cartItem.holder_id) {
|
|
931
|
-
selectedResources = (0,
|
|
932
|
-
cartItems,
|
|
933
|
-
cartItem.holder_id,
|
|
934
|
-
resourcesMap
|
|
935
|
-
);
|
|
992
|
+
selectedResources = (0, _resources.getOthersSelectedResources)(cartItems, cartItem.holder_id, resourcesMap);
|
|
936
993
|
} else {
|
|
937
|
-
selectedResources = (0,
|
|
938
|
-
cartItems,
|
|
939
|
-
cartItem._id,
|
|
940
|
-
resourcesMap
|
|
941
|
-
);
|
|
994
|
+
selectedResources = (0, _resources.getOthersCartSelectedResources)(cartItems, cartItem._id, resourcesMap);
|
|
942
995
|
}
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
selectedResources,
|
|
947
|
-
currentCapacity
|
|
948
|
-
);
|
|
996
|
+
// TODO:下面这一坨要放到 resources 模块去
|
|
997
|
+
const productResources = (0, _resources.getResourcesByProduct)(resourcesMap, cartItem._productOrigin?.product_resource?.resources || [], selectedResources, currentCapacity);
|
|
998
|
+
// 如果购物车里已经有了时间片,则需要按照时间片过滤
|
|
949
999
|
if (cartItem._origin.start_time) {
|
|
950
|
-
const startTime = (0,
|
|
951
|
-
|
|
952
|
-
);
|
|
953
|
-
const endTime = (0, import_dayjs.default)(
|
|
954
|
-
`${cartItem._origin.end_date} ${cartItem._origin.end_time}`
|
|
955
|
-
);
|
|
1000
|
+
const startTime = (0, _dayjs.default)(`${cartItem._origin.start_date} ${cartItem._origin.start_time}`);
|
|
1001
|
+
const endTime = (0, _dayjs.default)(`${cartItem._origin.end_date} ${cartItem._origin.end_time}`);
|
|
956
1002
|
const resourcesUseableMap = {};
|
|
957
|
-
productResources.forEach(
|
|
958
|
-
|
|
959
|
-
n.renderList = n.renderList
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
);
|
|
1003
|
+
productResources.forEach(n => {
|
|
1004
|
+
// 资源排下序,把单个资源靠前,组合资源排在后面
|
|
1005
|
+
n.renderList = (0, _resources.sortCombinedResources)(n.renderList);
|
|
1006
|
+
n.renderList = n.renderList.filter(m => {
|
|
1007
|
+
// m.times 需要做个过滤,假设 timeSlice.start_at 是 09:30 timeSlice.end_at 是 11:30
|
|
1008
|
+
// time 是 time.start_at = 2025-05-26 10:30, time.end_at = 2025-05-26 12:30
|
|
1009
|
+
// 需要判断 time 的开始结束时间 是否包含timeSlice的开始结束时间
|
|
1010
|
+
const mTimes = (0, _timeslots.filterConditionTimeSlots)(m.times, startTime, endTime);
|
|
1011
|
+
// 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
|
|
965
1012
|
if (mTimes.length === 0) {
|
|
966
1013
|
return false;
|
|
967
1014
|
}
|
|
968
|
-
const canUseArr = mTimes.map(
|
|
969
|
-
|
|
970
|
-
const res = (0, import_resources.getIsUsableByTimeItem)({
|
|
1015
|
+
const canUseArr = mTimes.map(item => {
|
|
1016
|
+
const res = (0, _resources.getIsUsableByTimeItem)({
|
|
971
1017
|
timeSlice: {
|
|
972
|
-
start_time: startTime.format(
|
|
973
|
-
end_time: endTime.format(
|
|
1018
|
+
start_time: startTime.format('HH:mm'),
|
|
1019
|
+
end_time: endTime.format('HH:mm'),
|
|
974
1020
|
start_at: startTime,
|
|
975
1021
|
end_at: endTime
|
|
976
1022
|
},
|
|
977
1023
|
time: item,
|
|
978
1024
|
resource: m,
|
|
979
1025
|
currentCount: currentCapacity || 0,
|
|
980
|
-
resourcesUseableMap,
|
|
981
|
-
cut_off_time:
|
|
1026
|
+
resourcesUseableMap: resourcesUseableMap,
|
|
1027
|
+
cut_off_time: cartItem._productOrigin?.cut_off_time
|
|
982
1028
|
});
|
|
983
|
-
|
|
1029
|
+
// 如果仅仅是因为子资源容量不够,不应该标记子资源是被占用的情况(因为组合资源还需要判断子资源够不够)
|
|
1030
|
+
if (resourcesUseableMap?.[m.id] !== false && res.reason !== 'capacityOnly') {
|
|
984
1031
|
resourcesUseableMap[m.id] = res.usable;
|
|
985
1032
|
}
|
|
986
1033
|
return res.usable;
|
|
987
1034
|
});
|
|
988
|
-
if (m.onlyComputed)
|
|
989
|
-
|
|
990
|
-
return !canUseArr.some(
|
|
1035
|
+
if (m.onlyComputed) return false;
|
|
1036
|
+
// 在已经选定时间的情况下,只要canUseTime 里有一个 false,那就代表不可用
|
|
1037
|
+
return !canUseArr.some(n => n === false);
|
|
991
1038
|
});
|
|
992
1039
|
});
|
|
993
1040
|
} else {
|
|
994
|
-
const hasFlexibleDuration =
|
|
995
|
-
const operating_day_boundary =
|
|
996
|
-
const maxBlockThreshold =
|
|
997
|
-
productResources.forEach(
|
|
998
|
-
|
|
999
|
-
|
|
1041
|
+
const hasFlexibleDuration = cartItem._productOrigin?.duration?.type === 'flexible';
|
|
1042
|
+
const operating_day_boundary = this.shopStore.get('core')?.core?.operating_day_boundary;
|
|
1043
|
+
const maxBlockThreshold = cartItem._productOrigin?.duration?.flexible_config?.is_enable_minimum_duration ? cartItem._productOrigin?.duration?.flexible_config?.block_threshold || 0 : 0;
|
|
1044
|
+
productResources.forEach(item => {
|
|
1045
|
+
// 如果资源的 capacity 已经小于了当前需要的 capacity ,则需要把资源给过滤掉
|
|
1046
|
+
// 同时,在这一步尝试去拉一下时间片,基于商品的时长,看每个资源是否还有空余时间能对这个商品做服务,如果没有则过滤
|
|
1047
|
+
item.renderList = item.renderList.filter(n => {
|
|
1000
1048
|
const recordCount = n.capacity || 0;
|
|
1001
|
-
if (n.onlyComputed)
|
|
1002
|
-
|
|
1003
|
-
const timeSlots = (0,
|
|
1049
|
+
if (n.onlyComputed) return false;
|
|
1050
|
+
// 查一下这个资源基于商品的可用时间片
|
|
1051
|
+
const timeSlots = (0, _resources.getTimeSlicesByResource)({
|
|
1004
1052
|
resource: n,
|
|
1005
|
-
duration:
|
|
1053
|
+
duration: cartItem._productOrigin?.duration?.value || 10,
|
|
1006
1054
|
split: 10,
|
|
1007
1055
|
currentDate: dateRange[0].date,
|
|
1008
1056
|
hasFlexibleDuration,
|
|
1009
|
-
cut_off_time:
|
|
1057
|
+
cut_off_time: cartItem._productOrigin?.cut_off_time,
|
|
1010
1058
|
operating_day_boundary,
|
|
1011
1059
|
maxBlockThreshold
|
|
1012
1060
|
});
|
|
@@ -1027,6 +1075,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1027
1075
|
});
|
|
1028
1076
|
return arr;
|
|
1029
1077
|
}
|
|
1078
|
+
|
|
1030
1079
|
/**
|
|
1031
1080
|
* 在日期那边点击下一步的时候,检查这一天购物车里的商品是不是都有资源可以用
|
|
1032
1081
|
*
|
|
@@ -1035,11 +1084,12 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1035
1084
|
*/
|
|
1036
1085
|
checkResourceListForDate() {
|
|
1037
1086
|
const resourcesList = this.getResourcesList();
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
);
|
|
1087
|
+
|
|
1088
|
+
// 检查每一项资源的 renderList 里是否都有数据
|
|
1089
|
+
const hasResource = resourcesList.every(item => item.resources.every(resource => resource.renderList.length > 0));
|
|
1041
1090
|
return hasResource;
|
|
1042
1091
|
}
|
|
1092
|
+
|
|
1043
1093
|
/**
|
|
1044
1094
|
* 给单个购物车里的商品获取资源列表,给 UI 用的
|
|
1045
1095
|
*
|
|
@@ -1048,45 +1098,32 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1048
1098
|
* @memberof BookingByStepImpl
|
|
1049
1099
|
*/
|
|
1050
1100
|
getResourcesListByCartItem(id) {
|
|
1051
|
-
|
|
1052
|
-
const cartItems = this.store.cart.getItems().filter((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
|
|
1101
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
1053
1102
|
const dateRange = this.store.date.getDateRange();
|
|
1054
1103
|
const resources = [];
|
|
1055
|
-
dateRange.forEach(
|
|
1056
|
-
if (n.resource)
|
|
1057
|
-
resources.push(...n.resource);
|
|
1104
|
+
dateRange.forEach(n => {
|
|
1105
|
+
if (n.resource) resources.push(...n.resource);
|
|
1058
1106
|
});
|
|
1059
|
-
|
|
1060
|
-
const
|
|
1107
|
+
// 用于确保后续分配的容量不会超出
|
|
1108
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(resources);
|
|
1109
|
+
const targetCartItem = cartItems.find(n => n._id === id);
|
|
1061
1110
|
if (!targetCartItem) {
|
|
1062
1111
|
throw new Error(`没有找到${id}购物车商品`);
|
|
1063
1112
|
}
|
|
1064
1113
|
let selectedResources = [];
|
|
1065
|
-
const {
|
|
1114
|
+
const {
|
|
1115
|
+
currentCapacity
|
|
1116
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(targetCartItem);
|
|
1066
1117
|
if (targetCartItem.holder_id) {
|
|
1067
|
-
selectedResources = (0,
|
|
1068
|
-
cartItems,
|
|
1069
|
-
targetCartItem.holder_id,
|
|
1070
|
-
resourcesMap
|
|
1071
|
-
);
|
|
1118
|
+
selectedResources = (0, _resources.getOthersSelectedResources)(cartItems, targetCartItem.holder_id, resourcesMap);
|
|
1072
1119
|
} else {
|
|
1073
|
-
selectedResources = (0,
|
|
1074
|
-
cartItems,
|
|
1075
|
-
targetCartItem._id,
|
|
1076
|
-
resourcesMap
|
|
1077
|
-
);
|
|
1120
|
+
selectedResources = (0, _resources.getOthersCartSelectedResources)(cartItems, targetCartItem._id, resourcesMap);
|
|
1078
1121
|
}
|
|
1079
|
-
const productResources = (0,
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
selectedResources,
|
|
1083
|
-
currentCapacity
|
|
1084
|
-
);
|
|
1085
|
-
productResources.forEach((item) => {
|
|
1086
|
-
item.renderList = item.renderList.filter((n) => {
|
|
1122
|
+
const productResources = (0, _resources.getResourcesByProduct)(resourcesMap, targetCartItem._productOrigin?.product_resource?.resources || [], selectedResources, currentCapacity);
|
|
1123
|
+
productResources.forEach(item => {
|
|
1124
|
+
item.renderList = item.renderList.filter(n => {
|
|
1087
1125
|
const recordCount = n.capacity || 0;
|
|
1088
|
-
if (n.onlyComputed)
|
|
1089
|
-
return false;
|
|
1126
|
+
if (n.onlyComputed) return false;
|
|
1090
1127
|
return recordCount >= currentCapacity;
|
|
1091
1128
|
});
|
|
1092
1129
|
});
|
|
@@ -1103,6 +1140,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1103
1140
|
};
|
|
1104
1141
|
}
|
|
1105
1142
|
}
|
|
1143
|
+
|
|
1106
1144
|
// 自动分派可用资源-pro 版,ui 传递某个账号,自动给某个账号下所有商品分配第一种资源
|
|
1107
1145
|
autoSelectAccountResources({
|
|
1108
1146
|
cartItem,
|
|
@@ -1112,109 +1150,111 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1112
1150
|
countMap,
|
|
1113
1151
|
capacity
|
|
1114
1152
|
}) {
|
|
1115
|
-
|
|
1116
|
-
if ((0, import_utils5.isNormalProduct)(cartItem._productOrigin)) {
|
|
1153
|
+
if ((0, _utils5.isNormalProduct)(cartItem._productOrigin)) {
|
|
1117
1154
|
return {};
|
|
1118
1155
|
}
|
|
1119
1156
|
const dateRange = this.store.date.getDateRange();
|
|
1120
|
-
const cartItems = (0,
|
|
1121
|
-
|
|
1157
|
+
const cartItems = (0, _lodashEs.cloneDeep)(this.store.cart.getItems());
|
|
1158
|
+
// 取到账号下所有的商品,然后根据商品的 duration 和资源列表,获取所有可用的资源
|
|
1159
|
+
let accountCartItems = cartItems.filter(n => n.holder_id === holder_id) || [];
|
|
1160
|
+
// 账号下没商品则处理所有购物车
|
|
1122
1161
|
if (!accountCartItems.length) {
|
|
1123
1162
|
accountCartItems = cartItems;
|
|
1124
1163
|
}
|
|
1164
|
+
// duration=所有商品时间的集合,如果是灵活时长,当做占用 10 分钟处理
|
|
1125
1165
|
let duration = accountCartItems.reduce((acc, n) => {
|
|
1126
|
-
|
|
1127
|
-
return acc + (((_b2 = (_a2 = n._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.value) || 10);
|
|
1166
|
+
return acc + (n._productOrigin?.duration?.value || 10);
|
|
1128
1167
|
}, 0);
|
|
1129
1168
|
let AllResources = [];
|
|
1130
|
-
if (dateRange
|
|
1131
|
-
dateRange.forEach(
|
|
1132
|
-
if (n.resource)
|
|
1133
|
-
AllResources.push(...n.resource);
|
|
1169
|
+
if (dateRange?.length) {
|
|
1170
|
+
dateRange.forEach(n => {
|
|
1171
|
+
if (n.resource) AllResources.push(...n.resource);
|
|
1134
1172
|
});
|
|
1135
1173
|
}
|
|
1174
|
+
// 如果此时 resources 为空,视作购物车里已经有了 dateRange 数据,此时 dateList 里明确就是那一天的数据
|
|
1136
1175
|
if (!AllResources.length) {
|
|
1137
|
-
const firstDateCartItem = cartItems
|
|
1138
|
-
if (firstDateCartItem
|
|
1139
|
-
const dateResources = this.store.date.getResourcesListByDate(
|
|
1140
|
-
|
|
1141
|
-
);
|
|
1142
|
-
AllResources.push(...dateResources || []);
|
|
1176
|
+
const firstDateCartItem = cartItems?.find(n => n.start_date);
|
|
1177
|
+
if (firstDateCartItem?.start_date) {
|
|
1178
|
+
const dateResources = this.store.date.getResourcesListByDate(firstDateCartItem.start_date);
|
|
1179
|
+
AllResources.push(...(dateResources || []));
|
|
1143
1180
|
} else {
|
|
1144
1181
|
const dateList = this.store.date.getDateList();
|
|
1145
|
-
dateList.forEach(
|
|
1146
|
-
if (n.resource)
|
|
1147
|
-
AllResources.push(...n.resource);
|
|
1182
|
+
dateList.forEach(n => {
|
|
1183
|
+
if (n.resource) AllResources.push(...n.resource);
|
|
1148
1184
|
});
|
|
1149
1185
|
}
|
|
1150
1186
|
}
|
|
1151
|
-
const resourcesMap = (0,
|
|
1152
|
-
const allCartItems = (0,
|
|
1153
|
-
const selectedResources = (0,
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
);
|
|
1158
|
-
let allProductResources = (0, import_resources.getResourcesByProduct)(
|
|
1159
|
-
resourcesMap,
|
|
1160
|
-
((_b = (_a = cartItem._productOrigin) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) || [],
|
|
1161
|
-
selectedResources,
|
|
1162
|
-
1
|
|
1163
|
-
);
|
|
1164
|
-
const resources = ((_c = allProductResources.find((n) => n.code === resources_code)) == null ? void 0 : _c.renderList) || [];
|
|
1187
|
+
const resourcesMap = (0, _utils2.getResourcesMap)((0, _lodashEs.cloneDeep)(AllResources));
|
|
1188
|
+
const allCartItems = (0, _lodashEs.cloneDeep)(this.store.cart.getItems());
|
|
1189
|
+
const selectedResources = (0, _resources.getOthersSelectedResources)(allCartItems, holder_id, resourcesMap);
|
|
1190
|
+
let allProductResources = (0, _resources.getResourcesByProduct)(resourcesMap, cartItem._productOrigin?.product_resource?.resources || [], selectedResources, 1);
|
|
1191
|
+
const resources = allProductResources.find(n => n.code === resources_code)?.renderList || [];
|
|
1192
|
+
// 资源排下序,把单个资源靠前,组合资源排在后面
|
|
1165
1193
|
resources.sort((a, b) => {
|
|
1166
|
-
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
if (aIsCombined &&
|
|
1170
|
-
return 1;
|
|
1171
|
-
if (!aIsCombined && bIsCombined)
|
|
1172
|
-
return -1;
|
|
1194
|
+
const aIsCombined = a.metadata?.combined_resource?.status === 1;
|
|
1195
|
+
const bIsCombined = b.metadata?.combined_resource?.status === 1;
|
|
1196
|
+
if (aIsCombined && !bIsCombined) return 1;
|
|
1197
|
+
if (!aIsCombined && bIsCombined) return -1;
|
|
1173
1198
|
return 0;
|
|
1174
1199
|
});
|
|
1175
|
-
const resourcesUseableMap = [
|
|
1176
|
-
|
|
1177
|
-
].reduce((acc, n) => {
|
|
1178
|
-
var _a2;
|
|
1179
|
-
acc[n] = ((_a2 = resourcesMap[n]) == null ? void 0 : _a2.resourceType) === "single" ? false : true;
|
|
1200
|
+
const resourcesUseableMap = [...selectedResources].reduce((acc, n) => {
|
|
1201
|
+
acc[n] = resourcesMap[n]?.resourceType === 'single' ? false : true;
|
|
1180
1202
|
return acc;
|
|
1181
1203
|
}, {});
|
|
1204
|
+
|
|
1205
|
+
// 如果有选择时间了,则代表不是第一种资源了,则需要根据开始时间去匹配
|
|
1206
|
+
// 每个商品
|
|
1182
1207
|
if (timeSlots) {
|
|
1208
|
+
// const start_time = timeSlots.start_at.format("YYYY-MM-DD HH:mm");
|
|
1209
|
+
// const end_time = dayjs(`${dateRange[0].date} ${timeSlots.start_time}`)
|
|
1210
|
+
// .add(duration, durationType as dayjs.ManipulateType)
|
|
1211
|
+
// .format("HH:mm");
|
|
1212
|
+
// 根据 start_time 和 end_time 去匹配资源
|
|
1183
1213
|
let targetResource = null;
|
|
1184
1214
|
let targetResourceTime = 0;
|
|
1185
1215
|
for (const n of resources) {
|
|
1186
|
-
|
|
1187
|
-
|
|
1216
|
+
// 如果资源是独占的,并且 countMap 里选择过这个资源,则直接跳过
|
|
1217
|
+
// if (n.resourceType === 'single' && countMap[n.id]) {
|
|
1218
|
+
// resourcesUseableMap[n.id] = false;
|
|
1219
|
+
// continue
|
|
1220
|
+
// }
|
|
1221
|
+
// const recordCount = countMap[n.id] || 0;
|
|
1222
|
+
// n.times 需要做个过滤,假设 timeSlice.start_at 是 09:30 timeSlice.end_at 是 11:30
|
|
1223
|
+
// time 是 time.start_at = 2025-05-26 10:30, time.end_at = 2025-05-26 12:30
|
|
1224
|
+
// 需要判断 time 的开始结束时间 是否包含timeSlice的开始结束时间
|
|
1225
|
+
const mTimes = n.times.filter(n => {
|
|
1226
|
+
return !(0, _dayjs.default)(n.start_at).isAfter((0, _dayjs.default)(timeSlots.start_at)) && !(0, _dayjs.default)(n.end_at).isBefore((0, _dayjs.default)(timeSlots.end_at));
|
|
1188
1227
|
});
|
|
1228
|
+
// 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
|
|
1189
1229
|
if (mTimes.length === 0) {
|
|
1190
1230
|
continue;
|
|
1191
1231
|
}
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
if (n.resourceType ===
|
|
1232
|
+
// 计算在时间片内有交集的预约容量总和
|
|
1233
|
+
const totalCapacity = (countMap[n.id] || []).reduce((sum, item) => {
|
|
1234
|
+
const hasOverlap = (0, _dayjs.default)(item.time.start_at).isBefore((0, _dayjs.default)(timeSlots.end_at)) && (0, _dayjs.default)(item.time.end_at).isAfter((0, _dayjs.default)(timeSlots.start_at));
|
|
1235
|
+
return hasOverlap ? sum + item.pax : sum;
|
|
1236
|
+
}, 0);
|
|
1237
|
+
|
|
1238
|
+
// 如果资源是单个预约,并且有 totalCapacity,则认为在当前 timeSlots 资源已经被选择过,就不可用了
|
|
1239
|
+
if (n.resourceType === 'single' && totalCapacity > 0) {
|
|
1200
1240
|
continue;
|
|
1201
1241
|
}
|
|
1202
|
-
const canUseTime = mTimes.find(
|
|
1203
|
-
|
|
1204
|
-
const res = (0, import_resources.getIsUsableByTimeItem)({
|
|
1242
|
+
const canUseTime = mTimes.find(item => {
|
|
1243
|
+
const res = (0, _resources.getIsUsableByTimeItem)({
|
|
1205
1244
|
timeSlice: timeSlots,
|
|
1206
1245
|
time: item,
|
|
1207
1246
|
resource: n,
|
|
1208
1247
|
currentCount: totalCapacity + (capacity || 0),
|
|
1209
1248
|
resourcesUseableMap,
|
|
1210
|
-
cut_off_time:
|
|
1249
|
+
cut_off_time: cartItem._productOrigin?.cut_off_time
|
|
1211
1250
|
});
|
|
1212
|
-
|
|
1251
|
+
// 如果只是因为子资源容量不够,而不是子资源被预约导致没时间片,不应该标记子资源为不可用,从而影响组合资源的情况
|
|
1252
|
+
if (resourcesUseableMap?.[n.id] !== false && res.reason !== 'capacityOnly') {
|
|
1213
1253
|
resourcesUseableMap[n.id] = res.usable;
|
|
1214
1254
|
}
|
|
1215
1255
|
return res.usable;
|
|
1216
1256
|
});
|
|
1217
|
-
const currentResourceIdleTime = (0,
|
|
1257
|
+
const currentResourceIdleTime = (0, _timeslots.calculateResourceAvailableTime)({
|
|
1218
1258
|
resource: n,
|
|
1219
1259
|
timeSlots,
|
|
1220
1260
|
currentCapacity: totalCapacity + (capacity || 0)
|
|
@@ -1229,79 +1269,82 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1229
1269
|
selectedResource: targetResource
|
|
1230
1270
|
};
|
|
1231
1271
|
} else {
|
|
1232
|
-
const
|
|
1233
|
-
const resourceIds = resources.map(
|
|
1234
|
-
const
|
|
1272
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(resources);
|
|
1273
|
+
const resourceIds = resources.map(n => n.id);
|
|
1274
|
+
const timeSlots = (0, _resources.getTimeSlicesByResources)({
|
|
1235
1275
|
resourceIds,
|
|
1236
|
-
resourcesMap
|
|
1276
|
+
resourcesMap,
|
|
1237
1277
|
duration,
|
|
1238
1278
|
currentDate: dateRange[0].date,
|
|
1239
1279
|
split: 10,
|
|
1240
1280
|
capacity,
|
|
1241
1281
|
resourcesUseableMap
|
|
1242
1282
|
});
|
|
1243
|
-
|
|
1244
|
-
|
|
1283
|
+
// 如果timeSlots返回了 空数组,代表没有可用的资源了
|
|
1284
|
+
if (!timeSlots) {
|
|
1285
|
+
return; // 给一个提示?
|
|
1245
1286
|
}
|
|
1246
1287
|
return {
|
|
1247
|
-
timeSlots
|
|
1288
|
+
timeSlots,
|
|
1248
1289
|
selectedResource: resources[0]
|
|
1249
1290
|
};
|
|
1250
1291
|
}
|
|
1251
1292
|
}
|
|
1293
|
+
|
|
1252
1294
|
// 给所有购物车里的商品先分配一个资源
|
|
1253
1295
|
autoSelectAllProductResources(resources_code, timeSlots) {
|
|
1254
|
-
var _a;
|
|
1255
1296
|
const dateRange = this.store.date.getDateRange();
|
|
1256
1297
|
const resources = [];
|
|
1257
|
-
if (
|
|
1258
|
-
dateRange.forEach(
|
|
1259
|
-
if (n.resource)
|
|
1260
|
-
resources.push(...n.resource);
|
|
1298
|
+
if (dateRange?.[0]?.date) {
|
|
1299
|
+
dateRange.forEach(n => {
|
|
1300
|
+
if (n.resource) resources.push(...n.resource);
|
|
1261
1301
|
});
|
|
1262
1302
|
}
|
|
1303
|
+
// 一个账号一个账号处理
|
|
1263
1304
|
const errorList = [];
|
|
1305
|
+
// 资源使用情况-单个预约
|
|
1264
1306
|
const selectResourcesMap = {};
|
|
1307
|
+
// 资源使用情况-多个预约
|
|
1265
1308
|
const selectResourcesWithTimeSlots = {};
|
|
1266
1309
|
const accountList = this.store.accountList.getAccounts();
|
|
1267
|
-
const selectForCartResources =
|
|
1268
|
-
let recordTimeSlots = (0,
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
)
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
const hasOriginTimeSlot = Boolean(item._origin.start_time) && Boolean(item._origin.end_time) && !
|
|
1310
|
+
const selectForCartResources = cartItems => {
|
|
1311
|
+
let recordTimeSlots = (0, _lodashEs.cloneDeep)(timeSlots);
|
|
1312
|
+
// timeSlots 传进来的只是用户选中的时间片,但是实际上需要根据多个商品时间进行累加
|
|
1313
|
+
// 假设 timeSlots.start_time 是15:40 duration 是 30min
|
|
1314
|
+
// 第一个商品分配完以后,第二个商品分配的start_time应该是第一个商品的 end_time ,然后 end_time 应该是 start_time+duration
|
|
1315
|
+
// 判断购物车里是否有 flexible 类型的商品,如果有则不累加时间
|
|
1316
|
+
const hasFlexibleProduct = cartItems.some(item => item._productOrigin?.duration?.type === 'flexible');
|
|
1317
|
+
cartItems.forEach((item, index) => {
|
|
1318
|
+
const {
|
|
1319
|
+
currentCapacity
|
|
1320
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(item);
|
|
1321
|
+
const hasOriginTimeSlot = Boolean(item._origin.start_time) && Boolean(item._origin.end_time) && !timeSlots?.start_time;
|
|
1322
|
+
// 如果商品已经有时间数据了,意味着是通过先选日期再选商品流程进来的,相当于时间切片已经选中了
|
|
1279
1323
|
if (hasOriginTimeSlot) {
|
|
1280
1324
|
recordTimeSlots = {
|
|
1281
1325
|
start_time: item._origin.start_time,
|
|
1282
1326
|
end_time: item._origin.end_time,
|
|
1283
|
-
start_at: (0,
|
|
1284
|
-
end_at: (0,
|
|
1327
|
+
start_at: (0, _dayjs.default)(`${item.start_date} ${item._origin.start_time}`),
|
|
1328
|
+
end_at: (0, _dayjs.default)(`${item.end_date} ${item._origin.end_time}`)
|
|
1285
1329
|
};
|
|
1286
1330
|
}
|
|
1287
1331
|
if (recordTimeSlots) {
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
);
|
|
1291
|
-
|
|
1292
|
-
|
|
1332
|
+
// 同一账号下,如果当前商品不是第一个,则需要根据上一个商品的 end_time 和 duration 计算出当前商品的 start_time 和 end_time
|
|
1333
|
+
// 前提:当前资源是单个预约才需要这么做
|
|
1334
|
+
const currentResourceConfig = item._productOrigin?.product_resource?.resources?.find(n => n.code === resources_code);
|
|
1335
|
+
// 只有 duration 类商品且不含有灵活时间的商品需要这个操作
|
|
1336
|
+
if (index !== 0 && recordTimeSlots && currentResourceConfig?.type === 'single' && item._productOrigin?.duration && !hasFlexibleProduct && !hasOriginTimeSlot) {
|
|
1337
|
+
const recordEndAt = recordTimeSlots.end_at ? (0, _dayjs.default)(recordTimeSlots.end_at) : (0, _dayjs.default)(`${item.start_date} ${recordTimeSlots.end_time}`);
|
|
1293
1338
|
let start_at = recordEndAt;
|
|
1294
|
-
let end_at = start_at.add(
|
|
1295
|
-
((_f = (_e = item._productOrigin) == null ? void 0 : _e.duration) == null ? void 0 : _f.value) || 10,
|
|
1296
|
-
"minutes"
|
|
1297
|
-
);
|
|
1339
|
+
let end_at = start_at.add(item._productOrigin?.duration?.value || 10, 'minutes');
|
|
1298
1340
|
recordTimeSlots = {
|
|
1299
|
-
start_time: start_at.format(
|
|
1300
|
-
end_time: end_at.format(
|
|
1341
|
+
start_time: start_at.format('HH:mm'),
|
|
1342
|
+
end_time: end_at.format('HH:mm'),
|
|
1301
1343
|
start_at,
|
|
1302
1344
|
end_at
|
|
1303
1345
|
};
|
|
1304
1346
|
}
|
|
1347
|
+
// 如果传递了 timeSlots,代表是第二种资源,则直接拿 timeSlots 去匹配
|
|
1305
1348
|
const res = this.autoSelectAccountResources({
|
|
1306
1349
|
cartItem: item,
|
|
1307
1350
|
holder_id: item.holder_id,
|
|
@@ -1310,14 +1353,12 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1310
1353
|
countMap: selectResourcesWithTimeSlots,
|
|
1311
1354
|
capacity: currentCapacity
|
|
1312
1355
|
});
|
|
1313
|
-
if (res
|
|
1356
|
+
if (res?.selectedResource) {
|
|
1314
1357
|
if (!selectResourcesWithTimeSlots[res.selectedResource.id]) {
|
|
1315
|
-
selectResourcesWithTimeSlots[res.selectedResource.id] = [
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
}
|
|
1320
|
-
];
|
|
1358
|
+
selectResourcesWithTimeSlots[res.selectedResource.id] = [{
|
|
1359
|
+
pax: currentCapacity,
|
|
1360
|
+
time: recordTimeSlots
|
|
1361
|
+
}];
|
|
1321
1362
|
} else {
|
|
1322
1363
|
selectResourcesWithTimeSlots[res.selectedResource.id].push({
|
|
1323
1364
|
pax: currentCapacity,
|
|
@@ -1325,94 +1366,73 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1325
1366
|
});
|
|
1326
1367
|
}
|
|
1327
1368
|
res.selectedResource.capacity = currentCapacity;
|
|
1328
|
-
(0,
|
|
1369
|
+
(0, _capacity.checkSubResourcesCapacity)(res.selectedResource);
|
|
1329
1370
|
this.store.cart.updateItem({
|
|
1330
1371
|
_id: item._id,
|
|
1331
1372
|
// 这里要做去重,避免出现同样类型的资源被塞进同一个商品
|
|
1332
|
-
resources: [
|
|
1333
|
-
...(item._origin.resources || []).filter(
|
|
1334
|
-
(existingRes) => {
|
|
1335
|
-
var _a3;
|
|
1336
|
-
return existingRes.form_id !== ((_a3 = res.selectedResource) == null ? void 0 : _a3.form_id);
|
|
1337
|
-
}
|
|
1338
|
-
),
|
|
1339
|
-
res.selectedResource
|
|
1340
|
-
]
|
|
1373
|
+
resources: [...(item._origin.resources || []).filter(existingRes => existingRes.form_id !== res.selectedResource?.form_id), res.selectedResource]
|
|
1341
1374
|
});
|
|
1342
1375
|
} else {
|
|
1376
|
+
// 如果没有可用的技师了,推到错误列表里让 UI 去提示
|
|
1343
1377
|
errorList.push(item._id);
|
|
1344
1378
|
}
|
|
1345
1379
|
} else {
|
|
1346
|
-
|
|
1380
|
+
// 这里必须每次循环重新读,避免前一次循环操作了购物车,导致数据变更
|
|
1381
|
+
// 能进到这种逻辑,说明是 duration 类商品或者灵活时长商品,且是第一种资源,还没有确定时间
|
|
1382
|
+
const allCartItems = (0, _lodashEs.cloneDeep)(this.store.cart.getItems());
|
|
1383
|
+
// 如果没有传递 timeSlots,代表是第一种资源,则直接拿商品的 duration,到资源列表里找一个公共可用的
|
|
1347
1384
|
let selectedResources = [];
|
|
1348
|
-
const
|
|
1349
|
-
((_h = (_g = item._productOrigin) == null ? void 0 : _g.product_resource) == null ? void 0 : _h.resources) || []
|
|
1350
|
-
);
|
|
1385
|
+
const resources = (0, _lodashEs.cloneDeep)(item._productOrigin?.product_resource?.resources || []);
|
|
1351
1386
|
const currentResourcesRenderList = [];
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
n.renderList = n.renderList.filter(
|
|
1356
|
-
|
|
1387
|
+
resources.forEach(n => {
|
|
1388
|
+
if (n.renderList?.length) {
|
|
1389
|
+
// 过滤掉 capacity 小于 currentCapacity 的资源
|
|
1390
|
+
n.renderList = n.renderList.filter(m => {
|
|
1391
|
+
// 同时 还需要减去 selectResourcesMap 里已经选中的资源的数量
|
|
1357
1392
|
const recordCount = (m.capacity || 0) - (selectResourcesMap[m.id] || 0);
|
|
1358
|
-
const
|
|
1393
|
+
const timeSlots = (0, _resources.getTimeSlicesByResource)({
|
|
1359
1394
|
resource: m,
|
|
1360
|
-
duration:
|
|
1395
|
+
duration: item?.duration?.value || 10,
|
|
1361
1396
|
split: 10,
|
|
1362
1397
|
currentDate: dateRange[0].date
|
|
1363
1398
|
});
|
|
1364
|
-
return recordCount >= currentCapacity &&
|
|
1399
|
+
return recordCount >= currentCapacity && timeSlots.length > 0;
|
|
1365
1400
|
});
|
|
1366
|
-
currentResourcesRenderList.push(...n.renderList || []);
|
|
1401
|
+
currentResourcesRenderList.push(...(n.renderList || []));
|
|
1367
1402
|
}
|
|
1368
1403
|
});
|
|
1369
|
-
const resourcesMap = (0,
|
|
1404
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(currentResourcesRenderList);
|
|
1370
1405
|
if (item.holder_id) {
|
|
1371
|
-
selectedResources = (0,
|
|
1372
|
-
allCartItems,
|
|
1373
|
-
item.holder_id,
|
|
1374
|
-
resourcesMap
|
|
1375
|
-
);
|
|
1406
|
+
selectedResources = (0, _resources.getOthersSelectedResources)(allCartItems, item.holder_id, resourcesMap);
|
|
1376
1407
|
} else {
|
|
1377
|
-
selectedResources = (0,
|
|
1378
|
-
allCartItems,
|
|
1379
|
-
item._id,
|
|
1380
|
-
resourcesMap
|
|
1381
|
-
);
|
|
1408
|
+
selectedResources = (0, _resources.getOthersCartSelectedResources)(allCartItems, item._id, resourcesMap);
|
|
1382
1409
|
}
|
|
1383
|
-
const productResources = (0,
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
selectedResources,
|
|
1387
|
-
currentCapacity
|
|
1388
|
-
);
|
|
1389
|
-
productResources.forEach((item2) => {
|
|
1390
|
-
item2.renderList = item2.renderList.filter((n) => {
|
|
1410
|
+
const productResources = (0, _resources.getResourcesByProduct)(resourcesMap, (0, _lodashEs.cloneDeep)(resources), selectedResources, currentCapacity);
|
|
1411
|
+
productResources.forEach(item => {
|
|
1412
|
+
item.renderList = item.renderList.filter(n => {
|
|
1391
1413
|
const recordCount = (n.capacity || 0) - (selectResourcesMap[n.id] || 0);
|
|
1392
|
-
if (n.onlyComputed)
|
|
1393
|
-
return false;
|
|
1414
|
+
if (n.onlyComputed) return false;
|
|
1394
1415
|
return recordCount >= currentCapacity;
|
|
1395
1416
|
});
|
|
1396
1417
|
});
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
)) == null ? void 0 : _i.renderList;
|
|
1418
|
+
// 自动选择 productResources 中对应 resources_code 的资源
|
|
1419
|
+
const targetRenderList = productResources.find(n => n.code === resources_code)?.renderList;
|
|
1400
1420
|
if (targetRenderList && targetRenderList.length > 0) {
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
)) {
|
|
1421
|
+
// 如果购物车里已经有同类型的 form_id 的资源了,则不处理
|
|
1422
|
+
if (item._origin.resources?.some(n => n.form_id === targetRenderList[0].form_id)) {
|
|
1404
1423
|
return;
|
|
1405
1424
|
}
|
|
1406
|
-
const fastestResource = (0,
|
|
1425
|
+
const fastestResource = (0, _timeslots.findFastestAvailableResource)({
|
|
1407
1426
|
resources: targetRenderList,
|
|
1408
|
-
currentCapacity,
|
|
1427
|
+
currentCapacity: currentCapacity,
|
|
1409
1428
|
countMap: selectResourcesMap,
|
|
1410
|
-
targetDate:
|
|
1411
|
-
durationMinutes:
|
|
1429
|
+
targetDate: dateRange?.[0]?.date,
|
|
1430
|
+
durationMinutes: item?.duration?.value || item?._productOrigin?.duration?.value || 10
|
|
1412
1431
|
});
|
|
1413
1432
|
const targetResource = fastestResource || targetRenderList[0];
|
|
1414
1433
|
targetResource.capacity = currentCapacity;
|
|
1415
|
-
|
|
1434
|
+
// 在这里处理 children 的数据
|
|
1435
|
+
(0, _capacity.checkSubResourcesCapacity)(targetResource);
|
|
1416
1436
|
if (!selectResourcesMap[targetResource.id]) {
|
|
1417
1437
|
selectResourcesMap[targetResource.id] = currentCapacity;
|
|
1418
1438
|
} else {
|
|
@@ -1420,101 +1440,107 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1420
1440
|
}
|
|
1421
1441
|
this.store.cart.updateItem({
|
|
1422
1442
|
_id: item._id,
|
|
1423
|
-
resources: [
|
|
1424
|
-
...(item._origin.resources || []).filter(
|
|
1425
|
-
(existingRes) => existingRes.resourceType !== targetRenderList[0].resourceType
|
|
1426
|
-
),
|
|
1427
|
-
targetResource
|
|
1428
|
-
]
|
|
1443
|
+
resources: [...(item._origin.resources || []).filter(existingRes => existingRes.resourceType !== targetRenderList[0].resourceType), targetResource]
|
|
1429
1444
|
});
|
|
1430
1445
|
} else {
|
|
1446
|
+
// 如果没有可用的技师了,推到错误列表里让 UI 去提示
|
|
1431
1447
|
errorList.push(item._id);
|
|
1432
1448
|
}
|
|
1433
1449
|
}
|
|
1434
1450
|
});
|
|
1435
1451
|
};
|
|
1436
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1452
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
1453
|
+
|
|
1454
|
+
// 如果购物车里没有 holderid数据,证明不按 holder 类流程预约走,给所有购物车一次性分派即可,不做账号下资源互斥逻辑
|
|
1455
|
+
if (cartItems?.[0].holder_id) {
|
|
1456
|
+
accountList.forEach(account => {
|
|
1457
|
+
const cartItems = this.store.cart.getCartByAccount(account.getId());
|
|
1458
|
+
selectForCartResources(cartItems);
|
|
1441
1459
|
});
|
|
1442
1460
|
} else {
|
|
1443
1461
|
selectForCartResources(cartItems);
|
|
1444
1462
|
}
|
|
1445
|
-
return {
|
|
1463
|
+
return {
|
|
1464
|
+
errorList
|
|
1465
|
+
};
|
|
1446
1466
|
}
|
|
1447
1467
|
// 从购物车中获取已经分配好第一步资源的所有时间片
|
|
1448
1468
|
getTimeSlotByAllResources(resources_code, split = 10) {
|
|
1449
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
1450
1469
|
let dateRange = this.store.date.getDateRange();
|
|
1470
|
+
// 取出购物车中所有一已选择的第一步资源
|
|
1451
1471
|
const resources = [];
|
|
1452
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
1472
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
1473
|
+
// if (cartItems?.[0].start_date) return [];
|
|
1453
1474
|
const resourceIds = [];
|
|
1454
|
-
let resourcesTypeId =
|
|
1475
|
+
let resourcesTypeId = undefined;
|
|
1455
1476
|
let isSingleResource = false;
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1477
|
+
|
|
1478
|
+
// 找出购物车里最大的 cut_off_time
|
|
1479
|
+
let maxCutOffTime = undefined;
|
|
1480
|
+
let maxCutOffTimeValue = (0, _dayjs.default)();
|
|
1481
|
+
cartItems.forEach(item => {
|
|
1482
|
+
item._productOrigin?.product_resource?.resources?.forEach(n => {
|
|
1483
|
+
// TODO: 少了个 status 的判断
|
|
1461
1484
|
if (n.code === resources_code) {
|
|
1462
|
-
resources.push(...n.renderList || []);
|
|
1463
|
-
isSingleResource = n.type ===
|
|
1485
|
+
resources.push(...(n.renderList || []));
|
|
1486
|
+
isSingleResource = n.type === 'single';
|
|
1464
1487
|
}
|
|
1465
1488
|
});
|
|
1489
|
+
// item._origin.resources?.forEach((n: any) => {
|
|
1490
|
+
// resourceIds.push(n.relation_id);
|
|
1491
|
+
// });
|
|
1466
1492
|
if (item.resource_id && !resourceIds.includes(item.resource_id)) {
|
|
1467
1493
|
resourceIds.push(item.resource_id);
|
|
1468
1494
|
}
|
|
1469
|
-
resourcesTypeId =
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
const currentCutOffTime = (0, import_dayjs.default)().add(
|
|
1474
|
-
item._productOrigin.cut_off_time.unit,
|
|
1475
|
-
item._productOrigin.cut_off_time.unit_type
|
|
1476
|
-
);
|
|
1477
|
-
if (currentCutOffTime.isAfter(maxCutOffTimeValue, "minute")) {
|
|
1495
|
+
resourcesTypeId = item?._productOrigin?.product_resource?.resources?.find(n => n.code === resources_code)?.id;
|
|
1496
|
+
if (item._productOrigin?.cut_off_time && item._productOrigin?.cut_off_time.type === 'advance') {
|
|
1497
|
+
const currentCutOffTime = (0, _dayjs.default)().add(item._productOrigin.cut_off_time.unit, item._productOrigin.cut_off_time.unit_type);
|
|
1498
|
+
if (currentCutOffTime.isAfter(maxCutOffTimeValue, 'minute')) {
|
|
1478
1499
|
maxCutOffTimeValue = currentCutOffTime;
|
|
1479
1500
|
maxCutOffTime = item._productOrigin.cut_off_time;
|
|
1480
1501
|
}
|
|
1481
1502
|
}
|
|
1482
1503
|
});
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1504
|
+
// 保险起见,在这里如果 dateRange 里也有 resources 的话,也 push 进去
|
|
1505
|
+
if (dateRange?.[0]?.resource?.length) {
|
|
1506
|
+
// resources.push(...dateRange[0].resource);
|
|
1507
|
+
dateRange[0].resource.forEach(n => {
|
|
1508
|
+
if (n.form_id === resourcesTypeId && !resources.find(m => m.id === n.id)) {
|
|
1486
1509
|
resources.push(n);
|
|
1487
1510
|
}
|
|
1488
1511
|
});
|
|
1489
1512
|
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1513
|
+
// 检查通过购物车 renderList 加入的资源数据里 times 的正确性,如果不对则需要修正
|
|
1514
|
+
if (dateRange?.[0]?.date && resources.length) {
|
|
1515
|
+
const currentDate = dateRange?.[0]?.date;
|
|
1492
1516
|
const theDateResources = this.store.date.getResourcesListByDate(currentDate);
|
|
1493
|
-
resources.forEach(
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
return (0, import_dayjs.default)(n.start_at).isSame((0, import_dayjs.default)(currentDate), "day");
|
|
1517
|
+
resources.forEach(item => {
|
|
1518
|
+
const noCurrentDateTimes = item.times.some(n => {
|
|
1519
|
+
return (0, _dayjs.default)(n.start_at).isSame((0, _dayjs.default)(currentDate), 'day');
|
|
1497
1520
|
});
|
|
1498
1521
|
if (!noCurrentDateTimes) {
|
|
1499
|
-
item.times =
|
|
1522
|
+
item.times = theDateResources?.find(n => n.id === item.id)?.times || [];
|
|
1500
1523
|
}
|
|
1501
1524
|
});
|
|
1502
1525
|
}
|
|
1526
|
+
|
|
1527
|
+
// 如果依然 resources 空的,则证明他是切换日期了,此时直接从 date 模块里取
|
|
1503
1528
|
if (resources.length === 0) {
|
|
1504
|
-
resources.push(...this.store.date.getResourcesListByDate(dateRange[0].date) || []);
|
|
1529
|
+
resources.push(...(this.store.date.getResourcesListByDate(dateRange[0].date) || []));
|
|
1505
1530
|
}
|
|
1506
|
-
const resourcesMap = (0,
|
|
1531
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(resources);
|
|
1507
1532
|
let duration = 0;
|
|
1533
|
+
// duration = 不同账号的最长时间
|
|
1508
1534
|
const accountList = this.store.accountList.getAccounts();
|
|
1509
|
-
const checkDuration =
|
|
1535
|
+
const checkDuration = cartItems => {
|
|
1510
1536
|
let accountDuration = 0;
|
|
1511
|
-
|
|
1512
|
-
|
|
1537
|
+
cartItems.forEach(item => {
|
|
1538
|
+
// 单个预约累加账号 多个预约取最大值
|
|
1513
1539
|
if (isSingleResource) {
|
|
1514
|
-
accountDuration +=
|
|
1540
|
+
accountDuration += item._productOrigin?.duration?.value || 10;
|
|
1515
1541
|
} else {
|
|
1516
|
-
if (accountDuration < (
|
|
1517
|
-
accountDuration =
|
|
1542
|
+
if (accountDuration < (item._productOrigin?.duration?.value || 10)) {
|
|
1543
|
+
accountDuration = item._productOrigin?.duration?.value || 10;
|
|
1518
1544
|
}
|
|
1519
1545
|
}
|
|
1520
1546
|
});
|
|
@@ -1522,74 +1548,68 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1522
1548
|
duration = accountDuration;
|
|
1523
1549
|
}
|
|
1524
1550
|
};
|
|
1525
|
-
if (cartItems
|
|
1526
|
-
accountList.forEach(
|
|
1527
|
-
const
|
|
1528
|
-
checkDuration(
|
|
1551
|
+
if (cartItems?.[0].holder_id) {
|
|
1552
|
+
accountList.forEach(account => {
|
|
1553
|
+
const cartItems = this.store.cart.getCartByAccount(account.getId());
|
|
1554
|
+
checkDuration(cartItems);
|
|
1529
1555
|
});
|
|
1530
1556
|
} else {
|
|
1531
1557
|
checkDuration(cartItems);
|
|
1532
1558
|
}
|
|
1533
|
-
|
|
1559
|
+
// 如果 cartItem 上既没有时间,也没有资源,认为外部属于异常调用,直接丢一个空数组出去
|
|
1560
|
+
// 同时 session 类商品的流程也不应该调用这个方法
|
|
1561
|
+
if (!cartItems?.[0]?.start_date && !cartItems?.[0]?.resource_id || !cartItems?.[0].duration) {
|
|
1534
1562
|
return [];
|
|
1535
1563
|
}
|
|
1536
|
-
if (
|
|
1537
|
-
dateRange = [
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
weekNum: 0
|
|
1549
|
-
}
|
|
1550
|
-
];
|
|
1564
|
+
if (cartItems?.[0].start_date && !dateRange) {
|
|
1565
|
+
dateRange = [{
|
|
1566
|
+
date: cartItems?.[0].start_date,
|
|
1567
|
+
status: 'available',
|
|
1568
|
+
week: '',
|
|
1569
|
+
weekNum: 0
|
|
1570
|
+
}, {
|
|
1571
|
+
date: cartItems?.[0]?.end_date || cartItems?.[0]?.start_date || '',
|
|
1572
|
+
status: 'available',
|
|
1573
|
+
week: '',
|
|
1574
|
+
weekNum: 0
|
|
1575
|
+
}];
|
|
1551
1576
|
}
|
|
1552
1577
|
const resourcesUseableMap = {};
|
|
1553
|
-
const hasFlexibleDuration = cartItems.some(
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
}
|
|
1558
|
-
);
|
|
1559
|
-
let operating_day_boundary = (_j = (_i = this.shopStore.get("core")) == null ? void 0 : _i.core) == null ? void 0 : _j.operating_day_boundary;
|
|
1578
|
+
const hasFlexibleDuration = cartItems.some(item => item._productOrigin?.duration?.type === 'flexible');
|
|
1579
|
+
let operating_day_boundary = this.shopStore.get('core')?.core?.operating_day_boundary;
|
|
1580
|
+
|
|
1581
|
+
// 如果有 hasFlexibleDuration,需要把动态时长商品(可能是多个,取最长的那个最低禁止购买时长)的最低禁止购买时长作为 split 的值
|
|
1560
1582
|
let maxBlockThreshold = 0;
|
|
1561
1583
|
if (hasFlexibleDuration) {
|
|
1562
1584
|
maxBlockThreshold = cartItems.reduce((max, item) => {
|
|
1563
|
-
|
|
1564
|
-
if (
|
|
1565
|
-
return Math.max(
|
|
1566
|
-
max,
|
|
1567
|
-
((_f2 = (_e2 = (_d2 = item._productOrigin) == null ? void 0 : _d2.duration) == null ? void 0 : _e2.flexible_config) == null ? void 0 : _f2.block_threshold) || 0
|
|
1568
|
-
);
|
|
1585
|
+
// 如果开启了灵活时长商品配置,则取 block_threshold 的值
|
|
1586
|
+
if (item._productOrigin?.duration?.flexible_config?.is_enable_minimum_duration) {
|
|
1587
|
+
return Math.max(max, item._productOrigin?.duration?.flexible_config?.block_threshold || 0);
|
|
1569
1588
|
}
|
|
1570
1589
|
return 0;
|
|
1571
1590
|
}, 0);
|
|
1572
1591
|
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
if (items.length === 0)
|
|
1576
|
-
|
|
1577
|
-
const firstResource =
|
|
1578
|
-
const sameResourceLength = items.filter(
|
|
1579
|
-
var _a3;
|
|
1580
|
-
return ((_a3 = item._resourceOrigin) == null ? void 0 : _a3[0].id) === firstResource;
|
|
1581
|
-
}).length;
|
|
1592
|
+
// 计算容量的辅助函数
|
|
1593
|
+
const calculateCapacityFromCartItems = items => {
|
|
1594
|
+
if (items.length === 0) return 0;
|
|
1595
|
+
// 还需要增加一个判断,maxCapacity 必须是我单个人里选择的资源只有同一种的情况下才可以累加,否则单个账号都是 1
|
|
1596
|
+
const firstResource = items[0]._resourceOrigin?.[0].id;
|
|
1597
|
+
const sameResourceLength = items.filter(item => item._resourceOrigin?.[0].id === firstResource).length;
|
|
1582
1598
|
if (sameResourceLength === items.length) {
|
|
1583
1599
|
return 1;
|
|
1584
1600
|
}
|
|
1585
|
-
|
|
1601
|
+
// 找出单个购物车里最大的需求 capacity 即可
|
|
1602
|
+
return Math.max(...items.map(item => (0, _capacity.getCapacityInfoByCartItem)(item).currentCapacity || 1));
|
|
1603
|
+
// return items.reduce((total, item) => {
|
|
1604
|
+
// return total + (getCapacityInfoByCartItem(item).currentCapacity || 0);
|
|
1605
|
+
// }, 0);
|
|
1586
1606
|
};
|
|
1607
|
+
|
|
1608
|
+
// 如果是多个人预约,去要求出几个 holder 下最大的商品需求容量capacity
|
|
1587
1609
|
let maxCapacity = 1;
|
|
1588
|
-
if (cartItems
|
|
1589
|
-
accountList.forEach(
|
|
1590
|
-
const accountCartItems = this.store.cart.getCartByAccount(
|
|
1591
|
-
account.getId()
|
|
1592
|
-
);
|
|
1610
|
+
if (cartItems?.[0].holder_id) {
|
|
1611
|
+
accountList.forEach(account => {
|
|
1612
|
+
const accountCartItems = this.store.cart.getCartByAccount(account.getId());
|
|
1593
1613
|
const currentCapacity = calculateCapacityFromCartItems(accountCartItems);
|
|
1594
1614
|
if (currentCapacity > maxCapacity) {
|
|
1595
1615
|
maxCapacity = currentCapacity;
|
|
@@ -1598,13 +1618,13 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1598
1618
|
} else {
|
|
1599
1619
|
maxCapacity = calculateCapacityFromCartItems(cartItems);
|
|
1600
1620
|
}
|
|
1601
|
-
const timeSlots = (0,
|
|
1621
|
+
const timeSlots = (0, _resources.getTimeSlicesByResources)({
|
|
1602
1622
|
resourceIds,
|
|
1603
1623
|
resourcesMap,
|
|
1604
1624
|
duration,
|
|
1605
1625
|
currentDate: dateRange[0].date,
|
|
1606
|
-
split,
|
|
1607
|
-
resourcesUseableMap,
|
|
1626
|
+
split: split,
|
|
1627
|
+
resourcesUseableMap: resourcesUseableMap,
|
|
1608
1628
|
capacity: maxCapacity,
|
|
1609
1629
|
cut_off_time: maxCutOffTime,
|
|
1610
1630
|
hasFlexibleDuration,
|
|
@@ -1614,61 +1634,70 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1614
1634
|
return timeSlots;
|
|
1615
1635
|
}
|
|
1616
1636
|
// 从购物车中获取已经分配好第一步资源的所有时间片,批量版本,用于给日期提供能否高亮的判断
|
|
1617
|
-
async getTimeSlotByAllResourcesForDate({
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1637
|
+
async getTimeSlotByAllResourcesForDate({
|
|
1638
|
+
resources_code,
|
|
1639
|
+
startDate,
|
|
1640
|
+
endDate
|
|
1641
|
+
}) {
|
|
1642
|
+
// 如果 end_date 距离start_date小于 30 天,自动追加 end_date 为今天往后的 30 天
|
|
1643
|
+
if ((0, _dayjs.default)(endDate).diff((0, _dayjs.default)(startDate), 'day') < 30) {
|
|
1644
|
+
endDate = (0, _dayjs.default)(startDate).add(30, 'day').format('YYYY-MM-DD');
|
|
1621
1645
|
}
|
|
1646
|
+
// 预请求资源数据,防止日期超过之前选择的范围
|
|
1622
1647
|
await this.getAvailableDate({
|
|
1623
|
-
startDate,
|
|
1624
|
-
endDate,
|
|
1648
|
+
startDate: startDate,
|
|
1649
|
+
endDate: endDate,
|
|
1625
1650
|
useCache: true
|
|
1626
1651
|
});
|
|
1652
|
+
// 取出购物车中所有一已选择的第一步资源
|
|
1627
1653
|
const resources = [];
|
|
1628
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
1654
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
1655
|
+
// if (cartItems?.[0].start_date) return [];
|
|
1629
1656
|
const resourceIds = [];
|
|
1630
|
-
let resourcesTypeId =
|
|
1657
|
+
let resourcesTypeId = undefined;
|
|
1631
1658
|
let isSingleResource = false;
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1659
|
+
|
|
1660
|
+
// 找出购物车里最大的 cut_off_time
|
|
1661
|
+
let maxCutOffTime = undefined;
|
|
1662
|
+
let maxCutOffTimeValue = (0, _dayjs.default)();
|
|
1663
|
+
cartItems.forEach(item => {
|
|
1664
|
+
item._productOrigin?.product_resource?.resources?.forEach(n => {
|
|
1665
|
+
// TODO: 少了个 status 的判断
|
|
1637
1666
|
if (n.code === resources_code) {
|
|
1638
|
-
resources.push(...n.renderList || []);
|
|
1639
|
-
isSingleResource = n.type ===
|
|
1667
|
+
resources.push(...(n.renderList || []));
|
|
1668
|
+
isSingleResource = n.type === 'single';
|
|
1640
1669
|
}
|
|
1641
1670
|
});
|
|
1671
|
+
// item._origin.resources?.forEach((n: any) => {
|
|
1672
|
+
// resourceIds.push(n.relation_id);
|
|
1673
|
+
// });
|
|
1642
1674
|
if (item.resource_id && !resourceIds.includes(item.resource_id)) {
|
|
1643
1675
|
resourceIds.push(item.resource_id);
|
|
1644
1676
|
}
|
|
1645
|
-
resourcesTypeId =
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
const currentCutOffTime = (0, import_dayjs.default)().add(
|
|
1650
|
-
item._productOrigin.cut_off_time.unit,
|
|
1651
|
-
item._productOrigin.cut_off_time.unit_type
|
|
1652
|
-
);
|
|
1653
|
-
if (currentCutOffTime.isAfter(maxCutOffTimeValue, "minute")) {
|
|
1677
|
+
resourcesTypeId = item?._productOrigin?.product_resource?.resources?.find(n => n.code === resources_code)?.id;
|
|
1678
|
+
if (item._productOrigin?.cut_off_time && item._productOrigin?.cut_off_time.type === 'advance') {
|
|
1679
|
+
const currentCutOffTime = (0, _dayjs.default)().add(item._productOrigin.cut_off_time.unit, item._productOrigin.cut_off_time.unit_type);
|
|
1680
|
+
if (currentCutOffTime.isAfter(maxCutOffTimeValue, 'minute')) {
|
|
1654
1681
|
maxCutOffTimeValue = currentCutOffTime;
|
|
1655
1682
|
maxCutOffTime = item._productOrigin.cut_off_time;
|
|
1656
1683
|
}
|
|
1657
1684
|
}
|
|
1658
1685
|
});
|
|
1659
|
-
|
|
1660
|
-
|
|
1686
|
+
|
|
1687
|
+
// 保护: 如果 resources 为空则直接 return
|
|
1688
|
+
if (!resources.length) return [];
|
|
1661
1689
|
let duration = 0;
|
|
1690
|
+
// duration = 不同账号的最长时间
|
|
1662
1691
|
const accountList = this.store.accountList.getAccounts();
|
|
1663
|
-
const checkDuration =
|
|
1692
|
+
const checkDuration = cartItems => {
|
|
1664
1693
|
let accountDuration = 0;
|
|
1665
|
-
|
|
1666
|
-
|
|
1694
|
+
cartItems.forEach(item => {
|
|
1695
|
+
// 单个预约累加账号 多个预约取最大值
|
|
1667
1696
|
if (isSingleResource) {
|
|
1668
|
-
accountDuration +=
|
|
1697
|
+
accountDuration += item._productOrigin?.duration?.value || 10;
|
|
1669
1698
|
} else {
|
|
1670
|
-
if (accountDuration < (
|
|
1671
|
-
accountDuration =
|
|
1699
|
+
if (accountDuration < (item._productOrigin?.duration?.value || 10)) {
|
|
1700
|
+
accountDuration = item._productOrigin?.duration?.value || 10;
|
|
1672
1701
|
}
|
|
1673
1702
|
}
|
|
1674
1703
|
});
|
|
@@ -1676,52 +1705,50 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1676
1705
|
duration = accountDuration;
|
|
1677
1706
|
}
|
|
1678
1707
|
};
|
|
1679
|
-
if (cartItems
|
|
1680
|
-
accountList.forEach(
|
|
1681
|
-
const
|
|
1682
|
-
checkDuration(
|
|
1708
|
+
if (cartItems?.[0].holder_id) {
|
|
1709
|
+
accountList.forEach(account => {
|
|
1710
|
+
const cartItems = this.store.cart.getCartByAccount(account.getId());
|
|
1711
|
+
checkDuration(cartItems);
|
|
1683
1712
|
});
|
|
1684
1713
|
} else {
|
|
1685
1714
|
checkDuration(cartItems);
|
|
1686
1715
|
}
|
|
1687
|
-
|
|
1716
|
+
// 如果 cartItem 上既没有时间,也没有资源,认为外部属于异常调用,直接丢一个空数组出去
|
|
1717
|
+
// 同时 session 类商品的流程也不应该调用这个方法
|
|
1718
|
+
if (!cartItems?.[0]?.start_date && !cartItems?.[0]?.resource_id || !cartItems?.[0].duration) {
|
|
1688
1719
|
return [];
|
|
1689
1720
|
}
|
|
1690
1721
|
const resourcesUseableMap = {};
|
|
1691
|
-
const hasFlexibleDuration = cartItems.some(
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
}
|
|
1696
|
-
);
|
|
1697
|
-
let operating_day_boundary = (_d = (_c = this.shopStore.get("core")) == null ? void 0 : _c.core) == null ? void 0 : _d.operating_day_boundary;
|
|
1722
|
+
const hasFlexibleDuration = cartItems.some(item => item._productOrigin?.duration?.type === 'flexible');
|
|
1723
|
+
let operating_day_boundary = this.shopStore.get('core')?.core?.operating_day_boundary;
|
|
1724
|
+
|
|
1725
|
+
// 如果有 hasFlexibleDuration,需要把动态时长商品(可能是多个,取最长的那个最低禁止购买时长)的最低禁止购买时长作为 split 的值
|
|
1698
1726
|
let maxBlockThreshold = 0;
|
|
1699
1727
|
if (hasFlexibleDuration) {
|
|
1700
1728
|
maxBlockThreshold = cartItems.reduce((max, item) => {
|
|
1701
|
-
|
|
1702
|
-
if (
|
|
1703
|
-
return Math.max(max,
|
|
1729
|
+
// 如果开启了灵活时长商品配置,则取 block_threshold 的值
|
|
1730
|
+
if (item._productOrigin?.duration?.flexible_config?.is_enable_minimum_duration) {
|
|
1731
|
+
return Math.max(max, item._productOrigin?.duration?.flexible_config?.block_threshold || 0);
|
|
1704
1732
|
}
|
|
1705
1733
|
return 0;
|
|
1706
1734
|
}, 0);
|
|
1707
1735
|
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
if (items.length === 0)
|
|
1711
|
-
|
|
1712
|
-
const firstResource =
|
|
1713
|
-
const sameResourceLength = items.filter(
|
|
1714
|
-
var _a3;
|
|
1715
|
-
return ((_a3 = item._resourceOrigin) == null ? void 0 : _a3[0].id) === firstResource;
|
|
1716
|
-
}).length;
|
|
1736
|
+
// 计算容量的辅助函数
|
|
1737
|
+
const calculateCapacityFromCartItems = items => {
|
|
1738
|
+
if (items.length === 0) return 0;
|
|
1739
|
+
// 还需要增加一个判断,maxCapacity 必须是我单个人里选择的资源只有同一种的情况下才可以累加,否则单个账号都是 1
|
|
1740
|
+
const firstResource = items[0]._resourceOrigin?.[0].id;
|
|
1741
|
+
const sameResourceLength = items.filter(item => item._resourceOrigin?.[0].id === firstResource).length;
|
|
1717
1742
|
if (sameResourceLength !== items.length) {
|
|
1718
1743
|
return 1;
|
|
1719
1744
|
}
|
|
1720
|
-
|
|
1745
|
+
// 找出单个购物车里最大的需求 capacity 即可
|
|
1746
|
+
return Math.max(...items.map(item => (0, _capacity.getCapacityInfoByCartItem)(item).currentCapacity || 1));
|
|
1721
1747
|
};
|
|
1748
|
+
// 如果是多个预约,去要求出几个 holder 下最大的需求容量capacity
|
|
1722
1749
|
let maxCapacity = 1;
|
|
1723
|
-
if (cartItems
|
|
1724
|
-
accountList.forEach(
|
|
1750
|
+
if (cartItems?.[0].holder_id) {
|
|
1751
|
+
accountList.forEach(account => {
|
|
1725
1752
|
const accountCartItems = this.store.cart.getCartByAccount(account.getId());
|
|
1726
1753
|
const currentCapacity = calculateCapacityFromCartItems(accountCartItems);
|
|
1727
1754
|
if (currentCapacity > maxCapacity) {
|
|
@@ -1732,31 +1759,33 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1732
1759
|
maxCapacity = calculateCapacityFromCartItems(cartItems);
|
|
1733
1760
|
}
|
|
1734
1761
|
const arr = [];
|
|
1735
|
-
const today = (0,
|
|
1736
|
-
|
|
1737
|
-
|
|
1762
|
+
const today = (0, _dayjs.default)().startOf('day');
|
|
1763
|
+
// 计算 start_date 到 end_date 之间的所有日期,遍历他们并且计算每一天的可用
|
|
1764
|
+
for (let i = (0, _dayjs.default)(startDate); i.isBefore((0, _dayjs.default)(endDate)); i = i.add(1, 'day')) {
|
|
1765
|
+
const currentDate = i.format('YYYY-MM-DD');
|
|
1738
1766
|
const theDateResources = this.store.date.getResourcesListByDate(currentDate);
|
|
1739
|
-
resources.forEach(
|
|
1740
|
-
|
|
1741
|
-
item.times = ((_a2 = theDateResources == null ? void 0 : theDateResources.find((n) => n.id === item.id)) == null ? void 0 : _a2.times) || [];
|
|
1767
|
+
resources.forEach(item => {
|
|
1768
|
+
item.times = theDateResources?.find(n => n.id === item.id)?.times || [];
|
|
1742
1769
|
});
|
|
1743
|
-
const resourcesMap = (0,
|
|
1770
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(resources);
|
|
1771
|
+
|
|
1772
|
+
// 如果日期已经过期则直接标记为不可用
|
|
1744
1773
|
if (i.isBefore(today)) {
|
|
1745
1774
|
arr.push({
|
|
1746
1775
|
date: currentDate,
|
|
1747
|
-
status:
|
|
1748
|
-
week: i.format(
|
|
1776
|
+
status: 'unavailable',
|
|
1777
|
+
week: i.format('ddd'),
|
|
1749
1778
|
weekNum: i.day()
|
|
1750
1779
|
});
|
|
1751
1780
|
continue;
|
|
1752
1781
|
}
|
|
1753
|
-
const timeSlots = (0,
|
|
1782
|
+
const timeSlots = (0, _resources.getTimeSlicesByResources)({
|
|
1754
1783
|
resourceIds,
|
|
1755
1784
|
resourcesMap,
|
|
1756
1785
|
duration,
|
|
1757
|
-
currentDate,
|
|
1786
|
+
currentDate: currentDate,
|
|
1758
1787
|
split: 10,
|
|
1759
|
-
resourcesUseableMap,
|
|
1788
|
+
resourcesUseableMap: resourcesUseableMap,
|
|
1760
1789
|
capacity: maxCapacity,
|
|
1761
1790
|
cut_off_time: maxCutOffTime,
|
|
1762
1791
|
hasFlexibleDuration,
|
|
@@ -1766,63 +1795,74 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1766
1795
|
if (timeSlots.length > 0) {
|
|
1767
1796
|
arr.push({
|
|
1768
1797
|
date: currentDate,
|
|
1769
|
-
status:
|
|
1770
|
-
week: i.format(
|
|
1798
|
+
status: 'available',
|
|
1799
|
+
week: i.format('ddd'),
|
|
1771
1800
|
weekNum: i.day()
|
|
1772
1801
|
});
|
|
1773
1802
|
} else {
|
|
1774
1803
|
arr.push({
|
|
1775
1804
|
date: currentDate,
|
|
1776
|
-
status:
|
|
1777
|
-
week: i.format(
|
|
1805
|
+
status: 'unavailable',
|
|
1806
|
+
week: i.format('ddd'),
|
|
1778
1807
|
weekNum: i.day()
|
|
1779
1808
|
});
|
|
1780
1809
|
}
|
|
1781
1810
|
}
|
|
1782
1811
|
return arr;
|
|
1783
1812
|
}
|
|
1813
|
+
|
|
1784
1814
|
// 提交时间切片,绑定到对应购物车的商品上,更新购物车---只有 duration 商品
|
|
1785
1815
|
submitTimeSlot(timeSlots) {
|
|
1786
|
-
|
|
1787
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
);
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1816
|
+
// 以账号为维度处理数据。购物车里每一项的 startTime应该是前一个商品的 endTime,如果是第一个商品则用 timeSlots.start_at
|
|
1817
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
1818
|
+
|
|
1819
|
+
// 取出所有资源列表
|
|
1820
|
+
const allResources = this.store.date.getResourcesListByDate(timeSlots.start_at.format('YYYY-MM-DD'));
|
|
1821
|
+
|
|
1822
|
+
// 按账号分组
|
|
1823
|
+
const itemsByAccount = cartItems.reduce((acc, item) => {
|
|
1824
|
+
const holderId = item.holder_id;
|
|
1825
|
+
if (!acc[holderId]) {
|
|
1826
|
+
acc[holderId] = [];
|
|
1827
|
+
}
|
|
1828
|
+
acc[holderId].push(item);
|
|
1829
|
+
return acc;
|
|
1830
|
+
}, {});
|
|
1831
|
+
|
|
1832
|
+
// 店铺营业结束时间
|
|
1833
|
+
const operating_day_boundary = this.shopStore.get('core')?.core?.operating_day_boundary;
|
|
1834
|
+
|
|
1835
|
+
// 处理每个账号的商品
|
|
1836
|
+
Object.values(itemsByAccount).forEach(accountItems => {
|
|
1837
|
+
let currentStartTime = timeSlots.start_at.format('YYYY-MM-DD HH:mm');
|
|
1805
1838
|
accountItems.forEach((item, index) => {
|
|
1806
|
-
var _a2;
|
|
1807
1839
|
const osWarnTips = [];
|
|
1808
|
-
const newResources = (0,
|
|
1809
|
-
newResources.forEach(
|
|
1810
|
-
|
|
1811
|
-
if (
|
|
1812
|
-
|
|
1813
|
-
|
|
1840
|
+
const newResources = (0, _lodashEs.cloneDeep)(item._origin.resources);
|
|
1841
|
+
newResources.forEach(resource => {
|
|
1842
|
+
// 如果商品配置的是灵活时长,开始时间设置为提交的时间,结束时间从资源的可用最晚时间和店铺营业结束时间里取一个最早的
|
|
1843
|
+
if (item._productOrigin?.duration?.type === 'flexible') {
|
|
1844
|
+
item.duration = {
|
|
1845
|
+
type: 'minutes',
|
|
1846
|
+
value: 10
|
|
1847
|
+
};
|
|
1848
|
+
resource.startTime = timeSlots.start_at.format('YYYY-MM-DD HH:mm');
|
|
1849
|
+
// 找到resource.times里最晚的end_at
|
|
1850
|
+
const targetResourceTimes = allResources?.find(n => n.id === resource.id)?.times;
|
|
1851
|
+
// 找到最晚的 end_at 还没用,因为可能存在资源工作时间是 10:00-19:00,但是资源的 times 里有 16:30-19:00 被 block 的情况
|
|
1852
|
+
// 所以还需要排除掉 block 时间
|
|
1853
|
+
function getEarliestBlockedStartTime({
|
|
1854
|
+
currentStartTime,
|
|
1814
1855
|
times
|
|
1815
1856
|
}) {
|
|
1816
|
-
|
|
1817
|
-
const currentStart = (0, import_dayjs.default)(currentStartTime2);
|
|
1857
|
+
const currentStart = (0, _dayjs.default)(currentStartTime);
|
|
1818
1858
|
let earliestBlockStart;
|
|
1819
1859
|
for (const time of times || []) {
|
|
1820
|
-
const blockedTimes =
|
|
1860
|
+
const blockedTimes = time.event_list?.filter(event => event.type !== 'schedule_event');
|
|
1821
1861
|
for (const event of blockedTimes || []) {
|
|
1822
|
-
const eventStart = (0,
|
|
1823
|
-
const eventEnd = (0,
|
|
1862
|
+
const eventStart = (0, _dayjs.default)(event.start_at);
|
|
1863
|
+
const eventEnd = (0, _dayjs.default)(event.end_at);
|
|
1824
1864
|
if (eventStart.isBefore(currentStart) && eventEnd.isAfter(currentStart)) {
|
|
1825
|
-
return currentStart.format(
|
|
1865
|
+
return currentStart.format('YYYY-MM-DD HH:mm');
|
|
1826
1866
|
}
|
|
1827
1867
|
if (eventStart.isAfter(currentStart)) {
|
|
1828
1868
|
if (!earliestBlockStart || eventStart.isBefore(earliestBlockStart)) {
|
|
@@ -1831,79 +1871,68 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1831
1871
|
}
|
|
1832
1872
|
}
|
|
1833
1873
|
}
|
|
1834
|
-
return earliestBlockStart
|
|
1835
|
-
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
};
|
|
1840
|
-
resource.startTime = timeSlots.start_at.format("YYYY-MM-DD HH:mm");
|
|
1841
|
-
const targetResourceTimes = (_c = allResources == null ? void 0 : allResources.find(
|
|
1842
|
-
(n) => n.id === resource.id
|
|
1843
|
-
)) == null ? void 0 : _c.times;
|
|
1844
|
-
const resourcesEndTime = targetResourceTimes.reduce(
|
|
1845
|
-
(acc, curr) => {
|
|
1846
|
-
return (0, import_dayjs.default)(curr.end_at).isAfter((0, import_dayjs.default)(acc.end_at)) ? curr : acc;
|
|
1847
|
-
},
|
|
1848
|
-
targetResourceTimes[0]
|
|
1849
|
-
);
|
|
1874
|
+
return earliestBlockStart?.format('YYYY-MM-DD HH:mm');
|
|
1875
|
+
}
|
|
1876
|
+
const resourcesEndTime = targetResourceTimes.reduce((acc, curr) => {
|
|
1877
|
+
return (0, _dayjs.default)(curr.end_at).isAfter((0, _dayjs.default)(acc.end_at)) ? curr : acc;
|
|
1878
|
+
}, targetResourceTimes[0]);
|
|
1850
1879
|
const earliestBlockedStartTime = getEarliestBlockedStartTime({
|
|
1851
1880
|
currentStartTime,
|
|
1852
1881
|
times: targetResourceTimes
|
|
1853
1882
|
});
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
);
|
|
1857
|
-
const operatingBoundaryDateTime = `${resourceDate} ${operating_day_boundary.type ===
|
|
1858
|
-
const endTimeCandidates = [
|
|
1859
|
-
resourcesEndTime.end_at,
|
|
1860
|
-
operatingBoundaryDateTime,
|
|
1861
|
-
...earliestBlockedStartTime ? [earliestBlockedStartTime] : []
|
|
1862
|
-
];
|
|
1883
|
+
|
|
1884
|
+
// 将 operating_day_boundary 转换为与 resourcesEndTime.end_at 相同日期的完整日期时间
|
|
1885
|
+
const resourceDate = (0, _dayjs.default)(resourcesEndTime.end_at).format('YYYY-MM-DD');
|
|
1886
|
+
const operatingBoundaryDateTime = `${resourceDate} ${operating_day_boundary.type === 'start_time' ? '23:59' : operating_day_boundary.time}`;
|
|
1887
|
+
const endTimeCandidates = [resourcesEndTime.end_at, operatingBoundaryDateTime, ...(earliestBlockedStartTime ? [earliestBlockedStartTime] : [])];
|
|
1863
1888
|
const endTime = endTimeCandidates.reduce((earliest, value) => {
|
|
1864
|
-
return (0,
|
|
1889
|
+
return (0, _dayjs.default)(value).isBefore((0, _dayjs.default)(earliest)) ? value : earliest;
|
|
1865
1890
|
}, endTimeCandidates[0]);
|
|
1891
|
+
// 修复:如果 endTime 只是时间格式(如 "17:00"),需要加上日期
|
|
1866
1892
|
let formattedEndTime;
|
|
1867
|
-
if (typeof endTime ===
|
|
1868
|
-
|
|
1869
|
-
|
|
1893
|
+
if (typeof endTime === 'string' && endTime.includes(':') && !endTime.includes(' ') && !endTime.includes('T')) {
|
|
1894
|
+
// 如果是纯时间格式,与当前日期合并
|
|
1895
|
+
const currentDate = timeSlots.start_at.format('YYYY-MM-DD');
|
|
1896
|
+
formattedEndTime = (0, _dayjs.default)(`${currentDate} ${endTime}`);
|
|
1870
1897
|
} else {
|
|
1871
|
-
formattedEndTime = (0,
|
|
1898
|
+
formattedEndTime = (0, _dayjs.default)(endTime);
|
|
1872
1899
|
}
|
|
1873
|
-
resource.endTime = formattedEndTime.format(
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1900
|
+
resource.endTime = formattedEndTime.format('YYYY-MM-DD HH:mm');
|
|
1901
|
+
// 如果是动态时长商品,并且当前选择的时间的结束时间小于了最低提示时长(warningThreshold),则追加一个提示
|
|
1902
|
+
// 如果currentStartTime + warningThreshold 大于 currentEndTime,且 osWarnTips 没有pisell2.product.card.closing-soon.warning 这一项,则加入这一项
|
|
1903
|
+
if (item._productOrigin?.duration?.flexible_config?.is_enable_minimum_duration && (0, _dayjs.default)(currentStartTime).add(item._productOrigin?.duration?.flexible_config?.warning_threshold || 0, 'minutes').isAfter((0, _dayjs.default)(formattedEndTime))) {
|
|
1904
|
+
if (!osWarnTips.includes('pisell2.product.card.closing-soon.warning')) {
|
|
1905
|
+
osWarnTips.push('pisell2.product.card.closing-soon.warning');
|
|
1877
1906
|
}
|
|
1878
1907
|
}
|
|
1879
1908
|
} else {
|
|
1880
1909
|
resource.startTime = currentStartTime;
|
|
1881
|
-
resource.endTime = (0,
|
|
1910
|
+
resource.endTime = (0, _dayjs.default)(currentStartTime).add(item._productOrigin?.duration?.value || 10, 'minutes').format('YYYY-MM-DD HH:mm');
|
|
1882
1911
|
}
|
|
1912
|
+
// delete resource.times;
|
|
1883
1913
|
});
|
|
1884
1914
|
this.store.cart.updateItem({
|
|
1885
1915
|
_id: item._id,
|
|
1886
1916
|
resources: newResources,
|
|
1887
1917
|
osWarnTips
|
|
1888
1918
|
});
|
|
1889
|
-
|
|
1919
|
+
|
|
1920
|
+
// 更新下一个商品的开始时间为当前商品的结束时间
|
|
1921
|
+
if (index < accountItems.length - 1 && newResources?.[0]?.resourceType === 'single') {
|
|
1890
1922
|
currentStartTime = newResources[0].endTime;
|
|
1891
1923
|
}
|
|
1892
1924
|
});
|
|
1893
1925
|
});
|
|
1894
|
-
this.core.effects.emit(
|
|
1895
|
-
`${this.store.cart.name}:onUpdateBookingDate`,
|
|
1896
|
-
{}
|
|
1897
|
-
);
|
|
1926
|
+
this.core.effects.emit(`${this.store.cart.name}:onUpdateBookingDate`, {});
|
|
1898
1927
|
}
|
|
1899
1928
|
getScheduleDataByIds(scheduleIds) {
|
|
1900
1929
|
const targetSchedules = this.store.schedule.getScheduleListByIds(scheduleIds);
|
|
1901
|
-
const targetSchedulesData = targetSchedules.map(
|
|
1902
|
-
return (0,
|
|
1930
|
+
const targetSchedulesData = targetSchedules.map(item => {
|
|
1931
|
+
return (0, _utils3.calcCalendarDataByScheduleResult)(item);
|
|
1903
1932
|
});
|
|
1904
1933
|
const newSchedule = {};
|
|
1905
|
-
targetSchedulesData.forEach(
|
|
1906
|
-
item.forEach(
|
|
1934
|
+
targetSchedulesData.forEach(item => {
|
|
1935
|
+
item.forEach(n => {
|
|
1907
1936
|
if (!newSchedule[n.date]) {
|
|
1908
1937
|
newSchedule[n.date] = n;
|
|
1909
1938
|
} else {
|
|
@@ -1914,8 +1943,9 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1914
1943
|
});
|
|
1915
1944
|
});
|
|
1916
1945
|
const newScheduleArr = Object.values(newSchedule);
|
|
1946
|
+
// newScheduleArr 需要做个排序,按日期从小到大
|
|
1917
1947
|
newScheduleArr.sort((a, b) => {
|
|
1918
|
-
return (0,
|
|
1948
|
+
return (0, _dayjs.default)(a.date).diff((0, _dayjs.default)(b.date));
|
|
1919
1949
|
});
|
|
1920
1950
|
return newScheduleArr;
|
|
1921
1951
|
}
|
|
@@ -1925,17 +1955,22 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1925
1955
|
if (targetProductData) {
|
|
1926
1956
|
this.store.currentProduct = targetProductData;
|
|
1927
1957
|
this.store.currentProductMeta = {};
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
);
|
|
1932
|
-
if (!this.store.currentProductMeta)
|
|
1933
|
-
this.store.currentProductMeta = {};
|
|
1958
|
+
// 资源预加载,如果是 duration 类型的商品,且是先选日期的流程,在这里预拉取资源数据
|
|
1959
|
+
if (targetProductData['schedule.ids']) {
|
|
1960
|
+
const newScheduleArr = this.getScheduleDataByIds(targetProductData['schedule.ids']);
|
|
1961
|
+
if (!this.store.currentProductMeta) this.store.currentProductMeta = {};
|
|
1934
1962
|
this.store.currentProductMeta.schedule = newScheduleArr;
|
|
1935
1963
|
} else if (targetProductData.duration) {
|
|
1936
1964
|
const dateRange = this.store.date.getDateRange();
|
|
1937
|
-
|
|
1938
|
-
|
|
1965
|
+
// 如果不是先选日期的流程 duration 商品就啥也不做
|
|
1966
|
+
if (!dateRange?.length) return;
|
|
1967
|
+
// this.store.date.getResourceDates({
|
|
1968
|
+
// query: {
|
|
1969
|
+
// start_date: dateRange[0].date,
|
|
1970
|
+
// end_date: dateRange[dateRange.length - 1].date,
|
|
1971
|
+
// resource_ids: targetProductData.product_resource?.resources?.map((n: any) => n.id),
|
|
1972
|
+
// },
|
|
1973
|
+
// });
|
|
1939
1974
|
this.getAvailableDate({
|
|
1940
1975
|
startDate: dateRange[0].date,
|
|
1941
1976
|
endDate: dateRange[dateRange.length - 1].date,
|
|
@@ -1948,8 +1983,9 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1948
1983
|
if (this.store.currentProductMeta) {
|
|
1949
1984
|
this.store.currentProductMeta.schedule = [];
|
|
1950
1985
|
}
|
|
1951
|
-
this.store.currentProduct =
|
|
1986
|
+
this.store.currentProduct = undefined;
|
|
1952
1987
|
}
|
|
1988
|
+
|
|
1953
1989
|
// 通过商品和 schedule 来获取视频可用的时间片、时间片内资源可用的数据
|
|
1954
1990
|
getTimeslotBySchedule({
|
|
1955
1991
|
date,
|
|
@@ -1957,59 +1993,43 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1957
1993
|
resources,
|
|
1958
1994
|
product
|
|
1959
1995
|
}) {
|
|
1960
|
-
var _a, _b, _c, _d;
|
|
1961
1996
|
const targetProduct = this.store.currentProduct;
|
|
1997
|
+
// 如果外面传递了product 优先用外面的
|
|
1962
1998
|
const targetProductData = product || targetProduct;
|
|
1963
1999
|
let targetSchedules = [];
|
|
1964
|
-
|
|
2000
|
+
// 如果外面传递了 scheduleIds,优先取入参
|
|
2001
|
+
if (scheduleIds?.length) {
|
|
1965
2002
|
targetSchedules = this.store.schedule.getScheduleListByIds(scheduleIds);
|
|
1966
2003
|
} else {
|
|
1967
|
-
targetSchedules = this.store.schedule.getScheduleListByIds(
|
|
1968
|
-
targetProductData["schedule.ids"]
|
|
1969
|
-
);
|
|
2004
|
+
targetSchedules = this.store.schedule.getScheduleListByIds(targetProductData['schedule.ids']);
|
|
1970
2005
|
}
|
|
1971
2006
|
const resourcesDates = this.store.date.getDateList();
|
|
1972
|
-
const targetResourceDate = resourcesDates.find(
|
|
1973
|
-
const cartItems = (0,
|
|
1974
|
-
const resourcesMap = (0,
|
|
1975
|
-
const selectedResources = (0,
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
resources || ((_b = (_a = this.store.currentProduct) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) || [],
|
|
1983
|
-
selectedResources,
|
|
1984
|
-
1
|
|
1985
|
-
);
|
|
1986
|
-
const minTimeMaxTime = (0, import_utils3.calcMinTimeMaxTimeBySchedules)(
|
|
1987
|
-
targetSchedules,
|
|
1988
|
-
{},
|
|
1989
|
-
date
|
|
1990
|
-
);
|
|
1991
|
-
const scheduleTimeSlots = (0, import_utils3.getAllSortedDateRanges)(minTimeMaxTime);
|
|
1992
|
-
let allProductResources = productResources.flatMap((n) => n.renderList);
|
|
2007
|
+
const targetResourceDate = resourcesDates.find(n => n.date === date);
|
|
2008
|
+
const cartItems = (0, _lodashEs.cloneDeep)(this.store.cart.getItems());
|
|
2009
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(targetResourceDate?.resource || []);
|
|
2010
|
+
const selectedResources = (0, _resources.getOthersSelectedResources)(cartItems, '', resourcesMap);
|
|
2011
|
+
const productResources = (0, _resources.getResourcesByProduct)(resourcesMap, resources || this.store.currentProduct?.product_resource?.resources || [], selectedResources, 1);
|
|
2012
|
+
const minTimeMaxTime = (0, _utils3.calcMinTimeMaxTimeBySchedules)(targetSchedules, {}, date);
|
|
2013
|
+
const scheduleTimeSlots = (0, _utils3.getAllSortedDateRanges)(minTimeMaxTime);
|
|
2014
|
+
// 当前所有待选择资源的集合,先提出来,提升性能
|
|
2015
|
+
let allProductResources = productResources.flatMap(n => n.renderList);
|
|
2016
|
+
// 资源排下序,把单个资源靠前,组合资源排在后面
|
|
1993
2017
|
allProductResources.sort((a, b) => {
|
|
1994
|
-
|
|
1995
|
-
const
|
|
1996
|
-
|
|
1997
|
-
if (aIsCombined &&
|
|
1998
|
-
return 1;
|
|
1999
|
-
if (!aIsCombined && bIsCombined)
|
|
2000
|
-
return -1;
|
|
2018
|
+
const aIsCombined = a.metadata?.combined_resource?.status === 1;
|
|
2019
|
+
const bIsCombined = b.metadata?.combined_resource?.status === 1;
|
|
2020
|
+
if (aIsCombined && !bIsCombined) return 1;
|
|
2021
|
+
if (!aIsCombined && bIsCombined) return -1;
|
|
2001
2022
|
return 0;
|
|
2002
2023
|
});
|
|
2003
|
-
const enabledResourceTypeConfigs = (
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
const formatScheduleTimeSlots = scheduleTimeSlots.map((item) => {
|
|
2024
|
+
const enabledResourceTypeConfigs = targetProductData?.product_resource?.resources?.filter(n => n.status === 1) || [];
|
|
2025
|
+
const resourceTypeConfigById = new Map(enabledResourceTypeConfigs.map(n => [n.id, n]));
|
|
2026
|
+
|
|
2027
|
+
// 计算每个日程切片下日程可用的资源的容量总和
|
|
2028
|
+
const formatScheduleTimeSlots = scheduleTimeSlots.map(item => {
|
|
2029
|
+
// 用来计算资源的可使用情况,针对单个schedule 时间片
|
|
2010
2030
|
const resourcesUseableMap = {};
|
|
2011
2031
|
const statsByResourceType = {};
|
|
2012
|
-
enabledResourceTypeConfigs.forEach(
|
|
2032
|
+
enabledResourceTypeConfigs.forEach(cfg => {
|
|
2013
2033
|
statsByResourceType[cfg.id] = {
|
|
2014
2034
|
count: 0,
|
|
2015
2035
|
left: 0,
|
|
@@ -2017,59 +2037,68 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2017
2037
|
summaryConfigCount: 0
|
|
2018
2038
|
};
|
|
2019
2039
|
});
|
|
2020
|
-
|
|
2040
|
+
|
|
2041
|
+
// 遍历所有资源
|
|
2042
|
+
allProductResources?.forEach(m => {
|
|
2021
2043
|
const currentResourceTypeConfig = resourceTypeConfigById.get(m.form_id);
|
|
2022
|
-
if (!currentResourceTypeConfig)
|
|
2023
|
-
|
|
2044
|
+
if (!currentResourceTypeConfig) return;
|
|
2045
|
+
|
|
2046
|
+
// 遍历所有资源的上工时间片
|
|
2024
2047
|
let currentResourceMaxRemainingCapacity = 0;
|
|
2025
2048
|
let isAllTimeSlicesUsable = true;
|
|
2026
|
-
|
|
2027
|
-
|
|
2049
|
+
// m.times 需要做个过滤,假设 timeSlice.start_at 是 09:30 timeSlice.end_at 是 11:30
|
|
2050
|
+
// time 是 time.start_at = 2025-05-26 10:30, time.end_at = 2025-05-26 12:30
|
|
2051
|
+
// 需要判断 time 的开始结束时间 是否包含timeSlice的开始结束时间
|
|
2052
|
+
|
|
2053
|
+
// n.start_at 是 2025-06-30 15:00 end_at 2025-06-30 17:00
|
|
2054
|
+
// item.start 是 2025-06-30 16:00 item.end 是 2025-06-30 19:00
|
|
2055
|
+
// 需要判断 n.start_at 和 n.end_at 是否在 item.start 和 item.end 之间
|
|
2056
|
+
// 如果是仅用于计算的资源, n.start_at 和 n.end_at 在 item.start 和 item.end 有交集,则此时间需要计算
|
|
2057
|
+
// https://project.feishu.cn/v2qint/bug/detail/6657165010
|
|
2058
|
+
const mTimes = m.times.filter(n => {
|
|
2059
|
+
return !(0, _dayjs.default)(n.start_at).isAfter((0, _dayjs.default)(item.start), 'minute') && !(0, _dayjs.default)(n.end_at).isBefore((0, _dayjs.default)(item.end), 'minute') || m.onlyComputed && (0, _dayjs.default)(n.start_at).isBefore((0, _dayjs.default)(item.end), 'minute') && (0, _dayjs.default)(n.end_at).isAfter((0, _dayjs.default)(item.start), 'minute');
|
|
2028
2060
|
});
|
|
2061
|
+
// 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
|
|
2029
2062
|
if (mTimes.length === 0) {
|
|
2030
2063
|
return;
|
|
2031
2064
|
}
|
|
2065
|
+
|
|
2066
|
+
// 统计该资源类型在这个时间片的“配置容量”(无占用),只统计上工的资源
|
|
2032
2067
|
if (!m.onlyComputed) {
|
|
2033
|
-
const
|
|
2068
|
+
const currentStats = statsByResourceType[m.form_id] || {
|
|
2034
2069
|
count: 0,
|
|
2035
2070
|
left: 0,
|
|
2036
2071
|
summaryCount: 0,
|
|
2037
2072
|
summaryConfigCount: 0
|
|
2038
2073
|
};
|
|
2039
|
-
if (currentResourceTypeConfig.type ===
|
|
2040
|
-
|
|
2041
|
-
else
|
|
2042
|
-
currentStats2.summaryConfigCount += 1;
|
|
2043
|
-
statsByResourceType[m.form_id] = currentStats2;
|
|
2074
|
+
if (currentResourceTypeConfig.type === 'multiple') currentStats.summaryConfigCount += m.capacity;else currentStats.summaryConfigCount += 1;
|
|
2075
|
+
statsByResourceType[m.form_id] = currentStats;
|
|
2044
2076
|
}
|
|
2045
|
-
mTimes.forEach(
|
|
2046
|
-
|
|
2077
|
+
mTimes.forEach(childTiem => {
|
|
2078
|
+
// 挨个去匹配某个工作时间段结合当前日程时间,资源能不能用,有多少容量能用
|
|
2079
|
+
const res = (0, _resources.getIsUsableByTimeItem)({
|
|
2047
2080
|
timeSlice: {
|
|
2048
2081
|
start_time: item.start,
|
|
2049
2082
|
end_time: item.end,
|
|
2050
|
-
start_at: (0,
|
|
2051
|
-
end_at: (0,
|
|
2083
|
+
start_at: (0, _dayjs.default)(item.start),
|
|
2084
|
+
end_at: (0, _dayjs.default)(item.end)
|
|
2052
2085
|
},
|
|
2053
2086
|
time: childTiem,
|
|
2054
2087
|
resource: m,
|
|
2055
2088
|
currentCount: 1,
|
|
2056
2089
|
resourcesUseableMap,
|
|
2057
|
-
cut_off_time: targetProductData
|
|
2090
|
+
cut_off_time: targetProductData?.cut_off_time
|
|
2058
2091
|
});
|
|
2059
|
-
if (
|
|
2092
|
+
if (resourcesUseableMap?.[m.id] !== false && res.reason !== 'capacityOnly') {
|
|
2060
2093
|
resourcesUseableMap[m.id] = res.usable;
|
|
2061
2094
|
}
|
|
2062
|
-
if (!res.usable)
|
|
2063
|
-
isAllTimeSlicesUsable = false;
|
|
2095
|
+
if (!res.usable) isAllTimeSlicesUsable = false;
|
|
2064
2096
|
if (res.usable && !m.onlyComputed) {
|
|
2065
|
-
if (res.remainingCapacity > currentResourceMaxRemainingCapacity)
|
|
2066
|
-
currentResourceMaxRemainingCapacity = res.remainingCapacity;
|
|
2097
|
+
if (res.remainingCapacity > currentResourceMaxRemainingCapacity) currentResourceMaxRemainingCapacity = res.remainingCapacity;
|
|
2067
2098
|
}
|
|
2068
2099
|
});
|
|
2069
|
-
if (!isAllTimeSlicesUsable)
|
|
2070
|
-
|
|
2071
|
-
if (m.onlyComputed)
|
|
2072
|
-
return;
|
|
2100
|
+
if (!isAllTimeSlicesUsable) return;
|
|
2101
|
+
if (m.onlyComputed) return;
|
|
2073
2102
|
const currentStats = statsByResourceType[m.form_id] || {
|
|
2074
2103
|
count: 0,
|
|
2075
2104
|
left: 0,
|
|
@@ -2077,55 +2106,61 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2077
2106
|
summaryConfigCount: 0
|
|
2078
2107
|
};
|
|
2079
2108
|
currentStats.left += 1;
|
|
2080
|
-
if (currentResourceTypeConfig.type ===
|
|
2109
|
+
if (currentResourceTypeConfig.type === 'multiple') {
|
|
2081
2110
|
currentStats.summaryCount += currentResourceMaxRemainingCapacity;
|
|
2082
2111
|
}
|
|
2083
|
-
if (currentResourceMaxRemainingCapacity > currentStats.count)
|
|
2084
|
-
|
|
2112
|
+
if (currentResourceMaxRemainingCapacity > currentStats.count) currentStats.count = currentResourceMaxRemainingCapacity;
|
|
2113
|
+
// else {
|
|
2114
|
+
// 单个预约:一个资源只计 1,不关心剩余容量
|
|
2115
|
+
// currentStats.summaryCount += 1;
|
|
2116
|
+
// if (currentStats.count < 1) currentStats.count = 1;
|
|
2117
|
+
//}
|
|
2118
|
+
|
|
2085
2119
|
statsByResourceType[m.form_id] = currentStats;
|
|
2086
2120
|
});
|
|
2087
|
-
|
|
2088
|
-
|
|
2121
|
+
// 容量检测
|
|
2122
|
+
const cartItems = this.store.cart.getItems();
|
|
2123
|
+
productResources.forEach(n => {
|
|
2089
2124
|
const currentResourceTypeConfig = resourceTypeConfigById.get(n.id);
|
|
2090
|
-
if (!currentResourceTypeConfig)
|
|
2091
|
-
return;
|
|
2125
|
+
if (!currentResourceTypeConfig) return;
|
|
2092
2126
|
const currentStats = statsByResourceType[n.id] || {
|
|
2093
2127
|
count: 0,
|
|
2094
2128
|
left: 0,
|
|
2095
2129
|
summaryCount: 0
|
|
2096
2130
|
};
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2131
|
+
|
|
2132
|
+
// 单个预约检测规则:
|
|
2133
|
+
// 1、跟我一样的商品同一时间在购物车里不可以超过我最少的那种资源的关联的资源个数
|
|
2134
|
+
// 2、跟我不一样的商品,只需要跟我当前商品有同一种类型的资源的同一时间的,她配置了几个资源的个数+我配置了几个资源的个数,然后购物车里有几个这样的商品,对应的资源做一个去重,不超过这个去重以后的总数
|
|
2135
|
+
if (n.type === 'single') {
|
|
2136
|
+
const currentResourcesSet = new Set([...n.optional_resource, ...n.default_resource]);
|
|
2137
|
+
// 规则 1
|
|
2138
|
+
const sameCartItems = cartItems.filter(m => m._productOrigin?.id?.toString() === targetProductData?.id?.toString() && `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end);
|
|
2103
2139
|
if (sameCartItems.length > 0 && sameCartItems.length >= currentResourcesSet.size || sameCartItems.length > currentStats.left) {
|
|
2104
2140
|
currentStats.left = 0;
|
|
2105
2141
|
currentStats.count = 0;
|
|
2106
2142
|
currentStats.summaryCount = 0;
|
|
2107
2143
|
}
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
const sameTypeResourcesSet = /* @__PURE__ */ new Set([...(sameTypeResources == null ? void 0 : sameTypeResources.optional_resource) || [], ...(sameTypeResources == null ? void 0 : sameTypeResources.default_resource) || []]);
|
|
2120
|
-
sameTypeResourcesSet.forEach((resource) => currentResourcesSet.add(resource));
|
|
2144
|
+
// 规则 2
|
|
2145
|
+
let otherCartItems = cartItems.filter(m => {
|
|
2146
|
+
const isTimeMatch = m._productOrigin?.id?.toString() !== targetProductData?.id?.toString() && `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end;
|
|
2147
|
+
const isResourceMatch = m._productOrigin?.product_resource?.resources?.find(m => m.type === n.type && m.status === 1);
|
|
2148
|
+
return isTimeMatch && isResourceMatch;
|
|
2149
|
+
});
|
|
2150
|
+
otherCartItems.forEach(m => {
|
|
2151
|
+
const sameTypeResources = m._productOrigin?.product_resource?.resources?.find(m => m.type === n.type && m.status === 1);
|
|
2152
|
+
const sameTypeResourcesSet = new Set([...(sameTypeResources?.optional_resource || []), ...(sameTypeResources?.default_resource || [])]);
|
|
2153
|
+
// 把sameTypeResourcesSet 加到currentResourcesSet
|
|
2154
|
+
sameTypeResourcesSet.forEach(resource => currentResourcesSet.add(resource));
|
|
2121
2155
|
});
|
|
2122
|
-
|
|
2123
|
-
currentDataResources
|
|
2156
|
+
// 先确定是否每一个currentResourcesSet在这个时间点的 event_list 都是空的,如果不是空的还需要把他踢出currentResourcesSet
|
|
2157
|
+
const currentDataResources = this.store.date.getResourcesListByDate((0, _dayjs.default)(item.start).format('YYYY-MM-DD'));
|
|
2158
|
+
currentDataResources?.forEach(m => {
|
|
2124
2159
|
if (currentResourcesSet.has(m.id)) {
|
|
2125
|
-
const mTimes = m.times.filter(
|
|
2126
|
-
return !(0,
|
|
2160
|
+
const mTimes = m.times.filter(n => {
|
|
2161
|
+
return !(0, _dayjs.default)(n.start_at).isAfter((0, _dayjs.default)(item.start), 'minute') && !(0, _dayjs.default)(n.end_at).isBefore((0, _dayjs.default)(item.end), 'minute') || (0, _dayjs.default)(n.start_at).isBefore((0, _dayjs.default)(item.end), 'minute') && (0, _dayjs.default)(n.end_at).isAfter((0, _dayjs.default)(item.start), 'minute');
|
|
2127
2162
|
});
|
|
2128
|
-
if (!mTimes.length || mTimes.some(
|
|
2163
|
+
if (!mTimes.length || mTimes.some(n => n.event_list.length)) {
|
|
2129
2164
|
currentResourcesSet.delete(m.id);
|
|
2130
2165
|
}
|
|
2131
2166
|
}
|
|
@@ -2136,57 +2171,61 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2136
2171
|
currentStats.summaryCount = 0;
|
|
2137
2172
|
}
|
|
2138
2173
|
} else {
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
const sameCartNeedCapacity = sameCartItems.reduce((acc, curr) => acc + (0, import_capacity.getCapacityInfoByCartItem)(curr).currentCapacity, 0);
|
|
2174
|
+
// 多个预约的检测规则:
|
|
2175
|
+
// 规则1、跟我一样的商品同一时间在购物车需要的容量总数不可以超过我配置的资源的 capacity 之和
|
|
2176
|
+
const sameCartItems = cartItems.filter(m => m._productOrigin?.id?.toString() === targetProductData?.id?.toString() && `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end);
|
|
2177
|
+
const sameCartNeedCapacity = sameCartItems.reduce((acc, curr) => acc + (0, _capacity.getCapacityInfoByCartItem)(curr).currentCapacity, 0);
|
|
2144
2178
|
const currentProductResourcesCapacity = n.renderList.reduce((acc, curr) => !curr.onlyComputed ? acc + curr.capacity || 0 : acc, 0);
|
|
2145
2179
|
if (sameCartNeedCapacity >= currentProductResourcesCapacity) {
|
|
2146
2180
|
currentStats.left = 0;
|
|
2147
2181
|
currentStats.count = 0;
|
|
2148
2182
|
currentStats.summaryCount = 0;
|
|
2149
2183
|
}
|
|
2150
|
-
|
|
2151
|
-
const
|
|
2152
|
-
const
|
|
2153
|
-
otherSameTimesCartItems.
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
if (m2.id === n.id) {
|
|
2163
|
-
m2.renderList.forEach((n2) => {
|
|
2164
|
-
if (!n2.onlyComputed && !allRenderList.find((m3) => m3.id === n2.id)) {
|
|
2165
|
-
allRenderList.push(n2);
|
|
2184
|
+
// 规则2、不管是不是跟我一样的商品,只需要跟我当前商品有同一种类型的资源的同一时间的,把所有购物车的 capacity 之和 和 所有当前类型资源的 capacity 之和比较,如果超过了resourcesCapacity,则不可用
|
|
2185
|
+
// const otherCartItems = cartItems.filter((m) => m._productOrigin?.id?.toString() !== targetProductData?.id?.toString() && m.start_time === item.start && m.end_time === item.end);
|
|
2186
|
+
const otherSameTimesCartItems = cartItems.filter(m => `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end);
|
|
2187
|
+
const otherCartNeedCapacity = otherSameTimesCartItems.reduce((acc, curr) => acc + (0, _capacity.getCapacityInfoByCartItem)(curr).currentCapacity, 0);
|
|
2188
|
+
const allRenderList = [...n.renderList.filter(m => !m.onlyComputed)];
|
|
2189
|
+
otherSameTimesCartItems.forEach(m => {
|
|
2190
|
+
const productResources = (0, _resources.getResourcesByProduct)((0, _utils2.getResourcesMap)(targetResourceDate?.resource || []), m._productOrigin?.product_resource?.resources || [], selectedResources, 1);
|
|
2191
|
+
productResources.forEach(m => {
|
|
2192
|
+
if (m.id === n.id) {
|
|
2193
|
+
m.renderList.forEach(n => {
|
|
2194
|
+
if (!n.onlyComputed && !allRenderList.find(m => m.id === n.id)) {
|
|
2195
|
+
allRenderList.push(n);
|
|
2166
2196
|
}
|
|
2167
2197
|
});
|
|
2168
2198
|
}
|
|
2169
2199
|
});
|
|
2170
2200
|
});
|
|
2171
2201
|
const currentTypeResourcesCapacity = allRenderList.reduce((acc, curr) => acc + curr.capacity || 0, 0);
|
|
2202
|
+
// 计算当前时间段内所有资源的已使用容量
|
|
2172
2203
|
const usedCapacity = allRenderList.reduce((acc, curr) => {
|
|
2173
|
-
const mTimes = curr.times.filter(
|
|
2174
|
-
return !(0,
|
|
2204
|
+
const mTimes = curr.times.filter(n => {
|
|
2205
|
+
return !(0, _dayjs.default)(n.start_at).isAfter((0, _dayjs.default)(item.start), 'minute') && !(0, _dayjs.default)(n.end_at).isBefore((0, _dayjs.default)(item.end), 'minute') || (0, _dayjs.default)(n.start_at).isBefore((0, _dayjs.default)(item.end), 'minute') && (0, _dayjs.default)(n.end_at).isAfter((0, _dayjs.default)(item.start), 'minute');
|
|
2175
2206
|
});
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2207
|
+
// 这里为什么要设置个 map,因为有可能日程有重叠,所以要把重叠的 event_list 去除
|
|
2208
|
+
const mSet = new Map();
|
|
2209
|
+
mTimes.forEach(n => {
|
|
2210
|
+
// acc += n.event_list?.reduce((acc: any, curr: any) => acc + curr.pax, 0);
|
|
2211
|
+
// mSet.set(n)
|
|
2212
|
+
n.event_list.forEach(m => {
|
|
2213
|
+
// 需要确认 m 的时间段是否和 item 的时间段有交集
|
|
2214
|
+
if ((0, _resources.isConflict)({
|
|
2215
|
+
start_at: m.start_at,
|
|
2216
|
+
end_at: m.end_at
|
|
2217
|
+
}, {
|
|
2218
|
+
start_at: (0, _dayjs.default)(item.start),
|
|
2219
|
+
end_at: (0, _dayjs.default)(item.end)
|
|
2220
|
+
})) {
|
|
2183
2221
|
mSet.set(m.id, m.pax ?? 1);
|
|
2184
2222
|
}
|
|
2185
2223
|
});
|
|
2186
2224
|
});
|
|
2187
|
-
acc += Array.from(mSet.values()).reduce((
|
|
2225
|
+
acc += Array.from(mSet.values()).reduce((acc, curr) => acc + curr, 0);
|
|
2188
2226
|
return acc;
|
|
2189
2227
|
}, 0);
|
|
2228
|
+
// 如果已使用容量超过了当前类型资源的容量,则不可用
|
|
2190
2229
|
if (otherCartNeedCapacity + usedCapacity >= currentTypeResourcesCapacity) {
|
|
2191
2230
|
currentStats.left = 0;
|
|
2192
2231
|
currentStats.count = 0;
|
|
@@ -2195,55 +2234,48 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2195
2234
|
}
|
|
2196
2235
|
statsByResourceType[n.id] = currentStats;
|
|
2197
2236
|
});
|
|
2198
|
-
const startDayJs = (0,
|
|
2199
|
-
const endDayJs = (0,
|
|
2237
|
+
const startDayJs = (0, _dayjs.default)(item.start);
|
|
2238
|
+
const endDayJs = (0, _dayjs.default)(item.end);
|
|
2239
|
+
|
|
2240
|
+
// 选择“瓶颈资源类型”:multiple 取 summaryCount 最小,single 取 left 最小
|
|
2200
2241
|
let bottleneckResourceTypeId;
|
|
2201
2242
|
let bottleneckValue = Infinity;
|
|
2202
|
-
enabledResourceTypeConfigs.forEach(
|
|
2243
|
+
enabledResourceTypeConfigs.forEach(cfg => {
|
|
2203
2244
|
const stats = statsByResourceType[cfg.id] || {
|
|
2204
2245
|
count: 0,
|
|
2205
2246
|
left: 0,
|
|
2206
2247
|
summaryCount: 0,
|
|
2207
2248
|
summaryConfigCount: 0
|
|
2208
2249
|
};
|
|
2209
|
-
const value = cfg.type ===
|
|
2250
|
+
const value = cfg.type === 'multiple' ? stats.summaryCount : stats.left;
|
|
2210
2251
|
if (value < bottleneckValue) {
|
|
2211
2252
|
bottleneckValue = value;
|
|
2212
2253
|
bottleneckResourceTypeId = cfg.id;
|
|
2213
2254
|
}
|
|
2214
2255
|
});
|
|
2215
|
-
const bottleneckStats = bottleneckResourceTypeId !==
|
|
2256
|
+
const bottleneckStats = bottleneckResourceTypeId !== undefined ? statsByResourceType[bottleneckResourceTypeId] || {
|
|
2216
2257
|
count: 0,
|
|
2217
2258
|
left: 0,
|
|
2218
2259
|
summaryCount: 0,
|
|
2219
2260
|
summaryConfigCount: 0
|
|
2220
|
-
} : {
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2261
|
+
} : {
|
|
2262
|
+
count: 0,
|
|
2263
|
+
left: 0,
|
|
2264
|
+
summaryCount: 0,
|
|
2265
|
+
summaryConfigCount: 0
|
|
2266
|
+
};
|
|
2267
|
+
const bottleneckConfig = bottleneckResourceTypeId !== undefined ? resourceTypeConfigById.get(bottleneckResourceTypeId) : undefined;
|
|
2268
|
+
let status = 'sold_out';
|
|
2269
|
+
if (bottleneckStats.left === 0) status = 'sold_out';else if (!bottleneckConfig || bottleneckStats.summaryConfigCount === 0) status = 'sold_out';else if (bottleneckConfig.type === 'multiple') {
|
|
2228
2270
|
const usageRatio = bottleneckStats.summaryCount / bottleneckStats.summaryConfigCount;
|
|
2229
|
-
if (usageRatio > 0.5)
|
|
2230
|
-
status = "lots_of_space";
|
|
2231
|
-
else if (bottleneckStats.summaryCount > 0)
|
|
2232
|
-
status = "filling_up_fast";
|
|
2233
|
-
else
|
|
2234
|
-
status = "sold_out";
|
|
2271
|
+
if (usageRatio > 0.5) status = 'lots_of_space';else if (bottleneckStats.summaryCount > 0) status = 'filling_up_fast';else status = 'sold_out';
|
|
2235
2272
|
} else {
|
|
2236
2273
|
const usageRatio = bottleneckStats.left / bottleneckStats.summaryConfigCount;
|
|
2237
|
-
if (usageRatio > 0.5)
|
|
2238
|
-
status = "lots_of_space";
|
|
2239
|
-
else if (bottleneckStats.count > 0)
|
|
2240
|
-
status = "filling_up_fast";
|
|
2241
|
-
else
|
|
2242
|
-
status = "sold_out";
|
|
2274
|
+
if (usageRatio > 0.5) status = 'lots_of_space';else if (bottleneckStats.count > 0) status = 'filling_up_fast';else status = 'sold_out';
|
|
2243
2275
|
}
|
|
2244
2276
|
return {
|
|
2245
|
-
start_time: startDayJs.format(
|
|
2246
|
-
end_time: endDayJs.format(
|
|
2277
|
+
start_time: startDayJs.format('HH:mm'),
|
|
2278
|
+
end_time: endDayJs.format('HH:mm'),
|
|
2247
2279
|
start_at: startDayJs,
|
|
2248
2280
|
end_at: endDayJs,
|
|
2249
2281
|
count: bottleneckStats.count,
|
|
@@ -2254,6 +2286,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2254
2286
|
});
|
|
2255
2287
|
return formatScheduleTimeSlots;
|
|
2256
2288
|
}
|
|
2289
|
+
|
|
2257
2290
|
// 提供给 UI的方法,当前步骤是选择商品,下一步不管是什么都需要在这里做一次检测
|
|
2258
2291
|
// 时长类商品关联的资源为多个预约时,在点击进入"选择资源"步骤之前,需要检测当前所有资源的总容量
|
|
2259
2292
|
// 选择商品数量大于所有资源配置的总容量时,不能进入下一步,需要在"选择商品"这一步时提示。
|
|
@@ -2262,27 +2295,27 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2262
2295
|
* 找到多个资源的公共可用时间段
|
|
2263
2296
|
*/
|
|
2264
2297
|
findCommonAvailableTimeSlots(resources) {
|
|
2265
|
-
if (resources.length === 0)
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
(
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
(slots) => slots.map((slot) => `${slot.start.format("HH:mm")}-${slot.end.format("HH:mm")}`)
|
|
2276
|
-
));
|
|
2277
|
-
let commonSlots = allTimeSlots[0];
|
|
2278
|
-
console.log("初始公共时间段:", commonSlots.map((slot) => `${slot.start.format("HH:mm")}-${slot.end.format("HH:mm")}`));
|
|
2298
|
+
if (resources.length === 0) return [];
|
|
2299
|
+
// 收集所有资源的时间段,转换为统一的时间格式
|
|
2300
|
+
const allTimeSlots = resources.map(resource => resource.times.map(time => ({
|
|
2301
|
+
start: (0, _dayjs.default)(time.start_at),
|
|
2302
|
+
end: (0, _dayjs.default)(time.end_at)
|
|
2303
|
+
})));
|
|
2304
|
+
// 找到公共时间段的交集
|
|
2305
|
+
let commonSlots = allTimeSlots[0]; // 从第一个资源的时间段开始
|
|
2306
|
+
|
|
2307
|
+
// 与其他资源的时间段求交集
|
|
2279
2308
|
for (let i = 1; i < allTimeSlots.length; i++) {
|
|
2280
2309
|
const currentResourceSlots = allTimeSlots[i];
|
|
2281
2310
|
const intersections = [];
|
|
2282
|
-
|
|
2283
|
-
|
|
2311
|
+
|
|
2312
|
+
// 计算当前公共时间段与下一个资源时间段的交集
|
|
2313
|
+
commonSlots.forEach(commonSlot => {
|
|
2314
|
+
currentResourceSlots.forEach(currentSlot => {
|
|
2284
2315
|
const overlapStart = commonSlot.start.isAfter(currentSlot.start) ? commonSlot.start : currentSlot.start;
|
|
2285
2316
|
const overlapEnd = commonSlot.end.isBefore(currentSlot.end) ? commonSlot.end : currentSlot.end;
|
|
2317
|
+
|
|
2318
|
+
// 如果有重叠时间且重叠时间大于0
|
|
2286
2319
|
if (overlapStart.isBefore(overlapEnd)) {
|
|
2287
2320
|
intersections.push({
|
|
2288
2321
|
start: overlapStart,
|
|
@@ -2292,74 +2325,88 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2292
2325
|
});
|
|
2293
2326
|
});
|
|
2294
2327
|
if (intersections.length === 0) {
|
|
2295
|
-
console.log(`资源${i}与当前公共时间段无交集,跳过该资源`);
|
|
2296
2328
|
continue;
|
|
2297
2329
|
}
|
|
2298
2330
|
commonSlots = intersections;
|
|
2299
|
-
console.log(`与资源${i}求交集后的公共时间段:`, commonSlots.map((slot) => `${slot.start.format("HH:mm")}-${slot.end.format("HH:mm")}`));
|
|
2300
2331
|
}
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2332
|
+
|
|
2333
|
+
// 格式化返回结果
|
|
2334
|
+
const result = commonSlots.map(slot => ({
|
|
2335
|
+
startTime: slot.start.format('HH:mm'),
|
|
2336
|
+
endTime: slot.end.format('HH:mm')
|
|
2304
2337
|
}));
|
|
2305
|
-
console.log("最终公共时间段:", result);
|
|
2306
2338
|
return result;
|
|
2307
2339
|
}
|
|
2308
2340
|
checkMaxDurationCapacity() {
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2341
|
+
const cartItems = this.store.cart.getItems().filter(item => !(0, _utils5.isNormalProduct)(item._productOrigin));
|
|
2342
|
+
if (cartItems.length === 0) return {
|
|
2343
|
+
success: true,
|
|
2344
|
+
minAvailableCount: 0
|
|
2345
|
+
};
|
|
2346
|
+
|
|
2347
|
+
// 将购物车商品分为有时间的和没有时间的
|
|
2313
2348
|
const itemsWithTime = [];
|
|
2314
2349
|
const itemsWithoutTime = [];
|
|
2350
|
+
// 记录每种资源类型的可用数量
|
|
2315
2351
|
const availableCountsByResourceType = [];
|
|
2316
|
-
cartItems.forEach(
|
|
2352
|
+
cartItems.forEach(cartItem => {
|
|
2317
2353
|
if (cartItem.start_time && cartItem.end_time && cartItem.start_date) {
|
|
2318
2354
|
itemsWithTime.push(cartItem);
|
|
2319
2355
|
} else {
|
|
2320
2356
|
itemsWithoutTime.push(cartItem);
|
|
2321
2357
|
}
|
|
2322
2358
|
});
|
|
2359
|
+
|
|
2360
|
+
// 处理没有时间的商品,为它们分配公共可用时间的第一个时间片
|
|
2323
2361
|
const processedItemsWithoutTime = [];
|
|
2324
2362
|
if (itemsWithoutTime.length > 0) {
|
|
2363
|
+
// 按资源类型分组处理没有时间的商品
|
|
2325
2364
|
const itemsByResourceType = {};
|
|
2326
|
-
itemsWithoutTime.forEach(
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
const resourceTypes = ((_a2 = cartItem._productOrigin.product_resource) == null ? void 0 : _a2.resources) || [];
|
|
2331
|
-
resourceTypes.forEach((resourceType) => {
|
|
2332
|
-
var _a3;
|
|
2365
|
+
itemsWithoutTime.forEach(cartItem => {
|
|
2366
|
+
if (!cartItem._productOrigin) return;
|
|
2367
|
+
const resourceTypes = cartItem._productOrigin.product_resource?.resources || [];
|
|
2368
|
+
resourceTypes.forEach(resourceType => {
|
|
2333
2369
|
if (resourceType.status === 1) {
|
|
2334
|
-
const resourceCode = resourceType.code ||
|
|
2370
|
+
const resourceCode = resourceType.code || resourceType.id?.toString();
|
|
2335
2371
|
if (!itemsByResourceType[resourceCode]) {
|
|
2336
2372
|
itemsByResourceType[resourceCode] = [];
|
|
2337
2373
|
}
|
|
2338
|
-
|
|
2374
|
+
// 避免重复添加同一个商品
|
|
2375
|
+
// 如果之前添加过的依赖相同资源的跟我现在是同一个 holder,也不需要重复添加
|
|
2376
|
+
if (itemsByResourceType[resourceCode].find(item => item.holder_id === cartItem.holder_id)) {
|
|
2339
2377
|
return;
|
|
2340
2378
|
}
|
|
2341
|
-
if (!itemsByResourceType[resourceCode].find(
|
|
2379
|
+
if (!itemsByResourceType[resourceCode].find(item => item._id === cartItem._id)) {
|
|
2342
2380
|
itemsByResourceType[resourceCode].push(cartItem);
|
|
2343
2381
|
}
|
|
2344
2382
|
}
|
|
2345
2383
|
});
|
|
2346
2384
|
});
|
|
2385
|
+
|
|
2386
|
+
// 为每种资源类型检查容量
|
|
2347
2387
|
const dateRange = this.store.date.getDateRange();
|
|
2348
|
-
if (!dateRange || dateRange.length === 0)
|
|
2349
|
-
|
|
2388
|
+
if (!dateRange || dateRange.length === 0) return {
|
|
2389
|
+
success: false,
|
|
2390
|
+
minAvailableCount: 0
|
|
2391
|
+
};
|
|
2350
2392
|
const resourcesDates = this.store.date.getDateList();
|
|
2351
|
-
const targetResourceDate = resourcesDates.find(
|
|
2352
|
-
if (!targetResourceDate)
|
|
2353
|
-
|
|
2354
|
-
|
|
2393
|
+
const targetResourceDate = resourcesDates.find(n => n.date === dateRange[0].date);
|
|
2394
|
+
if (!targetResourceDate) return {
|
|
2395
|
+
success: false,
|
|
2396
|
+
minAvailableCount: 0
|
|
2397
|
+
};
|
|
2398
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(targetResourceDate.resource || []);
|
|
2399
|
+
|
|
2400
|
+
// 从购物车商品中获取资源类型配置,建立 resourceCode 到 form_id 的映射关系
|
|
2355
2401
|
const resourceCodeToFormIdMap = {};
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2402
|
+
|
|
2403
|
+
// 遍历购物车中的商品,收集所有资源类型配置
|
|
2404
|
+
Object.values(itemsByResourceType).flat().forEach(cartItem => {
|
|
2405
|
+
if (cartItem._productOrigin?.product_resource?.resources) {
|
|
2406
|
+
cartItem._productOrigin.product_resource.resources.forEach(resourceConfig => {
|
|
2407
|
+
// 只处理启用的资源类型 (status === 1)
|
|
2361
2408
|
if (resourceConfig.status === 1 && resourceConfig.code) {
|
|
2362
|
-
const formId =
|
|
2409
|
+
const formId = resourceConfig.id?.toString() || resourceConfig.resource_type_id?.toString();
|
|
2363
2410
|
if (formId) {
|
|
2364
2411
|
resourceCodeToFormIdMap[resourceConfig.code] = formId;
|
|
2365
2412
|
}
|
|
@@ -2369,60 +2416,77 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2369
2416
|
});
|
|
2370
2417
|
let hasCapacityIssue = false;
|
|
2371
2418
|
const resourceCapacityInfo = [];
|
|
2372
|
-
|
|
2419
|
+
|
|
2420
|
+
// 用于跟踪已处理的商品,避免重复添加
|
|
2421
|
+
const processedCartItemIds = new Set();
|
|
2422
|
+
|
|
2423
|
+
// 先检查所有资源类型,收集可用数量信息
|
|
2373
2424
|
for (const [resourceCode, items] of Object.entries(itemsByResourceType)) {
|
|
2425
|
+
// 获取该资源类型对应的 form_id
|
|
2374
2426
|
const targetFormId = resourceCodeToFormIdMap[resourceCode];
|
|
2375
2427
|
if (!targetFormId) {
|
|
2376
|
-
|
|
2377
|
-
|
|
2428
|
+
return {
|
|
2429
|
+
success: false,
|
|
2430
|
+
minAvailableCount: 0
|
|
2431
|
+
};
|
|
2378
2432
|
}
|
|
2433
|
+
|
|
2434
|
+
// 获取该资源类型的所有资源
|
|
2379
2435
|
const resourcesOfThisType = [];
|
|
2380
|
-
items.forEach(
|
|
2381
|
-
const productResourceIds = (0,
|
|
2382
|
-
productResourceIds.forEach(
|
|
2383
|
-
var _a2;
|
|
2436
|
+
items.forEach(cartItem => {
|
|
2437
|
+
const productResourceIds = (0, _capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
|
|
2438
|
+
productResourceIds.forEach(resourceId => {
|
|
2384
2439
|
const resource = resourcesMap[resourceId];
|
|
2385
|
-
if (resource &&
|
|
2386
|
-
|
|
2440
|
+
if (resource && resource.form_id?.toString() === targetFormId) {
|
|
2441
|
+
// 避免重复添加同一个资源
|
|
2442
|
+
if (!resourcesOfThisType.find(r => r.id === resource.id)) {
|
|
2387
2443
|
resourcesOfThisType.push(resource);
|
|
2388
2444
|
}
|
|
2389
2445
|
}
|
|
2390
2446
|
});
|
|
2391
2447
|
});
|
|
2392
2448
|
if (resourcesOfThisType.length === 0) {
|
|
2393
|
-
|
|
2394
|
-
|
|
2449
|
+
return {
|
|
2450
|
+
success: false,
|
|
2451
|
+
minAvailableCount: 0
|
|
2452
|
+
};
|
|
2395
2453
|
}
|
|
2454
|
+
|
|
2455
|
+
// 检查资源类型(单个预约 vs 多个预约)
|
|
2456
|
+
// 从商品配置中获取资源类型信息
|
|
2396
2457
|
let resourceTypeConfig = null;
|
|
2397
2458
|
for (const cartItem of items) {
|
|
2398
|
-
if (
|
|
2399
|
-
resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(
|
|
2400
|
-
|
|
2401
|
-
);
|
|
2402
|
-
if (resourceTypeConfig)
|
|
2403
|
-
break;
|
|
2459
|
+
if (cartItem._productOrigin?.product_resource?.resources) {
|
|
2460
|
+
resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(r => r.code === resourceCode && r.status === 1);
|
|
2461
|
+
if (resourceTypeConfig) break;
|
|
2404
2462
|
}
|
|
2405
2463
|
}
|
|
2406
|
-
const isMultipleBooking =
|
|
2464
|
+
const isMultipleBooking = resourceTypeConfig?.type === 'multiple';
|
|
2407
2465
|
let totalAvailable;
|
|
2408
2466
|
let requiredAmount;
|
|
2409
2467
|
let availableAmount;
|
|
2410
2468
|
if (isMultipleBooking) {
|
|
2469
|
+
// 多个预约:计算容量
|
|
2411
2470
|
totalAvailable = resourcesOfThisType.reduce((sum, resource) => {
|
|
2412
2471
|
return sum + (resource.capacity || 0);
|
|
2413
2472
|
}, 0);
|
|
2414
2473
|
requiredAmount = items.reduce((sum, cartItem) => {
|
|
2415
|
-
const {
|
|
2474
|
+
const {
|
|
2475
|
+
currentCapacity
|
|
2476
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(cartItem);
|
|
2416
2477
|
return sum + currentCapacity;
|
|
2417
2478
|
}, 0);
|
|
2418
2479
|
availableAmount = Math.max(0, totalAvailable - requiredAmount);
|
|
2419
2480
|
} else {
|
|
2481
|
+
// 单个预约:计算资源个数
|
|
2420
2482
|
totalAvailable = resourcesOfThisType.length;
|
|
2421
2483
|
requiredAmount = items.reduce((sum, cartItem) => {
|
|
2422
2484
|
return sum + (cartItem.num || 1);
|
|
2423
2485
|
}, 0);
|
|
2424
2486
|
availableAmount = Math.max(0, totalAvailable - requiredAmount);
|
|
2425
2487
|
}
|
|
2488
|
+
|
|
2489
|
+
// 记录资源容量信息
|
|
2426
2490
|
resourceCapacityInfo.push({
|
|
2427
2491
|
code: resourceCode,
|
|
2428
2492
|
available: availableAmount,
|
|
@@ -2431,23 +2495,27 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2431
2495
|
isMultiple: isMultipleBooking
|
|
2432
2496
|
});
|
|
2433
2497
|
availableCountsByResourceType.push(availableAmount);
|
|
2498
|
+
|
|
2499
|
+
// 检查是否有容量问题
|
|
2434
2500
|
if (requiredAmount > totalAvailable) {
|
|
2435
2501
|
hasCapacityIssue = true;
|
|
2436
|
-
console.log(`资源类型 ${resourceCode} ${isMultipleBooking ? "容量" : "资源数量"}不足: 需要 ${requiredAmount}, 总共 ${totalAvailable}`);
|
|
2437
2502
|
}
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2503
|
+
|
|
2504
|
+
// 为通过检测的商品分配一个公共可用时间段
|
|
2505
|
+
|
|
2506
|
+
// 找到所有资源都可用的时间段
|
|
2442
2507
|
const commonTimeSlots = this.findCommonAvailableTimeSlots(resourcesOfThisType);
|
|
2443
|
-
console.log(`资源类型 ${resourceCode} 的公共时间段:`, commonTimeSlots);
|
|
2444
2508
|
if (commonTimeSlots.length === 0) {
|
|
2445
|
-
|
|
2446
|
-
|
|
2509
|
+
return {
|
|
2510
|
+
success: false,
|
|
2511
|
+
minAvailableCount: 0
|
|
2512
|
+
};
|
|
2447
2513
|
}
|
|
2514
|
+
|
|
2515
|
+
// 使用第一个公共可用时间段,但只处理未处理过的商品
|
|
2448
2516
|
const firstCommonSlot = commonTimeSlots[0];
|
|
2449
|
-
|
|
2450
|
-
|
|
2517
|
+
items.forEach(cartItem => {
|
|
2518
|
+
// 只处理未处理过的商品,避免重复添加
|
|
2451
2519
|
if (!processedCartItemIds.has(cartItem._id)) {
|
|
2452
2520
|
processedCartItemIds.add(cartItem._id);
|
|
2453
2521
|
const processedItem = {
|
|
@@ -2461,59 +2529,93 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2461
2529
|
}
|
|
2462
2530
|
});
|
|
2463
2531
|
}
|
|
2532
|
+
|
|
2533
|
+
// 如果有容量问题,找出限制最严格的资源类型,返回其总容量
|
|
2464
2534
|
if (hasCapacityIssue) {
|
|
2465
|
-
|
|
2535
|
+
// 找出超出容量的资源类型中,总容量最少的那个
|
|
2536
|
+
const overCapacityResources = resourceCapacityInfo.filter(info => info.required > info.total);
|
|
2466
2537
|
if (overCapacityResources.length > 0) {
|
|
2467
|
-
const
|
|
2468
|
-
return {
|
|
2538
|
+
const minTotalCapacity = Math.min(...overCapacityResources.map(info => info.total));
|
|
2539
|
+
return {
|
|
2540
|
+
success: false,
|
|
2541
|
+
minAvailableCount: minTotalCapacity
|
|
2542
|
+
};
|
|
2469
2543
|
}
|
|
2470
|
-
|
|
2471
|
-
|
|
2544
|
+
// 如果没有超出容量的(理论上不应该发生),返回总容量最少的
|
|
2545
|
+
const minTotalCapacity = Math.min(...resourceCapacityInfo.map(info => info.total));
|
|
2546
|
+
return {
|
|
2547
|
+
success: false,
|
|
2548
|
+
minAvailableCount: minTotalCapacity
|
|
2549
|
+
};
|
|
2472
2550
|
}
|
|
2473
2551
|
}
|
|
2552
|
+
|
|
2553
|
+
// 合并所有商品(有时间的 + 处理后的没有时间的)
|
|
2474
2554
|
const allProcessedItems = [...itemsWithTime, ...processedItemsWithoutTime];
|
|
2555
|
+
|
|
2556
|
+
// 按时间段分组检查
|
|
2475
2557
|
const cartItemsByTimeSlot = {};
|
|
2476
|
-
allProcessedItems.forEach(
|
|
2477
|
-
if (!cartItem.start_time || !cartItem.end_time || !cartItem.start_date)
|
|
2478
|
-
return;
|
|
2558
|
+
allProcessedItems.forEach(cartItem => {
|
|
2559
|
+
if (!cartItem.start_time || !cartItem.end_time || !cartItem.start_date) return;
|
|
2479
2560
|
const timeSlotKey = `${cartItem.start_date}_${cartItem.start_time}_${cartItem.end_date || cartItem.start_date}_${cartItem.end_time}`;
|
|
2480
2561
|
if (!cartItemsByTimeSlot[timeSlotKey]) {
|
|
2481
2562
|
cartItemsByTimeSlot[timeSlotKey] = [];
|
|
2482
2563
|
}
|
|
2483
2564
|
cartItemsByTimeSlot[timeSlotKey].push(cartItem);
|
|
2484
2565
|
});
|
|
2566
|
+
// 检查每个时间段是否有足够的资源容量
|
|
2485
2567
|
for (const [timeSlotKey, itemsInTimeSlot] of Object.entries(cartItemsByTimeSlot)) {
|
|
2486
|
-
const [startDate, startTime, endDate, endTime] = timeSlotKey.split(
|
|
2568
|
+
const [startDate, startTime, endDate, endTime] = timeSlotKey.split('_');
|
|
2487
2569
|
const timeSlotStart = `${startDate} ${startTime}`;
|
|
2488
2570
|
const timeSlotEnd = `${endDate} ${endTime}`;
|
|
2571
|
+
|
|
2572
|
+
// 获取这个时间段所有商品涉及的资源
|
|
2489
2573
|
const allResourcesForTimeSlot = [];
|
|
2490
|
-
const resourcesIdSet =
|
|
2574
|
+
const resourcesIdSet = new Set();
|
|
2575
|
+
|
|
2576
|
+
// 获取资源数据
|
|
2491
2577
|
const dateRange = this.store.date.getDateRange();
|
|
2492
2578
|
const resourcesDates = this.store.date.getDateList();
|
|
2493
|
-
const targetResourceDate = resourcesDates.find(
|
|
2494
|
-
if (!targetResourceDate)
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
const productResourceIds = (0,
|
|
2501
|
-
productResourceIds.forEach(
|
|
2579
|
+
const targetResourceDate = resourcesDates.find(n => n.date === startDate);
|
|
2580
|
+
if (!targetResourceDate) continue;
|
|
2581
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(targetResourceDate.resource || []);
|
|
2582
|
+
itemsInTimeSlot.forEach(cartItem => {
|
|
2583
|
+
if (!cartItem._productOrigin) return;
|
|
2584
|
+
|
|
2585
|
+
// 获取商品的资源配置
|
|
2586
|
+
const productResourceIds = (0, _capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
|
|
2587
|
+
productResourceIds.forEach(resourceId => {
|
|
2502
2588
|
if (resourcesMap[resourceId] && !resourcesIdSet.has(resourceId)) {
|
|
2503
2589
|
resourcesIdSet.add(resourceId);
|
|
2504
2590
|
allResourcesForTimeSlot.push(resourcesMap[resourceId]);
|
|
2505
2591
|
}
|
|
2506
2592
|
});
|
|
2507
2593
|
});
|
|
2508
|
-
|
|
2594
|
+
|
|
2595
|
+
// 按资源类型分组检查容量
|
|
2596
|
+
const {
|
|
2597
|
+
success,
|
|
2598
|
+
required,
|
|
2599
|
+
available
|
|
2600
|
+
} = (0, _capacity.checkTimeSlotCapacity)(timeSlotStart, timeSlotEnd, itemsInTimeSlot, allResourcesForTimeSlot);
|
|
2509
2601
|
if (!success) {
|
|
2510
|
-
|
|
2511
|
-
|
|
2602
|
+
// 如果有可用数量记录,返回最小值;否则返回 0
|
|
2603
|
+
const minAvailableCount = availableCountsByResourceType.length > 0 ? Math.min(...availableCountsByResourceType) : 0;
|
|
2604
|
+
return {
|
|
2605
|
+
success: false,
|
|
2606
|
+
minAvailableCount
|
|
2607
|
+
};
|
|
2512
2608
|
}
|
|
2513
2609
|
}
|
|
2610
|
+
|
|
2611
|
+
// 全部通过检测,返回成功和最小可用数量
|
|
2514
2612
|
const minAvailableCount = availableCountsByResourceType.length > 0 ? Math.min(...availableCountsByResourceType) : 0;
|
|
2515
|
-
return {
|
|
2613
|
+
return {
|
|
2614
|
+
success: true,
|
|
2615
|
+
minAvailableCount
|
|
2616
|
+
};
|
|
2516
2617
|
}
|
|
2618
|
+
|
|
2517
2619
|
/**
|
|
2518
2620
|
* 将 ProductData 转换为 CartItem,但不添加到购物车
|
|
2519
2621
|
* 参考 addProductToCart 方法的实现
|
|
@@ -2530,21 +2632,34 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2530
2632
|
product_variant_id,
|
|
2531
2633
|
quantity = 1
|
|
2532
2634
|
} = product || {};
|
|
2533
|
-
|
|
2534
|
-
|
|
2635
|
+
|
|
2636
|
+
// 处理商品数据,类似 addProductToCart 中的逻辑
|
|
2637
|
+
const productData = {
|
|
2638
|
+
...origin,
|
|
2639
|
+
product_variant_id
|
|
2640
|
+
};
|
|
2641
|
+
|
|
2642
|
+
// 处理组合商品
|
|
2643
|
+
const processedProduct = (0, _utils.handleVariantProduct)(productData);
|
|
2644
|
+
|
|
2645
|
+
// 如果没有传入账户,获取当前活跃账户
|
|
2535
2646
|
if (!account) {
|
|
2536
2647
|
const activeAccount = this.getActiveAccount();
|
|
2537
2648
|
if (activeAccount) {
|
|
2538
2649
|
account = activeAccount;
|
|
2539
2650
|
}
|
|
2540
2651
|
}
|
|
2652
|
+
|
|
2653
|
+
// 创建基础的 CartItem
|
|
2541
2654
|
const cartItem = {
|
|
2542
|
-
_id: (0,
|
|
2543
|
-
_origin: (0,
|
|
2655
|
+
_id: (0, _utils.getUniqueId)('temp_'),
|
|
2656
|
+
_origin: (0, _utils.createCartItemOrigin)(),
|
|
2544
2657
|
_productOrigin: processedProduct,
|
|
2545
2658
|
_productInit: product
|
|
2546
2659
|
};
|
|
2547
|
-
|
|
2660
|
+
|
|
2661
|
+
// 使用格式化函数填充 CartItem 数据
|
|
2662
|
+
(0, _utils.formatProductToCartItem)({
|
|
2548
2663
|
cartItem,
|
|
2549
2664
|
product: processedProduct,
|
|
2550
2665
|
bundle,
|
|
@@ -2552,14 +2667,18 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2552
2667
|
product_variant_id,
|
|
2553
2668
|
quantity
|
|
2554
2669
|
});
|
|
2670
|
+
|
|
2671
|
+
// 如果有日期信息,格式化日期到购物车
|
|
2555
2672
|
if (date) {
|
|
2556
|
-
(0,
|
|
2673
|
+
(0, _utils.formatDateToCartItem)({
|
|
2557
2674
|
cartItem,
|
|
2558
2675
|
date
|
|
2559
2676
|
});
|
|
2560
2677
|
}
|
|
2678
|
+
|
|
2679
|
+
// 如果有账户信息,格式化账户到购物车
|
|
2561
2680
|
if (account) {
|
|
2562
|
-
(0,
|
|
2681
|
+
(0, _utils.formatAccountToCartItem)({
|
|
2563
2682
|
cartItem,
|
|
2564
2683
|
account
|
|
2565
2684
|
});
|
|
@@ -2571,59 +2690,79 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2571
2690
|
date,
|
|
2572
2691
|
account
|
|
2573
2692
|
}) {
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2693
|
+
const cartItems = this.store.cart.getItems().filter(item => !(0, _utils5.isNormalProduct)(item._productOrigin));
|
|
2694
|
+
|
|
2695
|
+
// 将 ProductData 转换为 CartItem 但不真正添加到购物车
|
|
2696
|
+
const currentCartItem = this.convertProductToCartItem({
|
|
2697
|
+
product,
|
|
2698
|
+
date,
|
|
2699
|
+
account
|
|
2700
|
+
});
|
|
2577
2701
|
cartItems.push(currentCartItem);
|
|
2578
|
-
if (cartItems.length === 0)
|
|
2579
|
-
|
|
2702
|
+
if (cartItems.length === 0) return {
|
|
2703
|
+
success: true,
|
|
2704
|
+
minAvailableCount: 0
|
|
2705
|
+
};
|
|
2706
|
+
|
|
2707
|
+
// 将购物车商品分为有时间的和没有时间的
|
|
2580
2708
|
const itemsWithTime = [];
|
|
2581
2709
|
const itemsWithoutTime = [];
|
|
2710
|
+
// 记录每种资源类型的可用数量
|
|
2582
2711
|
const availableCountsByResourceType = [];
|
|
2583
|
-
cartItems.forEach(
|
|
2712
|
+
cartItems.forEach(cartItem => {
|
|
2584
2713
|
if (cartItem.start_time && cartItem.end_time && cartItem.start_date) {
|
|
2585
2714
|
itemsWithTime.push(cartItem);
|
|
2586
2715
|
} else {
|
|
2587
2716
|
itemsWithoutTime.push(cartItem);
|
|
2588
2717
|
}
|
|
2589
2718
|
});
|
|
2719
|
+
|
|
2720
|
+
// 处理没有时间的商品,为它们分配公共可用时间的第一个时间片
|
|
2590
2721
|
const processedItemsWithoutTime = [];
|
|
2591
2722
|
if (itemsWithoutTime.length > 0) {
|
|
2723
|
+
// 按资源类型分组处理没有时间的商品
|
|
2592
2724
|
const itemsByResourceType = {};
|
|
2593
|
-
itemsWithoutTime.forEach(
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
const resourceTypes = ((_a2 = cartItem._productOrigin.product_resource) == null ? void 0 : _a2.resources) || [];
|
|
2598
|
-
resourceTypes.forEach((resourceType) => {
|
|
2599
|
-
var _a3;
|
|
2725
|
+
itemsWithoutTime.forEach(cartItem => {
|
|
2726
|
+
if (!cartItem._productOrigin) return;
|
|
2727
|
+
const resourceTypes = cartItem._productOrigin.product_resource?.resources || [];
|
|
2728
|
+
resourceTypes.forEach(resourceType => {
|
|
2600
2729
|
if (resourceType.status === 1) {
|
|
2601
|
-
const resourceCode = resourceType.code ||
|
|
2730
|
+
const resourceCode = resourceType.code || resourceType.id?.toString();
|
|
2602
2731
|
if (!itemsByResourceType[resourceCode]) {
|
|
2603
2732
|
itemsByResourceType[resourceCode] = [];
|
|
2604
2733
|
}
|
|
2605
|
-
|
|
2734
|
+
// 避免重复添加同一个商品
|
|
2735
|
+
if (!itemsByResourceType[resourceCode].find(item => item._id === cartItem._id)) {
|
|
2606
2736
|
itemsByResourceType[resourceCode].push(cartItem);
|
|
2607
2737
|
}
|
|
2608
2738
|
}
|
|
2609
2739
|
});
|
|
2610
2740
|
});
|
|
2741
|
+
|
|
2742
|
+
// 为每种资源类型检查容量
|
|
2611
2743
|
const dateRange = this.store.date.getDateRange();
|
|
2612
|
-
if (!dateRange || dateRange.length === 0)
|
|
2613
|
-
|
|
2744
|
+
if (!dateRange || dateRange.length === 0) return {
|
|
2745
|
+
success: false,
|
|
2746
|
+
minAvailableCount: 0
|
|
2747
|
+
};
|
|
2614
2748
|
const resourcesDates = this.store.date.getDateList();
|
|
2615
|
-
const targetResourceDate = resourcesDates.find(
|
|
2616
|
-
if (!targetResourceDate)
|
|
2617
|
-
|
|
2618
|
-
|
|
2749
|
+
const targetResourceDate = resourcesDates.find(n => n.date === dateRange[0].date);
|
|
2750
|
+
if (!targetResourceDate) return {
|
|
2751
|
+
success: false,
|
|
2752
|
+
minAvailableCount: 0
|
|
2753
|
+
};
|
|
2754
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(targetResourceDate.resource || []);
|
|
2755
|
+
|
|
2756
|
+
// 从购物车商品中获取资源类型配置,建立 resourceCode 到 form_id 的映射关系
|
|
2619
2757
|
const resourceCodeToFormIdMap = {};
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2758
|
+
|
|
2759
|
+
// 遍历购物车中的商品,收集所有资源类型配置
|
|
2760
|
+
Object.values(itemsByResourceType).flat().forEach(cartItem => {
|
|
2761
|
+
if (cartItem._productOrigin?.product_resource?.resources) {
|
|
2762
|
+
cartItem._productOrigin.product_resource.resources.forEach(resourceConfig => {
|
|
2763
|
+
// 只处理启用的资源类型 (status === 1)
|
|
2625
2764
|
if (resourceConfig.status === 1 && resourceConfig.code) {
|
|
2626
|
-
const formId =
|
|
2765
|
+
const formId = resourceConfig.id?.toString() || resourceConfig.resource_type_id?.toString();
|
|
2627
2766
|
if (formId) {
|
|
2628
2767
|
resourceCodeToFormIdMap[resourceConfig.code] = formId;
|
|
2629
2768
|
}
|
|
@@ -2633,60 +2772,77 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2633
2772
|
});
|
|
2634
2773
|
let hasCapacityIssue = false;
|
|
2635
2774
|
const resourceCapacityInfo = [];
|
|
2636
|
-
|
|
2775
|
+
|
|
2776
|
+
// 用于跟踪已处理的商品,避免重复添加
|
|
2777
|
+
const processedCartItemIds = new Set();
|
|
2778
|
+
|
|
2779
|
+
// 先检查所有资源类型,收集可用数量信息
|
|
2637
2780
|
for (const [resourceCode, items] of Object.entries(itemsByResourceType)) {
|
|
2781
|
+
// 获取该资源类型对应的 form_id
|
|
2638
2782
|
const targetFormId = resourceCodeToFormIdMap[resourceCode];
|
|
2639
2783
|
if (!targetFormId) {
|
|
2640
|
-
|
|
2641
|
-
|
|
2784
|
+
return {
|
|
2785
|
+
success: false,
|
|
2786
|
+
minAvailableCount: 0
|
|
2787
|
+
};
|
|
2642
2788
|
}
|
|
2789
|
+
|
|
2790
|
+
// 获取该资源类型的所有资源
|
|
2643
2791
|
const resourcesOfThisType = [];
|
|
2644
|
-
items.forEach(
|
|
2645
|
-
const productResourceIds = (0,
|
|
2646
|
-
productResourceIds.forEach(
|
|
2647
|
-
var _a2;
|
|
2792
|
+
items.forEach(cartItem => {
|
|
2793
|
+
const productResourceIds = (0, _capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
|
|
2794
|
+
productResourceIds.forEach(resourceId => {
|
|
2648
2795
|
const resource = resourcesMap[resourceId];
|
|
2649
|
-
if (resource &&
|
|
2650
|
-
|
|
2796
|
+
if (resource && resource.form_id?.toString() === targetFormId) {
|
|
2797
|
+
// 避免重复添加同一个资源
|
|
2798
|
+
if (!resourcesOfThisType.find(r => r.id === resource.id)) {
|
|
2651
2799
|
resourcesOfThisType.push(resource);
|
|
2652
2800
|
}
|
|
2653
2801
|
}
|
|
2654
2802
|
});
|
|
2655
2803
|
});
|
|
2656
2804
|
if (resourcesOfThisType.length === 0) {
|
|
2657
|
-
|
|
2658
|
-
|
|
2805
|
+
return {
|
|
2806
|
+
success: false,
|
|
2807
|
+
minAvailableCount: 0
|
|
2808
|
+
};
|
|
2659
2809
|
}
|
|
2810
|
+
|
|
2811
|
+
// 检查资源类型(单个预约 vs 多个预约)
|
|
2812
|
+
// 从商品配置中获取资源类型信息
|
|
2660
2813
|
let resourceTypeConfig = null;
|
|
2661
2814
|
for (const cartItem of items) {
|
|
2662
|
-
if (
|
|
2663
|
-
resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(
|
|
2664
|
-
|
|
2665
|
-
);
|
|
2666
|
-
if (resourceTypeConfig)
|
|
2667
|
-
break;
|
|
2815
|
+
if (cartItem._productOrigin?.product_resource?.resources) {
|
|
2816
|
+
resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(r => r.code === resourceCode && r.status === 1);
|
|
2817
|
+
if (resourceTypeConfig) break;
|
|
2668
2818
|
}
|
|
2669
2819
|
}
|
|
2670
|
-
const isMultipleBooking =
|
|
2820
|
+
const isMultipleBooking = resourceTypeConfig?.type === 'multiple';
|
|
2671
2821
|
let totalAvailable;
|
|
2672
2822
|
let requiredAmount;
|
|
2673
2823
|
let availableAmount;
|
|
2674
2824
|
if (isMultipleBooking) {
|
|
2825
|
+
// 多个预约:计算容量
|
|
2675
2826
|
totalAvailable = resourcesOfThisType.reduce((sum, resource) => {
|
|
2676
2827
|
return sum + (resource.capacity || 0);
|
|
2677
2828
|
}, 0);
|
|
2678
2829
|
requiredAmount = items.reduce((sum, cartItem) => {
|
|
2679
|
-
const {
|
|
2830
|
+
const {
|
|
2831
|
+
currentCapacity
|
|
2832
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(cartItem);
|
|
2680
2833
|
return sum + currentCapacity;
|
|
2681
2834
|
}, 0);
|
|
2682
2835
|
availableAmount = Math.max(0, totalAvailable - requiredAmount);
|
|
2683
2836
|
} else {
|
|
2837
|
+
// 单个预约:计算资源个数
|
|
2684
2838
|
totalAvailable = resourcesOfThisType.length;
|
|
2685
2839
|
requiredAmount = items.reduce((sum, cartItem) => {
|
|
2686
2840
|
return sum + (cartItem.num || 1);
|
|
2687
2841
|
}, 0);
|
|
2688
2842
|
availableAmount = Math.max(0, totalAvailable - requiredAmount);
|
|
2689
2843
|
}
|
|
2844
|
+
|
|
2845
|
+
// 记录资源容量信息
|
|
2690
2846
|
resourceCapacityInfo.push({
|
|
2691
2847
|
code: resourceCode,
|
|
2692
2848
|
available: availableAmount,
|
|
@@ -2695,23 +2851,27 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2695
2851
|
isMultiple: isMultipleBooking
|
|
2696
2852
|
});
|
|
2697
2853
|
availableCountsByResourceType.push(availableAmount);
|
|
2854
|
+
|
|
2855
|
+
// 检查是否有容量问题
|
|
2698
2856
|
if (requiredAmount > totalAvailable) {
|
|
2699
2857
|
hasCapacityIssue = true;
|
|
2700
|
-
console.log(`资源类型 ${resourceCode} ${isMultipleBooking ? "容量" : "资源数量"}不足: 需要 ${requiredAmount}, 总共 ${totalAvailable}`);
|
|
2701
2858
|
}
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2859
|
+
|
|
2860
|
+
// 为通过检测的商品分配一个公共可用时间段
|
|
2861
|
+
|
|
2862
|
+
// 找到所有资源都可用的时间段
|
|
2706
2863
|
const commonTimeSlots = this.findCommonAvailableTimeSlots(resourcesOfThisType);
|
|
2707
|
-
console.log(`资源类型 ${resourceCode} 的公共时间段:`, commonTimeSlots);
|
|
2708
2864
|
if (commonTimeSlots.length === 0) {
|
|
2709
|
-
|
|
2710
|
-
|
|
2865
|
+
return {
|
|
2866
|
+
success: false,
|
|
2867
|
+
minAvailableCount: 0
|
|
2868
|
+
};
|
|
2711
2869
|
}
|
|
2870
|
+
|
|
2871
|
+
// 使用第一个公共可用时间段,但只处理未处理过的商品
|
|
2712
2872
|
const firstCommonSlot = commonTimeSlots[0];
|
|
2713
|
-
|
|
2714
|
-
|
|
2873
|
+
items.forEach(cartItem => {
|
|
2874
|
+
// 只处理未处理过的商品,避免重复添加
|
|
2715
2875
|
if (!processedCartItemIds.has(cartItem._id)) {
|
|
2716
2876
|
processedCartItemIds.add(cartItem._id);
|
|
2717
2877
|
const processedItem = {
|
|
@@ -2725,83 +2885,120 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2725
2885
|
}
|
|
2726
2886
|
});
|
|
2727
2887
|
}
|
|
2888
|
+
|
|
2889
|
+
// 如果有容量问题,找出限制最严格的资源类型,返回其总容量
|
|
2728
2890
|
if (hasCapacityIssue) {
|
|
2729
|
-
|
|
2891
|
+
// 找出超出容量的资源类型中,总容量最少的那个
|
|
2892
|
+
const overCapacityResources = resourceCapacityInfo.filter(info => info.required > info.total);
|
|
2730
2893
|
if (overCapacityResources.length > 0) {
|
|
2731
|
-
const
|
|
2732
|
-
return {
|
|
2894
|
+
const minTotalCapacity = Math.min(...overCapacityResources.map(info => info.total));
|
|
2895
|
+
return {
|
|
2896
|
+
success: false,
|
|
2897
|
+
minAvailableCount: minTotalCapacity
|
|
2898
|
+
};
|
|
2733
2899
|
}
|
|
2734
|
-
|
|
2735
|
-
|
|
2900
|
+
// 如果没有超出容量的(理论上不应该发生),返回总容量最少的
|
|
2901
|
+
const minTotalCapacity = Math.min(...resourceCapacityInfo.map(info => info.total));
|
|
2902
|
+
return {
|
|
2903
|
+
success: false,
|
|
2904
|
+
minAvailableCount: minTotalCapacity
|
|
2905
|
+
};
|
|
2736
2906
|
}
|
|
2737
2907
|
}
|
|
2908
|
+
|
|
2909
|
+
// 合并所有商品(有时间的 + 处理后的没有时间的)
|
|
2738
2910
|
const allProcessedItems = [...itemsWithTime, ...processedItemsWithoutTime];
|
|
2911
|
+
|
|
2912
|
+
// 按时间段分组检查
|
|
2739
2913
|
const cartItemsByTimeSlot = {};
|
|
2740
|
-
allProcessedItems.forEach(
|
|
2741
|
-
if (!cartItem.start_time || !cartItem.end_time || !cartItem.start_date)
|
|
2742
|
-
return;
|
|
2914
|
+
allProcessedItems.forEach(cartItem => {
|
|
2915
|
+
if (!cartItem.start_time || !cartItem.end_time || !cartItem.start_date) return;
|
|
2743
2916
|
const timeSlotKey = `${cartItem.start_date}_${cartItem.start_time}_${cartItem.end_date || cartItem.start_date}_${cartItem.end_time}`;
|
|
2744
2917
|
if (!cartItemsByTimeSlot[timeSlotKey]) {
|
|
2745
2918
|
cartItemsByTimeSlot[timeSlotKey] = [];
|
|
2746
2919
|
}
|
|
2747
2920
|
cartItemsByTimeSlot[timeSlotKey].push(cartItem);
|
|
2748
2921
|
});
|
|
2922
|
+
// 检查每个时间段是否有足够的资源容量
|
|
2749
2923
|
for (const [timeSlotKey, itemsInTimeSlot] of Object.entries(cartItemsByTimeSlot)) {
|
|
2750
|
-
const [startDate, startTime, endDate, endTime] = timeSlotKey.split(
|
|
2924
|
+
const [startDate, startTime, endDate, endTime] = timeSlotKey.split('_');
|
|
2751
2925
|
const timeSlotStart = `${startDate} ${startTime}`;
|
|
2752
2926
|
const timeSlotEnd = `${endDate} ${endTime}`;
|
|
2927
|
+
|
|
2928
|
+
// 获取这个时间段所有商品涉及的资源
|
|
2753
2929
|
const allResourcesForTimeSlot = [];
|
|
2754
|
-
const resourcesIdSet =
|
|
2930
|
+
const resourcesIdSet = new Set();
|
|
2931
|
+
|
|
2932
|
+
// 获取资源数据
|
|
2933
|
+
// const dateRange = this.store.date.getDateRange();
|
|
2755
2934
|
const resourcesDates = this.store.date.getDateList();
|
|
2756
|
-
const targetResourceDate = resourcesDates.find(
|
|
2757
|
-
if (!targetResourceDate)
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
const productResourceIds = (0,
|
|
2764
|
-
productResourceIds.forEach(
|
|
2935
|
+
const targetResourceDate = resourcesDates.find(n => n.date === startDate);
|
|
2936
|
+
if (!targetResourceDate) continue;
|
|
2937
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(targetResourceDate.resource || []);
|
|
2938
|
+
itemsInTimeSlot.forEach(cartItem => {
|
|
2939
|
+
if (!cartItem._productOrigin) return;
|
|
2940
|
+
|
|
2941
|
+
// 获取商品的资源配置
|
|
2942
|
+
const productResourceIds = (0, _capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
|
|
2943
|
+
productResourceIds.forEach(resourceId => {
|
|
2765
2944
|
if (resourcesMap[resourceId] && !resourcesIdSet.has(resourceId)) {
|
|
2766
2945
|
resourcesIdSet.add(resourceId);
|
|
2767
2946
|
allResourcesForTimeSlot.push(resourcesMap[resourceId]);
|
|
2768
2947
|
}
|
|
2769
2948
|
});
|
|
2770
2949
|
});
|
|
2771
|
-
|
|
2950
|
+
|
|
2951
|
+
// 按资源类型分组检查容量
|
|
2952
|
+
const {
|
|
2953
|
+
success,
|
|
2954
|
+
required,
|
|
2955
|
+
available
|
|
2956
|
+
} = (0, _capacity.checkTimeSlotCapacity)(timeSlotStart, timeSlotEnd, itemsInTimeSlot, allResourcesForTimeSlot);
|
|
2772
2957
|
if (!success) {
|
|
2773
|
-
|
|
2958
|
+
// 如果有可用数量记录,返回最小值;否则返回 0
|
|
2959
|
+
// const minAvailableCount = availableCountsByResourceType.length > 0 ? Math.min(...availableCountsByResourceType) : 0;
|
|
2960
|
+
return {
|
|
2961
|
+
success: false,
|
|
2962
|
+
minAvailableCount: available
|
|
2963
|
+
};
|
|
2774
2964
|
}
|
|
2775
2965
|
}
|
|
2966
|
+
|
|
2967
|
+
// 全部通过检测,返回成功和最小可用数量
|
|
2776
2968
|
const minAvailableCount = availableCountsByResourceType.length > 0 ? Math.min(...availableCountsByResourceType) : 0;
|
|
2777
|
-
return {
|
|
2969
|
+
return {
|
|
2970
|
+
success: true,
|
|
2971
|
+
minAvailableCount
|
|
2972
|
+
};
|
|
2778
2973
|
}
|
|
2779
2974
|
setOtherData(key, value) {
|
|
2780
2975
|
this.otherData[key] = value;
|
|
2781
2976
|
this.checkSaveCache({
|
|
2782
2977
|
cacheId: this.cacheId,
|
|
2783
2978
|
fatherModule: this.name,
|
|
2784
|
-
store: {
|
|
2785
|
-
|
|
2979
|
+
store: {
|
|
2980
|
+
otherData: this.otherData
|
|
2981
|
+
},
|
|
2982
|
+
cacheKey: ['otherData']
|
|
2786
2983
|
});
|
|
2787
2984
|
}
|
|
2788
2985
|
getOtherData(key) {
|
|
2789
2986
|
return this.otherData[key];
|
|
2790
2987
|
}
|
|
2791
2988
|
async getProductTypeById(id) {
|
|
2792
|
-
var _a;
|
|
2793
2989
|
const productData = await this.store.products.getProduct(id);
|
|
2794
2990
|
if (productData) {
|
|
2795
2991
|
if (productData.duration) {
|
|
2796
|
-
return
|
|
2992
|
+
return 'duration';
|
|
2797
2993
|
}
|
|
2798
|
-
if (
|
|
2799
|
-
return
|
|
2994
|
+
if (productData['schedule.ids']?.length) {
|
|
2995
|
+
return 'session';
|
|
2800
2996
|
}
|
|
2801
|
-
return
|
|
2997
|
+
return 'normal';
|
|
2802
2998
|
}
|
|
2803
|
-
return
|
|
2999
|
+
return 'normal';
|
|
2804
3000
|
}
|
|
3001
|
+
|
|
2805
3002
|
/**
|
|
2806
3003
|
* 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
|
|
2807
3004
|
*
|
|
@@ -2811,113 +3008,82 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2811
3008
|
* @memberof BookingByStepImpl
|
|
2812
3009
|
*/
|
|
2813
3010
|
getResourcesByCartItemAndCode(cartItemId, resourceCode) {
|
|
2814
|
-
var _a, _b;
|
|
2815
3011
|
const dateRange = this.store.date.getDateRange();
|
|
2816
3012
|
const resources = [];
|
|
2817
|
-
if (dateRange
|
|
2818
|
-
dateRange.forEach(
|
|
2819
|
-
if (n.resource)
|
|
2820
|
-
resources.push(...n.resource);
|
|
3013
|
+
if (dateRange?.length) {
|
|
3014
|
+
dateRange.forEach(n => {
|
|
3015
|
+
if (n.resource) resources.push(...n.resource);
|
|
2821
3016
|
});
|
|
2822
3017
|
}
|
|
2823
3018
|
if (!resources.length) {
|
|
2824
3019
|
const dateList = this.store.date.getDateList();
|
|
2825
|
-
dateList.forEach(
|
|
2826
|
-
if (n.resource)
|
|
2827
|
-
resources.push(...n.resource);
|
|
3020
|
+
dateList.forEach(n => {
|
|
3021
|
+
if (n.resource) resources.push(...n.resource);
|
|
2828
3022
|
});
|
|
2829
3023
|
}
|
|
2830
|
-
const resourcesMap = (0,
|
|
2831
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
2832
|
-
const cartItem = cartItems.find(
|
|
2833
|
-
if (!cartItem)
|
|
2834
|
-
return [];
|
|
3024
|
+
const resourcesMap = (0, _utils2.getResourcesMap)((0, _lodashEs.cloneDeep)(resources));
|
|
3025
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
3026
|
+
const cartItem = cartItems.find(item => item._id === cartItemId);
|
|
3027
|
+
if (!cartItem) return [];
|
|
2835
3028
|
let selectedResources = [];
|
|
2836
|
-
const {
|
|
3029
|
+
const {
|
|
3030
|
+
currentCapacity,
|
|
3031
|
+
formatCapacity
|
|
3032
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(cartItem);
|
|
2837
3033
|
cartItem._origin.metadata.capacity = formatCapacity;
|
|
2838
3034
|
if (cartItem.holder_id) {
|
|
2839
|
-
selectedResources = (0,
|
|
2840
|
-
cartItems,
|
|
2841
|
-
cartItem.holder_id,
|
|
2842
|
-
resourcesMap
|
|
2843
|
-
);
|
|
3035
|
+
selectedResources = (0, _resources.getOthersSelectedResources)(cartItems, cartItem.holder_id, resourcesMap);
|
|
2844
3036
|
} else {
|
|
2845
|
-
selectedResources = (0,
|
|
2846
|
-
cartItems,
|
|
2847
|
-
cartItem._id,
|
|
2848
|
-
resourcesMap
|
|
2849
|
-
);
|
|
3037
|
+
selectedResources = (0, _resources.getOthersCartSelectedResources)(cartItems, cartItem._id, resourcesMap);
|
|
2850
3038
|
}
|
|
2851
|
-
const productResources = (0,
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
selectedResources,
|
|
2855
|
-
currentCapacity
|
|
2856
|
-
);
|
|
2857
|
-
const targetResource = productResources.find(
|
|
2858
|
-
(resource) => resource.code === resourceCode
|
|
2859
|
-
);
|
|
2860
|
-
if (!targetResource)
|
|
2861
|
-
return [];
|
|
3039
|
+
const productResources = (0, _resources.getResourcesByProduct)(resourcesMap, cartItem._productOrigin?.product_resource?.resources || [], selectedResources, currentCapacity);
|
|
3040
|
+
const targetResource = productResources.find(resource => resource.code === resourceCode);
|
|
3041
|
+
if (!targetResource) return [];
|
|
2862
3042
|
if (cartItem._origin.start_time) {
|
|
2863
|
-
const startTime = (0,
|
|
2864
|
-
|
|
2865
|
-
);
|
|
2866
|
-
const endTime = (0, import_dayjs.default)(
|
|
2867
|
-
`${cartItem._origin.end_date} ${cartItem._origin.end_time}`
|
|
2868
|
-
);
|
|
3043
|
+
const startTime = (0, _dayjs.default)(`${cartItem._origin.start_date} ${cartItem._origin.start_time}`);
|
|
3044
|
+
const endTime = (0, _dayjs.default)(`${cartItem._origin.end_date} ${cartItem._origin.end_time}`);
|
|
2869
3045
|
const resourcesUseableMap = {};
|
|
2870
|
-
targetResource.renderList = targetResource.renderList.sort(
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
return 0;
|
|
2880
|
-
}
|
|
2881
|
-
);
|
|
2882
|
-
targetResource.renderList = targetResource.renderList.filter((m) => {
|
|
2883
|
-
const mTimes = m.times.filter((n) => {
|
|
2884
|
-
return !(0, import_dayjs.default)(n.start_at).isAfter((0, import_dayjs.default)(startTime)) && !(0, import_dayjs.default)(n.end_at).isBefore((0, import_dayjs.default)(endTime));
|
|
3046
|
+
targetResource.renderList = targetResource.renderList.sort((a, b) => {
|
|
3047
|
+
const aIsCombined = a.metadata?.combined_resource?.status === 1;
|
|
3048
|
+
const bIsCombined = b.metadata?.combined_resource?.status === 1;
|
|
3049
|
+
if (aIsCombined && !bIsCombined) return 1;
|
|
3050
|
+
if (!aIsCombined && bIsCombined) return -1;
|
|
3051
|
+
return 0;
|
|
3052
|
+
});
|
|
3053
|
+
targetResource.renderList = targetResource.renderList.filter(m => {
|
|
3054
|
+
const mTimes = m.times.filter(n => {
|
|
3055
|
+
return !(0, _dayjs.default)(n.start_at).isAfter((0, _dayjs.default)(startTime)) && !(0, _dayjs.default)(n.end_at).isBefore((0, _dayjs.default)(endTime));
|
|
2885
3056
|
});
|
|
2886
|
-
if (mTimes.length === 0)
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
var _a2;
|
|
2890
|
-
const res = (0, import_resources.getIsUsableByTimeItem)({
|
|
3057
|
+
if (mTimes.length === 0) return false;
|
|
3058
|
+
const canUseArr = mTimes.map(item => {
|
|
3059
|
+
const res = (0, _resources.getIsUsableByTimeItem)({
|
|
2891
3060
|
timeSlice: {
|
|
2892
|
-
start_time: startTime.format(
|
|
2893
|
-
end_time: endTime.format(
|
|
3061
|
+
start_time: startTime.format('HH:mm'),
|
|
3062
|
+
end_time: endTime.format('HH:mm'),
|
|
2894
3063
|
start_at: startTime,
|
|
2895
3064
|
end_at: endTime
|
|
2896
3065
|
},
|
|
2897
3066
|
time: item,
|
|
2898
3067
|
resource: m,
|
|
2899
3068
|
currentCount: currentCapacity || 0,
|
|
2900
|
-
resourcesUseableMap,
|
|
2901
|
-
cut_off_time:
|
|
3069
|
+
resourcesUseableMap: resourcesUseableMap,
|
|
3070
|
+
cut_off_time: cartItem._productOrigin?.cut_off_time
|
|
2902
3071
|
});
|
|
2903
|
-
if (
|
|
3072
|
+
if (resourcesUseableMap?.[m.id] !== false && res.reason !== 'capacityOnly') {
|
|
2904
3073
|
resourcesUseableMap[m.id] = res.usable;
|
|
2905
3074
|
}
|
|
2906
3075
|
return res.usable;
|
|
2907
3076
|
});
|
|
2908
|
-
if (m.onlyComputed)
|
|
2909
|
-
|
|
2910
|
-
return !canUseArr.some((n) => n === false);
|
|
3077
|
+
if (m.onlyComputed) return false;
|
|
3078
|
+
return !canUseArr.some(n => n === false);
|
|
2911
3079
|
});
|
|
2912
3080
|
} else {
|
|
2913
|
-
targetResource.renderList = targetResource.renderList.filter(
|
|
2914
|
-
var _a2, _b2;
|
|
3081
|
+
targetResource.renderList = targetResource.renderList.filter(n => {
|
|
2915
3082
|
const recordCount = n.capacity || 0;
|
|
2916
|
-
if (n.onlyComputed)
|
|
2917
|
-
|
|
2918
|
-
const timeSlots = (0, import_resources.getTimeSlicesByResource)({
|
|
3083
|
+
if (n.onlyComputed) return false;
|
|
3084
|
+
const timeSlots = (0, _resources.getTimeSlicesByResource)({
|
|
2919
3085
|
resource: n,
|
|
2920
|
-
duration:
|
|
3086
|
+
duration: cartItem._productOrigin?.duration?.value || 10,
|
|
2921
3087
|
split: 10,
|
|
2922
3088
|
currentDate: dateRange[0].date
|
|
2923
3089
|
});
|
|
@@ -2926,6 +3092,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2926
3092
|
}
|
|
2927
3093
|
return targetResource.renderList;
|
|
2928
3094
|
}
|
|
3095
|
+
|
|
2929
3096
|
/**
|
|
2930
3097
|
* 根据日期范围批量获取时间槽
|
|
2931
3098
|
* @param params 参数对象
|
|
@@ -2937,17 +3104,15 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2937
3104
|
scheduleIds,
|
|
2938
3105
|
resources
|
|
2939
3106
|
}) {
|
|
2940
|
-
|
|
2941
|
-
"appoimentBooking-session-date-getTimeslotsScheduleByDateRange",
|
|
2942
|
-
{ startDate, endDate, scheduleIds, resources }
|
|
2943
|
-
);
|
|
3107
|
+
// 生成日期范围内的所有日期
|
|
2944
3108
|
const dates = [];
|
|
2945
|
-
let currentDate = (0,
|
|
2946
|
-
const end = (0,
|
|
3109
|
+
let currentDate = (0, _dayjs.default)(startDate);
|
|
3110
|
+
const end = (0, _dayjs.default)(endDate);
|
|
2947
3111
|
while (currentDate.isSameOrBefore(end)) {
|
|
2948
|
-
dates.push(currentDate.format(
|
|
2949
|
-
currentDate = currentDate.add(1,
|
|
3112
|
+
dates.push(currentDate.format('YYYY-MM-DD'));
|
|
3113
|
+
currentDate = currentDate.add(1, 'day');
|
|
2950
3114
|
}
|
|
3115
|
+
// 如果不支持 Web Worker,使用同步方式处理
|
|
2951
3116
|
const results = {};
|
|
2952
3117
|
for (const date of dates) {
|
|
2953
3118
|
results[date] = this.getTimeslotBySchedule({
|
|
@@ -2959,25 +3124,36 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2959
3124
|
return results;
|
|
2960
3125
|
}
|
|
2961
3126
|
async getAvailableDateForSessionOptimize(params = {}) {
|
|
2962
|
-
|
|
2963
|
-
let {
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
}
|
|
2967
|
-
|
|
3127
|
+
// 开始日期如果小于今天,直接以今天当做开始日期
|
|
3128
|
+
let {
|
|
3129
|
+
startDate,
|
|
3130
|
+
endDate
|
|
3131
|
+
} = params;
|
|
3132
|
+
// 前端传递的 startDate,可能是今天之前的,如果 startDate 小于今天 且 endDate 小于或等于今天,需要把 startDate 置为今天
|
|
3133
|
+
if ((0, _dayjs.default)(startDate).isBefore((0, _dayjs.default)(), 'day') && ((0, _dayjs.default)(endDate).isAfter((0, _dayjs.default)(), 'day') || (0, _dayjs.default)(endDate).isSame((0, _dayjs.default)(), 'day'))) {
|
|
3134
|
+
startDate = (0, _dayjs.default)().format('YYYY-MM-DD');
|
|
3135
|
+
}
|
|
3136
|
+
// 不管前端传什么 endDate 默认查一个月的,以今天为开始日期。用于找到一个月内最近可用的日期
|
|
3137
|
+
// 优化策略:
|
|
3138
|
+
// 在 endDate 添加完一个月以后,如果 endDate 还小于 startDate + 7 天,则还需要 endDate+7 天
|
|
3139
|
+
const endDateAfterMonth = (0, _dayjs.default)().add(1, 'month').format('YYYY-MM-DD');
|
|
2968
3140
|
let tempEndDate = endDateAfterMonth;
|
|
2969
|
-
if ((0,
|
|
2970
|
-
tempEndDate = (0,
|
|
3141
|
+
if ((0, _dayjs.default)(startDate).add(7, 'day').isAfter((0, _dayjs.default)(endDateAfterMonth), 'day')) {
|
|
3142
|
+
tempEndDate = (0, _dayjs.default)(startDate).add(7, 'day').format('YYYY-MM-DD');
|
|
2971
3143
|
} else {
|
|
2972
3144
|
tempEndDate = endDateAfterMonth;
|
|
2973
3145
|
}
|
|
2974
|
-
|
|
2975
|
-
|
|
3146
|
+
// 如果这么算出来的 tempEndDate 还小于 endDate,则需要把 endDate 置为 tempEndDate
|
|
3147
|
+
if ((0, _dayjs.default)(tempEndDate).isBefore((0, _dayjs.default)(endDate), 'day')) {
|
|
3148
|
+
tempEndDate = endDate || '';
|
|
2976
3149
|
}
|
|
2977
3150
|
endDate = tempEndDate;
|
|
2978
|
-
|
|
3151
|
+
|
|
3152
|
+
// 先去读缓存结果,因为正常 UI 调用的是 7 天,而下面我会直接计算 30 天(最少也是 14 天),所以先去读缓存结果,如果缓存结果存在,则直接返回
|
|
3153
|
+
const cache = this.store.currentProductMeta?.['timeSlotBySchedule'];
|
|
2979
3154
|
if (cache) {
|
|
2980
|
-
|
|
3155
|
+
// 开始日期大于等于缓存的开始日期,且结束日期小于等于缓存的结束日期,则直接返回缓存结果
|
|
3156
|
+
if ((0, _dayjs.default)(params.startDate).isSameOrAfter((0, _dayjs.default)(cache.startDate), 'day') && (0, _dayjs.default)(params.endDate).isSameOrBefore((0, _dayjs.default)(cache.endDate), 'day')) {
|
|
2981
3157
|
this.store.date.setDateList(cache.dateList);
|
|
2982
3158
|
return {
|
|
2983
3159
|
dateList: cache.dateList,
|
|
@@ -2986,190 +3162,207 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2986
3162
|
}
|
|
2987
3163
|
}
|
|
2988
3164
|
let tempProducts;
|
|
3165
|
+
// 如果当前打开了某个的商品详情弹窗,则应该默认用这个商品
|
|
2989
3166
|
tempProducts = this.store.currentProduct;
|
|
2990
|
-
const schedule =
|
|
2991
|
-
const filteredSchedule = (0,
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
endDate || ""
|
|
2995
|
-
);
|
|
2996
|
-
const tempResourceIds = (0, import_capacity.getResourcesIdsByProduct)(tempProducts);
|
|
3167
|
+
const schedule = this.store.currentProductMeta?.['schedule'];
|
|
3168
|
+
const filteredSchedule = (0, _resources.filterScheduleByDateRange)(schedule, startDate || '', endDate || '');
|
|
3169
|
+
// 1.后端返回的数据,确定资源在每一天的可用和使用情况
|
|
3170
|
+
const tempResourceIds = (0, _capacity.getResourcesIdsByProduct)(tempProducts);
|
|
2997
3171
|
const res = await this.store.date.fetchResourceDates({
|
|
2998
3172
|
query: {
|
|
2999
|
-
start_date: startDate ||
|
|
3000
|
-
end_date: endDate ||
|
|
3173
|
+
start_date: startDate || '',
|
|
3174
|
+
end_date: endDate || '',
|
|
3001
3175
|
resource_ids: tempResourceIds
|
|
3002
3176
|
}
|
|
3003
3177
|
});
|
|
3178
|
+
// 2. 商品 schedule 数据,确定日程在每一天的时间片
|
|
3179
|
+
// 3. 把后端返回的和 schedule 的数据进行合并,确定每一天的可用和使用情况
|
|
3004
3180
|
let dates = [];
|
|
3005
|
-
let currentDate = (0,
|
|
3006
|
-
let firstAvailableDate =
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
)
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
);
|
|
3181
|
+
let currentDate = (0, _dayjs.default)(startDate);
|
|
3182
|
+
let firstAvailableDate = '';
|
|
3183
|
+
|
|
3184
|
+
// 预处理,获取商品下启用的资源类型,后面只需要遍历这些资源的资源列表即可
|
|
3185
|
+
const openResources = tempProducts?.product_resource?.resources?.filter(m => m.status === 1) || [];
|
|
3186
|
+
|
|
3187
|
+
// res.data 返回的一定是启用商品的资源列表,不需要再过滤了
|
|
3188
|
+
const allProductResources = (0, _lodashEs.cloneDeep)((0, _resources.sortCombinedResources)(res.data) || []);
|
|
3189
|
+
// allProductResources 需要根据商品里的资源的单个预约多个预约补充resourceType
|
|
3190
|
+
allProductResources.forEach(m => {
|
|
3191
|
+
const resource = tempProducts?.product_resource?.resources?.find(n => n.id === m.form_id);
|
|
3016
3192
|
if (resource) {
|
|
3017
3193
|
m.resourceType = resource.type;
|
|
3018
3194
|
}
|
|
3019
3195
|
});
|
|
3020
|
-
const targetSchedules = this.store.schedule.getScheduleListByIds(
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
const currentDateStr = currentDate.format("YYYY-MM-DD");
|
|
3025
|
-
let status = "available";
|
|
3196
|
+
const targetSchedules = this.store.schedule.getScheduleListByIds(tempProducts['schedule.ids']);
|
|
3197
|
+
while ((0, _dayjs.default)(currentDate).isBefore((0, _dayjs.default)(endDate), 'day') || (0, _dayjs.default)(currentDate).isSame((0, _dayjs.default)(endDate), 'day')) {
|
|
3198
|
+
const currentDateStr = currentDate.format('YYYY-MM-DD');
|
|
3199
|
+
let status = 'available';
|
|
3026
3200
|
let summaryCount = 0;
|
|
3027
3201
|
let availableCount = 0;
|
|
3028
|
-
|
|
3202
|
+
// 1. 检查商品的提前量等情况是否满足
|
|
3203
|
+
const {
|
|
3204
|
+
latestStartDate,
|
|
3205
|
+
earliestEndDate
|
|
3206
|
+
} = (0, _resources.checkSessionProductLeadTime)(tempProducts);
|
|
3029
3207
|
if (latestStartDate || earliestEndDate) {
|
|
3030
|
-
|
|
3031
|
-
|
|
3208
|
+
// 如果时间在最早开始时间之前,则设置为不可用
|
|
3209
|
+
if (latestStartDate && (0, _dayjs.default)(currentDate).isBefore(latestStartDate, 'day')) {
|
|
3210
|
+
status = 'unavailable';
|
|
3032
3211
|
}
|
|
3033
|
-
|
|
3034
|
-
|
|
3212
|
+
// 如果时间在最早结束时间之后,则设置为不可用
|
|
3213
|
+
if (earliestEndDate && (0, _dayjs.default)(currentDate).isAfter(earliestEndDate, 'day')) {
|
|
3214
|
+
status = 'unavailable';
|
|
3035
3215
|
}
|
|
3036
3216
|
}
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
)
|
|
3041
|
-
|
|
3042
|
-
status = "unavailable";
|
|
3217
|
+
// 2. 检查 schedule 数据,确定 schedule 里没有这一天,或者这一天的isExcluded: true ,则不可用
|
|
3218
|
+
if (status === 'available') {
|
|
3219
|
+
const scheduleByDate = filteredSchedule.find(n => n.date === currentDateStr);
|
|
3220
|
+
if (!scheduleByDate || scheduleByDate?.isExcluded) {
|
|
3221
|
+
status = 'unavailable';
|
|
3043
3222
|
}
|
|
3044
3223
|
}
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
const scheduleTimeSlots = (0, import_utils3.getAllSortedDateRanges)(minTimeMaxTime);
|
|
3224
|
+
|
|
3225
|
+
// 3. 检查这一天的 schedule 时间片里资源是否有可用的,每个时间片下每种资源只需找到第一个可用的即可
|
|
3226
|
+
if (status === 'available') {
|
|
3227
|
+
const minTimeMaxTime = (0, _utils3.calcMinTimeMaxTimeBySchedules)(targetSchedules, {}, currentDateStr);
|
|
3228
|
+
const scheduleTimeSlots = (0, _utils3.getAllSortedDateRanges)(minTimeMaxTime);
|
|
3229
|
+
// 同一天内多个时间片下 只要有一个可用则视为可用
|
|
3052
3230
|
let timesSlotCanUse = false;
|
|
3053
|
-
scheduleTimeSlots.forEach(
|
|
3231
|
+
scheduleTimeSlots.forEach(item => {
|
|
3232
|
+
// 用来计算资源的可使用情况,针对单个schedule 时间片
|
|
3054
3233
|
const resourcesUseableMap = {};
|
|
3234
|
+
// 遍历产品下启用的资源
|
|
3235
|
+
// 必须要保证每种类型的资源都至少有一个能够在对应时间点被选择
|
|
3236
|
+
// 求出第一个资源的剩余量和总量
|
|
3237
|
+
// 剩余量=每个资源在每个时间片内剩余之和
|
|
3238
|
+
// 总量=每个资源在每个时间片内资源总量之和
|
|
3055
3239
|
let isAllResourceTypesUseable = true;
|
|
3056
|
-
openResources.forEach(
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
);
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3240
|
+
openResources.forEach(resource => {
|
|
3241
|
+
// if (!isAllResourceTypesUseable) return;
|
|
3242
|
+
|
|
3243
|
+
// 获取当前资源类型的资源列表
|
|
3244
|
+
const currentResourcesList = allProductResources.filter(n => n.form_id === resource.resource_type_id);
|
|
3245
|
+
// 如果resource.renderList里含有 onlyComputed 的数据,需要把 currentResourcesList 的数据也修正回来
|
|
3246
|
+
resource.renderList?.forEach(item => {
|
|
3247
|
+
if (item.onlyComputed) {
|
|
3248
|
+
const targetIndex = currentResourcesList.findIndex(n => n.id === item.id);
|
|
3064
3249
|
if (targetIndex && targetIndex !== -1) {
|
|
3065
3250
|
currentResourcesList[targetIndex].onlyComputed = true;
|
|
3066
3251
|
}
|
|
3067
3252
|
}
|
|
3068
3253
|
});
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
if (!
|
|
3072
|
-
|
|
3254
|
+
// 可能存在 renderList 没有的情况,则需要判断 resource.optional_resource 和 resource.default_resource 是否存在那个资源,如果不存在也打上 onlyComputed 的标记
|
|
3255
|
+
currentResourcesList.forEach(item => {
|
|
3256
|
+
if (!resource.optional_resource?.includes(item.id) && !resource.default_resource?.includes(item.id)) {
|
|
3257
|
+
item.onlyComputed = true;
|
|
3073
3258
|
}
|
|
3074
3259
|
});
|
|
3260
|
+
// currentResourcesList 排序,onlyComputed 的资源排在前面先计算
|
|
3075
3261
|
currentResourcesList.sort((a, b) => {
|
|
3076
3262
|
return a.onlyComputed ? -1 : 1;
|
|
3077
3263
|
});
|
|
3078
3264
|
let isAnyResourceUseableInType = false;
|
|
3079
|
-
currentResourcesList
|
|
3080
|
-
|
|
3081
|
-
|
|
3265
|
+
currentResourcesList?.forEach(m => {
|
|
3266
|
+
// 遍历所有资源的上工时间片
|
|
3267
|
+
// m.times 需要做个过滤,假设 timeSlice.start_at 是 09:30 timeSlice.end_at 是 11:30
|
|
3268
|
+
// time 是 time.start_at = 2025-05-26 10:30, time.end_at = 2025-05-26 12:30
|
|
3269
|
+
// 需要判断 time 的开始结束时间 是否包含timeSlice的开始结束时间
|
|
3270
|
+
const mTimes = m.times.filter(n => {
|
|
3271
|
+
return !(0, _dayjs.default)(n.start_at).isAfter((0, _dayjs.default)(item.start), 'minute') && !(0, _dayjs.default)(n.end_at).isBefore((0, _dayjs.default)(item.end), 'minute');
|
|
3082
3272
|
});
|
|
3083
|
-
|
|
3084
|
-
|
|
3273
|
+
|
|
3274
|
+
// 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
|
|
3275
|
+
if (mTimes.length === 0) return;
|
|
3276
|
+
// 如果资源可用则把他的容量纳入总计
|
|
3085
3277
|
if (!m.onlyComputed) {
|
|
3086
|
-
if (resource.type ===
|
|
3278
|
+
if (resource.type === 'multiple') {
|
|
3087
3279
|
summaryCount += m.capacity;
|
|
3088
3280
|
} else {
|
|
3089
3281
|
summaryCount += 1;
|
|
3090
3282
|
}
|
|
3091
3283
|
}
|
|
3092
3284
|
let isAnyTimeSliceUseable = false;
|
|
3093
|
-
mTimes.forEach(
|
|
3094
|
-
if (isAnyTimeSliceUseable)
|
|
3095
|
-
|
|
3096
|
-
|
|
3285
|
+
mTimes.forEach(childTiem => {
|
|
3286
|
+
if (isAnyTimeSliceUseable) return;
|
|
3287
|
+
|
|
3288
|
+
// 挨个去匹配某个工作时间段结合当前日程时间,资源能不能用,有多少容量能用
|
|
3289
|
+
const res = (0, _resources.getIsUsableByTimeItem)({
|
|
3097
3290
|
timeSlice: {
|
|
3098
3291
|
start_time: item.start,
|
|
3099
3292
|
end_time: item.end,
|
|
3100
|
-
start_at: (0,
|
|
3101
|
-
end_at: (0,
|
|
3293
|
+
start_at: (0, _dayjs.default)(item.start),
|
|
3294
|
+
end_at: (0, _dayjs.default)(item.end)
|
|
3102
3295
|
},
|
|
3103
3296
|
time: childTiem,
|
|
3104
3297
|
resource: m,
|
|
3105
3298
|
currentCount: 1,
|
|
3106
3299
|
resourcesUseableMap,
|
|
3107
|
-
cut_off_time: tempProducts
|
|
3300
|
+
cut_off_time: tempProducts?.cut_off_time
|
|
3108
3301
|
});
|
|
3109
|
-
if (
|
|
3110
|
-
resourcesUseableMap[m.id] =
|
|
3302
|
+
if (resourcesUseableMap?.[m.id] !== false && res.reason !== 'capacityOnly') {
|
|
3303
|
+
resourcesUseableMap[m.id] = res.usable;
|
|
3111
3304
|
}
|
|
3112
|
-
if (
|
|
3305
|
+
if (res.usable && !m.onlyComputed) {
|
|
3113
3306
|
isAnyTimeSliceUseable = true;
|
|
3114
|
-
if (resource.type ===
|
|
3115
|
-
availableCount +=
|
|
3307
|
+
if (resource.type === 'multiple') {
|
|
3308
|
+
availableCount += res.remainingCapacity;
|
|
3116
3309
|
} else {
|
|
3117
3310
|
availableCount += 1;
|
|
3118
3311
|
}
|
|
3119
3312
|
}
|
|
3120
3313
|
;
|
|
3121
3314
|
});
|
|
3122
|
-
if (isAnyTimeSliceUseable)
|
|
3123
|
-
isAnyResourceUseableInType = true;
|
|
3315
|
+
if (isAnyTimeSliceUseable) isAnyResourceUseableInType = true;
|
|
3124
3316
|
});
|
|
3125
|
-
if (!isAnyResourceUseableInType)
|
|
3126
|
-
isAllResourceTypesUseable = false;
|
|
3317
|
+
if (!isAnyResourceUseableInType) isAllResourceTypesUseable = false;
|
|
3127
3318
|
});
|
|
3128
|
-
if (isAllResourceTypesUseable)
|
|
3129
|
-
timesSlotCanUse = true;
|
|
3319
|
+
if (isAllResourceTypesUseable) timesSlotCanUse = true;
|
|
3130
3320
|
});
|
|
3131
3321
|
if (!timesSlotCanUse) {
|
|
3132
|
-
status =
|
|
3322
|
+
status = 'unavailable';
|
|
3133
3323
|
}
|
|
3134
|
-
if (status ===
|
|
3324
|
+
if (status === 'available' && !firstAvailableDate) {
|
|
3135
3325
|
firstAvailableDate = currentDateStr;
|
|
3136
3326
|
}
|
|
3137
3327
|
}
|
|
3328
|
+
// 状态: lots_of_space: availableCount / summaryCount > 0.5
|
|
3329
|
+
// filling_up_fast: availableCount / summaryCount <= 0.5 && availableCount > 0
|
|
3330
|
+
// sold_out: summaryCount = 0
|
|
3331
|
+
// unavailable: summaryCount > 0 && availableCount = 0
|
|
3138
3332
|
let dateStatus;
|
|
3139
|
-
if (status ===
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
else
|
|
3143
|
-
dateStatus = "unavailable";
|
|
3333
|
+
if (status === 'unavailable') {
|
|
3334
|
+
// dateStatus = 'unavailable'
|
|
3335
|
+
if (availableCount === 0 && summaryCount > 0) dateStatus = 'sold_out';else dateStatus = 'unavailable';
|
|
3144
3336
|
} else {
|
|
3145
3337
|
const usageRatio = availableCount / summaryCount;
|
|
3146
|
-
if (usageRatio > 0.5)
|
|
3147
|
-
dateStatus = "lots_of_space";
|
|
3148
|
-
else
|
|
3149
|
-
dateStatus = "filling_up_fast";
|
|
3338
|
+
if (usageRatio > 0.5) dateStatus = 'lots_of_space';else dateStatus = 'filling_up_fast';
|
|
3150
3339
|
}
|
|
3151
3340
|
dates.push({
|
|
3152
|
-
date: (0,
|
|
3153
|
-
week: (0,
|
|
3154
|
-
weekNum: (0,
|
|
3341
|
+
date: (0, _dayjs.default)(currentDate).format('YYYY-MM-DD'),
|
|
3342
|
+
week: (0, _dayjs.default)(currentDate).format('ddd'),
|
|
3343
|
+
weekNum: (0, _dayjs.default)(currentDate).day(),
|
|
3155
3344
|
summaryCount,
|
|
3156
3345
|
availableCount,
|
|
3157
3346
|
status: dateStatus
|
|
3158
3347
|
});
|
|
3159
|
-
|
|
3348
|
+
|
|
3349
|
+
// 如果 firstAvailableDate 距离 startDate 大于 14 天了,则后面就不需要再找了,也是一种性能保护
|
|
3350
|
+
if (firstAvailableDate && (0, _dayjs.default)(currentDate).diff((0, _dayjs.default)(startDate), 'day') > 31) {
|
|
3160
3351
|
break;
|
|
3161
3352
|
}
|
|
3162
|
-
currentDate = (0,
|
|
3353
|
+
currentDate = (0, _dayjs.default)(currentDate).add(1, 'day');
|
|
3163
3354
|
}
|
|
3164
|
-
|
|
3355
|
+
// 最终把资源数据也加到日期内
|
|
3356
|
+
dates = (0, _utils4.handleAvailableDateByResource)(res.data, dates);
|
|
3165
3357
|
this.store.date.setDateList(dates);
|
|
3166
|
-
|
|
3167
|
-
|
|
3358
|
+
|
|
3359
|
+
// 缓存这次结果,以防后面他小幅度范围内去修改天数
|
|
3360
|
+
if (!this.store.currentProductMeta) this.store.currentProductMeta = {};
|
|
3168
3361
|
this.store.currentProductMeta.timeSlotBySchedule = {
|
|
3169
3362
|
dateList: dates,
|
|
3170
3363
|
firstAvailableDate,
|
|
3171
3364
|
startDate,
|
|
3172
|
-
endDate: (0,
|
|
3365
|
+
endDate: (0, _dayjs.default)(currentDate).format('YYYY-MM-DD')
|
|
3173
3366
|
};
|
|
3174
3367
|
return {
|
|
3175
3368
|
dateList: dates,
|
|
@@ -3177,33 +3370,27 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
3177
3370
|
};
|
|
3178
3371
|
}
|
|
3179
3372
|
isCartAllNormalProducts() {
|
|
3180
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
3373
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
3181
3374
|
return !cartItems.length;
|
|
3182
3375
|
}
|
|
3183
3376
|
isCartHasDurationProduct() {
|
|
3184
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
3185
|
-
return cartItems.some(
|
|
3186
|
-
var _a;
|
|
3187
|
-
return (_a = n._productOrigin) == null ? void 0 : _a.duration;
|
|
3188
|
-
});
|
|
3377
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
3378
|
+
return cartItems.some(n => n._productOrigin?.duration);
|
|
3189
3379
|
}
|
|
3190
3380
|
isTargetNormalProduct(product) {
|
|
3191
|
-
if (!product)
|
|
3192
|
-
|
|
3193
|
-
return (0, import_utils5.isNormalProduct)(product);
|
|
3381
|
+
if (!product) return false;
|
|
3382
|
+
return (0, _utils5.isNormalProduct)(product);
|
|
3194
3383
|
}
|
|
3195
3384
|
isTargetCartIdNormalProduct(id) {
|
|
3196
|
-
const cartItem = this.store.cart.getItems().find(
|
|
3197
|
-
return cartItem && (0,
|
|
3385
|
+
const cartItem = this.store.cart.getItems().find(n => n._id === id);
|
|
3386
|
+
return cartItem && (0, _utils5.isNormalProduct)(cartItem._productOrigin);
|
|
3198
3387
|
}
|
|
3388
|
+
|
|
3199
3389
|
/**
|
|
3200
3390
|
* 获取联系信息
|
|
3201
3391
|
*/
|
|
3202
3392
|
async getContactInfo(params) {
|
|
3203
|
-
return this.request.get(
|
|
3393
|
+
return this.request.get('/customer/metadata', params);
|
|
3204
3394
|
}
|
|
3205
|
-
}
|
|
3206
|
-
|
|
3207
|
-
0 && (module.exports = {
|
|
3208
|
-
BookingByStepImpl
|
|
3209
|
-
});
|
|
3395
|
+
}
|
|
3396
|
+
exports.BookingByStepImpl = BookingByStepImpl;
|