@pisell/materials 1.8.34 → 1.8.36
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/build/lowcode/assets-daily.json +11 -11
- package/build/lowcode/assets-dev.json +2 -2
- package/build/lowcode/assets-prod.json +11 -11
- package/build/lowcode/index.js +1 -1
- package/build/lowcode/meta.js +2 -2
- package/build/lowcode/preview.js +1 -1
- package/build/lowcode/render/default/view.css +1 -1
- package/build/lowcode/render/default/view.js +35 -35
- package/build/lowcode/view.css +1 -1
- package/build/lowcode/view.js +35 -35
- package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.js +25 -10
- package/es/components/pisellFloorMapLayout/appearance/floorMapAppearance.d.ts +4 -0
- package/es/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +22 -0
- package/es/components/pisellFloorMapLayout/components/EditableItemLayer.js +3 -2
- package/es/components/pisellFloorMapLayout/components/ItemLayer.js +7 -4
- package/es/components/pisellFloorMapLayout/components/ItemLayer.less +10 -0
- package/es/components/pisellFloorMapLayout/components/ViewControls.js +6 -5
- package/es/components/pisellFloorMapLayout/components/ViewControls.less +29 -2
- package/es/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +1 -0
- package/es/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +3 -1
- package/es/components/pisellFloorMapLayout/types.d.ts +21 -2
- package/es/components/pisellRecordBoard/index.d.ts +1 -1
- package/es/components/pisellRecordBoard/shellFrame/Calendar/BookingCalendar.js +280 -230
- package/es/components/pisellRecordBoard/shellFrame/Calendar/const/bookingCalendarConstants.js +18 -1
- package/es/components/pisellRecordBoard/shellFrame/Calendar/hooks/useBookingCalendarDayOverlayLayout.js +74 -0
- package/es/components/pisellRecordBoard/shellFrame/Calendar/modal/BookingCalendarBlockPanel.js +61 -0
- package/es/components/pisellRecordBoard/shellFrame/Calendar/modal/BookingCalendarOverflowListLayer.js +26 -0
- package/es/components/pisellRecordBoard/shellFrame/Calendar/utils/bookingCalendarDateUtils.js +11 -1
- package/es/components/pisellRecordBoard/shellFrame/Calendar/utils/bookingCalendarSelectionUtils.js +17 -0
- package/es/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarDaySelectionBar.js +12 -8
- package/es/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarDayView.js +3 -12
- package/es/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarResourceView.js +612 -0
- package/es/components/pisellRecordBoard/shellFrame/Calendar/view/day/useBookingCalendarDayHourRemaining.js +33 -0
- package/es/components/pisellRecordBoard/shellFrame/Calendar/view/day/useBookingCalendarDaySelection.js +37 -0
- package/es/components/pisellRecordBoard/shellFrame/Calendar/view/resource/useBookingCalendarResourceCellToggle.js +18 -0
- package/es/components/pisellRecordBoard/shellFrame/Calendar/view/resource/useBookingCalendarResourceDayHeaderRemaining.js +33 -0
- package/es/components/pisellRecordBoard/shellFrame/Calendar/view/useBookingCalendarGoToDayFromCell.js +29 -0
- package/es/components/pisellRecordBoard/types.d.ts +38 -6
- package/es/components/pisellReservationSchedule/PisellReservationSchedule.js +19 -3
- package/es/components/pisellReservationSchedule/PisellReservationSchedule.less +23 -0
- package/es/index.d.ts +2 -2
- package/es/locales/en-US.js +6 -5
- package/es/locales/ja.js +1 -0
- package/es/locales/pt.js +1 -0
- package/es/locales/zh-CN.js +1 -0
- package/es/locales/zh-TW.js +1 -0
- package/es/pisell-materials.tw.css +2413 -2
- package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.js +25 -10
- package/lib/components/pisellFloorMapLayout/appearance/floorMapAppearance.d.ts +4 -0
- package/lib/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +22 -0
- package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.js +3 -2
- package/lib/components/pisellFloorMapLayout/components/ItemLayer.js +7 -4
- package/lib/components/pisellFloorMapLayout/components/ItemLayer.less +10 -0
- package/lib/components/pisellFloorMapLayout/components/ViewControls.js +6 -5
- package/lib/components/pisellFloorMapLayout/components/ViewControls.less +29 -2
- package/lib/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +1 -0
- package/lib/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +3 -1
- package/lib/components/pisellFloorMapLayout/types.d.ts +21 -2
- package/lib/components/pisellRecordBoard/index.d.ts +1 -1
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/BookingCalendar.js +277 -227
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/const/bookingCalendarConstants.js +18 -0
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/hooks/useBookingCalendarDayOverlayLayout.js +75 -0
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/modal/BookingCalendarBlockPanel.js +63 -0
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/modal/BookingCalendarOverflowListLayer.js +28 -0
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/utils/bookingCalendarDateUtils.js +11 -1
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/utils/bookingCalendarSelectionUtils.js +17 -0
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarDaySelectionBar.js +12 -8
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarDayView.js +3 -12
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarResourceView.js +614 -0
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/day/useBookingCalendarDayHourRemaining.js +34 -0
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/day/useBookingCalendarDaySelection.js +38 -0
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/resource/useBookingCalendarResourceCellToggle.js +19 -0
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/resource/useBookingCalendarResourceDayHeaderRemaining.js +34 -0
- package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/useBookingCalendarGoToDayFromCell.js +30 -0
- package/lib/components/pisellRecordBoard/types.d.ts +38 -6
- package/lib/components/pisellReservationSchedule/PisellReservationSchedule.js +19 -3
- package/lib/components/pisellReservationSchedule/PisellReservationSchedule.less +23 -0
- package/lib/index.d.ts +2 -2
- package/lib/locales/en-US.js +6 -5
- package/lib/locales/ja.js +1 -0
- package/lib/locales/pt.js +1 -0
- package/lib/locales/zh-CN.js +1 -0
- package/lib/locales/zh-TW.js +1 -0
- package/lib/pisell-materials.tw.css +2413 -2
- package/lowcode/pisell-record-board-calendar-view/meta.ts +8 -0
- package/package.json +1 -1
package/es/components/pisellRecordBoard/shellFrame/Calendar/const/bookingCalendarConstants.js
CHANGED
|
@@ -16,7 +16,24 @@ function dayCourtOverlayRowHeightPx(displayLaneCount) {
|
|
|
16
16
|
const n = Math.max(1, displayLaneCount);
|
|
17
17
|
return 16 + n * 64 + (n - 1) * 2;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* 资源视图:按某一格「courtDaySummary」结果估算该格所需最小高度(px)。
|
|
21
|
+
* 用于横向虚拟化仅挂载可见日期列时,仍按**全月**最大内容撑开行高,避免日程只在屏幕外列时出现行高塌陷。
|
|
22
|
+
*/
|
|
23
|
+
function estimateResourceViewCourtCellHeightPx(summary) {
|
|
24
|
+
var _summary$items$length, _summary$items;
|
|
25
|
+
const pad = 8;
|
|
26
|
+
if (summary.fullyBooked) return 28 + pad;
|
|
27
|
+
const n = (_summary$items$length = (_summary$items = summary.items) === null || _summary$items === void 0 ? void 0 : _summary$items.length) !== null && _summary$items$length !== void 0 ? _summary$items$length : 0;
|
|
28
|
+
if (n === 0) return 44;
|
|
29
|
+
const previewCount = Math.min(3, n);
|
|
30
|
+
const showMoreTile = Math.max(0, n - 3) > 0 && previewCount > 0;
|
|
31
|
+
const gap = 4;
|
|
32
|
+
let content = previewCount * 48 + (previewCount > 1 ? (previewCount - 1) * gap : 0);
|
|
33
|
+
if (showMoreTile) content += gap + 48;
|
|
34
|
+
return pad + content;
|
|
35
|
+
}
|
|
19
36
|
const MONTH_OVERFLOW_POPOVER_ITEM_H = 72;
|
|
20
37
|
const OVERFLOW_MODAL_ROW_H = 108;
|
|
21
38
|
//#endregion
|
|
22
|
-
export { CALENDAR_EMPTY_DASHED_SLOT_CLASSNAME, DEFAULT_CALENDAR_TIMELINE, MONTH_OVERFLOW_POPOVER_ITEM_H, OVERFLOW_MODAL_ROW_H, dayCourtOverlayRowHeightPx };
|
|
39
|
+
export { CALENDAR_EMPTY_DASHED_SLOT_CLASSNAME, DEFAULT_CALENDAR_TIMELINE, MONTH_OVERFLOW_POPOVER_ITEM_H, OVERFLOW_MODAL_ROW_H, dayCourtOverlayRowHeightPx, estimateResourceViewCourtCellHeightPx };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { dayCourtOverlayRowHeightPx } from "../const/bookingCalendarConstants.js";
|
|
2
|
+
import { buildDayRowTopMap, buildOverlayBookings, clusterDayCourtOverlaysByOverlap, dayOverlayHiddenKey, effectiveDayOverlayDisplayLaneCount, maxConcurrentBookingsOnCourt } from "../utils/bookingCalendarDateUtils.js";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
//#region src/components/pisellRecordBoard/shellFrame/Calendar/hooks/useBookingCalendarDayOverlayLayout.ts
|
|
5
|
+
/**
|
|
6
|
+
* 日视图:按 overlay 并行度计算行高、booking overlay 列表、+N 溢出汇总。
|
|
7
|
+
*/
|
|
8
|
+
function useBookingCalendarDayOverlayLayout(visibleCourtRows, dayKey, bookings, hourSlots, slotStepHours) {
|
|
9
|
+
return useMemo(() => {
|
|
10
|
+
const defaultHeights = visibleCourtRows.map((row) => row.kind === "group" ? 38 : 44);
|
|
11
|
+
let overlays = buildOverlayBookings(visibleCourtRows, dayKey, bookings, buildDayRowTopMap(visibleCourtRows, defaultHeights), hourSlots, defaultHeights, slotStepHours);
|
|
12
|
+
const expandedHeights = visibleCourtRows.map((row, i) => {
|
|
13
|
+
if (row.kind !== "court") return defaultHeights[i];
|
|
14
|
+
if (!overlays.some((o) => o.courtId === row.id)) return defaultHeights[i];
|
|
15
|
+
return dayCourtOverlayRowHeightPx(effectiveDayOverlayDisplayLaneCount(maxConcurrentBookingsOnCourt(overlays, row.id)));
|
|
16
|
+
});
|
|
17
|
+
const tops2 = buildDayRowTopMap(visibleCourtRows, expandedHeights);
|
|
18
|
+
overlays = buildOverlayBookings(visibleCourtRows, dayKey, bookings, tops2, hourSlots, expandedHeights, slotStepHours);
|
|
19
|
+
const courtDayDisplayLaneCount = {};
|
|
20
|
+
const hiddenDayOverlayIdSet = /* @__PURE__ */ new Set();
|
|
21
|
+
const dayOverlayOverflowPluses = [];
|
|
22
|
+
for (const row of visibleCourtRows) {
|
|
23
|
+
if (row.kind !== "court") continue;
|
|
24
|
+
const cid = row.id;
|
|
25
|
+
courtDayDisplayLaneCount[cid] = effectiveDayOverlayDisplayLaneCount(maxConcurrentBookingsOnCourt(overlays, cid));
|
|
26
|
+
const clusters = clusterDayCourtOverlaysByOverlap(overlays, cid);
|
|
27
|
+
for (const cluster of clusters) {
|
|
28
|
+
if (cluster.length <= 3) continue;
|
|
29
|
+
const sortedByLane = [...cluster].sort((a, b) => {
|
|
30
|
+
var _a$lane, _b$lane;
|
|
31
|
+
return ((_a$lane = a.lane) !== null && _a$lane !== void 0 ? _a$lane : 0) - ((_b$lane = b.lane) !== null && _b$lane !== void 0 ? _b$lane : 0) || a.start - b.start;
|
|
32
|
+
});
|
|
33
|
+
for (let i = 3; i < sortedByLane.length; i++) {
|
|
34
|
+
const o = sortedByLane[i];
|
|
35
|
+
hiddenDayOverlayIdSet.add(dayOverlayHiddenKey(o.item, dayKey, o.courtId));
|
|
36
|
+
}
|
|
37
|
+
const hidden = sortedByLane.slice(3);
|
|
38
|
+
let minS = Infinity;
|
|
39
|
+
let maxE = -Infinity;
|
|
40
|
+
for (const o of cluster) {
|
|
41
|
+
minS = Math.min(minS, o.start);
|
|
42
|
+
maxE = Math.max(maxE, o.start + o.span);
|
|
43
|
+
}
|
|
44
|
+
const anchor = hidden[0];
|
|
45
|
+
dayOverlayOverflowPluses.push({
|
|
46
|
+
key: `${cid}-${minS}-${maxE}-${dayKey}`,
|
|
47
|
+
courtId: cid,
|
|
48
|
+
rowTop: anchor.rowTop,
|
|
49
|
+
rowHeight: anchor.rowHeight,
|
|
50
|
+
start: minS,
|
|
51
|
+
span: maxE - minS,
|
|
52
|
+
plusCount: hidden.length,
|
|
53
|
+
overflowItems: hidden.map((o) => o.item)
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
dayRowHeights: expandedHeights,
|
|
59
|
+
dayRowTopMap: tops2,
|
|
60
|
+
overlayBookings: overlays,
|
|
61
|
+
courtDayDisplayLaneCount,
|
|
62
|
+
hiddenDayOverlayIdSet,
|
|
63
|
+
dayOverlayOverflowPluses
|
|
64
|
+
};
|
|
65
|
+
}, [
|
|
66
|
+
visibleCourtRows,
|
|
67
|
+
dayKey,
|
|
68
|
+
bookings,
|
|
69
|
+
hourSlots,
|
|
70
|
+
slotStepHours
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { useBookingCalendarDayOverlayLayout };
|
package/es/components/pisellRecordBoard/shellFrame/Calendar/modal/BookingCalendarBlockPanel.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { tCal } from "../calendarI18n.js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { DatePicker } from "antd";
|
|
4
|
+
import { CloseOutlined } from "@ant-design/icons";
|
|
5
|
+
//#region src/components/pisellRecordBoard/shellFrame/Calendar/modal/BookingCalendarBlockPanel.tsx
|
|
6
|
+
const { RangePicker } = DatePicker;
|
|
7
|
+
/**
|
|
8
|
+
* 内置锁台 / 屏蔽时间表单(宿主未传 `onBlockedTimePanelRequest` 时使用)。
|
|
9
|
+
*/
|
|
10
|
+
function BookingCalendarBlockPanel({ blockPanelRef, isLight, blockFormName, setBlockFormName, blockModalNote, setBlockModalNote, blockResourceId, setBlockResourceId, blockTimeRange, setBlockTimeRange, resolvedSlotMinutes, visibleCourts, blockSaving, onClose, onSave }) {
|
|
11
|
+
return /* @__PURE__ */ React.createElement("div", { className: "fixed inset-0 z-50 bg-black/55 backdrop-blur-sm flex items-end md:items-center justify-center p-2 md:p-4" }, /* @__PURE__ */ React.createElement("div", {
|
|
12
|
+
ref: blockPanelRef,
|
|
13
|
+
className: `w-full max-w-[720px] max-h-[92vh] overflow-y-auto rounded-t-3xl md:rounded-3xl border p-4 md:p-6 shadow-2xl ${isLight ? "theme-panel theme-border soft-shadow" : "border-zinc-700 bg-[#121217]"}`
|
|
14
|
+
}, /* @__PURE__ */ React.createElement("div", { className: "mb-4 flex items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", { className: "text-xl font-semibold" }, tCal("pisell2.recordBoard.calendar.block.panelTitle")), /* @__PURE__ */ React.createElement("button", {
|
|
15
|
+
type: "button",
|
|
16
|
+
"aria-label": tCal("pisell2.recordBoard.calendar.block.closeAria"),
|
|
17
|
+
onClick: onClose,
|
|
18
|
+
className: `rounded-xl p-2 ${isLight ? "btn-neutral" : "border border-zinc-700 text-zinc-300"}`
|
|
19
|
+
}, /* @__PURE__ */ React.createElement(CloseOutlined, { style: { fontSize: 20 } }))), /* @__PURE__ */ React.createElement("div", { className: `space-y-4 rounded-2xl border p-4 ${isLight ? "theme-panel-alt theme-border" : "border-zinc-700 bg-[#171820]"}` }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}` }, tCal("pisell2.recordBoard.calendar.block.fieldTitle")), /* @__PURE__ */ React.createElement("input", {
|
|
20
|
+
value: blockFormName,
|
|
21
|
+
onChange: (e) => setBlockFormName(e.target.value),
|
|
22
|
+
placeholder: tCal("pisell2.recordBoard.calendar.block.placeholderTitle"),
|
|
23
|
+
className: `w-full rounded-xl px-3 py-2 outline-none ${isLight ? "theme-input theme-text" : "border border-zinc-700 bg-[#111218] text-white"}`
|
|
24
|
+
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}` }, "备注"), /* @__PURE__ */ React.createElement("input", {
|
|
25
|
+
value: blockModalNote,
|
|
26
|
+
onChange: (e) => setBlockModalNote(e.target.value),
|
|
27
|
+
placeholder: "选填",
|
|
28
|
+
className: `w-full rounded-xl px-3 py-2 outline-none ${isLight ? "theme-input theme-text" : "border border-zinc-700 bg-[#111218] text-white"}`
|
|
29
|
+
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}` }, tCal("pisell2.recordBoard.calendar.block.fieldResource")), /* @__PURE__ */ React.createElement("select", {
|
|
30
|
+
value: blockResourceId,
|
|
31
|
+
onChange: (e) => setBlockResourceId(e.target.value),
|
|
32
|
+
className: `w-full rounded-xl px-3 py-2 outline-none ${isLight ? "theme-input theme-text" : "border border-zinc-700 bg-[#111218] text-white"}`
|
|
33
|
+
}, /* @__PURE__ */ React.createElement("option", { value: "" }, tCal("pisell2.recordBoard.calendar.block.noResource")), visibleCourts.map((c) => /* @__PURE__ */ React.createElement("option", {
|
|
34
|
+
key: c.id,
|
|
35
|
+
value: String(c.id)
|
|
36
|
+
}, c.name)))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}` }, tCal("pisell2.recordBoard.calendar.block.fieldTimeRange")), /* @__PURE__ */ React.createElement(RangePicker, {
|
|
37
|
+
style: { width: "100%" },
|
|
38
|
+
showTime: {
|
|
39
|
+
format: "HH:mm",
|
|
40
|
+
minuteStep: resolvedSlotMinutes >= 60 ? 60 : Math.max(1, resolvedSlotMinutes)
|
|
41
|
+
},
|
|
42
|
+
format: "YYYY-MM-DD HH:mm",
|
|
43
|
+
value: blockTimeRange !== null && blockTimeRange !== void 0 ? blockTimeRange : void 0,
|
|
44
|
+
onChange: (v) => {
|
|
45
|
+
var _ref;
|
|
46
|
+
return setBlockTimeRange((_ref = v) !== null && _ref !== void 0 ? _ref : null);
|
|
47
|
+
}
|
|
48
|
+
}))), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-col-reverse sm:flex-row items-stretch sm:items-center justify-end gap-3" }, /* @__PURE__ */ React.createElement("button", {
|
|
49
|
+
type: "button",
|
|
50
|
+
disabled: blockSaving,
|
|
51
|
+
onClick: onClose,
|
|
52
|
+
className: `rounded-xl px-4 py-2 ${isLight ? "btn-neutral" : "border border-zinc-700 text-zinc-300"}`
|
|
53
|
+
}, tCal("pisell2.recordBoard.calendar.common.cancel")), /* @__PURE__ */ React.createElement("button", {
|
|
54
|
+
type: "button",
|
|
55
|
+
disabled: blockSaving,
|
|
56
|
+
onClick: () => void onSave(),
|
|
57
|
+
className: `rounded-xl px-5 py-3 text-sm font-semibold disabled:opacity-50 ${isLight ? "btn-brand" : "bg-violet-600 text-white"}`
|
|
58
|
+
}, blockSaving ? tCal("pisell2.recordBoard.calendar.common.saving") : tCal("pisell2.recordBoard.calendar.common.save")))));
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { BookingCalendarBlockPanel };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { tCal } from "../calendarI18n.js";
|
|
2
|
+
import { OverflowListModalVirtualList } from "./OverflowListModal.js";
|
|
3
|
+
import React from "react";
|
|
4
|
+
//#region src/components/pisellRecordBoard/shellFrame/Calendar/modal/BookingCalendarOverflowListLayer.tsx
|
|
5
|
+
/**
|
|
6
|
+
* 全局溢出预约列表弹层(月/周/资源格 `+N` 点开后)。
|
|
7
|
+
*/
|
|
8
|
+
function BookingCalendarOverflowListLayer({ overflowPanelRef, isLight, modal, onClose, onPickItem }) {
|
|
9
|
+
return /* @__PURE__ */ React.createElement("div", { className: "fixed inset-0 z-[69] bg-black/45 backdrop-blur-sm flex items-center justify-center p-4" }, /* @__PURE__ */ React.createElement("div", {
|
|
10
|
+
ref: overflowPanelRef,
|
|
11
|
+
className: `flex w-full max-w-[520px] max-h-[72vh] flex-col overflow-hidden rounded-3xl border p-5 shadow-2xl ${isLight ? "theme-panel theme-border soft-shadow" : "border-zinc-700 bg-[#121217]"}`
|
|
12
|
+
}, /* @__PURE__ */ React.createElement("div", { className: "mb-4 flex shrink-0 items-start justify-between" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "text-xl font-semibold" }, tCal("pisell2.recordBoard.calendar.overflow.bookingsForDay")), /* @__PURE__ */ React.createElement("div", { className: "mt-1 text-sm text-zinc-400" }, modal.title)), /* @__PURE__ */ React.createElement("button", {
|
|
13
|
+
type: "button",
|
|
14
|
+
onClick: onClose,
|
|
15
|
+
className: "rounded-xl border border-zinc-700 px-3 py-2 text-zinc-300"
|
|
16
|
+
}, tCal("pisell2.recordBoard.calendar.common.close"))), /* @__PURE__ */ React.createElement("div", { className: "min-h-0 flex-1 overflow-hidden px-0.5" }, /* @__PURE__ */ React.createElement(OverflowListModalVirtualList, {
|
|
17
|
+
items: modal.items,
|
|
18
|
+
dateKey: modal.date,
|
|
19
|
+
listWidth: 468,
|
|
20
|
+
onPickItem,
|
|
21
|
+
onClose,
|
|
22
|
+
showStatusUi: Boolean(modal.scope && String(modal.scope).startsWith("day-lane-overflow-"))
|
|
23
|
+
}))));
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { BookingCalendarOverflowListLayer };
|
package/es/components/pisellRecordBoard/shellFrame/Calendar/utils/bookingCalendarDateUtils.js
CHANGED
|
@@ -35,6 +35,16 @@ function rangeDays(anchor) {
|
|
|
35
35
|
const start = startOfWeek(anchor);
|
|
36
36
|
return Array.from({ length: 7 }, (_, i) => addDays(start, i));
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* 锚定日所在自然月的每一天(1 号至月末),用于资源视图横向「日」列。
|
|
40
|
+
*/
|
|
41
|
+
function monthCalendarDays(anchor) {
|
|
42
|
+
const base = anchor instanceof Date && !Number.isNaN(anchor.getTime()) ? anchor : /* @__PURE__ */ new Date();
|
|
43
|
+
const y = base.getFullYear();
|
|
44
|
+
const m = base.getMonth();
|
|
45
|
+
const last = new Date(y, m + 1, 0).getDate();
|
|
46
|
+
return Array.from({ length: last }, (_, i) => new Date(y, m, i + 1));
|
|
47
|
+
}
|
|
38
48
|
function isHourInTimelineSlots(hour, hourSlots) {
|
|
39
49
|
if (!(hourSlots === null || hourSlots === void 0 ? void 0 : hourSlots.length)) return false;
|
|
40
50
|
return hourSlots.some((x) => Math.abs(x - hour) < 1e-6);
|
|
@@ -519,4 +529,4 @@ function getBookingDetailData(item, courtsList = []) {
|
|
|
519
529
|
};
|
|
520
530
|
}
|
|
521
531
|
//#endregion
|
|
522
|
-
export { addDays, buildDayRowTopMap, buildOverlayBookings, clusterDayCourtOverlaysByOverlap, courtDaySummary, currentTimeLabel, dayAndHourToDayjs, dayOccupancy, dayOverlayHiddenKey, dayOverlayLaneMetrics, effectiveDayOverlayDisplayLaneCount, fmtDate, formatDateLoose, formatHourLabel, getBookingDetailData,
|
|
532
|
+
export { addDays, buildDayRowTopMap, buildOverlayBookings, clusterDayCourtOverlaysByOverlap, courtDaySummary, currentTimeLabel, dayAndHourToDayjs, dayOccupancy, dayOverlayHiddenKey, dayOverlayLaneMetrics, effectiveDayOverlayDisplayLaneCount, fmtDate, formatDateLoose, formatHourLabel, getBookingDetailData, getDisplayStatusTag, getLateMinutes, getViewNowReference, groupSelectedSlots, isFreeSelectionContiguousSameResource, isHourInTimelineSlots, maxConcurrentBookingsOnCourt, monthCalendarDays, monthGrid, parseDate, rangeDays, sameSlot, startOfWeek, statusTagMetaParts };
|
package/es/components/pisellRecordBoard/shellFrame/Calendar/utils/bookingCalendarSelectionUtils.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/components/pisellRecordBoard/shellFrame/Calendar/utils/bookingCalendarSelectionUtils.ts
|
|
2
|
+
/**
|
|
3
|
+
* 资源视图选区是否「同一 court + 连续多天」:
|
|
4
|
+
* 仅当满足时才允许 Block / Create Booking(与日视图「同 court 连续多小时」语义对应)。
|
|
5
|
+
* 单天选中(n === 1)也算连续。
|
|
6
|
+
*/
|
|
7
|
+
function isResourceSelectionContiguousSameCourt(selections) {
|
|
8
|
+
if (selections.length === 0) return false;
|
|
9
|
+
const courtId = selections[0].courtId;
|
|
10
|
+
if (selections.some((s) => s.courtId !== courtId)) return false;
|
|
11
|
+
if (selections.length === 1) return true;
|
|
12
|
+
const dates = [...selections].map((s) => s.dateKey).sort().map((s) => new Date(s).getTime());
|
|
13
|
+
for (let i = 1; i < dates.length; i += 1) if (Math.round((dates[i] - dates[i - 1]) / 864e5) !== 1) return false;
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { isResourceSelectionContiguousSameCourt };
|
package/es/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarDaySelectionBar.js
CHANGED
|
@@ -3,21 +3,25 @@ import { isFreeSelectionContiguousSameResource } from "../utils/bookingCalendarD
|
|
|
3
3
|
import React from "react";
|
|
4
4
|
//#region src/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarDaySelectionBar.tsx
|
|
5
5
|
/** 日视图底部:多选空闲 / 锁台后的固定操作条 */
|
|
6
|
-
function BookingCalendarDaySelectionBar({ slotStepHours, selectedFreeSlots,
|
|
7
|
-
if (
|
|
6
|
+
function BookingCalendarDaySelectionBar({ slotStepHours, selectedFreeSlots, resourceSelectionSummary, deselectAll, onOpenBlockPanel, createBookingFromSelection }) {
|
|
7
|
+
if (!(resourceSelectionSummary != null ? resourceSelectionSummary.freePickCount > 0 : selectedFreeSlots.length > 0)) return null;
|
|
8
|
+
/**
|
|
9
|
+
* 是否允许「Block」与「Create booking」操作。
|
|
10
|
+
* - 资源视图:仅当同一 court 连续多天 → `freeAllowsBlockPanel = true`
|
|
11
|
+
* - 日视图:仅当同一 court 连续小时槽 → `isFreeSelectionContiguousSameResource = true`
|
|
12
|
+
*
|
|
13
|
+
* Create booking 与 Block 共用判定:散乱选择不允许任何创建动作。
|
|
14
|
+
*/
|
|
15
|
+
const allowCreateOrBlock = resourceSelectionSummary != null ? resourceSelectionSummary.freeAllowsBlockPanel : isFreeSelectionContiguousSameResource(selectedFreeSlots, slotStepHours);
|
|
8
16
|
return /* @__PURE__ */ React.createElement("div", { className: "fixed bottom-6 left-1/2 z-50 -translate-x-1/2" }, /* @__PURE__ */ React.createElement("div", { className: "flex max-w-[92vw] flex-wrap items-center justify-center gap-3 rounded-2xl border border-white/10 bg-black/55 px-4 py-3 shadow-2xl shadow-black/40 backdrop-blur-xl" }, /* @__PURE__ */ React.createElement("button", {
|
|
9
17
|
type: "button",
|
|
10
18
|
onClick: deselectAll,
|
|
11
19
|
className: "rounded-xl bg-red-500/85 px-4 py-2 text-sm font-semibold text-white"
|
|
12
|
-
}, tCal("pisell2.recordBoard.calendar.day.deselectAll")),
|
|
13
|
-
type: "button",
|
|
14
|
-
onClick: openSelectedBlocks,
|
|
15
|
-
className: "rounded-xl bg-zinc-500/90 px-5 py-3 text-sm font-semibold text-white"
|
|
16
|
-
}, tCal("pisell2.recordBoard.calendar.day.openSlot")), selectedFreeSlots.length > 0 && isFreeSelectionContiguousSameResource(selectedFreeSlots, slotStepHours) && /* @__PURE__ */ React.createElement("button", {
|
|
20
|
+
}, tCal("pisell2.recordBoard.calendar.day.deselectAll")), allowCreateOrBlock && /* @__PURE__ */ React.createElement("button", {
|
|
17
21
|
type: "button",
|
|
18
22
|
onClick: onOpenBlockPanel,
|
|
19
23
|
className: "rounded-xl bg-zinc-500/90 px-5 py-3 text-sm font-semibold text-white"
|
|
20
|
-
}, tCal("pisell2.recordBoard.calendar.day.block")),
|
|
24
|
+
}, tCal("pisell2.recordBoard.calendar.day.block")), allowCreateOrBlock && /* @__PURE__ */ React.createElement("button", {
|
|
21
25
|
type: "button",
|
|
22
26
|
onClick: createBookingFromSelection,
|
|
23
27
|
className: "rounded-xl bg-violet-600 px-6 py-3 text-sm font-semibold text-white"
|
|
@@ -5,7 +5,6 @@ import { tCal } from "../calendarI18n.js";
|
|
|
5
5
|
import { currentTimeLabel, dayOccupancy, dayOverlayHiddenKey, dayOverlayLaneMetrics, formatHourLabel, getViewNowReference, parseDate } from "../utils/bookingCalendarDateUtils.js";
|
|
6
6
|
import { BookingCard, getBlockMetaLine, getRemainingToneClass } from "../bookingCalendarViewShared.js";
|
|
7
7
|
import { BookingCalendarGroupRowHeader } from "./BookingCalendarGroupRowHeader.js";
|
|
8
|
-
import { BookingCalendarDaySelectionBar } from "./BookingCalendarDaySelectionBar.js";
|
|
9
8
|
import { BookingCalendarDayChromeProvider } from "./bookingCalendarDayViewContext.js";
|
|
10
9
|
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
11
10
|
import { ClockCircleOutlined } from "@ant-design/icons";
|
|
@@ -15,7 +14,7 @@ import { ClockCircleOutlined } from "@ant-design/icons";
|
|
|
15
14
|
function BookingCalendarDayView(dayProps) {
|
|
16
15
|
var _props$timelineHeader, _props$timelineHeader2, _props$timelineHeader3;
|
|
17
16
|
const props = dayProps.calendarProps;
|
|
18
|
-
const { isLight, view, anchorDate, dayKey, hourSlots, resolvedSlotMinutes, slotColWidth, firstTimelineHour, endTimelineExclusive, isBusinessHour, dayHourRemaining, timelinePxPerHour, dayContentHeight, dayRowHeights, visibleCourtRows, overlayBookings, dayOverlayOverflowPluses, setCollapsedGroups, visibleCourts, bookings, slotStepHours, isFreeSelected, isBlockSelected, toggleSlot, handleDropMove, hiddenDayOverlayIdSet, courtDayDisplayLaneCount, openBookingDetail, setDraggingItem, setNavDirection, commitAnchor, setFocusedCourtId, setOverflowListModal, selectedFreeSlots, selectedBlockSlots,
|
|
17
|
+
const { isLight, view, anchorDate, dayKey, hourSlots, resolvedSlotMinutes, slotColWidth, firstTimelineHour, endTimelineExclusive, isBusinessHour, dayHourRemaining, timelinePxPerHour, dayContentHeight, dayRowHeights, visibleCourtRows, overlayBookings, dayOverlayOverflowPluses, setCollapsedGroups, visibleCourts, bookings, slotStepHours, isFreeSelected, isBlockSelected, toggleSlot, handleDropMove, hiddenDayOverlayIdSet, courtDayDisplayLaneCount, openBookingDetail, setDraggingItem, setNavDirection, commitAnchor, setFocusedCourtId, setOverflowListModal, selectedFreeSlots, selectedBlockSlots, focusedCourtId, dayTimelineScrollToNowToken } = dayProps;
|
|
19
18
|
const dayScrollRef = useRef(null);
|
|
20
19
|
const dayBodyGridRef = useRef(null);
|
|
21
20
|
const dayVirtRafRef = useRef(null);
|
|
@@ -495,7 +494,7 @@ function BookingCalendarDayView(dayProps) {
|
|
|
495
494
|
handleDropMove(row.id, dayKey, hour);
|
|
496
495
|
}
|
|
497
496
|
},
|
|
498
|
-
className: `relative flex h-full min-h-0 flex-col p-1 text-left transition outline-none ${isOccupied && !outsideBusiness ? "border-l-transparent border-b-transparent" : `border-b border-l ${isLight ? "theme-border" : "border-zinc-700"}`} ${outsideBusiness ? isLight ? "bg-slate-100 theme-text-faint" : "bg-zinc-800/80 text-zinc-500 border-zinc-700" : isBlock ? blockSelected ?
|
|
497
|
+
className: `relative flex h-full min-h-0 flex-col p-1 text-left transition outline-none ${isOccupied && !outsideBusiness ? "border-l-transparent border-b-transparent" : `border-b border-l ${isLight ? "theme-border" : "border-zinc-700"}`} ${outsideBusiness ? isLight ? "bg-slate-100 theme-text-faint" : "bg-zinc-800/80 text-zinc-500 border-zinc-700" : isBlock ? blockSelected ? `bg-red-500/25 ring-1 ring-inset ring-red-400/75 border-b border-l ${isLight ? "theme-border" : "border-zinc-700"}` : isLight ? "bg-red-50 border-red-200" : "bg-red-900/50 border-red-700/50" : isOccupied ? "bg-transparent" : freeSelected ? isLight ? "bg-violet-50 ring-1 ring-inset ring-violet-400/75 border-b border-l theme-border" : "bg-white/10 ring-1 ring-inset ring-violet-400/70 border-b border-l border-zinc-700" : isLight ? "theme-grid-cell" : "bg-zinc-900 border-zinc-700"}`
|
|
499
498
|
}, outsideBusiness ? /* @__PURE__ */ React.createElement("div", { className: "flex h-full items-center justify-center rounded-xl border border-dashed border-zinc-700 text-xs text-zinc-500" }, tCal("pisell2.recordBoard.calendar.day.outsideHours")) : (item === null || item === void 0 ? void 0 : item.kind) === "block" ? /* @__PURE__ */ React.createElement("div", { className: "flex h-full w-full flex-col justify-center rounded-xl px-2.5 text-sm font-medium" }, /* @__PURE__ */ React.createElement("div", { className: "truncate" }, blockSelected ? tCal("pisell2.recordBoard.calendar.day.selectedBlock") : item.name), item.note && /* @__PURE__ */ React.createElement("div", { className: "mt-1 text-xs text-zinc-300/90 truncate" }, item.note), getBlockMetaLine(item) && /* @__PURE__ */ React.createElement("div", { className: "mt-1 text-[10px] text-zinc-400 truncate" }, getBlockMetaLine(item))) : !item ? /* @__PURE__ */ React.createElement("div", { className: `${CALENDAR_EMPTY_DASHED_SLOT_CLASSNAME} text-center ${isLight ? "border-[#d8d0eb] text-[#8f86a9]" : "border-zinc-700 text-zinc-500"}` }, freeSelected ? tCal("pisell2.recordBoard.calendar.day.selected") : null) : null);
|
|
500
499
|
})))), visibleDayOverlayBookings.map((booking) => {
|
|
501
500
|
var _booking$rowHeight, _courtDayDisplayLaneC;
|
|
@@ -578,15 +577,7 @@ function BookingCalendarDayView(dayProps) {
|
|
|
578
577
|
},
|
|
579
578
|
className: `flex h-full w-full items-center justify-center rounded-xl px-1.5 text-sm font-semibold text-white shadow-sm ${isLight ? "bg-zinc-500/90" : "bg-zinc-600/90"}`
|
|
580
579
|
}, "+", pill.plusCount));
|
|
581
|
-
}))))
|
|
582
|
-
slotStepHours,
|
|
583
|
-
selectedFreeSlots,
|
|
584
|
-
selectedBlockSlots,
|
|
585
|
-
deselectAll,
|
|
586
|
-
openSelectedBlocks,
|
|
587
|
-
onOpenBlockPanel,
|
|
588
|
-
createBookingFromSelection
|
|
589
|
-
}))));
|
|
580
|
+
})))))));
|
|
590
581
|
}
|
|
591
582
|
//#endregion
|
|
592
583
|
export { BookingCalendarDayView };
|