@pisell/pisellos 2.3.72 → 2.3.74
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 +109 -65
- package/dist/modules/OpenData/types.d.ts +1 -0
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/utils.js +6 -1
- package/dist/modules/Quotation/index.d.ts +6 -0
- package/dist/modules/Quotation/index.js +75 -19
- package/dist/modules/ResourcePlanner/index.d.ts +0 -22
- package/dist/modules/ResourcePlanner/index.js +1 -180
- package/dist/modules/ResourcePlanner/localClock.d.ts +33 -0
- package/dist/modules/ResourcePlanner/localClock.js +183 -0
- package/dist/modules/ResourcePlanner/planner.d.ts +5 -14
- package/dist/modules/ResourcePlanner/planner.js +2019 -936
- package/dist/modules/ResourcePlanner/types.d.ts +346 -187
- package/dist/modules/ResourcePlanner/types.js +33 -1
- package/dist/plugins/request.d.ts +1 -0
- package/dist/server/index.d.ts +8 -2
- package/dist/server/index.js +206 -140
- 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 +48 -23
- package/dist/server/modules/order/index.d.ts +17 -7
- package/dist/server/modules/order/index.js +419 -207
- package/dist/server/modules/products/index.d.ts +8 -2
- package/dist/server/modules/products/index.js +167 -75
- package/dist/server/modules/resource/index.js +21 -13
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +4 -2
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +2 -1
- package/dist/solution/BookingTicket/utils/addProductDecision.js +3 -2
- package/dist/solution/UnifiedBookingSales/index.d.ts +110 -73
- package/dist/solution/UnifiedBookingSales/index.js +3349 -971
- package/dist/solution/UnifiedBookingSales/remoteOccupancyCache.d.ts +49 -0
- package/dist/solution/UnifiedBookingSales/remoteOccupancyCache.js +430 -0
- package/dist/solution/UnifiedBookingSales/types.d.ts +133 -76
- package/dist/solution/UnifiedBookingSales/types.js +4 -9
- package/lib/core/index.d.ts +7 -0
- package/lib/core/index.js +20 -2
- package/lib/model/strategy/adapter/promotion/index.js +0 -51
- package/lib/modules/OpenData/types.d.ts +1 -0
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/utils.js +5 -1
- package/lib/modules/Quotation/index.d.ts +6 -0
- package/lib/modules/Quotation/index.js +49 -5
- package/lib/modules/ResourcePlanner/index.d.ts +0 -22
- package/lib/modules/ResourcePlanner/index.js +0 -123
- package/lib/modules/ResourcePlanner/localClock.d.ts +33 -0
- package/lib/modules/ResourcePlanner/localClock.js +270 -0
- package/lib/modules/ResourcePlanner/planner.d.ts +5 -14
- package/lib/modules/ResourcePlanner/planner.js +1903 -798
- package/lib/modules/ResourcePlanner/types.d.ts +346 -187
- package/lib/modules/ResourcePlanner/types.js +19 -0
- package/lib/plugins/request.d.ts +1 -0
- package/lib/server/index.d.ts +8 -2
- package/lib/server/index.js +52 -17
- package/lib/server/modules/floor-plan/index.d.ts +4 -0
- package/lib/server/modules/floor-plan/index.js +54 -6
- package/lib/server/modules/menu/index.js +31 -5
- package/lib/server/modules/order/index.d.ts +17 -7
- package/lib/server/modules/order/index.js +197 -40
- package/lib/server/modules/products/index.d.ts +8 -2
- package/lib/server/modules/products/index.js +97 -24
- package/lib/server/modules/resource/index.js +7 -2
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +2 -1
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +2 -1
- package/lib/solution/BookingTicket/utils/addProductDecision.js +2 -0
- package/lib/solution/UnifiedBookingSales/index.d.ts +110 -73
- package/lib/solution/UnifiedBookingSales/index.js +2289 -374
- package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.d.ts +49 -0
- package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.js +376 -0
- package/lib/solution/UnifiedBookingSales/types.d.ts +133 -76
- package/lib/solution/UnifiedBookingSales/types.js +3 -2
- package/package.json +1 -1
|
@@ -192,7 +192,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
192
192
|
* Server 层负责传入完整 schedule 模块,Products 只负责把报价单计算结果转成价格响应形状。
|
|
193
193
|
*/
|
|
194
194
|
async setupQuotationPriceBridge(params) {
|
|
195
|
-
var _a;
|
|
195
|
+
var _a, _b, _c;
|
|
196
196
|
if (!this.core) {
|
|
197
197
|
this.logWarning("setupQuotationPriceBridge: core 尚未初始化");
|
|
198
198
|
return;
|
|
@@ -211,13 +211,13 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
211
211
|
this.quotationScheduleCacheSource = params.scheduleModule;
|
|
212
212
|
}
|
|
213
213
|
this.quotationPriceBridge.setScheduleResolver((id) => {
|
|
214
|
-
var _a2,
|
|
214
|
+
var _a2, _b2, _c2, _d, _e, _f;
|
|
215
215
|
const scheduleId = String(id);
|
|
216
216
|
if (this.quotationScheduleCache.has(scheduleId)) {
|
|
217
217
|
return this.quotationScheduleCache.get(scheduleId);
|
|
218
218
|
}
|
|
219
219
|
if (!this.quotationScheduleCacheLoaded) {
|
|
220
|
-
const scheduleList = ((
|
|
220
|
+
const scheduleList = ((_b2 = (_a2 = params.scheduleModule).getScheduleList) == null ? void 0 : _b2.call(_a2)) || [];
|
|
221
221
|
for (const schedule of scheduleList) {
|
|
222
222
|
this.quotationScheduleCache.set(String(schedule.id), schedule);
|
|
223
223
|
}
|
|
@@ -226,12 +226,21 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
226
226
|
if (this.quotationScheduleCache.has(scheduleId)) {
|
|
227
227
|
return this.quotationScheduleCache.get(scheduleId);
|
|
228
228
|
}
|
|
229
|
-
const schedules = ((_d = (
|
|
229
|
+
const schedules = ((_d = (_c2 = params.scheduleModule).getScheduleListByIds) == null ? void 0 : _d.call(_c2, [id])) || ((_f = (_e = params.scheduleModule).getScheduleByIds) == null ? void 0 : _f.call(_e, [id])) || [];
|
|
230
230
|
if (schedules[0])
|
|
231
231
|
this.quotationScheduleCache.set(scheduleId, schedules[0]);
|
|
232
232
|
return schedules[0];
|
|
233
233
|
});
|
|
234
234
|
}
|
|
235
|
+
if (params.onQuotationUpdated) {
|
|
236
|
+
this.quotationBridgeUpdatedCallback = params.onQuotationUpdated;
|
|
237
|
+
}
|
|
238
|
+
(_c = (_b = this.quotationPriceBridge).setQuotationListUpdatedListener) == null ? void 0 : _c.call(_b, () => {
|
|
239
|
+
var _a2;
|
|
240
|
+
this.quotationBridgeLoadedKey = this.getQuotationBridgeScopeKey();
|
|
241
|
+
this.clearPriceCache();
|
|
242
|
+
(_a2 = this.quotationBridgeUpdatedCallback) == null ? void 0 : _a2.call(this);
|
|
243
|
+
});
|
|
235
244
|
await this.refreshQuotationPriceBridge({ customer_id: params.customer_id });
|
|
236
245
|
}
|
|
237
246
|
/**
|
|
@@ -798,17 +807,20 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
798
807
|
*/
|
|
799
808
|
clearPriceCache() {
|
|
800
809
|
this.productsPriceCache.clear();
|
|
810
|
+
this.quotationScheduleCache.clear();
|
|
811
|
+
this.quotationScheduleCacheLoaded = false;
|
|
801
812
|
console.log("[ProductsModule] 🗑️ 商品价格缓存已清空");
|
|
802
813
|
}
|
|
803
814
|
/**
|
|
804
815
|
* 通过 ProductDataSource SSE 加载完整商品列表
|
|
805
816
|
*/
|
|
806
|
-
async loadProductsByServer() {
|
|
817
|
+
async loadProductsByServer(options = {}) {
|
|
807
818
|
if (!this.productDataSource) {
|
|
808
819
|
this.logWarning("loadProductsByServer: ProductDataSource 不可用");
|
|
809
820
|
return [];
|
|
810
821
|
}
|
|
811
|
-
|
|
822
|
+
const trigger = options.trigger || "unknown";
|
|
823
|
+
this.logInfo("开始通过 DataSource SSE 加载商品列表", { trigger });
|
|
812
824
|
const t0 = performance.now();
|
|
813
825
|
try {
|
|
814
826
|
const tSSE = performance.now();
|
|
@@ -816,6 +828,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
816
828
|
const list = productList || [];
|
|
817
829
|
(0, import_product.perfMark)("loadProductsByServer.SSE", performance.now() - tSSE, { count: list.length });
|
|
818
830
|
this.logInfo("通过 DataSource SSE 加载商品列表成功", {
|
|
831
|
+
trigger,
|
|
819
832
|
productCount: list.length,
|
|
820
833
|
duration: `${Math.round(performance.now() - t0)}ms`
|
|
821
834
|
});
|
|
@@ -829,6 +842,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
829
842
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
830
843
|
console.error("[Products] 加载商品数据失败:", error);
|
|
831
844
|
this.logError("通过 DataSource SSE 加载商品列表失败", {
|
|
845
|
+
trigger,
|
|
832
846
|
duration: `${duration}ms`,
|
|
833
847
|
error: errorMessage
|
|
834
848
|
});
|
|
@@ -1019,7 +1033,9 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1019
1033
|
async refreshProducts() {
|
|
1020
1034
|
const tTotal = performance.now();
|
|
1021
1035
|
this.logInfo("refreshProducts 开始");
|
|
1022
|
-
const products = await this.loadProductsByServer(
|
|
1036
|
+
const products = await this.loadProductsByServer({
|
|
1037
|
+
trigger: "product_sync"
|
|
1038
|
+
});
|
|
1023
1039
|
if (products && products.length > 0) {
|
|
1024
1040
|
this.store.list = products;
|
|
1025
1041
|
this.syncProductsMap();
|
|
@@ -1064,18 +1080,23 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1064
1080
|
this.logWarning("loadProductsFromIndexDB: dbManager 不可用");
|
|
1065
1081
|
return [];
|
|
1066
1082
|
}
|
|
1083
|
+
const startedAt = performance.now();
|
|
1067
1084
|
try {
|
|
1068
|
-
const t0 = performance.now();
|
|
1069
1085
|
const products = await this.dbManager.getAll(INDEXDB_STORE_NAME);
|
|
1070
|
-
|
|
1086
|
+
const durationMs = +(performance.now() - startedAt).toFixed(2);
|
|
1087
|
+
(0, import_product.perfMark)("loadProductsFromIndexDB", durationMs, { count: (products == null ? void 0 : products.length) ?? 0 });
|
|
1071
1088
|
this.logInfo("从 IndexDB 加载商品数据", {
|
|
1072
|
-
productCount: (products == null ? void 0 : products.length) ?? 0
|
|
1089
|
+
productCount: (products == null ? void 0 : products.length) ?? 0,
|
|
1090
|
+
durationMs
|
|
1073
1091
|
});
|
|
1074
1092
|
return products || [];
|
|
1075
1093
|
} catch (error) {
|
|
1076
1094
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1077
1095
|
console.error("[Products] 从 IndexDB 读取数据失败:", error);
|
|
1078
|
-
this.logError("从 IndexDB 读取数据失败", {
|
|
1096
|
+
this.logError("从 IndexDB 读取数据失败", {
|
|
1097
|
+
durationMs: +(performance.now() - startedAt).toFixed(2),
|
|
1098
|
+
error: errorMessage
|
|
1099
|
+
});
|
|
1079
1100
|
return [];
|
|
1080
1101
|
}
|
|
1081
1102
|
}
|
|
@@ -1103,22 +1124,54 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1103
1124
|
this.logWarning("replaceProductsSnapshotInIndexDB: dbManager 不可用");
|
|
1104
1125
|
return;
|
|
1105
1126
|
}
|
|
1127
|
+
const enqueuedAt = performance.now();
|
|
1128
|
+
let queueWaitMs = 0;
|
|
1129
|
+
let clearDurationMs = 0;
|
|
1130
|
+
let writeDurationMs = 0;
|
|
1106
1131
|
try {
|
|
1107
1132
|
await this.runInProductIndexDBSaveQueue(async () => {
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1133
|
+
const operationStartedAt = performance.now();
|
|
1134
|
+
queueWaitMs = +(operationStartedAt - enqueuedAt).toFixed(2);
|
|
1135
|
+
this.logInfo("replaceProductsSnapshotInIndexDB 开始", {
|
|
1136
|
+
source,
|
|
1137
|
+
productCount: products.length,
|
|
1138
|
+
queueWaitMs
|
|
1139
|
+
});
|
|
1140
|
+
const clearStartedAt = performance.now();
|
|
1141
|
+
try {
|
|
1142
|
+
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
1143
|
+
} finally {
|
|
1144
|
+
clearDurationMs = +(performance.now() - clearStartedAt).toFixed(2);
|
|
1145
|
+
}
|
|
1111
1146
|
if (products.length > 0) {
|
|
1112
|
-
|
|
1147
|
+
const writeStartedAt = performance.now();
|
|
1148
|
+
try {
|
|
1149
|
+
await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, products);
|
|
1150
|
+
} finally {
|
|
1151
|
+
writeDurationMs = +(performance.now() - writeStartedAt).toFixed(2);
|
|
1152
|
+
}
|
|
1113
1153
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1154
|
+
const executeDurationMs = +(performance.now() - operationStartedAt).toFixed(2);
|
|
1155
|
+
(0, import_product.perfMark)("replaceProductsSnapshotInIndexDB", executeDurationMs, { count: products.length });
|
|
1156
|
+
this.logInfo("replaceProductsSnapshotInIndexDB 完成", {
|
|
1157
|
+
source,
|
|
1158
|
+
productCount: products.length,
|
|
1159
|
+
queueWaitMs,
|
|
1160
|
+
clearDurationMs,
|
|
1161
|
+
writeDurationMs,
|
|
1162
|
+
executeDurationMs,
|
|
1163
|
+
totalDurationMs: +(performance.now() - enqueuedAt).toFixed(2)
|
|
1164
|
+
});
|
|
1116
1165
|
});
|
|
1117
1166
|
} catch (error) {
|
|
1118
1167
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1119
1168
|
this.logError("全量保存商品到 IndexDB 失败", {
|
|
1120
1169
|
source,
|
|
1121
1170
|
productCount: products.length,
|
|
1171
|
+
queueWaitMs,
|
|
1172
|
+
clearDurationMs,
|
|
1173
|
+
writeDurationMs,
|
|
1174
|
+
totalDurationMs: +(performance.now() - enqueuedAt).toFixed(2),
|
|
1122
1175
|
error: errorMessage
|
|
1123
1176
|
});
|
|
1124
1177
|
}
|
|
@@ -1200,6 +1253,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1200
1253
|
source: "IndexDB"
|
|
1201
1254
|
});
|
|
1202
1255
|
this.logInfo("预加载完成(从 IndexDB)", {
|
|
1256
|
+
trigger: "preload",
|
|
1203
1257
|
productCount: cachedData.length,
|
|
1204
1258
|
duration: `${Math.round(performance.now() - tTotal)}ms`,
|
|
1205
1259
|
source: "IndexDB"
|
|
@@ -1215,7 +1269,9 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1215
1269
|
this.logWarning("从 IndexDB 加载数据失败,准备从服务器加载", { error: errorMessage });
|
|
1216
1270
|
}
|
|
1217
1271
|
const tServer = performance.now();
|
|
1218
|
-
const products = await this.loadProductsByServer(
|
|
1272
|
+
const products = await this.loadProductsByServer({
|
|
1273
|
+
trigger: "preload"
|
|
1274
|
+
});
|
|
1219
1275
|
(0, import_product.perfMark)("preload.loadFromServer", performance.now() - tServer, { count: (products == null ? void 0 : products.length) ?? 0 });
|
|
1220
1276
|
if (products && products.length > 0) {
|
|
1221
1277
|
this.store.list = products;
|
|
@@ -1228,6 +1284,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1228
1284
|
source: "Server"
|
|
1229
1285
|
});
|
|
1230
1286
|
this.logInfo("预加载完成(从服务器)", {
|
|
1287
|
+
trigger: "preload",
|
|
1231
1288
|
productCount: products.length,
|
|
1232
1289
|
duration: `${Math.round(performance.now() - tTotal)}ms`,
|
|
1233
1290
|
source: "Server"
|
|
@@ -1592,17 +1649,31 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1592
1649
|
* 拿到完整数据后一次性替换 store,清除价格缓存,触发 onProductsSyncCompleted
|
|
1593
1650
|
* @returns 刷新后的商品列表
|
|
1594
1651
|
*/
|
|
1595
|
-
async silentRefresh() {
|
|
1652
|
+
async silentRefresh(options = {}) {
|
|
1596
1653
|
const t0 = performance.now();
|
|
1597
1654
|
const now = Date.now();
|
|
1598
|
-
const
|
|
1599
|
-
const
|
|
1600
|
-
|
|
1655
|
+
const trigger = options.trigger || "background";
|
|
1656
|
+
const elapsedSincePreloadMs = now - this.lastPreloadCompletedAtMs;
|
|
1657
|
+
const elapsedSinceFullFetchMs = now - this.lastServerFullFetchAtMs;
|
|
1658
|
+
if (this.lastPreloadCompletedAtMs > 0 && elapsedSincePreloadMs < PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS || this.lastServerFullFetchAtMs > 0 && elapsedSinceFullFetchMs < PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS) {
|
|
1659
|
+
this.logInfo("silentRefresh 跳过全量 SSE", {
|
|
1660
|
+
trigger,
|
|
1661
|
+
reason: "within_min_interval",
|
|
1662
|
+
minIntervalMs: PRODUCT_SILENT_REFRESH_MIN_INTERVAL_MS,
|
|
1663
|
+
elapsedSincePreloadMs,
|
|
1664
|
+
elapsedSinceFullFetchMs,
|
|
1665
|
+
productCount: this.store.list.length
|
|
1666
|
+
});
|
|
1601
1667
|
return this.store.list;
|
|
1602
1668
|
}
|
|
1603
|
-
this.logInfo("silentRefresh 开始"
|
|
1669
|
+
this.logInfo("silentRefresh 开始", {
|
|
1670
|
+
trigger,
|
|
1671
|
+
elapsedSincePreloadMs,
|
|
1672
|
+
elapsedSinceFullFetchMs,
|
|
1673
|
+
productCount: this.store.list.length
|
|
1674
|
+
});
|
|
1604
1675
|
try {
|
|
1605
|
-
const products = await this.loadProductsByServer();
|
|
1676
|
+
const products = await this.loadProductsByServer({ trigger });
|
|
1606
1677
|
if (products && products.length > 0) {
|
|
1607
1678
|
this.store.list = products;
|
|
1608
1679
|
this.syncProductsMap();
|
|
@@ -1610,6 +1681,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1610
1681
|
this.core.effects.emit(import_types.ProductsHooks.onProductsChanged, this.store.list);
|
|
1611
1682
|
await this.core.effects.emit(import_types.ProductsHooks.onProductsSyncCompleted, null);
|
|
1612
1683
|
this.logInfo("silentRefresh 完成", {
|
|
1684
|
+
trigger,
|
|
1613
1685
|
productCount: products.length,
|
|
1614
1686
|
duration: `${Math.round(performance.now() - t0)}ms`
|
|
1615
1687
|
});
|
|
@@ -1621,6 +1693,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1621
1693
|
} catch (error) {
|
|
1622
1694
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1623
1695
|
this.logError("silentRefresh 失败", {
|
|
1696
|
+
trigger,
|
|
1624
1697
|
duration: `${Math.round(performance.now() - t0)}ms`,
|
|
1625
1698
|
error: errorMessage
|
|
1626
1699
|
});
|
|
@@ -88,13 +88,18 @@ var ResourceModule = class extends import_BaseModule.BaseModule {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
async preload() {
|
|
91
|
-
await this.setupResourceSync();
|
|
92
91
|
const cachedResources = await this.loadResourcesFromSQLite();
|
|
93
92
|
if (cachedResources.length > 0) {
|
|
94
93
|
this.store.list = (0, import_lodash_es.cloneDeep)(cachedResources).map((item) => this.normalizeResource(item));
|
|
95
94
|
this.syncResourcesMap();
|
|
96
95
|
await this.safeEmit(import_types.ResourceHooks.onResourcesChanged, this.store.list);
|
|
97
|
-
|
|
96
|
+
void this.setupResourceSync().catch((error) => {
|
|
97
|
+
this.logError("后台初始化资源同步失败", error);
|
|
98
|
+
});
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
await this.setupResourceSync();
|
|
102
|
+
if (this.store.list.length === 0) {
|
|
98
103
|
const resources = await this.loadResourcesByServer();
|
|
99
104
|
if (resources.length > 0) {
|
|
100
105
|
this.store.list = (0, import_lodash_es.cloneDeep)(resources).map((item) => this.normalizeResource(item));
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 |
|
|
329
|
+
weekNum: 0 | 2 | 1 | 3 | 4 | 5 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -1398,7 +1398,8 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1398
1398
|
date,
|
|
1399
1399
|
presetStartTime: (extra == null ? void 0 : extra.presetStartTime) ?? (0, import_BookingContext.derivePresetStartTimeFromDate)(date),
|
|
1400
1400
|
customerId: orderCustomerId,
|
|
1401
|
-
...extra || {}
|
|
1401
|
+
...extra || {},
|
|
1402
|
+
channel: this.getSubmitOrderSalesChannel()
|
|
1402
1403
|
};
|
|
1403
1404
|
}
|
|
1404
1405
|
/**
|
|
@@ -5,7 +5,7 @@ import type { OrderProduct, OrderProductIdentity, AddProductBookingInput } from
|
|
|
5
5
|
* cart.addProduct 两阶段决策(与 ticketBooking `handleSelectProduct` 对齐):
|
|
6
6
|
*
|
|
7
7
|
* 1. `requiresDetail`:规格 / SKU / 套餐 / Session / 称重弹窗(门禁:`isOpenDetailModal` / `cartDetailValue` / `open_sold_weight`)
|
|
8
|
-
* 2. `requiresBookingEdit`:资源 /
|
|
8
|
+
* 2. `requiresBookingEdit`:资源 / 时间编辑抽屉(kiosk 强制进入;其他渠道由 `getIsAutoClose` 决定)
|
|
9
9
|
* 3. `add`:两关均通过,直接 transform + 加车
|
|
10
10
|
*/
|
|
11
11
|
export type AddProductDecision = {
|
|
@@ -65,6 +65,7 @@ export interface AddProductDecideContext extends BookingCalcContext {
|
|
|
65
65
|
type?: 'select' | 'detail';
|
|
66
66
|
quantity?: number;
|
|
67
67
|
customerId?: number | string;
|
|
68
|
+
channel?: string;
|
|
68
69
|
}
|
|
69
70
|
/**
|
|
70
71
|
* 统一补齐预约商品的运行态字段。
|
|
@@ -57,6 +57,8 @@ function needsSpecDetailModal(item) {
|
|
|
57
57
|
function needsBookingEdit(cacheItem, ctx) {
|
|
58
58
|
if (isNormalBookingProduct(cacheItem))
|
|
59
59
|
return false;
|
|
60
|
+
if ((ctx == null ? void 0 : ctx.channel) === "kiosk")
|
|
61
|
+
return true;
|
|
60
62
|
const isAutoAllocationOn = (ctx == null ? void 0 : ctx.isAutoAllocationOn) || (() => true);
|
|
61
63
|
return !(0, import_BookingContext.getIsAutoClose)(cacheItem, isAutoAllocationOn);
|
|
62
64
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type { Module } from '../../types';
|
|
1
|
+
import type { Module, ModuleOptions, PisellCore } from '../../types';
|
|
2
2
|
import type { ProductData } from '../../modules';
|
|
3
3
|
import type { OpenDataConfig } from '../../modules/OpenData';
|
|
4
4
|
import type { LoadScheduleAvailableDateParams, ScheduleItem } from '../../modules/Schedule/types';
|
|
5
5
|
import type { ProductListLoadProductsParams } from '../../modules/ProductList';
|
|
6
|
-
import type {
|
|
7
|
-
import type {
|
|
6
|
+
import type { AvailabilityDateRange, AvailabilityOccupancy, AvailabilityProduct, AvailabilityResource, GetProductTimeRangesRequest } from '../../modules/ResourcePlanner';
|
|
7
|
+
import type { AvailabilityContextRef, ContextualAvailabilityQuery, ContextualAvailabilityQueryResult, ContextualCommitAvailabilitySelectionParams, ContextualProductTimeRangeGroup, UnifiedBookingSalesAddRetailProductParams, UnifiedBookingSalesApplyPlannerDiscountsParams, UnifiedBookingSalesCommitAvailabilitySelectionResult, UnifiedBookingSalesDiscountResult, UnifiedBookingSalesLoadProductsByScheduleDateParams, UnifiedBookingSalesLoadOpenDataParams, UnifiedBookingSalesPrepareAvailabilityProjectionParams, UnifiedBookingSalesStageRetailProductsParams, UnifiedBookingSalesState } from './types';
|
|
8
8
|
import { BookingTicket } from '../BookingTicket';
|
|
9
9
|
export * from './types';
|
|
10
|
+
export { AvailabilityError } from '../../modules/ResourcePlanner';
|
|
10
11
|
/**
|
|
11
12
|
* Converts Rules/Order discount internals into a small UI-facing diagnostic. The result keeps
|
|
12
13
|
* candidate-card state separate from line-level applications: a selected card is not proof that
|
|
@@ -22,39 +23,37 @@ export declare function buildPlannerDiscountResult(params: {
|
|
|
22
23
|
preferredDiscountId?: number | string;
|
|
23
24
|
preferredDiscountFound?: boolean;
|
|
24
25
|
}): UnifiedBookingSalesDiscountResult;
|
|
25
|
-
/** Converts
|
|
26
|
-
export declare function
|
|
26
|
+
/** Converts ProductList and schedule records into the pure Availability vocabulary. */
|
|
27
|
+
export declare function normalizeProductForAvailability(product: ProductData | Record<string, any>, scheduleList?: ScheduleItem[], fixedOffsetMinutes?: number): AvailabilityProduct;
|
|
27
28
|
/**
|
|
28
29
|
* Materializes resource work windows locally from v2's schedule ids, then keeps its flat
|
|
29
|
-
* event_list as
|
|
30
|
+
* event_list as resource occupancy records. This deliberately avoids the older API's times -> event_list
|
|
30
31
|
* response nesting and lets one resource response serve any requested date range.
|
|
31
32
|
*/
|
|
32
|
-
export declare function
|
|
33
|
+
export declare function buildAvailabilityResourcesFromV2(params: {
|
|
33
34
|
rawResources: Record<string, any>[];
|
|
34
35
|
scheduleList: ScheduleItem[];
|
|
35
|
-
dateRange?:
|
|
36
|
+
dateRange?: AvailabilityDateRange;
|
|
37
|
+
fixedOffsetMinutes?: number;
|
|
36
38
|
}): {
|
|
37
|
-
resources:
|
|
38
|
-
|
|
39
|
+
resources: AvailabilityResource[];
|
|
40
|
+
resourceOccupancies: AvailabilityOccupancy[];
|
|
39
41
|
};
|
|
40
42
|
/** Combines URL-locked resources with every resource referenced by the selected products. */
|
|
41
|
-
export declare function
|
|
42
|
-
|
|
43
|
-
export declare function
|
|
44
|
-
assignment:
|
|
45
|
-
product:
|
|
43
|
+
export declare function collectAvailabilityResourceIds(products: AvailabilityProduct[], explicitResourceIds?: Array<number | string>): Array<number | string>;
|
|
44
|
+
export declare function buildAvailabilityLineIdentity(product: Record<string, any>): Record<string, any>;
|
|
45
|
+
export declare function buildBookingFromAvailabilityAssignment(params: {
|
|
46
|
+
assignment: Record<string, any>;
|
|
47
|
+
product: AvailabilityProduct;
|
|
48
|
+
timezone?: string;
|
|
49
|
+
fixedOffsetMinutes?: number;
|
|
46
50
|
}): Record<string, any>;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
export declare function buildBookingFromAssignments(params: {
|
|
53
|
-
assignments: ResourcePlannerAssignment[];
|
|
54
|
-
product: ResourcePlannerProduct;
|
|
51
|
+
export declare function buildBookingFromAvailabilityAssignments(params: {
|
|
52
|
+
assignments: Record<string, any>[];
|
|
53
|
+
product: AvailabilityProduct;
|
|
54
|
+
timezone?: string;
|
|
55
|
+
fixedOffsetMinutes?: number;
|
|
55
56
|
}): Record<string, any>;
|
|
56
|
-
/** Builds the exact identity BaseSales needs to remove only this solution's order lines. */
|
|
57
|
-
export declare function buildPlannerLineIdentity(product: Record<string, any>): Record<string, any>;
|
|
58
57
|
export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
59
58
|
protected defaultName: string;
|
|
60
59
|
protected defaultVersion: string;
|
|
@@ -63,7 +62,52 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
63
62
|
private openDataTarget;
|
|
64
63
|
private loadOpenDataInFlight;
|
|
65
64
|
private loadOpenDataInFlightTarget;
|
|
65
|
+
private availabilityRuntimeOffsetMinutes;
|
|
66
|
+
private availabilityScheduleCatalog;
|
|
67
|
+
private availabilityProjectionSequence;
|
|
68
|
+
private availabilityContextSequence;
|
|
69
|
+
private availabilityLifecycleGeneration;
|
|
70
|
+
private availabilityContextRegistry;
|
|
71
|
+
private availabilityProjectionPool;
|
|
72
|
+
private availabilityPrepareInFlight;
|
|
73
|
+
private availabilityProjectionRefreshInFlight;
|
|
74
|
+
private availabilityRemoteOccupancyCache;
|
|
75
|
+
private availabilityRemoteResourceQueryInFlight;
|
|
76
|
+
private availabilityRemoteResourceQuerySequence;
|
|
77
|
+
private availabilityRemoteResourceEpoch;
|
|
78
|
+
private availabilityCommitLocks;
|
|
79
|
+
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
66
80
|
protected getSubmitOrderSalesChannel(): string;
|
|
81
|
+
private createAvailabilityFacadeError;
|
|
82
|
+
private getAvailabilityScopeDescriptor;
|
|
83
|
+
private normalizeAvailabilityIdList;
|
|
84
|
+
private normalizeAvailabilityStringList;
|
|
85
|
+
private normalizeAvailabilityPrepareDescriptor;
|
|
86
|
+
private resolveAvailabilityPrepareDefaults;
|
|
87
|
+
private buildAvailabilityPrepareKey;
|
|
88
|
+
private clearAvailabilityRemoteResourceState;
|
|
89
|
+
private buildAvailabilityRemoteResourceScopeKey;
|
|
90
|
+
private buildAvailabilityRemoteResourceQueryKey;
|
|
91
|
+
setOtherParams(params: Record<string, any>, { cover }?: {
|
|
92
|
+
cover?: boolean;
|
|
93
|
+
}): Promise<void>;
|
|
94
|
+
destroy(): Promise<void>;
|
|
95
|
+
private createAvailabilityContextId;
|
|
96
|
+
private buildAvailabilityProjectionKey;
|
|
97
|
+
private getAvailabilityRuntimeOffsetMinutes;
|
|
98
|
+
private getAvailabilityRuntimeDateTime;
|
|
99
|
+
private cloneAvailabilityPrepareParams;
|
|
100
|
+
private getAvailabilityDurationCandidateAnchorAt;
|
|
101
|
+
private createAvailabilityContextRef;
|
|
102
|
+
private emitAvailabilityDiagnostic;
|
|
103
|
+
private touchAvailabilityContext;
|
|
104
|
+
private touchAvailabilityProjection;
|
|
105
|
+
private removeAvailabilityProjection;
|
|
106
|
+
private removeAvailabilityContext;
|
|
107
|
+
private evictAvailabilityProjectionPool;
|
|
108
|
+
private evictAvailabilityContextRegistry;
|
|
109
|
+
private invalidateAvailabilityContextsAfterCommit;
|
|
110
|
+
private resetAvailabilityProjectionState;
|
|
67
111
|
protected isSessionStoragePersistEnabled(): boolean;
|
|
68
112
|
protected shouldUseSessionStorageForSubModule(moduleName?: string): boolean;
|
|
69
113
|
/**
|
|
@@ -133,17 +177,10 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
133
177
|
* diagnostic boundary for new booking skins: no pricing logic is duplicated in the planner.
|
|
134
178
|
*/
|
|
135
179
|
applyPlannerDiscounts(params?: UnifiedBookingSalesApplyPlannerDiscountsParams): Promise<UnifiedBookingSalesDiscountResult>;
|
|
136
|
-
/** ResourcePlanner is a required child module; fail early instead of producing partial availability. */
|
|
137
|
-
private getPlanner;
|
|
138
180
|
private buildUnifiedOrderProduct;
|
|
139
181
|
/** Replacing a staged selection is idempotent and never removes unrelated cart lines. */
|
|
140
182
|
private removeExistingStagedLines;
|
|
141
183
|
private stageProducts;
|
|
142
|
-
/**
|
|
143
|
-
* Adds the current product choice to an otherwise clean planner cart without creating bookings.
|
|
144
|
-
* This separates "what the customer wants" from the later time/resource confirmation step.
|
|
145
|
-
*/
|
|
146
|
-
stagePlannerProducts(params: UnifiedBookingSalesStagePlannerProductsParams): Promise<Record<string, any> | null>;
|
|
147
184
|
/**
|
|
148
185
|
* Adds ordinary retail products without asking ResourcePlanner for booking facts.
|
|
149
186
|
* Its staged lines have separate ownership so planner and retail skins can coexist safely.
|
|
@@ -155,50 +192,50 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
155
192
|
* "replace the staged selection" for demo and wizard-like callers.
|
|
156
193
|
*/
|
|
157
194
|
addRetailProduct(params: UnifiedBookingSalesAddRetailProductParams): Promise<Record<string, any>[]>;
|
|
158
|
-
|
|
159
|
-
private
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
*/
|
|
166
|
-
private ensurePlannerSchedulesForResources;
|
|
195
|
+
private normalizeAvailabilityDateRange;
|
|
196
|
+
private assertAvailabilityPrepareParams;
|
|
197
|
+
private captureAvailabilityScheduleCatalog;
|
|
198
|
+
/** Returns the solution-lifetime schedule snapshot captured after initialization. */
|
|
199
|
+
private getAvailabilityScheduleCatalog;
|
|
200
|
+
private buildAvailabilityOperatingHoursSnapshot;
|
|
201
|
+
private loadAvailabilityProducts;
|
|
167
202
|
/**
|
|
168
203
|
* Fetches resource metadata plus flat occupied events. Work windows are intentionally derived
|
|
169
|
-
* locally in
|
|
204
|
+
* locally in buildAvailabilityResourcesFromV2 from /schedule, rather than requested from the legacy
|
|
170
205
|
* resource dates endpoint.
|
|
171
206
|
*/
|
|
172
|
-
private
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
private
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
207
|
+
private fetchAvailabilityResourcesV2;
|
|
208
|
+
private fetchAndPublishAvailabilityResourcesV2;
|
|
209
|
+
private refreshAvailabilityRemoteResourceQuery;
|
|
210
|
+
private loadAvailabilityResources;
|
|
211
|
+
private resolveEditingOccupancyExclusions;
|
|
212
|
+
private occupancyIsExcluded;
|
|
213
|
+
private collectCartResourceOccupancies;
|
|
214
|
+
private getCurrentOrderRevision;
|
|
215
|
+
private getAvailabilityContextEntry;
|
|
216
|
+
private getAvailabilityProjectionByKey;
|
|
217
|
+
private getActiveAvailabilityProjectionEntry;
|
|
218
|
+
private decorateAvailabilityCandidate;
|
|
219
|
+
private assertAvailabilityCandidateFreshness;
|
|
220
|
+
private assertContextualQueryFreshness;
|
|
221
|
+
private storeAvailabilityProjectionEntry;
|
|
222
|
+
private buildAvailabilityProjectionSnapshot;
|
|
223
|
+
private getSharedPreparedAvailabilitySnapshot;
|
|
224
|
+
private refreshAvailabilityContextProjection;
|
|
225
|
+
private ensureAvailabilityContextProjection;
|
|
226
|
+
private tryAcquireAvailabilityCommitLock;
|
|
227
|
+
private releaseAvailabilityCommitLock;
|
|
228
|
+
/** IO boundary: loads catalog, schedules, resources, occupancies, and registers one context. */
|
|
229
|
+
prepareAvailabilityProjection(params: UnifiedBookingSalesPrepareAvailabilityProjectionParams): Promise<AvailabilityContextRef>;
|
|
230
|
+
/** Pure configuration calculation over the current context projection. */
|
|
231
|
+
getProductTimeRanges(contextId: string, request?: GetProductTimeRangesRequest): Promise<ContextualProductTimeRangeGroup[]>;
|
|
232
|
+
/** Thin facade: auto-refresh on cart drift, then delegate to the pure projection query. */
|
|
233
|
+
queryBookingAvailability(contextId: string, request: ContextualAvailabilityQuery): Promise<ContextualAvailabilityQueryResult>;
|
|
234
|
+
releaseAvailabilityContext(contextId: string): void;
|
|
235
|
+
private assertAvailabilityCommitWriteCAS;
|
|
236
|
+
private findProductLineByUid;
|
|
237
|
+
private findLinkedBooking;
|
|
238
|
+
/** Revalidates against the latest landed occupancy cache, then mutates exactly one product line. */
|
|
239
|
+
commitAvailabilitySelection(contextId: string, params: ContextualCommitAvailabilitySelectionParams): Promise<UnifiedBookingSalesCommitAvailabilitySelectionResult>;
|
|
203
240
|
}
|
|
204
241
|
export declare const UnifiedBookingSales: typeof UnifiedBookingSalesImpl;
|