@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.
Files changed (86) hide show
  1. package/build/lowcode/assets-daily.json +11 -11
  2. package/build/lowcode/assets-dev.json +2 -2
  3. package/build/lowcode/assets-prod.json +11 -11
  4. package/build/lowcode/index.js +1 -1
  5. package/build/lowcode/meta.js +2 -2
  6. package/build/lowcode/preview.js +1 -1
  7. package/build/lowcode/render/default/view.css +1 -1
  8. package/build/lowcode/render/default/view.js +35 -35
  9. package/build/lowcode/view.css +1 -1
  10. package/build/lowcode/view.js +35 -35
  11. package/es/components/pisellFloorMapLayout/PisellFloorMapLayout.js +25 -10
  12. package/es/components/pisellFloorMapLayout/appearance/floorMapAppearance.d.ts +4 -0
  13. package/es/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +22 -0
  14. package/es/components/pisellFloorMapLayout/components/EditableItemLayer.js +3 -2
  15. package/es/components/pisellFloorMapLayout/components/ItemLayer.js +7 -4
  16. package/es/components/pisellFloorMapLayout/components/ItemLayer.less +10 -0
  17. package/es/components/pisellFloorMapLayout/components/ViewControls.js +6 -5
  18. package/es/components/pisellFloorMapLayout/components/ViewControls.less +29 -2
  19. package/es/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +1 -0
  20. package/es/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +3 -1
  21. package/es/components/pisellFloorMapLayout/types.d.ts +21 -2
  22. package/es/components/pisellRecordBoard/index.d.ts +1 -1
  23. package/es/components/pisellRecordBoard/shellFrame/Calendar/BookingCalendar.js +280 -230
  24. package/es/components/pisellRecordBoard/shellFrame/Calendar/const/bookingCalendarConstants.js +18 -1
  25. package/es/components/pisellRecordBoard/shellFrame/Calendar/hooks/useBookingCalendarDayOverlayLayout.js +74 -0
  26. package/es/components/pisellRecordBoard/shellFrame/Calendar/modal/BookingCalendarBlockPanel.js +61 -0
  27. package/es/components/pisellRecordBoard/shellFrame/Calendar/modal/BookingCalendarOverflowListLayer.js +26 -0
  28. package/es/components/pisellRecordBoard/shellFrame/Calendar/utils/bookingCalendarDateUtils.js +11 -1
  29. package/es/components/pisellRecordBoard/shellFrame/Calendar/utils/bookingCalendarSelectionUtils.js +17 -0
  30. package/es/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarDaySelectionBar.js +12 -8
  31. package/es/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarDayView.js +3 -12
  32. package/es/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarResourceView.js +612 -0
  33. package/es/components/pisellRecordBoard/shellFrame/Calendar/view/day/useBookingCalendarDayHourRemaining.js +33 -0
  34. package/es/components/pisellRecordBoard/shellFrame/Calendar/view/day/useBookingCalendarDaySelection.js +37 -0
  35. package/es/components/pisellRecordBoard/shellFrame/Calendar/view/resource/useBookingCalendarResourceCellToggle.js +18 -0
  36. package/es/components/pisellRecordBoard/shellFrame/Calendar/view/resource/useBookingCalendarResourceDayHeaderRemaining.js +33 -0
  37. package/es/components/pisellRecordBoard/shellFrame/Calendar/view/useBookingCalendarGoToDayFromCell.js +29 -0
  38. package/es/components/pisellRecordBoard/types.d.ts +38 -6
  39. package/es/components/pisellReservationSchedule/PisellReservationSchedule.js +19 -3
  40. package/es/components/pisellReservationSchedule/PisellReservationSchedule.less +23 -0
  41. package/es/index.d.ts +2 -2
  42. package/es/locales/en-US.js +6 -5
  43. package/es/locales/ja.js +1 -0
  44. package/es/locales/pt.js +1 -0
  45. package/es/locales/zh-CN.js +1 -0
  46. package/es/locales/zh-TW.js +1 -0
  47. package/es/pisell-materials.tw.css +2413 -2
  48. package/lib/components/pisellFloorMapLayout/PisellFloorMapLayout.js +25 -10
  49. package/lib/components/pisellFloorMapLayout/appearance/floorMapAppearance.d.ts +4 -0
  50. package/lib/components/pisellFloorMapLayout/appearance/floorMapAppearance.js +22 -0
  51. package/lib/components/pisellFloorMapLayout/components/EditableItemLayer.js +3 -2
  52. package/lib/components/pisellFloorMapLayout/components/ItemLayer.js +7 -4
  53. package/lib/components/pisellFloorMapLayout/components/ItemLayer.less +10 -0
  54. package/lib/components/pisellFloorMapLayout/components/ViewControls.js +6 -5
  55. package/lib/components/pisellFloorMapLayout/components/ViewControls.less +29 -2
  56. package/lib/components/pisellFloorMapLayout/components/ViewControlsWithZoom.js +1 -0
  57. package/lib/components/pisellFloorMapLayout/context/mergeFloorMapLayoutContext.js +3 -1
  58. package/lib/components/pisellFloorMapLayout/types.d.ts +21 -2
  59. package/lib/components/pisellRecordBoard/index.d.ts +1 -1
  60. package/lib/components/pisellRecordBoard/shellFrame/Calendar/BookingCalendar.js +277 -227
  61. package/lib/components/pisellRecordBoard/shellFrame/Calendar/const/bookingCalendarConstants.js +18 -0
  62. package/lib/components/pisellRecordBoard/shellFrame/Calendar/hooks/useBookingCalendarDayOverlayLayout.js +75 -0
  63. package/lib/components/pisellRecordBoard/shellFrame/Calendar/modal/BookingCalendarBlockPanel.js +63 -0
  64. package/lib/components/pisellRecordBoard/shellFrame/Calendar/modal/BookingCalendarOverflowListLayer.js +28 -0
  65. package/lib/components/pisellRecordBoard/shellFrame/Calendar/utils/bookingCalendarDateUtils.js +11 -1
  66. package/lib/components/pisellRecordBoard/shellFrame/Calendar/utils/bookingCalendarSelectionUtils.js +17 -0
  67. package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarDaySelectionBar.js +12 -8
  68. package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarDayView.js +3 -12
  69. package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/BookingCalendarResourceView.js +614 -0
  70. package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/day/useBookingCalendarDayHourRemaining.js +34 -0
  71. package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/day/useBookingCalendarDaySelection.js +38 -0
  72. package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/resource/useBookingCalendarResourceCellToggle.js +19 -0
  73. package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/resource/useBookingCalendarResourceDayHeaderRemaining.js +34 -0
  74. package/lib/components/pisellRecordBoard/shellFrame/Calendar/view/useBookingCalendarGoToDayFromCell.js +30 -0
  75. package/lib/components/pisellRecordBoard/types.d.ts +38 -6
  76. package/lib/components/pisellReservationSchedule/PisellReservationSchedule.js +19 -3
  77. package/lib/components/pisellReservationSchedule/PisellReservationSchedule.less +23 -0
  78. package/lib/index.d.ts +2 -2
  79. package/lib/locales/en-US.js +6 -5
  80. package/lib/locales/ja.js +1 -0
  81. package/lib/locales/pt.js +1 -0
  82. package/lib/locales/zh-CN.js +1 -0
  83. package/lib/locales/zh-TW.js +1 -0
  84. package/lib/pisell-materials.tw.css +2413 -2
  85. package/lowcode/pisell-record-board-calendar-view/meta.ts +8 -0
  86. 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 require_OverflowListModal = require("./modal/OverflowListModal.js");
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
- * 日视图专用:按资源行上「同时段最大并行条数」算行高(`dayCourtOverlayRowHeightPx`);无预约行仍用 `dayRowHeight`;有 overlay 时不再做不小于 `dayRowHeight` 的额外下限。
160
- * 周/月不读其中大部分字段,但为单 hook 依赖仍随 `visibleCourtRows` 重算。
176
+ * 日视图 overlay 行高 / 并行 lane / +N 溢出(详见 hook 内注释)。
161
177
  */
162
- const { dayRowHeights, dayRowTopMap, overlayBookings, courtDayDisplayLaneCount, hiddenDayOverlayIdSet, dayOverlayOverflowPluses } = (0, react.useMemo)(() => {
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 || selectedFreeSlots.length === 0) return;
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
- slotStepHours
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
- function isFreeSelected(courtId, hour) {
315
- return selectedFreeSlots.some((slot) => slot.courtId === courtId && slot.date === dayKey && slot.hour === hour);
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
- function openBookingDetail(item) {
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 newBookings = require_bookingCalendarDateUtils.groupSelectedSlots(selectedFreeSlots, slotStepHours).map((slot, idx) => ({
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
- /** 按多选锁台槽从本地 bookings 中移除对应 block 片段 */
376
- function openSelectedBlocks() {
377
- if (!allowPersist("removeBlocks")) return;
378
- if (selectedBlockSlots.length === 0) return;
379
- const selectedSet = new Set(selectedBlockSlots.map((s) => `${s.courtId}-${s.date}-${s.hour}`));
380
- setBookings((prev) => prev.filter((item) => {
381
- if (item.kind !== "block") return true;
382
- require_bookingCalendarDateUtils.getBookingSegmentForDate(item, item.date);
383
- return !hourSlots.filter((slotStart) => slotStart >= item.startHour - 1e-9 && slotStart < item.endHour - 1e-9).some((h) => selectedSet.has(`${item.courtId}-${item.date}-${h}`));
384
- }));
385
- setSelectedBlockSlots([]);
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: selectedFreeSlots.map((s) => {
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 (_unused) {}
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
- dayKey,
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
- function handleDropMove(targetCourtId, targetDate, targetHour) {
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 (!isBusinessHour(nextStart) || nextEnd > endTimelineExclusive) return;
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
- function handleGridDropMove(targetDate, targetCourtId = null) {
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
- }))), showBlockPanel && !props.onBlockedTimePanelRequest && selectedFreeSlots.length > 0 && require_bookingCalendarDateUtils.isFreeSelectionContiguousSameResource(selectedFreeSlots, slotStepHours) && /* @__PURE__ */ react.default.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.default.createElement("div", {
631
- ref: blockPanelRef,
632
- 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]"}`
633
- }, /* @__PURE__ */ react.default.createElement("div", { className: "mb-4 flex items-center justify-between gap-3" }, /* @__PURE__ */ react.default.createElement("div", { className: "text-xl font-semibold" }, require_calendarI18n.tCal("pisell2.recordBoard.calendar.block.panelTitle")), /* @__PURE__ */ react.default.createElement("button", {
634
- type: "button",
635
- "aria-label": require_calendarI18n.tCal("pisell2.recordBoard.calendar.block.closeAria"),
636
- onClick: () => setShowBlockPanel(false),
637
- className: `rounded-xl p-2 ${isLight ? "btn-neutral" : "border border-zinc-700 text-zinc-300"}`
638
- }, /* @__PURE__ */ react.default.createElement(_ant_design_icons.CloseOutlined, { style: { fontSize: 20 } }))), /* @__PURE__ */ react.default.createElement("div", { className: `space-y-4 rounded-2xl border p-4 ${isLight ? "theme-panel-alt theme-border" : "border-zinc-700 bg-[#171820]"}` }, /* @__PURE__ */ react.default.createElement("div", null, /* @__PURE__ */ react.default.createElement("label", { className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}` }, require_calendarI18n.tCal("pisell2.recordBoard.calendar.block.fieldTitle")), /* @__PURE__ */ react.default.createElement("input", {
639
- value: blockFormName,
640
- onChange: (e) => setBlockFormName(e.target.value),
641
- placeholder: require_calendarI18n.tCal("pisell2.recordBoard.calendar.block.placeholderTitle"),
642
- className: `w-full rounded-xl px-3 py-2 outline-none ${isLight ? "theme-input theme-text" : "border border-zinc-700 bg-[#111218] text-white"}`
643
- })), /* @__PURE__ */ react.default.createElement("div", null, /* @__PURE__ */ react.default.createElement("label", { className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}` }, "备注"), /* @__PURE__ */ react.default.createElement("input", {
644
- value: blockModalNote,
645
- onChange: (e) => setBlockModalNote(e.target.value),
646
- placeholder: "选填",
647
- className: `w-full rounded-xl px-3 py-2 outline-none ${isLight ? "theme-input theme-text" : "border border-zinc-700 bg-[#111218] text-white"}`
648
- })), /* @__PURE__ */ react.default.createElement("div", null, /* @__PURE__ */ react.default.createElement("label", { className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}` }, require_calendarI18n.tCal("pisell2.recordBoard.calendar.block.fieldResource")), /* @__PURE__ */ react.default.createElement("select", {
649
- value: blockResourceId,
650
- onChange: (e) => setBlockResourceId(e.target.value),
651
- className: `w-full rounded-xl px-3 py-2 outline-none ${isLight ? "theme-input theme-text" : "border border-zinc-700 bg-[#111218] text-white"}`
652
- }, /* @__PURE__ */ react.default.createElement("option", { value: "" }, require_calendarI18n.tCal("pisell2.recordBoard.calendar.block.noResource")), visibleCourts.map((c) => /* @__PURE__ */ react.default.createElement("option", {
653
- key: c.id,
654
- value: String(c.id)
655
- }, c.name)))), /* @__PURE__ */ react.default.createElement("div", null, /* @__PURE__ */ react.default.createElement("label", { className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}` }, require_calendarI18n.tCal("pisell2.recordBoard.calendar.block.fieldTimeRange")), /* @__PURE__ */ react.default.createElement(RangePicker, {
656
- style: { width: "100%" },
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
- showStatusUi: Boolean(overflowListModal.scope && String(overflowListModal.scope).startsWith("day-lane-overflow-"))
690
- })))), moveConfirm && /* @__PURE__ */ react.default.createElement(require_MoveConfirmModal.MoveConfirmModal, {
739
+ onPickItem: openBookingDetail
740
+ }), moveConfirm && /* @__PURE__ */ react.default.createElement(require_MoveConfirmModal.MoveConfirmModal, {
691
741
  moveConfirm,
692
742
  moveDraft,
693
743
  setMoveDraft,