@pisell/pisellos 2.3.74 → 2.3.76

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.
Files changed (283) hide show
  1. package/dist/core/index.js +6 -10
  2. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  3. package/dist/model/strategy/adapter/walletPass/example.js +3 -26
  4. package/dist/model/strategy/strategy-example.js +5 -19
  5. package/dist/modules/Cart/index.js +0 -3
  6. package/dist/modules/Cart/utils/cartProduct.js +0 -1
  7. package/dist/modules/Date/index.js +1 -5
  8. package/dist/modules/Discount/index.js +2 -4
  9. package/dist/modules/OpenData/index.js +0 -2
  10. package/dist/modules/Order/index.d.ts +1 -1
  11. package/dist/modules/Order/index.js +75 -91
  12. package/dist/modules/Order/types.d.ts +3 -1
  13. package/dist/modules/Payment/index.js +97 -162
  14. package/dist/modules/Rules/index.js +1 -4
  15. package/dist/modules/Schedule/index.js +0 -1
  16. package/dist/modules/Schedule/utils.js +0 -1
  17. package/dist/modules/Step/index.js +0 -1
  18. package/dist/plugins/request.js +1 -4
  19. package/dist/plugins/window.js +2 -6
  20. package/dist/server/index.js +97 -129
  21. package/dist/server/modules/menu/index.js +32 -41
  22. package/dist/server/modules/order/index.js +2 -4
  23. package/dist/server/modules/products/index.js +24 -42
  24. package/dist/server/modules/quotation/index.js +29 -38
  25. package/dist/server/modules/resource/index.js +3 -4
  26. package/dist/server/modules/schedule/index.js +27 -35
  27. package/dist/server/utils/product.js +0 -1
  28. package/dist/solution/BaseSales/index.js +100 -72
  29. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +5 -0
  30. package/dist/solution/BaseSales/utils/cartPromotion.js +15 -6
  31. package/dist/solution/BookingByStep/index.js +7 -59
  32. package/dist/solution/BookingByStep/utils/capacity.js +1 -11
  33. package/dist/solution/BookingByStep/utils/resources.js +1 -3
  34. package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
  35. package/dist/solution/BookingTicket/index.js +0 -2
  36. package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +6 -7
  37. package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
  38. package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
  39. package/dist/solution/BuyTickets/index.js +9 -12
  40. package/dist/solution/Checkout/index.js +177 -252
  41. package/dist/solution/Checkout/utils/index.js +4 -16
  42. package/dist/solution/RegisterAndLogin/index.js +30 -76
  43. package/dist/solution/ScanOrder/index.js +50 -60
  44. package/dist/solution/ShopDiscount/index.js +2 -7
  45. package/dist/solution/VenueBooking/index.js +45 -55
  46. package/dist/utils/task.js +15 -18
  47. package/dist/utils/watch.js +0 -1
  48. package/lib/apis/picoding.js +2 -0
  49. package/lib/core/index.js +134 -134
  50. package/lib/effects/index.js +46 -57
  51. package/lib/index.js +82 -49
  52. package/lib/model/index.js +14 -21
  53. package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
  54. package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
  55. package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
  56. package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
  57. package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
  58. package/lib/model/strategy/adapter/index.js +100 -64
  59. package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
  60. package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
  61. package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
  62. package/lib/model/strategy/adapter/itemRule/index.js +83 -57
  63. package/lib/model/strategy/adapter/itemRule/type.js +97 -36
  64. package/lib/model/strategy/adapter/promotion/adapter.js +91 -69
  65. package/lib/model/strategy/adapter/promotion/evaluator.js +444 -310
  66. package/lib/model/strategy/adapter/promotion/examples.js +222 -234
  67. package/lib/model/strategy/adapter/promotion/index.js +1 -0
  68. package/lib/model/strategy/adapter/promotion/type.js +243 -36
  69. package/lib/model/strategy/adapter/type.js +4 -16
  70. package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -150
  71. package/lib/model/strategy/adapter/walletPass/example.js +217 -190
  72. package/lib/model/strategy/adapter/walletPass/index.js +75 -51
  73. package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
  74. package/lib/model/strategy/adapter/walletPass/type.js +4 -16
  75. package/lib/model/strategy/adapter/walletPass/utils.js +588 -378
  76. package/lib/model/strategy/engine.js +270 -168
  77. package/lib/model/strategy/index.js +49 -34
  78. package/lib/model/strategy/strategy-example.js +243 -239
  79. package/lib/model/strategy/type.js +100 -40
  80. package/lib/modules/Account/index.js +39 -53
  81. package/lib/modules/Account/types.js +20 -33
  82. package/lib/modules/AccountList/index.js +116 -154
  83. package/lib/modules/AccountList/types.js +30 -31
  84. package/lib/modules/AccountList/utils.js +18 -30
  85. package/lib/modules/BaseModule.js +23 -42
  86. package/lib/modules/BookingContext/index.js +158 -136
  87. package/lib/modules/BookingContext/types.js +46 -32
  88. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +138 -146
  89. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +78 -83
  90. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +170 -150
  91. package/lib/modules/BookingContext/utils/flexible.js +38 -55
  92. package/lib/modules/BookingContext/utils/formatResourceList.js +19 -34
  93. package/lib/modules/BookingContext/utils/index.js +124 -41
  94. package/lib/modules/BookingContext/utils/noResource.js +58 -70
  95. package/lib/modules/BookingContext/utils/orderLineDisplay.js +14 -41
  96. package/lib/modules/BookingContext/utils/productExtend.js +202 -155
  97. package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
  98. package/lib/modules/BookingContext/utils/resourceSelection.js +19 -41
  99. package/lib/modules/BookingContext/utils/resources.js +209 -167
  100. package/lib/modules/BookingContext/utils/serviceTimes.js +115 -116
  101. package/lib/modules/BookingContext/utils/timeSlices.js +76 -86
  102. package/lib/modules/Cart/index.js +170 -124
  103. package/lib/modules/Cart/types.js +46 -51
  104. package/lib/modules/Cart/utils/cartAccount.js +40 -39
  105. package/lib/modules/Cart/utils/cartDate.js +56 -61
  106. package/lib/modules/Cart/utils/cartDiscount.js +28 -33
  107. package/lib/modules/Cart/utils/cartNote.js +27 -32
  108. package/lib/modules/Cart/utils/cartProduct.js +321 -251
  109. package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
  110. package/lib/modules/Cart/utils/cartResource.js +70 -78
  111. package/lib/modules/Cart/utils/changePrice.js +22 -50
  112. package/lib/modules/Cart/utils/index.js +106 -48
  113. package/lib/modules/Customer/constants.js +13 -34
  114. package/lib/modules/Customer/index.js +235 -172
  115. package/lib/modules/Customer/types.js +38 -35
  116. package/lib/modules/Date/index.js +116 -115
  117. package/lib/modules/Date/types.js +16 -28
  118. package/lib/modules/Date/utils.js +174 -123
  119. package/lib/modules/Discount/index.js +122 -127
  120. package/lib/modules/Discount/types.js +9 -31
  121. package/lib/modules/Guests/index.js +30 -56
  122. package/lib/modules/Guests/types.js +23 -33
  123. package/lib/modules/Holder/index.js +209 -189
  124. package/lib/modules/Holder/types.js +4 -16
  125. package/lib/modules/Holder/utils.js +20 -49
  126. package/lib/modules/OpenData/index.js +70 -76
  127. package/lib/modules/OpenData/types.js +4 -16
  128. package/lib/modules/OpenData/utils.js +44 -78
  129. package/lib/modules/Order/index.d.ts +1 -1
  130. package/lib/modules/Order/index.js +1733 -2121
  131. package/lib/modules/Order/payment-utils.js +77 -120
  132. package/lib/modules/Order/types.d.ts +3 -1
  133. package/lib/modules/Order/types.js +88 -35
  134. package/lib/modules/Order/utils/bundleDiscountHydration.js +41 -74
  135. package/lib/modules/Order/utils/discountProductLineIdentity.js +142 -100
  136. package/lib/modules/Order/utils/manualProductDiscount.js +124 -123
  137. package/lib/modules/Order/utils/orderCollectionIdentity.js +184 -244
  138. package/lib/modules/Order/utils.js +814 -647
  139. package/lib/modules/Payment/cash.js +20 -33
  140. package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
  141. package/lib/modules/Payment/eftpos.js +16 -30
  142. package/lib/modules/Payment/index.js +532 -399
  143. package/lib/modules/Payment/mx51.js +1 -0
  144. package/lib/modules/Payment/types.js +230 -108
  145. package/lib/modules/Payment/utils.js +52 -51
  146. package/lib/modules/Payment/walletpass.js +485 -660
  147. package/lib/modules/Product/index.js +51 -46
  148. package/lib/modules/Product/types.js +4 -16
  149. package/lib/modules/Product/utils.js +32 -33
  150. package/lib/modules/ProductList/index.js +113 -123
  151. package/lib/modules/ProductList/types.js +9 -31
  152. package/lib/modules/Quotation/index.js +81 -118
  153. package/lib/modules/Quotation/types.js +4 -16
  154. package/lib/modules/Resource/index.js +27 -59
  155. package/lib/modules/Resource/types.js +22 -32
  156. package/lib/modules/Resource/utils.js +30 -38
  157. package/lib/modules/ResourcePlanner/index.js +25 -23
  158. package/lib/modules/ResourcePlanner/localClock.js +54 -119
  159. package/lib/modules/ResourcePlanner/planner.js +589 -770
  160. package/lib/modules/ResourcePlanner/types.js +10 -29
  161. package/lib/modules/Rules/index.js +1218 -959
  162. package/lib/modules/Rules/types.js +17 -40
  163. package/lib/modules/SalesSummary/index.js +85 -90
  164. package/lib/modules/SalesSummary/types.js +4 -16
  165. package/lib/modules/SalesSummary/utils.js +355 -430
  166. package/lib/modules/ScanOrderLogger/index.js +59 -79
  167. package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
  168. package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
  169. package/lib/modules/ScanOrderLogger/types.js +4 -16
  170. package/lib/modules/Schedule/getDateIsInSchedule.js +334 -163
  171. package/lib/modules/Schedule/index.js +100 -114
  172. package/lib/modules/Schedule/type.js +4 -16
  173. package/lib/modules/Schedule/types.js +4 -16
  174. package/lib/modules/Schedule/utils.js +433 -291
  175. package/lib/modules/Step/index.js +40 -52
  176. package/lib/modules/Step/tyeps.js +4 -16
  177. package/lib/modules/Summary/index.js +66 -71
  178. package/lib/modules/Summary/types.js +4 -16
  179. package/lib/modules/Summary/utils.js +773 -418
  180. package/lib/modules/SurchargeList/index.js +46 -60
  181. package/lib/modules/SurchargeList/types.js +4 -16
  182. package/lib/modules/index.js +245 -63
  183. package/lib/plugins/app.js +4 -16
  184. package/lib/plugins/index.js +36 -25
  185. package/lib/plugins/request.js +137 -126
  186. package/lib/plugins/shopStore.js +4 -16
  187. package/lib/plugins/user.js +4 -16
  188. package/lib/plugins/window.js +171 -179
  189. package/lib/server/index.js +3050 -2665
  190. package/lib/server/modules/floor-plan/index.js +118 -134
  191. package/lib/server/modules/floor-plan/types.js +15 -30
  192. package/lib/server/modules/index.js +106 -68
  193. package/lib/server/modules/menu/index.js +142 -122
  194. package/lib/server/modules/menu/types.js +18 -31
  195. package/lib/server/modules/order/index.js +784 -1002
  196. package/lib/server/modules/order/types.js +122 -33
  197. package/lib/server/modules/order/utils/filterBookings.js +219 -194
  198. package/lib/server/modules/order/utils/filterOrders.js +118 -92
  199. package/lib/server/modules/payment/index.js +59 -83
  200. package/lib/server/modules/payment/types.js +4 -16
  201. package/lib/server/modules/products/index.js +583 -471
  202. package/lib/server/modules/products/types.js +44 -34
  203. package/lib/server/modules/quotation/index.js +137 -172
  204. package/lib/server/modules/quotation/types.js +21 -31
  205. package/lib/server/modules/resource/index.js +220 -186
  206. package/lib/server/modules/resource/types.js +42 -33
  207. package/lib/server/modules/schedule/index.js +135 -123
  208. package/lib/server/modules/schedule/types.js +14 -21
  209. package/lib/server/modules/schedule/utils.js +334 -163
  210. package/lib/server/types.js +4 -16
  211. package/lib/server/utils/index.js +25 -23
  212. package/lib/server/utils/product.js +196 -139
  213. package/lib/server/utils/schedule.js +34 -41
  214. package/lib/server/utils/small-ticket.js +479 -456
  215. package/lib/server/utils/time.js +40 -49
  216. package/lib/solution/BaseSales/index.js +1220 -1412
  217. package/lib/solution/BaseSales/types.js +42 -38
  218. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +5 -0
  219. package/lib/solution/BaseSales/utils/cartPromotion.js +652 -498
  220. package/lib/solution/BaseSales/utils/parseSalesResponse.js +85 -105
  221. package/lib/solution/BaseSales/utils/quotationPrice.js +56 -114
  222. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +108 -145
  223. package/lib/solution/BaseSales/utils.js +158 -143
  224. package/lib/solution/BookingByStep/index.js +1527 -1340
  225. package/lib/solution/BookingByStep/types.js +40 -99
  226. package/lib/solution/BookingByStep/utils/capacity.js +192 -160
  227. package/lib/solution/BookingByStep/utils/products.js +42 -52
  228. package/lib/solution/BookingByStep/utils/resources.js +527 -330
  229. package/lib/solution/BookingByStep/utils/stock.js +65 -44
  230. package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
  231. package/lib/solution/BookingTicket/index.js +607 -522
  232. package/lib/solution/BookingTicket/types.js +99 -77
  233. package/lib/solution/BookingTicket/utils/addProductDecision.js +226 -189
  234. package/lib/solution/BookingTicket/utils/addTimeAvailability.js +58 -89
  235. package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -78
  236. package/lib/solution/BookingTicket/utils/cartView.js +114 -99
  237. package/lib/solution/BookingTicket/utils/exampleData.js +185 -0
  238. package/lib/solution/BookingTicket/utils/orderCustomer.js +18 -41
  239. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +219 -86
  240. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +168 -116
  241. package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +79 -91
  242. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +54 -41
  243. package/lib/solution/BookingTicket/utils/scan/handleScan.js +84 -81
  244. package/lib/solution/BookingTicket/utils/scan/index.js +98 -104
  245. package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
  246. package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +52 -64
  247. package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +56 -58
  248. package/lib/solution/BookingTicket/utils/weighingProductSku.js +34 -48
  249. package/lib/solution/BuyTickets/index.js +67 -70
  250. package/lib/solution/BuyTickets/types.js +22 -38
  251. package/lib/solution/Checkout/index.js +1451 -1158
  252. package/lib/solution/Checkout/types.js +91 -61
  253. package/lib/solution/Checkout/utils/index.js +228 -156
  254. package/lib/solution/PlaceOrder/index.js +55 -0
  255. package/lib/solution/RegisterAndLogin/config.js +493 -460
  256. package/lib/solution/RegisterAndLogin/index.js +633 -630
  257. package/lib/solution/RegisterAndLogin/types.js +189 -76
  258. package/lib/solution/RegisterAndLogin/utils.js +183 -125
  259. package/lib/solution/Sales/index.js +328 -324
  260. package/lib/solution/Sales/types.js +27 -33
  261. package/lib/solution/ScanOrder/index.js +832 -864
  262. package/lib/solution/ScanOrder/types.js +33 -34
  263. package/lib/solution/ScanOrder/utils.js +409 -374
  264. package/lib/solution/ShopDiscount/index.js +226 -232
  265. package/lib/solution/ShopDiscount/types.js +15 -37
  266. package/lib/solution/ShopDiscount/utils.js +300 -172
  267. package/lib/solution/UnifiedBookingSales/index.js +1035 -1201
  268. package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.js +99 -159
  269. package/lib/solution/UnifiedBookingSales/types.js +10 -32
  270. package/lib/solution/VenueBooking/index.js +811 -879
  271. package/lib/solution/VenueBooking/types.js +19 -39
  272. package/lib/solution/VenueBooking/utils/dateSummary.js +27 -56
  273. package/lib/solution/VenueBooking/utils/resource.js +31 -54
  274. package/lib/solution/VenueBooking/utils/slotMerge.js +94 -107
  275. package/lib/solution/VenueBooking/utils/timeSlot.js +132 -132
  276. package/lib/solution/VenueBooking/utils.js +130 -67
  277. package/lib/solution/index.js +124 -41
  278. package/lib/store/createStore.js +32 -29
  279. package/lib/types/index.js +4 -16
  280. package/lib/utils/payment-number.js +26 -46
  281. package/lib/utils/task.js +36 -36
  282. package/lib/utils/watch.js +81 -47
  283. package/package.json +2 -1
@@ -1,139 +1,164 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _exportNames = {
7
+ SalesImpl: true,
8
+ Sales: true
18
9
  };
19
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/solution/Sales/index.ts
31
- var Sales_exports = {};
32
- __export(Sales_exports, {
33
- Sales: () => SalesImpl,
34
- SalesImpl: () => SalesImpl,
35
- default: () => Sales_default
10
+ exports.default = exports.SalesImpl = exports.Sales = void 0;
11
+ var _dayjs = _interopRequireDefault(require("dayjs"));
12
+ var _BaseModule = require("../../modules/BaseModule");
13
+ var _types = require("./types");
14
+ Object.keys(_types).forEach(function (key) {
15
+ if (key === "default" || key === "__esModule") return;
16
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
17
+ if (key in exports && exports[key] === _types[key]) return;
18
+ Object.defineProperty(exports, key, {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _types[key];
22
+ }
23
+ });
36
24
  });
37
- module.exports = __toCommonJS(Sales_exports);
38
- var import_dayjs = __toESM(require("dayjs"));
39
- var import_BaseModule = require("../../modules/BaseModule");
40
- var import_types = require("./types");
41
- __reExport(Sales_exports, require("./types"), module.exports);
42
- var UNPAID_PAYMENT_STATUSES = /* @__PURE__ */ new Set(["unpaid", "partially_paid", "payment_processing"]);
43
- var SalesImpl = class extends import_BaseModule.BaseModule {
44
- // LoggerManager 实例
25
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
26
+ const UNPAID_PAYMENT_STATUSES = new Set(['unpaid', 'partially_paid', 'payment_processing']);
27
+
28
+ /**
29
+ * Sales 解决方案基础骨架
30
+ *
31
+ * 当前阶段仅提供:
32
+ * - solution 目录结构
33
+ * - 标准入口导出
34
+ * - 基础生命周期占位
35
+ *
36
+ * 不提前实现 store 编排、初始化流程细节、状态计算逻辑。
37
+ * TIPS:这块应该改名叫 ReservationModule 更合适一些,目前这边只服务于 Reservation 的 floormap 展示。
38
+ */
39
+ class SalesImpl extends _BaseModule.BaseModule {
40
+ defaultName = 'sales';
41
+ defaultVersion = '1.0.0';
42
+ defaultTimelineBucketMinutes = 15;
43
+ isSolution = true;
44
+ store;
45
+ options = {};
46
+ otherParams = {};
47
+ request;
48
+ logger; // LoggerManager 实例
49
+
45
50
  constructor(name, version) {
46
51
  super(name, version);
47
- this.defaultName = "sales";
48
- this.defaultVersion = "1.0.0";
49
- this.defaultTimelineBucketMinutes = 15;
50
- this.isSolution = true;
51
- this.options = {};
52
- this.otherParams = {};
53
52
  }
54
53
  async initialize(core, options = {}) {
55
54
  this.core = core;
56
55
  this.options = options;
57
56
  this.otherParams = options.otherParams || {};
58
- const appPlugin = this.core.getPlugin("app");
59
- this.request = appPlugin == null ? void 0 : appPlugin.getApp().request;
57
+ const appPlugin = this.core.getPlugin('app');
58
+ // @ts-ignore
59
+ this.request = appPlugin?.getApp().request;
60
60
  if (!this.request) {
61
- throw new Error("Sales 解决方案需要 request 插件支持");
61
+ throw new Error('Sales 解决方案需要 request 插件支持');
62
62
  }
63
+
64
+ // 初始化 store 状态
63
65
  this.store = {
64
- currentDay: (0, import_dayjs.default)().startOf("day"),
66
+ currentDay: (0, _dayjs.default)().startOf('day'),
65
67
  reservationList: []
66
68
  };
67
- this.logger = appPlugin == null ? void 0 : appPlugin.getApp().logger;
69
+
70
+ // TODO(Rolo): 等领导提供 reservationList 的目标结构后,
71
+ // 在这里补充从 Server/Order 读取 currentDay 原始数据并转换为预约列表。
72
+
73
+ this.logger = appPlugin?.getApp().logger;
68
74
  await this.core.effects.emit(`${this.name}:onInited`, {});
69
75
  }
76
+
70
77
  // -------------------------------------------------------------------------
71
78
  // SalesModuleAPI 实现
72
79
  // -------------------------------------------------------------------------
80
+
73
81
  /** 获取当前 store 快照 */
74
82
  getState() {
75
- return { ...this.store };
83
+ return {
84
+ ...this.store
85
+ };
76
86
  }
87
+
77
88
  /** 获取当前选择日期 */
78
89
  getCurrentDay() {
79
90
  return this.store.currentDay;
80
91
  }
92
+
81
93
  /** 设置当前选择日期,会自动归一到当天 00:00:00 */
82
94
  setCurrentDay(currentDay) {
83
- const normalized = (0, import_dayjs.default)(currentDay).startOf("day");
95
+ const normalized = (0, _dayjs.default)(currentDay).startOf('day');
84
96
  this.store.currentDay = normalized;
85
- this.core.effects.emit(import_types.SalesHooks.onCurrentDayChanged, { currentDay: normalized });
97
+ this.core.effects.emit(_types.SalesHooks.onCurrentDayChanged, {
98
+ currentDay: normalized
99
+ });
86
100
  return normalized;
87
101
  }
102
+
88
103
  /** 获取当前预约列表 */
89
104
  getReservationList() {
90
105
  return [...this.store.reservationList];
91
106
  }
107
+
92
108
  /** 覆盖设置当前预约列表 */
93
109
  setReservationList(reservationList) {
94
110
  this.store.reservationList = reservationList;
95
- this.core.effects.emit(import_types.SalesHooks.onReservationListChanged, { reservationList });
111
+ this.core.effects.emit(_types.SalesHooks.onReservationListChanged, {
112
+ reservationList
113
+ });
96
114
  return reservationList;
97
115
  }
116
+
98
117
  /** 重置预约列表为空 */
99
118
  resetReservationList() {
100
119
  this.store.reservationList = [];
101
- this.core.effects.emit(import_types.SalesHooks.onReservationListChanged, { reservationList: [] });
120
+ this.core.effects.emit(_types.SalesHooks.onReservationListChanged, {
121
+ reservationList: []
122
+ });
102
123
  return [];
103
124
  }
104
125
  async cancelOrder(orderIds) {
105
- const orderModule = this.core.getModule("order");
126
+ const orderModule = this.core.getModule('order');
106
127
  if (!orderModule) {
107
- throw new Error("Sales 取消订单失败:Order 模块未注册");
128
+ throw new Error('Sales 取消订单失败:Order 模块未注册');
108
129
  }
109
- return orderModule.cancelOrder({ order_ids: orderIds });
130
+ return orderModule.cancelOrder({
131
+ order_ids: orderIds
132
+ });
110
133
  }
111
134
  async changeBookingStatus(params) {
112
- const orderModule = this.core.getModule("order");
135
+ const orderModule = this.core.getModule('order');
113
136
  if (!orderModule) {
114
- throw new Error("Sales 变更预约状态失败:Order 模块未注册");
137
+ throw new Error('Sales 变更预约状态失败:Order 模块未注册');
115
138
  }
116
139
  return orderModule.changeBookingStatus(params);
117
140
  }
141
+
118
142
  // -------------------------------------------------------------------------
119
143
  // 生命周期
120
144
  // -------------------------------------------------------------------------
145
+
121
146
  async destroy() {
122
147
  await this.core.effects.emit(`${this.name}:onDestroy`, {});
123
148
  super.destroy();
124
149
  }
150
+
125
151
  /**
126
152
  * 时间轴粒度(分钟)
127
153
  * - 默认 15 分钟
128
154
  * - 可通过 registerModule 时的 options.otherParams.timelineBucketMinutes 覆盖
129
155
  */
130
156
  getTimelineBucketMinutes() {
131
- var _a;
132
- const dynamicBucket = Number((_a = this.otherParams) == null ? void 0 : _a.timelineBucketMinutes);
133
- if (!Number.isFinite(dynamicBucket) || dynamicBucket <= 0)
134
- return this.defaultTimelineBucketMinutes;
157
+ const dynamicBucket = Number(this.otherParams?.timelineBucketMinutes);
158
+ if (!Number.isFinite(dynamicBucket) || dynamicBucket <= 0) return this.defaultTimelineBucketMinutes;
135
159
  return Math.floor(dynamicBucket);
136
160
  }
161
+
137
162
  /**
138
163
  * 解析营业日统计窗口:
139
164
  * - 当 operating_day_boundary.type === 'start_time'
@@ -141,23 +166,32 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
141
166
  * - 否则回退自然日(00:00 到次日 00:00)
142
167
  */
143
168
  getTimelineRangeByOperatingBoundary() {
144
- var _a, _b, _c, _d, _e, _f, _g;
145
- const today = (0, import_dayjs.default)();
146
- const defaultStart = today.startOf("day");
147
- const defaultEndExclusive = defaultStart.add(1, "day");
148
- const appPlugin = this.core.getPlugin("app");
149
- const coreData = (_f = (_d = (_c = (_b = (_a = appPlugin == null ? void 0 : appPlugin.getApp()) == null ? void 0 : _a.data) == null ? void 0 : _b.store) == null ? void 0 : _c.getStore) == null ? void 0 : (_e = _d.call(_c)).getDataByModel) == null ? void 0 : _f.call(_e, "core");
150
- const operatingDayBoundary = (_g = coreData == null ? void 0 : coreData.core) == null ? void 0 : _g.operating_day_boundary;
151
- if ((operatingDayBoundary == null ? void 0 : operatingDayBoundary.type) !== "start_time") {
152
- return { startAt: defaultStart, endExclusiveAt: defaultEndExclusive };
169
+ const today = (0, _dayjs.default)();
170
+ const defaultStart = today.startOf('day');
171
+ const defaultEndExclusive = defaultStart.add(1, 'day');
172
+ const appPlugin = this.core.getPlugin('app');
173
+ const coreData = appPlugin?.getApp()?.data?.store?.getStore?.().getDataByModel?.('core');
174
+ const operatingDayBoundary = coreData?.core?.operating_day_boundary;
175
+ if (operatingDayBoundary?.type !== 'start_time') {
176
+ return {
177
+ startAt: defaultStart,
178
+ endExclusiveAt: defaultEndExclusive
179
+ };
153
180
  }
154
- const boundaryTime = String(operatingDayBoundary.time || "").trim();
155
- const startAt = (0, import_dayjs.default)(`${today.format("YYYY-MM-DD")} ${boundaryTime}`);
181
+ const boundaryTime = String(operatingDayBoundary.time || '').trim();
182
+ const startAt = (0, _dayjs.default)(`${today.format('YYYY-MM-DD')} ${boundaryTime}`);
156
183
  if (!startAt.isValid()) {
157
- return { startAt: defaultStart, endExclusiveAt: defaultEndExclusive };
184
+ return {
185
+ startAt: defaultStart,
186
+ endExclusiveAt: defaultEndExclusive
187
+ };
158
188
  }
159
- return { startAt, endExclusiveAt: startAt.add(1, "day") };
189
+ return {
190
+ startAt,
191
+ endExclusiveAt: startAt.add(1, 'day')
192
+ };
160
193
  }
194
+
161
195
  /**
162
196
  * 统计时间轴每个时间片的预约数量。
163
197
  * 算法使用差分数组,复杂度 O(n + s):
@@ -166,39 +200,37 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
166
200
  */
167
201
  getTimelineHighlights(bookingList = [], startDateTime, endDateTime) {
168
202
  const bucketMinutes = this.getTimelineBucketMinutes();
169
- const bucketMs = bucketMinutes * 60 * 1e3;
170
- const customStartAt = startDateTime ? (0, import_dayjs.default)(startDateTime) : (0, import_dayjs.default)("");
171
- const customEndExclusiveAt = endDateTime ? (0, import_dayjs.default)(endDateTime) : (0, import_dayjs.default)("");
203
+ const bucketMs = bucketMinutes * 60 * 1000;
204
+ const customStartAt = startDateTime ? (0, _dayjs.default)(startDateTime) : (0, _dayjs.default)('');
205
+ const customEndExclusiveAt = endDateTime ? (0, _dayjs.default)(endDateTime) : (0, _dayjs.default)('');
172
206
  const hasValidCustomRange = customStartAt.isValid() && customEndExclusiveAt.isValid();
173
- const { startAt, endExclusiveAt } = hasValidCustomRange ? { startAt: customStartAt, endExclusiveAt: customEndExclusiveAt } : this.getTimelineRangeByOperatingBoundary();
207
+ const {
208
+ startAt,
209
+ endExclusiveAt
210
+ } = hasValidCustomRange ? {
211
+ startAt: customStartAt,
212
+ endExclusiveAt: customEndExclusiveAt
213
+ } : this.getTimelineRangeByOperatingBoundary();
174
214
  const startAtMs = startAt.valueOf();
175
215
  const endExclusiveAtMs = endExclusiveAt.valueOf();
176
- if (!startAt.isValid() || !endExclusiveAt.isValid() || endExclusiveAtMs <= startAtMs)
177
- return [];
216
+ if (!startAt.isValid() || !endExclusiveAt.isValid() || endExclusiveAtMs <= startAtMs) return [];
178
217
  const slotCount = Math.ceil((endExclusiveAtMs - startAtMs) / bucketMs);
179
- if (slotCount <= 0)
180
- return [];
218
+ if (slotCount <= 0) return [];
181
219
  const diff = new Int32Array(slotCount + 1);
182
220
  for (let i = 0; i < bookingList.length; i++) {
183
221
  const booking = bookingList[i];
184
- const appointmentStatus = String(booking.appointment_status ?? booking.status ?? "");
185
- if (appointmentStatus === "new" || appointmentStatus === "rejected" || appointmentStatus === "cancelled")
186
- continue;
222
+ const appointmentStatus = String(booking.appointment_status ?? booking.status ?? '');
223
+ if (appointmentStatus === 'new' || appointmentStatus === 'rejected' || appointmentStatus === 'cancelled') continue;
187
224
  const bookingStartAt = this.toBookingDateTime(booking.start_date, booking.start_time);
188
225
  const bookingEndAt = this.toBookingDateTime(booking.end_date, booking.end_time);
189
- if (!bookingStartAt.isValid() || !bookingEndAt.isValid())
190
- continue;
226
+ if (!bookingStartAt.isValid() || !bookingEndAt.isValid()) continue;
191
227
  const overlapStartMs = Math.max(bookingStartAt.valueOf(), startAtMs);
228
+ // 结束时间按 <= 处理:转成右开区间时 +1ms,保证命中 end_time 所在时间片
192
229
  const overlapEndExclusiveMs = Math.min(bookingEndAt.valueOf() + 1, endExclusiveAtMs);
193
- if (overlapStartMs >= overlapEndExclusiveMs)
194
- continue;
230
+ if (overlapStartMs >= overlapEndExclusiveMs) continue;
195
231
  const startIdx = Math.max(0, Math.ceil((overlapStartMs - startAtMs) / bucketMs));
196
- const endIdx = Math.min(
197
- slotCount - 1,
198
- Math.floor((overlapEndExclusiveMs - 1 - startAtMs) / bucketMs)
199
- );
200
- if (startIdx > endIdx)
201
- continue;
232
+ const endIdx = Math.min(slotCount - 1, Math.floor((overlapEndExclusiveMs - 1 - startAtMs) / bucketMs));
233
+ if (startIdx > endIdx) continue;
202
234
  diff[startIdx] += 1;
203
235
  diff[endIdx + 1] -= 1;
204
236
  }
@@ -210,14 +242,17 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
210
242
  }
211
243
  return timeline;
212
244
  }
245
+
213
246
  /** dayjs 未启用插件时,手动封装 >= 判断 */
214
247
  isSameOrAfter(left, right) {
215
248
  return left.isAfter(right) || left.isSame(right);
216
249
  }
250
+
217
251
  /** dayjs 未启用插件时,手动封装 <= 判断 */
218
252
  isSameOrBefore(left, right) {
219
253
  return left.isBefore(right) || left.isSame(right);
220
254
  }
255
+
221
256
  /**
222
257
  * 将 booking 的日期/时间字段统一组装为 dayjs
223
258
  * - date + time 都有:按完整时间解析
@@ -225,66 +260,59 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
225
260
  * - 都没有:返回 invalid
226
261
  */
227
262
  toBookingDateTime(date, time) {
228
- if (!date && !time)
229
- return (0, import_dayjs.default)("");
230
- if (date && time)
231
- return (0, import_dayjs.default)(`${date} ${time}`);
232
- return (0, import_dayjs.default)(date || time);
263
+ if (!date && !time) return (0, _dayjs.default)('');
264
+ if (date && time) return (0, _dayjs.default)(`${date} ${time}`);
265
+ return (0, _dayjs.default)(date || time);
233
266
  }
267
+
234
268
  /**
235
269
  * 预约状态映射(面向 UI 的统一状态)
236
270
  * 说明:locked 逻辑后续会补业务规则,这里先保留分支占位。
237
271
  */
238
272
  getBookingStatus(appointmentStatus) {
239
- if (appointmentStatus === "started")
240
- return "occupied";
241
- if (appointmentStatus === "confirmed" || appointmentStatus === "arrived") {
242
- return "reserved";
273
+ if (appointmentStatus === 'started') return 'occupied';
274
+ if (appointmentStatus === 'confirmed' || appointmentStatus === 'arrived') {
275
+ return 'reserved';
243
276
  }
244
- if (appointmentStatus === "locked")
245
- return "locked";
246
- return void 0;
277
+ // TODO: locked 的业务规则后续补充。
278
+ if (appointmentStatus === 'locked') return 'locked';
279
+ return undefined;
247
280
  }
248
281
  getResourceId(resource) {
249
- return resource.id ?? resource.form_record_id ?? "";
282
+ return resource.id ?? resource.form_record_id ?? '';
250
283
  }
251
284
  getBookingAppointmentStatus(booking) {
252
- return String(booking.appointment_status ?? booking.status ?? "");
285
+ return String(booking.appointment_status ?? booking.status ?? '');
253
286
  }
254
287
  isBookingIncludedInStats(booking) {
255
288
  const appointmentStatus = this.getBookingAppointmentStatus(booking);
256
- return appointmentStatus !== "new" && appointmentStatus !== "rejected" && appointmentStatus !== "cancelled";
289
+ return appointmentStatus !== 'new' && appointmentStatus !== 'rejected' && appointmentStatus !== 'cancelled';
257
290
  }
258
291
  getBookingOrderPaymentStatus(booking) {
259
- var _a;
260
- return String(((_a = booking.order) == null ? void 0 : _a.payment_status) ?? "");
292
+ return String(booking.order?.payment_status ?? '');
261
293
  }
262
294
  isUnpaidBooking(booking) {
263
295
  return UNPAID_PAYMENT_STATUSES.has(this.getBookingOrderPaymentStatus(booking));
264
296
  }
265
297
  countBookingOrders(bookings) {
266
- const orderIds = /* @__PURE__ */ new Set();
267
- bookings.forEach((booking) => {
268
- var _a;
269
- const orderId = booking.order_id ?? ((_a = booking.order) == null ? void 0 : _a.order_id);
270
- if (orderId === void 0 || orderId === null)
271
- return;
298
+ const orderIds = new Set();
299
+ bookings.forEach(booking => {
300
+ const orderId = booking.order_id ?? booking.order?.order_id;
301
+ if (orderId === undefined || orderId === null) return;
272
302
  orderIds.add(String(orderId));
273
303
  });
274
304
  return orderIds.size;
275
305
  }
276
306
  countCompletedBookings(bookings) {
277
- return bookings.filter((booking) => this.getBookingAppointmentStatus(booking) === "completed").length;
307
+ return bookings.filter(booking => this.getBookingAppointmentStatus(booking) === 'completed').length;
278
308
  }
279
309
  groupBookingsByResource(bookingList) {
280
- const bookingMap = /* @__PURE__ */ new Map();
281
- bookingList.forEach((booking) => {
282
- if (!Array.isArray(booking.resources))
283
- return;
284
- booking.resources.forEach((resource) => {
285
- const relationId = resource == null ? void 0 : resource.relation_id;
286
- if (relationId === void 0 || relationId === null)
287
- return;
310
+ const bookingMap = new Map();
311
+ bookingList.forEach(booking => {
312
+ if (!Array.isArray(booking.resources)) return;
313
+ booking.resources.forEach(resource => {
314
+ const relationId = resource?.relation_id;
315
+ if (relationId === undefined || relationId === null) return;
288
316
  const key = String(relationId);
289
317
  const list = bookingMap.get(key) || [];
290
318
  list.push(booking);
@@ -294,12 +322,10 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
294
322
  return bookingMap;
295
323
  }
296
324
  isBookingMatchedResource(booking, resourceId) {
297
- if (!Array.isArray(booking.resources))
298
- return false;
299
- return booking.resources.some((resource) => {
300
- const relationId = resource == null ? void 0 : resource.relation_id;
301
- if (relationId === void 0 || relationId === null)
302
- return false;
325
+ if (!Array.isArray(booking.resources)) return false;
326
+ return booking.resources.some(resource => {
327
+ const relationId = resource?.relation_id;
328
+ if (relationId === undefined || relationId === null) return false;
303
329
  return String(relationId) === String(resourceId);
304
330
  });
305
331
  }
@@ -310,6 +336,7 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
310
336
  return leftStartAt - rightStartAt;
311
337
  });
312
338
  }
339
+
313
340
  /**
314
341
  * 资源下 bookings 的返回裁剪策略:
315
342
  * 1) 优先返回当前时刻正在进行中的预约(允许并发返回多条)
@@ -319,109 +346,96 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
319
346
  * - includeAllFuture 时,保留选中预约并返回当天全部后续预约;仅详情接口启用。
320
347
  */
321
348
  pickBookingsForCurrentPoint(current, bookings, options = {}) {
322
- if (bookings.length === 0)
323
- return [];
324
- const currentDayStart = current.startOf("day");
325
- const currentDayEnd = current.endOf("day");
326
- const dayScopedBookings = bookings.filter((booking) => {
349
+ if (bookings.length === 0) return [];
350
+ const currentDayStart = current.startOf('day');
351
+ const currentDayEnd = current.endOf('day');
352
+
353
+ // 仅保留与 current 当天有时间交集的预约,避免跨天误命中
354
+ const dayScopedBookings = bookings.filter(booking => {
327
355
  const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
328
356
  const endAt = this.toBookingDateTime(booking.end_date, booking.end_time);
329
- if (!startAt.isValid() || !endAt.isValid())
330
- return false;
357
+ if (!startAt.isValid() || !endAt.isValid()) return false;
331
358
  return this.isSameOrBefore(startAt, currentDayEnd) && this.isSameOrAfter(endAt, currentDayStart);
332
359
  });
333
- if (dayScopedBookings.length === 0)
334
- return [];
335
- const appendNextStartGroupIfNeeded = (selectedBookings) => {
336
- if (selectedBookings.length === 0)
337
- return selectedBookings;
360
+ if (dayScopedBookings.length === 0) return [];
361
+ const appendNextStartGroupIfNeeded = selectedBookings => {
362
+ if (selectedBookings.length === 0) return selectedBookings;
338
363
  if (options.includeAllFuture) {
339
- const allFutureBookings = dayScopedBookings.filter((booking) => {
364
+ const allFutureBookings = dayScopedBookings.filter(booking => {
340
365
  const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
341
366
  return startAt.isValid() && startAt.isAfter(current);
342
367
  });
343
368
  return [...selectedBookings, ...allFutureBookings];
344
369
  }
345
- const shouldAppendNextGroup = selectedBookings.some(
346
- (booking) => booking.status === "reserved" || booking.status === "occupied"
347
- );
348
- if (!shouldAppendNextGroup)
349
- return selectedBookings;
350
- const selectedStartValues = new Set(
351
- selectedBookings.map((booking) => this.toBookingDateTime(booking.start_date, booking.start_time)).filter((startAt) => startAt.isValid()).map((startAt) => startAt.valueOf())
352
- );
353
- const futureCandidates = dayScopedBookings.filter((booking) => {
370
+ const shouldAppendNextGroup = selectedBookings.some(booking => booking.status === 'reserved' || booking.status === 'occupied');
371
+ if (!shouldAppendNextGroup) return selectedBookings;
372
+ const selectedStartValues = new Set(selectedBookings.map(booking => this.toBookingDateTime(booking.start_date, booking.start_time)).filter(startAt => startAt.isValid()).map(startAt => startAt.valueOf()));
373
+ const futureCandidates = dayScopedBookings.filter(booking => {
354
374
  const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
355
- if (!startAt.isValid())
356
- return false;
375
+ if (!startAt.isValid()) return false;
357
376
  return startAt.isAfter(current) && !selectedStartValues.has(startAt.valueOf());
358
377
  });
359
- if (futureCandidates.length === 0)
360
- return selectedBookings;
361
- const nextStartAt = this.toBookingDateTime(
362
- futureCandidates[0].start_date,
363
- futureCandidates[0].start_time
364
- ).valueOf();
365
- const nextStartGroup = futureCandidates.filter((booking) => {
378
+ if (futureCandidates.length === 0) return selectedBookings;
379
+ const nextStartAt = this.toBookingDateTime(futureCandidates[0].start_date, futureCandidates[0].start_time).valueOf();
380
+ const nextStartGroup = futureCandidates.filter(booking => {
366
381
  const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
367
382
  return startAt.isValid() && startAt.valueOf() === nextStartAt;
368
383
  });
369
- if (nextStartGroup.length === 0)
370
- return selectedBookings;
371
- nextStartGroup.forEach((booking) => {
384
+ if (nextStartGroup.length === 0) return selectedBookings;
385
+ nextStartGroup.forEach(booking => {
372
386
  booking.isNext = true;
373
387
  });
374
388
  return [...selectedBookings, ...nextStartGroup];
375
389
  };
376
- const activeBookings = dayScopedBookings.filter((booking) => {
390
+
391
+ // active: current 处于 [startAt, endAt] 区间
392
+ const activeBookings = dayScopedBookings.filter(booking => {
377
393
  const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
378
394
  const endAt = this.toBookingDateTime(booking.end_date, booking.end_time);
379
- if (!startAt.isValid() || !endAt.isValid())
380
- return false;
395
+ if (!startAt.isValid() || !endAt.isValid()) return false;
381
396
  return this.isSameOrAfter(current, startAt) && this.isSameOrBefore(current, endAt);
382
397
  });
383
- if (activeBookings.length > 0)
384
- return appendNextStartGroupIfNeeded(activeBookings);
385
- const timeoutOccupied = dayScopedBookings.filter(
386
- (booking) => booking.status === "occupied" && booking.isTimeout
387
- );
388
- if (timeoutOccupied.length > 0)
389
- return appendNextStartGroupIfNeeded(timeoutOccupied);
390
- const upcoming = dayScopedBookings.filter((booking) => {
398
+ if (activeBookings.length > 0) return appendNextStartGroupIfNeeded(activeBookings);
399
+
400
+ // timeout occupied: 占用中且超时
401
+ const timeoutOccupied = dayScopedBookings.filter(booking => booking.status === 'occupied' && booking.isTimeout);
402
+ if (timeoutOccupied.length > 0) return appendNextStartGroupIfNeeded(timeoutOccupied);
403
+
404
+ // upcoming: 从未来预约里只取最早那一组(同 start_time)
405
+ const upcoming = dayScopedBookings.filter(booking => {
391
406
  const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
392
- return startAt.isValid() && startAt.isAfter(current) && startAt.isSame(current, "day");
407
+ return startAt.isValid() && startAt.isAfter(current) && startAt.isSame(current, 'day');
393
408
  });
394
409
  if (upcoming.length > 0) {
395
- if (options.includeAllFuture)
396
- return upcoming;
410
+ if (options.includeAllFuture) return upcoming;
397
411
  const firstStartAt = this.toBookingDateTime(upcoming[0].start_date, upcoming[0].start_time).valueOf();
398
- const upcomingStartGroup = upcoming.filter((booking) => {
412
+ const upcomingStartGroup = upcoming.filter(booking => {
399
413
  const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
400
414
  return startAt.valueOf() === firstStartAt;
401
415
  });
402
416
  return appendNextStartGroupIfNeeded(upcomingStartGroup);
403
417
  }
418
+
419
+ // fallback: 全部是过去且非 timeout 的场景,保留末条便于前端兜底展示
404
420
  const fallback = dayScopedBookings[dayScopedBookings.length - 1];
405
421
  return fallback ? [fallback] : [];
406
422
  }
423
+
407
424
  /**
408
425
  * 计算 booking 在 current 时刻的执行进度百分比(0-100)。
409
426
  * - startAt/endAt 非法或 totalMinutes <= 0 返回 0
410
427
  * - current 早于 startAt 返回 0,晚于 endAt 返回 100
411
428
  */
412
429
  calcProgressPercent(current, startAt, endAt) {
413
- if (!startAt.isValid() || !endAt.isValid())
414
- return 0;
415
- const totalMinutes = endAt.diff(startAt, "minute");
416
- if (totalMinutes <= 0)
417
- return 0;
418
- const elapsedMinutes = current.diff(startAt, "minute");
419
- if (elapsedMinutes <= 0)
420
- return 0;
421
- if (elapsedMinutes >= totalMinutes)
422
- return 100;
430
+ if (!startAt.isValid() || !endAt.isValid()) return 0;
431
+ const totalMinutes = endAt.diff(startAt, 'minute');
432
+ if (totalMinutes <= 0) return 0;
433
+ const elapsedMinutes = current.diff(startAt, 'minute');
434
+ if (elapsedMinutes <= 0) return 0;
435
+ if (elapsedMinutes >= totalMinutes) return 100;
423
436
  return Math.floor(elapsedMinutes / totalMinutes * 100);
424
437
  }
438
+
425
439
  /**
426
440
  * 标准化单条 booking 的分发入口:
427
441
  * - 统一过滤 rejected / cancelled(视为没来过)
@@ -430,11 +444,10 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
430
444
  */
431
445
  normalizeMatchedBooking(current, deviceCurrent, booking, options = {}) {
432
446
  const appointmentStatus = this.getBookingAppointmentStatus(booking);
433
- if (appointmentStatus === "rejected" || appointmentStatus === "cancelled")
434
- return null;
447
+ if (appointmentStatus === 'rejected' || appointmentStatus === 'cancelled') return null;
435
448
  const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
436
449
  const endAt = this.toBookingDateTime(booking.end_date, booking.end_time);
437
- if (appointmentStatus === "completed" && options.includeCompleted) {
450
+ if (appointmentStatus === 'completed' && options.includeCompleted) {
438
451
  return this.buildCompletedBooking(current, booking, startAt, endAt);
439
452
  }
440
453
  if (current.isSame(deviceCurrent)) {
@@ -443,35 +456,35 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
443
456
  return this.buildSnapshotBooking(current, booking, appointmentStatus, startAt, endAt);
444
457
  }
445
458
  normalizeResourceBookings(current, deviceCurrent, bookingList, options = {}) {
446
- const normalizedBookings = bookingList.map((booking) => this.normalizeMatchedBooking(current, deviceCurrent, booking, options)).filter((booking) => Boolean(booking)).filter((booking) => booking.status);
459
+ const normalizedBookings = bookingList.map(booking => this.normalizeMatchedBooking(current, deviceCurrent, booking, options)).filter(booking => Boolean(booking)).filter(booking => booking.status);
447
460
  return this.sortMatchedBookings(normalizedBookings);
448
461
  }
449
462
  buildCompletedBooking(current, booking, startAt, endAt) {
450
- if (!startAt.isValid() || !endAt.isValid())
451
- return null;
463
+ if (!startAt.isValid() || !endAt.isValid()) return null;
452
464
  if (current.isBefore(startAt)) {
453
465
  return {
454
466
  ...booking,
455
- status: "reserved",
467
+ status: 'reserved',
456
468
  isTimeout: false,
457
- timeoutTime: void 0,
469
+ timeoutTime: undefined,
458
470
  progressPercent: 0,
459
- lateTime: void 0,
460
- reserved_status: "not_arrived",
461
- remainingReserveTime: Math.max(startAt.diff(current, "minute"), 0)
471
+ lateTime: undefined,
472
+ reserved_status: 'not_arrived',
473
+ remainingReserveTime: Math.max(startAt.diff(current, 'minute'), 0)
462
474
  };
463
475
  }
464
476
  return {
465
477
  ...booking,
466
- status: "occupied",
478
+ status: 'occupied',
467
479
  isTimeout: false,
468
- timeoutTime: void 0,
480
+ timeoutTime: undefined,
469
481
  progressPercent: this.isSameOrAfter(current, endAt) ? 100 : this.calcProgressPercent(current, startAt, endAt),
470
- lateTime: void 0,
471
- reserved_status: void 0,
472
- remainingReserveTime: void 0
482
+ lateTime: undefined,
483
+ reserved_status: undefined,
484
+ remainingReserveTime: undefined
473
485
  };
474
486
  }
487
+
475
488
  /**
476
489
  * 实时模式(current === deviceCurrent):信任 appointment_status
477
490
  * - 过滤 new / completed(实时视角下视为非活跃数据)
@@ -480,22 +493,21 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
480
493
  * - reserved 且 current < startAt 标记 not_arrived,否则标记 late
481
494
  */
482
495
  buildRealtimeBooking(current, booking, appointmentStatus, startAt, endAt) {
483
- if (appointmentStatus === "new" || appointmentStatus === "completed")
484
- return null;
496
+ if (appointmentStatus === 'new' || appointmentStatus === 'completed') return null;
485
497
  const bookingStatus = this.getBookingStatus(appointmentStatus);
486
- const isTimeout = bookingStatus === "occupied" && endAt.isValid() && current.isAfter(endAt);
487
- const timeoutTime = isTimeout ? current.diff(endAt, "minute") : void 0;
488
- const progressPercent = bookingStatus === "occupied" ? this.calcProgressPercent(current, startAt, endAt) : 0;
498
+ const isTimeout = bookingStatus === 'occupied' && endAt.isValid() && current.isAfter(endAt);
499
+ const timeoutTime = isTimeout ? current.diff(endAt, 'minute') : undefined;
500
+ const progressPercent = bookingStatus === 'occupied' ? this.calcProgressPercent(current, startAt, endAt) : 0;
489
501
  let reservedStatus;
490
502
  let lateTime;
491
503
  let remainingReserveTime;
492
- if (bookingStatus === "reserved" && startAt.isValid()) {
504
+ if (bookingStatus === 'reserved' && startAt.isValid()) {
493
505
  if (current.isBefore(startAt)) {
494
- reservedStatus = "not_arrived";
495
- remainingReserveTime = startAt.diff(current, "minute");
506
+ reservedStatus = 'not_arrived';
507
+ remainingReserveTime = startAt.diff(current, 'minute');
496
508
  } else {
497
- reservedStatus = "late";
498
- lateTime = Math.max(current.diff(startAt, "minute"), 0);
509
+ reservedStatus = 'late';
510
+ lateTime = Math.max(current.diff(startAt, 'minute'), 0);
499
511
  }
500
512
  }
501
513
  return {
@@ -509,6 +521,7 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
509
521
  remainingReserveTime
510
522
  };
511
523
  }
524
+
512
525
  /**
513
526
  * 快照模式(current !== deviceCurrent,过去或未来):忽略 appointment_status
514
527
  * 的实时态差异,仅按 booking 时间窗判定,为 current 提供时间点快照视图。
@@ -524,72 +537,77 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
524
537
  * 快照模式下 isTimeout 恒为 false,lateTime / timeoutTime 始终置空。
525
538
  */
526
539
  buildSnapshotBooking(current, booking, appointmentStatus, startAt, endAt) {
527
- if (appointmentStatus === "new")
528
- return null;
529
- if (appointmentStatus === "locked") {
540
+ if (appointmentStatus === 'new') return null;
541
+ if (appointmentStatus === 'locked') {
530
542
  return {
531
543
  ...booking,
532
- status: "locked",
544
+ status: 'locked',
533
545
  isTimeout: false,
534
- timeoutTime: void 0,
546
+ timeoutTime: undefined,
535
547
  progressPercent: 0,
536
- lateTime: void 0,
537
- reserved_status: void 0,
538
- remainingReserveTime: void 0
548
+ lateTime: undefined,
549
+ reserved_status: undefined,
550
+ remainingReserveTime: undefined
539
551
  };
540
552
  }
541
- if (!startAt.isValid() || !endAt.isValid())
542
- return null;
543
- if (current.isAfter(endAt))
544
- return null;
553
+ if (!startAt.isValid() || !endAt.isValid()) return null;
554
+ if (current.isAfter(endAt)) return null;
545
555
  if (this.isSameOrAfter(current, startAt) && this.isSameOrBefore(current, endAt)) {
546
556
  return {
547
557
  ...booking,
548
- status: "occupied",
558
+ status: 'occupied',
549
559
  isTimeout: false,
550
- timeoutTime: void 0,
560
+ timeoutTime: undefined,
551
561
  progressPercent: this.calcProgressPercent(current, startAt, endAt),
552
- lateTime: void 0,
553
- reserved_status: void 0,
554
- remainingReserveTime: void 0
562
+ lateTime: undefined,
563
+ reserved_status: undefined,
564
+ remainingReserveTime: undefined
555
565
  };
556
566
  }
557
567
  return {
558
568
  ...booking,
559
- status: "reserved",
569
+ status: 'reserved',
560
570
  isTimeout: false,
561
- timeoutTime: void 0,
571
+ timeoutTime: undefined,
562
572
  progressPercent: 0,
563
- lateTime: void 0,
564
- reserved_status: "not_arrived",
565
- remainingReserveTime: Math.max(startAt.diff(current, "minute"), 0)
573
+ lateTime: undefined,
574
+ reserved_status: 'not_arrived',
575
+ remainingReserveTime: Math.max(startAt.diff(current, 'minute'), 0)
566
576
  };
567
577
  }
568
578
  async getResourceBookingList(currentTime, bookingList = [], deviceTime = currentTime) {
569
- var _a;
570
- const current = (0, import_dayjs.default)(currentTime);
571
- if (!current.isValid())
572
- return [];
573
- const deviceCurrent = (0, import_dayjs.default)(deviceTime);
574
- if (!deviceCurrent.isValid())
575
- return [];
576
- const resourceResponse = await this.request.get(
577
- "/shop/form/resource/page",
578
- { skip: 1, num: 999 },
579
- // @ts-ignore
580
- { osServer: true, isShopApi: true }
581
- );
582
- const resourceList = ((_a = resourceResponse == null ? void 0 : resourceResponse.data) == null ? void 0 : _a.list) ?? [];
583
- if (!Array.isArray(resourceList) || resourceList.length === 0)
584
- return [];
579
+ // currentTime 约定为完整 datetime;非法值直接返回空,避免误判
580
+ const current = (0, _dayjs.default)(currentTime);
581
+ if (!current.isValid()) return [];
582
+ const deviceCurrent = (0, _dayjs.default)(deviceTime);
583
+ if (!deviceCurrent.isValid()) return [];
584
+
585
+ // 资源列表来源:Server 路由 /shop/form/resource/page
586
+ const resourceResponse = await this.request.get('/shop/form/resource/page', {
587
+ skip: 1,
588
+ num: 999
589
+ },
590
+ // @ts-ignore
591
+ {
592
+ osServer: true,
593
+ isShopApi: true
594
+ });
595
+ const resourceList = resourceResponse?.data?.list ?? [];
596
+ if (!Array.isArray(resourceList) || resourceList.length === 0) return [];
597
+
598
+ // 全局先做 booking 标准化 + start_time 升序,后续映射直接复用
585
599
  const normalizedBookings = this.normalizeResourceBookings(current, deviceCurrent, bookingList);
600
+
601
+ // 建立 resourceId -> bookings[] 倒排索引,加速资源匹配
586
602
  const rawBookingMap = this.groupBookingsByResource(bookingList);
587
603
  const bookingMap = this.groupBookingsByResource(normalizedBookings);
588
- const list = resourceList.map((resource) => {
604
+
605
+ // 输出:每个资源都返回;bookings 可能是 0 / 1 / 多条(并发场景)
606
+ const list = resourceList.map(resource => {
589
607
  const resourceId = this.getResourceId(resource);
590
608
  const rawMatchedBookings = rawBookingMap.get(String(resourceId)) || [];
591
609
  const matchedBookings = bookingMap.get(String(resourceId)) || [];
592
- const statsBookings = rawMatchedBookings.filter((booking) => this.isBookingIncludedInStats(booking));
610
+ const statsBookings = rawMatchedBookings.filter(booking => this.isBookingIncludedInStats(booking));
593
611
  const orderCount = this.countBookingOrders(statsBookings);
594
612
  const bookingCount = statsBookings.length;
595
613
  const compeleteBookingCount = this.countCompletedBookings(statsBookings);
@@ -604,81 +622,72 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
604
622
  };
605
623
  });
606
624
  this.logger.addLog({
607
- type: "info",
608
- title: "getResourceBookingList",
625
+ type: 'info',
626
+ title: 'getResourceBookingList',
609
627
  metadata: {
610
628
  currentTime,
611
- bookingList: bookingList == null ? void 0 : bookingList.length,
629
+ bookingList: bookingList?.length,
612
630
  deviceTime,
613
- list: list == null ? void 0 : list.length
631
+ list: list?.length
614
632
  }
615
633
  });
616
634
  return list;
617
635
  }
618
636
  async getResourceBookingItem(params) {
619
- var _a, _b;
620
- const current = (0, import_dayjs.default)(params.currentTime);
621
- if (!current.isValid())
622
- return null;
623
- const deviceCurrent = (0, import_dayjs.default)(params.deviceTime || params.currentTime);
624
- if (!deviceCurrent.isValid())
625
- return null;
626
- const resourceResponse = await this.request.get(
627
- "/shop/form/resource/page",
628
- { skip: 1, num: 999 },
629
- // @ts-ignore
630
- { osServer: true, isShopApi: true }
631
- );
632
- const resourceList = ((_a = resourceResponse == null ? void 0 : resourceResponse.data) == null ? void 0 : _a.list) ?? [];
633
- if (!Array.isArray(resourceList) || resourceList.length === 0)
634
- return null;
635
- const targetResource = resourceList.find(
636
- (resource) => String(this.getResourceId(resource)) === String(params.resourceId)
637
- );
638
- if (!targetResource)
639
- return null;
637
+ const current = (0, _dayjs.default)(params.currentTime);
638
+ if (!current.isValid()) return null;
639
+ const deviceCurrent = (0, _dayjs.default)(params.deviceTime || params.currentTime);
640
+ if (!deviceCurrent.isValid()) return null;
641
+ const resourceResponse = await this.request.get('/shop/form/resource/page', {
642
+ skip: 1,
643
+ num: 999
644
+ },
645
+ // @ts-ignore
646
+ {
647
+ osServer: true,
648
+ isShopApi: true
649
+ });
650
+ const resourceList = resourceResponse?.data?.list ?? [];
651
+ if (!Array.isArray(resourceList) || resourceList.length === 0) return null;
652
+ const targetResource = resourceList.find(resource => String(this.getResourceId(resource)) === String(params.resourceId));
653
+ if (!targetResource) return null;
640
654
  const resourceId = this.getResourceId(targetResource);
641
- const matchedBookingList = params.bookingList.filter(
642
- (booking) => this.isBookingMatchedResource(booking, resourceId)
643
- );
644
- const statsBookingList = matchedBookingList.filter((booking) => this.isBookingIncludedInStats(booking));
645
- const completedBookingList = matchedBookingList.filter(
646
- (booking) => this.getBookingAppointmentStatus(booking) === "completed"
647
- );
648
- const unpaidBookingList = matchedBookingList.filter((booking) => this.isUnpaidBooking(booking));
649
- const bookings = this.pickBookingsForCurrentPoint(
650
- current,
651
- this.normalizeResourceBookings(current, deviceCurrent, matchedBookingList),
652
- { includeAllFuture: true }
653
- );
654
- const completedBookings = completedBookingList.map((booking) => {
655
+ const matchedBookingList = params.bookingList.filter(booking => this.isBookingMatchedResource(booking, resourceId));
656
+ const statsBookingList = matchedBookingList.filter(booking => this.isBookingIncludedInStats(booking));
657
+ const completedBookingList = matchedBookingList.filter(booking => this.getBookingAppointmentStatus(booking) === 'completed');
658
+ // const unpaidBookingList = matchedBookingList.filter(
659
+ // (booking) => this.getBookingOrderPaymentStatus(booking) === 'unpaid' || this.getBookingOrderPaymentStatus(booking) === 'payment_processing',
660
+ // );
661
+ const unpaidBookingList = matchedBookingList.filter(booking => this.isUnpaidBooking(booking));
662
+ const bookings = this.pickBookingsForCurrentPoint(current, this.normalizeResourceBookings(current, deviceCurrent, matchedBookingList), {
663
+ includeAllFuture: true
664
+ });
665
+ const completedBookings = completedBookingList.map(booking => {
655
666
  return {
656
667
  ...booking,
657
- status: "compelete",
668
+ status: 'compelete',
658
669
  isTimeout: false,
659
- timeoutTime: void 0,
670
+ timeoutTime: undefined,
660
671
  progressPercent: 100,
661
- lateTime: void 0,
662
- reserved_status: void 0,
663
- remainingReserveTime: void 0
672
+ lateTime: undefined,
673
+ reserved_status: undefined,
674
+ remainingReserveTime: undefined
664
675
  };
665
676
  });
666
- const unpaidBookings = this.pickBookingsForCurrentPoint(
667
- current,
668
- this.normalizeResourceBookings(current, deviceCurrent, unpaidBookingList),
669
- { includeAllFuture: true }
670
- );
677
+ const unpaidBookings = this.pickBookingsForCurrentPoint(current, this.normalizeResourceBookings(current, deviceCurrent, unpaidBookingList), {
678
+ includeAllFuture: true
679
+ });
671
680
  const orderCount = this.countBookingOrders(statsBookingList);
672
681
  const bookingCount = statsBookingList.length;
673
682
  const compeleteBookingCount = this.countCompletedBookings(statsBookingList);
674
683
  this.logger.addLog({
675
- type: "info",
676
- title: "getResourceBookingItem",
684
+ type: 'info',
685
+ title: 'getResourceBookingItem',
677
686
  metadata: {
678
687
  currentTime: params.currentTime,
679
688
  deviceTime: params.deviceTime || params.currentTime,
680
689
  resourceId,
681
- bookingList: (_b = params.bookingList) == null ? void 0 : _b.length,
690
+ bookingList: params.bookingList?.length,
682
691
  bookings: bookings.length,
683
692
  completedBookings: completedBookings.length,
684
693
  unpaidBookings: unpaidBookings.length,
@@ -698,11 +707,6 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
698
707
  unpaidBookings
699
708
  };
700
709
  }
701
- };
702
- var Sales_default = SalesImpl;
703
- // Annotate the CommonJS export names for ESM import in node:
704
- 0 && (module.exports = {
705
- Sales,
706
- SalesImpl,
707
- ...require("./types")
708
- });
710
+ }
711
+ exports.Sales = exports.SalesImpl = SalesImpl;
712
+ var _default = exports.default = SalesImpl;