@pisell/pisellos 0.0.273 → 0.0.275

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.
@@ -44,7 +44,7 @@ import { handleAvailableDateByResource } from "../../modules/Date/utils";
44
44
  import { areAllNormalProducts, isNormalProduct } from "../../modules/Product/utils";
45
45
  import { calculateResourceAvailableTime, filterConditionTimeSlots, findFastestAvailableResource } from "./utils/timeslots";
46
46
  import { updateAllCartItemPrice } from "../../modules/Cart/utils/changePrice";
47
- import { getCapacityInfoByCartItem, checkSubResourcesCapacity, checkResourceCanUseByCapacity, getResourcesIdsByProduct, checkTimeSlotCapacity } from "./utils/capacity";
47
+ import { getCapacityInfoByCartItem, checkSubResourcesCapacity, checkResourceCanUseByCapacity, calculateCartItemsCapacityUsageByResourceType, getResourcesIdsByProduct, checkTimeSlotCapacity } from "./utils/capacity";
48
48
  import { checkProductStock } from "./utils/stock";
49
49
  export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
50
50
  _inherits(BookingByStepImpl, _BaseModule);
@@ -2367,9 +2367,7 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2367
2367
  }, {
2368
2368
  key: "getTimeslotBySchedule",
2369
2369
  value: function getTimeslotBySchedule(_ref10) {
2370
- var _this$store$currentPr2,
2371
- _targetProductData$pr,
2372
- _this14 = this;
2370
+ var _this$store$currentPr2, _targetProductData$pr;
2373
2371
  var date = _ref10.date,
2374
2372
  scheduleIds = _ref10.scheduleIds,
2375
2373
  resources = _ref10.resources,
@@ -2417,159 +2415,139 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2417
2415
  var formatScheduleTimeSlots = scheduleTimeSlots.map(function (item) {
2418
2416
  // 用来计算资源的可使用情况,针对单个schedule 时间片
2419
2417
  var resourcesUseableMap = {};
2420
- var count = 0;
2421
- var bookingLeft = 0;
2422
- // 遍历所有资源
2423
- allProductResources === null || allProductResources === void 0 || allProductResources.forEach(function (m) {
2424
- // 遍历所有资源的上工时间片
2425
- var currentResourcesCount = 0;
2426
- var currentResourcesTimeSlotCanUsedArr = [];
2427
- // m.times 需要做个过滤,假设 timeSlice.start_at 是 09:30 timeSlice.end_at 是 11:30
2428
- // time 是 time.start_at = 2025-05-26 10:30, time.end_at = 2025-05-26 12:30
2429
- // 需要判断 time 的开始结束时间 是否包含timeSlice的开始结束时间
2430
-
2431
- // n.start_at 是 2025-06-30 15:00 end_at 2025-06-30 17:00
2432
- // item.start 是 2025-06-30 16:00 item.end 是 2025-06-30 19:00
2433
- // 需要判断 n.start_at 和 n.end_at 是否在 item.start 和 item.end 之间
2434
- // 如果 n.start_at 和 n.end_at 在 item.start 和 item.end 有交集,则此时间需要计算
2435
- var mTimes = m.times.filter(function (n) {
2436
- 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');
2437
- });
2438
- // 如果在这个区间的时间一个都没有,可以直接认为这个资源不可用
2439
- if (mTimes.length === 0) {
2440
- return;
2441
- }
2442
- mTimes.forEach(function (childTiem) {
2443
- // 挨个去匹配某个工作时间段结合当前日程时间,资源能不能用,有多少容量能用
2444
- var res = getIsUsableByTimeItem({
2445
- timeSlice: {
2446
- start_time: item.start,
2447
- end_time: item.end,
2448
- start_at: dayjs(item.start),
2449
- end_at: dayjs(item.end)
2450
- },
2451
- time: childTiem,
2452
- resource: m,
2453
- currentCount: 1,
2454
- resourcesUseableMap: resourcesUseableMap,
2455
- cut_off_time: targetProductData === null || targetProductData === void 0 ? void 0 : targetProductData.cut_off_time
2456
- });
2457
- if ((resourcesUseableMap === null || resourcesUseableMap === void 0 ? void 0 : resourcesUseableMap[m.id]) !== false && res.reason !== 'capacityOnly') {
2458
- resourcesUseableMap[m.id] = res.usable;
2459
- }
2460
- if (res.usable && res.remainingCapacity >= count && !m.onlyComputed) {
2461
- currentResourcesCount = res.remainingCapacity;
2462
- }
2463
- currentResourcesTimeSlotCanUsedArr.push(res.usable);
2464
- });
2465
- // 在已经选定时间的情况下,只要canUseTime如果有一个 false 那就不可用
2466
- if (!currentResourcesTimeSlotCanUsedArr.some(function (n) {
2467
- return n === false;
2468
- }) &&
2469
- // 只统计第一种资源的容量和 left
2470
- m.form_id === firstEnabledResourceId) {
2471
- if (currentResourcesCount >= count) {
2472
- count = currentResourcesCount;
2473
- }
2474
- if (!m.onlyComputed) {
2475
- bookingLeft += 1;
2476
- }
2418
+
2419
+ // 按资源类型分组
2420
+ var resourceTypeMap = {};
2421
+ allProductResources === null || allProductResources === void 0 || allProductResources.forEach(function (resource) {
2422
+ var _resource$form_id;
2423
+ var formId = ((_resource$form_id = resource.form_id) === null || _resource$form_id === void 0 ? void 0 : _resource$form_id.toString()) || 'default';
2424
+ if (!resourceTypeMap[formId]) {
2425
+ resourceTypeMap[formId] = [];
2477
2426
  }
2427
+ resourceTypeMap[formId].push(resource);
2478
2428
  });
2479
- // 容量检测
2480
- var cartItems = _this14.store.cart.getItems();
2481
- productResources.forEach(function (n) {
2482
- // 单个预约检测规则:
2483
- // 1、跟我一样的商品同一时间在购物车里不可以超过我最少的那种资源的关联的资源个数
2484
- // 2、跟我不一样的商品,只需要跟我当前商品有同一种类型的资源的同一时间的,她配置了几个资源的个数+我配置了几个资源的个数,然后购物车里有几个这样的商品,对应的资源做一个去重,不超过这个去重以后的总数
2485
- if (n.type === 'single') {
2486
- var currentResourcesSet = new Set([].concat(_toConsumableArray(n.optional_resource), _toConsumableArray(n.default_resource)));
2487
- // 规则 1
2488
- var sameCartItems = cartItems.filter(function (m) {
2489
- var _m$_productOrigin, _targetProductData$id;
2490
- return ((_m$_productOrigin = m._productOrigin) === null || _m$_productOrigin === void 0 || (_m$_productOrigin = _m$_productOrigin.id) === null || _m$_productOrigin === void 0 ? void 0 : _m$_productOrigin.toString()) === (targetProductData === null || targetProductData === void 0 || (_targetProductData$id = targetProductData.id) === null || _targetProductData$id === void 0 ? void 0 : _targetProductData$id.toString()) && "".concat(m.start_date, " ").concat(m.start_time) === item.start && "".concat(m.start_date, " ").concat(m.end_time) === item.end;
2491
- });
2492
- if (sameCartItems.length > 0 && sameCartItems.length >= currentResourcesSet.size) {
2493
- bookingLeft = 0;
2494
- }
2495
- // 规则 2
2496
- var otherCartItems = cartItems.filter(function (m) {
2497
- var _m$_productOrigin2, _targetProductData$id2;
2498
- return ((_m$_productOrigin2 = m._productOrigin) === null || _m$_productOrigin2 === void 0 || (_m$_productOrigin2 = _m$_productOrigin2.id) === null || _m$_productOrigin2 === void 0 ? void 0 : _m$_productOrigin2.toString()) !== (targetProductData === null || targetProductData === void 0 || (_targetProductData$id2 = targetProductData.id) === null || _targetProductData$id2 === void 0 ? void 0 : _targetProductData$id2.toString()) && "".concat(m.start_date, " ").concat(m.start_time) === item.start && "".concat(m.start_date, " ").concat(m.end_time) === item.end;
2499
- });
2500
- otherCartItems.forEach(function (m) {
2501
- var _m$_productOrigin3;
2502
- var sameTypeResources = (_m$_productOrigin3 = m._productOrigin) === null || _m$_productOrigin3 === void 0 || (_m$_productOrigin3 = _m$_productOrigin3.product_resource) === null || _m$_productOrigin3 === void 0 || (_m$_productOrigin3 = _m$_productOrigin3.resources) === null || _m$_productOrigin3 === void 0 ? void 0 : _m$_productOrigin3.find(function (m) {
2503
- return m.type === n.type;
2429
+
2430
+ // 计算购物车中商品的容量占用情况
2431
+ var cartCapacityUsage = calculateCartItemsCapacityUsageByResourceType({
2432
+ cartItems: cartItems,
2433
+ timeSlotStart: item.start,
2434
+ timeSlotEnd: item.end,
2435
+ allProductResources: allProductResources || []
2436
+ });
2437
+
2438
+ // 计算每种资源类型的可用容量
2439
+ var minAvailableCount = Number.MAX_SAFE_INTEGER;
2440
+ var totalBookingLeft = 0;
2441
+ var hasAnyAvailableResource = false;
2442
+ Object.keys(resourceTypeMap).forEach(function (formId) {
2443
+ var resourcesInType = resourceTypeMap[formId];
2444
+ if (resourcesInType.length === 0) return;
2445
+
2446
+ // 确定这种资源类型的预约类型(取第一个资源的类型)
2447
+ var firstResource = resourcesInType[0];
2448
+ var isMultipleBooking = firstResource.resourceType === 'multiple';
2449
+ var cartUsageForThisType = cartCapacityUsage[formId] || 0;
2450
+ if (isMultipleBooking) {
2451
+ // 多个预约:计算所有资源的总可用容量
2452
+ var totalAvailableCapacity = 0;
2453
+ var availableResourceCount = 0;
2454
+ resourcesInType.forEach(function (resource) {
2455
+ var mTimes = resource.times.filter(function (n) {
2456
+ 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');
2504
2457
  });
2505
- var sameTypeResourcesSet = new Set([].concat(_toConsumableArray((sameTypeResources === null || sameTypeResources === void 0 ? void 0 : sameTypeResources.optional_resource) || []), _toConsumableArray((sameTypeResources === null || sameTypeResources === void 0 ? void 0 : sameTypeResources.default_resource) || [])));
2506
- // 把sameTypeResourcesSet 加到currentResourcesSet
2507
- sameTypeResourcesSet.forEach(function (resource) {
2508
- return currentResourcesSet.add(resource);
2458
+ if (mTimes.length === 0) return;
2459
+ var resourceAvailableCapacity = 0;
2460
+ mTimes.forEach(function (childTime) {
2461
+ var res = getIsUsableByTimeItem({
2462
+ timeSlice: {
2463
+ start_time: item.start,
2464
+ end_time: item.end,
2465
+ start_at: dayjs(item.start),
2466
+ end_at: dayjs(item.end)
2467
+ },
2468
+ time: childTime,
2469
+ resource: resource,
2470
+ currentCount: 1,
2471
+ resourcesUseableMap: resourcesUseableMap,
2472
+ cut_off_time: targetProductData === null || targetProductData === void 0 ? void 0 : targetProductData.cut_off_time
2473
+ });
2474
+ if ((resourcesUseableMap === null || resourcesUseableMap === void 0 ? void 0 : resourcesUseableMap[resource.id]) !== false && res.reason !== 'capacityOnly') {
2475
+ resourcesUseableMap[resource.id] = res.usable;
2476
+ }
2477
+ if (res.usable && !resource.onlyComputed) {
2478
+ resourceAvailableCapacity = Math.max(resourceAvailableCapacity, res.remainingCapacity);
2479
+ availableResourceCount++;
2480
+ }
2509
2481
  });
2482
+ totalAvailableCapacity += resourceAvailableCapacity;
2510
2483
  });
2511
- if (currentResourcesSet.size > 0 && otherCartItems.length + sameCartItems.length >= currentResourcesSet.size) {
2512
- bookingLeft = 0;
2484
+
2485
+ // 减去购物车中已占用的容量
2486
+ var netAvailableCapacity = Math.max(0, totalAvailableCapacity - cartUsageForThisType);
2487
+ if (netAvailableCapacity < minAvailableCount) {
2488
+ minAvailableCount = netAvailableCapacity;
2513
2489
  }
2514
- } else {
2515
- // 多个预约的检测规则:
2516
- // 规则1、跟我一样的商品同一时间在购物车需要的容量总数不可以超过我配置的资源的 capacity 之和
2517
- var _sameCartItems = cartItems.filter(function (m) {
2518
- var _m$_productOrigin4, _targetProductData$id3;
2519
- return ((_m$_productOrigin4 = m._productOrigin) === null || _m$_productOrigin4 === void 0 || (_m$_productOrigin4 = _m$_productOrigin4.id) === null || _m$_productOrigin4 === void 0 ? void 0 : _m$_productOrigin4.toString()) === (targetProductData === null || targetProductData === void 0 || (_targetProductData$id3 = targetProductData.id) === null || _targetProductData$id3 === void 0 ? void 0 : _targetProductData$id3.toString()) && "".concat(m.start_date, " ").concat(m.start_time) === item.start && "".concat(m.start_date, " ").concat(m.end_time) === item.end;
2520
- });
2521
- var sameCartNeedCapacity = _sameCartItems.reduce(function (acc, curr) {
2522
- return acc + getCapacityInfoByCartItem(curr).currentCapacity;
2523
- }, 0);
2524
- var currentProductResourcesCapacity = n.renderList.reduce(function (acc, curr) {
2525
- return !curr.onlyComputed ? acc + curr.capacity || 0 : acc;
2526
- }, 0);
2527
- if (sameCartNeedCapacity >= currentProductResourcesCapacity) {
2528
- bookingLeft = 0;
2490
+ if (netAvailableCapacity > 0) {
2491
+ hasAnyAvailableResource = true;
2529
2492
  }
2530
- // 规则2、不管是不是跟我一样的商品,只需要跟我当前商品有同一种类型的资源的同一时间的,把所有购物车的 capacity 之和 和 所有当前类型资源的 capacity 之和比较,如果超过了resourcesCapacity,则不可用
2531
- // const otherCartItems = cartItems.filter((m) => m._productOrigin?.id?.toString() !== targetProductData?.id?.toString() && m.start_time === item.start && m.end_time === item.end);
2532
- var otherSameTimesCartItems = cartItems.filter(function (m) {
2533
- return "".concat(m.start_date, " ").concat(m.start_time) === item.start && "".concat(m.start_date, " ").concat(m.end_time) === item.end;
2534
- });
2535
- var otherCartNeedCapacity = otherSameTimesCartItems.reduce(function (acc, curr) {
2536
- return acc + getCapacityInfoByCartItem(curr).currentCapacity;
2537
- }, 0);
2538
- var allRenderList = _toConsumableArray(n.renderList.filter(function (m) {
2539
- return !m.onlyComputed;
2540
- }));
2541
- otherSameTimesCartItems.forEach(function (m) {
2542
- var _m$_productOrigin5;
2543
- var productResources = getResourcesByProduct(getResourcesMap((targetResourceDate === null || targetResourceDate === void 0 ? void 0 : targetResourceDate.resource) || []), ((_m$_productOrigin5 = m._productOrigin) === null || _m$_productOrigin5 === void 0 || (_m$_productOrigin5 = _m$_productOrigin5.product_resource) === null || _m$_productOrigin5 === void 0 ? void 0 : _m$_productOrigin5.resources) || [], selectedResources, 1);
2544
- productResources.forEach(function (m) {
2545
- if (m.id === n.id) {
2546
- m.renderList.forEach(function (n) {
2547
- if (!n.onlyComputed && !allRenderList.find(function (m) {
2548
- return m.id === n.id;
2549
- })) {
2550
- allRenderList.push(n);
2551
- }
2552
- });
2493
+ } else {
2494
+ // 单个预约:计算可用资源个数
2495
+ var _availableResourceCount = 0;
2496
+ resourcesInType.forEach(function (resource) {
2497
+ var mTimes = resource.times.filter(function (n) {
2498
+ 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');
2499
+ });
2500
+ if (mTimes.length === 0) return;
2501
+ var isResourceAvailable = false;
2502
+ mTimes.forEach(function (childTime) {
2503
+ var res = getIsUsableByTimeItem({
2504
+ timeSlice: {
2505
+ start_time: item.start,
2506
+ end_time: item.end,
2507
+ start_at: dayjs(item.start),
2508
+ end_at: dayjs(item.end)
2509
+ },
2510
+ time: childTime,
2511
+ resource: resource,
2512
+ currentCount: 1,
2513
+ resourcesUseableMap: resourcesUseableMap,
2514
+ cut_off_time: targetProductData === null || targetProductData === void 0 ? void 0 : targetProductData.cut_off_time
2515
+ });
2516
+ if ((resourcesUseableMap === null || resourcesUseableMap === void 0 ? void 0 : resourcesUseableMap[resource.id]) !== false && res.reason !== 'capacityOnly') {
2517
+ resourcesUseableMap[resource.id] = res.usable;
2518
+ }
2519
+ if (res.usable && !resource.onlyComputed) {
2520
+ isResourceAvailable = true;
2553
2521
  }
2554
2522
  });
2523
+ if (isResourceAvailable) {
2524
+ _availableResourceCount++;
2525
+ }
2555
2526
  });
2556
- var currentTypeResourcesCapacity = allRenderList.reduce(function (acc, curr) {
2557
- return acc + curr.capacity || 0;
2558
- }, 0);
2559
- if (sameCartNeedCapacity + otherCartNeedCapacity >= currentTypeResourcesCapacity) {
2560
- bookingLeft = 0;
2527
+
2528
+ // 减去购物车中需要占用的资源个数
2529
+ var netAvailableResources = Math.max(0, _availableResourceCount - cartUsageForThisType);
2530
+ if (netAvailableResources < minAvailableCount) {
2531
+ minAvailableCount = netAvailableResources;
2532
+ }
2533
+ if (netAvailableResources > 0) {
2534
+ hasAnyAvailableResource = true;
2561
2535
  }
2536
+ totalBookingLeft += netAvailableResources;
2562
2537
  }
2563
2538
  });
2564
2539
  var startDayJs = dayjs(item.start);
2565
2540
  var endDayJs = dayjs(item.end);
2541
+
2542
+ // 最终的可用容量是所有资源类型中最小的那个
2543
+ var finalCount = hasAnyAvailableResource ? minAvailableCount === Number.MAX_SAFE_INTEGER ? 0 : minAvailableCount : 0;
2566
2544
  return {
2567
2545
  start_time: startDayJs.format('HH:mm'),
2568
2546
  end_time: endDayJs.format('HH:mm'),
2569
2547
  start_at: startDayJs,
2570
2548
  end_at: endDayJs,
2571
- count: count,
2572
- left: bookingLeft
2549
+ count: finalCount,
2550
+ left: Math.max(0, totalBookingLeft)
2573
2551
  };
2574
2552
  });
2575
2553
  return formatScheduleTimeSlots;
@@ -2579,16 +2557,100 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2579
2557
  // 时长类商品关联的资源为多个预约时,在点击进入"选择资源"步骤之前,需要检测当前所有资源的总容量
2580
2558
  // 选择商品数量大于所有资源配置的总容量时,不能进入下一步,需要在"选择商品"这一步时提示。
2581
2559
  // 注意 资源分为多个种类,需要每个种类单独检测,不能一股脑把所有资源的容量加起来检测
2560
+ /**
2561
+ * 找到多个资源的公共可用时间段
2562
+ */
2563
+ }, {
2564
+ key: "findCommonAvailableTimeSlots",
2565
+ value: function findCommonAvailableTimeSlots(resources) {
2566
+ if (resources.length === 0) return [];
2567
+ console.log("\u8BA1\u7B97 ".concat(resources.length, " \u4E2A\u8D44\u6E90\u7684\u516C\u5171\u65F6\u95F4\u6BB5"));
2568
+
2569
+ // 收集所有资源的时间段,转换为统一的时间格式
2570
+ var allTimeSlots = resources.map(function (resource) {
2571
+ return resource.times.map(function (time) {
2572
+ return {
2573
+ start: dayjs(time.start_at),
2574
+ end: dayjs(time.end_at)
2575
+ };
2576
+ });
2577
+ });
2578
+ console.log('所有资源的时间段:', allTimeSlots.map(function (slots) {
2579
+ return slots.map(function (slot) {
2580
+ return "".concat(slot.start.format('HH:mm'), "-").concat(slot.end.format('HH:mm'));
2581
+ });
2582
+ }));
2583
+
2584
+ // 找到公共时间段的交集
2585
+ var commonSlots = allTimeSlots[0]; // 从第一个资源的时间段开始
2586
+ console.log('初始公共时间段:', commonSlots.map(function (slot) {
2587
+ return "".concat(slot.start.format('HH:mm'), "-").concat(slot.end.format('HH:mm'));
2588
+ }));
2589
+
2590
+ // 与其他资源的时间段求交集
2591
+ var _loop2 = function _loop2() {
2592
+ var currentResourceSlots = allTimeSlots[i];
2593
+ var intersections = [];
2594
+
2595
+ // 计算当前公共时间段与下一个资源时间段的交集
2596
+ commonSlots.forEach(function (commonSlot) {
2597
+ currentResourceSlots.forEach(function (currentSlot) {
2598
+ var overlapStart = commonSlot.start.isAfter(currentSlot.start) ? commonSlot.start : currentSlot.start;
2599
+ var overlapEnd = commonSlot.end.isBefore(currentSlot.end) ? commonSlot.end : currentSlot.end;
2600
+
2601
+ // 如果有重叠时间且重叠时间大于0
2602
+ if (overlapStart.isBefore(overlapEnd)) {
2603
+ intersections.push({
2604
+ start: overlapStart,
2605
+ end: overlapEnd
2606
+ });
2607
+ }
2608
+ });
2609
+ });
2610
+ commonSlots = intersections;
2611
+ console.log("\u4E0E\u8D44\u6E90".concat(i, "\u6C42\u4EA4\u96C6\u540E\u7684\u516C\u5171\u65F6\u95F4\u6BB5:"), commonSlots.map(function (slot) {
2612
+ return "".concat(slot.start.format('HH:mm'), "-").concat(slot.end.format('HH:mm'));
2613
+ }));
2614
+
2615
+ // 如果没有公共时间段,直接返回
2616
+ if (commonSlots.length === 0) {
2617
+ console.log('没有找到公共时间段');
2618
+ return {
2619
+ v: []
2620
+ };
2621
+ }
2622
+ },
2623
+ _ret2;
2624
+ for (var i = 1; i < allTimeSlots.length; i++) {
2625
+ _ret2 = _loop2();
2626
+ if (_ret2) return _ret2.v;
2627
+ }
2628
+
2629
+ // 格式化返回结果
2630
+ var result = commonSlots.map(function (slot) {
2631
+ return {
2632
+ startTime: slot.start.format('HH:mm'),
2633
+ endTime: slot.end.format('HH:mm')
2634
+ };
2635
+ });
2636
+ console.log('最终公共时间段:', result);
2637
+ return result;
2638
+ }
2582
2639
  }, {
2583
2640
  key: "checkMaxDurationCapacity",
2584
2641
  value: function checkMaxDurationCapacity() {
2585
- var _this15 = this;
2642
+ var _this14 = this;
2586
2643
  var cartItems = cloneDeep(this.store.cart.getItems());
2587
- if (cartItems.length === 0) return true;
2644
+ if (cartItems.length === 0) return {
2645
+ success: true,
2646
+ minAvailableCount: 0
2647
+ };
2588
2648
 
2589
2649
  // 将购物车商品分为有时间的和没有时间的
2590
2650
  var itemsWithTime = [];
2591
2651
  var itemsWithoutTime = [];
2652
+ // 记录每种资源类型的可用数量
2653
+ var availableCountsByResourceType = [];
2592
2654
  cartItems.forEach(function (cartItem) {
2593
2655
  if (cartItem.start_time && cartItem.end_time && cartItem.start_date) {
2594
2656
  itemsWithTime.push(cartItem);
@@ -2623,48 +2685,215 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2623
2685
  });
2624
2686
  });
2625
2687
 
2626
- // 为每种资源类型获取公共可用时间
2627
- var _loop2 = function _loop2() {
2688
+ // 为每种资源类型检查容量
2689
+ var dateRange = this.store.date.getDateRange();
2690
+ if (!dateRange || dateRange.length === 0) return {
2691
+ success: false,
2692
+ minAvailableCount: 0
2693
+ };
2694
+ var resourcesDates = this.store.date.getDateList();
2695
+ var targetResourceDate = resourcesDates.find(function (n) {
2696
+ return n.date === dateRange[0].date;
2697
+ });
2698
+ if (!targetResourceDate) return {
2699
+ success: false,
2700
+ minAvailableCount: 0
2701
+ };
2702
+ var resourcesMap = getResourcesMap(targetResourceDate.resource || []);
2703
+
2704
+ // 从购物车商品中获取资源类型配置,建立 resourceCode 到 form_id 的映射关系
2705
+ var resourceCodeToFormIdMap = {};
2706
+
2707
+ // 遍历购物车中的商品,收集所有资源类型配置
2708
+ Object.values(itemsByResourceType).flat().forEach(function (cartItem) {
2709
+ var _cartItem$_productOri11;
2710
+ if ((_cartItem$_productOri11 = cartItem._productOrigin) !== null && _cartItem$_productOri11 !== void 0 && (_cartItem$_productOri11 = _cartItem$_productOri11.product_resource) !== null && _cartItem$_productOri11 !== void 0 && _cartItem$_productOri11.resources) {
2711
+ cartItem._productOrigin.product_resource.resources.forEach(function (resourceConfig) {
2712
+ // 只处理启用的资源类型 (status === 1)
2713
+ if (resourceConfig.status === 1 && resourceConfig.code) {
2714
+ var _resourceConfig$id, _resourceConfig$resou;
2715
+ var formId = ((_resourceConfig$id = resourceConfig.id) === null || _resourceConfig$id === void 0 ? void 0 : _resourceConfig$id.toString()) || ((_resourceConfig$resou = resourceConfig.resource_type_id) === null || _resourceConfig$resou === void 0 ? void 0 : _resourceConfig$resou.toString());
2716
+ if (formId) {
2717
+ resourceCodeToFormIdMap[resourceConfig.code] = formId;
2718
+ }
2719
+ }
2720
+ });
2721
+ }
2722
+ });
2723
+ var hasCapacityIssue = false;
2724
+ var resourceCapacityInfo = [];
2725
+
2726
+ // 先检查所有资源类型,收集可用数量信息
2727
+ var _loop3 = function _loop3() {
2728
+ var _resourceTypeConfig;
2628
2729
  var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
2629
2730
  resourceCode = _Object$entries$_i[0],
2630
2731
  items = _Object$entries$_i[1];
2732
+ // 获取该资源类型对应的 form_id
2733
+ var targetFormId = resourceCodeToFormIdMap[resourceCode];
2734
+ if (!targetFormId) {
2735
+ console.log("\u8D44\u6E90\u7C7B\u578B ".concat(resourceCode, " \u627E\u4E0D\u5230\u5BF9\u5E94\u7684 form_id"));
2736
+ return {
2737
+ v: {
2738
+ success: false,
2739
+ minAvailableCount: 0
2740
+ }
2741
+ };
2742
+ }
2743
+
2744
+ // 获取该资源类型的所有资源
2745
+ var resourcesOfThisType = [];
2746
+ items.forEach(function (cartItem) {
2747
+ var productResourceIds = getResourcesIdsByProduct(cartItem._productOrigin);
2748
+ productResourceIds.forEach(function (resourceId) {
2749
+ var _resource$form_id2;
2750
+ var resource = resourcesMap[resourceId];
2751
+ if (resource && ((_resource$form_id2 = resource.form_id) === null || _resource$form_id2 === void 0 ? void 0 : _resource$form_id2.toString()) === targetFormId) {
2752
+ // 避免重复添加同一个资源
2753
+ if (!resourcesOfThisType.find(function (r) {
2754
+ return r.id === resource.id;
2755
+ })) {
2756
+ resourcesOfThisType.push(resource);
2757
+ }
2758
+ }
2759
+ });
2760
+ });
2761
+ if (resourcesOfThisType.length === 0) {
2762
+ console.log("\u8D44\u6E90\u7C7B\u578B ".concat(resourceCode, " \u6CA1\u6709\u627E\u5230\u53EF\u7528\u8D44\u6E90"));
2763
+ return {
2764
+ v: {
2765
+ success: false,
2766
+ minAvailableCount: 0
2767
+ }
2768
+ };
2769
+ }
2770
+
2771
+ // 检查资源类型(单个预约 vs 多个预约)
2772
+ // 从商品配置中获取资源类型信息
2773
+ var resourceTypeConfig = null;
2774
+ var _iterator3 = _createForOfIteratorHelper(items),
2775
+ _step3;
2631
2776
  try {
2632
- var commonTimeSlots = _this15.getTimeSlotByAllResources(resourceCode);
2633
- if (commonTimeSlots && commonTimeSlots.length > 0) {
2634
- // 使用第一个可用时间片
2635
- var firstTimeSlot = commonTimeSlots[0];
2636
- var startDate = dayjs(firstTimeSlot.start_at).format('YYYY-MM-DD');
2637
- var startTime = firstTimeSlot.start_time;
2638
- var endTime = firstTimeSlot.end_time;
2639
-
2640
- // 为这些商品设置时间信息(创建副本,不修改原始数据)
2641
- items.forEach(function (cartItem) {
2642
- var processedItem = _objectSpread(_objectSpread({}, cartItem), {}, {
2643
- start_date: startDate,
2644
- start_time: startTime,
2645
- end_time: endTime,
2646
- end_date: startDate
2777
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
2778
+ var _cartItem$_productOri12;
2779
+ var cartItem = _step3.value;
2780
+ if ((_cartItem$_productOri12 = cartItem._productOrigin) !== null && _cartItem$_productOri12 !== void 0 && (_cartItem$_productOri12 = _cartItem$_productOri12.product_resource) !== null && _cartItem$_productOri12 !== void 0 && _cartItem$_productOri12.resources) {
2781
+ resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(function (r) {
2782
+ return r.code === resourceCode && r.status === 1;
2647
2783
  });
2648
- processedItemsWithoutTime.push(processedItem);
2649
- });
2650
- } else {
2651
- // 如果没有公共可用时间,说明容量不足
2652
- console.log("\u8D44\u6E90\u7C7B\u578B ".concat(resourceCode, " \u6CA1\u6709\u516C\u5171\u53EF\u7528\u65F6\u95F4"));
2653
- return {
2654
- v: false
2655
- };
2784
+ if (resourceTypeConfig) break;
2785
+ }
2656
2786
  }
2657
- } catch (error) {
2658
- console.warn("\u83B7\u53D6\u8D44\u6E90\u7C7B\u578B ".concat(resourceCode, " \u7684\u516C\u5171\u53EF\u7528\u65F6\u95F4\u5931\u8D25:"), error);
2659
- // 如果获取公共时间失败,继续处理其他资源类型
2660
- return 0; // continue
2787
+ } catch (err) {
2788
+ _iterator3.e(err);
2789
+ } finally {
2790
+ _iterator3.f();
2791
+ }
2792
+ var isMultipleBooking = ((_resourceTypeConfig = resourceTypeConfig) === null || _resourceTypeConfig === void 0 ? void 0 : _resourceTypeConfig.type) === 'multiple';
2793
+ var totalAvailable;
2794
+ var requiredAmount;
2795
+ var availableAmount;
2796
+ if (isMultipleBooking) {
2797
+ // 多个预约:计算容量
2798
+ totalAvailable = resourcesOfThisType.reduce(function (sum, resource) {
2799
+ return sum + (resource.capacity || 0);
2800
+ }, 0);
2801
+ requiredAmount = items.reduce(function (sum, cartItem) {
2802
+ var _getCapacityInfoByCar7 = getCapacityInfoByCartItem(cartItem),
2803
+ currentCapacity = _getCapacityInfoByCar7.currentCapacity;
2804
+ return sum + currentCapacity;
2805
+ }, 0);
2806
+ availableAmount = Math.max(0, totalAvailable - requiredAmount);
2807
+ } else {
2808
+ // 单个预约:计算资源个数
2809
+ totalAvailable = resourcesOfThisType.length;
2810
+ requiredAmount = items.reduce(function (sum, cartItem) {
2811
+ return sum + (cartItem.num || 1);
2812
+ }, 0);
2813
+ availableAmount = Math.max(0, totalAvailable - requiredAmount);
2661
2814
  }
2815
+
2816
+ // 记录资源容量信息
2817
+ resourceCapacityInfo.push({
2818
+ code: resourceCode,
2819
+ available: availableAmount,
2820
+ total: totalAvailable,
2821
+ required: requiredAmount,
2822
+ isMultiple: isMultipleBooking
2823
+ });
2824
+ availableCountsByResourceType.push(availableAmount);
2825
+
2826
+ // 检查是否有容量问题
2827
+ if (requiredAmount > totalAvailable) {
2828
+ hasCapacityIssue = true;
2829
+ console.log("\u8D44\u6E90\u7C7B\u578B ".concat(resourceCode, " ").concat(isMultipleBooking ? '容量' : '资源数量', "\u4E0D\u8DB3: \u9700\u8981 ").concat(requiredAmount, ", \u603B\u5171 ").concat(totalAvailable));
2830
+ }
2831
+
2832
+ // 为通过检测的商品分配一个公共可用时间段
2833
+ console.log("\u8D44\u6E90\u7C7B\u578B ".concat(resourceCode, " \u7684\u8D44\u6E90\u65F6\u95F4\u4FE1\u606F:"), resourcesOfThisType.map(function (r) {
2834
+ return {
2835
+ id: r.id,
2836
+ times: r.times.map(function (t) {
2837
+ return "".concat(t.start_at, " - ").concat(t.end_at);
2838
+ })
2839
+ };
2840
+ }));
2841
+
2842
+ // 找到所有资源都可用的时间段
2843
+ var commonTimeSlots = _this14.findCommonAvailableTimeSlots(resourcesOfThisType);
2844
+ console.log("\u8D44\u6E90\u7C7B\u578B ".concat(resourceCode, " \u7684\u516C\u5171\u65F6\u95F4\u6BB5:"), commonTimeSlots);
2845
+ if (commonTimeSlots.length === 0) {
2846
+ console.log("\u8D44\u6E90\u7C7B\u578B ".concat(resourceCode, " \u6CA1\u6709\u516C\u5171\u53EF\u7528\u65F6\u95F4\u6BB5"));
2847
+ return {
2848
+ v: {
2849
+ success: false,
2850
+ minAvailableCount: 0
2851
+ }
2852
+ };
2853
+ }
2854
+
2855
+ // 使用第一个公共可用时间段
2856
+ var firstCommonSlot = commonTimeSlots[0];
2857
+ console.log("\u4F7F\u7528\u516C\u5171\u65F6\u95F4\u6BB5: ".concat(firstCommonSlot.startTime, " - ").concat(firstCommonSlot.endTime));
2858
+ items.forEach(function (cartItem) {
2859
+ var processedItem = _objectSpread(_objectSpread({}, cartItem), {}, {
2860
+ start_date: dateRange[0].date,
2861
+ start_time: firstCommonSlot.startTime,
2862
+ end_time: firstCommonSlot.endTime,
2863
+ end_date: dateRange[0].date
2864
+ });
2865
+ processedItemsWithoutTime.push(processedItem);
2866
+ });
2662
2867
  },
2663
- _ret2;
2868
+ _ret3;
2664
2869
  for (var _i = 0, _Object$entries = Object.entries(itemsByResourceType); _i < _Object$entries.length; _i++) {
2665
- _ret2 = _loop2();
2666
- if (_ret2 === 0) continue;
2667
- if (_ret2) return _ret2.v;
2870
+ _ret3 = _loop3();
2871
+ if (_ret3) return _ret3.v;
2872
+ }
2873
+
2874
+ // 如果有容量问题,找出限制最严格的资源类型,返回其总容量
2875
+ if (hasCapacityIssue) {
2876
+ // 找出超出容量的资源类型中,总容量最少的那个
2877
+ var overCapacityResources = resourceCapacityInfo.filter(function (info) {
2878
+ return info.required > info.total;
2879
+ });
2880
+ if (overCapacityResources.length > 0) {
2881
+ var _minTotalCapacity = Math.min.apply(Math, _toConsumableArray(overCapacityResources.map(function (info) {
2882
+ return info.total;
2883
+ })));
2884
+ return {
2885
+ success: false,
2886
+ minAvailableCount: _minTotalCapacity
2887
+ };
2888
+ }
2889
+ // 如果没有超出容量的(理论上不应该发生),返回总容量最少的
2890
+ var minTotalCapacity = Math.min.apply(Math, _toConsumableArray(resourceCapacityInfo.map(function (info) {
2891
+ return info.total;
2892
+ })));
2893
+ return {
2894
+ success: false,
2895
+ minAvailableCount: minTotalCapacity
2896
+ };
2668
2897
  }
2669
2898
  }
2670
2899
 
@@ -2683,7 +2912,7 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2683
2912
  });
2684
2913
 
2685
2914
  // 检查每个时间段是否有足够的资源容量
2686
- var _loop3 = function _loop3() {
2915
+ var _loop4 = function _loop4() {
2687
2916
  var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
2688
2917
  timeSlotKey = _Object$entries2$_i[0],
2689
2918
  itemsInTimeSlot = _Object$entries2$_i[1];
@@ -2701,8 +2930,8 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2701
2930
  var resourcesIdSet = new Set();
2702
2931
 
2703
2932
  // 获取资源数据
2704
- var dateRange = _this15.store.date.getDateRange();
2705
- var resourcesDates = _this15.store.date.getDateList();
2933
+ var dateRange = _this14.store.date.getDateRange();
2934
+ var resourcesDates = _this14.store.date.getDateList();
2706
2935
  var targetResourceDate = resourcesDates.find(function (n) {
2707
2936
  return n.date === startDate;
2708
2937
  });
@@ -2723,18 +2952,29 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2723
2952
 
2724
2953
  // 按资源类型分组检查容量
2725
2954
  if (!checkTimeSlotCapacity(timeSlotStart, timeSlotEnd, itemsInTimeSlot, allResourcesForTimeSlot)) {
2955
+ // 如果有可用数量记录,返回最小值;否则返回 0
2956
+ var _minAvailableCount = availableCountsByResourceType.length > 0 ? Math.min.apply(Math, availableCountsByResourceType) : 0;
2726
2957
  return {
2727
- v: false
2958
+ v: {
2959
+ success: false,
2960
+ minAvailableCount: _minAvailableCount
2961
+ }
2728
2962
  };
2729
2963
  }
2730
2964
  },
2731
- _ret3;
2965
+ _ret4;
2732
2966
  for (var _i2 = 0, _Object$entries2 = Object.entries(cartItemsByTimeSlot); _i2 < _Object$entries2.length; _i2++) {
2733
- _ret3 = _loop3();
2734
- if (_ret3 === 0) continue;
2735
- if (_ret3) return _ret3.v;
2967
+ _ret4 = _loop4();
2968
+ if (_ret4 === 0) continue;
2969
+ if (_ret4) return _ret4.v;
2736
2970
  }
2737
- return true;
2971
+
2972
+ // 全部通过检测,返回成功和最小可用数量
2973
+ var minAvailableCount = availableCountsByResourceType.length > 0 ? Math.min.apply(Math, availableCountsByResourceType) : 0;
2974
+ return {
2975
+ success: true,
2976
+ minAvailableCount: minAvailableCount
2977
+ };
2738
2978
  }
2739
2979
  }, {
2740
2980
  key: "setOtherData",
@@ -2807,7 +3047,7 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2807
3047
  }, {
2808
3048
  key: "getResourcesByCartItemAndCode",
2809
3049
  value: function getResourcesByCartItemAndCode(cartItemId, resourceCode) {
2810
- var _cartItem$_productOri11;
3050
+ var _cartItem$_productOri13;
2811
3051
  var dateRange = this.store.date.getDateRange();
2812
3052
  var resources = [];
2813
3053
  if (dateRange !== null && dateRange !== void 0 && dateRange.length) {
@@ -2830,16 +3070,16 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2830
3070
  });
2831
3071
  if (!cartItem) return [];
2832
3072
  var selectedResources = [];
2833
- var _getCapacityInfoByCar7 = getCapacityInfoByCartItem(cartItem),
2834
- currentCapacity = _getCapacityInfoByCar7.currentCapacity,
2835
- formatCapacity = _getCapacityInfoByCar7.formatCapacity;
3073
+ var _getCapacityInfoByCar8 = getCapacityInfoByCartItem(cartItem),
3074
+ currentCapacity = _getCapacityInfoByCar8.currentCapacity,
3075
+ formatCapacity = _getCapacityInfoByCar8.formatCapacity;
2836
3076
  cartItem._origin.metadata.capacity = formatCapacity;
2837
3077
  if (cartItem.holder_id) {
2838
3078
  selectedResources = getOthersSelectedResources(cartItems, cartItem.holder_id, resourcesMap);
2839
3079
  } else {
2840
3080
  selectedResources = getOthersCartSelectedResources(cartItems, cartItem._id, resourcesMap);
2841
3081
  }
2842
- var productResources = getResourcesByProduct(resourcesMap, ((_cartItem$_productOri11 = cartItem._productOrigin) === null || _cartItem$_productOri11 === void 0 || (_cartItem$_productOri11 = _cartItem$_productOri11.product_resource) === null || _cartItem$_productOri11 === void 0 ? void 0 : _cartItem$_productOri11.resources) || [], selectedResources, currentCapacity);
3082
+ var productResources = getResourcesByProduct(resourcesMap, ((_cartItem$_productOri13 = cartItem._productOrigin) === null || _cartItem$_productOri13 === void 0 || (_cartItem$_productOri13 = _cartItem$_productOri13.product_resource) === null || _cartItem$_productOri13 === void 0 ? void 0 : _cartItem$_productOri13.resources) || [], selectedResources, currentCapacity);
2843
3083
  var targetResource = productResources.find(function (resource) {
2844
3084
  return resource.code === resourceCode;
2845
3085
  });
@@ -2862,7 +3102,7 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2862
3102
  });
2863
3103
  if (mTimes.length === 0) return false;
2864
3104
  var canUseArr = mTimes.map(function (item) {
2865
- var _cartItem$_productOri12;
3105
+ var _cartItem$_productOri14;
2866
3106
  var res = getIsUsableByTimeItem({
2867
3107
  timeSlice: {
2868
3108
  start_time: startTime.format('HH:mm'),
@@ -2874,7 +3114,7 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2874
3114
  resource: m,
2875
3115
  currentCount: currentCapacity || 0,
2876
3116
  resourcesUseableMap: resourcesUseableMap,
2877
- cut_off_time: (_cartItem$_productOri12 = cartItem._productOrigin) === null || _cartItem$_productOri12 === void 0 ? void 0 : _cartItem$_productOri12.cut_off_time
3117
+ cut_off_time: (_cartItem$_productOri14 = cartItem._productOrigin) === null || _cartItem$_productOri14 === void 0 ? void 0 : _cartItem$_productOri14.cut_off_time
2878
3118
  });
2879
3119
  if ((resourcesUseableMap === null || resourcesUseableMap === void 0 ? void 0 : resourcesUseableMap[m.id]) !== false && res.reason !== 'capacityOnly') {
2880
3120
  resourcesUseableMap[m.id] = res.usable;
@@ -2888,12 +3128,12 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2888
3128
  });
2889
3129
  } else {
2890
3130
  targetResource.renderList = targetResource.renderList.filter(function (n) {
2891
- var _cartItem$_productOri13;
3131
+ var _cartItem$_productOri15;
2892
3132
  var recordCount = n.capacity || 0;
2893
3133
  if (n.onlyComputed) return false;
2894
3134
  var timeSlots = getTimeSlicesByResource({
2895
3135
  resource: n,
2896
- duration: ((_cartItem$_productOri13 = cartItem._productOrigin) === null || _cartItem$_productOri13 === void 0 || (_cartItem$_productOri13 = _cartItem$_productOri13.duration) === null || _cartItem$_productOri13 === void 0 ? void 0 : _cartItem$_productOri13.value) || 10,
3136
+ duration: ((_cartItem$_productOri15 = cartItem._productOrigin) === null || _cartItem$_productOri15 === void 0 || (_cartItem$_productOri15 = _cartItem$_productOri15.duration) === null || _cartItem$_productOri15 === void 0 ? void 0 : _cartItem$_productOri15.value) || 10,
2897
3137
  split: 10,
2898
3138
  currentDate: dateRange[0].date
2899
3139
  });
@@ -2975,7 +3215,7 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
2975
3215
  openResources,
2976
3216
  allProductResources,
2977
3217
  targetSchedules,
2978
- _loop4,
3218
+ _loop5,
2979
3219
  _args28 = arguments;
2980
3220
  return _regeneratorRuntime().wrap(function _callee27$(_context28) {
2981
3221
  while (1) switch (_context28.prev = _context28.next) {
@@ -3052,9 +3292,9 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
3052
3292
  }
3053
3293
  });
3054
3294
  targetSchedules = this.store.schedule.getScheduleListByIds(tempProducts['schedule.ids']);
3055
- _loop4 = /*#__PURE__*/_regeneratorRuntime().mark(function _loop4() {
3295
+ _loop5 = /*#__PURE__*/_regeneratorRuntime().mark(function _loop5() {
3056
3296
  var currentDateStr, status, _checkSessionProductL, latestStartDate, earliestEndDate, scheduleByDate, minTimeMaxTime, scheduleTimeSlots, timesSlotCanUse;
3057
- return _regeneratorRuntime().wrap(function _loop4$(_context27) {
3297
+ return _regeneratorRuntime().wrap(function _loop5$(_context27) {
3058
3298
  while (1) switch (_context27.prev = _context27.next) {
3059
3299
  case 0:
3060
3300
  currentDateStr = currentDate.format('YYYY-MM-DD');
@@ -3157,14 +3397,14 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
3157
3397
  case "end":
3158
3398
  return _context27.stop();
3159
3399
  }
3160
- }, _loop4);
3400
+ }, _loop5);
3161
3401
  });
3162
3402
  case 28:
3163
3403
  if (!(dayjs(currentDate).isBefore(dayjs(endDate), 'day') || dayjs(currentDate).isSame(dayjs(endDate), 'day'))) {
3164
3404
  _context28.next = 34;
3165
3405
  break;
3166
3406
  }
3167
- return _context28.delegateYield(_loop4(), "t0", 30);
3407
+ return _context28.delegateYield(_loop5(), "t0", 30);
3168
3408
  case 30:
3169
3409
  if (!_context28.t0) {
3170
3410
  _context28.next = 32;