@pisell/pisellos 0.0.567 → 0.0.568
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 -9
- package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -2
- package/dist/model/strategy/adapter/walletPass/example.js +3 -26
- package/dist/model/strategy/adapter/walletPass/utils.js +0 -3
- 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 +1 -4
- package/dist/modules/OpenData/index.js +0 -2
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +14 -41
- package/dist/modules/Payment/index.js +142 -270
- package/dist/modules/Payment/walletpass.js +4 -5
- package/dist/modules/Rules/index.js +0 -7
- 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 +88 -121
- package/dist/server/modules/menu/index.js +32 -41
- package/dist/server/modules/products/index.js +29 -49
- 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 +32 -40
- package/dist/server/utils/product.js +0 -1
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- 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.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +5 -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 -246
- 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.d.ts +5 -0
- package/dist/solution/VenueBooking/index.js +364 -327
- 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 +130 -131
- package/lib/effects/index.js +46 -57
- package/lib/index.js +92 -53
- 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 +84 -63
- package/lib/model/strategy/adapter/promotion/evaluator.js +381 -231
- package/lib/model/strategy/adapter/promotion/examples.js +139 -159
- package/lib/model/strategy/adapter/promotion/index.js +1 -49
- package/lib/model/strategy/adapter/promotion/type.js +199 -35
- package/lib/model/strategy/adapter/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -152
- 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 +652 -402
- 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 +22 -45
- 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 +306 -241
- package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
- package/lib/modules/Cart/utils/cartResource.js +72 -78
- package/lib/modules/Cart/utils/changePrice.js +26 -62
- package/lib/modules/Cart/utils/index.js +106 -48
- package/lib/modules/Customer/constants.js +13 -34
- package/lib/modules/Customer/index.js +216 -153
- 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 +117 -113
- 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 +63 -74
- 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 +332 -320
- package/lib/modules/Order/types.js +24 -33
- package/lib/modules/Order/utils.js +350 -284
- 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 +566 -432
- package/lib/modules/Payment/mx51.js +1 -0
- package/lib/modules/Payment/types.js +216 -107
- package/lib/modules/Payment/utils.js +50 -47
- package/lib/modules/Payment/walletpass.js +221 -203
- 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 +111 -110
- package/lib/modules/ProductList/types.js +9 -31
- package/lib/modules/Quotation/index.js +60 -82
- 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/Rules/index.js +1172 -872
- package/lib/modules/Rules/types.js +17 -40
- package/lib/modules/SalesSummary/index.js +59 -68
- package/lib/modules/SalesSummary/types.js +4 -16
- package/lib/modules/SalesSummary/utils.js +176 -193
- 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 -167
- package/lib/modules/Schedule/index.js +97 -107
- 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 -70
- package/lib/modules/Summary/types.js +4 -16
- package/lib/modules/Summary/utils.js +782 -429
- package/lib/modules/index.js +212 -57
- 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 +882 -623
- package/lib/server/modules/index.js +85 -59
- package/lib/server/modules/menu/index.js +146 -122
- package/lib/server/modules/menu/types.js +18 -31
- package/lib/server/modules/order/index.js +195 -231
- package/lib/server/modules/order/types.js +107 -32
- package/lib/server/modules/order/utils/filterBookings.js +174 -140
- package/lib/server/modules/order/utils/filterOrders.js +89 -60
- package/lib/server/modules/products/index.js +430 -335
- package/lib/server/modules/products/types.js +41 -34
- package/lib/server/modules/quotation/index.js +76 -77
- package/lib/server/modules/quotation/types.js +21 -31
- package/lib/server/modules/resource/index.js +216 -187
- package/lib/server/modules/resource/types.js +42 -33
- package/lib/server/modules/schedule/index.js +134 -119
- 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/time.js +40 -49
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1530 -1343
- 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.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +147 -122
- package/lib/solution/BookingTicket/types.js +38 -64
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +64 -80
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +82 -80
- package/lib/solution/BookingTicket/utils/scan/index.js +90 -94
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
- 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 +227 -158
- 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 +218 -200
- package/lib/solution/Sales/types.js +27 -33
- package/lib/solution/ScanOrder/index.js +803 -840
- package/lib/solution/ScanOrder/types.js +34 -34
- package/lib/solution/ScanOrder/utils.js +372 -331
- package/lib/solution/ShopDiscount/index.js +230 -236
- package/lib/solution/ShopDiscount/types.js +15 -37
- package/lib/solution/ShopDiscount/utils.js +309 -172
- package/lib/solution/VenueBooking/index.d.ts +5 -0
- package/lib/solution/VenueBooking/index.js +886 -929
- package/lib/solution/VenueBooking/types.js +20 -40
- package/lib/solution/VenueBooking/utils/dateSummary.js +22 -54
- package/lib/solution/VenueBooking/utils/resource.js +31 -54
- package/lib/solution/VenueBooking/utils/slotMerge.js +88 -106
- package/lib/solution/VenueBooking/utils/smartPricing.js +112 -100
- package/lib/solution/VenueBooking/utils/timeSlot.js +133 -132
- package/lib/solution/VenueBooking/utils.js +130 -67
- package/lib/solution/index.js +102 -37
- package/lib/store/createStore.js +32 -29
- package/lib/types/index.js +4 -16
- 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,132 +944,120 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
884
944
|
return errorCartItemIds;
|
|
885
945
|
}
|
|
886
946
|
destroy() {
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
(_i = this.store.order) == null ? void 0 : _i.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();
|
|
953
|
+
this.store.schedule?.destroy();
|
|
954
|
+
this.store.summary?.destroy();
|
|
955
|
+
this.store.order?.destroy();
|
|
897
956
|
this.core.effects.offByModuleDestroy(this.name);
|
|
898
957
|
this.core.unregisterModule(this);
|
|
899
958
|
}
|
|
959
|
+
|
|
900
960
|
// 获取当前购物车内所有关联的资源列表,拼装数据格式
|
|
901
961
|
getResourcesList() {
|
|
902
962
|
const dateRange = this.store.date.getDateRange();
|
|
903
963
|
const resources = [];
|
|
904
|
-
if (dateRange
|
|
905
|
-
dateRange.forEach(
|
|
906
|
-
if (n.resource)
|
|
907
|
-
resources.push(...n.resource);
|
|
964
|
+
if (dateRange?.length) {
|
|
965
|
+
dateRange.forEach(n => {
|
|
966
|
+
if (n.resource) resources.push(...n.resource);
|
|
908
967
|
});
|
|
909
968
|
}
|
|
910
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
969
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
970
|
+
|
|
971
|
+
// 如果此时 resources 为空,视作购物车里已经有了 dateRange 数据,此时 dateList 里明确就是那一天的数据
|
|
911
972
|
if (!resources.length) {
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
);
|
|
917
|
-
resources.push(...dateResources || []);
|
|
973
|
+
// 如果此时购物车里已经有了开始时间,则直接取那天的数据即可
|
|
974
|
+
const firstDateCartItem = cartItems?.find(n => n.start_date);
|
|
975
|
+
if (firstDateCartItem?.start_date) {
|
|
976
|
+
const dateResources = this.store.date.getResourcesListByDate(firstDateCartItem.start_date);
|
|
977
|
+
resources.push(...(dateResources || []));
|
|
918
978
|
} else {
|
|
919
979
|
const dateList = this.store.date.getDateList();
|
|
920
|
-
dateList
|
|
921
|
-
if (n.resource)
|
|
922
|
-
resources.push(...n.resource);
|
|
980
|
+
dateList?.forEach(n => {
|
|
981
|
+
if (n.resource) resources.push(...n.resource);
|
|
923
982
|
});
|
|
924
983
|
}
|
|
925
984
|
}
|
|
926
|
-
const resourcesMap = (0,
|
|
985
|
+
const resourcesMap = (0, _utils2.getResourcesMap)((0, _lodashEs.cloneDeep)(resources));
|
|
927
986
|
const arr = [];
|
|
928
|
-
cartItems.forEach(
|
|
929
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
987
|
+
cartItems.forEach(cartItem => {
|
|
930
988
|
let selectedResources = [];
|
|
931
|
-
const {
|
|
989
|
+
const {
|
|
990
|
+
currentCapacity,
|
|
991
|
+
formatCapacity
|
|
992
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(cartItem);
|
|
932
993
|
cartItem._origin.metadata.capacity = formatCapacity;
|
|
933
994
|
if (cartItem.holder_id) {
|
|
934
|
-
selectedResources = (0,
|
|
935
|
-
cartItems,
|
|
936
|
-
cartItem.holder_id,
|
|
937
|
-
resourcesMap
|
|
938
|
-
);
|
|
995
|
+
selectedResources = (0, _resources.getOthersSelectedResources)(cartItems, cartItem.holder_id, resourcesMap);
|
|
939
996
|
} else {
|
|
940
|
-
selectedResources = (0,
|
|
941
|
-
cartItems,
|
|
942
|
-
cartItem._id,
|
|
943
|
-
resourcesMap
|
|
944
|
-
);
|
|
997
|
+
selectedResources = (0, _resources.getOthersCartSelectedResources)(cartItems, cartItem._id, resourcesMap);
|
|
945
998
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
selectedResources,
|
|
950
|
-
currentCapacity
|
|
951
|
-
);
|
|
999
|
+
// TODO:下面这一坨要放到 resources 模块去
|
|
1000
|
+
const productResources = (0, _resources.getResourcesByProduct)(resourcesMap, cartItem._productOrigin?.product_resource?.resources || [], selectedResources, currentCapacity);
|
|
1001
|
+
// 如果购物车里已经有了时间片,则需要按照时间片过滤
|
|
952
1002
|
if (cartItem._origin.start_time) {
|
|
953
|
-
const startTime = (0,
|
|
954
|
-
|
|
955
|
-
);
|
|
956
|
-
const endTime = (0, import_dayjs.default)(
|
|
957
|
-
`${cartItem._origin.end_date} ${cartItem._origin.end_time}`
|
|
958
|
-
);
|
|
1003
|
+
const startTime = (0, _dayjs.default)(`${cartItem._origin.start_date} ${cartItem._origin.start_time}`);
|
|
1004
|
+
const endTime = (0, _dayjs.default)(`${cartItem._origin.end_date} ${cartItem._origin.end_time}`);
|
|
959
1005
|
const resourcesUseableMap = {};
|
|
960
|
-
productResources.forEach(
|
|
961
|
-
|
|
962
|
-
n.renderList = n.renderList
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
);
|
|
1006
|
+
productResources.forEach(n => {
|
|
1007
|
+
// 资源排下序,把单个资源靠前,组合资源排在后面
|
|
1008
|
+
n.renderList = (0, _resources.sortCombinedResources)(n.renderList);
|
|
1009
|
+
n.renderList = n.renderList.filter(m => {
|
|
1010
|
+
// m.times 需要做个过滤,假设 timeSlice.start_at 是 09:30 timeSlice.end_at 是 11:30
|
|
1011
|
+
// time 是 time.start_at = 2025-05-26 10:30, time.end_at = 2025-05-26 12:30
|
|
1012
|
+
// 需要判断 time 的开始结束时间 是否包含timeSlice的开始结束时间
|
|
1013
|
+
const mTimes = (0, _timeslots.filterConditionTimeSlots)(m.times, startTime, endTime);
|
|
1014
|
+
// 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
|
|
968
1015
|
if (mTimes.length === 0) {
|
|
969
1016
|
return false;
|
|
970
1017
|
}
|
|
971
|
-
const canUseArr = mTimes.map(
|
|
972
|
-
|
|
973
|
-
const res = (0, import_resources.getIsUsableByTimeItem)({
|
|
1018
|
+
const canUseArr = mTimes.map(item => {
|
|
1019
|
+
const res = (0, _resources.getIsUsableByTimeItem)({
|
|
974
1020
|
timeSlice: {
|
|
975
|
-
start_time: startTime.format(
|
|
976
|
-
end_time: endTime.format(
|
|
1021
|
+
start_time: startTime.format('HH:mm'),
|
|
1022
|
+
end_time: endTime.format('HH:mm'),
|
|
977
1023
|
start_at: startTime,
|
|
978
1024
|
end_at: endTime
|
|
979
1025
|
},
|
|
980
1026
|
time: item,
|
|
981
1027
|
resource: m,
|
|
982
1028
|
currentCount: currentCapacity || 0,
|
|
983
|
-
resourcesUseableMap,
|
|
984
|
-
cut_off_time:
|
|
1029
|
+
resourcesUseableMap: resourcesUseableMap,
|
|
1030
|
+
cut_off_time: cartItem._productOrigin?.cut_off_time
|
|
985
1031
|
});
|
|
986
|
-
|
|
1032
|
+
// 如果仅仅是因为子资源容量不够,不应该标记子资源是被占用的情况(因为组合资源还需要判断子资源够不够)
|
|
1033
|
+
if (resourcesUseableMap?.[m.id] !== false && res.reason !== 'capacityOnly') {
|
|
987
1034
|
resourcesUseableMap[m.id] = res.usable;
|
|
988
1035
|
}
|
|
989
1036
|
return res.usable;
|
|
990
1037
|
});
|
|
991
|
-
if (m.onlyComputed)
|
|
992
|
-
|
|
993
|
-
return !canUseArr.some(
|
|
1038
|
+
if (m.onlyComputed) return false;
|
|
1039
|
+
// 在已经选定时间的情况下,只要canUseTime 里有一个 false,那就代表不可用
|
|
1040
|
+
return !canUseArr.some(n => n === false);
|
|
994
1041
|
});
|
|
995
1042
|
});
|
|
996
1043
|
} else {
|
|
997
|
-
const hasFlexibleDuration =
|
|
998
|
-
const operating_day_boundary =
|
|
999
|
-
const maxBlockThreshold =
|
|
1000
|
-
productResources.forEach(
|
|
1001
|
-
|
|
1002
|
-
|
|
1044
|
+
const hasFlexibleDuration = cartItem._productOrigin?.duration?.type === 'flexible';
|
|
1045
|
+
const operating_day_boundary = this.shopStore.get('core')?.core?.operating_day_boundary;
|
|
1046
|
+
const maxBlockThreshold = cartItem._productOrigin?.duration?.flexible_config?.is_enable_minimum_duration ? cartItem._productOrigin?.duration?.flexible_config?.block_threshold || 0 : 0;
|
|
1047
|
+
productResources.forEach(item => {
|
|
1048
|
+
// 如果资源的 capacity 已经小于了当前需要的 capacity ,则需要把资源给过滤掉
|
|
1049
|
+
// 同时,在这一步尝试去拉一下时间片,基于商品的时长,看每个资源是否还有空余时间能对这个商品做服务,如果没有则过滤
|
|
1050
|
+
item.renderList = item.renderList.filter(n => {
|
|
1003
1051
|
const recordCount = n.capacity || 0;
|
|
1004
|
-
if (n.onlyComputed)
|
|
1005
|
-
|
|
1006
|
-
const timeSlots = (0,
|
|
1052
|
+
if (n.onlyComputed) return false;
|
|
1053
|
+
// 查一下这个资源基于商品的可用时间片
|
|
1054
|
+
const timeSlots = (0, _resources.getTimeSlicesByResource)({
|
|
1007
1055
|
resource: n,
|
|
1008
|
-
duration:
|
|
1056
|
+
duration: cartItem._productOrigin?.duration?.value || 10,
|
|
1009
1057
|
split: 10,
|
|
1010
1058
|
currentDate: dateRange[0].date,
|
|
1011
1059
|
hasFlexibleDuration,
|
|
1012
|
-
cut_off_time:
|
|
1060
|
+
cut_off_time: cartItem._productOrigin?.cut_off_time,
|
|
1013
1061
|
operating_day_boundary,
|
|
1014
1062
|
maxBlockThreshold
|
|
1015
1063
|
});
|
|
@@ -1030,6 +1078,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1030
1078
|
});
|
|
1031
1079
|
return arr;
|
|
1032
1080
|
}
|
|
1081
|
+
|
|
1033
1082
|
/**
|
|
1034
1083
|
* 在日期那边点击下一步的时候,检查这一天购物车里的商品是不是都有资源可以用
|
|
1035
1084
|
*
|
|
@@ -1038,11 +1087,12 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1038
1087
|
*/
|
|
1039
1088
|
checkResourceListForDate() {
|
|
1040
1089
|
const resourcesList = this.getResourcesList();
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
);
|
|
1090
|
+
|
|
1091
|
+
// 检查每一项资源的 renderList 里是否都有数据
|
|
1092
|
+
const hasResource = resourcesList.every(item => item.resources.every(resource => resource.renderList.length > 0));
|
|
1044
1093
|
return hasResource;
|
|
1045
1094
|
}
|
|
1095
|
+
|
|
1046
1096
|
/**
|
|
1047
1097
|
* 给单个购物车里的商品获取资源列表,给 UI 用的
|
|
1048
1098
|
*
|
|
@@ -1051,45 +1101,32 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1051
1101
|
* @memberof BookingByStepImpl
|
|
1052
1102
|
*/
|
|
1053
1103
|
getResourcesListByCartItem(id) {
|
|
1054
|
-
|
|
1055
|
-
const cartItems = this.store.cart.getItems().filter((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
|
|
1104
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
1056
1105
|
const dateRange = this.store.date.getDateRange();
|
|
1057
1106
|
const resources = [];
|
|
1058
|
-
dateRange.forEach(
|
|
1059
|
-
if (n.resource)
|
|
1060
|
-
resources.push(...n.resource);
|
|
1107
|
+
dateRange.forEach(n => {
|
|
1108
|
+
if (n.resource) resources.push(...n.resource);
|
|
1061
1109
|
});
|
|
1062
|
-
|
|
1063
|
-
const
|
|
1110
|
+
// 用于确保后续分配的容量不会超出
|
|
1111
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(resources);
|
|
1112
|
+
const targetCartItem = cartItems.find(n => n._id === id);
|
|
1064
1113
|
if (!targetCartItem) {
|
|
1065
1114
|
throw new Error(`没有找到${id}购物车商品`);
|
|
1066
1115
|
}
|
|
1067
1116
|
let selectedResources = [];
|
|
1068
|
-
const {
|
|
1117
|
+
const {
|
|
1118
|
+
currentCapacity
|
|
1119
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(targetCartItem);
|
|
1069
1120
|
if (targetCartItem.holder_id) {
|
|
1070
|
-
selectedResources = (0,
|
|
1071
|
-
cartItems,
|
|
1072
|
-
targetCartItem.holder_id,
|
|
1073
|
-
resourcesMap
|
|
1074
|
-
);
|
|
1121
|
+
selectedResources = (0, _resources.getOthersSelectedResources)(cartItems, targetCartItem.holder_id, resourcesMap);
|
|
1075
1122
|
} else {
|
|
1076
|
-
selectedResources = (0,
|
|
1077
|
-
cartItems,
|
|
1078
|
-
targetCartItem._id,
|
|
1079
|
-
resourcesMap
|
|
1080
|
-
);
|
|
1123
|
+
selectedResources = (0, _resources.getOthersCartSelectedResources)(cartItems, targetCartItem._id, resourcesMap);
|
|
1081
1124
|
}
|
|
1082
|
-
const productResources = (0,
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
selectedResources,
|
|
1086
|
-
currentCapacity
|
|
1087
|
-
);
|
|
1088
|
-
productResources.forEach((item) => {
|
|
1089
|
-
item.renderList = item.renderList.filter((n) => {
|
|
1125
|
+
const productResources = (0, _resources.getResourcesByProduct)(resourcesMap, targetCartItem._productOrigin?.product_resource?.resources || [], selectedResources, currentCapacity);
|
|
1126
|
+
productResources.forEach(item => {
|
|
1127
|
+
item.renderList = item.renderList.filter(n => {
|
|
1090
1128
|
const recordCount = n.capacity || 0;
|
|
1091
|
-
if (n.onlyComputed)
|
|
1092
|
-
return false;
|
|
1129
|
+
if (n.onlyComputed) return false;
|
|
1093
1130
|
return recordCount >= currentCapacity;
|
|
1094
1131
|
});
|
|
1095
1132
|
});
|
|
@@ -1106,6 +1143,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1106
1143
|
};
|
|
1107
1144
|
}
|
|
1108
1145
|
}
|
|
1146
|
+
|
|
1109
1147
|
// 自动分派可用资源-pro 版,ui 传递某个账号,自动给某个账号下所有商品分配第一种资源
|
|
1110
1148
|
autoSelectAccountResources({
|
|
1111
1149
|
cartItem,
|
|
@@ -1115,109 +1153,111 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1115
1153
|
countMap,
|
|
1116
1154
|
capacity
|
|
1117
1155
|
}) {
|
|
1118
|
-
|
|
1119
|
-
if ((0, import_utils5.isNormalProduct)(cartItem._productOrigin)) {
|
|
1156
|
+
if ((0, _utils5.isNormalProduct)(cartItem._productOrigin)) {
|
|
1120
1157
|
return {};
|
|
1121
1158
|
}
|
|
1122
1159
|
const dateRange = this.store.date.getDateRange();
|
|
1123
|
-
const cartItems = (0,
|
|
1124
|
-
|
|
1160
|
+
const cartItems = (0, _lodashEs.cloneDeep)(this.store.cart.getItems());
|
|
1161
|
+
// 取到账号下所有的商品,然后根据商品的 duration 和资源列表,获取所有可用的资源
|
|
1162
|
+
let accountCartItems = cartItems.filter(n => n.holder_id === holder_id) || [];
|
|
1163
|
+
// 账号下没商品则处理所有购物车
|
|
1125
1164
|
if (!accountCartItems.length) {
|
|
1126
1165
|
accountCartItems = cartItems;
|
|
1127
1166
|
}
|
|
1167
|
+
// duration=所有商品时间的集合,如果是灵活时长,当做占用 10 分钟处理
|
|
1128
1168
|
let duration = accountCartItems.reduce((acc, n) => {
|
|
1129
|
-
|
|
1130
|
-
return acc + (((_b2 = (_a2 = n._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.value) || 10);
|
|
1169
|
+
return acc + (n._productOrigin?.duration?.value || 10);
|
|
1131
1170
|
}, 0);
|
|
1132
1171
|
let AllResources = [];
|
|
1133
|
-
if (dateRange
|
|
1134
|
-
dateRange.forEach(
|
|
1135
|
-
if (n.resource)
|
|
1136
|
-
AllResources.push(...n.resource);
|
|
1172
|
+
if (dateRange?.length) {
|
|
1173
|
+
dateRange.forEach(n => {
|
|
1174
|
+
if (n.resource) AllResources.push(...n.resource);
|
|
1137
1175
|
});
|
|
1138
1176
|
}
|
|
1177
|
+
// 如果此时 resources 为空,视作购物车里已经有了 dateRange 数据,此时 dateList 里明确就是那一天的数据
|
|
1139
1178
|
if (!AllResources.length) {
|
|
1140
|
-
const firstDateCartItem = cartItems
|
|
1141
|
-
if (firstDateCartItem
|
|
1142
|
-
const dateResources = this.store.date.getResourcesListByDate(
|
|
1143
|
-
|
|
1144
|
-
);
|
|
1145
|
-
AllResources.push(...dateResources || []);
|
|
1179
|
+
const firstDateCartItem = cartItems?.find(n => n.start_date);
|
|
1180
|
+
if (firstDateCartItem?.start_date) {
|
|
1181
|
+
const dateResources = this.store.date.getResourcesListByDate(firstDateCartItem.start_date);
|
|
1182
|
+
AllResources.push(...(dateResources || []));
|
|
1146
1183
|
} else {
|
|
1147
1184
|
const dateList = this.store.date.getDateList();
|
|
1148
|
-
dateList.forEach(
|
|
1149
|
-
if (n.resource)
|
|
1150
|
-
AllResources.push(...n.resource);
|
|
1185
|
+
dateList.forEach(n => {
|
|
1186
|
+
if (n.resource) AllResources.push(...n.resource);
|
|
1151
1187
|
});
|
|
1152
1188
|
}
|
|
1153
1189
|
}
|
|
1154
|
-
const resourcesMap = (0,
|
|
1155
|
-
const allCartItems = (0,
|
|
1156
|
-
const selectedResources = (0,
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
);
|
|
1161
|
-
let allProductResources = (0, import_resources.getResourcesByProduct)(
|
|
1162
|
-
resourcesMap,
|
|
1163
|
-
((_b = (_a = cartItem._productOrigin) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) || [],
|
|
1164
|
-
selectedResources,
|
|
1165
|
-
1
|
|
1166
|
-
);
|
|
1167
|
-
const resources = ((_c = allProductResources.find((n) => n.code === resources_code)) == null ? void 0 : _c.renderList) || [];
|
|
1190
|
+
const resourcesMap = (0, _utils2.getResourcesMap)((0, _lodashEs.cloneDeep)(AllResources));
|
|
1191
|
+
const allCartItems = (0, _lodashEs.cloneDeep)(this.store.cart.getItems());
|
|
1192
|
+
const selectedResources = (0, _resources.getOthersSelectedResources)(allCartItems, holder_id, resourcesMap);
|
|
1193
|
+
let allProductResources = (0, _resources.getResourcesByProduct)(resourcesMap, cartItem._productOrigin?.product_resource?.resources || [], selectedResources, 1);
|
|
1194
|
+
const resources = allProductResources.find(n => n.code === resources_code)?.renderList || [];
|
|
1195
|
+
// 资源排下序,把单个资源靠前,组合资源排在后面
|
|
1168
1196
|
resources.sort((a, b) => {
|
|
1169
|
-
|
|
1170
|
-
const
|
|
1171
|
-
|
|
1172
|
-
if (aIsCombined &&
|
|
1173
|
-
return 1;
|
|
1174
|
-
if (!aIsCombined && bIsCombined)
|
|
1175
|
-
return -1;
|
|
1197
|
+
const aIsCombined = a.metadata?.combined_resource?.status === 1;
|
|
1198
|
+
const bIsCombined = b.metadata?.combined_resource?.status === 1;
|
|
1199
|
+
if (aIsCombined && !bIsCombined) return 1;
|
|
1200
|
+
if (!aIsCombined && bIsCombined) return -1;
|
|
1176
1201
|
return 0;
|
|
1177
1202
|
});
|
|
1178
|
-
const resourcesUseableMap = [
|
|
1179
|
-
|
|
1180
|
-
].reduce((acc, n) => {
|
|
1181
|
-
var _a2;
|
|
1182
|
-
acc[n] = ((_a2 = resourcesMap[n]) == null ? void 0 : _a2.resourceType) === "single" ? false : true;
|
|
1203
|
+
const resourcesUseableMap = [...selectedResources].reduce((acc, n) => {
|
|
1204
|
+
acc[n] = resourcesMap[n]?.resourceType === 'single' ? false : true;
|
|
1183
1205
|
return acc;
|
|
1184
1206
|
}, {});
|
|
1207
|
+
|
|
1208
|
+
// 如果有选择时间了,则代表不是第一种资源了,则需要根据开始时间去匹配
|
|
1209
|
+
// 每个商品
|
|
1185
1210
|
if (timeSlots) {
|
|
1211
|
+
// const start_time = timeSlots.start_at.format("YYYY-MM-DD HH:mm");
|
|
1212
|
+
// const end_time = dayjs(`${dateRange[0].date} ${timeSlots.start_time}`)
|
|
1213
|
+
// .add(duration, durationType as dayjs.ManipulateType)
|
|
1214
|
+
// .format("HH:mm");
|
|
1215
|
+
// 根据 start_time 和 end_time 去匹配资源
|
|
1186
1216
|
let targetResource = null;
|
|
1187
1217
|
let targetResourceTime = 0;
|
|
1188
1218
|
for (const n of resources) {
|
|
1189
|
-
|
|
1190
|
-
|
|
1219
|
+
// 如果资源是独占的,并且 countMap 里选择过这个资源,则直接跳过
|
|
1220
|
+
// if (n.resourceType === 'single' && countMap[n.id]) {
|
|
1221
|
+
// resourcesUseableMap[n.id] = false;
|
|
1222
|
+
// continue
|
|
1223
|
+
// }
|
|
1224
|
+
// const recordCount = countMap[n.id] || 0;
|
|
1225
|
+
// n.times 需要做个过滤,假设 timeSlice.start_at 是 09:30 timeSlice.end_at 是 11:30
|
|
1226
|
+
// time 是 time.start_at = 2025-05-26 10:30, time.end_at = 2025-05-26 12:30
|
|
1227
|
+
// 需要判断 time 的开始结束时间 是否包含timeSlice的开始结束时间
|
|
1228
|
+
const mTimes = n.times.filter(n => {
|
|
1229
|
+
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));
|
|
1191
1230
|
});
|
|
1231
|
+
// 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
|
|
1192
1232
|
if (mTimes.length === 0) {
|
|
1193
1233
|
continue;
|
|
1194
1234
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
if (n.resourceType ===
|
|
1235
|
+
// 计算在时间片内有交集的预约容量总和
|
|
1236
|
+
const totalCapacity = (countMap[n.id] || []).reduce((sum, item) => {
|
|
1237
|
+
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));
|
|
1238
|
+
return hasOverlap ? sum + item.pax : sum;
|
|
1239
|
+
}, 0);
|
|
1240
|
+
|
|
1241
|
+
// 如果资源是单个预约,并且有 totalCapacity,则认为在当前 timeSlots 资源已经被选择过,就不可用了
|
|
1242
|
+
if (n.resourceType === 'single' && totalCapacity > 0) {
|
|
1203
1243
|
continue;
|
|
1204
1244
|
}
|
|
1205
|
-
const canUseTime = mTimes.find(
|
|
1206
|
-
|
|
1207
|
-
const res = (0, import_resources.getIsUsableByTimeItem)({
|
|
1245
|
+
const canUseTime = mTimes.find(item => {
|
|
1246
|
+
const res = (0, _resources.getIsUsableByTimeItem)({
|
|
1208
1247
|
timeSlice: timeSlots,
|
|
1209
1248
|
time: item,
|
|
1210
1249
|
resource: n,
|
|
1211
1250
|
currentCount: totalCapacity + (capacity || 0),
|
|
1212
1251
|
resourcesUseableMap,
|
|
1213
|
-
cut_off_time:
|
|
1252
|
+
cut_off_time: cartItem._productOrigin?.cut_off_time
|
|
1214
1253
|
});
|
|
1215
|
-
|
|
1254
|
+
// 如果只是因为子资源容量不够,而不是子资源被预约导致没时间片,不应该标记子资源为不可用,从而影响组合资源的情况
|
|
1255
|
+
if (resourcesUseableMap?.[n.id] !== false && res.reason !== 'capacityOnly') {
|
|
1216
1256
|
resourcesUseableMap[n.id] = res.usable;
|
|
1217
1257
|
}
|
|
1218
1258
|
return res.usable;
|
|
1219
1259
|
});
|
|
1220
|
-
const currentResourceIdleTime = (0,
|
|
1260
|
+
const currentResourceIdleTime = (0, _timeslots.calculateResourceAvailableTime)({
|
|
1221
1261
|
resource: n,
|
|
1222
1262
|
timeSlots,
|
|
1223
1263
|
currentCapacity: totalCapacity + (capacity || 0)
|
|
@@ -1232,79 +1272,82 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1232
1272
|
selectedResource: targetResource
|
|
1233
1273
|
};
|
|
1234
1274
|
} else {
|
|
1235
|
-
const
|
|
1236
|
-
const resourceIds = resources.map(
|
|
1237
|
-
const
|
|
1275
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(resources);
|
|
1276
|
+
const resourceIds = resources.map(n => n.id);
|
|
1277
|
+
const timeSlots = (0, _resources.getTimeSlicesByResources)({
|
|
1238
1278
|
resourceIds,
|
|
1239
|
-
resourcesMap
|
|
1279
|
+
resourcesMap,
|
|
1240
1280
|
duration,
|
|
1241
1281
|
currentDate: dateRange[0].date,
|
|
1242
1282
|
split: 10,
|
|
1243
1283
|
capacity,
|
|
1244
1284
|
resourcesUseableMap
|
|
1245
1285
|
});
|
|
1246
|
-
|
|
1247
|
-
|
|
1286
|
+
// 如果timeSlots返回了 空数组,代表没有可用的资源了
|
|
1287
|
+
if (!timeSlots) {
|
|
1288
|
+
return; // 给一个提示?
|
|
1248
1289
|
}
|
|
1249
1290
|
return {
|
|
1250
|
-
timeSlots
|
|
1291
|
+
timeSlots,
|
|
1251
1292
|
selectedResource: resources[0]
|
|
1252
1293
|
};
|
|
1253
1294
|
}
|
|
1254
1295
|
}
|
|
1296
|
+
|
|
1255
1297
|
// 给所有购物车里的商品先分配一个资源
|
|
1256
1298
|
autoSelectAllProductResources(resources_code, timeSlots) {
|
|
1257
|
-
var _a;
|
|
1258
1299
|
const dateRange = this.store.date.getDateRange();
|
|
1259
1300
|
const resources = [];
|
|
1260
|
-
if (
|
|
1261
|
-
dateRange.forEach(
|
|
1262
|
-
if (n.resource)
|
|
1263
|
-
resources.push(...n.resource);
|
|
1301
|
+
if (dateRange?.[0]?.date) {
|
|
1302
|
+
dateRange.forEach(n => {
|
|
1303
|
+
if (n.resource) resources.push(...n.resource);
|
|
1264
1304
|
});
|
|
1265
1305
|
}
|
|
1306
|
+
// 一个账号一个账号处理
|
|
1266
1307
|
const errorList = [];
|
|
1308
|
+
// 资源使用情况-单个预约
|
|
1267
1309
|
const selectResourcesMap = {};
|
|
1310
|
+
// 资源使用情况-多个预约
|
|
1268
1311
|
const selectResourcesWithTimeSlots = {};
|
|
1269
1312
|
const accountList = this.store.accountList.getAccounts();
|
|
1270
|
-
const selectForCartResources =
|
|
1271
|
-
let recordTimeSlots = (0,
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
)
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
const hasOriginTimeSlot = Boolean(item._origin.start_time) && Boolean(item._origin.end_time) && !
|
|
1313
|
+
const selectForCartResources = cartItems => {
|
|
1314
|
+
let recordTimeSlots = (0, _lodashEs.cloneDeep)(timeSlots);
|
|
1315
|
+
// timeSlots 传进来的只是用户选中的时间片,但是实际上需要根据多个商品时间进行累加
|
|
1316
|
+
// 假设 timeSlots.start_time 是15:40 duration 是 30min
|
|
1317
|
+
// 第一个商品分配完以后,第二个商品分配的start_time应该是第一个商品的 end_time ,然后 end_time 应该是 start_time+duration
|
|
1318
|
+
// 判断购物车里是否有 flexible 类型的商品,如果有则不累加时间
|
|
1319
|
+
const hasFlexibleProduct = cartItems.some(item => item._productOrigin?.duration?.type === 'flexible');
|
|
1320
|
+
cartItems.forEach((item, index) => {
|
|
1321
|
+
const {
|
|
1322
|
+
currentCapacity
|
|
1323
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(item);
|
|
1324
|
+
const hasOriginTimeSlot = Boolean(item._origin.start_time) && Boolean(item._origin.end_time) && !timeSlots?.start_time;
|
|
1325
|
+
// 如果商品已经有时间数据了,意味着是通过先选日期再选商品流程进来的,相当于时间切片已经选中了
|
|
1282
1326
|
if (hasOriginTimeSlot) {
|
|
1283
1327
|
recordTimeSlots = {
|
|
1284
1328
|
start_time: item._origin.start_time,
|
|
1285
1329
|
end_time: item._origin.end_time,
|
|
1286
|
-
start_at: (0,
|
|
1287
|
-
end_at: (0,
|
|
1330
|
+
start_at: (0, _dayjs.default)(`${item.start_date} ${item._origin.start_time}`),
|
|
1331
|
+
end_at: (0, _dayjs.default)(`${item.end_date} ${item._origin.end_time}`)
|
|
1288
1332
|
};
|
|
1289
1333
|
}
|
|
1290
1334
|
if (recordTimeSlots) {
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
);
|
|
1294
|
-
|
|
1295
|
-
|
|
1335
|
+
// 同一账号下,如果当前商品不是第一个,则需要根据上一个商品的 end_time 和 duration 计算出当前商品的 start_time 和 end_time
|
|
1336
|
+
// 前提:当前资源是单个预约才需要这么做
|
|
1337
|
+
const currentResourceConfig = item._productOrigin?.product_resource?.resources?.find(n => n.code === resources_code);
|
|
1338
|
+
// 只有 duration 类商品且不含有灵活时间的商品需要这个操作
|
|
1339
|
+
if (index !== 0 && recordTimeSlots && currentResourceConfig?.type === 'single' && item._productOrigin?.duration && !hasFlexibleProduct && !hasOriginTimeSlot) {
|
|
1340
|
+
const recordEndAt = recordTimeSlots.end_at ? (0, _dayjs.default)(recordTimeSlots.end_at) : (0, _dayjs.default)(`${item.start_date} ${recordTimeSlots.end_time}`);
|
|
1296
1341
|
let start_at = recordEndAt;
|
|
1297
|
-
let end_at = start_at.add(
|
|
1298
|
-
((_f = (_e = item._productOrigin) == null ? void 0 : _e.duration) == null ? void 0 : _f.value) || 10,
|
|
1299
|
-
"minutes"
|
|
1300
|
-
);
|
|
1342
|
+
let end_at = start_at.add(item._productOrigin?.duration?.value || 10, 'minutes');
|
|
1301
1343
|
recordTimeSlots = {
|
|
1302
|
-
start_time: start_at.format(
|
|
1303
|
-
end_time: end_at.format(
|
|
1344
|
+
start_time: start_at.format('HH:mm'),
|
|
1345
|
+
end_time: end_at.format('HH:mm'),
|
|
1304
1346
|
start_at,
|
|
1305
1347
|
end_at
|
|
1306
1348
|
};
|
|
1307
1349
|
}
|
|
1350
|
+
// 如果传递了 timeSlots,代表是第二种资源,则直接拿 timeSlots 去匹配
|
|
1308
1351
|
const res = this.autoSelectAccountResources({
|
|
1309
1352
|
cartItem: item,
|
|
1310
1353
|
holder_id: item.holder_id,
|
|
@@ -1313,14 +1356,12 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1313
1356
|
countMap: selectResourcesWithTimeSlots,
|
|
1314
1357
|
capacity: currentCapacity
|
|
1315
1358
|
});
|
|
1316
|
-
if (res
|
|
1359
|
+
if (res?.selectedResource) {
|
|
1317
1360
|
if (!selectResourcesWithTimeSlots[res.selectedResource.id]) {
|
|
1318
|
-
selectResourcesWithTimeSlots[res.selectedResource.id] = [
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
}
|
|
1323
|
-
];
|
|
1361
|
+
selectResourcesWithTimeSlots[res.selectedResource.id] = [{
|
|
1362
|
+
pax: currentCapacity,
|
|
1363
|
+
time: recordTimeSlots
|
|
1364
|
+
}];
|
|
1324
1365
|
} else {
|
|
1325
1366
|
selectResourcesWithTimeSlots[res.selectedResource.id].push({
|
|
1326
1367
|
pax: currentCapacity,
|
|
@@ -1328,94 +1369,73 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1328
1369
|
});
|
|
1329
1370
|
}
|
|
1330
1371
|
res.selectedResource.capacity = currentCapacity;
|
|
1331
|
-
(0,
|
|
1372
|
+
(0, _capacity.checkSubResourcesCapacity)(res.selectedResource);
|
|
1332
1373
|
this.store.cart.updateItem({
|
|
1333
1374
|
_id: item._id,
|
|
1334
1375
|
// 这里要做去重,避免出现同样类型的资源被塞进同一个商品
|
|
1335
|
-
resources: [
|
|
1336
|
-
...(item._origin.resources || []).filter(
|
|
1337
|
-
(existingRes) => {
|
|
1338
|
-
var _a3;
|
|
1339
|
-
return existingRes.form_id !== ((_a3 = res.selectedResource) == null ? void 0 : _a3.form_id);
|
|
1340
|
-
}
|
|
1341
|
-
),
|
|
1342
|
-
res.selectedResource
|
|
1343
|
-
]
|
|
1376
|
+
resources: [...(item._origin.resources || []).filter(existingRes => existingRes.form_id !== res.selectedResource?.form_id), res.selectedResource]
|
|
1344
1377
|
});
|
|
1345
1378
|
} else {
|
|
1379
|
+
// 如果没有可用的技师了,推到错误列表里让 UI 去提示
|
|
1346
1380
|
errorList.push(item._id);
|
|
1347
1381
|
}
|
|
1348
1382
|
} else {
|
|
1349
|
-
|
|
1383
|
+
// 这里必须每次循环重新读,避免前一次循环操作了购物车,导致数据变更
|
|
1384
|
+
// 能进到这种逻辑,说明是 duration 类商品或者灵活时长商品,且是第一种资源,还没有确定时间
|
|
1385
|
+
const allCartItems = (0, _lodashEs.cloneDeep)(this.store.cart.getItems());
|
|
1386
|
+
// 如果没有传递 timeSlots,代表是第一种资源,则直接拿商品的 duration,到资源列表里找一个公共可用的
|
|
1350
1387
|
let selectedResources = [];
|
|
1351
|
-
const
|
|
1352
|
-
((_h = (_g = item._productOrigin) == null ? void 0 : _g.product_resource) == null ? void 0 : _h.resources) || []
|
|
1353
|
-
);
|
|
1388
|
+
const resources = (0, _lodashEs.cloneDeep)(item._productOrigin?.product_resource?.resources || []);
|
|
1354
1389
|
const currentResourcesRenderList = [];
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
n.renderList = n.renderList.filter(
|
|
1359
|
-
|
|
1390
|
+
resources.forEach(n => {
|
|
1391
|
+
if (n.renderList?.length) {
|
|
1392
|
+
// 过滤掉 capacity 小于 currentCapacity 的资源
|
|
1393
|
+
n.renderList = n.renderList.filter(m => {
|
|
1394
|
+
// 同时 还需要减去 selectResourcesMap 里已经选中的资源的数量
|
|
1360
1395
|
const recordCount = (m.capacity || 0) - (selectResourcesMap[m.id] || 0);
|
|
1361
|
-
const
|
|
1396
|
+
const timeSlots = (0, _resources.getTimeSlicesByResource)({
|
|
1362
1397
|
resource: m,
|
|
1363
|
-
duration:
|
|
1398
|
+
duration: item?.duration?.value || 10,
|
|
1364
1399
|
split: 10,
|
|
1365
1400
|
currentDate: dateRange[0].date
|
|
1366
1401
|
});
|
|
1367
|
-
return recordCount >= currentCapacity &&
|
|
1402
|
+
return recordCount >= currentCapacity && timeSlots.length > 0;
|
|
1368
1403
|
});
|
|
1369
|
-
currentResourcesRenderList.push(...n.renderList || []);
|
|
1404
|
+
currentResourcesRenderList.push(...(n.renderList || []));
|
|
1370
1405
|
}
|
|
1371
1406
|
});
|
|
1372
|
-
const resourcesMap = (0,
|
|
1407
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(currentResourcesRenderList);
|
|
1373
1408
|
if (item.holder_id) {
|
|
1374
|
-
selectedResources = (0,
|
|
1375
|
-
allCartItems,
|
|
1376
|
-
item.holder_id,
|
|
1377
|
-
resourcesMap
|
|
1378
|
-
);
|
|
1409
|
+
selectedResources = (0, _resources.getOthersSelectedResources)(allCartItems, item.holder_id, resourcesMap);
|
|
1379
1410
|
} else {
|
|
1380
|
-
selectedResources = (0,
|
|
1381
|
-
allCartItems,
|
|
1382
|
-
item._id,
|
|
1383
|
-
resourcesMap
|
|
1384
|
-
);
|
|
1411
|
+
selectedResources = (0, _resources.getOthersCartSelectedResources)(allCartItems, item._id, resourcesMap);
|
|
1385
1412
|
}
|
|
1386
|
-
const productResources = (0,
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
selectedResources,
|
|
1390
|
-
currentCapacity
|
|
1391
|
-
);
|
|
1392
|
-
productResources.forEach((item2) => {
|
|
1393
|
-
item2.renderList = item2.renderList.filter((n) => {
|
|
1413
|
+
const productResources = (0, _resources.getResourcesByProduct)(resourcesMap, (0, _lodashEs.cloneDeep)(resources), selectedResources, currentCapacity);
|
|
1414
|
+
productResources.forEach(item => {
|
|
1415
|
+
item.renderList = item.renderList.filter(n => {
|
|
1394
1416
|
const recordCount = (n.capacity || 0) - (selectResourcesMap[n.id] || 0);
|
|
1395
|
-
if (n.onlyComputed)
|
|
1396
|
-
return false;
|
|
1417
|
+
if (n.onlyComputed) return false;
|
|
1397
1418
|
return recordCount >= currentCapacity;
|
|
1398
1419
|
});
|
|
1399
1420
|
});
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
)) == null ? void 0 : _i.renderList;
|
|
1421
|
+
// 自动选择 productResources 中对应 resources_code 的资源
|
|
1422
|
+
const targetRenderList = productResources.find(n => n.code === resources_code)?.renderList;
|
|
1403
1423
|
if (targetRenderList && targetRenderList.length > 0) {
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
)) {
|
|
1424
|
+
// 如果购物车里已经有同类型的 form_id 的资源了,则不处理
|
|
1425
|
+
if (item._origin.resources?.some(n => n.form_id === targetRenderList[0].form_id)) {
|
|
1407
1426
|
return;
|
|
1408
1427
|
}
|
|
1409
|
-
const fastestResource = (0,
|
|
1428
|
+
const fastestResource = (0, _timeslots.findFastestAvailableResource)({
|
|
1410
1429
|
resources: targetRenderList,
|
|
1411
|
-
currentCapacity,
|
|
1430
|
+
currentCapacity: currentCapacity,
|
|
1412
1431
|
countMap: selectResourcesMap,
|
|
1413
|
-
targetDate:
|
|
1414
|
-
durationMinutes:
|
|
1432
|
+
targetDate: dateRange?.[0]?.date,
|
|
1433
|
+
durationMinutes: item?.duration?.value || item?._productOrigin?.duration?.value || 10
|
|
1415
1434
|
});
|
|
1416
1435
|
const targetResource = fastestResource || targetRenderList[0];
|
|
1417
1436
|
targetResource.capacity = currentCapacity;
|
|
1418
|
-
|
|
1437
|
+
// 在这里处理 children 的数据
|
|
1438
|
+
(0, _capacity.checkSubResourcesCapacity)(targetResource);
|
|
1419
1439
|
if (!selectResourcesMap[targetResource.id]) {
|
|
1420
1440
|
selectResourcesMap[targetResource.id] = currentCapacity;
|
|
1421
1441
|
} else {
|
|
@@ -1423,101 +1443,107 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1423
1443
|
}
|
|
1424
1444
|
this.store.cart.updateItem({
|
|
1425
1445
|
_id: item._id,
|
|
1426
|
-
resources: [
|
|
1427
|
-
...(item._origin.resources || []).filter(
|
|
1428
|
-
(existingRes) => existingRes.resourceType !== targetRenderList[0].resourceType
|
|
1429
|
-
),
|
|
1430
|
-
targetResource
|
|
1431
|
-
]
|
|
1446
|
+
resources: [...(item._origin.resources || []).filter(existingRes => existingRes.resourceType !== targetRenderList[0].resourceType), targetResource]
|
|
1432
1447
|
});
|
|
1433
1448
|
} else {
|
|
1449
|
+
// 如果没有可用的技师了,推到错误列表里让 UI 去提示
|
|
1434
1450
|
errorList.push(item._id);
|
|
1435
1451
|
}
|
|
1436
1452
|
}
|
|
1437
1453
|
});
|
|
1438
1454
|
};
|
|
1439
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1455
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
1456
|
+
|
|
1457
|
+
// 如果购物车里没有 holderid数据,证明不按 holder 类流程预约走,给所有购物车一次性分派即可,不做账号下资源互斥逻辑
|
|
1458
|
+
if (cartItems?.[0].holder_id) {
|
|
1459
|
+
accountList.forEach(account => {
|
|
1460
|
+
const cartItems = this.store.cart.getCartByAccount(account.getId());
|
|
1461
|
+
selectForCartResources(cartItems);
|
|
1444
1462
|
});
|
|
1445
1463
|
} else {
|
|
1446
1464
|
selectForCartResources(cartItems);
|
|
1447
1465
|
}
|
|
1448
|
-
return {
|
|
1466
|
+
return {
|
|
1467
|
+
errorList
|
|
1468
|
+
};
|
|
1449
1469
|
}
|
|
1450
1470
|
// 从购物车中获取已经分配好第一步资源的所有时间片
|
|
1451
1471
|
getTimeSlotByAllResources(resources_code, split = 10) {
|
|
1452
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
1453
1472
|
let dateRange = this.store.date.getDateRange();
|
|
1473
|
+
// 取出购物车中所有一已选择的第一步资源
|
|
1454
1474
|
const resources = [];
|
|
1455
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
1475
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
1476
|
+
// if (cartItems?.[0].start_date) return [];
|
|
1456
1477
|
const resourceIds = [];
|
|
1457
|
-
let resourcesTypeId =
|
|
1478
|
+
let resourcesTypeId = undefined;
|
|
1458
1479
|
let isSingleResource = false;
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1480
|
+
|
|
1481
|
+
// 找出购物车里最大的 cut_off_time
|
|
1482
|
+
let maxCutOffTime = undefined;
|
|
1483
|
+
let maxCutOffTimeValue = (0, _dayjs.default)();
|
|
1484
|
+
cartItems.forEach(item => {
|
|
1485
|
+
item._productOrigin?.product_resource?.resources?.forEach(n => {
|
|
1486
|
+
// TODO: 少了个 status 的判断
|
|
1464
1487
|
if (n.code === resources_code) {
|
|
1465
|
-
resources.push(...n.renderList || []);
|
|
1466
|
-
isSingleResource = n.type ===
|
|
1488
|
+
resources.push(...(n.renderList || []));
|
|
1489
|
+
isSingleResource = n.type === 'single';
|
|
1467
1490
|
}
|
|
1468
1491
|
});
|
|
1492
|
+
// item._origin.resources?.forEach((n: any) => {
|
|
1493
|
+
// resourceIds.push(n.relation_id);
|
|
1494
|
+
// });
|
|
1469
1495
|
if (item.resource_id && !resourceIds.includes(item.resource_id)) {
|
|
1470
1496
|
resourceIds.push(item.resource_id);
|
|
1471
1497
|
}
|
|
1472
|
-
resourcesTypeId =
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
const currentCutOffTime = (0, import_dayjs.default)().add(
|
|
1477
|
-
item._productOrigin.cut_off_time.unit,
|
|
1478
|
-
item._productOrigin.cut_off_time.unit_type
|
|
1479
|
-
);
|
|
1480
|
-
if (currentCutOffTime.isAfter(maxCutOffTimeValue, "minute")) {
|
|
1498
|
+
resourcesTypeId = item?._productOrigin?.product_resource?.resources?.find(n => n.code === resources_code)?.id;
|
|
1499
|
+
if (item._productOrigin?.cut_off_time && item._productOrigin?.cut_off_time.type === 'advance') {
|
|
1500
|
+
const currentCutOffTime = (0, _dayjs.default)().add(item._productOrigin.cut_off_time.unit, item._productOrigin.cut_off_time.unit_type);
|
|
1501
|
+
if (currentCutOffTime.isAfter(maxCutOffTimeValue, 'minute')) {
|
|
1481
1502
|
maxCutOffTimeValue = currentCutOffTime;
|
|
1482
1503
|
maxCutOffTime = item._productOrigin.cut_off_time;
|
|
1483
1504
|
}
|
|
1484
1505
|
}
|
|
1485
1506
|
});
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1507
|
+
// 保险起见,在这里如果 dateRange 里也有 resources 的话,也 push 进去
|
|
1508
|
+
if (dateRange?.[0]?.resource?.length) {
|
|
1509
|
+
// resources.push(...dateRange[0].resource);
|
|
1510
|
+
dateRange[0].resource.forEach(n => {
|
|
1511
|
+
if (n.form_id === resourcesTypeId && !resources.find(m => m.id === n.id)) {
|
|
1489
1512
|
resources.push(n);
|
|
1490
1513
|
}
|
|
1491
1514
|
});
|
|
1492
1515
|
}
|
|
1493
|
-
|
|
1494
|
-
|
|
1516
|
+
// 检查通过购物车 renderList 加入的资源数据里 times 的正确性,如果不对则需要修正
|
|
1517
|
+
if (dateRange?.[0]?.date && resources.length) {
|
|
1518
|
+
const currentDate = dateRange?.[0]?.date;
|
|
1495
1519
|
const theDateResources = this.store.date.getResourcesListByDate(currentDate);
|
|
1496
|
-
resources.forEach(
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
return (0, import_dayjs.default)(n.start_at).isSame((0, import_dayjs.default)(currentDate), "day");
|
|
1520
|
+
resources.forEach(item => {
|
|
1521
|
+
const noCurrentDateTimes = item.times.some(n => {
|
|
1522
|
+
return (0, _dayjs.default)(n.start_at).isSame((0, _dayjs.default)(currentDate), 'day');
|
|
1500
1523
|
});
|
|
1501
1524
|
if (!noCurrentDateTimes) {
|
|
1502
|
-
item.times =
|
|
1525
|
+
item.times = theDateResources?.find(n => n.id === item.id)?.times || [];
|
|
1503
1526
|
}
|
|
1504
1527
|
});
|
|
1505
1528
|
}
|
|
1529
|
+
|
|
1530
|
+
// 如果依然 resources 空的,则证明他是切换日期了,此时直接从 date 模块里取
|
|
1506
1531
|
if (resources.length === 0) {
|
|
1507
|
-
resources.push(...this.store.date.getResourcesListByDate(dateRange[0].date) || []);
|
|
1532
|
+
resources.push(...(this.store.date.getResourcesListByDate(dateRange[0].date) || []));
|
|
1508
1533
|
}
|
|
1509
|
-
const resourcesMap = (0,
|
|
1534
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(resources);
|
|
1510
1535
|
let duration = 0;
|
|
1536
|
+
// duration = 不同账号的最长时间
|
|
1511
1537
|
const accountList = this.store.accountList.getAccounts();
|
|
1512
|
-
const checkDuration =
|
|
1538
|
+
const checkDuration = cartItems => {
|
|
1513
1539
|
let accountDuration = 0;
|
|
1514
|
-
|
|
1515
|
-
|
|
1540
|
+
cartItems.forEach(item => {
|
|
1541
|
+
// 单个预约累加账号 多个预约取最大值
|
|
1516
1542
|
if (isSingleResource) {
|
|
1517
|
-
accountDuration +=
|
|
1543
|
+
accountDuration += item._productOrigin?.duration?.value || 10;
|
|
1518
1544
|
} else {
|
|
1519
|
-
if (accountDuration < (
|
|
1520
|
-
accountDuration =
|
|
1545
|
+
if (accountDuration < (item._productOrigin?.duration?.value || 10)) {
|
|
1546
|
+
accountDuration = item._productOrigin?.duration?.value || 10;
|
|
1521
1547
|
}
|
|
1522
1548
|
}
|
|
1523
1549
|
});
|
|
@@ -1525,74 +1551,68 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1525
1551
|
duration = accountDuration;
|
|
1526
1552
|
}
|
|
1527
1553
|
};
|
|
1528
|
-
if (cartItems
|
|
1529
|
-
accountList.forEach(
|
|
1530
|
-
const
|
|
1531
|
-
checkDuration(
|
|
1554
|
+
if (cartItems?.[0].holder_id) {
|
|
1555
|
+
accountList.forEach(account => {
|
|
1556
|
+
const cartItems = this.store.cart.getCartByAccount(account.getId());
|
|
1557
|
+
checkDuration(cartItems);
|
|
1532
1558
|
});
|
|
1533
1559
|
} else {
|
|
1534
1560
|
checkDuration(cartItems);
|
|
1535
1561
|
}
|
|
1536
|
-
|
|
1562
|
+
// 如果 cartItem 上既没有时间,也没有资源,认为外部属于异常调用,直接丢一个空数组出去
|
|
1563
|
+
// 同时 session 类商品的流程也不应该调用这个方法
|
|
1564
|
+
if (!cartItems?.[0]?.start_date && !cartItems?.[0]?.resource_id || !cartItems?.[0].duration) {
|
|
1537
1565
|
return [];
|
|
1538
1566
|
}
|
|
1539
|
-
if (
|
|
1540
|
-
dateRange = [
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
weekNum: 0
|
|
1552
|
-
}
|
|
1553
|
-
];
|
|
1567
|
+
if (cartItems?.[0].start_date && !dateRange) {
|
|
1568
|
+
dateRange = [{
|
|
1569
|
+
date: cartItems?.[0].start_date,
|
|
1570
|
+
status: 'available',
|
|
1571
|
+
week: '',
|
|
1572
|
+
weekNum: 0
|
|
1573
|
+
}, {
|
|
1574
|
+
date: cartItems?.[0]?.end_date || cartItems?.[0]?.start_date || '',
|
|
1575
|
+
status: 'available',
|
|
1576
|
+
week: '',
|
|
1577
|
+
weekNum: 0
|
|
1578
|
+
}];
|
|
1554
1579
|
}
|
|
1555
1580
|
const resourcesUseableMap = {};
|
|
1556
|
-
const hasFlexibleDuration = cartItems.some(
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
}
|
|
1561
|
-
);
|
|
1562
|
-
let operating_day_boundary = (_j = (_i = this.shopStore.get("core")) == null ? void 0 : _i.core) == null ? void 0 : _j.operating_day_boundary;
|
|
1581
|
+
const hasFlexibleDuration = cartItems.some(item => item._productOrigin?.duration?.type === 'flexible');
|
|
1582
|
+
let operating_day_boundary = this.shopStore.get('core')?.core?.operating_day_boundary;
|
|
1583
|
+
|
|
1584
|
+
// 如果有 hasFlexibleDuration,需要把动态时长商品(可能是多个,取最长的那个最低禁止购买时长)的最低禁止购买时长作为 split 的值
|
|
1563
1585
|
let maxBlockThreshold = 0;
|
|
1564
1586
|
if (hasFlexibleDuration) {
|
|
1565
1587
|
maxBlockThreshold = cartItems.reduce((max, item) => {
|
|
1566
|
-
|
|
1567
|
-
if (
|
|
1568
|
-
return Math.max(
|
|
1569
|
-
max,
|
|
1570
|
-
((_f2 = (_e2 = (_d2 = item._productOrigin) == null ? void 0 : _d2.duration) == null ? void 0 : _e2.flexible_config) == null ? void 0 : _f2.block_threshold) || 0
|
|
1571
|
-
);
|
|
1588
|
+
// 如果开启了灵活时长商品配置,则取 block_threshold 的值
|
|
1589
|
+
if (item._productOrigin?.duration?.flexible_config?.is_enable_minimum_duration) {
|
|
1590
|
+
return Math.max(max, item._productOrigin?.duration?.flexible_config?.block_threshold || 0);
|
|
1572
1591
|
}
|
|
1573
1592
|
return 0;
|
|
1574
1593
|
}, 0);
|
|
1575
1594
|
}
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
if (items.length === 0)
|
|
1579
|
-
|
|
1580
|
-
const firstResource =
|
|
1581
|
-
const sameResourceLength = items.filter(
|
|
1582
|
-
var _a3;
|
|
1583
|
-
return ((_a3 = item._resourceOrigin) == null ? void 0 : _a3[0].id) === firstResource;
|
|
1584
|
-
}).length;
|
|
1595
|
+
// 计算容量的辅助函数
|
|
1596
|
+
const calculateCapacityFromCartItems = items => {
|
|
1597
|
+
if (items.length === 0) return 0;
|
|
1598
|
+
// 还需要增加一个判断,maxCapacity 必须是我单个人里选择的资源只有同一种的情况下才可以累加,否则单个账号都是 1
|
|
1599
|
+
const firstResource = items[0]._resourceOrigin?.[0].id;
|
|
1600
|
+
const sameResourceLength = items.filter(item => item._resourceOrigin?.[0].id === firstResource).length;
|
|
1585
1601
|
if (sameResourceLength === items.length) {
|
|
1586
1602
|
return 1;
|
|
1587
1603
|
}
|
|
1588
|
-
|
|
1604
|
+
// 找出单个购物车里最大的需求 capacity 即可
|
|
1605
|
+
return Math.max(...items.map(item => (0, _capacity.getCapacityInfoByCartItem)(item).currentCapacity || 1));
|
|
1606
|
+
// return items.reduce((total, item) => {
|
|
1607
|
+
// return total + (getCapacityInfoByCartItem(item).currentCapacity || 0);
|
|
1608
|
+
// }, 0);
|
|
1589
1609
|
};
|
|
1610
|
+
|
|
1611
|
+
// 如果是多个人预约,去要求出几个 holder 下最大的商品需求容量capacity
|
|
1590
1612
|
let maxCapacity = 1;
|
|
1591
|
-
if (cartItems
|
|
1592
|
-
accountList.forEach(
|
|
1593
|
-
const accountCartItems = this.store.cart.getCartByAccount(
|
|
1594
|
-
account.getId()
|
|
1595
|
-
);
|
|
1613
|
+
if (cartItems?.[0].holder_id) {
|
|
1614
|
+
accountList.forEach(account => {
|
|
1615
|
+
const accountCartItems = this.store.cart.getCartByAccount(account.getId());
|
|
1596
1616
|
const currentCapacity = calculateCapacityFromCartItems(accountCartItems);
|
|
1597
1617
|
if (currentCapacity > maxCapacity) {
|
|
1598
1618
|
maxCapacity = currentCapacity;
|
|
@@ -1601,13 +1621,13 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1601
1621
|
} else {
|
|
1602
1622
|
maxCapacity = calculateCapacityFromCartItems(cartItems);
|
|
1603
1623
|
}
|
|
1604
|
-
const timeSlots = (0,
|
|
1624
|
+
const timeSlots = (0, _resources.getTimeSlicesByResources)({
|
|
1605
1625
|
resourceIds,
|
|
1606
1626
|
resourcesMap,
|
|
1607
1627
|
duration,
|
|
1608
1628
|
currentDate: dateRange[0].date,
|
|
1609
|
-
split,
|
|
1610
|
-
resourcesUseableMap,
|
|
1629
|
+
split: split,
|
|
1630
|
+
resourcesUseableMap: resourcesUseableMap,
|
|
1611
1631
|
capacity: maxCapacity,
|
|
1612
1632
|
cut_off_time: maxCutOffTime,
|
|
1613
1633
|
hasFlexibleDuration,
|
|
@@ -1617,61 +1637,70 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1617
1637
|
return timeSlots;
|
|
1618
1638
|
}
|
|
1619
1639
|
// 从购物车中获取已经分配好第一步资源的所有时间片,批量版本,用于给日期提供能否高亮的判断
|
|
1620
|
-
async getTimeSlotByAllResourcesForDate({
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1640
|
+
async getTimeSlotByAllResourcesForDate({
|
|
1641
|
+
resources_code,
|
|
1642
|
+
startDate,
|
|
1643
|
+
endDate
|
|
1644
|
+
}) {
|
|
1645
|
+
// 如果 end_date 距离start_date小于 30 天,自动追加 end_date 为今天往后的 30 天
|
|
1646
|
+
if ((0, _dayjs.default)(endDate).diff((0, _dayjs.default)(startDate), 'day') < 30) {
|
|
1647
|
+
endDate = (0, _dayjs.default)(startDate).add(30, 'day').format('YYYY-MM-DD');
|
|
1624
1648
|
}
|
|
1649
|
+
// 预请求资源数据,防止日期超过之前选择的范围
|
|
1625
1650
|
await this.getAvailableDate({
|
|
1626
|
-
startDate,
|
|
1627
|
-
endDate,
|
|
1651
|
+
startDate: startDate,
|
|
1652
|
+
endDate: endDate,
|
|
1628
1653
|
useCache: true
|
|
1629
1654
|
});
|
|
1655
|
+
// 取出购物车中所有一已选择的第一步资源
|
|
1630
1656
|
const resources = [];
|
|
1631
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
1657
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
1658
|
+
// if (cartItems?.[0].start_date) return [];
|
|
1632
1659
|
const resourceIds = [];
|
|
1633
|
-
let resourcesTypeId =
|
|
1660
|
+
let resourcesTypeId = undefined;
|
|
1634
1661
|
let isSingleResource = false;
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1662
|
+
|
|
1663
|
+
// 找出购物车里最大的 cut_off_time
|
|
1664
|
+
let maxCutOffTime = undefined;
|
|
1665
|
+
let maxCutOffTimeValue = (0, _dayjs.default)();
|
|
1666
|
+
cartItems.forEach(item => {
|
|
1667
|
+
item._productOrigin?.product_resource?.resources?.forEach(n => {
|
|
1668
|
+
// TODO: 少了个 status 的判断
|
|
1640
1669
|
if (n.code === resources_code) {
|
|
1641
|
-
resources.push(...n.renderList || []);
|
|
1642
|
-
isSingleResource = n.type ===
|
|
1670
|
+
resources.push(...(n.renderList || []));
|
|
1671
|
+
isSingleResource = n.type === 'single';
|
|
1643
1672
|
}
|
|
1644
1673
|
});
|
|
1674
|
+
// item._origin.resources?.forEach((n: any) => {
|
|
1675
|
+
// resourceIds.push(n.relation_id);
|
|
1676
|
+
// });
|
|
1645
1677
|
if (item.resource_id && !resourceIds.includes(item.resource_id)) {
|
|
1646
1678
|
resourceIds.push(item.resource_id);
|
|
1647
1679
|
}
|
|
1648
|
-
resourcesTypeId =
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
const currentCutOffTime = (0, import_dayjs.default)().add(
|
|
1653
|
-
item._productOrigin.cut_off_time.unit,
|
|
1654
|
-
item._productOrigin.cut_off_time.unit_type
|
|
1655
|
-
);
|
|
1656
|
-
if (currentCutOffTime.isAfter(maxCutOffTimeValue, "minute")) {
|
|
1680
|
+
resourcesTypeId = item?._productOrigin?.product_resource?.resources?.find(n => n.code === resources_code)?.id;
|
|
1681
|
+
if (item._productOrigin?.cut_off_time && item._productOrigin?.cut_off_time.type === 'advance') {
|
|
1682
|
+
const currentCutOffTime = (0, _dayjs.default)().add(item._productOrigin.cut_off_time.unit, item._productOrigin.cut_off_time.unit_type);
|
|
1683
|
+
if (currentCutOffTime.isAfter(maxCutOffTimeValue, 'minute')) {
|
|
1657
1684
|
maxCutOffTimeValue = currentCutOffTime;
|
|
1658
1685
|
maxCutOffTime = item._productOrigin.cut_off_time;
|
|
1659
1686
|
}
|
|
1660
1687
|
}
|
|
1661
1688
|
});
|
|
1662
|
-
|
|
1663
|
-
|
|
1689
|
+
|
|
1690
|
+
// 保护: 如果 resources 为空则直接 return
|
|
1691
|
+
if (!resources.length) return [];
|
|
1664
1692
|
let duration = 0;
|
|
1693
|
+
// duration = 不同账号的最长时间
|
|
1665
1694
|
const accountList = this.store.accountList.getAccounts();
|
|
1666
|
-
const checkDuration =
|
|
1695
|
+
const checkDuration = cartItems => {
|
|
1667
1696
|
let accountDuration = 0;
|
|
1668
|
-
|
|
1669
|
-
|
|
1697
|
+
cartItems.forEach(item => {
|
|
1698
|
+
// 单个预约累加账号 多个预约取最大值
|
|
1670
1699
|
if (isSingleResource) {
|
|
1671
|
-
accountDuration +=
|
|
1700
|
+
accountDuration += item._productOrigin?.duration?.value || 10;
|
|
1672
1701
|
} else {
|
|
1673
|
-
if (accountDuration < (
|
|
1674
|
-
accountDuration =
|
|
1702
|
+
if (accountDuration < (item._productOrigin?.duration?.value || 10)) {
|
|
1703
|
+
accountDuration = item._productOrigin?.duration?.value || 10;
|
|
1675
1704
|
}
|
|
1676
1705
|
}
|
|
1677
1706
|
});
|
|
@@ -1679,52 +1708,50 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1679
1708
|
duration = accountDuration;
|
|
1680
1709
|
}
|
|
1681
1710
|
};
|
|
1682
|
-
if (cartItems
|
|
1683
|
-
accountList.forEach(
|
|
1684
|
-
const
|
|
1685
|
-
checkDuration(
|
|
1711
|
+
if (cartItems?.[0].holder_id) {
|
|
1712
|
+
accountList.forEach(account => {
|
|
1713
|
+
const cartItems = this.store.cart.getCartByAccount(account.getId());
|
|
1714
|
+
checkDuration(cartItems);
|
|
1686
1715
|
});
|
|
1687
1716
|
} else {
|
|
1688
1717
|
checkDuration(cartItems);
|
|
1689
1718
|
}
|
|
1690
|
-
|
|
1719
|
+
// 如果 cartItem 上既没有时间,也没有资源,认为外部属于异常调用,直接丢一个空数组出去
|
|
1720
|
+
// 同时 session 类商品的流程也不应该调用这个方法
|
|
1721
|
+
if (!cartItems?.[0]?.start_date && !cartItems?.[0]?.resource_id || !cartItems?.[0].duration) {
|
|
1691
1722
|
return [];
|
|
1692
1723
|
}
|
|
1693
1724
|
const resourcesUseableMap = {};
|
|
1694
|
-
const hasFlexibleDuration = cartItems.some(
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
}
|
|
1699
|
-
);
|
|
1700
|
-
let operating_day_boundary = (_d = (_c = this.shopStore.get("core")) == null ? void 0 : _c.core) == null ? void 0 : _d.operating_day_boundary;
|
|
1725
|
+
const hasFlexibleDuration = cartItems.some(item => item._productOrigin?.duration?.type === 'flexible');
|
|
1726
|
+
let operating_day_boundary = this.shopStore.get('core')?.core?.operating_day_boundary;
|
|
1727
|
+
|
|
1728
|
+
// 如果有 hasFlexibleDuration,需要把动态时长商品(可能是多个,取最长的那个最低禁止购买时长)的最低禁止购买时长作为 split 的值
|
|
1701
1729
|
let maxBlockThreshold = 0;
|
|
1702
1730
|
if (hasFlexibleDuration) {
|
|
1703
1731
|
maxBlockThreshold = cartItems.reduce((max, item) => {
|
|
1704
|
-
|
|
1705
|
-
if (
|
|
1706
|
-
return Math.max(max,
|
|
1732
|
+
// 如果开启了灵活时长商品配置,则取 block_threshold 的值
|
|
1733
|
+
if (item._productOrigin?.duration?.flexible_config?.is_enable_minimum_duration) {
|
|
1734
|
+
return Math.max(max, item._productOrigin?.duration?.flexible_config?.block_threshold || 0);
|
|
1707
1735
|
}
|
|
1708
1736
|
return 0;
|
|
1709
1737
|
}, 0);
|
|
1710
1738
|
}
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
if (items.length === 0)
|
|
1714
|
-
|
|
1715
|
-
const firstResource =
|
|
1716
|
-
const sameResourceLength = items.filter(
|
|
1717
|
-
var _a3;
|
|
1718
|
-
return ((_a3 = item._resourceOrigin) == null ? void 0 : _a3[0].id) === firstResource;
|
|
1719
|
-
}).length;
|
|
1739
|
+
// 计算容量的辅助函数
|
|
1740
|
+
const calculateCapacityFromCartItems = items => {
|
|
1741
|
+
if (items.length === 0) return 0;
|
|
1742
|
+
// 还需要增加一个判断,maxCapacity 必须是我单个人里选择的资源只有同一种的情况下才可以累加,否则单个账号都是 1
|
|
1743
|
+
const firstResource = items[0]._resourceOrigin?.[0].id;
|
|
1744
|
+
const sameResourceLength = items.filter(item => item._resourceOrigin?.[0].id === firstResource).length;
|
|
1720
1745
|
if (sameResourceLength !== items.length) {
|
|
1721
1746
|
return 1;
|
|
1722
1747
|
}
|
|
1723
|
-
|
|
1748
|
+
// 找出单个购物车里最大的需求 capacity 即可
|
|
1749
|
+
return Math.max(...items.map(item => (0, _capacity.getCapacityInfoByCartItem)(item).currentCapacity || 1));
|
|
1724
1750
|
};
|
|
1751
|
+
// 如果是多个预约,去要求出几个 holder 下最大的需求容量capacity
|
|
1725
1752
|
let maxCapacity = 1;
|
|
1726
|
-
if (cartItems
|
|
1727
|
-
accountList.forEach(
|
|
1753
|
+
if (cartItems?.[0].holder_id) {
|
|
1754
|
+
accountList.forEach(account => {
|
|
1728
1755
|
const accountCartItems = this.store.cart.getCartByAccount(account.getId());
|
|
1729
1756
|
const currentCapacity = calculateCapacityFromCartItems(accountCartItems);
|
|
1730
1757
|
if (currentCapacity > maxCapacity) {
|
|
@@ -1735,31 +1762,33 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1735
1762
|
maxCapacity = calculateCapacityFromCartItems(cartItems);
|
|
1736
1763
|
}
|
|
1737
1764
|
const arr = [];
|
|
1738
|
-
const today = (0,
|
|
1739
|
-
|
|
1740
|
-
|
|
1765
|
+
const today = (0, _dayjs.default)().startOf('day');
|
|
1766
|
+
// 计算 start_date 到 end_date 之间的所有日期,遍历他们并且计算每一天的可用
|
|
1767
|
+
for (let i = (0, _dayjs.default)(startDate); i.isBefore((0, _dayjs.default)(endDate)); i = i.add(1, 'day')) {
|
|
1768
|
+
const currentDate = i.format('YYYY-MM-DD');
|
|
1741
1769
|
const theDateResources = this.store.date.getResourcesListByDate(currentDate);
|
|
1742
|
-
resources.forEach(
|
|
1743
|
-
|
|
1744
|
-
item.times = ((_a2 = theDateResources == null ? void 0 : theDateResources.find((n) => n.id === item.id)) == null ? void 0 : _a2.times) || [];
|
|
1770
|
+
resources.forEach(item => {
|
|
1771
|
+
item.times = theDateResources?.find(n => n.id === item.id)?.times || [];
|
|
1745
1772
|
});
|
|
1746
|
-
const resourcesMap = (0,
|
|
1773
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(resources);
|
|
1774
|
+
|
|
1775
|
+
// 如果日期已经过期则直接标记为不可用
|
|
1747
1776
|
if (i.isBefore(today)) {
|
|
1748
1777
|
arr.push({
|
|
1749
1778
|
date: currentDate,
|
|
1750
|
-
status:
|
|
1751
|
-
week: i.format(
|
|
1779
|
+
status: 'unavailable',
|
|
1780
|
+
week: i.format('ddd'),
|
|
1752
1781
|
weekNum: i.day()
|
|
1753
1782
|
});
|
|
1754
1783
|
continue;
|
|
1755
1784
|
}
|
|
1756
|
-
const timeSlots = (0,
|
|
1785
|
+
const timeSlots = (0, _resources.getTimeSlicesByResources)({
|
|
1757
1786
|
resourceIds,
|
|
1758
1787
|
resourcesMap,
|
|
1759
1788
|
duration,
|
|
1760
|
-
currentDate,
|
|
1789
|
+
currentDate: currentDate,
|
|
1761
1790
|
split: 10,
|
|
1762
|
-
resourcesUseableMap,
|
|
1791
|
+
resourcesUseableMap: resourcesUseableMap,
|
|
1763
1792
|
capacity: maxCapacity,
|
|
1764
1793
|
cut_off_time: maxCutOffTime,
|
|
1765
1794
|
hasFlexibleDuration,
|
|
@@ -1769,63 +1798,74 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1769
1798
|
if (timeSlots.length > 0) {
|
|
1770
1799
|
arr.push({
|
|
1771
1800
|
date: currentDate,
|
|
1772
|
-
status:
|
|
1773
|
-
week: i.format(
|
|
1801
|
+
status: 'available',
|
|
1802
|
+
week: i.format('ddd'),
|
|
1774
1803
|
weekNum: i.day()
|
|
1775
1804
|
});
|
|
1776
1805
|
} else {
|
|
1777
1806
|
arr.push({
|
|
1778
1807
|
date: currentDate,
|
|
1779
|
-
status:
|
|
1780
|
-
week: i.format(
|
|
1808
|
+
status: 'unavailable',
|
|
1809
|
+
week: i.format('ddd'),
|
|
1781
1810
|
weekNum: i.day()
|
|
1782
1811
|
});
|
|
1783
1812
|
}
|
|
1784
1813
|
}
|
|
1785
1814
|
return arr;
|
|
1786
1815
|
}
|
|
1816
|
+
|
|
1787
1817
|
// 提交时间切片,绑定到对应购物车的商品上,更新购物车---只有 duration 商品
|
|
1788
1818
|
submitTimeSlot(timeSlots) {
|
|
1789
|
-
|
|
1790
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
);
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1819
|
+
// 以账号为维度处理数据。购物车里每一项的 startTime应该是前一个商品的 endTime,如果是第一个商品则用 timeSlots.start_at
|
|
1820
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
1821
|
+
|
|
1822
|
+
// 取出所有资源列表
|
|
1823
|
+
const allResources = this.store.date.getResourcesListByDate(timeSlots.start_at.format('YYYY-MM-DD'));
|
|
1824
|
+
|
|
1825
|
+
// 按账号分组
|
|
1826
|
+
const itemsByAccount = cartItems.reduce((acc, item) => {
|
|
1827
|
+
const holderId = item.holder_id;
|
|
1828
|
+
if (!acc[holderId]) {
|
|
1829
|
+
acc[holderId] = [];
|
|
1830
|
+
}
|
|
1831
|
+
acc[holderId].push(item);
|
|
1832
|
+
return acc;
|
|
1833
|
+
}, {});
|
|
1834
|
+
|
|
1835
|
+
// 店铺营业结束时间
|
|
1836
|
+
const operating_day_boundary = this.shopStore.get('core')?.core?.operating_day_boundary;
|
|
1837
|
+
|
|
1838
|
+
// 处理每个账号的商品
|
|
1839
|
+
Object.values(itemsByAccount).forEach(accountItems => {
|
|
1840
|
+
let currentStartTime = timeSlots.start_at.format('YYYY-MM-DD HH:mm');
|
|
1808
1841
|
accountItems.forEach((item, index) => {
|
|
1809
|
-
var _a2;
|
|
1810
1842
|
const osWarnTips = [];
|
|
1811
|
-
const newResources = (0,
|
|
1812
|
-
newResources.forEach(
|
|
1813
|
-
|
|
1814
|
-
if (
|
|
1815
|
-
|
|
1816
|
-
|
|
1843
|
+
const newResources = (0, _lodashEs.cloneDeep)(item._origin.resources);
|
|
1844
|
+
newResources.forEach(resource => {
|
|
1845
|
+
// 如果商品配置的是灵活时长,开始时间设置为提交的时间,结束时间从资源的可用最晚时间和店铺营业结束时间里取一个最早的
|
|
1846
|
+
if (item._productOrigin?.duration?.type === 'flexible') {
|
|
1847
|
+
item.duration = {
|
|
1848
|
+
type: 'minutes',
|
|
1849
|
+
value: 10
|
|
1850
|
+
};
|
|
1851
|
+
resource.startTime = timeSlots.start_at.format('YYYY-MM-DD HH:mm');
|
|
1852
|
+
// 找到resource.times里最晚的end_at
|
|
1853
|
+
const targetResourceTimes = allResources?.find(n => n.id === resource.id)?.times;
|
|
1854
|
+
// 找到最晚的 end_at 还没用,因为可能存在资源工作时间是 10:00-19:00,但是资源的 times 里有 16:30-19:00 被 block 的情况
|
|
1855
|
+
// 所以还需要排除掉 block 时间
|
|
1856
|
+
function getEarliestBlockedStartTime({
|
|
1857
|
+
currentStartTime,
|
|
1817
1858
|
times
|
|
1818
1859
|
}) {
|
|
1819
|
-
|
|
1820
|
-
const currentStart = (0, import_dayjs.default)(currentStartTime2);
|
|
1860
|
+
const currentStart = (0, _dayjs.default)(currentStartTime);
|
|
1821
1861
|
let earliestBlockStart;
|
|
1822
1862
|
for (const time of times || []) {
|
|
1823
|
-
const blockedTimes =
|
|
1863
|
+
const blockedTimes = time.event_list?.filter(event => event.type !== 'schedule_event');
|
|
1824
1864
|
for (const event of blockedTimes || []) {
|
|
1825
|
-
const eventStart = (0,
|
|
1826
|
-
const eventEnd = (0,
|
|
1865
|
+
const eventStart = (0, _dayjs.default)(event.start_at);
|
|
1866
|
+
const eventEnd = (0, _dayjs.default)(event.end_at);
|
|
1827
1867
|
if (eventStart.isBefore(currentStart) && eventEnd.isAfter(currentStart)) {
|
|
1828
|
-
return currentStart.format(
|
|
1868
|
+
return currentStart.format('YYYY-MM-DD HH:mm');
|
|
1829
1869
|
}
|
|
1830
1870
|
if (eventStart.isAfter(currentStart)) {
|
|
1831
1871
|
if (!earliestBlockStart || eventStart.isBefore(earliestBlockStart)) {
|
|
@@ -1834,79 +1874,68 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1834
1874
|
}
|
|
1835
1875
|
}
|
|
1836
1876
|
}
|
|
1837
|
-
return earliestBlockStart
|
|
1838
|
-
}
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
};
|
|
1843
|
-
resource.startTime = timeSlots.start_at.format("YYYY-MM-DD HH:mm");
|
|
1844
|
-
const targetResourceTimes = (_c = allResources == null ? void 0 : allResources.find(
|
|
1845
|
-
(n) => n.id === resource.id
|
|
1846
|
-
)) == null ? void 0 : _c.times;
|
|
1847
|
-
const resourcesEndTime = targetResourceTimes.reduce(
|
|
1848
|
-
(acc, curr) => {
|
|
1849
|
-
return (0, import_dayjs.default)(curr.end_at).isAfter((0, import_dayjs.default)(acc.end_at)) ? curr : acc;
|
|
1850
|
-
},
|
|
1851
|
-
targetResourceTimes[0]
|
|
1852
|
-
);
|
|
1877
|
+
return earliestBlockStart?.format('YYYY-MM-DD HH:mm');
|
|
1878
|
+
}
|
|
1879
|
+
const resourcesEndTime = targetResourceTimes.reduce((acc, curr) => {
|
|
1880
|
+
return (0, _dayjs.default)(curr.end_at).isAfter((0, _dayjs.default)(acc.end_at)) ? curr : acc;
|
|
1881
|
+
}, targetResourceTimes[0]);
|
|
1853
1882
|
const earliestBlockedStartTime = getEarliestBlockedStartTime({
|
|
1854
1883
|
currentStartTime,
|
|
1855
1884
|
times: targetResourceTimes
|
|
1856
1885
|
});
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
);
|
|
1860
|
-
const operatingBoundaryDateTime = `${resourceDate} ${operating_day_boundary.type ===
|
|
1861
|
-
const endTimeCandidates = [
|
|
1862
|
-
resourcesEndTime.end_at,
|
|
1863
|
-
operatingBoundaryDateTime,
|
|
1864
|
-
...earliestBlockedStartTime ? [earliestBlockedStartTime] : []
|
|
1865
|
-
];
|
|
1886
|
+
|
|
1887
|
+
// 将 operating_day_boundary 转换为与 resourcesEndTime.end_at 相同日期的完整日期时间
|
|
1888
|
+
const resourceDate = (0, _dayjs.default)(resourcesEndTime.end_at).format('YYYY-MM-DD');
|
|
1889
|
+
const operatingBoundaryDateTime = `${resourceDate} ${operating_day_boundary.type === 'start_time' ? '23:59' : operating_day_boundary.time}`;
|
|
1890
|
+
const endTimeCandidates = [resourcesEndTime.end_at, operatingBoundaryDateTime, ...(earliestBlockedStartTime ? [earliestBlockedStartTime] : [])];
|
|
1866
1891
|
const endTime = endTimeCandidates.reduce((earliest, value) => {
|
|
1867
|
-
return (0,
|
|
1892
|
+
return (0, _dayjs.default)(value).isBefore((0, _dayjs.default)(earliest)) ? value : earliest;
|
|
1868
1893
|
}, endTimeCandidates[0]);
|
|
1894
|
+
// 修复:如果 endTime 只是时间格式(如 "17:00"),需要加上日期
|
|
1869
1895
|
let formattedEndTime;
|
|
1870
|
-
if (typeof endTime ===
|
|
1871
|
-
|
|
1872
|
-
|
|
1896
|
+
if (typeof endTime === 'string' && endTime.includes(':') && !endTime.includes(' ') && !endTime.includes('T')) {
|
|
1897
|
+
// 如果是纯时间格式,与当前日期合并
|
|
1898
|
+
const currentDate = timeSlots.start_at.format('YYYY-MM-DD');
|
|
1899
|
+
formattedEndTime = (0, _dayjs.default)(`${currentDate} ${endTime}`);
|
|
1873
1900
|
} else {
|
|
1874
|
-
formattedEndTime = (0,
|
|
1901
|
+
formattedEndTime = (0, _dayjs.default)(endTime);
|
|
1875
1902
|
}
|
|
1876
|
-
resource.endTime = formattedEndTime.format(
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1903
|
+
resource.endTime = formattedEndTime.format('YYYY-MM-DD HH:mm');
|
|
1904
|
+
// 如果是动态时长商品,并且当前选择的时间的结束时间小于了最低提示时长(warningThreshold),则追加一个提示
|
|
1905
|
+
// 如果currentStartTime + warningThreshold 大于 currentEndTime,且 osWarnTips 没有pisell2.product.card.closing-soon.warning 这一项,则加入这一项
|
|
1906
|
+
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))) {
|
|
1907
|
+
if (!osWarnTips.includes('pisell2.product.card.closing-soon.warning')) {
|
|
1908
|
+
osWarnTips.push('pisell2.product.card.closing-soon.warning');
|
|
1880
1909
|
}
|
|
1881
1910
|
}
|
|
1882
1911
|
} else {
|
|
1883
1912
|
resource.startTime = currentStartTime;
|
|
1884
|
-
resource.endTime = (0,
|
|
1913
|
+
resource.endTime = (0, _dayjs.default)(currentStartTime).add(item._productOrigin?.duration?.value || 10, 'minutes').format('YYYY-MM-DD HH:mm');
|
|
1885
1914
|
}
|
|
1915
|
+
// delete resource.times;
|
|
1886
1916
|
});
|
|
1887
1917
|
this.store.cart.updateItem({
|
|
1888
1918
|
_id: item._id,
|
|
1889
1919
|
resources: newResources,
|
|
1890
1920
|
osWarnTips
|
|
1891
1921
|
});
|
|
1892
|
-
|
|
1922
|
+
|
|
1923
|
+
// 更新下一个商品的开始时间为当前商品的结束时间
|
|
1924
|
+
if (index < accountItems.length - 1 && newResources?.[0]?.resourceType === 'single') {
|
|
1893
1925
|
currentStartTime = newResources[0].endTime;
|
|
1894
1926
|
}
|
|
1895
1927
|
});
|
|
1896
1928
|
});
|
|
1897
|
-
this.core.effects.emit(
|
|
1898
|
-
`${this.store.cart.name}:onUpdateBookingDate`,
|
|
1899
|
-
{}
|
|
1900
|
-
);
|
|
1929
|
+
this.core.effects.emit(`${this.store.cart.name}:onUpdateBookingDate`, {});
|
|
1901
1930
|
}
|
|
1902
1931
|
getScheduleDataByIds(scheduleIds) {
|
|
1903
1932
|
const targetSchedules = this.store.schedule.getScheduleListByIds(scheduleIds);
|
|
1904
|
-
const targetSchedulesData = targetSchedules.map(
|
|
1905
|
-
return (0,
|
|
1933
|
+
const targetSchedulesData = targetSchedules.map(item => {
|
|
1934
|
+
return (0, _utils3.calcCalendarDataByScheduleResult)(item);
|
|
1906
1935
|
});
|
|
1907
1936
|
const newSchedule = {};
|
|
1908
|
-
targetSchedulesData.forEach(
|
|
1909
|
-
item.forEach(
|
|
1937
|
+
targetSchedulesData.forEach(item => {
|
|
1938
|
+
item.forEach(n => {
|
|
1910
1939
|
if (!newSchedule[n.date]) {
|
|
1911
1940
|
newSchedule[n.date] = n;
|
|
1912
1941
|
} else {
|
|
@@ -1917,8 +1946,9 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1917
1946
|
});
|
|
1918
1947
|
});
|
|
1919
1948
|
const newScheduleArr = Object.values(newSchedule);
|
|
1949
|
+
// newScheduleArr 需要做个排序,按日期从小到大
|
|
1920
1950
|
newScheduleArr.sort((a, b) => {
|
|
1921
|
-
return (0,
|
|
1951
|
+
return (0, _dayjs.default)(a.date).diff((0, _dayjs.default)(b.date));
|
|
1922
1952
|
});
|
|
1923
1953
|
return newScheduleArr;
|
|
1924
1954
|
}
|
|
@@ -1928,17 +1958,22 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1928
1958
|
if (targetProductData) {
|
|
1929
1959
|
this.store.currentProduct = targetProductData;
|
|
1930
1960
|
this.store.currentProductMeta = {};
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
);
|
|
1935
|
-
if (!this.store.currentProductMeta)
|
|
1936
|
-
this.store.currentProductMeta = {};
|
|
1961
|
+
// 资源预加载,如果是 duration 类型的商品,且是先选日期的流程,在这里预拉取资源数据
|
|
1962
|
+
if (targetProductData['schedule.ids']) {
|
|
1963
|
+
const newScheduleArr = this.getScheduleDataByIds(targetProductData['schedule.ids']);
|
|
1964
|
+
if (!this.store.currentProductMeta) this.store.currentProductMeta = {};
|
|
1937
1965
|
this.store.currentProductMeta.schedule = newScheduleArr;
|
|
1938
1966
|
} else if (targetProductData.duration) {
|
|
1939
1967
|
const dateRange = this.store.date.getDateRange();
|
|
1940
|
-
|
|
1941
|
-
|
|
1968
|
+
// 如果不是先选日期的流程 duration 商品就啥也不做
|
|
1969
|
+
if (!dateRange?.length) return;
|
|
1970
|
+
// this.store.date.getResourceDates({
|
|
1971
|
+
// query: {
|
|
1972
|
+
// start_date: dateRange[0].date,
|
|
1973
|
+
// end_date: dateRange[dateRange.length - 1].date,
|
|
1974
|
+
// resource_ids: targetProductData.product_resource?.resources?.map((n: any) => n.id),
|
|
1975
|
+
// },
|
|
1976
|
+
// });
|
|
1942
1977
|
this.getAvailableDate({
|
|
1943
1978
|
startDate: dateRange[0].date,
|
|
1944
1979
|
endDate: dateRange[dateRange.length - 1].date,
|
|
@@ -1951,8 +1986,9 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1951
1986
|
if (this.store.currentProductMeta) {
|
|
1952
1987
|
this.store.currentProductMeta.schedule = [];
|
|
1953
1988
|
}
|
|
1954
|
-
this.store.currentProduct =
|
|
1989
|
+
this.store.currentProduct = undefined;
|
|
1955
1990
|
}
|
|
1991
|
+
|
|
1956
1992
|
// 通过商品和 schedule 来获取视频可用的时间片、时间片内资源可用的数据
|
|
1957
1993
|
getTimeslotBySchedule({
|
|
1958
1994
|
date,
|
|
@@ -1960,59 +1996,43 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
1960
1996
|
resources,
|
|
1961
1997
|
product
|
|
1962
1998
|
}) {
|
|
1963
|
-
var _a, _b, _c, _d;
|
|
1964
1999
|
const targetProduct = this.store.currentProduct;
|
|
2000
|
+
// 如果外面传递了product 优先用外面的
|
|
1965
2001
|
const targetProductData = product || targetProduct;
|
|
1966
2002
|
let targetSchedules = [];
|
|
1967
|
-
|
|
2003
|
+
// 如果外面传递了 scheduleIds,优先取入参
|
|
2004
|
+
if (scheduleIds?.length) {
|
|
1968
2005
|
targetSchedules = this.store.schedule.getScheduleListByIds(scheduleIds);
|
|
1969
2006
|
} else {
|
|
1970
|
-
targetSchedules = this.store.schedule.getScheduleListByIds(
|
|
1971
|
-
targetProductData["schedule.ids"]
|
|
1972
|
-
);
|
|
2007
|
+
targetSchedules = this.store.schedule.getScheduleListByIds(targetProductData['schedule.ids']);
|
|
1973
2008
|
}
|
|
1974
2009
|
const resourcesDates = this.store.date.getDateList();
|
|
1975
|
-
const targetResourceDate = resourcesDates.find(
|
|
1976
|
-
const cartItems = (0,
|
|
1977
|
-
const resourcesMap = (0,
|
|
1978
|
-
const selectedResources = (0,
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
resources || ((_b = (_a = this.store.currentProduct) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) || [],
|
|
1986
|
-
selectedResources,
|
|
1987
|
-
1
|
|
1988
|
-
);
|
|
1989
|
-
const minTimeMaxTime = (0, import_utils3.calcMinTimeMaxTimeBySchedules)(
|
|
1990
|
-
targetSchedules,
|
|
1991
|
-
{},
|
|
1992
|
-
date
|
|
1993
|
-
);
|
|
1994
|
-
const scheduleTimeSlots = (0, import_utils3.getAllSortedDateRanges)(minTimeMaxTime);
|
|
1995
|
-
let allProductResources = productResources.flatMap((n) => n.renderList);
|
|
2010
|
+
const targetResourceDate = resourcesDates.find(n => n.date === date);
|
|
2011
|
+
const cartItems = (0, _lodashEs.cloneDeep)(this.store.cart.getItems());
|
|
2012
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(targetResourceDate?.resource || []);
|
|
2013
|
+
const selectedResources = (0, _resources.getOthersSelectedResources)(cartItems, '', resourcesMap);
|
|
2014
|
+
const productResources = (0, _resources.getResourcesByProduct)(resourcesMap, resources || this.store.currentProduct?.product_resource?.resources || [], selectedResources, 1);
|
|
2015
|
+
const minTimeMaxTime = (0, _utils3.calcMinTimeMaxTimeBySchedules)(targetSchedules, {}, date);
|
|
2016
|
+
const scheduleTimeSlots = (0, _utils3.getAllSortedDateRanges)(minTimeMaxTime);
|
|
2017
|
+
// 当前所有待选择资源的集合,先提出来,提升性能
|
|
2018
|
+
let allProductResources = productResources.flatMap(n => n.renderList);
|
|
2019
|
+
// 资源排下序,把单个资源靠前,组合资源排在后面
|
|
1996
2020
|
allProductResources.sort((a, b) => {
|
|
1997
|
-
|
|
1998
|
-
const
|
|
1999
|
-
|
|
2000
|
-
if (aIsCombined &&
|
|
2001
|
-
return 1;
|
|
2002
|
-
if (!aIsCombined && bIsCombined)
|
|
2003
|
-
return -1;
|
|
2021
|
+
const aIsCombined = a.metadata?.combined_resource?.status === 1;
|
|
2022
|
+
const bIsCombined = b.metadata?.combined_resource?.status === 1;
|
|
2023
|
+
if (aIsCombined && !bIsCombined) return 1;
|
|
2024
|
+
if (!aIsCombined && bIsCombined) return -1;
|
|
2004
2025
|
return 0;
|
|
2005
2026
|
});
|
|
2006
|
-
const enabledResourceTypeConfigs = (
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
const formatScheduleTimeSlots = scheduleTimeSlots.map((item) => {
|
|
2027
|
+
const enabledResourceTypeConfigs = targetProductData?.product_resource?.resources?.filter(n => n.status === 1) || [];
|
|
2028
|
+
const resourceTypeConfigById = new Map(enabledResourceTypeConfigs.map(n => [n.id, n]));
|
|
2029
|
+
|
|
2030
|
+
// 计算每个日程切片下日程可用的资源的容量总和
|
|
2031
|
+
const formatScheduleTimeSlots = scheduleTimeSlots.map(item => {
|
|
2032
|
+
// 用来计算资源的可使用情况,针对单个schedule 时间片
|
|
2013
2033
|
const resourcesUseableMap = {};
|
|
2014
2034
|
const statsByResourceType = {};
|
|
2015
|
-
enabledResourceTypeConfigs.forEach(
|
|
2035
|
+
enabledResourceTypeConfigs.forEach(cfg => {
|
|
2016
2036
|
statsByResourceType[cfg.id] = {
|
|
2017
2037
|
count: 0,
|
|
2018
2038
|
left: 0,
|
|
@@ -2020,59 +2040,68 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2020
2040
|
summaryConfigCount: 0
|
|
2021
2041
|
};
|
|
2022
2042
|
});
|
|
2023
|
-
|
|
2043
|
+
|
|
2044
|
+
// 遍历所有资源
|
|
2045
|
+
allProductResources?.forEach(m => {
|
|
2024
2046
|
const currentResourceTypeConfig = resourceTypeConfigById.get(m.form_id);
|
|
2025
|
-
if (!currentResourceTypeConfig)
|
|
2026
|
-
|
|
2047
|
+
if (!currentResourceTypeConfig) return;
|
|
2048
|
+
|
|
2049
|
+
// 遍历所有资源的上工时间片
|
|
2027
2050
|
let currentResourceMaxRemainingCapacity = 0;
|
|
2028
2051
|
let isAllTimeSlicesUsable = true;
|
|
2029
|
-
|
|
2030
|
-
|
|
2052
|
+
// m.times 需要做个过滤,假设 timeSlice.start_at 是 09:30 timeSlice.end_at 是 11:30
|
|
2053
|
+
// time 是 time.start_at = 2025-05-26 10:30, time.end_at = 2025-05-26 12:30
|
|
2054
|
+
// 需要判断 time 的开始结束时间 是否包含timeSlice的开始结束时间
|
|
2055
|
+
|
|
2056
|
+
// n.start_at 是 2025-06-30 15:00 end_at 2025-06-30 17:00
|
|
2057
|
+
// item.start 是 2025-06-30 16:00 item.end 是 2025-06-30 19:00
|
|
2058
|
+
// 需要判断 n.start_at 和 n.end_at 是否在 item.start 和 item.end 之间
|
|
2059
|
+
// 如果是仅用于计算的资源, n.start_at 和 n.end_at 在 item.start 和 item.end 有交集,则此时间需要计算
|
|
2060
|
+
// https://project.feishu.cn/v2qint/bug/detail/6657165010
|
|
2061
|
+
const mTimes = m.times.filter(n => {
|
|
2062
|
+
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');
|
|
2031
2063
|
});
|
|
2064
|
+
// 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
|
|
2032
2065
|
if (mTimes.length === 0) {
|
|
2033
2066
|
return;
|
|
2034
2067
|
}
|
|
2068
|
+
|
|
2069
|
+
// 统计该资源类型在这个时间片的“配置容量”(无占用),只统计上工的资源
|
|
2035
2070
|
if (!m.onlyComputed) {
|
|
2036
|
-
const
|
|
2071
|
+
const currentStats = statsByResourceType[m.form_id] || {
|
|
2037
2072
|
count: 0,
|
|
2038
2073
|
left: 0,
|
|
2039
2074
|
summaryCount: 0,
|
|
2040
2075
|
summaryConfigCount: 0
|
|
2041
2076
|
};
|
|
2042
|
-
if (currentResourceTypeConfig.type ===
|
|
2043
|
-
|
|
2044
|
-
else
|
|
2045
|
-
currentStats2.summaryConfigCount += 1;
|
|
2046
|
-
statsByResourceType[m.form_id] = currentStats2;
|
|
2077
|
+
if (currentResourceTypeConfig.type === 'multiple') currentStats.summaryConfigCount += m.capacity;else currentStats.summaryConfigCount += 1;
|
|
2078
|
+
statsByResourceType[m.form_id] = currentStats;
|
|
2047
2079
|
}
|
|
2048
|
-
mTimes.forEach(
|
|
2049
|
-
|
|
2080
|
+
mTimes.forEach(childTiem => {
|
|
2081
|
+
// 挨个去匹配某个工作时间段结合当前日程时间,资源能不能用,有多少容量能用
|
|
2082
|
+
const res = (0, _resources.getIsUsableByTimeItem)({
|
|
2050
2083
|
timeSlice: {
|
|
2051
2084
|
start_time: item.start,
|
|
2052
2085
|
end_time: item.end,
|
|
2053
|
-
start_at: (0,
|
|
2054
|
-
end_at: (0,
|
|
2086
|
+
start_at: (0, _dayjs.default)(item.start),
|
|
2087
|
+
end_at: (0, _dayjs.default)(item.end)
|
|
2055
2088
|
},
|
|
2056
2089
|
time: childTiem,
|
|
2057
2090
|
resource: m,
|
|
2058
2091
|
currentCount: 1,
|
|
2059
2092
|
resourcesUseableMap,
|
|
2060
|
-
cut_off_time: targetProductData
|
|
2093
|
+
cut_off_time: targetProductData?.cut_off_time
|
|
2061
2094
|
});
|
|
2062
|
-
if (
|
|
2095
|
+
if (resourcesUseableMap?.[m.id] !== false && res.reason !== 'capacityOnly') {
|
|
2063
2096
|
resourcesUseableMap[m.id] = res.usable;
|
|
2064
2097
|
}
|
|
2065
|
-
if (!res.usable)
|
|
2066
|
-
isAllTimeSlicesUsable = false;
|
|
2098
|
+
if (!res.usable) isAllTimeSlicesUsable = false;
|
|
2067
2099
|
if (res.usable && !m.onlyComputed) {
|
|
2068
|
-
if (res.remainingCapacity > currentResourceMaxRemainingCapacity)
|
|
2069
|
-
currentResourceMaxRemainingCapacity = res.remainingCapacity;
|
|
2100
|
+
if (res.remainingCapacity > currentResourceMaxRemainingCapacity) currentResourceMaxRemainingCapacity = res.remainingCapacity;
|
|
2070
2101
|
}
|
|
2071
2102
|
});
|
|
2072
|
-
if (!isAllTimeSlicesUsable)
|
|
2073
|
-
|
|
2074
|
-
if (m.onlyComputed)
|
|
2075
|
-
return;
|
|
2103
|
+
if (!isAllTimeSlicesUsable) return;
|
|
2104
|
+
if (m.onlyComputed) return;
|
|
2076
2105
|
const currentStats = statsByResourceType[m.form_id] || {
|
|
2077
2106
|
count: 0,
|
|
2078
2107
|
left: 0,
|
|
@@ -2080,55 +2109,61 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2080
2109
|
summaryConfigCount: 0
|
|
2081
2110
|
};
|
|
2082
2111
|
currentStats.left += 1;
|
|
2083
|
-
if (currentResourceTypeConfig.type ===
|
|
2112
|
+
if (currentResourceTypeConfig.type === 'multiple') {
|
|
2084
2113
|
currentStats.summaryCount += currentResourceMaxRemainingCapacity;
|
|
2085
2114
|
}
|
|
2086
|
-
if (currentResourceMaxRemainingCapacity > currentStats.count)
|
|
2087
|
-
|
|
2115
|
+
if (currentResourceMaxRemainingCapacity > currentStats.count) currentStats.count = currentResourceMaxRemainingCapacity;
|
|
2116
|
+
// else {
|
|
2117
|
+
// 单个预约:一个资源只计 1,不关心剩余容量
|
|
2118
|
+
// currentStats.summaryCount += 1;
|
|
2119
|
+
// if (currentStats.count < 1) currentStats.count = 1;
|
|
2120
|
+
//}
|
|
2121
|
+
|
|
2088
2122
|
statsByResourceType[m.form_id] = currentStats;
|
|
2089
2123
|
});
|
|
2090
|
-
|
|
2091
|
-
|
|
2124
|
+
// 容量检测
|
|
2125
|
+
const cartItems = this.store.cart.getItems();
|
|
2126
|
+
productResources.forEach(n => {
|
|
2092
2127
|
const currentResourceTypeConfig = resourceTypeConfigById.get(n.id);
|
|
2093
|
-
if (!currentResourceTypeConfig)
|
|
2094
|
-
return;
|
|
2128
|
+
if (!currentResourceTypeConfig) return;
|
|
2095
2129
|
const currentStats = statsByResourceType[n.id] || {
|
|
2096
2130
|
count: 0,
|
|
2097
2131
|
left: 0,
|
|
2098
2132
|
summaryCount: 0
|
|
2099
2133
|
};
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2134
|
+
|
|
2135
|
+
// 单个预约检测规则:
|
|
2136
|
+
// 1、跟我一样的商品同一时间在购物车里不可以超过我最少的那种资源的关联的资源个数
|
|
2137
|
+
// 2、跟我不一样的商品,只需要跟我当前商品有同一种类型的资源的同一时间的,她配置了几个资源的个数+我配置了几个资源的个数,然后购物车里有几个这样的商品,对应的资源做一个去重,不超过这个去重以后的总数
|
|
2138
|
+
if (n.type === 'single') {
|
|
2139
|
+
const currentResourcesSet = new Set([...n.optional_resource, ...n.default_resource]);
|
|
2140
|
+
// 规则 1
|
|
2141
|
+
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);
|
|
2106
2142
|
if (sameCartItems.length > 0 && sameCartItems.length >= currentResourcesSet.size || sameCartItems.length > currentStats.left) {
|
|
2107
2143
|
currentStats.left = 0;
|
|
2108
2144
|
currentStats.count = 0;
|
|
2109
2145
|
currentStats.summaryCount = 0;
|
|
2110
2146
|
}
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
const sameTypeResourcesSet = /* @__PURE__ */ new Set([...(sameTypeResources == null ? void 0 : sameTypeResources.optional_resource) || [], ...(sameTypeResources == null ? void 0 : sameTypeResources.default_resource) || []]);
|
|
2123
|
-
sameTypeResourcesSet.forEach((resource) => currentResourcesSet.add(resource));
|
|
2147
|
+
// 规则 2
|
|
2148
|
+
let otherCartItems = cartItems.filter(m => {
|
|
2149
|
+
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;
|
|
2150
|
+
const isResourceMatch = m._productOrigin?.product_resource?.resources?.find(m => m.type === n.type && m.status === 1);
|
|
2151
|
+
return isTimeMatch && isResourceMatch;
|
|
2152
|
+
});
|
|
2153
|
+
otherCartItems.forEach(m => {
|
|
2154
|
+
const sameTypeResources = m._productOrigin?.product_resource?.resources?.find(m => m.type === n.type && m.status === 1);
|
|
2155
|
+
const sameTypeResourcesSet = new Set([...(sameTypeResources?.optional_resource || []), ...(sameTypeResources?.default_resource || [])]);
|
|
2156
|
+
// 把sameTypeResourcesSet 加到currentResourcesSet
|
|
2157
|
+
sameTypeResourcesSet.forEach(resource => currentResourcesSet.add(resource));
|
|
2124
2158
|
});
|
|
2125
|
-
|
|
2126
|
-
currentDataResources
|
|
2159
|
+
// 先确定是否每一个currentResourcesSet在这个时间点的 event_list 都是空的,如果不是空的还需要把他踢出currentResourcesSet
|
|
2160
|
+
const currentDataResources = this.store.date.getResourcesListByDate((0, _dayjs.default)(item.start).format('YYYY-MM-DD'));
|
|
2161
|
+
currentDataResources?.forEach(m => {
|
|
2127
2162
|
if (currentResourcesSet.has(m.id)) {
|
|
2128
|
-
const mTimes = m.times.filter(
|
|
2129
|
-
return !(0,
|
|
2163
|
+
const mTimes = m.times.filter(n => {
|
|
2164
|
+
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');
|
|
2130
2165
|
});
|
|
2131
|
-
if (!mTimes.length || mTimes.some(
|
|
2166
|
+
if (!mTimes.length || mTimes.some(n => n.event_list.length)) {
|
|
2132
2167
|
currentResourcesSet.delete(m.id);
|
|
2133
2168
|
}
|
|
2134
2169
|
}
|
|
@@ -2139,57 +2174,61 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2139
2174
|
currentStats.summaryCount = 0;
|
|
2140
2175
|
}
|
|
2141
2176
|
} else {
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
const sameCartNeedCapacity = sameCartItems.reduce((acc, curr) => acc + (0, import_capacity.getCapacityInfoByCartItem)(curr).currentCapacity, 0);
|
|
2177
|
+
// 多个预约的检测规则:
|
|
2178
|
+
// 规则1、跟我一样的商品同一时间在购物车需要的容量总数不可以超过我配置的资源的 capacity 之和
|
|
2179
|
+
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);
|
|
2180
|
+
const sameCartNeedCapacity = sameCartItems.reduce((acc, curr) => acc + (0, _capacity.getCapacityInfoByCartItem)(curr).currentCapacity, 0);
|
|
2147
2181
|
const currentProductResourcesCapacity = n.renderList.reduce((acc, curr) => !curr.onlyComputed ? acc + curr.capacity || 0 : acc, 0);
|
|
2148
2182
|
if (sameCartNeedCapacity >= currentProductResourcesCapacity) {
|
|
2149
2183
|
currentStats.left = 0;
|
|
2150
2184
|
currentStats.count = 0;
|
|
2151
2185
|
currentStats.summaryCount = 0;
|
|
2152
2186
|
}
|
|
2153
|
-
|
|
2154
|
-
const
|
|
2155
|
-
const
|
|
2156
|
-
otherSameTimesCartItems.
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
if (m2.id === n.id) {
|
|
2166
|
-
m2.renderList.forEach((n2) => {
|
|
2167
|
-
if (!n2.onlyComputed && !allRenderList.find((m3) => m3.id === n2.id)) {
|
|
2168
|
-
allRenderList.push(n2);
|
|
2187
|
+
// 规则2、不管是不是跟我一样的商品,只需要跟我当前商品有同一种类型的资源的同一时间的,把所有购物车的 capacity 之和 和 所有当前类型资源的 capacity 之和比较,如果超过了resourcesCapacity,则不可用
|
|
2188
|
+
// const otherCartItems = cartItems.filter((m) => m._productOrigin?.id?.toString() !== targetProductData?.id?.toString() && m.start_time === item.start && m.end_time === item.end);
|
|
2189
|
+
const otherSameTimesCartItems = cartItems.filter(m => `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end);
|
|
2190
|
+
const otherCartNeedCapacity = otherSameTimesCartItems.reduce((acc, curr) => acc + (0, _capacity.getCapacityInfoByCartItem)(curr).currentCapacity, 0);
|
|
2191
|
+
const allRenderList = [...n.renderList.filter(m => !m.onlyComputed)];
|
|
2192
|
+
otherSameTimesCartItems.forEach(m => {
|
|
2193
|
+
const productResources = (0, _resources.getResourcesByProduct)((0, _utils2.getResourcesMap)(targetResourceDate?.resource || []), m._productOrigin?.product_resource?.resources || [], selectedResources, 1);
|
|
2194
|
+
productResources.forEach(m => {
|
|
2195
|
+
if (m.id === n.id) {
|
|
2196
|
+
m.renderList.forEach(n => {
|
|
2197
|
+
if (!n.onlyComputed && !allRenderList.find(m => m.id === n.id)) {
|
|
2198
|
+
allRenderList.push(n);
|
|
2169
2199
|
}
|
|
2170
2200
|
});
|
|
2171
2201
|
}
|
|
2172
2202
|
});
|
|
2173
2203
|
});
|
|
2174
2204
|
const currentTypeResourcesCapacity = allRenderList.reduce((acc, curr) => acc + curr.capacity || 0, 0);
|
|
2205
|
+
// 计算当前时间段内所有资源的已使用容量
|
|
2175
2206
|
const usedCapacity = allRenderList.reduce((acc, curr) => {
|
|
2176
|
-
const mTimes = curr.times.filter(
|
|
2177
|
-
return !(0,
|
|
2207
|
+
const mTimes = curr.times.filter(n => {
|
|
2208
|
+
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');
|
|
2178
2209
|
});
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2210
|
+
// 这里为什么要设置个 map,因为有可能日程有重叠,所以要把重叠的 event_list 去除
|
|
2211
|
+
const mSet = new Map();
|
|
2212
|
+
mTimes.forEach(n => {
|
|
2213
|
+
// acc += n.event_list?.reduce((acc: any, curr: any) => acc + curr.pax, 0);
|
|
2214
|
+
// mSet.set(n)
|
|
2215
|
+
n.event_list.forEach(m => {
|
|
2216
|
+
// 需要确认 m 的时间段是否和 item 的时间段有交集
|
|
2217
|
+
if ((0, _resources.isConflict)({
|
|
2218
|
+
start_at: m.start_at,
|
|
2219
|
+
end_at: m.end_at
|
|
2220
|
+
}, {
|
|
2221
|
+
start_at: (0, _dayjs.default)(item.start),
|
|
2222
|
+
end_at: (0, _dayjs.default)(item.end)
|
|
2223
|
+
})) {
|
|
2186
2224
|
mSet.set(m.id, m.pax ?? 1);
|
|
2187
2225
|
}
|
|
2188
2226
|
});
|
|
2189
2227
|
});
|
|
2190
|
-
acc += Array.from(mSet.values()).reduce((
|
|
2228
|
+
acc += Array.from(mSet.values()).reduce((acc, curr) => acc + curr, 0);
|
|
2191
2229
|
return acc;
|
|
2192
2230
|
}, 0);
|
|
2231
|
+
// 如果已使用容量超过了当前类型资源的容量,则不可用
|
|
2193
2232
|
if (otherCartNeedCapacity + usedCapacity >= currentTypeResourcesCapacity) {
|
|
2194
2233
|
currentStats.left = 0;
|
|
2195
2234
|
currentStats.count = 0;
|
|
@@ -2198,55 +2237,48 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2198
2237
|
}
|
|
2199
2238
|
statsByResourceType[n.id] = currentStats;
|
|
2200
2239
|
});
|
|
2201
|
-
const startDayJs = (0,
|
|
2202
|
-
const endDayJs = (0,
|
|
2240
|
+
const startDayJs = (0, _dayjs.default)(item.start);
|
|
2241
|
+
const endDayJs = (0, _dayjs.default)(item.end);
|
|
2242
|
+
|
|
2243
|
+
// 选择“瓶颈资源类型”:multiple 取 summaryCount 最小,single 取 left 最小
|
|
2203
2244
|
let bottleneckResourceTypeId;
|
|
2204
2245
|
let bottleneckValue = Infinity;
|
|
2205
|
-
enabledResourceTypeConfigs.forEach(
|
|
2246
|
+
enabledResourceTypeConfigs.forEach(cfg => {
|
|
2206
2247
|
const stats = statsByResourceType[cfg.id] || {
|
|
2207
2248
|
count: 0,
|
|
2208
2249
|
left: 0,
|
|
2209
2250
|
summaryCount: 0,
|
|
2210
2251
|
summaryConfigCount: 0
|
|
2211
2252
|
};
|
|
2212
|
-
const value = cfg.type ===
|
|
2253
|
+
const value = cfg.type === 'multiple' ? stats.summaryCount : stats.left;
|
|
2213
2254
|
if (value < bottleneckValue) {
|
|
2214
2255
|
bottleneckValue = value;
|
|
2215
2256
|
bottleneckResourceTypeId = cfg.id;
|
|
2216
2257
|
}
|
|
2217
2258
|
});
|
|
2218
|
-
const bottleneckStats = bottleneckResourceTypeId !==
|
|
2259
|
+
const bottleneckStats = bottleneckResourceTypeId !== undefined ? statsByResourceType[bottleneckResourceTypeId] || {
|
|
2219
2260
|
count: 0,
|
|
2220
2261
|
left: 0,
|
|
2221
2262
|
summaryCount: 0,
|
|
2222
2263
|
summaryConfigCount: 0
|
|
2223
|
-
} : {
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2264
|
+
} : {
|
|
2265
|
+
count: 0,
|
|
2266
|
+
left: 0,
|
|
2267
|
+
summaryCount: 0,
|
|
2268
|
+
summaryConfigCount: 0
|
|
2269
|
+
};
|
|
2270
|
+
const bottleneckConfig = bottleneckResourceTypeId !== undefined ? resourceTypeConfigById.get(bottleneckResourceTypeId) : undefined;
|
|
2271
|
+
let status = 'sold_out';
|
|
2272
|
+
if (bottleneckStats.left === 0) status = 'sold_out';else if (!bottleneckConfig || bottleneckStats.summaryConfigCount === 0) status = 'sold_out';else if (bottleneckConfig.type === 'multiple') {
|
|
2231
2273
|
const usageRatio = bottleneckStats.summaryCount / bottleneckStats.summaryConfigCount;
|
|
2232
|
-
if (usageRatio > 0.5)
|
|
2233
|
-
status = "lots_of_space";
|
|
2234
|
-
else if (bottleneckStats.summaryCount > 0)
|
|
2235
|
-
status = "filling_up_fast";
|
|
2236
|
-
else
|
|
2237
|
-
status = "sold_out";
|
|
2274
|
+
if (usageRatio > 0.5) status = 'lots_of_space';else if (bottleneckStats.summaryCount > 0) status = 'filling_up_fast';else status = 'sold_out';
|
|
2238
2275
|
} else {
|
|
2239
2276
|
const usageRatio = bottleneckStats.left / bottleneckStats.summaryConfigCount;
|
|
2240
|
-
if (usageRatio > 0.5)
|
|
2241
|
-
status = "lots_of_space";
|
|
2242
|
-
else if (bottleneckStats.count > 0)
|
|
2243
|
-
status = "filling_up_fast";
|
|
2244
|
-
else
|
|
2245
|
-
status = "sold_out";
|
|
2277
|
+
if (usageRatio > 0.5) status = 'lots_of_space';else if (bottleneckStats.count > 0) status = 'filling_up_fast';else status = 'sold_out';
|
|
2246
2278
|
}
|
|
2247
2279
|
return {
|
|
2248
|
-
start_time: startDayJs.format(
|
|
2249
|
-
end_time: endDayJs.format(
|
|
2280
|
+
start_time: startDayJs.format('HH:mm'),
|
|
2281
|
+
end_time: endDayJs.format('HH:mm'),
|
|
2250
2282
|
start_at: startDayJs,
|
|
2251
2283
|
end_at: endDayJs,
|
|
2252
2284
|
count: bottleneckStats.count,
|
|
@@ -2257,6 +2289,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2257
2289
|
});
|
|
2258
2290
|
return formatScheduleTimeSlots;
|
|
2259
2291
|
}
|
|
2292
|
+
|
|
2260
2293
|
// 提供给 UI的方法,当前步骤是选择商品,下一步不管是什么都需要在这里做一次检测
|
|
2261
2294
|
// 时长类商品关联的资源为多个预约时,在点击进入"选择资源"步骤之前,需要检测当前所有资源的总容量
|
|
2262
2295
|
// 选择商品数量大于所有资源配置的总容量时,不能进入下一步,需要在"选择商品"这一步时提示。
|
|
@@ -2265,27 +2298,27 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2265
2298
|
* 找到多个资源的公共可用时间段
|
|
2266
2299
|
*/
|
|
2267
2300
|
findCommonAvailableTimeSlots(resources) {
|
|
2268
|
-
if (resources.length === 0)
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
(
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
(slots) => slots.map((slot) => `${slot.start.format("HH:mm")}-${slot.end.format("HH:mm")}`)
|
|
2279
|
-
));
|
|
2280
|
-
let commonSlots = allTimeSlots[0];
|
|
2281
|
-
console.log("初始公共时间段:", commonSlots.map((slot) => `${slot.start.format("HH:mm")}-${slot.end.format("HH:mm")}`));
|
|
2301
|
+
if (resources.length === 0) return [];
|
|
2302
|
+
// 收集所有资源的时间段,转换为统一的时间格式
|
|
2303
|
+
const allTimeSlots = resources.map(resource => resource.times.map(time => ({
|
|
2304
|
+
start: (0, _dayjs.default)(time.start_at),
|
|
2305
|
+
end: (0, _dayjs.default)(time.end_at)
|
|
2306
|
+
})));
|
|
2307
|
+
// 找到公共时间段的交集
|
|
2308
|
+
let commonSlots = allTimeSlots[0]; // 从第一个资源的时间段开始
|
|
2309
|
+
|
|
2310
|
+
// 与其他资源的时间段求交集
|
|
2282
2311
|
for (let i = 1; i < allTimeSlots.length; i++) {
|
|
2283
2312
|
const currentResourceSlots = allTimeSlots[i];
|
|
2284
2313
|
const intersections = [];
|
|
2285
|
-
|
|
2286
|
-
|
|
2314
|
+
|
|
2315
|
+
// 计算当前公共时间段与下一个资源时间段的交集
|
|
2316
|
+
commonSlots.forEach(commonSlot => {
|
|
2317
|
+
currentResourceSlots.forEach(currentSlot => {
|
|
2287
2318
|
const overlapStart = commonSlot.start.isAfter(currentSlot.start) ? commonSlot.start : currentSlot.start;
|
|
2288
2319
|
const overlapEnd = commonSlot.end.isBefore(currentSlot.end) ? commonSlot.end : currentSlot.end;
|
|
2320
|
+
|
|
2321
|
+
// 如果有重叠时间且重叠时间大于0
|
|
2289
2322
|
if (overlapStart.isBefore(overlapEnd)) {
|
|
2290
2323
|
intersections.push({
|
|
2291
2324
|
start: overlapStart,
|
|
@@ -2295,74 +2328,88 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2295
2328
|
});
|
|
2296
2329
|
});
|
|
2297
2330
|
if (intersections.length === 0) {
|
|
2298
|
-
console.log(`资源${i}与当前公共时间段无交集,跳过该资源`);
|
|
2299
2331
|
continue;
|
|
2300
2332
|
}
|
|
2301
2333
|
commonSlots = intersections;
|
|
2302
|
-
console.log(`与资源${i}求交集后的公共时间段:`, commonSlots.map((slot) => `${slot.start.format("HH:mm")}-${slot.end.format("HH:mm")}`));
|
|
2303
2334
|
}
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2335
|
+
|
|
2336
|
+
// 格式化返回结果
|
|
2337
|
+
const result = commonSlots.map(slot => ({
|
|
2338
|
+
startTime: slot.start.format('HH:mm'),
|
|
2339
|
+
endTime: slot.end.format('HH:mm')
|
|
2307
2340
|
}));
|
|
2308
|
-
console.log("最终公共时间段:", result);
|
|
2309
2341
|
return result;
|
|
2310
2342
|
}
|
|
2311
2343
|
checkMaxDurationCapacity() {
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2344
|
+
const cartItems = this.store.cart.getItems().filter(item => !(0, _utils5.isNormalProduct)(item._productOrigin));
|
|
2345
|
+
if (cartItems.length === 0) return {
|
|
2346
|
+
success: true,
|
|
2347
|
+
minAvailableCount: 0
|
|
2348
|
+
};
|
|
2349
|
+
|
|
2350
|
+
// 将购物车商品分为有时间的和没有时间的
|
|
2316
2351
|
const itemsWithTime = [];
|
|
2317
2352
|
const itemsWithoutTime = [];
|
|
2353
|
+
// 记录每种资源类型的可用数量
|
|
2318
2354
|
const availableCountsByResourceType = [];
|
|
2319
|
-
cartItems.forEach(
|
|
2355
|
+
cartItems.forEach(cartItem => {
|
|
2320
2356
|
if (cartItem.start_time && cartItem.end_time && cartItem.start_date) {
|
|
2321
2357
|
itemsWithTime.push(cartItem);
|
|
2322
2358
|
} else {
|
|
2323
2359
|
itemsWithoutTime.push(cartItem);
|
|
2324
2360
|
}
|
|
2325
2361
|
});
|
|
2362
|
+
|
|
2363
|
+
// 处理没有时间的商品,为它们分配公共可用时间的第一个时间片
|
|
2326
2364
|
const processedItemsWithoutTime = [];
|
|
2327
2365
|
if (itemsWithoutTime.length > 0) {
|
|
2366
|
+
// 按资源类型分组处理没有时间的商品
|
|
2328
2367
|
const itemsByResourceType = {};
|
|
2329
|
-
itemsWithoutTime.forEach(
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
const resourceTypes = ((_a2 = cartItem._productOrigin.product_resource) == null ? void 0 : _a2.resources) || [];
|
|
2334
|
-
resourceTypes.forEach((resourceType) => {
|
|
2335
|
-
var _a3;
|
|
2368
|
+
itemsWithoutTime.forEach(cartItem => {
|
|
2369
|
+
if (!cartItem._productOrigin) return;
|
|
2370
|
+
const resourceTypes = cartItem._productOrigin.product_resource?.resources || [];
|
|
2371
|
+
resourceTypes.forEach(resourceType => {
|
|
2336
2372
|
if (resourceType.status === 1) {
|
|
2337
|
-
const resourceCode = resourceType.code ||
|
|
2373
|
+
const resourceCode = resourceType.code || resourceType.id?.toString();
|
|
2338
2374
|
if (!itemsByResourceType[resourceCode]) {
|
|
2339
2375
|
itemsByResourceType[resourceCode] = [];
|
|
2340
2376
|
}
|
|
2341
|
-
|
|
2377
|
+
// 避免重复添加同一个商品
|
|
2378
|
+
// 如果之前添加过的依赖相同资源的跟我现在是同一个 holder,也不需要重复添加
|
|
2379
|
+
if (itemsByResourceType[resourceCode].find(item => item.holder_id === cartItem.holder_id)) {
|
|
2342
2380
|
return;
|
|
2343
2381
|
}
|
|
2344
|
-
if (!itemsByResourceType[resourceCode].find(
|
|
2382
|
+
if (!itemsByResourceType[resourceCode].find(item => item._id === cartItem._id)) {
|
|
2345
2383
|
itemsByResourceType[resourceCode].push(cartItem);
|
|
2346
2384
|
}
|
|
2347
2385
|
}
|
|
2348
2386
|
});
|
|
2349
2387
|
});
|
|
2388
|
+
|
|
2389
|
+
// 为每种资源类型检查容量
|
|
2350
2390
|
const dateRange = this.store.date.getDateRange();
|
|
2351
|
-
if (!dateRange || dateRange.length === 0)
|
|
2352
|
-
|
|
2391
|
+
if (!dateRange || dateRange.length === 0) return {
|
|
2392
|
+
success: false,
|
|
2393
|
+
minAvailableCount: 0
|
|
2394
|
+
};
|
|
2353
2395
|
const resourcesDates = this.store.date.getDateList();
|
|
2354
|
-
const targetResourceDate = resourcesDates.find(
|
|
2355
|
-
if (!targetResourceDate)
|
|
2356
|
-
|
|
2357
|
-
|
|
2396
|
+
const targetResourceDate = resourcesDates.find(n => n.date === dateRange[0].date);
|
|
2397
|
+
if (!targetResourceDate) return {
|
|
2398
|
+
success: false,
|
|
2399
|
+
minAvailableCount: 0
|
|
2400
|
+
};
|
|
2401
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(targetResourceDate.resource || []);
|
|
2402
|
+
|
|
2403
|
+
// 从购物车商品中获取资源类型配置,建立 resourceCode 到 form_id 的映射关系
|
|
2358
2404
|
const resourceCodeToFormIdMap = {};
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2405
|
+
|
|
2406
|
+
// 遍历购物车中的商品,收集所有资源类型配置
|
|
2407
|
+
Object.values(itemsByResourceType).flat().forEach(cartItem => {
|
|
2408
|
+
if (cartItem._productOrigin?.product_resource?.resources) {
|
|
2409
|
+
cartItem._productOrigin.product_resource.resources.forEach(resourceConfig => {
|
|
2410
|
+
// 只处理启用的资源类型 (status === 1)
|
|
2364
2411
|
if (resourceConfig.status === 1 && resourceConfig.code) {
|
|
2365
|
-
const formId =
|
|
2412
|
+
const formId = resourceConfig.id?.toString() || resourceConfig.resource_type_id?.toString();
|
|
2366
2413
|
if (formId) {
|
|
2367
2414
|
resourceCodeToFormIdMap[resourceConfig.code] = formId;
|
|
2368
2415
|
}
|
|
@@ -2372,60 +2419,77 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2372
2419
|
});
|
|
2373
2420
|
let hasCapacityIssue = false;
|
|
2374
2421
|
const resourceCapacityInfo = [];
|
|
2375
|
-
|
|
2422
|
+
|
|
2423
|
+
// 用于跟踪已处理的商品,避免重复添加
|
|
2424
|
+
const processedCartItemIds = new Set();
|
|
2425
|
+
|
|
2426
|
+
// 先检查所有资源类型,收集可用数量信息
|
|
2376
2427
|
for (const [resourceCode, items] of Object.entries(itemsByResourceType)) {
|
|
2428
|
+
// 获取该资源类型对应的 form_id
|
|
2377
2429
|
const targetFormId = resourceCodeToFormIdMap[resourceCode];
|
|
2378
2430
|
if (!targetFormId) {
|
|
2379
|
-
|
|
2380
|
-
|
|
2431
|
+
return {
|
|
2432
|
+
success: false,
|
|
2433
|
+
minAvailableCount: 0
|
|
2434
|
+
};
|
|
2381
2435
|
}
|
|
2436
|
+
|
|
2437
|
+
// 获取该资源类型的所有资源
|
|
2382
2438
|
const resourcesOfThisType = [];
|
|
2383
|
-
items.forEach(
|
|
2384
|
-
const productResourceIds = (0,
|
|
2385
|
-
productResourceIds.forEach(
|
|
2386
|
-
var _a2;
|
|
2439
|
+
items.forEach(cartItem => {
|
|
2440
|
+
const productResourceIds = (0, _capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
|
|
2441
|
+
productResourceIds.forEach(resourceId => {
|
|
2387
2442
|
const resource = resourcesMap[resourceId];
|
|
2388
|
-
if (resource &&
|
|
2389
|
-
|
|
2443
|
+
if (resource && resource.form_id?.toString() === targetFormId) {
|
|
2444
|
+
// 避免重复添加同一个资源
|
|
2445
|
+
if (!resourcesOfThisType.find(r => r.id === resource.id)) {
|
|
2390
2446
|
resourcesOfThisType.push(resource);
|
|
2391
2447
|
}
|
|
2392
2448
|
}
|
|
2393
2449
|
});
|
|
2394
2450
|
});
|
|
2395
2451
|
if (resourcesOfThisType.length === 0) {
|
|
2396
|
-
|
|
2397
|
-
|
|
2452
|
+
return {
|
|
2453
|
+
success: false,
|
|
2454
|
+
minAvailableCount: 0
|
|
2455
|
+
};
|
|
2398
2456
|
}
|
|
2457
|
+
|
|
2458
|
+
// 检查资源类型(单个预约 vs 多个预约)
|
|
2459
|
+
// 从商品配置中获取资源类型信息
|
|
2399
2460
|
let resourceTypeConfig = null;
|
|
2400
2461
|
for (const cartItem of items) {
|
|
2401
|
-
if (
|
|
2402
|
-
resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(
|
|
2403
|
-
|
|
2404
|
-
);
|
|
2405
|
-
if (resourceTypeConfig)
|
|
2406
|
-
break;
|
|
2462
|
+
if (cartItem._productOrigin?.product_resource?.resources) {
|
|
2463
|
+
resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(r => r.code === resourceCode && r.status === 1);
|
|
2464
|
+
if (resourceTypeConfig) break;
|
|
2407
2465
|
}
|
|
2408
2466
|
}
|
|
2409
|
-
const isMultipleBooking =
|
|
2467
|
+
const isMultipleBooking = resourceTypeConfig?.type === 'multiple';
|
|
2410
2468
|
let totalAvailable;
|
|
2411
2469
|
let requiredAmount;
|
|
2412
2470
|
let availableAmount;
|
|
2413
2471
|
if (isMultipleBooking) {
|
|
2472
|
+
// 多个预约:计算容量
|
|
2414
2473
|
totalAvailable = resourcesOfThisType.reduce((sum, resource) => {
|
|
2415
2474
|
return sum + (resource.capacity || 0);
|
|
2416
2475
|
}, 0);
|
|
2417
2476
|
requiredAmount = items.reduce((sum, cartItem) => {
|
|
2418
|
-
const {
|
|
2477
|
+
const {
|
|
2478
|
+
currentCapacity
|
|
2479
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(cartItem);
|
|
2419
2480
|
return sum + currentCapacity;
|
|
2420
2481
|
}, 0);
|
|
2421
2482
|
availableAmount = Math.max(0, totalAvailable - requiredAmount);
|
|
2422
2483
|
} else {
|
|
2484
|
+
// 单个预约:计算资源个数
|
|
2423
2485
|
totalAvailable = resourcesOfThisType.length;
|
|
2424
2486
|
requiredAmount = items.reduce((sum, cartItem) => {
|
|
2425
2487
|
return sum + (cartItem.num || 1);
|
|
2426
2488
|
}, 0);
|
|
2427
2489
|
availableAmount = Math.max(0, totalAvailable - requiredAmount);
|
|
2428
2490
|
}
|
|
2491
|
+
|
|
2492
|
+
// 记录资源容量信息
|
|
2429
2493
|
resourceCapacityInfo.push({
|
|
2430
2494
|
code: resourceCode,
|
|
2431
2495
|
available: availableAmount,
|
|
@@ -2434,23 +2498,27 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2434
2498
|
isMultiple: isMultipleBooking
|
|
2435
2499
|
});
|
|
2436
2500
|
availableCountsByResourceType.push(availableAmount);
|
|
2501
|
+
|
|
2502
|
+
// 检查是否有容量问题
|
|
2437
2503
|
if (requiredAmount > totalAvailable) {
|
|
2438
2504
|
hasCapacityIssue = true;
|
|
2439
|
-
console.log(`资源类型 ${resourceCode} ${isMultipleBooking ? "容量" : "资源数量"}不足: 需要 ${requiredAmount}, 总共 ${totalAvailable}`);
|
|
2440
2505
|
}
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2506
|
+
|
|
2507
|
+
// 为通过检测的商品分配一个公共可用时间段
|
|
2508
|
+
|
|
2509
|
+
// 找到所有资源都可用的时间段
|
|
2445
2510
|
const commonTimeSlots = this.findCommonAvailableTimeSlots(resourcesOfThisType);
|
|
2446
|
-
console.log(`资源类型 ${resourceCode} 的公共时间段:`, commonTimeSlots);
|
|
2447
2511
|
if (commonTimeSlots.length === 0) {
|
|
2448
|
-
|
|
2449
|
-
|
|
2512
|
+
return {
|
|
2513
|
+
success: false,
|
|
2514
|
+
minAvailableCount: 0
|
|
2515
|
+
};
|
|
2450
2516
|
}
|
|
2517
|
+
|
|
2518
|
+
// 使用第一个公共可用时间段,但只处理未处理过的商品
|
|
2451
2519
|
const firstCommonSlot = commonTimeSlots[0];
|
|
2452
|
-
|
|
2453
|
-
|
|
2520
|
+
items.forEach(cartItem => {
|
|
2521
|
+
// 只处理未处理过的商品,避免重复添加
|
|
2454
2522
|
if (!processedCartItemIds.has(cartItem._id)) {
|
|
2455
2523
|
processedCartItemIds.add(cartItem._id);
|
|
2456
2524
|
const processedItem = {
|
|
@@ -2464,59 +2532,93 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2464
2532
|
}
|
|
2465
2533
|
});
|
|
2466
2534
|
}
|
|
2535
|
+
|
|
2536
|
+
// 如果有容量问题,找出限制最严格的资源类型,返回其总容量
|
|
2467
2537
|
if (hasCapacityIssue) {
|
|
2468
|
-
|
|
2538
|
+
// 找出超出容量的资源类型中,总容量最少的那个
|
|
2539
|
+
const overCapacityResources = resourceCapacityInfo.filter(info => info.required > info.total);
|
|
2469
2540
|
if (overCapacityResources.length > 0) {
|
|
2470
|
-
const
|
|
2471
|
-
return {
|
|
2541
|
+
const minTotalCapacity = Math.min(...overCapacityResources.map(info => info.total));
|
|
2542
|
+
return {
|
|
2543
|
+
success: false,
|
|
2544
|
+
minAvailableCount: minTotalCapacity
|
|
2545
|
+
};
|
|
2472
2546
|
}
|
|
2473
|
-
|
|
2474
|
-
|
|
2547
|
+
// 如果没有超出容量的(理论上不应该发生),返回总容量最少的
|
|
2548
|
+
const minTotalCapacity = Math.min(...resourceCapacityInfo.map(info => info.total));
|
|
2549
|
+
return {
|
|
2550
|
+
success: false,
|
|
2551
|
+
minAvailableCount: minTotalCapacity
|
|
2552
|
+
};
|
|
2475
2553
|
}
|
|
2476
2554
|
}
|
|
2555
|
+
|
|
2556
|
+
// 合并所有商品(有时间的 + 处理后的没有时间的)
|
|
2477
2557
|
const allProcessedItems = [...itemsWithTime, ...processedItemsWithoutTime];
|
|
2558
|
+
|
|
2559
|
+
// 按时间段分组检查
|
|
2478
2560
|
const cartItemsByTimeSlot = {};
|
|
2479
|
-
allProcessedItems.forEach(
|
|
2480
|
-
if (!cartItem.start_time || !cartItem.end_time || !cartItem.start_date)
|
|
2481
|
-
return;
|
|
2561
|
+
allProcessedItems.forEach(cartItem => {
|
|
2562
|
+
if (!cartItem.start_time || !cartItem.end_time || !cartItem.start_date) return;
|
|
2482
2563
|
const timeSlotKey = `${cartItem.start_date}_${cartItem.start_time}_${cartItem.end_date || cartItem.start_date}_${cartItem.end_time}`;
|
|
2483
2564
|
if (!cartItemsByTimeSlot[timeSlotKey]) {
|
|
2484
2565
|
cartItemsByTimeSlot[timeSlotKey] = [];
|
|
2485
2566
|
}
|
|
2486
2567
|
cartItemsByTimeSlot[timeSlotKey].push(cartItem);
|
|
2487
2568
|
});
|
|
2569
|
+
// 检查每个时间段是否有足够的资源容量
|
|
2488
2570
|
for (const [timeSlotKey, itemsInTimeSlot] of Object.entries(cartItemsByTimeSlot)) {
|
|
2489
|
-
const [startDate, startTime, endDate, endTime] = timeSlotKey.split(
|
|
2571
|
+
const [startDate, startTime, endDate, endTime] = timeSlotKey.split('_');
|
|
2490
2572
|
const timeSlotStart = `${startDate} ${startTime}`;
|
|
2491
2573
|
const timeSlotEnd = `${endDate} ${endTime}`;
|
|
2574
|
+
|
|
2575
|
+
// 获取这个时间段所有商品涉及的资源
|
|
2492
2576
|
const allResourcesForTimeSlot = [];
|
|
2493
|
-
const resourcesIdSet =
|
|
2577
|
+
const resourcesIdSet = new Set();
|
|
2578
|
+
|
|
2579
|
+
// 获取资源数据
|
|
2494
2580
|
const dateRange = this.store.date.getDateRange();
|
|
2495
2581
|
const resourcesDates = this.store.date.getDateList();
|
|
2496
|
-
const targetResourceDate = resourcesDates.find(
|
|
2497
|
-
if (!targetResourceDate)
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
const productResourceIds = (0,
|
|
2504
|
-
productResourceIds.forEach(
|
|
2582
|
+
const targetResourceDate = resourcesDates.find(n => n.date === startDate);
|
|
2583
|
+
if (!targetResourceDate) continue;
|
|
2584
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(targetResourceDate.resource || []);
|
|
2585
|
+
itemsInTimeSlot.forEach(cartItem => {
|
|
2586
|
+
if (!cartItem._productOrigin) return;
|
|
2587
|
+
|
|
2588
|
+
// 获取商品的资源配置
|
|
2589
|
+
const productResourceIds = (0, _capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
|
|
2590
|
+
productResourceIds.forEach(resourceId => {
|
|
2505
2591
|
if (resourcesMap[resourceId] && !resourcesIdSet.has(resourceId)) {
|
|
2506
2592
|
resourcesIdSet.add(resourceId);
|
|
2507
2593
|
allResourcesForTimeSlot.push(resourcesMap[resourceId]);
|
|
2508
2594
|
}
|
|
2509
2595
|
});
|
|
2510
2596
|
});
|
|
2511
|
-
|
|
2597
|
+
|
|
2598
|
+
// 按资源类型分组检查容量
|
|
2599
|
+
const {
|
|
2600
|
+
success,
|
|
2601
|
+
required,
|
|
2602
|
+
available
|
|
2603
|
+
} = (0, _capacity.checkTimeSlotCapacity)(timeSlotStart, timeSlotEnd, itemsInTimeSlot, allResourcesForTimeSlot);
|
|
2512
2604
|
if (!success) {
|
|
2513
|
-
|
|
2514
|
-
|
|
2605
|
+
// 如果有可用数量记录,返回最小值;否则返回 0
|
|
2606
|
+
const minAvailableCount = availableCountsByResourceType.length > 0 ? Math.min(...availableCountsByResourceType) : 0;
|
|
2607
|
+
return {
|
|
2608
|
+
success: false,
|
|
2609
|
+
minAvailableCount
|
|
2610
|
+
};
|
|
2515
2611
|
}
|
|
2516
2612
|
}
|
|
2613
|
+
|
|
2614
|
+
// 全部通过检测,返回成功和最小可用数量
|
|
2517
2615
|
const minAvailableCount = availableCountsByResourceType.length > 0 ? Math.min(...availableCountsByResourceType) : 0;
|
|
2518
|
-
return {
|
|
2616
|
+
return {
|
|
2617
|
+
success: true,
|
|
2618
|
+
minAvailableCount
|
|
2619
|
+
};
|
|
2519
2620
|
}
|
|
2621
|
+
|
|
2520
2622
|
/**
|
|
2521
2623
|
* 将 ProductData 转换为 CartItem,但不添加到购物车
|
|
2522
2624
|
* 参考 addProductToCart 方法的实现
|
|
@@ -2533,21 +2635,34 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2533
2635
|
product_variant_id,
|
|
2534
2636
|
quantity = 1
|
|
2535
2637
|
} = product || {};
|
|
2536
|
-
|
|
2537
|
-
|
|
2638
|
+
|
|
2639
|
+
// 处理商品数据,类似 addProductToCart 中的逻辑
|
|
2640
|
+
const productData = {
|
|
2641
|
+
...origin,
|
|
2642
|
+
product_variant_id
|
|
2643
|
+
};
|
|
2644
|
+
|
|
2645
|
+
// 处理组合商品
|
|
2646
|
+
const processedProduct = (0, _utils.handleVariantProduct)(productData);
|
|
2647
|
+
|
|
2648
|
+
// 如果没有传入账户,获取当前活跃账户
|
|
2538
2649
|
if (!account) {
|
|
2539
2650
|
const activeAccount = this.getActiveAccount();
|
|
2540
2651
|
if (activeAccount) {
|
|
2541
2652
|
account = activeAccount;
|
|
2542
2653
|
}
|
|
2543
2654
|
}
|
|
2655
|
+
|
|
2656
|
+
// 创建基础的 CartItem
|
|
2544
2657
|
const cartItem = {
|
|
2545
|
-
_id: (0,
|
|
2546
|
-
_origin: (0,
|
|
2658
|
+
_id: (0, _utils.getUniqueId)('temp_'),
|
|
2659
|
+
_origin: (0, _utils.createCartItemOrigin)(),
|
|
2547
2660
|
_productOrigin: processedProduct,
|
|
2548
2661
|
_productInit: product
|
|
2549
2662
|
};
|
|
2550
|
-
|
|
2663
|
+
|
|
2664
|
+
// 使用格式化函数填充 CartItem 数据
|
|
2665
|
+
(0, _utils.formatProductToCartItem)({
|
|
2551
2666
|
cartItem,
|
|
2552
2667
|
product: processedProduct,
|
|
2553
2668
|
bundle,
|
|
@@ -2555,14 +2670,18 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2555
2670
|
product_variant_id,
|
|
2556
2671
|
quantity
|
|
2557
2672
|
});
|
|
2673
|
+
|
|
2674
|
+
// 如果有日期信息,格式化日期到购物车
|
|
2558
2675
|
if (date) {
|
|
2559
|
-
(0,
|
|
2676
|
+
(0, _utils.formatDateToCartItem)({
|
|
2560
2677
|
cartItem,
|
|
2561
2678
|
date
|
|
2562
2679
|
});
|
|
2563
2680
|
}
|
|
2681
|
+
|
|
2682
|
+
// 如果有账户信息,格式化账户到购物车
|
|
2564
2683
|
if (account) {
|
|
2565
|
-
(0,
|
|
2684
|
+
(0, _utils.formatAccountToCartItem)({
|
|
2566
2685
|
cartItem,
|
|
2567
2686
|
account
|
|
2568
2687
|
});
|
|
@@ -2574,59 +2693,79 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2574
2693
|
date,
|
|
2575
2694
|
account
|
|
2576
2695
|
}) {
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2696
|
+
const cartItems = this.store.cart.getItems().filter(item => !(0, _utils5.isNormalProduct)(item._productOrigin));
|
|
2697
|
+
|
|
2698
|
+
// 将 ProductData 转换为 CartItem 但不真正添加到购物车
|
|
2699
|
+
const currentCartItem = this.convertProductToCartItem({
|
|
2700
|
+
product,
|
|
2701
|
+
date,
|
|
2702
|
+
account
|
|
2703
|
+
});
|
|
2580
2704
|
cartItems.push(currentCartItem);
|
|
2581
|
-
if (cartItems.length === 0)
|
|
2582
|
-
|
|
2705
|
+
if (cartItems.length === 0) return {
|
|
2706
|
+
success: true,
|
|
2707
|
+
minAvailableCount: 0
|
|
2708
|
+
};
|
|
2709
|
+
|
|
2710
|
+
// 将购物车商品分为有时间的和没有时间的
|
|
2583
2711
|
const itemsWithTime = [];
|
|
2584
2712
|
const itemsWithoutTime = [];
|
|
2713
|
+
// 记录每种资源类型的可用数量
|
|
2585
2714
|
const availableCountsByResourceType = [];
|
|
2586
|
-
cartItems.forEach(
|
|
2715
|
+
cartItems.forEach(cartItem => {
|
|
2587
2716
|
if (cartItem.start_time && cartItem.end_time && cartItem.start_date) {
|
|
2588
2717
|
itemsWithTime.push(cartItem);
|
|
2589
2718
|
} else {
|
|
2590
2719
|
itemsWithoutTime.push(cartItem);
|
|
2591
2720
|
}
|
|
2592
2721
|
});
|
|
2722
|
+
|
|
2723
|
+
// 处理没有时间的商品,为它们分配公共可用时间的第一个时间片
|
|
2593
2724
|
const processedItemsWithoutTime = [];
|
|
2594
2725
|
if (itemsWithoutTime.length > 0) {
|
|
2726
|
+
// 按资源类型分组处理没有时间的商品
|
|
2595
2727
|
const itemsByResourceType = {};
|
|
2596
|
-
itemsWithoutTime.forEach(
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
const resourceTypes = ((_a2 = cartItem._productOrigin.product_resource) == null ? void 0 : _a2.resources) || [];
|
|
2601
|
-
resourceTypes.forEach((resourceType) => {
|
|
2602
|
-
var _a3;
|
|
2728
|
+
itemsWithoutTime.forEach(cartItem => {
|
|
2729
|
+
if (!cartItem._productOrigin) return;
|
|
2730
|
+
const resourceTypes = cartItem._productOrigin.product_resource?.resources || [];
|
|
2731
|
+
resourceTypes.forEach(resourceType => {
|
|
2603
2732
|
if (resourceType.status === 1) {
|
|
2604
|
-
const resourceCode = resourceType.code ||
|
|
2733
|
+
const resourceCode = resourceType.code || resourceType.id?.toString();
|
|
2605
2734
|
if (!itemsByResourceType[resourceCode]) {
|
|
2606
2735
|
itemsByResourceType[resourceCode] = [];
|
|
2607
2736
|
}
|
|
2608
|
-
|
|
2737
|
+
// 避免重复添加同一个商品
|
|
2738
|
+
if (!itemsByResourceType[resourceCode].find(item => item._id === cartItem._id)) {
|
|
2609
2739
|
itemsByResourceType[resourceCode].push(cartItem);
|
|
2610
2740
|
}
|
|
2611
2741
|
}
|
|
2612
2742
|
});
|
|
2613
2743
|
});
|
|
2744
|
+
|
|
2745
|
+
// 为每种资源类型检查容量
|
|
2614
2746
|
const dateRange = this.store.date.getDateRange();
|
|
2615
|
-
if (!dateRange || dateRange.length === 0)
|
|
2616
|
-
|
|
2747
|
+
if (!dateRange || dateRange.length === 0) return {
|
|
2748
|
+
success: false,
|
|
2749
|
+
minAvailableCount: 0
|
|
2750
|
+
};
|
|
2617
2751
|
const resourcesDates = this.store.date.getDateList();
|
|
2618
|
-
const targetResourceDate = resourcesDates.find(
|
|
2619
|
-
if (!targetResourceDate)
|
|
2620
|
-
|
|
2621
|
-
|
|
2752
|
+
const targetResourceDate = resourcesDates.find(n => n.date === dateRange[0].date);
|
|
2753
|
+
if (!targetResourceDate) return {
|
|
2754
|
+
success: false,
|
|
2755
|
+
minAvailableCount: 0
|
|
2756
|
+
};
|
|
2757
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(targetResourceDate.resource || []);
|
|
2758
|
+
|
|
2759
|
+
// 从购物车商品中获取资源类型配置,建立 resourceCode 到 form_id 的映射关系
|
|
2622
2760
|
const resourceCodeToFormIdMap = {};
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2761
|
+
|
|
2762
|
+
// 遍历购物车中的商品,收集所有资源类型配置
|
|
2763
|
+
Object.values(itemsByResourceType).flat().forEach(cartItem => {
|
|
2764
|
+
if (cartItem._productOrigin?.product_resource?.resources) {
|
|
2765
|
+
cartItem._productOrigin.product_resource.resources.forEach(resourceConfig => {
|
|
2766
|
+
// 只处理启用的资源类型 (status === 1)
|
|
2628
2767
|
if (resourceConfig.status === 1 && resourceConfig.code) {
|
|
2629
|
-
const formId =
|
|
2768
|
+
const formId = resourceConfig.id?.toString() || resourceConfig.resource_type_id?.toString();
|
|
2630
2769
|
if (formId) {
|
|
2631
2770
|
resourceCodeToFormIdMap[resourceConfig.code] = formId;
|
|
2632
2771
|
}
|
|
@@ -2636,60 +2775,77 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2636
2775
|
});
|
|
2637
2776
|
let hasCapacityIssue = false;
|
|
2638
2777
|
const resourceCapacityInfo = [];
|
|
2639
|
-
|
|
2778
|
+
|
|
2779
|
+
// 用于跟踪已处理的商品,避免重复添加
|
|
2780
|
+
const processedCartItemIds = new Set();
|
|
2781
|
+
|
|
2782
|
+
// 先检查所有资源类型,收集可用数量信息
|
|
2640
2783
|
for (const [resourceCode, items] of Object.entries(itemsByResourceType)) {
|
|
2784
|
+
// 获取该资源类型对应的 form_id
|
|
2641
2785
|
const targetFormId = resourceCodeToFormIdMap[resourceCode];
|
|
2642
2786
|
if (!targetFormId) {
|
|
2643
|
-
|
|
2644
|
-
|
|
2787
|
+
return {
|
|
2788
|
+
success: false,
|
|
2789
|
+
minAvailableCount: 0
|
|
2790
|
+
};
|
|
2645
2791
|
}
|
|
2792
|
+
|
|
2793
|
+
// 获取该资源类型的所有资源
|
|
2646
2794
|
const resourcesOfThisType = [];
|
|
2647
|
-
items.forEach(
|
|
2648
|
-
const productResourceIds = (0,
|
|
2649
|
-
productResourceIds.forEach(
|
|
2650
|
-
var _a2;
|
|
2795
|
+
items.forEach(cartItem => {
|
|
2796
|
+
const productResourceIds = (0, _capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
|
|
2797
|
+
productResourceIds.forEach(resourceId => {
|
|
2651
2798
|
const resource = resourcesMap[resourceId];
|
|
2652
|
-
if (resource &&
|
|
2653
|
-
|
|
2799
|
+
if (resource && resource.form_id?.toString() === targetFormId) {
|
|
2800
|
+
// 避免重复添加同一个资源
|
|
2801
|
+
if (!resourcesOfThisType.find(r => r.id === resource.id)) {
|
|
2654
2802
|
resourcesOfThisType.push(resource);
|
|
2655
2803
|
}
|
|
2656
2804
|
}
|
|
2657
2805
|
});
|
|
2658
2806
|
});
|
|
2659
2807
|
if (resourcesOfThisType.length === 0) {
|
|
2660
|
-
|
|
2661
|
-
|
|
2808
|
+
return {
|
|
2809
|
+
success: false,
|
|
2810
|
+
minAvailableCount: 0
|
|
2811
|
+
};
|
|
2662
2812
|
}
|
|
2813
|
+
|
|
2814
|
+
// 检查资源类型(单个预约 vs 多个预约)
|
|
2815
|
+
// 从商品配置中获取资源类型信息
|
|
2663
2816
|
let resourceTypeConfig = null;
|
|
2664
2817
|
for (const cartItem of items) {
|
|
2665
|
-
if (
|
|
2666
|
-
resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(
|
|
2667
|
-
|
|
2668
|
-
);
|
|
2669
|
-
if (resourceTypeConfig)
|
|
2670
|
-
break;
|
|
2818
|
+
if (cartItem._productOrigin?.product_resource?.resources) {
|
|
2819
|
+
resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(r => r.code === resourceCode && r.status === 1);
|
|
2820
|
+
if (resourceTypeConfig) break;
|
|
2671
2821
|
}
|
|
2672
2822
|
}
|
|
2673
|
-
const isMultipleBooking =
|
|
2823
|
+
const isMultipleBooking = resourceTypeConfig?.type === 'multiple';
|
|
2674
2824
|
let totalAvailable;
|
|
2675
2825
|
let requiredAmount;
|
|
2676
2826
|
let availableAmount;
|
|
2677
2827
|
if (isMultipleBooking) {
|
|
2828
|
+
// 多个预约:计算容量
|
|
2678
2829
|
totalAvailable = resourcesOfThisType.reduce((sum, resource) => {
|
|
2679
2830
|
return sum + (resource.capacity || 0);
|
|
2680
2831
|
}, 0);
|
|
2681
2832
|
requiredAmount = items.reduce((sum, cartItem) => {
|
|
2682
|
-
const {
|
|
2833
|
+
const {
|
|
2834
|
+
currentCapacity
|
|
2835
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(cartItem);
|
|
2683
2836
|
return sum + currentCapacity;
|
|
2684
2837
|
}, 0);
|
|
2685
2838
|
availableAmount = Math.max(0, totalAvailable - requiredAmount);
|
|
2686
2839
|
} else {
|
|
2840
|
+
// 单个预约:计算资源个数
|
|
2687
2841
|
totalAvailable = resourcesOfThisType.length;
|
|
2688
2842
|
requiredAmount = items.reduce((sum, cartItem) => {
|
|
2689
2843
|
return sum + (cartItem.num || 1);
|
|
2690
2844
|
}, 0);
|
|
2691
2845
|
availableAmount = Math.max(0, totalAvailable - requiredAmount);
|
|
2692
2846
|
}
|
|
2847
|
+
|
|
2848
|
+
// 记录资源容量信息
|
|
2693
2849
|
resourceCapacityInfo.push({
|
|
2694
2850
|
code: resourceCode,
|
|
2695
2851
|
available: availableAmount,
|
|
@@ -2698,23 +2854,27 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2698
2854
|
isMultiple: isMultipleBooking
|
|
2699
2855
|
});
|
|
2700
2856
|
availableCountsByResourceType.push(availableAmount);
|
|
2857
|
+
|
|
2858
|
+
// 检查是否有容量问题
|
|
2701
2859
|
if (requiredAmount > totalAvailable) {
|
|
2702
2860
|
hasCapacityIssue = true;
|
|
2703
|
-
console.log(`资源类型 ${resourceCode} ${isMultipleBooking ? "容量" : "资源数量"}不足: 需要 ${requiredAmount}, 总共 ${totalAvailable}`);
|
|
2704
2861
|
}
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2862
|
+
|
|
2863
|
+
// 为通过检测的商品分配一个公共可用时间段
|
|
2864
|
+
|
|
2865
|
+
// 找到所有资源都可用的时间段
|
|
2709
2866
|
const commonTimeSlots = this.findCommonAvailableTimeSlots(resourcesOfThisType);
|
|
2710
|
-
console.log(`资源类型 ${resourceCode} 的公共时间段:`, commonTimeSlots);
|
|
2711
2867
|
if (commonTimeSlots.length === 0) {
|
|
2712
|
-
|
|
2713
|
-
|
|
2868
|
+
return {
|
|
2869
|
+
success: false,
|
|
2870
|
+
minAvailableCount: 0
|
|
2871
|
+
};
|
|
2714
2872
|
}
|
|
2873
|
+
|
|
2874
|
+
// 使用第一个公共可用时间段,但只处理未处理过的商品
|
|
2715
2875
|
const firstCommonSlot = commonTimeSlots[0];
|
|
2716
|
-
|
|
2717
|
-
|
|
2876
|
+
items.forEach(cartItem => {
|
|
2877
|
+
// 只处理未处理过的商品,避免重复添加
|
|
2718
2878
|
if (!processedCartItemIds.has(cartItem._id)) {
|
|
2719
2879
|
processedCartItemIds.add(cartItem._id);
|
|
2720
2880
|
const processedItem = {
|
|
@@ -2728,83 +2888,120 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2728
2888
|
}
|
|
2729
2889
|
});
|
|
2730
2890
|
}
|
|
2891
|
+
|
|
2892
|
+
// 如果有容量问题,找出限制最严格的资源类型,返回其总容量
|
|
2731
2893
|
if (hasCapacityIssue) {
|
|
2732
|
-
|
|
2894
|
+
// 找出超出容量的资源类型中,总容量最少的那个
|
|
2895
|
+
const overCapacityResources = resourceCapacityInfo.filter(info => info.required > info.total);
|
|
2733
2896
|
if (overCapacityResources.length > 0) {
|
|
2734
|
-
const
|
|
2735
|
-
return {
|
|
2897
|
+
const minTotalCapacity = Math.min(...overCapacityResources.map(info => info.total));
|
|
2898
|
+
return {
|
|
2899
|
+
success: false,
|
|
2900
|
+
minAvailableCount: minTotalCapacity
|
|
2901
|
+
};
|
|
2736
2902
|
}
|
|
2737
|
-
|
|
2738
|
-
|
|
2903
|
+
// 如果没有超出容量的(理论上不应该发生),返回总容量最少的
|
|
2904
|
+
const minTotalCapacity = Math.min(...resourceCapacityInfo.map(info => info.total));
|
|
2905
|
+
return {
|
|
2906
|
+
success: false,
|
|
2907
|
+
minAvailableCount: minTotalCapacity
|
|
2908
|
+
};
|
|
2739
2909
|
}
|
|
2740
2910
|
}
|
|
2911
|
+
|
|
2912
|
+
// 合并所有商品(有时间的 + 处理后的没有时间的)
|
|
2741
2913
|
const allProcessedItems = [...itemsWithTime, ...processedItemsWithoutTime];
|
|
2914
|
+
|
|
2915
|
+
// 按时间段分组检查
|
|
2742
2916
|
const cartItemsByTimeSlot = {};
|
|
2743
|
-
allProcessedItems.forEach(
|
|
2744
|
-
if (!cartItem.start_time || !cartItem.end_time || !cartItem.start_date)
|
|
2745
|
-
return;
|
|
2917
|
+
allProcessedItems.forEach(cartItem => {
|
|
2918
|
+
if (!cartItem.start_time || !cartItem.end_time || !cartItem.start_date) return;
|
|
2746
2919
|
const timeSlotKey = `${cartItem.start_date}_${cartItem.start_time}_${cartItem.end_date || cartItem.start_date}_${cartItem.end_time}`;
|
|
2747
2920
|
if (!cartItemsByTimeSlot[timeSlotKey]) {
|
|
2748
2921
|
cartItemsByTimeSlot[timeSlotKey] = [];
|
|
2749
2922
|
}
|
|
2750
2923
|
cartItemsByTimeSlot[timeSlotKey].push(cartItem);
|
|
2751
2924
|
});
|
|
2925
|
+
// 检查每个时间段是否有足够的资源容量
|
|
2752
2926
|
for (const [timeSlotKey, itemsInTimeSlot] of Object.entries(cartItemsByTimeSlot)) {
|
|
2753
|
-
const [startDate, startTime, endDate, endTime] = timeSlotKey.split(
|
|
2927
|
+
const [startDate, startTime, endDate, endTime] = timeSlotKey.split('_');
|
|
2754
2928
|
const timeSlotStart = `${startDate} ${startTime}`;
|
|
2755
2929
|
const timeSlotEnd = `${endDate} ${endTime}`;
|
|
2930
|
+
|
|
2931
|
+
// 获取这个时间段所有商品涉及的资源
|
|
2756
2932
|
const allResourcesForTimeSlot = [];
|
|
2757
|
-
const resourcesIdSet =
|
|
2933
|
+
const resourcesIdSet = new Set();
|
|
2934
|
+
|
|
2935
|
+
// 获取资源数据
|
|
2936
|
+
// const dateRange = this.store.date.getDateRange();
|
|
2758
2937
|
const resourcesDates = this.store.date.getDateList();
|
|
2759
|
-
const targetResourceDate = resourcesDates.find(
|
|
2760
|
-
if (!targetResourceDate)
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
const productResourceIds = (0,
|
|
2767
|
-
productResourceIds.forEach(
|
|
2938
|
+
const targetResourceDate = resourcesDates.find(n => n.date === startDate);
|
|
2939
|
+
if (!targetResourceDate) continue;
|
|
2940
|
+
const resourcesMap = (0, _utils2.getResourcesMap)(targetResourceDate.resource || []);
|
|
2941
|
+
itemsInTimeSlot.forEach(cartItem => {
|
|
2942
|
+
if (!cartItem._productOrigin) return;
|
|
2943
|
+
|
|
2944
|
+
// 获取商品的资源配置
|
|
2945
|
+
const productResourceIds = (0, _capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
|
|
2946
|
+
productResourceIds.forEach(resourceId => {
|
|
2768
2947
|
if (resourcesMap[resourceId] && !resourcesIdSet.has(resourceId)) {
|
|
2769
2948
|
resourcesIdSet.add(resourceId);
|
|
2770
2949
|
allResourcesForTimeSlot.push(resourcesMap[resourceId]);
|
|
2771
2950
|
}
|
|
2772
2951
|
});
|
|
2773
2952
|
});
|
|
2774
|
-
|
|
2953
|
+
|
|
2954
|
+
// 按资源类型分组检查容量
|
|
2955
|
+
const {
|
|
2956
|
+
success,
|
|
2957
|
+
required,
|
|
2958
|
+
available
|
|
2959
|
+
} = (0, _capacity.checkTimeSlotCapacity)(timeSlotStart, timeSlotEnd, itemsInTimeSlot, allResourcesForTimeSlot);
|
|
2775
2960
|
if (!success) {
|
|
2776
|
-
|
|
2961
|
+
// 如果有可用数量记录,返回最小值;否则返回 0
|
|
2962
|
+
// const minAvailableCount = availableCountsByResourceType.length > 0 ? Math.min(...availableCountsByResourceType) : 0;
|
|
2963
|
+
return {
|
|
2964
|
+
success: false,
|
|
2965
|
+
minAvailableCount: available
|
|
2966
|
+
};
|
|
2777
2967
|
}
|
|
2778
2968
|
}
|
|
2969
|
+
|
|
2970
|
+
// 全部通过检测,返回成功和最小可用数量
|
|
2779
2971
|
const minAvailableCount = availableCountsByResourceType.length > 0 ? Math.min(...availableCountsByResourceType) : 0;
|
|
2780
|
-
return {
|
|
2972
|
+
return {
|
|
2973
|
+
success: true,
|
|
2974
|
+
minAvailableCount
|
|
2975
|
+
};
|
|
2781
2976
|
}
|
|
2782
2977
|
setOtherData(key, value) {
|
|
2783
2978
|
this.otherData[key] = value;
|
|
2784
2979
|
this.checkSaveCache({
|
|
2785
2980
|
cacheId: this.cacheId,
|
|
2786
2981
|
fatherModule: this.name,
|
|
2787
|
-
store: {
|
|
2788
|
-
|
|
2982
|
+
store: {
|
|
2983
|
+
otherData: this.otherData
|
|
2984
|
+
},
|
|
2985
|
+
cacheKey: ['otherData']
|
|
2789
2986
|
});
|
|
2790
2987
|
}
|
|
2791
2988
|
getOtherData(key) {
|
|
2792
2989
|
return this.otherData[key];
|
|
2793
2990
|
}
|
|
2794
2991
|
async getProductTypeById(id) {
|
|
2795
|
-
var _a;
|
|
2796
2992
|
const productData = await this.store.products.getProduct(id);
|
|
2797
2993
|
if (productData) {
|
|
2798
2994
|
if (productData.duration) {
|
|
2799
|
-
return
|
|
2995
|
+
return 'duration';
|
|
2800
2996
|
}
|
|
2801
|
-
if (
|
|
2802
|
-
return
|
|
2997
|
+
if (productData['schedule.ids']?.length) {
|
|
2998
|
+
return 'session';
|
|
2803
2999
|
}
|
|
2804
|
-
return
|
|
3000
|
+
return 'normal';
|
|
2805
3001
|
}
|
|
2806
|
-
return
|
|
3002
|
+
return 'normal';
|
|
2807
3003
|
}
|
|
3004
|
+
|
|
2808
3005
|
/**
|
|
2809
3006
|
* 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
|
|
2810
3007
|
*
|
|
@@ -2814,113 +3011,82 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2814
3011
|
* @memberof BookingByStepImpl
|
|
2815
3012
|
*/
|
|
2816
3013
|
getResourcesByCartItemAndCode(cartItemId, resourceCode) {
|
|
2817
|
-
var _a, _b;
|
|
2818
3014
|
const dateRange = this.store.date.getDateRange();
|
|
2819
3015
|
const resources = [];
|
|
2820
|
-
if (dateRange
|
|
2821
|
-
dateRange.forEach(
|
|
2822
|
-
if (n.resource)
|
|
2823
|
-
resources.push(...n.resource);
|
|
3016
|
+
if (dateRange?.length) {
|
|
3017
|
+
dateRange.forEach(n => {
|
|
3018
|
+
if (n.resource) resources.push(...n.resource);
|
|
2824
3019
|
});
|
|
2825
3020
|
}
|
|
2826
3021
|
if (!resources.length) {
|
|
2827
3022
|
const dateList = this.store.date.getDateList();
|
|
2828
|
-
dateList.forEach(
|
|
2829
|
-
if (n.resource)
|
|
2830
|
-
resources.push(...n.resource);
|
|
3023
|
+
dateList.forEach(n => {
|
|
3024
|
+
if (n.resource) resources.push(...n.resource);
|
|
2831
3025
|
});
|
|
2832
3026
|
}
|
|
2833
|
-
const resourcesMap = (0,
|
|
2834
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
2835
|
-
const cartItem = cartItems.find(
|
|
2836
|
-
if (!cartItem)
|
|
2837
|
-
return [];
|
|
3027
|
+
const resourcesMap = (0, _utils2.getResourcesMap)((0, _lodashEs.cloneDeep)(resources));
|
|
3028
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
3029
|
+
const cartItem = cartItems.find(item => item._id === cartItemId);
|
|
3030
|
+
if (!cartItem) return [];
|
|
2838
3031
|
let selectedResources = [];
|
|
2839
|
-
const {
|
|
3032
|
+
const {
|
|
3033
|
+
currentCapacity,
|
|
3034
|
+
formatCapacity
|
|
3035
|
+
} = (0, _capacity.getCapacityInfoByCartItem)(cartItem);
|
|
2840
3036
|
cartItem._origin.metadata.capacity = formatCapacity;
|
|
2841
3037
|
if (cartItem.holder_id) {
|
|
2842
|
-
selectedResources = (0,
|
|
2843
|
-
cartItems,
|
|
2844
|
-
cartItem.holder_id,
|
|
2845
|
-
resourcesMap
|
|
2846
|
-
);
|
|
3038
|
+
selectedResources = (0, _resources.getOthersSelectedResources)(cartItems, cartItem.holder_id, resourcesMap);
|
|
2847
3039
|
} else {
|
|
2848
|
-
selectedResources = (0,
|
|
2849
|
-
cartItems,
|
|
2850
|
-
cartItem._id,
|
|
2851
|
-
resourcesMap
|
|
2852
|
-
);
|
|
3040
|
+
selectedResources = (0, _resources.getOthersCartSelectedResources)(cartItems, cartItem._id, resourcesMap);
|
|
2853
3041
|
}
|
|
2854
|
-
const productResources = (0,
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
selectedResources,
|
|
2858
|
-
currentCapacity
|
|
2859
|
-
);
|
|
2860
|
-
const targetResource = productResources.find(
|
|
2861
|
-
(resource) => resource.code === resourceCode
|
|
2862
|
-
);
|
|
2863
|
-
if (!targetResource)
|
|
2864
|
-
return [];
|
|
3042
|
+
const productResources = (0, _resources.getResourcesByProduct)(resourcesMap, cartItem._productOrigin?.product_resource?.resources || [], selectedResources, currentCapacity);
|
|
3043
|
+
const targetResource = productResources.find(resource => resource.code === resourceCode);
|
|
3044
|
+
if (!targetResource) return [];
|
|
2865
3045
|
if (cartItem._origin.start_time) {
|
|
2866
|
-
const startTime = (0,
|
|
2867
|
-
|
|
2868
|
-
);
|
|
2869
|
-
const endTime = (0, import_dayjs.default)(
|
|
2870
|
-
`${cartItem._origin.end_date} ${cartItem._origin.end_time}`
|
|
2871
|
-
);
|
|
3046
|
+
const startTime = (0, _dayjs.default)(`${cartItem._origin.start_date} ${cartItem._origin.start_time}`);
|
|
3047
|
+
const endTime = (0, _dayjs.default)(`${cartItem._origin.end_date} ${cartItem._origin.end_time}`);
|
|
2872
3048
|
const resourcesUseableMap = {};
|
|
2873
|
-
targetResource.renderList = targetResource.renderList.sort(
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
return 0;
|
|
2883
|
-
}
|
|
2884
|
-
);
|
|
2885
|
-
targetResource.renderList = targetResource.renderList.filter((m) => {
|
|
2886
|
-
const mTimes = m.times.filter((n) => {
|
|
2887
|
-
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));
|
|
3049
|
+
targetResource.renderList = targetResource.renderList.sort((a, b) => {
|
|
3050
|
+
const aIsCombined = a.metadata?.combined_resource?.status === 1;
|
|
3051
|
+
const bIsCombined = b.metadata?.combined_resource?.status === 1;
|
|
3052
|
+
if (aIsCombined && !bIsCombined) return 1;
|
|
3053
|
+
if (!aIsCombined && bIsCombined) return -1;
|
|
3054
|
+
return 0;
|
|
3055
|
+
});
|
|
3056
|
+
targetResource.renderList = targetResource.renderList.filter(m => {
|
|
3057
|
+
const mTimes = m.times.filter(n => {
|
|
3058
|
+
return !(0, _dayjs.default)(n.start_at).isAfter((0, _dayjs.default)(startTime)) && !(0, _dayjs.default)(n.end_at).isBefore((0, _dayjs.default)(endTime));
|
|
2888
3059
|
});
|
|
2889
|
-
if (mTimes.length === 0)
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
var _a2;
|
|
2893
|
-
const res = (0, import_resources.getIsUsableByTimeItem)({
|
|
3060
|
+
if (mTimes.length === 0) return false;
|
|
3061
|
+
const canUseArr = mTimes.map(item => {
|
|
3062
|
+
const res = (0, _resources.getIsUsableByTimeItem)({
|
|
2894
3063
|
timeSlice: {
|
|
2895
|
-
start_time: startTime.format(
|
|
2896
|
-
end_time: endTime.format(
|
|
3064
|
+
start_time: startTime.format('HH:mm'),
|
|
3065
|
+
end_time: endTime.format('HH:mm'),
|
|
2897
3066
|
start_at: startTime,
|
|
2898
3067
|
end_at: endTime
|
|
2899
3068
|
},
|
|
2900
3069
|
time: item,
|
|
2901
3070
|
resource: m,
|
|
2902
3071
|
currentCount: currentCapacity || 0,
|
|
2903
|
-
resourcesUseableMap,
|
|
2904
|
-
cut_off_time:
|
|
3072
|
+
resourcesUseableMap: resourcesUseableMap,
|
|
3073
|
+
cut_off_time: cartItem._productOrigin?.cut_off_time
|
|
2905
3074
|
});
|
|
2906
|
-
if (
|
|
3075
|
+
if (resourcesUseableMap?.[m.id] !== false && res.reason !== 'capacityOnly') {
|
|
2907
3076
|
resourcesUseableMap[m.id] = res.usable;
|
|
2908
3077
|
}
|
|
2909
3078
|
return res.usable;
|
|
2910
3079
|
});
|
|
2911
|
-
if (m.onlyComputed)
|
|
2912
|
-
|
|
2913
|
-
return !canUseArr.some((n) => n === false);
|
|
3080
|
+
if (m.onlyComputed) return false;
|
|
3081
|
+
return !canUseArr.some(n => n === false);
|
|
2914
3082
|
});
|
|
2915
3083
|
} else {
|
|
2916
|
-
targetResource.renderList = targetResource.renderList.filter(
|
|
2917
|
-
var _a2, _b2;
|
|
3084
|
+
targetResource.renderList = targetResource.renderList.filter(n => {
|
|
2918
3085
|
const recordCount = n.capacity || 0;
|
|
2919
|
-
if (n.onlyComputed)
|
|
2920
|
-
|
|
2921
|
-
const timeSlots = (0, import_resources.getTimeSlicesByResource)({
|
|
3086
|
+
if (n.onlyComputed) return false;
|
|
3087
|
+
const timeSlots = (0, _resources.getTimeSlicesByResource)({
|
|
2922
3088
|
resource: n,
|
|
2923
|
-
duration:
|
|
3089
|
+
duration: cartItem._productOrigin?.duration?.value || 10,
|
|
2924
3090
|
split: 10,
|
|
2925
3091
|
currentDate: dateRange[0].date
|
|
2926
3092
|
});
|
|
@@ -2929,6 +3095,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2929
3095
|
}
|
|
2930
3096
|
return targetResource.renderList;
|
|
2931
3097
|
}
|
|
3098
|
+
|
|
2932
3099
|
/**
|
|
2933
3100
|
* 根据日期范围批量获取时间槽
|
|
2934
3101
|
* @param params 参数对象
|
|
@@ -2940,17 +3107,15 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2940
3107
|
scheduleIds,
|
|
2941
3108
|
resources
|
|
2942
3109
|
}) {
|
|
2943
|
-
|
|
2944
|
-
"appoimentBooking-session-date-getTimeslotsScheduleByDateRange",
|
|
2945
|
-
{ startDate, endDate, scheduleIds, resources }
|
|
2946
|
-
);
|
|
3110
|
+
// 生成日期范围内的所有日期
|
|
2947
3111
|
const dates = [];
|
|
2948
|
-
let currentDate = (0,
|
|
2949
|
-
const end = (0,
|
|
3112
|
+
let currentDate = (0, _dayjs.default)(startDate);
|
|
3113
|
+
const end = (0, _dayjs.default)(endDate);
|
|
2950
3114
|
while (currentDate.isSameOrBefore(end)) {
|
|
2951
|
-
dates.push(currentDate.format(
|
|
2952
|
-
currentDate = currentDate.add(1,
|
|
3115
|
+
dates.push(currentDate.format('YYYY-MM-DD'));
|
|
3116
|
+
currentDate = currentDate.add(1, 'day');
|
|
2953
3117
|
}
|
|
3118
|
+
// 如果不支持 Web Worker,使用同步方式处理
|
|
2954
3119
|
const results = {};
|
|
2955
3120
|
for (const date of dates) {
|
|
2956
3121
|
results[date] = this.getTimeslotBySchedule({
|
|
@@ -2962,25 +3127,36 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2962
3127
|
return results;
|
|
2963
3128
|
}
|
|
2964
3129
|
async getAvailableDateForSessionOptimize(params = {}) {
|
|
2965
|
-
|
|
2966
|
-
let {
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
}
|
|
2970
|
-
|
|
3130
|
+
// 开始日期如果小于今天,直接以今天当做开始日期
|
|
3131
|
+
let {
|
|
3132
|
+
startDate,
|
|
3133
|
+
endDate
|
|
3134
|
+
} = params;
|
|
3135
|
+
// 前端传递的 startDate,可能是今天之前的,如果 startDate 小于今天 且 endDate 小于或等于今天,需要把 startDate 置为今天
|
|
3136
|
+
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'))) {
|
|
3137
|
+
startDate = (0, _dayjs.default)().format('YYYY-MM-DD');
|
|
3138
|
+
}
|
|
3139
|
+
// 不管前端传什么 endDate 默认查一个月的,以今天为开始日期。用于找到一个月内最近可用的日期
|
|
3140
|
+
// 优化策略:
|
|
3141
|
+
// 在 endDate 添加完一个月以后,如果 endDate 还小于 startDate + 7 天,则还需要 endDate+7 天
|
|
3142
|
+
const endDateAfterMonth = (0, _dayjs.default)().add(1, 'month').format('YYYY-MM-DD');
|
|
2971
3143
|
let tempEndDate = endDateAfterMonth;
|
|
2972
|
-
if ((0,
|
|
2973
|
-
tempEndDate = (0,
|
|
3144
|
+
if ((0, _dayjs.default)(startDate).add(7, 'day').isAfter((0, _dayjs.default)(endDateAfterMonth), 'day')) {
|
|
3145
|
+
tempEndDate = (0, _dayjs.default)(startDate).add(7, 'day').format('YYYY-MM-DD');
|
|
2974
3146
|
} else {
|
|
2975
3147
|
tempEndDate = endDateAfterMonth;
|
|
2976
3148
|
}
|
|
2977
|
-
|
|
2978
|
-
|
|
3149
|
+
// 如果这么算出来的 tempEndDate 还小于 endDate,则需要把 endDate 置为 tempEndDate
|
|
3150
|
+
if ((0, _dayjs.default)(tempEndDate).isBefore((0, _dayjs.default)(endDate), 'day')) {
|
|
3151
|
+
tempEndDate = endDate || '';
|
|
2979
3152
|
}
|
|
2980
3153
|
endDate = tempEndDate;
|
|
2981
|
-
|
|
3154
|
+
|
|
3155
|
+
// 先去读缓存结果,因为正常 UI 调用的是 7 天,而下面我会直接计算 30 天(最少也是 14 天),所以先去读缓存结果,如果缓存结果存在,则直接返回
|
|
3156
|
+
const cache = this.store.currentProductMeta?.['timeSlotBySchedule'];
|
|
2982
3157
|
if (cache) {
|
|
2983
|
-
|
|
3158
|
+
// 开始日期大于等于缓存的开始日期,且结束日期小于等于缓存的结束日期,则直接返回缓存结果
|
|
3159
|
+
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')) {
|
|
2984
3160
|
this.store.date.setDateList(cache.dateList);
|
|
2985
3161
|
return {
|
|
2986
3162
|
dateList: cache.dateList,
|
|
@@ -2989,190 +3165,207 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
2989
3165
|
}
|
|
2990
3166
|
}
|
|
2991
3167
|
let tempProducts;
|
|
3168
|
+
// 如果当前打开了某个的商品详情弹窗,则应该默认用这个商品
|
|
2992
3169
|
tempProducts = this.store.currentProduct;
|
|
2993
|
-
const schedule =
|
|
2994
|
-
const filteredSchedule = (0,
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
endDate || ""
|
|
2998
|
-
);
|
|
2999
|
-
const tempResourceIds = (0, import_capacity.getResourcesIdsByProduct)(tempProducts);
|
|
3170
|
+
const schedule = this.store.currentProductMeta?.['schedule'];
|
|
3171
|
+
const filteredSchedule = (0, _resources.filterScheduleByDateRange)(schedule, startDate || '', endDate || '');
|
|
3172
|
+
// 1.后端返回的数据,确定资源在每一天的可用和使用情况
|
|
3173
|
+
const tempResourceIds = (0, _capacity.getResourcesIdsByProduct)(tempProducts);
|
|
3000
3174
|
const res = await this.store.date.fetchResourceDates({
|
|
3001
3175
|
query: {
|
|
3002
|
-
start_date: startDate ||
|
|
3003
|
-
end_date: endDate ||
|
|
3176
|
+
start_date: startDate || '',
|
|
3177
|
+
end_date: endDate || '',
|
|
3004
3178
|
resource_ids: tempResourceIds
|
|
3005
3179
|
}
|
|
3006
3180
|
});
|
|
3181
|
+
// 2. 商品 schedule 数据,确定日程在每一天的时间片
|
|
3182
|
+
// 3. 把后端返回的和 schedule 的数据进行合并,确定每一天的可用和使用情况
|
|
3007
3183
|
let dates = [];
|
|
3008
|
-
let currentDate = (0,
|
|
3009
|
-
let firstAvailableDate =
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
)
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
);
|
|
3184
|
+
let currentDate = (0, _dayjs.default)(startDate);
|
|
3185
|
+
let firstAvailableDate = '';
|
|
3186
|
+
|
|
3187
|
+
// 预处理,获取商品下启用的资源类型,后面只需要遍历这些资源的资源列表即可
|
|
3188
|
+
const openResources = tempProducts?.product_resource?.resources?.filter(m => m.status === 1) || [];
|
|
3189
|
+
|
|
3190
|
+
// res.data 返回的一定是启用商品的资源列表,不需要再过滤了
|
|
3191
|
+
const allProductResources = (0, _lodashEs.cloneDeep)((0, _resources.sortCombinedResources)(res.data) || []);
|
|
3192
|
+
// allProductResources 需要根据商品里的资源的单个预约多个预约补充resourceType
|
|
3193
|
+
allProductResources.forEach(m => {
|
|
3194
|
+
const resource = tempProducts?.product_resource?.resources?.find(n => n.id === m.form_id);
|
|
3019
3195
|
if (resource) {
|
|
3020
3196
|
m.resourceType = resource.type;
|
|
3021
3197
|
}
|
|
3022
3198
|
});
|
|
3023
|
-
const targetSchedules = this.store.schedule.getScheduleListByIds(
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
const currentDateStr = currentDate.format("YYYY-MM-DD");
|
|
3028
|
-
let status = "available";
|
|
3199
|
+
const targetSchedules = this.store.schedule.getScheduleListByIds(tempProducts['schedule.ids']);
|
|
3200
|
+
while ((0, _dayjs.default)(currentDate).isBefore((0, _dayjs.default)(endDate), 'day') || (0, _dayjs.default)(currentDate).isSame((0, _dayjs.default)(endDate), 'day')) {
|
|
3201
|
+
const currentDateStr = currentDate.format('YYYY-MM-DD');
|
|
3202
|
+
let status = 'available';
|
|
3029
3203
|
let summaryCount = 0;
|
|
3030
3204
|
let availableCount = 0;
|
|
3031
|
-
|
|
3205
|
+
// 1. 检查商品的提前量等情况是否满足
|
|
3206
|
+
const {
|
|
3207
|
+
latestStartDate,
|
|
3208
|
+
earliestEndDate
|
|
3209
|
+
} = (0, _resources.checkSessionProductLeadTime)(tempProducts);
|
|
3032
3210
|
if (latestStartDate || earliestEndDate) {
|
|
3033
|
-
|
|
3034
|
-
|
|
3211
|
+
// 如果时间在最早开始时间之前,则设置为不可用
|
|
3212
|
+
if (latestStartDate && (0, _dayjs.default)(currentDate).isBefore(latestStartDate, 'day')) {
|
|
3213
|
+
status = 'unavailable';
|
|
3035
3214
|
}
|
|
3036
|
-
|
|
3037
|
-
|
|
3215
|
+
// 如果时间在最早结束时间之后,则设置为不可用
|
|
3216
|
+
if (earliestEndDate && (0, _dayjs.default)(currentDate).isAfter(earliestEndDate, 'day')) {
|
|
3217
|
+
status = 'unavailable';
|
|
3038
3218
|
}
|
|
3039
3219
|
}
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
)
|
|
3044
|
-
|
|
3045
|
-
status = "unavailable";
|
|
3220
|
+
// 2. 检查 schedule 数据,确定 schedule 里没有这一天,或者这一天的isExcluded: true ,则不可用
|
|
3221
|
+
if (status === 'available') {
|
|
3222
|
+
const scheduleByDate = filteredSchedule.find(n => n.date === currentDateStr);
|
|
3223
|
+
if (!scheduleByDate || scheduleByDate?.isExcluded) {
|
|
3224
|
+
status = 'unavailable';
|
|
3046
3225
|
}
|
|
3047
3226
|
}
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
const scheduleTimeSlots = (0, import_utils3.getAllSortedDateRanges)(minTimeMaxTime);
|
|
3227
|
+
|
|
3228
|
+
// 3. 检查这一天的 schedule 时间片里资源是否有可用的,每个时间片下每种资源只需找到第一个可用的即可
|
|
3229
|
+
if (status === 'available') {
|
|
3230
|
+
const minTimeMaxTime = (0, _utils3.calcMinTimeMaxTimeBySchedules)(targetSchedules, {}, currentDateStr);
|
|
3231
|
+
const scheduleTimeSlots = (0, _utils3.getAllSortedDateRanges)(minTimeMaxTime);
|
|
3232
|
+
// 同一天内多个时间片下 只要有一个可用则视为可用
|
|
3055
3233
|
let timesSlotCanUse = false;
|
|
3056
|
-
scheduleTimeSlots.forEach(
|
|
3234
|
+
scheduleTimeSlots.forEach(item => {
|
|
3235
|
+
// 用来计算资源的可使用情况,针对单个schedule 时间片
|
|
3057
3236
|
const resourcesUseableMap = {};
|
|
3237
|
+
// 遍历产品下启用的资源
|
|
3238
|
+
// 必须要保证每种类型的资源都至少有一个能够在对应时间点被选择
|
|
3239
|
+
// 求出第一个资源的剩余量和总量
|
|
3240
|
+
// 剩余量=每个资源在每个时间片内剩余之和
|
|
3241
|
+
// 总量=每个资源在每个时间片内资源总量之和
|
|
3058
3242
|
let isAllResourceTypesUseable = true;
|
|
3059
|
-
openResources.forEach(
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
);
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3243
|
+
openResources.forEach(resource => {
|
|
3244
|
+
// if (!isAllResourceTypesUseable) return;
|
|
3245
|
+
|
|
3246
|
+
// 获取当前资源类型的资源列表
|
|
3247
|
+
const currentResourcesList = allProductResources.filter(n => n.form_id === resource.resource_type_id);
|
|
3248
|
+
// 如果resource.renderList里含有 onlyComputed 的数据,需要把 currentResourcesList 的数据也修正回来
|
|
3249
|
+
resource.renderList?.forEach(item => {
|
|
3250
|
+
if (item.onlyComputed) {
|
|
3251
|
+
const targetIndex = currentResourcesList.findIndex(n => n.id === item.id);
|
|
3067
3252
|
if (targetIndex && targetIndex !== -1) {
|
|
3068
3253
|
currentResourcesList[targetIndex].onlyComputed = true;
|
|
3069
3254
|
}
|
|
3070
3255
|
}
|
|
3071
3256
|
});
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
if (!
|
|
3075
|
-
|
|
3257
|
+
// 可能存在 renderList 没有的情况,则需要判断 resource.optional_resource 和 resource.default_resource 是否存在那个资源,如果不存在也打上 onlyComputed 的标记
|
|
3258
|
+
currentResourcesList.forEach(item => {
|
|
3259
|
+
if (!resource.optional_resource?.includes(item.id) && !resource.default_resource?.includes(item.id)) {
|
|
3260
|
+
item.onlyComputed = true;
|
|
3076
3261
|
}
|
|
3077
3262
|
});
|
|
3263
|
+
// currentResourcesList 排序,onlyComputed 的资源排在前面先计算
|
|
3078
3264
|
currentResourcesList.sort((a, b) => {
|
|
3079
3265
|
return a.onlyComputed ? -1 : 1;
|
|
3080
3266
|
});
|
|
3081
3267
|
let isAnyResourceUseableInType = false;
|
|
3082
|
-
currentResourcesList
|
|
3083
|
-
|
|
3084
|
-
|
|
3268
|
+
currentResourcesList?.forEach(m => {
|
|
3269
|
+
// 遍历所有资源的上工时间片
|
|
3270
|
+
// m.times 需要做个过滤,假设 timeSlice.start_at 是 09:30 timeSlice.end_at 是 11:30
|
|
3271
|
+
// time 是 time.start_at = 2025-05-26 10:30, time.end_at = 2025-05-26 12:30
|
|
3272
|
+
// 需要判断 time 的开始结束时间 是否包含timeSlice的开始结束时间
|
|
3273
|
+
const mTimes = m.times.filter(n => {
|
|
3274
|
+
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');
|
|
3085
3275
|
});
|
|
3086
|
-
|
|
3087
|
-
|
|
3276
|
+
|
|
3277
|
+
// 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
|
|
3278
|
+
if (mTimes.length === 0) return;
|
|
3279
|
+
// 如果资源可用则把他的容量纳入总计
|
|
3088
3280
|
if (!m.onlyComputed) {
|
|
3089
|
-
if (resource.type ===
|
|
3281
|
+
if (resource.type === 'multiple') {
|
|
3090
3282
|
summaryCount += m.capacity;
|
|
3091
3283
|
} else {
|
|
3092
3284
|
summaryCount += 1;
|
|
3093
3285
|
}
|
|
3094
3286
|
}
|
|
3095
3287
|
let isAnyTimeSliceUseable = false;
|
|
3096
|
-
mTimes.forEach(
|
|
3097
|
-
if (isAnyTimeSliceUseable)
|
|
3098
|
-
|
|
3099
|
-
|
|
3288
|
+
mTimes.forEach(childTiem => {
|
|
3289
|
+
if (isAnyTimeSliceUseable) return;
|
|
3290
|
+
|
|
3291
|
+
// 挨个去匹配某个工作时间段结合当前日程时间,资源能不能用,有多少容量能用
|
|
3292
|
+
const res = (0, _resources.getIsUsableByTimeItem)({
|
|
3100
3293
|
timeSlice: {
|
|
3101
3294
|
start_time: item.start,
|
|
3102
3295
|
end_time: item.end,
|
|
3103
|
-
start_at: (0,
|
|
3104
|
-
end_at: (0,
|
|
3296
|
+
start_at: (0, _dayjs.default)(item.start),
|
|
3297
|
+
end_at: (0, _dayjs.default)(item.end)
|
|
3105
3298
|
},
|
|
3106
3299
|
time: childTiem,
|
|
3107
3300
|
resource: m,
|
|
3108
3301
|
currentCount: 1,
|
|
3109
3302
|
resourcesUseableMap,
|
|
3110
|
-
cut_off_time: tempProducts
|
|
3303
|
+
cut_off_time: tempProducts?.cut_off_time
|
|
3111
3304
|
});
|
|
3112
|
-
if (
|
|
3113
|
-
resourcesUseableMap[m.id] =
|
|
3305
|
+
if (resourcesUseableMap?.[m.id] !== false && res.reason !== 'capacityOnly') {
|
|
3306
|
+
resourcesUseableMap[m.id] = res.usable;
|
|
3114
3307
|
}
|
|
3115
|
-
if (
|
|
3308
|
+
if (res.usable && !m.onlyComputed) {
|
|
3116
3309
|
isAnyTimeSliceUseable = true;
|
|
3117
|
-
if (resource.type ===
|
|
3118
|
-
availableCount +=
|
|
3310
|
+
if (resource.type === 'multiple') {
|
|
3311
|
+
availableCount += res.remainingCapacity;
|
|
3119
3312
|
} else {
|
|
3120
3313
|
availableCount += 1;
|
|
3121
3314
|
}
|
|
3122
3315
|
}
|
|
3123
3316
|
;
|
|
3124
3317
|
});
|
|
3125
|
-
if (isAnyTimeSliceUseable)
|
|
3126
|
-
isAnyResourceUseableInType = true;
|
|
3318
|
+
if (isAnyTimeSliceUseable) isAnyResourceUseableInType = true;
|
|
3127
3319
|
});
|
|
3128
|
-
if (!isAnyResourceUseableInType)
|
|
3129
|
-
isAllResourceTypesUseable = false;
|
|
3320
|
+
if (!isAnyResourceUseableInType) isAllResourceTypesUseable = false;
|
|
3130
3321
|
});
|
|
3131
|
-
if (isAllResourceTypesUseable)
|
|
3132
|
-
timesSlotCanUse = true;
|
|
3322
|
+
if (isAllResourceTypesUseable) timesSlotCanUse = true;
|
|
3133
3323
|
});
|
|
3134
3324
|
if (!timesSlotCanUse) {
|
|
3135
|
-
status =
|
|
3325
|
+
status = 'unavailable';
|
|
3136
3326
|
}
|
|
3137
|
-
if (status ===
|
|
3327
|
+
if (status === 'available' && !firstAvailableDate) {
|
|
3138
3328
|
firstAvailableDate = currentDateStr;
|
|
3139
3329
|
}
|
|
3140
3330
|
}
|
|
3331
|
+
// 状态: lots_of_space: availableCount / summaryCount > 0.5
|
|
3332
|
+
// filling_up_fast: availableCount / summaryCount <= 0.5 && availableCount > 0
|
|
3333
|
+
// sold_out: summaryCount = 0
|
|
3334
|
+
// unavailable: summaryCount > 0 && availableCount = 0
|
|
3141
3335
|
let dateStatus;
|
|
3142
|
-
if (status ===
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
else
|
|
3146
|
-
dateStatus = "unavailable";
|
|
3336
|
+
if (status === 'unavailable') {
|
|
3337
|
+
// dateStatus = 'unavailable'
|
|
3338
|
+
if (availableCount === 0 && summaryCount > 0) dateStatus = 'sold_out';else dateStatus = 'unavailable';
|
|
3147
3339
|
} else {
|
|
3148
3340
|
const usageRatio = availableCount / summaryCount;
|
|
3149
|
-
if (usageRatio > 0.5)
|
|
3150
|
-
dateStatus = "lots_of_space";
|
|
3151
|
-
else
|
|
3152
|
-
dateStatus = "filling_up_fast";
|
|
3341
|
+
if (usageRatio > 0.5) dateStatus = 'lots_of_space';else dateStatus = 'filling_up_fast';
|
|
3153
3342
|
}
|
|
3154
3343
|
dates.push({
|
|
3155
|
-
date: (0,
|
|
3156
|
-
week: (0,
|
|
3157
|
-
weekNum: (0,
|
|
3344
|
+
date: (0, _dayjs.default)(currentDate).format('YYYY-MM-DD'),
|
|
3345
|
+
week: (0, _dayjs.default)(currentDate).format('ddd'),
|
|
3346
|
+
weekNum: (0, _dayjs.default)(currentDate).day(),
|
|
3158
3347
|
summaryCount,
|
|
3159
3348
|
availableCount,
|
|
3160
3349
|
status: dateStatus
|
|
3161
3350
|
});
|
|
3162
|
-
|
|
3351
|
+
|
|
3352
|
+
// 如果 firstAvailableDate 距离 startDate 大于 14 天了,则后面就不需要再找了,也是一种性能保护
|
|
3353
|
+
if (firstAvailableDate && (0, _dayjs.default)(currentDate).diff((0, _dayjs.default)(startDate), 'day') > 31) {
|
|
3163
3354
|
break;
|
|
3164
3355
|
}
|
|
3165
|
-
currentDate = (0,
|
|
3356
|
+
currentDate = (0, _dayjs.default)(currentDate).add(1, 'day');
|
|
3166
3357
|
}
|
|
3167
|
-
|
|
3358
|
+
// 最终把资源数据也加到日期内
|
|
3359
|
+
dates = (0, _utils4.handleAvailableDateByResource)(res.data, dates);
|
|
3168
3360
|
this.store.date.setDateList(dates);
|
|
3169
|
-
|
|
3170
|
-
|
|
3361
|
+
|
|
3362
|
+
// 缓存这次结果,以防后面他小幅度范围内去修改天数
|
|
3363
|
+
if (!this.store.currentProductMeta) this.store.currentProductMeta = {};
|
|
3171
3364
|
this.store.currentProductMeta.timeSlotBySchedule = {
|
|
3172
3365
|
dateList: dates,
|
|
3173
3366
|
firstAvailableDate,
|
|
3174
3367
|
startDate,
|
|
3175
|
-
endDate: (0,
|
|
3368
|
+
endDate: (0, _dayjs.default)(currentDate).format('YYYY-MM-DD')
|
|
3176
3369
|
};
|
|
3177
3370
|
return {
|
|
3178
3371
|
dateList: dates,
|
|
@@ -3180,33 +3373,27 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
3180
3373
|
};
|
|
3181
3374
|
}
|
|
3182
3375
|
isCartAllNormalProducts() {
|
|
3183
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
3376
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
3184
3377
|
return !cartItems.length;
|
|
3185
3378
|
}
|
|
3186
3379
|
isCartHasDurationProduct() {
|
|
3187
|
-
const cartItems = this.store.cart.getItems().filter(
|
|
3188
|
-
return cartItems.some(
|
|
3189
|
-
var _a;
|
|
3190
|
-
return (_a = n._productOrigin) == null ? void 0 : _a.duration;
|
|
3191
|
-
});
|
|
3380
|
+
const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
|
|
3381
|
+
return cartItems.some(n => n._productOrigin?.duration);
|
|
3192
3382
|
}
|
|
3193
3383
|
isTargetNormalProduct(product) {
|
|
3194
|
-
if (!product)
|
|
3195
|
-
|
|
3196
|
-
return (0, import_utils5.isNormalProduct)(product);
|
|
3384
|
+
if (!product) return false;
|
|
3385
|
+
return (0, _utils5.isNormalProduct)(product);
|
|
3197
3386
|
}
|
|
3198
3387
|
isTargetCartIdNormalProduct(id) {
|
|
3199
|
-
const cartItem = this.store.cart.getItems().find(
|
|
3200
|
-
return cartItem && (0,
|
|
3388
|
+
const cartItem = this.store.cart.getItems().find(n => n._id === id);
|
|
3389
|
+
return cartItem && (0, _utils5.isNormalProduct)(cartItem._productOrigin);
|
|
3201
3390
|
}
|
|
3391
|
+
|
|
3202
3392
|
/**
|
|
3203
3393
|
* 获取联系信息
|
|
3204
3394
|
*/
|
|
3205
3395
|
async getContactInfo(params) {
|
|
3206
|
-
return this.request.get(
|
|
3396
|
+
return this.request.get('/customer/metadata', params);
|
|
3207
3397
|
}
|
|
3208
|
-
}
|
|
3209
|
-
|
|
3210
|
-
0 && (module.exports = {
|
|
3211
|
-
BookingByStepImpl
|
|
3212
|
-
});
|
|
3398
|
+
}
|
|
3399
|
+
exports.BookingByStepImpl = BookingByStepImpl;
|