@pisell/pisellos 2.3.73 → 2.3.75
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 +7 -0
- package/dist/core/index.js +111 -71
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/model/strategy/adapter/walletPass/example.js +3 -26
- package/dist/model/strategy/strategy-example.js +5 -19
- package/dist/modules/Cart/index.js +0 -3
- package/dist/modules/Cart/utils/cartProduct.js +0 -1
- package/dist/modules/Date/index.js +1 -5
- package/dist/modules/Discount/index.js +2 -4
- package/dist/modules/OpenData/index.js +0 -2
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +36 -64
- package/dist/modules/Payment/index.js +97 -162
- package/dist/modules/Quotation/index.d.ts +6 -0
- package/dist/modules/Quotation/index.js +75 -19
- package/dist/modules/Rules/index.js +1 -4
- package/dist/modules/Schedule/index.js +0 -1
- package/dist/modules/Schedule/utils.js +0 -1
- package/dist/modules/Step/index.js +0 -1
- package/dist/plugins/request.d.ts +1 -0
- package/dist/plugins/request.js +1 -4
- package/dist/plugins/window.js +2 -6
- package/dist/server/index.d.ts +8 -2
- package/dist/server/index.js +303 -269
- package/dist/server/modules/floor-plan/index.d.ts +4 -0
- package/dist/server/modules/floor-plan/index.js +240 -98
- package/dist/server/modules/menu/index.js +75 -59
- package/dist/server/modules/order/index.d.ts +17 -7
- package/dist/server/modules/order/index.js +421 -211
- package/dist/server/modules/products/index.d.ts +8 -2
- package/dist/server/modules/products/index.js +191 -117
- package/dist/server/modules/quotation/index.js +29 -38
- package/dist/server/modules/resource/index.js +24 -17
- package/dist/server/modules/schedule/index.js +27 -35
- package/dist/server/utils/product.js +0 -1
- package/dist/solution/BaseSales/index.js +38 -41
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingByStep/index.js +7 -59
- package/dist/solution/BookingByStep/utils/capacity.js +1 -11
- package/dist/solution/BookingByStep/utils/resources.js +1 -3
- package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
- package/dist/solution/BookingTicket/index.js +0 -2
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +6 -7
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
- package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
- package/dist/solution/BuyTickets/index.js +9 -12
- package/dist/solution/Checkout/index.js +177 -252
- package/dist/solution/Checkout/utils/index.js +4 -16
- package/dist/solution/RegisterAndLogin/index.js +30 -76
- package/dist/solution/ScanOrder/index.js +50 -60
- package/dist/solution/ShopDiscount/index.js +2 -7
- package/dist/solution/VenueBooking/index.js +45 -55
- package/dist/utils/task.js +15 -18
- package/dist/utils/watch.js +0 -1
- package/lib/apis/picoding.js +2 -0
- package/lib/core/index.d.ts +7 -0
- package/lib/core/index.js +149 -131
- package/lib/effects/index.js +46 -57
- package/lib/index.js +82 -49
- package/lib/model/index.js +14 -21
- package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
- package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
- package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
- package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
- package/lib/model/strategy/adapter/index.js +100 -64
- package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
- package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
- package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
- package/lib/model/strategy/adapter/itemRule/index.js +83 -57
- package/lib/model/strategy/adapter/itemRule/type.js +97 -36
- package/lib/model/strategy/adapter/promotion/adapter.js +91 -69
- package/lib/model/strategy/adapter/promotion/evaluator.js +444 -310
- package/lib/model/strategy/adapter/promotion/examples.js +222 -234
- package/lib/model/strategy/adapter/promotion/index.js +1 -0
- package/lib/model/strategy/adapter/promotion/type.js +243 -36
- package/lib/model/strategy/adapter/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -150
- package/lib/model/strategy/adapter/walletPass/example.js +217 -190
- package/lib/model/strategy/adapter/walletPass/index.js +75 -51
- package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
- package/lib/model/strategy/adapter/walletPass/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/utils.js +588 -378
- package/lib/model/strategy/engine.js +270 -168
- package/lib/model/strategy/index.js +49 -34
- package/lib/model/strategy/strategy-example.js +243 -239
- package/lib/model/strategy/type.js +100 -40
- package/lib/modules/Account/index.js +39 -53
- package/lib/modules/Account/types.js +20 -33
- package/lib/modules/AccountList/index.js +116 -154
- package/lib/modules/AccountList/types.js +30 -31
- package/lib/modules/AccountList/utils.js +18 -30
- package/lib/modules/BaseModule.js +23 -42
- package/lib/modules/BookingContext/index.js +158 -136
- package/lib/modules/BookingContext/types.js +46 -32
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +138 -146
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +78 -83
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +170 -150
- package/lib/modules/BookingContext/utils/flexible.js +38 -55
- package/lib/modules/BookingContext/utils/formatResourceList.js +19 -34
- package/lib/modules/BookingContext/utils/index.js +124 -41
- package/lib/modules/BookingContext/utils/noResource.js +58 -70
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +14 -41
- package/lib/modules/BookingContext/utils/productExtend.js +202 -155
- package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
- package/lib/modules/BookingContext/utils/resourceSelection.js +19 -41
- package/lib/modules/BookingContext/utils/resources.js +209 -167
- package/lib/modules/BookingContext/utils/serviceTimes.js +115 -116
- package/lib/modules/BookingContext/utils/timeSlices.js +76 -86
- package/lib/modules/Cart/index.js +170 -124
- package/lib/modules/Cart/types.js +46 -51
- package/lib/modules/Cart/utils/cartAccount.js +40 -39
- package/lib/modules/Cart/utils/cartDate.js +56 -61
- package/lib/modules/Cart/utils/cartDiscount.js +28 -33
- package/lib/modules/Cart/utils/cartNote.js +27 -32
- package/lib/modules/Cart/utils/cartProduct.js +321 -251
- package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
- package/lib/modules/Cart/utils/cartResource.js +70 -78
- package/lib/modules/Cart/utils/changePrice.js +22 -50
- package/lib/modules/Cart/utils/index.js +106 -48
- package/lib/modules/Customer/constants.js +13 -34
- package/lib/modules/Customer/index.js +235 -172
- package/lib/modules/Customer/types.js +38 -35
- package/lib/modules/Date/index.js +116 -115
- package/lib/modules/Date/types.js +16 -28
- package/lib/modules/Date/utils.js +174 -123
- package/lib/modules/Discount/index.js +122 -127
- package/lib/modules/Discount/types.js +9 -31
- package/lib/modules/Guests/index.js +30 -56
- package/lib/modules/Guests/types.js +23 -33
- package/lib/modules/Holder/index.js +209 -189
- package/lib/modules/Holder/types.js +4 -16
- package/lib/modules/Holder/utils.js +20 -49
- package/lib/modules/OpenData/index.js +70 -76
- package/lib/modules/OpenData/types.js +4 -16
- package/lib/modules/OpenData/utils.js +44 -78
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +1713 -2118
- package/lib/modules/Order/payment-utils.js +77 -120
- package/lib/modules/Order/types.js +88 -35
- package/lib/modules/Order/utils/bundleDiscountHydration.js +41 -74
- package/lib/modules/Order/utils/discountProductLineIdentity.js +142 -100
- package/lib/modules/Order/utils/manualProductDiscount.js +124 -123
- package/lib/modules/Order/utils/orderCollectionIdentity.js +184 -244
- package/lib/modules/Order/utils.js +814 -647
- package/lib/modules/Payment/cash.js +20 -33
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
- package/lib/modules/Payment/eftpos.js +16 -30
- package/lib/modules/Payment/index.js +532 -399
- package/lib/modules/Payment/mx51.js +1 -0
- package/lib/modules/Payment/types.js +230 -108
- package/lib/modules/Payment/utils.js +52 -51
- package/lib/modules/Payment/walletpass.js +485 -660
- package/lib/modules/Product/index.js +51 -46
- package/lib/modules/Product/types.js +4 -16
- package/lib/modules/Product/utils.js +32 -33
- package/lib/modules/ProductList/index.js +113 -123
- package/lib/modules/ProductList/types.js +9 -31
- package/lib/modules/Quotation/index.d.ts +6 -0
- package/lib/modules/Quotation/index.js +110 -103
- package/lib/modules/Quotation/types.js +4 -16
- package/lib/modules/Resource/index.js +27 -59
- package/lib/modules/Resource/types.js +22 -32
- package/lib/modules/Resource/utils.js +30 -38
- package/lib/modules/ResourcePlanner/index.js +25 -23
- package/lib/modules/ResourcePlanner/localClock.js +54 -119
- package/lib/modules/ResourcePlanner/planner.js +589 -770
- package/lib/modules/ResourcePlanner/types.js +10 -29
- package/lib/modules/Rules/index.js +1218 -959
- package/lib/modules/Rules/types.js +17 -40
- package/lib/modules/SalesSummary/index.js +85 -90
- package/lib/modules/SalesSummary/types.js +4 -16
- package/lib/modules/SalesSummary/utils.js +355 -430
- package/lib/modules/ScanOrderLogger/index.js +59 -79
- package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
- package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
- package/lib/modules/ScanOrderLogger/types.js +4 -16
- package/lib/modules/Schedule/getDateIsInSchedule.js +334 -163
- package/lib/modules/Schedule/index.js +100 -114
- package/lib/modules/Schedule/type.js +4 -16
- package/lib/modules/Schedule/types.js +4 -16
- package/lib/modules/Schedule/utils.js +433 -291
- package/lib/modules/Step/index.js +40 -52
- package/lib/modules/Step/tyeps.js +4 -16
- package/lib/modules/Summary/index.js +66 -71
- package/lib/modules/Summary/types.js +4 -16
- package/lib/modules/Summary/utils.js +773 -418
- package/lib/modules/SurchargeList/index.js +46 -60
- package/lib/modules/SurchargeList/types.js +4 -16
- package/lib/modules/index.js +245 -63
- package/lib/plugins/app.js +4 -16
- package/lib/plugins/index.js +36 -25
- package/lib/plugins/request.d.ts +1 -0
- package/lib/plugins/request.js +137 -126
- package/lib/plugins/shopStore.js +4 -16
- package/lib/plugins/user.js +4 -16
- package/lib/plugins/window.js +171 -179
- package/lib/server/index.d.ts +8 -2
- package/lib/server/index.js +3083 -2663
- package/lib/server/modules/floor-plan/index.d.ts +4 -0
- package/lib/server/modules/floor-plan/index.js +159 -127
- package/lib/server/modules/floor-plan/types.js +15 -30
- package/lib/server/modules/index.js +106 -68
- package/lib/server/modules/menu/index.js +170 -124
- package/lib/server/modules/menu/types.js +18 -31
- package/lib/server/modules/order/index.d.ts +17 -7
- package/lib/server/modules/order/index.js +916 -977
- package/lib/server/modules/order/types.js +122 -33
- package/lib/server/modules/order/utils/filterBookings.js +219 -194
- package/lib/server/modules/order/utils/filterOrders.js +118 -92
- package/lib/server/modules/payment/index.js +59 -83
- package/lib/server/modules/payment/types.js +4 -16
- package/lib/server/modules/products/index.d.ts +8 -2
- package/lib/server/modules/products/index.js +656 -471
- package/lib/server/modules/products/types.js +44 -34
- package/lib/server/modules/quotation/index.js +137 -172
- package/lib/server/modules/quotation/types.js +21 -31
- package/lib/server/modules/resource/index.js +225 -186
- package/lib/server/modules/resource/types.js +42 -33
- package/lib/server/modules/schedule/index.js +135 -123
- package/lib/server/modules/schedule/types.js +14 -21
- package/lib/server/modules/schedule/utils.js +334 -163
- package/lib/server/types.js +4 -16
- package/lib/server/utils/index.js +25 -23
- package/lib/server/utils/product.js +196 -139
- package/lib/server/utils/schedule.js +34 -41
- package/lib/server/utils/small-ticket.js +479 -456
- package/lib/server/utils/time.js +40 -49
- package/lib/solution/BaseSales/index.js +1186 -1410
- package/lib/solution/BaseSales/types.js +42 -38
- package/lib/solution/BaseSales/utils/cartPromotion.js +642 -498
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +85 -105
- package/lib/solution/BaseSales/utils/quotationPrice.js +56 -114
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +108 -145
- package/lib/solution/BaseSales/utils.js +158 -143
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1527 -1340
- package/lib/solution/BookingByStep/types.js +40 -99
- package/lib/solution/BookingByStep/utils/capacity.js +192 -160
- package/lib/solution/BookingByStep/utils/products.js +42 -52
- package/lib/solution/BookingByStep/utils/resources.js +527 -330
- package/lib/solution/BookingByStep/utils/stock.js +65 -44
- package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
- package/lib/solution/BookingTicket/index.js +607 -522
- package/lib/solution/BookingTicket/types.js +99 -77
- package/lib/solution/BookingTicket/utils/addProductDecision.js +226 -189
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +58 -89
- package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -78
- package/lib/solution/BookingTicket/utils/cartView.js +114 -99
- package/lib/solution/BookingTicket/utils/exampleData.js +185 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.js +18 -41
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +219 -86
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +168 -116
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +79 -91
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +54 -41
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +84 -81
- package/lib/solution/BookingTicket/utils/scan/index.js +98 -104
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +52 -64
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +56 -58
- package/lib/solution/BookingTicket/utils/weighingProductSku.js +34 -48
- package/lib/solution/BuyTickets/index.js +67 -70
- package/lib/solution/BuyTickets/types.js +22 -38
- package/lib/solution/Checkout/index.js +1451 -1158
- package/lib/solution/Checkout/types.js +91 -61
- package/lib/solution/Checkout/utils/index.js +228 -156
- package/lib/solution/PlaceOrder/index.js +55 -0
- package/lib/solution/RegisterAndLogin/config.js +493 -460
- package/lib/solution/RegisterAndLogin/index.js +633 -630
- package/lib/solution/RegisterAndLogin/types.js +189 -76
- package/lib/solution/RegisterAndLogin/utils.js +183 -125
- package/lib/solution/Sales/index.js +328 -324
- package/lib/solution/Sales/types.js +27 -33
- package/lib/solution/ScanOrder/index.js +832 -864
- package/lib/solution/ScanOrder/types.js +33 -34
- package/lib/solution/ScanOrder/utils.js +409 -374
- package/lib/solution/ShopDiscount/index.js +226 -232
- package/lib/solution/ShopDiscount/types.js +15 -37
- package/lib/solution/ShopDiscount/utils.js +300 -172
- package/lib/solution/UnifiedBookingSales/index.js +1035 -1201
- package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.js +99 -159
- package/lib/solution/UnifiedBookingSales/types.js +10 -32
- package/lib/solution/VenueBooking/index.js +811 -879
- package/lib/solution/VenueBooking/types.js +19 -39
- package/lib/solution/VenueBooking/utils/dateSummary.js +27 -56
- package/lib/solution/VenueBooking/utils/resource.js +31 -54
- package/lib/solution/VenueBooking/utils/slotMerge.js +94 -107
- package/lib/solution/VenueBooking/utils/timeSlot.js +132 -132
- package/lib/solution/VenueBooking/utils.js +130 -67
- package/lib/solution/index.js +124 -41
- package/lib/store/createStore.js +32 -29
- package/lib/types/index.js +4 -16
- package/lib/utils/payment-number.js +26 -46
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +81 -47
- package/package.json +2 -1
|
@@ -1,126 +1,118 @@
|
|
|
1
|
-
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
1
|
+
"use strict";
|
|
28
2
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
__export(filterBookings_exports, {
|
|
32
|
-
filterBookings: () => filterBookings,
|
|
33
|
-
filterBookingsFromOrders: () => filterBookingsFromOrders,
|
|
34
|
-
flattenOrdersToBookings: () => flattenOrdersToBookings,
|
|
35
|
-
productsForBooking: () => productsForBooking,
|
|
36
|
-
sortBookings: () => sortBookings
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
37
5
|
});
|
|
38
|
-
|
|
39
|
-
|
|
6
|
+
exports.filterBookings = filterBookings;
|
|
7
|
+
exports.filterBookingsFromOrders = filterBookingsFromOrders;
|
|
8
|
+
exports.flattenOrdersToBookings = flattenOrdersToBookings;
|
|
9
|
+
exports.productsForBooking = productsForBooking;
|
|
10
|
+
exports.sortBookings = sortBookings;
|
|
11
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
12
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
+
/** 预约状态:协议 appointment_status 优先,兼容历史 status */
|
|
40
14
|
function getBookingAppointmentStatus(booking) {
|
|
41
|
-
return String(booking.appointment_status ?? booking.status ??
|
|
15
|
+
return String(booking.appointment_status ?? booking.status ?? '');
|
|
42
16
|
}
|
|
17
|
+
|
|
18
|
+
// ─────────────────────────────────────────────────────────────────
|
|
19
|
+
// 时间戳 / 范围解析
|
|
20
|
+
// ─────────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
43
22
|
function toTimestamp(value) {
|
|
44
|
-
if (value ===
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const d = (0, import_dayjs.default)(value);
|
|
23
|
+
if (value === undefined || value === null || value === '') return 0;
|
|
24
|
+
if (typeof value === 'number') return value;
|
|
25
|
+
// 使用 dayjs 按本地时区解析,避免 new Date("YYYY-MM-DD") 被当作 UTC 0 点
|
|
26
|
+
const d = (0, _dayjs.default)(value);
|
|
49
27
|
return d.isValid() ? d.valueOf() : 0;
|
|
50
28
|
}
|
|
51
|
-
|
|
29
|
+
|
|
30
|
+
/** 日期范围端点解析:纯日期串自动对齐到当天起止边界(本地时区) */
|
|
31
|
+
const DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
52
32
|
function toRangeBoundary(value, isEnd) {
|
|
53
|
-
if (value ===
|
|
54
|
-
|
|
55
|
-
if (typeof value === "number")
|
|
56
|
-
return value;
|
|
33
|
+
if (value === undefined || value === null || value === '') return 0;
|
|
34
|
+
if (typeof value === 'number') return value;
|
|
57
35
|
const str = String(value).trim();
|
|
58
|
-
const d = (0,
|
|
59
|
-
if (!d.isValid())
|
|
60
|
-
return 0;
|
|
36
|
+
const d = (0, _dayjs.default)(str);
|
|
37
|
+
if (!d.isValid()) return 0;
|
|
61
38
|
if (DATE_ONLY_RE.test(str)) {
|
|
62
|
-
return (isEnd ? d.endOf(
|
|
39
|
+
return (isEnd ? d.endOf('day') : d.startOf('day')).valueOf();
|
|
63
40
|
}
|
|
64
41
|
return d.valueOf();
|
|
65
42
|
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 将 start_date / start_time(或 end_*)拼成可被 Date 稳定解析的字符串。
|
|
46
|
+
* 时间字段协议为 H:i(如 15:00)时补全为 H:i:00,避免部分环境对「无秒」非 ISO 串(空格分隔)解析不一致。
|
|
47
|
+
*/
|
|
66
48
|
function bookingDateTimeString(datePart, timePart) {
|
|
67
|
-
const d = (datePart ??
|
|
68
|
-
let t = (timePart ??
|
|
49
|
+
const d = (datePart ?? '').trim();
|
|
50
|
+
let t = (timePart ?? '').trim();
|
|
69
51
|
if (t && /^\d{1,2}:\d{2}$/.test(t)) {
|
|
70
52
|
t = `${t}:00`;
|
|
71
53
|
}
|
|
72
54
|
return `${d} ${t}`.trim();
|
|
73
55
|
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 解析预约自身的起止时间区间,供 `sales_time_between` 做区间重叠匹配。
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const span = resolveBookingTimeRange({ start_date: '2026-06-09', start_time: '10:00', end_date: '2026-06-15', end_time: '10:00' })
|
|
62
|
+
*/
|
|
74
63
|
function resolveBookingTimeRange(booking) {
|
|
75
64
|
const start = toTimestamp(bookingDateTimeString(booking.start_date, booking.start_time));
|
|
76
|
-
if (!start)
|
|
77
|
-
|
|
78
|
-
const end = toTimestamp(
|
|
79
|
-
bookingDateTimeString(
|
|
80
|
-
booking.end_date || booking.start_date,
|
|
81
|
-
booking.end_time || booking.start_time
|
|
82
|
-
)
|
|
83
|
-
) || start;
|
|
65
|
+
if (!start) return null;
|
|
66
|
+
const end = toTimestamp(bookingDateTimeString(booking.end_date || booking.start_date, booking.end_time || booking.start_time)) || start;
|
|
84
67
|
return end >= start ? [start, end] : [end, start];
|
|
85
68
|
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 判断两个闭区间是否有交集。
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* isRangeOverlapping([1, 10], [5, 6]) // true
|
|
75
|
+
*/
|
|
86
76
|
function isRangeOverlapping(left, right) {
|
|
87
77
|
return left[0] <= right[1] && left[1] >= right[0];
|
|
88
78
|
}
|
|
89
79
|
function parseDateRange(range) {
|
|
90
|
-
if (!Array.isArray(range) || range.length < 2)
|
|
91
|
-
return null;
|
|
80
|
+
if (!Array.isArray(range) || range.length < 2) return null;
|
|
92
81
|
const start = toRangeBoundary(range[0], false);
|
|
93
82
|
const end = toRangeBoundary(range[1], true);
|
|
94
|
-
if (!start && !end)
|
|
95
|
-
return null;
|
|
83
|
+
if (!start && !end) return null;
|
|
96
84
|
return [start, end];
|
|
97
85
|
}
|
|
98
86
|
function parseNumberRange(range) {
|
|
99
|
-
if (!Array.isArray(range) || range.length < 2)
|
|
100
|
-
return null;
|
|
87
|
+
if (!Array.isArray(range) || range.length < 2) return null;
|
|
101
88
|
const min = Number(range[0]);
|
|
102
89
|
const max = Number(range[1]);
|
|
103
|
-
if (isNaN(min) || isNaN(max))
|
|
104
|
-
return null;
|
|
90
|
+
if (isNaN(min) || isNaN(max)) return null;
|
|
105
91
|
return [min, max];
|
|
106
92
|
}
|
|
93
|
+
|
|
94
|
+
// ─────────────────────────────────────────────────────────────────
|
|
95
|
+
// 预编译过滤上下文:将 filters 一次性解析为高效的 Set / Range,
|
|
96
|
+
// 供 matchOrder、matchBooking 复用,避免重复计算
|
|
97
|
+
// ─────────────────────────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
/** 预约列表搜索兼容前端通用 `keyword` 与后端协议 `keywords` 两种字段 */
|
|
107
100
|
function resolveBookingKeyword(f) {
|
|
108
101
|
const keyword = f.keyword ?? f.keywords;
|
|
109
|
-
return typeof keyword ===
|
|
102
|
+
return typeof keyword === 'string' ? keyword.trim() : '';
|
|
110
103
|
}
|
|
111
104
|
function prepareFilters(f) {
|
|
112
|
-
|
|
113
|
-
const hasCustomerId = f.customer_id !== void 0 && f.customer_id !== null;
|
|
105
|
+
const hasCustomerId = f.customer_id !== undefined && f.customer_id !== null;
|
|
114
106
|
const keyword = resolveBookingKeyword(f);
|
|
115
107
|
return {
|
|
116
|
-
orderPaymentStatusSet:
|
|
117
|
-
orderStatusSet:
|
|
118
|
-
orderSalesChannelSet:
|
|
119
|
-
paymentMethodSet:
|
|
120
|
-
appointmentStatusSet:
|
|
121
|
-
formRecordIdSet:
|
|
108
|
+
orderPaymentStatusSet: f.order_payment_status?.length ? new Set(f.order_payment_status) : null,
|
|
109
|
+
orderStatusSet: f.order_status?.length ? new Set(f.order_status) : null,
|
|
110
|
+
orderSalesChannelSet: f.order_sales_channel?.length ? new Set(f.order_sales_channel) : null,
|
|
111
|
+
paymentMethodSet: f.payment_method?.length ? new Set(f.payment_method) : null,
|
|
112
|
+
appointmentStatusSet: f.appointment_status?.length ? new Set(f.appointment_status) : null,
|
|
113
|
+
formRecordIdSet: f.form_record_ids?.length ? new Set(f.form_record_ids) : null,
|
|
122
114
|
hasCustomerId,
|
|
123
|
-
customerIdStr: hasCustomerId ? String(f.customer_id) :
|
|
115
|
+
customerIdStr: hasCustomerId ? String(f.customer_id) : '',
|
|
124
116
|
hasBusinessCode: !!f.business_code,
|
|
125
117
|
businessCode: f.business_code,
|
|
126
118
|
bookingTimeRange: parseDateRange(f.sales_time_between),
|
|
@@ -128,33 +120,30 @@ function prepareFilters(f) {
|
|
|
128
120
|
updatedAtRange: parseDateRange(f.updated_at_between),
|
|
129
121
|
numberRange: parseNumberRange(f.number_between),
|
|
130
122
|
totalAmountRange: Array.isArray(f.total_amount_between) && f.total_amount_between.length === 2 ? f.total_amount_between : null,
|
|
131
|
-
keywordLower: keyword ? keyword.toLowerCase() :
|
|
123
|
+
keywordLower: keyword ? keyword.toLowerCase() : '',
|
|
132
124
|
afterExecutionTimeMs: (() => {
|
|
133
125
|
const raw = f.after_execution_time;
|
|
134
|
-
if (raw ===
|
|
135
|
-
return null;
|
|
126
|
+
if (raw === undefined || raw === null || raw === '') return null;
|
|
136
127
|
const ms = toTimestamp(raw);
|
|
137
128
|
return Number.isFinite(ms) ? ms : null;
|
|
138
129
|
})(),
|
|
139
130
|
enableChildBookingFilter: f.child_booking === 1
|
|
140
131
|
};
|
|
141
132
|
}
|
|
133
|
+
|
|
134
|
+
// ─────────────────────────────────────────────────────────────────
|
|
135
|
+
// 订单级匹配:不通过则整个 order 下所有 bookings 跳过
|
|
136
|
+
// ─────────────────────────────────────────────────────────────────
|
|
137
|
+
|
|
142
138
|
function matchOrder(order, ctx) {
|
|
143
|
-
|
|
144
|
-
if (ctx.
|
|
145
|
-
|
|
146
|
-
if (ctx.
|
|
147
|
-
|
|
148
|
-
if (ctx.orderPaymentStatusSet && !ctx.orderPaymentStatusSet.has(order.payment_status))
|
|
149
|
-
return false;
|
|
150
|
-
if (ctx.orderStatusSet && !ctx.orderStatusSet.has(order.status))
|
|
151
|
-
return false;
|
|
152
|
-
if (ctx.orderSalesChannelSet && !ctx.orderSalesChannelSet.has(order.order_sales_channel))
|
|
153
|
-
return false;
|
|
139
|
+
if (ctx.hasBusinessCode && order.business_code !== ctx.businessCode) return false;
|
|
140
|
+
if (ctx.hasCustomerId && String(order.customer_id) !== ctx.customerIdStr) return false;
|
|
141
|
+
if (ctx.orderPaymentStatusSet && !ctx.orderPaymentStatusSet.has(order.payment_status)) return false;
|
|
142
|
+
if (ctx.orderStatusSet && !ctx.orderStatusSet.has(order.status)) return false;
|
|
143
|
+
if (ctx.orderSalesChannelSet && !ctx.orderSalesChannelSet.has(order.order_sales_channel)) return false;
|
|
154
144
|
if (ctx.paymentMethodSet) {
|
|
155
145
|
const pm = order.payments;
|
|
156
|
-
if (!Array.isArray(pm) || pm.length === 0)
|
|
157
|
-
return false;
|
|
146
|
+
if (!Array.isArray(pm) || pm.length === 0) return false;
|
|
158
147
|
let matched = false;
|
|
159
148
|
for (let k = 0; k < pm.length; k++) {
|
|
160
149
|
if (ctx.paymentMethodSet.has(pm[k].code)) {
|
|
@@ -162,113 +151,109 @@ function matchOrder(order, ctx) {
|
|
|
162
151
|
break;
|
|
163
152
|
}
|
|
164
153
|
}
|
|
165
|
-
if (!matched)
|
|
166
|
-
return false;
|
|
154
|
+
if (!matched) return false;
|
|
167
155
|
}
|
|
168
156
|
if (ctx.createdAtRange) {
|
|
169
157
|
const ts = toTimestamp(order.created_at);
|
|
170
|
-
if (ts < ctx.createdAtRange[0] || ts > ctx.createdAtRange[1])
|
|
171
|
-
return false;
|
|
158
|
+
if (ts < ctx.createdAtRange[0] || ts > ctx.createdAtRange[1]) return false;
|
|
172
159
|
}
|
|
173
160
|
if (ctx.updatedAtRange) {
|
|
174
161
|
const ts = toTimestamp(order.updated_at);
|
|
175
|
-
if (ts < ctx.updatedAtRange[0] || ts > ctx.updatedAtRange[1])
|
|
176
|
-
return false;
|
|
162
|
+
if (ts < ctx.updatedAtRange[0] || ts > ctx.updatedAtRange[1]) return false;
|
|
177
163
|
}
|
|
178
164
|
if (ctx.totalAmountRange) {
|
|
179
|
-
const raw =
|
|
165
|
+
const raw = order.summary?.total_amount ?? order.total_amount;
|
|
180
166
|
const amt = Number(raw);
|
|
181
|
-
if (isNaN(amt))
|
|
182
|
-
|
|
183
|
-
if (ctx.totalAmountRange[
|
|
184
|
-
return false;
|
|
185
|
-
if (ctx.totalAmountRange[1] != null && amt > ctx.totalAmountRange[1])
|
|
186
|
-
return false;
|
|
167
|
+
if (isNaN(amt)) return false;
|
|
168
|
+
if (ctx.totalAmountRange[0] != null && amt < ctx.totalAmountRange[0]) return false;
|
|
169
|
+
if (ctx.totalAmountRange[1] != null && amt > ctx.totalAmountRange[1]) return false;
|
|
187
170
|
}
|
|
188
171
|
return true;
|
|
189
172
|
}
|
|
173
|
+
|
|
174
|
+
// ─────────────────────────────────────────────────────────────────
|
|
175
|
+
// Booking 级匹配:在订单通过之后逐条检查每个 booking
|
|
176
|
+
// orderInfo 用于 keyword 搜索时的 JSON 序列化
|
|
177
|
+
// ─────────────────────────────────────────────────────────────────
|
|
178
|
+
|
|
190
179
|
function matchBooking(booking, orderInfo, ctx) {
|
|
191
180
|
if (ctx.enableChildBookingFilter && booking.booking_id) {
|
|
192
|
-
const parentId = Number(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
booking.item_type ?? ""
|
|
197
|
-
);
|
|
198
|
-
const isMatched = parentId !== 0 && itemType !== "recurring_booking" || parentId === 0 && itemType === "recurring_booking";
|
|
199
|
-
if (!isMatched)
|
|
200
|
-
return false;
|
|
181
|
+
const parentId = Number(booking.parent_id ?? 0);
|
|
182
|
+
const itemType = String(booking.item_type ?? '');
|
|
183
|
+
const isMatched = parentId !== 0 && itemType !== 'recurring_booking' || parentId === 0 && itemType === 'recurring_booking';
|
|
184
|
+
if (!isMatched) return false;
|
|
201
185
|
}
|
|
202
|
-
if (ctx.appointmentStatusSet && !ctx.appointmentStatusSet.has(getBookingAppointmentStatus(booking)))
|
|
203
|
-
return false;
|
|
186
|
+
if (ctx.appointmentStatusSet && !ctx.appointmentStatusSet.has(getBookingAppointmentStatus(booking))) return false;
|
|
204
187
|
if (ctx.bookingTimeRange) {
|
|
205
188
|
const bookingRange = resolveBookingTimeRange(booking);
|
|
206
|
-
if (!bookingRange || !isRangeOverlapping(bookingRange, ctx.bookingTimeRange))
|
|
207
|
-
return false;
|
|
189
|
+
if (!bookingRange || !isRangeOverlapping(bookingRange, ctx.bookingTimeRange)) return false;
|
|
208
190
|
}
|
|
209
191
|
if (ctx.afterExecutionTimeMs != null) {
|
|
210
192
|
const bookingStartMs = toTimestamp(bookingDateTimeString(booking.start_date, booking.start_time));
|
|
211
|
-
if (!Number.isFinite(bookingStartMs) || bookingStartMs < ctx.afterExecutionTimeMs)
|
|
212
|
-
return false;
|
|
193
|
+
if (!Number.isFinite(bookingStartMs) || bookingStartMs < ctx.afterExecutionTimeMs) return false;
|
|
213
194
|
}
|
|
214
195
|
if (ctx.numberRange) {
|
|
215
196
|
const num = Number(booking.number);
|
|
216
|
-
if (isNaN(num) || num < ctx.numberRange[0] || num > ctx.numberRange[1])
|
|
217
|
-
return false;
|
|
197
|
+
if (isNaN(num) || num < ctx.numberRange[0] || num > ctx.numberRange[1]) return false;
|
|
218
198
|
}
|
|
219
199
|
if (ctx.formRecordIdSet) {
|
|
220
200
|
let formMatched = false;
|
|
221
201
|
const resources = booking.resources;
|
|
222
202
|
if (Array.isArray(resources)) {
|
|
223
203
|
for (let r = 0; r < resources.length; r++) {
|
|
224
|
-
if (resources[r].relation_type ===
|
|
204
|
+
if (resources[r].relation_type === 'form' && ctx.formRecordIdSet.has(resources[r].relation_id)) {
|
|
225
205
|
formMatched = true;
|
|
226
206
|
break;
|
|
227
207
|
}
|
|
228
208
|
}
|
|
229
209
|
}
|
|
230
|
-
if (!formMatched && booking.relation_type ===
|
|
210
|
+
if (!formMatched && booking.relation_type === 'form' && booking.relation_id && booking.relation_id > 0) {
|
|
231
211
|
formMatched = ctx.formRecordIdSet.has(booking.relation_id);
|
|
232
212
|
}
|
|
233
|
-
if (!formMatched)
|
|
234
|
-
return false;
|
|
213
|
+
if (!formMatched) return false;
|
|
235
214
|
}
|
|
236
215
|
if (ctx.keywordLower) {
|
|
237
|
-
const target = orderInfo ? {
|
|
216
|
+
const target = orderInfo ? {
|
|
217
|
+
...booking,
|
|
218
|
+
order: orderInfo
|
|
219
|
+
} : booking;
|
|
238
220
|
const str = JSON.stringify(target).toLowerCase();
|
|
239
|
-
if (!str.includes(ctx.keywordLower))
|
|
240
|
-
return false;
|
|
221
|
+
if (!str.includes(ctx.keywordLower)) return false;
|
|
241
222
|
}
|
|
242
223
|
return true;
|
|
243
224
|
}
|
|
225
|
+
|
|
226
|
+
// ─────────────────────────────────────────────────────────────────
|
|
227
|
+
// 当前预约归属商品:先按 schedule_event_id 命中,再按 relation_items.resource_id 追加(去重保序)
|
|
228
|
+
// ─────────────────────────────────────────────────────────────────
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* 从整单 `order.products` 中归集属于指定 `booking` 的明细行。
|
|
232
|
+
* - 第一遍:`product.schedule_event_id === booking.schedule_event_id`(保持 products 原顺序)
|
|
233
|
+
* - 第二遍:按 `relation_items` 顺序追加 `resource_id` 与 `order_detail_id` 匹配且尚未收录的行
|
|
234
|
+
*/
|
|
244
235
|
function productsForBooking(order, booking) {
|
|
245
|
-
var _a;
|
|
246
236
|
const products = order.products;
|
|
247
|
-
if (!Array.isArray(products) || products.length === 0)
|
|
248
|
-
return [];
|
|
237
|
+
if (!Array.isArray(products) || products.length === 0) return [];
|
|
249
238
|
const bookingEventId = booking.schedule_event_id;
|
|
250
|
-
const byDetailId =
|
|
239
|
+
const byDetailId = new Map();
|
|
251
240
|
for (let i = 0, len = products.length; i < len; i++) {
|
|
252
241
|
const p = products[i];
|
|
253
242
|
const oid = p.order_detail_id;
|
|
254
|
-
if (oid ===
|
|
255
|
-
continue;
|
|
243
|
+
if (oid === undefined || oid === null) continue;
|
|
256
244
|
const detailId = Number(oid);
|
|
257
|
-
if (Number.isNaN(detailId))
|
|
258
|
-
continue;
|
|
245
|
+
if (Number.isNaN(detailId)) continue;
|
|
259
246
|
byDetailId.set(detailId, p);
|
|
260
247
|
}
|
|
261
|
-
const seen =
|
|
248
|
+
const seen = new Set();
|
|
262
249
|
const out = [];
|
|
263
250
|
for (let i = 0, len = products.length; i < len; i++) {
|
|
264
251
|
const p = products[i];
|
|
265
252
|
const oid = p.order_detail_id;
|
|
266
|
-
if (oid ===
|
|
267
|
-
continue;
|
|
253
|
+
if (oid === undefined || oid === null) continue;
|
|
268
254
|
const detailId = Number(oid);
|
|
269
|
-
if (Number.isNaN(detailId))
|
|
270
|
-
|
|
271
|
-
if (bookingEventId !== void 0 && bookingEventId !== null && p.schedule_event_id !== void 0 && p.schedule_event_id !== null && Number(p.schedule_event_id) === Number(bookingEventId)) {
|
|
255
|
+
if (Number.isNaN(detailId)) continue;
|
|
256
|
+
if (bookingEventId !== undefined && bookingEventId !== null && p.schedule_event_id !== undefined && p.schedule_event_id !== null && Number(p.schedule_event_id) === Number(bookingEventId)) {
|
|
272
257
|
if (!seen.has(detailId)) {
|
|
273
258
|
seen.add(detailId);
|
|
274
259
|
out.push(p);
|
|
@@ -278,12 +263,10 @@ function productsForBooking(order, booking) {
|
|
|
278
263
|
const relationItems = booking.relation_items;
|
|
279
264
|
if (Array.isArray(relationItems) && relationItems.length > 0) {
|
|
280
265
|
for (let r = 0, rLen = relationItems.length; r < rLen; r++) {
|
|
281
|
-
const rid =
|
|
282
|
-
if (rid ===
|
|
283
|
-
continue;
|
|
266
|
+
const rid = relationItems[r]?.resource_id;
|
|
267
|
+
if (rid === undefined || rid === null) continue;
|
|
284
268
|
const detailId = Number(rid);
|
|
285
|
-
if (Number.isNaN(detailId) || seen.has(detailId))
|
|
286
|
-
continue;
|
|
269
|
+
if (Number.isNaN(detailId) || seen.has(detailId)) continue;
|
|
287
270
|
const line = byDetailId.get(detailId);
|
|
288
271
|
if (line) {
|
|
289
272
|
seen.add(detailId);
|
|
@@ -293,16 +276,22 @@ function productsForBooking(order, booking) {
|
|
|
293
276
|
}
|
|
294
277
|
return out;
|
|
295
278
|
}
|
|
279
|
+
|
|
280
|
+
// ─────────────────────────────────────────────────────────────────
|
|
281
|
+
// 转换:OrderData[] → BookingData[](独立导出,供其他场景使用)
|
|
282
|
+
// ─────────────────────────────────────────────────────────────────
|
|
283
|
+
|
|
296
284
|
function flattenOrdersToBookings(orders) {
|
|
297
|
-
if (!orders || !Array.isArray(orders))
|
|
298
|
-
return [];
|
|
285
|
+
if (!orders || !Array.isArray(orders)) return [];
|
|
299
286
|
const result = [];
|
|
300
287
|
for (let i = 0, len = orders.length; i < len; i++) {
|
|
301
288
|
const order = orders[i];
|
|
302
289
|
const bookings = order.bookings;
|
|
303
|
-
if (!Array.isArray(bookings) || bookings.length === 0)
|
|
304
|
-
|
|
305
|
-
|
|
290
|
+
if (!Array.isArray(bookings) || bookings.length === 0) continue;
|
|
291
|
+
const {
|
|
292
|
+
bookings: _omit,
|
|
293
|
+
...orderInfo
|
|
294
|
+
} = order;
|
|
306
295
|
for (let j = 0, bLen = bookings.length; j < bLen; j++) {
|
|
307
296
|
const booking = bookings[j];
|
|
308
297
|
result.push({
|
|
@@ -314,10 +303,25 @@ function flattenOrdersToBookings(orders) {
|
|
|
314
303
|
}
|
|
315
304
|
return result;
|
|
316
305
|
}
|
|
306
|
+
|
|
307
|
+
// ─────────────────────────────────────────────────────────────────
|
|
308
|
+
// 核心:单遍扫描 — 展开 + 过滤 + 分页
|
|
309
|
+
//
|
|
310
|
+
// 性能策略:
|
|
311
|
+
// 1. 订单级条件在外层循环 matchOrder 预判,不匹配则整组 bookings 跳过
|
|
312
|
+
// 2. orderInfo 延迟到有命中 booking 时才创建,同一 order 只创建一次
|
|
313
|
+
// 3. 只对最终命中的 booking 做 object spread
|
|
314
|
+
// ─────────────────────────────────────────────────────────────────
|
|
315
|
+
|
|
317
316
|
function filterBookingsFromOrders(orders, filters) {
|
|
318
317
|
const f = filters || {};
|
|
319
318
|
if (!orders || !Array.isArray(orders)) {
|
|
320
|
-
return {
|
|
319
|
+
return {
|
|
320
|
+
list: [],
|
|
321
|
+
count: 0,
|
|
322
|
+
size: 0,
|
|
323
|
+
skip: 0
|
|
324
|
+
};
|
|
321
325
|
}
|
|
322
326
|
const size = f.num || 20;
|
|
323
327
|
const page = f.skip || 1;
|
|
@@ -328,22 +332,33 @@ function filterBookingsFromOrders(orders, filters) {
|
|
|
328
332
|
for (let i = 0, oLen = orders.length; i < oLen; i++) {
|
|
329
333
|
const order = orders[i];
|
|
330
334
|
const bookings = order.bookings;
|
|
331
|
-
if (!Array.isArray(bookings) || bookings.length === 0)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
+
if (!Array.isArray(bookings) || bookings.length === 0) continue;
|
|
336
|
+
|
|
337
|
+
// 订单级预过滤
|
|
338
|
+
if (!matchOrder(order, ctx)) continue;
|
|
339
|
+
|
|
340
|
+
// 订单通过,遍历其 bookings;orderInfo 延迟创建
|
|
335
341
|
let orderInfo = null;
|
|
336
342
|
for (let j = 0, bLen = bookings.length; j < bLen; j++) {
|
|
337
343
|
const booking = bookings[j];
|
|
344
|
+
|
|
345
|
+
// keyword 匹配需要 orderInfo,提前创建
|
|
338
346
|
if (ctx.keywordLower && !orderInfo) {
|
|
339
|
-
const {
|
|
347
|
+
const {
|
|
348
|
+
bookings: _omit,
|
|
349
|
+
...rest
|
|
350
|
+
} = order;
|
|
340
351
|
orderInfo = rest;
|
|
341
352
|
}
|
|
342
|
-
if (!matchBooking(booking, orderInfo, ctx))
|
|
343
|
-
|
|
353
|
+
if (!matchBooking(booking, orderInfo, ctx)) continue;
|
|
354
|
+
|
|
355
|
+
// 命中:收集到分页窗口内
|
|
344
356
|
if (totalCount >= startIndex && paginatedList.length < size) {
|
|
345
357
|
if (!orderInfo) {
|
|
346
|
-
const {
|
|
358
|
+
const {
|
|
359
|
+
bookings: _omit,
|
|
360
|
+
...rest
|
|
361
|
+
} = order;
|
|
347
362
|
orderInfo = rest;
|
|
348
363
|
}
|
|
349
364
|
paginatedList.push({
|
|
@@ -362,28 +377,32 @@ function filterBookingsFromOrders(orders, filters) {
|
|
|
362
377
|
skip: page
|
|
363
378
|
};
|
|
364
379
|
}
|
|
380
|
+
|
|
381
|
+
// ─────────────────────────────────────────────────────────────────
|
|
382
|
+
// 排序预约列表
|
|
383
|
+
// order_by 格式:"field:direction",如 "start_at:desc"
|
|
384
|
+
// 不带方向后缀则不排序
|
|
385
|
+
// ─────────────────────────────────────────────────────────────────
|
|
386
|
+
|
|
365
387
|
function sortBookings(result, filters) {
|
|
366
388
|
const f = filters || {};
|
|
367
389
|
const orderBy = f.order_by;
|
|
368
|
-
if (!orderBy)
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
if (separatorIdx === -1)
|
|
372
|
-
return result;
|
|
390
|
+
if (!orderBy) return result;
|
|
391
|
+
const separatorIdx = orderBy.lastIndexOf(':');
|
|
392
|
+
if (separatorIdx === -1) return result;
|
|
373
393
|
const field = orderBy.slice(0, separatorIdx);
|
|
374
394
|
const direction = orderBy.slice(separatorIdx + 1);
|
|
375
|
-
if (direction !==
|
|
376
|
-
|
|
377
|
-
const
|
|
378
|
-
const getTimestamp = (booking) => {
|
|
395
|
+
if (direction !== 'asc' && direction !== 'desc') return result;
|
|
396
|
+
const multiplier = direction === 'asc' ? 1 : -1;
|
|
397
|
+
const getTimestamp = booking => {
|
|
379
398
|
switch (field) {
|
|
380
|
-
case
|
|
399
|
+
case 'start_at':
|
|
381
400
|
return toTimestamp(bookingDateTimeString(booking.start_date, booking.start_time));
|
|
382
|
-
case
|
|
401
|
+
case 'end_at':
|
|
383
402
|
return toTimestamp(bookingDateTimeString(booking.end_date, booking.end_time));
|
|
384
|
-
case
|
|
403
|
+
case 'created_at':
|
|
385
404
|
return toTimestamp(booking.order.created_at);
|
|
386
|
-
case
|
|
405
|
+
case 'updated_at':
|
|
387
406
|
return toTimestamp(booking.order.updated_at);
|
|
388
407
|
default:
|
|
389
408
|
return 0;
|
|
@@ -392,12 +411,26 @@ function sortBookings(result, filters) {
|
|
|
392
411
|
const sorted = result.list.slice().sort((a, b) => {
|
|
393
412
|
return (getTimestamp(a) - getTimestamp(b)) * multiplier;
|
|
394
413
|
});
|
|
395
|
-
return {
|
|
414
|
+
return {
|
|
415
|
+
...result,
|
|
416
|
+
list: sorted
|
|
417
|
+
};
|
|
396
418
|
}
|
|
419
|
+
|
|
420
|
+
// ─────────────────────────────────────────────────────────────────
|
|
421
|
+
// 兼容独立调用:对已展开的 BookingData[] 做筛选
|
|
422
|
+
// 复用 matchOrder + matchBooking,仅负责迭代与分页
|
|
423
|
+
// ─────────────────────────────────────────────────────────────────
|
|
424
|
+
|
|
397
425
|
function filterBookings(bookings, filters) {
|
|
398
426
|
const f = filters || {};
|
|
399
427
|
if (!bookings || !Array.isArray(bookings)) {
|
|
400
|
-
return {
|
|
428
|
+
return {
|
|
429
|
+
list: [],
|
|
430
|
+
count: 0,
|
|
431
|
+
size: 0,
|
|
432
|
+
skip: 0
|
|
433
|
+
};
|
|
401
434
|
}
|
|
402
435
|
const size = f.num || 20;
|
|
403
436
|
const page = f.skip || 1;
|
|
@@ -408,10 +441,10 @@ function filterBookings(bookings, filters) {
|
|
|
408
441
|
for (let i = 0, len = bookings.length; i < len; i++) {
|
|
409
442
|
const booking = bookings[i];
|
|
410
443
|
const order = booking.order;
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
if (!
|
|
414
|
-
|
|
444
|
+
|
|
445
|
+
// 订单级 + booking 级统一匹配
|
|
446
|
+
if (!matchOrder(order, ctx)) continue;
|
|
447
|
+
if (!matchBooking(booking, order, ctx)) continue;
|
|
415
448
|
if (totalCount >= startIndex && paginatedList.length < size) {
|
|
416
449
|
paginatedList.push({
|
|
417
450
|
...booking,
|
|
@@ -426,12 +459,4 @@ function filterBookings(bookings, filters) {
|
|
|
426
459
|
size,
|
|
427
460
|
skip: page
|
|
428
461
|
};
|
|
429
|
-
}
|
|
430
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
431
|
-
0 && (module.exports = {
|
|
432
|
-
filterBookings,
|
|
433
|
-
filterBookingsFromOrders,
|
|
434
|
-
flattenOrdersToBookings,
|
|
435
|
-
productsForBooking,
|
|
436
|
-
sortBookings
|
|
437
|
-
});
|
|
462
|
+
}
|