@pisell/pisellos 2.3.137 → 2.3.138
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/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/modules/ResourcePlanner/planner.js +10 -8
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/RegisterAndLogin/config.js +33 -11
- package/dist/solution/RegisterAndLogin/index.d.ts +2 -0
- package/dist/solution/RegisterAndLogin/index.js +1 -1
- package/dist/solution/RegisterAndLogin/utils.d.ts +12 -4
- package/dist/solution/RegisterAndLogin/utils.js +36 -16
- package/dist/solution/Sales/index.d.ts +2 -0
- package/dist/solution/Sales/index.js +15 -1
- package/dist/solution/UnifiedBookingSales/index.js +3 -4
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/ResourcePlanner/planner.js +10 -8
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/RegisterAndLogin/config.js +32 -11
- package/lib/solution/RegisterAndLogin/index.d.ts +2 -0
- package/lib/solution/RegisterAndLogin/index.js +9 -1
- package/lib/solution/RegisterAndLogin/utils.d.ts +12 -4
- package/lib/solution/RegisterAndLogin/utils.js +24 -17
- package/lib/solution/Sales/index.d.ts +2 -0
- package/lib/solution/Sales/index.js +10 -1
- package/lib/solution/UnifiedBookingSales/index.js +3 -4
- package/package.json +1 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// 导出评估器
|
|
2
|
+
export { PromotionEvaluator } from "./evaluator";
|
|
3
|
+
|
|
4
|
+
// 导出适配器
|
|
5
|
+
export { PromotionAdapter } from "./adapter";
|
|
6
|
+
export { default } from "./adapter";
|
|
7
|
+
|
|
8
|
+
// 导出策略配置示例常量
|
|
9
|
+
export { X_ITEMS_FOR_Y_PRICE_STRATEGY, BUY_X_GET_Y_FREE_STRATEGY, ITEM_REWARD_STRATEGY } from "./examples";
|
|
@@ -436,7 +436,7 @@ function normalizeOccupancy(occupancy, coverage, timezoneName, fixedOffsetMinute
|
|
|
436
436
|
}
|
|
437
437
|
function normalizeRequirementGroup(product, requirementGroup) {
|
|
438
438
|
var _requirementGroup$for;
|
|
439
|
-
var resourceType = 'single';
|
|
439
|
+
var resourceType = requirementGroup.resourceType === 'multiple' || requirementGroup.resourceType === 'capacity' ? requirementGroup.resourceType : 'single';
|
|
440
440
|
var required = requirementGroup.required !== false;
|
|
441
441
|
var min = required ? 1 : 0;
|
|
442
442
|
return _objectSpread(_objectSpread({}, requirementGroup), {}, {
|
|
@@ -482,7 +482,7 @@ function normalizeProducts(products) {
|
|
|
482
482
|
function normalizeResources(resources) {
|
|
483
483
|
return resources.map(function (resource) {
|
|
484
484
|
return _objectSpread(_objectSpread({}, resource), {}, {
|
|
485
|
-
resourceType: 'single',
|
|
485
|
+
resourceType: resource.resourceType === 'multiple' || resource.resourceType === 'capacity' ? resource.resourceType : 'single',
|
|
486
486
|
capacity: Math.max(1, Number(resource.capacity || 1) || 1),
|
|
487
487
|
windows: (resource.windows || []).map(function (window) {
|
|
488
488
|
return _objectSpread({}, window);
|
|
@@ -637,7 +637,8 @@ function buildCells(projection) {
|
|
|
637
637
|
var usedCapacity = segmentOccupancies.reduce(function (sum, occupancy) {
|
|
638
638
|
return sum + Math.max(1, Number(occupancy.pax || 1) || 1);
|
|
639
639
|
}, 0);
|
|
640
|
-
|
|
640
|
+
// 预约模式来自商品资源组;v2 资源记录可能不包含 type。
|
|
641
|
+
var remainingCapacity = requirementGroup.resourceType === 'single' && segmentOccupancies.length > 0 ? 0 : Math.max(0, resource.capacity - usedCapacity);
|
|
641
642
|
var requiredCapacity = resolveRequiredCapacity(requirementGroup, product);
|
|
642
643
|
var reasonCodes = Array.from(new Set(segmentOccupancies.flatMap(function (occupancy) {
|
|
643
644
|
var source = occupancy.source || 'remote';
|
|
@@ -671,7 +672,7 @@ function buildCells(projection) {
|
|
|
671
672
|
requirementFormId: requirementGroup.formId,
|
|
672
673
|
resourceId: resource.id,
|
|
673
674
|
resourceName: resource.name,
|
|
674
|
-
resourceType:
|
|
675
|
+
resourceType: requirementGroup.resourceType,
|
|
675
676
|
startAt: formatDateTime(start, timezoneName, fixedOffsetMinutes),
|
|
676
677
|
endAt: formatDateTime(end, timezoneName, fixedOffsetMinutes),
|
|
677
678
|
date: formatDate(start, timezoneName),
|
|
@@ -679,7 +680,7 @@ function buildCells(projection) {
|
|
|
679
680
|
endTime: formatTime(end, timezoneName),
|
|
680
681
|
timezone: projection.meta.timezone,
|
|
681
682
|
status: status,
|
|
682
|
-
//
|
|
683
|
+
// capacity 表示人数;single 被占用时不再贡献可用容量。
|
|
683
684
|
remainingCapacity: remainingCapacity,
|
|
684
685
|
maxCapacity: resource.capacity,
|
|
685
686
|
reasonCodes: Array.from(new Set(reasonCodes)),
|
|
@@ -1739,7 +1740,7 @@ function evaluateCandidate(projection, candidate, request) {
|
|
|
1739
1740
|
resourceName: resource.name,
|
|
1740
1741
|
resourceFormId: resource.formId,
|
|
1741
1742
|
policyId: (_resource$raw = resource.raw) === null || _resource$raw === void 0 ? void 0 : _resource$raw.policy_id,
|
|
1742
|
-
resourceType:
|
|
1743
|
+
resourceType: requirementGroup.resourceType,
|
|
1743
1744
|
status: _isPast ? 'past' : 'unavailable',
|
|
1744
1745
|
maxPartySize: 0,
|
|
1745
1746
|
reasonCodes: _isPast ? ['past'] : [].concat(_toConsumableArray(isExcludedScheduleDate ? ['schedule_excluded_date'] : []), ['outside_resource_window'])
|
|
@@ -1763,7 +1764,7 @@ function evaluateCandidate(projection, candidate, request) {
|
|
|
1763
1764
|
resourceName: resource.name,
|
|
1764
1765
|
resourceFormId: resource.formId,
|
|
1765
1766
|
policyId: (_resource$raw2 = resource.raw) === null || _resource$raw2 === void 0 ? void 0 : _resource$raw2.policy_id,
|
|
1766
|
-
resourceType:
|
|
1767
|
+
resourceType: requirementGroup.resourceType,
|
|
1767
1768
|
status: status,
|
|
1768
1769
|
remainingCapacity: remainingCapacity,
|
|
1769
1770
|
maxCapacity: maxCapacity,
|
|
@@ -2330,7 +2331,8 @@ export function validateAvailabilitySelection(projection, params) {
|
|
|
2330
2331
|
var remainingCapacity = matchedCell === null || matchedCell === void 0 ? void 0 : matchedCell.remainingCapacity;
|
|
2331
2332
|
if (option && (option.status === 'available' || option.status === 'limited') && remainingCapacity !== undefined) {
|
|
2332
2333
|
var capacityPerBooking = normalizedPartySize !== null && normalizedPartySize !== void 0 ? normalizedPartySize : 1;
|
|
2333
|
-
var
|
|
2334
|
+
var capacityQuantity = Math.max(0, Math.floor(remainingCapacity / capacityPerBooking));
|
|
2335
|
+
var availableQuantity = matchedGroup.resourceType === 'single' ? Math.min(1, capacityQuantity) : capacityQuantity;
|
|
2334
2336
|
if (normalizedBookingCount > availableQuantity) {
|
|
2335
2337
|
conflicts.push({
|
|
2336
2338
|
code: 'resource_capacity_exceeded',
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 | 2 | 1 |
|
|
329
|
+
weekNum: 0 | 2 | 1 | 3 | 4 | 5 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -733,6 +733,16 @@ var defaultConfig = {
|
|
|
733
733
|
/**
|
|
734
734
|
* webpos 渠道配置
|
|
735
735
|
*/
|
|
736
|
+
var webposPasswordResetOptions = {
|
|
737
|
+
prefix: false,
|
|
738
|
+
isDefaultSaasDomain: true,
|
|
739
|
+
cache: false,
|
|
740
|
+
noToast: true,
|
|
741
|
+
headers: {
|
|
742
|
+
Accept: 'application/json',
|
|
743
|
+
'Content-Type': 'application/json'
|
|
744
|
+
}
|
|
745
|
+
};
|
|
736
746
|
var webposConfig = {
|
|
737
747
|
sendEmailVerificationCode: {
|
|
738
748
|
url: '/auth/email/register-code',
|
|
@@ -885,15 +895,23 @@ var webposConfig = {
|
|
|
885
895
|
}
|
|
886
896
|
},
|
|
887
897
|
checkEmailCode: {
|
|
888
|
-
url: '/
|
|
889
|
-
method: '
|
|
898
|
+
url: '/tenant/account/reset-password/email-code/verify',
|
|
899
|
+
method: 'POST',
|
|
890
900
|
transformParams: function transformParams(params) {
|
|
891
901
|
return {
|
|
892
902
|
email: params.email,
|
|
893
|
-
code: params.code
|
|
894
|
-
action: params.action
|
|
903
|
+
code: params.code
|
|
895
904
|
};
|
|
896
|
-
}
|
|
905
|
+
},
|
|
906
|
+
// SaaS 成功时 data 为 null,统一为既有验证码校验返回结构。
|
|
907
|
+
transformResponse: function transformResponse(response) {
|
|
908
|
+
return (response === null || response === void 0 ? void 0 : response.status) === true ? _objectSpread(_objectSpread({}, response), {}, {
|
|
909
|
+
data: {
|
|
910
|
+
valid: true
|
|
911
|
+
}
|
|
912
|
+
}) : response;
|
|
913
|
+
},
|
|
914
|
+
options: webposPasswordResetOptions
|
|
897
915
|
},
|
|
898
916
|
checkMobileCode: {
|
|
899
917
|
url: '/auth/mobile/check-mobile-code',
|
|
@@ -919,13 +937,14 @@ var webposConfig = {
|
|
|
919
937
|
}
|
|
920
938
|
},
|
|
921
939
|
sendPasswordResetEmail: {
|
|
922
|
-
url: '/
|
|
923
|
-
method: '
|
|
940
|
+
url: '/tenant/account/reset-password/email-code/send',
|
|
941
|
+
method: 'POST',
|
|
924
942
|
transformParams: function transformParams(params) {
|
|
925
943
|
return {
|
|
926
944
|
email: params.email
|
|
927
945
|
};
|
|
928
|
-
}
|
|
946
|
+
},
|
|
947
|
+
options: webposPasswordResetOptions
|
|
929
948
|
},
|
|
930
949
|
sendPasswordResetSms: {
|
|
931
950
|
url: '/auth/mobile/sms-forget',
|
|
@@ -966,15 +985,18 @@ var webposConfig = {
|
|
|
966
985
|
}
|
|
967
986
|
},
|
|
968
987
|
resetPasswordByEmail: {
|
|
969
|
-
url: '/
|
|
988
|
+
url: '/tenant/account/reset-password/email-code',
|
|
970
989
|
method: 'POST',
|
|
971
990
|
transformParams: function transformParams(params) {
|
|
972
991
|
return {
|
|
973
992
|
email: params.email,
|
|
974
993
|
password: params.password,
|
|
975
|
-
code: params.code
|
|
994
|
+
code: params.code,
|
|
995
|
+
// 页面先校验两次输入完全一致,SDK 保持原有重置参数。
|
|
996
|
+
password_confirmation: params.password
|
|
976
997
|
};
|
|
977
|
-
}
|
|
998
|
+
},
|
|
999
|
+
options: webposPasswordResetOptions
|
|
978
1000
|
},
|
|
979
1001
|
resetPasswordByPhone: {
|
|
980
1002
|
url: '/auth/mobile/reset-password',
|
|
@@ -4,6 +4,8 @@ import { RegisterParams, LoginParams, OAuthLoginParams, SendVerificationCodePara
|
|
|
4
4
|
import { ApiCaller } from './config';
|
|
5
5
|
export * from './types';
|
|
6
6
|
export * from './config';
|
|
7
|
+
export { validatePassword } from './utils';
|
|
8
|
+
export type { PasswordValidationOptions } from './utils';
|
|
7
9
|
/**
|
|
8
10
|
* 注册登录解决方案实现
|
|
9
11
|
*/
|
|
@@ -22,7 +22,7 @@ import { RegisterAndLoginHooks, VerificationCodeType, VerificationPurpose } from
|
|
|
22
22
|
import { createApiCaller } from "./config";
|
|
23
23
|
export * from "./types";
|
|
24
24
|
export * from "./config";
|
|
25
|
-
|
|
25
|
+
export { validatePassword } from "./utils";
|
|
26
26
|
/**
|
|
27
27
|
* 注册登录解决方案实现
|
|
28
28
|
*/
|
|
@@ -10,10 +10,18 @@ export declare function validateEmail(email: string): boolean;
|
|
|
10
10
|
* 验证手机号格式(支持多种国际格式)
|
|
11
11
|
*/
|
|
12
12
|
export declare function validatePhone(phone: string): boolean;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
export interface PasswordValidationOptions {
|
|
14
|
+
minLength?: number;
|
|
15
|
+
maxLength?: number;
|
|
16
|
+
requireLowercase?: boolean;
|
|
17
|
+
requireUppercase?: boolean;
|
|
18
|
+
requireNumber?: boolean;
|
|
19
|
+
requireSpecialCharacters?: boolean;
|
|
20
|
+
specialCharactersPattern?: RegExp;
|
|
21
|
+
messages?: Partial<Record<'minLength' | 'maxLength' | 'requireLowercase' | 'requireUppercase' | 'requireNumber' | 'requireSpecialCharacters', string>>;
|
|
22
|
+
}
|
|
23
|
+
/** 验证密码强度;不传 options 时保持原有规则与返回格式。 */
|
|
24
|
+
export declare function validatePassword(password: string, options?: PasswordValidationOptions): {
|
|
17
25
|
isValid: boolean;
|
|
18
26
|
errors: string[];
|
|
19
27
|
};
|
|
@@ -33,29 +33,49 @@ export function validatePhone(phone) {
|
|
|
33
33
|
var phoneRegex = /^(\+\d{1,3}[- ]?)?\d{10,14}$/;
|
|
34
34
|
return phoneRegex.test(cleanPhone);
|
|
35
35
|
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 验证密码强度
|
|
39
|
-
*/
|
|
36
|
+
/** 验证密码强度;不传 options 时保持原有规则与返回格式。 */
|
|
40
37
|
export function validatePassword(password) {
|
|
38
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
41
39
|
var errors = [];
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
var _options$minLength = options.minLength,
|
|
41
|
+
minLength = _options$minLength === void 0 ? 8 : _options$minLength,
|
|
42
|
+
_options$maxLength = options.maxLength,
|
|
43
|
+
maxLength = _options$maxLength === void 0 ? 128 : _options$maxLength,
|
|
44
|
+
_options$requireLower = options.requireLowercase,
|
|
45
|
+
requireLowercase = _options$requireLower === void 0 ? true : _options$requireLower,
|
|
46
|
+
_options$requireUpper = options.requireUppercase,
|
|
47
|
+
requireUppercase = _options$requireUpper === void 0 ? true : _options$requireUpper,
|
|
48
|
+
_options$requireNumbe = options.requireNumber,
|
|
49
|
+
requireNumber = _options$requireNumbe === void 0 ? true : _options$requireNumbe,
|
|
50
|
+
_options$requireSpeci = options.requireSpecialCharacters,
|
|
51
|
+
requireSpecialCharacters = _options$requireSpeci === void 0 ? true : _options$requireSpeci,
|
|
52
|
+
_options$specialChara = options.specialCharactersPattern,
|
|
53
|
+
specialCharactersPattern = _options$specialChara === void 0 ? /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/ : _options$specialChara,
|
|
54
|
+
_options$messages = options.messages,
|
|
55
|
+
messages = _options$messages === void 0 ? {} : _options$messages;
|
|
56
|
+
if (password.length < minLength) {
|
|
57
|
+
var _messages$minLength;
|
|
58
|
+
errors.push((_messages$minLength = messages.minLength) !== null && _messages$minLength !== void 0 ? _messages$minLength : "\u5BC6\u7801\u957F\u5EA6\u81F3\u5C11\u4E3A".concat(minLength, "\u4F4D"));
|
|
44
59
|
}
|
|
45
|
-
if (password.length >
|
|
46
|
-
|
|
60
|
+
if (password.length > maxLength) {
|
|
61
|
+
var _messages$maxLength;
|
|
62
|
+
errors.push((_messages$maxLength = messages.maxLength) !== null && _messages$maxLength !== void 0 ? _messages$maxLength : "\u5BC6\u7801\u957F\u5EA6\u4E0D\u80FD\u8D85\u8FC7".concat(maxLength, "\u4F4D"));
|
|
47
63
|
}
|
|
48
|
-
if (!/[a-z]/.test(password)) {
|
|
49
|
-
|
|
64
|
+
if (requireLowercase && !/[a-z]/.test(password)) {
|
|
65
|
+
var _messages$requireLowe;
|
|
66
|
+
errors.push((_messages$requireLowe = messages.requireLowercase) !== null && _messages$requireLowe !== void 0 ? _messages$requireLowe : '密码必须包含至少一个小写字母');
|
|
50
67
|
}
|
|
51
|
-
if (!/[A-Z]/.test(password)) {
|
|
52
|
-
|
|
68
|
+
if (requireUppercase && !/[A-Z]/.test(password)) {
|
|
69
|
+
var _messages$requireUppe;
|
|
70
|
+
errors.push((_messages$requireUppe = messages.requireUppercase) !== null && _messages$requireUppe !== void 0 ? _messages$requireUppe : '密码必须包含至少一个大写字母');
|
|
53
71
|
}
|
|
54
|
-
if (!/\d/.test(password)) {
|
|
55
|
-
|
|
72
|
+
if (requireNumber && !/\d/.test(password)) {
|
|
73
|
+
var _messages$requireNumb;
|
|
74
|
+
errors.push((_messages$requireNumb = messages.requireNumber) !== null && _messages$requireNumb !== void 0 ? _messages$requireNumb : '密码必须包含至少一个数字');
|
|
56
75
|
}
|
|
57
|
-
if (
|
|
58
|
-
|
|
76
|
+
if (requireSpecialCharacters && !specialCharactersPattern.test(password)) {
|
|
77
|
+
var _messages$requireSpec;
|
|
78
|
+
errors.push((_messages$requireSpec = messages.requireSpecialCharacters) !== null && _messages$requireSpec !== void 0 ? _messages$requireSpec : '密码必须包含至少一个特殊字符');
|
|
59
79
|
}
|
|
60
80
|
return {
|
|
61
81
|
isValid: errors.length === 0,
|
|
@@ -105,6 +105,8 @@ export declare class SalesImpl extends BaseModule implements Module, SalesModule
|
|
|
105
105
|
private groupBookingsByResource;
|
|
106
106
|
private isBookingMatchedResource;
|
|
107
107
|
private sortMatchedBookings;
|
|
108
|
+
/** 已完成:按订单创建时间降序,避免实时追加和重新加载导致显示顺序不同。 */
|
|
109
|
+
private sortCompletedBookings;
|
|
108
110
|
/** Unpaid:与 Current 重合的订单沿用 Current 顺序,其余欠款订单按开始时间降序追加。 */
|
|
109
111
|
private sortUnpaidBookings;
|
|
110
112
|
/**
|
|
@@ -760,6 +760,20 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
760
760
|
});
|
|
761
761
|
}
|
|
762
762
|
|
|
763
|
+
/** 已完成:按订单创建时间降序,避免实时追加和重新加载导致显示顺序不同。 */
|
|
764
|
+
}, {
|
|
765
|
+
key: "sortCompletedBookings",
|
|
766
|
+
value: function sortCompletedBookings(bookings) {
|
|
767
|
+
var createdAt = function createdAt(booking) {
|
|
768
|
+
var _booking$order3;
|
|
769
|
+
var timestamp = dayjs(((_booking$order3 = booking.order) === null || _booking$order3 === void 0 ? void 0 : _booking$order3.created_at) || '').valueOf();
|
|
770
|
+
return Number.isFinite(timestamp) ? timestamp : 0;
|
|
771
|
+
};
|
|
772
|
+
return _toConsumableArray(bookings).sort(function (left, right) {
|
|
773
|
+
return createdAt(right) - createdAt(left);
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
|
|
763
777
|
/** Unpaid:与 Current 重合的订单沿用 Current 顺序,其余欠款订单按开始时间降序追加。 */
|
|
764
778
|
}, {
|
|
765
779
|
key: "sortUnpaidBookings",
|
|
@@ -1260,7 +1274,7 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1260
1274
|
bookings = this.pickBookingsForCurrentPoint(current, this.normalizeResourceBookings(current, deviceCurrent, matchedBookingList), {
|
|
1261
1275
|
includeAllFuture: true
|
|
1262
1276
|
});
|
|
1263
|
-
completedBookings = completedBookingList.map(function (booking) {
|
|
1277
|
+
completedBookings = this.sortCompletedBookings(completedBookingList).map(function (booking) {
|
|
1264
1278
|
return _objectSpread(_objectSpread({}, booking), {}, {
|
|
1265
1279
|
status: 'compelete',
|
|
1266
1280
|
isTimeout: false,
|
|
@@ -304,10 +304,9 @@ function assertAvailabilityCatalogProductIds(productIds, context) {
|
|
|
304
304
|
});
|
|
305
305
|
}
|
|
306
306
|
}
|
|
307
|
-
function normalizeResourceType(
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
return 'single';
|
|
307
|
+
function normalizeResourceType(value) {
|
|
308
|
+
// 预约是否独占与每组选择几个资源是两个独立配置。
|
|
309
|
+
return value === 'multiple' || value === 'capacity' ? value : 'single';
|
|
311
310
|
}
|
|
312
311
|
function resolveProductKind(product) {
|
|
313
312
|
var _product$cartDetailVa, _product$_extend;
|
|
@@ -1 +1,46 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "BUY_X_GET_Y_FREE_STRATEGY", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _examples.BUY_X_GET_Y_FREE_STRATEGY;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "ITEM_REWARD_STRATEGY", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _examples.ITEM_REWARD_STRATEGY;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "PromotionAdapter", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _adapter.PromotionAdapter;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "PromotionEvaluator", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () {
|
|
27
|
+
return _evaluator.PromotionEvaluator;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(exports, "X_ITEMS_FOR_Y_PRICE_STRATEGY", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _examples.X_ITEMS_FOR_Y_PRICE_STRATEGY;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "default", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () {
|
|
39
|
+
return _adapter.default;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
var _evaluator = require("./evaluator");
|
|
43
|
+
var _adapter = _interopRequireWildcard(require("./adapter"));
|
|
44
|
+
var _examples = require("./examples");
|
|
45
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
46
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
@@ -412,7 +412,7 @@ function normalizeOccupancy(occupancy, coverage, timezoneName, fixedOffsetMinute
|
|
|
412
412
|
};
|
|
413
413
|
}
|
|
414
414
|
function normalizeRequirementGroup(product, requirementGroup) {
|
|
415
|
-
const resourceType = 'single';
|
|
415
|
+
const resourceType = requirementGroup.resourceType === 'multiple' || requirementGroup.resourceType === 'capacity' ? requirementGroup.resourceType : 'single';
|
|
416
416
|
const required = requirementGroup.required !== false;
|
|
417
417
|
const min = required ? 1 : 0;
|
|
418
418
|
return {
|
|
@@ -457,7 +457,7 @@ function normalizeProducts(products) {
|
|
|
457
457
|
function normalizeResources(resources) {
|
|
458
458
|
return resources.map(resource => ({
|
|
459
459
|
...resource,
|
|
460
|
-
resourceType: 'single',
|
|
460
|
+
resourceType: resource.resourceType === 'multiple' || resource.resourceType === 'capacity' ? resource.resourceType : 'single',
|
|
461
461
|
capacity: Math.max(1, Number(resource.capacity || 1) || 1),
|
|
462
462
|
windows: (resource.windows || []).map(window => ({
|
|
463
463
|
...window
|
|
@@ -573,7 +573,8 @@ function buildCells(projection) {
|
|
|
573
573
|
occupancy
|
|
574
574
|
}) => occupancy) : [];
|
|
575
575
|
const usedCapacity = segmentOccupancies.reduce((sum, occupancy) => sum + Math.max(1, Number(occupancy.pax || 1) || 1), 0);
|
|
576
|
-
|
|
576
|
+
// 预约模式来自商品资源组;v2 资源记录可能不包含 type。
|
|
577
|
+
const remainingCapacity = requirementGroup.resourceType === 'single' && segmentOccupancies.length > 0 ? 0 : Math.max(0, resource.capacity - usedCapacity);
|
|
577
578
|
const requiredCapacity = resolveRequiredCapacity(requirementGroup, product);
|
|
578
579
|
const reasonCodes = Array.from(new Set(segmentOccupancies.flatMap(occupancy => {
|
|
579
580
|
const source = occupancy.source || 'remote';
|
|
@@ -607,7 +608,7 @@ function buildCells(projection) {
|
|
|
607
608
|
requirementFormId: requirementGroup.formId,
|
|
608
609
|
resourceId: resource.id,
|
|
609
610
|
resourceName: resource.name,
|
|
610
|
-
resourceType:
|
|
611
|
+
resourceType: requirementGroup.resourceType,
|
|
611
612
|
startAt: formatDateTime(start, timezoneName, fixedOffsetMinutes),
|
|
612
613
|
endAt: formatDateTime(end, timezoneName, fixedOffsetMinutes),
|
|
613
614
|
date: formatDate(start, timezoneName),
|
|
@@ -615,7 +616,7 @@ function buildCells(projection) {
|
|
|
615
616
|
endTime: formatTime(end, timezoneName),
|
|
616
617
|
timezone: projection.meta.timezone,
|
|
617
618
|
status,
|
|
618
|
-
//
|
|
619
|
+
// capacity 表示人数;single 被占用时不再贡献可用容量。
|
|
619
620
|
remainingCapacity,
|
|
620
621
|
maxCapacity: resource.capacity,
|
|
621
622
|
reasonCodes: Array.from(new Set(reasonCodes)),
|
|
@@ -1500,7 +1501,7 @@ function evaluateCandidate(projection, candidate, request) {
|
|
|
1500
1501
|
resourceName: resource.name,
|
|
1501
1502
|
resourceFormId: resource.formId,
|
|
1502
1503
|
policyId: resource.raw?.policy_id,
|
|
1503
|
-
resourceType:
|
|
1504
|
+
resourceType: requirementGroup.resourceType,
|
|
1504
1505
|
status: isPast ? 'past' : 'unavailable',
|
|
1505
1506
|
maxPartySize: 0,
|
|
1506
1507
|
reasonCodes: isPast ? ['past'] : [...(isExcludedScheduleDate ? ['schedule_excluded_date'] : []), 'outside_resource_window']
|
|
@@ -1524,7 +1525,7 @@ function evaluateCandidate(projection, candidate, request) {
|
|
|
1524
1525
|
resourceName: resource.name,
|
|
1525
1526
|
resourceFormId: resource.formId,
|
|
1526
1527
|
policyId: resource.raw?.policy_id,
|
|
1527
|
-
resourceType:
|
|
1528
|
+
resourceType: requirementGroup.resourceType,
|
|
1528
1529
|
status,
|
|
1529
1530
|
remainingCapacity,
|
|
1530
1531
|
maxCapacity,
|
|
@@ -2008,7 +2009,8 @@ function validateAvailabilitySelection(projection, params, runtimeOptions = {})
|
|
|
2008
2009
|
const remainingCapacity = matchedCell?.remainingCapacity;
|
|
2009
2010
|
if (option && (option.status === 'available' || option.status === 'limited') && remainingCapacity !== undefined) {
|
|
2010
2011
|
const capacityPerBooking = normalizedPartySize ?? 1;
|
|
2011
|
-
const
|
|
2012
|
+
const capacityQuantity = Math.max(0, Math.floor(remainingCapacity / capacityPerBooking));
|
|
2013
|
+
const availableQuantity = matchedGroup.resourceType === 'single' ? Math.min(1, capacityQuantity) : capacityQuantity;
|
|
2012
2014
|
if (normalizedBookingCount > availableQuantity) {
|
|
2013
2015
|
conflicts.push({
|
|
2014
2016
|
code: 'resource_capacity_exceeded',
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 | 2 | 1 |
|
|
329
|
+
weekNum: 0 | 2 | 1 | 3 | 4 | 5 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -588,6 +588,16 @@ const defaultConfig = {
|
|
|
588
588
|
/**
|
|
589
589
|
* webpos 渠道配置
|
|
590
590
|
*/
|
|
591
|
+
const webposPasswordResetOptions = {
|
|
592
|
+
prefix: false,
|
|
593
|
+
isDefaultSaasDomain: true,
|
|
594
|
+
cache: false,
|
|
595
|
+
noToast: true,
|
|
596
|
+
headers: {
|
|
597
|
+
Accept: 'application/json',
|
|
598
|
+
'Content-Type': 'application/json'
|
|
599
|
+
}
|
|
600
|
+
};
|
|
591
601
|
const webposConfig = {
|
|
592
602
|
sendEmailVerificationCode: {
|
|
593
603
|
url: '/auth/email/register-code',
|
|
@@ -710,13 +720,20 @@ const webposConfig = {
|
|
|
710
720
|
})
|
|
711
721
|
},
|
|
712
722
|
checkEmailCode: {
|
|
713
|
-
url: '/
|
|
714
|
-
method: '
|
|
723
|
+
url: '/tenant/account/reset-password/email-code/verify',
|
|
724
|
+
method: 'POST',
|
|
715
725
|
transformParams: params => ({
|
|
716
726
|
email: params.email,
|
|
717
|
-
code: params.code
|
|
718
|
-
|
|
719
|
-
|
|
727
|
+
code: params.code
|
|
728
|
+
}),
|
|
729
|
+
// SaaS 成功时 data 为 null,统一为既有验证码校验返回结构。
|
|
730
|
+
transformResponse: response => response?.status === true ? {
|
|
731
|
+
...response,
|
|
732
|
+
data: {
|
|
733
|
+
valid: true
|
|
734
|
+
}
|
|
735
|
+
} : response,
|
|
736
|
+
options: webposPasswordResetOptions
|
|
720
737
|
},
|
|
721
738
|
checkMobileCode: {
|
|
722
739
|
url: '/auth/mobile/check-mobile-code',
|
|
@@ -738,11 +755,12 @@ const webposConfig = {
|
|
|
738
755
|
})
|
|
739
756
|
},
|
|
740
757
|
sendPasswordResetEmail: {
|
|
741
|
-
url: '/
|
|
742
|
-
method: '
|
|
758
|
+
url: '/tenant/account/reset-password/email-code/send',
|
|
759
|
+
method: 'POST',
|
|
743
760
|
transformParams: params => ({
|
|
744
761
|
email: params.email
|
|
745
|
-
})
|
|
762
|
+
}),
|
|
763
|
+
options: webposPasswordResetOptions
|
|
746
764
|
},
|
|
747
765
|
sendPasswordResetSms: {
|
|
748
766
|
url: '/auth/mobile/sms-forget',
|
|
@@ -775,13 +793,16 @@ const webposConfig = {
|
|
|
775
793
|
})
|
|
776
794
|
},
|
|
777
795
|
resetPasswordByEmail: {
|
|
778
|
-
url: '/
|
|
796
|
+
url: '/tenant/account/reset-password/email-code',
|
|
779
797
|
method: 'POST',
|
|
780
798
|
transformParams: params => ({
|
|
781
799
|
email: params.email,
|
|
782
800
|
password: params.password,
|
|
783
|
-
code: params.code
|
|
784
|
-
|
|
801
|
+
code: params.code,
|
|
802
|
+
// 页面先校验两次输入完全一致,SDK 保持原有重置参数。
|
|
803
|
+
password_confirmation: params.password
|
|
804
|
+
}),
|
|
805
|
+
options: webposPasswordResetOptions
|
|
785
806
|
},
|
|
786
807
|
resetPasswordByPhone: {
|
|
787
808
|
url: '/auth/mobile/reset-password',
|
|
@@ -4,6 +4,8 @@ import { RegisterParams, LoginParams, OAuthLoginParams, SendVerificationCodePara
|
|
|
4
4
|
import { ApiCaller } from './config';
|
|
5
5
|
export * from './types';
|
|
6
6
|
export * from './config';
|
|
7
|
+
export { validatePassword } from './utils';
|
|
8
|
+
export type { PasswordValidationOptions } from './utils';
|
|
7
9
|
/**
|
|
8
10
|
* 注册登录解决方案实现
|
|
9
11
|
*/
|
|
@@ -4,9 +4,16 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
var _exportNames = {
|
|
7
|
-
RegisterAndLoginImpl: true
|
|
7
|
+
RegisterAndLoginImpl: true,
|
|
8
|
+
validatePassword: true
|
|
8
9
|
};
|
|
9
10
|
exports.RegisterAndLoginImpl = void 0;
|
|
11
|
+
Object.defineProperty(exports, "validatePassword", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () {
|
|
14
|
+
return _utils.validatePassword;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
10
17
|
var _BaseModule = require("../../modules/BaseModule");
|
|
11
18
|
var _types = require("./types");
|
|
12
19
|
Object.keys(_types).forEach(function (key) {
|
|
@@ -32,6 +39,7 @@ Object.keys(_config).forEach(function (key) {
|
|
|
32
39
|
}
|
|
33
40
|
});
|
|
34
41
|
});
|
|
42
|
+
var _utils = require("./utils");
|
|
35
43
|
/**
|
|
36
44
|
* 注册登录解决方案实现
|
|
37
45
|
*/
|
|
@@ -10,10 +10,18 @@ export declare function validateEmail(email: string): boolean;
|
|
|
10
10
|
* 验证手机号格式(支持多种国际格式)
|
|
11
11
|
*/
|
|
12
12
|
export declare function validatePhone(phone: string): boolean;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
export interface PasswordValidationOptions {
|
|
14
|
+
minLength?: number;
|
|
15
|
+
maxLength?: number;
|
|
16
|
+
requireLowercase?: boolean;
|
|
17
|
+
requireUppercase?: boolean;
|
|
18
|
+
requireNumber?: boolean;
|
|
19
|
+
requireSpecialCharacters?: boolean;
|
|
20
|
+
specialCharactersPattern?: RegExp;
|
|
21
|
+
messages?: Partial<Record<'minLength' | 'maxLength' | 'requireLowercase' | 'requireUppercase' | 'requireNumber' | 'requireSpecialCharacters', string>>;
|
|
22
|
+
}
|
|
23
|
+
/** 验证密码强度;不传 options 时保持原有规则与返回格式。 */
|
|
24
|
+
export declare function validatePassword(password: string, options?: PasswordValidationOptions): {
|
|
17
25
|
isValid: boolean;
|
|
18
26
|
errors: string[];
|
|
19
27
|
};
|
|
@@ -49,29 +49,36 @@ function validatePhone(phone) {
|
|
|
49
49
|
const phoneRegex = /^(\+\d{1,3}[- ]?)?\d{10,14}$/;
|
|
50
50
|
return phoneRegex.test(cleanPhone);
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* 验证密码强度
|
|
55
|
-
*/
|
|
56
|
-
function validatePassword(password) {
|
|
52
|
+
/** 验证密码强度;不传 options 时保持原有规则与返回格式。 */
|
|
53
|
+
function validatePassword(password, options = {}) {
|
|
57
54
|
const errors = [];
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
const {
|
|
56
|
+
minLength = 8,
|
|
57
|
+
maxLength = 128,
|
|
58
|
+
requireLowercase = true,
|
|
59
|
+
requireUppercase = true,
|
|
60
|
+
requireNumber = true,
|
|
61
|
+
requireSpecialCharacters = true,
|
|
62
|
+
specialCharactersPattern = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/,
|
|
63
|
+
messages = {}
|
|
64
|
+
} = options;
|
|
65
|
+
if (password.length < minLength) {
|
|
66
|
+
errors.push(messages.minLength ?? `密码长度至少为${minLength}位`);
|
|
60
67
|
}
|
|
61
|
-
if (password.length >
|
|
62
|
-
errors.push(
|
|
68
|
+
if (password.length > maxLength) {
|
|
69
|
+
errors.push(messages.maxLength ?? `密码长度不能超过${maxLength}位`);
|
|
63
70
|
}
|
|
64
|
-
if (!/[a-z]/.test(password)) {
|
|
65
|
-
errors.push('密码必须包含至少一个小写字母');
|
|
71
|
+
if (requireLowercase && !/[a-z]/.test(password)) {
|
|
72
|
+
errors.push(messages.requireLowercase ?? '密码必须包含至少一个小写字母');
|
|
66
73
|
}
|
|
67
|
-
if (!/[A-Z]/.test(password)) {
|
|
68
|
-
errors.push('密码必须包含至少一个大写字母');
|
|
74
|
+
if (requireUppercase && !/[A-Z]/.test(password)) {
|
|
75
|
+
errors.push(messages.requireUppercase ?? '密码必须包含至少一个大写字母');
|
|
69
76
|
}
|
|
70
|
-
if (!/\d/.test(password)) {
|
|
71
|
-
errors.push('密码必须包含至少一个数字');
|
|
77
|
+
if (requireNumber && !/\d/.test(password)) {
|
|
78
|
+
errors.push(messages.requireNumber ?? '密码必须包含至少一个数字');
|
|
72
79
|
}
|
|
73
|
-
if (
|
|
74
|
-
errors.push('密码必须包含至少一个特殊字符');
|
|
80
|
+
if (requireSpecialCharacters && !specialCharactersPattern.test(password)) {
|
|
81
|
+
errors.push(messages.requireSpecialCharacters ?? '密码必须包含至少一个特殊字符');
|
|
75
82
|
}
|
|
76
83
|
return {
|
|
77
84
|
isValid: errors.length === 0,
|
|
@@ -105,6 +105,8 @@ export declare class SalesImpl extends BaseModule implements Module, SalesModule
|
|
|
105
105
|
private groupBookingsByResource;
|
|
106
106
|
private isBookingMatchedResource;
|
|
107
107
|
private sortMatchedBookings;
|
|
108
|
+
/** 已完成:按订单创建时间降序,避免实时追加和重新加载导致显示顺序不同。 */
|
|
109
|
+
private sortCompletedBookings;
|
|
108
110
|
/** Unpaid:与 Current 重合的订单沿用 Current 顺序,其余欠款订单按开始时间降序追加。 */
|
|
109
111
|
private sortUnpaidBookings;
|
|
110
112
|
/**
|
|
@@ -507,6 +507,15 @@ class SalesImpl extends _BaseModule.BaseModule {
|
|
|
507
507
|
});
|
|
508
508
|
}
|
|
509
509
|
|
|
510
|
+
/** 已完成:按订单创建时间降序,避免实时追加和重新加载导致显示顺序不同。 */
|
|
511
|
+
sortCompletedBookings(bookings) {
|
|
512
|
+
const createdAt = booking => {
|
|
513
|
+
const timestamp = (0, _dayjs.default)(booking.order?.created_at || '').valueOf();
|
|
514
|
+
return Number.isFinite(timestamp) ? timestamp : 0;
|
|
515
|
+
};
|
|
516
|
+
return [...bookings].sort((left, right) => createdAt(right) - createdAt(left));
|
|
517
|
+
}
|
|
518
|
+
|
|
510
519
|
/** Unpaid:与 Current 重合的订单沿用 Current 顺序,其余欠款订单按开始时间降序追加。 */
|
|
511
520
|
sortUnpaidBookings(bookings, currentBookings) {
|
|
512
521
|
const currentOrderIndexes = new Map(currentBookings.map((booking, index) => [String(booking.order.order_id), index]));
|
|
@@ -881,7 +890,7 @@ class SalesImpl extends _BaseModule.BaseModule {
|
|
|
881
890
|
const bookings = this.pickBookingsForCurrentPoint(current, this.normalizeResourceBookings(current, deviceCurrent, matchedBookingList), {
|
|
882
891
|
includeAllFuture: true
|
|
883
892
|
});
|
|
884
|
-
const completedBookings = completedBookingList.map(booking => {
|
|
893
|
+
const completedBookings = this.sortCompletedBookings(completedBookingList).map(booking => {
|
|
885
894
|
return {
|
|
886
895
|
...booking,
|
|
887
896
|
status: 'compelete',
|
|
@@ -283,10 +283,9 @@ function assertAvailabilityCatalogProductIds(productIds, context) {
|
|
|
283
283
|
});
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
|
-
function normalizeResourceType(
|
|
287
|
-
//
|
|
288
|
-
|
|
289
|
-
return 'single';
|
|
286
|
+
function normalizeResourceType(value) {
|
|
287
|
+
// 预约是否独占与每组选择几个资源是两个独立配置。
|
|
288
|
+
return value === 'multiple' || value === 'capacity' ? value : 'single';
|
|
290
289
|
}
|
|
291
290
|
function resolveProductKind(product) {
|
|
292
291
|
if (product.duration || product.service_duration) return 'duration';
|