@pisell/pisellos 0.0.567 → 0.0.568
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.js +6 -9
- package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -2
- package/dist/model/strategy/adapter/walletPass/example.js +3 -26
- package/dist/model/strategy/adapter/walletPass/utils.js +0 -3
- 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 +1 -4
- package/dist/modules/OpenData/index.js +0 -2
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +14 -41
- package/dist/modules/Payment/index.js +142 -270
- package/dist/modules/Payment/walletpass.js +4 -5
- package/dist/modules/Rules/index.js +0 -7
- package/dist/modules/Schedule/utils.js +0 -1
- package/dist/modules/Step/index.js +0 -1
- package/dist/plugins/request.js +1 -4
- package/dist/plugins/window.js +2 -6
- package/dist/server/index.js +88 -121
- package/dist/server/modules/menu/index.js +32 -41
- package/dist/server/modules/products/index.js +29 -49
- package/dist/server/modules/quotation/index.js +29 -38
- package/dist/server/modules/resource/index.js +3 -4
- package/dist/server/modules/schedule/index.js +32 -40
- package/dist/server/utils/product.js +0 -1
- 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.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +5 -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 -246
- 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.d.ts +5 -0
- package/dist/solution/VenueBooking/index.js +364 -327
- 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.js +130 -131
- package/lib/effects/index.js +46 -57
- package/lib/index.js +92 -53
- 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 +84 -63
- package/lib/model/strategy/adapter/promotion/evaluator.js +381 -231
- package/lib/model/strategy/adapter/promotion/examples.js +139 -159
- package/lib/model/strategy/adapter/promotion/index.js +1 -49
- package/lib/model/strategy/adapter/promotion/type.js +199 -35
- package/lib/model/strategy/adapter/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -152
- 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 +652 -402
- 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 +22 -45
- 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 +306 -241
- package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
- package/lib/modules/Cart/utils/cartResource.js +72 -78
- package/lib/modules/Cart/utils/changePrice.js +26 -62
- package/lib/modules/Cart/utils/index.js +106 -48
- package/lib/modules/Customer/constants.js +13 -34
- package/lib/modules/Customer/index.js +216 -153
- 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 +117 -113
- 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 +63 -74
- 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 +332 -320
- package/lib/modules/Order/types.js +24 -33
- package/lib/modules/Order/utils.js +350 -284
- 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 +566 -432
- package/lib/modules/Payment/mx51.js +1 -0
- package/lib/modules/Payment/types.js +216 -107
- package/lib/modules/Payment/utils.js +50 -47
- package/lib/modules/Payment/walletpass.js +221 -203
- 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 +111 -110
- package/lib/modules/ProductList/types.js +9 -31
- package/lib/modules/Quotation/index.js +60 -82
- 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/Rules/index.js +1172 -872
- package/lib/modules/Rules/types.js +17 -40
- package/lib/modules/SalesSummary/index.js +59 -68
- package/lib/modules/SalesSummary/types.js +4 -16
- package/lib/modules/SalesSummary/utils.js +176 -193
- 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 -167
- package/lib/modules/Schedule/index.js +97 -107
- 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 -70
- package/lib/modules/Summary/types.js +4 -16
- package/lib/modules/Summary/utils.js +782 -429
- package/lib/modules/index.js +212 -57
- package/lib/plugins/app.js +4 -16
- package/lib/plugins/index.js +36 -25
- 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.js +882 -623
- package/lib/server/modules/index.js +85 -59
- package/lib/server/modules/menu/index.js +146 -122
- package/lib/server/modules/menu/types.js +18 -31
- package/lib/server/modules/order/index.js +195 -231
- package/lib/server/modules/order/types.js +107 -32
- package/lib/server/modules/order/utils/filterBookings.js +174 -140
- package/lib/server/modules/order/utils/filterOrders.js +89 -60
- package/lib/server/modules/products/index.js +430 -335
- package/lib/server/modules/products/types.js +41 -34
- package/lib/server/modules/quotation/index.js +76 -77
- package/lib/server/modules/quotation/types.js +21 -31
- package/lib/server/modules/resource/index.js +216 -187
- package/lib/server/modules/resource/types.js +42 -33
- package/lib/server/modules/schedule/index.js +134 -119
- 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/time.js +40 -49
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1530 -1343
- 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.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +147 -122
- package/lib/solution/BookingTicket/types.js +38 -64
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +64 -80
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +82 -80
- package/lib/solution/BookingTicket/utils/scan/index.js +90 -94
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
- 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 +227 -158
- 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 +218 -200
- package/lib/solution/Sales/types.js +27 -33
- package/lib/solution/ScanOrder/index.js +803 -840
- package/lib/solution/ScanOrder/types.js +34 -34
- package/lib/solution/ScanOrder/utils.js +372 -331
- package/lib/solution/ShopDiscount/index.js +230 -236
- package/lib/solution/ShopDiscount/types.js +15 -37
- package/lib/solution/ShopDiscount/utils.js +309 -172
- package/lib/solution/VenueBooking/index.d.ts +5 -0
- package/lib/solution/VenueBooking/index.js +886 -929
- package/lib/solution/VenueBooking/types.js +20 -40
- package/lib/solution/VenueBooking/utils/dateSummary.js +22 -54
- package/lib/solution/VenueBooking/utils/resource.js +31 -54
- package/lib/solution/VenueBooking/utils/slotMerge.js +88 -106
- package/lib/solution/VenueBooking/utils/smartPricing.js +112 -100
- package/lib/solution/VenueBooking/utils/timeSlot.js +133 -132
- package/lib/solution/VenueBooking/utils.js +130 -67
- package/lib/solution/index.js +102 -37
- package/lib/store/createStore.js +32 -29
- package/lib/types/index.js +4 -16
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +81 -47
- package/package.json +2 -1
package/lib/server/index.js
CHANGED
|
@@ -1,462 +1,283 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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 __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
|
|
30
|
-
// src/server/index.ts
|
|
31
|
-
var server_exports = {};
|
|
32
|
-
__export(server_exports, {
|
|
33
|
-
default: () => server_default
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
34
5
|
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
var
|
|
40
|
-
var
|
|
41
|
-
var
|
|
42
|
-
var
|
|
43
|
-
var
|
|
44
|
-
var
|
|
45
|
-
var
|
|
46
|
-
var
|
|
47
|
-
var
|
|
48
|
-
var
|
|
49
|
-
|
|
50
|
-
var
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
},
|
|
114
|
-
resource: {
|
|
115
|
-
name: "resource",
|
|
116
|
-
moduleClass: import_resource.ResourceModule,
|
|
117
|
-
moduleName: "server_resource",
|
|
118
|
-
version: "1.0.0",
|
|
119
|
-
defaultStore: {
|
|
120
|
-
list: [],
|
|
121
|
-
map: /* @__PURE__ */ new Map(),
|
|
122
|
-
bookings: []
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
/**
|
|
127
|
-
* 处理商品查询请求
|
|
128
|
-
* 存储订阅者信息,便于数据变更时推送最新结果
|
|
129
|
-
*/
|
|
130
|
-
this.handleProductQuery = async ({ url, method, data, config }) => {
|
|
131
|
-
console.log("[Server] handleProductQuery:", url, method, data, config);
|
|
132
|
-
const { menu_list_ids, schedule_datetime, schedule_date } = data;
|
|
133
|
-
const { callback, subscriberId } = config || {};
|
|
134
|
-
this.logInfo("handleProductQuery: 开始处理商品查询请求", {
|
|
135
|
-
menu_list_ids,
|
|
136
|
-
schedule_datetime,
|
|
137
|
-
schedule_date
|
|
138
|
-
});
|
|
139
|
-
if (subscriberId && typeof callback === "function") {
|
|
140
|
-
this.productQuerySubscribers.set(subscriberId, {
|
|
141
|
-
callback,
|
|
142
|
-
context: { menu_list_ids, schedule_date, schedule_datetime }
|
|
143
|
-
});
|
|
144
|
-
this.logInfo("handleProductQuery: 已注册订阅者", {
|
|
145
|
-
subscriberId,
|
|
146
|
-
totalSubscribers: this.productQuerySubscribers.size
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
return this.computeProductQueryResult({ menu_list_ids, schedule_date, schedule_datetime });
|
|
150
|
-
};
|
|
151
|
-
/**
|
|
152
|
-
* 取消商品查询订阅(HTTP 路由入口)
|
|
153
|
-
*/
|
|
154
|
-
this.handleUnsubscribeProductQuery = async ({ data }) => {
|
|
155
|
-
const { subscriberId } = data || {};
|
|
156
|
-
this.removeProductQuerySubscriber(subscriberId);
|
|
157
|
-
return { code: 200, message: "ok", status: true };
|
|
158
|
-
};
|
|
159
|
-
/**
|
|
160
|
-
* 处理订单列表查询
|
|
161
|
-
* 存储订阅者信息,本地计算结果;数据变更时通过 callback 推送
|
|
162
|
-
*/
|
|
163
|
-
this.handleOrderList = async ({ url, method, data, config }) => {
|
|
164
|
-
console.log("[Server] handleOrderList:", url, method, data, config);
|
|
165
|
-
const queryPayload = data && typeof data === "object" ? { ...data } : {};
|
|
166
|
-
const { callback, subscriberId } = config || {};
|
|
167
|
-
this.logInfo("handleOrderList: 开始处理订单列表请求", { data: queryPayload });
|
|
168
|
-
if (subscriberId && typeof callback === "function") {
|
|
169
|
-
this.orderQuerySubscribers.set(subscriberId, {
|
|
170
|
-
callback,
|
|
171
|
-
context: queryPayload
|
|
172
|
-
});
|
|
173
|
-
this.logInfo("handleOrderList: 已注册订阅者", {
|
|
174
|
-
subscriberId,
|
|
175
|
-
totalSubscribers: this.orderQuerySubscribers.size
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
return this.computeOrderQueryResult(queryPayload);
|
|
179
|
-
};
|
|
180
|
-
/**
|
|
181
|
-
* 取消订单列表查询订阅(HTTP 路由入口)
|
|
182
|
-
*/
|
|
183
|
-
this.handleUnsubscribeOrderQuery = async ({ data }) => {
|
|
184
|
-
const { subscriberId } = data || {};
|
|
185
|
-
if (subscriberId) {
|
|
186
|
-
this.orderQuerySubscribers.delete(subscriberId);
|
|
187
|
-
this.logInfo("handleUnsubscribeOrderQuery: 已移除订阅者", {
|
|
188
|
-
subscriberId,
|
|
189
|
-
remaining: this.orderQuerySubscribers.size
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
return { code: 200, message: "ok", status: true };
|
|
193
|
-
};
|
|
194
|
-
/**
|
|
195
|
-
* 处理预约列表查询
|
|
196
|
-
* 今天:注册订阅者 + 本地数据筛选;非今天:清理订阅者 + 走真实 API
|
|
197
|
-
*/
|
|
198
|
-
this.handleBookingList = async ({ url, method, data, config }) => {
|
|
199
|
-
console.log("[Server] handleBookingList:", url, method, data, config);
|
|
200
|
-
const queryPayload = data && typeof data === "object" ? { ...data } : {};
|
|
201
|
-
const { callback, subscriberId } = config || {};
|
|
202
|
-
const isToday = this.isBookingQueryForToday(queryPayload);
|
|
203
|
-
this.logInfo("handleBookingList: 开始处理预约列表请求", {
|
|
204
|
-
data: queryPayload,
|
|
205
|
-
isToday
|
|
206
|
-
});
|
|
207
|
-
if (isToday) {
|
|
208
|
-
if (subscriberId && typeof callback === "function") {
|
|
209
|
-
this.bookingQuerySubscribers.set(subscriberId, {
|
|
210
|
-
callback,
|
|
211
|
-
context: queryPayload
|
|
212
|
-
});
|
|
213
|
-
this.logInfo("handleBookingList: 已注册订阅者(今天)", {
|
|
214
|
-
subscriberId,
|
|
215
|
-
totalSubscribers: this.bookingQuerySubscribers.size
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
return this.computeBookingQueryResult(queryPayload);
|
|
219
|
-
} else {
|
|
220
|
-
if (subscriberId) {
|
|
221
|
-
this.bookingQuerySubscribers.delete(subscriberId);
|
|
222
|
-
this.logInfo("handleBookingList: 已清理订阅者(非今天)", {
|
|
223
|
-
subscriberId,
|
|
224
|
-
remaining: this.bookingQuerySubscribers.size
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
return this.fetchBookingListFromAPI(queryPayload);
|
|
6
|
+
var _exportNames = {};
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
9
|
+
var _products = require("./modules/products");
|
|
10
|
+
var _menu = require("./modules/menu");
|
|
11
|
+
var _quotation = require("./modules/quotation");
|
|
12
|
+
var _schedule = require("./modules/schedule");
|
|
13
|
+
var _resource = require("./modules/resource");
|
|
14
|
+
var _schedule2 = require("./utils/schedule");
|
|
15
|
+
var _types = require("./modules/products/types");
|
|
16
|
+
var _product = require("./utils/product");
|
|
17
|
+
var _order = require("./modules/order");
|
|
18
|
+
var _types2 = require("./modules/order/types");
|
|
19
|
+
var _filterOrders = require("./modules/order/utils/filterOrders");
|
|
20
|
+
var _filterBookings = require("./modules/order/utils/filterBookings");
|
|
21
|
+
var _modules = require("./modules");
|
|
22
|
+
Object.keys(_modules).forEach(function (key) {
|
|
23
|
+
if (key === "default" || key === "__esModule") return;
|
|
24
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
25
|
+
if (key in exports && exports[key] === _modules[key]) return;
|
|
26
|
+
Object.defineProperty(exports, key, {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: function () {
|
|
29
|
+
return _modules[key];
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
34
|
+
// 重新导出类型供外部使用
|
|
35
|
+
|
|
36
|
+
/** 商品查询订阅者 */
|
|
37
|
+
|
|
38
|
+
/** 订单列表查询订阅者 */
|
|
39
|
+
|
|
40
|
+
/** 预约列表查询订阅者 */
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Server 类
|
|
44
|
+
* 用于注册和管理服务端模块
|
|
45
|
+
*/
|
|
46
|
+
class Server {
|
|
47
|
+
core;
|
|
48
|
+
app; // App instance
|
|
49
|
+
logger; // LoggerManager instance
|
|
50
|
+
|
|
51
|
+
// 模块实例
|
|
52
|
+
products;
|
|
53
|
+
menu;
|
|
54
|
+
quotation;
|
|
55
|
+
schedule;
|
|
56
|
+
resource;
|
|
57
|
+
order;
|
|
58
|
+
|
|
59
|
+
// 路由注册表
|
|
60
|
+
router = {
|
|
61
|
+
get: {},
|
|
62
|
+
post: {},
|
|
63
|
+
put: {},
|
|
64
|
+
remove: {}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// ---- 商品查询订阅者 ----
|
|
68
|
+
productQuerySubscribers = new Map();
|
|
69
|
+
|
|
70
|
+
// ---- 订单 / 预约列表查询订阅者 ----
|
|
71
|
+
orderQuerySubscribers = new Map();
|
|
72
|
+
bookingQuerySubscribers = new Map();
|
|
73
|
+
|
|
74
|
+
// 模块注册表 - 定义所有可用的模块配置
|
|
75
|
+
moduleRegistry = {
|
|
76
|
+
products: {
|
|
77
|
+
name: 'products',
|
|
78
|
+
moduleClass: _products.ProductsModule,
|
|
79
|
+
moduleName: 'server_products',
|
|
80
|
+
version: '1.0.0',
|
|
81
|
+
defaultStore: {
|
|
82
|
+
list: [],
|
|
83
|
+
selectProducts: []
|
|
228
84
|
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const list = (_a = this.resource) == null ? void 0 : _a.getResources({
|
|
238
|
-
skip: (data == null ? void 0 : data.skip) || 1,
|
|
239
|
-
num: (data == null ? void 0 : data.num) || 10
|
|
240
|
-
});
|
|
241
|
-
return {
|
|
242
|
-
code: 200,
|
|
243
|
-
data: { list, count: (list == null ? void 0 : list.length) || 0 },
|
|
244
|
-
message: "",
|
|
245
|
-
status: true
|
|
246
|
-
};
|
|
247
|
-
};
|
|
248
|
-
/**
|
|
249
|
-
* 取消预约列表查询订阅(HTTP 路由入口)
|
|
250
|
-
*/
|
|
251
|
-
this.handleUnsubscribeBookingQuery = async ({ data }) => {
|
|
252
|
-
const { subscriberId } = data || {};
|
|
253
|
-
if (subscriberId) {
|
|
254
|
-
this.bookingQuerySubscribers.delete(subscriberId);
|
|
255
|
-
this.logInfo("handleUnsubscribeBookingQuery: 已移除订阅者", {
|
|
256
|
-
subscriberId,
|
|
257
|
-
remaining: this.bookingQuerySubscribers.size
|
|
258
|
-
});
|
|
85
|
+
},
|
|
86
|
+
menu: {
|
|
87
|
+
name: 'menu',
|
|
88
|
+
moduleClass: _menu.MenuModule,
|
|
89
|
+
moduleName: 'server_menu',
|
|
90
|
+
version: '1.0.0',
|
|
91
|
+
defaultStore: {
|
|
92
|
+
menuList: []
|
|
259
93
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const { menu_list_ids } = data;
|
|
269
|
-
this.logInfo("handleGetScheduleTimePoints 开始处理", { menuListIdsCount: (menu_list_ids == null ? void 0 : menu_list_ids.length) ?? 0, menu_list_ids });
|
|
270
|
-
if (!this.menu) {
|
|
271
|
-
console.error("[Server] Menu 模块未注册");
|
|
272
|
-
this.logError("handleGetScheduleTimePoints: Menu 模块未注册");
|
|
273
|
-
return {
|
|
274
|
-
code: 500,
|
|
275
|
-
message: "Menu 模块未注册",
|
|
276
|
-
data: [],
|
|
277
|
-
status: false
|
|
278
|
-
};
|
|
94
|
+
},
|
|
95
|
+
quotation: {
|
|
96
|
+
name: 'quotation',
|
|
97
|
+
moduleClass: _quotation.QuotationModule,
|
|
98
|
+
moduleName: 'server_quotation',
|
|
99
|
+
version: '1.0.0',
|
|
100
|
+
defaultStore: {
|
|
101
|
+
quotationList: []
|
|
279
102
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
103
|
+
},
|
|
104
|
+
schedule: {
|
|
105
|
+
name: 'schedule',
|
|
106
|
+
moduleClass: _schedule.ScheduleModuleEx,
|
|
107
|
+
moduleName: 'server_schedule',
|
|
108
|
+
version: '1.1.0',
|
|
109
|
+
defaultStore: {
|
|
110
|
+
scheduleList: [],
|
|
111
|
+
availabilityDateList: [],
|
|
112
|
+
otherProductsIds: []
|
|
289
113
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
};
|
|
114
|
+
},
|
|
115
|
+
order: {
|
|
116
|
+
name: 'order',
|
|
117
|
+
moduleClass: _order.OrderModule,
|
|
118
|
+
moduleName: 'server_order',
|
|
119
|
+
version: '1.0.0',
|
|
120
|
+
defaultStore: {
|
|
121
|
+
list: []
|
|
299
122
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
console.log(`[Server] 提取到 ${scheduleIds.length} 个日程ID:`, scheduleIds);
|
|
311
|
-
this.logInfo("handleGetScheduleTimePoints: 提取到日程 IDs", {
|
|
312
|
-
scheduleCount: scheduleIds.length
|
|
313
|
-
});
|
|
314
|
-
if (scheduleIds.length === 0) {
|
|
315
|
-
this.logInfo("handleGetScheduleTimePoints: 没有找到相关日程", { menuListIdsCount: menu_list_ids.length });
|
|
316
|
-
return {
|
|
317
|
-
code: 200,
|
|
318
|
-
message: "没有找到相关日程",
|
|
319
|
-
data: [],
|
|
320
|
-
status: true
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
const scheduleList = this.schedule.getScheduleByIds(scheduleIds);
|
|
324
|
-
console.log(`[Server] 找到 ${scheduleList.length} 个日程`);
|
|
325
|
-
this.logInfo("handleGetScheduleTimePoints: 获取到日程详情", {
|
|
326
|
-
requestedCount: scheduleIds.length,
|
|
327
|
-
foundCount: scheduleList.length
|
|
328
|
-
});
|
|
329
|
-
const timePoints = (0, import_schedule2.extractTimePointsFromSchedules)(scheduleList);
|
|
330
|
-
console.log(`[Server] 提取到 ${timePoints.length} 个时间点:`, timePoints);
|
|
331
|
-
this.logInfo("handleGetScheduleTimePoints 处理完成", {
|
|
332
|
-
menuListIdsCount: menu_list_ids.length,
|
|
333
|
-
menuCount: menuList.length,
|
|
334
|
-
scheduleCount: scheduleList.length,
|
|
335
|
-
timePointCount: timePoints.length
|
|
336
|
-
});
|
|
337
|
-
return {
|
|
338
|
-
code: 200,
|
|
339
|
-
message: "获取成功",
|
|
340
|
-
data: timePoints,
|
|
341
|
-
status: true
|
|
342
|
-
};
|
|
343
|
-
} catch (error) {
|
|
344
|
-
const errorMessage = error instanceof Error ? error.message : "未知错误";
|
|
345
|
-
console.error("[Server] 获取日程时间点失败:", error);
|
|
346
|
-
this.logError("handleGetScheduleTimePoints: 获取日程时间点失败", {
|
|
347
|
-
menuListIdsCount: menu_list_ids.length,
|
|
348
|
-
error: errorMessage
|
|
349
|
-
});
|
|
350
|
-
return {
|
|
351
|
-
code: 500,
|
|
352
|
-
message: `获取失败: ${errorMessage}`,
|
|
353
|
-
data: [],
|
|
354
|
-
status: false
|
|
355
|
-
};
|
|
123
|
+
},
|
|
124
|
+
resource: {
|
|
125
|
+
name: 'resource',
|
|
126
|
+
moduleClass: _resource.ResourceModule,
|
|
127
|
+
moduleName: 'server_resource',
|
|
128
|
+
version: '1.0.0',
|
|
129
|
+
defaultStore: {
|
|
130
|
+
list: [],
|
|
131
|
+
map: new Map(),
|
|
132
|
+
bookings: []
|
|
356
133
|
}
|
|
357
|
-
}
|
|
358
|
-
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
constructor(core) {
|
|
359
137
|
this.core = core;
|
|
360
|
-
const appPlugin = core.getPlugin(
|
|
361
|
-
this.app =
|
|
362
|
-
this.logger =
|
|
363
|
-
|
|
364
|
-
this.logInfo("Server 初始化", {
|
|
138
|
+
const appPlugin = core.getPlugin('app');
|
|
139
|
+
this.app = appPlugin?.getApp() || null;
|
|
140
|
+
this.logger = this.app?.logger || null;
|
|
141
|
+
this.logInfo('Server 初始化', {
|
|
365
142
|
hasApp: !!this.app,
|
|
366
143
|
hasLogger: !!this.logger
|
|
367
144
|
});
|
|
368
145
|
}
|
|
146
|
+
|
|
369
147
|
/**
|
|
370
148
|
* 注册路由
|
|
371
149
|
* @param routes 路由定义数组
|
|
372
150
|
*/
|
|
373
151
|
registerRoutes(routes) {
|
|
374
|
-
routes.forEach(
|
|
375
|
-
const {
|
|
152
|
+
routes.forEach(route => {
|
|
153
|
+
const {
|
|
154
|
+
method,
|
|
155
|
+
path,
|
|
156
|
+
handler
|
|
157
|
+
} = route;
|
|
376
158
|
if (!this.router[method]) {
|
|
377
159
|
console.warn(`[Server] 不支持的 HTTP 方法: ${method}`);
|
|
378
|
-
this.logWarning(`不支持的 HTTP 方法`, {
|
|
160
|
+
this.logWarning(`不支持的 HTTP 方法`, {
|
|
161
|
+
method,
|
|
162
|
+
path
|
|
163
|
+
});
|
|
379
164
|
return;
|
|
380
165
|
}
|
|
166
|
+
|
|
167
|
+
// 检查路由是否已存在
|
|
381
168
|
if (this.router[method][path]) {
|
|
382
169
|
console.warn(`[Server] 路由已存在,将被覆盖: ${method.toUpperCase()} ${path}`);
|
|
383
|
-
this.logWarning(`路由已存在,将被覆盖`, {
|
|
170
|
+
this.logWarning(`路由已存在,将被覆盖`, {
|
|
171
|
+
method,
|
|
172
|
+
path
|
|
173
|
+
});
|
|
384
174
|
}
|
|
385
175
|
this.router[method][path] = handler;
|
|
386
|
-
|
|
387
|
-
|
|
176
|
+
this.logInfo(`注册路由`, {
|
|
177
|
+
method: method.toUpperCase(),
|
|
178
|
+
path
|
|
179
|
+
});
|
|
388
180
|
});
|
|
389
181
|
}
|
|
182
|
+
|
|
390
183
|
/**
|
|
391
184
|
* 注册单个模块并自动注册其路由
|
|
392
185
|
* @param module 模块实例
|
|
393
186
|
* @param options 模块配置
|
|
394
187
|
* @param moduleName 模块名称(用于日志)
|
|
395
188
|
*/
|
|
396
|
-
async registerModuleWithRoutes(
|
|
397
|
-
this.logInfo(`开始注册模块: ${moduleName}`, {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
189
|
+
async registerModuleWithRoutes(module, options, moduleName) {
|
|
190
|
+
this.logInfo(`开始注册模块: ${moduleName}`, {
|
|
191
|
+
moduleName,
|
|
192
|
+
options
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// 注册模块到 Core
|
|
196
|
+
await this.core.registerModule(module, options);
|
|
197
|
+
this.logInfo(`模块注册成功: ${moduleName}`, {
|
|
198
|
+
moduleName
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// 自动注册模块的路由
|
|
202
|
+
if (typeof module.getRoutes === 'function') {
|
|
203
|
+
const routes = module.getRoutes();
|
|
403
204
|
if (routes && routes.length > 0) {
|
|
404
205
|
this.registerRoutes(routes);
|
|
405
|
-
this.logInfo(`模块路由已注册: ${moduleName}`, {
|
|
206
|
+
this.logInfo(`模块路由已注册: ${moduleName}`, {
|
|
207
|
+
moduleName,
|
|
208
|
+
routesCount: routes.length
|
|
209
|
+
});
|
|
406
210
|
}
|
|
407
211
|
}
|
|
408
212
|
}
|
|
213
|
+
|
|
409
214
|
/**
|
|
410
215
|
* 根据模块名称注册单个模块
|
|
411
216
|
* @param moduleConfig 模块配置(可以是字符串或配置对象)
|
|
412
217
|
*/
|
|
413
218
|
async registerModuleByName(moduleConfig) {
|
|
414
|
-
|
|
415
|
-
const
|
|
416
|
-
const
|
|
219
|
+
// 解析配置
|
|
220
|
+
const moduleName = typeof moduleConfig === 'string' ? moduleConfig : moduleConfig.name;
|
|
221
|
+
const shouldPreload = typeof moduleConfig === 'object' ? moduleConfig.preload !== false : true;
|
|
222
|
+
const customConfig = typeof moduleConfig === 'object' ? moduleConfig.config : {};
|
|
417
223
|
this.logInfo(`解析模块配置: ${moduleName}`, {
|
|
418
224
|
moduleName,
|
|
419
225
|
shouldPreload,
|
|
420
226
|
customConfig
|
|
421
227
|
});
|
|
228
|
+
|
|
229
|
+
// 查找模块配置
|
|
422
230
|
const registryConfig = this.moduleRegistry[moduleName];
|
|
423
231
|
if (!registryConfig) {
|
|
424
|
-
this.logError(`未找到模块配置: ${moduleName}`, {
|
|
232
|
+
this.logError(`未找到模块配置: ${moduleName}`, {
|
|
233
|
+
moduleName
|
|
234
|
+
});
|
|
425
235
|
throw new Error(`[Server] 未找到模块配置: ${moduleName}`);
|
|
426
236
|
}
|
|
237
|
+
|
|
238
|
+
// 创建模块实例
|
|
427
239
|
const ModuleClass = registryConfig.moduleClass;
|
|
428
240
|
const moduleInstance = new ModuleClass(registryConfig.moduleName, registryConfig.version);
|
|
241
|
+
|
|
242
|
+
// 合并配置
|
|
429
243
|
const moduleOptions = {
|
|
430
|
-
store: {
|
|
244
|
+
store: {
|
|
245
|
+
...registryConfig.defaultStore
|
|
246
|
+
},
|
|
431
247
|
...customConfig
|
|
432
248
|
};
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
249
|
+
|
|
250
|
+
// 注册模块和路由
|
|
251
|
+
await this.registerModuleWithRoutes(moduleInstance, moduleOptions, moduleName.charAt(0).toUpperCase() + moduleName.slice(1));
|
|
252
|
+
|
|
253
|
+
// 保存模块实例
|
|
438
254
|
this[moduleName] = moduleInstance;
|
|
439
255
|
this.logInfo(`模块注册完成: ${moduleName}`, {
|
|
440
256
|
moduleName,
|
|
441
257
|
shouldPreload,
|
|
442
258
|
version: registryConfig.version
|
|
443
259
|
});
|
|
444
|
-
return {
|
|
260
|
+
return {
|
|
261
|
+
module: moduleInstance,
|
|
262
|
+
config: registryConfig,
|
|
263
|
+
shouldPreload
|
|
264
|
+
};
|
|
445
265
|
}
|
|
266
|
+
|
|
446
267
|
/**
|
|
447
268
|
* 注册指定的服务端模块
|
|
448
269
|
* @param moduleConfigs 要注册的模块配置数组(模块名称或配置对象)
|
|
449
270
|
*/
|
|
450
271
|
async registerModules(moduleConfigs) {
|
|
451
|
-
|
|
272
|
+
// 如果没有指定模块,则注册所有模块
|
|
452
273
|
const configs = moduleConfigs || Object.keys(this.moduleRegistry);
|
|
453
|
-
this.logInfo(
|
|
274
|
+
this.logInfo('开始批量注册模块', {
|
|
454
275
|
moduleConfigs: configs,
|
|
455
276
|
totalCount: configs.length
|
|
456
277
|
});
|
|
457
278
|
const registeredModules = [];
|
|
458
279
|
for (const config of configs) {
|
|
459
|
-
const configName = typeof config ===
|
|
280
|
+
const configName = typeof config === 'string' ? config : config.name;
|
|
460
281
|
try {
|
|
461
282
|
const result = await this.registerModuleByName(config);
|
|
462
283
|
registeredModules.push(result);
|
|
@@ -470,50 +291,57 @@ var Server = class {
|
|
|
470
291
|
throw error;
|
|
471
292
|
}
|
|
472
293
|
}
|
|
473
|
-
|
|
474
|
-
this.logInfo("所有模块注册完成", {
|
|
294
|
+
this.logInfo('所有模块注册完成', {
|
|
475
295
|
registeredCount: registeredModules.length,
|
|
476
|
-
moduleNames: registeredModules.map(
|
|
477
|
-
var _a;
|
|
478
|
-
return (_a = m == null ? void 0 : m.config) == null ? void 0 : _a.name;
|
|
479
|
-
})
|
|
296
|
+
moduleNames: registeredModules.map(m => m?.config?.name)
|
|
480
297
|
});
|
|
481
298
|
return registeredModules;
|
|
482
299
|
}
|
|
300
|
+
|
|
483
301
|
/**
|
|
484
302
|
* 预加载指定模块的数据
|
|
485
303
|
* @param registeredModules 已注册的模块信息
|
|
486
304
|
*/
|
|
487
305
|
async preloadModulesData(registeredModules, options) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const modulesToPreload = registeredModules.filter((m) => m.shouldPreload);
|
|
491
|
-
this.logInfo("开始预加载模块数据", {
|
|
306
|
+
const modulesToPreload = registeredModules.filter(m => m.shouldPreload);
|
|
307
|
+
this.logInfo('开始预加载模块数据', {
|
|
492
308
|
totalModules: registeredModules.length,
|
|
493
309
|
preloadCount: modulesToPreload.length,
|
|
494
310
|
modulesToPreload
|
|
495
311
|
});
|
|
496
312
|
const preloadResults = [];
|
|
497
|
-
for (const {
|
|
313
|
+
for (const {
|
|
314
|
+
module,
|
|
315
|
+
config,
|
|
316
|
+
shouldPreload
|
|
317
|
+
} of registeredModules) {
|
|
498
318
|
if (!shouldPreload) {
|
|
499
|
-
|
|
500
|
-
|
|
319
|
+
this.logInfo(`跳过模块预加载: ${config.name}`, {
|
|
320
|
+
moduleName: config.name,
|
|
321
|
+
reason: 'shouldPreload=false'
|
|
322
|
+
});
|
|
501
323
|
continue;
|
|
502
324
|
}
|
|
503
|
-
|
|
325
|
+
|
|
326
|
+
// 统一调用模块的 preload() 方法
|
|
327
|
+
if (typeof module.preload === 'function') {
|
|
504
328
|
const startTime = Date.now();
|
|
505
329
|
try {
|
|
506
|
-
this.logInfo(`开始预加载模块: ${config.name}`, {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
330
|
+
this.logInfo(`开始预加载模块: ${config.name}`, {
|
|
331
|
+
moduleName: config.name
|
|
332
|
+
});
|
|
333
|
+
options?.onModuleLoad?.(config.name);
|
|
334
|
+
await module.preload();
|
|
335
|
+
options?.onModuleLoadComplete?.(config.name);
|
|
510
336
|
const duration = Date.now() - startTime;
|
|
511
|
-
console.log(`[Server] ✅ ${config.name} 模块数据已预加载`);
|
|
512
337
|
this.logInfo(`模块预加载成功: ${config.name}`, {
|
|
513
338
|
moduleName: config.name,
|
|
514
339
|
duration: `${duration}ms`
|
|
515
340
|
});
|
|
516
|
-
preloadResults.push({
|
|
341
|
+
preloadResults.push({
|
|
342
|
+
name: config.name,
|
|
343
|
+
success: true
|
|
344
|
+
});
|
|
517
345
|
} catch (error) {
|
|
518
346
|
const duration = Date.now() - startTime;
|
|
519
347
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -523,21 +351,26 @@ var Server = class {
|
|
|
523
351
|
duration: `${duration}ms`,
|
|
524
352
|
error: errorMessage
|
|
525
353
|
});
|
|
526
|
-
preloadResults.push({
|
|
354
|
+
preloadResults.push({
|
|
355
|
+
name: config.name,
|
|
356
|
+
success: false,
|
|
357
|
+
error: errorMessage
|
|
358
|
+
});
|
|
527
359
|
}
|
|
528
360
|
} else {
|
|
529
|
-
|
|
530
|
-
|
|
361
|
+
this.logWarning(`模块未实现 preload 方法: ${config.name}`, {
|
|
362
|
+
moduleName: config.name
|
|
363
|
+
});
|
|
531
364
|
}
|
|
532
365
|
}
|
|
533
|
-
const successCount = preloadResults.filter(
|
|
534
|
-
const failCount = preloadResults.filter(
|
|
535
|
-
|
|
536
|
-
this.logInfo("所有模块预加载完成", {
|
|
366
|
+
const successCount = preloadResults.filter(r => r.success).length;
|
|
367
|
+
const failCount = preloadResults.filter(r => !r.success).length;
|
|
368
|
+
this.logInfo('所有模块预加载完成', {
|
|
537
369
|
successCount,
|
|
538
370
|
failCount
|
|
539
371
|
});
|
|
540
372
|
}
|
|
373
|
+
|
|
541
374
|
/**
|
|
542
375
|
* 初始化 Server(注册模块并预加载数据)
|
|
543
376
|
* @param moduleConfigs 要注册的模块配置
|
|
@@ -545,77 +378,89 @@ var Server = class {
|
|
|
545
378
|
*/
|
|
546
379
|
async initialize(moduleConfigs, autoPreload = true, options) {
|
|
547
380
|
const startTime = Date.now();
|
|
548
|
-
this.logInfo(
|
|
549
|
-
moduleConfigCount:
|
|
381
|
+
this.logInfo('Server 初始化开始', {
|
|
382
|
+
moduleConfigCount: moduleConfigs?.length ?? 'all',
|
|
550
383
|
autoPreload,
|
|
551
384
|
moduleConfigs
|
|
552
385
|
});
|
|
386
|
+
|
|
387
|
+
// 注册 Server 层的业务路由
|
|
553
388
|
this.registerServerRoutes();
|
|
389
|
+
|
|
390
|
+
// 注册模块
|
|
554
391
|
const registeredModules = await this.registerModules(moduleConfigs);
|
|
392
|
+
|
|
393
|
+
// 自动预加载数据
|
|
555
394
|
if (autoPreload) {
|
|
556
395
|
await this.preloadModulesData(registeredModules, options);
|
|
557
396
|
} else {
|
|
558
|
-
this.logInfo(
|
|
397
|
+
this.logInfo('跳过自动预加载', {
|
|
398
|
+
autoPreload
|
|
399
|
+
});
|
|
559
400
|
}
|
|
560
|
-
|
|
401
|
+
|
|
402
|
+
// 监听 ProductsModule 同步完成事件,重新计算并推送查询结果
|
|
403
|
+
this.core.effects.on(_types.ProductsHooks.onProductsSyncCompleted, payload => {
|
|
561
404
|
this.recomputeAndNotifyProductQuery({
|
|
562
|
-
changedIds: payload
|
|
405
|
+
changedIds: payload?.changedIds
|
|
563
406
|
});
|
|
564
407
|
});
|
|
565
|
-
|
|
408
|
+
|
|
409
|
+
// 订单 / 预约本地数据变更时,向订阅者推送最新列表
|
|
410
|
+
this.core.effects.on(_types2.OrderHooks.onOrdersChanged, () => {
|
|
566
411
|
this.recomputeAndNotifyOrderQuery();
|
|
567
412
|
this.recomputeAndNotifyBookingQuery();
|
|
568
413
|
});
|
|
569
414
|
const duration = Date.now() - startTime;
|
|
570
|
-
this.logInfo(
|
|
415
|
+
this.logInfo('Server 初始化完成', {
|
|
571
416
|
duration: `${duration}ms`,
|
|
572
417
|
registeredModuleCount: registeredModules.length
|
|
573
418
|
});
|
|
574
419
|
return registeredModules;
|
|
575
420
|
}
|
|
421
|
+
|
|
576
422
|
/**
|
|
577
423
|
* 获取 Products 模块实例
|
|
578
424
|
*/
|
|
579
425
|
getProducts() {
|
|
580
426
|
return this.products;
|
|
581
427
|
}
|
|
428
|
+
|
|
582
429
|
/**
|
|
583
430
|
* 获取 Menu 模块实例
|
|
584
431
|
*/
|
|
585
432
|
getMenu() {
|
|
586
433
|
return this.menu;
|
|
587
434
|
}
|
|
435
|
+
|
|
588
436
|
/**
|
|
589
437
|
* 获取 Quotation 模块实例
|
|
590
438
|
*/
|
|
591
439
|
getQuotation() {
|
|
592
440
|
return this.quotation;
|
|
593
441
|
}
|
|
442
|
+
|
|
594
443
|
/**
|
|
595
444
|
* 获取 Schedule 模块实例
|
|
596
445
|
*/
|
|
597
446
|
getSchedule() {
|
|
598
447
|
return this.schedule;
|
|
599
448
|
}
|
|
449
|
+
|
|
600
450
|
/**
|
|
601
451
|
* 获取所有已注册的模块列表
|
|
602
452
|
*/
|
|
603
453
|
getRegisteredModules() {
|
|
604
454
|
const modules = [];
|
|
605
|
-
if (this.products)
|
|
606
|
-
|
|
607
|
-
if (this.
|
|
608
|
-
|
|
609
|
-
if (this.
|
|
610
|
-
|
|
611
|
-
if (this.schedule)
|
|
612
|
-
modules.push("schedule");
|
|
613
|
-
if (this.resource)
|
|
614
|
-
modules.push("resource");
|
|
615
|
-
if (this.order)
|
|
616
|
-
modules.push("order");
|
|
455
|
+
if (this.products) modules.push('products');
|
|
456
|
+
if (this.menu) modules.push('menu');
|
|
457
|
+
if (this.quotation) modules.push('quotation');
|
|
458
|
+
if (this.schedule) modules.push('schedule');
|
|
459
|
+
if (this.resource) modules.push('resource');
|
|
460
|
+
if (this.order) modules.push('order');
|
|
617
461
|
return modules;
|
|
618
462
|
}
|
|
463
|
+
|
|
619
464
|
/**
|
|
620
465
|
* 后台静默刷新商品数据
|
|
621
466
|
* 重新拉取全量 SSE 接口,更新本地数据后触发 onProductsSyncCompleted
|
|
@@ -623,100 +468,112 @@ var Server = class {
|
|
|
623
468
|
*/
|
|
624
469
|
async refreshProductsInBackground() {
|
|
625
470
|
if (!this.products) {
|
|
626
|
-
this.logWarning(
|
|
471
|
+
this.logWarning('refreshProductsInBackground: Products 模块未注册');
|
|
627
472
|
return;
|
|
628
473
|
}
|
|
629
|
-
this.logInfo(
|
|
474
|
+
this.logInfo('refreshProductsInBackground 开始');
|
|
630
475
|
const startTime = Date.now();
|
|
631
476
|
try {
|
|
632
477
|
await this.products.silentRefresh();
|
|
633
478
|
const duration = Date.now() - startTime;
|
|
634
|
-
this.logInfo(
|
|
479
|
+
this.logInfo('refreshProductsInBackground 完成', {
|
|
480
|
+
duration: `${duration}ms`
|
|
481
|
+
});
|
|
635
482
|
} catch (error) {
|
|
636
483
|
const duration = Date.now() - startTime;
|
|
637
484
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
638
|
-
console.error(
|
|
639
|
-
this.logError(
|
|
485
|
+
console.error('[Server] refreshProductsInBackground 失败:', error);
|
|
486
|
+
this.logError('refreshProductsInBackground 失败', {
|
|
640
487
|
duration: `${duration}ms`,
|
|
641
488
|
error: errorMessage
|
|
642
489
|
});
|
|
643
490
|
}
|
|
644
491
|
}
|
|
492
|
+
|
|
645
493
|
/**
|
|
646
494
|
* 清空所有server模块的IndexedDB缓存
|
|
647
495
|
* @returns Promise<void>
|
|
648
496
|
*/
|
|
649
497
|
async clearAllIndexDB() {
|
|
650
|
-
|
|
651
|
-
this.logInfo("开始清空所有模块的 IndexedDB 缓存");
|
|
498
|
+
this.logInfo('开始清空所有模块的 IndexedDB 缓存');
|
|
652
499
|
const clearTasks = [];
|
|
653
500
|
const moduleNames = [];
|
|
501
|
+
|
|
502
|
+
// 收集所有模块的清空任务
|
|
654
503
|
if (this.products) {
|
|
655
504
|
clearTasks.push(this.products.clear());
|
|
656
|
-
moduleNames.push(
|
|
505
|
+
moduleNames.push('Products');
|
|
657
506
|
}
|
|
658
507
|
if (this.menu) {
|
|
659
508
|
clearTasks.push(this.menu.clear());
|
|
660
|
-
moduleNames.push(
|
|
509
|
+
moduleNames.push('Menu');
|
|
661
510
|
}
|
|
662
511
|
if (this.quotation) {
|
|
663
512
|
clearTasks.push(this.quotation.clear());
|
|
664
|
-
moduleNames.push(
|
|
513
|
+
moduleNames.push('Quotation');
|
|
665
514
|
}
|
|
666
515
|
if (this.schedule) {
|
|
667
516
|
clearTasks.push(this.schedule.clear());
|
|
668
|
-
moduleNames.push(
|
|
517
|
+
moduleNames.push('Schedule');
|
|
669
518
|
}
|
|
670
519
|
if (this.resource) {
|
|
671
520
|
clearTasks.push(this.resource.clear());
|
|
672
|
-
moduleNames.push(
|
|
521
|
+
moduleNames.push('Resource');
|
|
673
522
|
}
|
|
674
523
|
if (this.order) {
|
|
675
524
|
clearTasks.push(this.order.clear());
|
|
676
|
-
moduleNames.push(
|
|
525
|
+
moduleNames.push('Order');
|
|
677
526
|
}
|
|
678
527
|
if (clearTasks.length === 0) {
|
|
679
|
-
console.warn(
|
|
680
|
-
this.logWarning(
|
|
528
|
+
console.warn('[Server] 没有找到已注册的模块,无需清空');
|
|
529
|
+
this.logWarning('没有找到已注册的模块,无需清空 IndexedDB');
|
|
681
530
|
return;
|
|
682
531
|
}
|
|
683
|
-
this.logInfo(
|
|
532
|
+
this.logInfo('准备清空模块缓存', {
|
|
533
|
+
moduleNames
|
|
534
|
+
});
|
|
684
535
|
try {
|
|
536
|
+
// 并行执行所有清空操作
|
|
685
537
|
await Promise.all(clearTasks);
|
|
686
|
-
|
|
687
|
-
|
|
538
|
+
this.logInfo('成功清空所有模块的 IndexedDB 缓存', {
|
|
539
|
+
moduleNames
|
|
540
|
+
});
|
|
688
541
|
} catch (error) {
|
|
689
542
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
690
|
-
console.error(
|
|
691
|
-
this.logError(
|
|
543
|
+
console.error('[Server] ❌ 清空IndexedDB缓存时发生错误:', error);
|
|
544
|
+
this.logError('清空 IndexedDB 缓存时发生错误', {
|
|
545
|
+
moduleNames,
|
|
546
|
+
error: errorMessage
|
|
547
|
+
});
|
|
692
548
|
throw error;
|
|
693
549
|
}
|
|
694
550
|
}
|
|
551
|
+
|
|
695
552
|
/**
|
|
696
553
|
* 获取所有注册的路由
|
|
697
554
|
*/
|
|
698
555
|
getRoutes() {
|
|
699
556
|
return this.router;
|
|
700
557
|
}
|
|
558
|
+
|
|
701
559
|
/**
|
|
702
560
|
* 根据方法和路径获取路由处理函数
|
|
703
561
|
* @param method HTTP 方法
|
|
704
562
|
* @param path 路径
|
|
705
563
|
*/
|
|
706
564
|
getRouteHandler(method, path) {
|
|
707
|
-
|
|
708
|
-
return (_a = this.router[method]) == null ? void 0 : _a[path];
|
|
565
|
+
return this.router[method]?.[path];
|
|
709
566
|
}
|
|
567
|
+
|
|
710
568
|
/**
|
|
711
569
|
* 检查路由是否存在
|
|
712
570
|
* @param method HTTP 方法
|
|
713
571
|
* @param path 路径
|
|
714
572
|
*/
|
|
715
573
|
hasRoute(method, path) {
|
|
716
|
-
|
|
717
|
-
console.log(method, path, "method, path");
|
|
718
|
-
return !!((_a = this.router[method]) == null ? void 0 : _a[path]);
|
|
574
|
+
return !!this.router[method]?.[path];
|
|
719
575
|
}
|
|
576
|
+
|
|
720
577
|
/**
|
|
721
578
|
* 执行路由处理函数
|
|
722
579
|
* @param method HTTP 方法
|
|
@@ -733,7 +590,10 @@ var Server = class {
|
|
|
733
590
|
});
|
|
734
591
|
const handler = this.getRouteHandler(method, path);
|
|
735
592
|
if (!handler) {
|
|
736
|
-
this.logError(`路由未找到: ${method.toUpperCase()} ${path}`, {
|
|
593
|
+
this.logError(`路由未找到: ${method.toUpperCase()} ${path}`, {
|
|
594
|
+
method,
|
|
595
|
+
path
|
|
596
|
+
});
|
|
737
597
|
throw new Error(`Route not found: ${method.toUpperCase()} ${path}`);
|
|
738
598
|
}
|
|
739
599
|
try {
|
|
@@ -743,8 +603,8 @@ var Server = class {
|
|
|
743
603
|
method: method.toUpperCase(),
|
|
744
604
|
path,
|
|
745
605
|
duration: `${duration}ms`,
|
|
746
|
-
resultCode: result
|
|
747
|
-
resultStatus: result
|
|
606
|
+
resultCode: result?.code,
|
|
607
|
+
resultStatus: result?.status
|
|
748
608
|
});
|
|
749
609
|
return result;
|
|
750
610
|
} catch (error) {
|
|
@@ -761,152 +621,386 @@ var Server = class {
|
|
|
761
621
|
throw error;
|
|
762
622
|
}
|
|
763
623
|
}
|
|
624
|
+
|
|
764
625
|
/**
|
|
765
626
|
* 获取所有路由列表(用于调试和文档)
|
|
766
627
|
*/
|
|
767
628
|
getAllRoutes() {
|
|
768
629
|
const routes = [];
|
|
769
|
-
[
|
|
770
|
-
Object.keys(this.router[method]).forEach(
|
|
771
|
-
routes.push({
|
|
630
|
+
['get', 'post', 'put', 'remove'].forEach(method => {
|
|
631
|
+
Object.keys(this.router[method]).forEach(path => {
|
|
632
|
+
routes.push({
|
|
633
|
+
method,
|
|
634
|
+
path
|
|
635
|
+
});
|
|
772
636
|
});
|
|
773
637
|
});
|
|
774
638
|
return routes;
|
|
775
639
|
}
|
|
640
|
+
|
|
776
641
|
/**
|
|
777
642
|
* 注册 Server 层的业务路由
|
|
778
643
|
* 这些路由需要编排多个模块的数据
|
|
779
644
|
* @private
|
|
780
645
|
*/
|
|
781
646
|
registerServerRoutes() {
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
method: "get",
|
|
816
|
-
path: "/shop/schedule/booking/unsubscribe",
|
|
817
|
-
handler: this.handleUnsubscribeBookingQuery.bind(this)
|
|
818
|
-
},
|
|
819
|
-
{
|
|
820
|
-
method: "get",
|
|
821
|
-
path: "/shop/form/resource/page",
|
|
822
|
-
handler: this.handleResourceList.bind(this)
|
|
823
|
-
}
|
|
824
|
-
]);
|
|
647
|
+
this.registerRoutes([{
|
|
648
|
+
method: 'post',
|
|
649
|
+
path: '/shop/product/query',
|
|
650
|
+
handler: this.handleProductQuery.bind(this)
|
|
651
|
+
}, {
|
|
652
|
+
method: 'post',
|
|
653
|
+
path: '/shop/product/query/unsubscribe',
|
|
654
|
+
handler: this.handleUnsubscribeProductQuery.bind(this)
|
|
655
|
+
}, {
|
|
656
|
+
method: 'post',
|
|
657
|
+
path: '/shop/menu/schedule-time-points',
|
|
658
|
+
handler: this.handleGetScheduleTimePoints.bind(this)
|
|
659
|
+
}, {
|
|
660
|
+
method: 'post',
|
|
661
|
+
path: '/shop/order/v2/list',
|
|
662
|
+
handler: this.handleOrderList.bind(this)
|
|
663
|
+
}, {
|
|
664
|
+
method: 'post',
|
|
665
|
+
path: '/shop/order/v2/list/unsubscribe',
|
|
666
|
+
handler: this.handleUnsubscribeOrderQuery.bind(this)
|
|
667
|
+
}, {
|
|
668
|
+
method: 'get',
|
|
669
|
+
path: '/shop/schedule/booking',
|
|
670
|
+
handler: this.handleBookingList.bind(this)
|
|
671
|
+
}, {
|
|
672
|
+
method: 'get',
|
|
673
|
+
path: '/shop/schedule/booking/unsubscribe',
|
|
674
|
+
handler: this.handleUnsubscribeBookingQuery.bind(this)
|
|
675
|
+
}, {
|
|
676
|
+
method: 'get',
|
|
677
|
+
path: '/shop/form/resource/page',
|
|
678
|
+
handler: this.handleResourceList.bind(this)
|
|
679
|
+
}]);
|
|
825
680
|
}
|
|
681
|
+
|
|
826
682
|
/**
|
|
827
683
|
* 根据 subscriberId 移除商品查询订阅者
|
|
828
684
|
*/
|
|
829
685
|
removeProductQuerySubscriber(subscriberId) {
|
|
830
686
|
if (subscriberId) {
|
|
831
687
|
this.productQuerySubscribers.delete(subscriberId);
|
|
832
|
-
this.logInfo(
|
|
688
|
+
this.logInfo('removeProductQuerySubscriber: 已移除订阅者', {
|
|
833
689
|
subscriberId,
|
|
834
690
|
remaining: this.productQuerySubscribers.size
|
|
835
691
|
});
|
|
836
692
|
}
|
|
837
693
|
}
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* 处理商品查询请求
|
|
697
|
+
* 存储订阅者信息,便于数据变更时推送最新结果
|
|
698
|
+
*/
|
|
699
|
+
handleProductQuery = async ({
|
|
700
|
+
url,
|
|
701
|
+
method,
|
|
702
|
+
data,
|
|
703
|
+
config
|
|
704
|
+
}) => {
|
|
705
|
+
const {
|
|
706
|
+
menu_list_ids,
|
|
707
|
+
schedule_datetime,
|
|
708
|
+
schedule_date
|
|
709
|
+
} = data;
|
|
710
|
+
const {
|
|
711
|
+
callback,
|
|
712
|
+
subscriberId
|
|
713
|
+
} = config || {};
|
|
714
|
+
this.logInfo('handleProductQuery: 开始处理商品查询请求', {
|
|
715
|
+
menu_list_ids,
|
|
716
|
+
schedule_datetime,
|
|
717
|
+
schedule_date
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
// 存储订阅者:后续 pubsub 数据变更时可通过 callback 推送最新结果
|
|
721
|
+
if (subscriberId && typeof callback === 'function') {
|
|
722
|
+
this.productQuerySubscribers.set(subscriberId, {
|
|
723
|
+
callback,
|
|
724
|
+
context: {
|
|
725
|
+
menu_list_ids,
|
|
726
|
+
schedule_date,
|
|
727
|
+
schedule_datetime
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
this.logInfo('handleProductQuery: 已注册订阅者', {
|
|
731
|
+
subscriberId,
|
|
732
|
+
totalSubscribers: this.productQuerySubscribers.size
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
return this.computeProductQueryResult({
|
|
736
|
+
menu_list_ids,
|
|
737
|
+
schedule_date,
|
|
738
|
+
schedule_datetime
|
|
739
|
+
});
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* 取消商品查询订阅(HTTP 路由入口)
|
|
744
|
+
*/
|
|
745
|
+
handleUnsubscribeProductQuery = async ({
|
|
746
|
+
data
|
|
747
|
+
}) => {
|
|
748
|
+
const {
|
|
749
|
+
subscriberId
|
|
750
|
+
} = data || {};
|
|
751
|
+
this.removeProductQuerySubscriber(subscriberId);
|
|
752
|
+
return {
|
|
753
|
+
code: 200,
|
|
754
|
+
message: 'ok',
|
|
755
|
+
status: true
|
|
756
|
+
};
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* 处理订单列表查询
|
|
761
|
+
* 存储订阅者信息,本地计算结果;数据变更时通过 callback 推送
|
|
762
|
+
*/
|
|
763
|
+
handleOrderList = async ({
|
|
764
|
+
url,
|
|
765
|
+
method,
|
|
766
|
+
data,
|
|
767
|
+
config
|
|
768
|
+
}) => {
|
|
769
|
+
const queryPayload = data && typeof data === 'object' ? {
|
|
770
|
+
...data
|
|
771
|
+
} : {};
|
|
772
|
+
const {
|
|
773
|
+
callback,
|
|
774
|
+
subscriberId
|
|
775
|
+
} = config || {};
|
|
776
|
+
this.logInfo('handleOrderList: 开始处理订单列表请求', {
|
|
777
|
+
data: queryPayload
|
|
778
|
+
});
|
|
779
|
+
if (subscriberId && typeof callback === 'function') {
|
|
780
|
+
this.orderQuerySubscribers.set(subscriberId, {
|
|
781
|
+
callback,
|
|
782
|
+
context: queryPayload
|
|
783
|
+
});
|
|
784
|
+
this.logInfo('handleOrderList: 已注册订阅者', {
|
|
785
|
+
subscriberId,
|
|
786
|
+
totalSubscribers: this.orderQuerySubscribers.size
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
return this.computeOrderQueryResult(queryPayload);
|
|
790
|
+
};
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* 取消订单列表查询订阅(HTTP 路由入口)
|
|
794
|
+
*/
|
|
795
|
+
handleUnsubscribeOrderQuery = async ({
|
|
796
|
+
data
|
|
797
|
+
}) => {
|
|
798
|
+
const {
|
|
799
|
+
subscriberId
|
|
800
|
+
} = data || {};
|
|
801
|
+
if (subscriberId) {
|
|
802
|
+
this.orderQuerySubscribers.delete(subscriberId);
|
|
803
|
+
this.logInfo('handleUnsubscribeOrderQuery: 已移除订阅者', {
|
|
804
|
+
subscriberId,
|
|
805
|
+
remaining: this.orderQuerySubscribers.size
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
return {
|
|
809
|
+
code: 200,
|
|
810
|
+
message: 'ok',
|
|
811
|
+
status: true
|
|
812
|
+
};
|
|
813
|
+
};
|
|
814
|
+
|
|
838
815
|
/**
|
|
839
816
|
* 判断预约查询的 sales_time_between 起始日期是否为今天
|
|
840
817
|
*/
|
|
841
818
|
isBookingQueryForToday(data) {
|
|
842
|
-
const range = data
|
|
843
|
-
if (!Array.isArray(range) || range.length < 1)
|
|
844
|
-
|
|
845
|
-
const
|
|
846
|
-
const todayStr = (0, import_dayjs.default)().format("YYYY-MM-DD");
|
|
819
|
+
const range = data?.sales_time_between;
|
|
820
|
+
if (!Array.isArray(range) || range.length < 1) return true;
|
|
821
|
+
const startDateStr = String(range[0]).split('T')[0].split(' ')[0];
|
|
822
|
+
const todayStr = (0, _dayjs.default)().format('YYYY-MM-DD');
|
|
847
823
|
return startDateStr === todayStr;
|
|
848
824
|
}
|
|
825
|
+
|
|
849
826
|
/**
|
|
850
827
|
* 非今天的预约查询:通过真实 API 获取数据,再做 flattenOrdersToBookings 拆分
|
|
851
828
|
*/
|
|
852
829
|
async fetchBookingListFromAPI(data) {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
this.logError("fetchBookingListFromAPI: app.request 不可用");
|
|
830
|
+
if (!this.app?.request) {
|
|
831
|
+
this.logError('fetchBookingListFromAPI: app.request 不可用');
|
|
856
832
|
return {
|
|
857
833
|
code: 500,
|
|
858
|
-
message:
|
|
859
|
-
data: {
|
|
834
|
+
message: 'app.request 不可用',
|
|
835
|
+
data: {
|
|
836
|
+
list: [],
|
|
837
|
+
count: 0
|
|
838
|
+
},
|
|
860
839
|
status: false
|
|
861
840
|
};
|
|
862
841
|
}
|
|
863
842
|
try {
|
|
864
|
-
const response = await this.app.request.get(
|
|
843
|
+
const response = await this.app.request.get('/shop/order/sales', {
|
|
844
|
+
...data,
|
|
845
|
+
form_record_ids: undefined,
|
|
846
|
+
with: ["all"]
|
|
847
|
+
}, {
|
|
865
848
|
isShopApi: true
|
|
866
849
|
});
|
|
867
|
-
const rawList =
|
|
868
|
-
const list = (0,
|
|
869
|
-
this.logInfo(
|
|
850
|
+
const rawList = response?.data?.list ?? response?.list ?? [];
|
|
851
|
+
const list = (0, _filterBookings.filterBookingsFromOrders)(rawList, data);
|
|
852
|
+
this.logInfo('fetchBookingListFromAPI: API 返回并拆分完成', {
|
|
870
853
|
rawCount: rawList.length,
|
|
871
854
|
flattenedCount: list.count
|
|
872
855
|
});
|
|
873
856
|
return {
|
|
874
857
|
code: 200,
|
|
875
|
-
data: {
|
|
876
|
-
|
|
858
|
+
data: {
|
|
859
|
+
...response.data,
|
|
860
|
+
list: list?.list || []
|
|
861
|
+
},
|
|
862
|
+
message: '',
|
|
877
863
|
status: true
|
|
878
864
|
};
|
|
879
865
|
} catch (error) {
|
|
880
866
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
881
|
-
this.logError(
|
|
867
|
+
this.logError('fetchBookingListFromAPI: 请求失败', {
|
|
868
|
+
error: errorMessage
|
|
869
|
+
});
|
|
882
870
|
return {
|
|
883
871
|
code: 500,
|
|
884
872
|
message: errorMessage,
|
|
885
|
-
data: {
|
|
873
|
+
data: {
|
|
874
|
+
list: [],
|
|
875
|
+
count: 0
|
|
876
|
+
},
|
|
886
877
|
status: false
|
|
887
878
|
};
|
|
888
879
|
}
|
|
889
880
|
}
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* 处理预约列表查询
|
|
884
|
+
* 今天:注册订阅者 + 本地数据筛选;非今天:清理订阅者 + 走真实 API
|
|
885
|
+
*/
|
|
886
|
+
handleBookingList = async ({
|
|
887
|
+
url,
|
|
888
|
+
method,
|
|
889
|
+
data,
|
|
890
|
+
config
|
|
891
|
+
}) => {
|
|
892
|
+
const queryPayload = data && typeof data === 'object' ? {
|
|
893
|
+
...data
|
|
894
|
+
} : {};
|
|
895
|
+
const {
|
|
896
|
+
callback,
|
|
897
|
+
subscriberId
|
|
898
|
+
} = config || {};
|
|
899
|
+
const isToday = this.isBookingQueryForToday(queryPayload);
|
|
900
|
+
this.logInfo('handleBookingList: 开始处理预约列表请求', {
|
|
901
|
+
data: queryPayload,
|
|
902
|
+
isToday
|
|
903
|
+
});
|
|
904
|
+
if (isToday) {
|
|
905
|
+
if (subscriberId && typeof callback === 'function') {
|
|
906
|
+
this.bookingQuerySubscribers.set(subscriberId, {
|
|
907
|
+
callback,
|
|
908
|
+
context: queryPayload
|
|
909
|
+
});
|
|
910
|
+
this.logInfo('handleBookingList: 已注册订阅者(今天)', {
|
|
911
|
+
subscriberId,
|
|
912
|
+
totalSubscribers: this.bookingQuerySubscribers.size
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
return this.computeBookingQueryResult(queryPayload);
|
|
916
|
+
} else {
|
|
917
|
+
if (subscriberId) {
|
|
918
|
+
this.bookingQuerySubscribers.delete(subscriberId);
|
|
919
|
+
this.logInfo('handleBookingList: 已清理订阅者(非今天)', {
|
|
920
|
+
subscriberId,
|
|
921
|
+
remaining: this.bookingQuerySubscribers.size
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
return this.fetchBookingListFromAPI(queryPayload);
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* 处理资源列表查询
|
|
930
|
+
* 转发到资源模块去
|
|
931
|
+
*/
|
|
932
|
+
handleResourceList = async ({
|
|
933
|
+
url,
|
|
934
|
+
method,
|
|
935
|
+
data,
|
|
936
|
+
config
|
|
937
|
+
}) => {
|
|
938
|
+
const list = this.resource?.getResources({
|
|
939
|
+
skip: data?.skip || 1,
|
|
940
|
+
num: data?.num || 10
|
|
941
|
+
});
|
|
942
|
+
return {
|
|
943
|
+
code: 200,
|
|
944
|
+
data: {
|
|
945
|
+
list,
|
|
946
|
+
count: list?.length || 0
|
|
947
|
+
},
|
|
948
|
+
message: '',
|
|
949
|
+
status: true
|
|
950
|
+
};
|
|
951
|
+
};
|
|
952
|
+
|
|
953
|
+
/**
|
|
954
|
+
* 取消预约列表查询订阅(HTTP 路由入口)
|
|
955
|
+
*/
|
|
956
|
+
handleUnsubscribeBookingQuery = async ({
|
|
957
|
+
data
|
|
958
|
+
}) => {
|
|
959
|
+
const {
|
|
960
|
+
subscriberId
|
|
961
|
+
} = data || {};
|
|
962
|
+
if (subscriberId) {
|
|
963
|
+
this.bookingQuerySubscribers.delete(subscriberId);
|
|
964
|
+
this.logInfo('handleUnsubscribeBookingQuery: 已移除订阅者', {
|
|
965
|
+
subscriberId,
|
|
966
|
+
remaining: this.bookingQuerySubscribers.size
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
return {
|
|
970
|
+
code: 200,
|
|
971
|
+
message: 'ok',
|
|
972
|
+
status: true
|
|
973
|
+
};
|
|
974
|
+
};
|
|
975
|
+
|
|
890
976
|
/**
|
|
891
977
|
* 订单列表本地计算(编排 Order 模块)
|
|
892
978
|
* filter 逻辑暂为 mock,仅记录参数
|
|
893
979
|
*/
|
|
894
980
|
async computeOrderQueryResult(data) {
|
|
895
|
-
this.logInfo(
|
|
896
|
-
|
|
981
|
+
this.logInfo('computeOrderQueryResult: 开始过滤', {
|
|
982
|
+
data
|
|
983
|
+
});
|
|
897
984
|
if (!this.order) {
|
|
898
|
-
this.logError(
|
|
985
|
+
this.logError('computeOrderQueryResult: Order 模块未注册');
|
|
899
986
|
return {
|
|
900
987
|
code: 500,
|
|
901
|
-
message:
|
|
902
|
-
data: {
|
|
988
|
+
message: 'Order 模块未注册',
|
|
989
|
+
data: {
|
|
990
|
+
list: [],
|
|
991
|
+
count: 0
|
|
992
|
+
},
|
|
903
993
|
status: false
|
|
904
994
|
};
|
|
905
995
|
}
|
|
906
996
|
const rawList = this.order.getOrders();
|
|
907
|
-
this.logInfo(
|
|
908
|
-
|
|
909
|
-
|
|
997
|
+
this.logInfo('computeOrderQueryResult: 本地订单数量', {
|
|
998
|
+
rawCount: rawList.length
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
// 使用 filterOrders 进行过滤、排序、分页
|
|
1002
|
+
const result = (0, _filterOrders.filterOrders)(rawList, data);
|
|
1003
|
+
this.logInfo('computeOrderQueryResult: 过滤结果', {
|
|
910
1004
|
rawCount: rawList.length,
|
|
911
1005
|
filteredCount: result.count,
|
|
912
1006
|
size: result.size,
|
|
@@ -915,28 +1009,32 @@ var Server = class {
|
|
|
915
1009
|
return {
|
|
916
1010
|
code: 200,
|
|
917
1011
|
data: result,
|
|
918
|
-
message:
|
|
1012
|
+
message: '',
|
|
919
1013
|
status: true
|
|
920
1014
|
};
|
|
921
1015
|
}
|
|
1016
|
+
|
|
922
1017
|
/**
|
|
923
1018
|
* 预约列表本地计算(编排 Order 模块)
|
|
924
1019
|
* 从订单中展开 bookings,再按条件筛选 + 分页
|
|
925
1020
|
*/
|
|
926
1021
|
async computeBookingQueryResult(data) {
|
|
927
1022
|
if (!this.order) {
|
|
928
|
-
this.logError(
|
|
1023
|
+
this.logError('computeBookingQueryResult: Order 模块未注册');
|
|
929
1024
|
return {
|
|
930
1025
|
code: 500,
|
|
931
|
-
message:
|
|
932
|
-
data: {
|
|
1026
|
+
message: 'Order 模块未注册',
|
|
1027
|
+
data: {
|
|
1028
|
+
list: [],
|
|
1029
|
+
count: 0
|
|
1030
|
+
},
|
|
933
1031
|
status: false
|
|
934
1032
|
};
|
|
935
1033
|
}
|
|
936
1034
|
const rawOrders = this.order.getOrders();
|
|
937
|
-
let result = (0,
|
|
938
|
-
result = (0,
|
|
939
|
-
this.logInfo(
|
|
1035
|
+
let result = (0, _filterBookings.filterBookingsFromOrders)(rawOrders, data);
|
|
1036
|
+
result = (0, _filterBookings.sortBookings)(result, data);
|
|
1037
|
+
this.logInfo('computeBookingQueryResult: 过滤结果', {
|
|
940
1038
|
orderCount: rawOrders.length,
|
|
941
1039
|
filteredCount: result.count,
|
|
942
1040
|
size: result.size,
|
|
@@ -945,10 +1043,11 @@ var Server = class {
|
|
|
945
1043
|
return {
|
|
946
1044
|
code: 200,
|
|
947
1045
|
data: result,
|
|
948
|
-
message:
|
|
1046
|
+
message: '',
|
|
949
1047
|
status: true
|
|
950
1048
|
};
|
|
951
1049
|
}
|
|
1050
|
+
|
|
952
1051
|
/**
|
|
953
1052
|
* 商品查询的核心计算逻辑(编排 Products、Menu、Schedule 模块)
|
|
954
1053
|
* 供 handleProductQuery 首次返回及 pubsub 变更推送复用
|
|
@@ -958,34 +1057,55 @@ var Server = class {
|
|
|
958
1057
|
*/
|
|
959
1058
|
async computeProductQueryResult(context, options) {
|
|
960
1059
|
const tTotal = performance.now();
|
|
961
|
-
const {
|
|
962
|
-
|
|
963
|
-
|
|
1060
|
+
const {
|
|
1061
|
+
menu_list_ids,
|
|
1062
|
+
schedule_date,
|
|
1063
|
+
schedule_datetime
|
|
1064
|
+
} = context;
|
|
1065
|
+
this.logInfo('computeProductQueryResult 开始', {
|
|
1066
|
+
menuListIdsCount: menu_list_ids?.length ?? 0,
|
|
964
1067
|
schedule_datetime,
|
|
965
1068
|
schedule_date,
|
|
966
|
-
changedIds: options
|
|
1069
|
+
changedIds: options?.changedIds
|
|
967
1070
|
});
|
|
968
1071
|
if (!this.products) {
|
|
969
|
-
this.logError(
|
|
970
|
-
return {
|
|
1072
|
+
this.logError('computeProductQueryResult: Products 模块未注册');
|
|
1073
|
+
return {
|
|
1074
|
+
message: 'Products 模块未注册',
|
|
1075
|
+
data: {
|
|
1076
|
+
list: [],
|
|
1077
|
+
count: 0
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
971
1080
|
}
|
|
972
1081
|
if (!this.menu) {
|
|
973
|
-
this.logError(
|
|
974
|
-
return {
|
|
1082
|
+
this.logError('computeProductQueryResult: Menu 模块未注册');
|
|
1083
|
+
return {
|
|
1084
|
+
message: 'Menu 模块未注册',
|
|
1085
|
+
data: {
|
|
1086
|
+
list: [],
|
|
1087
|
+
count: 0
|
|
1088
|
+
}
|
|
1089
|
+
};
|
|
975
1090
|
}
|
|
976
1091
|
if (!this.schedule) {
|
|
977
|
-
this.logError(
|
|
978
|
-
return {
|
|
1092
|
+
this.logError('computeProductQueryResult: Schedule 模块未注册');
|
|
1093
|
+
return {
|
|
1094
|
+
message: 'Schedule 模块未注册',
|
|
1095
|
+
data: {
|
|
1096
|
+
list: [],
|
|
1097
|
+
count: 0
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
979
1100
|
}
|
|
980
1101
|
let activeMenuList = [];
|
|
981
1102
|
if (menu_list_ids && Array.isArray(menu_list_ids) && menu_list_ids.length > 0) {
|
|
982
1103
|
const tMenu = performance.now();
|
|
983
1104
|
const menuList = this.menu.getMenuByIds(menu_list_ids);
|
|
984
|
-
activeMenuList = menuList.filter(
|
|
985
|
-
|
|
986
|
-
return ((_a = this.schedule) == null ? void 0 : _a.getDateIsInSchedule(schedule_datetime, menu.schedule)) || false;
|
|
1105
|
+
activeMenuList = menuList.filter(menu => {
|
|
1106
|
+
return this.schedule?.getDateIsInSchedule(schedule_datetime, menu.schedule) || false;
|
|
987
1107
|
});
|
|
988
|
-
(0,
|
|
1108
|
+
(0, _product.perfMark)('computeQuery.filterActiveMenu', performance.now() - tMenu, {
|
|
989
1109
|
totalMenu: menuList.length,
|
|
990
1110
|
activeMenu: activeMenuList.length
|
|
991
1111
|
});
|
|
@@ -994,49 +1114,54 @@ var Server = class {
|
|
|
994
1114
|
const allProductsWithPrice = await this.products.getProductsWithPrice(schedule_date, {
|
|
995
1115
|
scheduleModule: this.getSchedule()
|
|
996
1116
|
}, {
|
|
997
|
-
changedIds: options
|
|
1117
|
+
changedIds: options?.changedIds
|
|
998
1118
|
});
|
|
999
|
-
(0,
|
|
1119
|
+
(0, _product.perfMark)('computeQuery.getProductsWithPrice', performance.now() - tPrice, {
|
|
1000
1120
|
count: allProductsWithPrice.length
|
|
1001
1121
|
});
|
|
1002
1122
|
const tFilter = performance.now();
|
|
1003
1123
|
let filteredProducts = this.filterProductsByMenuConfig(allProductsWithPrice, activeMenuList);
|
|
1004
|
-
(0,
|
|
1124
|
+
(0, _product.perfMark)('computeQuery.filterByMenu', performance.now() - tFilter, {
|
|
1005
1125
|
before: allProductsWithPrice.length,
|
|
1006
1126
|
after: filteredProducts.length
|
|
1007
1127
|
});
|
|
1008
1128
|
const tStatus = performance.now();
|
|
1009
1129
|
const beforeStatusCount = filteredProducts.length;
|
|
1010
|
-
filteredProducts = filteredProducts.filter(
|
|
1011
|
-
(0,
|
|
1130
|
+
filteredProducts = filteredProducts.filter(p => (p?.status || "published") === 'published');
|
|
1131
|
+
(0, _product.perfMark)('computeQuery.filterByStatus', performance.now() - tStatus, {
|
|
1012
1132
|
before: beforeStatusCount,
|
|
1013
1133
|
after: filteredProducts.length
|
|
1014
1134
|
});
|
|
1015
1135
|
const tSort = performance.now();
|
|
1016
1136
|
filteredProducts = filteredProducts.sort((a, b) => {
|
|
1017
1137
|
const sortDiff = Number(b.sort) - Number(a.sort);
|
|
1018
|
-
if (sortDiff !== 0)
|
|
1019
|
-
|
|
1020
|
-
|
|
1138
|
+
if (sortDiff !== 0) return sortDiff;
|
|
1139
|
+
return (a.title || '').localeCompare(b.title || '');
|
|
1140
|
+
});
|
|
1141
|
+
(0, _product.perfMark)('computeQuery.sort', performance.now() - tSort, {
|
|
1142
|
+
count: filteredProducts.length
|
|
1021
1143
|
});
|
|
1022
|
-
(0,
|
|
1023
|
-
(0, import_product.perfMark)("computeProductQueryResult", performance.now() - tTotal, {
|
|
1144
|
+
(0, _product.perfMark)('computeProductQueryResult', performance.now() - tTotal, {
|
|
1024
1145
|
originalCount: allProductsWithPrice.length,
|
|
1025
1146
|
filteredCount: filteredProducts.length,
|
|
1026
1147
|
activeMenuCount: activeMenuList.length
|
|
1027
1148
|
});
|
|
1028
|
-
this.logInfo(
|
|
1149
|
+
this.logInfo('computeProductQueryResult 完成', {
|
|
1029
1150
|
originalCount: allProductsWithPrice.length,
|
|
1030
1151
|
filteredCount: filteredProducts.length,
|
|
1031
1152
|
activeMenuCount: activeMenuList.length
|
|
1032
1153
|
});
|
|
1033
1154
|
return {
|
|
1034
1155
|
code: 200,
|
|
1035
|
-
data: {
|
|
1036
|
-
|
|
1156
|
+
data: {
|
|
1157
|
+
list: filteredProducts,
|
|
1158
|
+
count: filteredProducts.length
|
|
1159
|
+
},
|
|
1160
|
+
message: '',
|
|
1037
1161
|
status: true
|
|
1038
1162
|
};
|
|
1039
1163
|
}
|
|
1164
|
+
|
|
1040
1165
|
/**
|
|
1041
1166
|
* 数据变更后,遍历所有订阅者重新计算查询结果并通过 callback 推送
|
|
1042
1167
|
* 由 ProductsModule 的 onProductsSyncCompleted 事件触发
|
|
@@ -1044,74 +1169,80 @@ var Server = class {
|
|
|
1044
1169
|
* @param options.changedIds 变更的商品 IDs,用于增量更新价格缓存
|
|
1045
1170
|
*/
|
|
1046
1171
|
async recomputeAndNotifyProductQuery(options) {
|
|
1047
|
-
if (this.productQuerySubscribers.size === 0)
|
|
1048
|
-
|
|
1049
|
-
this.logInfo("recomputeAndNotifyProductQuery: 开始推送", {
|
|
1172
|
+
if (this.productQuerySubscribers.size === 0) return;
|
|
1173
|
+
this.logInfo('recomputeAndNotifyProductQuery: 开始推送', {
|
|
1050
1174
|
subscriberCount: this.productQuerySubscribers.size,
|
|
1051
|
-
changedIds: options
|
|
1175
|
+
changedIds: options?.changedIds
|
|
1052
1176
|
});
|
|
1053
1177
|
for (const [subscriberId, subscriber] of this.productQuerySubscribers.entries()) {
|
|
1054
1178
|
try {
|
|
1055
1179
|
const result = await this.computeProductQueryResult(subscriber.context, {
|
|
1056
|
-
changedIds: options
|
|
1180
|
+
changedIds: options?.changedIds
|
|
1057
1181
|
});
|
|
1058
1182
|
subscriber.callback(result);
|
|
1059
|
-
this.logInfo(
|
|
1183
|
+
this.logInfo('recomputeAndNotifyProductQuery: 已推送', {
|
|
1184
|
+
subscriberId
|
|
1185
|
+
});
|
|
1060
1186
|
} catch (error) {
|
|
1061
1187
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1062
|
-
this.logError(
|
|
1188
|
+
this.logError('recomputeAndNotifyProductQuery: 推送失败', {
|
|
1063
1189
|
subscriberId,
|
|
1064
1190
|
error: errorMessage
|
|
1065
1191
|
});
|
|
1066
1192
|
}
|
|
1067
1193
|
}
|
|
1068
1194
|
}
|
|
1195
|
+
|
|
1069
1196
|
/**
|
|
1070
1197
|
* 订单数据变更后,遍历订阅者重新计算并通过 callback 推送
|
|
1071
1198
|
*/
|
|
1072
1199
|
async recomputeAndNotifyOrderQuery() {
|
|
1073
|
-
if (this.orderQuerySubscribers.size === 0)
|
|
1074
|
-
|
|
1075
|
-
this.logInfo("recomputeAndNotifyOrderQuery: 开始推送", {
|
|
1200
|
+
if (this.orderQuerySubscribers.size === 0) return;
|
|
1201
|
+
this.logInfo('recomputeAndNotifyOrderQuery: 开始推送', {
|
|
1076
1202
|
subscriberCount: this.orderQuerySubscribers.size
|
|
1077
1203
|
});
|
|
1078
1204
|
for (const [subscriberId, subscriber] of this.orderQuerySubscribers.entries()) {
|
|
1079
1205
|
try {
|
|
1080
1206
|
const result = await this.computeOrderQueryResult(subscriber.context);
|
|
1081
1207
|
subscriber.callback(result);
|
|
1082
|
-
this.logInfo(
|
|
1208
|
+
this.logInfo('recomputeAndNotifyOrderQuery: 已推送', {
|
|
1209
|
+
subscriberId
|
|
1210
|
+
});
|
|
1083
1211
|
} catch (error) {
|
|
1084
1212
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1085
|
-
this.logError(
|
|
1213
|
+
this.logError('recomputeAndNotifyOrderQuery: 推送失败', {
|
|
1086
1214
|
subscriberId,
|
|
1087
1215
|
error: errorMessage
|
|
1088
1216
|
});
|
|
1089
1217
|
}
|
|
1090
1218
|
}
|
|
1091
1219
|
}
|
|
1220
|
+
|
|
1092
1221
|
/**
|
|
1093
1222
|
* 预约数据变更后,遍历订阅者重新计算并通过 callback 推送
|
|
1094
1223
|
*/
|
|
1095
1224
|
async recomputeAndNotifyBookingQuery() {
|
|
1096
|
-
if (this.bookingQuerySubscribers.size === 0)
|
|
1097
|
-
|
|
1098
|
-
this.logInfo("recomputeAndNotifyBookingQuery: 开始推送", {
|
|
1225
|
+
if (this.bookingQuerySubscribers.size === 0) return;
|
|
1226
|
+
this.logInfo('recomputeAndNotifyBookingQuery: 开始推送', {
|
|
1099
1227
|
subscriberCount: this.bookingQuerySubscribers.size
|
|
1100
1228
|
});
|
|
1101
1229
|
for (const [subscriberId, subscriber] of this.bookingQuerySubscribers.entries()) {
|
|
1102
1230
|
try {
|
|
1103
1231
|
const result = await this.computeBookingQueryResult(subscriber.context);
|
|
1104
1232
|
subscriber.callback(result);
|
|
1105
|
-
this.logInfo(
|
|
1233
|
+
this.logInfo('recomputeAndNotifyBookingQuery: 已推送', {
|
|
1234
|
+
subscriberId
|
|
1235
|
+
});
|
|
1106
1236
|
} catch (error) {
|
|
1107
1237
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1108
|
-
this.logError(
|
|
1238
|
+
this.logError('recomputeAndNotifyBookingQuery: 推送失败', {
|
|
1109
1239
|
subscriberId,
|
|
1110
1240
|
error: errorMessage
|
|
1111
1241
|
});
|
|
1112
1242
|
}
|
|
1113
1243
|
}
|
|
1114
1244
|
}
|
|
1245
|
+
|
|
1115
1246
|
/**
|
|
1116
1247
|
* 根据餐牌配置过滤商品
|
|
1117
1248
|
* @param products 所有商品列表
|
|
@@ -1120,30 +1251,33 @@ var Server = class {
|
|
|
1120
1251
|
* @private
|
|
1121
1252
|
*/
|
|
1122
1253
|
filterProductsByMenuConfig(products, activeMenuList) {
|
|
1254
|
+
// 如果没有生效的餐牌,返回空数组
|
|
1123
1255
|
if (!activeMenuList || activeMenuList.length === 0) {
|
|
1124
|
-
|
|
1125
|
-
this.logInfo("filterProductsByMenuConfig: 没有生效的餐牌,返回空数组", {
|
|
1256
|
+
this.logInfo('filterProductsByMenuConfig: 没有生效的餐牌,返回空数组', {
|
|
1126
1257
|
productCount: products.length,
|
|
1127
1258
|
activeMenuCount: 0
|
|
1128
1259
|
});
|
|
1129
1260
|
return [];
|
|
1130
1261
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1262
|
+
|
|
1263
|
+
// 收集允许的商品 IDs 和集合 IDs
|
|
1264
|
+
let allowedProductIds = new Set();
|
|
1265
|
+
let allowedCollectionIds = new Set();
|
|
1133
1266
|
let hasProductAll = false;
|
|
1134
1267
|
for (const menu of activeMenuList) {
|
|
1135
1268
|
const config = menu.partyroom_package;
|
|
1136
1269
|
if (!config) {
|
|
1137
|
-
console.warn(
|
|
1138
|
-
this.logWarning(
|
|
1270
|
+
console.warn('[Server] 餐牌缺少 partyroom_package 配置:', menu);
|
|
1271
|
+
this.logWarning('filterProductsByMenuConfig: 餐牌缺少 partyroom_package 配置', {
|
|
1139
1272
|
menuId: menu.form_record_id,
|
|
1140
1273
|
menuName: menu.name
|
|
1141
1274
|
});
|
|
1142
1275
|
continue;
|
|
1143
1276
|
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1277
|
+
|
|
1278
|
+
// 如果有任何一个餐牌是 product_all,则返回所有商品
|
|
1279
|
+
if (config.type === 'product_all') {
|
|
1280
|
+
this.logInfo('filterProductsByMenuConfig: 餐牌允许所有商品', {
|
|
1147
1281
|
menuId: menu.form_record_id,
|
|
1148
1282
|
menuName: menu.name,
|
|
1149
1283
|
configType: config.type
|
|
@@ -1151,22 +1285,24 @@ var Server = class {
|
|
|
1151
1285
|
hasProductAll = true;
|
|
1152
1286
|
break;
|
|
1153
1287
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1288
|
+
|
|
1289
|
+
// 如果是 product_ids 类型,从 ProductItemType 中提取 product_id
|
|
1290
|
+
if (config.type === 'products' && Array.isArray(config.products)) {
|
|
1291
|
+
const productIds = config.products.map(item => item.product_id);
|
|
1292
|
+
productIds.forEach(id => id && allowedProductIds.add(id));
|
|
1293
|
+
this.logInfo('filterProductsByMenuConfig: 餐牌允许指定商品', {
|
|
1159
1294
|
menuId: menu.form_record_id,
|
|
1160
1295
|
menuName: menu.name,
|
|
1161
1296
|
configType: config.type,
|
|
1162
1297
|
productIdsCount: productIds.length
|
|
1163
1298
|
});
|
|
1164
1299
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1300
|
+
|
|
1301
|
+
// 如果是 product_collection 类型,从 ProductItemType 中提取 product_collection_id
|
|
1302
|
+
if (config.type === 'product_collection' && Array.isArray(config.products)) {
|
|
1303
|
+
const collectionIds = config.products.map(item => item.product_collection_id);
|
|
1304
|
+
collectionIds.forEach(id => id && allowedCollectionIds.add(id));
|
|
1305
|
+
this.logInfo('filterProductsByMenuConfig: 餐牌允许商品集合', {
|
|
1170
1306
|
menuId: menu.form_record_id,
|
|
1171
1307
|
menuName: menu.name,
|
|
1172
1308
|
configType: config.type,
|
|
@@ -1174,15 +1310,18 @@ var Server = class {
|
|
|
1174
1310
|
});
|
|
1175
1311
|
}
|
|
1176
1312
|
}
|
|
1313
|
+
|
|
1314
|
+
// 如果有餐牌允许所有商品,返回所有商品
|
|
1177
1315
|
if (hasProductAll) {
|
|
1178
|
-
this.logInfo(
|
|
1316
|
+
this.logInfo('filterProductsByMenuConfig: 返回所有商品(product_all)', {
|
|
1179
1317
|
productCount: products.length
|
|
1180
1318
|
});
|
|
1181
1319
|
return products;
|
|
1182
1320
|
}
|
|
1321
|
+
|
|
1322
|
+
// 如果没有收集到任何商品 ID 和集合 ID,返回空数组
|
|
1183
1323
|
if (allowedProductIds.size === 0 && allowedCollectionIds.size === 0) {
|
|
1184
|
-
|
|
1185
|
-
this.logWarning("filterProductsByMenuConfig: 没有允许的商品和集合", {
|
|
1324
|
+
this.logWarning('filterProductsByMenuConfig: 没有允许的商品和集合', {
|
|
1186
1325
|
productCount: products.length,
|
|
1187
1326
|
activeMenuCount: activeMenuList.length
|
|
1188
1327
|
});
|
|
@@ -1190,34 +1329,35 @@ var Server = class {
|
|
|
1190
1329
|
}
|
|
1191
1330
|
const allowedProductIdsArray = Array.from(allowedProductIds);
|
|
1192
1331
|
const allowedCollectionIdsArray = Array.from(allowedCollectionIds);
|
|
1193
|
-
|
|
1194
|
-
console.log("[Server] 允许的集合 IDs:", allowedCollectionIdsArray);
|
|
1195
|
-
this.logInfo("filterProductsByMenuConfig: 收集到的允许规则", {
|
|
1332
|
+
this.logInfo('filterProductsByMenuConfig: 收集到的允许规则', {
|
|
1196
1333
|
allowedProductCount: allowedProductIds.size,
|
|
1197
1334
|
allowedCollectionCount: allowedCollectionIds.size
|
|
1198
1335
|
});
|
|
1199
|
-
|
|
1336
|
+
|
|
1337
|
+
// 过滤商品
|
|
1338
|
+
const filteredProducts = products.filter(product => {
|
|
1339
|
+
// 1. 检查商品 ID 是否在允许列表中
|
|
1200
1340
|
if (allowedProductIds.has(product.id)) {
|
|
1201
1341
|
return true;
|
|
1202
1342
|
}
|
|
1343
|
+
|
|
1344
|
+
// 2. 检查商品是否属于允许的集合
|
|
1203
1345
|
if (allowedCollectionIds.size > 0 && Array.isArray(product.collection)) {
|
|
1204
|
-
const hasMatchingCollection = product.collection.some(
|
|
1205
|
-
(col) => allowedCollectionIds.has(col.id)
|
|
1206
|
-
);
|
|
1346
|
+
const hasMatchingCollection = product.collection.some(col => allowedCollectionIds.has(col.id));
|
|
1207
1347
|
if (hasMatchingCollection) {
|
|
1208
1348
|
return true;
|
|
1209
1349
|
}
|
|
1210
1350
|
}
|
|
1211
1351
|
return false;
|
|
1212
1352
|
});
|
|
1213
|
-
|
|
1214
|
-
this.logInfo("filterProductsByMenuConfig: 过滤完成", {
|
|
1353
|
+
this.logInfo('filterProductsByMenuConfig: 过滤完成', {
|
|
1215
1354
|
originalCount: products.length,
|
|
1216
1355
|
filteredCount: filteredProducts.length,
|
|
1217
1356
|
removedCount: products.length - filteredProducts.length
|
|
1218
1357
|
});
|
|
1219
1358
|
return filteredProducts;
|
|
1220
1359
|
}
|
|
1360
|
+
|
|
1221
1361
|
/**
|
|
1222
1362
|
* 记录信息日志
|
|
1223
1363
|
* @param title 日志标题
|
|
@@ -1227,14 +1367,16 @@ var Server = class {
|
|
|
1227
1367
|
try {
|
|
1228
1368
|
if (this.logger) {
|
|
1229
1369
|
this.logger.addLog({
|
|
1230
|
-
type:
|
|
1370
|
+
type: 'info',
|
|
1231
1371
|
title: `[Server] ${title}`,
|
|
1232
1372
|
metadata: metadata || {}
|
|
1233
1373
|
});
|
|
1234
1374
|
}
|
|
1235
1375
|
} catch {
|
|
1376
|
+
// 日志记录失败不影响主流程
|
|
1236
1377
|
}
|
|
1237
1378
|
}
|
|
1379
|
+
|
|
1238
1380
|
/**
|
|
1239
1381
|
* 记录警告日志
|
|
1240
1382
|
* @param title 日志标题
|
|
@@ -1244,14 +1386,16 @@ var Server = class {
|
|
|
1244
1386
|
try {
|
|
1245
1387
|
if (this.logger) {
|
|
1246
1388
|
this.logger.addLog({
|
|
1247
|
-
type:
|
|
1389
|
+
type: 'warning',
|
|
1248
1390
|
title: `[Server] ${title}`,
|
|
1249
1391
|
metadata: metadata || {}
|
|
1250
1392
|
});
|
|
1251
1393
|
}
|
|
1252
1394
|
} catch {
|
|
1395
|
+
// 日志记录失败不影响主流程
|
|
1253
1396
|
}
|
|
1254
1397
|
}
|
|
1398
|
+
|
|
1255
1399
|
/**
|
|
1256
1400
|
* 记录错误日志
|
|
1257
1401
|
* @param title 日志标题
|
|
@@ -1261,17 +1405,132 @@ var Server = class {
|
|
|
1261
1405
|
try {
|
|
1262
1406
|
if (this.logger) {
|
|
1263
1407
|
this.logger.addLog({
|
|
1264
|
-
type:
|
|
1408
|
+
type: 'error',
|
|
1265
1409
|
title: `[Server] ${title}`,
|
|
1266
1410
|
metadata: metadata || {}
|
|
1267
1411
|
});
|
|
1268
1412
|
}
|
|
1269
1413
|
} catch {
|
|
1414
|
+
// 日志记录失败不影响主流程
|
|
1270
1415
|
}
|
|
1271
1416
|
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1417
|
+
|
|
1418
|
+
/**
|
|
1419
|
+
* 处理获取日程时间段点的请求
|
|
1420
|
+
* 通过餐牌ID列表获取所有相关日程的时间段点
|
|
1421
|
+
*/
|
|
1422
|
+
handleGetScheduleTimePoints = async ({
|
|
1423
|
+
url,
|
|
1424
|
+
method,
|
|
1425
|
+
data,
|
|
1426
|
+
config
|
|
1427
|
+
}) => {
|
|
1428
|
+
const {
|
|
1429
|
+
menu_list_ids
|
|
1430
|
+
} = data;
|
|
1431
|
+
this.logInfo('handleGetScheduleTimePoints 开始处理', {
|
|
1432
|
+
menuListIdsCount: menu_list_ids?.length ?? 0,
|
|
1433
|
+
menu_list_ids
|
|
1434
|
+
});
|
|
1435
|
+
|
|
1436
|
+
// 检查必要的模块是否已注册
|
|
1437
|
+
if (!this.menu) {
|
|
1438
|
+
console.error('[Server] Menu 模块未注册');
|
|
1439
|
+
this.logError('handleGetScheduleTimePoints: Menu 模块未注册');
|
|
1440
|
+
return {
|
|
1441
|
+
code: 500,
|
|
1442
|
+
message: 'Menu 模块未注册',
|
|
1443
|
+
data: [],
|
|
1444
|
+
status: false
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
if (!this.schedule) {
|
|
1448
|
+
console.error('[Server] Schedule 模块未注册');
|
|
1449
|
+
this.logError('handleGetScheduleTimePoints: Schedule 模块未注册');
|
|
1450
|
+
return {
|
|
1451
|
+
code: 500,
|
|
1452
|
+
message: 'Schedule 模块未注册',
|
|
1453
|
+
data: [],
|
|
1454
|
+
status: false
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
// 检查参数
|
|
1459
|
+
if (!menu_list_ids || !Array.isArray(menu_list_ids) || menu_list_ids.length === 0) {
|
|
1460
|
+
console.error('[Server] menu_list_ids 参数无效');
|
|
1461
|
+
this.logWarning('handleGetScheduleTimePoints: menu_list_ids 参数无效', {
|
|
1462
|
+
menuListIdsCount: menu_list_ids?.length ?? 0,
|
|
1463
|
+
menu_list_ids
|
|
1464
|
+
});
|
|
1465
|
+
return {
|
|
1466
|
+
code: 400,
|
|
1467
|
+
message: 'menu_list_ids 参数无效',
|
|
1468
|
+
data: [],
|
|
1469
|
+
status: false
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
try {
|
|
1473
|
+
// 1. 获取餐牌列表
|
|
1474
|
+
const menuList = this.menu.getMenuByIds(menu_list_ids);
|
|
1475
|
+
this.logInfo('handleGetScheduleTimePoints: 获取到餐牌列表', {
|
|
1476
|
+
requestedCount: menu_list_ids.length,
|
|
1477
|
+
foundCount: menuList.length,
|
|
1478
|
+
menu_list_ids,
|
|
1479
|
+
menuList
|
|
1480
|
+
});
|
|
1481
|
+
|
|
1482
|
+
// 2. 提取所有的 schedule IDs
|
|
1483
|
+
const scheduleIds = (0, _schedule2.extractScheduleIdsFromMenus)(menuList);
|
|
1484
|
+
this.logInfo('handleGetScheduleTimePoints: 提取到日程 IDs', {
|
|
1485
|
+
scheduleCount: scheduleIds.length
|
|
1486
|
+
});
|
|
1487
|
+
if (scheduleIds.length === 0) {
|
|
1488
|
+
this.logInfo('handleGetScheduleTimePoints: 没有找到相关日程', {
|
|
1489
|
+
menuListIdsCount: menu_list_ids.length
|
|
1490
|
+
});
|
|
1491
|
+
return {
|
|
1492
|
+
code: 200,
|
|
1493
|
+
message: '没有找到相关日程',
|
|
1494
|
+
data: [],
|
|
1495
|
+
status: true
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
// 3. 获取日程详情
|
|
1500
|
+
const scheduleList = this.schedule.getScheduleByIds(scheduleIds);
|
|
1501
|
+
this.logInfo('handleGetScheduleTimePoints: 获取到日程详情', {
|
|
1502
|
+
requestedCount: scheduleIds.length,
|
|
1503
|
+
foundCount: scheduleList.length
|
|
1504
|
+
});
|
|
1505
|
+
|
|
1506
|
+
// 4. 提取时间点
|
|
1507
|
+
const timePoints = (0, _schedule2.extractTimePointsFromSchedules)(scheduleList);
|
|
1508
|
+
this.logInfo('handleGetScheduleTimePoints 处理完成', {
|
|
1509
|
+
menuListIdsCount: menu_list_ids.length,
|
|
1510
|
+
menuCount: menuList.length,
|
|
1511
|
+
scheduleCount: scheduleList.length,
|
|
1512
|
+
timePointCount: timePoints.length
|
|
1513
|
+
});
|
|
1514
|
+
return {
|
|
1515
|
+
code: 200,
|
|
1516
|
+
message: '获取成功',
|
|
1517
|
+
data: timePoints,
|
|
1518
|
+
status: true
|
|
1519
|
+
};
|
|
1520
|
+
} catch (error) {
|
|
1521
|
+
const errorMessage = error instanceof Error ? error.message : '未知错误';
|
|
1522
|
+
console.error('[Server] 获取日程时间点失败:', error);
|
|
1523
|
+
this.logError('handleGetScheduleTimePoints: 获取日程时间点失败', {
|
|
1524
|
+
menuListIdsCount: menu_list_ids.length,
|
|
1525
|
+
error: errorMessage
|
|
1526
|
+
});
|
|
1527
|
+
return {
|
|
1528
|
+
code: 500,
|
|
1529
|
+
message: `获取失败: ${errorMessage}`,
|
|
1530
|
+
data: [],
|
|
1531
|
+
status: false
|
|
1532
|
+
};
|
|
1533
|
+
}
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
var _default = exports.default = Server; // 导出模块类型
|