@pisell/pisellos 2.2.190 → 2.2.191
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/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +2 -1
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -7
- package/dist/modules/Cart/utils/cartProduct.js +13 -2
- package/dist/modules/Order/index.d.ts +1 -3
- package/dist/modules/Order/index.js +69 -95
- package/dist/modules/Order/types.d.ts +9 -6
- package/dist/modules/Order/utils.d.ts +9 -2
- package/dist/modules/Order/utils.js +36 -13
- package/dist/modules/SalesSummary/types.d.ts +3 -1
- package/dist/modules/SalesSummary/utils.js +7 -3
- package/dist/server/modules/order/index.d.ts +126 -6
- package/dist/server/modules/order/index.js +1204 -285
- package/dist/server/modules/order/types.d.ts +0 -2
- package/dist/server/modules/products/index.d.ts +90 -6
- package/dist/server/modules/products/index.js +1017 -361
- package/dist/solution/BaseSales/index.js +13 -7
- package/dist/solution/BaseSales/types.d.ts +8 -5
- package/dist/solution/BaseSales/types.js +2 -3
- package/dist/solution/BaseSales/utils/cartPromotion.js +7 -7
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +16 -13
- package/dist/solution/BaseSales/utils.d.ts +1 -1
- package/dist/solution/BaseSales/utils.js +22 -19
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/ScanOrder/index.js +7 -5
- package/dist/solution/ScanOrder/types.d.ts +8 -5
- package/dist/solution/ScanOrder/types.js +2 -3
- package/dist/solution/ScanOrder/utils.d.ts +1 -1
- package/dist/solution/ScanOrder/utils.js +26 -23
- package/dist/solution/VenueBooking/index.js +5 -3
- package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
- package/lib/model/strategy/adapter/promotion/index.js +0 -49
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +2 -1
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
- package/lib/modules/Cart/utils/cartProduct.js +9 -2
- package/lib/modules/Order/index.d.ts +1 -3
- package/lib/modules/Order/index.js +45 -58
- package/lib/modules/Order/types.d.ts +9 -6
- package/lib/modules/Order/utils.d.ts +9 -2
- package/lib/modules/Order/utils.js +41 -10
- package/lib/modules/SalesSummary/types.d.ts +3 -1
- package/lib/modules/SalesSummary/utils.js +5 -3
- package/lib/server/modules/order/index.d.ts +126 -6
- package/lib/server/modules/order/index.js +722 -42
- package/lib/server/modules/order/types.d.ts +0 -2
- package/lib/server/modules/products/index.d.ts +90 -6
- package/lib/server/modules/products/index.js +492 -30
- package/lib/solution/BaseSales/index.js +14 -5
- package/lib/solution/BaseSales/types.d.ts +8 -5
- package/lib/solution/BaseSales/utils/cartPromotion.js +6 -6
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +21 -14
- package/lib/solution/BaseSales/utils.d.ts +1 -1
- package/lib/solution/BaseSales/utils.js +11 -7
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/ScanOrder/index.js +4 -4
- package/lib/solution/ScanOrder/types.d.ts +8 -5
- package/lib/solution/ScanOrder/utils.d.ts +1 -1
- package/lib/solution/ScanOrder/utils.js +12 -8
- package/lib/solution/VenueBooking/index.js +2 -2
- package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
- package/package.json +1 -1
- package/dist/solution/Checkout/appointmentDemo.json +0 -1
- package/lib/solution/Checkout/appointmentDemo.json +0 -1
|
@@ -40,6 +40,15 @@ var INDEXDB_STORE_NAME = "orders";
|
|
|
40
40
|
var ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = "server_order_last_full_fetch_at";
|
|
41
41
|
var ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = "order_sync_throttle_ms";
|
|
42
42
|
var DEFAULT_ORDER_SYNC_THROTTLE_MS = 2e3;
|
|
43
|
+
var ORDER_FLOW_LOG_WINDOW_KEY = "__orderModuleFlowLogs";
|
|
44
|
+
var ORDER_WRITE_STATS_WINDOW_KEY = "__orderModuleWriteStats";
|
|
45
|
+
var ORDER_FLOW_LOG_MAX_LENGTH = 1e3;
|
|
46
|
+
var ORDER_SQLITE_DEDUPE_MS = 15e3;
|
|
47
|
+
var ORDER_SILENT_REFRESH_MIN_INTERVAL_MS = 3e4;
|
|
48
|
+
var ORDER_BUSINESS_WRITE_SOURCES = /* @__PURE__ */ new Set([
|
|
49
|
+
"upsertOrdersFromRemote",
|
|
50
|
+
"overwriteExistingOrder"
|
|
51
|
+
]);
|
|
43
52
|
var OrderModule = class extends import_BaseModule.BaseModule {
|
|
44
53
|
constructor(name, version) {
|
|
45
54
|
super(name, version);
|
|
@@ -51,6 +60,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
51
60
|
// Map<resource_id, OrderId[]> 资源到订单的倒排索引
|
|
52
61
|
this.resourceIdIndex = /* @__PURE__ */ new Map();
|
|
53
62
|
this.orderSQLiteSaveQueue = Promise.resolve();
|
|
63
|
+
/** 全局递增的 SQLite 写入序号,便于日志关联同一次操作 */
|
|
64
|
+
this.orderFlowWriteSeq = 0;
|
|
65
|
+
/** 按 storageKey 记录最近一次 SQLite 写入来源与时间,用于去重 */
|
|
66
|
+
this.recentSqliteWriteByStorageKey = /* @__PURE__ */ new Map();
|
|
67
|
+
/** 最近一次 SSE 全量拉取完成时间 */
|
|
68
|
+
this.lastServerFullFetchAtMs = 0;
|
|
54
69
|
}
|
|
55
70
|
async initialize(core, options) {
|
|
56
71
|
var _a, _b;
|
|
@@ -113,8 +128,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
113
128
|
this.store.list = [];
|
|
114
129
|
this.store.map = /* @__PURE__ */ new Map();
|
|
115
130
|
}
|
|
131
|
+
this.initOrderFlowLogs();
|
|
116
132
|
this.initOrderDataSource();
|
|
117
133
|
this.setupOrderSync();
|
|
134
|
+
this.pushOrderFlowLog("initialize.complete", {
|
|
135
|
+
hasDbManager: !!this.dbManager,
|
|
136
|
+
hasLogger: !!this.logger,
|
|
137
|
+
initialOrderCount: this.store.list.length,
|
|
138
|
+
createdAtQuery: this.store.createdAtQuery || null
|
|
139
|
+
});
|
|
118
140
|
this.logInfo("OrderServer模块初始化完成", {
|
|
119
141
|
hasDbManager: !!this.dbManager,
|
|
120
142
|
hasLogger: !!this.logger,
|
|
@@ -154,6 +176,297 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
154
176
|
}
|
|
155
177
|
} catch {
|
|
156
178
|
}
|
|
179
|
+
this.pushOrderFlowLog(`error.${title}`, metadata);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* 初始化 window 上的订单流程调试日志数组及辅助方法。
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* window.clearOrderModuleFlowLogs()
|
|
186
|
+
* // 操作完成后:
|
|
187
|
+
* copy(window.exportOrderModuleFlowLogs?.() || '[]')
|
|
188
|
+
*/
|
|
189
|
+
initOrderFlowLogs() {
|
|
190
|
+
try {
|
|
191
|
+
const win = typeof globalThis !== "undefined" ? globalThis.window : void 0;
|
|
192
|
+
if (!win)
|
|
193
|
+
return;
|
|
194
|
+
win[ORDER_FLOW_LOG_WINDOW_KEY] = [];
|
|
195
|
+
win[ORDER_WRITE_STATS_WINDOW_KEY] = {};
|
|
196
|
+
win.clearOrderModuleFlowLogs = () => {
|
|
197
|
+
win[ORDER_FLOW_LOG_WINDOW_KEY] = [];
|
|
198
|
+
win[ORDER_WRITE_STATS_WINDOW_KEY] = {};
|
|
199
|
+
this.orderFlowWriteSeq = 0;
|
|
200
|
+
this.recentSqliteWriteByStorageKey.clear();
|
|
201
|
+
this.lastServerFullFetchAtMs = 0;
|
|
202
|
+
this.pushOrderFlowLog("debug.clear", {});
|
|
203
|
+
};
|
|
204
|
+
win.exportOrderModuleFlowLogs = () => {
|
|
205
|
+
const logs = win[ORDER_FLOW_LOG_WINDOW_KEY] || [];
|
|
206
|
+
return JSON.stringify(logs, null, 2);
|
|
207
|
+
};
|
|
208
|
+
win.exportOrderModuleWriteStats = () => {
|
|
209
|
+
const stats = win[ORDER_WRITE_STATS_WINDOW_KEY] || {};
|
|
210
|
+
return JSON.stringify(stats, null, 2);
|
|
211
|
+
};
|
|
212
|
+
win.summarizeOrderModuleWrites = (topN = 20) => {
|
|
213
|
+
const stats = win[ORDER_WRITE_STATS_WINDOW_KEY] || {};
|
|
214
|
+
return Object.entries(stats).map(([storageKey, entries]) => {
|
|
215
|
+
const list = entries || [];
|
|
216
|
+
const sources = [...new Set(list.map((item) => item.source))];
|
|
217
|
+
const last = list[list.length - 1];
|
|
218
|
+
return {
|
|
219
|
+
storageKey,
|
|
220
|
+
orderId: (last == null ? void 0 : last.orderId) ?? null,
|
|
221
|
+
writeCount: list.length,
|
|
222
|
+
sources,
|
|
223
|
+
lastWriteAt: (last == null ? void 0 : last.ts) || ""
|
|
224
|
+
};
|
|
225
|
+
}).sort((a, b) => b.writeCount - a.writeCount).slice(0, topN);
|
|
226
|
+
};
|
|
227
|
+
this.pushOrderFlowLog("debug.init", {
|
|
228
|
+
logKey: ORDER_FLOW_LOG_WINDOW_KEY,
|
|
229
|
+
writeStatsKey: ORDER_WRITE_STATS_WINDOW_KEY,
|
|
230
|
+
helpers: [
|
|
231
|
+
"clearOrderModuleFlowLogs",
|
|
232
|
+
"exportOrderModuleFlowLogs",
|
|
233
|
+
"exportOrderModuleWriteStats",
|
|
234
|
+
"summarizeOrderModuleWrites"
|
|
235
|
+
]
|
|
236
|
+
});
|
|
237
|
+
} catch {
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* 写入 window 订单流程调试日志。
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* this.pushOrderFlowLog('mergeOrdersToStore.start', { count: 3 })
|
|
245
|
+
*/
|
|
246
|
+
pushOrderFlowLog(step, metadata) {
|
|
247
|
+
try {
|
|
248
|
+
const win = typeof globalThis !== "undefined" ? globalThis.window : void 0;
|
|
249
|
+
if (!win)
|
|
250
|
+
return;
|
|
251
|
+
if (!Array.isArray(win[ORDER_FLOW_LOG_WINDOW_KEY])) {
|
|
252
|
+
win[ORDER_FLOW_LOG_WINDOW_KEY] = [];
|
|
253
|
+
}
|
|
254
|
+
const entry = {
|
|
255
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
256
|
+
step,
|
|
257
|
+
metadata: metadata || {}
|
|
258
|
+
};
|
|
259
|
+
win[ORDER_FLOW_LOG_WINDOW_KEY].push(entry);
|
|
260
|
+
const logs = win[ORDER_FLOW_LOG_WINDOW_KEY];
|
|
261
|
+
if (logs.length > ORDER_FLOW_LOG_MAX_LENGTH) {
|
|
262
|
+
logs.splice(0, logs.length - ORDER_FLOW_LOG_MAX_LENGTH);
|
|
263
|
+
}
|
|
264
|
+
console.log(`[OrderFlow] ${step}`, metadata || {});
|
|
265
|
+
} catch {
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/** 当前内存 store 快照信息,供流程日志使用 */
|
|
269
|
+
getOrderStoreSnapshot() {
|
|
270
|
+
return {
|
|
271
|
+
storeListCount: this.store.list.length,
|
|
272
|
+
storeMapCount: this.store.map.size,
|
|
273
|
+
pendingSyncCount: this.pendingSyncMessages.length,
|
|
274
|
+
isProcessingSyncBatch: this.isProcessingSyncBatch,
|
|
275
|
+
isIdlePhase: this.isIdlePhase
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* 记录一次 SQLite 写入到 window 统计,用于排查同一订单被多次写入的原因。
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* this.trackOrderWrite('upsertOrdersFromRemote', 'bulkUpdate', orders, 'insert')
|
|
283
|
+
*/
|
|
284
|
+
trackOrderWrite(source, writeMethod, orders, mergeActions = {}, defaultMergeAction = "update") {
|
|
285
|
+
this.orderFlowWriteSeq += 1;
|
|
286
|
+
const writeSeq = this.orderFlowWriteSeq;
|
|
287
|
+
try {
|
|
288
|
+
const win = typeof globalThis !== "undefined" ? globalThis.window : void 0;
|
|
289
|
+
if (!win)
|
|
290
|
+
return writeSeq;
|
|
291
|
+
if (!win[ORDER_WRITE_STATS_WINDOW_KEY]) {
|
|
292
|
+
win[ORDER_WRITE_STATS_WINDOW_KEY] = {};
|
|
293
|
+
}
|
|
294
|
+
const stats = win[ORDER_WRITE_STATS_WINDOW_KEY];
|
|
295
|
+
for (const order of orders) {
|
|
296
|
+
const storageKey = this.getOrderStorageKey(order);
|
|
297
|
+
if (!storageKey)
|
|
298
|
+
continue;
|
|
299
|
+
const orderKey = order.order_id !== void 0 && order.order_id !== null ? this.getIdKey(order.order_id) : "";
|
|
300
|
+
const mergeAction = orderKey && mergeActions[orderKey] || defaultMergeAction;
|
|
301
|
+
const entry = {
|
|
302
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
303
|
+
writeSeq,
|
|
304
|
+
source,
|
|
305
|
+
writeMethod,
|
|
306
|
+
orderId: order.order_id ?? null,
|
|
307
|
+
storageKey,
|
|
308
|
+
mergeAction
|
|
309
|
+
};
|
|
310
|
+
if (!stats[storageKey])
|
|
311
|
+
stats[storageKey] = [];
|
|
312
|
+
stats[storageKey].push(entry);
|
|
313
|
+
}
|
|
314
|
+
} catch {
|
|
315
|
+
}
|
|
316
|
+
return writeSeq;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* 记录订单最近一次 SQLite 写入,供 pubsub 回声去重使用。
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* this.recordRecentSqliteWrite('upsertOrdersFromRemote', orders)
|
|
323
|
+
*/
|
|
324
|
+
recordRecentSqliteWrite(source, orders) {
|
|
325
|
+
const now = Date.now();
|
|
326
|
+
for (const order of orders) {
|
|
327
|
+
const storageKey = this.getOrderStorageKey(order);
|
|
328
|
+
if (!storageKey)
|
|
329
|
+
continue;
|
|
330
|
+
this.recentSqliteWriteByStorageKey.set(storageKey, { source, ts: now });
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* 过滤 pubsub 触发的冗余 SQLite patch(业务 API 刚写入过的 update 回声)。
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* const { toWrite, skipped } = this.filterRedundantPatchOrders('pubsub.bodyUpsert', orders, mergeActions)
|
|
338
|
+
*/
|
|
339
|
+
filterRedundantPatchOrders(source, orders, mergeActions) {
|
|
340
|
+
const eligibleSkipSources = /* @__PURE__ */ new Set(["pubsub.bodyUpsert", "pubsub.httpRefresh"]);
|
|
341
|
+
if (!eligibleSkipSources.has(source)) {
|
|
342
|
+
return { toWrite: orders, skipped: [] };
|
|
343
|
+
}
|
|
344
|
+
const now = Date.now();
|
|
345
|
+
const toWrite = [];
|
|
346
|
+
const skipped = [];
|
|
347
|
+
for (const order of orders) {
|
|
348
|
+
const storageKey = this.getOrderStorageKey(order);
|
|
349
|
+
if (!storageKey) {
|
|
350
|
+
toWrite.push(order);
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
const orderKey = order.order_id !== void 0 && order.order_id !== null ? this.getIdKey(order.order_id) : "";
|
|
354
|
+
const mergeAction = orderKey ? mergeActions[orderKey] : void 0;
|
|
355
|
+
if (mergeAction === "insert") {
|
|
356
|
+
toWrite.push(order);
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
const recent = this.recentSqliteWriteByStorageKey.get(storageKey);
|
|
360
|
+
if (recent && ORDER_BUSINESS_WRITE_SOURCES.has(recent.source) && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
|
|
361
|
+
skipped.push({
|
|
362
|
+
orderId: order.order_id ?? null,
|
|
363
|
+
storageKey,
|
|
364
|
+
reason: "skip_pubsub_echo_after_business_write",
|
|
365
|
+
lastSource: recent.source,
|
|
366
|
+
elapsedMs: now - recent.ts
|
|
367
|
+
});
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
toWrite.push(order);
|
|
371
|
+
}
|
|
372
|
+
return { toWrite, skipped };
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* 过滤 pubsub HTTP 增量拉取 ids:本地刚由业务 API 写入的单可跳过 HTTP。
|
|
376
|
+
*
|
|
377
|
+
* @example
|
|
378
|
+
* const ids = this.filterRedundantHttpRefreshIds([99331, 99332])
|
|
379
|
+
*/
|
|
380
|
+
filterRedundantHttpRefreshIds(ids) {
|
|
381
|
+
const now = Date.now();
|
|
382
|
+
const toFetch = [];
|
|
383
|
+
const skipped = [];
|
|
384
|
+
for (const id of ids) {
|
|
385
|
+
const existing = this.getOrderByOrderId(id);
|
|
386
|
+
if (!existing) {
|
|
387
|
+
toFetch.push(id);
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
const storageKey = this.getOrderStorageKey(existing);
|
|
391
|
+
const recent = storageKey ? this.recentSqliteWriteByStorageKey.get(storageKey) : void 0;
|
|
392
|
+
if (recent && recent.source === "upsertOrdersFromRemote" && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
|
|
393
|
+
skipped.push({
|
|
394
|
+
orderId: id,
|
|
395
|
+
lastSource: recent.source,
|
|
396
|
+
elapsedMs: now - recent.ts
|
|
397
|
+
});
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
toFetch.push(id);
|
|
401
|
+
}
|
|
402
|
+
return { toFetch, skipped };
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* 解析 pubsub 消息会走哪条同步分支,便于对照为何触发 HTTP 重拉或 body 直写。
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* this.resolveSyncMessageRoute(msg)
|
|
409
|
+
* // => { route: 'httpRefresh.batchIds', ... }
|
|
410
|
+
*/
|
|
411
|
+
resolveSyncMessageRoute(msg) {
|
|
412
|
+
var _a;
|
|
413
|
+
const hasBatchIds = Array.isArray(msg.ids) && msg.ids.length > 0;
|
|
414
|
+
const singleIdRaw = msg.id ?? msg.order_id;
|
|
415
|
+
const hasSingleId = !hasBatchIds && singleIdRaw !== void 0 && singleIdRaw !== null;
|
|
416
|
+
const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
|
|
417
|
+
if (hasBatchIds) {
|
|
418
|
+
return {
|
|
419
|
+
route: "httpRefresh.batchIds",
|
|
420
|
+
hasBatchIds: true,
|
|
421
|
+
hasSingleId: false,
|
|
422
|
+
hasNormalizedBody: !!normalizedBody,
|
|
423
|
+
singleId: null,
|
|
424
|
+
batchIds: msg.ids || [],
|
|
425
|
+
bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
if (hasSingleId && normalizedBody) {
|
|
429
|
+
return {
|
|
430
|
+
route: "bodyUpsert",
|
|
431
|
+
hasBatchIds: false,
|
|
432
|
+
hasSingleId: true,
|
|
433
|
+
hasNormalizedBody: true,
|
|
434
|
+
singleId: singleIdRaw,
|
|
435
|
+
batchIds: [],
|
|
436
|
+
bodyOrderId: normalizedBody.order_id ?? null
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
if (hasSingleId) {
|
|
440
|
+
return {
|
|
441
|
+
route: "httpRefresh.singleId",
|
|
442
|
+
hasBatchIds: false,
|
|
443
|
+
hasSingleId: true,
|
|
444
|
+
hasNormalizedBody: !!normalizedBody,
|
|
445
|
+
singleId: singleIdRaw,
|
|
446
|
+
batchIds: [],
|
|
447
|
+
bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
if ((_a = msg.relation_order_ids) == null ? void 0 : _a.length) {
|
|
451
|
+
return {
|
|
452
|
+
route: "httpRefresh.relationIds",
|
|
453
|
+
hasBatchIds: false,
|
|
454
|
+
hasSingleId: false,
|
|
455
|
+
hasNormalizedBody: !!normalizedBody,
|
|
456
|
+
singleId: null,
|
|
457
|
+
batchIds: msg.relation_order_ids,
|
|
458
|
+
bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
return {
|
|
462
|
+
route: "noop",
|
|
463
|
+
hasBatchIds: false,
|
|
464
|
+
hasSingleId: false,
|
|
465
|
+
hasNormalizedBody: !!normalizedBody,
|
|
466
|
+
singleId: null,
|
|
467
|
+
batchIds: [],
|
|
468
|
+
bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
|
|
469
|
+
};
|
|
157
470
|
}
|
|
158
471
|
getOrderSyncThrottleMs() {
|
|
159
472
|
const raw = localStorage.getItem(ORDER_SYNC_THROTTLE_MS_STORAGE_KEY);
|
|
@@ -165,14 +478,21 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
165
478
|
return DEFAULT_ORDER_SYNC_THROTTLE_MS;
|
|
166
479
|
}
|
|
167
480
|
async preload() {
|
|
481
|
+
this.pushOrderFlowLog("preload.start", this.getOrderStoreSnapshot());
|
|
168
482
|
const getData = async () => {
|
|
169
483
|
const orders = await this.loadOrdersByServer();
|
|
170
|
-
if (orders.length === 0)
|
|
484
|
+
if (orders.length === 0) {
|
|
485
|
+
this.pushOrderFlowLog("preload.empty", this.getOrderStoreSnapshot());
|
|
171
486
|
return;
|
|
487
|
+
}
|
|
172
488
|
this.store.list = (0, import_lodash_es.cloneDeep)(orders);
|
|
173
489
|
this.syncOrdersMap();
|
|
174
490
|
this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, this.store.list);
|
|
175
491
|
this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
492
|
+
this.pushOrderFlowLog("preload.done", {
|
|
493
|
+
...this.getOrderStoreSnapshot(),
|
|
494
|
+
loadedCount: orders.length
|
|
495
|
+
});
|
|
176
496
|
};
|
|
177
497
|
getData();
|
|
178
498
|
}
|
|
@@ -189,8 +509,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
189
509
|
async getLocalOrderByOrderId(orderId) {
|
|
190
510
|
const key = this.getIdKey(orderId);
|
|
191
511
|
const memoryOrder = this.store.map.get(key);
|
|
192
|
-
if (memoryOrder)
|
|
512
|
+
if (memoryOrder) {
|
|
513
|
+
this.pushOrderFlowLog("getLocalOrderByOrderId.hitMemory", { orderId, key });
|
|
193
514
|
return memoryOrder;
|
|
515
|
+
}
|
|
516
|
+
this.pushOrderFlowLog("getLocalOrderByOrderId.missMemory", { orderId, key });
|
|
194
517
|
const orders = await this.loadOrdersFromSQLite();
|
|
195
518
|
const localOrder = orders.find((order) => {
|
|
196
519
|
const shopOrderNumber = order == null ? void 0 : order.shop_order_number;
|
|
@@ -208,11 +531,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
208
531
|
return localOrder;
|
|
209
532
|
}
|
|
210
533
|
async loadOrdersByServer() {
|
|
211
|
-
var _a;
|
|
534
|
+
var _a, _b;
|
|
212
535
|
let orderList = [];
|
|
536
|
+
this.pushOrderFlowLog("loadOrdersByServer.start", {
|
|
537
|
+
...this.getOrderStoreSnapshot(),
|
|
538
|
+
query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null,
|
|
539
|
+
hasOrderDataSource: !!this.orderDataSource
|
|
540
|
+
});
|
|
213
541
|
this.logInfo("loadOrdersByServer-开始", {
|
|
214
542
|
hasOrderDataSource: !!this.orderDataSource,
|
|
215
|
-
query: ((
|
|
543
|
+
query: ((_b = this.store) == null ? void 0 : _b.createdAtQuery) || null
|
|
216
544
|
});
|
|
217
545
|
if (this.orderDataSource) {
|
|
218
546
|
try {
|
|
@@ -222,16 +550,23 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
222
550
|
}
|
|
223
551
|
});
|
|
224
552
|
orderList = data || [];
|
|
553
|
+
this.pushOrderFlowLog("loadOrdersByServer.sseSuccess", { count: orderList.length });
|
|
225
554
|
this.logInfo("loadOrdersByServer-SSE拉取成功", {
|
|
226
555
|
count: orderList.length
|
|
227
556
|
});
|
|
228
557
|
this.markOrderPulledAtNow();
|
|
558
|
+
this.lastServerFullFetchAtMs = Date.now();
|
|
229
559
|
} catch {
|
|
230
560
|
orderList = [];
|
|
561
|
+
this.pushOrderFlowLog("loadOrdersByServer.sseFailed", {});
|
|
231
562
|
this.logInfo("loadOrdersByServer-SSE拉取失败,回退为空数组");
|
|
232
563
|
}
|
|
233
564
|
}
|
|
234
|
-
await this.
|
|
565
|
+
await this.replaceOrdersSnapshotInSQLite(orderList, "loadOrdersByServer");
|
|
566
|
+
this.pushOrderFlowLog("loadOrdersByServer.done", {
|
|
567
|
+
count: orderList.length,
|
|
568
|
+
...this.getOrderStoreSnapshot()
|
|
569
|
+
});
|
|
235
570
|
this.logInfo("loadOrdersByServer-结束", {
|
|
236
571
|
count: orderList.length
|
|
237
572
|
});
|
|
@@ -245,6 +580,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
245
580
|
*/
|
|
246
581
|
async silentRefresh() {
|
|
247
582
|
const startTime = Date.now();
|
|
583
|
+
const elapsedSinceFullFetch = Date.now() - this.lastServerFullFetchAtMs;
|
|
584
|
+
if (this.lastServerFullFetchAtMs > 0 && elapsedSinceFullFetch < ORDER_SILENT_REFRESH_MIN_INTERVAL_MS) {
|
|
585
|
+
this.pushOrderFlowLog("silentRefresh.skipped", {
|
|
586
|
+
elapsedMs: elapsedSinceFullFetch,
|
|
587
|
+
minIntervalMs: ORDER_SILENT_REFRESH_MIN_INTERVAL_MS,
|
|
588
|
+
...this.getOrderStoreSnapshot()
|
|
589
|
+
});
|
|
590
|
+
return this.store.list;
|
|
591
|
+
}
|
|
592
|
+
this.pushOrderFlowLog("silentRefresh.start", {
|
|
593
|
+
...this.getOrderStoreSnapshot(),
|
|
594
|
+
callerHint: "Server.refreshOrdersInBackground 或其他调用方"
|
|
595
|
+
});
|
|
248
596
|
this.logInfo("silentRefresh 开始");
|
|
249
597
|
try {
|
|
250
598
|
const orders = await this.loadOrdersByServer();
|
|
@@ -253,11 +601,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
253
601
|
this.syncOrdersMap();
|
|
254
602
|
this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, this.store.list);
|
|
255
603
|
await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
|
|
604
|
+
this.pushOrderFlowLog("silentRefresh.done", {
|
|
605
|
+
orderCount: orders.length,
|
|
606
|
+
durationMs: Date.now() - startTime,
|
|
607
|
+
...this.getOrderStoreSnapshot()
|
|
608
|
+
});
|
|
256
609
|
this.logInfo("silentRefresh 完成", {
|
|
257
610
|
orderCount: orders.length,
|
|
258
611
|
duration: `${Date.now() - startTime}ms`
|
|
259
612
|
});
|
|
260
613
|
} else {
|
|
614
|
+
this.pushOrderFlowLog("silentRefresh.empty", { durationMs: Date.now() - startTime });
|
|
261
615
|
this.logInfo("silentRefresh: 服务器未返回数据");
|
|
262
616
|
}
|
|
263
617
|
return this.store.list;
|
|
@@ -289,6 +643,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
289
643
|
this.logInfo("overwriteExistingOrder-本地不存在该订单,跳过", { orderId });
|
|
290
644
|
return { overwritten: false };
|
|
291
645
|
}
|
|
646
|
+
this.pushOrderFlowLog("overwriteExistingOrder.start", {
|
|
647
|
+
orderId,
|
|
648
|
+
storageKey: this.getOrderStorageKey(fresh),
|
|
649
|
+
...this.getOrderStoreSnapshot(),
|
|
650
|
+
callerHint: "Server.handleUpdateLocalOrder 本地已存在时"
|
|
651
|
+
});
|
|
292
652
|
this.logInfo("overwriteExistingOrder-开始覆盖", {
|
|
293
653
|
orderId,
|
|
294
654
|
storeOrderCountBefore: this.store.list.length
|
|
@@ -300,7 +660,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
300
660
|
return this.getIdKey(id) === key ? fresh : order;
|
|
301
661
|
});
|
|
302
662
|
this.syncOrdersMap();
|
|
303
|
-
await this.
|
|
663
|
+
await this.updateOrderInSQLite(fresh, "overwriteExistingOrder");
|
|
664
|
+
this.pushOrderFlowLog("overwriteExistingOrder.done", {
|
|
665
|
+
orderId,
|
|
666
|
+
...this.getOrderStoreSnapshot()
|
|
667
|
+
});
|
|
304
668
|
this.logInfo("overwriteExistingOrder-结束", {
|
|
305
669
|
orderId,
|
|
306
670
|
storeOrderCountAfter: this.store.list.length
|
|
@@ -317,8 +681,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
317
681
|
this.logInfo("upsertOrdersFromRemote-订单列表为空", {});
|
|
318
682
|
return;
|
|
319
683
|
}
|
|
684
|
+
this.pushOrderFlowLog("upsertOrdersFromRemote.start", {
|
|
685
|
+
count: freshOrders.length,
|
|
686
|
+
orderIds: freshOrders.map((o) => o.order_id).filter((id) => id !== void 0 && id !== null),
|
|
687
|
+
callerHint: "Server.handleUpdateLocalOrder / handleOrderSalesDetail / handleUpdateLocalOrdersBatch"
|
|
688
|
+
});
|
|
320
689
|
this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length });
|
|
321
|
-
await this.mergeOrdersToStore(freshOrders);
|
|
690
|
+
await this.mergeOrdersToStore(freshOrders, "upsertOrdersFromRemote");
|
|
322
691
|
}
|
|
323
692
|
/**
|
|
324
693
|
* 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
|
|
@@ -426,7 +795,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
426
795
|
this.orderDataSource.run({
|
|
427
796
|
pubsub: {
|
|
428
797
|
callback: (res) => {
|
|
429
|
-
console.log("orderDataSource");
|
|
798
|
+
console.log("orderDataSource", res);
|
|
430
799
|
const pubsubReceivedAt = Date.now();
|
|
431
800
|
const message = this.normalizeOrderSyncMessage(res);
|
|
432
801
|
if (!message)
|
|
@@ -434,6 +803,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
434
803
|
message._pubsubReceivedAt = pubsubReceivedAt;
|
|
435
804
|
this.pendingSyncMessages.push(message);
|
|
436
805
|
const throttleMs = this.getOrderSyncThrottleMs();
|
|
806
|
+
const routeInfo = this.resolveSyncMessageRoute(message);
|
|
807
|
+
this.pushOrderFlowLog("orderSync.received", {
|
|
808
|
+
id: message.id ?? null,
|
|
809
|
+
order_id: message.order_id ?? null,
|
|
810
|
+
type: message.type ?? null,
|
|
811
|
+
pendingCount: this.pendingSyncMessages.length,
|
|
812
|
+
throttleMs,
|
|
813
|
+
...routeInfo,
|
|
814
|
+
duplicateRiskHint: routeInfo.route === "httpRefresh.batchIds" && routeInfo.hasNormalizedBody ? "有 body 但被 ids 优先,会走 HTTP 重拉" : routeInfo.route === "bodyUpsert" ? "body 直写,可能与 upsertOrdersFromRemote 重复" : null
|
|
815
|
+
});
|
|
437
816
|
this.logInfo("orderSync-收到消息并入队", {
|
|
438
817
|
id: message.id ?? null,
|
|
439
818
|
order_id: message.order_id ?? null,
|
|
@@ -459,6 +838,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
459
838
|
return;
|
|
460
839
|
if (this.isIdlePhase) {
|
|
461
840
|
this.isIdlePhase = false;
|
|
841
|
+
this.pushOrderFlowLog("orderSync.flushImmediate", {
|
|
842
|
+
pendingCount: this.pendingSyncMessages.length
|
|
843
|
+
});
|
|
462
844
|
this.logInfo("orderSync-首条消息立即触发处理");
|
|
463
845
|
void this.flushOrderSyncMessagesByThrottle();
|
|
464
846
|
return;
|
|
@@ -466,6 +848,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
466
848
|
if (this.syncTimer)
|
|
467
849
|
return;
|
|
468
850
|
const throttleMs = this.getOrderSyncThrottleMs();
|
|
851
|
+
this.pushOrderFlowLog("orderSync.flushScheduled", {
|
|
852
|
+
pendingCount: this.pendingSyncMessages.length,
|
|
853
|
+
throttleMs
|
|
854
|
+
});
|
|
469
855
|
this.syncTimer = setTimeout(() => {
|
|
470
856
|
this.syncTimer = void 0;
|
|
471
857
|
void this.flushOrderSyncMessagesByThrottle();
|
|
@@ -483,6 +869,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
483
869
|
return;
|
|
484
870
|
}
|
|
485
871
|
this.isProcessingSyncBatch = true;
|
|
872
|
+
this.pushOrderFlowLog("orderSync.flushStart", {
|
|
873
|
+
pendingCount: this.pendingSyncMessages.length
|
|
874
|
+
});
|
|
486
875
|
try {
|
|
487
876
|
await this.processOrderSyncMessages();
|
|
488
877
|
} finally {
|
|
@@ -506,12 +895,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
506
895
|
* await this.processOrderSyncMessages()
|
|
507
896
|
*/
|
|
508
897
|
async processOrderSyncMessages() {
|
|
509
|
-
var _a;
|
|
510
898
|
const messages = [...this.pendingSyncMessages];
|
|
511
899
|
this.pendingSyncMessages = [];
|
|
512
900
|
if (messages.length === 0)
|
|
513
901
|
return;
|
|
514
902
|
const batchProcessStartAt = Date.now();
|
|
903
|
+
this.pushOrderFlowLog("processOrderSyncMessages.start", {
|
|
904
|
+
messageCount: messages.length,
|
|
905
|
+
...this.getOrderStoreSnapshot()
|
|
906
|
+
});
|
|
515
907
|
const earliestReceivedAt = Math.min(
|
|
516
908
|
...messages.map((m) => m._pubsubReceivedAt ?? batchProcessStartAt)
|
|
517
909
|
);
|
|
@@ -523,39 +915,74 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
523
915
|
});
|
|
524
916
|
const upsertOrders = /* @__PURE__ */ new Map();
|
|
525
917
|
const refreshIds = [];
|
|
526
|
-
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
918
|
+
messages.forEach((msg, msgIndex) => {
|
|
919
|
+
const routeInfo = this.resolveSyncMessageRoute(msg);
|
|
920
|
+
this.pushOrderFlowLog("processOrderSyncMessages.messageRoute", {
|
|
921
|
+
msgIndex,
|
|
922
|
+
...routeInfo
|
|
923
|
+
});
|
|
924
|
+
const hasBatchIds = routeInfo.hasBatchIds;
|
|
925
|
+
const singleId = routeInfo.singleId;
|
|
926
|
+
const hasSingleId = routeInfo.hasSingleId;
|
|
927
|
+
const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
|
|
928
|
+
if (routeInfo.route === "bodyUpsert" && normalizedBody) {
|
|
533
929
|
upsertOrders.set(this.getIdKey(normalizedBody.order_id), normalizedBody);
|
|
534
|
-
|
|
930
|
+
return;
|
|
535
931
|
}
|
|
536
932
|
if (hasBatchIds)
|
|
537
|
-
refreshIds.push(...
|
|
538
|
-
else if (
|
|
933
|
+
refreshIds.push(...routeInfo.batchIds);
|
|
934
|
+
else if (routeInfo.route === "httpRefresh.singleId" && singleId !== null)
|
|
539
935
|
refreshIds.push(singleId);
|
|
540
|
-
else if (
|
|
541
|
-
refreshIds.push(...
|
|
542
|
-
}
|
|
936
|
+
else if (routeInfo.route === "httpRefresh.relationIds")
|
|
937
|
+
refreshIds.push(...routeInfo.batchIds);
|
|
938
|
+
});
|
|
543
939
|
const uniqueRefreshIds = this.uniqueOrderIds(refreshIds);
|
|
544
940
|
const upsertList = [...upsertOrders.values()];
|
|
941
|
+
this.pushOrderFlowLog("processOrderSyncMessages.deduped", {
|
|
942
|
+
upsertCount: upsertList.length,
|
|
943
|
+
upsertOrderIds: upsertList.map((o) => o.order_id),
|
|
944
|
+
refreshIdCount: uniqueRefreshIds.length,
|
|
945
|
+
refreshIds: uniqueRefreshIds,
|
|
946
|
+
willCallMergeTimes: (upsertList.length > 0 ? 1 : 0) + (uniqueRefreshIds.length > 0 ? 1 : 0)
|
|
947
|
+
});
|
|
545
948
|
this.logInfo("processOrderSyncMessages-去重完成", {
|
|
546
949
|
upsertCount: upsertList.length,
|
|
547
950
|
refreshIdCount: uniqueRefreshIds.length
|
|
548
951
|
});
|
|
549
|
-
if (upsertList.length > 0)
|
|
550
|
-
await this.mergeOrdersToStore(upsertList);
|
|
952
|
+
if (upsertList.length > 0) {
|
|
953
|
+
await this.mergeOrdersToStore(upsertList, "pubsub.bodyUpsert");
|
|
954
|
+
}
|
|
551
955
|
if (uniqueRefreshIds.length > 0) {
|
|
552
|
-
const
|
|
553
|
-
if (
|
|
554
|
-
|
|
956
|
+
const { toFetch, skipped } = this.filterRedundantHttpRefreshIds(uniqueRefreshIds);
|
|
957
|
+
if (skipped.length > 0) {
|
|
958
|
+
this.pushOrderFlowLog("processOrderSyncMessages.httpRefreshFiltered", {
|
|
959
|
+
requestedIds: uniqueRefreshIds,
|
|
960
|
+
skippedIds: skipped.map((item) => item.orderId),
|
|
961
|
+
skipped
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
if (toFetch.length > 0) {
|
|
965
|
+
const freshOrders = await this.fetchOrdersByHttp(toFetch);
|
|
966
|
+
if (freshOrders.length > 0) {
|
|
967
|
+
await this.mergeOrdersToStore(freshOrders, "pubsub.httpRefresh");
|
|
968
|
+
} else {
|
|
969
|
+
this.pushOrderFlowLog("processOrderSyncMessages.httpRefreshEmpty", {
|
|
970
|
+
refreshIds: toFetch
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
}
|
|
555
974
|
}
|
|
556
|
-
if (upsertList.length === 0 && uniqueRefreshIds.length === 0)
|
|
975
|
+
if (upsertList.length === 0 && uniqueRefreshIds.length === 0) {
|
|
976
|
+
this.pushOrderFlowLog("processOrderSyncMessages.noop", {});
|
|
557
977
|
return;
|
|
978
|
+
}
|
|
558
979
|
const batchProcessEndAt = Date.now();
|
|
980
|
+
this.pushOrderFlowLog("processOrderSyncMessages.done", {
|
|
981
|
+
upsertCount: upsertList.length,
|
|
982
|
+
refreshIdCount: uniqueRefreshIds.length,
|
|
983
|
+
batchProcessDurationMs: batchProcessEndAt - batchProcessStartAt,
|
|
984
|
+
...this.getOrderStoreSnapshot()
|
|
985
|
+
});
|
|
559
986
|
this.logInfo("processOrderSyncMessages-结束", {
|
|
560
987
|
upsertCount: upsertList.length,
|
|
561
988
|
refreshIdCount: uniqueRefreshIds.length,
|
|
@@ -577,9 +1004,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
577
1004
|
async fetchOrdersByHttp(ids) {
|
|
578
1005
|
if (!this.orderDataSource || ids.length === 0)
|
|
579
1006
|
return [];
|
|
1007
|
+
this.pushOrderFlowLog("fetchOrdersByHttp.start", { ids, count: ids.length });
|
|
580
1008
|
try {
|
|
581
1009
|
if (typeof this.orderDataSource.fetchOrdersByIds === "function") {
|
|
582
1010
|
const orderList2 = await this.orderDataSource.fetchOrdersByIds(ids);
|
|
1011
|
+
this.pushOrderFlowLog("fetchOrdersByHttp.done", {
|
|
1012
|
+
ids,
|
|
1013
|
+
count: (orderList2 == null ? void 0 : orderList2.length) || 0,
|
|
1014
|
+
via: "fetchOrdersByIds"
|
|
1015
|
+
});
|
|
583
1016
|
return orderList2 || [];
|
|
584
1017
|
}
|
|
585
1018
|
const orderList = await this.orderDataSource.run({
|
|
@@ -587,15 +1020,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
587
1020
|
query: { ids }
|
|
588
1021
|
}
|
|
589
1022
|
});
|
|
1023
|
+
this.pushOrderFlowLog("fetchOrdersByHttp.done", {
|
|
1024
|
+
ids,
|
|
1025
|
+
count: (orderList == null ? void 0 : orderList.length) || 0,
|
|
1026
|
+
via: "run.http"
|
|
1027
|
+
});
|
|
590
1028
|
return orderList || [];
|
|
591
1029
|
} catch {
|
|
1030
|
+
this.pushOrderFlowLog("fetchOrdersByHttp.failed", { ids });
|
|
592
1031
|
return [];
|
|
593
1032
|
}
|
|
594
1033
|
}
|
|
595
1034
|
/**
|
|
596
1035
|
* 将增量订单合并到 store
|
|
597
1036
|
*/
|
|
598
|
-
async mergeOrdersToStore(freshOrders) {
|
|
1037
|
+
async mergeOrdersToStore(freshOrders, source) {
|
|
1038
|
+
this.pushOrderFlowLog("mergeOrdersToStore.start", {
|
|
1039
|
+
source,
|
|
1040
|
+
freshOrderCount: freshOrders.length,
|
|
1041
|
+
freshOrderIds: freshOrders.map((o) => o.order_id).filter((id) => id !== void 0 && id !== null),
|
|
1042
|
+
...this.getOrderStoreSnapshot()
|
|
1043
|
+
});
|
|
599
1044
|
this.logInfo("mergeOrdersToStore-开始", {
|
|
600
1045
|
freshOrderCount: freshOrders.length,
|
|
601
1046
|
storeOrderCountBefore: this.store.list.length
|
|
@@ -608,6 +1053,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
608
1053
|
freshMap.set(this.getIdKey(id), order);
|
|
609
1054
|
}
|
|
610
1055
|
const uniqueFreshCount = freshMap.size;
|
|
1056
|
+
const patchedOrders = [...freshMap.values()];
|
|
1057
|
+
const mergeActions = {};
|
|
611
1058
|
const updatedList = this.store.list.map((order) => {
|
|
612
1059
|
const id = order.order_id;
|
|
613
1060
|
if (id === void 0 || id === null)
|
|
@@ -617,14 +1064,32 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
617
1064
|
return order;
|
|
618
1065
|
const fresh = freshMap.get(key);
|
|
619
1066
|
freshMap.delete(key);
|
|
1067
|
+
mergeActions[key] = "update";
|
|
620
1068
|
return fresh;
|
|
621
1069
|
});
|
|
622
1070
|
for (const order of freshMap.values()) {
|
|
1071
|
+
const id = order.order_id;
|
|
1072
|
+
if (id !== void 0 && id !== null) {
|
|
1073
|
+
mergeActions[this.getIdKey(id)] = "insert";
|
|
1074
|
+
}
|
|
623
1075
|
updatedList.push(order);
|
|
624
1076
|
}
|
|
1077
|
+
const insertCount = Object.values(mergeActions).filter((v) => v === "insert").length;
|
|
1078
|
+
const updateCount = Object.values(mergeActions).filter((v) => v === "update").length;
|
|
625
1079
|
this.store.list = updatedList;
|
|
626
1080
|
this.syncOrdersMap();
|
|
627
|
-
await this.
|
|
1081
|
+
await this.patchOrdersInSQLite(patchedOrders, source, mergeActions);
|
|
1082
|
+
this.pushOrderFlowLog("mergeOrdersToStore.done", {
|
|
1083
|
+
source,
|
|
1084
|
+
uniqueFreshCount,
|
|
1085
|
+
insertCount,
|
|
1086
|
+
updateCount,
|
|
1087
|
+
patchedCount: patchedOrders.length,
|
|
1088
|
+
patchedOrderIds: patchedOrders.map((o) => o.order_id),
|
|
1089
|
+
patchedStorageKeys: patchedOrders.map((o) => this.getOrderStorageKey(o)),
|
|
1090
|
+
mergeActions,
|
|
1091
|
+
...this.getOrderStoreSnapshot()
|
|
1092
|
+
});
|
|
628
1093
|
this.logInfo("mergeOrdersToStore-结束", {
|
|
629
1094
|
uniqueFreshCount,
|
|
630
1095
|
storeOrderCountAfter: this.store.list.length
|
|
@@ -674,6 +1139,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
674
1139
|
getIdKey(id) {
|
|
675
1140
|
return String(id);
|
|
676
1141
|
}
|
|
1142
|
+
/**
|
|
1143
|
+
* 解析订单 SQLite 主键,规则与宿主 OrderDataSource.getOrderStorageKey 一致。
|
|
1144
|
+
*
|
|
1145
|
+
* @example
|
|
1146
|
+
* const key = this.getOrderStorageKey({ order_id: 1001, external_sale_number: 'S-1001' })
|
|
1147
|
+
* // => 'S-1001'
|
|
1148
|
+
*/
|
|
1149
|
+
getOrderStorageKey(order) {
|
|
1150
|
+
const externalSaleNumber = order == null ? void 0 : order.external_sale_number;
|
|
1151
|
+
if (externalSaleNumber !== void 0 && externalSaleNumber !== null && externalSaleNumber !== "") {
|
|
1152
|
+
return String(externalSaleNumber);
|
|
1153
|
+
}
|
|
1154
|
+
const orderId = order == null ? void 0 : order.order_id;
|
|
1155
|
+
if (orderId !== void 0 && orderId !== null && orderId !== "") {
|
|
1156
|
+
return String(orderId);
|
|
1157
|
+
}
|
|
1158
|
+
return "";
|
|
1159
|
+
}
|
|
677
1160
|
/**
|
|
678
1161
|
* 当前订单拉取窗口:
|
|
679
1162
|
* - 优先使用 createdAtQuery.sales_time_between(已按营业日边界初始化)
|
|
@@ -745,12 +1228,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
745
1228
|
}
|
|
746
1229
|
}
|
|
747
1230
|
/**
|
|
748
|
-
* 串行执行订单 SQLite
|
|
1231
|
+
* 串行执行订单 SQLite 写入任务,避免快照替换与增量 upsert 并发交错。
|
|
749
1232
|
*
|
|
750
1233
|
* @example
|
|
751
1234
|
* await this.runInOrderSQLiteSaveQueue(async () => {
|
|
752
|
-
* await this.dbManager.
|
|
753
|
-
* await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, orders)
|
|
1235
|
+
* await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, orders)
|
|
754
1236
|
* })
|
|
755
1237
|
*/
|
|
756
1238
|
async runInOrderSQLiteSaveQueue(task) {
|
|
@@ -759,33 +1241,231 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
759
1241
|
return queuedTask;
|
|
760
1242
|
}
|
|
761
1243
|
/**
|
|
762
|
-
*
|
|
1244
|
+
* 批量增量 upsert 订单到 SQLite,不清空表;用于 pubsub / HTTP 增量合并。
|
|
763
1245
|
*
|
|
764
1246
|
* @example
|
|
765
|
-
* await this.
|
|
1247
|
+
* await this.patchOrdersInSQLite(freshOrders)
|
|
766
1248
|
*/
|
|
767
|
-
async
|
|
768
|
-
if (!this.dbManager)
|
|
1249
|
+
async patchOrdersInSQLite(orders, source, mergeActions = {}) {
|
|
1250
|
+
if (!this.dbManager || orders.length === 0) {
|
|
1251
|
+
this.pushOrderFlowLog("patchOrdersInSQLite.skip", {
|
|
1252
|
+
source,
|
|
1253
|
+
hasDbManager: !!this.dbManager,
|
|
1254
|
+
inputCount: orders.length
|
|
1255
|
+
});
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).filter((order) => this.getOrderStorageKey(order));
|
|
1259
|
+
if (ordersSnapshot.length === 0) {
|
|
1260
|
+
this.pushOrderFlowLog("patchOrdersInSQLite.skipNoStorageKey", {
|
|
1261
|
+
source,
|
|
1262
|
+
inputCount: orders.length
|
|
1263
|
+
});
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
const { toWrite, skipped } = this.filterRedundantPatchOrders(
|
|
1267
|
+
source,
|
|
1268
|
+
ordersSnapshot,
|
|
1269
|
+
mergeActions
|
|
1270
|
+
);
|
|
1271
|
+
if (skipped.length > 0) {
|
|
1272
|
+
this.pushOrderFlowLog("patchOrdersInSQLite.dedupeSkipped", {
|
|
1273
|
+
source,
|
|
1274
|
+
skippedCount: skipped.length,
|
|
1275
|
+
skipped
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
if (toWrite.length === 0) {
|
|
1279
|
+
this.pushOrderFlowLog("patchOrdersInSQLite.skipAllDeduped", {
|
|
1280
|
+
source,
|
|
1281
|
+
inputCount: ordersSnapshot.length,
|
|
1282
|
+
skipped
|
|
1283
|
+
});
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
1286
|
+
try {
|
|
1287
|
+
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
1288
|
+
let writeMethod = "none";
|
|
1289
|
+
this.pushOrderFlowLog("patchOrdersInSQLite.start", {
|
|
1290
|
+
source,
|
|
1291
|
+
count: toWrite.length,
|
|
1292
|
+
orderIds: toWrite.map((o) => o.order_id),
|
|
1293
|
+
storageKeys: toWrite.map((o) => this.getOrderStorageKey(o)),
|
|
1294
|
+
dedupedCount: skipped.length
|
|
1295
|
+
});
|
|
1296
|
+
this.logInfo("patchOrdersInSQLite-开始", {
|
|
1297
|
+
source,
|
|
1298
|
+
count: toWrite.length
|
|
1299
|
+
});
|
|
1300
|
+
if (typeof this.dbManager.bulkUpdate === "function") {
|
|
1301
|
+
writeMethod = "bulkUpdate";
|
|
1302
|
+
await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, toWrite);
|
|
1303
|
+
} else if (typeof this.dbManager.bulkAdd === "function") {
|
|
1304
|
+
writeMethod = "bulkAdd";
|
|
1305
|
+
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, toWrite);
|
|
1306
|
+
} else if (typeof this.dbManager.update === "function") {
|
|
1307
|
+
writeMethod = "update";
|
|
1308
|
+
for (const order of toWrite) {
|
|
1309
|
+
await this.dbManager.update(INDEXDB_STORE_NAME, order);
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
const writeSeq = this.trackOrderWrite(source, writeMethod, toWrite, mergeActions);
|
|
1313
|
+
this.recordRecentSqliteWrite(source, toWrite);
|
|
1314
|
+
this.pushOrderFlowLog("patchOrdersInSQLite.done", {
|
|
1315
|
+
source,
|
|
1316
|
+
writeSeq,
|
|
1317
|
+
count: toWrite.length,
|
|
1318
|
+
writeMethod,
|
|
1319
|
+
dedupedCount: skipped.length
|
|
1320
|
+
});
|
|
1321
|
+
this.logInfo("patchOrdersInSQLite-完成", {
|
|
1322
|
+
source,
|
|
1323
|
+
count: toWrite.length,
|
|
1324
|
+
dedupedCount: skipped.length
|
|
1325
|
+
});
|
|
1326
|
+
});
|
|
1327
|
+
} catch (error) {
|
|
1328
|
+
this.pushOrderFlowLog("patchOrdersInSQLite.error", {
|
|
1329
|
+
source,
|
|
1330
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1331
|
+
orderCount: ordersSnapshot.length
|
|
1332
|
+
});
|
|
1333
|
+
this.logError("增量保存订单到 SQLite 失败", {
|
|
1334
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1335
|
+
orderCount: ordersSnapshot.length
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
/**
|
|
1340
|
+
* 单条 upsert 订单到 SQLite;用于 overwriteExistingOrder 等单条覆盖场景。
|
|
1341
|
+
*
|
|
1342
|
+
* @example
|
|
1343
|
+
* await this.updateOrderInSQLite(freshOrder)
|
|
1344
|
+
*/
|
|
1345
|
+
async updateOrderInSQLite(order, source) {
|
|
1346
|
+
if (!this.dbManager || !this.getOrderStorageKey(order)) {
|
|
1347
|
+
this.pushOrderFlowLog("updateOrderInSQLite.skip", {
|
|
1348
|
+
source,
|
|
1349
|
+
hasDbManager: !!this.dbManager,
|
|
1350
|
+
orderId: (order == null ? void 0 : order.order_id) ?? null
|
|
1351
|
+
});
|
|
769
1352
|
return;
|
|
1353
|
+
}
|
|
1354
|
+
const orderSnapshot = (0, import_lodash_es.cloneDeep)(order);
|
|
1355
|
+
try {
|
|
1356
|
+
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
1357
|
+
let writeMethod = "none";
|
|
1358
|
+
this.pushOrderFlowLog("updateOrderInSQLite.start", {
|
|
1359
|
+
source,
|
|
1360
|
+
orderId: orderSnapshot.order_id ?? null,
|
|
1361
|
+
storageKey: this.getOrderStorageKey(orderSnapshot)
|
|
1362
|
+
});
|
|
1363
|
+
this.logInfo("updateOrderInSQLite-开始", {
|
|
1364
|
+
source,
|
|
1365
|
+
orderId: orderSnapshot.order_id ?? null,
|
|
1366
|
+
storageKey: this.getOrderStorageKey(orderSnapshot)
|
|
1367
|
+
});
|
|
1368
|
+
if (typeof this.dbManager.update === "function") {
|
|
1369
|
+
writeMethod = "update";
|
|
1370
|
+
await this.dbManager.update(INDEXDB_STORE_NAME, orderSnapshot);
|
|
1371
|
+
} else if (typeof this.dbManager.bulkUpdate === "function") {
|
|
1372
|
+
writeMethod = "bulkUpdate";
|
|
1373
|
+
await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, [orderSnapshot]);
|
|
1374
|
+
} else if (typeof this.dbManager.bulkAdd === "function") {
|
|
1375
|
+
writeMethod = "bulkAdd";
|
|
1376
|
+
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, [orderSnapshot]);
|
|
1377
|
+
}
|
|
1378
|
+
const writeSeq = this.trackOrderWrite(
|
|
1379
|
+
source,
|
|
1380
|
+
writeMethod,
|
|
1381
|
+
[orderSnapshot],
|
|
1382
|
+
{},
|
|
1383
|
+
"singleUpdate"
|
|
1384
|
+
);
|
|
1385
|
+
this.recordRecentSqliteWrite(source, [orderSnapshot]);
|
|
1386
|
+
this.pushOrderFlowLog("updateOrderInSQLite.done", {
|
|
1387
|
+
source,
|
|
1388
|
+
writeSeq,
|
|
1389
|
+
orderId: orderSnapshot.order_id ?? null,
|
|
1390
|
+
storageKey: this.getOrderStorageKey(orderSnapshot),
|
|
1391
|
+
writeMethod
|
|
1392
|
+
});
|
|
1393
|
+
this.logInfo("updateOrderInSQLite-完成", {
|
|
1394
|
+
orderId: orderSnapshot.order_id ?? null
|
|
1395
|
+
});
|
|
1396
|
+
});
|
|
1397
|
+
} catch (error) {
|
|
1398
|
+
this.pushOrderFlowLog("updateOrderInSQLite.error", {
|
|
1399
|
+
source,
|
|
1400
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1401
|
+
orderId: orderSnapshot.order_id ?? null
|
|
1402
|
+
});
|
|
1403
|
+
this.logError("单条保存订单到 SQLite 失败", {
|
|
1404
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1405
|
+
orderId: orderSnapshot.order_id ?? null
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
/**
|
|
1410
|
+
* 全量快照替换 orders 表(clear + bulkAdd),用于 SSE 全量拉取与营业日窗口裁剪。
|
|
1411
|
+
*
|
|
1412
|
+
* @example
|
|
1413
|
+
* await this.replaceOrdersSnapshotInSQLite(orderList)
|
|
1414
|
+
*/
|
|
1415
|
+
async replaceOrdersSnapshotInSQLite(orderList, source) {
|
|
1416
|
+
if (!this.dbManager) {
|
|
1417
|
+
this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.skip", { source, count: orderList.length });
|
|
1418
|
+
return;
|
|
1419
|
+
}
|
|
770
1420
|
const orderListSnapshot = (0, import_lodash_es.cloneDeep)(orderList);
|
|
771
1421
|
try {
|
|
772
1422
|
await this.runInOrderSQLiteSaveQueue(async () => {
|
|
773
|
-
this.
|
|
1423
|
+
this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.start", {
|
|
1424
|
+
source,
|
|
1425
|
+
count: orderListSnapshot.length
|
|
1426
|
+
});
|
|
1427
|
+
this.logInfo("replaceOrdersSnapshotInSQLite-开始", {
|
|
1428
|
+
source,
|
|
774
1429
|
count: orderListSnapshot.length
|
|
775
1430
|
});
|
|
776
1431
|
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
777
|
-
this.
|
|
1432
|
+
this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.cleared", {
|
|
1433
|
+
source,
|
|
778
1434
|
count: orderListSnapshot.length
|
|
779
1435
|
});
|
|
780
|
-
|
|
1436
|
+
this.logInfo("replaceOrdersSnapshotInSQLite-clear完成", {
|
|
1437
|
+
count: orderListSnapshot.length
|
|
1438
|
+
});
|
|
1439
|
+
if (orderListSnapshot.length === 0) {
|
|
1440
|
+
this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.doneEmpty", { source });
|
|
781
1441
|
return;
|
|
1442
|
+
}
|
|
782
1443
|
await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, orderListSnapshot);
|
|
783
|
-
this.
|
|
1444
|
+
const writeSeq = this.trackOrderWrite(
|
|
1445
|
+
source,
|
|
1446
|
+
"clear+bulkAdd",
|
|
1447
|
+
orderListSnapshot,
|
|
1448
|
+
{},
|
|
1449
|
+
"snapshot"
|
|
1450
|
+
);
|
|
1451
|
+
this.recordRecentSqliteWrite(source, orderListSnapshot);
|
|
1452
|
+
this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.done", {
|
|
1453
|
+
source,
|
|
1454
|
+
writeSeq,
|
|
1455
|
+
count: orderListSnapshot.length,
|
|
1456
|
+
writeMethod: "clear+bulkAdd"
|
|
1457
|
+
});
|
|
1458
|
+
this.logInfo("replaceOrdersSnapshotInSQLite-bulkAdd完成", {
|
|
784
1459
|
count: orderListSnapshot.length
|
|
785
1460
|
});
|
|
786
1461
|
});
|
|
787
1462
|
} catch (error) {
|
|
788
|
-
this.
|
|
1463
|
+
this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.error", {
|
|
1464
|
+
source,
|
|
1465
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1466
|
+
orderList: orderListSnapshot.length
|
|
1467
|
+
});
|
|
1468
|
+
this.logError("全量保存订单到 SQLite 失败", {
|
|
789
1469
|
error: error instanceof Error ? error.message : String(error),
|
|
790
1470
|
orderList: orderListSnapshot.length
|
|
791
1471
|
});
|