@pisell/pisellos 2.3.57 → 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.
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.js +109 -65
- package/dist/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/modules/Quotation/index.d.ts +6 -0
- package/dist/modules/Quotation/index.js +75 -19
- package/dist/modules/Rules/index.js +14 -7
- package/dist/plugins/request.d.ts +1 -0
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.js +970 -842
- 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/order/index.d.ts +7 -5
- package/dist/server/modules/order/index.js +185 -80
- package/dist/server/modules/order/types.d.ts +1 -1
- package/dist/server/modules/products/index.d.ts +2 -0
- package/dist/server/modules/products/index.js +17 -3
- package/dist/server/modules/resource/index.js +21 -13
- package/lib/core/index.d.ts +7 -0
- package/lib/core/index.js +20 -2
- package/lib/modules/Quotation/index.d.ts +6 -0
- package/lib/modules/Quotation/index.js +49 -5
- package/lib/modules/Rules/index.js +20 -5
- package/lib/plugins/request.d.ts +1 -0
- package/lib/server/index.d.ts +15 -0
- package/lib/server/index.js +120 -15
- 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/order/index.d.ts +7 -5
- package/lib/server/modules/order/index.js +114 -26
- package/lib/server/modules/order/types.d.ts +1 -1
- package/lib/server/modules/products/index.d.ts +2 -0
- package/lib/server/modules/products/index.js +15 -4
- package/lib/server/modules/resource/index.js +7 -2
- package/package.json +1 -1
package/lib/core/index.js
CHANGED
|
@@ -36,7 +36,6 @@ module.exports = __toCommonJS(core_exports);
|
|
|
36
36
|
var import_createStore = require("../store/createStore");
|
|
37
37
|
var import_effects = require("../effects");
|
|
38
38
|
var PisellOSCore = class {
|
|
39
|
-
// 保存 Server 配置
|
|
40
39
|
constructor(options) {
|
|
41
40
|
this.plugins = /* @__PURE__ */ new Map();
|
|
42
41
|
this.modules = /* @__PURE__ */ new Map();
|
|
@@ -50,6 +49,7 @@ var PisellOSCore = class {
|
|
|
50
49
|
this.serverOptions = options.server;
|
|
51
50
|
}
|
|
52
51
|
this.initialize(options);
|
|
52
|
+
console.log("constructor123456");
|
|
53
53
|
}
|
|
54
54
|
initialize(options) {
|
|
55
55
|
if (options == null ? void 0 : options.plugins) {
|
|
@@ -64,6 +64,24 @@ var PisellOSCore = class {
|
|
|
64
64
|
}
|
|
65
65
|
this.log("[PisellOS] 核心初始化完成");
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* 仅预加载 Server 模块代码,不创建实例、不注册模块、不请求业务数据。
|
|
69
|
+
* 导入失败会清空 Promise,正式 initializeServer 时仍可重新尝试。
|
|
70
|
+
*/
|
|
71
|
+
async preloadServerModule() {
|
|
72
|
+
if (this.server || !this.serverOptions)
|
|
73
|
+
return;
|
|
74
|
+
await this.loadServerModule();
|
|
75
|
+
}
|
|
76
|
+
loadServerModule() {
|
|
77
|
+
if (!this.serverModulePromise) {
|
|
78
|
+
this.serverModulePromise = import("../server").catch((error) => {
|
|
79
|
+
this.serverModulePromise = void 0;
|
|
80
|
+
throw error;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return this.serverModulePromise;
|
|
84
|
+
}
|
|
67
85
|
/**
|
|
68
86
|
* 初始化 Server(公开方法,需要外部显式调用并等待)
|
|
69
87
|
* Server 配置从构造函数传入的 options.server 中获取
|
|
@@ -78,7 +96,7 @@ var PisellOSCore = class {
|
|
|
78
96
|
return;
|
|
79
97
|
}
|
|
80
98
|
try {
|
|
81
|
-
const ServerModule = await
|
|
99
|
+
const ServerModule = await this.loadServerModule();
|
|
82
100
|
const Server = ServerModule.default;
|
|
83
101
|
this.server = new Server(this);
|
|
84
102
|
this.log("Server 实例已创建");
|
|
@@ -9,6 +9,8 @@ export declare class QuotationModule extends BaseModule implements Module {
|
|
|
9
9
|
private request;
|
|
10
10
|
private store;
|
|
11
11
|
private scheduleResolver?;
|
|
12
|
+
private app;
|
|
13
|
+
private quotationListUpdatedListener?;
|
|
12
14
|
constructor(name?: string, version?: string);
|
|
13
15
|
initialize(core: PisellCore, options: ModuleOptions): Promise<void>;
|
|
14
16
|
loadQuotations(params?: {
|
|
@@ -16,6 +18,7 @@ export declare class QuotationModule extends BaseModule implements Module {
|
|
|
16
18
|
customer_id?: number | string;
|
|
17
19
|
}): Promise<void>;
|
|
18
20
|
getQuotationList(): QuotationItem[];
|
|
21
|
+
setQuotationListUpdatedListener(listener?: () => void): void;
|
|
19
22
|
getQuotationCustomerScopeInfo(): QuotationCustomerScopeInfo;
|
|
20
23
|
/**
|
|
21
24
|
* Look up the quotation price for a specific product (+ optional variant) at a given datetime.
|
|
@@ -60,6 +63,9 @@ export declare class QuotationModule extends BaseModule implements Module {
|
|
|
60
63
|
customer_id?: number | string;
|
|
61
64
|
}): Map<string, string | null>;
|
|
62
65
|
setScheduleResolver(resolver: (id: number) => ScheduleItem | undefined): void;
|
|
66
|
+
private applyQuotationResponse;
|
|
67
|
+
private notifyQuotationListUpdated;
|
|
68
|
+
private getQuotationCacheKeyData;
|
|
63
69
|
private isQuotationVisibleForCustomer;
|
|
64
70
|
private hasValidCustomerId;
|
|
65
71
|
private normalizeCustomerId;
|
|
@@ -32,32 +32,49 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
|
|
|
32
32
|
this.store = { list: [] };
|
|
33
33
|
}
|
|
34
34
|
async initialize(core, options) {
|
|
35
|
+
var _a, _b;
|
|
35
36
|
this.core = core;
|
|
36
37
|
this.request = core.getPlugin("request");
|
|
37
38
|
if (!this.request)
|
|
38
39
|
throw new Error("QuotationModule 需要 request 插件支持");
|
|
40
|
+
this.app = (_b = (_a = core.getPlugin("app")) == null ? void 0 : _a.getApp) == null ? void 0 : _b.call(_a);
|
|
39
41
|
this.store = { list: [] };
|
|
40
42
|
}
|
|
41
43
|
async loadQuotations(params) {
|
|
42
|
-
var _a;
|
|
43
44
|
const query = {};
|
|
44
45
|
if (params == null ? void 0 : params.channel)
|
|
45
46
|
query.channel = params.channel;
|
|
46
47
|
if ((params == null ? void 0 : params.channel) === "online_store") {
|
|
47
48
|
query.channel = "online-store";
|
|
48
49
|
}
|
|
50
|
+
let initialResultApplied = false;
|
|
51
|
+
const applyRemoteUpdate = (response) => {
|
|
52
|
+
this.applyQuotationResponse(response);
|
|
53
|
+
if (initialResultApplied) {
|
|
54
|
+
this.notifyQuotationListUpdated();
|
|
55
|
+
}
|
|
56
|
+
};
|
|
49
57
|
const res = await this.request.get(
|
|
50
58
|
"/quotation/available",
|
|
51
59
|
query,
|
|
52
|
-
{
|
|
60
|
+
{
|
|
61
|
+
cache: {
|
|
62
|
+
type: "indexDB",
|
|
63
|
+
updateCache: true,
|
|
64
|
+
cacheKeyData: this.getQuotationCacheKeyData(query)
|
|
65
|
+
},
|
|
66
|
+
cacheUpdateChange: applyRemoteUpdate
|
|
67
|
+
}
|
|
53
68
|
);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
this.store.list = list;
|
|
69
|
+
this.applyQuotationResponse(res);
|
|
70
|
+
initialResultApplied = true;
|
|
57
71
|
}
|
|
58
72
|
getQuotationList() {
|
|
59
73
|
return this.store.list;
|
|
60
74
|
}
|
|
75
|
+
setQuotationListUpdatedListener(listener) {
|
|
76
|
+
this.quotationListUpdatedListener = listener;
|
|
77
|
+
}
|
|
61
78
|
getQuotationCustomerScopeInfo() {
|
|
62
79
|
const customerById = /* @__PURE__ */ new Map();
|
|
63
80
|
const quotationScopes = this.store.list.filter((quotation) => Array.isArray(quotation.customer) && quotation.customer.length > 0).map((quotation) => {
|
|
@@ -156,6 +173,33 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
|
|
|
156
173
|
setScheduleResolver(resolver) {
|
|
157
174
|
this.scheduleResolver = resolver;
|
|
158
175
|
}
|
|
176
|
+
applyQuotationResponse(response) {
|
|
177
|
+
var _a;
|
|
178
|
+
const source = ((_a = response == null ? void 0 : response.data) == null ? void 0 : _a.list) || (response == null ? void 0 : response.list) || [];
|
|
179
|
+
this.store.list = [...source].sort((a, b) => Number(b.sort || 0) - Number(a.sort || 0));
|
|
180
|
+
}
|
|
181
|
+
notifyQuotationListUpdated() {
|
|
182
|
+
var _a;
|
|
183
|
+
try {
|
|
184
|
+
(_a = this.quotationListUpdatedListener) == null ? void 0 : _a.call(this);
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.warn("[QuotationModule] 报价单后台更新回调失败", error);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
getQuotationCacheKeyData(query) {
|
|
190
|
+
var _a, _b, _c;
|
|
191
|
+
let shopId = "";
|
|
192
|
+
try {
|
|
193
|
+
const storedCore = (_c = (_b = (_a = this.app) == null ? void 0 : _a.storage) == null ? void 0 : _b.getStorage) == null ? void 0 : _c.call(_b, "core");
|
|
194
|
+
const coreInfo = typeof storedCore === "string" ? JSON.parse(storedCore || "{}") : storedCore || {};
|
|
195
|
+
shopId = String((coreInfo == null ? void 0 : coreInfo.id) || "");
|
|
196
|
+
} catch {
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
...query,
|
|
200
|
+
shop_id: shopId
|
|
201
|
+
};
|
|
202
|
+
}
|
|
159
203
|
isQuotationVisibleForCustomer(quotation, customerId) {
|
|
160
204
|
const customers = quotation.customer || [];
|
|
161
205
|
if (customers.length === 0)
|
|
@@ -858,15 +858,30 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
858
858
|
}
|
|
859
859
|
return false;
|
|
860
860
|
});
|
|
861
|
-
const
|
|
861
|
+
const explicitlySelectedDiscount = (options == null ? void 0 : options.isSelected) === true && options.discountId !== void 0 ? applicableDiscounts.find((discount) => {
|
|
862
862
|
const discountType = discount.tag || discount.type;
|
|
863
|
-
return String(discount.id) === String(options.discountId) && ["discount_card", "product_discount_card"].includes(
|
|
863
|
+
return String(discount.id) === String(options.discountId) && ["good_pass", "discount_card", "product_discount_card"].includes(
|
|
864
|
+
discountType
|
|
865
|
+
);
|
|
864
866
|
}) : void 0;
|
|
867
|
+
const explicitlySelectedDiscountCard = explicitlySelectedDiscount && (explicitlySelectedDiscount.tag || explicitlySelectedDiscount.type) !== "good_pass" ? explicitlySelectedDiscount : void 0;
|
|
865
868
|
const scannedSelectedDiscountCard = applicableDiscounts.find(
|
|
866
869
|
(n) => n.isScan && n.isSelected && (n.tag || n.type) !== "good_pass"
|
|
867
870
|
);
|
|
868
871
|
const selectedDiscountCard = explicitlySelectedDiscountCard || scannedSelectedDiscountCard;
|
|
869
|
-
const selectedDiscount = selectedDiscountCard || applicableDiscounts[0];
|
|
872
|
+
const selectedDiscount = explicitlySelectedDiscount || selectedDiscountCard || applicableDiscounts[0];
|
|
873
|
+
const prioritizedApplicableDiscounts = explicitlySelectedDiscount && (explicitlySelectedDiscount.tag || explicitlySelectedDiscount.type) === "good_pass" ? [
|
|
874
|
+
explicitlySelectedDiscount,
|
|
875
|
+
...applicableDiscounts.filter(
|
|
876
|
+
(discount) => {
|
|
877
|
+
const discountType = discount.tag || discount.type;
|
|
878
|
+
return discountType === "good_pass" && String(discount.id) !== String(explicitlySelectedDiscount.id);
|
|
879
|
+
}
|
|
880
|
+
),
|
|
881
|
+
...applicableDiscounts.filter(
|
|
882
|
+
(discount) => (discount.tag || discount.type) !== "good_pass"
|
|
883
|
+
)
|
|
884
|
+
] : applicableDiscounts;
|
|
870
885
|
let isManualDiscount = false;
|
|
871
886
|
let isItemRewardProductDiscount = false;
|
|
872
887
|
if (flatItem.type === "main") {
|
|
@@ -1103,7 +1118,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1103
1118
|
);
|
|
1104
1119
|
}
|
|
1105
1120
|
for (let i = 0; i < splitCount; i++) {
|
|
1106
|
-
const selectedDiscount2 = selectedDiscountCard || applicableDiscounts[i];
|
|
1121
|
+
const selectedDiscount2 = isNeedSplit ? prioritizedApplicableDiscounts[i] : selectedDiscountCard || applicableDiscounts[i];
|
|
1107
1122
|
usedDiscounts.set(selectedDiscount2.id, true);
|
|
1108
1123
|
if ((selectedDiscount2.tag || selectedDiscount2.type) === "good_pass") {
|
|
1109
1124
|
const currentCount = usedProductIdCounts.get(selectedDiscount2.product_id) || 0;
|
|
@@ -1230,7 +1245,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1230
1245
|
const discountNum = splitCount;
|
|
1231
1246
|
const normalNum = totalQuantity - discountNum;
|
|
1232
1247
|
for (let i = 0; i < discountNum; i++) {
|
|
1233
|
-
const selectedDiscount2 =
|
|
1248
|
+
const selectedDiscount2 = prioritizedApplicableDiscounts[i];
|
|
1234
1249
|
usedDiscounts.set(selectedDiscount2.id, true);
|
|
1235
1250
|
if ((selectedDiscount2.tag || selectedDiscount2.type) === "good_pass") {
|
|
1236
1251
|
const currentCount = usedProductIdCounts.get(selectedDiscount2.product_id) || 0;
|
package/lib/plugins/request.d.ts
CHANGED
package/lib/server/index.d.ts
CHANGED
|
@@ -164,6 +164,12 @@ declare class Server {
|
|
|
164
164
|
* 不影响当前界面展示,适用于切回前台、定时刷新等场景
|
|
165
165
|
*/
|
|
166
166
|
refreshOrdersInBackground(): Promise<void>;
|
|
167
|
+
/**
|
|
168
|
+
* 编辑正式订单时强制查询 Server 最新快照并覆盖本地缓存。
|
|
169
|
+
* 商品成员增删由 OrderModule 在 SQLite/Store 更新完成后广播,
|
|
170
|
+
* UI 可复用 order:onRemoteProductMembershipChanged 处理冲突。
|
|
171
|
+
*/
|
|
172
|
+
checkRemoteOrderProductMembership(orderId: string | number): Promise<void>;
|
|
167
173
|
/**
|
|
168
174
|
* 清空所有server模块的IndexedDB缓存
|
|
169
175
|
* @returns Promise<void>
|
|
@@ -257,6 +263,11 @@ declare class Server {
|
|
|
257
263
|
* 对单个商品 query 订阅者重算并推送(定时路径;不新建 schedule timer)。
|
|
258
264
|
*/
|
|
259
265
|
private recomputeAndNotifySubscriber;
|
|
266
|
+
/**
|
|
267
|
+
* 根据餐牌 ID 获取其绑定日程中的全部时间点。
|
|
268
|
+
* 商品查询定时器与 schedule-time-points 路由共用此逻辑。
|
|
269
|
+
*/
|
|
270
|
+
private getMenuScheduleTimePoints;
|
|
260
271
|
/**
|
|
261
272
|
* query 完成后为 subscriber 同步 schedule 定时器(先 clear 再 schedule)。
|
|
262
273
|
*/
|
|
@@ -512,6 +523,10 @@ declare class Server {
|
|
|
512
523
|
private handleOrderDraftSubmit;
|
|
513
524
|
private handlePendingSyncCheckoutOrder;
|
|
514
525
|
private buildPendingSyncCheckoutOrder;
|
|
526
|
+
/**
|
|
527
|
+
* Android 结账自动小票由当前设备设置控制;其它平台保持原有行为。
|
|
528
|
+
*/
|
|
529
|
+
private shouldAutoPrintCheckoutReceipt;
|
|
515
530
|
private shouldBuildSmallTicketData;
|
|
516
531
|
private shouldPrintSyncedOrder;
|
|
517
532
|
private hasPaymentStatus;
|
package/lib/server/index.js
CHANGED
|
@@ -45,6 +45,7 @@ var import_floor_plan = require("./modules/floor-plan");
|
|
|
45
45
|
var import_types = require("./modules/floor-plan/types");
|
|
46
46
|
var import_payment = require("./modules/payment");
|
|
47
47
|
var import_schedule2 = require("./utils/schedule");
|
|
48
|
+
var import_time = require("./utils/time");
|
|
48
49
|
var import_types2 = require("./modules/products/types");
|
|
49
50
|
var import_product = require("./utils/product");
|
|
50
51
|
var import_order = require("./modules/order");
|
|
@@ -65,6 +66,7 @@ var PRODUCT_TITLE_SNAPSHOT_KEYS = [
|
|
|
65
66
|
"kitchen",
|
|
66
67
|
"original"
|
|
67
68
|
];
|
|
69
|
+
var AUTO_PRINT_STORAGE_KEY = "auto_print";
|
|
68
70
|
var Server = class {
|
|
69
71
|
constructor(core) {
|
|
70
72
|
this.quotationAvailableCache = /* @__PURE__ */ new Map();
|
|
@@ -254,7 +256,11 @@ var Server = class {
|
|
|
254
256
|
strategy_context
|
|
255
257
|
});
|
|
256
258
|
if (subscriberId && typeof callback === "function") {
|
|
257
|
-
this.syncProductQueryScheduleTimers(
|
|
259
|
+
this.syncProductQueryScheduleTimers({
|
|
260
|
+
subscriberId,
|
|
261
|
+
menu_list_ids,
|
|
262
|
+
strategy_context
|
|
263
|
+
});
|
|
258
264
|
}
|
|
259
265
|
return result;
|
|
260
266
|
};
|
|
@@ -1081,7 +1087,12 @@ var Server = class {
|
|
|
1081
1087
|
};
|
|
1082
1088
|
}
|
|
1083
1089
|
try {
|
|
1084
|
-
const
|
|
1090
|
+
const {
|
|
1091
|
+
menuList,
|
|
1092
|
+
scheduleIds,
|
|
1093
|
+
scheduleList,
|
|
1094
|
+
timePoints
|
|
1095
|
+
} = this.getMenuScheduleTimePoints(menu_list_ids);
|
|
1085
1096
|
console.log(`[Server] 找到 ${menuList.length} 个餐牌`);
|
|
1086
1097
|
this.logInfo("handleGetScheduleTimePoints: 获取到餐牌列表", {
|
|
1087
1098
|
requestedCount: menu_list_ids.length,
|
|
@@ -1089,7 +1100,6 @@ var Server = class {
|
|
|
1089
1100
|
menu_list_ids,
|
|
1090
1101
|
menuList
|
|
1091
1102
|
});
|
|
1092
|
-
const scheduleIds = (0, import_schedule2.extractScheduleIdsFromMenus)(menuList);
|
|
1093
1103
|
console.log(`[Server] 提取到 ${scheduleIds.length} 个日程ID:`, scheduleIds);
|
|
1094
1104
|
this.logInfo("handleGetScheduleTimePoints: 提取到日程 IDs", {
|
|
1095
1105
|
scheduleCount: scheduleIds.length
|
|
@@ -1103,13 +1113,11 @@ var Server = class {
|
|
|
1103
1113
|
status: true
|
|
1104
1114
|
};
|
|
1105
1115
|
}
|
|
1106
|
-
const scheduleList = this.schedule.getScheduleByIds(scheduleIds);
|
|
1107
1116
|
console.log(`[Server] 找到 ${scheduleList.length} 个日程`);
|
|
1108
1117
|
this.logInfo("handleGetScheduleTimePoints: 获取到日程详情", {
|
|
1109
1118
|
requestedCount: scheduleIds.length,
|
|
1110
1119
|
foundCount: scheduleList.length
|
|
1111
1120
|
});
|
|
1112
|
-
const timePoints = (0, import_schedule2.extractTimePointsFromSchedules)(scheduleList);
|
|
1113
1121
|
console.log(`[Server] 提取到 ${timePoints.length} 个时间点:`, timePoints);
|
|
1114
1122
|
this.logInfo("handleGetScheduleTimePoints 处理完成", {
|
|
1115
1123
|
menuListIdsCount: menu_list_ids.length,
|
|
@@ -1680,11 +1688,22 @@ var Server = class {
|
|
|
1680
1688
|
return;
|
|
1681
1689
|
}
|
|
1682
1690
|
try {
|
|
1683
|
-
await this.schedule.loadAllSchedule();
|
|
1684
1691
|
this.products.clearPriceCache();
|
|
1685
1692
|
await this.products.setupQuotationPriceBridge({
|
|
1686
1693
|
scheduleModule: this.schedule,
|
|
1687
|
-
channel: (_a = this.core.context) == null ? void 0 : _a.channel
|
|
1694
|
+
channel: (_a = this.core.context) == null ? void 0 : _a.channel,
|
|
1695
|
+
onQuotationUpdated: () => {
|
|
1696
|
+
void this.recomputeAndNotifyProductQuery();
|
|
1697
|
+
}
|
|
1698
|
+
});
|
|
1699
|
+
void this.schedule.loadAllSchedule().then(() => {
|
|
1700
|
+
var _a2;
|
|
1701
|
+
(_a2 = this.products) == null ? void 0 : _a2.clearPriceCache();
|
|
1702
|
+
void this.recomputeAndNotifyProductQuery();
|
|
1703
|
+
}).catch((error) => {
|
|
1704
|
+
this.logWarning("Products 报价单价格桥接后台刷新 Schedule 失败,继续使用本地数据", {
|
|
1705
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1706
|
+
});
|
|
1688
1707
|
});
|
|
1689
1708
|
this.logInfo("Products 报价单价格桥接初始化完成");
|
|
1690
1709
|
} catch (error) {
|
|
@@ -1789,6 +1808,57 @@ var Server = class {
|
|
|
1789
1808
|
});
|
|
1790
1809
|
}
|
|
1791
1810
|
}
|
|
1811
|
+
/**
|
|
1812
|
+
* 编辑正式订单时强制查询 Server 最新快照并覆盖本地缓存。
|
|
1813
|
+
* 商品成员增删由 OrderModule 在 SQLite/Store 更新完成后广播,
|
|
1814
|
+
* UI 可复用 order:onRemoteProductMembershipChanged 处理冲突。
|
|
1815
|
+
*/
|
|
1816
|
+
async checkRemoteOrderProductMembership(orderId) {
|
|
1817
|
+
const normalizedOrderId = String(orderId ?? "").trim();
|
|
1818
|
+
if (!normalizedOrderId || normalizedOrderId.startsWith("local_order")) {
|
|
1819
|
+
this.logInfo("checkRemoteOrderProductMembership: 跳过非正式订单", {
|
|
1820
|
+
orderId
|
|
1821
|
+
});
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
if (!this.order) {
|
|
1825
|
+
const error = new Error("Order 模块未注册");
|
|
1826
|
+
this.logWarning("checkRemoteOrderProductMembership: Order 模块未注册", {
|
|
1827
|
+
orderId: normalizedOrderId
|
|
1828
|
+
});
|
|
1829
|
+
throw error;
|
|
1830
|
+
}
|
|
1831
|
+
this.logInfo("checkRemoteOrderProductMembership 开始", {
|
|
1832
|
+
orderId: normalizedOrderId
|
|
1833
|
+
});
|
|
1834
|
+
const startTime = Date.now();
|
|
1835
|
+
try {
|
|
1836
|
+
const freshOrders = await this.order.fetchOrdersByHttp([
|
|
1837
|
+
normalizedOrderId
|
|
1838
|
+
]);
|
|
1839
|
+
const freshOrder = freshOrders.find(
|
|
1840
|
+
(order) => String(order == null ? void 0 : order.order_id) === normalizedOrderId
|
|
1841
|
+
);
|
|
1842
|
+
if (!freshOrder) {
|
|
1843
|
+
throw new Error("Server 未返回目标订单最新快照");
|
|
1844
|
+
}
|
|
1845
|
+
await this.order.upsertOrdersFromRemote(
|
|
1846
|
+
[freshOrder],
|
|
1847
|
+
"manual.editOpenRemoteCheck"
|
|
1848
|
+
);
|
|
1849
|
+
this.logInfo("checkRemoteOrderProductMembership 完成", {
|
|
1850
|
+
orderId: normalizedOrderId,
|
|
1851
|
+
duration: `${Date.now() - startTime}ms`
|
|
1852
|
+
});
|
|
1853
|
+
} catch (error) {
|
|
1854
|
+
this.logError("checkRemoteOrderProductMembership 失败", {
|
|
1855
|
+
orderId: normalizedOrderId,
|
|
1856
|
+
duration: `${Date.now() - startTime}ms`,
|
|
1857
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1858
|
+
});
|
|
1859
|
+
throw error;
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1792
1862
|
/**
|
|
1793
1863
|
* 清空所有server模块的IndexedDB缓存
|
|
1794
1864
|
* @returns Promise<void>
|
|
@@ -2268,16 +2338,44 @@ var Server = class {
|
|
|
2268
2338
|
});
|
|
2269
2339
|
}
|
|
2270
2340
|
}
|
|
2341
|
+
/**
|
|
2342
|
+
* 根据餐牌 ID 获取其绑定日程中的全部时间点。
|
|
2343
|
+
* 商品查询定时器与 schedule-time-points 路由共用此逻辑。
|
|
2344
|
+
*/
|
|
2345
|
+
getMenuScheduleTimePoints(menuListIds) {
|
|
2346
|
+
var _a, _b;
|
|
2347
|
+
const menuList = ((_a = this.menu) == null ? void 0 : _a.getMenuByIds(menuListIds)) ?? [];
|
|
2348
|
+
const scheduleIds = (0, import_schedule2.extractScheduleIdsFromMenus)(menuList);
|
|
2349
|
+
const scheduleList = scheduleIds.length > 0 ? ((_b = this.schedule) == null ? void 0 : _b.getScheduleByIds(scheduleIds)) ?? [] : [];
|
|
2350
|
+
const timePoints = (0, import_schedule2.extractTimePointsFromSchedules)(scheduleList);
|
|
2351
|
+
return {
|
|
2352
|
+
menuList,
|
|
2353
|
+
scheduleIds,
|
|
2354
|
+
scheduleList,
|
|
2355
|
+
timePoints
|
|
2356
|
+
};
|
|
2357
|
+
}
|
|
2271
2358
|
/**
|
|
2272
2359
|
* query 完成后为 subscriber 同步 schedule 定时器(先 clear 再 schedule)。
|
|
2273
2360
|
*/
|
|
2274
|
-
syncProductQueryScheduleTimers(
|
|
2361
|
+
syncProductQueryScheduleTimers({
|
|
2362
|
+
subscriberId,
|
|
2363
|
+
menu_list_ids,
|
|
2364
|
+
strategy_context
|
|
2365
|
+
}) {
|
|
2275
2366
|
var _a, _b;
|
|
2276
2367
|
this.clearSubscriberScheduleTimers(subscriberId);
|
|
2277
2368
|
if (!this.shouldScheduleProductQueryReload(strategy_context)) {
|
|
2278
2369
|
return;
|
|
2279
2370
|
}
|
|
2280
|
-
const
|
|
2371
|
+
const productTimePoints = ((_b = (_a = this.products) == null ? void 0 : _a.getLastScheduleTimePoints) == null ? void 0 : _b.call(_a)) ?? [];
|
|
2372
|
+
const menuListIds = Array.isArray(menu_list_ids) ? Array.from(new Set(
|
|
2373
|
+
menu_list_ids.map((id) => Number(id)).filter((id) => Number.isFinite(id))
|
|
2374
|
+
)) : [];
|
|
2375
|
+
const menuTimePoints = this.getMenuScheduleTimePoints(menuListIds).timePoints;
|
|
2376
|
+
const timePoints = (0, import_time.sortTimePoints)(
|
|
2377
|
+
Array.from(/* @__PURE__ */ new Set([...productTimePoints, ...menuTimePoints]))
|
|
2378
|
+
);
|
|
2281
2379
|
if (timePoints.length > 0) {
|
|
2282
2380
|
this.scheduleSubscriberTimePointReloads(subscriberId, timePoints);
|
|
2283
2381
|
}
|
|
@@ -3740,7 +3838,6 @@ var Server = class {
|
|
|
3740
3838
|
});
|
|
3741
3839
|
}
|
|
3742
3840
|
async handleOrderCheckoutSubmit(params) {
|
|
3743
|
-
var _a;
|
|
3744
3841
|
const { backendPath, data, title } = params;
|
|
3745
3842
|
this.logInfo(`${title}: 开始处理`, {
|
|
3746
3843
|
backendPath,
|
|
@@ -3765,15 +3862,14 @@ var Server = class {
|
|
|
3765
3862
|
});
|
|
3766
3863
|
if ((pendingResult == null ? void 0 : pendingResult.status) === true) {
|
|
3767
3864
|
const pendingOrder = pendingResult.data;
|
|
3768
|
-
|
|
3769
|
-
const isAndroid = platform === "android";
|
|
3770
|
-
if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && // TODO 这里先加个兼容,如果是安卓,则需要 type=virtual 才走打印,如果是苹果则无限制
|
|
3771
|
-
(isAndroid ? checkoutData.type === "virtual" : true)) {
|
|
3865
|
+
if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && this.shouldAutoPrintCheckoutReceipt()) {
|
|
3772
3866
|
await this.dispatchLocalReceiptPrint({
|
|
3773
3867
|
checkoutData,
|
|
3774
3868
|
order: pendingOrder,
|
|
3775
3869
|
response: pendingResult,
|
|
3776
|
-
requireFullyPaid: true
|
|
3870
|
+
requireFullyPaid: true,
|
|
3871
|
+
// 自动小票固定使用 print_all 的收据类型 0,不随订单 type 改成券/手环类型 99。
|
|
3872
|
+
isManualPrint: true
|
|
3777
3873
|
});
|
|
3778
3874
|
}
|
|
3779
3875
|
await this.dispatchCheckoutSyncTask({
|
|
@@ -4003,6 +4099,15 @@ var Server = class {
|
|
|
4003
4099
|
{ requireFullyPaid: true, productMap }
|
|
4004
4100
|
);
|
|
4005
4101
|
}
|
|
4102
|
+
/**
|
|
4103
|
+
* Android 结账自动小票由当前设备设置控制;其它平台保持原有行为。
|
|
4104
|
+
*/
|
|
4105
|
+
shouldAutoPrintCheckoutReceipt() {
|
|
4106
|
+
var _a, _b, _c, _d, _e;
|
|
4107
|
+
if (((_b = (_a = this.core.context) == null ? void 0 : _a.getPlatform) == null ? void 0 : _b.call(_a)) !== "android")
|
|
4108
|
+
return true;
|
|
4109
|
+
return ((_e = (_d = (_c = this.app) == null ? void 0 : _c.storage) == null ? void 0 : _d.getStorage) == null ? void 0 : _e.call(_d, AUTO_PRINT_STORAGE_KEY)) === "true";
|
|
4110
|
+
}
|
|
4006
4111
|
shouldBuildSmallTicketData(order) {
|
|
4007
4112
|
if (!order || typeof order !== "object")
|
|
4008
4113
|
return false;
|
|
@@ -10,6 +10,7 @@ export declare class FloorPlanModule extends BaseModule implements Module {
|
|
|
10
10
|
private store;
|
|
11
11
|
private request;
|
|
12
12
|
private logger;
|
|
13
|
+
private dbManager;
|
|
13
14
|
private floorPlanDataSource;
|
|
14
15
|
private pendingSyncMessages;
|
|
15
16
|
private syncTimer?;
|
|
@@ -28,6 +29,9 @@ export declare class FloorPlanModule extends BaseModule implements Module {
|
|
|
28
29
|
private mergeItems;
|
|
29
30
|
private removeByIds;
|
|
30
31
|
private loadListFromServer;
|
|
32
|
+
private loadListFromSQLite;
|
|
33
|
+
private saveListToSQLite;
|
|
34
|
+
private refreshListFromServer;
|
|
31
35
|
fetchByIdFromServer(id: number | string): Promise<FloorPlanItem | null>;
|
|
32
36
|
fetchByCodeFromServer(code: string): Promise<FloorPlanItem | null>;
|
|
33
37
|
preload(): Promise<void>;
|
|
@@ -25,6 +25,7 @@ module.exports = __toCommonJS(floor_plan_exports);
|
|
|
25
25
|
var import_BaseModule = require("../../../modules/BaseModule");
|
|
26
26
|
var import_types = require("./types");
|
|
27
27
|
var FLOOR_PLAN_SYNC_DEBOUNCE_MS = 3e3;
|
|
28
|
+
var FLOOR_PLAN_STORE_NAME = "floor_plans";
|
|
28
29
|
var FloorPlanModule = class extends import_BaseModule.BaseModule {
|
|
29
30
|
constructor(name, version) {
|
|
30
31
|
super(name, version);
|
|
@@ -50,6 +51,7 @@ var FloorPlanModule = class extends import_BaseModule.BaseModule {
|
|
|
50
51
|
if (appPlugin) {
|
|
51
52
|
const app = appPlugin.getApp();
|
|
52
53
|
this.logger = app.logger;
|
|
54
|
+
this.dbManager = app.sqlite || app.dbManager;
|
|
53
55
|
}
|
|
54
56
|
this.initFloorPlanDataSource();
|
|
55
57
|
this.setupFloorPlanSync();
|
|
@@ -159,6 +161,45 @@ var FloorPlanModule = class extends import_BaseModule.BaseModule {
|
|
|
159
161
|
return [];
|
|
160
162
|
}
|
|
161
163
|
}
|
|
164
|
+
async loadListFromSQLite() {
|
|
165
|
+
if (!this.dbManager)
|
|
166
|
+
return [];
|
|
167
|
+
try {
|
|
168
|
+
const list = await this.dbManager.getAll(FLOOR_PLAN_STORE_NAME);
|
|
169
|
+
return Array.isArray(list) ? list : [];
|
|
170
|
+
} catch (error) {
|
|
171
|
+
this.logWarning("从 SQLite 读取平面图失败", {
|
|
172
|
+
error: error instanceof Error ? error.message : String(error)
|
|
173
|
+
});
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async saveListToSQLite(list) {
|
|
178
|
+
if (!this.dbManager)
|
|
179
|
+
return;
|
|
180
|
+
try {
|
|
181
|
+
await this.dbManager.clear(FLOOR_PLAN_STORE_NAME);
|
|
182
|
+
if (list.length > 0) {
|
|
183
|
+
await this.dbManager.bulkAdd(FLOOR_PLAN_STORE_NAME, list);
|
|
184
|
+
}
|
|
185
|
+
} catch (error) {
|
|
186
|
+
this.logWarning("保存平面图到 SQLite 失败", {
|
|
187
|
+
count: list.length,
|
|
188
|
+
error: error instanceof Error ? error.message : String(error)
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async refreshListFromServer() {
|
|
193
|
+
const list = await this.loadListFromServer();
|
|
194
|
+
if (list.length === 0) {
|
|
195
|
+
this.logWarning("远端平面图刷新完成但列表为空");
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
this.replaceStore(list);
|
|
199
|
+
await this.saveListToSQLite(list);
|
|
200
|
+
this.core.effects.emit(import_types.FloorPlanHooks.onFloorPlansChanged, this.getSortedList());
|
|
201
|
+
this.logInfo("远端平面图刷新完成", { count: list.length });
|
|
202
|
+
}
|
|
162
203
|
async fetchByIdFromServer(id) {
|
|
163
204
|
try {
|
|
164
205
|
const res = await this.request.get(
|
|
@@ -190,14 +231,19 @@ var FloorPlanModule = class extends import_BaseModule.BaseModule {
|
|
|
190
231
|
}
|
|
191
232
|
async preload() {
|
|
192
233
|
this.logInfo("开始预加载平面图列表");
|
|
193
|
-
const
|
|
194
|
-
if (
|
|
195
|
-
this.replaceStore(
|
|
234
|
+
const cachedList = await this.loadListFromSQLite();
|
|
235
|
+
if (cachedList.length > 0) {
|
|
236
|
+
this.replaceStore(cachedList);
|
|
196
237
|
this.core.effects.emit(import_types.FloorPlanHooks.onFloorPlansChanged, this.getSortedList());
|
|
197
|
-
this.logInfo("
|
|
198
|
-
|
|
199
|
-
|
|
238
|
+
this.logInfo("预加载完成(SQLite)", { count: cachedList.length });
|
|
239
|
+
void this.refreshListFromServer().catch((error) => {
|
|
240
|
+
this.logWarning("后台刷新平面图失败,继续使用本地数据", {
|
|
241
|
+
error: error instanceof Error ? error.message : String(error)
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
return;
|
|
200
245
|
}
|
|
246
|
+
await this.refreshListFromServer();
|
|
201
247
|
}
|
|
202
248
|
initFloorPlanDataSource() {
|
|
203
249
|
var _a, _b;
|
|
@@ -299,6 +345,7 @@ var FloorPlanModule = class extends import_BaseModule.BaseModule {
|
|
|
299
345
|
}
|
|
300
346
|
}
|
|
301
347
|
if (changed) {
|
|
348
|
+
await this.saveListToSQLite(this.store.list);
|
|
302
349
|
this.core.effects.emit(import_types.FloorPlanHooks.onFloorPlansChanged, this.getSortedList());
|
|
303
350
|
this.core.effects.emit(import_types.FloorPlanHooks.onFloorPlanSyncCompleted, null);
|
|
304
351
|
}
|
|
@@ -307,6 +354,7 @@ var FloorPlanModule = class extends import_BaseModule.BaseModule {
|
|
|
307
354
|
this.store.list = [];
|
|
308
355
|
this.store.map.clear();
|
|
309
356
|
this.store.codeMap.clear();
|
|
357
|
+
await this.saveListToSQLite([]);
|
|
310
358
|
}
|
|
311
359
|
destroy() {
|
|
312
360
|
var _a;
|
|
@@ -235,6 +235,7 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
235
235
|
*/
|
|
236
236
|
private lookupOrderIndexByIdentityKeys;
|
|
237
237
|
private isRemoteEchoMergeSource;
|
|
238
|
+
private isRemoteProductMembershipChangeSource;
|
|
238
239
|
private getProductMembershipKey;
|
|
239
240
|
private doProductsHaveStableMembershipIdentity;
|
|
240
241
|
/**
|
|
@@ -289,13 +290,14 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
289
290
|
private logDuplicateOrders;
|
|
290
291
|
private compactOrderListByIdentity;
|
|
291
292
|
/**
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
* - 无法解析时退化为自然日窗口
|
|
293
|
+
* 当前订单缓存可复用窗口。
|
|
294
|
+
* start_time 模式使用精确的营业日起止时间;配置缺失或异常时退化为自然日。
|
|
295
295
|
*/
|
|
296
|
-
private
|
|
296
|
+
private getCurrentOrderCacheWindow;
|
|
297
297
|
private hasPulledOrdersToday;
|
|
298
298
|
private markOrderPulledAtNow;
|
|
299
|
+
private clearOrderSnapshotMarker;
|
|
300
|
+
private getCurrentShopId;
|
|
299
301
|
private getStorageItem;
|
|
300
302
|
private setStorageItem;
|
|
301
303
|
private loadOrdersFromSQLite;
|
|
@@ -333,7 +335,7 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
333
335
|
* 用于 SSE 全量拉取与营业日窗口裁剪。
|
|
334
336
|
*
|
|
335
337
|
* @example
|
|
336
|
-
* await this.replaceOrdersSnapshotInSQLite(orderList)
|
|
338
|
+
* const { orders, persisted } = await this.replaceOrdersSnapshotInSQLite(orderList, 'refresh')
|
|
337
339
|
*/
|
|
338
340
|
private replaceOrdersSnapshotInSQLite;
|
|
339
341
|
/**
|