Google Apps Script 自動排班系統,適用於公司同仁班表管理。
- 自動產生月班表(N×M 搜索架構 + ILS 迭代優化)
- 動態評分機制:自動適應不同月份結構(如 2 月年假密集期)
- 智慧優化:Gap-Fixing Swap(空班填補交換)+ Hour-Balancing Swap(工時平衡交換)
- 人力吃緊日識別與保護機制(Look-ahead 預判)
- 跨月約束檢查:參考上月最後 5 天班表,確保月初排班符合所有法規約束
- 支援排休意願、指定班表、公假
- 差勤匯出 (CSV)
- 行事曆匯出 (ICS)
本專案由三個 JavaScript 檔案組成,需全部貼入 Google Apps Script:
| 檔案 | 說明 | 主要功能 |
|---|---|---|
scheduling.js |
排班主程式 | 選單建立、排班流程控制、核心排班迴圈、輸出寫入 |
helper.js |
輔助函式庫 | 候選人篩選/評分、連續天數檢查、智慧優化 (Swap)、ILS 演算法 |
load.js |
資料讀取模組 | 讀取工作表並解析為結構化資料(含上月班表) |
直接建立範本副本即可開始使用。範本內已包含所有必要的工作表格式以及 Apps Script 程式碼。
-
取得範本:點此開啟「排班系統」範本
-
建立副本:點擊選單 「檔案」 → 「建立副本」。
-
完成:您現在擁有一個已經設定好的試算表了!請直接跳至 步驟 5:授權與執行 進行授權。
如果您希望從頭開始建立試算表,請依照以下步驟操作:
- 前往 Google Sheets
- 點擊 「空白」 建立新試算表
- 將試算表命名為
排班系統(或任意名稱)
在試算表底部,點擊 「+」 新增工作表,並依照以下 名稱完全一致 建立:
| # | 工作表名稱 | 用途 | 必要 |
|---|---|---|---|
| 1 | 人員名單 (Staff) |
員工基本資料 | 必要 |
| 2 | 班別資料庫 (Shift_DB) |
班別定義 | 必要 |
| 3 | 系統參數 (System_Params) |
假日設定、預設規則 | 必要 |
| 4 | 每日需求 (Daily_Needs) |
特定日期人力需求 | 必要 |
| 5 | 指定班表 (Fixed_Shifts) |
強制指定班別 | 必要 |
| 6 | 排休意願 (Leave_Requests) |
員工請假/畫休/公假 | 必要 |
| 7 | 上月班表 (Prev_Month) |
上月最後 5 天班表(跨月約束) | 選填 |
| 8 | 排班主表 (Scheduler) |
【輸出】產生的班表 | 必要 |
| 9 | 統計報告 (Summary) |
【輸出】工時統計 | 必要 |
| 10 | 差勤匯出 (CSV_Export) |
【輸出】差勤格式 | 必要 |
重要:名稱必須 完全一致(含空格、括號),否則程式會報錯! 提示:第 7 項「上月班表」為選填,不建立也不影響排班功能。
| A 欄 | B 欄 | C 欄 | D 欄 | E 欄 |
|---|---|---|---|---|
| 員工代號 | 姓名 | 工號 | 啟用 | (顏色標記) |
範例資料:
員工代號 姓名 工號 啟用 (E欄可留空)
A 王小明 EMP001 TRUE
B 李小華 EMP002 TRUE
C 張大文 EMP003 FALSE ← 不參與排班
提示:E 欄可設定背景顏色,該顏色會顯示在班表上
| A 欄 | B 欄 | C 欄 | D 欄 | E 欄 | F 欄 | G 欄 |
|---|---|---|---|---|---|---|
| 班別代號 | 班別名稱 | 開始時間 | 結束時間 | 工時 | 差勤代碼 | 11小時限制 |
必要班別(系統需要這三個):
班別代號 班別名稱 開始時間 結束時間 工時 差勤代碼 11小時限制
S1 正規班 08:00 17:00 8 125-2 FALSE
CA 公假 08:00 17:00 8 CA FALSE
OFF 休息 - - 0 0 FALSE
可選班別(夜班範例):
S2 夜班CF 14:00 01:00 11 CF TRUE
S3 夜班CL 15:00 02:00 11 CL TRUE
關鍵代碼說明:
125-2:預設工作班(必須有)CA:請假班(必須有)0:休息班(必須有)11小時限制 = TRUE:該班下班後,隔天不能排早班
| A 欄 | B 欄 | C 欄 | D 欄 | E 欄 | ... |
|---|---|---|---|---|---|
| 日期 | 星期 | (姓名1) | (姓名2) | (姓名3) | ... |
範例資料:
(A1 留空) (B1 留空) ← 第 1 行:空白或標題
(A2 留空) (B2 留空) ← 第 2 行:空白或標題
1 三 王小明 李小華*
2 四 張大文
3 五
重要:前兩行為 header,系統會跳過,請從第 3 行開始填寫資料。
命名規則:
王小明:畫休(輪休,無工時)王小明*或王小明(公假):請假(CA,計算工時)王小明(公)或王小明(公):公假(OL,計算連續上班天數,8 小時工時)
| A 欄 | B 欄 | C 欄 |
|---|---|---|
| 日期 | 班別代號 | 需求人數 |
範例資料:
日期 班別代號 需求人數
2025/1/15 S1 8 ← 1/15 需要 8 人上正規班
2025/1/15 S2 0 ← 1/15 不需要夜班
2025/1/20 S1 10 ← 1/20 全員動員
重要:若某日有特殊需求,必須所有工作班別都指定人數才會正常運作。例如 1/15 要調整 S1 人數,則 S2、S3 也必須一併指定,否則未指定的班別會使用預設規則。
| A 欄 | B 欄 | C 欄 | D 欄 | E 欄 |
|---|---|---|---|---|
| 假日日期 | (備註) | 規則類型 | 班別代號 | 需求人數 |
範例資料:
假日日期 備註 規則類型 班別代號 需求人數
2025/1/1 元旦 weekday S1 6
2025/1/29 除夕 weekday S2 2
holiday S1 3
holiday S2 1
規則類型:
weekday:平日預設需求holiday:假日預設需求重要:非六日的國定假日(如元旦、春節、端午等)必須在 A 欄手動輸入日期,否則系統會將該日視為平日排班。
| A 欄 | B 欄 | C 欄 | D 欄 | ... |
|---|---|---|---|---|
| 日期 | 班別代號 | 姓名1 | 姓名2 | ... |
範例資料:
日期 班別代號 (指定人員)
2025/1/10 S2 王小明 李小華
2025/1/11 S3 張大文
說明:指定班表優先權最高,會覆蓋排休意願
格式與「排班主表 (Scheduler)」的輸出格式相同。用於跨月約束檢查,只需填入上月最後 5 天的班表資料。
第一行為 header,格式範例:
排休 125-2(6) CF(2) CL(1)
排休:該欄列出當天排休的員工姓名(格式:姓名(公),姓名(假),姓名(休),逗號分隔)125-2(6):班別名稱 + 括號內數字(數字可為任意值,系統只看班別名稱)- 各班別欄位中填入該班的員工姓名,一行一天
資料列範例(假設上月為 1 月,填最後 5 天):
排休 125-2(6) CF(2) CL(1)
王小明(休), 李小華(假) 張大文, 陳小芳 趙六 錢七
...
提示:
- 最簡單的做法:直接從上月「排班主表」整份複製(含 header)貼上即可,系統會自動只取最後 5 天的資料
- 若不建立此工作表,系統行為與以前完全一致(月初不做跨月約束檢查)
以下三個工作表 不需要手動填寫,系統會自動產生:
排班主表 (Scheduler)- 產生的班表統計報告 (Summary)- 工時統計差勤匯出 (CSV_Export)- 差勤系統格式
-
在試算表中,點擊選單 「擴充功能」 → 「Apps Script」
-
刪除編輯器中預設的程式碼:
function myFunction() { }
-
建立 三個 檔案,並分別貼上對應的程式碼:
Apps Script 檔案名稱 來源檔案 說明 scheduling.gsscheduling.js主程式(含 onOpen選單)helper.gshelper.js輔助函式與優化演算法 load.gsload.js資料讀取模組 在 Apps Script 編輯器中,點擊左側檔案列表旁的 「+」 → 「指令碼」 來新增檔案。 提示:新增檔案時只需輸入檔名前綴(如
scheduling),Apps Script 會自動加上.gs副檔名。 -
點擊 「儲存」 圖示 (或按
Ctrl+S) -
將專案命名為
排班引擎
-
首次執行需要授權:
- 點擊 「執行」 按鈕(或從試算表選單執行)
- 出現「需要授權」對話框,點擊 「查看權限」
- 選擇你的 Google 帳號
- 點擊 「進階」 → 「前往 排班引擎 (不安全)」
- 點擊 「允許」
-
重新整理試算表(按
F5或重新開啟) -
試算表選單會出現 「排班引擎 V7.2」
- 點擊選單 「排班引擎 V7.2」 → 「1. 產生本月班表」
- 輸入 年份 (例如: 2025)
- 輸入 月份 (例如: 1)
- 確認執行
- 系統執行運算,視人數多寡約需 2-5 分鐘
提示:執行中的進度訊息會顯示在試算表右下角,顯示目前處理到第幾個初始解及 ILS 迭代進度。
- 先產生班表(或手動修改過班表後想重新計算統計)
- 點擊 「2. 產生統計報告 (Summary)」
- 輸入年份確認
- 結果會寫入
統計報告 (Summary)工作表
提示:產生班表時會自動產生統計報告。此功能適用於手動調整班表後,需要重新計算統計數據的情境。
- 先產生班表
- 點擊 「3. 產生差勤匯出 (CSV)」
- 輸入年份確認
- 結果會寫入
差勤匯出 (CSV_Export)工作表
- 先產生班表
- 點擊 「4. 產生行事曆 (ICS)」
- 輸入年份確認
- ICS 檔案會存到 Google Drive 資料夾
每個初始解都獨立做 ILS 優化,最後取全域最佳,搜索廣度遠優於「先選最佳再優化」。
Phase 0: 載入上月班表 (若有)
└─ Warm-up:回放上月最後 5 天,初始化連續天數/lastShift 等狀態
Phase 1+2: N×M 搜索 (50 個初始解 × 20 次 ILS = 1,000 次運算)
For each 初始解:
├─ 核心排班 (coreScheduler)
│ ├─ P0 吃緊日預排
│ ├─ P1 每日需求分配
│ ├─ P2 請假處理
│ ├─ P3 畫休處理
│ └─ P4B 剩餘人員填補 (燃盡圖邏輯)
├─ 空班補救 (fillUnfilledSlots)
├─ 智慧優化 (Gap-Fixing Swap + Hour-Balancing Swap)
├─ 工時消減 (reduceOverworkedStaff)
├─ ILS 迭代優化 (最多 20 次)
│ ├─ 擾動 (Perturbation)
│ │ ├─ 策略 A: 同日交換兩人班別
│ │ ├─ 策略 B: 隨機切換上班/休息
│ │ └─ 策略 C: 跨日交換 (同一人不同天)
│ └─ 局部搜索 + 接受/拒絕判定
└─ 與全域最佳比較,保留更優解
Phase 3: 最終驗收
├─ 計算空班數
├─ 計算工時全距
└─ 輸出結果報告
指定班表 > 公假 > 每日需求 > 排休意願 > 畫休意願 > 自動填補
| 規則 | 說明 |
|---|---|
| 全域連續上限 | 最多連續上班 5 天 |
| 含夜班連續上限 | 含夜班時最多連續 3 天 |
| 純夜班連續上限 | 純夜班最多連續 3 天 |
| 11 小時規則 | 夜班 (S2/S3) 後隔天不能接早班(雙向檢查) |
| 吃緊日保護 | 人力吃緊日預排結果受保護,不被後續覆蓋 |
| Look-ahead 預判 | 排班時預判是否會與未來吃緊日衝突 |
| 跨月約束 | 月初排班參考上月最後 5 天,所有約束跨月生效 |
- 目標工時 =
當月工作日數 × 8 小時 - 系統透過 ILS 優化,盡量讓全員工時全距 ≤ 4 小時
- 完美達成條件:零空班 + 工時全距 ≤ 4 小時
系統會根據當月結構自動調整評分權重,解決 2 月等假日密集月份的超時問題:
優先順序:工時全距 >> 超工時 >= 空班
| 指標 | 權重 | 說明 |
|---|---|---|
| 工時全距 | 56,000 / 小時 | 最高優先,確保全員工時均衡 |
| 超工時 | 5,000 × sqrt | 遞減效應,避免糾結不可避免的超時 |
| 空班數 | 3,000 / 空班 | 填班重要但不強制 |
動態超時門檻:系統自動計算當月「結構性超時」(總需求 > 總容量時不可避免的超時),門檻會自動上移,讓演算法專注於可改善的項目。
例:2 月目標工時 120h,但需求換算人均 140h → 門檻自動提升至 144h,低於門檻不扣分
當某個班別出現空缺時,尋找可行的三方交換:
- 找到空班 T(Target Shift)
- 找到員工 A:目前上 S 班,但可以上 T 班
- 找到員工 B:目前休息,但可以上 S 班
- 交換:A 補 T,B 接手 S
計算全員平均工時,讓工時高於平均的人將班次轉給工時低於平均的人,縮小整體工時差距。
每個初始解各自進行「擾動 + 局部搜索」循環,透過隨機擾動跳脫局部最佳解,並設有:
- 連續無改善上限(8 次)自動停止
- 時間上限(5 分鐘)保護
- 機率性接受較差解(10%)避免陷入局部最優
A: 請確認工作表名稱完全一致,包含空格和括號。
A: 檢查「人員名單」的 D 欄(啟用)是否為 TRUE。
A:
- 檢查「系統參數」的 weekday/holiday 規則
- 檢查「每日需求」是否有特殊設定
- 檢查「指定班表」是否有強制指派
A: 確認「班別資料庫」的 G 欄(11小時限制)設為 TRUE。
A: V7.2 採用 N×M 搜索架構(50 個初始解 × 20 次 ILS = 1,000 次運算),通常需要 2-5 分鐘。每個初始解都有機會被優化到各自的局部最優,最後取全域最佳,品質比舊架構更好。
A: 在「排休意願」工作表中,姓名後加上 (公) 或 (公),例如 王小明(公)。公假會計算 8 小時工時並計入連續上班天數。
A: 「上月班表 (Prev_Month)」工作表為選填。不建立此工作表,系統行為與以前完全一致。 若要啟用跨月約束檢查,最簡單的做法是:從上月排好的「排班主表」複製最後 5 行(含第一行 header)貼到「上月班表」即可。系統會自動參考這些資料,確保月初不會出現上月夜班隔天接早班、連續上班超過上限等違規情況。
A: 可以。系統只取最後 5 天資料,若不足 5 天則以實際天數為準。填越多天數,跨月約束檢查越完整。
- V7.2 - N×M 搜索架構(50×20)+ 動態評分機制(自動適應 2 月等特殊月份)
- V7.1 - 跨月約束檢查:讀取上月最後 5 天班表,月初排班所有約束跨月生效
- V7.0 - ILS 迭代優化架構 + 預先初始化 finalSchedule
- V6.9.25 - 智慧優化演算法:Gap-Fixing Swap 空班填補交換
- V6.9.24 - 空班補救支援 S2/S3 + 11hr 雙向檢查
- V6.9.23 - 吃緊日保護機制 + Look-ahead 預判,減少空班
- V6.9.22 - 空班補救機制(只補空班,不強制工時達標)
- V6.9.20 - 修正含夜班連續天數限制 hasNightInStreak
- V6.9.19 - 公假明天不排夜班的往前看規則
- V6.9.18 - 公假獨立結構 (OL)
- V6.9.17 - 新增公假虛擬班別
- V6.9.15 - 動態班別排序(候選人少的優先)
- V6.9.12 - 人力吃緊日識別機制
- V6.9.11 - 班別分配順序:S2 → S3 → S1
- V6.9.10 - 修正姓名匹配邏輯
- V6.9.9 - 新增班別計數統計
- V6.9.8 - 修正 11 小時規則
- V6.8 - 新增工時平衡重跑機制
本專案採用 MIT License 授權。




















