@pisell/pisellos
Version:
一个可扩展的前端模块化SDK框架,支持插件系统
647 lines (645 loc) • 24 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/solution/BookingByStep/utils/resources.ts
var resources_exports = {};
__export(resources_exports, {
checkSessionProductLeadTime: () => checkSessionProductLeadTime,
checkTwoResourcesIntersection: () => checkTwoResourcesIntersection,
filterResourcesByFormItem: () => filterResourcesByFormItem,
filterScheduleByDateRange: () => filterScheduleByDateRange,
formatResources: () => formatResources,
getIsUsableByTimeItem: () => getIsUsableByTimeItem,
getOthersCartSelectedResources: () => getOthersCartSelectedResources,
getOthersSelectedResources: () => getOthersSelectedResources,
getResourcesByIds: () => getResourcesByIds,
getResourcesByProduct: () => getResourcesByProduct,
getResourcesIdsByProduct: () => getResourcesIdsByProduct,
getTimeSlicesByResource: () => getTimeSlicesByResource,
getTimeSlicesByResources: () => getTimeSlicesByResources,
getTimesIntersection: () => getTimesIntersection,
isConflict: () => isConflict,
mergeSubResourcesTimeSlices: () => mergeSubResourcesTimeSlices,
sortCombinedResources: () => sortCombinedResources
});
module.exports = __toCommonJS(resources_exports);
var import_dayjs = __toESM(require("dayjs"));
var getUseableEventCount = (eventList, current) => {
return (eventList || []).reduce((pre, event) => {
return pre - event.pax;
}, current || 0);
};
var isConflict = (event, current) => {
const eventStart = (0, import_dayjs.default)(event.start_at);
const eventEnd = (0, import_dayjs.default)(event.end_at);
const currentStart = (0, import_dayjs.default)(current.start_at);
const _isBefore = currentStart.isBefore(eventEnd);
let _isAfter = true;
if (current.end_at) {
const currentEnd = (0, import_dayjs.default)(current.end_at);
_isAfter = currentEnd.isAfter(eventStart);
}
return _isBefore && _isAfter;
};
var checkAfterToDay = (date, today = (0, import_dayjs.default)()) => {
return (0, import_dayjs.default)(date).isAfter((0, import_dayjs.default)(today));
};
var formatResource = (resourceItem, booking) => {
let _resourceItem = { ...resourceItem };
_resourceItem.timeSlices = getTimeSlicesByResource({
resource: _resourceItem,
duration: booking.duration,
split: 10,
currentDate: (0, import_dayjs.default)().format("YYYY-MM-DD")
});
_resourceItem.labelText = _resourceItem.main_field;
return _resourceItem;
};
var checkCapacity = ({
event_list,
timeSlice,
resource,
currentCount = 1
}) => {
const isMultipleBooking = resource.resourceType === "multiple";
if (currentCount > resource.capacity && (isMultipleBooking || !isMultipleBooking && event_list.length === 0)) {
return {
status: false,
capacity: resource.capacity,
reason: "capacityOnly"
};
}
let conflict = (event_list || []).filter((d) => {
return isConflict(
{ start_at: d.start_at, end_at: d.end_at },
{ start_at: timeSlice.start_at, end_at: timeSlice.end_at }
);
});
let conflictCount = getUseableEventCount(conflict, resource.capacity);
if (resource.resourceType === "single") {
if (conflict.length === 0) {
return {
status: true,
capacity: conflictCount
};
} else {
return {
status: false,
capacity: conflictCount
};
}
} else {
if (currentCount <= conflictCount) {
return {
status: true,
capacity: conflictCount
};
} else {
return {
status: false,
capacity: conflictCount
};
}
}
};
var getIsUsableByTimeItem = ({
timeSlice,
time,
resource,
currentCount = 1,
resourcesUseableMap = {},
cut_off_time
}) => {
var _a;
let status = {
afterToDay: false,
capacity: false,
usable: false,
remainingCapacity: 0,
// 剩余容量
reason: ""
};
let earliest = (0, import_dayjs.default)();
let canBookingForOngoing = false;
const { unit, unit_type, type, ongoing } = cut_off_time || {};
if (type === "ongoing" && (ongoing == null ? void 0 : ongoing.type) === "after_start") {
if ((0, import_dayjs.default)(timeSlice.start_at).isBefore((0, import_dayjs.default)())) {
if (earliest.isBefore((0, import_dayjs.default)(timeSlice.start_at).add(ongoing.unit, "minute"))) {
canBookingForOngoing = true;
}
}
} else if (type === "ongoing" && (ongoing == null ? void 0 : ongoing.type) === "before_end") {
if ((0, import_dayjs.default)(timeSlice.end_at).isAfter(earliest)) {
canBookingForOngoing = true;
}
} else {
if (unit) {
earliest = earliest.add(unit, unit_type);
}
}
if (!checkAfterToDay(timeSlice.start_at, earliest) && !canBookingForOngoing) {
return status;
}
status.afterToDay = true;
const checkCapacityResult = checkCapacity({
event_list: time == null ? void 0 : time.event_list,
timeSlice,
resource,
currentCount
});
if ((_a = resource.combined_resource) == null ? void 0 : _a.status) {
const resourceIds = resource.combined_resource.resource_ids;
resourceIds.forEach((id) => {
if ((resourcesUseableMap == null ? void 0 : resourcesUseableMap[id]) === false) {
checkCapacityResult.status = false;
}
});
}
status.reason = checkCapacityResult.reason || "";
if (!checkCapacityResult.status) {
return status;
}
status.remainingCapacity = checkCapacityResult.capacity;
status.capacity = true;
status.usable = true;
return status;
};
var getResourcesByProduct = (resourcesMap, resources, selectedResources, capacity = 1) => {
return (resources || []).reduce((acc, item) => {
if ((item == null ? void 0 : item.status) == 1) {
const form_id = item.id;
item.optional_resource = (item.optional_resource || []).filter(
(d) => item.default_resource.indexOf(d) == -1
);
let optional_resource = item.optional_resource.reduce(
(childAcc, d) => {
var _a;
const isSelectSingleResources = ((_a = resourcesMap[d]) == null ? void 0 : _a.resourceType) === "single" && selectedResources.includes(resourcesMap[d].id);
if (resourcesMap[d] && !isSelectSingleResources) {
const combiningResources = [];
if (resourcesMap[d].combined_resource && resourcesMap[d].combined_resource.status === 1) {
resourcesMap[d].combined_resource.resource_ids.forEach(
(id) => {
if (resourcesMap[id]) {
combiningResources.push(resourcesMap[id]);
childAcc.push(
Object.assign({}, resourcesMap[id], {
form_id,
resourceType: item.type,
children: combiningResources,
onlyComputed: true,
// 是否是只用来计算用,组合资源里,假设商品只关联了组合资源没关联子资源,需要通过这个计算来在后面从 renderList 里删除这个资源
metadata: {
...resourcesMap[id].metadata,
combined_resource: resourcesMap[id].combined_resource,
form_name: item.title,
resource_name: resourcesMap[id].main_field
}
})
);
}
}
);
}
childAcc.push(
Object.assign({}, resourcesMap[d], {
form_id,
resourceType: item.type,
children: combiningResources,
metadata: {
...resourcesMap[d].metadata,
combined_resource: resourcesMap[d].combined_resource,
form_name: item.title,
resource_name: resourcesMap[d].main_field
}
})
);
}
return childAcc;
},
[]
);
let default_resource = item.default_resource.reduce(
(childAcc, d) => {
var _a;
const isSelectSingleResources = ((_a = resourcesMap[d]) == null ? void 0 : _a.resourceType) === "single" && selectedResources.includes(resourcesMap[d].id);
if (resourcesMap[d] && !isSelectSingleResources) {
const combiningResources = [];
if (resourcesMap[d].combined_resource && resourcesMap[d].combined_resource.status === 1) {
resourcesMap[d].combined_resource.resource_ids.forEach(
(id) => {
if (resourcesMap[id]) {
combiningResources.push(resourcesMap[id]);
childAcc.push(
Object.assign({}, resourcesMap[id], {
form_id,
resourceType: item.type,
children: combiningResources,
onlyComputed: true,
// 是否是只用来计算用,组合资源里,假设商品只关联了组合资源没关联子资源,需要通过这个计算来在后面从 renderList 里删除这个资源
metadata: {
...resourcesMap[id].metadata,
combined_resource: resourcesMap[id].combined_resource,
form_name: item.title,
resource_name: resourcesMap[id].main_field
}
})
);
}
}
);
}
childAcc.push(
Object.assign({}, resourcesMap[d], {
form_id,
resourceType: item.type,
is_default: 1,
children: combiningResources,
metadata: {
...resourcesMap[d].metadata,
combined_resource: resourcesMap[d].combined_resource,
form_name: item.title,
resource_name: resourcesMap[d].main_field
}
})
);
}
return childAcc;
},
[]
);
item.renderList = optional_resource.concat(default_resource);
item.renderList = item.renderList.filter((d) => {
const latestTime = d.times.reduce((latest, current) => {
return (0, import_dayjs.default)(current.end_at).isAfter((0, import_dayjs.default)(latest.end_at)) ? current : latest;
}, d.times[0]);
return (0, import_dayjs.default)(latestTime.end_at).isAfter((0, import_dayjs.default)()) && d.capacity >= capacity;
});
item.form_id = form_id;
acc.push(item);
}
return acc;
}, []);
};
var formatResources = ({
booking,
resources
}) => {
try {
let _list = [...resources];
let maps = {};
for (let item of _list) {
let renderListMaps = {};
item.renderList = item.renderList.map((d) => {
let res = formatResource(d, booking);
renderListMaps[res.id] = res;
return res;
});
maps[item.form_id] = {
...item,
renderListMaps
};
}
return { list: _list, maps };
} catch (err) {
console.log("formatResourcesErr", err);
}
return {
list: [],
maps: {}
};
};
var getTimeSlicesByResource = ({
resource,
duration,
split = 10,
currentDate = (0, import_dayjs.default)(),
capacity,
resourcesUseableMap = {},
cut_off_time,
hasFlexibleDuration,
operating_day_boundary,
maxBlockThreshold
}) => {
let { times } = resource;
const timeSlices = [];
times.sort((a, b) => {
return (0, import_dayjs.default)(a.start_at).diff((0, import_dayjs.default)(b.start_at), "minute");
});
times.forEach((time) => {
const startTime = (0, import_dayjs.default)(`${time.start_at}`);
let endTime = (0, import_dayjs.default)(`${time.end_at}`);
if (endTime.isAfter((0, import_dayjs.default)(currentDate).endOf("day"))) {
endTime = (0, import_dayjs.default)(currentDate).endOf("day");
}
let currentStart = startTime;
while (true) {
const currentEnd = currentStart.add(duration, "minute");
if (currentEnd.isAfter(endTime)) {
break;
}
const timeSlice = {
start_time: currentStart.format("HH:mm"),
end_time: currentEnd.format("HH:mm"),
start_at: currentStart,
end_at: currentEnd
};
const _status = getIsUsableByTimeItem({
timeSlice,
time,
resource,
currentCount: capacity || 1,
resourcesUseableMap,
cut_off_time
});
if ((resourcesUseableMap == null ? void 0 : resourcesUseableMap[resource.id]) !== false) {
resourcesUseableMap[resource.id] = _status.usable;
}
if (_status.usable) {
const operatingBoundaryDateTime = (operating_day_boundary == null ? void 0 : operating_day_boundary.type) === "start_time" ? "23:59" : operating_day_boundary == null ? void 0 : operating_day_boundary.time;
if (hasFlexibleDuration && operating_day_boundary && timeSlice.start_time >= (operatingBoundaryDateTime || "23:59")) {
break;
}
const operatingBoundaryDateTimeObj = (0, import_dayjs.default)(`${endTime.format("YYYY-MM-DD")} ${operatingBoundaryDateTime}`);
const earlyTime = endTime.isBefore(operatingBoundaryDateTimeObj) ? endTime : operatingBoundaryDateTimeObj;
if (hasFlexibleDuration && operating_day_boundary && maxBlockThreshold && timeSlice.start_at.add(maxBlockThreshold || 0, "minutes").isAfter(earlyTime)) {
break;
}
timeSlices.push({
...timeSlice,
// 这里需要补充这个时间段内是否可预约
_status
});
}
currentStart = currentStart.add(split, "minute");
}
});
return timeSlices;
};
var getTimesIntersection = (times, count) => {
let obj = times.reduce((acc, item) => {
let _key = `${item.start_time}-${item.end_time}`;
if (!acc[_key]) {
acc[_key] = {
item,
count: 1
};
} else {
acc[_key].count += 1;
}
return acc;
}, {});
return Object.values(obj).filter((d) => d.count >= count).map((d) => d.item);
};
var getResourcesByIds = (resourcesMap, ids) => {
return (ids || []).map((id) => resourcesMap[id]);
};
var mergeSubResourcesTimeSlices = (resources, resourcesMap) => {
return resources.forEach((item) => {
var _a, _b;
if (((_a = item == null ? void 0 : item.combined_resource) == null ? void 0 : _a.status) === 1) {
(_b = item == null ? void 0 : item.combined_resource) == null ? void 0 : _b.resource_ids.forEach((id) => {
const subResource = resourcesMap[id];
if (subResource) {
subResource.times.forEach((time) => {
const fatherResourcesTime = item.times.find(
(n) => n.start_at === time.start_at && n.end_at === time.end_at
);
if (fatherResourcesTime) {
fatherResourcesTime.event_list.push(...time.event_list || []);
}
});
}
});
}
});
};
var getTimeSlicesByResources = ({
resourceIds,
resourcesMap,
duration,
currentDate,
split,
capacity,
resourcesUseableMap,
cut_off_time,
hasFlexibleDuration,
operating_day_boundary,
maxBlockThreshold
}) => {
let resources = getResourcesByIds(resourcesMap, resourceIds);
mergeSubResourcesTimeSlices(resources, resourcesMap);
resources.sort((a, b) => {
var _a, _b, _c, _d;
const aIsCombined = ((_b = (_a = a.metadata) == null ? void 0 : _a.combined_resource) == null ? void 0 : _b.status) === 1;
const bIsCombined = ((_d = (_c = b.metadata) == null ? void 0 : _c.combined_resource) == null ? void 0 : _d.status) === 1;
if (aIsCombined && !bIsCombined)
return 1;
if (!aIsCombined && bIsCombined)
return -1;
return 0;
});
let timeSliceList = resources.reduce(
(acc, item) => {
return acc.concat(
getTimeSlicesByResource({
resource: item,
duration,
split,
currentDate,
capacity,
resourcesUseableMap,
cut_off_time,
hasFlexibleDuration,
operating_day_boundary,
maxBlockThreshold
})
);
},
[]
);
let intersection = getTimesIntersection(timeSliceList, resources.length);
return intersection;
};
var getOthersSelectedResources = (cartItems, accountId, resourcesMap) => {
return cartItems.reduce((acc, d) => {
var _a;
if (d.holder_id !== accountId) {
if ((_a = d._origin) == null ? void 0 : _a.resources) {
d._origin.resources.forEach((n) => {
if (n.metadata.combined_resource && n.metadata.combined_resource.status === 1) {
if (n.metadata.combined_resource.resource_ids.some(
(m) => acc.includes(m)
)) {
return acc;
}
acc.push(...n.metadata.combined_resource.resource_ids);
} else {
Object.values(resourcesMap).forEach((m) => {
if (m.combined_resource && m.combined_resource.status === 1) {
if (m.combined_resource.resource_ids.includes(n.id)) {
acc.push(m.id);
}
}
});
}
acc.push(n.id);
});
}
}
return acc;
}, []);
};
var getOthersCartSelectedResources = (cartItems, cartItemId, resourcesMap) => {
return cartItems.reduce((acc, d) => {
var _a;
if (d._id !== cartItemId) {
if ((_a = d._origin) == null ? void 0 : _a.resources) {
d._origin.resources.forEach((n) => {
if (n.metadata.combined_resource && n.metadata.combined_resource.status === 1) {
if (n.metadata.combined_resource.resource_ids.some(
(m) => acc.includes(m)
)) {
return acc;
}
acc.push(...n.metadata.combined_resource.resource_ids);
} else {
Object.values(resourcesMap).forEach((m) => {
if (m.combined_resource && m.combined_resource.status === 1) {
if (m.combined_resource.resource_ids.includes(n.id)) {
acc.push(m.id);
}
}
});
}
acc.push(n.id);
});
}
}
return acc;
}, []);
};
function filterScheduleByDateRange(schedule, startDate, endDate) {
if (!(schedule == null ? void 0 : schedule.length))
return [];
const start = new Date(startDate);
const end = new Date(endDate);
return schedule.filter((item) => {
const itemDate = new Date(item.date);
return itemDate >= start && itemDate <= end;
});
}
function checkSessionProductLeadTime(product) {
let latestStartDate = "";
let earliestEndDate = "";
const { future_day, unit, unit_type } = product.cut_off_time;
if (future_day) {
const endDate = (0, import_dayjs.default)().add(future_day, "day");
if (!earliestEndDate || endDate.isBefore((0, import_dayjs.default)(earliestEndDate), "day")) {
earliestEndDate = endDate.format("YYYY-MM-DD");
}
} else if (future_day === 0) {
const endDate = (0, import_dayjs.default)();
if (!earliestEndDate || endDate.isBefore((0, import_dayjs.default)(earliestEndDate), "day")) {
earliestEndDate = endDate.format("YYYY-MM-DD");
}
}
if (unit && unit_type) {
const startDate = (0, import_dayjs.default)(
(0, import_dayjs.default)().add(unit, unit_type).format("YYYY-MM-DD")
);
if (!latestStartDate || startDate.isAfter((0, import_dayjs.default)(latestStartDate), "day")) {
latestStartDate = startDate.format("YYYY-MM-DD");
}
}
return {
latestStartDate,
earliestEndDate
};
}
function getResourcesIdsByProduct(product) {
var _a, _b, _c;
const tempResourceIds = [];
(_c = (_b = (_a = product == null ? void 0 : product.product_resource) == null ? void 0 : _a.resources) == null ? void 0 : _b.forEach) == null ? void 0 : _c.call(_b, (resource) => {
var _a2, _b2;
if ((resource == null ? void 0 : resource.status) == 1) {
if ((_a2 = resource == null ? void 0 : resource.default_resource) == null ? void 0 : _a2.length) {
tempResourceIds.push(...resource == null ? void 0 : resource.default_resource);
} else if ((_b2 = resource == null ? void 0 : resource.optional_resource) == null ? void 0 : _b2.length) {
tempResourceIds.push(...resource == null ? void 0 : resource.optional_resource);
}
}
});
return tempResourceIds;
}
function sortCombinedResources(resourcesList) {
const newResourcesList = [...resourcesList];
newResourcesList.sort((a, b) => {
var _a, _b, _c, _d;
const aIsCombined = ((_b = (_a = a.metadata) == null ? void 0 : _a.combined_resource) == null ? void 0 : _b.status) === 1;
const bIsCombined = ((_d = (_c = b.metadata) == null ? void 0 : _c.combined_resource) == null ? void 0 : _d.status) === 1;
return aIsCombined === bIsCombined ? 0 : aIsCombined ? 1 : -1;
});
return newResourcesList;
}
function filterResourcesByFormItem(resources, form_id) {
return resources.filter((n) => n.form_id === form_id);
}
function checkTwoResourcesIntersection(resource1, resource2) {
var _a, _b;
if (resource1.id === resource2.id)
return true;
if (((_a = resource1.metadata.combined_resource) == null ? void 0 : _a.status) === 1 && // 如果现在选择的是组合资源,需要判断
// 1、当前其他购物车里是否选了当前组合资源的子资源
// 2、如果其他购物车里的商品也是组合资源,出了组合资源本身的 id 需要判断,还需要判断子资源的 id 是否有交集
(resource1.metadata.combined_resource.resource_ids.includes(resource2.id) || resource1.metadata.combined_resource.resource_ids.some((n) => {
return resource2.metadata.combined_resource.resource_ids.includes(n);
})))
return true;
if (((_b = resource2.metadata.combined_resource) == null ? void 0 : _b.status) === 1 && resource2.metadata.combined_resource.resource_ids.includes(resource2.id))
return true;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
checkSessionProductLeadTime,
checkTwoResourcesIntersection,
filterResourcesByFormItem,
filterScheduleByDateRange,
formatResources,
getIsUsableByTimeItem,
getOthersCartSelectedResources,
getOthersSelectedResources,
getResourcesByIds,
getResourcesByProduct,
getResourcesIdsByProduct,
getTimeSlicesByResource,
getTimeSlicesByResources,
getTimesIntersection,
isConflict,
mergeSubResourcesTimeSlices,
sortCombinedResources
});