@pisell/pisellos 2.1.67 → 2.1.71

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.
@@ -20,7 +20,9 @@ export interface ITime {
20
20
  date: string;
21
21
  week: string;
22
22
  weekNum: number;
23
- status: 'unavailable' | 'available';
23
+ status: 'unavailable' | 'available' | 'lots_of_space' | 'filling_up_fast' | 'sold_out';
24
+ summaryCount?: number;
25
+ availableCount?: number;
24
26
  resource?: any[];
25
27
  color?: string[];
26
28
  }
@@ -108,7 +108,6 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
108
108
  if (!product.isNeedHolder) return true;
109
109
  // 商品需要holder,但父预约及商品都无holder,返回false
110
110
  if (!orderHolderId && !productHolderId) return false;
111
-
112
111
  // 最终直接匹配 holder 是否相同
113
112
  return (productHolderId || orderHolderId) === discount.holder.holder_id;
114
113
  }
@@ -146,10 +145,11 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
146
145
  }
147
146
 
148
147
  // 合并新旧折扣列表,并计算折扣结果,注意,如果旧折扣里有 isEditMode 为 true 的优惠券,则不合并
148
+ // 保留之前扫码得到的商品券(isScan: true)
149
149
  var filteredOldDiscountList = oldDiscountList.filter(function (discount) {
150
- return !discount.isEditMode && discount.tag !== 'good_pass';
150
+ return !discount.isEditMode && (discount.tag !== 'good_pass' || discount.isScan);
151
151
  });
152
- var mergedDiscountList = uniqueById(uniqueById([].concat(_toConsumableArray(filteredOldDiscountList), _toConsumableArray(newDiscountList))), 'product_id');
152
+ var mergedDiscountList = uniqueById([].concat(_toConsumableArray(filteredOldDiscountList), _toConsumableArray(newDiscountList)));
153
153
  var result = this.calcDiscount({
154
154
  discountList: mergedDiscountList,
155
155
  productList: _toConsumableArray(productList),
@@ -610,7 +610,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
610
610
  // 收集该折扣卡适用的商品(排除被其他专属折扣卡占用的商品)
611
611
  var applicableProducts = [];
612
612
  sortedFlattenedList.forEach(function (flatItem) {
613
- var _flatItem$parentProdu2;
613
+ var _flatItem$parentProdu2, _product$price, _ref5, _flatItem$original_pr;
614
614
  // 🔥 检查该商品是否被其他专属折扣卡占用
615
615
  var occupyingDiscountId = occupiedItems.get(flatItem._id);
616
616
  if (occupyingDiscountId !== undefined && occupyingDiscountId !== discount.id) {
@@ -636,10 +636,14 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
636
636
  // 对于 bundle 子商品,quantity 需要乘以主商品的购买数量
637
637
  var quantity = flatItem.type === 'main' ? product.quantity || 1 : (product.num || 1) * (((_flatItem$parentProdu2 = flatItem.parentProduct) === null || _flatItem$parentProdu2 === void 0 ? void 0 : _flatItem$parentProdu2.quantity) || 1);
638
638
 
639
+ // 对于主商品:使用 price
640
+ // 对于子商品:优先使用 flatItem.original_price,否则使用 flatItem.price
641
+ var originalAmount = flatItem.type === 'main' ? Number((_product$price = product.price) !== null && _product$price !== void 0 ? _product$price : 0) : Number((_ref5 = (_flatItem$original_pr = flatItem.original_price) !== null && _flatItem$original_pr !== void 0 ? _flatItem$original_pr : flatItem.price) !== null && _ref5 !== void 0 ? _ref5 : 0);
642
+
639
643
  // 传递 parentQuantity 用于差值处理时判断是否是真正的"数量为1"
640
644
  var productData = {
641
645
  productId: flatItem._id,
642
- amount: Number(product.price || 0),
646
+ amount: originalAmount,
643
647
  quantity: quantity
644
648
  };
645
649
 
@@ -857,8 +861,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
857
861
  var _product$discount_lis5, _product11, _product11$every;
858
862
  // 主商品:判断自身是否手动折扣
859
863
  isManualDiscount = typeof product.isManualDiscount === 'boolean' ? product.isManualDiscount : product.total != product.origin_total && (product.bundle || []).every(function (item) {
860
- var _ref5;
861
- return !((_ref5 = item.discount_list || []) !== null && _ref5 !== void 0 && _ref5.length);
864
+ var _ref6;
865
+ return !((_ref6 = item.discount_list || []) !== null && _ref6 !== void 0 && _ref6.length);
862
866
  }) && (!((_product$discount_lis5 = product.discount_list) !== null && _product$discount_lis5 !== void 0 && _product$discount_lis5.length) || ((_product11 = product) === null || _product11 === void 0 || (_product11 = _product11.discount_list) === null || _product11 === void 0 || (_product11$every = _product11.every) === null || _product11$every === void 0 ? void 0 : _product11$every.call(_product11, function (item) {
863
867
  return item.type === 'product';
864
868
  })));
@@ -868,8 +872,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
868
872
  if (parentProduct) {
869
873
  var _parentProduct$discou, _parentProduct$discou2, _parentProduct$discou3;
870
874
  isManualDiscount = typeof parentProduct.isManualDiscount === 'boolean' ? parentProduct.isManualDiscount : parentProduct.total != parentProduct.origin_total && (parentProduct.bundle || []).every(function (item) {
871
- var _ref6;
872
- return !((_ref6 = item.discount_list || []) !== null && _ref6 !== void 0 && _ref6.length);
875
+ var _ref7;
876
+ return !((_ref7 = item.discount_list || []) !== null && _ref7 !== void 0 && _ref7.length);
873
877
  }) && (!((_parentProduct$discou = parentProduct.discount_list) !== null && _parentProduct$discou !== void 0 && _parentProduct$discou.length) || (parentProduct === null || parentProduct === void 0 || (_parentProduct$discou2 = parentProduct.discount_list) === null || _parentProduct$discou2 === void 0 || (_parentProduct$discou3 = _parentProduct$discou2.every) === null || _parentProduct$discou3 === void 0 ? void 0 : _parentProduct$discou3.call(_parentProduct$discou2, function (item) {
874
878
  return item.type === 'product';
875
879
  })));
@@ -316,6 +316,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
316
316
  count: number;
317
317
  left: number;
318
318
  summaryCount: number;
319
+ status: keyof TimeStatusMap;
319
320
  }[];
320
321
  /**
321
322
  * 找到多个资源的公共可用时间段
@@ -343,7 +344,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
343
344
  };
344
345
  setOtherData(key: string, value: any): void;
345
346
  getOtherData(key: string): any;
346
- getProductTypeById(id: number): Promise<"normal" | "duration" | "session">;
347
+ getProductTypeById(id: number): Promise<"duration" | "session" | "normal">;
347
348
  /**
348
349
  * 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
349
350
  *
@@ -380,3 +381,9 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
380
381
  */
381
382
  getContactInfo(params: any): Promise<any>;
382
383
  }
384
+ interface TimeStatusMap {
385
+ lots_of_space: true;
386
+ filling_up_fast: true;
387
+ sold_out: true;
388
+ }
389
+ export {};
@@ -2420,6 +2420,7 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2420
2420
  value: function getTimeslotBySchedule(_ref10) {
2421
2421
  var _this$store$currentPr2,
2422
2422
  _targetProductData$pr,
2423
+ _targetProductData$pr2,
2423
2424
  _this14 = this;
2424
2425
  var date = _ref10.date,
2425
2426
  scheduleIds = _ref10.scheduleIds,
@@ -2463,7 +2464,10 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2463
2464
  var firstEnabledResourceId = targetProductData === null || targetProductData === void 0 || (_targetProductData$pr = targetProductData.product_resource) === null || _targetProductData$pr === void 0 || (_targetProductData$pr = _targetProductData$pr.resources) === null || _targetProductData$pr === void 0 || (_targetProductData$pr = _targetProductData$pr.find(function (n) {
2464
2465
  return n.status === 1;
2465
2466
  })) === null || _targetProductData$pr === void 0 ? void 0 : _targetProductData$pr.id;
2466
-
2467
+ var firstEnabledResourceConfig = targetProductData === null || targetProductData === void 0 || (_targetProductData$pr2 = targetProductData.product_resource) === null || _targetProductData$pr2 === void 0 || (_targetProductData$pr2 = _targetProductData$pr2.resources) === null || _targetProductData$pr2 === void 0 ? void 0 : _targetProductData$pr2.find(function (n) {
2468
+ return n.status === 1 && n.id === firstEnabledResourceId;
2469
+ });
2470
+ var isMultipleBooking = (firstEnabledResourceConfig === null || firstEnabledResourceConfig === void 0 ? void 0 : firstEnabledResourceConfig.type) === 'multiple';
2467
2471
  // 计算每个日程切片下日程可用的资源的容量总和
2468
2472
  var formatScheduleTimeSlots = scheduleTimeSlots.map(function (item) {
2469
2473
  // 用来计算资源的可使用情况,针对单个schedule 时间片
@@ -2471,6 +2475,7 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2471
2475
  var count = 0;
2472
2476
  var bookingLeft = 0;
2473
2477
  var summaryCount = 0;
2478
+ var summaryConfigCount = 0;
2474
2479
  // 遍历所有资源
2475
2480
  allProductResources === null || allProductResources === void 0 || allProductResources.forEach(function (m) {
2476
2481
  // 遍历所有资源的上工时间片
@@ -2484,9 +2489,10 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2484
2489
  // n.start_at 是 2025-06-30 15:00 end_at 2025-06-30 17:00
2485
2490
  // item.start 是 2025-06-30 16:00 item.end 是 2025-06-30 19:00
2486
2491
  // 需要判断 n.start_at 和 n.end_at 是否在 item.start 和 item.end 之间
2487
- // 如果 n.start_at 和 n.end_at 在 item.start 和 item.end 有交集,则此时间需要计算
2492
+ // 如果是仅用于计算的资源, n.start_at 和 n.end_at 在 item.start 和 item.end 有交集,则此时间需要计算
2493
+ // https://project.feishu.cn/v2qint/bug/detail/6657165010
2488
2494
  var mTimes = m.times.filter(function (n) {
2489
- return !dayjs(n.start_at).isAfter(dayjs(item.start), 'minute') && !dayjs(n.end_at).isBefore(dayjs(item.end), 'minute') || dayjs(n.start_at).isBefore(dayjs(item.end), 'minute') && dayjs(n.end_at).isAfter(dayjs(item.start), 'minute');
2495
+ return !dayjs(n.start_at).isAfter(dayjs(item.start), 'minute') && !dayjs(n.end_at).isBefore(dayjs(item.end), 'minute') || m.onlyComputed && dayjs(n.start_at).isBefore(dayjs(item.end), 'minute') && dayjs(n.end_at).isAfter(dayjs(item.start), 'minute');
2490
2496
  });
2491
2497
  // 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
2492
2498
  if (mTimes.length === 0) {
@@ -2518,6 +2524,14 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2518
2524
  }
2519
2525
  currentResourcesTimeSlotCanUsedArr.push(res.usable);
2520
2526
  });
2527
+ if (m.form_id === firstEnabledResourceId) {
2528
+ // 确认当前资源是单个预约还是多个预约,单个预约则只需要计数,多个预约才添加容量
2529
+ if (isMultipleBooking) {
2530
+ summaryConfigCount += m.capacity;
2531
+ } else {
2532
+ summaryConfigCount += 1;
2533
+ }
2534
+ }
2521
2535
  // 在已经选定时间的情况下,只要canUseTime如果有一个 false 那就不可用
2522
2536
  if (!currentResourcesTimeSlotCanUsedArr.some(function (n) {
2523
2537
  return n === false;
@@ -2672,6 +2686,28 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2672
2686
  });
2673
2687
  var startDayJs = dayjs(item.start);
2674
2688
  var endDayJs = dayjs(item.end);
2689
+
2690
+ // 状态
2691
+ // 如果是isMultipleBooking
2692
+ // lots_of_space: summaryCount / summaryConfigCount > 0.5
2693
+ // filling_up_fast: summaryCount / summaryConfigCount <= 0.5 && summaryCount > 0
2694
+ // sold_out: bookingLeft = 0
2695
+ // 如果不是isMultipleBooking
2696
+ // lots_of_space: bookingLeft / summaryConfigCount > 0.5
2697
+ // filling_up_fast: bookingLeft / summaryConfigCount <= 0.5 && count > 0
2698
+ // sold_out: bookingLeft = 0
2699
+ var timeStatus = 'sold_out';
2700
+ if (bookingLeft === 0) timeStatus = 'sold_out';else if (isMultipleBooking) {
2701
+ if (summaryConfigCount === 0) timeStatus = 'sold_out';else {
2702
+ var usageRatio = summaryCount / summaryConfigCount;
2703
+ if (usageRatio > 0.5) timeStatus = 'lots_of_space';else if (summaryCount > 0) timeStatus = 'filling_up_fast';else timeStatus = 'sold_out';
2704
+ }
2705
+ } else {
2706
+ if (summaryConfigCount === 0) timeStatus = 'sold_out';else {
2707
+ var _usageRatio = bookingLeft / summaryConfigCount;
2708
+ if (_usageRatio > 0.5) timeStatus = 'lots_of_space';else if (count > 0) timeStatus = 'filling_up_fast';else timeStatus = 'sold_out';
2709
+ }
2710
+ }
2675
2711
  return {
2676
2712
  start_time: startDayJs.format('HH:mm'),
2677
2713
  end_time: endDayJs.format('HH:mm'),
@@ -2679,7 +2715,8 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2679
2715
  end_at: endDayJs,
2680
2716
  count: count,
2681
2717
  left: bookingLeft,
2682
- summaryCount: summaryCount
2718
+ summaryCount: summaryCount,
2719
+ status: timeStatus
2683
2720
  };
2684
2721
  });
2685
2722
  return formatScheduleTimeSlots;
@@ -3864,12 +3901,14 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
3864
3901
  });
3865
3902
  targetSchedules = this.store.schedule.getScheduleListByIds(tempProducts['schedule.ids']);
3866
3903
  _loop7 = /*#__PURE__*/_regeneratorRuntime().mark(function _loop7() {
3867
- var currentDateStr, status, _checkSessionProductL, latestStartDate, earliestEndDate, scheduleByDate, minTimeMaxTime, scheduleTimeSlots, timesSlotCanUse;
3904
+ var currentDateStr, status, summaryCount, availableCount, _checkSessionProductL, latestStartDate, earliestEndDate, scheduleByDate, minTimeMaxTime, scheduleTimeSlots, timesSlotCanUse, dateStatus, usageRatio;
3868
3905
  return _regeneratorRuntime().wrap(function _loop7$(_context27) {
3869
3906
  while (1) switch (_context27.prev = _context27.next) {
3870
3907
  case 0:
3871
3908
  currentDateStr = currentDate.format('YYYY-MM-DD');
3872
- status = 'available'; // 1. 检查商品的提前量等情况是否满足
3909
+ status = 'available';
3910
+ summaryCount = 0;
3911
+ availableCount = 0; // 1. 检查商品的提前量等情况是否满足
3873
3912
  _checkSessionProductL = checkSessionProductLeadTime(tempProducts), latestStartDate = _checkSessionProductL.latestStartDate, earliestEndDate = _checkSessionProductL.earliestEndDate;
3874
3913
  if (latestStartDate || earliestEndDate) {
3875
3914
  // 如果时间在最早开始时间之前,则设置为不可用
@@ -3895,17 +3934,25 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
3895
3934
  if (status === 'available') {
3896
3935
  minTimeMaxTime = calcMinTimeMaxTimeBySchedules(targetSchedules, {}, currentDateStr);
3897
3936
  scheduleTimeSlots = getAllSortedDateRanges(minTimeMaxTime); // 同一天内多个时间片下 只要有一个可用则视为可用
3898
- timesSlotCanUse = scheduleTimeSlots.some(function (item) {
3937
+ timesSlotCanUse = false;
3938
+ scheduleTimeSlots.forEach(function (item) {
3899
3939
  // 用来计算资源的可使用情况,针对单个schedule 时间片
3900
3940
  var resourcesUseableMap = {};
3901
3941
  // 遍历产品下启用的资源
3902
3942
  // 必须要保证每种类型的资源都至少有一个能够在对应时间点被选择
3903
- return openResources.every(function (resource) {
3943
+ // 求出第一个资源的剩余量和总量
3944
+ // 剩余量=每个资源在每个时间片内剩余之和
3945
+ // 总量=每个资源在每个时间片内资源总量之和
3946
+ var isAllResourceTypesUseable = true;
3947
+ openResources.forEach(function (resource) {
3948
+ // if (!isAllResourceTypesUseable) return;
3949
+
3904
3950
  // 获取当前资源类型的资源列表
3905
3951
  var currentResourcesList = allProductResources.filter(function (n) {
3906
3952
  return n.form_id === resource.resource_type_id;
3907
3953
  });
3908
- return currentResourcesList === null || currentResourcesList === void 0 ? void 0 : currentResourcesList.some(function (m) {
3954
+ var isAnyResourceUseableInType = false;
3955
+ currentResourcesList === null || currentResourcesList === void 0 || currentResourcesList.forEach(function (m) {
3909
3956
  // 遍历所有资源的上工时间片
3910
3957
  // m.times 需要做个过滤,假设 timeSlice.start_at 是 09:30 timeSlice.end_at 是 11:30
3911
3958
  // time 是 time.start_at = 2025-05-26 10:30, time.end_at = 2025-05-26 12:30
@@ -3913,12 +3960,20 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
3913
3960
  var mTimes = m.times.filter(function (n) {
3914
3961
  return !dayjs(n.start_at).isAfter(dayjs(item.start), 'minute') && !dayjs(n.end_at).isBefore(dayjs(item.end), 'minute');
3915
3962
  });
3963
+
3916
3964
  // 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
3917
- if (mTimes.length === 0) {
3918
- return;
3965
+ if (mTimes.length === 0) return;
3966
+ // 如果资源可用则把他的容量纳入总计
3967
+ if (resource.type === 'multiple') {
3968
+ summaryCount += m.capacity;
3969
+ } else {
3970
+ summaryCount += 1;
3919
3971
  }
3920
- var targetCanUseTimes = mTimes.some(function (childTiem) {
3972
+ var isAnyTimeSliceUseable = false;
3973
+ mTimes.forEach(function (childTiem) {
3921
3974
  var _tempProducts3;
3975
+ if (isAnyTimeSliceUseable) return;
3976
+
3922
3977
  // 挨个去匹配某个工作时间段结合当前日程时间,资源能不能用,有多少容量能用
3923
3978
  var res = getIsUsableByTimeItem({
3924
3979
  timeSlice: {
@@ -3936,11 +3991,21 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
3936
3991
  if ((resourcesUseableMap === null || resourcesUseableMap === void 0 ? void 0 : resourcesUseableMap[m.id]) !== false && res.reason !== 'capacityOnly') {
3937
3992
  resourcesUseableMap[m.id] = res.usable;
3938
3993
  }
3939
- return res.usable && !m.onlyComputed;
3994
+ if (res.usable && !m.onlyComputed) {
3995
+ isAnyTimeSliceUseable = true;
3996
+ if (resource.type === 'multiple') {
3997
+ availableCount += res.remainingCapacity;
3998
+ } else {
3999
+ availableCount += 1;
4000
+ }
4001
+ }
4002
+ ;
3940
4003
  });
3941
- return targetCanUseTimes;
4004
+ if (isAnyTimeSliceUseable) isAnyResourceUseableInType = true;
3942
4005
  });
4006
+ if (!isAnyResourceUseableInType) isAllResourceTypesUseable = false;
3943
4007
  });
4008
+ if (isAllResourceTypesUseable) timesSlotCanUse = true;
3944
4009
  });
3945
4010
  if (!timesSlotCanUse) {
3946
4011
  status = 'unavailable';
@@ -3949,22 +4014,36 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
3949
4014
  firstAvailableDate = currentDateStr;
3950
4015
  }
3951
4016
  }
4017
+ // 状态: lots_of_space: availableCount / summaryCount > 0.5
4018
+ // filling_up_fast: availableCount / summaryCount <= 0.5 && availableCount > 0
4019
+ // sold_out: summaryCount = 0
4020
+ // unavailable: summaryCount > 0 && availableCount = 0
4021
+
4022
+ if (status === 'unavailable') {
4023
+ // dateStatus = 'unavailable'
4024
+ if (availableCount === 0 && summaryCount > 0) dateStatus = 'sold_out';else dateStatus = 'unavailable';
4025
+ } else {
4026
+ usageRatio = availableCount / summaryCount;
4027
+ if (usageRatio > 0.5) dateStatus = 'lots_of_space';else dateStatus = 'filling_up_fast';
4028
+ }
3952
4029
  dates.push({
3953
4030
  date: dayjs(currentDate).format('YYYY-MM-DD'),
3954
4031
  week: dayjs(currentDate).format('ddd'),
3955
4032
  weekNum: dayjs(currentDate).day(),
3956
- status: status
4033
+ summaryCount: summaryCount,
4034
+ availableCount: availableCount,
4035
+ status: dateStatus
3957
4036
  });
3958
4037
 
3959
4038
  // 如果 firstAvailableDate 距离 startDate 大于 14 天了,则后面就不需要再找了,也是一种性能保护
3960
4039
  if (!(firstAvailableDate && dayjs(currentDate).diff(dayjs(startDate), 'day') > 31)) {
3961
- _context27.next = 9;
4040
+ _context27.next = 12;
3962
4041
  break;
3963
4042
  }
3964
4043
  return _context27.abrupt("return", 1);
3965
- case 9:
4044
+ case 12:
3966
4045
  currentDate = dayjs(currentDate).add(1, 'day');
3967
- case 10:
4046
+ case 13:
3968
4047
  case "end":
3969
4048
  return _context27.stop();
3970
4049
  }
@@ -320,7 +320,7 @@ export function checkTimeSlotCapacity(timeSlotStart, timeSlotEnd, cartItems, all
320
320
  resourcesInType.forEach(function (resource) {
321
321
  // 过滤出在时间段内的资源时间片
322
322
  var availableTimes = resource.times.filter(function (time) {
323
- return !dayjs(time.start_at).isAfter(dayjs(timeSlotStart), 'minute') && !dayjs(time.end_at).isBefore(dayjs(timeSlotEnd), 'minute') || dayjs(time.start_at).isBefore(dayjs(timeSlotEnd), 'minute') && dayjs(time.end_at).isAfter(dayjs(timeSlotStart), 'minute');
323
+ return !dayjs(time.start_at).isAfter(dayjs(timeSlotStart), 'minute') && !dayjs(time.end_at).isBefore(dayjs(timeSlotEnd), 'minute') || resource.onlyComputed && dayjs(time.start_at).isBefore(dayjs(timeSlotEnd), 'minute') && dayjs(time.end_at).isAfter(dayjs(timeSlotStart), 'minute');
324
324
  });
325
325
  if (availableTimes.length > 0) {
326
326
  // 简化逻辑:如果资源在时间段内有可用时间,就计算其容量
@@ -115,7 +115,7 @@ export declare class BookingTicketImpl extends BaseModule implements Module {
115
115
  * 获取当前的客户搜索条件
116
116
  * @returns 当前搜索条件
117
117
  */
118
- getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
118
+ getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
119
119
  /**
120
120
  * 获取客户列表状态(包含滚动加载相关状态)
121
121
  * @returns 客户状态
@@ -20,7 +20,9 @@ export interface ITime {
20
20
  date: string;
21
21
  week: string;
22
22
  weekNum: number;
23
- status: 'unavailable' | 'available';
23
+ status: 'unavailable' | 'available' | 'lots_of_space' | 'filling_up_fast' | 'sold_out';
24
+ summaryCount?: number;
25
+ availableCount?: number;
24
26
  resource?: any[];
25
27
  color?: string[];
26
28
  }
@@ -96,11 +96,13 @@ var RulesModule = class extends import_BaseModule.BaseModule {
96
96
  productList
97
97
  };
98
98
  }
99
- const filteredOldDiscountList = oldDiscountList.filter((discount) => !discount.isEditMode && discount.tag !== "good_pass");
100
- const mergedDiscountList = (0, import_utils.uniqueById)((0, import_utils.uniqueById)([
99
+ const filteredOldDiscountList = oldDiscountList.filter(
100
+ (discount) => !discount.isEditMode && (discount.tag !== "good_pass" || discount.isScan)
101
+ );
102
+ const mergedDiscountList = (0, import_utils.uniqueById)([
101
103
  ...filteredOldDiscountList,
102
104
  ...newDiscountList
103
- ]), "product_id");
105
+ ]);
104
106
  const result = this.calcDiscount({
105
107
  discountList: mergedDiscountList,
106
108
  productList: [...productList],
@@ -431,9 +433,10 @@ var RulesModule = class extends import_BaseModule.BaseModule {
431
433
  };
432
434
  }
433
435
  const quantity = flatItem.type === "main" ? product.quantity || 1 : (product.num || 1) * (((_a = flatItem.parentProduct) == null ? void 0 : _a.quantity) || 1);
436
+ const originalAmount = flatItem.type === "main" ? Number(product.price ?? 0) : Number(flatItem.original_price ?? flatItem.price ?? 0);
434
437
  const productData = {
435
438
  productId: flatItem._id,
436
- amount: Number(product.price || 0),
439
+ amount: originalAmount,
437
440
  quantity
438
441
  };
439
442
  if (flatItem.type === "bundle") {
@@ -316,6 +316,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
316
316
  count: number;
317
317
  left: number;
318
318
  summaryCount: number;
319
+ status: keyof TimeStatusMap;
319
320
  }[];
320
321
  /**
321
322
  * 找到多个资源的公共可用时间段
@@ -343,7 +344,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
343
344
  };
344
345
  setOtherData(key: string, value: any): void;
345
346
  getOtherData(key: string): any;
346
- getProductTypeById(id: number): Promise<"normal" | "duration" | "session">;
347
+ getProductTypeById(id: number): Promise<"duration" | "session" | "normal">;
347
348
  /**
348
349
  * 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
349
350
  *
@@ -380,3 +381,9 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
380
381
  */
381
382
  getContactInfo(params: any): Promise<any>;
382
383
  }
384
+ interface TimeStatusMap {
385
+ lots_of_space: true;
386
+ filling_up_fast: true;
387
+ sold_out: true;
388
+ }
389
+ export {};
@@ -1685,7 +1685,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1685
1685
  resources,
1686
1686
  product
1687
1687
  }) {
1688
- var _a, _b, _c, _d, _e;
1688
+ var _a, _b, _c, _d, _e, _f, _g;
1689
1689
  const targetProduct = this.store.currentProduct;
1690
1690
  const targetProductData = product || targetProduct;
1691
1691
  let targetSchedules = [];
@@ -1731,17 +1731,22 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1731
1731
  const firstEnabledResourceId = (_e = (_d = (_c = targetProductData == null ? void 0 : targetProductData.product_resource) == null ? void 0 : _c.resources) == null ? void 0 : _d.find(
1732
1732
  (n) => n.status === 1
1733
1733
  )) == null ? void 0 : _e.id;
1734
+ const firstEnabledResourceConfig = (_g = (_f = targetProductData == null ? void 0 : targetProductData.product_resource) == null ? void 0 : _f.resources) == null ? void 0 : _g.find(
1735
+ (n) => n.status === 1 && n.id === firstEnabledResourceId
1736
+ );
1737
+ const isMultipleBooking = (firstEnabledResourceConfig == null ? void 0 : firstEnabledResourceConfig.type) === "multiple";
1734
1738
  const formatScheduleTimeSlots = scheduleTimeSlots.map((item) => {
1735
1739
  const resourcesUseableMap = {};
1736
1740
  let count = 0;
1737
1741
  let bookingLeft = 0;
1738
1742
  let summaryCount = 0;
1743
+ let summaryConfigCount = 0;
1739
1744
  allProductResources == null ? void 0 : allProductResources.forEach((m) => {
1740
1745
  let currentResourcesCount = 0;
1741
1746
  let currentResourcesSummaryCount = 0;
1742
1747
  const currentResourcesTimeSlotCanUsedArr = [];
1743
1748
  const mTimes = m.times.filter((n) => {
1744
- 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") || (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");
1749
+ 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");
1745
1750
  });
1746
1751
  if (mTimes.length === 0) {
1747
1752
  return;
@@ -1771,6 +1776,13 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1771
1776
  }
1772
1777
  currentResourcesTimeSlotCanUsedArr.push(res.usable);
1773
1778
  });
1779
+ if (m.form_id === firstEnabledResourceId) {
1780
+ if (isMultipleBooking) {
1781
+ summaryConfigCount += m.capacity;
1782
+ } else {
1783
+ summaryConfigCount += 1;
1784
+ }
1785
+ }
1774
1786
  if (!currentResourcesTimeSlotCanUsedArr.some(
1775
1787
  (n) => n === false
1776
1788
  ) && // 只统计第一种资源的容量和 left
@@ -1884,6 +1896,34 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1884
1896
  });
1885
1897
  const startDayJs = (0, import_dayjs.default)(item.start);
1886
1898
  const endDayJs = (0, import_dayjs.default)(item.end);
1899
+ let timeStatus = "sold_out";
1900
+ if (bookingLeft === 0)
1901
+ timeStatus = "sold_out";
1902
+ else if (isMultipleBooking) {
1903
+ if (summaryConfigCount === 0)
1904
+ timeStatus = "sold_out";
1905
+ else {
1906
+ const usageRatio = summaryCount / summaryConfigCount;
1907
+ if (usageRatio > 0.5)
1908
+ timeStatus = "lots_of_space";
1909
+ else if (summaryCount > 0)
1910
+ timeStatus = "filling_up_fast";
1911
+ else
1912
+ timeStatus = "sold_out";
1913
+ }
1914
+ } else {
1915
+ if (summaryConfigCount === 0)
1916
+ timeStatus = "sold_out";
1917
+ else {
1918
+ const usageRatio = bookingLeft / summaryConfigCount;
1919
+ if (usageRatio > 0.5)
1920
+ timeStatus = "lots_of_space";
1921
+ else if (count > 0)
1922
+ timeStatus = "filling_up_fast";
1923
+ else
1924
+ timeStatus = "sold_out";
1925
+ }
1926
+ }
1887
1927
  return {
1888
1928
  start_time: startDayJs.format("HH:mm"),
1889
1929
  end_time: endDayJs.format("HH:mm"),
@@ -1891,7 +1931,8 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1891
1931
  end_at: endDayJs,
1892
1932
  count,
1893
1933
  left: bookingLeft,
1894
- summaryCount
1934
+ summaryCount,
1935
+ status: timeStatus
1895
1936
  };
1896
1937
  });
1897
1938
  return formatScheduleTimeSlots;
@@ -2662,6 +2703,8 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
2662
2703
  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")) {
2663
2704
  const currentDateStr = currentDate.format("YYYY-MM-DD");
2664
2705
  let status = "available";
2706
+ let summaryCount = 0;
2707
+ let availableCount = 0;
2665
2708
  const { latestStartDate, earliestEndDate } = (0, import_resources.checkSessionProductLeadTime)(tempProducts);
2666
2709
  if (latestStartDate || earliestEndDate) {
2667
2710
  if (latestStartDate && (0, import_dayjs.default)(currentDate).isBefore(latestStartDate, "day")) {
@@ -2686,43 +2729,64 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
2686
2729
  currentDateStr
2687
2730
  );
2688
2731
  const scheduleTimeSlots = (0, import_utils3.getAllSortedDateRanges)(minTimeMaxTime);
2689
- const timesSlotCanUse = scheduleTimeSlots.some((item) => {
2732
+ let timesSlotCanUse = false;
2733
+ scheduleTimeSlots.forEach((item) => {
2690
2734
  const resourcesUseableMap = {};
2691
- return openResources.every((resource) => {
2735
+ let isAllResourceTypesUseable = true;
2736
+ openResources.forEach((resource) => {
2692
2737
  const currentResourcesList = allProductResources.filter(
2693
2738
  (n) => n.form_id === resource.resource_type_id
2694
2739
  );
2695
- return currentResourcesList == null ? void 0 : currentResourcesList.some((m) => {
2740
+ let isAnyResourceUseableInType = false;
2741
+ currentResourcesList == null ? void 0 : currentResourcesList.forEach((m) => {
2696
2742
  const mTimes = m.times.filter((n) => {
2697
2743
  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");
2698
2744
  });
2699
- if (mTimes.length === 0) {
2745
+ if (mTimes.length === 0)
2700
2746
  return;
2747
+ if (resource.type === "multiple") {
2748
+ summaryCount += m.capacity;
2749
+ } else {
2750
+ summaryCount += 1;
2701
2751
  }
2702
- const targetCanUseTimes = mTimes.some(
2703
- (childTiem) => {
2704
- const res2 = (0, import_resources.getIsUsableByTimeItem)({
2705
- timeSlice: {
2706
- start_time: item.start,
2707
- end_time: item.end,
2708
- start_at: (0, import_dayjs.default)(item.start),
2709
- end_at: (0, import_dayjs.default)(item.end)
2710
- },
2711
- time: childTiem,
2712
- resource: m,
2713
- currentCount: 1,
2714
- resourcesUseableMap,
2715
- cut_off_time: tempProducts == null ? void 0 : tempProducts.cut_off_time
2716
- });
2717
- if ((resourcesUseableMap == null ? void 0 : resourcesUseableMap[m.id]) !== false && res2.reason !== "capacityOnly") {
2718
- resourcesUseableMap[m.id] = res2.usable;
2752
+ let isAnyTimeSliceUseable = false;
2753
+ mTimes.forEach((childTiem) => {
2754
+ if (isAnyTimeSliceUseable)
2755
+ return;
2756
+ const res2 = (0, import_resources.getIsUsableByTimeItem)({
2757
+ timeSlice: {
2758
+ start_time: item.start,
2759
+ end_time: item.end,
2760
+ start_at: (0, import_dayjs.default)(item.start),
2761
+ end_at: (0, import_dayjs.default)(item.end)
2762
+ },
2763
+ time: childTiem,
2764
+ resource: m,
2765
+ currentCount: 1,
2766
+ resourcesUseableMap,
2767
+ cut_off_time: tempProducts == null ? void 0 : tempProducts.cut_off_time
2768
+ });
2769
+ if ((resourcesUseableMap == null ? void 0 : resourcesUseableMap[m.id]) !== false && res2.reason !== "capacityOnly") {
2770
+ resourcesUseableMap[m.id] = res2.usable;
2771
+ }
2772
+ if (res2.usable && !m.onlyComputed) {
2773
+ isAnyTimeSliceUseable = true;
2774
+ if (resource.type === "multiple") {
2775
+ availableCount += res2.remainingCapacity;
2776
+ } else {
2777
+ availableCount += 1;
2719
2778
  }
2720
- return res2.usable && !m.onlyComputed;
2721
2779
  }
2722
- );
2723
- return targetCanUseTimes;
2780
+ ;
2781
+ });
2782
+ if (isAnyTimeSliceUseable)
2783
+ isAnyResourceUseableInType = true;
2724
2784
  });
2785
+ if (!isAnyResourceUseableInType)
2786
+ isAllResourceTypesUseable = false;
2725
2787
  });
2788
+ if (isAllResourceTypesUseable)
2789
+ timesSlotCanUse = true;
2726
2790
  });
2727
2791
  if (!timesSlotCanUse) {
2728
2792
  status = "unavailable";
@@ -2731,11 +2795,26 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
2731
2795
  firstAvailableDate = currentDateStr;
2732
2796
  }
2733
2797
  }
2798
+ let dateStatus;
2799
+ if (status === "unavailable") {
2800
+ if (availableCount === 0 && summaryCount > 0)
2801
+ dateStatus = "sold_out";
2802
+ else
2803
+ dateStatus = "unavailable";
2804
+ } else {
2805
+ const usageRatio = availableCount / summaryCount;
2806
+ if (usageRatio > 0.5)
2807
+ dateStatus = "lots_of_space";
2808
+ else
2809
+ dateStatus = "filling_up_fast";
2810
+ }
2734
2811
  dates.push({
2735
2812
  date: (0, import_dayjs.default)(currentDate).format("YYYY-MM-DD"),
2736
2813
  week: (0, import_dayjs.default)(currentDate).format("ddd"),
2737
2814
  weekNum: (0, import_dayjs.default)(currentDate).day(),
2738
- status
2815
+ summaryCount,
2816
+ availableCount,
2817
+ status: dateStatus
2739
2818
  });
2740
2819
  if (firstAvailableDate && (0, import_dayjs.default)(currentDate).diff((0, import_dayjs.default)(startDate), "day") > 31) {
2741
2820
  break;
@@ -230,7 +230,7 @@ function checkTimeSlotCapacity(timeSlotStart, timeSlotEnd, cartItems, allResourc
230
230
  let totalAvailableCapacity = 0;
231
231
  resourcesInType.forEach((resource) => {
232
232
  const availableTimes = resource.times.filter((time) => {
233
- return !(0, import_dayjs.default)(time.start_at).isAfter((0, import_dayjs.default)(timeSlotStart), "minute") && !(0, import_dayjs.default)(time.end_at).isBefore((0, import_dayjs.default)(timeSlotEnd), "minute") || (0, import_dayjs.default)(time.start_at).isBefore((0, import_dayjs.default)(timeSlotEnd), "minute") && (0, import_dayjs.default)(time.end_at).isAfter((0, import_dayjs.default)(timeSlotStart), "minute");
233
+ return !(0, import_dayjs.default)(time.start_at).isAfter((0, import_dayjs.default)(timeSlotStart), "minute") && !(0, import_dayjs.default)(time.end_at).isBefore((0, import_dayjs.default)(timeSlotEnd), "minute") || resource.onlyComputed && (0, import_dayjs.default)(time.start_at).isBefore((0, import_dayjs.default)(timeSlotEnd), "minute") && (0, import_dayjs.default)(time.end_at).isAfter((0, import_dayjs.default)(timeSlotStart), "minute");
234
234
  });
235
235
  if (availableTimes.length > 0) {
236
236
  totalAvailableCapacity += resource.capacity || 0;
@@ -115,7 +115,7 @@ export declare class BookingTicketImpl extends BaseModule implements Module {
115
115
  * 获取当前的客户搜索条件
116
116
  * @returns 当前搜索条件
117
117
  */
118
- getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
118
+ getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
119
119
  /**
120
120
  * 获取客户列表状态(包含滚动加载相关状态)
121
121
  * @returns 客户状态
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.1.67",
4
+ "version": "2.1.71",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",