@pisell/pisellos 2.2.93 → 2.2.94
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 +0 -1
- package/dist/core/index.js +0 -7
- package/dist/modules/Customer/index.d.ts +0 -1
- package/dist/modules/Customer/index.js +12 -28
- package/dist/plugins/app-types/app/app.d.ts +1 -0
- package/dist/server/index.d.ts +55 -5
- package/dist/server/index.js +832 -236
- package/dist/server/modules/index.d.ts +6 -0
- package/dist/server/modules/index.js +7 -0
- package/dist/server/modules/order/index.d.ts +87 -0
- package/dist/server/modules/order/index.js +916 -0
- package/dist/server/modules/order/types.d.ts +530 -0
- package/dist/server/modules/order/types.js +141 -0
- package/dist/server/modules/order/utils/filterBookings.d.ts +6 -0
- package/dist/server/modules/order/utils/filterBookings.js +350 -0
- package/dist/server/modules/order/utils/filterOrders.d.ts +15 -0
- package/dist/server/modules/order/utils/filterOrders.js +226 -0
- package/dist/server/modules/products/index.d.ts +24 -19
- package/dist/server/modules/products/index.js +600 -429
- package/dist/server/modules/products/types.d.ts +0 -1
- package/dist/server/modules/resource/index.d.ts +88 -0
- package/dist/server/modules/resource/index.js +1202 -0
- package/dist/server/modules/resource/types.d.ts +121 -0
- package/dist/server/modules/resource/types.js +47 -0
- package/dist/server/utils/product.d.ts +0 -4
- package/dist/server/utils/product.js +0 -34
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/Sales/index.d.ts +96 -0
- package/dist/solution/Sales/index.js +510 -0
- package/dist/solution/Sales/types.d.ts +65 -0
- package/dist/solution/Sales/types.js +26 -0
- package/dist/solution/index.d.ts +1 -0
- package/dist/solution/index.js +2 -1
- package/dist/types/index.d.ts +0 -2
- package/lib/core/index.d.ts +0 -1
- package/lib/core/index.js +0 -4
- package/lib/modules/Customer/index.d.ts +0 -1
- package/lib/modules/Customer/index.js +6 -21
- package/lib/plugins/app-types/app/app.d.ts +1 -0
- package/lib/server/index.d.ts +55 -5
- package/lib/server/index.js +350 -28
- package/lib/server/modules/index.d.ts +6 -0
- package/lib/server/modules/index.js +16 -2
- package/lib/server/modules/order/index.d.ts +87 -0
- package/lib/server/modules/order/index.js +543 -0
- package/lib/server/modules/order/types.d.ts +530 -0
- package/lib/server/modules/order/types.js +34 -0
- package/lib/server/modules/order/utils/filterBookings.d.ts +6 -0
- package/lib/server/modules/order/utils/filterBookings.js +320 -0
- package/lib/server/modules/order/utils/filterOrders.d.ts +15 -0
- package/lib/server/modules/order/utils/filterOrders.js +197 -0
- package/lib/server/modules/products/index.d.ts +24 -19
- package/lib/server/modules/products/index.js +150 -151
- package/lib/server/modules/products/types.d.ts +0 -1
- package/lib/server/modules/resource/index.d.ts +88 -0
- package/lib/server/modules/resource/index.js +571 -0
- package/lib/server/modules/resource/types.d.ts +121 -0
- package/lib/server/modules/resource/types.js +35 -0
- package/lib/server/utils/product.d.ts +0 -4
- package/lib/server/utils/product.js +0 -27
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/Sales/index.d.ts +96 -0
- package/lib/solution/Sales/index.js +358 -0
- package/lib/solution/Sales/types.d.ts +65 -0
- package/lib/solution/Sales/types.js +35 -0
- package/lib/solution/index.d.ts +1 -0
- package/lib/solution/index.js +3 -1
- package/lib/types/index.d.ts +0 -2
- package/package.json +1 -1
|
@@ -177,7 +177,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
177
177
|
duration: `${duration}ms`,
|
|
178
178
|
error: errorMessage
|
|
179
179
|
});
|
|
180
|
-
|
|
180
|
+
throw error;
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
183
|
/**
|
|
@@ -186,70 +186,13 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
186
186
|
* 缓存的是已经应用了价格的完整商品列表,避免重复转换
|
|
187
187
|
* @param schedule_date 日期
|
|
188
188
|
* @param extraContext 额外的上下文数据(可选,由 Server 层传入)
|
|
189
|
-
* @param options 可选参数
|
|
190
|
-
* @param options.changedIds 变更的商品 IDs,非空时仅对这些商品增量执行 prepare 并更新缓存
|
|
191
189
|
* @returns 应用了价格的商品列表
|
|
192
190
|
*/
|
|
193
|
-
async getProductsWithPrice(schedule_date, extraContext
|
|
191
|
+
async getProductsWithPrice(schedule_date, extraContext) {
|
|
194
192
|
const t0 = performance.now();
|
|
195
193
|
const cacheKey = schedule_date;
|
|
196
|
-
const changedIds = options == null ? void 0 : options.changedIds;
|
|
197
194
|
if (this.productsPriceCache.has(cacheKey)) {
|
|
198
195
|
const cachedProducts = this.productsPriceCache.get(cacheKey);
|
|
199
|
-
if (changedIds && changedIds.length > 0) {
|
|
200
|
-
this.logInfo("商品价格缓存命中,增量更新变更商品", {
|
|
201
|
-
cacheKey,
|
|
202
|
-
changedIds,
|
|
203
|
-
cachedProductCount: cachedProducts.length
|
|
204
|
-
});
|
|
205
|
-
try {
|
|
206
|
-
const updatedProducts = await this.prepareProductsWithPrice(
|
|
207
|
-
schedule_date,
|
|
208
|
-
extraContext,
|
|
209
|
-
{ productIds: changedIds }
|
|
210
|
-
);
|
|
211
|
-
if (updatedProducts.length > 0) {
|
|
212
|
-
const updatedMap = new Map(updatedProducts.map((p) => [p.id, p]));
|
|
213
|
-
const mergedCache = [];
|
|
214
|
-
for (const p of cachedProducts) {
|
|
215
|
-
if (updatedMap.has(p.id)) {
|
|
216
|
-
mergedCache.push(updatedMap.get(p.id));
|
|
217
|
-
updatedMap.delete(p.id);
|
|
218
|
-
} else {
|
|
219
|
-
mergedCache.push(p);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
for (const p of updatedMap.values()) {
|
|
223
|
-
mergedCache.push(p);
|
|
224
|
-
}
|
|
225
|
-
this.productsPriceCache.set(cacheKey, mergedCache);
|
|
226
|
-
this.logInfo("增量更新完成", {
|
|
227
|
-
cacheKey,
|
|
228
|
-
changedCount: updatedProducts.length,
|
|
229
|
-
totalCount: mergedCache.length
|
|
230
|
-
});
|
|
231
|
-
(0, import_product.perfMark)("getProductsWithPrice(incrementalUpdate)", performance.now() - t0, {
|
|
232
|
-
cacheKey,
|
|
233
|
-
changedCount: changedIds.length,
|
|
234
|
-
count: mergedCache.length
|
|
235
|
-
});
|
|
236
|
-
return mergedCache;
|
|
237
|
-
}
|
|
238
|
-
} catch (error) {
|
|
239
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
240
|
-
this.logError("增量更新失败,返回现有缓存", {
|
|
241
|
-
cacheKey,
|
|
242
|
-
changedIds,
|
|
243
|
-
error: errorMessage
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
(0, import_product.perfMark)("getProductsWithPrice(incrementalUpdate)", performance.now() - t0, {
|
|
247
|
-
cacheKey,
|
|
248
|
-
changedCount: changedIds.length,
|
|
249
|
-
count: cachedProducts.length
|
|
250
|
-
});
|
|
251
|
-
return cachedProducts;
|
|
252
|
-
}
|
|
253
196
|
(0, import_product.perfMark)("getProductsWithPrice(cacheHit)", performance.now() - t0, {
|
|
254
197
|
cacheKey,
|
|
255
198
|
count: cachedProducts.length
|
|
@@ -278,38 +221,21 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
278
221
|
* 准备带价格的商品数据(通过格式化器流程处理)
|
|
279
222
|
* @param schedule_date 日期
|
|
280
223
|
* @param extraContext 额外的上下文数据(可选)
|
|
281
|
-
* @
|
|
282
|
-
* @param options.productIds 指定商品 IDs,仅处理这些商品;不传则处理全量
|
|
283
|
-
* @returns 处理后的商品列表
|
|
224
|
+
* @returns 完整处理后的商品列表
|
|
284
225
|
* @private
|
|
285
226
|
*/
|
|
286
|
-
async prepareProductsWithPrice(schedule_date, extraContext
|
|
287
|
-
var _a, _b;
|
|
227
|
+
async prepareProductsWithPrice(schedule_date, extraContext) {
|
|
288
228
|
const tTotal = performance.now();
|
|
289
|
-
|
|
290
|
-
const isIncremental = targetIds && targetIds.length > 0;
|
|
291
|
-
this.logInfo("prepareProductsWithPrice 开始处理", {
|
|
292
|
-
schedule_date,
|
|
293
|
-
mode: isIncremental ? "incremental" : "full",
|
|
294
|
-
targetIdsCount: targetIds == null ? void 0 : targetIds.length
|
|
295
|
-
});
|
|
229
|
+
this.logInfo("prepareProductsWithPrice 开始处理", { schedule_date });
|
|
296
230
|
try {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
ids =
|
|
303
|
-
} else {
|
|
304
|
-
products = this.getProductsRef();
|
|
305
|
-
const tIds = performance.now();
|
|
306
|
-
ids = new Array(products.length);
|
|
307
|
-
for (let i = 0; i < products.length; i++) {
|
|
308
|
-
ids[i] = products[i].id;
|
|
309
|
-
}
|
|
310
|
-
(0, import_product.perfMark)("prepareProducts.extractIds", performance.now() - tIds, { count: ids.length });
|
|
231
|
+
const allProducts = this.getProductsRef();
|
|
232
|
+
this.logInfo("获取到商品列表", { productCount: allProducts.length });
|
|
233
|
+
const tIds = performance.now();
|
|
234
|
+
const ids = new Array(allProducts.length);
|
|
235
|
+
for (let i = 0; i < allProducts.length; i++) {
|
|
236
|
+
ids[i] = allProducts[i].id;
|
|
311
237
|
}
|
|
312
|
-
|
|
238
|
+
(0, import_product.perfMark)("prepareProducts.extractIds", performance.now() - tIds, { count: ids.length });
|
|
313
239
|
const tPrice = performance.now();
|
|
314
240
|
const priceData = await this.loadProductsPrice({
|
|
315
241
|
ids,
|
|
@@ -320,31 +246,26 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
320
246
|
const context = {
|
|
321
247
|
schedule_date,
|
|
322
248
|
priceData,
|
|
323
|
-
locale: (_b = (_a = this.core) == null ? void 0 : _a.context) == null ? void 0 : _b.locale,
|
|
324
249
|
...extraContext
|
|
325
250
|
};
|
|
326
251
|
const tFormat = performance.now();
|
|
327
|
-
const processedProducts = await this.applyFormatters(
|
|
252
|
+
const processedProducts = await this.applyFormatters(allProducts, context);
|
|
328
253
|
(0, import_product.perfMark)("prepareProducts.applyFormatters", performance.now() - tFormat, {
|
|
329
|
-
count:
|
|
254
|
+
count: allProducts.length,
|
|
330
255
|
formatterCount: this.formatters.length
|
|
331
256
|
});
|
|
332
257
|
this.logInfo("prepareProductsWithPrice 处理完成", {
|
|
333
|
-
|
|
334
|
-
originalProductCount: products.length,
|
|
258
|
+
originalProductCount: allProducts.length,
|
|
335
259
|
processedProductCount: processedProducts.length,
|
|
336
260
|
formatterCount: this.formatters.length
|
|
337
261
|
});
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
);
|
|
343
|
-
}
|
|
262
|
+
await this.core.effects.emit(
|
|
263
|
+
import_types.ProductsHooks.onProductsPriceApplied,
|
|
264
|
+
processedProducts
|
|
265
|
+
);
|
|
344
266
|
(0, import_product.perfMark)("prepareProductsWithPrice", performance.now() - tTotal, {
|
|
345
|
-
productCount:
|
|
346
|
-
formatterCount: this.formatters.length
|
|
347
|
-
mode: isIncremental ? "incremental" : "full"
|
|
267
|
+
productCount: allProducts.length,
|
|
268
|
+
formatterCount: this.formatters.length
|
|
348
269
|
});
|
|
349
270
|
return processedProducts;
|
|
350
271
|
} catch (err) {
|
|
@@ -419,14 +340,10 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
419
340
|
console.log(`[ProductsModule] 💰 应用价格数据到 ${products.length} 个商品`);
|
|
420
341
|
return (0, import_product.applyPriceDataToProducts)(products, context.priceData);
|
|
421
342
|
};
|
|
422
|
-
const i18nFormatter = (products, context) => {
|
|
423
|
-
return (0, import_product.applyI18nToProducts)(products, context.locale);
|
|
424
|
-
};
|
|
425
343
|
const detailValueFormatter = (products, context) => {
|
|
426
344
|
return (0, import_product.applyDetailValueToProducts)(products, context);
|
|
427
345
|
};
|
|
428
346
|
this.formatters.unshift(priceFormatter);
|
|
429
|
-
this.formatters.push(i18nFormatter);
|
|
430
347
|
this.formatters.push(detailValueFormatter);
|
|
431
348
|
this.isPriceFormatterRegistered = true;
|
|
432
349
|
console.log("[ProductsModule] ✅ 内置价格格式化器已注册(第 1 个)");
|
|
@@ -687,6 +604,29 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
687
604
|
(0, import_product.perfMark)("refreshProducts", performance.now() - tTotal, { count: this.store.list.length });
|
|
688
605
|
return this.store.list;
|
|
689
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* 局部更新指定商品的报价单价格
|
|
609
|
+
* 遍历所有已缓存的日期,为目标商品重新获取价格并覆盖到缓存中
|
|
610
|
+
*/
|
|
611
|
+
async updateProductPriceByIds(ids) {
|
|
612
|
+
this.logInfo("updateProductPriceByIds", { ids });
|
|
613
|
+
for (const [dateKey, cachedProducts] of this.productsPriceCache.entries()) {
|
|
614
|
+
try {
|
|
615
|
+
const priceData = await this.loadProductsPrice({
|
|
616
|
+
ids,
|
|
617
|
+
schedule_date: dateKey
|
|
618
|
+
});
|
|
619
|
+
if (priceData && priceData.length > 0) {
|
|
620
|
+
const updatedProducts = (0, import_product.applyPriceDataToProducts)(cachedProducts, priceData);
|
|
621
|
+
this.productsPriceCache.set(dateKey, updatedProducts);
|
|
622
|
+
this.logInfo("updateProductPriceByIds: 缓存已更新", { dateKey, priceDataCount: priceData.length });
|
|
623
|
+
}
|
|
624
|
+
} catch (error) {
|
|
625
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
626
|
+
this.logError("updateProductPriceByIds: 失败", { dateKey, ids, error: errorMessage });
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
690
630
|
/**
|
|
691
631
|
* 清空缓存
|
|
692
632
|
*/
|
|
@@ -748,7 +688,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
748
688
|
try {
|
|
749
689
|
const t0 = performance.now();
|
|
750
690
|
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
751
|
-
await this.dbManager.
|
|
691
|
+
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, products);
|
|
752
692
|
(0, import_product.perfMark)("saveProductsToIndexDB", performance.now() - t0, { count: products.length });
|
|
753
693
|
console.log(
|
|
754
694
|
`[Products] 已将 ${products.length} 个商品平铺保存到 IndexDB`
|
|
@@ -913,21 +853,18 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
913
853
|
*
|
|
914
854
|
* product 模块:
|
|
915
855
|
* - operation === 'delete' → 本地删除
|
|
916
|
-
* -
|
|
917
|
-
* -
|
|
918
|
-
* -
|
|
856
|
+
* - 有 body(无 price change_types) → body 完整数据直接覆盖本地
|
|
857
|
+
* - change_types 包含 price → SSE 增量拉取 + 刷新报价单价格缓存
|
|
858
|
+
* - change_types 仅 stock → 跳过(暂不响应)
|
|
919
859
|
*
|
|
920
|
-
* product_collection / product_category:
|
|
860
|
+
* product_collection / product_category / product_quotation:
|
|
921
861
|
* - 按 relation_product_ids SSE 拉取受影响商品
|
|
862
|
+
* - product_quotation 额外刷新报价单价格缓存
|
|
922
863
|
*
|
|
923
|
-
*
|
|
924
|
-
* - 报价单变更影响范围大,直接清除价格缓存走全量重建
|
|
925
|
-
*
|
|
926
|
-
* 处理完成后 emit onProductsSyncCompleted(携带 changedIds),
|
|
927
|
-
* Server 层监听该事件后对变更商品增量执行 prepareProductsWithPrice 并更新缓存
|
|
864
|
+
* 处理完成后 emit onProductsSyncCompleted 通知 Server 层
|
|
928
865
|
*/
|
|
929
866
|
async processProductSyncMessages() {
|
|
930
|
-
var _a, _b, _c, _d, _e
|
|
867
|
+
var _a, _b, _c, _d, _e;
|
|
931
868
|
const messages = [...this.pendingSyncMessages];
|
|
932
869
|
this.pendingSyncMessages = [];
|
|
933
870
|
if (messages.length === 0)
|
|
@@ -937,28 +874,24 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
937
874
|
const bodyUpdates = /* @__PURE__ */ new Map();
|
|
938
875
|
const sseRefreshIds = [];
|
|
939
876
|
const priceRefreshIds = [];
|
|
940
|
-
let shouldClearPriceCache = false;
|
|
941
877
|
for (const msg of messages) {
|
|
942
878
|
const channelKey = msg._channelKey || msg.module || "product";
|
|
943
879
|
if (channelKey === "product") {
|
|
944
|
-
if ((_a = msg.relation_product_ids) == null ? void 0 : _a.length) {
|
|
945
|
-
sseRefreshIds.push(...msg.relation_product_ids);
|
|
946
|
-
}
|
|
947
880
|
if (msg.operation === "delete" || msg.action === "delete") {
|
|
948
|
-
if ((
|
|
881
|
+
if ((_a = msg.ids) == null ? void 0 : _a.length)
|
|
949
882
|
deleteIds.push(...msg.ids);
|
|
950
883
|
else if (msg.id)
|
|
951
884
|
deleteIds.push(msg.id);
|
|
952
885
|
continue;
|
|
953
886
|
}
|
|
887
|
+
if (((_b = msg.change_types) == null ? void 0 : _b.length) && msg.change_types.every((t) => t === "stock")) {
|
|
888
|
+
this.logInfo("跳过仅库存变更", { ids: msg.ids });
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
954
891
|
if ((_c = msg.change_types) == null ? void 0 : _c.includes("price")) {
|
|
955
892
|
const ids = msg.ids || (msg.id ? [msg.id] : []);
|
|
893
|
+
sseRefreshIds.push(...ids);
|
|
956
894
|
priceRefreshIds.push(...ids);
|
|
957
|
-
if (msg.body) {
|
|
958
|
-
const bodyId = msg.body.id;
|
|
959
|
-
if (bodyId)
|
|
960
|
-
bodyUpdates.set(bodyId, msg.body);
|
|
961
|
-
}
|
|
962
895
|
continue;
|
|
963
896
|
}
|
|
964
897
|
if (msg.body) {
|
|
@@ -972,14 +905,13 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
972
905
|
} else if (msg.id) {
|
|
973
906
|
sseRefreshIds.push(msg.id);
|
|
974
907
|
}
|
|
975
|
-
} else if (
|
|
976
|
-
shouldClearPriceCache = true;
|
|
908
|
+
} else if (["product_collection", "product_category", "product_quotation"].includes(channelKey)) {
|
|
977
909
|
if ((_e = msg.relation_product_ids) == null ? void 0 : _e.length) {
|
|
978
910
|
sseRefreshIds.push(...msg.relation_product_ids);
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
911
|
+
if (channelKey === "product_quotation") {
|
|
912
|
+
this.clearPriceCache();
|
|
913
|
+
priceRefreshIds.push(...msg.relation_product_ids);
|
|
914
|
+
}
|
|
983
915
|
}
|
|
984
916
|
}
|
|
985
917
|
}
|
|
@@ -996,36 +928,29 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
996
928
|
const freshProducts = await this.fetchProductsBySSE(uniqueSSEIds);
|
|
997
929
|
if (freshProducts.length > 0) {
|
|
998
930
|
await this.mergeProductsToStore(freshProducts);
|
|
931
|
+
await this.updatePriceCacheForProducts(freshProducts);
|
|
999
932
|
}
|
|
1000
|
-
this.logInfo("processProductSyncMessages: SSE 增量更新完成
|
|
933
|
+
this.logInfo("processProductSyncMessages: SSE 增量更新完成", {
|
|
1001
934
|
requestedCount: uniqueSSEIds.length,
|
|
1002
935
|
receivedCount: freshProducts.length
|
|
1003
936
|
});
|
|
1004
937
|
}
|
|
1005
|
-
const
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
this.logInfo("processProductSyncMessages: 处理完成
|
|
938
|
+
const sseHandledSet = new Set(uniqueSSEIds);
|
|
939
|
+
const remainingPriceIds = uniquePriceIds.filter((id) => !sseHandledSet.has(id));
|
|
940
|
+
if (remainingPriceIds.length > 0) {
|
|
941
|
+
await this.updateProductPriceByIds(remainingPriceIds);
|
|
942
|
+
}
|
|
943
|
+
this.logInfo("processProductSyncMessages: 处理完成", {
|
|
1011
944
|
deleteCount: uniqueDeleteIds.length,
|
|
1012
945
|
bodyUpdateCount: bodyUpdates.size,
|
|
1013
946
|
sseRefreshCount: uniqueSSEIds.length,
|
|
1014
|
-
priceRefreshCount: uniquePriceIds.length
|
|
1015
|
-
allChangedIdsCount: allChangedIds.length,
|
|
1016
|
-
shouldClearPriceCache
|
|
947
|
+
priceRefreshCount: uniquePriceIds.length
|
|
1017
948
|
});
|
|
1018
|
-
|
|
1019
|
-
if (!hasChanges) {
|
|
949
|
+
if (uniqueDeleteIds.length === 0 && bodyUpdates.size === 0 && uniqueSSEIds.length === 0 && uniquePriceIds.length === 0) {
|
|
1020
950
|
this.logInfo("processProductSyncMessages: 没有变更,不触发 onProductsSyncCompleted");
|
|
1021
951
|
return;
|
|
1022
952
|
}
|
|
1023
|
-
|
|
1024
|
-
this.clearPriceCache();
|
|
1025
|
-
}
|
|
1026
|
-
await this.core.effects.emit(import_types.ProductsHooks.onProductsSyncCompleted, {
|
|
1027
|
-
changedIds: allChangedIds
|
|
1028
|
-
});
|
|
953
|
+
await this.core.effects.emit(import_types.ProductsHooks.onProductsSyncCompleted, null);
|
|
1029
954
|
}
|
|
1030
955
|
/**
|
|
1031
956
|
* 通过 SSE 按 ids 增量拉取商品数据
|
|
@@ -1059,8 +984,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1059
984
|
/**
|
|
1060
985
|
* 将 body 完整数据直接覆盖到本地 store(不调用报价单接口)
|
|
1061
986
|
* 已存在的 → 直接替换;不存在的 → 追加
|
|
1062
|
-
* 同时更新 Map 缓存、IndexDB
|
|
1063
|
-
* 价格缓存由 processProductSyncMessages 末尾统一清除
|
|
987
|
+
* 同时更新 Map 缓存、IndexDB,清空价格缓存,触发 onProductsChanged
|
|
1064
988
|
*/
|
|
1065
989
|
async applyBodyUpdatesToStore(bodyUpdates) {
|
|
1066
990
|
this.logInfo("applyBodyUpdatesToStore: 开始", { count: bodyUpdates.size });
|
|
@@ -1083,6 +1007,7 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1083
1007
|
}
|
|
1084
1008
|
this.syncProductsMap();
|
|
1085
1009
|
await this.saveProductsToIndexDB(this.store.list);
|
|
1010
|
+
await this.updatePriceCacheForProducts([...bodyUpdates.values()]);
|
|
1086
1011
|
this.core.effects.emit(import_types.ProductsHooks.onProductsChanged, this.store.list);
|
|
1087
1012
|
this.logInfo("applyBodyUpdatesToStore: 完成", {
|
|
1088
1013
|
updatedCount,
|
|
@@ -1123,6 +1048,80 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
1123
1048
|
});
|
|
1124
1049
|
this.core.effects.emit(import_types.ProductsHooks.onProductsChanged, this.store.list);
|
|
1125
1050
|
}
|
|
1051
|
+
/**
|
|
1052
|
+
* 增量更新价格缓存中变更的商品
|
|
1053
|
+
* 对每个已缓存的日期 key:替换/追加最新商品数据,重新拉取这些 ID 的价格并应用
|
|
1054
|
+
*/
|
|
1055
|
+
async updatePriceCacheForProducts(freshProducts) {
|
|
1056
|
+
if (this.productsPriceCache.size === 0)
|
|
1057
|
+
return;
|
|
1058
|
+
const freshIds = freshProducts.map((p) => p.id);
|
|
1059
|
+
const freshMap = /* @__PURE__ */ new Map();
|
|
1060
|
+
for (const p of freshProducts) {
|
|
1061
|
+
freshMap.set(p.id, p);
|
|
1062
|
+
}
|
|
1063
|
+
this.logInfo("updatePriceCacheForProducts: 开始", {
|
|
1064
|
+
freshIds,
|
|
1065
|
+
cachedDateCount: this.productsPriceCache.size
|
|
1066
|
+
});
|
|
1067
|
+
for (const [dateKey, cachedProducts] of this.productsPriceCache.entries()) {
|
|
1068
|
+
try {
|
|
1069
|
+
const updatedList = cachedProducts.map((p) => {
|
|
1070
|
+
const fresh = freshMap.get(p.id);
|
|
1071
|
+
return fresh ? { ...fresh } : p;
|
|
1072
|
+
});
|
|
1073
|
+
const existingIds = new Set(cachedProducts.map((p) => p.id));
|
|
1074
|
+
for (const p of freshProducts) {
|
|
1075
|
+
if (!existingIds.has(p.id)) {
|
|
1076
|
+
updatedList.push({ ...p });
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
const priceData = await this.loadProductsPrice({
|
|
1080
|
+
ids: freshIds,
|
|
1081
|
+
schedule_date: dateKey
|
|
1082
|
+
});
|
|
1083
|
+
const result = priceData && priceData.length > 0 ? (0, import_product.applyPriceDataToProducts)(updatedList, priceData) : updatedList;
|
|
1084
|
+
this.productsPriceCache.set(dateKey, result);
|
|
1085
|
+
this.logInfo("updatePriceCacheForProducts: 日期缓存已更新", {
|
|
1086
|
+
dateKey,
|
|
1087
|
+
updatedIds: freshIds
|
|
1088
|
+
});
|
|
1089
|
+
} catch (error) {
|
|
1090
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1091
|
+
this.logError("updatePriceCacheForProducts: 失败", { dateKey, error: errorMessage });
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* 全量重新拉取报价单价格并重建价格缓存
|
|
1097
|
+
* 遍历当前已缓存的所有日期 key,对每个日期重新调用 loadProductsPrice
|
|
1098
|
+
*/
|
|
1099
|
+
async refreshAllPriceCache() {
|
|
1100
|
+
const allProducts = this.getProductsRef();
|
|
1101
|
+
if (allProducts.length === 0)
|
|
1102
|
+
return;
|
|
1103
|
+
const ids = allProducts.map((p) => p.id);
|
|
1104
|
+
const dateKeys = Array.from(this.productsPriceCache.keys());
|
|
1105
|
+
this.clearPriceCache();
|
|
1106
|
+
if (dateKeys.length === 0) {
|
|
1107
|
+
this.logInfo("refreshAllPriceCache: 无已缓存日期,跳过");
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
this.logInfo("refreshAllPriceCache: 开始重新拉取", { dateKeys, productCount: ids.length });
|
|
1111
|
+
for (const dateKey of dateKeys) {
|
|
1112
|
+
try {
|
|
1113
|
+
const priceData = await this.loadProductsPrice({ ids, schedule_date: dateKey });
|
|
1114
|
+
if (priceData && priceData.length > 0) {
|
|
1115
|
+
const updatedProducts = (0, import_product.applyPriceDataToProducts)(allProducts, priceData);
|
|
1116
|
+
this.productsPriceCache.set(dateKey, updatedProducts);
|
|
1117
|
+
}
|
|
1118
|
+
this.logInfo("refreshAllPriceCache: 日期缓存已更新", { dateKey });
|
|
1119
|
+
} catch (error) {
|
|
1120
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1121
|
+
this.logError("refreshAllPriceCache: 失败", { dateKey, error: errorMessage });
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1126
1125
|
/**
|
|
1127
1126
|
* 静默全量刷新:后台重新拉取全量 SSE 数据并更新本地
|
|
1128
1127
|
* 拿到完整数据后一次性替换 store,清除价格缓存,触发 onProductsSyncCompleted
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Module, ModuleOptions, PisellCore } from '../../../types';
|
|
2
|
+
import { BaseModule } from '../../../modules/BaseModule';
|
|
3
|
+
import { type ResourceBooking, type ResourceData, type ResourceId, type QueryOptions } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Resource 模块
|
|
6
|
+
*/
|
|
7
|
+
export declare class ResourceModule extends BaseModule implements Module {
|
|
8
|
+
protected defaultName: string;
|
|
9
|
+
protected defaultVersion: string;
|
|
10
|
+
private store;
|
|
11
|
+
private dbManager;
|
|
12
|
+
private logger;
|
|
13
|
+
private resourceDataSource;
|
|
14
|
+
/** 倒排索引: resourceId -> ResourceBooking[] */
|
|
15
|
+
private resourceIdIndex;
|
|
16
|
+
/** 待处理的同步消息队列 */
|
|
17
|
+
private pendingSyncMessages;
|
|
18
|
+
private syncTimer?;
|
|
19
|
+
constructor(name?: string, version?: string);
|
|
20
|
+
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
21
|
+
private logInfo;
|
|
22
|
+
private logError;
|
|
23
|
+
preload(): Promise<void>;
|
|
24
|
+
getRoutes(): never[];
|
|
25
|
+
destroy(): void;
|
|
26
|
+
/**
|
|
27
|
+
* 获取所有资源(支持 includeBookings 附加预订信息)
|
|
28
|
+
*/
|
|
29
|
+
getResources(queryOptions?: QueryOptions): ResourceData[];
|
|
30
|
+
/**
|
|
31
|
+
* 根据 ID 获取单个资源
|
|
32
|
+
*/
|
|
33
|
+
getResourceById(id: ResourceId, queryOptions?: QueryOptions): ResourceData | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* 创建资源
|
|
36
|
+
*/
|
|
37
|
+
createResource(data: Partial<ResourceData>): ResourceData;
|
|
38
|
+
/**
|
|
39
|
+
* 更新资源
|
|
40
|
+
*/
|
|
41
|
+
updateResource(id: ResourceId, data: Partial<ResourceData>): ResourceData | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* 删除资源
|
|
44
|
+
*/
|
|
45
|
+
deleteResource(id: ResourceId): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* 根据资源 ID 获取预订列表
|
|
48
|
+
*/
|
|
49
|
+
getBookingsByResourceId(resourceId: ResourceId): ResourceBooking[];
|
|
50
|
+
/**
|
|
51
|
+
* 创建预订
|
|
52
|
+
*/
|
|
53
|
+
createBooking(booking: Partial<ResourceBooking>): ResourceBooking;
|
|
54
|
+
/**
|
|
55
|
+
* 更新预订
|
|
56
|
+
*/
|
|
57
|
+
updateBooking(id: ResourceId, data: Partial<ResourceBooking>): ResourceBooking | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* 删除预订
|
|
60
|
+
*/
|
|
61
|
+
deleteBooking(id: ResourceId): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* 清空缓存
|
|
64
|
+
*/
|
|
65
|
+
clear(): Promise<void>;
|
|
66
|
+
private attachBookingsToResource;
|
|
67
|
+
private normalizeResource;
|
|
68
|
+
private safeEmit;
|
|
69
|
+
private syncResourcesMap;
|
|
70
|
+
private syncBookingsIndex;
|
|
71
|
+
private rebuildBookingsIndex;
|
|
72
|
+
private getIdKey;
|
|
73
|
+
private loadResourcesByServer;
|
|
74
|
+
private loadResourcesFromSQLite;
|
|
75
|
+
private saveResourcesToSQLite;
|
|
76
|
+
private loadBookingsFromSQLite;
|
|
77
|
+
private saveBookingsToSQLite;
|
|
78
|
+
private initResourceDataSource;
|
|
79
|
+
private setupResourceSync;
|
|
80
|
+
private processSyncMessages;
|
|
81
|
+
private fetchResourcesBySSE;
|
|
82
|
+
private removeResourcesByIds;
|
|
83
|
+
private mergeResourcesToStore;
|
|
84
|
+
private uniqueResourceIds;
|
|
85
|
+
}
|
|
86
|
+
export declare const resourceModule: ResourceModule;
|
|
87
|
+
export type { ResourceData, ResourceBooking, ResourceState, ResourceId, ResourcePageQuery, ResourcePageResult, QueryOptions, ScheduleEventResource, } from './types';
|
|
88
|
+
export { ResourceHooks } from './types';
|