import type { Dayjs } from 'dayjs'; import type { RecordBoardCalendarBookingLike } from '../../../types'; /** * 日历日期与时间轴纯函数:`fmtDate`、占用矩阵、月格、overlay 分段、周范围等,供 BookingCalendar 三视图共用。 */ /** 与 {@link RecordBoardCalendarBookingLike} 一致,并支持跨日 endDate */ export declare type CalendarBookingSegmentInput = RecordBoardCalendarBookingLike & { endDate?: string; }; export interface BookingSegmentForDate { startHour: number; endHour: number; continuesPrev: boolean; continuesNext: boolean; } export interface ViewNowReference { dateKey: string; hourFloat: number; } export declare function fmtDate(date: Date): string; /** 本地当前日期键与「日历时」小数小时,用于状态徽标与当前时刻线 */ export declare function getViewNowReference(): ViewNowReference; export declare function parseDate(str: string): Date; export declare function addDays(date: Date, n: number): Date; export declare function startOfWeek(date: Date): Date; export declare function rangeDays(anchor: Date): Date[]; /** * 锚定日所在自然月的每一天(1 号至月末),用于资源视图横向「日」列。 */ export declare function monthCalendarDays(anchor: Date): Date[]; export declare function isHourInTimelineSlots(hour: number, hourSlots: number[] | undefined): boolean; export declare function formatHourLabel(hour: number): string; export declare function buildTimeOptions(start?: number, end?: number, sliceMinutes?: number): number[]; export declare function monthGrid(date: Date, bookings: CalendarBookingSegmentInput[], courtsList: { id: string; }[] | undefined, hourSlotsIn: number[] | undefined, slotStepHours?: number): { date: Date; key: string; inMonth: boolean; bookingCount: number; blockCount: number; fullyBooked: boolean; }[]; export declare function getBookingSegmentForDate(item: CalendarBookingSegmentInput, dateKey: string): BookingSegmentForDate | null; export declare function dayOccupancy(courtId: string, dateKey: string, bookings: CalendarBookingSegmentInput[], hourSlots: number[] | undefined, slotStepHours: number): Record; export interface SelectedSlotLike { courtId: string; date: string; hour: number; } export declare function groupSelectedSlots(slots: SelectedSlotLike[], slotStepHours?: number): Array<{ courtId: string; date: string; startHour: number; endHour: number; }>; /** * 日视图空闲格:仅当全部为同一 court、同一日,且时间上首尾相接成一段时返回 true(与 {@link groupSelectedSlots} 合并规则一致)。 */ export declare function isFreeSelectionContiguousSameResource(slots: SelectedSlotLike[], slotStepHours?: number): boolean; export declare function hasConflict(bookings: CalendarBookingSegmentInput[], courtId: string, date: string, startHour: number, endHour: number, ignoreId?: string | null): boolean; export declare function overlappingBookings(bookings: CalendarBookingSegmentInput[], courtId: string, date: string, startHour: number, endHour: number): CalendarBookingSegmentInput[]; export declare function courtDaySummary(courtId: string, dateKey: string, bookings: CalendarBookingSegmentInput[], hourSlots: number[] | undefined, slotStepHours: number): { occupiedHours: number[]; hasBlock: boolean; fullyBooked: boolean; items: CalendarBookingSegmentInput[]; }; export declare function sameSlot(a: SelectedSlotLike, b: SelectedSlotLike): boolean; /** 营业日 `dateStr` + 浮点小时(含半格)→ dayjs */ export declare function dayAndHourToDayjs(dateStr: string, hourFloat: number): Dayjs; export declare function getDisplayStatusTag(item: CalendarBookingSegmentInput, dateKey: string): string | null; export declare function getLateMinutes(item: CalendarBookingSegmentInput, dateKey: string): number | null; export declare function currentTimeLabel(): string; export declare function formatDateLoose(str: string | undefined): string; export declare function formatTimelineStamp(value: string | undefined | null): { date: string; time: string; }; /** 日视图 overlay 条(可原地写入 lane) */ export declare type DayOverlayLaneMutable = { courtId: string; start: number; span: number; lane?: number; laneCount?: number; }; /** * 同一 court 上时间重叠的 overlay 分配纵向 lane,避免多张卡片完全叠在同一矩形里。 * 使用按开始时间排序 + 贪心:每条预约放入「上一条已结束时间不晚于本段开始」的最小编号线。 */ export declare function assignDayOverlapLanesInPlace(overlays: DayOverlayLaneMutable[]): void; /** 扫描时间轴:同一 court 在任一时刻的最大并行条数(用于行高,与分 lane 一致) */ export declare function maxConcurrentBookingsOnCourt(overlays: Array<{ courtId: string; start: number; span: number; }>, courtId: string): number; /** 并行超过 cap 时:cap 条内容 + 1 行「+N」占位 */ export declare function effectiveDayOverlayDisplayLaneCount(rawConcurrent: number): number; /** 同一 court 下时间轴区间相交的 overlay 归为一簇(用于 3+N 合并展示) */ export declare function clusterDayCourtOverlaysByOverlap(overlays: T[], courtId: string): T[][]; export declare function dayOverlayHiddenKey(item: { id?: string | number; } | null | undefined, dayKey: string, courtId: string): string; /** * 将 totalInner 像素整数分给 n 条竖向 lane(含缝),保证 Σheight + Σgap === totalInner,消除底部留白缝。 */ export declare function dayOverlayLaneMetrics(totalInner: number, laneCount: number, gap: number): { topFor: (lane: number) => number; heightFor: (lane: number) => number; }; export interface BuildOverlayBookingRow { kind: string; id: string; } export interface BuiltDayOverlay { item: CalendarBookingSegmentInput; rowIndex: number; rowTop: number; rowHeight: number; courtId: string; start: number; end: number; span: number; continuesNext?: boolean; continuesPrev?: boolean; lane?: number; laneCount?: number; } export declare function buildOverlayBookings(visibleCourtRows: BuildOverlayBookingRow[], dayKey: string, bookings: CalendarBookingSegmentInput[], rowTopMap: Record | undefined, hourSlots: number[] | undefined, dayRowHeights: number[], slotStepHours?: number): BuiltDayOverlay[]; /** 日视图:按行高累加每行 rowTop(court / group) */ export declare function buildDayRowTopMap(visibleCourtRows: Array<{ id: string; }>, heights: number[]): Record; /** 日历状态徽标:返回 i18n key + className;文案在 UI 层通过 tCal 解析,便于 utils 单测 */ export declare function statusTagMetaParts(tag: string | null | undefined): { labelI18nKey: string; className: string; } | null; export declare type CalendarCourtNameRow = { id: string; name?: string | null; }; export declare function getBookingDetailData(item: CalendarBookingSegmentInput, courtsList?: CalendarCourtNameRow[]): { rawSales: null; bookingId: string; orderNumber: string; shopOrderNumber: string; orderStatus: string; appointmentStatus: string; paymentStatus: string; customer: { id: null; name: string; email: string; phone: string; }; guestCount: number; checkedInCount: number; guests: never[]; schedule: { startDate: string; startTime: string; endDate: string; endTime: string; duration: number; arrivedAt: null; completedAt: null; }; resources: never[]; summaryItems: never[]; items: never[]; note: string; files: { form: never[]; uploaded: never[]; invoice: never[]; }; payments: never[]; history: never[]; summary: {}; paymentSummary: { totalAmount: number; paidAmount: number; balanceAmount: number; currencySymbol: string; isFullyPaid: boolean; }; itemSummary: { itemCount: number; itemQtyTotal: number; }; headerSummary: { customerName: string; guestCount: number; checkedInCount: number; timeLabel: string; resourceLabel: string; }; headerTags: { paymentTag: string; fulfillmentTag: string; hasNote: boolean; paymentStatus: string; orderStatus: string; }; fileCount: number; canChangeCustomer: boolean; noteCount: number; noteGroups: { internal: never[]; order: { id: string; label: string; text: string; }[]; item: never[]; }; metaFlags: { itemsChanged: boolean; paymentsChanged: boolean; guestChanged: boolean; filesChanged: boolean; notesChanged: boolean; formChanged: boolean; uploadedChanged: boolean; invoiceChanged: boolean; historyChanged: boolean; }; actions: never[]; };