@pisell/pisellos 2.3.61 → 2.3.62
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 -66
- package/dist/modules/Quotation/index.d.ts +6 -0
- package/dist/modules/Quotation/index.js +75 -19
- package/dist/plugins/request.d.ts +1 -0
- package/dist/server/index.d.ts +6 -2
- package/dist/server/index.js +130 -90
- 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 +12 -7
- package/dist/server/modules/order/index.js +248 -96
- 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/lib/core/index.d.ts +7 -0
- package/lib/core/index.js +20 -3
- package/lib/model/strategy/adapter/promotion/index.js +51 -0
- package/lib/modules/Quotation/index.d.ts +6 -0
- package/lib/modules/Quotation/index.js +49 -5
- package/lib/plugins/request.d.ts +1 -0
- package/lib/server/index.d.ts +6 -2
- package/lib/server/index.js +18 -8
- 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 +12 -7
- package/lib/server/modules/order/index.js +143 -28
- 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/package.json +1 -1
|
@@ -40,6 +40,7 @@ var import_types = require("./types");
|
|
|
40
40
|
var import_payment_utils = require("../../../modules/Order/payment-utils");
|
|
41
41
|
var INDEXDB_STORE_NAME = "orders";
|
|
42
42
|
var ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = "server_order_last_full_fetch_at";
|
|
43
|
+
var ORDER_LAST_FULL_FETCH_SHOP_ID_STORAGE_KEY = "server_order_last_full_fetch_shop_id";
|
|
43
44
|
var ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = "order_sync_throttle_ms";
|
|
44
45
|
var DEFAULT_ORDER_SYNC_THROTTLE_MS = 2e3;
|
|
45
46
|
var ORDER_SQLITE_DEDUPE_MS = 15e3;
|
|
@@ -524,11 +525,47 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
524
525
|
return DEFAULT_ORDER_SYNC_THROTTLE_MS;
|
|
525
526
|
}
|
|
526
527
|
async preload() {
|
|
527
|
-
const
|
|
528
|
+
const preloadStartedAt = Date.now();
|
|
529
|
+
let cachedOrders = null;
|
|
530
|
+
if (this.dbManager) {
|
|
531
|
+
try {
|
|
532
|
+
cachedOrders = await this.loadOrdersFromSQLite({ throwOnError: true });
|
|
533
|
+
} catch (error) {
|
|
534
|
+
this.logWarning("preload-SQLite读取失败,回退远端全量拉取", {
|
|
535
|
+
error: error instanceof Error ? error.message : String(error)
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
if (cachedOrders !== null && this.hasPulledOrdersToday()) {
|
|
540
|
+
const memoryOrders = this.normalizeOrdersForMemoryList(
|
|
541
|
+
cachedOrders,
|
|
542
|
+
"preload.sqliteMemory"
|
|
543
|
+
);
|
|
544
|
+
this.store.list = (0, import_lodash_es.cloneDeep)(memoryOrders);
|
|
545
|
+
this.syncOrdersMap();
|
|
546
|
+
await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded, this.store.list);
|
|
547
|
+
await this.emitOrdersChanged([], "preload.sqlite");
|
|
548
|
+
this.logInfo("预加载完成", {
|
|
549
|
+
trigger: "preload",
|
|
550
|
+
source: "SQLite",
|
|
551
|
+
orderCount: this.store.list.length,
|
|
552
|
+
duration: `${Date.now() - preloadStartedAt}ms`
|
|
553
|
+
});
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const orders = await this.loadOrdersByServer({
|
|
557
|
+
trigger: "preload"
|
|
558
|
+
});
|
|
528
559
|
this.store.list = (0, import_lodash_es.cloneDeep)(orders);
|
|
529
560
|
this.syncOrdersMap();
|
|
530
561
|
await this.emitOrdersChanged([], "preload");
|
|
531
562
|
await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
563
|
+
this.logInfo("预加载完成", {
|
|
564
|
+
trigger: "preload",
|
|
565
|
+
source: "Server",
|
|
566
|
+
orderCount: this.store.list.length,
|
|
567
|
+
duration: `${Date.now() - preloadStartedAt}ms`
|
|
568
|
+
});
|
|
532
569
|
}
|
|
533
570
|
getOrders() {
|
|
534
571
|
return this.store.list;
|
|
@@ -749,13 +786,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
749
786
|
this.logInfo("updateLocalPayment-变更事件完成", paymentContext);
|
|
750
787
|
return { order: nextOrder, payment: nextPayment, previousPayment };
|
|
751
788
|
}
|
|
752
|
-
async loadOrdersByServer() {
|
|
789
|
+
async loadOrdersByServer(options = {}) {
|
|
753
790
|
var _a;
|
|
754
791
|
let orderList = [];
|
|
792
|
+
let hasFetchedRemoteSnapshot = false;
|
|
793
|
+
const trigger = options.trigger || "unknown";
|
|
755
794
|
const protectedOrdersBeforeRemoteFetch = (await this.loadOrdersFromSQLite()).filter(
|
|
756
795
|
(order) => this.shouldProtectLocalOrderFromRemoteSnapshot(order)
|
|
757
796
|
);
|
|
758
797
|
this.logInfo("loadOrdersByServer-开始", {
|
|
798
|
+
trigger,
|
|
759
799
|
hasOrderDataSource: !!this.orderDataSource,
|
|
760
800
|
query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null,
|
|
761
801
|
protectedLocalOrderCount: protectedOrdersBeforeRemoteFetch.length,
|
|
@@ -773,25 +813,36 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
773
813
|
});
|
|
774
814
|
orderList = data || [];
|
|
775
815
|
this.logInfo("loadOrdersByServer-SSE拉取成功", {
|
|
816
|
+
trigger,
|
|
776
817
|
count: orderList.length
|
|
777
818
|
});
|
|
778
|
-
|
|
819
|
+
hasFetchedRemoteSnapshot = true;
|
|
779
820
|
this.lastServerFullFetchAtMs = Date.now();
|
|
780
821
|
} catch {
|
|
781
822
|
this.logInfo("loadOrdersByServer-SSE拉取失败,保持当前内存订单");
|
|
782
823
|
return this.store.list;
|
|
783
824
|
}
|
|
784
825
|
}
|
|
785
|
-
|
|
826
|
+
if (hasFetchedRemoteSnapshot) {
|
|
827
|
+
this.clearOrderSnapshotMarker();
|
|
828
|
+
}
|
|
829
|
+
const {
|
|
830
|
+
orders: mergedOrders,
|
|
831
|
+
persisted: isRemoteSnapshotPersisted
|
|
832
|
+
} = await this.replaceOrdersSnapshotInSQLite(
|
|
786
833
|
orderList,
|
|
787
834
|
"loadOrdersByServer",
|
|
788
835
|
protectedOrdersBeforeRemoteFetch
|
|
789
836
|
);
|
|
837
|
+
if (hasFetchedRemoteSnapshot && isRemoteSnapshotPersisted) {
|
|
838
|
+
this.markOrderPulledAtNow();
|
|
839
|
+
}
|
|
790
840
|
const memoryOrders = this.normalizeOrdersForMemoryList(
|
|
791
841
|
mergedOrders,
|
|
792
842
|
"loadOrdersByServer.memory"
|
|
793
843
|
);
|
|
794
844
|
this.logInfo("loadOrdersByServer-结束", {
|
|
845
|
+
trigger,
|
|
795
846
|
count: memoryOrders.length,
|
|
796
847
|
persistedCount: mergedOrders.length,
|
|
797
848
|
sqliteOnlyDraftCount: mergedOrders.length - memoryOrders.length
|
|
@@ -804,21 +855,34 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
804
855
|
* 拿到完整数据后一次性替换 store,触发订单变更与同步完成事件
|
|
805
856
|
* @returns 刷新后的订单列表
|
|
806
857
|
*/
|
|
807
|
-
async silentRefresh() {
|
|
858
|
+
async silentRefresh(options = {}) {
|
|
808
859
|
const startTime = Date.now();
|
|
860
|
+
const trigger = options.trigger || "background";
|
|
809
861
|
const elapsedSinceFullFetch = Date.now() - this.lastServerFullFetchAtMs;
|
|
810
862
|
if (this.lastServerFullFetchAtMs > 0 && elapsedSinceFullFetch < ORDER_SILENT_REFRESH_MIN_INTERVAL_MS) {
|
|
863
|
+
this.logInfo("silentRefresh 跳过全量 SSE", {
|
|
864
|
+
trigger,
|
|
865
|
+
reason: "within_min_interval",
|
|
866
|
+
minIntervalMs: ORDER_SILENT_REFRESH_MIN_INTERVAL_MS,
|
|
867
|
+
elapsedSinceFullFetchMs: elapsedSinceFullFetch,
|
|
868
|
+
orderCount: this.store.list.length
|
|
869
|
+
});
|
|
811
870
|
return this.store.list;
|
|
812
871
|
}
|
|
813
|
-
this.logInfo("silentRefresh 开始"
|
|
872
|
+
this.logInfo("silentRefresh 开始", {
|
|
873
|
+
trigger,
|
|
874
|
+
elapsedSinceFullFetchMs: elapsedSinceFullFetch,
|
|
875
|
+
orderCount: this.store.list.length
|
|
876
|
+
});
|
|
814
877
|
try {
|
|
815
878
|
this.updateCreateStore();
|
|
816
|
-
const orders = await this.loadOrdersByServer();
|
|
879
|
+
const orders = await this.loadOrdersByServer({ trigger });
|
|
817
880
|
this.store.list = (0, import_lodash_es.cloneDeep)(orders);
|
|
818
881
|
this.syncOrdersMap();
|
|
819
882
|
await this.emitOrdersChanged([], "silentRefresh");
|
|
820
883
|
await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
821
884
|
this.logInfo("silentRefresh 完成", {
|
|
885
|
+
trigger,
|
|
822
886
|
orderCount: orders.length,
|
|
823
887
|
duration: `${Date.now() - startTime}ms`
|
|
824
888
|
});
|
|
@@ -826,6 +890,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
826
890
|
} catch (error) {
|
|
827
891
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
828
892
|
this.logError("silentRefresh 失败", {
|
|
893
|
+
trigger,
|
|
829
894
|
duration: `${Date.now() - startTime}ms`,
|
|
830
895
|
error: errorMessage
|
|
831
896
|
});
|
|
@@ -2119,20 +2184,29 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2119
2184
|
return { list, removedCount };
|
|
2120
2185
|
}
|
|
2121
2186
|
/**
|
|
2122
|
-
*
|
|
2123
|
-
*
|
|
2124
|
-
* - 无法解析时退化为自然日窗口
|
|
2187
|
+
* 当前订单缓存可复用窗口。
|
|
2188
|
+
* start_time 模式使用精确的营业日起止时间;配置缺失或异常时退化为自然日。
|
|
2125
2189
|
*/
|
|
2126
|
-
|
|
2127
|
-
var _a
|
|
2190
|
+
getCurrentOrderCacheWindow() {
|
|
2191
|
+
var _a;
|
|
2128
2192
|
const now = (0, import_dayjs.default)();
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
const
|
|
2132
|
-
const
|
|
2133
|
-
|
|
2134
|
-
|
|
2193
|
+
try {
|
|
2194
|
+
const appPlugin = this.core.getPlugin("app");
|
|
2195
|
+
const app = appPlugin == null ? void 0 : appPlugin.getApp();
|
|
2196
|
+
const coreData = app == null ? void 0 : app.data.store.getStore().getDataByModel("core");
|
|
2197
|
+
const boundary = (_a = coreData == null ? void 0 : coreData.core) == null ? void 0 : _a.operating_day_boundary;
|
|
2198
|
+
if ((boundary == null ? void 0 : boundary.type) === "start_time") {
|
|
2199
|
+
const boundaryTime = String(boundary.time || "").trim();
|
|
2200
|
+
const todayBoundary = (0, import_dayjs.default)(`${now.format("YYYY-MM-DD")} ${boundaryTime}`);
|
|
2201
|
+
if (todayBoundary.isValid()) {
|
|
2202
|
+
const startAt2 = now.isBefore(todayBoundary) ? todayBoundary.subtract(1, "day") : todayBoundary;
|
|
2203
|
+
return {
|
|
2204
|
+
startAt: startAt2,
|
|
2205
|
+
endExclusiveAt: startAt2.add(1, "day")
|
|
2206
|
+
};
|
|
2207
|
+
}
|
|
2135
2208
|
}
|
|
2209
|
+
} catch {
|
|
2136
2210
|
}
|
|
2137
2211
|
const startAt = now.startOf("day");
|
|
2138
2212
|
return { startAt, endExclusiveAt: startAt.add(1, "day") };
|
|
@@ -2141,17 +2215,51 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2141
2215
|
const lastFullFetchAt = this.getStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY);
|
|
2142
2216
|
if (!lastFullFetchAt)
|
|
2143
2217
|
return false;
|
|
2218
|
+
const currentShopId = this.getCurrentShopId();
|
|
2219
|
+
const lastFullFetchShopId = this.getStorageItem(
|
|
2220
|
+
ORDER_LAST_FULL_FETCH_SHOP_ID_STORAGE_KEY
|
|
2221
|
+
);
|
|
2222
|
+
if (!currentShopId || !lastFullFetchShopId || currentShopId !== lastFullFetchShopId) {
|
|
2223
|
+
return false;
|
|
2224
|
+
}
|
|
2144
2225
|
const parsed = (0, import_dayjs.default)(lastFullFetchAt);
|
|
2145
2226
|
if (!parsed.isValid())
|
|
2146
2227
|
return false;
|
|
2147
|
-
const { startAt, endExclusiveAt } = this.
|
|
2228
|
+
const { startAt, endExclusiveAt } = this.getCurrentOrderCacheWindow();
|
|
2148
2229
|
return (parsed.isAfter(startAt) || parsed.isSame(startAt)) && parsed.isBefore(endExclusiveAt);
|
|
2149
2230
|
}
|
|
2150
2231
|
markOrderPulledAtNow() {
|
|
2232
|
+
const currentShopId = this.getCurrentShopId();
|
|
2233
|
+
if (!currentShopId)
|
|
2234
|
+
return;
|
|
2151
2235
|
this.setStorageItem(
|
|
2152
2236
|
ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY,
|
|
2153
2237
|
(0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
|
|
2154
2238
|
);
|
|
2239
|
+
this.setStorageItem(
|
|
2240
|
+
ORDER_LAST_FULL_FETCH_SHOP_ID_STORAGE_KEY,
|
|
2241
|
+
currentShopId
|
|
2242
|
+
);
|
|
2243
|
+
}
|
|
2244
|
+
clearOrderSnapshotMarker() {
|
|
2245
|
+
this.setStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY, "");
|
|
2246
|
+
this.setStorageItem(ORDER_LAST_FULL_FETCH_SHOP_ID_STORAGE_KEY, "");
|
|
2247
|
+
}
|
|
2248
|
+
getCurrentShopId() {
|
|
2249
|
+
var _a;
|
|
2250
|
+
try {
|
|
2251
|
+
const appPlugin = this.core.getPlugin("app");
|
|
2252
|
+
const app = appPlugin == null ? void 0 : appPlugin.getApp();
|
|
2253
|
+
if (!app)
|
|
2254
|
+
return null;
|
|
2255
|
+
const coreData = app.data.store.getStore().getDataByModel("core");
|
|
2256
|
+
const shopId = (_a = coreData == null ? void 0 : coreData.core) == null ? void 0 : _a.id;
|
|
2257
|
+
if (shopId === void 0 || shopId === null || shopId === "")
|
|
2258
|
+
return null;
|
|
2259
|
+
return String(shopId);
|
|
2260
|
+
} catch {
|
|
2261
|
+
return null;
|
|
2262
|
+
}
|
|
2155
2263
|
}
|
|
2156
2264
|
getStorageItem(key) {
|
|
2157
2265
|
var _a;
|
|
@@ -2178,7 +2286,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2178
2286
|
} catch {
|
|
2179
2287
|
}
|
|
2180
2288
|
}
|
|
2181
|
-
async loadOrdersFromSQLite() {
|
|
2289
|
+
async loadOrdersFromSQLite(options = {}) {
|
|
2182
2290
|
if (!this.dbManager)
|
|
2183
2291
|
return [];
|
|
2184
2292
|
try {
|
|
@@ -2186,7 +2294,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2186
2294
|
return (orders || []).map(
|
|
2187
2295
|
(order) => this.normalizeOrderCollectionsForIngress(order, "loadOrdersFromSQLite")
|
|
2188
2296
|
);
|
|
2189
|
-
} catch {
|
|
2297
|
+
} catch (error) {
|
|
2298
|
+
if (options.throwOnError)
|
|
2299
|
+
throw error;
|
|
2190
2300
|
return [];
|
|
2191
2301
|
}
|
|
2192
2302
|
}
|
|
@@ -2408,14 +2518,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2408
2518
|
* 用于 SSE 全量拉取与营业日窗口裁剪。
|
|
2409
2519
|
*
|
|
2410
2520
|
* @example
|
|
2411
|
-
* await this.replaceOrdersSnapshotInSQLite(orderList)
|
|
2521
|
+
* const { orders, persisted } = await this.replaceOrdersSnapshotInSQLite(orderList, 'refresh')
|
|
2412
2522
|
*/
|
|
2413
2523
|
async replaceOrdersSnapshotInSQLite(orderList, source, protectedOrdersBeforeRemoteFetch = []) {
|
|
2414
2524
|
if (!this.dbManager) {
|
|
2415
|
-
return
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2525
|
+
return {
|
|
2526
|
+
orders: this.compactOrderListByIdentity(
|
|
2527
|
+
orderList.map((order) => this.normalizeRemoteSyncedOrder(order)),
|
|
2528
|
+
`${source}.snapshotNoDb`
|
|
2529
|
+
).list,
|
|
2530
|
+
persisted: false
|
|
2531
|
+
};
|
|
2419
2532
|
}
|
|
2420
2533
|
const remoteSnapshot = (0, import_lodash_es.cloneDeep)(orderList).map(
|
|
2421
2534
|
(order) => this.normalizeOrderCollectionsForIngress(order, `${source}.remoteIngress`)
|
|
@@ -2424,6 +2537,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2424
2537
|
remoteSnapshot.map((order) => this.normalizeRemoteSyncedOrder(order)),
|
|
2425
2538
|
`${source}.remoteSnapshot`
|
|
2426
2539
|
).list;
|
|
2540
|
+
let persisted = false;
|
|
2427
2541
|
try {
|
|
2428
2542
|
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
2429
2543
|
const existingOrders = typeof this.dbManager.getAll === "function" ? await this.dbManager.getAll(INDEXDB_STORE_NAME) : [];
|
|
@@ -2488,13 +2602,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2488
2602
|
count: mergedSnapshot.length
|
|
2489
2603
|
});
|
|
2490
2604
|
});
|
|
2605
|
+
persisted = true;
|
|
2491
2606
|
} catch (error) {
|
|
2492
2607
|
this.logError("全量保存订单到 SQLite 失败", {
|
|
2493
2608
|
error: error instanceof Error ? error.message : String(error),
|
|
2494
2609
|
orderList: remoteSnapshot.length
|
|
2495
2610
|
});
|
|
2496
2611
|
}
|
|
2497
|
-
return mergedSnapshot;
|
|
2612
|
+
return { orders: mergedSnapshot, persisted };
|
|
2498
2613
|
}
|
|
2499
2614
|
/**
|
|
2500
2615
|
* 清空订单模块的内存数据和本地 SQLite 订单表。
|
|
@@ -2510,7 +2625,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2510
2625
|
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
2511
2626
|
});
|
|
2512
2627
|
}
|
|
2513
|
-
this.
|
|
2628
|
+
this.clearOrderSnapshotMarker();
|
|
2514
2629
|
this.emitOrdersChanged([], "clear");
|
|
2515
2630
|
}
|
|
2516
2631
|
};
|
|
@@ -25,6 +25,7 @@ export declare class ProductsModule extends BaseModule implements Module {
|
|
|
25
25
|
private quotationBridgeLoadedKey?;
|
|
26
26
|
private quotationBridgeRefreshPromise?;
|
|
27
27
|
private quotationBridgeRefreshKey?;
|
|
28
|
+
private quotationBridgeUpdatedCallback?;
|
|
28
29
|
private quotationScheduleCache;
|
|
29
30
|
private quotationScheduleCacheSource;
|
|
30
31
|
private quotationScheduleCacheLoaded;
|
|
@@ -72,6 +73,7 @@ export declare class ProductsModule extends BaseModule implements Module {
|
|
|
72
73
|
scheduleModule?: any;
|
|
73
74
|
channel?: string;
|
|
74
75
|
customer_id?: number | string;
|
|
76
|
+
onQuotationUpdated?: () => void;
|
|
75
77
|
}): Promise<void>;
|
|
76
78
|
/**
|
|
77
79
|
* 刷新桥接器内的报价单列表。
|
|
@@ -181,7 +183,9 @@ export declare class ProductsModule extends BaseModule implements Module {
|
|
|
181
183
|
/**
|
|
182
184
|
* 通过 ProductDataSource SSE 加载完整商品列表
|
|
183
185
|
*/
|
|
184
|
-
loadProductsByServer(
|
|
186
|
+
loadProductsByServer(options?: {
|
|
187
|
+
trigger?: string;
|
|
188
|
+
}): Promise<any>;
|
|
185
189
|
/**
|
|
186
190
|
* 纯请求方法:通过 HTTP 接口获取商品列表(无副作用,不触发事件、不写 IndexDB)
|
|
187
191
|
* @param params 查询参数
|
|
@@ -331,7 +335,9 @@ export declare class ProductsModule extends BaseModule implements Module {
|
|
|
331
335
|
* 拿到完整数据后一次性替换 store,清除价格缓存,触发 onProductsSyncCompleted
|
|
332
336
|
* @returns 刷新后的商品列表
|
|
333
337
|
*/
|
|
334
|
-
silentRefresh(
|
|
338
|
+
silentRefresh(options?: {
|
|
339
|
+
trigger?: string;
|
|
340
|
+
}): Promise<ProductData[]>;
|
|
335
341
|
/**
|
|
336
342
|
* 销毁同步资源(取消 pubsub 订阅、清除定时器)
|
|
337
343
|
*/
|
|
@@ -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));
|