@pisell/pisellos 2.3.73 → 2.3.74
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/modules/Order/index.d.ts +1 -1
- 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 +8 -2
- package/dist/server/index.js +206 -140
- 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 +17 -7
- package/dist/server/modules/order/index.js +419 -207
- 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/dist/solution/BookingByStep/index.d.ts +1 -1
- package/lib/core/index.d.ts +7 -0
- package/lib/core/index.js +20 -2
- package/lib/modules/Order/index.d.ts +1 -1
- 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 +8 -2
- package/lib/server/index.js +52 -17
- 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 +17 -7
- package/lib/server/modules/order/index.js +197 -40
- 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/lib/solution/BookingByStep/index.d.ts +1 -1
- 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
|
@@ -51,6 +51,8 @@ declare class Server {
|
|
|
51
51
|
private productQueryScheduleTimers;
|
|
52
52
|
/** 餐牌筛选为空时才触发的菜单/日程缓存自愈,避免每次商品查询都请求远端。 */
|
|
53
53
|
private menuScheduleRefreshInFlight;
|
|
54
|
+
/** 启动阶段模块预加载任务;预渲染商品查询复用该任务,避免缓存尚未 ready 时误触发远端自愈。 */
|
|
55
|
+
private startupModulePreloadInFlight;
|
|
54
56
|
private lastMenuScheduleRefreshAt;
|
|
55
57
|
private readonly MENU_SCHEDULE_REFRESH_COOLDOWN_MS;
|
|
56
58
|
private orderQuerySubscribers;
|
|
@@ -157,13 +159,17 @@ declare class Server {
|
|
|
157
159
|
* 重新拉取全量 SSE 接口,更新本地数据后触发 onProductsSyncCompleted
|
|
158
160
|
* 不影响当前界面展示,适用于切回前台、定时刷新等场景
|
|
159
161
|
*/
|
|
160
|
-
refreshProductsInBackground(
|
|
162
|
+
refreshProductsInBackground(options?: {
|
|
163
|
+
trigger?: string;
|
|
164
|
+
}): Promise<void>;
|
|
161
165
|
/**
|
|
162
166
|
* 后台静默刷新订单数据
|
|
163
167
|
* 重新拉取全量 SSE 接口,更新本地数据后触发 onOrdersSyncCompleted
|
|
164
168
|
* 不影响当前界面展示,适用于切回前台、定时刷新等场景
|
|
165
169
|
*/
|
|
166
|
-
refreshOrdersInBackground(
|
|
170
|
+
refreshOrdersInBackground(options?: {
|
|
171
|
+
trigger?: string;
|
|
172
|
+
}): Promise<void>;
|
|
167
173
|
/**
|
|
168
174
|
* 编辑正式订单时强制查询 Server 最新快照并覆盖本地缓存。
|
|
169
175
|
* 商品成员增删由 OrderModule 在 SQLite/Store 更新完成后广播,
|
package/lib/server/index.js
CHANGED
|
@@ -86,6 +86,8 @@ var Server = class {
|
|
|
86
86
|
this.productQueryScheduleTimers = /* @__PURE__ */ new Map();
|
|
87
87
|
/** 餐牌筛选为空时才触发的菜单/日程缓存自愈,避免每次商品查询都请求远端。 */
|
|
88
88
|
this.menuScheduleRefreshInFlight = null;
|
|
89
|
+
/** 启动阶段模块预加载任务;预渲染商品查询复用该任务,避免缓存尚未 ready 时误触发远端自愈。 */
|
|
90
|
+
this.startupModulePreloadInFlight = null;
|
|
89
91
|
this.lastMenuScheduleRefreshAt = 0;
|
|
90
92
|
this.MENU_SCHEDULE_REFRESH_COOLDOWN_MS = 30 * 1e3;
|
|
91
93
|
// ---- 订单 / 预约列表查询订阅者 ----
|
|
@@ -1383,7 +1385,15 @@ var Server = class {
|
|
|
1383
1385
|
this.registerDeviceTaskActions();
|
|
1384
1386
|
const registeredModules = await this.registerModules(moduleConfigs);
|
|
1385
1387
|
if (autoPreload) {
|
|
1386
|
-
|
|
1388
|
+
const preloadTask = this.preloadModulesData(registeredModules, options);
|
|
1389
|
+
this.startupModulePreloadInFlight = preloadTask;
|
|
1390
|
+
try {
|
|
1391
|
+
await preloadTask;
|
|
1392
|
+
} finally {
|
|
1393
|
+
if (this.startupModulePreloadInFlight === preloadTask) {
|
|
1394
|
+
this.startupModulePreloadInFlight = null;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1387
1397
|
} else {
|
|
1388
1398
|
this.logInfo("跳过自动预加载", { autoPreload });
|
|
1389
1399
|
}
|
|
@@ -1688,11 +1698,22 @@ var Server = class {
|
|
|
1688
1698
|
return;
|
|
1689
1699
|
}
|
|
1690
1700
|
try {
|
|
1691
|
-
await this.schedule.loadAllSchedule();
|
|
1692
1701
|
this.products.clearPriceCache();
|
|
1693
1702
|
await this.products.setupQuotationPriceBridge({
|
|
1694
1703
|
scheduleModule: this.schedule,
|
|
1695
|
-
channel: (_a = this.core.context) == null ? void 0 : _a.channel
|
|
1704
|
+
channel: (_a = this.core.context) == null ? void 0 : _a.channel,
|
|
1705
|
+
onQuotationUpdated: () => {
|
|
1706
|
+
void this.recomputeAndNotifyProductQuery();
|
|
1707
|
+
}
|
|
1708
|
+
});
|
|
1709
|
+
void this.schedule.loadAllSchedule().then(() => {
|
|
1710
|
+
var _a2;
|
|
1711
|
+
(_a2 = this.products) == null ? void 0 : _a2.clearPriceCache();
|
|
1712
|
+
void this.recomputeAndNotifyProductQuery();
|
|
1713
|
+
}).catch((error) => {
|
|
1714
|
+
this.logWarning("Products 报价单价格桥接后台刷新 Schedule 失败,继续使用本地数据", {
|
|
1715
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1716
|
+
});
|
|
1696
1717
|
});
|
|
1697
1718
|
this.logInfo("Products 报价单价格桥接初始化完成");
|
|
1698
1719
|
} catch (error) {
|
|
@@ -1750,22 +1771,27 @@ var Server = class {
|
|
|
1750
1771
|
* 重新拉取全量 SSE 接口,更新本地数据后触发 onProductsSyncCompleted
|
|
1751
1772
|
* 不影响当前界面展示,适用于切回前台、定时刷新等场景
|
|
1752
1773
|
*/
|
|
1753
|
-
async refreshProductsInBackground() {
|
|
1774
|
+
async refreshProductsInBackground(options = {}) {
|
|
1754
1775
|
if (!this.products) {
|
|
1755
1776
|
this.logWarning("refreshProductsInBackground: Products 模块未注册");
|
|
1756
1777
|
return;
|
|
1757
1778
|
}
|
|
1758
|
-
|
|
1779
|
+
const trigger = options.trigger || "background";
|
|
1780
|
+
this.logInfo("refreshProductsInBackground 开始", { trigger });
|
|
1759
1781
|
const startTime = Date.now();
|
|
1760
1782
|
try {
|
|
1761
|
-
await this.products.silentRefresh();
|
|
1783
|
+
await this.products.silentRefresh({ trigger });
|
|
1762
1784
|
const duration = Date.now() - startTime;
|
|
1763
|
-
this.logInfo("refreshProductsInBackground 完成", {
|
|
1785
|
+
this.logInfo("refreshProductsInBackground 完成", {
|
|
1786
|
+
trigger,
|
|
1787
|
+
duration: `${duration}ms`
|
|
1788
|
+
});
|
|
1764
1789
|
} catch (error) {
|
|
1765
1790
|
const duration = Date.now() - startTime;
|
|
1766
1791
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1767
1792
|
console.error("[Server] refreshProductsInBackground 失败:", error);
|
|
1768
1793
|
this.logError("refreshProductsInBackground 失败", {
|
|
1794
|
+
trigger,
|
|
1769
1795
|
duration: `${duration}ms`,
|
|
1770
1796
|
error: errorMessage
|
|
1771
1797
|
});
|
|
@@ -1776,22 +1802,27 @@ var Server = class {
|
|
|
1776
1802
|
* 重新拉取全量 SSE 接口,更新本地数据后触发 onOrdersSyncCompleted
|
|
1777
1803
|
* 不影响当前界面展示,适用于切回前台、定时刷新等场景
|
|
1778
1804
|
*/
|
|
1779
|
-
async refreshOrdersInBackground() {
|
|
1805
|
+
async refreshOrdersInBackground(options = {}) {
|
|
1780
1806
|
if (!this.order) {
|
|
1781
1807
|
this.logWarning("refreshOrdersInBackground: Order 模块未注册");
|
|
1782
1808
|
return;
|
|
1783
1809
|
}
|
|
1784
|
-
|
|
1810
|
+
const trigger = options.trigger || "background";
|
|
1811
|
+
this.logInfo("refreshOrdersInBackground 开始", { trigger });
|
|
1785
1812
|
const startTime = Date.now();
|
|
1786
1813
|
try {
|
|
1787
|
-
await this.order.silentRefresh();
|
|
1814
|
+
await this.order.silentRefresh({ trigger });
|
|
1788
1815
|
const duration = Date.now() - startTime;
|
|
1789
|
-
this.logInfo("refreshOrdersInBackground 完成", {
|
|
1816
|
+
this.logInfo("refreshOrdersInBackground 完成", {
|
|
1817
|
+
trigger,
|
|
1818
|
+
duration: `${duration}ms`
|
|
1819
|
+
});
|
|
1790
1820
|
} catch (error) {
|
|
1791
1821
|
const duration = Date.now() - startTime;
|
|
1792
1822
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1793
1823
|
console.error("[Server] refreshOrdersInBackground 失败:", error);
|
|
1794
1824
|
this.logError("refreshOrdersInBackground 失败", {
|
|
1825
|
+
trigger,
|
|
1795
1826
|
duration: `${duration}ms`,
|
|
1796
1827
|
error: errorMessage
|
|
1797
1828
|
});
|
|
@@ -5079,12 +5110,6 @@ var Server = class {
|
|
|
5079
5110
|
const tTotal = performance.now();
|
|
5080
5111
|
const { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type, product_id, strategy_context } = context;
|
|
5081
5112
|
const queryIds = Array.isArray(ids) ? ids.map((id) => Number(id)).filter((id) => Number.isFinite(id)) : [];
|
|
5082
|
-
const formatterContext = this.buildProductFormatterContext({
|
|
5083
|
-
schedule_date,
|
|
5084
|
-
schedule_datetime,
|
|
5085
|
-
customer_id,
|
|
5086
|
-
strategy_context
|
|
5087
|
-
});
|
|
5088
5113
|
this.logInfo("computeProductQueryResult 开始", {
|
|
5089
5114
|
menuListIdsCount: (menu_list_ids == null ? void 0 : menu_list_ids.length) ?? 0,
|
|
5090
5115
|
ids: queryIds,
|
|
@@ -5096,6 +5121,16 @@ var Server = class {
|
|
|
5096
5121
|
strategyContextKeys: strategy_context ? Object.keys(strategy_context) : [],
|
|
5097
5122
|
changedIds: options == null ? void 0 : options.changedIds
|
|
5098
5123
|
});
|
|
5124
|
+
const startupPreloadTask = this.startupModulePreloadInFlight;
|
|
5125
|
+
if (startupPreloadTask) {
|
|
5126
|
+
await startupPreloadTask;
|
|
5127
|
+
}
|
|
5128
|
+
const formatterContext = this.buildProductFormatterContext({
|
|
5129
|
+
schedule_date,
|
|
5130
|
+
schedule_datetime,
|
|
5131
|
+
customer_id,
|
|
5132
|
+
strategy_context
|
|
5133
|
+
});
|
|
5099
5134
|
if (!this.products) {
|
|
5100
5135
|
this.logError("computeProductQueryResult: Products 模块未注册");
|
|
5101
5136
|
return { message: "Products 模块未注册", data: this.buildProductQueryResultPayload([], 0) };
|
|
@@ -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,14 +119,23 @@ 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;
|
|
134
|
+
/**
|
|
135
|
+
* 将已经完成集合规范化的订单转换为内存身份,不重复扫描 products/bookings/payments。
|
|
136
|
+
*/
|
|
137
|
+
private prepareNormalizedOrderForMemoryList;
|
|
138
|
+
private prepareNormalizedOrdersForMemoryList;
|
|
130
139
|
private normalizeOrdersForMemoryList;
|
|
131
140
|
private hasRealOrderId;
|
|
132
141
|
private shouldKeepOrderInMemory;
|
|
@@ -291,13 +300,14 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
291
300
|
private logDuplicateOrders;
|
|
292
301
|
private compactOrderListByIdentity;
|
|
293
302
|
/**
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
* - 无法解析时退化为自然日窗口
|
|
303
|
+
* 当前订单缓存可复用窗口。
|
|
304
|
+
* start_time 模式使用精确的营业日起止时间;配置缺失或异常时退化为自然日。
|
|
297
305
|
*/
|
|
298
|
-
private
|
|
306
|
+
private getCurrentOrderCacheWindow;
|
|
299
307
|
private hasPulledOrdersToday;
|
|
300
308
|
private markOrderPulledAtNow;
|
|
309
|
+
private clearOrderSnapshotMarker;
|
|
310
|
+
private getCurrentShopId;
|
|
301
311
|
private getStorageItem;
|
|
302
312
|
private setStorageItem;
|
|
303
313
|
private loadOrdersFromSQLite;
|
|
@@ -335,7 +345,7 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
335
345
|
* 用于 SSE 全量拉取与营业日窗口裁剪。
|
|
336
346
|
*
|
|
337
347
|
* @example
|
|
338
|
-
* await this.replaceOrdersSnapshotInSQLite(orderList)
|
|
348
|
+
* const { orders, persisted } = await this.replaceOrdersSnapshotInSQLite(orderList, 'refresh')
|
|
339
349
|
*/
|
|
340
350
|
private replaceOrdersSnapshotInSQLite;
|
|
341
351
|
/**
|