@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.
Files changed (228) hide show
  1. package/dist/core/index.js +6 -9
  2. package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -2
  3. package/dist/model/strategy/adapter/walletPass/example.js +3 -26
  4. package/dist/model/strategy/adapter/walletPass/utils.js +0 -3
  5. package/dist/model/strategy/strategy-example.js +5 -19
  6. package/dist/modules/Cart/index.js +0 -3
  7. package/dist/modules/Cart/utils/cartProduct.js +0 -1
  8. package/dist/modules/Date/index.js +1 -5
  9. package/dist/modules/Discount/index.js +1 -4
  10. package/dist/modules/OpenData/index.js +0 -2
  11. package/dist/modules/Order/index.d.ts +1 -1
  12. package/dist/modules/Order/index.js +14 -41
  13. package/dist/modules/Payment/index.js +142 -270
  14. package/dist/modules/Payment/walletpass.js +4 -5
  15. package/dist/modules/Rules/index.js +0 -7
  16. package/dist/modules/Schedule/utils.js +0 -1
  17. package/dist/modules/Step/index.js +0 -1
  18. package/dist/plugins/request.js +1 -4
  19. package/dist/plugins/window.js +2 -6
  20. package/dist/server/index.js +88 -121
  21. package/dist/server/modules/menu/index.js +32 -41
  22. package/dist/server/modules/products/index.js +29 -49
  23. package/dist/server/modules/quotation/index.js +29 -38
  24. package/dist/server/modules/resource/index.js +3 -4
  25. package/dist/server/modules/schedule/index.js +32 -40
  26. package/dist/server/utils/product.js +0 -1
  27. package/dist/solution/BookingByStep/index.d.ts +1 -1
  28. package/dist/solution/BookingByStep/index.js +7 -59
  29. package/dist/solution/BookingByStep/utils/capacity.js +1 -11
  30. package/dist/solution/BookingByStep/utils/resources.js +1 -3
  31. package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
  32. package/dist/solution/BookingTicket/index.d.ts +1 -1
  33. package/dist/solution/BookingTicket/index.js +5 -7
  34. package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
  35. package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
  36. package/dist/solution/BuyTickets/index.js +9 -12
  37. package/dist/solution/Checkout/index.js +177 -246
  38. package/dist/solution/Checkout/utils/index.js +4 -16
  39. package/dist/solution/RegisterAndLogin/index.js +30 -76
  40. package/dist/solution/ScanOrder/index.js +50 -60
  41. package/dist/solution/ShopDiscount/index.js +2 -7
  42. package/dist/solution/VenueBooking/index.d.ts +5 -0
  43. package/dist/solution/VenueBooking/index.js +364 -327
  44. package/dist/utils/task.js +15 -18
  45. package/dist/utils/watch.js +0 -1
  46. package/lib/apis/picoding.js +2 -0
  47. package/lib/core/index.js +130 -131
  48. package/lib/effects/index.js +46 -57
  49. package/lib/index.js +92 -53
  50. package/lib/model/index.js +14 -21
  51. package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
  52. package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
  53. package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
  54. package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
  55. package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
  56. package/lib/model/strategy/adapter/index.js +100 -64
  57. package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
  58. package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
  59. package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
  60. package/lib/model/strategy/adapter/itemRule/index.js +83 -57
  61. package/lib/model/strategy/adapter/itemRule/type.js +97 -36
  62. package/lib/model/strategy/adapter/promotion/adapter.js +84 -63
  63. package/lib/model/strategy/adapter/promotion/evaluator.js +381 -231
  64. package/lib/model/strategy/adapter/promotion/examples.js +139 -159
  65. package/lib/model/strategy/adapter/promotion/index.js +1 -49
  66. package/lib/model/strategy/adapter/promotion/type.js +199 -35
  67. package/lib/model/strategy/adapter/type.js +4 -16
  68. package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -152
  69. package/lib/model/strategy/adapter/walletPass/example.js +217 -190
  70. package/lib/model/strategy/adapter/walletPass/index.js +75 -51
  71. package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
  72. package/lib/model/strategy/adapter/walletPass/type.js +4 -16
  73. package/lib/model/strategy/adapter/walletPass/utils.js +652 -402
  74. package/lib/model/strategy/engine.js +270 -168
  75. package/lib/model/strategy/index.js +49 -34
  76. package/lib/model/strategy/strategy-example.js +243 -239
  77. package/lib/model/strategy/type.js +100 -40
  78. package/lib/modules/Account/index.js +39 -53
  79. package/lib/modules/Account/types.js +20 -33
  80. package/lib/modules/AccountList/index.js +116 -154
  81. package/lib/modules/AccountList/types.js +30 -31
  82. package/lib/modules/AccountList/utils.js +18 -30
  83. package/lib/modules/BaseModule.js +22 -45
  84. package/lib/modules/Cart/index.js +170 -124
  85. package/lib/modules/Cart/types.js +46 -51
  86. package/lib/modules/Cart/utils/cartAccount.js +40 -39
  87. package/lib/modules/Cart/utils/cartDate.js +56 -61
  88. package/lib/modules/Cart/utils/cartDiscount.js +28 -33
  89. package/lib/modules/Cart/utils/cartNote.js +27 -32
  90. package/lib/modules/Cart/utils/cartProduct.js +306 -241
  91. package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
  92. package/lib/modules/Cart/utils/cartResource.js +72 -78
  93. package/lib/modules/Cart/utils/changePrice.js +26 -62
  94. package/lib/modules/Cart/utils/index.js +106 -48
  95. package/lib/modules/Customer/constants.js +13 -34
  96. package/lib/modules/Customer/index.js +216 -153
  97. package/lib/modules/Customer/types.js +38 -35
  98. package/lib/modules/Date/index.js +116 -115
  99. package/lib/modules/Date/types.js +16 -28
  100. package/lib/modules/Date/utils.js +174 -123
  101. package/lib/modules/Discount/index.js +117 -113
  102. package/lib/modules/Discount/types.js +9 -31
  103. package/lib/modules/Guests/index.js +30 -56
  104. package/lib/modules/Guests/types.js +23 -33
  105. package/lib/modules/Holder/index.js +209 -189
  106. package/lib/modules/Holder/types.js +4 -16
  107. package/lib/modules/Holder/utils.js +20 -49
  108. package/lib/modules/OpenData/index.js +63 -74
  109. package/lib/modules/OpenData/types.js +4 -16
  110. package/lib/modules/OpenData/utils.js +44 -78
  111. package/lib/modules/Order/index.d.ts +1 -1
  112. package/lib/modules/Order/index.js +332 -320
  113. package/lib/modules/Order/types.js +24 -33
  114. package/lib/modules/Order/utils.js +350 -284
  115. package/lib/modules/Payment/cash.js +20 -33
  116. package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
  117. package/lib/modules/Payment/eftpos.js +16 -30
  118. package/lib/modules/Payment/index.js +566 -432
  119. package/lib/modules/Payment/mx51.js +1 -0
  120. package/lib/modules/Payment/types.js +216 -107
  121. package/lib/modules/Payment/utils.js +50 -47
  122. package/lib/modules/Payment/walletpass.js +221 -203
  123. package/lib/modules/Product/index.js +51 -46
  124. package/lib/modules/Product/types.js +4 -16
  125. package/lib/modules/Product/utils.js +32 -33
  126. package/lib/modules/ProductList/index.js +111 -110
  127. package/lib/modules/ProductList/types.js +9 -31
  128. package/lib/modules/Quotation/index.js +60 -82
  129. package/lib/modules/Quotation/types.js +4 -16
  130. package/lib/modules/Resource/index.js +27 -59
  131. package/lib/modules/Resource/types.js +22 -32
  132. package/lib/modules/Resource/utils.js +30 -38
  133. package/lib/modules/Rules/index.js +1172 -872
  134. package/lib/modules/Rules/types.js +17 -40
  135. package/lib/modules/SalesSummary/index.js +59 -68
  136. package/lib/modules/SalesSummary/types.js +4 -16
  137. package/lib/modules/SalesSummary/utils.js +176 -193
  138. package/lib/modules/ScanOrderLogger/index.js +59 -79
  139. package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
  140. package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
  141. package/lib/modules/ScanOrderLogger/types.js +4 -16
  142. package/lib/modules/Schedule/getDateIsInSchedule.js +334 -167
  143. package/lib/modules/Schedule/index.js +97 -107
  144. package/lib/modules/Schedule/type.js +4 -16
  145. package/lib/modules/Schedule/types.js +4 -16
  146. package/lib/modules/Schedule/utils.js +433 -291
  147. package/lib/modules/Step/index.js +40 -52
  148. package/lib/modules/Step/tyeps.js +4 -16
  149. package/lib/modules/Summary/index.js +66 -70
  150. package/lib/modules/Summary/types.js +4 -16
  151. package/lib/modules/Summary/utils.js +782 -429
  152. package/lib/modules/index.js +212 -57
  153. package/lib/plugins/app.js +4 -16
  154. package/lib/plugins/index.js +36 -25
  155. package/lib/plugins/request.js +137 -126
  156. package/lib/plugins/shopStore.js +4 -16
  157. package/lib/plugins/user.js +4 -16
  158. package/lib/plugins/window.js +171 -179
  159. package/lib/server/index.js +882 -623
  160. package/lib/server/modules/index.js +85 -59
  161. package/lib/server/modules/menu/index.js +146 -122
  162. package/lib/server/modules/menu/types.js +18 -31
  163. package/lib/server/modules/order/index.js +195 -231
  164. package/lib/server/modules/order/types.js +107 -32
  165. package/lib/server/modules/order/utils/filterBookings.js +174 -140
  166. package/lib/server/modules/order/utils/filterOrders.js +89 -60
  167. package/lib/server/modules/products/index.js +430 -335
  168. package/lib/server/modules/products/types.js +41 -34
  169. package/lib/server/modules/quotation/index.js +76 -77
  170. package/lib/server/modules/quotation/types.js +21 -31
  171. package/lib/server/modules/resource/index.js +216 -187
  172. package/lib/server/modules/resource/types.js +42 -33
  173. package/lib/server/modules/schedule/index.js +134 -119
  174. package/lib/server/modules/schedule/types.js +14 -21
  175. package/lib/server/modules/schedule/utils.js +334 -163
  176. package/lib/server/types.js +4 -16
  177. package/lib/server/utils/index.js +25 -23
  178. package/lib/server/utils/product.js +196 -139
  179. package/lib/server/utils/schedule.js +34 -41
  180. package/lib/server/utils/time.js +40 -49
  181. package/lib/solution/BookingByStep/index.d.ts +1 -1
  182. package/lib/solution/BookingByStep/index.js +1530 -1343
  183. package/lib/solution/BookingByStep/types.js +40 -99
  184. package/lib/solution/BookingByStep/utils/capacity.js +192 -160
  185. package/lib/solution/BookingByStep/utils/products.js +42 -52
  186. package/lib/solution/BookingByStep/utils/resources.js +527 -330
  187. package/lib/solution/BookingByStep/utils/stock.js +65 -44
  188. package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
  189. package/lib/solution/BookingTicket/index.d.ts +1 -1
  190. package/lib/solution/BookingTicket/index.js +147 -122
  191. package/lib/solution/BookingTicket/types.js +38 -64
  192. package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +64 -80
  193. package/lib/solution/BookingTicket/utils/scan/handleScan.js +82 -80
  194. package/lib/solution/BookingTicket/utils/scan/index.js +90 -94
  195. package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
  196. package/lib/solution/BuyTickets/index.js +67 -70
  197. package/lib/solution/BuyTickets/types.js +22 -38
  198. package/lib/solution/Checkout/index.js +1451 -1158
  199. package/lib/solution/Checkout/types.js +91 -61
  200. package/lib/solution/Checkout/utils/index.js +227 -158
  201. package/lib/solution/PlaceOrder/index.js +55 -0
  202. package/lib/solution/RegisterAndLogin/config.js +493 -460
  203. package/lib/solution/RegisterAndLogin/index.js +633 -630
  204. package/lib/solution/RegisterAndLogin/types.js +189 -76
  205. package/lib/solution/RegisterAndLogin/utils.js +183 -125
  206. package/lib/solution/Sales/index.js +218 -200
  207. package/lib/solution/Sales/types.js +27 -33
  208. package/lib/solution/ScanOrder/index.js +803 -840
  209. package/lib/solution/ScanOrder/types.js +34 -34
  210. package/lib/solution/ScanOrder/utils.js +372 -331
  211. package/lib/solution/ShopDiscount/index.js +230 -236
  212. package/lib/solution/ShopDiscount/types.js +15 -37
  213. package/lib/solution/ShopDiscount/utils.js +309 -172
  214. package/lib/solution/VenueBooking/index.d.ts +5 -0
  215. package/lib/solution/VenueBooking/index.js +886 -929
  216. package/lib/solution/VenueBooking/types.js +20 -40
  217. package/lib/solution/VenueBooking/utils/dateSummary.js +22 -54
  218. package/lib/solution/VenueBooking/utils/resource.js +31 -54
  219. package/lib/solution/VenueBooking/utils/slotMerge.js +88 -106
  220. package/lib/solution/VenueBooking/utils/smartPricing.js +112 -100
  221. package/lib/solution/VenueBooking/utils/timeSlot.js +133 -132
  222. package/lib/solution/VenueBooking/utils.js +130 -67
  223. package/lib/solution/index.js +102 -37
  224. package/lib/store/createStore.js +32 -29
  225. package/lib/types/index.js +4 -16
  226. package/lib/utils/task.js +36 -36
  227. package/lib/utils/watch.js +81 -47
  228. package/package.json +2 -1
@@ -1,115 +1,84 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
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
- module.exports = __toCommonJS(BookingByStep_exports);
35
- var import_BaseModule = require("../../modules/BaseModule");
36
- var import_types = require("./types");
37
- var import_utils = require("../../modules/Cart/utils");
38
- var import_products = require("./utils/products");
39
- var import_resources = require("./utils/resources");
40
- var import_dayjs = __toESM(require("dayjs"));
41
- var import_isSameOrBefore = __toESM(require("dayjs/plugin/isSameOrBefore"));
42
- var import_isSameOrAfter = __toESM(require("dayjs/plugin/isSameOrAfter"));
43
- var import_utils2 = require("../../modules/Resource/utils");
44
- var import_lodash_es = require("lodash-es");
45
- var import_utils3 = require("../../modules/Schedule/utils");
46
- var import_utils4 = require("../../modules/Date/utils");
47
- var import_utils5 = require("../../modules/Product/utils");
48
- var import_timeslots = require("./utils/timeslots");
49
- var import_changePrice = require("../../modules/Cart/utils/changePrice");
50
- var import_capacity = require("./utils/capacity");
51
- var import_stock = require("./utils/stock");
52
- import_dayjs.default.extend(import_isSameOrBefore.default);
53
- import_dayjs.default.extend(import_isSameOrAfter.default);
54
- var BookingByStepImpl = class extends import_BaseModule.BaseModule {
55
- constructor() {
56
- super(...arguments);
57
- this.defaultName = "bookingByStep";
58
- this.defaultVersion = "1.0.0";
59
- this.isSolution = true;
60
- this.otherParams = {};
61
- this.otherData = {};
62
- }
63
- // 平台类型,用于判断是 PC / H5
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
- console.log("[BookingByStep] 初始化完成");
70
- this.request = core.getPlugin("request");
71
- this.window = core.getPlugin("window");
72
- this.shopStore = core.getPlugin("shopStore");
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("bookingByStep解决方案需要 request 插件支持");
49
+ throw new Error('bookingByStep解决方案需要 request 插件支持');
75
50
  }
76
51
  if (!this.shopStore) {
77
- throw new Error("SummaryModule 需要 shopStore 插件支持");
52
+ throw new Error('SummaryModule 需要 shopStore 插件支持');
78
53
  }
54
+
55
+ // 如果有传 cacheid,默认需要收集上面这些模块里用户操作选中的数据
56
+ // 并且在上面 registerModule 的时候,读取 sessionStroage 里的数据,塞进默认值
79
57
  let targetCacheData = {};
80
- this.cacheId = (_a = this.otherParams) == null ? void 0 : _a.cacheId;
81
- this.platform = (_b = this.otherParams) == null ? void 0 : _b.platform;
82
- if ((_c = this.otherParams) == null ? void 0 : _c.cacheId) {
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 = ((_e = (_d = data[this.otherParams.cacheId]) == null ? void 0 : _d[this.name]) == null ? void 0 : _e["otherData"]) || {};
67
+ this.otherData = data[this.otherParams.cacheId]?.[this.name]?.['otherData'] || {};
88
68
  }
89
69
  }
90
- const moduleArr = [
91
- "accountList",
92
- "holder",
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 == null ? void 0 : targetCacheData[targetModule.name],
76
+ initialState: targetCacheData?.[targetModule.name],
108
77
  otherParams: {
109
78
  ...this.otherParams,
110
79
  fatherModule: this.name,
111
- openCache: ((_a2 = this.otherParams) == null ? void 0 : _a2.cacheId) ? true : false,
112
- cacheId: (_b2 = this.otherParams) == null ? void 0 : _b2.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, import_dayjs.default)().format("YYYY-MM-DD"),
198
- endDate: schedule_date || (0, import_dayjs.default)().format("YYYY-MM-DD"),
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
- this.setDateRange([
226
- { date, status: "available", week: "", weekNum: 0 },
227
- { date, status: "available", week: "", weekNum: 0 }
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 schedule = scheduleList.find((n) => n.date === date);
231
- if (schedule && ((_a = schedule.product_ids) == null ? void 0 : _a.length)) {
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("user");
256
- let customer_id = void 0;
252
+ let userPlugin = this.core.getPlugin('user');
253
+ let customer_id = undefined;
257
254
  try {
258
- customer_id = (_a = userPlugin == null ? void 0 : userPlugin.get()) == null ? void 0 : _a.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((n) => n.id),
260
+ ids: cartItems.map(n => n.id),
264
261
  schedule_date: date,
265
262
  customer_id
266
263
  });
267
- await (0, import_changePrice.updateAllCartItemPrice)(
268
- cartItems,
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
- if ((extra == null ? void 0 : extra.type) === "holder") {
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: "unshift"
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
- if ((extra == null ? void 0 : extra.type) === "holder") {
313
+ // 如果是holder类型的需要先做数据转换
314
+ if (extra?.type === 'holder') {
324
315
  this.store.accountList.addHolderAccounts({
325
316
  holders: accounts,
326
317
  customerId: extra.customerId,
327
- type: "unshift"
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((account) => account.getAccount());
336
+ return accounts.map(account => account.getAccount());
347
337
  }
348
338
  checkHasLoginAccount() {
349
339
  const accounts = this.store.accountList.getAccounts();
350
- return accounts.some((account) => account.getLoginStatus());
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 == null ? void 0 : activeAccount.getAccount();
358
- return account === null ? void 0 : account;
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 = (_b = (_a = this.store.date.getDateRange()) == null ? void 0 : _a[0]) == null ? void 0 : _b.date;
363
+ let date = this.store.date.getDateRange()?.[0]?.date;
373
364
  if (!date) {
374
- const normalProductCartItem = cartItems.find(
375
- (n) => !(0, import_utils5.isNormalProduct)(n._productOrigin)
376
- );
377
- date = (normalProductCartItem == null ? void 0 : normalProductCartItem.start_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 == null ? void 0 : params.customer_id,
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
- var _a, _b, _c, _d;
424
- let { products, startDate, endDate, type, useCache = true } = params;
425
- if ((0, import_dayjs.default)(startDate).isBefore((0, import_dayjs.default)(), "day") && ((0, import_dayjs.default)(endDate).isAfter((0, import_dayjs.default)(), "day") || (0, import_dayjs.default)(endDate).isSame((0, import_dayjs.default)(), "day"))) {
426
- startDate = (0, import_dayjs.default)().format("YYYY-MM-DD");
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((p) => p._productOrigin);
433
+ let tempProducts = products || this.store.cart.getItems().map(p => p._productOrigin);
429
434
  if (tempProducts.length) {
430
- tempProducts.forEach((p) => {
431
- if (p == null ? void 0 : p["schedule.ids"]) {
432
- const scheduleData = this.getScheduleDataByIds(p["schedule.ids"]);
433
- p["_schedule"] = scheduleData;
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
- ...this.store.currentProduct,
441
- _schedule: (_a = this.store.currentProductMeta) == null ? void 0 : _a["schedule"]
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 || ((_b = dateRange == null ? void 0 : dateRange[0]) == null ? void 0 : _b.date);
447
- const tempEndDate = endDate || ((_c = dateRange == null ? void 0 : dateRange[1]) == null ? void 0 : _c.date) || ((_d = dateRange == null ? void 0 : dateRange[0]) == null ? void 0 : _d.date);
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
- const { resourceIds, rules, resourcesMap } = (0, import_products.getAvailableProductResources)(tempProducts) || {};
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((item) => {
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 = (_b = (_a = this.store.date.getDateRange()) == null ? void 0 : _a[0]) == null ? void 0 : _b.date;
517
+ let date = this.store.date.getDateRange()?.[0]?.date;
504
518
  if (!date) {
505
- const normalProductCartItem = cartItems.find(
506
- (n) => !(0, import_utils5.isNormalProduct)(n._productOrigin)
507
- );
508
- date = (normalProductCartItem == null ? void 0 : normalProductCartItem.start_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("[BookingByStep] 登录后刷新 holder 表单失败", 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, import_lodash_es.cloneDeep)(cartItems);
548
- newCartItems.forEach((item) => {
549
- var _a2;
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((n) => {
552
- const newResourcesItem = (0, import_lodash_es.cloneDeep)(n);
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 { ...newResourcesItem };
574
+ return {
575
+ ...newResourcesItem
576
+ };
557
577
  });
558
- const { currentCapacity, formatCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(item);
559
- if (!((_a2 = item._origin) == null ? void 0 : _a2.metadata)) {
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 ? "virtual" : "appointment_booking";
567
- if ((0, import_utils5.areAllNormalProducts)(
568
- newCartItems.map((n) => n._productOrigin)
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: (_a = this.otherParams) == null ? void 0 : _a.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
- async setOtherParams(params, { cover = false } = {}) {
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 = { ...this.otherParams, ...params };
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 = { ...origin, product_variant_id };
641
- if ((0, import_products.isSessionProduct)(productData)) {
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 { success: false, errorCode: "date_or_time_required" };
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, import_stock.checkProductStock)({
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: (productData == null ? void 0 : productData.shop_id) || "",
708
+ shop_id: productData?.shop_id || '',
667
709
  useCache: true
668
710
  });
669
711
  } catch (error) {
670
- console.error("[BookingByStep] 加载 holder 表单失败", 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 || void 0
717
+ account: account || undefined
676
718
  });
677
719
  if (flag) {
678
- return { success: true };
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({ date });
693
- if (addItemParams.quantity > 1 && !(0, import_utils5.isNormalProduct)(productData)) {
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, import_lodash_es.cloneDeep)(addItemParams);
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 { success: true };
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((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
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((n) => {
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 { currentCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(targetCartItem);
728
- params.resources = params.resources.map((n) => {
784
+ const {
785
+ currentCapacity
786
+ } = (0, _capacity.getCapacityInfoByCartItem)(targetCartItem);
787
+ params.resources = params.resources.map(n => {
729
788
  n.capacity = currentCapacity || 1;
730
- (0, import_capacity.checkSubResourcesCapacity)(n);
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
- var _a;
815
+ // 零售模板不需要检测
755
816
  if (this.otherParams.isRetailTemplate) {
756
817
  return;
757
818
  }
758
819
  let currentResourcesCapacityMap = {};
759
- (_a = params.resources) == null ? void 0 : _a.forEach((n) => {
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 == null ? void 0 : dateRange.length) {
765
- dateRange.forEach((n) => {
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 == null ? void 0 : dateList.forEach((n) => {
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((item) => {
780
- var _a2;
841
+ cartItems.forEach(item => {
781
842
  if (item._id !== targetCartItem._id) {
782
- const { currentCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(item);
783
- const resources = (_a2 = item._origin.resources) == null ? void 0 : _a2.filter((m) => {
784
- const sameFormIdResources = (0, import_resources.filterResourcesByFormItem)(
785
- targetCartItem._origin.resources,
786
- m.form_id
787
- );
788
- if (!(sameFormIdResources == null ? void 0 : sameFormIdResources.length)) {
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((targetRes) => {
792
- if (targetRes.resourceType !== "single") {
793
- const originResource = allOriginResources.find(
794
- (n) => n.id === targetRes.id
795
- );
796
- const canUse = (0, import_capacity.checkResourceCanUseByCapacity)(
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 !== (targetCartItem == null ? void 0 : targetCartItem.holder_id)) {
806
- return (0, import_resources.checkTwoResourcesIntersection)(targetRes, m);
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, import_dayjs.default)(`${start_date} ${start_time}`).format(
821
- "YYYY-MM-DD HH:mm"
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((params) => {
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
- const cartItems = this.store.cart.getItems().filter((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
935
+ // 预约流程中普通商品无需检测这些东西
936
+ const cartItems = this.store.cart.getItems().filter(n => !(0, _utils5.isNormalProduct)(n._productOrigin));
877
937
  const errorCartItemIds = [];
878
- cartItems.forEach((cartItem) => {
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
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
888
- (_a = this.store.cart) == null ? void 0 : _a.destroy();
889
- (_b = this.store.step) == null ? void 0 : _b.destroy();
890
- (_c = this.store.products) == null ? void 0 : _c.destroy();
891
- (_d = this.store.guests) == null ? void 0 : _d.destroy();
892
- (_e = this.store.date) == null ? void 0 : _e.destroy();
893
- (_f = this.store.accountList) == null ? void 0 : _f.destroy();
894
- (_g = this.store.schedule) == null ? void 0 : _g.destroy();
895
- (_h = this.store.summary) == null ? void 0 : _h.destroy();
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 == null ? void 0 : dateRange.length) {
905
- dateRange.forEach((n) => {
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((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
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
- const firstDateCartItem = cartItems == null ? void 0 : cartItems.find((n) => n.start_date);
913
- if (firstDateCartItem == null ? void 0 : firstDateCartItem.start_date) {
914
- const dateResources = this.store.date.getResourcesListByDate(
915
- firstDateCartItem.start_date
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 == null ? void 0 : dateList.forEach((n) => {
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, import_utils2.getResourcesMap)((0, import_lodash_es.cloneDeep)(resources));
985
+ const resourcesMap = (0, _utils2.getResourcesMap)((0, _lodashEs.cloneDeep)(resources));
927
986
  const arr = [];
928
- cartItems.forEach((cartItem) => {
929
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
987
+ cartItems.forEach(cartItem => {
930
988
  let selectedResources = [];
931
- const { currentCapacity, formatCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(cartItem);
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, import_resources.getOthersSelectedResources)(
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, import_resources.getOthersCartSelectedResources)(
941
- cartItems,
942
- cartItem._id,
943
- resourcesMap
944
- );
997
+ selectedResources = (0, _resources.getOthersCartSelectedResources)(cartItems, cartItem._id, resourcesMap);
945
998
  }
946
- const productResources = (0, import_resources.getResourcesByProduct)(
947
- resourcesMap,
948
- ((_b = (_a = cartItem._productOrigin) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) || [],
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, import_dayjs.default)(
954
- `${cartItem._origin.start_date} ${cartItem._origin.start_time}`
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((n) => {
961
- n.renderList = (0, import_resources.sortCombinedResources)(n.renderList);
962
- n.renderList = n.renderList.filter((m) => {
963
- const mTimes = (0, import_timeslots.filterConditionTimeSlots)(
964
- m.times,
965
- startTime,
966
- endTime
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((item) => {
972
- var _a2;
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("HH:mm"),
976
- end_time: endTime.format("HH:mm"),
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: (_a2 = cartItem._productOrigin) == null ? void 0 : _a2.cut_off_time
1029
+ resourcesUseableMap: resourcesUseableMap,
1030
+ cut_off_time: cartItem._productOrigin?.cut_off_time
985
1031
  });
986
- if ((resourcesUseableMap == null ? void 0 : resourcesUseableMap[m.id]) !== false && res.reason !== "capacityOnly") {
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
- return false;
993
- return !canUseArr.some((n2) => n2 === false);
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 = ((_d = (_c = cartItem._productOrigin) == null ? void 0 : _c.duration) == null ? void 0 : _d.type) === "flexible";
998
- const operating_day_boundary = (_f = (_e = this.shopStore.get("core")) == null ? void 0 : _e.core) == null ? void 0 : _f.operating_day_boundary;
999
- const maxBlockThreshold = ((_i = (_h = (_g = cartItem._productOrigin) == null ? void 0 : _g.duration) == null ? void 0 : _h.flexible_config) == null ? void 0 : _i.is_enable_minimum_duration) ? ((_l = (_k = (_j = cartItem._productOrigin) == null ? void 0 : _j.duration) == null ? void 0 : _k.flexible_config) == null ? void 0 : _l.block_threshold) || 0 : 0;
1000
- productResources.forEach((item) => {
1001
- item.renderList = item.renderList.filter((n) => {
1002
- var _a2, _b2, _c2;
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
- return false;
1006
- const timeSlots = (0, import_resources.getTimeSlicesByResource)({
1052
+ if (n.onlyComputed) return false;
1053
+ // 查一下这个资源基于商品的可用时间片
1054
+ const timeSlots = (0, _resources.getTimeSlicesByResource)({
1007
1055
  resource: n,
1008
- duration: ((_b2 = (_a2 = cartItem._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.value) || 10,
1056
+ duration: cartItem._productOrigin?.duration?.value || 10,
1009
1057
  split: 10,
1010
1058
  currentDate: dateRange[0].date,
1011
1059
  hasFlexibleDuration,
1012
- cut_off_time: (_c2 = cartItem._productOrigin) == null ? void 0 : _c2.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
- const hasResource = resourcesList.every(
1042
- (item) => item.resources.every((resource) => resource.renderList.length > 0)
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
- var _a, _b;
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((n) => {
1059
- if (n.resource)
1060
- resources.push(...n.resource);
1107
+ dateRange.forEach(n => {
1108
+ if (n.resource) resources.push(...n.resource);
1061
1109
  });
1062
- const resourcesMap = (0, import_utils2.getResourcesMap)(resources);
1063
- const targetCartItem = cartItems.find((n) => n._id === id);
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 { currentCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(targetCartItem);
1117
+ const {
1118
+ currentCapacity
1119
+ } = (0, _capacity.getCapacityInfoByCartItem)(targetCartItem);
1069
1120
  if (targetCartItem.holder_id) {
1070
- selectedResources = (0, import_resources.getOthersSelectedResources)(
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, import_resources.getOthersCartSelectedResources)(
1077
- cartItems,
1078
- targetCartItem._id,
1079
- resourcesMap
1080
- );
1123
+ selectedResources = (0, _resources.getOthersCartSelectedResources)(cartItems, targetCartItem._id, resourcesMap);
1081
1124
  }
1082
- const productResources = (0, import_resources.getResourcesByProduct)(
1083
- resourcesMap,
1084
- ((_b = (_a = targetCartItem._productOrigin) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) || [],
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
- var _a, _b, _c;
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, import_lodash_es.cloneDeep)(this.store.cart.getItems());
1124
- let accountCartItems = cartItems.filter((n) => n.holder_id === holder_id) || [];
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
- var _a2, _b2;
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 == null ? void 0 : dateRange.length) {
1134
- dateRange.forEach((n) => {
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 == null ? void 0 : cartItems.find((n) => n.start_date);
1141
- if (firstDateCartItem == null ? void 0 : firstDateCartItem.start_date) {
1142
- const dateResources = this.store.date.getResourcesListByDate(
1143
- firstDateCartItem.start_date
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((n) => {
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, import_utils2.getResourcesMap)((0, import_lodash_es.cloneDeep)(AllResources));
1155
- const allCartItems = (0, import_lodash_es.cloneDeep)(this.store.cart.getItems());
1156
- const selectedResources = (0, import_resources.getOthersSelectedResources)(
1157
- allCartItems,
1158
- holder_id,
1159
- resourcesMap
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
- var _a2, _b2, _c2, _d;
1170
- const aIsCombined = ((_b2 = (_a2 = a.metadata) == null ? void 0 : _a2.combined_resource) == null ? void 0 : _b2.status) === 1;
1171
- const bIsCombined = ((_d = (_c2 = b.metadata) == null ? void 0 : _c2.combined_resource) == null ? void 0 : _d.status) === 1;
1172
- if (aIsCombined && !bIsCombined)
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
- ...selectedResources
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
- const mTimes = n.times.filter((n2) => {
1190
- return !(0, import_dayjs.default)(n2.start_at).isAfter((0, import_dayjs.default)(timeSlots.start_at)) && !(0, import_dayjs.default)(n2.end_at).isBefore((0, import_dayjs.default)(timeSlots.end_at));
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
- const totalCapacity = (countMap[n.id] || []).reduce(
1196
- (sum, item) => {
1197
- const hasOverlap = (0, import_dayjs.default)(item.time.start_at).isBefore((0, import_dayjs.default)(timeSlots.end_at)) && (0, import_dayjs.default)(item.time.end_at).isAfter((0, import_dayjs.default)(timeSlots.start_at));
1198
- return hasOverlap ? sum + item.pax : sum;
1199
- },
1200
- 0
1201
- );
1202
- if (n.resourceType === "single" && totalCapacity > 0) {
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((item) => {
1206
- var _a2;
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: (_a2 = cartItem._productOrigin) == null ? void 0 : _a2.cut_off_time
1252
+ cut_off_time: cartItem._productOrigin?.cut_off_time
1214
1253
  });
1215
- if ((resourcesUseableMap == null ? void 0 : resourcesUseableMap[n.id]) !== false && res.reason !== "capacityOnly") {
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, import_timeslots.calculateResourceAvailableTime)({
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 resourcesMap2 = (0, import_utils2.getResourcesMap)(resources);
1236
- const resourceIds = resources.map((n) => n.id);
1237
- const timeSlots2 = (0, import_resources.getTimeSlicesByResources)({
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: resourcesMap2,
1279
+ resourcesMap,
1240
1280
  duration,
1241
1281
  currentDate: dateRange[0].date,
1242
1282
  split: 10,
1243
1283
  capacity,
1244
1284
  resourcesUseableMap
1245
1285
  });
1246
- if (!timeSlots2) {
1247
- return;
1286
+ // 如果timeSlots返回了 空数组,代表没有可用的资源了
1287
+ if (!timeSlots) {
1288
+ return; // 给一个提示?
1248
1289
  }
1249
1290
  return {
1250
- timeSlots: timeSlots2,
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 ((_a = dateRange == null ? void 0 : dateRange[0]) == null ? void 0 : _a.date) {
1261
- dateRange.forEach((n) => {
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 = (cartItems2) => {
1271
- let recordTimeSlots = (0, import_lodash_es.cloneDeep)(timeSlots);
1272
- const hasFlexibleProduct = cartItems2.some(
1273
- (item) => {
1274
- var _a2, _b;
1275
- return ((_b = (_a2 = item._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b.type) === "flexible";
1276
- }
1277
- );
1278
- cartItems2.forEach((item, index) => {
1279
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
1280
- const { currentCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(item);
1281
- const hasOriginTimeSlot = Boolean(item._origin.start_time) && Boolean(item._origin.end_time) && !(timeSlots == null ? void 0 : timeSlots.start_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, import_dayjs.default)(`${item.start_date} ${item._origin.start_time}`),
1287
- end_at: (0, import_dayjs.default)(`${item.end_date} ${item._origin.end_time}`)
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
- const currentResourceConfig = (_c = (_b = (_a2 = item._productOrigin) == null ? void 0 : _a2.product_resource) == null ? void 0 : _b.resources) == null ? void 0 : _c.find(
1292
- (n) => n.code === resources_code
1293
- );
1294
- if (index !== 0 && recordTimeSlots && (currentResourceConfig == null ? void 0 : currentResourceConfig.type) === "single" && ((_d = item._productOrigin) == null ? void 0 : _d.duration) && !hasFlexibleProduct && !hasOriginTimeSlot) {
1295
- const recordEndAt = recordTimeSlots.end_at ? (0, import_dayjs.default)(recordTimeSlots.end_at) : (0, import_dayjs.default)(`${item.start_date} ${recordTimeSlots.end_time}`);
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("HH:mm"),
1303
- end_time: end_at.format("HH:mm"),
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 == null ? void 0 : res.selectedResource) {
1359
+ if (res?.selectedResource) {
1317
1360
  if (!selectResourcesWithTimeSlots[res.selectedResource.id]) {
1318
- selectResourcesWithTimeSlots[res.selectedResource.id] = [
1319
- {
1320
- pax: currentCapacity,
1321
- time: recordTimeSlots
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, import_capacity.checkSubResourcesCapacity)(res.selectedResource);
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
- const allCartItems = (0, import_lodash_es.cloneDeep)(this.store.cart.getItems());
1383
+ // 这里必须每次循环重新读,避免前一次循环操作了购物车,导致数据变更
1384
+ // 能进到这种逻辑,说明是 duration 类商品或者灵活时长商品,且是第一种资源,还没有确定时间
1385
+ const allCartItems = (0, _lodashEs.cloneDeep)(this.store.cart.getItems());
1386
+ // 如果没有传递 timeSlots,代表是第一种资源,则直接拿商品的 duration,到资源列表里找一个公共可用的
1350
1387
  let selectedResources = [];
1351
- const resources2 = (0, import_lodash_es.cloneDeep)(
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
- resources2.forEach((n) => {
1356
- var _a3;
1357
- if ((_a3 = n.renderList) == null ? void 0 : _a3.length) {
1358
- n.renderList = n.renderList.filter((m) => {
1359
- var _a4;
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 timeSlots2 = (0, import_resources.getTimeSlicesByResource)({
1396
+ const timeSlots = (0, _resources.getTimeSlicesByResource)({
1362
1397
  resource: m,
1363
- duration: ((_a4 = item == null ? void 0 : item.duration) == null ? void 0 : _a4.value) || 10,
1398
+ duration: item?.duration?.value || 10,
1364
1399
  split: 10,
1365
1400
  currentDate: dateRange[0].date
1366
1401
  });
1367
- return recordCount >= currentCapacity && timeSlots2.length > 0;
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, import_utils2.getResourcesMap)(currentResourcesRenderList);
1407
+ const resourcesMap = (0, _utils2.getResourcesMap)(currentResourcesRenderList);
1373
1408
  if (item.holder_id) {
1374
- selectedResources = (0, import_resources.getOthersSelectedResources)(
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, import_resources.getOthersCartSelectedResources)(
1381
- allCartItems,
1382
- item._id,
1383
- resourcesMap
1384
- );
1411
+ selectedResources = (0, _resources.getOthersCartSelectedResources)(allCartItems, item._id, resourcesMap);
1385
1412
  }
1386
- const productResources = (0, import_resources.getResourcesByProduct)(
1387
- resourcesMap,
1388
- (0, import_lodash_es.cloneDeep)(resources2),
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
- const targetRenderList = (_i = productResources.find(
1401
- (n) => n.code === resources_code
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
- if ((_j = item._origin.resources) == null ? void 0 : _j.some(
1405
- (n) => n.form_id === targetRenderList[0].form_id
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, import_timeslots.findFastestAvailableResource)({
1428
+ const fastestResource = (0, _timeslots.findFastestAvailableResource)({
1410
1429
  resources: targetRenderList,
1411
- currentCapacity,
1430
+ currentCapacity: currentCapacity,
1412
1431
  countMap: selectResourcesMap,
1413
- targetDate: (_k = dateRange == null ? void 0 : dateRange[0]) == null ? void 0 : _k.date,
1414
- durationMinutes: ((_l = item == null ? void 0 : item.duration) == null ? void 0 : _l.value) || ((_n = (_m = item == null ? void 0 : item._productOrigin) == null ? void 0 : _m.duration) == null ? void 0 : _n.value) || 10
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
- (0, import_capacity.checkSubResourcesCapacity)(targetResource);
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((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
1440
- if (cartItems == null ? void 0 : cartItems[0].holder_id) {
1441
- accountList.forEach((account) => {
1442
- const cartItems2 = this.store.cart.getCartByAccount(account.getId());
1443
- selectForCartResources(cartItems2);
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 { errorList };
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((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
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 = void 0;
1478
+ let resourcesTypeId = undefined;
1458
1479
  let isSingleResource = false;
1459
- let maxCutOffTime = void 0;
1460
- let maxCutOffTimeValue = (0, import_dayjs.default)();
1461
- cartItems.forEach((item) => {
1462
- var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2;
1463
- (_c2 = (_b2 = (_a2 = item._productOrigin) == null ? void 0 : _a2.product_resource) == null ? void 0 : _b2.resources) == null ? void 0 : _c2.forEach((n) => {
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 === "single";
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 = (_g2 = (_f2 = (_e2 = (_d2 = item == null ? void 0 : item._productOrigin) == null ? void 0 : _d2.product_resource) == null ? void 0 : _e2.resources) == null ? void 0 : _f2.find(
1473
- (n) => n.code === resources_code
1474
- )) == null ? void 0 : _g2.id;
1475
- if (((_h2 = item._productOrigin) == null ? void 0 : _h2.cut_off_time) && ((_i2 = item._productOrigin) == null ? void 0 : _i2.cut_off_time.type) === "advance") {
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
- if ((_b = (_a = dateRange == null ? void 0 : dateRange[0]) == null ? void 0 : _a.resource) == null ? void 0 : _b.length) {
1487
- dateRange[0].resource.forEach((n) => {
1488
- if (n.form_id === resourcesTypeId && !resources.find((m) => m.id === n.id)) {
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
- if (((_c = dateRange == null ? void 0 : dateRange[0]) == null ? void 0 : _c.date) && resources.length) {
1494
- const currentDate = (_d = dateRange == null ? void 0 : dateRange[0]) == null ? void 0 : _d.date;
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((item) => {
1497
- var _a2;
1498
- const noCurrentDateTimes = item.times.some((n) => {
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 = ((_a2 = theDateResources == null ? void 0 : theDateResources.find((n) => n.id === item.id)) == null ? void 0 : _a2.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, import_utils2.getResourcesMap)(resources);
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 = (cartItems2) => {
1538
+ const checkDuration = cartItems => {
1513
1539
  let accountDuration = 0;
1514
- cartItems2.forEach((item) => {
1515
- var _a2, _b2, _c2, _d2, _e2, _f2;
1540
+ cartItems.forEach(item => {
1541
+ // 单个预约累加账号 多个预约取最大值
1516
1542
  if (isSingleResource) {
1517
- accountDuration += ((_b2 = (_a2 = item._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.value) || 10;
1543
+ accountDuration += item._productOrigin?.duration?.value || 10;
1518
1544
  } else {
1519
- if (accountDuration < (((_d2 = (_c2 = item._productOrigin) == null ? void 0 : _c2.duration) == null ? void 0 : _d2.value) || 10)) {
1520
- accountDuration = ((_f2 = (_e2 = item._productOrigin) == null ? void 0 : _e2.duration) == null ? void 0 : _f2.value) || 10;
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 == null ? void 0 : cartItems[0].holder_id) {
1529
- accountList.forEach((account) => {
1530
- const cartItems2 = this.store.cart.getCartByAccount(account.getId());
1531
- checkDuration(cartItems2);
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
- if (!((_e = cartItems == null ? void 0 : cartItems[0]) == null ? void 0 : _e.start_date) && !((_f = cartItems == null ? void 0 : cartItems[0]) == null ? void 0 : _f.resource_id) || !(cartItems == null ? void 0 : cartItems[0].duration)) {
1562
+ // 如果 cartItem 上既没有时间,也没有资源,认为外部属于异常调用,直接丢一个空数组出去
1563
+ // 同时 session 类商品的流程也不应该调用这个方法
1564
+ if (!cartItems?.[0]?.start_date && !cartItems?.[0]?.resource_id || !cartItems?.[0].duration) {
1537
1565
  return [];
1538
1566
  }
1539
- if ((cartItems == null ? void 0 : cartItems[0].start_date) && !dateRange) {
1540
- dateRange = [
1541
- {
1542
- date: cartItems == null ? void 0 : cartItems[0].start_date,
1543
- status: "available",
1544
- week: "",
1545
- weekNum: 0
1546
- },
1547
- {
1548
- date: ((_g = cartItems == null ? void 0 : cartItems[0]) == null ? void 0 : _g.end_date) || ((_h = cartItems == null ? void 0 : cartItems[0]) == null ? void 0 : _h.start_date) || "",
1549
- status: "available",
1550
- week: "",
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
- (item) => {
1558
- var _a2, _b2;
1559
- return ((_b2 = (_a2 = item._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.type) === "flexible";
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
- var _a2, _b2, _c2, _d2, _e2, _f2;
1567
- if ((_c2 = (_b2 = (_a2 = item._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.flexible_config) == null ? void 0 : _c2.is_enable_minimum_duration) {
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
- const calculateCapacityFromCartItems = (items) => {
1577
- var _a2;
1578
- if (items.length === 0)
1579
- return 0;
1580
- const firstResource = (_a2 = items[0]._resourceOrigin) == null ? void 0 : _a2[0].id;
1581
- const sameResourceLength = items.filter((item) => {
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
- return Math.max(...items.map((item) => (0, import_capacity.getCapacityInfoByCartItem)(item).currentCapacity || 1));
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 == null ? void 0 : cartItems[0].holder_id) {
1592
- accountList.forEach((account) => {
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, import_resources.getTimeSlicesByResources)({
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({ resources_code, startDate, endDate }) {
1621
- var _a, _b, _c, _d;
1622
- if ((0, import_dayjs.default)(endDate).diff((0, import_dayjs.default)(startDate), "day") < 30) {
1623
- endDate = (0, import_dayjs.default)(startDate).add(30, "day").format("YYYY-MM-DD");
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((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
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 = void 0;
1660
+ let resourcesTypeId = undefined;
1634
1661
  let isSingleResource = false;
1635
- let maxCutOffTime = void 0;
1636
- let maxCutOffTimeValue = (0, import_dayjs.default)();
1637
- cartItems.forEach((item) => {
1638
- var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i;
1639
- (_c2 = (_b2 = (_a2 = item._productOrigin) == null ? void 0 : _a2.product_resource) == null ? void 0 : _b2.resources) == null ? void 0 : _c2.forEach((n) => {
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 === "single";
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 = (_g = (_f = (_e = (_d2 = item == null ? void 0 : item._productOrigin) == null ? void 0 : _d2.product_resource) == null ? void 0 : _e.resources) == null ? void 0 : _f.find(
1649
- (n) => n.code === resources_code
1650
- )) == null ? void 0 : _g.id;
1651
- if (((_h = item._productOrigin) == null ? void 0 : _h.cut_off_time) && ((_i = item._productOrigin) == null ? void 0 : _i.cut_off_time.type) === "advance") {
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
- if (!resources.length)
1663
- return [];
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 = (cartItems2) => {
1695
+ const checkDuration = cartItems => {
1667
1696
  let accountDuration = 0;
1668
- cartItems2.forEach((item) => {
1669
- var _a2, _b2, _c2, _d2, _e, _f;
1697
+ cartItems.forEach(item => {
1698
+ // 单个预约累加账号 多个预约取最大值
1670
1699
  if (isSingleResource) {
1671
- accountDuration += ((_b2 = (_a2 = item._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.value) || 10;
1700
+ accountDuration += item._productOrigin?.duration?.value || 10;
1672
1701
  } else {
1673
- if (accountDuration < (((_d2 = (_c2 = item._productOrigin) == null ? void 0 : _c2.duration) == null ? void 0 : _d2.value) || 10)) {
1674
- accountDuration = ((_f = (_e = item._productOrigin) == null ? void 0 : _e.duration) == null ? void 0 : _f.value) || 10;
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 == null ? void 0 : cartItems[0].holder_id) {
1683
- accountList.forEach((account) => {
1684
- const cartItems2 = this.store.cart.getCartByAccount(account.getId());
1685
- checkDuration(cartItems2);
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
- if (!((_a = cartItems == null ? void 0 : cartItems[0]) == null ? void 0 : _a.start_date) && !((_b = cartItems == null ? void 0 : cartItems[0]) == null ? void 0 : _b.resource_id) || !(cartItems == null ? void 0 : cartItems[0].duration)) {
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
- (item) => {
1696
- var _a2, _b2;
1697
- return ((_b2 = (_a2 = item._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.type) === "flexible";
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
- var _a2, _b2, _c2, _d2, _e, _f;
1705
- if ((_c2 = (_b2 = (_a2 = item._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.flexible_config) == null ? void 0 : _c2.is_enable_minimum_duration) {
1706
- return Math.max(max, ((_f = (_e = (_d2 = item._productOrigin) == null ? void 0 : _d2.duration) == null ? void 0 : _e.flexible_config) == null ? void 0 : _f.block_threshold) || 0);
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
- const calculateCapacityFromCartItems = (items) => {
1712
- var _a2;
1713
- if (items.length === 0)
1714
- return 0;
1715
- const firstResource = (_a2 = items[0]._resourceOrigin) == null ? void 0 : _a2[0].id;
1716
- const sameResourceLength = items.filter((item) => {
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
- return Math.max(...items.map((item) => (0, import_capacity.getCapacityInfoByCartItem)(item).currentCapacity || 1));
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 == null ? void 0 : cartItems[0].holder_id) {
1727
- accountList.forEach((account) => {
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, import_dayjs.default)().startOf("day");
1739
- for (let i = (0, import_dayjs.default)(startDate); i.isBefore((0, import_dayjs.default)(endDate)); i = i.add(1, "day")) {
1740
- const currentDate = i.format("YYYY-MM-DD");
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((item) => {
1743
- var _a2;
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, import_utils2.getResourcesMap)(resources);
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: "unavailable",
1751
- week: i.format("ddd"),
1779
+ status: 'unavailable',
1780
+ week: i.format('ddd'),
1752
1781
  weekNum: i.day()
1753
1782
  });
1754
1783
  continue;
1755
1784
  }
1756
- const timeSlots = (0, import_resources.getTimeSlicesByResources)({
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: "available",
1773
- week: i.format("ddd"),
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: "unavailable",
1780
- week: i.format("ddd"),
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
- var _a, _b;
1790
- const cartItems = this.store.cart.getItems().filter((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
1791
- const allResources = this.store.date.getResourcesListByDate(
1792
- timeSlots.start_at.format("YYYY-MM-DD")
1793
- );
1794
- const itemsByAccount = cartItems.reduce(
1795
- (acc, item) => {
1796
- const holderId = item.holder_id;
1797
- if (!acc[holderId]) {
1798
- acc[holderId] = [];
1799
- }
1800
- acc[holderId].push(item);
1801
- return acc;
1802
- },
1803
- {}
1804
- );
1805
- const operating_day_boundary = (_b = (_a = this.shopStore.get("core")) == null ? void 0 : _a.core) == null ? void 0 : _b.operating_day_boundary;
1806
- Object.values(itemsByAccount).forEach((accountItems) => {
1807
- let currentStartTime = timeSlots.start_at.format("YYYY-MM-DD HH:mm");
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, import_lodash_es.cloneDeep)(item._origin.resources);
1812
- newResources.forEach((resource) => {
1813
- var _a3, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1814
- if (((_b2 = (_a3 = item._productOrigin) == null ? void 0 : _a3.duration) == null ? void 0 : _b2.type) === "flexible") {
1815
- let getEarliestBlockedStartTime = function({
1816
- currentStartTime: currentStartTime2,
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
- var _a4;
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 = (_a4 = time.event_list) == null ? void 0 : _a4.filter((event) => event.type !== "schedule_event");
1863
+ const blockedTimes = time.event_list?.filter(event => event.type !== 'schedule_event');
1824
1864
  for (const event of blockedTimes || []) {
1825
- const eventStart = (0, import_dayjs.default)(event.start_at);
1826
- const eventEnd = (0, import_dayjs.default)(event.end_at);
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("YYYY-MM-DD HH:mm");
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 == null ? void 0 : earliestBlockStart.format("YYYY-MM-DD HH:mm");
1838
- };
1839
- item.duration = {
1840
- type: "minutes",
1841
- value: 10
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
- const resourceDate = (0, import_dayjs.default)(resourcesEndTime.end_at).format(
1858
- "YYYY-MM-DD"
1859
- );
1860
- const operatingBoundaryDateTime = `${resourceDate} ${operating_day_boundary.type === "start_time" ? "23:59" : operating_day_boundary.time}`;
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, import_dayjs.default)(value).isBefore((0, import_dayjs.default)(earliest)) ? value : earliest;
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 === "string" && endTime.includes(":") && !endTime.includes(" ") && !endTime.includes("T")) {
1871
- const currentDate = timeSlots.start_at.format("YYYY-MM-DD");
1872
- formattedEndTime = (0, import_dayjs.default)(`${currentDate} ${endTime}`);
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, import_dayjs.default)(endTime);
1901
+ formattedEndTime = (0, _dayjs.default)(endTime);
1875
1902
  }
1876
- resource.endTime = formattedEndTime.format("YYYY-MM-DD HH:mm");
1877
- if (((_f = (_e = (_d = item._productOrigin) == null ? void 0 : _d.duration) == null ? void 0 : _e.flexible_config) == null ? void 0 : _f.is_enable_minimum_duration) && (0, import_dayjs.default)(currentStartTime).add(((_i = (_h = (_g = item._productOrigin) == null ? void 0 : _g.duration) == null ? void 0 : _h.flexible_config) == null ? void 0 : _i.warning_threshold) || 0, "minutes").isAfter((0, import_dayjs.default)(formattedEndTime))) {
1878
- if (!osWarnTips.includes("pisell2.product.card.closing-soon.warning")) {
1879
- osWarnTips.push("pisell2.product.card.closing-soon.warning");
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, import_dayjs.default)(currentStartTime).add(((_k = (_j = item._productOrigin) == null ? void 0 : _j.duration) == null ? void 0 : _k.value) || 10, "minutes").format("YYYY-MM-DD HH:mm");
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
- if (index < accountItems.length - 1 && ((_a2 = newResources == null ? void 0 : newResources[0]) == null ? void 0 : _a2.resourceType) === "single") {
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((item) => {
1905
- return (0, import_utils3.calcCalendarDataByScheduleResult)(item);
1933
+ const targetSchedulesData = targetSchedules.map(item => {
1934
+ return (0, _utils3.calcCalendarDataByScheduleResult)(item);
1906
1935
  });
1907
1936
  const newSchedule = {};
1908
- targetSchedulesData.forEach((item) => {
1909
- item.forEach((n) => {
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, import_dayjs.default)(a.date).diff((0, import_dayjs.default)(b.date));
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
- if (targetProductData["schedule.ids"]) {
1932
- const newScheduleArr = this.getScheduleDataByIds(
1933
- targetProductData["schedule.ids"]
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
- if (!(dateRange == null ? void 0 : dateRange.length))
1941
- return;
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 = void 0;
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
- if (scheduleIds == null ? void 0 : scheduleIds.length) {
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((n) => n.date === date);
1976
- const cartItems = (0, import_lodash_es.cloneDeep)(this.store.cart.getItems());
1977
- const resourcesMap = (0, import_utils2.getResourcesMap)((targetResourceDate == null ? void 0 : targetResourceDate.resource) || []);
1978
- const selectedResources = (0, import_resources.getOthersSelectedResources)(
1979
- cartItems,
1980
- "",
1981
- resourcesMap
1982
- );
1983
- const productResources = (0, import_resources.getResourcesByProduct)(
1984
- resourcesMap,
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
- var _a2, _b2, _c2, _d2;
1998
- const aIsCombined = ((_b2 = (_a2 = a.metadata) == null ? void 0 : _a2.combined_resource) == null ? void 0 : _b2.status) === 1;
1999
- const bIsCombined = ((_d2 = (_c2 = b.metadata) == null ? void 0 : _c2.combined_resource) == null ? void 0 : _d2.status) === 1;
2000
- if (aIsCombined && !bIsCombined)
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 = ((_d = (_c = targetProductData == null ? void 0 : targetProductData.product_resource) == null ? void 0 : _c.resources) == null ? void 0 : _d.filter(
2007
- (n) => n.status === 1
2008
- )) || [];
2009
- const resourceTypeConfigById = new Map(
2010
- enabledResourceTypeConfigs.map((n) => [n.id, n])
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((cfg) => {
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
- allProductResources == null ? void 0 : allProductResources.forEach((m) => {
2043
+
2044
+ // 遍历所有资源
2045
+ allProductResources?.forEach(m => {
2024
2046
  const currentResourceTypeConfig = resourceTypeConfigById.get(m.form_id);
2025
- if (!currentResourceTypeConfig)
2026
- return;
2047
+ if (!currentResourceTypeConfig) return;
2048
+
2049
+ // 遍历所有资源的上工时间片
2027
2050
  let currentResourceMaxRemainingCapacity = 0;
2028
2051
  let isAllTimeSlicesUsable = true;
2029
- const mTimes = m.times.filter((n) => {
2030
- return !(0, import_dayjs.default)(n.start_at).isAfter((0, import_dayjs.default)(item.start), "minute") && !(0, import_dayjs.default)(n.end_at).isBefore((0, import_dayjs.default)(item.end), "minute") || m.onlyComputed && (0, import_dayjs.default)(n.start_at).isBefore((0, import_dayjs.default)(item.end), "minute") && (0, import_dayjs.default)(n.end_at).isAfter((0, import_dayjs.default)(item.start), "minute");
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 currentStats2 = statsByResourceType[m.form_id] || {
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 === "multiple")
2043
- currentStats2.summaryConfigCount += m.capacity;
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((childTiem) => {
2049
- const res = (0, import_resources.getIsUsableByTimeItem)({
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, import_dayjs.default)(item.start),
2054
- end_at: (0, import_dayjs.default)(item.end)
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 == null ? void 0 : targetProductData.cut_off_time
2093
+ cut_off_time: targetProductData?.cut_off_time
2061
2094
  });
2062
- if ((resourcesUseableMap == null ? void 0 : resourcesUseableMap[m.id]) !== false && res.reason !== "capacityOnly") {
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
- return;
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 === "multiple") {
2112
+ if (currentResourceTypeConfig.type === 'multiple') {
2084
2113
  currentStats.summaryCount += currentResourceMaxRemainingCapacity;
2085
2114
  }
2086
- if (currentResourceMaxRemainingCapacity > currentStats.count)
2087
- currentStats.count = currentResourceMaxRemainingCapacity;
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
- const cartItems2 = this.store.cart.getItems();
2091
- productResources.forEach((n) => {
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
- if (n.type === "single") {
2101
- const currentResourcesSet = /* @__PURE__ */ new Set([...n.optional_resource, ...n.default_resource]);
2102
- const sameCartItems = cartItems2.filter((m) => {
2103
- var _a2, _b2, _c2;
2104
- return ((_b2 = (_a2 = m._productOrigin) == null ? void 0 : _a2.id) == null ? void 0 : _b2.toString()) === ((_c2 = targetProductData == null ? void 0 : targetProductData.id) == null ? void 0 : _c2.toString()) && `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end;
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
- let otherCartItems = cartItems2.filter(
2112
- (m) => {
2113
- var _a2, _b2, _c2, _d2, _e, _f;
2114
- const isTimeMatch = ((_b2 = (_a2 = m._productOrigin) == null ? void 0 : _a2.id) == null ? void 0 : _b2.toString()) !== ((_c2 = targetProductData == null ? void 0 : targetProductData.id) == null ? void 0 : _c2.toString()) && `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end;
2115
- const isResourceMatch = (_f = (_e = (_d2 = m._productOrigin) == null ? void 0 : _d2.product_resource) == null ? void 0 : _e.resources) == null ? void 0 : _f.find((m2) => m2.type === n.type && m2.status === 1);
2116
- return isTimeMatch && isResourceMatch;
2117
- }
2118
- );
2119
- otherCartItems.forEach((m) => {
2120
- var _a2, _b2, _c2;
2121
- const sameTypeResources = (_c2 = (_b2 = (_a2 = m._productOrigin) == null ? void 0 : _a2.product_resource) == null ? void 0 : _b2.resources) == null ? void 0 : _c2.find((m2) => m2.type === n.type && m2.status === 1);
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
- const currentDataResources = this.store.date.getResourcesListByDate((0, import_dayjs.default)(item.start).format("YYYY-MM-DD"));
2126
- currentDataResources == null ? void 0 : currentDataResources.forEach((m) => {
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((n2) => {
2129
- return !(0, import_dayjs.default)(n2.start_at).isAfter((0, import_dayjs.default)(item.start), "minute") && !(0, import_dayjs.default)(n2.end_at).isBefore((0, import_dayjs.default)(item.end), "minute") || (0, import_dayjs.default)(n2.start_at).isBefore((0, import_dayjs.default)(item.end), "minute") && (0, import_dayjs.default)(n2.end_at).isAfter((0, import_dayjs.default)(item.start), "minute");
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((n2) => n2.event_list.length)) {
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
- const sameCartItems = cartItems2.filter((m) => {
2143
- var _a2, _b2, _c2;
2144
- return ((_b2 = (_a2 = m._productOrigin) == null ? void 0 : _a2.id) == null ? void 0 : _b2.toString()) === ((_c2 = targetProductData == null ? void 0 : targetProductData.id) == null ? void 0 : _c2.toString()) && `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end;
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
- const otherSameTimesCartItems = cartItems2.filter((m) => `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end);
2154
- const otherCartNeedCapacity = otherSameTimesCartItems.reduce((acc, curr) => acc + (0, import_capacity.getCapacityInfoByCartItem)(curr).currentCapacity, 0);
2155
- const allRenderList = [...n.renderList.filter((m) => !m.onlyComputed)];
2156
- otherSameTimesCartItems.forEach((m) => {
2157
- var _a2, _b2;
2158
- const productResources2 = (0, import_resources.getResourcesByProduct)(
2159
- (0, import_utils2.getResourcesMap)((targetResourceDate == null ? void 0 : targetResourceDate.resource) || []),
2160
- ((_b2 = (_a2 = m._productOrigin) == null ? void 0 : _a2.product_resource) == null ? void 0 : _b2.resources) || [],
2161
- selectedResources,
2162
- 1
2163
- );
2164
- productResources2.forEach((m2) => {
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((n2) => {
2177
- return !(0, import_dayjs.default)(n2.start_at).isAfter((0, import_dayjs.default)(item.start), "minute") && !(0, import_dayjs.default)(n2.end_at).isBefore((0, import_dayjs.default)(item.end), "minute") || (0, import_dayjs.default)(n2.start_at).isBefore((0, import_dayjs.default)(item.end), "minute") && (0, import_dayjs.default)(n2.end_at).isAfter((0, import_dayjs.default)(item.start), "minute");
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
- const mSet = /* @__PURE__ */ new Map();
2180
- mTimes.forEach((n2) => {
2181
- n2.event_list.forEach((m) => {
2182
- if ((0, import_resources.isConflict)(
2183
- { start_at: m.start_at, end_at: m.end_at },
2184
- { start_at: (0, import_dayjs.default)(item.start), end_at: (0, import_dayjs.default)(item.end) }
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((acc2, curr2) => acc2 + curr2, 0);
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, import_dayjs.default)(item.start);
2202
- const endDayJs = (0, import_dayjs.default)(item.end);
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((cfg) => {
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 === "multiple" ? stats.summaryCount : stats.left;
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 !== void 0 ? statsByResourceType[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
- } : { count: 0, left: 0, summaryCount: 0, summaryConfigCount: 0 };
2224
- const bottleneckConfig = bottleneckResourceTypeId !== void 0 ? resourceTypeConfigById.get(bottleneckResourceTypeId) : void 0;
2225
- let status = "sold_out";
2226
- if (bottleneckStats.left === 0)
2227
- status = "sold_out";
2228
- else if (!bottleneckConfig || bottleneckStats.summaryConfigCount === 0)
2229
- status = "sold_out";
2230
- else if (bottleneckConfig.type === "multiple") {
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("HH:mm"),
2249
- end_time: endDayJs.format("HH:mm"),
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
- return [];
2270
- console.log(`计算 ${resources.length} 个资源的公共时间段`);
2271
- const allTimeSlots = resources.map(
2272
- (resource) => resource.times.map((time) => ({
2273
- start: (0, import_dayjs.default)(time.start_at),
2274
- end: (0, import_dayjs.default)(time.end_at)
2275
- }))
2276
- );
2277
- console.log("所有资源的时间段:", allTimeSlots.map(
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
- commonSlots.forEach((commonSlot) => {
2286
- currentResourceSlots.forEach((currentSlot) => {
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
- const result = commonSlots.map((slot) => ({
2305
- startTime: slot.start.format("HH:mm"),
2306
- endTime: slot.end.format("HH:mm")
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
- var _a, _b;
2313
- const cartItems = this.store.cart.getItems().filter((item) => !(0, import_utils5.isNormalProduct)(item._productOrigin));
2314
- if (cartItems.length === 0)
2315
- return { success: true, minAvailableCount: 0 };
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((cartItem) => {
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((cartItem) => {
2330
- var _a2;
2331
- if (!cartItem._productOrigin)
2332
- return;
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 || ((_a3 = resourceType.id) == null ? void 0 : _a3.toString());
2373
+ const resourceCode = resourceType.code || resourceType.id?.toString();
2338
2374
  if (!itemsByResourceType[resourceCode]) {
2339
2375
  itemsByResourceType[resourceCode] = [];
2340
2376
  }
2341
- if (itemsByResourceType[resourceCode].find((item) => item.holder_id === cartItem.holder_id)) {
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((item) => item._id === cartItem._id)) {
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
- return { success: false, minAvailableCount: 0 };
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((n) => n.date === dateRange[0].date);
2355
- if (!targetResourceDate)
2356
- return { success: false, minAvailableCount: 0 };
2357
- const resourcesMap = (0, import_utils2.getResourcesMap)(targetResourceDate.resource || []);
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
- Object.values(itemsByResourceType).flat().forEach((cartItem) => {
2360
- var _a2, _b2;
2361
- if ((_b2 = (_a2 = cartItem._productOrigin) == null ? void 0 : _a2.product_resource) == null ? void 0 : _b2.resources) {
2362
- cartItem._productOrigin.product_resource.resources.forEach((resourceConfig) => {
2363
- var _a3, _b3;
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 = ((_a3 = resourceConfig.id) == null ? void 0 : _a3.toString()) || ((_b3 = resourceConfig.resource_type_id) == null ? void 0 : _b3.toString());
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
- const processedCartItemIds = /* @__PURE__ */ new Set();
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
- console.log(`资源类型 ${resourceCode} 找不到对应的 form_id`);
2380
- return { success: false, minAvailableCount: 0 };
2431
+ return {
2432
+ success: false,
2433
+ minAvailableCount: 0
2434
+ };
2381
2435
  }
2436
+
2437
+ // 获取该资源类型的所有资源
2382
2438
  const resourcesOfThisType = [];
2383
- items.forEach((cartItem) => {
2384
- const productResourceIds = (0, import_capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
2385
- productResourceIds.forEach((resourceId) => {
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 && ((_a2 = resource.form_id) == null ? void 0 : _a2.toString()) === targetFormId) {
2389
- if (!resourcesOfThisType.find((r) => r.id === resource.id)) {
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
- console.log(`资源类型 ${resourceCode} 没有找到可用资源`);
2397
- return { success: false, minAvailableCount: 0 };
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 ((_b = (_a = cartItem._productOrigin) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) {
2402
- resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(
2403
- (r) => r.code === resourceCode && r.status === 1
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 = (resourceTypeConfig == null ? void 0 : resourceTypeConfig.type) === "multiple";
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 { currentCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(cartItem);
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
- console.log(`资源类型 ${resourceCode} 的资源时间信息:`, resourcesOfThisType.map((r) => ({
2442
- id: r.id,
2443
- times: r.times.map((t) => `${t.start_at} - ${t.end_at}`)
2444
- })));
2506
+
2507
+ // 为通过检测的商品分配一个公共可用时间段
2508
+
2509
+ // 找到所有资源都可用的时间段
2445
2510
  const commonTimeSlots = this.findCommonAvailableTimeSlots(resourcesOfThisType);
2446
- console.log(`资源类型 ${resourceCode} 的公共时间段:`, commonTimeSlots);
2447
2511
  if (commonTimeSlots.length === 0) {
2448
- console.log(`资源类型 ${resourceCode} 没有公共可用时间段`);
2449
- return { success: false, minAvailableCount: 0 };
2512
+ return {
2513
+ success: false,
2514
+ minAvailableCount: 0
2515
+ };
2450
2516
  }
2517
+
2518
+ // 使用第一个公共可用时间段,但只处理未处理过的商品
2451
2519
  const firstCommonSlot = commonTimeSlots[0];
2452
- console.log(`使用公共时间段: ${firstCommonSlot.startTime} - ${firstCommonSlot.endTime}`);
2453
- items.forEach((cartItem) => {
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
- const overCapacityResources = resourceCapacityInfo.filter((info) => info.required > info.total);
2538
+ // 找出超出容量的资源类型中,总容量最少的那个
2539
+ const overCapacityResources = resourceCapacityInfo.filter(info => info.required > info.total);
2469
2540
  if (overCapacityResources.length > 0) {
2470
- const minTotalCapacity2 = Math.min(...overCapacityResources.map((info) => info.total));
2471
- return { success: false, minAvailableCount: minTotalCapacity2 };
2541
+ const minTotalCapacity = Math.min(...overCapacityResources.map(info => info.total));
2542
+ return {
2543
+ success: false,
2544
+ minAvailableCount: minTotalCapacity
2545
+ };
2472
2546
  }
2473
- const minTotalCapacity = Math.min(...resourceCapacityInfo.map((info) => info.total));
2474
- return { success: false, minAvailableCount: minTotalCapacity };
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((cartItem) => {
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 = /* @__PURE__ */ new Set();
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((n) => n.date === startDate);
2497
- if (!targetResourceDate)
2498
- continue;
2499
- const resourcesMap = (0, import_utils2.getResourcesMap)(targetResourceDate.resource || []);
2500
- itemsInTimeSlot.forEach((cartItem) => {
2501
- if (!cartItem._productOrigin)
2502
- return;
2503
- const productResourceIds = (0, import_capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
2504
- productResourceIds.forEach((resourceId) => {
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
- const { success, required, available } = (0, import_capacity.checkTimeSlotCapacity)(timeSlotStart, timeSlotEnd, itemsInTimeSlot, allResourcesForTimeSlot);
2597
+
2598
+ // 按资源类型分组检查容量
2599
+ const {
2600
+ success,
2601
+ required,
2602
+ available
2603
+ } = (0, _capacity.checkTimeSlotCapacity)(timeSlotStart, timeSlotEnd, itemsInTimeSlot, allResourcesForTimeSlot);
2512
2604
  if (!success) {
2513
- const minAvailableCount2 = availableCountsByResourceType.length > 0 ? Math.min(...availableCountsByResourceType) : 0;
2514
- return { success: false, minAvailableCount: minAvailableCount2 };
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 { success: true, minAvailableCount };
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
- const productData = { ...origin, product_variant_id };
2537
- const processedProduct = (0, import_utils.handleVariantProduct)(productData);
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, import_utils.getUniqueId)("temp_"),
2546
- _origin: (0, import_utils.createCartItemOrigin)(),
2658
+ _id: (0, _utils.getUniqueId)('temp_'),
2659
+ _origin: (0, _utils.createCartItemOrigin)(),
2547
2660
  _productOrigin: processedProduct,
2548
2661
  _productInit: product
2549
2662
  };
2550
- (0, import_utils.formatProductToCartItem)({
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, import_utils.formatDateToCartItem)({
2676
+ (0, _utils.formatDateToCartItem)({
2560
2677
  cartItem,
2561
2678
  date
2562
2679
  });
2563
2680
  }
2681
+
2682
+ // 如果有账户信息,格式化账户到购物车
2564
2683
  if (account) {
2565
- (0, import_utils.formatAccountToCartItem)({
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
- var _a, _b;
2578
- const cartItems = this.store.cart.getItems().filter((item) => !(0, import_utils5.isNormalProduct)(item._productOrigin));
2579
- const currentCartItem = this.convertProductToCartItem({ product, date, account });
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
- return { success: true, minAvailableCount: 0 };
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((cartItem) => {
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((cartItem) => {
2597
- var _a2;
2598
- if (!cartItem._productOrigin)
2599
- return;
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 || ((_a3 = resourceType.id) == null ? void 0 : _a3.toString());
2733
+ const resourceCode = resourceType.code || resourceType.id?.toString();
2605
2734
  if (!itemsByResourceType[resourceCode]) {
2606
2735
  itemsByResourceType[resourceCode] = [];
2607
2736
  }
2608
- if (!itemsByResourceType[resourceCode].find((item) => item._id === cartItem._id)) {
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
- return { success: false, minAvailableCount: 0 };
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((n) => n.date === dateRange[0].date);
2619
- if (!targetResourceDate)
2620
- return { success: false, minAvailableCount: 0 };
2621
- const resourcesMap = (0, import_utils2.getResourcesMap)(targetResourceDate.resource || []);
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
- Object.values(itemsByResourceType).flat().forEach((cartItem) => {
2624
- var _a2, _b2;
2625
- if ((_b2 = (_a2 = cartItem._productOrigin) == null ? void 0 : _a2.product_resource) == null ? void 0 : _b2.resources) {
2626
- cartItem._productOrigin.product_resource.resources.forEach((resourceConfig) => {
2627
- var _a3, _b3;
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 = ((_a3 = resourceConfig.id) == null ? void 0 : _a3.toString()) || ((_b3 = resourceConfig.resource_type_id) == null ? void 0 : _b3.toString());
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
- const processedCartItemIds = /* @__PURE__ */ new Set();
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
- console.log(`资源类型 ${resourceCode} 找不到对应的 form_id`);
2644
- return { success: false, minAvailableCount: 0 };
2787
+ return {
2788
+ success: false,
2789
+ minAvailableCount: 0
2790
+ };
2645
2791
  }
2792
+
2793
+ // 获取该资源类型的所有资源
2646
2794
  const resourcesOfThisType = [];
2647
- items.forEach((cartItem) => {
2648
- const productResourceIds = (0, import_capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
2649
- productResourceIds.forEach((resourceId) => {
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 && ((_a2 = resource.form_id) == null ? void 0 : _a2.toString()) === targetFormId) {
2653
- if (!resourcesOfThisType.find((r) => r.id === resource.id)) {
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
- console.log(`资源类型 ${resourceCode} 没有找到可用资源`);
2661
- return { success: false, minAvailableCount: 0 };
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 ((_b = (_a = cartItem._productOrigin) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) {
2666
- resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(
2667
- (r) => r.code === resourceCode && r.status === 1
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 = (resourceTypeConfig == null ? void 0 : resourceTypeConfig.type) === "multiple";
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 { currentCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(cartItem);
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
- console.log(`资源类型 ${resourceCode} 的资源时间信息:`, resourcesOfThisType.map((r) => ({
2706
- id: r.id,
2707
- times: r.times.map((t) => `${t.start_at} - ${t.end_at}`)
2708
- })));
2862
+
2863
+ // 为通过检测的商品分配一个公共可用时间段
2864
+
2865
+ // 找到所有资源都可用的时间段
2709
2866
  const commonTimeSlots = this.findCommonAvailableTimeSlots(resourcesOfThisType);
2710
- console.log(`资源类型 ${resourceCode} 的公共时间段:`, commonTimeSlots);
2711
2867
  if (commonTimeSlots.length === 0) {
2712
- console.log(`资源类型 ${resourceCode} 没有公共可用时间段`);
2713
- return { success: false, minAvailableCount: 0 };
2868
+ return {
2869
+ success: false,
2870
+ minAvailableCount: 0
2871
+ };
2714
2872
  }
2873
+
2874
+ // 使用第一个公共可用时间段,但只处理未处理过的商品
2715
2875
  const firstCommonSlot = commonTimeSlots[0];
2716
- console.log(`使用公共时间段: ${firstCommonSlot.startTime} - ${firstCommonSlot.endTime}`);
2717
- items.forEach((cartItem) => {
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
- const overCapacityResources = resourceCapacityInfo.filter((info) => info.required > info.total);
2894
+ // 找出超出容量的资源类型中,总容量最少的那个
2895
+ const overCapacityResources = resourceCapacityInfo.filter(info => info.required > info.total);
2733
2896
  if (overCapacityResources.length > 0) {
2734
- const minTotalCapacity2 = Math.min(...overCapacityResources.map((info) => info.total));
2735
- return { success: false, minAvailableCount: minTotalCapacity2 };
2897
+ const minTotalCapacity = Math.min(...overCapacityResources.map(info => info.total));
2898
+ return {
2899
+ success: false,
2900
+ minAvailableCount: minTotalCapacity
2901
+ };
2736
2902
  }
2737
- const minTotalCapacity = Math.min(...resourceCapacityInfo.map((info) => info.total));
2738
- return { success: false, minAvailableCount: minTotalCapacity };
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((cartItem) => {
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 = /* @__PURE__ */ new Set();
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((n) => n.date === startDate);
2760
- if (!targetResourceDate)
2761
- continue;
2762
- const resourcesMap = (0, import_utils2.getResourcesMap)(targetResourceDate.resource || []);
2763
- itemsInTimeSlot.forEach((cartItem) => {
2764
- if (!cartItem._productOrigin)
2765
- return;
2766
- const productResourceIds = (0, import_capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
2767
- productResourceIds.forEach((resourceId) => {
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
- const { success, required, available } = (0, import_capacity.checkTimeSlotCapacity)(timeSlotStart, timeSlotEnd, itemsInTimeSlot, allResourcesForTimeSlot);
2953
+
2954
+ // 按资源类型分组检查容量
2955
+ const {
2956
+ success,
2957
+ required,
2958
+ available
2959
+ } = (0, _capacity.checkTimeSlotCapacity)(timeSlotStart, timeSlotEnd, itemsInTimeSlot, allResourcesForTimeSlot);
2775
2960
  if (!success) {
2776
- return { success: false, minAvailableCount: available };
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 { success: true, minAvailableCount };
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: { otherData: this.otherData },
2788
- cacheKey: ["otherData"]
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 "duration";
2995
+ return 'duration';
2800
2996
  }
2801
- if ((_a = productData["schedule.ids"]) == null ? void 0 : _a.length) {
2802
- return "session";
2997
+ if (productData['schedule.ids']?.length) {
2998
+ return 'session';
2803
2999
  }
2804
- return "normal";
3000
+ return 'normal';
2805
3001
  }
2806
- return "normal";
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 == null ? void 0 : dateRange.length) {
2821
- dateRange.forEach((n) => {
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((n) => {
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, import_utils2.getResourcesMap)((0, import_lodash_es.cloneDeep)(resources));
2834
- const cartItems = this.store.cart.getItems().filter((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
2835
- const cartItem = cartItems.find((item) => item._id === cartItemId);
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 { currentCapacity, formatCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(cartItem);
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, import_resources.getOthersSelectedResources)(
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, import_resources.getOthersCartSelectedResources)(
2849
- cartItems,
2850
- cartItem._id,
2851
- resourcesMap
2852
- );
3040
+ selectedResources = (0, _resources.getOthersCartSelectedResources)(cartItems, cartItem._id, resourcesMap);
2853
3041
  }
2854
- const productResources = (0, import_resources.getResourcesByProduct)(
2855
- resourcesMap,
2856
- ((_b = (_a = cartItem._productOrigin) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) || [],
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, import_dayjs.default)(
2867
- `${cartItem._origin.start_date} ${cartItem._origin.start_time}`
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
- (a, b) => {
2875
- var _a2, _b2, _c, _d;
2876
- const aIsCombined = ((_b2 = (_a2 = a.metadata) == null ? void 0 : _a2.combined_resource) == null ? void 0 : _b2.status) === 1;
2877
- const bIsCombined = ((_d = (_c = b.metadata) == null ? void 0 : _c.combined_resource) == null ? void 0 : _d.status) === 1;
2878
- if (aIsCombined && !bIsCombined)
2879
- return 1;
2880
- if (!aIsCombined && bIsCombined)
2881
- return -1;
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
- return false;
2891
- const canUseArr = mTimes.map((item) => {
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("HH:mm"),
2896
- end_time: endTime.format("HH:mm"),
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: (_a2 = cartItem._productOrigin) == null ? void 0 : _a2.cut_off_time
3072
+ resourcesUseableMap: resourcesUseableMap,
3073
+ cut_off_time: cartItem._productOrigin?.cut_off_time
2905
3074
  });
2906
- if ((resourcesUseableMap == null ? void 0 : resourcesUseableMap[m.id]) !== false && res.reason !== "capacityOnly") {
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
- return false;
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((n) => {
2917
- var _a2, _b2;
3084
+ targetResource.renderList = targetResource.renderList.filter(n => {
2918
3085
  const recordCount = n.capacity || 0;
2919
- if (n.onlyComputed)
2920
- return false;
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: ((_b2 = (_a2 = cartItem._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.value) || 10,
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
- console.log(
2944
- "appoimentBooking-session-date-getTimeslotsScheduleByDateRange",
2945
- { startDate, endDate, scheduleIds, resources }
2946
- );
3110
+ // 生成日期范围内的所有日期
2947
3111
  const dates = [];
2948
- let currentDate = (0, import_dayjs.default)(startDate);
2949
- const end = (0, import_dayjs.default)(endDate);
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("YYYY-MM-DD"));
2952
- currentDate = currentDate.add(1, "day");
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
- var _a, _b, _c, _d;
2966
- let { startDate, endDate } = params;
2967
- if ((0, import_dayjs.default)(startDate).isBefore((0, import_dayjs.default)(), "day") && ((0, import_dayjs.default)(endDate).isAfter((0, import_dayjs.default)(), "day") || (0, import_dayjs.default)(endDate).isSame((0, import_dayjs.default)(), "day"))) {
2968
- startDate = (0, import_dayjs.default)().format("YYYY-MM-DD");
2969
- }
2970
- const endDateAfterMonth = (0, import_dayjs.default)().add(1, "month").format("YYYY-MM-DD");
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, import_dayjs.default)(startDate).add(7, "day").isAfter((0, import_dayjs.default)(endDateAfterMonth), "day")) {
2973
- tempEndDate = (0, import_dayjs.default)(startDate).add(7, "day").format("YYYY-MM-DD");
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
- if ((0, import_dayjs.default)(tempEndDate).isBefore((0, import_dayjs.default)(endDate), "day")) {
2978
- tempEndDate = endDate || "";
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
- const cache = (_a = this.store.currentProductMeta) == null ? void 0 : _a["timeSlotBySchedule"];
3154
+
3155
+ // 先去读缓存结果,因为正常 UI 调用的是 7 天,而下面我会直接计算 30 天(最少也是 14 天),所以先去读缓存结果,如果缓存结果存在,则直接返回
3156
+ const cache = this.store.currentProductMeta?.['timeSlotBySchedule'];
2982
3157
  if (cache) {
2983
- if ((0, import_dayjs.default)(params.startDate).isSameOrAfter((0, import_dayjs.default)(cache.startDate), "day") && (0, import_dayjs.default)(params.endDate).isSameOrBefore((0, import_dayjs.default)(cache.endDate), "day")) {
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 = (_b = this.store.currentProductMeta) == null ? void 0 : _b["schedule"];
2994
- const filteredSchedule = (0, import_resources.filterScheduleByDateRange)(
2995
- schedule,
2996
- startDate || "",
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, import_dayjs.default)(startDate);
3009
- let firstAvailableDate = "";
3010
- const openResources = ((_d = (_c = tempProducts == null ? void 0 : tempProducts.product_resource) == null ? void 0 : _c.resources) == null ? void 0 : _d.filter(
3011
- (m) => m.status === 1
3012
- )) || [];
3013
- const allProductResources = (0, import_lodash_es.cloneDeep)((0, import_resources.sortCombinedResources)(res.data) || []);
3014
- allProductResources.forEach((m) => {
3015
- var _a2, _b2;
3016
- const resource = (_b2 = (_a2 = tempProducts == null ? void 0 : tempProducts.product_resource) == null ? void 0 : _a2.resources) == null ? void 0 : _b2.find(
3017
- (n) => n.id === m.form_id
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
- tempProducts["schedule.ids"]
3025
- );
3026
- while ((0, import_dayjs.default)(currentDate).isBefore((0, import_dayjs.default)(endDate), "day") || (0, import_dayjs.default)(currentDate).isSame((0, import_dayjs.default)(endDate), "day")) {
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
- const { latestStartDate, earliestEndDate } = (0, import_resources.checkSessionProductLeadTime)(tempProducts);
3205
+ // 1. 检查商品的提前量等情况是否满足
3206
+ const {
3207
+ latestStartDate,
3208
+ earliestEndDate
3209
+ } = (0, _resources.checkSessionProductLeadTime)(tempProducts);
3032
3210
  if (latestStartDate || earliestEndDate) {
3033
- if (latestStartDate && (0, import_dayjs.default)(currentDate).isBefore(latestStartDate, "day")) {
3034
- status = "unavailable";
3211
+ // 如果时间在最早开始时间之前,则设置为不可用
3212
+ if (latestStartDate && (0, _dayjs.default)(currentDate).isBefore(latestStartDate, 'day')) {
3213
+ status = 'unavailable';
3035
3214
  }
3036
- if (earliestEndDate && (0, import_dayjs.default)(currentDate).isAfter(earliestEndDate, "day")) {
3037
- status = "unavailable";
3215
+ // 如果时间在最早结束时间之后,则设置为不可用
3216
+ if (earliestEndDate && (0, _dayjs.default)(currentDate).isAfter(earliestEndDate, 'day')) {
3217
+ status = 'unavailable';
3038
3218
  }
3039
3219
  }
3040
- if (status === "available") {
3041
- const scheduleByDate = filteredSchedule.find(
3042
- (n) => n.date === currentDateStr
3043
- );
3044
- if (!scheduleByDate || (scheduleByDate == null ? void 0 : scheduleByDate.isExcluded)) {
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
- if (status === "available") {
3049
- const minTimeMaxTime = (0, import_utils3.calcMinTimeMaxTimeBySchedules)(
3050
- targetSchedules,
3051
- {},
3052
- currentDateStr
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((item) => {
3234
+ scheduleTimeSlots.forEach(item => {
3235
+ // 用来计算资源的可使用情况,针对单个schedule 时间片
3057
3236
  const resourcesUseableMap = {};
3237
+ // 遍历产品下启用的资源
3238
+ // 必须要保证每种类型的资源都至少有一个能够在对应时间点被选择
3239
+ // 求出第一个资源的剩余量和总量
3240
+ // 剩余量=每个资源在每个时间片内剩余之和
3241
+ // 总量=每个资源在每个时间片内资源总量之和
3058
3242
  let isAllResourceTypesUseable = true;
3059
- openResources.forEach((resource) => {
3060
- var _a2;
3061
- const currentResourcesList = allProductResources.filter(
3062
- (n) => n.form_id === resource.resource_type_id
3063
- );
3064
- (_a2 = resource.renderList) == null ? void 0 : _a2.forEach((item2) => {
3065
- if (item2.onlyComputed) {
3066
- const targetIndex = currentResourcesList.findIndex((n) => n.id === item2.id);
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
- currentResourcesList.forEach((item2) => {
3073
- var _a3, _b2;
3074
- if (!((_a3 = resource.optional_resource) == null ? void 0 : _a3.includes(item2.id)) && !((_b2 = resource.default_resource) == null ? void 0 : _b2.includes(item2.id))) {
3075
- item2.onlyComputed = true;
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 == null ? void 0 : currentResourcesList.forEach((m) => {
3083
- const mTimes = m.times.filter((n) => {
3084
- return !(0, import_dayjs.default)(n.start_at).isAfter((0, import_dayjs.default)(item.start), "minute") && !(0, import_dayjs.default)(n.end_at).isBefore((0, import_dayjs.default)(item.end), "minute");
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
- if (mTimes.length === 0)
3087
- return;
3276
+
3277
+ // 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
3278
+ if (mTimes.length === 0) return;
3279
+ // 如果资源可用则把他的容量纳入总计
3088
3280
  if (!m.onlyComputed) {
3089
- if (resource.type === "multiple") {
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((childTiem) => {
3097
- if (isAnyTimeSliceUseable)
3098
- return;
3099
- const res2 = (0, import_resources.getIsUsableByTimeItem)({
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, import_dayjs.default)(item.start),
3104
- end_at: (0, import_dayjs.default)(item.end)
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 == null ? void 0 : tempProducts.cut_off_time
3303
+ cut_off_time: tempProducts?.cut_off_time
3111
3304
  });
3112
- if ((resourcesUseableMap == null ? void 0 : resourcesUseableMap[m.id]) !== false && res2.reason !== "capacityOnly") {
3113
- resourcesUseableMap[m.id] = res2.usable;
3305
+ if (resourcesUseableMap?.[m.id] !== false && res.reason !== 'capacityOnly') {
3306
+ resourcesUseableMap[m.id] = res.usable;
3114
3307
  }
3115
- if (res2.usable && !m.onlyComputed) {
3308
+ if (res.usable && !m.onlyComputed) {
3116
3309
  isAnyTimeSliceUseable = true;
3117
- if (resource.type === "multiple") {
3118
- availableCount += res2.remainingCapacity;
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 = "unavailable";
3325
+ status = 'unavailable';
3136
3326
  }
3137
- if (status === "available" && !firstAvailableDate) {
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 === "unavailable") {
3143
- if (availableCount === 0 && summaryCount > 0)
3144
- dateStatus = "sold_out";
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, import_dayjs.default)(currentDate).format("YYYY-MM-DD"),
3156
- week: (0, import_dayjs.default)(currentDate).format("ddd"),
3157
- weekNum: (0, import_dayjs.default)(currentDate).day(),
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
- if (firstAvailableDate && (0, import_dayjs.default)(currentDate).diff((0, import_dayjs.default)(startDate), "day") > 31) {
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, import_dayjs.default)(currentDate).add(1, "day");
3356
+ currentDate = (0, _dayjs.default)(currentDate).add(1, 'day');
3166
3357
  }
3167
- dates = (0, import_utils4.handleAvailableDateByResource)(res.data, dates);
3358
+ // 最终把资源数据也加到日期内
3359
+ dates = (0, _utils4.handleAvailableDateByResource)(res.data, dates);
3168
3360
  this.store.date.setDateList(dates);
3169
- if (!this.store.currentProductMeta)
3170
- this.store.currentProductMeta = {};
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, import_dayjs.default)(currentDate).format("YYYY-MM-DD")
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((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
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((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
3188
- return cartItems.some((n) => {
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
- return false;
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((n) => n._id === id);
3200
- return cartItem && (0, import_utils5.isNormalProduct)(cartItem._productOrigin);
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("/customer/metadata", params);
3396
+ return this.request.get('/customer/metadata', params);
3207
3397
  }
3208
- };
3209
- // Annotate the CommonJS export names for ESM import in node:
3210
- 0 && (module.exports = {
3211
- BookingByStepImpl
3212
- });
3398
+ }
3399
+ exports.BookingByStepImpl = BookingByStepImpl;