@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
|
@@ -7,22 +7,30 @@ const require_bookingCalendarConstants = require("./const/bookingCalendarConstan
|
|
|
7
7
|
const require_calendarI18n = require("./calendarI18n.js");
|
|
8
8
|
const require_bookingCalendarDateUtils = require("./utils/bookingCalendarDateUtils.js");
|
|
9
9
|
const require_MoveConfirmModal = require("./modal/MoveConfirmModal.js");
|
|
10
|
+
const require_BookingCalendarBlockPanel = require("./modal/BookingCalendarBlockPanel.js");
|
|
10
11
|
const require_bookingCalendarViewShared = require("./bookingCalendarViewShared.js");
|
|
11
|
-
const
|
|
12
|
+
const require_BookingCalendarOverflowListLayer = require("./modal/BookingCalendarOverflowListLayer.js");
|
|
12
13
|
const require_BookingCalendarMonthView = require("./view/BookingCalendarMonthView.js");
|
|
13
14
|
const require_BookingCalendarWeekView = require("./view/BookingCalendarWeekView.js");
|
|
14
15
|
const require_BookingCalendarDayView = require("./view/BookingCalendarDayView.js");
|
|
16
|
+
const require_BookingCalendarResourceView = require("./view/BookingCalendarResourceView.js");
|
|
17
|
+
const require_BookingCalendarDaySelectionBar = require("./view/BookingCalendarDaySelectionBar.js");
|
|
18
|
+
const require_bookingCalendarSelectionUtils = require("./utils/bookingCalendarSelectionUtils.js");
|
|
19
|
+
const require_useBookingCalendarDayOverlayLayout = require("./hooks/useBookingCalendarDayOverlayLayout.js");
|
|
20
|
+
const require_useBookingCalendarDayHourRemaining = require("./view/day/useBookingCalendarDayHourRemaining.js");
|
|
21
|
+
const require_useBookingCalendarDaySelection = require("./view/day/useBookingCalendarDaySelection.js");
|
|
22
|
+
const require_useBookingCalendarResourceDayHeaderRemaining = require("./view/resource/useBookingCalendarResourceDayHeaderRemaining.js");
|
|
23
|
+
const require_useBookingCalendarResourceCellToggle = require("./view/resource/useBookingCalendarResourceCellToggle.js");
|
|
24
|
+
const require_useBookingCalendarGoToDayFromCell = require("./view/useBookingCalendarGoToDayFromCell.js");
|
|
15
25
|
let react = require("react");
|
|
16
26
|
react = require_runtime.__toESM(react);
|
|
17
27
|
let antd = require("antd");
|
|
18
|
-
let _ant_design_icons = require("@ant-design/icons");
|
|
19
28
|
require("./BookingCalendar.less");
|
|
20
29
|
//#region src/components/pisellRecordBoard/shellFrame/Calendar/BookingCalendar.tsx
|
|
21
30
|
/**
|
|
22
31
|
* RecordBoard 预约日历:月 / 周 / 日三视图,资源分组与折叠、锁台、拖拽改期、日视图多 lane overlay。
|
|
23
32
|
* 受控:`calendarView`、`anchorDate`、`bookings` 等见 {@link RecordBoardCalendarProps};未传时由内部 state 驱动(便于 Story)。
|
|
24
33
|
*/
|
|
25
|
-
const { RangePicker } = antd.DatePicker;
|
|
26
34
|
/** 看板日历根组件:内含主题 CSS 与 Spin,按 `view` 挂载月 / 周 / 日子组件 */
|
|
27
35
|
function BookingCalendar(props = {}) {
|
|
28
36
|
var _hourSlots$;
|
|
@@ -57,8 +65,10 @@ function BookingCalendar(props = {}) {
|
|
|
57
65
|
return Math.min(1440, n);
|
|
58
66
|
}, [props.slotStepMinutes]);
|
|
59
67
|
const slotStepHours = resolvedSlotMinutes / 60;
|
|
60
|
-
/**
|
|
68
|
+
/** 每槽一列固定为「原整点列」宽度,细粒度仅增加列数,由容器横向滚动承载(日/周等时间轴) */
|
|
61
69
|
const slotColWidth = 92;
|
|
70
|
+
/** 资源视图:按「日」分列,单列单独加宽 */
|
|
71
|
+
const resourceViewSlotColWidth = 102;
|
|
62
72
|
const timelinePxPerHour = 92 / slotStepHours;
|
|
63
73
|
/** 切换月/周/日:先 `onCalendarViewChange`,无受控回调时再 `setInternalView` */
|
|
64
74
|
const commitView = (v) => {
|
|
@@ -84,6 +94,9 @@ function BookingCalendar(props = {}) {
|
|
|
84
94
|
if (view === "month") {
|
|
85
95
|
rangeStart = new Date(a.getFullYear(), a.getMonth(), 1);
|
|
86
96
|
rangeEnd = new Date(a.getFullYear(), a.getMonth() + 1, 0);
|
|
97
|
+
} else if (view === "resource") {
|
|
98
|
+
rangeStart = new Date(a.getFullYear(), a.getMonth(), 1);
|
|
99
|
+
rangeEnd = new Date(a.getFullYear(), a.getMonth() + 1, 0);
|
|
87
100
|
} else if (view === "week") {
|
|
88
101
|
rangeStart = require_bookingCalendarDateUtils.startOfWeek(a);
|
|
89
102
|
rangeEnd = require_bookingCalendarDateUtils.addDays(rangeStart, 6);
|
|
@@ -104,6 +117,7 @@ function BookingCalendar(props = {}) {
|
|
|
104
117
|
]);
|
|
105
118
|
const [selectedFreeSlots, setSelectedFreeSlots] = (0, react.useState)([]);
|
|
106
119
|
const [selectedBlockSlots, setSelectedBlockSlots] = (0, react.useState)([]);
|
|
120
|
+
const [selectedResourceCells, setSelectedResourceCells] = (0, react.useState)([]);
|
|
107
121
|
const [focusedCourtId, setFocusedCourtId] = (0, react.useState)(null);
|
|
108
122
|
const [showBlockPanel, setShowBlockPanel] = (0, react.useState)(false);
|
|
109
123
|
const [blockFormName, setBlockFormName] = (0, react.useState)(() => require_calendarI18n.tCal("pisell2.recordBoard.calendar.block.defaultTitle"));
|
|
@@ -127,11 +141,14 @@ function BookingCalendar(props = {}) {
|
|
|
127
141
|
* 供日视图将横向 scroll 定位到「当前时间」列。
|
|
128
142
|
*/
|
|
129
143
|
const [dayTimelineScrollToNowToken, setDayTimelineScrollToNowToken] = (0, react.useState)(0);
|
|
144
|
+
const [resourceMonthScrollToTodayToken, setResourceMonthScrollToTodayToken] = (0, react.useState)(0);
|
|
130
145
|
const prevCalendarViewRef = (0, react.useRef)(null);
|
|
146
|
+
const prevViewForSlotIsolationRef = (0, react.useRef)(view);
|
|
131
147
|
/** 任意入口切入 `day` 时递增一次(含首屏即为日视图:`prev === null`) */
|
|
132
148
|
(0, react.useLayoutEffect)(() => {
|
|
133
149
|
const prev = prevCalendarViewRef.current;
|
|
134
150
|
if (view === "day" && (prev === null || prev !== "day")) setDayTimelineScrollToNowToken((t) => t + 1);
|
|
151
|
+
if (view === "resource" && (prev === null || prev !== "resource")) setResourceMonthScrollToTodayToken((t) => t + 1);
|
|
135
152
|
prevCalendarViewRef.current = view;
|
|
136
153
|
}, [view]);
|
|
137
154
|
const blockPanelRef = (0, react.useRef)(null);
|
|
@@ -156,79 +173,45 @@ function BookingCalendar(props = {}) {
|
|
|
156
173
|
resolvedSlotMinutes
|
|
157
174
|
]);
|
|
158
175
|
/**
|
|
159
|
-
*
|
|
160
|
-
* 周/月不读其中大部分字段,但为单 hook 依赖仍随 `visibleCourtRows` 重算。
|
|
176
|
+
* 日视图 overlay 行高 / 并行 lane / +N 溢出(详见 hook 内注释)。
|
|
161
177
|
*/
|
|
162
|
-
const { dayRowHeights,
|
|
163
|
-
const defaultHeights = visibleCourtRows.map((row) => row.kind === "group" ? 38 : 44);
|
|
164
|
-
let overlays = require_bookingCalendarDateUtils.buildOverlayBookings(visibleCourtRows, dayKey, bookings, require_bookingCalendarDateUtils.buildDayRowTopMap(visibleCourtRows, defaultHeights), hourSlots, defaultHeights, slotStepHours);
|
|
165
|
-
const expandedHeights = visibleCourtRows.map((row, i) => {
|
|
166
|
-
if (row.kind !== "court") return defaultHeights[i];
|
|
167
|
-
if (!overlays.some((o) => o.courtId === row.id)) return defaultHeights[i];
|
|
168
|
-
return require_bookingCalendarConstants.dayCourtOverlayRowHeightPx(require_bookingCalendarDateUtils.effectiveDayOverlayDisplayLaneCount(require_bookingCalendarDateUtils.maxConcurrentBookingsOnCourt(overlays, row.id)));
|
|
169
|
-
});
|
|
170
|
-
const tops2 = require_bookingCalendarDateUtils.buildDayRowTopMap(visibleCourtRows, expandedHeights);
|
|
171
|
-
overlays = require_bookingCalendarDateUtils.buildOverlayBookings(visibleCourtRows, dayKey, bookings, tops2, hourSlots, expandedHeights, slotStepHours);
|
|
172
|
-
const courtDayDisplayLaneCount = {};
|
|
173
|
-
const hiddenDayOverlayIdSet = /* @__PURE__ */ new Set();
|
|
174
|
-
const dayOverlayOverflowPluses = [];
|
|
175
|
-
for (const row of visibleCourtRows) {
|
|
176
|
-
if (row.kind !== "court") continue;
|
|
177
|
-
const cid = row.id;
|
|
178
|
-
courtDayDisplayLaneCount[cid] = require_bookingCalendarDateUtils.effectiveDayOverlayDisplayLaneCount(require_bookingCalendarDateUtils.maxConcurrentBookingsOnCourt(overlays, cid));
|
|
179
|
-
const clusters = require_bookingCalendarDateUtils.clusterDayCourtOverlaysByOverlap(overlays, cid);
|
|
180
|
-
for (const cluster of clusters) {
|
|
181
|
-
if (cluster.length <= 3) continue;
|
|
182
|
-
const sortedByLane = [...cluster].sort((a, b) => {
|
|
183
|
-
var _a$lane, _b$lane;
|
|
184
|
-
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;
|
|
185
|
-
});
|
|
186
|
-
for (let i = 3; i < sortedByLane.length; i++) {
|
|
187
|
-
const o = sortedByLane[i];
|
|
188
|
-
hiddenDayOverlayIdSet.add(require_bookingCalendarDateUtils.dayOverlayHiddenKey(o.item, dayKey, o.courtId));
|
|
189
|
-
}
|
|
190
|
-
const hidden = sortedByLane.slice(3);
|
|
191
|
-
let minS = Infinity;
|
|
192
|
-
let maxE = -Infinity;
|
|
193
|
-
for (const o of cluster) {
|
|
194
|
-
minS = Math.min(minS, o.start);
|
|
195
|
-
maxE = Math.max(maxE, o.start + o.span);
|
|
196
|
-
}
|
|
197
|
-
const anchor = hidden[0];
|
|
198
|
-
dayOverlayOverflowPluses.push({
|
|
199
|
-
key: `${cid}-${minS}-${maxE}-${dayKey}`,
|
|
200
|
-
courtId: cid,
|
|
201
|
-
rowTop: anchor.rowTop,
|
|
202
|
-
rowHeight: anchor.rowHeight,
|
|
203
|
-
start: minS,
|
|
204
|
-
span: maxE - minS,
|
|
205
|
-
plusCount: hidden.length,
|
|
206
|
-
overflowItems: hidden.map((o) => o.item)
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
return {
|
|
211
|
-
dayRowHeights: expandedHeights,
|
|
212
|
-
dayRowTopMap: tops2,
|
|
213
|
-
overlayBookings: overlays,
|
|
214
|
-
courtDayDisplayLaneCount,
|
|
215
|
-
hiddenDayOverlayIdSet,
|
|
216
|
-
dayOverlayOverflowPluses
|
|
217
|
-
};
|
|
218
|
-
}, [
|
|
219
|
-
visibleCourtRows,
|
|
220
|
-
dayKey,
|
|
221
|
-
bookings,
|
|
222
|
-
hourSlots,
|
|
223
|
-
slotStepHours
|
|
224
|
-
]);
|
|
178
|
+
const { dayRowHeights, overlayBookings, courtDayDisplayLaneCount, hiddenDayOverlayIdSet, dayOverlayOverflowPluses } = require_useBookingCalendarDayOverlayLayout.useBookingCalendarDayOverlayLayout(visibleCourtRows, dayKey, bookings, hourSlots, slotStepHours);
|
|
225
179
|
/** 周视图表头对应的 7 个自然日 */
|
|
226
180
|
const weekDays = (0, react.useMemo)(() => require_bookingCalendarDateUtils.rangeDays(anchorDate), [anchorDate]);
|
|
181
|
+
/** 资源视图:当月每日一列 */
|
|
182
|
+
const resourceMonthDays = (0, react.useMemo)(() => require_bookingCalendarDateUtils.monthCalendarDays(anchorDate), [anchorDate]);
|
|
227
183
|
(0, react.useMemo)(() => new Set(weekDays.map((d) => require_bookingCalendarDateUtils.fmtDate(d))), [weekDays]);
|
|
228
184
|
const firstTimelineHour = (_hourSlots$ = hourSlots[0]) !== null && _hourSlots$ !== void 0 ? _hourSlots$ : 0;
|
|
229
185
|
const endTimelineExclusive = hourSlots.length ? hourSlots[hourSlots.length - 1] + slotStepHours : 24;
|
|
230
186
|
/** 槽位起始小时是否落在当前营业/时间轴配置内 */
|
|
231
|
-
const isBusinessHour = (h) => require_bookingCalendarDateUtils.isHourInTimelineSlots(h, hourSlots);
|
|
187
|
+
const isBusinessHour = (0, react.useCallback)((h) => require_bookingCalendarDateUtils.isHourInTimelineSlots(h, hourSlots), [hourSlots]);
|
|
188
|
+
const dayHourRemaining = require_useBookingCalendarDayHourRemaining.useBookingCalendarDayHourRemaining(visibleCourts, dayKey, bookings, hourSlots, slotStepHours, isBusinessHour);
|
|
189
|
+
const resourceDayHeaderRemaining = require_useBookingCalendarResourceDayHeaderRemaining.useBookingCalendarResourceDayHeaderRemaining(resourceMonthDays, visibleCourts, bookings, hourSlots, slotStepHours);
|
|
190
|
+
/**
|
|
191
|
+
* 资源视图:选区是否可触发 Block / Create Booking。
|
|
192
|
+
* - 任何选中 → SelectionBar 显示「Cancel」。
|
|
193
|
+
* - 同 court + 连续多天(含单日) → 才显示「Block / Create」按钮。
|
|
194
|
+
*/
|
|
195
|
+
const resourceSelectionContiguous = (0, react.useMemo)(() => require_bookingCalendarSelectionUtils.isResourceSelectionContiguousSameCourt(selectedResourceCells), [selectedResourceCells]);
|
|
196
|
+
const resourceSelectionBarMeta = (0, react.useMemo)(() => {
|
|
197
|
+
if (selectedResourceCells.length === 0) return null;
|
|
198
|
+
return {
|
|
199
|
+
freePickCount: selectedResourceCells.length,
|
|
200
|
+
blockPickCount: selectedResourceCells.length,
|
|
201
|
+
freeAllowsBlockPanel: resourceSelectionContiguous
|
|
202
|
+
};
|
|
203
|
+
}, [selectedResourceCells, resourceSelectionContiguous]);
|
|
204
|
+
/** 日视图与资源视图选中隔离:切换视图时清空另一侧 */
|
|
205
|
+
(0, react.useEffect)(() => {
|
|
206
|
+
if (prevViewForSlotIsolationRef.current !== view) {
|
|
207
|
+
if (view === "day") setSelectedResourceCells([]);
|
|
208
|
+
if (view === "resource") {
|
|
209
|
+
setSelectedFreeSlots([]);
|
|
210
|
+
setSelectedBlockSlots([]);
|
|
211
|
+
}
|
|
212
|
+
prevViewForSlotIsolationRef.current = view;
|
|
213
|
+
}
|
|
214
|
+
}, [view]);
|
|
232
215
|
/** 月历每格摘要(占用点、锁台等),供月视图渲染 */
|
|
233
216
|
const monthDays = (0, react.useMemo)(() => require_bookingCalendarDateUtils.monthGrid(anchorDate, bookings, courts, hourSlots, slotStepHours), [
|
|
234
217
|
anchorDate,
|
|
@@ -237,29 +220,6 @@ function BookingCalendar(props = {}) {
|
|
|
237
220
|
hourSlots,
|
|
238
221
|
slotStepHours
|
|
239
222
|
]);
|
|
240
|
-
/** 日视图表头:每个整点列上仍有空的资源数占比(按全部可见资源计,与分组折叠无关) */
|
|
241
|
-
const dayHourRemaining = (0, react.useMemo)(() => {
|
|
242
|
-
const total = visibleCourts.length;
|
|
243
|
-
return Object.fromEntries(hourSlots.map((hour) => {
|
|
244
|
-
if (!isBusinessHour(hour)) return [hour, {
|
|
245
|
-
remaining: 0,
|
|
246
|
-
total,
|
|
247
|
-
ratio: 0
|
|
248
|
-
}];
|
|
249
|
-
const remaining = visibleCourts.filter((court) => !require_bookingCalendarDateUtils.dayOccupancy(court.id, dayKey, bookings, hourSlots, slotStepHours)[hour]).length;
|
|
250
|
-
return [hour, {
|
|
251
|
-
remaining,
|
|
252
|
-
total,
|
|
253
|
-
ratio: total > 0 ? remaining / total : 0
|
|
254
|
-
}];
|
|
255
|
-
}));
|
|
256
|
-
}, [
|
|
257
|
-
visibleCourts,
|
|
258
|
-
dayKey,
|
|
259
|
-
bookings,
|
|
260
|
-
hourSlots,
|
|
261
|
-
slotStepHours
|
|
262
|
-
]);
|
|
263
223
|
/** 日视图内容区总高度(表头 + 各资源行叠加以 overlay 抬高后的高度) */
|
|
264
224
|
const dayContentHeight = 56 + dayRowHeights.reduce((sum, h) => sum + h, 0);
|
|
265
225
|
/** 点击文档空白处关闭锁台面版、溢出浮层、改期确认等面板 */
|
|
@@ -283,16 +243,39 @@ function BookingCalendar(props = {}) {
|
|
|
283
243
|
/** 锁台面版打开时若选区不再连续同资源则自动收起(避免与表单状态不一致) */
|
|
284
244
|
(0, react.useEffect)(() => {
|
|
285
245
|
if (!showBlockPanel) return;
|
|
246
|
+
if (view === "resource") {
|
|
247
|
+
if (!resourceSelectionContiguous) setShowBlockPanel(false);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
286
250
|
if (!require_bookingCalendarDateUtils.isFreeSelectionContiguousSameResource(selectedFreeSlots, slotStepHours)) setShowBlockPanel(false);
|
|
287
251
|
}, [
|
|
288
252
|
showBlockPanel,
|
|
253
|
+
view,
|
|
289
254
|
selectedFreeSlots,
|
|
255
|
+
resourceSelectionContiguous,
|
|
290
256
|
slotStepHours
|
|
291
257
|
]);
|
|
292
258
|
/** 打开锁台面版时用当前选中的空闲连续段预填资源与时间范围(仅内置锁台面版) */
|
|
293
259
|
(0, react.useEffect)(() => {
|
|
294
260
|
if (props.onBlockedTimePanelRequest) return;
|
|
295
|
-
if (!showBlockPanel
|
|
261
|
+
if (!showBlockPanel) return;
|
|
262
|
+
if (view === "resource") {
|
|
263
|
+
var _bizHours$, _bizHours;
|
|
264
|
+
if (!resourceSelectionContiguous) return;
|
|
265
|
+
const sortedDates = [...selectedResourceCells].map((s) => s.dateKey).sort();
|
|
266
|
+
const firstDate = sortedDates[0];
|
|
267
|
+
const lastDate = sortedDates[sortedDates.length - 1];
|
|
268
|
+
const bizHours = hourSlots.filter((h) => require_bookingCalendarDateUtils.isHourInTimelineSlots(h, hourSlots));
|
|
269
|
+
const h0 = (_bizHours$ = bizHours[0]) !== null && _bizHours$ !== void 0 ? _bizHours$ : 0;
|
|
270
|
+
const hLast = (_bizHours = bizHours[bizHours.length - 1]) !== null && _bizHours !== void 0 ? _bizHours : h0;
|
|
271
|
+
const slotStep = slotStepHours > 0 ? slotStepHours : 1;
|
|
272
|
+
setBlockResourceId(String(selectedResourceCells[0].courtId));
|
|
273
|
+
setBlockTimeRange([require_bookingCalendarDateUtils.dayAndHourToDayjs(firstDate, h0), require_bookingCalendarDateUtils.dayAndHourToDayjs(lastDate, hLast + slotStep)]);
|
|
274
|
+
setBlockFormName(require_calendarI18n.tCal("pisell2.recordBoard.calendar.block.defaultTitle"));
|
|
275
|
+
setBlockModalNote("");
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (selectedFreeSlots.length === 0) return;
|
|
296
279
|
const g = require_bookingCalendarDateUtils.groupSelectedSlots(selectedFreeSlots, slotStepHours)[0];
|
|
297
280
|
if (!g) return;
|
|
298
281
|
setBlockResourceId(String(g.courtId));
|
|
@@ -301,8 +284,13 @@ function BookingCalendar(props = {}) {
|
|
|
301
284
|
setBlockModalNote("");
|
|
302
285
|
}, [
|
|
303
286
|
showBlockPanel,
|
|
287
|
+
view,
|
|
304
288
|
selectedFreeSlots,
|
|
305
|
-
|
|
289
|
+
selectedResourceCells,
|
|
290
|
+
resourceSelectionContiguous,
|
|
291
|
+
hourSlots,
|
|
292
|
+
slotStepHours,
|
|
293
|
+
props.onBlockedTimePanelRequest
|
|
306
294
|
]);
|
|
307
295
|
/** 周/月跳入日视图时的短动画标记,超时清除 */
|
|
308
296
|
(0, react.useEffect)(() => {
|
|
@@ -310,47 +298,15 @@ function BookingCalendar(props = {}) {
|
|
|
310
298
|
const timer = setTimeout(() => setTransitioningToDay(null), 280);
|
|
311
299
|
return () => clearTimeout(timer);
|
|
312
300
|
}, [transitioningToDay]);
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
317
|
-
/** 当前日锚定下,该资源该槽是否在「锁台多选」集合中 */
|
|
318
|
-
function isBlockSelected(courtId, hour) {
|
|
319
|
-
return selectedBlockSlots.some((slot) => slot.courtId === courtId && slot.date === dayKey && slot.hour === hour);
|
|
320
|
-
}
|
|
321
|
-
/** 从周/月单元格调起日视图:更新锚定日、可选聚焦资源、记录过渡动画方向 */
|
|
322
|
-
function goToDayFromCell(day, courtId, source) {
|
|
323
|
-
setNavDirection(day > anchorDate ? 1 : -1);
|
|
324
|
-
setTransitioningToDay({ source });
|
|
325
|
-
/** 周/月只是“跳转查看”,不应把日视图多选状态带过去造成误解(像是系统替用户选了格子) */
|
|
326
|
-
setSelectedFreeSlots([]);
|
|
327
|
-
setSelectedBlockSlots([]);
|
|
328
|
-
commitAnchor(day);
|
|
329
|
-
setFocusedCourtId(courtId || null);
|
|
330
|
-
commitView("day");
|
|
331
|
-
}
|
|
301
|
+
const goToDayFromCell = require_useBookingCalendarGoToDayFromCell.useBookingCalendarGoToDayFromCell(anchorDate, commitAnchor, commitView, setNavDirection, setTransitioningToDay, setSelectedFreeSlots, setSelectedBlockSlots, setSelectedResourceCells, setFocusedCourtId);
|
|
302
|
+
const toggleResourceCell = require_useBookingCalendarResourceCellToggle.useBookingCalendarResourceCellToggle(setSelectedResourceCells);
|
|
303
|
+
const { isFreeSelected, isBlockSelected, toggleSlot } = require_useBookingCalendarDaySelection.useBookingCalendarDaySelection(dayKey, bookings, hourSlots, slotStepHours, courts, selectedFreeSlots, selectedBlockSlots, setSelectedFreeSlots, setSelectedBlockSlots);
|
|
332
304
|
/** 卡片详情:业务若 `onBookingClick` 返回 true 则视为已消费;否则关闭溢出气泡 */
|
|
333
|
-
|
|
305
|
+
const openBookingDetail = (0, react.useCallback)((item) => {
|
|
334
306
|
var _props$onBookingClick;
|
|
335
307
|
if (((_props$onBookingClick = props.onBookingClick) === null || _props$onBookingClick === void 0 ? void 0 : _props$onBookingClick.call(props, item)) === true) return;
|
|
336
308
|
setOverflowPopover(null);
|
|
337
|
-
}
|
|
338
|
-
/** 日视图格子点击:空闲槽进多选;锁台槽进锁台多选;已约不动 */
|
|
339
|
-
function toggleSlot(courtId, hour) {
|
|
340
|
-
const existing = require_bookingCalendarDateUtils.dayOccupancy(courtId, dayKey, bookings, hourSlots, slotStepHours)[hour];
|
|
341
|
-
const court = courts.find((c) => c.id === courtId);
|
|
342
|
-
const slot = {
|
|
343
|
-
courtId,
|
|
344
|
-
court: court === null || court === void 0 ? void 0 : court.name,
|
|
345
|
-
date: dayKey,
|
|
346
|
-
hour
|
|
347
|
-
};
|
|
348
|
-
if (!existing) {
|
|
349
|
-
setSelectedFreeSlots((prev) => prev.some((s) => require_bookingCalendarDateUtils.sameSlot(s, slot)) ? prev.filter((s) => !require_bookingCalendarDateUtils.sameSlot(s, slot)) : [...prev, slot]);
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
if (existing.kind === "block") setSelectedBlockSlots((prev) => prev.some((s) => require_bookingCalendarDateUtils.sameSlot(s, slot)) ? prev.filter((s) => !require_bookingCalendarDateUtils.sameSlot(s, slot)) : [...prev, slot]);
|
|
353
|
-
}
|
|
309
|
+
}, [props.onBookingClick]);
|
|
354
310
|
/** 清空空闲与锁台多选 */
|
|
355
311
|
function deselectAll() {
|
|
356
312
|
setSelectedFreeSlots([]);
|
|
@@ -358,9 +314,27 @@ function BookingCalendar(props = {}) {
|
|
|
358
314
|
}
|
|
359
315
|
/** 将连续空闲选区合并为一条或多条本地预约(演示/未接写接口时) */
|
|
360
316
|
function createBookingFromSelection() {
|
|
361
|
-
if (!allowPersist("createBooking")) return;
|
|
362
317
|
if (selectedFreeSlots.length === 0) return;
|
|
363
|
-
const
|
|
318
|
+
const groups = require_bookingCalendarDateUtils.groupSelectedSlots(selectedFreeSlots, slotStepHours);
|
|
319
|
+
const host = props.onCreateBookingFromSelection;
|
|
320
|
+
if (host) {
|
|
321
|
+
require_asyncToGenerator._asyncToGenerator(function* () {
|
|
322
|
+
try {
|
|
323
|
+
if ((yield Promise.resolve(host({
|
|
324
|
+
mode: "day",
|
|
325
|
+
groups: groups.map((g) => ({
|
|
326
|
+
courtId: g.courtId,
|
|
327
|
+
date: g.date,
|
|
328
|
+
startHour: g.startHour,
|
|
329
|
+
endHour: g.endHour
|
|
330
|
+
}))
|
|
331
|
+
}))) !== false) setSelectedFreeSlots([]);
|
|
332
|
+
} catch (_unused) {}
|
|
333
|
+
})();
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (!allowPersist("createBooking")) return;
|
|
337
|
+
const newBookings = groups.map((slot, idx) => ({
|
|
364
338
|
id: `new-${slot.courtId}-${slot.date}-${slot.startHour}-${idx}`,
|
|
365
339
|
courtId: slot.courtId,
|
|
366
340
|
date: slot.date,
|
|
@@ -372,17 +346,48 @@ function BookingCalendar(props = {}) {
|
|
|
372
346
|
setBookings((prev) => [...newBookings, ...prev]);
|
|
373
347
|
setSelectedFreeSlots([]);
|
|
374
348
|
}
|
|
375
|
-
/**
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
349
|
+
/**
|
|
350
|
+
* 资源视图:连续多天 → 一条跨日整天预约,时间 = 营业开始 → 营业结束。
|
|
351
|
+
* 单日 → 同样按整天写入。仅在 `resourceSelectionContiguous` 为 true 时执行。
|
|
352
|
+
*/
|
|
353
|
+
function createBookingFromResourceSelection() {
|
|
354
|
+
var _bizHours$2, _bizHours2;
|
|
355
|
+
if (!resourceSelectionContiguous) return;
|
|
356
|
+
const sortedDates = [...selectedResourceCells].map((s) => s.dateKey).sort();
|
|
357
|
+
const firstDate = sortedDates[0];
|
|
358
|
+
const lastDate = sortedDates[sortedDates.length - 1];
|
|
359
|
+
const courtId = selectedResourceCells[0].courtId;
|
|
360
|
+
const bizHours = hourSlots.filter((h) => require_bookingCalendarDateUtils.isHourInTimelineSlots(h, hourSlots));
|
|
361
|
+
const h0 = (_bizHours$2 = bizHours[0]) !== null && _bizHours$2 !== void 0 ? _bizHours$2 : 0;
|
|
362
|
+
const endHour = ((_bizHours2 = bizHours[bizHours.length - 1]) !== null && _bizHours2 !== void 0 ? _bizHours2 : h0) + (slotStepHours > 0 ? slotStepHours : 1);
|
|
363
|
+
const host = props.onCreateBookingFromSelection;
|
|
364
|
+
if (host) {
|
|
365
|
+
require_asyncToGenerator._asyncToGenerator(function* () {
|
|
366
|
+
try {
|
|
367
|
+
if ((yield Promise.resolve(host({
|
|
368
|
+
mode: "resource",
|
|
369
|
+
courtId,
|
|
370
|
+
dates: sortedDates,
|
|
371
|
+
startHour: h0,
|
|
372
|
+
endHour
|
|
373
|
+
}))) !== false) setSelectedResourceCells([]);
|
|
374
|
+
} catch (_unused2) {}
|
|
375
|
+
})();
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (!allowPersist("createBooking")) return;
|
|
379
|
+
const newBooking = {
|
|
380
|
+
id: `new-${courtId}-${firstDate}-${Date.now()}`,
|
|
381
|
+
courtId,
|
|
382
|
+
date: firstDate,
|
|
383
|
+
endDate: lastDate !== firstDate ? lastDate : void 0,
|
|
384
|
+
startHour: h0,
|
|
385
|
+
endHour,
|
|
386
|
+
name: require_calendarI18n.tCal("pisell2.recordBoard.calendar.common.newBookingName"),
|
|
387
|
+
kind: "booking"
|
|
388
|
+
};
|
|
389
|
+
setBookings((prev) => [newBooking, ...prev]);
|
|
390
|
+
setSelectedResourceCells([]);
|
|
386
391
|
}
|
|
387
392
|
/** 屏蔽:宿主 lock 弹窗,或内置锁台面版 */
|
|
388
393
|
const handleOpenBlockPanelFromSelection = (0, react.useCallback)(require_asyncToGenerator._asyncToGenerator(function* () {
|
|
@@ -391,20 +396,21 @@ function BookingCalendar(props = {}) {
|
|
|
391
396
|
if (!g) return;
|
|
392
397
|
if (props.onBlockedTimePanelRequest) {
|
|
393
398
|
try {
|
|
399
|
+
const slotsPayload = selectedFreeSlots.map((s) => {
|
|
400
|
+
const slot = {
|
|
401
|
+
courtId: s.courtId,
|
|
402
|
+
date: s.date,
|
|
403
|
+
hour: s.hour
|
|
404
|
+
};
|
|
405
|
+
const extra = s;
|
|
406
|
+
if (extra.court !== void 0 && extra.court !== "") slot.court = extra.court;
|
|
407
|
+
return slot;
|
|
408
|
+
});
|
|
394
409
|
const payload = {
|
|
395
410
|
slotStepHours,
|
|
396
411
|
slotStepMinutes: resolvedSlotMinutes,
|
|
397
|
-
dayKey,
|
|
398
|
-
selectedFreeSlots:
|
|
399
|
-
const slot = {
|
|
400
|
-
courtId: s.courtId,
|
|
401
|
-
date: s.date,
|
|
402
|
-
hour: s.hour
|
|
403
|
-
};
|
|
404
|
-
const extra = s;
|
|
405
|
-
if (extra.court !== void 0 && extra.court !== "") slot.court = extra.court;
|
|
406
|
-
return slot;
|
|
407
|
-
}),
|
|
412
|
+
dayKey: g.date,
|
|
413
|
+
selectedFreeSlots: slotsPayload,
|
|
408
414
|
mergedRange: {
|
|
409
415
|
courtId: g.courtId,
|
|
410
416
|
date: g.date,
|
|
@@ -413,7 +419,7 @@ function BookingCalendar(props = {}) {
|
|
|
413
419
|
}
|
|
414
420
|
};
|
|
415
421
|
if ((yield props.onBlockedTimePanelRequest(payload)) !== false) setSelectedFreeSlots([]);
|
|
416
|
-
} catch (
|
|
422
|
+
} catch (_unused3) {}
|
|
417
423
|
return;
|
|
418
424
|
}
|
|
419
425
|
setShowBlockPanel(true);
|
|
@@ -421,7 +427,56 @@ function BookingCalendar(props = {}) {
|
|
|
421
427
|
selectedFreeSlots,
|
|
422
428
|
slotStepHours,
|
|
423
429
|
resolvedSlotMinutes,
|
|
424
|
-
|
|
430
|
+
props.onBlockedTimePanelRequest
|
|
431
|
+
]);
|
|
432
|
+
/**
|
|
433
|
+
* 资源视图:仅在「同 court + 连续多天」时打开 Block 面板,按整天预填资源 + 跨日时间范围。
|
|
434
|
+
*/
|
|
435
|
+
const handleOpenBlockPanelFromResource = (0, react.useCallback)(require_asyncToGenerator._asyncToGenerator(function* () {
|
|
436
|
+
var _bizHours$3, _bizHours3;
|
|
437
|
+
if (!resourceSelectionContiguous) return;
|
|
438
|
+
const sortedDates = [...selectedResourceCells].map((s) => s.dateKey).sort();
|
|
439
|
+
const firstDate = sortedDates[0];
|
|
440
|
+
const lastDate = sortedDates[sortedDates.length - 1];
|
|
441
|
+
const courtId = selectedResourceCells[0].courtId;
|
|
442
|
+
const court = courts.find((c) => c.id === courtId);
|
|
443
|
+
const bizHours = hourSlots.filter((h) => require_bookingCalendarDateUtils.isHourInTimelineSlots(h, hourSlots));
|
|
444
|
+
const h0 = (_bizHours$3 = bizHours[0]) !== null && _bizHours$3 !== void 0 ? _bizHours$3 : 0;
|
|
445
|
+
const hLast = (_bizHours3 = bizHours[bizHours.length - 1]) !== null && _bizHours3 !== void 0 ? _bizHours3 : h0;
|
|
446
|
+
const slotStep = slotStepHours > 0 ? slotStepHours : 1;
|
|
447
|
+
const startHour = h0;
|
|
448
|
+
const endHour = hLast + slotStep;
|
|
449
|
+
if (props.onBlockedTimePanelRequest) {
|
|
450
|
+
try {
|
|
451
|
+
const payload = {
|
|
452
|
+
slotStepHours,
|
|
453
|
+
slotStepMinutes: resolvedSlotMinutes,
|
|
454
|
+
dayKey: firstDate,
|
|
455
|
+
selectedFreeSlots: sortedDates.map((d) => require_objectSpread2._objectSpread2({
|
|
456
|
+
courtId,
|
|
457
|
+
date: d,
|
|
458
|
+
hour: startHour
|
|
459
|
+
}, (court === null || court === void 0 ? void 0 : court.name) ? { court: court.name } : {})),
|
|
460
|
+
mergedRange: {
|
|
461
|
+
courtId,
|
|
462
|
+
date: firstDate,
|
|
463
|
+
endDate: lastDate !== firstDate ? lastDate : void 0,
|
|
464
|
+
startHour,
|
|
465
|
+
endHour
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
if ((yield props.onBlockedTimePanelRequest(payload)) !== false) setSelectedResourceCells([]);
|
|
469
|
+
} catch (_unused4) {}
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
setShowBlockPanel(true);
|
|
473
|
+
}), [
|
|
474
|
+
selectedResourceCells,
|
|
475
|
+
resourceSelectionContiguous,
|
|
476
|
+
hourSlots,
|
|
477
|
+
slotStepHours,
|
|
478
|
+
courts,
|
|
479
|
+
resolvedSlotMinutes,
|
|
425
480
|
props.onBlockedTimePanelRequest
|
|
426
481
|
]);
|
|
427
482
|
/** 提交锁台:优先走 `onBlockedTimeSave`;否则写入本地 block 片段 */
|
|
@@ -460,6 +515,7 @@ function BookingCalendar(props = {}) {
|
|
|
460
515
|
if ((yield props.onBlockedTimeSave(payload)) === false) return;
|
|
461
516
|
setShowBlockPanel(false);
|
|
462
517
|
setSelectedFreeSlots([]);
|
|
518
|
+
setSelectedResourceCells([]);
|
|
463
519
|
setBlockModalNote("");
|
|
464
520
|
} finally {
|
|
465
521
|
setBlockSaving(false);
|
|
@@ -486,18 +542,19 @@ function BookingCalendar(props = {}) {
|
|
|
486
542
|
if (!allowPersist("createBlock")) return;
|
|
487
543
|
setBookings((prev) => [nextBlock, ...prev]);
|
|
488
544
|
setSelectedFreeSlots([]);
|
|
545
|
+
setSelectedResourceCells([]);
|
|
489
546
|
setShowBlockPanel(false);
|
|
490
547
|
setBlockModalNote("");
|
|
491
548
|
});
|
|
492
549
|
return _saveBlockedTime.apply(this, arguments);
|
|
493
550
|
}
|
|
494
551
|
/** 拖拽改期松手:宿主接管改约,或弹出内置确认框 */
|
|
495
|
-
|
|
552
|
+
const handleDropMove = (0, react.useCallback)((targetCourtId, targetDate, targetHour) => {
|
|
496
553
|
if (!draggingItem) return;
|
|
497
554
|
const duration = draggingItem.endHour - draggingItem.startHour;
|
|
498
555
|
const nextStart = targetHour;
|
|
499
556
|
const nextEnd = targetHour + duration;
|
|
500
|
-
if (!
|
|
557
|
+
if (!require_bookingCalendarDateUtils.isHourInTimelineSlots(nextStart, hourSlots) || nextEnd > endTimelineExclusive) return;
|
|
501
558
|
const targetCourt = targetCourtId !== null && targetCourtId !== void 0 ? targetCourtId : draggingItem.courtId;
|
|
502
559
|
const itemSnapshot = draggingItem;
|
|
503
560
|
const draft = {
|
|
@@ -520,12 +577,17 @@ function BookingCalendar(props = {}) {
|
|
|
520
577
|
targetHour
|
|
521
578
|
});
|
|
522
579
|
setMoveDraft(draft);
|
|
523
|
-
}
|
|
580
|
+
}, [
|
|
581
|
+
draggingItem,
|
|
582
|
+
hourSlots,
|
|
583
|
+
endTimelineExclusive,
|
|
584
|
+
props.onBookingMoveRequest
|
|
585
|
+
]);
|
|
524
586
|
/** 周/月格 drop:保持原开始小时,仅换日或资源 */
|
|
525
|
-
|
|
587
|
+
const handleGridDropMove = (0, react.useCallback)((targetDate, targetCourtId = null) => {
|
|
526
588
|
if (!draggingItem || draggingItem.kind === "block") return;
|
|
527
589
|
handleDropMove(targetCourtId !== null && targetCourtId !== void 0 ? targetCourtId : draggingItem.courtId, targetDate, draggingItem.startHour);
|
|
528
|
-
}
|
|
590
|
+
}, [draggingItem, handleDropMove]);
|
|
529
591
|
/** 确认改期:在 bookings 中平移该条的起止小时与 court/date */
|
|
530
592
|
function confirmMove() {
|
|
531
593
|
if (!moveConfirm || !moveDraft) return;
|
|
@@ -584,6 +646,29 @@ function BookingCalendar(props = {}) {
|
|
|
584
646
|
overflowListModal,
|
|
585
647
|
setOverflowListModal,
|
|
586
648
|
overflowPanelRef
|
|
649
|
+
}), view === "resource" && /* @__PURE__ */ react.default.createElement(require_BookingCalendarResourceView.BookingCalendarResourceView, {
|
|
650
|
+
calendarProps: props,
|
|
651
|
+
isLight,
|
|
652
|
+
anchorDate,
|
|
653
|
+
monthDays: resourceMonthDays,
|
|
654
|
+
slotColWidth: resourceViewSlotColWidth,
|
|
655
|
+
bookings,
|
|
656
|
+
hourSlots,
|
|
657
|
+
slotStepHours,
|
|
658
|
+
visibleCourts,
|
|
659
|
+
visibleCourtRows,
|
|
660
|
+
handleGridDropMove,
|
|
661
|
+
openBookingDetail,
|
|
662
|
+
setDraggingItem,
|
|
663
|
+
setCollapsedGroups,
|
|
664
|
+
overflowPopover,
|
|
665
|
+
setOverflowPopover,
|
|
666
|
+
setOverflowListModal,
|
|
667
|
+
overflowPanelRef,
|
|
668
|
+
resourceMonthScrollToTodayToken,
|
|
669
|
+
resourceDayHeaderRemaining,
|
|
670
|
+
toggleResourceCell,
|
|
671
|
+
selectedResourceCells
|
|
587
672
|
}), view === "day" && /* @__PURE__ */ react.default.createElement(require_BookingCalendarDayView.BookingCalendarDayView, {
|
|
588
673
|
calendarProps: props,
|
|
589
674
|
isLight,
|
|
@@ -621,73 +706,38 @@ function BookingCalendar(props = {}) {
|
|
|
621
706
|
setOverflowListModal,
|
|
622
707
|
selectedFreeSlots,
|
|
623
708
|
selectedBlockSlots,
|
|
624
|
-
deselectAll,
|
|
625
|
-
openSelectedBlocks,
|
|
626
|
-
onOpenBlockPanel: handleOpenBlockPanelFromSelection,
|
|
627
|
-
createBookingFromSelection,
|
|
628
709
|
focusedCourtId,
|
|
629
710
|
dayTimelineScrollToNowToken
|
|
630
|
-
}))),
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
"
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
showTime: {
|
|
658
|
-
format: "HH:mm",
|
|
659
|
-
minuteStep: resolvedSlotMinutes >= 60 ? 60 : Math.max(1, resolvedSlotMinutes)
|
|
660
|
-
},
|
|
661
|
-
format: "YYYY-MM-DD HH:mm",
|
|
662
|
-
value: blockTimeRange !== null && blockTimeRange !== void 0 ? blockTimeRange : void 0,
|
|
663
|
-
onChange: (v) => {
|
|
664
|
-
var _ref;
|
|
665
|
-
return setBlockTimeRange((_ref = v) !== null && _ref !== void 0 ? _ref : null);
|
|
666
|
-
}
|
|
667
|
-
}))), /* @__PURE__ */ react.default.createElement("div", { className: "mt-6 flex flex-col-reverse sm:flex-row items-stretch sm:items-center justify-end gap-3" }, /* @__PURE__ */ react.default.createElement("button", {
|
|
668
|
-
type: "button",
|
|
669
|
-
disabled: blockSaving,
|
|
670
|
-
onClick: () => setShowBlockPanel(false),
|
|
671
|
-
className: `rounded-xl px-4 py-2 ${isLight ? "btn-neutral" : "border border-zinc-700 text-zinc-300"}`
|
|
672
|
-
}, require_calendarI18n.tCal("pisell2.recordBoard.calendar.common.cancel")), /* @__PURE__ */ react.default.createElement("button", {
|
|
673
|
-
type: "button",
|
|
674
|
-
disabled: blockSaving,
|
|
675
|
-
onClick: () => void saveBlockedTime(),
|
|
676
|
-
className: `rounded-xl px-5 py-3 text-sm font-semibold disabled:opacity-50 ${isLight ? "btn-brand" : "bg-violet-600 text-white"}`
|
|
677
|
-
}, blockSaving ? require_calendarI18n.tCal("pisell2.recordBoard.calendar.common.saving") : require_calendarI18n.tCal("pisell2.recordBoard.calendar.common.save"))))), overflowListModal && /* @__PURE__ */ react.default.createElement("div", { className: "fixed inset-0 z-[69] bg-black/45 backdrop-blur-sm flex items-center justify-center p-4" }, /* @__PURE__ */ react.default.createElement("div", {
|
|
678
|
-
ref: overflowPanelRef,
|
|
679
|
-
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]"}`
|
|
680
|
-
}, /* @__PURE__ */ react.default.createElement("div", { className: "mb-4 flex shrink-0 items-start justify-between" }, /* @__PURE__ */ react.default.createElement("div", null, /* @__PURE__ */ react.default.createElement("div", { className: "text-xl font-semibold" }, require_calendarI18n.tCal("pisell2.recordBoard.calendar.overflow.bookingsForDay")), /* @__PURE__ */ react.default.createElement("div", { className: "mt-1 text-sm text-zinc-400" }, overflowListModal.title)), /* @__PURE__ */ react.default.createElement("button", {
|
|
681
|
-
onClick: () => setOverflowListModal(null),
|
|
682
|
-
className: "rounded-xl border border-zinc-700 px-3 py-2 text-zinc-300"
|
|
683
|
-
}, require_calendarI18n.tCal("pisell2.recordBoard.calendar.common.close"))), /* @__PURE__ */ react.default.createElement("div", { className: "min-h-0 flex-1 overflow-hidden px-0.5" }, /* @__PURE__ */ react.default.createElement(require_OverflowListModal.OverflowListModalVirtualList, {
|
|
684
|
-
items: overflowListModal.items,
|
|
685
|
-
dateKey: overflowListModal.date,
|
|
686
|
-
listWidth: 468,
|
|
687
|
-
onPickItem: openBookingDetail,
|
|
711
|
+
}))), view === "day" && (selectedFreeSlots.length > 0 || selectedBlockSlots.length > 0) || view === "resource" && selectedResourceCells.length > 0 ? /* @__PURE__ */ react.default.createElement(require_BookingCalendarDaySelectionBar.BookingCalendarDaySelectionBar, {
|
|
712
|
+
slotStepHours,
|
|
713
|
+
selectedFreeSlots: view === "resource" ? [] : selectedFreeSlots,
|
|
714
|
+
resourceSelectionSummary: view === "resource" ? resourceSelectionBarMeta : void 0,
|
|
715
|
+
deselectAll: view === "resource" ? () => setSelectedResourceCells([]) : deselectAll,
|
|
716
|
+
onOpenBlockPanel: view === "resource" ? handleOpenBlockPanelFromResource : handleOpenBlockPanelFromSelection,
|
|
717
|
+
createBookingFromSelection: view === "resource" ? createBookingFromResourceSelection : createBookingFromSelection
|
|
718
|
+
}) : null, showBlockPanel && !props.onBlockedTimePanelRequest && (view === "resource" ? resourceSelectionContiguous : selectedFreeSlots.length > 0 && require_bookingCalendarDateUtils.isFreeSelectionContiguousSameResource(selectedFreeSlots, slotStepHours)) && /* @__PURE__ */ react.default.createElement(require_BookingCalendarBlockPanel.BookingCalendarBlockPanel, {
|
|
719
|
+
blockPanelRef,
|
|
720
|
+
isLight,
|
|
721
|
+
blockFormName,
|
|
722
|
+
setBlockFormName,
|
|
723
|
+
blockModalNote,
|
|
724
|
+
setBlockModalNote,
|
|
725
|
+
blockResourceId,
|
|
726
|
+
setBlockResourceId,
|
|
727
|
+
blockTimeRange,
|
|
728
|
+
setBlockTimeRange,
|
|
729
|
+
resolvedSlotMinutes,
|
|
730
|
+
visibleCourts,
|
|
731
|
+
blockSaving,
|
|
732
|
+
onClose: () => setShowBlockPanel(false),
|
|
733
|
+
onSave: saveBlockedTime
|
|
734
|
+
}), overflowListModal && /* @__PURE__ */ react.default.createElement(require_BookingCalendarOverflowListLayer.BookingCalendarOverflowListLayer, {
|
|
735
|
+
overflowPanelRef,
|
|
736
|
+
isLight,
|
|
737
|
+
modal: overflowListModal,
|
|
688
738
|
onClose: () => setOverflowListModal(null),
|
|
689
|
-
|
|
690
|
-
})
|
|
739
|
+
onPickItem: openBookingDetail
|
|
740
|
+
}), moveConfirm && /* @__PURE__ */ react.default.createElement(require_MoveConfirmModal.MoveConfirmModal, {
|
|
691
741
|
moveConfirm,
|
|
692
742
|
moveDraft,
|
|
693
743
|
setMoveDraft,
|