@pisell/pisellos 2.3.58 → 2.3.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.js +109 -66
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/modules/Quotation/index.d.ts +6 -0
- package/dist/modules/Quotation/index.js +75 -19
- package/dist/plugins/request.d.ts +1 -0
- package/dist/server/index.d.ts +15 -2
- package/dist/server/index.js +222 -147
- package/dist/server/modules/floor-plan/index.d.ts +4 -0
- package/dist/server/modules/floor-plan/index.js +240 -98
- package/dist/server/modules/menu/index.js +48 -23
- package/dist/server/modules/order/index.d.ts +12 -7
- package/dist/server/modules/order/index.js +248 -96
- package/dist/server/modules/products/index.d.ts +8 -2
- package/dist/server/modules/products/index.js +167 -75
- package/dist/server/modules/resource/index.js +21 -13
- package/lib/core/index.d.ts +7 -0
- package/lib/core/index.js +20 -3
- package/lib/model/strategy/adapter/promotion/index.js +51 -0
- package/lib/modules/Quotation/index.d.ts +6 -0
- package/lib/modules/Quotation/index.js +49 -5
- package/lib/plugins/request.d.ts +1 -0
- package/lib/server/index.d.ts +15 -2
- package/lib/server/index.js +87 -23
- package/lib/server/modules/floor-plan/index.d.ts +4 -0
- package/lib/server/modules/floor-plan/index.js +54 -6
- package/lib/server/modules/menu/index.js +31 -5
- package/lib/server/modules/order/index.d.ts +12 -7
- package/lib/server/modules/order/index.js +143 -28
- package/lib/server/modules/products/index.d.ts +8 -2
- package/lib/server/modules/products/index.js +97 -24
- package/lib/server/modules/resource/index.js +7 -2
- package/package.json +1 -1
|
@@ -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)
|
package/lib/plugins/request.d.ts
CHANGED
package/lib/server/index.d.ts
CHANGED
|
@@ -157,13 +157,17 @@ declare class Server {
|
|
|
157
157
|
* 重新拉取全量 SSE 接口,更新本地数据后触发 onProductsSyncCompleted
|
|
158
158
|
* 不影响当前界面展示,适用于切回前台、定时刷新等场景
|
|
159
159
|
*/
|
|
160
|
-
refreshProductsInBackground(
|
|
160
|
+
refreshProductsInBackground(options?: {
|
|
161
|
+
trigger?: string;
|
|
162
|
+
}): Promise<void>;
|
|
161
163
|
/**
|
|
162
164
|
* 后台静默刷新订单数据
|
|
163
165
|
* 重新拉取全量 SSE 接口,更新本地数据后触发 onOrdersSyncCompleted
|
|
164
166
|
* 不影响当前界面展示,适用于切回前台、定时刷新等场景
|
|
165
167
|
*/
|
|
166
|
-
refreshOrdersInBackground(
|
|
168
|
+
refreshOrdersInBackground(options?: {
|
|
169
|
+
trigger?: string;
|
|
170
|
+
}): Promise<void>;
|
|
167
171
|
/**
|
|
168
172
|
* 编辑正式订单时强制查询 Server 最新快照并覆盖本地缓存。
|
|
169
173
|
* 商品成员增删由 OrderModule 在 SQLite/Store 更新完成后广播,
|
|
@@ -263,6 +267,11 @@ declare class Server {
|
|
|
263
267
|
* 对单个商品 query 订阅者重算并推送(定时路径;不新建 schedule timer)。
|
|
264
268
|
*/
|
|
265
269
|
private recomputeAndNotifySubscriber;
|
|
270
|
+
/**
|
|
271
|
+
* 根据餐牌 ID 获取其绑定日程中的全部时间点。
|
|
272
|
+
* 商品查询定时器与 schedule-time-points 路由共用此逻辑。
|
|
273
|
+
*/
|
|
274
|
+
private getMenuScheduleTimePoints;
|
|
266
275
|
/**
|
|
267
276
|
* query 完成后为 subscriber 同步 schedule 定时器(先 clear 再 schedule)。
|
|
268
277
|
*/
|
|
@@ -518,6 +527,10 @@ declare class Server {
|
|
|
518
527
|
private handleOrderDraftSubmit;
|
|
519
528
|
private handlePendingSyncCheckoutOrder;
|
|
520
529
|
private buildPendingSyncCheckoutOrder;
|
|
530
|
+
/**
|
|
531
|
+
* Android 结账自动小票由当前设备设置控制;其它平台保持原有行为。
|
|
532
|
+
*/
|
|
533
|
+
private shouldAutoPrintCheckoutReceipt;
|
|
521
534
|
private shouldBuildSmallTicketData;
|
|
522
535
|
private shouldPrintSyncedOrder;
|
|
523
536
|
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) {
|
|
@@ -1742,22 +1761,27 @@ var Server = class {
|
|
|
1742
1761
|
* 重新拉取全量 SSE 接口,更新本地数据后触发 onProductsSyncCompleted
|
|
1743
1762
|
* 不影响当前界面展示,适用于切回前台、定时刷新等场景
|
|
1744
1763
|
*/
|
|
1745
|
-
async refreshProductsInBackground() {
|
|
1764
|
+
async refreshProductsInBackground(options = {}) {
|
|
1746
1765
|
if (!this.products) {
|
|
1747
1766
|
this.logWarning("refreshProductsInBackground: Products 模块未注册");
|
|
1748
1767
|
return;
|
|
1749
1768
|
}
|
|
1750
|
-
|
|
1769
|
+
const trigger = options.trigger || "background";
|
|
1770
|
+
this.logInfo("refreshProductsInBackground 开始", { trigger });
|
|
1751
1771
|
const startTime = Date.now();
|
|
1752
1772
|
try {
|
|
1753
|
-
await this.products.silentRefresh();
|
|
1773
|
+
await this.products.silentRefresh({ trigger });
|
|
1754
1774
|
const duration = Date.now() - startTime;
|
|
1755
|
-
this.logInfo("refreshProductsInBackground 完成", {
|
|
1775
|
+
this.logInfo("refreshProductsInBackground 完成", {
|
|
1776
|
+
trigger,
|
|
1777
|
+
duration: `${duration}ms`
|
|
1778
|
+
});
|
|
1756
1779
|
} catch (error) {
|
|
1757
1780
|
const duration = Date.now() - startTime;
|
|
1758
1781
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1759
1782
|
console.error("[Server] refreshProductsInBackground 失败:", error);
|
|
1760
1783
|
this.logError("refreshProductsInBackground 失败", {
|
|
1784
|
+
trigger,
|
|
1761
1785
|
duration: `${duration}ms`,
|
|
1762
1786
|
error: errorMessage
|
|
1763
1787
|
});
|
|
@@ -1768,22 +1792,27 @@ var Server = class {
|
|
|
1768
1792
|
* 重新拉取全量 SSE 接口,更新本地数据后触发 onOrdersSyncCompleted
|
|
1769
1793
|
* 不影响当前界面展示,适用于切回前台、定时刷新等场景
|
|
1770
1794
|
*/
|
|
1771
|
-
async refreshOrdersInBackground() {
|
|
1795
|
+
async refreshOrdersInBackground(options = {}) {
|
|
1772
1796
|
if (!this.order) {
|
|
1773
1797
|
this.logWarning("refreshOrdersInBackground: Order 模块未注册");
|
|
1774
1798
|
return;
|
|
1775
1799
|
}
|
|
1776
|
-
|
|
1800
|
+
const trigger = options.trigger || "background";
|
|
1801
|
+
this.logInfo("refreshOrdersInBackground 开始", { trigger });
|
|
1777
1802
|
const startTime = Date.now();
|
|
1778
1803
|
try {
|
|
1779
|
-
await this.order.silentRefresh();
|
|
1804
|
+
await this.order.silentRefresh({ trigger });
|
|
1780
1805
|
const duration = Date.now() - startTime;
|
|
1781
|
-
this.logInfo("refreshOrdersInBackground 完成", {
|
|
1806
|
+
this.logInfo("refreshOrdersInBackground 完成", {
|
|
1807
|
+
trigger,
|
|
1808
|
+
duration: `${duration}ms`
|
|
1809
|
+
});
|
|
1782
1810
|
} catch (error) {
|
|
1783
1811
|
const duration = Date.now() - startTime;
|
|
1784
1812
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1785
1813
|
console.error("[Server] refreshOrdersInBackground 失败:", error);
|
|
1786
1814
|
this.logError("refreshOrdersInBackground 失败", {
|
|
1815
|
+
trigger,
|
|
1787
1816
|
duration: `${duration}ms`,
|
|
1788
1817
|
error: errorMessage
|
|
1789
1818
|
});
|
|
@@ -2319,16 +2348,44 @@ var Server = class {
|
|
|
2319
2348
|
});
|
|
2320
2349
|
}
|
|
2321
2350
|
}
|
|
2351
|
+
/**
|
|
2352
|
+
* 根据餐牌 ID 获取其绑定日程中的全部时间点。
|
|
2353
|
+
* 商品查询定时器与 schedule-time-points 路由共用此逻辑。
|
|
2354
|
+
*/
|
|
2355
|
+
getMenuScheduleTimePoints(menuListIds) {
|
|
2356
|
+
var _a, _b;
|
|
2357
|
+
const menuList = ((_a = this.menu) == null ? void 0 : _a.getMenuByIds(menuListIds)) ?? [];
|
|
2358
|
+
const scheduleIds = (0, import_schedule2.extractScheduleIdsFromMenus)(menuList);
|
|
2359
|
+
const scheduleList = scheduleIds.length > 0 ? ((_b = this.schedule) == null ? void 0 : _b.getScheduleByIds(scheduleIds)) ?? [] : [];
|
|
2360
|
+
const timePoints = (0, import_schedule2.extractTimePointsFromSchedules)(scheduleList);
|
|
2361
|
+
return {
|
|
2362
|
+
menuList,
|
|
2363
|
+
scheduleIds,
|
|
2364
|
+
scheduleList,
|
|
2365
|
+
timePoints
|
|
2366
|
+
};
|
|
2367
|
+
}
|
|
2322
2368
|
/**
|
|
2323
2369
|
* query 完成后为 subscriber 同步 schedule 定时器(先 clear 再 schedule)。
|
|
2324
2370
|
*/
|
|
2325
|
-
syncProductQueryScheduleTimers(
|
|
2371
|
+
syncProductQueryScheduleTimers({
|
|
2372
|
+
subscriberId,
|
|
2373
|
+
menu_list_ids,
|
|
2374
|
+
strategy_context
|
|
2375
|
+
}) {
|
|
2326
2376
|
var _a, _b;
|
|
2327
2377
|
this.clearSubscriberScheduleTimers(subscriberId);
|
|
2328
2378
|
if (!this.shouldScheduleProductQueryReload(strategy_context)) {
|
|
2329
2379
|
return;
|
|
2330
2380
|
}
|
|
2331
|
-
const
|
|
2381
|
+
const productTimePoints = ((_b = (_a = this.products) == null ? void 0 : _a.getLastScheduleTimePoints) == null ? void 0 : _b.call(_a)) ?? [];
|
|
2382
|
+
const menuListIds = Array.isArray(menu_list_ids) ? Array.from(new Set(
|
|
2383
|
+
menu_list_ids.map((id) => Number(id)).filter((id) => Number.isFinite(id))
|
|
2384
|
+
)) : [];
|
|
2385
|
+
const menuTimePoints = this.getMenuScheduleTimePoints(menuListIds).timePoints;
|
|
2386
|
+
const timePoints = (0, import_time.sortTimePoints)(
|
|
2387
|
+
Array.from(/* @__PURE__ */ new Set([...productTimePoints, ...menuTimePoints]))
|
|
2388
|
+
);
|
|
2332
2389
|
if (timePoints.length > 0) {
|
|
2333
2390
|
this.scheduleSubscriberTimePointReloads(subscriberId, timePoints);
|
|
2334
2391
|
}
|
|
@@ -3791,7 +3848,6 @@ var Server = class {
|
|
|
3791
3848
|
});
|
|
3792
3849
|
}
|
|
3793
3850
|
async handleOrderCheckoutSubmit(params) {
|
|
3794
|
-
var _a;
|
|
3795
3851
|
const { backendPath, data, title } = params;
|
|
3796
3852
|
this.logInfo(`${title}: 开始处理`, {
|
|
3797
3853
|
backendPath,
|
|
@@ -3816,15 +3872,14 @@ var Server = class {
|
|
|
3816
3872
|
});
|
|
3817
3873
|
if ((pendingResult == null ? void 0 : pendingResult.status) === true) {
|
|
3818
3874
|
const pendingOrder = pendingResult.data;
|
|
3819
|
-
|
|
3820
|
-
const isAndroid = platform === "android";
|
|
3821
|
-
if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && // TODO 这里先加个兼容,如果是安卓,则需要 type=virtual 才走打印,如果是苹果则无限制
|
|
3822
|
-
(isAndroid ? checkoutData.type === "virtual" : true)) {
|
|
3875
|
+
if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && this.shouldAutoPrintCheckoutReceipt()) {
|
|
3823
3876
|
await this.dispatchLocalReceiptPrint({
|
|
3824
3877
|
checkoutData,
|
|
3825
3878
|
order: pendingOrder,
|
|
3826
3879
|
response: pendingResult,
|
|
3827
|
-
requireFullyPaid: true
|
|
3880
|
+
requireFullyPaid: true,
|
|
3881
|
+
// 自动小票固定使用 print_all 的收据类型 0,不随订单 type 改成券/手环类型 99。
|
|
3882
|
+
isManualPrint: true
|
|
3828
3883
|
});
|
|
3829
3884
|
}
|
|
3830
3885
|
await this.dispatchCheckoutSyncTask({
|
|
@@ -4054,6 +4109,15 @@ var Server = class {
|
|
|
4054
4109
|
{ requireFullyPaid: true, productMap }
|
|
4055
4110
|
);
|
|
4056
4111
|
}
|
|
4112
|
+
/**
|
|
4113
|
+
* Android 结账自动小票由当前设备设置控制;其它平台保持原有行为。
|
|
4114
|
+
*/
|
|
4115
|
+
shouldAutoPrintCheckoutReceipt() {
|
|
4116
|
+
var _a, _b, _c, _d, _e;
|
|
4117
|
+
if (((_b = (_a = this.core.context) == null ? void 0 : _a.getPlatform) == null ? void 0 : _b.call(_a)) !== "android")
|
|
4118
|
+
return true;
|
|
4119
|
+
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";
|
|
4120
|
+
}
|
|
4057
4121
|
shouldBuildSmallTicketData(order) {
|
|
4058
4122
|
if (!order || typeof order !== "object")
|
|
4059
4123
|
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;
|
|
@@ -185,16 +185,21 @@ var MenuModule = class extends import_BaseModule.BaseModule {
|
|
|
185
185
|
this.logWarning("loadMenuFromIndexDB: dbManager 不可用");
|
|
186
186
|
return [];
|
|
187
187
|
}
|
|
188
|
+
const startedAt = performance.now();
|
|
188
189
|
try {
|
|
189
190
|
const menuList = await this.dbManager.getAll(INDEXDB_STORE_NAME);
|
|
190
191
|
this.logInfo("从 IndexDB 加载餐牌数据", {
|
|
191
|
-
menuCount: (menuList == null ? void 0 : menuList.length) ?? 0
|
|
192
|
+
menuCount: (menuList == null ? void 0 : menuList.length) ?? 0,
|
|
193
|
+
durationMs: +(performance.now() - startedAt).toFixed(2)
|
|
192
194
|
});
|
|
193
195
|
return menuList || [];
|
|
194
196
|
} catch (error) {
|
|
195
197
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
196
198
|
console.error("[Menu] 从 IndexDB 读取数据失败:", error);
|
|
197
|
-
this.logError("从 IndexDB 读取数据失败", {
|
|
199
|
+
this.logError("从 IndexDB 读取数据失败", {
|
|
200
|
+
durationMs: +(performance.now() - startedAt).toFixed(2),
|
|
201
|
+
error: errorMessage
|
|
202
|
+
});
|
|
198
203
|
return [];
|
|
199
204
|
}
|
|
200
205
|
}
|
|
@@ -207,20 +212,41 @@ var MenuModule = class extends import_BaseModule.BaseModule {
|
|
|
207
212
|
this.logWarning("saveMenuToIndexDB: dbManager 不可用");
|
|
208
213
|
return;
|
|
209
214
|
}
|
|
215
|
+
const startedAt = performance.now();
|
|
216
|
+
let clearDurationMs = 0;
|
|
217
|
+
let writeDurationMs = 0;
|
|
210
218
|
this.logInfo("开始保存餐牌数据到 IndexDB", { menuCount: menuList.length });
|
|
211
219
|
try {
|
|
212
|
-
|
|
220
|
+
const clearStartedAt = performance.now();
|
|
221
|
+
try {
|
|
222
|
+
await this.dbManager.clear(INDEXDB_STORE_NAME);
|
|
223
|
+
} finally {
|
|
224
|
+
clearDurationMs = +(performance.now() - clearStartedAt).toFixed(2);
|
|
225
|
+
}
|
|
226
|
+
const writeStartedAt = performance.now();
|
|
213
227
|
const savePromises = menuList.map(
|
|
214
228
|
(menu) => this.dbManager.add(INDEXDB_STORE_NAME, menu)
|
|
215
229
|
);
|
|
216
|
-
|
|
230
|
+
try {
|
|
231
|
+
await Promise.all(savePromises);
|
|
232
|
+
} finally {
|
|
233
|
+
writeDurationMs = +(performance.now() - writeStartedAt).toFixed(2);
|
|
234
|
+
}
|
|
217
235
|
console.log(`[Menu] 已将 ${menuList.length} 条餐牌数据保存到 IndexDB`);
|
|
218
|
-
this.logInfo("餐牌数据已保存到 IndexDB", {
|
|
236
|
+
this.logInfo("餐牌数据已保存到 IndexDB", {
|
|
237
|
+
menuCount: menuList.length,
|
|
238
|
+
clearDurationMs,
|
|
239
|
+
writeDurationMs,
|
|
240
|
+
totalDurationMs: +(performance.now() - startedAt).toFixed(2)
|
|
241
|
+
});
|
|
219
242
|
} catch (error) {
|
|
220
243
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
221
244
|
console.error("[Menu] 保存数据到 IndexDB 失败:", error);
|
|
222
245
|
this.logError("保存数据到 IndexDB 失败", {
|
|
223
246
|
menuCount: menuList.length,
|
|
247
|
+
clearDurationMs,
|
|
248
|
+
writeDurationMs,
|
|
249
|
+
totalDurationMs: +(performance.now() - startedAt).toFixed(2),
|
|
224
250
|
error: errorMessage
|
|
225
251
|
});
|
|
226
252
|
}
|
|
@@ -119,13 +119,17 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
119
119
|
payment: Record<string, any>;
|
|
120
120
|
previousPayment: Record<string, any>;
|
|
121
121
|
} | null>;
|
|
122
|
-
loadOrdersByServer(
|
|
122
|
+
loadOrdersByServer(options?: {
|
|
123
|
+
trigger?: string;
|
|
124
|
+
}): Promise<OrderData[]>;
|
|
123
125
|
/**
|
|
124
126
|
* 静默全量刷新:后台重新拉取全量 SSE 订单数据并更新本地
|
|
125
127
|
* 拿到完整数据后一次性替换 store,触发订单变更与同步完成事件
|
|
126
128
|
* @returns 刷新后的订单列表
|
|
127
129
|
*/
|
|
128
|
-
silentRefresh(
|
|
130
|
+
silentRefresh(options?: {
|
|
131
|
+
trigger?: string;
|
|
132
|
+
}): Promise<OrderData[]>;
|
|
129
133
|
private normalizeOrderForMemoryList;
|
|
130
134
|
private normalizeOrdersForMemoryList;
|
|
131
135
|
private hasRealOrderId;
|
|
@@ -290,13 +294,14 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
290
294
|
private logDuplicateOrders;
|
|
291
295
|
private compactOrderListByIdentity;
|
|
292
296
|
/**
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
* - 无法解析时退化为自然日窗口
|
|
297
|
+
* 当前订单缓存可复用窗口。
|
|
298
|
+
* start_time 模式使用精确的营业日起止时间;配置缺失或异常时退化为自然日。
|
|
296
299
|
*/
|
|
297
|
-
private
|
|
300
|
+
private getCurrentOrderCacheWindow;
|
|
298
301
|
private hasPulledOrdersToday;
|
|
299
302
|
private markOrderPulledAtNow;
|
|
303
|
+
private clearOrderSnapshotMarker;
|
|
304
|
+
private getCurrentShopId;
|
|
300
305
|
private getStorageItem;
|
|
301
306
|
private setStorageItem;
|
|
302
307
|
private loadOrdersFromSQLite;
|
|
@@ -334,7 +339,7 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
334
339
|
* 用于 SSE 全量拉取与营业日窗口裁剪。
|
|
335
340
|
*
|
|
336
341
|
* @example
|
|
337
|
-
* await this.replaceOrdersSnapshotInSQLite(orderList)
|
|
342
|
+
* const { orders, persisted } = await this.replaceOrdersSnapshotInSQLite(orderList, 'refresh')
|
|
338
343
|
*/
|
|
339
344
|
private replaceOrdersSnapshotInSQLite;
|
|
340
345
|
/**
|