@jungtz/calendar-scheduler
v0.4.2
Published
Hotel room reservation calendar scheduler - vanilla JS library
Maintainers
Readme
Calendar Scheduler v2 📅
這是一款專為**飯店客房預訂(Hotel Reservation)與物業管理系統(PMS)**量身打造的輕量化、高效能日曆排程表(Calendar Scheduler)套件。
本套件完全基於 純 JavaScript (Vanilla JS) 與 Sass/SCSS 自研構建,零外部 UI 框架依賴,並採用現代的 Class-based 邏輯與 ESM 格式輸出,具備極高的相容性與極輕的代碼體積。
🌟 核心特色 (Core Features)
- 零框架依賴:擺脫 Vue、React 或 Bootstrap-Vue 等沉重框架束縛,大小極度輕量,能無縫整合至任何前端專案中。
- 漸進式無痕更新 (Idiomorph DOM Morphing):
- 引進先進的
Idiomorph進行虛擬 DOM 比對與局部節點更新。 - 徹底告別傳統
innerHTML暴力重繪所造成的 UI 閃爍、捲軸移位與輸入焦點遺失,帶來絲滑順暢的更新體驗。
- 引進先進的
- 純資料驅動的跨行 (Rowspan) 計算:
- 重構了 rowspan 的佈局引擎。不再低效地在渲染後去查詢 DOM 節點數量。
- 在渲染前,直接由
dataResult資料結構預先計算每個資源在特定時間區間內的最大排程長度,提供極致穩定的佈局與渲染效能。
- HTML5 原生拖曳 (Drag & Drop) 引擎:
- 精確限定拖曳目標容器(
[data-type="content"], [data-type="wait"]),大幅提升互動精準度。 - 智慧衝突過濾:自動識別並保留原先已存在的衝突(Orig Conflicts),只對「拖放所產生的新衝突」進行干預與警報。
- 零變更優化:當原地拖放(無實質資料變更)時,自動跳過重新渲染與事件觸發,大幅降低 CPU 負載。
- 精確限定拖曳目標容器(
- 流暢的雙向滾動同步 (Scroll Sync):
- 完美同步左側資源菜單與右側排程表,不發生位置偏差。
- 水平滾動時會自動快取滾動位置(儲存至
sessionStorage),確保頁面重整後視圖不跳動。 - 垂直滾動時提供流暢、動態計算定位基準的 Sticky 標題浮動效果。
- 自適應折疊動畫:改用平滑的
max-heightCSS 動畫優化資源菜單的展開與折疊。 - 健全的 Month (月) 視圖支援:除了動態天數外,亦完整支援
month視圖,能自動計算當月的首尾日期。 - UID 穩定機制:自動為所有預訂卡片(Items)分配並維護穩定的
_uid,以保證 DOM Morphing 時的節點穩定對齊。
📦 安裝指南 (Installation)
Peer Dependencies
本套件需要以下 peer dependencies,請確保您的專案中已安裝:
dayjs(>= 1.11.13) - 用於日期與時間計算split.js(>= 1.6.5) - 用於左右區塊拖曳分割
npm install dayjs split.js引入套件
您可以使用 NPM 安裝此套件(或直接引入建置後的 ESM 模組與樣式檔):
import { CalendarScheduler } from '@jungtz/calendar-scheduler';
import '@jungtz/calendar-scheduler/dist/style.css';🚀 快速開始 (Quick Start)
在您的 HTML 中建立一個容器:
<!-- 引入 Font Awesome 6 (可選,用於圖示顯示) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" />
<div id="calendar-container"></div>在 JavaScript 中初始化:
import { CalendarScheduler } from '@jungtz/calendar-scheduler';
import '@jungtz/calendar-scheduler/dist/style.css';
// 1. 定義資源資料 (房型與房號)
const resources = [
{
id: 1,
name: '標準雙人房',
active: true,
children: [
{ id: 101, name: '101 室' },
{ id: 102, name: '102 室' }
]
}
];
// 2. 定義預訂卡片資料 (Items)
const items = [
{
id: 'res-9981',
title: '王小明 (3晚)',
start: '2026-05-20',
end: '2026-05-23',
room_type: 1,
room_number_id: 101,
assign: true, // 已指派房號
checked_status: 'checked-in' // 自訂樣式狀態
}
];
// 3. 初始化排程表
const calendar = new CalendarScheduler('#calendar-container', {
resource: resources,
items: items,
locale: 'tw', // 支援 'tw', 'en', 'ja'
allowEdit: true, // 允許編輯與彈窗事件
allowContinuous: true, // 支援跨日拖曳
allowAutoAssign: true, // 支援自動指派
showAssignButton: true,// 顯示指派按鈕
view: {
count: 7 // 預設展示 7 天 (亦可設定為 'month' 展示整月)
}
});
// 4. 監聽拖放完成事件 (Drop)
calendar.on('drop', (event) => {
console.log('拖放成功,新預訂資訊:', event);
// 可在此串接 API 將變更寫回資料庫
});📖 API 參考文件 (API Reference)
初始化設定 (Initialization Options)
| 選項參數 | 類型 | 預設值 | 說明 |
| :--- | :--- | :--- | :--- |
| resource | Array | [] | 資源樹資料結構(包含父房型與子房號)。 |
| items | Array | [] | 預訂卡片資料陣列(會自動生成或對齊 _uid)。 |
| stock | Object | {} | 每日庫存量與剩餘房數資訊。 |
| holidays | Array | [] | 特殊節假日資料,會在表頭顯示標記。 |
| locale | String | 'tw' | 語系設定:'tw' (繁體中文)、'en' (英文)、'ja' (日文)。 |
| allowEdit | Boolean | true | 是否啟用編輯與點擊卡片事件。 |
| allowContinuous| Boolean | true | 是否允許跨日連續卡片顯示。 |
| allowAutoAssign| Boolean | true | 是否啟用拖曳自動指派機制。 |
| allowChangeDate| Boolean | true | 是否允許在拖放中改變日期。 |
| allowChangeType| Boolean | true | 是否允許在拖放中改變房型/資源類別。 |
| showAssignButton| Boolean | false | 是否在預訂卡片上顯示指派按鈕。 |
| view.count | Number\|String| 7 | 展示天數(傳入數字)或設定為 'month'。 |
📊 資料格式說明 (Data Formats)
為了讓排程表正常運作,傳入的 resource、items 以及 stock 必須符合特定的資料結構。以下是各資料結構的詳細說明與範例:
1. 資源資料 (resource)
資源資料通常為樹狀結構,代表「房型(父級)」與「房號(子級)」。
id(Number|String): 資源的唯一識別碼。name(String): 資源顯示名稱。active(Boolean, 選填): 是否啟用。children(Array, 選填): 子級資源清單(如房號)。子級資源同樣包含id與name。
const resources = [
{
id: 1,
name: '標準雙人房',
active: true,
children: [
{ id: 101, name: '101 室' },
{ id: 102, name: '102 室' }
]
}
];2. 預訂卡片資料 (items)
代表預訂或排程卡片,顯示於時間軸上。
id(Number|String): 預訂的唯一識別碼。title(String): 卡片上顯示的標題或客戶姓名。start(String): 開始日期,格式為YYYY-MM-DD。end(String): 結束日期,格式為YYYY-MM-DD。room_type(Number|String): 所屬的父級資源(房型)ID。room_number_id(Number|String, 選填): 所屬的子級資源(房號)ID。若為null或未指定且啟用自動分配,則可能被視為未排房。assign(Boolean): 是否已指派房號。checked_status(String, 選填): 自訂的狀態樣式名稱(例如'checked-in','checked-out','noshow')。
const items = [
{
id: 'res-9981',
title: '王小明 (3晚)',
start: '2026-05-20',
end: '2026-05-23',
room_type: 1,
room_number_id: 101,
assign: true,
checked_status: 'checked-in'
}
];3. 每日庫存資料 (stock)
用於呈現每日的房間庫存、價格及開放狀態。結構為巢狀物件:外層 Key 為資源 ID(房型 ID),內層 Key 為日期(YYYY-MM-DD)。
每個日期對應的 Stock 物件必要內容如下:
price(Number): 每日房價。stock(Number): 剩餘庫存量。open(Number): 庫存開啟狀態,1表示開啟,0表示關閉(關閉時會顯示鎖定/無庫存狀態)。full(Number): 滿房狀態,1表示已滿,0表示未滿(滿房時會呈現滿房樣式)。
const stock = {
// Key '1' 代表 room_type_id 為 1 的房型
"1": {
"2026-05-20": {
"price": 2800,
"stock": 5,
"open": 1,
"full": 0
},
"2026-05-21": {
"price": 2800,
"stock": 0,
"open": 1,
"full": 1 // 滿房
},
"2026-05-22": {
"price": 3200,
"stock": 3,
"open": 0, // 關閉房況
"full": 0
}
}
};公開方法 (Public Methods)
套件實例提供了多個 API 方法,便於您動態控制排程表:
setItems(items)更新排程卡片資料。內部會自動維護_uid的一致性並透過 Idiomorph 進行局部 DOM 無痕刷新。calendar.setItems(newItemsList);setResource(resource)更新資源選單資料並重新計算排程網格。calendar.setResource(newResourcesList);setStock(stock)更新每日庫存與剩餘房數。calendar.setStock(newStockData);refresh()手動觸發視圖重新渲染。calendar.refresh();destroy()徹底銷毀排程表實例,清除所有全域事件監聽器(如window滾動監聽),並還原 DOM 容器。calendar.destroy();
事件監聽 (Event Listeners)
您可以使用 .on(eventName, callback) 方法監聽排程表內的交互事件:
click當點擊卡片、空白網格或日期表頭時觸發。calendar.on('click', (data) => { // data 包含 type ('item'|'date'|'cell'), value 及原始事件 e console.log('點擊事件:', data); });drop當預訂卡片拖曳釋放並成功變更位置時觸發。calendar.on('drop', (data) => { // data 包含卡片的 _uid, 新日期, 房號 room, 原始數據 rawData 等 console.log('拖曳落點更新:', data); });change當開關選項、視圖天數改變或刷新時觸發。calendar.on('change', (data) => { console.log('狀態變更:', data); });
🛠️ 開發與建置 (Development)
若您需要對套件進行二次開發或客製化,請確保已在專案目錄下執行 npm install。
啟動本地開發伺服器
運行 Vite 開發伺服器,並開啟 Dev Demo 頁面進行調試:
npm run dev建置生產環境版本
使用 Vite 將源碼與樣式打包編譯至 dist 目錄:
npm run build建置輸出將包含:
dist/calendar-scheduler.es.js- 優化壓縮後的 ESM 核心邏輯dist/style.css- 自研 CSS 樣式檔
監聽建置模式
npm run build:watch📄 授權協議 (License)
本專案採用 MIT License 授權協議。您可以自由地商用、修改及分發。
