@pisell/pisellos 2.2.94 → 2.2.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +7 -0
- package/dist/modules/Customer/index.d.ts +1 -0
- package/dist/modules/Customer/index.js +28 -12
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/server/index.d.ts +6 -1
- package/dist/server/index.js +40 -17
- package/dist/server/modules/order/types.d.ts +1 -1
- package/dist/server/modules/order/utils/filterBookings.js +1 -1
- package/dist/server/modules/products/index.d.ts +19 -24
- package/dist/server/modules/products/index.js +429 -600
- package/dist/server/modules/products/types.d.ts +1 -0
- package/dist/server/utils/product.d.ts +4 -0
- package/dist/server/utils/product.js +34 -0
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/Sales/index.d.ts +1 -1
- package/dist/solution/Sales/index.js +72 -20
- package/dist/solution/Sales/types.d.ts +5 -4
- package/dist/types/index.d.ts +2 -0
- package/lib/core/index.d.ts +1 -0
- package/lib/core/index.js +4 -0
- package/lib/modules/Customer/index.d.ts +1 -0
- package/lib/modules/Customer/index.js +21 -6
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/server/index.d.ts +6 -1
- package/lib/server/index.js +33 -13
- package/lib/server/modules/order/types.d.ts +1 -1
- package/lib/server/modules/order/utils/filterBookings.js +1 -1
- package/lib/server/modules/products/index.d.ts +19 -24
- package/lib/server/modules/products/index.js +151 -150
- package/lib/server/modules/products/types.d.ts +1 -0
- package/lib/server/utils/product.d.ts +4 -0
- package/lib/server/utils/product.js +27 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/Sales/index.d.ts +1 -1
- package/lib/solution/Sales/index.js +67 -12
- package/lib/solution/Sales/types.d.ts +5 -4
- package/lib/types/index.d.ts +2 -0
- package/package.json +1 -1
|
@@ -10,6 +10,10 @@ export declare function perfMark(label: string, durationMs: number, meta?: Recor
|
|
|
10
10
|
*/
|
|
11
11
|
export declare function applyPriceDataToProducts(products: ProductData[], priceData: LoadProductsPriceData[]): ProductData[];
|
|
12
12
|
export declare const getIsSessionProduct: (product: ProductData) => boolean;
|
|
13
|
+
/**
|
|
14
|
+
* 根据 locale 将商品的 i18n 字段覆盖到对应原始字段
|
|
15
|
+
*/
|
|
16
|
+
export declare function applyI18nToProducts(products: ProductData[], locale?: string): ProductData[];
|
|
13
17
|
/**
|
|
14
18
|
* 将详情值数据应用到商品列表
|
|
15
19
|
* @param products 商品列表
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
2
|
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
3
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
4
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
5
|
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
4
6
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
7
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
8
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
5
9
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
6
10
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
7
11
|
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
@@ -186,6 +190,36 @@ var getIsOpenDetailModal = function getIsOpenDetailModal(product, context) {
|
|
|
186
190
|
scheduleTimeSlots: scheduleTimeSlots
|
|
187
191
|
};
|
|
188
192
|
};
|
|
193
|
+
var I18N_FIELD_MAP = {
|
|
194
|
+
title_i18n: 'title',
|
|
195
|
+
subtitle_i18n: 'subtitle',
|
|
196
|
+
description_i18n: 'description',
|
|
197
|
+
cover_i18n: 'cover'
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* 根据 locale 将商品的 i18n 字段覆盖到对应原始字段
|
|
202
|
+
*/
|
|
203
|
+
export function applyI18nToProducts(products, locale) {
|
|
204
|
+
if (!locale) return products;
|
|
205
|
+
return products.map(function (product) {
|
|
206
|
+
var _patched;
|
|
207
|
+
var patched = null;
|
|
208
|
+
for (var _i = 0, _Object$entries = Object.entries(I18N_FIELD_MAP); _i < _Object$entries.length; _i++) {
|
|
209
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
210
|
+
i18nKey = _Object$entries$_i[0],
|
|
211
|
+
originalKey = _Object$entries$_i[1];
|
|
212
|
+
var i18nDict = product[i18nKey];
|
|
213
|
+
if (!i18nDict) continue;
|
|
214
|
+
var localizedValue = i18nDict[locale];
|
|
215
|
+
if (localizedValue) {
|
|
216
|
+
if (!patched) patched = _objectSpread({}, product);
|
|
217
|
+
patched[originalKey] = localizedValue;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return (_patched = patched) !== null && _patched !== void 0 ? _patched : product;
|
|
221
|
+
});
|
|
222
|
+
}
|
|
189
223
|
var formatDataKey = function formatDataKey(data) {
|
|
190
224
|
var _data$option, _data$bundle;
|
|
191
225
|
var _data = _objectSpread({}, data);
|
|
@@ -344,7 +344,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
344
344
|
};
|
|
345
345
|
setOtherData(key: string, value: any): void;
|
|
346
346
|
getOtherData(key: string): any;
|
|
347
|
-
getProductTypeById(id: number): Promise<"
|
|
347
|
+
getProductTypeById(id: number): Promise<"duration" | "session" | "normal">;
|
|
348
348
|
/**
|
|
349
349
|
* 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
|
|
350
350
|
*
|
|
@@ -58,7 +58,7 @@ export declare class SalesImpl extends BaseModule implements Module, SalesModule
|
|
|
58
58
|
* - n = booking 数量
|
|
59
59
|
* - s = 时间片数量
|
|
60
60
|
*/
|
|
61
|
-
getTimelineHighlights(bookingList?: BookingData[]): SalesTimelineHighlights;
|
|
61
|
+
getTimelineHighlights(bookingList?: BookingData[], startDateTime?: string, endDateTime?: string): SalesTimelineHighlights;
|
|
62
62
|
/** dayjs 未启用插件时,手动封装 >= 判断 */
|
|
63
63
|
private isSameOrAfter;
|
|
64
64
|
/** dayjs 未启用插件时,手动封装 <= 判断 */
|
|
@@ -242,16 +242,24 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
242
242
|
key: "getTimelineHighlights",
|
|
243
243
|
value: function getTimelineHighlights() {
|
|
244
244
|
var bookingList = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
245
|
+
var startDateTime = arguments.length > 1 ? arguments[1] : undefined;
|
|
246
|
+
var endDateTime = arguments.length > 2 ? arguments[2] : undefined;
|
|
245
247
|
var bucketMinutes = this.getTimelineBucketMinutes();
|
|
246
248
|
var bucketMs = bucketMinutes * 60 * 1000;
|
|
247
|
-
var
|
|
248
|
-
|
|
249
|
-
|
|
249
|
+
var customStartAt = startDateTime ? dayjs(startDateTime) : dayjs('');
|
|
250
|
+
var customEndExclusiveAt = endDateTime ? dayjs(endDateTime) : dayjs('');
|
|
251
|
+
var hasValidCustomRange = customStartAt.isValid() && customEndExclusiveAt.isValid();
|
|
252
|
+
var _ref = hasValidCustomRange ? {
|
|
253
|
+
startAt: customStartAt,
|
|
254
|
+
endExclusiveAt: customEndExclusiveAt
|
|
255
|
+
} : this.getTimelineRangeByOperatingBoundary(),
|
|
256
|
+
startAt = _ref.startAt,
|
|
257
|
+
endExclusiveAt = _ref.endExclusiveAt;
|
|
250
258
|
var startAtMs = startAt.valueOf();
|
|
251
259
|
var endExclusiveAtMs = endExclusiveAt.valueOf();
|
|
252
|
-
if (!startAt.isValid() || !endExclusiveAt.isValid() || endExclusiveAtMs <= startAtMs) return
|
|
260
|
+
if (!startAt.isValid() || !endExclusiveAt.isValid() || endExclusiveAtMs <= startAtMs) return [];
|
|
253
261
|
var slotCount = Math.ceil((endExclusiveAtMs - startAtMs) / bucketMs);
|
|
254
|
-
if (slotCount <= 0) return
|
|
262
|
+
if (slotCount <= 0) return [];
|
|
255
263
|
var diff = new Int32Array(slotCount + 1);
|
|
256
264
|
for (var i = 0; i < bookingList.length; i++) {
|
|
257
265
|
var booking = bookingList[i];
|
|
@@ -268,12 +276,11 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
268
276
|
diff[startIdx] += 1;
|
|
269
277
|
diff[endIdx + 1] -= 1;
|
|
270
278
|
}
|
|
271
|
-
var timeline =
|
|
279
|
+
var timeline = [];
|
|
272
280
|
var runningCount = 0;
|
|
273
281
|
for (var _i = 0; _i < slotCount; _i++) {
|
|
274
282
|
runningCount += diff[_i];
|
|
275
|
-
|
|
276
|
-
timeline[label] = runningCount;
|
|
283
|
+
timeline.push(runningCount);
|
|
277
284
|
}
|
|
278
285
|
return timeline;
|
|
279
286
|
}
|
|
@@ -324,8 +331,8 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
324
331
|
}, {
|
|
325
332
|
key: "getResourceId",
|
|
326
333
|
value: function getResourceId(resource) {
|
|
327
|
-
var
|
|
328
|
-
return (
|
|
334
|
+
var _ref2, _resource$id;
|
|
335
|
+
return (_ref2 = (_resource$id = resource.id) !== null && _resource$id !== void 0 ? _resource$id : resource.form_record_id) !== null && _ref2 !== void 0 ? _ref2 : '';
|
|
329
336
|
}
|
|
330
337
|
|
|
331
338
|
/**
|
|
@@ -351,6 +358,33 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
351
358
|
return _this2.isSameOrBefore(startAt, currentDayEnd) && _this2.isSameOrAfter(endAt, currentDayStart);
|
|
352
359
|
});
|
|
353
360
|
if (dayScopedBookings.length === 0) return [];
|
|
361
|
+
var appendNextStartGroupIfNeeded = function appendNextStartGroupIfNeeded(selectedBookings) {
|
|
362
|
+
if (selectedBookings.length === 0) return selectedBookings;
|
|
363
|
+
var shouldAppendNextGroup = selectedBookings.some(function (booking) {
|
|
364
|
+
return booking.status === 'reserved' || booking.status === 'occupied';
|
|
365
|
+
});
|
|
366
|
+
if (!shouldAppendNextGroup) return selectedBookings;
|
|
367
|
+
var selectedStartValues = new Set(selectedBookings.map(function (booking) {
|
|
368
|
+
return _this2.toBookingDateTime(booking.start_date, booking.start_time);
|
|
369
|
+
}).filter(function (startAt) {
|
|
370
|
+
return startAt.isValid();
|
|
371
|
+
}).map(function (startAt) {
|
|
372
|
+
return startAt.valueOf();
|
|
373
|
+
}));
|
|
374
|
+
var futureCandidates = dayScopedBookings.filter(function (booking) {
|
|
375
|
+
var startAt = _this2.toBookingDateTime(booking.start_date, booking.start_time);
|
|
376
|
+
if (!startAt.isValid()) return false;
|
|
377
|
+
return startAt.isAfter(current) && !selectedStartValues.has(startAt.valueOf());
|
|
378
|
+
});
|
|
379
|
+
if (futureCandidates.length === 0) return selectedBookings;
|
|
380
|
+
var nextStartAt = _this2.toBookingDateTime(futureCandidates[0].start_date, futureCandidates[0].start_time).valueOf();
|
|
381
|
+
var nextStartGroup = futureCandidates.filter(function (booking) {
|
|
382
|
+
var startAt = _this2.toBookingDateTime(booking.start_date, booking.start_time);
|
|
383
|
+
return startAt.isValid() && startAt.valueOf() === nextStartAt;
|
|
384
|
+
});
|
|
385
|
+
if (nextStartGroup.length === 0) return selectedBookings;
|
|
386
|
+
return [].concat(_toConsumableArray(selectedBookings), _toConsumableArray(nextStartGroup));
|
|
387
|
+
};
|
|
354
388
|
|
|
355
389
|
// active: current 处于 [startAt, endAt] 区间
|
|
356
390
|
var activeBookings = dayScopedBookings.filter(function (booking) {
|
|
@@ -359,13 +393,13 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
359
393
|
if (!startAt.isValid() || !endAt.isValid()) return false;
|
|
360
394
|
return _this2.isSameOrAfter(current, startAt) && _this2.isSameOrBefore(current, endAt);
|
|
361
395
|
});
|
|
362
|
-
if (activeBookings.length > 0) return activeBookings;
|
|
396
|
+
if (activeBookings.length > 0) return appendNextStartGroupIfNeeded(activeBookings);
|
|
363
397
|
|
|
364
398
|
// timeout occupied: 占用中且超时
|
|
365
399
|
var timeoutOccupied = dayScopedBookings.filter(function (booking) {
|
|
366
400
|
return booking.status === 'occupied' && booking.isTimeout;
|
|
367
401
|
});
|
|
368
|
-
if (timeoutOccupied.length > 0) return timeoutOccupied;
|
|
402
|
+
if (timeoutOccupied.length > 0) return appendNextStartGroupIfNeeded(timeoutOccupied);
|
|
369
403
|
|
|
370
404
|
// upcoming: 从未来预约里只取最早那一组(同 start_time)
|
|
371
405
|
var upcoming = dayScopedBookings.filter(function (booking) {
|
|
@@ -374,10 +408,11 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
374
408
|
});
|
|
375
409
|
if (upcoming.length > 0) {
|
|
376
410
|
var firstStartAt = this.toBookingDateTime(upcoming[0].start_date, upcoming[0].start_time).valueOf();
|
|
377
|
-
|
|
411
|
+
var upcomingStartGroup = upcoming.filter(function (booking) {
|
|
378
412
|
var startAt = _this2.toBookingDateTime(booking.start_date, booking.start_time);
|
|
379
413
|
return startAt.valueOf() === firstStartAt;
|
|
380
414
|
});
|
|
415
|
+
return appendNextStartGroupIfNeeded(upcomingStartGroup);
|
|
381
416
|
}
|
|
382
417
|
|
|
383
418
|
// fallback: 全部是过去且非 timeout 的场景,保留末条便于前端兜底展示
|
|
@@ -393,8 +428,8 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
393
428
|
}, {
|
|
394
429
|
key: "normalizeMatchedBooking",
|
|
395
430
|
value: function normalizeMatchedBooking(current, booking) {
|
|
396
|
-
var
|
|
397
|
-
var appointmentStatus = String((
|
|
431
|
+
var _ref3, _booking$appointment_;
|
|
432
|
+
var appointmentStatus = String((_ref3 = (_booking$appointment_ = booking.appointment_status) !== null && _booking$appointment_ !== void 0 ? _booking$appointment_ : booking.status) !== null && _ref3 !== void 0 ? _ref3 : '');
|
|
398
433
|
if (appointmentStatus === 'rejected' || appointmentStatus === 'cancelled' || appointmentStatus === 'completed') {
|
|
399
434
|
return null;
|
|
400
435
|
}
|
|
@@ -402,14 +437,32 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
402
437
|
var endAt = this.toBookingDateTime(booking.end_date, booking.end_time);
|
|
403
438
|
var startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
|
|
404
439
|
var isTimeout = bookingStatus === 'occupied' && endAt.isValid() && current.isAfter(endAt);
|
|
440
|
+
var timeoutTime = isTimeout ? current.diff(endAt, 'minute') : undefined;
|
|
441
|
+
var progressPercent = function () {
|
|
442
|
+
if (bookingStatus !== 'occupied') return 0;
|
|
443
|
+
if (!startAt.isValid() || !endAt.isValid()) return 0;
|
|
444
|
+
var totalMinutes = endAt.diff(startAt, 'minute');
|
|
445
|
+
if (totalMinutes <= 0) return 0;
|
|
446
|
+
var elapsedMinutes = current.diff(startAt, 'minute');
|
|
447
|
+
if (elapsedMinutes <= 0) return 0;
|
|
448
|
+
if (elapsedMinutes >= totalMinutes) return 100;
|
|
449
|
+
return Math.floor(elapsedMinutes / totalMinutes * 100);
|
|
450
|
+
}();
|
|
405
451
|
var reservedStatus;
|
|
452
|
+
var lateTime;
|
|
406
453
|
if (bookingStatus === 'reserved' && startAt.isValid() && endAt.isValid()) {
|
|
407
454
|
if (current.isBefore(startAt)) reservedStatus = 'not_arrived';
|
|
408
|
-
if (current.isAfter(endAt))
|
|
455
|
+
if (current.isAfter(endAt)) {
|
|
456
|
+
reservedStatus = 'late';
|
|
457
|
+
lateTime = current.diff(startAt, 'minute');
|
|
458
|
+
}
|
|
409
459
|
}
|
|
410
460
|
return _objectSpread(_objectSpread({}, booking), {}, {
|
|
411
461
|
status: bookingStatus,
|
|
412
462
|
isTimeout: isTimeout,
|
|
463
|
+
timeoutTime: timeoutTime,
|
|
464
|
+
progressPercent: progressPercent,
|
|
465
|
+
lateTime: lateTime,
|
|
413
466
|
reserved_status: reservedStatus
|
|
414
467
|
});
|
|
415
468
|
}
|
|
@@ -452,13 +505,12 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
452
505
|
case 6:
|
|
453
506
|
resourceResponse = _context3.sent;
|
|
454
507
|
resourceList = (_resourceResponse$dat = resourceResponse === null || resourceResponse === void 0 || (_resourceResponse$dat2 = resourceResponse.data) === null || _resourceResponse$dat2 === void 0 ? void 0 : _resourceResponse$dat2.list) !== null && _resourceResponse$dat !== void 0 ? _resourceResponse$dat : [];
|
|
455
|
-
console.log(1111, currentTime, resourceList, bookingList);
|
|
456
508
|
if (!(!Array.isArray(resourceList) || resourceList.length === 0)) {
|
|
457
|
-
_context3.next =
|
|
509
|
+
_context3.next = 10;
|
|
458
510
|
break;
|
|
459
511
|
}
|
|
460
512
|
return _context3.abrupt("return", []);
|
|
461
|
-
case
|
|
513
|
+
case 10:
|
|
462
514
|
// 全局先做 booking 标准化 + start_time 升序,后续映射直接复用
|
|
463
515
|
normalizedBookings = bookingList.map(function (booking) {
|
|
464
516
|
return _this3.normalizeMatchedBooking(current, booking);
|
|
@@ -492,7 +544,7 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
492
544
|
bookings: bookings
|
|
493
545
|
});
|
|
494
546
|
}));
|
|
495
|
-
case
|
|
547
|
+
case 14:
|
|
496
548
|
case "end":
|
|
497
549
|
return _context3.stop();
|
|
498
550
|
}
|
|
@@ -21,15 +21,16 @@ export type SalesReservedStatus = 'not_arrived' | 'late' | undefined;
|
|
|
21
21
|
export interface SalesResourceMatchedBooking extends Omit<BookingData, 'status'> {
|
|
22
22
|
status: SalesBookingStatus;
|
|
23
23
|
isTimeout: boolean;
|
|
24
|
+
timeoutTime?: number;
|
|
25
|
+
progressPercent?: number;
|
|
26
|
+
lateTime?: number;
|
|
24
27
|
reserved_status: SalesReservedStatus;
|
|
25
28
|
}
|
|
26
29
|
export interface SalesResourceBookingItem extends Omit<ResourceData, 'bookings'> {
|
|
27
30
|
resource_id: ResourceId;
|
|
28
31
|
bookings: SalesResourceMatchedBooking[];
|
|
29
32
|
}
|
|
30
|
-
export
|
|
31
|
-
[time: string]: number;
|
|
32
|
-
}
|
|
33
|
+
export type SalesTimelineHighlights = number[];
|
|
33
34
|
/**
|
|
34
35
|
* Sales 解决方案状态
|
|
35
36
|
*
|
|
@@ -61,5 +62,5 @@ export interface SalesModuleAPI {
|
|
|
61
62
|
/** 获取资源维度的预约占用列表 */
|
|
62
63
|
getResourceBookingList: (currentTime: string, bookingList: BookingData[]) => Promise<SalesResourceBookingItem[]>;
|
|
63
64
|
/** 获取时间轴每个时间片的预约数量 */
|
|
64
|
-
getTimelineHighlights: (bookingList: BookingData[]) => SalesTimelineHighlights;
|
|
65
|
+
getTimelineHighlights: (bookingList: BookingData[], startDateTime?: string, endDateTime?: string) => SalesTimelineHighlights;
|
|
65
66
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -52,6 +52,7 @@ export interface PisellCore {
|
|
|
52
52
|
validateContext: (config: ModuleContextConfig) => boolean;
|
|
53
53
|
serverOptions?: ServerOptions;
|
|
54
54
|
server?: any;
|
|
55
|
+
setContext: (ctx: Partial<BusinessContext>) => void;
|
|
55
56
|
}
|
|
56
57
|
/**
|
|
57
58
|
* 业务上下文接口
|
|
@@ -59,6 +60,7 @@ export interface PisellCore {
|
|
|
59
60
|
export interface BusinessContext {
|
|
60
61
|
userId?: string;
|
|
61
62
|
companyId?: string;
|
|
63
|
+
locale?: string;
|
|
62
64
|
[key: string]: any;
|
|
63
65
|
}
|
|
64
66
|
/**
|
package/lib/core/index.d.ts
CHANGED
package/lib/core/index.js
CHANGED
|
@@ -235,6 +235,10 @@ var PisellOSCore = class {
|
|
|
235
235
|
this.plugins.clear();
|
|
236
236
|
this.log("PisellOS 核心已销毁");
|
|
237
237
|
}
|
|
238
|
+
setContext(ctx) {
|
|
239
|
+
this.context = { ...this.context, ...ctx };
|
|
240
|
+
this.log(`上下文已更新: ${JSON.stringify(Object.keys(ctx))}`);
|
|
241
|
+
}
|
|
238
242
|
/**
|
|
239
243
|
* 验证上下文参数
|
|
240
244
|
*/
|
|
@@ -9,6 +9,7 @@ export declare class CustomerModule extends BaseModule implements Module, Custom
|
|
|
9
9
|
private cacheId;
|
|
10
10
|
private openCache;
|
|
11
11
|
private fatherModule;
|
|
12
|
+
private otherParams;
|
|
12
13
|
constructor(name?: string, version?: string);
|
|
13
14
|
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
14
15
|
/**
|
|
@@ -46,12 +46,14 @@ var CustomerModule = class extends import_BaseModule.BaseModule {
|
|
|
46
46
|
searchParams: {}
|
|
47
47
|
};
|
|
48
48
|
this.openCache = false;
|
|
49
|
+
this.otherParams = {};
|
|
49
50
|
}
|
|
50
51
|
async initialize(core, options) {
|
|
51
52
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
52
53
|
this.core = core;
|
|
53
54
|
this.store = options == null ? void 0 : options.store;
|
|
54
55
|
this.request = this.core.getPlugin("request");
|
|
56
|
+
this.otherParams = (options == null ? void 0 : options.otherParams) || {};
|
|
55
57
|
if (Array.isArray((_a = options == null ? void 0 : options.initialState) == null ? void 0 : _a.customerList)) {
|
|
56
58
|
const customerList = (0, import_lodash_es.cloneDeep)(options.initialState.customerList || []);
|
|
57
59
|
this.store.customerList = customerList;
|
|
@@ -95,9 +97,12 @@ var CustomerModule = class extends import_BaseModule.BaseModule {
|
|
|
95
97
|
* @returns API响应数据
|
|
96
98
|
*/
|
|
97
99
|
async fetchCustomerListData(params = {}) {
|
|
98
|
-
var _a, _b;
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
var _a, _b, _c, _d;
|
|
101
|
+
let url = "/customer/select-list";
|
|
102
|
+
if ((_a = this.otherParams) == null ? void 0 : _a.isFranchisee) {
|
|
103
|
+
url = "/franchisee/customer/select-list";
|
|
104
|
+
}
|
|
105
|
+
const { skip = 1, num = import_constants.DEFAULT_PAGE_SIZE, search, ..._otherParams } = params;
|
|
101
106
|
const queryParams = {
|
|
102
107
|
skip,
|
|
103
108
|
num,
|
|
@@ -106,7 +111,7 @@ var CustomerModule = class extends import_BaseModule.BaseModule {
|
|
|
106
111
|
search_wallet_flag: 1,
|
|
107
112
|
search_wallet_pass_flag: 1,
|
|
108
113
|
...search && { search },
|
|
109
|
-
...
|
|
114
|
+
..._otherParams
|
|
110
115
|
};
|
|
111
116
|
const res = await this.request.get(url, queryParams, {
|
|
112
117
|
cache: {
|
|
@@ -117,9 +122,19 @@ var CustomerModule = class extends import_BaseModule.BaseModule {
|
|
|
117
122
|
if ((res == null ? void 0 : res.code) !== 200) {
|
|
118
123
|
throw new Error(res == null ? void 0 : res.message);
|
|
119
124
|
}
|
|
125
|
+
let _customerList = ((_b = res == null ? void 0 : res.data) == null ? void 0 : _b.list) || [];
|
|
126
|
+
if (((_c = this.otherParams) == null ? void 0 : _c.isFranchisee) && (_customerList == null ? void 0 : _customerList.length) > 0) {
|
|
127
|
+
_customerList = _customerList == null ? void 0 : _customerList.map((item) => {
|
|
128
|
+
return {
|
|
129
|
+
...item || {},
|
|
130
|
+
is_franchisor_customer: 1
|
|
131
|
+
// 标识是总店的客户
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
}
|
|
120
135
|
return {
|
|
121
|
-
customerList:
|
|
122
|
-
total: ((
|
|
136
|
+
customerList: _customerList,
|
|
137
|
+
total: ((_d = res == null ? void 0 : res.data) == null ? void 0 : _d.count) || 0,
|
|
123
138
|
page: skip,
|
|
124
139
|
pageSize: num
|
|
125
140
|
};
|
|
@@ -23,7 +23,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
23
23
|
*/
|
|
24
24
|
private logError;
|
|
25
25
|
createOrder(params: CommitOrderParams['query']): {
|
|
26
|
-
type: "
|
|
26
|
+
type: "appointment_booking" | "virtual";
|
|
27
27
|
platform: string;
|
|
28
28
|
sales_channel: string;
|
|
29
29
|
order_sales_channel: string;
|
package/lib/server/index.d.ts
CHANGED
|
@@ -167,7 +167,7 @@ declare class Server {
|
|
|
167
167
|
*/
|
|
168
168
|
private handleUnsubscribeOrderQuery;
|
|
169
169
|
/**
|
|
170
|
-
* 判断预约查询的
|
|
170
|
+
* 判断预约查询的 sales_time_between 起始日期是否为今天
|
|
171
171
|
*/
|
|
172
172
|
private isBookingQueryForToday;
|
|
173
173
|
/**
|
|
@@ -201,11 +201,16 @@ declare class Server {
|
|
|
201
201
|
/**
|
|
202
202
|
* 商品查询的核心计算逻辑(编排 Products、Menu、Schedule 模块)
|
|
203
203
|
* 供 handleProductQuery 首次返回及 pubsub 变更推送复用
|
|
204
|
+
* @param context 查询上下文
|
|
205
|
+
* @param options 可选参数
|
|
206
|
+
* @param options.changedIds 变更的商品 IDs,用于增量更新价格缓存
|
|
204
207
|
*/
|
|
205
208
|
private computeProductQueryResult;
|
|
206
209
|
/**
|
|
207
210
|
* 数据变更后,遍历所有订阅者重新计算查询结果并通过 callback 推送
|
|
208
211
|
* 由 ProductsModule 的 onProductsSyncCompleted 事件触发
|
|
212
|
+
* @param options 可选参数
|
|
213
|
+
* @param options.changedIds 变更的商品 IDs,用于增量更新价格缓存
|
|
209
214
|
*/
|
|
210
215
|
private recomputeAndNotifyProductQuery;
|
|
211
216
|
/**
|
package/lib/server/index.js
CHANGED
|
@@ -557,8 +557,10 @@ var Server = class {
|
|
|
557
557
|
} else {
|
|
558
558
|
this.logInfo("跳过自动预加载", { autoPreload });
|
|
559
559
|
}
|
|
560
|
-
this.core.effects.on(import_types.ProductsHooks.onProductsSyncCompleted, () => {
|
|
561
|
-
this.recomputeAndNotifyProductQuery(
|
|
560
|
+
this.core.effects.on(import_types.ProductsHooks.onProductsSyncCompleted, (payload) => {
|
|
561
|
+
this.recomputeAndNotifyProductQuery({
|
|
562
|
+
changedIds: payload == null ? void 0 : payload.changedIds
|
|
563
|
+
});
|
|
562
564
|
});
|
|
563
565
|
this.core.effects.on(import_types2.OrderHooks.onOrdersChanged, () => {
|
|
564
566
|
this.recomputeAndNotifyOrderQuery();
|
|
@@ -834,10 +836,10 @@ var Server = class {
|
|
|
834
836
|
}
|
|
835
837
|
}
|
|
836
838
|
/**
|
|
837
|
-
* 判断预约查询的
|
|
839
|
+
* 判断预约查询的 sales_time_between 起始日期是否为今天
|
|
838
840
|
*/
|
|
839
841
|
isBookingQueryForToday(data) {
|
|
840
|
-
const range = data == null ? void 0 : data.
|
|
842
|
+
const range = data == null ? void 0 : data.sales_time_between;
|
|
841
843
|
if (!Array.isArray(range) || range.length < 1)
|
|
842
844
|
return true;
|
|
843
845
|
const startDateStr = String(range[0]).split("T")[0].split(" ")[0];
|
|
@@ -859,18 +861,18 @@ var Server = class {
|
|
|
859
861
|
};
|
|
860
862
|
}
|
|
861
863
|
try {
|
|
862
|
-
const response = await this.app.request.get("/shop/order/sales", { ...data, with: ["all"] }, {
|
|
864
|
+
const response = await this.app.request.get("/shop/order/sales", { ...data, form_record_ids: void 0, with: ["all"] }, {
|
|
863
865
|
isShopApi: true
|
|
864
866
|
});
|
|
865
867
|
const rawList = ((_b = response == null ? void 0 : response.data) == null ? void 0 : _b.list) ?? (response == null ? void 0 : response.list) ?? [];
|
|
866
|
-
const list = (0, import_filterBookings.
|
|
868
|
+
const list = (0, import_filterBookings.filterBookingsFromOrders)(rawList, data);
|
|
867
869
|
this.logInfo("fetchBookingListFromAPI: API 返回并拆分完成", {
|
|
868
870
|
rawCount: rawList.length,
|
|
869
|
-
flattenedCount: list.
|
|
871
|
+
flattenedCount: list.count
|
|
870
872
|
});
|
|
871
873
|
return {
|
|
872
874
|
code: 200,
|
|
873
|
-
data: { ...response.data, list },
|
|
875
|
+
data: { ...response.data, list: (list == null ? void 0 : list.list) || [] },
|
|
874
876
|
message: "",
|
|
875
877
|
status: true
|
|
876
878
|
};
|
|
@@ -950,14 +952,18 @@ var Server = class {
|
|
|
950
952
|
/**
|
|
951
953
|
* 商品查询的核心计算逻辑(编排 Products、Menu、Schedule 模块)
|
|
952
954
|
* 供 handleProductQuery 首次返回及 pubsub 变更推送复用
|
|
955
|
+
* @param context 查询上下文
|
|
956
|
+
* @param options 可选参数
|
|
957
|
+
* @param options.changedIds 变更的商品 IDs,用于增量更新价格缓存
|
|
953
958
|
*/
|
|
954
|
-
async computeProductQueryResult(context) {
|
|
959
|
+
async computeProductQueryResult(context, options) {
|
|
955
960
|
const tTotal = performance.now();
|
|
956
961
|
const { menu_list_ids, schedule_date, schedule_datetime } = context;
|
|
957
962
|
this.logInfo("computeProductQueryResult 开始", {
|
|
958
963
|
menuListIdsCount: (menu_list_ids == null ? void 0 : menu_list_ids.length) ?? 0,
|
|
959
964
|
schedule_datetime,
|
|
960
|
-
schedule_date
|
|
965
|
+
schedule_date,
|
|
966
|
+
changedIds: options == null ? void 0 : options.changedIds
|
|
961
967
|
});
|
|
962
968
|
if (!this.products) {
|
|
963
969
|
this.logError("computeProductQueryResult: Products 模块未注册");
|
|
@@ -987,6 +993,8 @@ var Server = class {
|
|
|
987
993
|
const tPrice = performance.now();
|
|
988
994
|
const allProductsWithPrice = await this.products.getProductsWithPrice(schedule_date, {
|
|
989
995
|
scheduleModule: this.getSchedule()
|
|
996
|
+
}, {
|
|
997
|
+
changedIds: options == null ? void 0 : options.changedIds
|
|
990
998
|
});
|
|
991
999
|
(0, import_product.perfMark)("computeQuery.getProductsWithPrice", performance.now() - tPrice, {
|
|
992
1000
|
count: allProductsWithPrice.length
|
|
@@ -997,6 +1005,13 @@ var Server = class {
|
|
|
997
1005
|
before: allProductsWithPrice.length,
|
|
998
1006
|
after: filteredProducts.length
|
|
999
1007
|
});
|
|
1008
|
+
const tStatus = performance.now();
|
|
1009
|
+
const beforeStatusCount = filteredProducts.length;
|
|
1010
|
+
filteredProducts = filteredProducts.filter((p) => ((p == null ? void 0 : p.status) || "published") === "published");
|
|
1011
|
+
(0, import_product.perfMark)("computeQuery.filterByStatus", performance.now() - tStatus, {
|
|
1012
|
+
before: beforeStatusCount,
|
|
1013
|
+
after: filteredProducts.length
|
|
1014
|
+
});
|
|
1000
1015
|
const tSort = performance.now();
|
|
1001
1016
|
filteredProducts = filteredProducts.sort((a, b) => {
|
|
1002
1017
|
const sortDiff = Number(b.sort) - Number(a.sort);
|
|
@@ -1025,16 +1040,21 @@ var Server = class {
|
|
|
1025
1040
|
/**
|
|
1026
1041
|
* 数据变更后,遍历所有订阅者重新计算查询结果并通过 callback 推送
|
|
1027
1042
|
* 由 ProductsModule 的 onProductsSyncCompleted 事件触发
|
|
1043
|
+
* @param options 可选参数
|
|
1044
|
+
* @param options.changedIds 变更的商品 IDs,用于增量更新价格缓存
|
|
1028
1045
|
*/
|
|
1029
|
-
async recomputeAndNotifyProductQuery() {
|
|
1046
|
+
async recomputeAndNotifyProductQuery(options) {
|
|
1030
1047
|
if (this.productQuerySubscribers.size === 0)
|
|
1031
1048
|
return;
|
|
1032
1049
|
this.logInfo("recomputeAndNotifyProductQuery: 开始推送", {
|
|
1033
|
-
subscriberCount: this.productQuerySubscribers.size
|
|
1050
|
+
subscriberCount: this.productQuerySubscribers.size,
|
|
1051
|
+
changedIds: options == null ? void 0 : options.changedIds
|
|
1034
1052
|
});
|
|
1035
1053
|
for (const [subscriberId, subscriber] of this.productQuerySubscribers.entries()) {
|
|
1036
1054
|
try {
|
|
1037
|
-
const result = await this.computeProductQueryResult(subscriber.context
|
|
1055
|
+
const result = await this.computeProductQueryResult(subscriber.context, {
|
|
1056
|
+
changedIds: options == null ? void 0 : options.changedIds
|
|
1057
|
+
});
|
|
1038
1058
|
subscriber.callback(result);
|
|
1039
1059
|
this.logInfo("recomputeAndNotifyProductQuery: 已推送", { subscriberId });
|
|
1040
1060
|
} catch (error) {
|
|
@@ -438,7 +438,7 @@ export interface BookingFilters {
|
|
|
438
438
|
payment_method?: string[];
|
|
439
439
|
business_code?: string;
|
|
440
440
|
appointment_status?: string[];
|
|
441
|
-
|
|
441
|
+
sales_time_between?: string[];
|
|
442
442
|
/**
|
|
443
443
|
* 仅保留「预约开始时刻」大于等于该时间的条目。
|
|
444
444
|
* 预约时刻由 start_date 与 start_time 拼接解析(与 order_by start_at 一致)。
|
|
@@ -75,7 +75,7 @@ function prepareFilters(f) {
|
|
|
75
75
|
customerIdStr: hasCustomerId ? String(f.customer_id) : "",
|
|
76
76
|
hasBusinessCode: !!f.business_code,
|
|
77
77
|
businessCode: f.business_code,
|
|
78
|
-
bookingTimeRange: parseDateRange(f.
|
|
78
|
+
bookingTimeRange: parseDateRange(f.sales_time_between),
|
|
79
79
|
createdAtRange: parseDateRange(f.created_at_between),
|
|
80
80
|
updatedAtRange: parseDateRange(f.updated_at_between),
|
|
81
81
|
numberRange: parseNumberRange(f.number_between),
|