@pisell/pisellos 2.2.93 → 2.2.94
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 +0 -1
- package/dist/core/index.js +0 -7
- package/dist/modules/Customer/index.d.ts +0 -1
- package/dist/modules/Customer/index.js +12 -28
- package/dist/plugins/app-types/app/app.d.ts +1 -0
- package/dist/server/index.d.ts +55 -5
- package/dist/server/index.js +832 -236
- package/dist/server/modules/index.d.ts +6 -0
- package/dist/server/modules/index.js +7 -0
- package/dist/server/modules/order/index.d.ts +87 -0
- package/dist/server/modules/order/index.js +916 -0
- package/dist/server/modules/order/types.d.ts +530 -0
- package/dist/server/modules/order/types.js +141 -0
- package/dist/server/modules/order/utils/filterBookings.d.ts +6 -0
- package/dist/server/modules/order/utils/filterBookings.js +350 -0
- package/dist/server/modules/order/utils/filterOrders.d.ts +15 -0
- package/dist/server/modules/order/utils/filterOrders.js +226 -0
- package/dist/server/modules/products/index.d.ts +24 -19
- package/dist/server/modules/products/index.js +600 -429
- package/dist/server/modules/products/types.d.ts +0 -1
- package/dist/server/modules/resource/index.d.ts +88 -0
- package/dist/server/modules/resource/index.js +1202 -0
- package/dist/server/modules/resource/types.d.ts +121 -0
- package/dist/server/modules/resource/types.js +47 -0
- package/dist/server/utils/product.d.ts +0 -4
- package/dist/server/utils/product.js +0 -34
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/Sales/index.d.ts +96 -0
- package/dist/solution/Sales/index.js +510 -0
- package/dist/solution/Sales/types.d.ts +65 -0
- package/dist/solution/Sales/types.js +26 -0
- package/dist/solution/index.d.ts +1 -0
- package/dist/solution/index.js +2 -1
- package/dist/types/index.d.ts +0 -2
- package/lib/core/index.d.ts +0 -1
- package/lib/core/index.js +0 -4
- package/lib/modules/Customer/index.d.ts +0 -1
- package/lib/modules/Customer/index.js +6 -21
- package/lib/plugins/app-types/app/app.d.ts +1 -0
- package/lib/server/index.d.ts +55 -5
- package/lib/server/index.js +350 -28
- package/lib/server/modules/index.d.ts +6 -0
- package/lib/server/modules/index.js +16 -2
- package/lib/server/modules/order/index.d.ts +87 -0
- package/lib/server/modules/order/index.js +543 -0
- package/lib/server/modules/order/types.d.ts +530 -0
- package/lib/server/modules/order/types.js +34 -0
- package/lib/server/modules/order/utils/filterBookings.d.ts +6 -0
- package/lib/server/modules/order/utils/filterBookings.js +320 -0
- package/lib/server/modules/order/utils/filterOrders.d.ts +15 -0
- package/lib/server/modules/order/utils/filterOrders.js +197 -0
- package/lib/server/modules/products/index.d.ts +24 -19
- package/lib/server/modules/products/index.js +150 -151
- package/lib/server/modules/products/types.d.ts +0 -1
- package/lib/server/modules/resource/index.d.ts +88 -0
- package/lib/server/modules/resource/index.js +571 -0
- package/lib/server/modules/resource/types.d.ts +121 -0
- package/lib/server/modules/resource/types.js +35 -0
- package/lib/server/utils/product.d.ts +0 -4
- package/lib/server/utils/product.js +0 -27
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/Sales/index.d.ts +96 -0
- package/lib/solution/Sales/index.js +358 -0
- package/lib/solution/Sales/types.d.ts +65 -0
- package/lib/solution/Sales/types.js +35 -0
- package/lib/solution/index.d.ts +1 -0
- package/lib/solution/index.js +3 -1
- package/lib/types/index.d.ts +0 -2
- package/package.json +1 -1
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/server/modules/resource/index.ts
|
|
20
|
+
var resource_exports = {};
|
|
21
|
+
__export(resource_exports, {
|
|
22
|
+
ResourceHooks: () => import_types2.ResourceHooks,
|
|
23
|
+
ResourceModule: () => ResourceModule,
|
|
24
|
+
resourceModule: () => resourceModule
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(resource_exports);
|
|
27
|
+
var import_lodash_es = require("lodash-es");
|
|
28
|
+
var import_BaseModule = require("../../../modules/BaseModule");
|
|
29
|
+
var import_types = require("./types");
|
|
30
|
+
var import_types2 = require("./types");
|
|
31
|
+
var RESOURCE_STORE_NAME = "resources";
|
|
32
|
+
var BOOKING_STORE_NAME = "resource_bookings";
|
|
33
|
+
var DEFAULT_PAGE_SIZE = 999;
|
|
34
|
+
var RESOURCE_SYNC_DEBOUNCE_MS = 1e4;
|
|
35
|
+
var ResourceModule = class extends import_BaseModule.BaseModule {
|
|
36
|
+
constructor(name, version) {
|
|
37
|
+
super(name, version);
|
|
38
|
+
this.defaultName = "resource";
|
|
39
|
+
this.defaultVersion = "1.0.0";
|
|
40
|
+
/** 倒排索引: resourceId -> ResourceBooking[] */
|
|
41
|
+
this.resourceIdIndex = /* @__PURE__ */ new Map();
|
|
42
|
+
/** 待处理的同步消息队列 */
|
|
43
|
+
this.pendingSyncMessages = [];
|
|
44
|
+
}
|
|
45
|
+
// ─────────────────────────────────────────────────────────────────
|
|
46
|
+
// 初始化 & 生命周期
|
|
47
|
+
// ─────────────────────────────────────────────────────────────────
|
|
48
|
+
async initialize(core, options) {
|
|
49
|
+
var _a, _b;
|
|
50
|
+
this.core = core;
|
|
51
|
+
this.store = options == null ? void 0 : options.store;
|
|
52
|
+
if (Array.isArray((_a = options == null ? void 0 : options.initialState) == null ? void 0 : _a.list)) {
|
|
53
|
+
this.store.list = ((_b = options == null ? void 0 : options.initialState) == null ? void 0 : _b.list).map(
|
|
54
|
+
(item) => this.normalizeResource(item)
|
|
55
|
+
);
|
|
56
|
+
this.syncResourcesMap();
|
|
57
|
+
this.core.effects.emit(import_types.ResourceHooks.onResourcesChanged, this.store.list);
|
|
58
|
+
} else {
|
|
59
|
+
this.store.list = [];
|
|
60
|
+
this.store.map = /* @__PURE__ */ new Map();
|
|
61
|
+
}
|
|
62
|
+
if (!Array.isArray(this.store.bookings)) {
|
|
63
|
+
this.store.bookings = [];
|
|
64
|
+
}
|
|
65
|
+
const appPlugin = core.getPlugin("app");
|
|
66
|
+
if (appPlugin) {
|
|
67
|
+
const app = appPlugin.getApp();
|
|
68
|
+
this.dbManager = app.sqlite || app.dbManager;
|
|
69
|
+
this.logger = app.logger;
|
|
70
|
+
}
|
|
71
|
+
this.initResourceDataSource();
|
|
72
|
+
this.setupResourceSync();
|
|
73
|
+
}
|
|
74
|
+
logInfo(title, metadata) {
|
|
75
|
+
if (this.logger) {
|
|
76
|
+
this.logger.addLog({
|
|
77
|
+
type: "info",
|
|
78
|
+
title: `[ResourceModule] ${title}`,
|
|
79
|
+
metadata: metadata || {}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
logError(title, error, metadata) {
|
|
84
|
+
if (this.logger) {
|
|
85
|
+
this.logger.addLog({
|
|
86
|
+
type: "error",
|
|
87
|
+
title: `[ResourceModule] ${title}`,
|
|
88
|
+
metadata: metadata || {}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async preload() {
|
|
93
|
+
const cachedResources = await this.loadResourcesFromSQLite();
|
|
94
|
+
if (cachedResources.length > 0) {
|
|
95
|
+
this.store.list = (0, import_lodash_es.cloneDeep)(cachedResources).map((item) => this.normalizeResource(item));
|
|
96
|
+
this.syncResourcesMap();
|
|
97
|
+
await this.safeEmit(import_types.ResourceHooks.onResourcesChanged, this.store.list);
|
|
98
|
+
} else {
|
|
99
|
+
const resources = await this.loadResourcesByServer();
|
|
100
|
+
if (resources.length > 0) {
|
|
101
|
+
this.store.list = (0, import_lodash_es.cloneDeep)(resources).map((item) => this.normalizeResource(item));
|
|
102
|
+
this.syncResourcesMap();
|
|
103
|
+
await this.safeEmit(import_types.ResourceHooks.onResourcesChanged, this.store.list);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const cachedBookings = await this.loadBookingsFromSQLite();
|
|
107
|
+
if (cachedBookings.length > 0) {
|
|
108
|
+
this.store.bookings = (0, import_lodash_es.cloneDeep)(cachedBookings);
|
|
109
|
+
this.syncBookingsIndex();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
getRoutes() {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
destroy() {
|
|
116
|
+
var _a;
|
|
117
|
+
if (this.syncTimer) {
|
|
118
|
+
clearTimeout(this.syncTimer);
|
|
119
|
+
this.syncTimer = void 0;
|
|
120
|
+
}
|
|
121
|
+
this.pendingSyncMessages = [];
|
|
122
|
+
if ((_a = this.resourceDataSource) == null ? void 0 : _a.destroy)
|
|
123
|
+
this.resourceDataSource.destroy();
|
|
124
|
+
super.destroy();
|
|
125
|
+
}
|
|
126
|
+
// ─────────────────────────────────────────────────────────────────
|
|
127
|
+
// Resource CRUD
|
|
128
|
+
// ─────────────────────────────────────────────────────────────────
|
|
129
|
+
/**
|
|
130
|
+
* 获取所有资源(支持 includeBookings 附加预订信息)
|
|
131
|
+
*/
|
|
132
|
+
getResources(queryOptions) {
|
|
133
|
+
this.logInfo("getResources", {
|
|
134
|
+
queryOptions
|
|
135
|
+
});
|
|
136
|
+
if (!(queryOptions == null ? void 0 : queryOptions.includeBookings)) {
|
|
137
|
+
return this.store.list;
|
|
138
|
+
}
|
|
139
|
+
return this.store.list.map((resource) => this.attachBookingsToResource(resource));
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 根据 ID 获取单个资源
|
|
143
|
+
*/
|
|
144
|
+
getResourceById(id, queryOptions) {
|
|
145
|
+
const resource = this.store.map.get(id);
|
|
146
|
+
if (!resource)
|
|
147
|
+
return void 0;
|
|
148
|
+
if (queryOptions == null ? void 0 : queryOptions.includeBookings) {
|
|
149
|
+
return this.attachBookingsToResource(resource);
|
|
150
|
+
}
|
|
151
|
+
return resource;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 创建资源
|
|
155
|
+
*/
|
|
156
|
+
createResource(data) {
|
|
157
|
+
const id = (data == null ? void 0 : data.id) ?? (data == null ? void 0 : data.form_record_id) ?? Date.now();
|
|
158
|
+
const resource = this.normalizeResource({ ...data, id });
|
|
159
|
+
this.store.list.push(resource);
|
|
160
|
+
this.store.map.set(resource.id, resource);
|
|
161
|
+
this.saveResourcesToSQLite(this.store.list).catch(() => {
|
|
162
|
+
});
|
|
163
|
+
this.safeEmit(import_types.ResourceHooks.onResourcesChanged, this.store.list);
|
|
164
|
+
return resource;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* 更新资源
|
|
168
|
+
*/
|
|
169
|
+
updateResource(id, data) {
|
|
170
|
+
const index = this.store.list.findIndex((r) => this.getIdKey(r.id) === this.getIdKey(id));
|
|
171
|
+
if (index === -1)
|
|
172
|
+
return void 0;
|
|
173
|
+
const updated = this.normalizeResource({ ...this.store.list[index], ...data, id });
|
|
174
|
+
this.store.list[index] = updated;
|
|
175
|
+
this.store.map.set(updated.id, updated);
|
|
176
|
+
this.saveResourcesToSQLite(this.store.list).catch(() => {
|
|
177
|
+
});
|
|
178
|
+
this.safeEmit(import_types.ResourceHooks.onResourcesChanged, this.store.list);
|
|
179
|
+
return updated;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* 删除资源
|
|
183
|
+
*/
|
|
184
|
+
deleteResource(id) {
|
|
185
|
+
const key = this.getIdKey(id);
|
|
186
|
+
const index = this.store.list.findIndex((r) => this.getIdKey(r.id) === key);
|
|
187
|
+
if (index === -1)
|
|
188
|
+
return false;
|
|
189
|
+
this.store.list.splice(index, 1);
|
|
190
|
+
this.store.map.delete(id);
|
|
191
|
+
this.saveResourcesToSQLite(this.store.list).catch(() => {
|
|
192
|
+
});
|
|
193
|
+
this.safeEmit(import_types.ResourceHooks.onResourcesChanged, this.store.list);
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
// ─────────────────────────────────────────────────────────────────
|
|
197
|
+
// Booking CRUD
|
|
198
|
+
// ─────────────────────────────────────────────────────────────────
|
|
199
|
+
/**
|
|
200
|
+
* 根据资源 ID 获取预订列表
|
|
201
|
+
*/
|
|
202
|
+
getBookingsByResourceId(resourceId) {
|
|
203
|
+
return this.resourceIdIndex.get(resourceId) || [];
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* 创建预订
|
|
207
|
+
*/
|
|
208
|
+
createBooking(booking) {
|
|
209
|
+
const id = (booking == null ? void 0 : booking.id) ?? Date.now();
|
|
210
|
+
const normalized = {
|
|
211
|
+
id,
|
|
212
|
+
...booking
|
|
213
|
+
};
|
|
214
|
+
this.store.bookings.push(normalized);
|
|
215
|
+
const rid = normalized.resource_id ?? normalized.resourceId;
|
|
216
|
+
if (rid !== void 0) {
|
|
217
|
+
const existing = this.resourceIdIndex.get(rid) || [];
|
|
218
|
+
existing.push(normalized);
|
|
219
|
+
this.resourceIdIndex.set(rid, existing);
|
|
220
|
+
}
|
|
221
|
+
this.saveBookingsToSQLite(this.store.bookings).catch(() => {
|
|
222
|
+
});
|
|
223
|
+
this.safeEmit(import_types.ResourceHooks.onBookingsChanged, this.store.bookings);
|
|
224
|
+
return normalized;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* 更新预订
|
|
228
|
+
*/
|
|
229
|
+
updateBooking(id, data) {
|
|
230
|
+
const index = this.store.bookings.findIndex((b) => this.getIdKey(b.id) === this.getIdKey(id));
|
|
231
|
+
if (index === -1)
|
|
232
|
+
return void 0;
|
|
233
|
+
const old = this.store.bookings[index];
|
|
234
|
+
const updated = { ...old, ...data, id: old.id };
|
|
235
|
+
this.store.bookings[index] = updated;
|
|
236
|
+
this.rebuildBookingsIndex();
|
|
237
|
+
this.saveBookingsToSQLite(this.store.bookings).catch(() => {
|
|
238
|
+
});
|
|
239
|
+
this.safeEmit(import_types.ResourceHooks.onBookingsChanged, this.store.bookings);
|
|
240
|
+
return updated;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* 删除预订
|
|
244
|
+
*/
|
|
245
|
+
deleteBooking(id) {
|
|
246
|
+
const index = this.store.bookings.findIndex((b) => this.getIdKey(b.id) === this.getIdKey(id));
|
|
247
|
+
if (index === -1)
|
|
248
|
+
return false;
|
|
249
|
+
this.store.bookings.splice(index, 1);
|
|
250
|
+
this.rebuildBookingsIndex();
|
|
251
|
+
this.saveBookingsToSQLite(this.store.bookings).catch(() => {
|
|
252
|
+
});
|
|
253
|
+
this.safeEmit(import_types.ResourceHooks.onBookingsChanged, this.store.bookings);
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* 清空缓存
|
|
258
|
+
*/
|
|
259
|
+
async clear() {
|
|
260
|
+
this.store.list = [];
|
|
261
|
+
this.store.map.clear();
|
|
262
|
+
this.store.bookings = [];
|
|
263
|
+
this.resourceIdIndex.clear();
|
|
264
|
+
if (this.dbManager) {
|
|
265
|
+
try {
|
|
266
|
+
await this.dbManager.clear(RESOURCE_STORE_NAME);
|
|
267
|
+
} catch {
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
await this.safeEmit(import_types.ResourceHooks.onResourcesChanged, this.store.list);
|
|
271
|
+
await this.safeEmit(import_types.ResourceHooks.onBookingsChanged, this.store.bookings);
|
|
272
|
+
}
|
|
273
|
+
// ─────────────────────────────────────────────────────────────────
|
|
274
|
+
// 内部工具方法
|
|
275
|
+
// ─────────────────────────────────────────────────────────────────
|
|
276
|
+
attachBookingsToResource(resource) {
|
|
277
|
+
return {
|
|
278
|
+
...resource,
|
|
279
|
+
bookings: this.getBookingsByResourceId(resource.id)
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
normalizeResource(resource) {
|
|
283
|
+
const normalized = {
|
|
284
|
+
...resource,
|
|
285
|
+
id: (resource == null ? void 0 : resource.id) ?? (resource == null ? void 0 : resource.form_record_id) ?? ""
|
|
286
|
+
};
|
|
287
|
+
if (normalized.form_record_id === void 0 && normalized.id !== "") {
|
|
288
|
+
normalized.form_record_id = normalized.id;
|
|
289
|
+
}
|
|
290
|
+
if (normalized.resource_form_id === void 0 || normalized.resource_form_id === null) {
|
|
291
|
+
normalized.resource_form_id = "";
|
|
292
|
+
}
|
|
293
|
+
if (normalized.schedule === void 0 || normalized.schedule === null) {
|
|
294
|
+
normalized.schedule = "";
|
|
295
|
+
}
|
|
296
|
+
if (Array.isArray(normalized.times)) {
|
|
297
|
+
normalized.times = normalized.times.map((timeSlot) => {
|
|
298
|
+
if (!timeSlot || typeof timeSlot !== "object")
|
|
299
|
+
return timeSlot;
|
|
300
|
+
const startAt = timeSlot.start_at ?? timeSlot.start;
|
|
301
|
+
const endAt = timeSlot.end_at ?? timeSlot.end;
|
|
302
|
+
return {
|
|
303
|
+
...timeSlot,
|
|
304
|
+
start_at: startAt,
|
|
305
|
+
end_at: endAt,
|
|
306
|
+
start: timeSlot.start ?? startAt,
|
|
307
|
+
end: timeSlot.end ?? endAt
|
|
308
|
+
};
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
if (Array.isArray(normalized.children)) {
|
|
312
|
+
normalized.children = normalized.children.map((child) => this.normalizeResource(child));
|
|
313
|
+
}
|
|
314
|
+
return normalized;
|
|
315
|
+
}
|
|
316
|
+
async safeEmit(event, payload) {
|
|
317
|
+
try {
|
|
318
|
+
await this.core.effects.emit(event, payload);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
console.error(`[ResourceModule] 事件派发失败: ${event}`, error);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
syncResourcesMap() {
|
|
324
|
+
this.store.map = /* @__PURE__ */ new Map();
|
|
325
|
+
for (const resource of this.store.list) {
|
|
326
|
+
this.store.map.set(resource.id, resource);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
syncBookingsIndex() {
|
|
330
|
+
this.resourceIdIndex.clear();
|
|
331
|
+
for (const booking of this.store.bookings) {
|
|
332
|
+
const rid = booking.resource_id ?? booking.resourceId;
|
|
333
|
+
if (rid === void 0)
|
|
334
|
+
continue;
|
|
335
|
+
const existing = this.resourceIdIndex.get(rid) || [];
|
|
336
|
+
existing.push(booking);
|
|
337
|
+
this.resourceIdIndex.set(rid, existing);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
rebuildBookingsIndex() {
|
|
341
|
+
this.syncBookingsIndex();
|
|
342
|
+
}
|
|
343
|
+
getIdKey(id) {
|
|
344
|
+
return String(id);
|
|
345
|
+
}
|
|
346
|
+
// ─────────────────────────────────────────────────────────────────
|
|
347
|
+
// 数据加载
|
|
348
|
+
// ─────────────────────────────────────────────────────────────────
|
|
349
|
+
async loadResourcesByServer() {
|
|
350
|
+
if (!this.resourceDataSource)
|
|
351
|
+
return [];
|
|
352
|
+
try {
|
|
353
|
+
const response = await this.resourceDataSource.getResourcePage({
|
|
354
|
+
num: DEFAULT_PAGE_SIZE,
|
|
355
|
+
skip: 1
|
|
356
|
+
});
|
|
357
|
+
const resourceList = Array.isArray(response == null ? void 0 : response.list) ? response.list : [];
|
|
358
|
+
const normalizedList = resourceList.map((item) => this.normalizeResource(item));
|
|
359
|
+
await this.saveResourcesToSQLite(normalizedList);
|
|
360
|
+
await this.safeEmit(import_types.ResourceHooks.onResourcesLoaded, normalizedList);
|
|
361
|
+
return normalizedList;
|
|
362
|
+
} catch {
|
|
363
|
+
return [];
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
// ─────────────────────────────────────────────────────────────────
|
|
367
|
+
// SQLite 持久化
|
|
368
|
+
// ─────────────────────────────────────────────────────────────────
|
|
369
|
+
async loadResourcesFromSQLite() {
|
|
370
|
+
if (!this.dbManager)
|
|
371
|
+
return [];
|
|
372
|
+
try {
|
|
373
|
+
const resources = await this.dbManager.getAll(RESOURCE_STORE_NAME);
|
|
374
|
+
return resources || [];
|
|
375
|
+
} catch {
|
|
376
|
+
return [];
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
async saveResourcesToSQLite(resourceList) {
|
|
380
|
+
if (!this.dbManager)
|
|
381
|
+
return;
|
|
382
|
+
try {
|
|
383
|
+
await this.dbManager.clear(RESOURCE_STORE_NAME);
|
|
384
|
+
if (resourceList.length === 0)
|
|
385
|
+
return;
|
|
386
|
+
if (this.dbManager.bulkAdd) {
|
|
387
|
+
await this.dbManager.bulkAdd(RESOURCE_STORE_NAME, resourceList);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
await Promise.all(resourceList.map((r) => this.dbManager.add(RESOURCE_STORE_NAME, r)));
|
|
391
|
+
} catch (error) {
|
|
392
|
+
console.error("saveResourcesToSQLite error", error);
|
|
393
|
+
this.logError("保存资源到 SQLite 失败", {
|
|
394
|
+
error: error instanceof Error ? error.message : String(error),
|
|
395
|
+
resourceList: resourceList.length
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
async loadBookingsFromSQLite() {
|
|
400
|
+
if (!this.dbManager)
|
|
401
|
+
return [];
|
|
402
|
+
try {
|
|
403
|
+
const bookings = await this.dbManager.getAll(BOOKING_STORE_NAME);
|
|
404
|
+
return bookings || [];
|
|
405
|
+
} catch {
|
|
406
|
+
return [];
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
async saveBookingsToSQLite(bookings) {
|
|
410
|
+
if (!this.dbManager)
|
|
411
|
+
return;
|
|
412
|
+
try {
|
|
413
|
+
await this.dbManager.clear(BOOKING_STORE_NAME);
|
|
414
|
+
if (bookings.length === 0)
|
|
415
|
+
return;
|
|
416
|
+
if (this.dbManager.bulkAdd) {
|
|
417
|
+
await this.dbManager.bulkAdd(BOOKING_STORE_NAME, bookings);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
await Promise.all(bookings.map((b) => this.dbManager.add(BOOKING_STORE_NAME, b)));
|
|
421
|
+
} catch {
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
// ─────────────────────────────────────────────────────────────────
|
|
425
|
+
// pubsub 同步
|
|
426
|
+
// ─────────────────────────────────────────────────────────────────
|
|
427
|
+
initResourceDataSource() {
|
|
428
|
+
var _a, _b;
|
|
429
|
+
const ResourceDataSourceClass = (_b = (_a = this.core.serverOptions) == null ? void 0 : _a.All_DATA_SOURCES) == null ? void 0 : _b.ResourceDataSource;
|
|
430
|
+
if (!ResourceDataSourceClass)
|
|
431
|
+
return;
|
|
432
|
+
this.resourceDataSource = new ResourceDataSourceClass();
|
|
433
|
+
}
|
|
434
|
+
async setupResourceSync() {
|
|
435
|
+
var _a, _b, _c;
|
|
436
|
+
if (!this.resourceDataSource)
|
|
437
|
+
return;
|
|
438
|
+
const result = await this.resourceDataSource.run({
|
|
439
|
+
pubsub: {
|
|
440
|
+
callback: (res) => {
|
|
441
|
+
const data = (res == null ? void 0 : res.data) || res;
|
|
442
|
+
if (!data)
|
|
443
|
+
return;
|
|
444
|
+
const channelKey = data.module || "resource";
|
|
445
|
+
this.pendingSyncMessages.push({ ...data, _channelKey: channelKey });
|
|
446
|
+
if (this.syncTimer)
|
|
447
|
+
clearTimeout(this.syncTimer);
|
|
448
|
+
this.syncTimer = setTimeout(() => {
|
|
449
|
+
this.processSyncMessages();
|
|
450
|
+
}, RESOURCE_SYNC_DEBOUNCE_MS);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}).catch(() => {
|
|
454
|
+
});
|
|
455
|
+
console.log("result", result);
|
|
456
|
+
if ((_b = (_a = result == null ? void 0 : result.data) == null ? void 0 : _a.list) == null ? void 0 : _b.length) {
|
|
457
|
+
await this.mergeResourcesToStore((_c = result == null ? void 0 : result.data) == null ? void 0 : _c.list);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
async processSyncMessages() {
|
|
461
|
+
var _a, _b, _c;
|
|
462
|
+
const messages = [...this.pendingSyncMessages];
|
|
463
|
+
this.pendingSyncMessages = [];
|
|
464
|
+
if (messages.length === 0)
|
|
465
|
+
return;
|
|
466
|
+
const deleteIds = [];
|
|
467
|
+
const bodyUpdates = /* @__PURE__ */ new Map();
|
|
468
|
+
const sseRefreshIds = [];
|
|
469
|
+
for (const msg of messages) {
|
|
470
|
+
if (msg.operation === "delete" || msg.action === "delete") {
|
|
471
|
+
if ((_a = msg.ids) == null ? void 0 : _a.length)
|
|
472
|
+
deleteIds.push(...msg.ids);
|
|
473
|
+
else if (msg.id !== void 0)
|
|
474
|
+
deleteIds.push(msg.id);
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
if (msg.body) {
|
|
478
|
+
const bodyId = msg.body.id ?? msg.id;
|
|
479
|
+
if (bodyId === void 0)
|
|
480
|
+
continue;
|
|
481
|
+
bodyUpdates.set(this.getIdKey(bodyId), { ...msg.body, id: bodyId });
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
if ((_b = msg.ids) == null ? void 0 : _b.length) {
|
|
485
|
+
sseRefreshIds.push(...msg.ids);
|
|
486
|
+
} else if (msg.id !== void 0) {
|
|
487
|
+
sseRefreshIds.push(msg.id);
|
|
488
|
+
} else if ((_c = msg.relation_resource_ids) == null ? void 0 : _c.length) {
|
|
489
|
+
sseRefreshIds.push(...msg.relation_resource_ids);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
const uniqueDeleteIds = this.uniqueResourceIds(deleteIds);
|
|
493
|
+
const uniqueSSEIds = this.uniqueResourceIds(sseRefreshIds);
|
|
494
|
+
const bodyList = [...bodyUpdates.values()];
|
|
495
|
+
if (uniqueDeleteIds.length > 0)
|
|
496
|
+
await this.removeResourcesByIds(uniqueDeleteIds);
|
|
497
|
+
if (bodyList.length > 0)
|
|
498
|
+
await this.mergeResourcesToStore(bodyList);
|
|
499
|
+
if (uniqueSSEIds.length > 0) {
|
|
500
|
+
const freshResources = await this.fetchResourcesBySSE(uniqueSSEIds);
|
|
501
|
+
if (freshResources.length > 0)
|
|
502
|
+
await this.mergeResourcesToStore(freshResources);
|
|
503
|
+
}
|
|
504
|
+
if (uniqueDeleteIds.length === 0 && bodyList.length === 0 && uniqueSSEIds.length === 0)
|
|
505
|
+
return;
|
|
506
|
+
await this.core.effects.emit(import_types.ResourceHooks.onResourcesSyncCompleted, null);
|
|
507
|
+
}
|
|
508
|
+
async fetchResourcesBySSE(ids) {
|
|
509
|
+
if (!this.resourceDataSource)
|
|
510
|
+
return [];
|
|
511
|
+
try {
|
|
512
|
+
const list = await this.resourceDataSource.run({
|
|
513
|
+
sse: { query: { type: "resource", ids } }
|
|
514
|
+
});
|
|
515
|
+
return list || [];
|
|
516
|
+
} catch {
|
|
517
|
+
return [];
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
async removeResourcesByIds(ids) {
|
|
521
|
+
const keySet = new Set(ids.map((id) => this.getIdKey(id)));
|
|
522
|
+
this.store.list = this.store.list.filter((r) => !keySet.has(this.getIdKey(r.id)));
|
|
523
|
+
this.syncResourcesMap();
|
|
524
|
+
if (this.dbManager) {
|
|
525
|
+
try {
|
|
526
|
+
for (const id of ids) {
|
|
527
|
+
await this.dbManager.delete(RESOURCE_STORE_NAME, id);
|
|
528
|
+
}
|
|
529
|
+
} catch {
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
await this.safeEmit(import_types.ResourceHooks.onResourcesChanged, this.store.list);
|
|
533
|
+
}
|
|
534
|
+
async mergeResourcesToStore(freshResources) {
|
|
535
|
+
const freshMap = /* @__PURE__ */ new Map();
|
|
536
|
+
for (const r of freshResources) {
|
|
537
|
+
if ((r == null ? void 0 : r.id) === void 0)
|
|
538
|
+
continue;
|
|
539
|
+
freshMap.set(this.getIdKey(r.id), this.normalizeResource(r));
|
|
540
|
+
}
|
|
541
|
+
const updatedList = this.store.list.map((r) => {
|
|
542
|
+
const key = this.getIdKey(r.id);
|
|
543
|
+
if (!freshMap.has(key))
|
|
544
|
+
return r;
|
|
545
|
+
const fresh = freshMap.get(key);
|
|
546
|
+
freshMap.delete(key);
|
|
547
|
+
return fresh;
|
|
548
|
+
});
|
|
549
|
+
for (const r of freshMap.values()) {
|
|
550
|
+
updatedList.push(r);
|
|
551
|
+
}
|
|
552
|
+
this.store.list = updatedList;
|
|
553
|
+
this.syncResourcesMap();
|
|
554
|
+
await this.saveResourcesToSQLite(this.store.list);
|
|
555
|
+
await this.safeEmit(import_types.ResourceHooks.onResourcesChanged, this.store.list);
|
|
556
|
+
}
|
|
557
|
+
uniqueResourceIds(ids) {
|
|
558
|
+
const idMap = /* @__PURE__ */ new Map();
|
|
559
|
+
for (const id of ids) {
|
|
560
|
+
idMap.set(this.getIdKey(id), id);
|
|
561
|
+
}
|
|
562
|
+
return [...idMap.values()];
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
var resourceModule = new ResourceModule();
|
|
566
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
567
|
+
0 && (module.exports = {
|
|
568
|
+
ResourceHooks,
|
|
569
|
+
ResourceModule,
|
|
570
|
+
resourceModule
|
|
571
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource 模块主键类型
|
|
3
|
+
*/
|
|
4
|
+
export type ResourceId = number | string;
|
|
5
|
+
/**
|
|
6
|
+
* Sales / ScheduleEventResource:预约条目内关联资源(仅 ID 与占用,详情由设备端基准数据解析)
|
|
7
|
+
* @see 统一 Sales 数据协议 3.4.1 resources
|
|
8
|
+
*/
|
|
9
|
+
export interface ScheduleEventResource {
|
|
10
|
+
/** 表单 ID。来源:ScheduleEventResource.form_id */
|
|
11
|
+
form_id: number;
|
|
12
|
+
/** 关联类型(如 form)。来源:ScheduleEventResource.relation_type */
|
|
13
|
+
relation_type: string;
|
|
14
|
+
/** 关联资源 ID(设备端用此 ID 从本地基准数据取资源详情)。来源:ScheduleEventResource.relation_id */
|
|
15
|
+
relation_id: number;
|
|
16
|
+
/** 占用容量。来源:ScheduleEventResource.capacity */
|
|
17
|
+
capacity: number;
|
|
18
|
+
/** 特殊状态。来源:ScheduleEventResource.like_status */
|
|
19
|
+
like_status?: string;
|
|
20
|
+
/** 资源元数据。来源:ScheduleEventResource.metadata */
|
|
21
|
+
metadata?: Record<string, unknown> | null;
|
|
22
|
+
/** 子资源(组合资源场景),结构同父级 */
|
|
23
|
+
children?: ScheduleEventResource[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 资源预订数据结构
|
|
27
|
+
*/
|
|
28
|
+
export interface ResourceBooking {
|
|
29
|
+
id: ResourceId;
|
|
30
|
+
resource_id?: ResourceId;
|
|
31
|
+
resourceId?: ResourceId;
|
|
32
|
+
user_id?: string | number;
|
|
33
|
+
userId?: string | number;
|
|
34
|
+
start_time?: string | number;
|
|
35
|
+
end_time?: string | number;
|
|
36
|
+
startTime?: string | number;
|
|
37
|
+
endTime?: string | number;
|
|
38
|
+
status?: string;
|
|
39
|
+
notes?: string;
|
|
40
|
+
metadata?: Record<string, any> | null;
|
|
41
|
+
[key: string]: any;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 资源数据结构(兼容历史数据)
|
|
45
|
+
*/
|
|
46
|
+
export interface ResourceData {
|
|
47
|
+
id: ResourceId;
|
|
48
|
+
form_record_id?: ResourceId;
|
|
49
|
+
main_field?: string;
|
|
50
|
+
form_id?: number | string;
|
|
51
|
+
capacity?: number;
|
|
52
|
+
like_status?: 'common' | 'like';
|
|
53
|
+
type?: string;
|
|
54
|
+
resourceType?: string;
|
|
55
|
+
resource_form_id?: number | string | '';
|
|
56
|
+
schedule?: any[] | '';
|
|
57
|
+
times?: any;
|
|
58
|
+
metadata?: Record<string, any> | null;
|
|
59
|
+
children?: ResourceData[];
|
|
60
|
+
bookings?: ResourceBooking[];
|
|
61
|
+
[key: string]: any;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 查询选项
|
|
65
|
+
*/
|
|
66
|
+
export interface QueryOptions {
|
|
67
|
+
includeBookings?: boolean;
|
|
68
|
+
[key: string]: any;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resource 模块状态
|
|
72
|
+
*/
|
|
73
|
+
export interface ResourceState {
|
|
74
|
+
/** 资源列表 */
|
|
75
|
+
list: ResourceData[];
|
|
76
|
+
/** 资源 Map 缓存(以 id 为 key,加速查询) */
|
|
77
|
+
map: Map<ResourceId, ResourceData>;
|
|
78
|
+
/** 预订列表 */
|
|
79
|
+
bookings: ResourceBooking[];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 与 ResourceDataSource 对齐的分页查询参数
|
|
83
|
+
*/
|
|
84
|
+
export interface ResourcePageQuery {
|
|
85
|
+
'ids[]'?: ResourceId[] | ResourceId;
|
|
86
|
+
ids?: ResourceId[];
|
|
87
|
+
num?: number | string;
|
|
88
|
+
skip?: number | string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 与 ResourceDataSource 对齐的分页返回结构
|
|
92
|
+
*/
|
|
93
|
+
export interface ResourcePageResult {
|
|
94
|
+
list: ResourceData[];
|
|
95
|
+
count: number;
|
|
96
|
+
skip: number;
|
|
97
|
+
size: number;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* ResourceSyncMessage - pubsub 同步消息结构
|
|
101
|
+
*/
|
|
102
|
+
export interface ResourceSyncMessage {
|
|
103
|
+
module?: string;
|
|
104
|
+
action?: string;
|
|
105
|
+
operation?: string;
|
|
106
|
+
id?: ResourceId;
|
|
107
|
+
ids?: ResourceId[];
|
|
108
|
+
body?: Partial<ResourceData>;
|
|
109
|
+
change_types?: string[];
|
|
110
|
+
relation_resource_ids?: ResourceId[];
|
|
111
|
+
_channelKey?: string;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Resource 模块钩子
|
|
115
|
+
*/
|
|
116
|
+
export declare enum ResourceHooks {
|
|
117
|
+
onResourcesLoaded = "resource:onResourcesLoaded",
|
|
118
|
+
onResourcesChanged = "resource:onResourcesChanged",
|
|
119
|
+
onResourcesSyncCompleted = "resource:onResourcesSyncCompleted",
|
|
120
|
+
onBookingsChanged = "resource:onBookingsChanged"
|
|
121
|
+
}
|