@pisell/pisellos 2.3.89 → 2.3.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/Order/utils.js +21 -6
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +978 -885
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/Sales/index.d.ts +4 -3
- package/dist/solution/Sales/index.js +23 -16
- package/lib/model/strategy/adapter/promotion/index.js +1 -46
- package/lib/modules/Order/utils.js +17 -1
- package/lib/server/index.d.ts +3 -0
- package/lib/server/index.js +44 -1
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/Sales/index.d.ts +4 -3
- package/lib/solution/Sales/index.js +19 -14
- package/package.json +1 -1
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 | 2 | 1 |
|
|
329
|
+
weekNum: 0 | 2 | 1 | 6 | 4 | 3 | 5;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -50,11 +50,12 @@ export declare class SalesImpl extends BaseModule implements Module, SalesModule
|
|
|
50
50
|
*/
|
|
51
51
|
private getTimelineBucketMinutes;
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
53
|
+
* 解析 current 所属营业日窗口:
|
|
54
54
|
* - 当 operating_day_boundary.type === 'start_time'
|
|
55
|
-
*
|
|
55
|
+
* 使用「最近一个 boundary.time」到「下一个 boundary.time」
|
|
56
56
|
* - 否则回退自然日(00:00 到次日 00:00)
|
|
57
57
|
*/
|
|
58
|
+
private getOperatingDayRange;
|
|
58
59
|
private getTimelineRangeByOperatingBoundary;
|
|
59
60
|
/**
|
|
60
61
|
* 统计时间轴每个时间片的预约数量。
|
|
@@ -95,7 +96,7 @@ export declare class SalesImpl extends BaseModule implements Module, SalesModule
|
|
|
95
96
|
* 2) 若无 active,返回已超时且仍占用中的预约(允许并发多条)
|
|
96
97
|
* 3) 若仍无,返回最近一组未来预约(同 start_time 的并发预约全部返回)
|
|
97
98
|
* 4) 最后兜底返回一条(避免资源有历史预约时完全无反馈)
|
|
98
|
-
* - includeAllFuture
|
|
99
|
+
* - includeAllFuture 时,保留选中预约并返回当前营业日全部后续预约;仅详情接口启用。
|
|
99
100
|
*/
|
|
100
101
|
private pickBookingsForCurrentPoint;
|
|
101
102
|
/**
|
|
@@ -258,19 +258,19 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
/**
|
|
261
|
-
*
|
|
261
|
+
* 解析 current 所属营业日窗口:
|
|
262
262
|
* - 当 operating_day_boundary.type === 'start_time'
|
|
263
|
-
*
|
|
263
|
+
* 使用「最近一个 boundary.time」到「下一个 boundary.time」
|
|
264
264
|
* - 否则回退自然日(00:00 到次日 00:00)
|
|
265
265
|
*/
|
|
266
266
|
}, {
|
|
267
|
-
key: "
|
|
268
|
-
value: function
|
|
269
|
-
var _appPlugin$getApp, _appPlugin$getApp$get, _appPlugin$getApp$get2, _appPlugin$getApp$get3, _coreData$core;
|
|
270
|
-
var
|
|
271
|
-
var defaultStart =
|
|
267
|
+
key: "getOperatingDayRange",
|
|
268
|
+
value: function getOperatingDayRange() {
|
|
269
|
+
var _this$core, _appPlugin$getApp, _appPlugin$getApp$get, _appPlugin$getApp$get2, _appPlugin$getApp$get3, _coreData$core;
|
|
270
|
+
var referenceTime = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : dayjs();
|
|
271
|
+
var defaultStart = referenceTime.startOf('day');
|
|
272
272
|
var defaultEndExclusive = defaultStart.add(1, 'day');
|
|
273
|
-
var appPlugin = this.core.getPlugin('app');
|
|
273
|
+
var appPlugin = (_this$core = this.core) === null || _this$core === void 0 ? void 0 : _this$core.getPlugin('app');
|
|
274
274
|
var coreData = appPlugin === null || appPlugin === void 0 || (_appPlugin$getApp = appPlugin.getApp()) === null || _appPlugin$getApp === void 0 || (_appPlugin$getApp = _appPlugin$getApp.data) === null || _appPlugin$getApp === void 0 || (_appPlugin$getApp = _appPlugin$getApp.store) === null || _appPlugin$getApp === void 0 || (_appPlugin$getApp$get = _appPlugin$getApp.getStore) === null || _appPlugin$getApp$get === void 0 || (_appPlugin$getApp$get2 = (_appPlugin$getApp$get3 = _appPlugin$getApp$get.call(_appPlugin$getApp)).getDataByModel) === null || _appPlugin$getApp$get2 === void 0 ? void 0 : _appPlugin$getApp$get2.call(_appPlugin$getApp$get3, 'core');
|
|
275
275
|
var operatingDayBoundary = coreData === null || coreData === void 0 || (_coreData$core = coreData.core) === null || _coreData$core === void 0 ? void 0 : _coreData$core.operating_day_boundary;
|
|
276
276
|
if ((operatingDayBoundary === null || operatingDayBoundary === void 0 ? void 0 : operatingDayBoundary.type) !== 'start_time') {
|
|
@@ -280,18 +280,24 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
280
280
|
};
|
|
281
281
|
}
|
|
282
282
|
var boundaryTime = String(operatingDayBoundary.time || '').trim();
|
|
283
|
-
var
|
|
284
|
-
if (!
|
|
283
|
+
var boundaryStart = dayjs("".concat(referenceTime.format('YYYY-MM-DD'), " ").concat(boundaryTime));
|
|
284
|
+
if (!boundaryStart.isValid()) {
|
|
285
285
|
return {
|
|
286
286
|
startAt: defaultStart,
|
|
287
287
|
endExclusiveAt: defaultEndExclusive
|
|
288
288
|
};
|
|
289
289
|
}
|
|
290
|
+
var startAt = referenceTime.isBefore(boundaryStart) ? boundaryStart.subtract(1, 'day') : boundaryStart;
|
|
290
291
|
return {
|
|
291
292
|
startAt: startAt,
|
|
292
293
|
endExclusiveAt: startAt.add(1, 'day')
|
|
293
294
|
};
|
|
294
295
|
}
|
|
296
|
+
}, {
|
|
297
|
+
key: "getTimelineRangeByOperatingBoundary",
|
|
298
|
+
value: function getTimelineRangeByOperatingBoundary() {
|
|
299
|
+
return this.getOperatingDayRange();
|
|
300
|
+
}
|
|
295
301
|
|
|
296
302
|
/**
|
|
297
303
|
* 统计时间轴每个时间片的预约数量。
|
|
@@ -485,7 +491,7 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
485
491
|
* 2) 若无 active,返回已超时且仍占用中的预约(允许并发多条)
|
|
486
492
|
* 3) 若仍无,返回最近一组未来预约(同 start_time 的并发预约全部返回)
|
|
487
493
|
* 4) 最后兜底返回一条(避免资源有历史预约时完全无反馈)
|
|
488
|
-
* - includeAllFuture
|
|
494
|
+
* - includeAllFuture 时,保留选中预约并返回当前营业日全部后续预约;仅详情接口启用。
|
|
489
495
|
*/
|
|
490
496
|
}, {
|
|
491
497
|
key: "pickBookingsForCurrentPoint",
|
|
@@ -493,15 +499,16 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
493
499
|
var _this4 = this;
|
|
494
500
|
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
495
501
|
if (bookings.length === 0) return [];
|
|
496
|
-
var
|
|
497
|
-
|
|
502
|
+
var _this$getOperatingDay = this.getOperatingDayRange(current),
|
|
503
|
+
operatingDayStart = _this$getOperatingDay.startAt,
|
|
504
|
+
operatingDayEndExclusive = _this$getOperatingDay.endExclusiveAt;
|
|
498
505
|
|
|
499
|
-
// 仅保留与 current
|
|
506
|
+
// 仅保留与 current 所属营业日窗口有时间交集的预约,避免跨营业日误命中
|
|
500
507
|
var dayScopedBookings = bookings.filter(function (booking) {
|
|
501
508
|
var startAt = _this4.toBookingDateTime(booking.start_date, booking.start_time);
|
|
502
509
|
var endAt = _this4.toBookingDateTime(booking.end_date, booking.end_time);
|
|
503
510
|
if (!startAt.isValid() || !endAt.isValid()) return false;
|
|
504
|
-
return
|
|
511
|
+
return startAt.isBefore(operatingDayEndExclusive) && _this4.isSameOrAfter(endAt, operatingDayStart);
|
|
505
512
|
});
|
|
506
513
|
if (dayScopedBookings.length === 0) return [];
|
|
507
514
|
var appendNextStartGroupIfNeeded = function appendNextStartGroupIfNeeded(selectedBookings) {
|
|
@@ -560,7 +567,7 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
560
567
|
// upcoming: 从未来预约里只取最早那一组(同 start_time)
|
|
561
568
|
var upcoming = dayScopedBookings.filter(function (booking) {
|
|
562
569
|
var startAt = _this4.toBookingDateTime(booking.start_date, booking.start_time);
|
|
563
|
-
return startAt.isValid() && startAt.isAfter(current)
|
|
570
|
+
return startAt.isValid() && startAt.isAfter(current);
|
|
564
571
|
});
|
|
565
572
|
if (upcoming.length > 0) {
|
|
566
573
|
if (options.includeAllFuture) return upcoming;
|
|
@@ -1,46 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
Object.defineProperty(exports, "BUY_X_GET_Y_FREE_STRATEGY", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: function () {
|
|
9
|
-
return _examples.BUY_X_GET_Y_FREE_STRATEGY;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
Object.defineProperty(exports, "ITEM_REWARD_STRATEGY", {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
get: function () {
|
|
15
|
-
return _examples.ITEM_REWARD_STRATEGY;
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
Object.defineProperty(exports, "PromotionAdapter", {
|
|
19
|
-
enumerable: true,
|
|
20
|
-
get: function () {
|
|
21
|
-
return _adapter.PromotionAdapter;
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
Object.defineProperty(exports, "PromotionEvaluator", {
|
|
25
|
-
enumerable: true,
|
|
26
|
-
get: function () {
|
|
27
|
-
return _evaluator.PromotionEvaluator;
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
Object.defineProperty(exports, "X_ITEMS_FOR_Y_PRICE_STRATEGY", {
|
|
31
|
-
enumerable: true,
|
|
32
|
-
get: function () {
|
|
33
|
-
return _examples.X_ITEMS_FOR_Y_PRICE_STRATEGY;
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
Object.defineProperty(exports, "default", {
|
|
37
|
-
enumerable: true,
|
|
38
|
-
get: function () {
|
|
39
|
-
return _adapter.default;
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
var _evaluator = require("./evaluator");
|
|
43
|
-
var _adapter = _interopRequireWildcard(require("./adapter"));
|
|
44
|
-
var _examples = require("./examples");
|
|
45
|
-
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
46
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
1
|
+
"use strict";
|
|
@@ -855,6 +855,11 @@ function normalizeSubmitPlatform(platform) {
|
|
|
855
855
|
if (lower === 'h5') return 'H5';
|
|
856
856
|
return value;
|
|
857
857
|
}
|
|
858
|
+
function normalizeSubmitProductionCode(value) {
|
|
859
|
+
if (value === undefined || value === null) return undefined;
|
|
860
|
+
const productionCode = String(value).trim();
|
|
861
|
+
return productionCode || undefined;
|
|
862
|
+
}
|
|
858
863
|
|
|
859
864
|
// 后端 checkout 协议字段 option_group_item_id;tempOrder 内部也保持同一字段名。
|
|
860
865
|
function formatSubmitOptionItems(options) {
|
|
@@ -866,6 +871,9 @@ function formatSubmitOptionItems(options) {
|
|
|
866
871
|
option_group_item_id: d?.option_group_item_id,
|
|
867
872
|
option_group_id: d?.option_group_id
|
|
868
873
|
};
|
|
874
|
+
const productionCode = normalizeSubmitProductionCode(d?.production_code);
|
|
875
|
+
delete option.production_code;
|
|
876
|
+
if (productionCode !== undefined) option.production_code = productionCode;
|
|
869
877
|
const addPrice = d?.add_price ?? d?.price;
|
|
870
878
|
if (addPrice !== undefined) option.add_price = String(addPrice);
|
|
871
879
|
delete option.price;
|
|
@@ -906,10 +914,13 @@ function formatSubmitBundleItems(bundle) {
|
|
|
906
914
|
const num = toBundleNumber(rawBundle.num ?? rawBundle.quantity, 1);
|
|
907
915
|
const bundleMapId = resolveSubmitBundleMapId(rawBundle);
|
|
908
916
|
const hasSubmitBundleDiscounts = Array.isArray(rawBundle.discount_list) && rawBundle.discount_list.length > 0;
|
|
917
|
+
const productionCode = normalizeSubmitProductionCode(rawBundle.production_code);
|
|
909
918
|
return {
|
|
910
919
|
is_charge_tax: rawBundle.is_charge_tax ?? 0,
|
|
911
920
|
bundle_variant_id: rawBundle.bundle_variant_id ?? 0,
|
|
912
|
-
|
|
921
|
+
...(productionCode !== undefined ? {
|
|
922
|
+
production_code: productionCode
|
|
923
|
+
} : {}),
|
|
913
924
|
num,
|
|
914
925
|
quantity: toBundleNumber(rawBundle.quantity ?? rawBundle.num, num),
|
|
915
926
|
extension_id: rawBundle.extension_id ?? 0,
|
|
@@ -966,8 +977,10 @@ function normalizeSubmitProduct(product) {
|
|
|
966
977
|
discountway: _deprecatedDiscountway,
|
|
967
978
|
product_discount_reason: _deprecatedProductDiscountReason,
|
|
968
979
|
discount_per: _deprecatedDiscountPer,
|
|
980
|
+
production_code: rawProductionCode,
|
|
969
981
|
...productRest
|
|
970
982
|
} = submitProduct;
|
|
983
|
+
const productionCode = normalizeSubmitProductionCode(rawProductionCode);
|
|
971
984
|
delete productRest[`product_${'option'}_item`];
|
|
972
985
|
const rawMetadata = submitProduct.metadata || {};
|
|
973
986
|
const bookingUid = rawMetadata.booking_uid;
|
|
@@ -1001,6 +1014,9 @@ function normalizeSubmitProduct(product) {
|
|
|
1001
1014
|
};
|
|
1002
1015
|
return {
|
|
1003
1016
|
...productRest,
|
|
1017
|
+
...(productionCode !== undefined ? {
|
|
1018
|
+
production_code: productionCode
|
|
1019
|
+
} : {}),
|
|
1004
1020
|
...(bookingUid ? {
|
|
1005
1021
|
booking_uid: bookingUid
|
|
1006
1022
|
} : {}),
|
package/lib/server/index.d.ts
CHANGED
|
@@ -128,6 +128,9 @@ declare class Server {
|
|
|
128
128
|
private runCheckoutSync;
|
|
129
129
|
private omitCheckoutSyncMode;
|
|
130
130
|
private buildRemoteCheckoutData;
|
|
131
|
+
private buildCheckoutDeviceHeaders;
|
|
132
|
+
private applyKioskCheckoutOperator;
|
|
133
|
+
private resolveKioskCheckoutOperatorId;
|
|
131
134
|
private mergeCheckoutSyncPayments;
|
|
132
135
|
private persistSyncedCheckoutOrder;
|
|
133
136
|
/**
|
package/lib/server/index.js
CHANGED
|
@@ -629,12 +629,16 @@ class Server {
|
|
|
629
629
|
const numberedData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
|
|
630
630
|
const checkoutData = this.applyCheckoutFulfillmentBuzzer(numberedData, title);
|
|
631
631
|
const remoteCheckoutData = this.buildRemoteCheckoutData(checkoutData, title);
|
|
632
|
+
const deviceHeaders = await this.buildCheckoutDeviceHeaders(title);
|
|
632
633
|
if (!this.app?.request?.post) {
|
|
633
634
|
throw new Error('app.request 不可用');
|
|
634
635
|
}
|
|
635
636
|
const response = await this.app.request.post(backendPath, remoteCheckoutData, {
|
|
636
637
|
isShopApi: true,
|
|
637
|
-
customToast: () => {}
|
|
638
|
+
customToast: () => {},
|
|
639
|
+
...(Object.keys(deviceHeaders).length > 0 ? {
|
|
640
|
+
headers: deviceHeaders
|
|
641
|
+
} : {})
|
|
638
642
|
});
|
|
639
643
|
if (this.isCheckoutResponseRejected(response)) {
|
|
640
644
|
return {
|
|
@@ -697,6 +701,7 @@ class Server {
|
|
|
697
701
|
if (!next || typeof next !== 'object') return next;
|
|
698
702
|
const record = next;
|
|
699
703
|
delete record[OS_FULFILLMENT_REF_MODE_FIELD];
|
|
704
|
+
this.applyKioskCheckoutOperator(record);
|
|
700
705
|
if (!Array.isArray(record.payments)) return next;
|
|
701
706
|
const originalPayments = record.payments;
|
|
702
707
|
const filteredPayments = originalPayments.filter(payment => !(0, _paymentUtils.isPendingOrderPayment)(payment));
|
|
@@ -711,6 +716,44 @@ class Server {
|
|
|
711
716
|
});
|
|
712
717
|
return next;
|
|
713
718
|
}
|
|
719
|
+
async buildCheckoutDeviceHeaders(title) {
|
|
720
|
+
const getAsyncIotDeviceInfo = this.getAppData('async_iot_device_info');
|
|
721
|
+
if (!getAsyncIotDeviceInfo) return {};
|
|
722
|
+
let deviceInfo;
|
|
723
|
+
try {
|
|
724
|
+
deviceInfo = typeof getAsyncIotDeviceInfo === 'function' ? await getAsyncIotDeviceInfo() : getAsyncIotDeviceInfo;
|
|
725
|
+
} catch (error) {
|
|
726
|
+
this.logWarning(`${title}: 读取 async_iot_device_info 失败,跳过 checkout 设备请求头`, {
|
|
727
|
+
error: this.getUnknownErrorMessage(error)
|
|
728
|
+
});
|
|
729
|
+
return {};
|
|
730
|
+
}
|
|
731
|
+
if (!deviceInfo || typeof deviceInfo !== 'object') return {};
|
|
732
|
+
const headers = {};
|
|
733
|
+
const assignHeader = (key, value) => {
|
|
734
|
+
if (this.isBlankCheckoutValue(value)) return;
|
|
735
|
+
headers[key] = String(value);
|
|
736
|
+
};
|
|
737
|
+
assignHeader('Device-ID', deviceInfo.id);
|
|
738
|
+
assignHeader('Device-Type-Code', deviceInfo.type_code);
|
|
739
|
+
assignHeader('Device-Model-Code', deviceInfo.model_code);
|
|
740
|
+
return headers;
|
|
741
|
+
}
|
|
742
|
+
applyKioskCheckoutOperator(record) {
|
|
743
|
+
if (record.platform !== 'kiosk') return;
|
|
744
|
+
record.operator_type = 'customer';
|
|
745
|
+
record.operator_id = this.resolveKioskCheckoutOperatorId(record.customer_id);
|
|
746
|
+
}
|
|
747
|
+
resolveKioskCheckoutOperatorId(customerId) {
|
|
748
|
+
if (customerId === undefined || customerId === null) return 1;
|
|
749
|
+
if (typeof customerId === 'string') {
|
|
750
|
+
const trimmed = customerId.trim();
|
|
751
|
+
if (trimmed === '' || trimmed === '0' || trimmed === '1') return 1;
|
|
752
|
+
return customerId;
|
|
753
|
+
}
|
|
754
|
+
if (customerId === 0 || customerId === 1) return 1;
|
|
755
|
+
return customerId;
|
|
756
|
+
}
|
|
714
757
|
mergeCheckoutSyncPayments(checkoutData, fresh, title) {
|
|
715
758
|
const localPayments = Array.isArray(checkoutData?.payments) ? checkoutData.payments : [];
|
|
716
759
|
const freshRecord = fresh;
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 | 2 | 1 |
|
|
329
|
+
weekNum: 0 | 2 | 1 | 6 | 4 | 3 | 5;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -50,11 +50,12 @@ export declare class SalesImpl extends BaseModule implements Module, SalesModule
|
|
|
50
50
|
*/
|
|
51
51
|
private getTimelineBucketMinutes;
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
53
|
+
* 解析 current 所属营业日窗口:
|
|
54
54
|
* - 当 operating_day_boundary.type === 'start_time'
|
|
55
|
-
*
|
|
55
|
+
* 使用「最近一个 boundary.time」到「下一个 boundary.time」
|
|
56
56
|
* - 否则回退自然日(00:00 到次日 00:00)
|
|
57
57
|
*/
|
|
58
|
+
private getOperatingDayRange;
|
|
58
59
|
private getTimelineRangeByOperatingBoundary;
|
|
59
60
|
/**
|
|
60
61
|
* 统计时间轴每个时间片的预约数量。
|
|
@@ -95,7 +96,7 @@ export declare class SalesImpl extends BaseModule implements Module, SalesModule
|
|
|
95
96
|
* 2) 若无 active,返回已超时且仍占用中的预约(允许并发多条)
|
|
96
97
|
* 3) 若仍无,返回最近一组未来预约(同 start_time 的并发预约全部返回)
|
|
97
98
|
* 4) 最后兜底返回一条(避免资源有历史预约时完全无反馈)
|
|
98
|
-
* - includeAllFuture
|
|
99
|
+
* - includeAllFuture 时,保留选中预约并返回当前营业日全部后续预约;仅详情接口启用。
|
|
99
100
|
*/
|
|
100
101
|
private pickBookingsForCurrentPoint;
|
|
101
102
|
/**
|
|
@@ -160,16 +160,15 @@ class SalesImpl extends _BaseModule.BaseModule {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
/**
|
|
163
|
-
*
|
|
163
|
+
* 解析 current 所属营业日窗口:
|
|
164
164
|
* - 当 operating_day_boundary.type === 'start_time'
|
|
165
|
-
*
|
|
165
|
+
* 使用「最近一个 boundary.time」到「下一个 boundary.time」
|
|
166
166
|
* - 否则回退自然日(00:00 到次日 00:00)
|
|
167
167
|
*/
|
|
168
|
-
|
|
169
|
-
const
|
|
170
|
-
const defaultStart = today.startOf('day');
|
|
168
|
+
getOperatingDayRange(referenceTime = (0, _dayjs.default)()) {
|
|
169
|
+
const defaultStart = referenceTime.startOf('day');
|
|
171
170
|
const defaultEndExclusive = defaultStart.add(1, 'day');
|
|
172
|
-
const appPlugin = this.core
|
|
171
|
+
const appPlugin = this.core?.getPlugin('app');
|
|
173
172
|
const coreData = appPlugin?.getApp()?.data?.store?.getStore?.().getDataByModel?.('core');
|
|
174
173
|
const operatingDayBoundary = coreData?.core?.operating_day_boundary;
|
|
175
174
|
if (operatingDayBoundary?.type !== 'start_time') {
|
|
@@ -179,18 +178,22 @@ class SalesImpl extends _BaseModule.BaseModule {
|
|
|
179
178
|
};
|
|
180
179
|
}
|
|
181
180
|
const boundaryTime = String(operatingDayBoundary.time || '').trim();
|
|
182
|
-
const
|
|
183
|
-
if (!
|
|
181
|
+
const boundaryStart = (0, _dayjs.default)(`${referenceTime.format('YYYY-MM-DD')} ${boundaryTime}`);
|
|
182
|
+
if (!boundaryStart.isValid()) {
|
|
184
183
|
return {
|
|
185
184
|
startAt: defaultStart,
|
|
186
185
|
endExclusiveAt: defaultEndExclusive
|
|
187
186
|
};
|
|
188
187
|
}
|
|
188
|
+
const startAt = referenceTime.isBefore(boundaryStart) ? boundaryStart.subtract(1, 'day') : boundaryStart;
|
|
189
189
|
return {
|
|
190
190
|
startAt,
|
|
191
191
|
endExclusiveAt: startAt.add(1, 'day')
|
|
192
192
|
};
|
|
193
193
|
}
|
|
194
|
+
getTimelineRangeByOperatingBoundary() {
|
|
195
|
+
return this.getOperatingDayRange();
|
|
196
|
+
}
|
|
194
197
|
|
|
195
198
|
/**
|
|
196
199
|
* 统计时间轴每个时间片的预约数量。
|
|
@@ -343,19 +346,21 @@ class SalesImpl extends _BaseModule.BaseModule {
|
|
|
343
346
|
* 2) 若无 active,返回已超时且仍占用中的预约(允许并发多条)
|
|
344
347
|
* 3) 若仍无,返回最近一组未来预约(同 start_time 的并发预约全部返回)
|
|
345
348
|
* 4) 最后兜底返回一条(避免资源有历史预约时完全无反馈)
|
|
346
|
-
* - includeAllFuture
|
|
349
|
+
* - includeAllFuture 时,保留选中预约并返回当前营业日全部后续预约;仅详情接口启用。
|
|
347
350
|
*/
|
|
348
351
|
pickBookingsForCurrentPoint(current, bookings, options = {}) {
|
|
349
352
|
if (bookings.length === 0) return [];
|
|
350
|
-
const
|
|
351
|
-
|
|
353
|
+
const {
|
|
354
|
+
startAt: operatingDayStart,
|
|
355
|
+
endExclusiveAt: operatingDayEndExclusive
|
|
356
|
+
} = this.getOperatingDayRange(current);
|
|
352
357
|
|
|
353
|
-
// 仅保留与 current
|
|
358
|
+
// 仅保留与 current 所属营业日窗口有时间交集的预约,避免跨营业日误命中
|
|
354
359
|
const dayScopedBookings = bookings.filter(booking => {
|
|
355
360
|
const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
|
|
356
361
|
const endAt = this.toBookingDateTime(booking.end_date, booking.end_time);
|
|
357
362
|
if (!startAt.isValid() || !endAt.isValid()) return false;
|
|
358
|
-
return
|
|
363
|
+
return startAt.isBefore(operatingDayEndExclusive) && this.isSameOrAfter(endAt, operatingDayStart);
|
|
359
364
|
});
|
|
360
365
|
if (dayScopedBookings.length === 0) return [];
|
|
361
366
|
const appendNextStartGroupIfNeeded = selectedBookings => {
|
|
@@ -404,7 +409,7 @@ class SalesImpl extends _BaseModule.BaseModule {
|
|
|
404
409
|
// upcoming: 从未来预约里只取最早那一组(同 start_time)
|
|
405
410
|
const upcoming = dayScopedBookings.filter(booking => {
|
|
406
411
|
const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
|
|
407
|
-
return startAt.isValid() && startAt.isAfter(current)
|
|
412
|
+
return startAt.isValid() && startAt.isAfter(current);
|
|
408
413
|
});
|
|
409
414
|
if (upcoming.length > 0) {
|
|
410
415
|
if (options.includeAllFuture) return upcoming;
|