@pisell/pisellos 2.2.124 → 2.2.126
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.js +1 -0
- package/dist/modules/Quotation/index.d.ts +48 -0
- package/dist/modules/Quotation/index.js +248 -0
- package/dist/modules/Quotation/types.d.ts +42 -0
- package/dist/modules/Quotation/types.js +1 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.js +551 -362
- package/dist/server/modules/order/index.d.ts +7 -0
- package/dist/server/modules/order/index.js +221 -151
- package/dist/solution/Sales/index.d.ts +33 -4
- package/dist/solution/Sales/index.js +94 -38
- package/lib/core/index.js +1 -0
- package/lib/modules/Quotation/index.d.ts +48 -0
- package/lib/modules/Quotation/index.js +152 -0
- package/lib/modules/Quotation/types.d.ts +42 -0
- package/lib/modules/Quotation/types.js +17 -0
- package/lib/server/index.d.ts +11 -0
- package/lib/server/index.js +116 -0
- package/lib/server/modules/order/index.d.ts +7 -0
- package/lib/server/modules/order/index.js +34 -0
- package/lib/solution/Sales/index.d.ts +33 -4
- package/lib/solution/Sales/index.js +98 -48
- package/package.json +1 -1
|
@@ -218,6 +218,40 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
218
218
|
const ids = this.resourceIdIndex.get(String(resourceId)) || [];
|
|
219
219
|
return ids.map((id) => this.store.map.get(id)).filter((order) => !!order);
|
|
220
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
|
|
223
|
+
* 适用于"按 order_id 主动刷新本地订单详情"的代理场景。
|
|
224
|
+
*/
|
|
225
|
+
async overwriteExistingOrder(fresh) {
|
|
226
|
+
const orderId = fresh == null ? void 0 : fresh.order_id;
|
|
227
|
+
if (orderId === void 0 || orderId === null) {
|
|
228
|
+
this.logError("overwriteExistingOrder-入参缺少 order_id");
|
|
229
|
+
return { overwritten: false };
|
|
230
|
+
}
|
|
231
|
+
const key = this.getIdKey(orderId);
|
|
232
|
+
if (!this.store.map.has(key)) {
|
|
233
|
+
this.logInfo("overwriteExistingOrder-本地不存在该订单,跳过", { orderId });
|
|
234
|
+
return { overwritten: false };
|
|
235
|
+
}
|
|
236
|
+
this.logInfo("overwriteExistingOrder-开始覆盖", {
|
|
237
|
+
orderId,
|
|
238
|
+
storeOrderCountBefore: this.store.list.length
|
|
239
|
+
});
|
|
240
|
+
this.store.list = this.store.list.map((order) => {
|
|
241
|
+
const id = order == null ? void 0 : order.order_id;
|
|
242
|
+
if (id === void 0 || id === null)
|
|
243
|
+
return order;
|
|
244
|
+
return this.getIdKey(id) === key ? fresh : order;
|
|
245
|
+
});
|
|
246
|
+
this.syncOrdersMap();
|
|
247
|
+
await this.saveOrdersToSQLite(this.store.list);
|
|
248
|
+
this.logInfo("overwriteExistingOrder-结束", {
|
|
249
|
+
orderId,
|
|
250
|
+
storeOrderCountAfter: this.store.list.length
|
|
251
|
+
});
|
|
252
|
+
await this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, this.store.list);
|
|
253
|
+
return { overwritten: true };
|
|
254
|
+
}
|
|
221
255
|
/**
|
|
222
256
|
* 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
|
|
223
257
|
*/
|
|
@@ -86,12 +86,41 @@ export declare class SalesImpl extends BaseModule implements Module, SalesModule
|
|
|
86
86
|
*/
|
|
87
87
|
private pickBookingsForCurrentPoint;
|
|
88
88
|
/**
|
|
89
|
-
*
|
|
90
|
-
* -
|
|
91
|
-
* -
|
|
92
|
-
|
|
89
|
+
* 计算 booking 在 current 时刻的执行进度百分比(0-100)。
|
|
90
|
+
* - startAt/endAt 非法或 totalMinutes <= 0 返回 0
|
|
91
|
+
* - current 早于 startAt 返回 0,晚于 endAt 返回 100
|
|
92
|
+
*/
|
|
93
|
+
private calcProgressPercent;
|
|
94
|
+
/**
|
|
95
|
+
* 标准化单条 booking 的分发入口:
|
|
96
|
+
* - 统一过滤 rejected / cancelled(视为没来过)
|
|
97
|
+
* - current === deviceCurrent 走实时分支(信任 appointment_status)
|
|
98
|
+
* - 否则走快照分支(纯时间窗判定,忽略 appointment_status 的 arrived/started/completed 差异)
|
|
93
99
|
*/
|
|
94
100
|
private normalizeMatchedBooking;
|
|
101
|
+
/**
|
|
102
|
+
* 实时模式(current === deviceCurrent):信任 appointment_status
|
|
103
|
+
* - 过滤 new / completed(实时视角下视为非活跃数据)
|
|
104
|
+
* - status 由 getBookingStatus 映射
|
|
105
|
+
* - occupied 且 current > endAt 标记 isTimeout + timeoutTime
|
|
106
|
+
* - reserved 且 current < startAt 标记 not_arrived,否则标记 late
|
|
107
|
+
*/
|
|
108
|
+
private buildRealtimeBooking;
|
|
109
|
+
/**
|
|
110
|
+
* 快照模式(current !== deviceCurrent,过去或未来):忽略 appointment_status
|
|
111
|
+
* 的实时态差异,仅按 booking 时间窗判定,为 current 提供时间点快照视图。
|
|
112
|
+
*
|
|
113
|
+
* - new:视作尚未成为真实预约,过滤
|
|
114
|
+
* - locked:保留 status=locked,不计算 timeout/late/progress
|
|
115
|
+
* - 其他非终态:
|
|
116
|
+
* - startAt/endAt 非法 → 过滤
|
|
117
|
+
* - current > endAt → 过滤(已结束,不入池)
|
|
118
|
+
* - current ∈ [startAt, endAt] → occupied,附带 progressPercent
|
|
119
|
+
* - current < startAt → reserved + not_arrived,附带 remainingReserveTime
|
|
120
|
+
*
|
|
121
|
+
* 快照模式下 isTimeout 恒为 false,lateTime / timeoutTime 始终置空。
|
|
122
|
+
*/
|
|
123
|
+
private buildSnapshotBooking;
|
|
95
124
|
getResourceBookingList(currentTime: string, bookingList?: BookingData[], deviceTime?: string): Promise<SalesResourceBookingItem[]>;
|
|
96
125
|
}
|
|
97
126
|
export { SalesImpl as Sales };
|
|
@@ -315,39 +315,54 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
315
315
|
return fallback ? [fallback] : [];
|
|
316
316
|
}
|
|
317
317
|
/**
|
|
318
|
-
*
|
|
319
|
-
* -
|
|
320
|
-
* -
|
|
321
|
-
|
|
318
|
+
* 计算 booking 在 current 时刻的执行进度百分比(0-100)。
|
|
319
|
+
* - startAt/endAt 非法或 totalMinutes <= 0 返回 0
|
|
320
|
+
* - current 早于 startAt 返回 0,晚于 endAt 返回 100
|
|
321
|
+
*/
|
|
322
|
+
calcProgressPercent(current, startAt, endAt) {
|
|
323
|
+
if (!startAt.isValid() || !endAt.isValid())
|
|
324
|
+
return 0;
|
|
325
|
+
const totalMinutes = endAt.diff(startAt, "minute");
|
|
326
|
+
if (totalMinutes <= 0)
|
|
327
|
+
return 0;
|
|
328
|
+
const elapsedMinutes = current.diff(startAt, "minute");
|
|
329
|
+
if (elapsedMinutes <= 0)
|
|
330
|
+
return 0;
|
|
331
|
+
if (elapsedMinutes >= totalMinutes)
|
|
332
|
+
return 100;
|
|
333
|
+
return Math.floor(elapsedMinutes / totalMinutes * 100);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* 标准化单条 booking 的分发入口:
|
|
337
|
+
* - 统一过滤 rejected / cancelled(视为没来过)
|
|
338
|
+
* - current === deviceCurrent 走实时分支(信任 appointment_status)
|
|
339
|
+
* - 否则走快照分支(纯时间窗判定,忽略 appointment_status 的 arrived/started/completed 差异)
|
|
322
340
|
*/
|
|
323
341
|
normalizeMatchedBooking(current, deviceCurrent, booking) {
|
|
324
342
|
const appointmentStatus = String(booking.appointment_status ?? booking.status ?? "");
|
|
325
|
-
if (appointmentStatus === "
|
|
343
|
+
if (appointmentStatus === "rejected" || appointmentStatus === "cancelled")
|
|
326
344
|
return null;
|
|
327
|
-
|
|
345
|
+
const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
|
|
328
346
|
const endAt = this.toBookingDateTime(booking.end_date, booking.end_time);
|
|
329
|
-
|
|
330
|
-
|
|
347
|
+
if (current.isSame(deviceCurrent)) {
|
|
348
|
+
return this.buildRealtimeBooking(current, booking, appointmentStatus, startAt, endAt);
|
|
349
|
+
}
|
|
350
|
+
return this.buildSnapshotBooking(current, booking, appointmentStatus, startAt, endAt);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* 实时模式(current === deviceCurrent):信任 appointment_status
|
|
354
|
+
* - 过滤 new / completed(实时视角下视为非活跃数据)
|
|
355
|
+
* - status 由 getBookingStatus 映射
|
|
356
|
+
* - occupied 且 current > endAt 标记 isTimeout + timeoutTime
|
|
357
|
+
* - reserved 且 current < startAt 标记 not_arrived,否则标记 late
|
|
358
|
+
*/
|
|
359
|
+
buildRealtimeBooking(current, booking, appointmentStatus, startAt, endAt) {
|
|
360
|
+
if (appointmentStatus === "new" || appointmentStatus === "completed")
|
|
331
361
|
return null;
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
let progressPercent = (() => {
|
|
337
|
-
if (bookingStatus !== "occupied")
|
|
338
|
-
return 0;
|
|
339
|
-
if (!startAt.isValid() || !endAt.isValid())
|
|
340
|
-
return 0;
|
|
341
|
-
const totalMinutes = endAt.diff(startAt, "minute");
|
|
342
|
-
if (totalMinutes <= 0)
|
|
343
|
-
return 0;
|
|
344
|
-
const elapsedMinutes = current.diff(startAt, "minute");
|
|
345
|
-
if (elapsedMinutes <= 0)
|
|
346
|
-
return 0;
|
|
347
|
-
if (elapsedMinutes >= totalMinutes)
|
|
348
|
-
return 100;
|
|
349
|
-
return Math.floor(elapsedMinutes / totalMinutes * 100);
|
|
350
|
-
})();
|
|
362
|
+
const bookingStatus = this.getBookingStatus(appointmentStatus);
|
|
363
|
+
const isTimeout = bookingStatus === "occupied" && endAt.isValid() && current.isAfter(endAt);
|
|
364
|
+
const timeoutTime = isTimeout ? current.diff(endAt, "minute") : void 0;
|
|
365
|
+
const progressPercent = bookingStatus === "occupied" ? this.calcProgressPercent(current, startAt, endAt) : 0;
|
|
351
366
|
let reservedStatus;
|
|
352
367
|
let lateTime;
|
|
353
368
|
let remainingReserveTime;
|
|
@@ -360,27 +375,6 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
360
375
|
lateTime = Math.max(current.diff(startAt, "minute"), 0);
|
|
361
376
|
}
|
|
362
377
|
}
|
|
363
|
-
if (current.isAfter(deviceCurrent) && bookingStatus === "reserved" && reservedStatus === "late" && endAt.isValid() && endAt.isSameOrAfter(current)) {
|
|
364
|
-
bookingStatus = "occupied";
|
|
365
|
-
reservedStatus = void 0;
|
|
366
|
-
lateTime = void 0;
|
|
367
|
-
remainingReserveTime = void 0;
|
|
368
|
-
isTimeout = false;
|
|
369
|
-
timeoutTime = void 0;
|
|
370
|
-
progressPercent = (() => {
|
|
371
|
-
if (!startAt.isValid() || !endAt.isValid())
|
|
372
|
-
return 0;
|
|
373
|
-
const totalMinutes = endAt.diff(startAt, "minute");
|
|
374
|
-
if (totalMinutes <= 0)
|
|
375
|
-
return 0;
|
|
376
|
-
const elapsedMinutes = current.diff(startAt, "minute");
|
|
377
|
-
if (elapsedMinutes <= 0)
|
|
378
|
-
return 0;
|
|
379
|
-
if (elapsedMinutes >= totalMinutes)
|
|
380
|
-
return 100;
|
|
381
|
-
return Math.floor(elapsedMinutes / totalMinutes * 100);
|
|
382
|
-
})();
|
|
383
|
-
}
|
|
384
378
|
return {
|
|
385
379
|
...booking,
|
|
386
380
|
status: bookingStatus,
|
|
@@ -392,6 +386,62 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
392
386
|
remainingReserveTime
|
|
393
387
|
};
|
|
394
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* 快照模式(current !== deviceCurrent,过去或未来):忽略 appointment_status
|
|
391
|
+
* 的实时态差异,仅按 booking 时间窗判定,为 current 提供时间点快照视图。
|
|
392
|
+
*
|
|
393
|
+
* - new:视作尚未成为真实预约,过滤
|
|
394
|
+
* - locked:保留 status=locked,不计算 timeout/late/progress
|
|
395
|
+
* - 其他非终态:
|
|
396
|
+
* - startAt/endAt 非法 → 过滤
|
|
397
|
+
* - current > endAt → 过滤(已结束,不入池)
|
|
398
|
+
* - current ∈ [startAt, endAt] → occupied,附带 progressPercent
|
|
399
|
+
* - current < startAt → reserved + not_arrived,附带 remainingReserveTime
|
|
400
|
+
*
|
|
401
|
+
* 快照模式下 isTimeout 恒为 false,lateTime / timeoutTime 始终置空。
|
|
402
|
+
*/
|
|
403
|
+
buildSnapshotBooking(current, booking, appointmentStatus, startAt, endAt) {
|
|
404
|
+
if (appointmentStatus === "new")
|
|
405
|
+
return null;
|
|
406
|
+
if (appointmentStatus === "locked") {
|
|
407
|
+
return {
|
|
408
|
+
...booking,
|
|
409
|
+
status: "locked",
|
|
410
|
+
isTimeout: false,
|
|
411
|
+
timeoutTime: void 0,
|
|
412
|
+
progressPercent: 0,
|
|
413
|
+
lateTime: void 0,
|
|
414
|
+
reserved_status: void 0,
|
|
415
|
+
remainingReserveTime: void 0
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
if (!startAt.isValid() || !endAt.isValid())
|
|
419
|
+
return null;
|
|
420
|
+
if (current.isAfter(endAt))
|
|
421
|
+
return null;
|
|
422
|
+
if (this.isSameOrAfter(current, startAt) && this.isSameOrBefore(current, endAt)) {
|
|
423
|
+
return {
|
|
424
|
+
...booking,
|
|
425
|
+
status: "occupied",
|
|
426
|
+
isTimeout: false,
|
|
427
|
+
timeoutTime: void 0,
|
|
428
|
+
progressPercent: this.calcProgressPercent(current, startAt, endAt),
|
|
429
|
+
lateTime: void 0,
|
|
430
|
+
reserved_status: void 0,
|
|
431
|
+
remainingReserveTime: void 0
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
return {
|
|
435
|
+
...booking,
|
|
436
|
+
status: "reserved",
|
|
437
|
+
isTimeout: false,
|
|
438
|
+
timeoutTime: void 0,
|
|
439
|
+
progressPercent: 0,
|
|
440
|
+
lateTime: void 0,
|
|
441
|
+
reserved_status: "not_arrived",
|
|
442
|
+
remainingReserveTime: Math.max(startAt.diff(current, "minute"), 0)
|
|
443
|
+
};
|
|
444
|
+
}
|
|
395
445
|
async getResourceBookingList(currentTime, bookingList = [], deviceTime = currentTime) {
|
|
396
446
|
var _a;
|
|
397
447
|
const current = (0, import_dayjs.default)(currentTime);
|