@pisell/pisellos 2.3.58 → 2.3.59

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.
@@ -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,6 +525,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
524
525
  return DEFAULT_ORDER_SYNC_THROTTLE_MS;
525
526
  }
526
527
  async preload() {
528
+ let cachedOrders = null;
529
+ if (this.dbManager) {
530
+ try {
531
+ cachedOrders = await this.loadOrdersFromSQLite({ throwOnError: true });
532
+ } catch (error) {
533
+ this.logWarning("preload-SQLite读取失败,回退远端全量拉取", {
534
+ error: error instanceof Error ? error.message : String(error)
535
+ });
536
+ }
537
+ }
538
+ if (cachedOrders !== null && this.hasPulledOrdersToday()) {
539
+ const memoryOrders = this.normalizeOrdersForMemoryList(
540
+ cachedOrders,
541
+ "preload.sqliteMemory"
542
+ );
543
+ this.store.list = (0, import_lodash_es.cloneDeep)(memoryOrders);
544
+ this.syncOrdersMap();
545
+ await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded, this.store.list);
546
+ await this.emitOrdersChanged([], "preload.sqlite");
547
+ return;
548
+ }
527
549
  const orders = await this.loadOrdersByServer();
528
550
  this.store.list = (0, import_lodash_es.cloneDeep)(orders);
529
551
  this.syncOrdersMap();
@@ -752,6 +774,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
752
774
  async loadOrdersByServer() {
753
775
  var _a;
754
776
  let orderList = [];
777
+ let hasFetchedRemoteSnapshot = false;
755
778
  const protectedOrdersBeforeRemoteFetch = (await this.loadOrdersFromSQLite()).filter(
756
779
  (order) => this.shouldProtectLocalOrderFromRemoteSnapshot(order)
757
780
  );
@@ -775,18 +798,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
775
798
  this.logInfo("loadOrdersByServer-SSE拉取成功", {
776
799
  count: orderList.length
777
800
  });
778
- this.markOrderPulledAtNow();
801
+ hasFetchedRemoteSnapshot = true;
779
802
  this.lastServerFullFetchAtMs = Date.now();
780
803
  } catch {
781
804
  this.logInfo("loadOrdersByServer-SSE拉取失败,保持当前内存订单");
782
805
  return this.store.list;
783
806
  }
784
807
  }
785
- const mergedOrders = await this.replaceOrdersSnapshotInSQLite(
808
+ if (hasFetchedRemoteSnapshot) {
809
+ this.clearOrderSnapshotMarker();
810
+ }
811
+ const {
812
+ orders: mergedOrders,
813
+ persisted: isRemoteSnapshotPersisted
814
+ } = await this.replaceOrdersSnapshotInSQLite(
786
815
  orderList,
787
816
  "loadOrdersByServer",
788
817
  protectedOrdersBeforeRemoteFetch
789
818
  );
819
+ if (hasFetchedRemoteSnapshot && isRemoteSnapshotPersisted) {
820
+ this.markOrderPulledAtNow();
821
+ }
790
822
  const memoryOrders = this.normalizeOrdersForMemoryList(
791
823
  mergedOrders,
792
824
  "loadOrdersByServer.memory"
@@ -2119,20 +2151,29 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2119
2151
  return { list, removedCount };
2120
2152
  }
2121
2153
  /**
2122
- * 当前订单拉取窗口:
2123
- * - 优先使用 createdAtQuery.sales_time_between(已按营业日边界初始化)
2124
- * - 无法解析时退化为自然日窗口
2154
+ * 当前订单缓存可复用窗口。
2155
+ * start_time 模式使用精确的营业日起止时间;配置缺失或异常时退化为自然日。
2125
2156
  */
2126
- getCurrentPullWindow() {
2127
- var _a, _b;
2157
+ getCurrentOrderCacheWindow() {
2158
+ var _a;
2128
2159
  const now = (0, import_dayjs.default)();
2129
- const range = (_b = (_a = this.store) == null ? void 0 : _a.createdAtQuery) == null ? void 0 : _b.sales_time_between;
2130
- if (Array.isArray(range) && range.length >= 2) {
2131
- const startAt2 = (0, import_dayjs.default)(range[0]);
2132
- const endExclusiveAt = (0, import_dayjs.default)(range[1]);
2133
- if (startAt2.isValid() && endExclusiveAt.isValid() && endExclusiveAt.isAfter(startAt2)) {
2134
- return { startAt: startAt2, endExclusiveAt };
2160
+ try {
2161
+ const appPlugin = this.core.getPlugin("app");
2162
+ const app = appPlugin == null ? void 0 : appPlugin.getApp();
2163
+ const coreData = app == null ? void 0 : app.data.store.getStore().getDataByModel("core");
2164
+ const boundary = (_a = coreData == null ? void 0 : coreData.core) == null ? void 0 : _a.operating_day_boundary;
2165
+ if ((boundary == null ? void 0 : boundary.type) === "start_time") {
2166
+ const boundaryTime = String(boundary.time || "").trim();
2167
+ const todayBoundary = (0, import_dayjs.default)(`${now.format("YYYY-MM-DD")} ${boundaryTime}`);
2168
+ if (todayBoundary.isValid()) {
2169
+ const startAt2 = now.isBefore(todayBoundary) ? todayBoundary.subtract(1, "day") : todayBoundary;
2170
+ return {
2171
+ startAt: startAt2,
2172
+ endExclusiveAt: startAt2.add(1, "day")
2173
+ };
2174
+ }
2135
2175
  }
2176
+ } catch {
2136
2177
  }
2137
2178
  const startAt = now.startOf("day");
2138
2179
  return { startAt, endExclusiveAt: startAt.add(1, "day") };
@@ -2141,17 +2182,51 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2141
2182
  const lastFullFetchAt = this.getStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY);
2142
2183
  if (!lastFullFetchAt)
2143
2184
  return false;
2185
+ const currentShopId = this.getCurrentShopId();
2186
+ const lastFullFetchShopId = this.getStorageItem(
2187
+ ORDER_LAST_FULL_FETCH_SHOP_ID_STORAGE_KEY
2188
+ );
2189
+ if (!currentShopId || !lastFullFetchShopId || currentShopId !== lastFullFetchShopId) {
2190
+ return false;
2191
+ }
2144
2192
  const parsed = (0, import_dayjs.default)(lastFullFetchAt);
2145
2193
  if (!parsed.isValid())
2146
2194
  return false;
2147
- const { startAt, endExclusiveAt } = this.getCurrentPullWindow();
2195
+ const { startAt, endExclusiveAt } = this.getCurrentOrderCacheWindow();
2148
2196
  return (parsed.isAfter(startAt) || parsed.isSame(startAt)) && parsed.isBefore(endExclusiveAt);
2149
2197
  }
2150
2198
  markOrderPulledAtNow() {
2199
+ const currentShopId = this.getCurrentShopId();
2200
+ if (!currentShopId)
2201
+ return;
2151
2202
  this.setStorageItem(
2152
2203
  ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY,
2153
2204
  (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
2154
2205
  );
2206
+ this.setStorageItem(
2207
+ ORDER_LAST_FULL_FETCH_SHOP_ID_STORAGE_KEY,
2208
+ currentShopId
2209
+ );
2210
+ }
2211
+ clearOrderSnapshotMarker() {
2212
+ this.setStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY, "");
2213
+ this.setStorageItem(ORDER_LAST_FULL_FETCH_SHOP_ID_STORAGE_KEY, "");
2214
+ }
2215
+ getCurrentShopId() {
2216
+ var _a;
2217
+ try {
2218
+ const appPlugin = this.core.getPlugin("app");
2219
+ const app = appPlugin == null ? void 0 : appPlugin.getApp();
2220
+ if (!app)
2221
+ return null;
2222
+ const coreData = app.data.store.getStore().getDataByModel("core");
2223
+ const shopId = (_a = coreData == null ? void 0 : coreData.core) == null ? void 0 : _a.id;
2224
+ if (shopId === void 0 || shopId === null || shopId === "")
2225
+ return null;
2226
+ return String(shopId);
2227
+ } catch {
2228
+ return null;
2229
+ }
2155
2230
  }
2156
2231
  getStorageItem(key) {
2157
2232
  var _a;
@@ -2178,7 +2253,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2178
2253
  } catch {
2179
2254
  }
2180
2255
  }
2181
- async loadOrdersFromSQLite() {
2256
+ async loadOrdersFromSQLite(options = {}) {
2182
2257
  if (!this.dbManager)
2183
2258
  return [];
2184
2259
  try {
@@ -2186,7 +2261,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2186
2261
  return (orders || []).map(
2187
2262
  (order) => this.normalizeOrderCollectionsForIngress(order, "loadOrdersFromSQLite")
2188
2263
  );
2189
- } catch {
2264
+ } catch (error) {
2265
+ if (options.throwOnError)
2266
+ throw error;
2190
2267
  return [];
2191
2268
  }
2192
2269
  }
@@ -2408,14 +2485,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2408
2485
  * 用于 SSE 全量拉取与营业日窗口裁剪。
2409
2486
  *
2410
2487
  * @example
2411
- * await this.replaceOrdersSnapshotInSQLite(orderList)
2488
+ * const { orders, persisted } = await this.replaceOrdersSnapshotInSQLite(orderList, 'refresh')
2412
2489
  */
2413
2490
  async replaceOrdersSnapshotInSQLite(orderList, source, protectedOrdersBeforeRemoteFetch = []) {
2414
2491
  if (!this.dbManager) {
2415
- return this.compactOrderListByIdentity(
2416
- orderList.map((order) => this.normalizeRemoteSyncedOrder(order)),
2417
- `${source}.snapshotNoDb`
2418
- ).list;
2492
+ return {
2493
+ orders: this.compactOrderListByIdentity(
2494
+ orderList.map((order) => this.normalizeRemoteSyncedOrder(order)),
2495
+ `${source}.snapshotNoDb`
2496
+ ).list,
2497
+ persisted: false
2498
+ };
2419
2499
  }
2420
2500
  const remoteSnapshot = (0, import_lodash_es.cloneDeep)(orderList).map(
2421
2501
  (order) => this.normalizeOrderCollectionsForIngress(order, `${source}.remoteIngress`)
@@ -2424,6 +2504,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2424
2504
  remoteSnapshot.map((order) => this.normalizeRemoteSyncedOrder(order)),
2425
2505
  `${source}.remoteSnapshot`
2426
2506
  ).list;
2507
+ let persisted = false;
2427
2508
  try {
2428
2509
  await this.runInOrderSQLiteSaveQueue(async () => {
2429
2510
  const existingOrders = typeof this.dbManager.getAll === "function" ? await this.dbManager.getAll(INDEXDB_STORE_NAME) : [];
@@ -2488,13 +2569,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2488
2569
  count: mergedSnapshot.length
2489
2570
  });
2490
2571
  });
2572
+ persisted = true;
2491
2573
  } catch (error) {
2492
2574
  this.logError("全量保存订单到 SQLite 失败", {
2493
2575
  error: error instanceof Error ? error.message : String(error),
2494
2576
  orderList: remoteSnapshot.length
2495
2577
  });
2496
2578
  }
2497
- return mergedSnapshot;
2579
+ return { orders: mergedSnapshot, persisted };
2498
2580
  }
2499
2581
  /**
2500
2582
  * 清空订单模块的内存数据和本地 SQLite 订单表。
@@ -2510,7 +2592,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2510
2592
  await this.dbManager.clear(INDEXDB_STORE_NAME);
2511
2593
  });
2512
2594
  }
2513
- this.setStorageItem(ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY, "");
2595
+ this.clearOrderSnapshotMarker();
2514
2596
  this.emitOrdersChanged([], "clear");
2515
2597
  }
2516
2598
  };
@@ -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
  * 刷新桥接器内的报价单列表。
@@ -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, _b, _c, _d, _e, _f;
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 = ((_b = (_a2 = params.scheduleModule).getScheduleList) == null ? void 0 : _b.call(_a2)) || [];
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 = (_c = params.scheduleModule).getScheduleListByIds) == null ? void 0 : _d.call(_c, [id])) || ((_f = (_e = params.scheduleModule).getScheduleByIds) == null ? void 0 : _f.call(_e, [id])) || [];
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,6 +807,8 @@ 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
  /**
@@ -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
- } else {
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));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.3.58",
4
+ "version": "2.3.59",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",