@pisell/pisellos
Version:
一个可扩展的前端模块化SDK框架,支持插件系统
221 lines (219 loc) • 10.5 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/timeslots.ts
var timeslots_exports = {};
__export(timeslots_exports, {
calculateResourceAvailableTime: () => calculateResourceAvailableTime,
filterConditionTimeSlots: () => filterConditionTimeSlots,
findFastestAvailableResource: () => findFastestAvailableResource
});
module.exports = __toCommonJS(timeslots_exports);
var import_dayjs = __toESM(require("dayjs"));
function calculateResourceAvailableTime({
resource,
timeSlots,
currentCapacity = 1
}) {
const matchingTimes = resource.times.filter((time) => {
return (0, import_dayjs.default)(time.start_at).isSame((0, import_dayjs.default)(timeSlots.start_at), "day");
});
if (matchingTimes.length === 0)
return 0;
const overlaps = [];
for (const time of matchingTimes) {
const overlapStart = (0, import_dayjs.default)(time.start_at).isAfter((0, import_dayjs.default)(timeSlots.start_at)) ? (0, import_dayjs.default)(time.start_at) : (0, import_dayjs.default)(timeSlots.start_at);
const overlapEnd = (0, import_dayjs.default)(time.end_at).isBefore((0, import_dayjs.default)(timeSlots.end_at)) ? (0, import_dayjs.default)(time.end_at) : (0, import_dayjs.default)(timeSlots.end_at);
if (overlapStart.isBefore(overlapEnd)) {
overlaps.push({ start: overlapStart, end: overlapEnd });
}
}
if (overlaps.length === 0)
return 0;
overlaps.sort((a, b) => a.start.diff(b.start));
const merged = [];
let current = overlaps[0];
for (let i = 1; i < overlaps.length; i++) {
const next = overlaps[i];
if (current.end.isSameOrAfter(next.start)) {
current.end = current.end.isAfter(next.end) ? current.end : next.end;
} else {
merged.push(current);
current = next;
}
}
merged.push(current);
let totalAvailableMinutes = 0;
for (const segment of merged) {
totalAvailableMinutes += segment.end.diff(segment.start, "minute");
}
return totalAvailableMinutes;
}
function findFastestAvailableResource({
resources,
currentCapacity = 1,
countMap = {}
}) {
var _a, _b, _c;
const currentTime = (0, import_dayjs.default)();
let fastestTime = null;
let fastestResources = [];
console.log("[TimeslotUtils] 查找最快可用资源:", {
currentTime: currentTime.format("YYYY-MM-DD HH:mm:ss"),
resourceCount: resources.length,
currentCapacity,
countMap
});
for (const resource of resources) {
const todayTimes = resource.times.filter((time) => {
const isToday = (0, import_dayjs.default)(time.start_at).isSame(currentTime, "day");
const isStillWorking = (0, import_dayjs.default)(time.end_at).isAfter(currentTime);
return isToday && isStillWorking;
});
if (todayTimes.length === 0) {
console.log(`[TimeslotUtils] 资源 ${resource.id}(${resource.main_field}) 今日无可用时间段`);
continue;
}
for (const time of todayTimes) {
const workStartTime = (0, import_dayjs.default)(time.start_at);
const workEndTime = (0, import_dayjs.default)(time.end_at);
let nextAvailableTime = currentTime.isBefore(workStartTime) ? workStartTime : currentTime;
console.log(`[TimeslotUtils] 检查资源 ${resource.id}(${resource.main_field}):`, {
workTime: `${workStartTime.format("HH:mm")}-${workEndTime.format("HH:mm")}`,
checkStartTime: nextAvailableTime.format("HH:mm:ss"),
eventCount: ((_a = time.event_list) == null ? void 0 : _a.length) || 0
});
const relevantEvents = ((_b = time.event_list) == null ? void 0 : _b.filter((event) => {
const eventEnd = (0, import_dayjs.default)(event.end_at);
return eventEnd.isAfter(nextAvailableTime);
})) || [];
relevantEvents.sort(
(a, b) => (0, import_dayjs.default)(a.start_at).diff((0, import_dayjs.default)(b.start_at))
);
let finalAvailableTime = nextAvailableTime;
for (const event of relevantEvents) {
const eventStart = (0, import_dayjs.default)(event.start_at);
const eventEnd = (0, import_dayjs.default)(event.end_at);
console.log(`[TimeslotUtils] 检查事件冲突:`, {
resourceId: resource.id,
eventTime: `${eventStart.format("HH:mm")}-${eventEnd.format("HH:mm")}`,
checkTime: finalAvailableTime.format("HH:mm:ss"),
pax: event.pax || 1
});
if (resource.resourceType === "single" || (resource.capacity || 1) === 1) {
if (finalAvailableTime.isBefore(eventEnd) && eventStart.isBefore(finalAvailableTime.add(30, "minute"))) {
finalAvailableTime = eventEnd;
console.log(`[TimeslotUtils] 发现时间冲突,调整到: ${finalAvailableTime.format("HH:mm:ss")}`);
}
} else {
const totalCapacity = resource.capacity || 0;
const currentUsedCapacity = countMap[resource.id] || 0;
const eventUsedCapacity = event.pax || 1;
if (finalAvailableTime.isBefore(eventEnd) && eventStart.isBefore(finalAvailableTime.add(30, "minute"))) {
const totalRequiredCapacity = currentUsedCapacity + currentCapacity + eventUsedCapacity;
if (totalRequiredCapacity > totalCapacity) {
finalAvailableTime = eventEnd;
console.log(`[TimeslotUtils] 容量不足,调整到: ${finalAvailableTime.format("HH:mm:ss")}`);
}
}
}
}
if (finalAvailableTime.isAfter(workEndTime)) {
console.log(`[TimeslotUtils] 资源 ${resource.id} 可用时间超出工作时间,跳过`);
continue;
}
console.log(`[TimeslotUtils] 资源 ${resource.id}(${resource.main_field}) 最快可用时间: ${finalAvailableTime.format("HH:mm:ss")}`);
if (!fastestTime || finalAvailableTime.isBefore(fastestTime)) {
fastestTime = finalAvailableTime;
fastestResources = [resource];
console.log(`[TimeslotUtils] 更新最快时间: ${fastestTime.format("HH:mm:ss")}, 资源: ${resource.main_field}`);
} else if (finalAvailableTime.isSame(fastestTime)) {
fastestResources.push(resource);
console.log(`[TimeslotUtils] 添加相同时间资源: ${resource.main_field}`);
}
break;
}
}
if (!fastestTime || fastestResources.length === 0) {
console.log("[TimeslotUtils] 未找到可用资源");
return null;
}
console.log(`[TimeslotUtils] 找到 ${fastestResources.length} 个最快可用资源,时间: ${fastestTime.format("HH:mm:ss")}`);
if (fastestResources.length === 1) {
console.log(`[TimeslotUtils] 返回唯一最快资源: ${fastestResources[0].main_field}`);
return fastestResources[0];
}
let selectedResource = fastestResources[0];
let maxIdleTime = 0;
console.log(`[TimeslotUtils] 比较 ${fastestResources.length} 个资源的空闲时间:`);
for (const resource of fastestResources) {
const workingTime = resource.times.find((time) => {
const isToday = (0, import_dayjs.default)(time.start_at).isSame(fastestTime, "day");
const isStillWorking = (0, import_dayjs.default)(time.end_at).isAfter(fastestTime);
return isToday && isStillWorking;
});
if (!workingTime)
continue;
const workEndTime = (0, import_dayjs.default)(workingTime.end_at);
let totalIdleTime = workEndTime.diff(fastestTime, "minute");
const relevantEvents = ((_c = workingTime.event_list) == null ? void 0 : _c.filter((event) => {
const eventStart = (0, import_dayjs.default)(event.start_at);
const eventEnd = (0, import_dayjs.default)(event.end_at);
return eventEnd.isAfter(fastestTime) && eventStart.isAfter(fastestTime);
})) || [];
for (const event of relevantEvents) {
const eventStart = (0, import_dayjs.default)(event.start_at);
const eventEnd = (0, import_dayjs.default)(event.end_at);
const eventDuration = eventEnd.diff(eventStart, "minute");
totalIdleTime -= eventDuration;
}
console.log(`[TimeslotUtils] 资源 ${resource.id}(${resource.main_field}):`, {
工作结束时间: workEndTime.format("HH:mm"),
总工作时长: workEndTime.diff(fastestTime, "minute") + "分钟",
预约占用时长: workEndTime.diff(fastestTime, "minute") - totalIdleTime + "分钟",
实际空闲时长: totalIdleTime + "分钟"
});
if (totalIdleTime > maxIdleTime) {
maxIdleTime = totalIdleTime;
selectedResource = resource;
console.log(`[TimeslotUtils] 更新最佳选择: ${resource.main_field} (空闲${totalIdleTime}分钟)`);
}
}
console.log(`[TimeslotUtils] 最终选择资源: ${selectedResource.main_field} (最长空闲${maxIdleTime}分钟)`);
return selectedResource;
}
function filterConditionTimeSlots(times, startTime, endTime) {
return times.filter((n) => {
return !(0, import_dayjs.default)(n.start_at).isAfter((0, import_dayjs.default)(startTime)) && !(0, import_dayjs.default)(n.end_at).isBefore((0, import_dayjs.default)(endTime));
});
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
calculateResourceAvailableTime,
filterConditionTimeSlots,
findFastestAvailableResource
});