|
@@ -1325,6 +1325,7 @@
|
|
|
<script type="module">
|
|
<script type="module">
|
|
|
import * as Vue from 'vue'
|
|
import * as Vue from 'vue'
|
|
|
import '@iconify/iconify'
|
|
import '@iconify/iconify'
|
|
|
|
|
+import { fmtDate, parseLocal, addDays, daysBetween, buildWeeks, bannersForWeek as _bannersForWeek } from './src/lib/calendar-grid/index.js'
|
|
|
const API_BASE = window.API_BASE
|
|
const API_BASE = window.API_BASE
|
|
|
const { createApp, ref, computed, watch, onMounted, nextTick, reactive } = Vue;
|
|
const { createApp, ref, computed, watch, onMounted, nextTick, reactive } = Vue;
|
|
|
const DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
const DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
@@ -1768,26 +1769,7 @@ createApp({
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ── Helpers ────────────────────────────────────────────
|
|
// ── Helpers ────────────────────────────────────────────
|
|
|
- function pad(n) { return String(n).padStart(2, '0'); }
|
|
|
|
|
-
|
|
|
|
|
- function fmtDate(d) {
|
|
|
|
|
- return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function parseLocal(str) {
|
|
|
|
|
- const [y, m, d] = str.split('-').map(Number);
|
|
|
|
|
- return new Date(y, m - 1, d);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function addDays(d, n) {
|
|
|
|
|
- const r = new Date(d);
|
|
|
|
|
- r.setDate(r.getDate() + n);
|
|
|
|
|
- return r;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function daysBetween(a, b) {
|
|
|
|
|
- return Math.round((b - a) / 86400000);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // fmtDate, parseLocal, addDays, daysBetween imported from calendar-grid
|
|
|
|
|
|
|
|
function capitalize(str) {
|
|
function capitalize(str) {
|
|
|
return str ? str.charAt(0).toUpperCase() + str.slice(1) : '';
|
|
return str ? str.charAt(0).toUpperCase() + str.slice(1) : '';
|
|
@@ -1820,20 +1802,7 @@ createApp({
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ── Calendar grid ──────────────────────────────────────
|
|
// ── Calendar grid ──────────────────────────────────────
|
|
|
- const weeks = computed(() => {
|
|
|
|
|
- const first = new Date(year.value, month.value, 1);
|
|
|
|
|
- const last = new Date(year.value, month.value + 1, 0);
|
|
|
|
|
- const cursor = new Date(first);
|
|
|
|
|
- cursor.setDate(cursor.getDate() - cursor.getDay());
|
|
|
|
|
- const result = [];
|
|
|
|
|
- while (true) {
|
|
|
|
|
- const week = [];
|
|
|
|
|
- for (let i = 0; i < 7; i++) { week.push(new Date(cursor)); cursor.setDate(cursor.getDate() + 1); }
|
|
|
|
|
- result.push(week);
|
|
|
|
|
- if (cursor > last) break;
|
|
|
|
|
- }
|
|
|
|
|
- return result;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ const weeks = computed(() => buildWeeks(year.value, month.value));
|
|
|
|
|
|
|
|
const monthName = computed(() =>
|
|
const monthName = computed(() =>
|
|
|
new Date(year.value, month.value, 1).toLocaleString('default', { month: 'long' })
|
|
new Date(year.value, month.value, 1).toLocaleString('default', { month: 'long' })
|
|
@@ -2087,34 +2056,8 @@ createApp({
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
function bannersForWeek(week) {
|
|
function bannersForWeek(week) {
|
|
|
- const weekStart = week[0];
|
|
|
|
|
- const weekEnd = week[6];
|
|
|
|
|
- const banners = [];
|
|
|
|
|
-
|
|
|
|
|
- for (const span of [...reservationSpans.value, ...closureSpans.value]) {
|
|
|
|
|
- if (span.end < weekStart || span.start > weekEnd) continue;
|
|
|
|
|
-
|
|
|
|
|
- const clipStart = span.start < weekStart ? weekStart : span.start;
|
|
|
|
|
- const clipEnd = span.end > weekEnd ? weekEnd : span.end;
|
|
|
|
|
-
|
|
|
|
|
- const startCol = daysBetween(weekStart, clipStart);
|
|
|
|
|
- const spanCols = daysBetween(clipStart, clipEnd) + 1;
|
|
|
|
|
- const leftInset = span.start >= weekStart ? 0.2 : 0;
|
|
|
|
|
- const rightBleed = span.end <= weekEnd ? 0.8 : 0;
|
|
|
|
|
-
|
|
|
|
|
- const leftPct = ((startCol + leftInset) / 7) * 100;
|
|
|
|
|
- const widthPct = ((spanCols - leftInset - rightBleed) / 7) * 100;
|
|
|
|
|
-
|
|
|
|
|
- banners.push({
|
|
|
|
|
- cls: span.cls,
|
|
|
|
|
- label: span.label,
|
|
|
|
|
- spanKey: span.resKey ?? null,
|
|
|
|
|
- span,
|
|
|
|
|
- left: `calc(${leftPct.toFixed(4)}% + 2px)`,
|
|
|
|
|
- width: `calc(${widthPct.toFixed(4)}% - 4px)`,
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- return banners;
|
|
|
|
|
|
|
+ return _bannersForWeek(week, [...reservationSpans.value, ...closureSpans.value])
|
|
|
|
|
+ .map(b => ({ ...b, spanKey: b.resKey ?? null, span: b }));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ── Fetch ──────────────────────────────────────────────
|
|
// ── Fetch ──────────────────────────────────────────────
|