@pisell/pisellos 2.3.46 → 2.3.47

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.
@@ -568,6 +568,19 @@ export interface OrderChangedPayload {
568
568
  /** 触发来源,便于订阅者区分 pubsub / 远端覆盖 / 清空等场景 */
569
569
  source?: string;
570
570
  }
571
+ export type RemoteProductMembershipChangeSource = 'pubsub.bodyUpsert' | 'pubsub.httpRefresh';
572
+ /**
573
+ * 远端订单快照相对本地订单产生商品成员增删时的广播载荷。
574
+ * 只表达商品行成员关系变化,不包含数量、价格、备注等字段级修改。
575
+ */
576
+ export interface RemoteProductMembershipChangedPayload {
577
+ order_id: OrderId;
578
+ source: RemoteProductMembershipChangeSource;
579
+ added_product_keys: string[];
580
+ removed_product_keys: string[];
581
+ previous_product_count: number;
582
+ current_product_count: number;
583
+ }
571
584
  /**
572
585
  * OrderSyncMessage - pubsub 同步消息结构
573
586
  */
@@ -605,5 +618,6 @@ export interface OrderState {
605
618
  export declare enum OrderHooks {
606
619
  onOrdersLoaded = "order:onOrdersLoaded",
607
620
  onOrdersChanged = "order:onOrdersChanged",
621
+ onRemoteProductMembershipChanged = "order:onRemoteProductMembershipChanged",
608
622
  onOrdersSyncCompleted = "order:onOrdersSyncCompleted"
609
623
  }
@@ -135,6 +135,11 @@
135
135
  * const changedOrders = payload.changedOrders
136
136
  */
137
137
 
138
+ /**
139
+ * 远端订单快照相对本地订单产生商品成员增删时的广播载荷。
140
+ * 只表达商品行成员关系变化,不包含数量、价格、备注等字段级修改。
141
+ */
142
+
138
143
  /**
139
144
  * OrderSyncMessage - pubsub 同步消息结构
140
145
  */
@@ -149,6 +154,7 @@
149
154
  export var OrderHooks = /*#__PURE__*/function (OrderHooks) {
150
155
  OrderHooks["onOrdersLoaded"] = "order:onOrdersLoaded";
151
156
  OrderHooks["onOrdersChanged"] = "order:onOrdersChanged";
157
+ OrderHooks["onRemoteProductMembershipChanged"] = "order:onRemoteProductMembershipChanged";
152
158
  OrderHooks["onOrdersSyncCompleted"] = "order:onOrdersSyncCompleted";
153
159
  return OrderHooks;
154
160
  }({});
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
311
  date: string;
312
312
  status: string;
313
313
  week: string;
314
- weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
314
+ weekNum: 0 | 2 | 1 | 5 | 4 | 3 | 6;
315
315
  }[]>;
316
316
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
317
  private getScheduleDataByIds;
@@ -445,7 +445,19 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
445
445
  * 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
446
446
  * 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
447
447
  */
448
- decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
448
+ decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): {
449
+ action: "reloadCatalog";
450
+ } | {
451
+ action: "add";
452
+ cacheItem: any;
453
+ } | {
454
+ action: "requiresDetail";
455
+ payload: AddProductRequiresDetailPayload;
456
+ } | {
457
+ action: "requiresBookingEdit";
458
+ cacheItem: any;
459
+ payload: import("./utils/addProductDecision").AddProductRequiresBookingEditPayload;
460
+ };
449
461
  /** 规格弹窗 callback 后的第二段决策。 */
450
462
  decideAfterDetail(cacheItem: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
451
463
  /**
@@ -0,0 +1,51 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/model/strategy/adapter/promotion/index.ts
30
+ var promotion_exports = {};
31
+ __export(promotion_exports, {
32
+ BUY_X_GET_Y_FREE_STRATEGY: () => import_examples.BUY_X_GET_Y_FREE_STRATEGY,
33
+ ITEM_REWARD_STRATEGY: () => import_examples.ITEM_REWARD_STRATEGY,
34
+ PromotionAdapter: () => import_adapter.PromotionAdapter,
35
+ PromotionEvaluator: () => import_evaluator.PromotionEvaluator,
36
+ X_ITEMS_FOR_Y_PRICE_STRATEGY: () => import_examples.X_ITEMS_FOR_Y_PRICE_STRATEGY,
37
+ default: () => import_adapter2.default
38
+ });
39
+ module.exports = __toCommonJS(promotion_exports);
40
+ var import_evaluator = require("./evaluator");
41
+ var import_adapter = require("./adapter");
42
+ var import_adapter2 = __toESM(require("./adapter"));
43
+ var import_examples = require("./examples");
44
+ // Annotate the CommonJS export names for ESM import in node:
45
+ 0 && (module.exports = {
46
+ BUY_X_GET_Y_FREE_STRATEGY,
47
+ ITEM_REWARD_STRATEGY,
48
+ PromotionAdapter,
49
+ PromotionEvaluator,
50
+ X_ITEMS_FOR_Y_PRICE_STRATEGY
51
+ });
@@ -14,7 +14,7 @@ export { QuotationHooks } from './quotation/types';
14
14
  export { ScheduleModuleEx } from './schedule';
15
15
  export type { ScheduleState, ScheduleItem } from './schedule/types';
16
16
  export { OrderModule } from './order';
17
- export type { OrderState, OrderData, OrderId, OrderSummary, OrderBookingItem, OrderProductLineItem, OrderPaymentItem, OrderSurchargeItem, OrderProductDiscountItem, OrderWithoutBookings, BookingData, OrderFilters, BookingFilters, OrderFilterResult, OrderFilterRejectDetail, OrderFilterRejectedEntry, BookingFilterResult, OrderModulePagedResult, } from './order/types';
17
+ export type { OrderState, OrderData, OrderId, OrderSummary, OrderBookingItem, OrderProductLineItem, OrderPaymentItem, OrderSurchargeItem, OrderProductDiscountItem, OrderWithoutBookings, BookingData, OrderFilters, BookingFilters, OrderFilterResult, OrderFilterRejectDetail, OrderFilterRejectedEntry, BookingFilterResult, OrderModulePagedResult, RemoteProductMembershipChangedPayload, RemoteProductMembershipChangeSource, } from './order/types';
18
18
  export { OrderHooks } from './order/types';
19
19
  export { PaymentServerModule } from './payment';
20
20
  export type { PaymentMethod, PaymentMethodsChangedEventData, PaymentServerState } from './payment/types';
@@ -30,6 +30,10 @@ export declare class OrderModule extends BaseModule implements Module {
30
30
  * await this.emitOrdersChanged([freshOrder], 'pubsub.bodyUpsert')
31
31
  */
32
32
  private emitOrdersChanged;
33
+ /**
34
+ * 广播远端商品成员增删。监听器异常必须与订单落库和原有订单广播隔离。
35
+ */
36
+ private emitRemoteProductMembershipChanges;
33
37
  initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
34
38
  /**
35
39
  * 记录信息日志
@@ -231,6 +235,18 @@ export declare class OrderModule extends BaseModule implements Module {
231
235
  */
232
236
  private lookupOrderIndexByIdentityKeys;
233
237
  private isRemoteEchoMergeSource;
238
+ private getProductMembershipKey;
239
+ private doProductsHaveStableMembershipIdentity;
240
+ /**
241
+ * 冲突提示关注逻辑商品行,而不是服务端 checkout 过程中可能被重建的 detail 记录。
242
+ * 通用集合合并仍以 order_detail_id 为事实主键;这里只允许相同稳定 UID 跨 detail id 对齐,
243
+ * 避免本机 checkout 回声被误判成“一删一增”。
244
+ */
245
+ private isSameProductMembershipItem;
246
+ /**
247
+ * 对比合并前后的商品成员集合。商品字段修改与数组重排不会产生 diff。
248
+ */
249
+ private getRemoteProductMembershipChange;
234
250
  /**
235
251
  * 将订单的全部身份键登记到索引并指向其在列表中的下标。
236
252
  * 合并后订单新增的身份字段(如挂单同步后拿到 order_id)也会被登记。
@@ -89,6 +89,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
89
89
  };
90
90
  await this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, payload);
91
91
  }
92
+ /**
93
+ * 广播远端商品成员增删。监听器异常必须与订单落库和原有订单广播隔离。
94
+ */
95
+ async emitRemoteProductMembershipChanges(changes) {
96
+ for (const payload of changes) {
97
+ try {
98
+ await this.core.effects.emit(import_types.OrderHooks.onRemoteProductMembershipChanged, payload);
99
+ } catch (error) {
100
+ this.logError("广播远端订单商品成员变更失败", {
101
+ order_id: payload.order_id,
102
+ source: payload.source,
103
+ added_product_count: payload.added_product_keys.length,
104
+ removed_product_count: payload.removed_product_keys.length,
105
+ error: error instanceof Error ? error.message : String(error)
106
+ });
107
+ }
108
+ }
109
+ }
92
110
  async initialize(core, options) {
93
111
  var _a;
94
112
  this.core = core;
@@ -314,7 +332,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
314
332
  * @example
315
333
  * const { toWrite, skipped } = this.filterRedundantPatchOrders('pubsub.bodyUpsert', orders, mergeActions)
316
334
  */
317
- filterRedundantPatchOrders(source, orders, mergeActions) {
335
+ filterRedundantPatchOrders(source, orders, mergeActions, forceWriteStorageKeys = /* @__PURE__ */ new Set()) {
318
336
  const eligibleSkipSources = /* @__PURE__ */ new Set(["pubsub.bodyUpsert", "pubsub.httpRefresh"]);
319
337
  if (!eligibleSkipSources.has(source)) {
320
338
  return { toWrite: orders, skipped: [] };
@@ -334,6 +352,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
334
352
  toWrite.push(order);
335
353
  continue;
336
354
  }
355
+ if (forceWriteStorageKeys.has(storageKey)) {
356
+ toWrite.push(order);
357
+ continue;
358
+ }
337
359
  const recent = this.recentSqliteWriteByStorageKey.get(storageKey);
338
360
  if (recent && ORDER_BUSINESS_WRITE_SOURCES.has(recent.source) && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
339
361
  skipped.push({
@@ -1484,10 +1506,20 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1484
1506
  });
1485
1507
  this.logDuplicateOrders(`${source}.beforeMerge`, this.store.list);
1486
1508
  const normalizedFreshOrders = [];
1509
+ const incomingProductsHaveStableIdentity = /* @__PURE__ */ new Map();
1487
1510
  for (const order of freshOrders) {
1488
1511
  const id = order == null ? void 0 : order.order_id;
1489
1512
  if (id === void 0 || id === null)
1490
1513
  continue;
1514
+ const rawProducts = order.products;
1515
+ if (Array.isArray(rawProducts)) {
1516
+ const allProductsHaveStableIdentity = this.doProductsHaveStableMembershipIdentity(rawProducts);
1517
+ const orderIdKey = this.getIdKey(id);
1518
+ incomingProductsHaveStableIdentity.set(
1519
+ orderIdKey,
1520
+ (incomingProductsHaveStableIdentity.get(orderIdKey) ?? true) && allProductsHaveStableIdentity
1521
+ );
1522
+ }
1491
1523
  normalizedFreshOrders.push(this.normalizeRemoteSyncedOrder(order));
1492
1524
  }
1493
1525
  const uniqueFreshOrders = this.compactOrderListByIdentity(
@@ -1496,7 +1528,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1496
1528
  ).list;
1497
1529
  const uniqueFreshCount = uniqueFreshOrders.length;
1498
1530
  const patchedOrders = [];
1531
+ const remoteProductMembershipChanges = [];
1532
+ const forceWriteStorageKeys = /* @__PURE__ */ new Set();
1499
1533
  const mergeActions = {};
1534
+ const existingProductsHaveStableIdentity = this.store.list.map(
1535
+ (order) => this.doProductsHaveStableMembershipIdentity(
1536
+ order.products
1537
+ )
1538
+ );
1500
1539
  const updatedList = this.store.list.map(
1501
1540
  (order) => this.normalizeOrderForMemoryList(order, `${source}.existingMemory`)
1502
1541
  );
@@ -1540,6 +1579,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1540
1579
  continue;
1541
1580
  }
1542
1581
  let mergedOrder = this.mergeOrderRecords(existingOrder, fresh);
1582
+ const freshOrderId = fresh.order_id;
1583
+ const incomingProductsAreStable = freshOrderId !== void 0 && freshOrderId !== null && incomingProductsHaveStableIdentity.get(this.getIdKey(freshOrderId)) !== false;
1584
+ let membershipChange = null;
1585
+ if (Array.isArray(fresh.products) && freshOrderId !== void 0 && freshOrderId !== null && existingProductsHaveStableIdentity[matchIndex] !== false && incomingProductsAreStable) {
1586
+ membershipChange = this.getRemoteProductMembershipChange(
1587
+ existingOrder,
1588
+ mergedOrder,
1589
+ source
1590
+ );
1591
+ }
1592
+ let mergedProductsHaveStableIdentity = existingProductsHaveStableIdentity[matchIndex] !== false && incomingProductsAreStable;
1543
1593
  let adjustedMatchIndex = matchIndex;
1544
1594
  const duplicateIndexes = /* @__PURE__ */ new Set();
1545
1595
  for (const key of freshIdentityKeys) {
@@ -1551,7 +1601,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1551
1601
  if (duplicateIndexes.size > 0) {
1552
1602
  for (const duplicateIndex of [...duplicateIndexes].sort((left, right) => right - left)) {
1553
1603
  mergedOrder = this.mergeOrderRecords(mergedOrder, updatedList[duplicateIndex]);
1604
+ mergedProductsHaveStableIdentity = mergedProductsHaveStableIdentity && existingProductsHaveStableIdentity[duplicateIndex] !== false;
1554
1605
  updatedList.splice(duplicateIndex, 1);
1606
+ existingProductsHaveStableIdentity.splice(duplicateIndex, 1);
1555
1607
  if (duplicateIndex < adjustedMatchIndex)
1556
1608
  adjustedMatchIndex -= 1;
1557
1609
  }
@@ -1564,6 +1616,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1564
1616
  }
1565
1617
  }
1566
1618
  updatedList[adjustedMatchIndex] = mergedOrder;
1619
+ existingProductsHaveStableIdentity[adjustedMatchIndex] = mergedProductsHaveStableIdentity;
1620
+ if (membershipChange) {
1621
+ remoteProductMembershipChanges.push(membershipChange);
1622
+ const mergedStorageKey = this.getOrderStorageKey(mergedOrder);
1623
+ if (mergedStorageKey)
1624
+ forceWriteStorageKeys.add(mergedStorageKey);
1625
+ }
1567
1626
  this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, adjustedMatchIndex);
1568
1627
  patchedOrders.push(mergedOrder);
1569
1628
  if (mergeKey)
@@ -1572,6 +1631,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1572
1631
  }
1573
1632
  const insertIndex = updatedList.length;
1574
1633
  updatedList.push(fresh);
1634
+ existingProductsHaveStableIdentity.push(
1635
+ fresh.order_id !== void 0 && fresh.order_id !== null && incomingProductsHaveStableIdentity.get(this.getIdKey(fresh.order_id)) !== false
1636
+ );
1575
1637
  this.registerOrderIdentityKeys(identityKeyToIndex, fresh, insertIndex);
1576
1638
  patchedOrders.push(fresh);
1577
1639
  if (mergeKey)
@@ -1586,13 +1648,20 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1586
1648
  });
1587
1649
  this.store.list = this.runOrderStoreSelfCheck(updatedList, `${source}.store`);
1588
1650
  this.syncOrdersMap();
1589
- await this.patchOrdersInSQLite(patchedOrders, source, mergeActions);
1651
+ await this.patchOrdersInSQLite(
1652
+ patchedOrders,
1653
+ source,
1654
+ mergeActions,
1655
+ {},
1656
+ forceWriteStorageKeys
1657
+ );
1590
1658
  this.logInfo("mergeOrdersToStore-结束", {
1591
1659
  uniqueFreshCount,
1592
1660
  storeOrderCountAfter: this.store.list.length,
1593
1661
  insertCount,
1594
1662
  updateCount
1595
1663
  });
1664
+ await this.emitRemoteProductMembershipChanges(remoteProductMembershipChanges);
1596
1665
  await this.emitOrdersChanged(patchedOrders, source);
1597
1666
  }
1598
1667
  /**
@@ -1616,6 +1685,72 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1616
1685
  isRemoteEchoMergeSource(source) {
1617
1686
  return source === "pubsub.bodyUpsert" || source === "pubsub.httpRefresh";
1618
1687
  }
1688
+ getProductMembershipKey(product) {
1689
+ const persistentId = (0, import_orderCollectionIdentity.getOrderCollectionPersistentId)("product", product);
1690
+ if (persistentId)
1691
+ return `order_detail_id:${persistentId}`;
1692
+ const uid = (0, import_orderCollectionIdentity.getOrderCollectionUid)("product", product);
1693
+ return uid ? `unique_identification_number:${uid}` : "";
1694
+ }
1695
+ doProductsHaveStableMembershipIdentity(products) {
1696
+ if (!Array.isArray(products))
1697
+ return true;
1698
+ return products.every(
1699
+ (product) => Boolean(
1700
+ (0, import_orderCollectionIdentity.getOrderCollectionPersistentId)("product", product) || (0, import_orderCollectionIdentity.getOrderCollectionUid)("product", product)
1701
+ )
1702
+ );
1703
+ }
1704
+ /**
1705
+ * 冲突提示关注逻辑商品行,而不是服务端 checkout 过程中可能被重建的 detail 记录。
1706
+ * 通用集合合并仍以 order_detail_id 为事实主键;这里只允许相同稳定 UID 跨 detail id 对齐,
1707
+ * 避免本机 checkout 回声被误判成“一删一增”。
1708
+ */
1709
+ isSameProductMembershipItem(left, right) {
1710
+ if ((0, import_orderCollectionIdentity.isSameOrderCollectionItem)("product", left, right))
1711
+ return true;
1712
+ const leftUid = (0, import_orderCollectionIdentity.getOrderCollectionUid)("product", left);
1713
+ const rightUid = (0, import_orderCollectionIdentity.getOrderCollectionUid)("product", right);
1714
+ return Boolean(leftUid && rightUid && leftUid === rightUid);
1715
+ }
1716
+ /**
1717
+ * 对比合并前后的商品成员集合。商品字段修改与数组重排不会产生 diff。
1718
+ */
1719
+ getRemoteProductMembershipChange(existingOrder, mergedOrder, source) {
1720
+ if (!this.isRemoteEchoMergeSource(source))
1721
+ return null;
1722
+ const previousProducts = Array.isArray(existingOrder.products) ? existingOrder.products : [];
1723
+ const currentProducts = Array.isArray(mergedOrder.products) ? mergedOrder.products : [];
1724
+ const unmatchedCurrentIndexes = new Set(currentProducts.map((_, index) => index));
1725
+ const removedProductKeys = [];
1726
+ for (const previousProduct of previousProducts) {
1727
+ const matchedIndex = currentProducts.findIndex(
1728
+ (currentProduct, index) => unmatchedCurrentIndexes.has(index) && this.isSameProductMembershipItem(previousProduct, currentProduct)
1729
+ );
1730
+ if (matchedIndex >= 0) {
1731
+ unmatchedCurrentIndexes.delete(matchedIndex);
1732
+ continue;
1733
+ }
1734
+ const productKey = this.getProductMembershipKey(previousProduct);
1735
+ if (productKey)
1736
+ removedProductKeys.push(productKey);
1737
+ }
1738
+ const addedProductKeys = [...unmatchedCurrentIndexes].map((index) => this.getProductMembershipKey(currentProducts[index])).filter(Boolean);
1739
+ if (addedProductKeys.length === 0 && removedProductKeys.length === 0) {
1740
+ return null;
1741
+ }
1742
+ const orderId = mergedOrder.order_id ?? existingOrder.order_id;
1743
+ if (orderId === void 0 || orderId === null)
1744
+ return null;
1745
+ return {
1746
+ order_id: orderId,
1747
+ source,
1748
+ added_product_keys: addedProductKeys,
1749
+ removed_product_keys: removedProductKeys,
1750
+ previous_product_count: previousProducts.length,
1751
+ current_product_count: currentProducts.length
1752
+ };
1753
+ }
1619
1754
  /**
1620
1755
  * 将订单的全部身份键登记到索引并指向其在列表中的下标。
1621
1756
  * 合并后订单新增的身份字段(如挂单同步后拿到 order_id)也会被登记。
@@ -2140,7 +2275,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2140
2275
  * @example
2141
2276
  * await this.patchOrdersInSQLite(freshOrders)
2142
2277
  */
2143
- async patchOrdersInSQLite(orders, source, mergeActions = {}, options = {}) {
2278
+ async patchOrdersInSQLite(orders, source, mergeActions = {}, options = {}, forceWriteStorageKeys = /* @__PURE__ */ new Set()) {
2144
2279
  if (orders.length === 0) {
2145
2280
  return;
2146
2281
  }
@@ -2156,7 +2291,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2156
2291
  const { toWrite, skipped } = this.filterRedundantPatchOrders(
2157
2292
  source,
2158
2293
  ordersSnapshot,
2159
- mergeActions
2294
+ mergeActions,
2295
+ forceWriteStorageKeys
2160
2296
  );
2161
2297
  if (toWrite.length === 0) {
2162
2298
  return;
@@ -568,6 +568,19 @@ export interface OrderChangedPayload {
568
568
  /** 触发来源,便于订阅者区分 pubsub / 远端覆盖 / 清空等场景 */
569
569
  source?: string;
570
570
  }
571
+ export type RemoteProductMembershipChangeSource = 'pubsub.bodyUpsert' | 'pubsub.httpRefresh';
572
+ /**
573
+ * 远端订单快照相对本地订单产生商品成员增删时的广播载荷。
574
+ * 只表达商品行成员关系变化,不包含数量、价格、备注等字段级修改。
575
+ */
576
+ export interface RemoteProductMembershipChangedPayload {
577
+ order_id: OrderId;
578
+ source: RemoteProductMembershipChangeSource;
579
+ added_product_keys: string[];
580
+ removed_product_keys: string[];
581
+ previous_product_count: number;
582
+ current_product_count: number;
583
+ }
571
584
  /**
572
585
  * OrderSyncMessage - pubsub 同步消息结构
573
586
  */
@@ -605,5 +618,6 @@ export interface OrderState {
605
618
  export declare enum OrderHooks {
606
619
  onOrdersLoaded = "order:onOrdersLoaded",
607
620
  onOrdersChanged = "order:onOrdersChanged",
621
+ onRemoteProductMembershipChanged = "order:onRemoteProductMembershipChanged",
608
622
  onOrdersSyncCompleted = "order:onOrdersSyncCompleted"
609
623
  }
@@ -25,6 +25,7 @@ module.exports = __toCommonJS(types_exports);
25
25
  var OrderHooks = /* @__PURE__ */ ((OrderHooks2) => {
26
26
  OrderHooks2["onOrdersLoaded"] = "order:onOrdersLoaded";
27
27
  OrderHooks2["onOrdersChanged"] = "order:onOrdersChanged";
28
+ OrderHooks2["onRemoteProductMembershipChanged"] = "order:onRemoteProductMembershipChanged";
28
29
  OrderHooks2["onOrdersSyncCompleted"] = "order:onOrdersSyncCompleted";
29
30
  return OrderHooks2;
30
31
  })(OrderHooks || {});
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
311
  date: string;
312
312
  status: string;
313
313
  week: string;
314
- weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
314
+ weekNum: 0 | 2 | 1 | 5 | 4 | 3 | 6;
315
315
  }[]>;
316
316
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
317
  private getScheduleDataByIds;
@@ -445,7 +445,19 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
445
445
  * 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
446
446
  * 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
447
447
  */
448
- decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
448
+ decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): {
449
+ action: "reloadCatalog";
450
+ } | {
451
+ action: "add";
452
+ cacheItem: any;
453
+ } | {
454
+ action: "requiresDetail";
455
+ payload: AddProductRequiresDetailPayload;
456
+ } | {
457
+ action: "requiresBookingEdit";
458
+ cacheItem: any;
459
+ payload: import("./utils/addProductDecision").AddProductRequiresBookingEditPayload;
460
+ };
449
461
  /** 规格弹窗 callback 后的第二段决策。 */
450
462
  decideAfterDetail(cacheItem: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
451
463
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.3.46",
4
+ "version": "2.3.47",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",