UNPKG

@pisell/pisellos

Version:

一个可扩展的前端模块化SDK框架,支持插件系统

647 lines (645 loc) 24 kB
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 });