# 排班模板設計提案 (Schedule Template Design Proposal)

根據您的需求，我們需要設計一個能夠靈活支持「小時制」、「天制」與「月份制」的排班模板結構。目前的 `start_time` / `end_time` 設計過於簡單，建議將其擴展為一個更具結構化的 `config` 欄位。

## 1. 核心邏輯設計

我們建議將模板類型 (`type`) 分為三種，並根據不同類型定義其專屬的設定結構：

- **小時制 (Hourly)**: 以 24 小時為基底，預設支援插入休息時段。
- **天制 (Daily)**: 以 1~31 號為單位，不考慮月份天數差異。
- **月份制 (Monthly)**: 以 1~12 月為單位。

---

## 2. 建議的介面結構 (TypeScript)

根據後端已建立的結構，[ResponseScheduleTemplate](file:///Users/david/Downloads/easyapp/lover-visa-nuxt/app/api/response/response_schedule_template.ts#1-20) 採用平鋪式的欄位設計：

```typescript
// 1. 完整的排班模板資料 (打平結構)
export interface ScheduleTemplateData {
    id: string;
    member_id: string;
    type: string;          // 小時制 ('hour'), 天制 ('day'), 月份制 ('month')
    
    // 基礎設定與工作時間
    start_time: string;    // e.g. "09:00"
    end_time: string;      // e.g. "22:00"
    price: string;
    required_cells: string;
    rejected_price: string;
    can_renew: string;      // '1' 代表可續約, '0' 代表否
    
    // 休息時段設定 (直接對應 rest_time)
    // - 預設為字串，回傳可為字串陣列。
    // - 內容格式視模式而定 (時間/日期/月份)。
    rest_time: string | string[];

    created_at: string;
    updated_at: string;
}
```

---

## 3. 資料範例 (打平結構與 rest_time)

### A. 小時制 (Hourly)
- **資料範例**:
  ```json
  {
    "type": "hour",
    "start_time": "09:00",
    "end_time": "18:00",
    "price": "3000",
    "rest_time": ["12:00", "13:00"]
  }
  ```

### B. 天制 (Daily)
- **資料範例**:
  ```json
  {
    "type": "day",
    "start_time": "00:00",
    "end_time": "23:59",
    "rest_time": ["05", "20"]
  }
  ```

### C. 月份制 (Monthly)
- **資料範例**:
  ```json
  {
    "type": "month",
    "rest_time": ["02", "08"]
  }
  ```

---

---

## 5. 實際班表實例與異動邏輯 (Schedule Instance & Interaction Logic)

當從「模板」走向「實際班表」（如：今日班表）時，需要處理資料儲存、預約衝突與金額鎖定等問題。

### A. 虛擬化初始化 (Virtualization)
- **邏輯**: 當前端請求某日班表時，若資料庫尚無該日期的特定紀錄，後端應根據「模板」**即時生成**一份虛擬資料回傳，而非直接回報空資料。
- **欄位建議**: 增加一個 `is_template: boolean` 標記。若使用者進行修改並儲存，則在資料庫正式建立該日期的 `id` 實例。

### B. 狀態與鎖定 (Status & Locking)
- **狀態定義 (`status`)**:
  - `0`: 可預約 (Available)
  - `1`: 已被預約 (Booked)
  - `2`: 休息 (Break/Rest)
- **衝突處理**: 
  - **預約優先**: 如果某個時段（小時制）或某天（天制）已經有人預約 (`status: 1`)，該項目在 UI 上必須改為 **唯讀 (Read-only)**，不可改為休息。
  - **連動預約列表**: 修改班表儲存前，後端必須校驗該時段是否已有存在的訂單 (Orders)，避免將已售出的時段改為休息。

### C. 金額鎖定與更新邏輯 (Pricing Policy)
- **單一化金額 (外層設計)**: 
  - 若您的系統設計僅有「單一外層設定金額」，不包含每一格個別改價的功能。
  - **鎖定規則**: 只要該範圍（小時制/天制中的「今天」，或月份制的「本月」）內有**任何一筆**已成立的訂單 (`status: 1`)，則該範圍的**外層 `price` 欄位應立即設為「唯讀 (Locked)」**。
  - **原因**: 因為只有一個金額輸入框，若有預約存在（假設當時是 $1000），使用者若再把輸入框大改成 $2000，會造成畫面上的呈現與後端訂單快照不同步，容易產生誤解。
  - **解法**: 建議若要改價，應針對「尚未產生預約的未來日期或月份」進行模板調整。

- **異動行為 (進階設計)**:
  - **已預約項目**: 若 `status: 1`，該項目的成交價已快照進訂單，禁止修改。
  - **未預約項目**: 若系統未來支援「個別時段改價」，則僅針對 `status: 0` 的項目進行批次更新。

---

## 6. 各模式下的操作細節建議

### 小時制 (Hourly)
- **行為**: 畫面顯示今日 24 小時（或指定時段）的列表。
- **連動**: 顯示各時段的預約狀態。若有預約，點擊應連動至該預約訂單詳情。
- **時段異動限制 (Window Constraints)**:
  - **縮減服務時間**: 若要調整外層的 `start_time` 或 `end_time` (縮小工作窗口)，系統必須驗證**被縮減掉的時段內是否有已成立的預約**。若有預約，則禁止縮減（或限制縮減至最邊界的一筆訂單為止）。
  ### 休息時段 (rest_time) 的生命週期與異動限制
- **可隨時刪除 (Deletable)**: 
  - 因為 `rest_time` 僅代表「休息」，並未產生任何與消費者的合約（預約），因此使用者應可以隨時在 UI 上刪除特定的休息時段。
  - 刪除後，該單元應自動恢復為 `status: 0 (Available)`。
- **可修改範圍**: 
  - 您可以修改休息時段，只要它不與「現有的預約單」產生重合即可。
- **與預約的區分**: 
  - 預約格 (`status: 1`) = 鎖定、不可刪除（需走取消訂單流程）。
  - 休息格 (`status: 2 / rest_time`) = 非鎖定、可隨時由排班者移除或調整。

### 天制 (Daily)
- **行為**: 僅判斷「今天」是否在 `breaks` 名單中。
- **修改**: 修改時僅針對「今日」這筆紀錄儲存 `is_work: boolean` 或 `status`。不應影響模板。

### 月份制 (Monthly)
- **行為**: 判斷本月是否休息。
- **修改**: 使用者若要修改，通常代表整個月份的策略調整。建議在月份制下，修改會直接提示「是否同步更新此月份的所有剩餘天數」。

### 月份制 (Monthly) - 今日班表視角
- **畫面呈現**: 雖然使用者點選的是「今日」，但畫面應提示當前為「月份制」，並以「本月 (Current Month)」為操作核心。
- **判斷範圍**: 後端應檢查**整個月份**是否有任何一筆訂單。
- **鎖定邏輯**:
  - **金額/設定修改**: 只要本月有任何預約，則該月的 `is_price_locked` 與 `is_config_locked` 均設為 `true`。
  - **休息開關**: 若本月已有預約，**禁止**將該月改為「休息」。
- **UI 建議**:
  - 標題顯示：「2026年3月 服務設定」。
  - 顯示本月已預約的總次數/總時數，作為鎖定原因的提示。
  - 若需修改，應明確告知「此修改將套用至整個月份」。

---

---

## 8. 實際班表細節欄位建議 (ResponseScheduleDetail Columns)

針對您提到的外層設定鎖定問題，建議在 [ResponseScheduleDetail](file:///Users/david/Downloads/easyapp/lover-visa-nuxt/app/api/response/response_schedule_detail.ts#1-6) 的 `data` 層級增加幾項控制開關（Flags），讓前端能精準判斷哪些 UI 需要變成可編輯或唯讀。

### 建議的介面結構

```typescript
export interface ScheduleDetailData {
    id: string;
    current_day: string;
    member_id: string;
    type: string;
    
    // 預設時段設定
    start_time: string;
    end_time: string;
    
    // 核心參數 (由 Template 帶入或個別設定)
    price: string;            // 小時單價
    required_cells: string;   // 低消 (單位：項/小時)
    rejected_price: string;   // 預約被拒絕時產生的補償金額
    can_renew: string;        // 是否可續約
    
    // --- 控制開關 (由後端根據「是否有預約」判斷並回傳) ---
    
    // 1. 鎖定單價 (當有人預約，且修改外層金額會導致舊訂單顯示/帳務混亂)
    is_price_locked: boolean; 

    // 2. 鎖定核心參數 (低消、拒絕補償、續約設定)
    // 這些屬性通常在預約成立時已視為合約一部分。
    is_config_locked: boolean; 

    // 3. 鎖定工作起訖時間
    // 若現有預約覆蓋到邊界時間，或縮短時間會導致預約衝突。
    is_time_locked: boolean;

    // 分段資料狀態
    items: ScheduleDetailItemData[];
}
```

---

## 9. 欄位修改與設計結果總結 (Implementation Summary)

以下是針對排班系統從「模板」到「實際班表」需要異動的欄位與邏輯總結：

### A. 模板系統：[ResponseScheduleTemplate](file:///Users/david/Downloads/easyapp/lover-visa-nuxt/app/api/response/response_schedule_template.ts#1-20)
-   **調整項**：維持扁平結構，整合 `rest_time` 為主要的休息控制欄位。
-   **核心欄位**：
    -   `type`: (String) `'hour'`, `'day'`, `'month'`。
    -   `rest_time`: (String | String[])
        -   內容格式由後端與前端約定，支援多種單元表示（小時/日期/月份）。

### B. 實際班表：[ResponseScheduleDetail](file:///Users/david/Downloads/easyapp/lover-visa-nuxt/app/api/response/response_schedule_detail.ts#1-6)
-   **調整項**：增加對「已預約」狀態的顯性支援。
-   **新增旗標 (Flags)**：
    -   `is_template`: (Boolean) 判斷目前是「顯示模板預設值」還是「已有專屬今日的設定」。
    -   `is_price_locked`: (Boolean) 今日已有預約，鎖定單價修改。
    -   `is_config_locked`: (Boolean) 今日已有預約，鎖定低消、續約、補償金修改。
    -   `is_time_locked`: (Boolean) 今日已有預約，鎖定班表起訖時間修改。
-   **單項細節 (`items`)**：
    -   `status`: (String/Enum) `"available"` (0), `"booked"` (1), `"rest"` (2)。
    -   `item_price`: (String) 該時段/日期的成交金額快照。

### C. 模式行為設計 (成果)

| 模式 | 排班單位 | 鎖定範圍 | 休息操作 |
| :--- | :--- | :--- | :--- |
| **小時制** | 小時 (Hour) | 僅鎖定有預約的小時格 | 剩餘沒人的小時可改休息 |
| **天制** | 每月日期 (1-31) | 鎖定受預約的「該日期」 | 沒人的日期可單飛休息 |
| **月份制** | 月份 (1-12) | **鎖定整個月份** (只要本月有人) | 本月沒人時才能改大休 |

---

---

## 10. 整合後的 API 回傳介面設計 (Proposed Unified Interfaces)

以下整合了四個核心 API 回傳檔案的建議修改結構，不異動現有 JSON 底層邏輯，僅優化中間的 `data` 部分。

### A. 模板相關 (Template & TemplateModify)
主要更新：維持平鋪結構，確保 `rest_time` 格式正確。

```typescript
// 適用於 ResponseScheduleTemplate 與 ResponseScheduleTemplateModify
export interface ScheduleTemplateContent {
    id: string;
    member_id: string;
    type: string; // 'hour' | 'day' | 'month'
    price: string;
    required_cells: string;
    rejected_price: string;
    can_renew: string;
    
    // 排班與休息設定
    start_time: string;
    end_time: string;
    rest_time: string | string[];

    created_at: string;
    updated_at: string;
}
```

### B. 實際班表相關 (Detail & Modify)
主要更新：增加「讀取/修改」時必需的鎖定標記與實例狀態。

```typescript
// 適用於 ResponseScheduleDetail 與 ResponseScheduleModify
export interface ScheduleDetailContent {
    id: string;
    current_day: string;
    member_id: string;
    type: string;
    
    // 當前參值 (由 Template 繼承或已覆寫)
    price: string;
    required_cells: string;
    rejected_price: string;
    can_renew: string;

    // --- 擴展控制旗標 (重要) ---
    is_template: boolean;      // 此資料是否來自模板預設值 (尚未儲存實體)
    is_price_locked: boolean;   // 今日是否有預約，鎖定單價
    is_config_locked: boolean;  // 今日是否有預約，鎖定規則
    is_time_locked: boolean;    // 今日是否有預約，鎖定起訖時間

    // 分段資料 (小時制 24 格 / 天制 1 格)
    items: Array<{
        id: string;
        scheduler_id: string;
        item_date: string;
        item_price: string;    // 快照當下成交價
        status: string;        // 'available'(0) | 'booked'(1) | 'rest'(2)
        price_customized: boolean; // 是否為手動改過的特殊價格
    }>;
}
```

## 11. 實體班表建立邏輯總結 (Instantiation Logic)

為了確保三種模式的資料結構一致性，我們採用「主檔 (Master) + 子項 (Item)」的雙層架構。以下是各模式在建立班表時的對應關係：

### A. 小時制 (Hourly)
- **主檔範圍**: 針對「單一日期」(e.g., `["2026-03-30"]`) 建立規則（起訖時間、單價）。
- **子項結構**: 自動建立 **24 個子項目**，每個項目代表 1 個小時 (00:00 ~ 23:00)。
- **關係**: 1 個主檔 = 24 個子項目。

### B. 天制 (Daily)
- **主檔範圍**: 針對「整個月份」(e.g., `["2026-03"]`) 建立規則（單價、打槍費、低消）。
- **子項結構**: 根據該月實際天數 (28~31天)，自動針對 1號到最後一號建立 **子項目**（時間標記統一為 `00:00:00`）。
- **狀態判定**: 由 `start_time` 至 `end_time` 決定 `開放` 範圍，其餘為 `停用`；在範圍內若符合 `rest_times` 則標記為 `休息`。
- **鎖定規則**: 實體班表建立後，**打槍費用 (Rejected Price) 禁止修改**。
- **連動邏輯**: 
    - 修改主檔金額時，僅同步更新狀態為 `開放`、`休息` 或 `停用` 的子項目成交價。
    - **已預約 (`booked`) 的項目絕對不可修改**（保持成交當下的價格快照）。

### C. 月份制 (Monthly)
- **主檔範圍**: 針對「整年度」(e.g., `["2026"]`) 或跨月區間建立規則。
- **子項結構**: 針對區間內的**每一個月**建立 **1 個子項目**。
- **關係**: 1 個主檔 = 12 個子項目 (若為全年)。
- **邏輯同上**: 鎖定規則與價格連動邏輯與天制、小時制保持一致。

---

## 12. 結論

透過此統一架構，三種模式的邏輯已完全收斂：
1. **小時制**：`yyyy-MM-dd` -> 24 個子項目。
2. **天制**：`yyyy-MM` -> 當月天數個子項目。
3. **月份制**：`yyyy` -> 當年月份個子項目。

所有模式均遵循「子項目優先於主檔」的原則（除非是由主檔發起的批次更新），且「已預約」狀態擁有最高優先權與唯讀保護。
