@pisell/pisellos 2.1.2 → 2.1.3
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/modules/Discount/index.d.ts +2 -1
- package/dist/modules/Discount/index.js +67 -4
- package/dist/modules/Discount/types.d.ts +25 -0
- package/dist/solution/BookingByStep/index.js +1 -1
- package/dist/solution/BookingByStep/utils/timeslots.js +161 -69
- package/dist/solution/ShopDiscount/index.d.ts +1 -1
- package/dist/solution/ShopDiscount/index.js +6 -6
- package/lib/modules/Discount/index.d.ts +2 -1
- package/lib/modules/Discount/index.js +45 -3
- package/lib/modules/Discount/types.d.ts +25 -0
- package/lib/solution/BookingByStep/index.js +1 -1
- package/lib/solution/BookingByStep/utils/timeslots.js +103 -49
- package/lib/solution/ShopDiscount/index.d.ts +1 -1
- package/lib/solution/ShopDiscount/index.js +2 -2
- package/package.json +1 -1
|
@@ -20,8 +20,9 @@ export declare class DiscountModule extends BaseModule implements Module, Discou
|
|
|
20
20
|
with_discount_card: 0 | 1;
|
|
21
21
|
customer_id: number;
|
|
22
22
|
}): Promise<Discount[]>;
|
|
23
|
-
batchSearch(code: string): Promise<Discount[]>;
|
|
23
|
+
batchSearch(code: string, customerId?: number): Promise<Discount[]>;
|
|
24
24
|
filterEnabledDiscountList(discountList: Discount[]): Discount[];
|
|
25
|
+
private checkUsageCreditsLimit;
|
|
25
26
|
uniqueByProductId(discountList: Discount[]): Discount[];
|
|
26
27
|
filterDiscountListByProductIds(discountList: Discount[], productIds: number[]): Discount[];
|
|
27
28
|
calcDiscountApplicableProductTotalPrice(discount: Discount): number | undefined;
|
|
@@ -145,7 +145,7 @@ export var DiscountModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
145
145
|
}, {
|
|
146
146
|
key: "batchSearch",
|
|
147
147
|
value: function () {
|
|
148
|
-
var _batchSearch = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(code) {
|
|
148
|
+
var _batchSearch = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(code, customerId) {
|
|
149
149
|
var result, resultDiscountList;
|
|
150
150
|
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
|
|
151
151
|
while (1) switch (_context4.prev = _context4.next) {
|
|
@@ -156,7 +156,10 @@ export var DiscountModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
156
156
|
translate_flag: 1,
|
|
157
157
|
tags: ['good_pass', 'product_discount_card'],
|
|
158
158
|
available: 1,
|
|
159
|
-
relation_product: 1
|
|
159
|
+
relation_product: 1,
|
|
160
|
+
with: ['extensionData'],
|
|
161
|
+
order_behavior_count: 1,
|
|
162
|
+
order_behavior_count_customer_id: customerId || 1
|
|
160
163
|
});
|
|
161
164
|
case 2:
|
|
162
165
|
result = _context4.sent;
|
|
@@ -168,7 +171,7 @@ export var DiscountModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
168
171
|
}
|
|
169
172
|
}, _callee4, this);
|
|
170
173
|
}));
|
|
171
|
-
function batchSearch(_x5) {
|
|
174
|
+
function batchSearch(_x5, _x6) {
|
|
172
175
|
return _batchSearch.apply(this, arguments);
|
|
173
176
|
}
|
|
174
177
|
return batchSearch;
|
|
@@ -176,11 +179,71 @@ export var DiscountModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
176
179
|
}, {
|
|
177
180
|
key: "filterEnabledDiscountList",
|
|
178
181
|
value: function filterEnabledDiscountList(discountList) {
|
|
182
|
+
var _this2 = this;
|
|
179
183
|
return discountList.filter(function (discount) {
|
|
180
|
-
return discount.limit_status === 'enable' && new Decimal((discount === null || discount === void 0 ? void 0 : discount.par_value) || 0).minus(new Decimal((discount === null || discount === void 0 ? void 0 : discount.used_par_value) || 0)).greaterThan(0);
|
|
184
|
+
return discount.limit_status === 'enable' && new Decimal((discount === null || discount === void 0 ? void 0 : discount.par_value) || 0).minus(new Decimal((discount === null || discount === void 0 ? void 0 : discount.used_par_value) || 0)).greaterThan(0) && _this2.checkUsageCreditsLimit(discount);
|
|
181
185
|
});
|
|
182
186
|
}
|
|
183
187
|
|
|
188
|
+
// 检查使用次数限制
|
|
189
|
+
}, {
|
|
190
|
+
key: "checkUsageCreditsLimit",
|
|
191
|
+
value: function checkUsageCreditsLimit(discount) {
|
|
192
|
+
// 如果没有 extension_data,则不需要限制
|
|
193
|
+
if (!discount.extension_data || discount.extension_data.length === 0) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// 查找 field_key 为 usage_credits 的数据
|
|
198
|
+
var usageCreditsData = discount.extension_data.find(function (data) {
|
|
199
|
+
return data.field_key === 'usage_credits';
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// 如果没有找到 usage_credits 数据,则不需要限制
|
|
203
|
+
if (!usageCreditsData) {
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
var value = usageCreditsData.value;
|
|
207
|
+
|
|
208
|
+
// 检查总次数限制
|
|
209
|
+
if (value.total_credits && value.total_credits > 0) {
|
|
210
|
+
if ((discount.total_order_behavior_count || 0) >= value.total_credits) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// 检查单用户限制
|
|
216
|
+
if (value.per_user_limit && value.per_user_limit > 0) {
|
|
217
|
+
if ((discount.customer_order_behavior_count || 0) >= value.per_user_limit) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// 检查单日限制
|
|
223
|
+
if (value.max_per_day && value.max_per_day > 0) {
|
|
224
|
+
if ((discount.today_order_behavior_count || 0) >= value.max_per_day) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 检查单周限制
|
|
230
|
+
if (value.max_per_week && value.max_per_week > 0) {
|
|
231
|
+
if ((discount.week_order_behavior_count || 0) >= value.max_per_week) {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 检查单月限制
|
|
237
|
+
if (value.max_per_month && value.max_per_month > 0) {
|
|
238
|
+
if ((discount.month_order_behavior_count || 0) >= value.max_per_month) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 所有检查都通过
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
|
|
184
247
|
// 根据productIds去重
|
|
185
248
|
}, {
|
|
186
249
|
key: "uniqueByProductId",
|
|
@@ -36,6 +36,25 @@ interface ApplicableProductDetails {
|
|
|
36
36
|
title?: string;
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
+
interface UsageCreditsValue {
|
|
40
|
+
total_credits: number;
|
|
41
|
+
per_user_limit: number;
|
|
42
|
+
max_per_day: number;
|
|
43
|
+
max_per_week: number;
|
|
44
|
+
max_per_month: number;
|
|
45
|
+
}
|
|
46
|
+
interface ExtensionData {
|
|
47
|
+
id: number;
|
|
48
|
+
shop_id: number;
|
|
49
|
+
product_id: number;
|
|
50
|
+
field_id: number;
|
|
51
|
+
field_key: string;
|
|
52
|
+
type: string;
|
|
53
|
+
value: UsageCreditsValue | Record<string, any> | string | number | boolean | any[];
|
|
54
|
+
created_at: string | null;
|
|
55
|
+
updated_at: string | null;
|
|
56
|
+
deleted_at: string | null;
|
|
57
|
+
}
|
|
39
58
|
export interface Discount {
|
|
40
59
|
id: number;
|
|
41
60
|
product_name: string;
|
|
@@ -70,6 +89,12 @@ export interface Discount {
|
|
|
70
89
|
appliedProductDetails: ApplicableProductDetails[];
|
|
71
90
|
isDisabledForProductUsed?: boolean;
|
|
72
91
|
amount?: number;
|
|
92
|
+
extension_data?: ExtensionData[];
|
|
93
|
+
total_order_behavior_count?: number;
|
|
94
|
+
today_order_behavior_count?: number;
|
|
95
|
+
week_order_behavior_count?: number;
|
|
96
|
+
month_order_behavior_count?: number;
|
|
97
|
+
customer_order_behavior_count?: number;
|
|
73
98
|
}
|
|
74
99
|
export interface DiscountState {
|
|
75
100
|
discountList: Discount[];
|
|
@@ -1281,7 +1281,7 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1281
1281
|
// 如果此时 resources 为空,视作购物车里已经有了 dateRange 数据,此时 dateList 里明确就是那一天的数据
|
|
1282
1282
|
if (!allOriginResources.length) {
|
|
1283
1283
|
var dateList = this.store.date.getDateList();
|
|
1284
|
-
dateList.forEach(function (n) {
|
|
1284
|
+
dateList === null || dateList === void 0 || dateList.forEach(function (n) {
|
|
1285
1285
|
if (n.resource) allOriginResources.push.apply(allOriginResources, _toConsumableArray(n.resource));
|
|
1286
1286
|
});
|
|
1287
1287
|
}
|
|
@@ -95,6 +95,12 @@ export function findFastestAvailableResource(_ref2) {
|
|
|
95
95
|
var currentTime = dayjs();
|
|
96
96
|
var fastestTime = null;
|
|
97
97
|
var fastestResources = [];
|
|
98
|
+
console.log('[TimeslotUtils] 查找最快可用资源:', {
|
|
99
|
+
currentTime: currentTime.format('YYYY-MM-DD HH:mm:ss'),
|
|
100
|
+
resourceCount: resources.length,
|
|
101
|
+
currentCapacity: currentCapacity,
|
|
102
|
+
countMap: countMap
|
|
103
|
+
});
|
|
98
104
|
|
|
99
105
|
// 遍历所有资源,找到最快可用的时间点
|
|
100
106
|
var _iterator2 = _createForOfIteratorHelper(resources),
|
|
@@ -102,75 +108,120 @@ export function findFastestAvailableResource(_ref2) {
|
|
|
102
108
|
try {
|
|
103
109
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
104
110
|
var _resource = _step2.value;
|
|
105
|
-
//
|
|
111
|
+
// 获取资源当天且还在工作时间内的时间段
|
|
106
112
|
var todayTimes = _resource.times.filter(function (time) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// 按开始时间排序
|
|
112
|
-
todayTimes.sort(function (a, b) {
|
|
113
|
-
return dayjs(a.start_at).diff(dayjs(b.start_at));
|
|
113
|
+
var isToday = dayjs(time.start_at).isSame(currentTime, 'day');
|
|
114
|
+
var isStillWorking = dayjs(time.end_at).isAfter(currentTime);
|
|
115
|
+
return isToday && isStillWorking;
|
|
114
116
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
if (todayTimes.length === 0) {
|
|
118
|
+
console.log("[TimeslotUtils] \u8D44\u6E90 ".concat(_resource.id, "(").concat(_resource.main_field, ") \u4ECA\u65E5\u65E0\u53EF\u7528\u65F6\u95F4\u6BB5"));
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
var _iterator4 = _createForOfIteratorHelper(todayTimes),
|
|
122
|
+
_step4;
|
|
119
123
|
try {
|
|
120
124
|
var _loop = function _loop() {
|
|
121
|
-
var
|
|
122
|
-
var
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
125
|
+
var _time$event_list, _time$event_list2;
|
|
126
|
+
var time = _step4.value;
|
|
127
|
+
var workStartTime = dayjs(time.start_at);
|
|
128
|
+
var workEndTime = dayjs(time.end_at);
|
|
129
|
+
|
|
130
|
+
// 确定检查的起始时间(当前时间 vs 工作开始时间)
|
|
131
|
+
var nextAvailableTime = currentTime.isBefore(workStartTime) ? workStartTime : currentTime;
|
|
132
|
+
console.log("[TimeslotUtils] \u68C0\u67E5\u8D44\u6E90 ".concat(_resource.id, "(").concat(_resource.main_field, "):"), {
|
|
133
|
+
workTime: "".concat(workStartTime.format('HH:mm'), "-").concat(workEndTime.format('HH:mm')),
|
|
134
|
+
checkStartTime: nextAvailableTime.format('HH:mm:ss'),
|
|
135
|
+
eventCount: ((_time$event_list = time.event_list) === null || _time$event_list === void 0 ? void 0 : _time$event_list.length) || 0
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// 获取所有影响的预约事件(当前时间之后的)
|
|
139
|
+
var relevantEvents = ((_time$event_list2 = time.event_list) === null || _time$event_list2 === void 0 ? void 0 : _time$event_list2.filter(function (event) {
|
|
140
|
+
var eventEnd = dayjs(event.end_at);
|
|
141
|
+
return eventEnd.isAfter(nextAvailableTime);
|
|
142
|
+
})) || [];
|
|
143
|
+
|
|
144
|
+
// 按开始时间排序
|
|
145
|
+
relevantEvents.sort(function (a, b) {
|
|
146
|
+
return dayjs(a.start_at).diff(dayjs(b.start_at));
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// 检查从 nextAvailableTime 开始的可用性
|
|
150
|
+
var finalAvailableTime = nextAvailableTime;
|
|
151
|
+
var _iterator5 = _createForOfIteratorHelper(relevantEvents),
|
|
152
|
+
_step5;
|
|
153
|
+
try {
|
|
154
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
155
|
+
var _event = _step5.value;
|
|
156
|
+
var _eventStart = dayjs(_event.start_at);
|
|
157
|
+
var _eventEnd = dayjs(_event.end_at);
|
|
158
|
+
console.log("[TimeslotUtils] \u68C0\u67E5\u4E8B\u4EF6\u51B2\u7A81:", {
|
|
159
|
+
resourceId: _resource.id,
|
|
160
|
+
eventTime: "".concat(_eventStart.format('HH:mm'), "-").concat(_eventEnd.format('HH:mm')),
|
|
161
|
+
checkTime: finalAvailableTime.format('HH:mm:ss'),
|
|
162
|
+
pax: _event.pax || 1
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// 检查资源类型和容量
|
|
166
|
+
if (_resource.resourceType === 'single' || (_resource.capacity || 1) === 1) {
|
|
167
|
+
// 单人预约资源:检查时间冲突
|
|
168
|
+
if (finalAvailableTime.isBefore(_eventEnd) && _eventStart.isBefore(finalAvailableTime.add(30, 'minute'))) {
|
|
169
|
+
// 有冲突,使用事件结束时间
|
|
170
|
+
finalAvailableTime = _eventEnd;
|
|
171
|
+
console.log("[TimeslotUtils] \u53D1\u73B0\u65F6\u95F4\u51B2\u7A81\uFF0C\u8C03\u6574\u5230: ".concat(finalAvailableTime.format('HH:mm:ss')));
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
// 多人预约资源:检查容量
|
|
175
|
+
var totalCapacity = _resource.capacity || 0;
|
|
176
|
+
var currentUsedCapacity = countMap[_resource.id] || 0;
|
|
177
|
+
var eventUsedCapacity = _event.pax || 1;
|
|
178
|
+
|
|
179
|
+
// 如果在事件时间范围内,检查容量是否足够
|
|
180
|
+
if (finalAvailableTime.isBefore(_eventEnd) && _eventStart.isBefore(finalAvailableTime.add(30, 'minute'))) {
|
|
181
|
+
var totalRequiredCapacity = currentUsedCapacity + currentCapacity + eventUsedCapacity;
|
|
182
|
+
if (totalRequiredCapacity > totalCapacity) {
|
|
183
|
+
// 容量不足,使用事件结束时间
|
|
184
|
+
finalAvailableTime = _eventEnd;
|
|
185
|
+
console.log("[TimeslotUtils] \u5BB9\u91CF\u4E0D\u8DB3\uFF0C\u8C03\u6574\u5230: ".concat(finalAvailableTime.format('HH:mm:ss')));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
159
188
|
}
|
|
160
|
-
return 1; // break
|
|
161
189
|
}
|
|
190
|
+
|
|
191
|
+
// 确保可用时间在工作时间内
|
|
192
|
+
} catch (err) {
|
|
193
|
+
_iterator5.e(err);
|
|
194
|
+
} finally {
|
|
195
|
+
_iterator5.f();
|
|
196
|
+
}
|
|
197
|
+
if (finalAvailableTime.isAfter(workEndTime)) {
|
|
198
|
+
console.log("[TimeslotUtils] \u8D44\u6E90 ".concat(_resource.id, " \u53EF\u7528\u65F6\u95F4\u8D85\u51FA\u5DE5\u4F5C\u65F6\u95F4\uFF0C\u8DF3\u8FC7"));
|
|
199
|
+
return 0; // continue
|
|
162
200
|
}
|
|
201
|
+
console.log("[TimeslotUtils] \u8D44\u6E90 ".concat(_resource.id, "(").concat(_resource.main_field, ") \u6700\u5FEB\u53EF\u7528\u65F6\u95F4: ").concat(finalAvailableTime.format('HH:mm:ss')));
|
|
202
|
+
|
|
203
|
+
// 更新最快可用时间和资源
|
|
204
|
+
if (!fastestTime || finalAvailableTime.isBefore(fastestTime)) {
|
|
205
|
+
fastestTime = finalAvailableTime;
|
|
206
|
+
fastestResources = [_resource];
|
|
207
|
+
console.log("[TimeslotUtils] \u66F4\u65B0\u6700\u5FEB\u65F6\u95F4: ".concat(fastestTime.format('HH:mm:ss'), ", \u8D44\u6E90: ").concat(_resource.main_field));
|
|
208
|
+
} else if (finalAvailableTime.isSame(fastestTime)) {
|
|
209
|
+
fastestResources.push(_resource);
|
|
210
|
+
console.log("[TimeslotUtils] \u6DFB\u52A0\u76F8\u540C\u65F6\u95F4\u8D44\u6E90: ".concat(_resource.main_field));
|
|
211
|
+
}
|
|
212
|
+
return 1; // break
|
|
213
|
+
// 每个资源只需要计算一次
|
|
163
214
|
},
|
|
164
215
|
_ret;
|
|
165
|
-
for (
|
|
216
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
166
217
|
_ret = _loop();
|
|
167
218
|
if (_ret === 0) continue;
|
|
168
219
|
if (_ret === 1) break;
|
|
169
220
|
}
|
|
170
221
|
} catch (err) {
|
|
171
|
-
|
|
222
|
+
_iterator4.e(err);
|
|
172
223
|
} finally {
|
|
173
|
-
|
|
224
|
+
_iterator4.f();
|
|
174
225
|
}
|
|
175
226
|
}
|
|
176
227
|
|
|
@@ -180,31 +231,72 @@ export function findFastestAvailableResource(_ref2) {
|
|
|
180
231
|
} finally {
|
|
181
232
|
_iterator2.f();
|
|
182
233
|
}
|
|
183
|
-
if (!fastestTime || fastestResources.length === 0)
|
|
234
|
+
if (!fastestTime || fastestResources.length === 0) {
|
|
235
|
+
console.log('[TimeslotUtils] 未找到可用资源');
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
console.log("[TimeslotUtils] \u627E\u5230 ".concat(fastestResources.length, " \u4E2A\u6700\u5FEB\u53EF\u7528\u8D44\u6E90\uFF0C\u65F6\u95F4: ").concat(fastestTime.format('HH:mm:ss')));
|
|
184
239
|
|
|
185
240
|
// 如果只有一个最快可用的资源,直接返回
|
|
186
|
-
if (fastestResources.length === 1)
|
|
241
|
+
if (fastestResources.length === 1) {
|
|
242
|
+
console.log("[TimeslotUtils] \u8FD4\u56DE\u552F\u4E00\u6700\u5FEB\u8D44\u6E90: ".concat(fastestResources[0].main_field));
|
|
243
|
+
return fastestResources[0];
|
|
244
|
+
}
|
|
187
245
|
|
|
188
|
-
//
|
|
246
|
+
// 如果有多个最快可用的资源,选择空闲时间最长的资源
|
|
247
|
+
var selectedResource = fastestResources[0];
|
|
189
248
|
var maxIdleTime = 0;
|
|
190
|
-
|
|
249
|
+
console.log("[TimeslotUtils] \u6BD4\u8F83 ".concat(fastestResources.length, " \u4E2A\u8D44\u6E90\u7684\u7A7A\u95F2\u65F6\u95F4:"));
|
|
191
250
|
for (var _i2 = 0, _fastestResources = fastestResources; _i2 < _fastestResources.length; _i2++) {
|
|
251
|
+
var _workingTime$event_li;
|
|
192
252
|
var resource = _fastestResources[_i2];
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
253
|
+
// 找到该资源当天且还在工作的时间段
|
|
254
|
+
var workingTime = resource.times.find(function (time) {
|
|
255
|
+
var isToday = dayjs(time.start_at).isSame(fastestTime, 'day');
|
|
256
|
+
var isStillWorking = dayjs(time.end_at).isAfter(fastestTime);
|
|
257
|
+
return isToday && isStillWorking;
|
|
258
|
+
});
|
|
259
|
+
if (!workingTime) continue;
|
|
260
|
+
var workEndTime = dayjs(workingTime.end_at);
|
|
261
|
+
|
|
262
|
+
// 计算从最快可用时间到工作结束时间的空闲时长(分钟)
|
|
263
|
+
var totalIdleTime = workEndTime.diff(fastestTime, 'minute');
|
|
264
|
+
|
|
265
|
+
// 减去已有预约占用的时间
|
|
266
|
+
var relevantEvents = ((_workingTime$event_li = workingTime.event_list) === null || _workingTime$event_li === void 0 ? void 0 : _workingTime$event_li.filter(function (event) {
|
|
267
|
+
var eventStart = dayjs(event.start_at);
|
|
268
|
+
var eventEnd = dayjs(event.end_at);
|
|
269
|
+
// 只计算在最快可用时间之后的预约
|
|
270
|
+
return eventEnd.isAfter(fastestTime) && eventStart.isAfter(fastestTime);
|
|
271
|
+
})) || [];
|
|
272
|
+
var _iterator3 = _createForOfIteratorHelper(relevantEvents),
|
|
273
|
+
_step3;
|
|
274
|
+
try {
|
|
275
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
276
|
+
var event = _step3.value;
|
|
277
|
+
var eventStart = dayjs(event.start_at);
|
|
278
|
+
var eventEnd = dayjs(event.end_at);
|
|
279
|
+
var eventDuration = eventEnd.diff(eventStart, 'minute');
|
|
280
|
+
totalIdleTime -= eventDuration;
|
|
281
|
+
}
|
|
282
|
+
} catch (err) {
|
|
283
|
+
_iterator3.e(err);
|
|
284
|
+
} finally {
|
|
285
|
+
_iterator3.f();
|
|
286
|
+
}
|
|
287
|
+
console.log("[TimeslotUtils] \u8D44\u6E90 ".concat(resource.id, "(").concat(resource.main_field, "):"), {
|
|
288
|
+
工作结束时间: workEndTime.format('HH:mm'),
|
|
289
|
+
总工作时长: workEndTime.diff(fastestTime, 'minute') + '分钟',
|
|
290
|
+
预约占用时长: workEndTime.diff(fastestTime, 'minute') - totalIdleTime + '分钟',
|
|
291
|
+
实际空闲时长: totalIdleTime + '分钟'
|
|
202
292
|
});
|
|
203
|
-
if (
|
|
204
|
-
maxIdleTime =
|
|
293
|
+
if (totalIdleTime > maxIdleTime) {
|
|
294
|
+
maxIdleTime = totalIdleTime;
|
|
205
295
|
selectedResource = resource;
|
|
296
|
+
console.log("[TimeslotUtils] \u66F4\u65B0\u6700\u4F73\u9009\u62E9: ".concat(resource.main_field, " (\u7A7A\u95F2").concat(totalIdleTime, "\u5206\u949F)"));
|
|
206
297
|
}
|
|
207
298
|
}
|
|
299
|
+
console.log("[TimeslotUtils] \u6700\u7EC8\u9009\u62E9\u8D44\u6E90: ".concat(selectedResource.main_field, " (\u6700\u957F\u7A7A\u95F2").concat(maxIdleTime, "\u5206\u949F)"));
|
|
208
300
|
return selectedResource;
|
|
209
301
|
}
|
|
210
302
|
|
|
@@ -34,7 +34,7 @@ export declare class ShopDiscountImpl extends BaseModule implements Module {
|
|
|
34
34
|
discountList: Discount[];
|
|
35
35
|
};
|
|
36
36
|
setProductList(productList: Record<string, any>[]): void;
|
|
37
|
-
scanCode(code: string): Promise<{
|
|
37
|
+
scanCode(code: string, customerId?: number): Promise<{
|
|
38
38
|
isAvailable: boolean;
|
|
39
39
|
productList: Record<string, any>[];
|
|
40
40
|
discountList: Discount[];
|
|
@@ -304,14 +304,14 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
304
304
|
}, {
|
|
305
305
|
key: "scanCode",
|
|
306
306
|
value: function () {
|
|
307
|
-
var _scanCode = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(code) {
|
|
307
|
+
var _scanCode = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(code, customerId) {
|
|
308
308
|
var _this$store$discount3, resultDiscountList, rulesModule, withScanList, _ref3, newProductList, newDiscountList, isAvailable, _this$options$otherPa6;
|
|
309
309
|
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
|
|
310
310
|
while (1) switch (_context5.prev = _context5.next) {
|
|
311
311
|
case 0:
|
|
312
312
|
_context5.prev = 0;
|
|
313
313
|
_context5.next = 3;
|
|
314
|
-
return (_this$store$discount3 = this.store.discount) === null || _this$store$discount3 === void 0 ? void 0 : _this$store$discount3.batchSearch(code);
|
|
314
|
+
return (_this$store$discount3 = this.store.discount) === null || _this$store$discount3 === void 0 ? void 0 : _this$store$discount3.batchSearch(code, customerId);
|
|
315
315
|
case 3:
|
|
316
316
|
_context5.t0 = _context5.sent;
|
|
317
317
|
if (_context5.t0) {
|
|
@@ -393,7 +393,7 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
393
393
|
}
|
|
394
394
|
}, _callee5, this, [[0, 23]]);
|
|
395
395
|
}));
|
|
396
|
-
function scanCode(_x4) {
|
|
396
|
+
function scanCode(_x4, _x5) {
|
|
397
397
|
return _scanCode.apply(this, arguments);
|
|
398
398
|
}
|
|
399
399
|
return scanCode;
|
|
@@ -438,7 +438,7 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
438
438
|
}
|
|
439
439
|
}, _callee6, this);
|
|
440
440
|
}));
|
|
441
|
-
function emitDiscountListChange(
|
|
441
|
+
function emitDiscountListChange(_x6) {
|
|
442
442
|
return _emitDiscountListChange.apply(this, arguments);
|
|
443
443
|
}
|
|
444
444
|
return emitDiscountListChange;
|
|
@@ -574,7 +574,7 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
574
574
|
}
|
|
575
575
|
}, _callee7, this, [[0, 11]]);
|
|
576
576
|
}));
|
|
577
|
-
function getCustomerWallet(
|
|
577
|
+
function getCustomerWallet(_x7) {
|
|
578
578
|
return _getCustomerWallet.apply(this, arguments);
|
|
579
579
|
}
|
|
580
580
|
return getCustomerWallet;
|
|
@@ -634,7 +634,7 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
634
634
|
}
|
|
635
635
|
}, _callee8, this, [[0, 18]]);
|
|
636
636
|
}));
|
|
637
|
-
function loadPrepareConfig(
|
|
637
|
+
function loadPrepareConfig(_x8) {
|
|
638
638
|
return _loadPrepareConfig.apply(this, arguments);
|
|
639
639
|
}
|
|
640
640
|
return loadPrepareConfig;
|
|
@@ -20,8 +20,9 @@ export declare class DiscountModule extends BaseModule implements Module, Discou
|
|
|
20
20
|
with_discount_card: 0 | 1;
|
|
21
21
|
customer_id: number;
|
|
22
22
|
}): Promise<Discount[]>;
|
|
23
|
-
batchSearch(code: string): Promise<Discount[]>;
|
|
23
|
+
batchSearch(code: string, customerId?: number): Promise<Discount[]>;
|
|
24
24
|
filterEnabledDiscountList(discountList: Discount[]): Discount[];
|
|
25
|
+
private checkUsageCreditsLimit;
|
|
25
26
|
uniqueByProductId(discountList: Discount[]): Discount[];
|
|
26
27
|
filterDiscountListByProductIds(discountList: Discount[], productIds: number[]): Discount[];
|
|
27
28
|
calcDiscountApplicableProductTotalPrice(discount: Discount): number | undefined;
|
|
@@ -89,22 +89,64 @@ var DiscountModule = class extends import_BaseModule.BaseModule {
|
|
|
89
89
|
) || [];
|
|
90
90
|
return goodPassList;
|
|
91
91
|
}
|
|
92
|
-
async batchSearch(code) {
|
|
92
|
+
async batchSearch(code, customerId) {
|
|
93
93
|
const result = await this.request.get(`/machinecode/batch-search`, {
|
|
94
94
|
code,
|
|
95
95
|
translate_flag: 1,
|
|
96
96
|
tags: ["good_pass", "product_discount_card"],
|
|
97
97
|
available: 1,
|
|
98
|
-
relation_product: 1
|
|
98
|
+
relation_product: 1,
|
|
99
|
+
with: ["extensionData"],
|
|
100
|
+
order_behavior_count: 1,
|
|
101
|
+
order_behavior_count_customer_id: customerId || 1
|
|
99
102
|
});
|
|
100
103
|
const resultDiscountList = this.filterEnabledDiscountList((result == null ? void 0 : result.data) || []) || [];
|
|
101
104
|
return resultDiscountList;
|
|
102
105
|
}
|
|
103
106
|
filterEnabledDiscountList(discountList) {
|
|
104
107
|
return discountList.filter(
|
|
105
|
-
(discount) => discount.limit_status === "enable" && new import_decimal.default((discount == null ? void 0 : discount.par_value) || 0).minus(new import_decimal.default((discount == null ? void 0 : discount.used_par_value) || 0)).greaterThan(0)
|
|
108
|
+
(discount) => discount.limit_status === "enable" && new import_decimal.default((discount == null ? void 0 : discount.par_value) || 0).minus(new import_decimal.default((discount == null ? void 0 : discount.used_par_value) || 0)).greaterThan(0) && this.checkUsageCreditsLimit(discount)
|
|
106
109
|
);
|
|
107
110
|
}
|
|
111
|
+
// 检查使用次数限制
|
|
112
|
+
checkUsageCreditsLimit(discount) {
|
|
113
|
+
if (!discount.extension_data || discount.extension_data.length === 0) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
const usageCreditsData = discount.extension_data.find(
|
|
117
|
+
(data) => data.field_key === "usage_credits"
|
|
118
|
+
);
|
|
119
|
+
if (!usageCreditsData) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
const value = usageCreditsData.value;
|
|
123
|
+
if (value.total_credits && value.total_credits > 0) {
|
|
124
|
+
if ((discount.total_order_behavior_count || 0) >= value.total_credits) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (value.per_user_limit && value.per_user_limit > 0) {
|
|
129
|
+
if ((discount.customer_order_behavior_count || 0) >= value.per_user_limit) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (value.max_per_day && value.max_per_day > 0) {
|
|
134
|
+
if ((discount.today_order_behavior_count || 0) >= value.max_per_day) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (value.max_per_week && value.max_per_week > 0) {
|
|
139
|
+
if ((discount.week_order_behavior_count || 0) >= value.max_per_week) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (value.max_per_month && value.max_per_month > 0) {
|
|
144
|
+
if ((discount.month_order_behavior_count || 0) >= value.max_per_month) {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
108
150
|
// 根据productIds去重
|
|
109
151
|
uniqueByProductId(discountList) {
|
|
110
152
|
return (0, import_utils.uniqueById)(discountList, "product_id");
|
|
@@ -36,6 +36,25 @@ interface ApplicableProductDetails {
|
|
|
36
36
|
title?: string;
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
+
interface UsageCreditsValue {
|
|
40
|
+
total_credits: number;
|
|
41
|
+
per_user_limit: number;
|
|
42
|
+
max_per_day: number;
|
|
43
|
+
max_per_week: number;
|
|
44
|
+
max_per_month: number;
|
|
45
|
+
}
|
|
46
|
+
interface ExtensionData {
|
|
47
|
+
id: number;
|
|
48
|
+
shop_id: number;
|
|
49
|
+
product_id: number;
|
|
50
|
+
field_id: number;
|
|
51
|
+
field_key: string;
|
|
52
|
+
type: string;
|
|
53
|
+
value: UsageCreditsValue | Record<string, any> | string | number | boolean | any[];
|
|
54
|
+
created_at: string | null;
|
|
55
|
+
updated_at: string | null;
|
|
56
|
+
deleted_at: string | null;
|
|
57
|
+
}
|
|
39
58
|
export interface Discount {
|
|
40
59
|
id: number;
|
|
41
60
|
product_name: string;
|
|
@@ -70,6 +89,12 @@ export interface Discount {
|
|
|
70
89
|
appliedProductDetails: ApplicableProductDetails[];
|
|
71
90
|
isDisabledForProductUsed?: boolean;
|
|
72
91
|
amount?: number;
|
|
92
|
+
extension_data?: ExtensionData[];
|
|
93
|
+
total_order_behavior_count?: number;
|
|
94
|
+
today_order_behavior_count?: number;
|
|
95
|
+
week_order_behavior_count?: number;
|
|
96
|
+
month_order_behavior_count?: number;
|
|
97
|
+
customer_order_behavior_count?: number;
|
|
73
98
|
}
|
|
74
99
|
export interface DiscountState {
|
|
75
100
|
discountList: Discount[];
|
|
@@ -694,7 +694,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
|
|
|
694
694
|
}
|
|
695
695
|
if (!allOriginResources.length) {
|
|
696
696
|
const dateList = this.store.date.getDateList();
|
|
697
|
-
dateList.forEach((n) => {
|
|
697
|
+
dateList == null ? void 0 : dateList.forEach((n) => {
|
|
698
698
|
if (n.resource)
|
|
699
699
|
allOriginResources.push(...n.resource);
|
|
700
700
|
});
|
|
@@ -79,78 +79,132 @@ function findFastestAvailableResource({
|
|
|
79
79
|
currentCapacity = 1,
|
|
80
80
|
countMap = {}
|
|
81
81
|
}) {
|
|
82
|
-
var _a, _b;
|
|
82
|
+
var _a, _b, _c;
|
|
83
83
|
const currentTime = (0, import_dayjs.default)();
|
|
84
84
|
let fastestTime = null;
|
|
85
85
|
let fastestResources = [];
|
|
86
|
+
console.log("[TimeslotUtils] 查找最快可用资源:", {
|
|
87
|
+
currentTime: currentTime.format("YYYY-MM-DD HH:mm:ss"),
|
|
88
|
+
resourceCount: resources.length,
|
|
89
|
+
currentCapacity,
|
|
90
|
+
countMap
|
|
91
|
+
});
|
|
86
92
|
for (const resource of resources) {
|
|
87
93
|
const todayTimes = resource.times.filter((time) => {
|
|
88
|
-
|
|
94
|
+
const isToday = (0, import_dayjs.default)(time.start_at).isSame(currentTime, "day");
|
|
95
|
+
const isStillWorking = (0, import_dayjs.default)(time.end_at).isAfter(currentTime);
|
|
96
|
+
return isToday && isStillWorking;
|
|
89
97
|
});
|
|
90
|
-
if (todayTimes.length === 0)
|
|
98
|
+
if (todayTimes.length === 0) {
|
|
99
|
+
console.log(`[TimeslotUtils] 资源 ${resource.id}(${resource.main_field}) 今日无可用时间段`);
|
|
91
100
|
continue;
|
|
92
|
-
|
|
93
|
-
return (0, import_dayjs.default)(a.start_at).diff((0, import_dayjs.default)(b.start_at));
|
|
94
|
-
});
|
|
101
|
+
}
|
|
95
102
|
for (const time of todayTimes) {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
const workStartTime = (0, import_dayjs.default)(time.start_at);
|
|
104
|
+
const workEndTime = (0, import_dayjs.default)(time.end_at);
|
|
105
|
+
let nextAvailableTime = currentTime.isBefore(workStartTime) ? workStartTime : currentTime;
|
|
106
|
+
console.log(`[TimeslotUtils] 检查资源 ${resource.id}(${resource.main_field}):`, {
|
|
107
|
+
workTime: `${workStartTime.format("HH:mm")}-${workEndTime.format("HH:mm")}`,
|
|
108
|
+
checkStartTime: nextAvailableTime.format("HH:mm:ss"),
|
|
109
|
+
eventCount: ((_a = time.event_list) == null ? void 0 : _a.length) || 0
|
|
110
|
+
});
|
|
111
|
+
const relevantEvents = ((_b = time.event_list) == null ? void 0 : _b.filter((event) => {
|
|
112
|
+
const eventEnd = (0, import_dayjs.default)(event.end_at);
|
|
113
|
+
return eventEnd.isAfter(nextAvailableTime);
|
|
114
|
+
})) || [];
|
|
115
|
+
relevantEvents.sort(
|
|
116
|
+
(a, b) => (0, import_dayjs.default)(a.start_at).diff((0, import_dayjs.default)(b.start_at))
|
|
117
|
+
);
|
|
118
|
+
let finalAvailableTime = nextAvailableTime;
|
|
119
|
+
for (const event of relevantEvents) {
|
|
120
|
+
const eventStart = (0, import_dayjs.default)(event.start_at);
|
|
121
|
+
const eventEnd = (0, import_dayjs.default)(event.end_at);
|
|
122
|
+
console.log(`[TimeslotUtils] 检查事件冲突:`, {
|
|
123
|
+
resourceId: resource.id,
|
|
124
|
+
eventTime: `${eventStart.format("HH:mm")}-${eventEnd.format("HH:mm")}`,
|
|
125
|
+
checkTime: finalAvailableTime.format("HH:mm:ss"),
|
|
126
|
+
pax: event.pax || 1
|
|
102
127
|
});
|
|
103
|
-
if (
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
} else if (startTime.isBefore(fastestTime)) {
|
|
108
|
-
fastestTime = startTime;
|
|
109
|
-
fastestResources = [resource];
|
|
128
|
+
if (resource.resourceType === "single" || (resource.capacity || 1) === 1) {
|
|
129
|
+
if (finalAvailableTime.isBefore(eventEnd) && eventStart.isBefore(finalAvailableTime.add(30, "minute"))) {
|
|
130
|
+
finalAvailableTime = eventEnd;
|
|
131
|
+
console.log(`[TimeslotUtils] 发现时间冲突,调整到: ${finalAvailableTime.format("HH:mm:ss")}`);
|
|
110
132
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
fastestTime = startTime;
|
|
122
|
-
fastestResources.push(resource);
|
|
123
|
-
} else if (startTime.isBefore(fastestTime)) {
|
|
124
|
-
fastestTime = startTime;
|
|
125
|
-
fastestResources = [resource];
|
|
133
|
+
} else {
|
|
134
|
+
const totalCapacity = resource.capacity || 0;
|
|
135
|
+
const currentUsedCapacity = countMap[resource.id] || 0;
|
|
136
|
+
const eventUsedCapacity = event.pax || 1;
|
|
137
|
+
if (finalAvailableTime.isBefore(eventEnd) && eventStart.isBefore(finalAvailableTime.add(30, "minute"))) {
|
|
138
|
+
const totalRequiredCapacity = currentUsedCapacity + currentCapacity + eventUsedCapacity;
|
|
139
|
+
if (totalRequiredCapacity > totalCapacity) {
|
|
140
|
+
finalAvailableTime = eventEnd;
|
|
141
|
+
console.log(`[TimeslotUtils] 容量不足,调整到: ${finalAvailableTime.format("HH:mm:ss")}`);
|
|
142
|
+
}
|
|
126
143
|
}
|
|
127
|
-
break;
|
|
128
144
|
}
|
|
129
145
|
}
|
|
146
|
+
if (finalAvailableTime.isAfter(workEndTime)) {
|
|
147
|
+
console.log(`[TimeslotUtils] 资源 ${resource.id} 可用时间超出工作时间,跳过`);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
console.log(`[TimeslotUtils] 资源 ${resource.id}(${resource.main_field}) 最快可用时间: ${finalAvailableTime.format("HH:mm:ss")}`);
|
|
151
|
+
if (!fastestTime || finalAvailableTime.isBefore(fastestTime)) {
|
|
152
|
+
fastestTime = finalAvailableTime;
|
|
153
|
+
fastestResources = [resource];
|
|
154
|
+
console.log(`[TimeslotUtils] 更新最快时间: ${fastestTime.format("HH:mm:ss")}, 资源: ${resource.main_field}`);
|
|
155
|
+
} else if (finalAvailableTime.isSame(fastestTime)) {
|
|
156
|
+
fastestResources.push(resource);
|
|
157
|
+
console.log(`[TimeslotUtils] 添加相同时间资源: ${resource.main_field}`);
|
|
158
|
+
}
|
|
159
|
+
break;
|
|
130
160
|
}
|
|
131
161
|
}
|
|
132
|
-
if (!fastestTime || fastestResources.length === 0)
|
|
162
|
+
if (!fastestTime || fastestResources.length === 0) {
|
|
163
|
+
console.log("[TimeslotUtils] 未找到可用资源");
|
|
133
164
|
return null;
|
|
134
|
-
|
|
165
|
+
}
|
|
166
|
+
console.log(`[TimeslotUtils] 找到 ${fastestResources.length} 个最快可用资源,时间: ${fastestTime.format("HH:mm:ss")}`);
|
|
167
|
+
if (fastestResources.length === 1) {
|
|
168
|
+
console.log(`[TimeslotUtils] 返回唯一最快资源: ${fastestResources[0].main_field}`);
|
|
135
169
|
return fastestResources[0];
|
|
170
|
+
}
|
|
171
|
+
let selectedResource = fastestResources[0];
|
|
136
172
|
let maxIdleTime = 0;
|
|
137
|
-
|
|
173
|
+
console.log(`[TimeslotUtils] 比较 ${fastestResources.length} 个资源的空闲时间:`);
|
|
138
174
|
for (const resource of fastestResources) {
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
175
|
+
const workingTime = resource.times.find((time) => {
|
|
176
|
+
const isToday = (0, import_dayjs.default)(time.start_at).isSame(fastestTime, "day");
|
|
177
|
+
const isStillWorking = (0, import_dayjs.default)(time.end_at).isAfter(fastestTime);
|
|
178
|
+
return isToday && isStillWorking;
|
|
179
|
+
});
|
|
180
|
+
if (!workingTime)
|
|
181
|
+
continue;
|
|
182
|
+
const workEndTime = (0, import_dayjs.default)(workingTime.end_at);
|
|
183
|
+
let totalIdleTime = workEndTime.diff(fastestTime, "minute");
|
|
184
|
+
const relevantEvents = ((_c = workingTime.event_list) == null ? void 0 : _c.filter((event) => {
|
|
185
|
+
const eventStart = (0, import_dayjs.default)(event.start_at);
|
|
186
|
+
const eventEnd = (0, import_dayjs.default)(event.end_at);
|
|
187
|
+
return eventEnd.isAfter(fastestTime) && eventStart.isAfter(fastestTime);
|
|
188
|
+
})) || [];
|
|
189
|
+
for (const event of relevantEvents) {
|
|
190
|
+
const eventStart = (0, import_dayjs.default)(event.start_at);
|
|
191
|
+
const eventEnd = (0, import_dayjs.default)(event.end_at);
|
|
192
|
+
const eventDuration = eventEnd.diff(eventStart, "minute");
|
|
193
|
+
totalIdleTime -= eventDuration;
|
|
194
|
+
}
|
|
195
|
+
console.log(`[TimeslotUtils] 资源 ${resource.id}(${resource.main_field}):`, {
|
|
196
|
+
工作结束时间: workEndTime.format("HH:mm"),
|
|
197
|
+
总工作时长: workEndTime.diff(fastestTime, "minute") + "分钟",
|
|
198
|
+
预约占用时长: workEndTime.diff(fastestTime, "minute") - totalIdleTime + "分钟",
|
|
199
|
+
实际空闲时长: totalIdleTime + "分钟"
|
|
148
200
|
});
|
|
149
|
-
if (
|
|
150
|
-
maxIdleTime =
|
|
201
|
+
if (totalIdleTime > maxIdleTime) {
|
|
202
|
+
maxIdleTime = totalIdleTime;
|
|
151
203
|
selectedResource = resource;
|
|
204
|
+
console.log(`[TimeslotUtils] 更新最佳选择: ${resource.main_field} (空闲${totalIdleTime}分钟)`);
|
|
152
205
|
}
|
|
153
206
|
}
|
|
207
|
+
console.log(`[TimeslotUtils] 最终选择资源: ${selectedResource.main_field} (最长空闲${maxIdleTime}分钟)`);
|
|
154
208
|
return selectedResource;
|
|
155
209
|
}
|
|
156
210
|
function filterConditionTimeSlots(times, startTime, endTime) {
|
|
@@ -34,7 +34,7 @@ export declare class ShopDiscountImpl extends BaseModule implements Module {
|
|
|
34
34
|
discountList: Discount[];
|
|
35
35
|
};
|
|
36
36
|
setProductList(productList: Record<string, any>[]): void;
|
|
37
|
-
scanCode(code: string): Promise<{
|
|
37
|
+
scanCode(code: string, customerId?: number): Promise<{
|
|
38
38
|
isAvailable: boolean;
|
|
39
39
|
productList: Record<string, any>[];
|
|
40
40
|
discountList: Discount[];
|
|
@@ -198,10 +198,10 @@ var ShopDiscountImpl = class extends import_BaseModule.BaseModule {
|
|
|
198
198
|
this.store.productList = productList;
|
|
199
199
|
}
|
|
200
200
|
// 扫码输入code
|
|
201
|
-
async scanCode(code) {
|
|
201
|
+
async scanCode(code, customerId) {
|
|
202
202
|
var _a, _b;
|
|
203
203
|
try {
|
|
204
|
-
const resultDiscountList = await ((_a = this.store.discount) == null ? void 0 : _a.batchSearch(code)) || [];
|
|
204
|
+
const resultDiscountList = await ((_a = this.store.discount) == null ? void 0 : _a.batchSearch(code, customerId)) || [];
|
|
205
205
|
const rulesModule = this.store.rules;
|
|
206
206
|
if (!rulesModule) {
|
|
207
207
|
return {
|