iT邦幫忙

2026 iThome 鐵人賽

DAY 19
0
Modern Web

從 UI/UX 設計到前端實作:30 天打造專屬的任務學習計時器系列 第 19 篇

DAY 19|任務管理(二):自動狀態流轉邏輯

  • 分享至 

  • xImage
  •  

接下來我們要處理任務的狀態(未開始、進行中、已完成)。

使用者建立任務時,會自動分類成「未開始」;當該子任務有計時紀錄時,會自動轉為「進行中」;只有已完成是需要使用者自己勾選。

所以這篇將實現透過使用者的 「計時行為」 與 「Modal 勾選」 ,讓任務狀態自動且精確地切換。


狀態轉換規則

1. 未開始:剛建立的任務,完全沒有任何專注計時紀錄。

2. 進行中:只要該任務產生過至少一次計時紀錄,系統即自動將狀態提升為「進行中」。

3. 已完成:使用者在「儲存計時 Modal」中手動勾選完成,或在任務列表中手動切換。


更新資料結構

為了支援狀態追蹤,在子任務物件中新增 status 欄位(預設為 'not_started'),並配合 logs 紀錄歷程:

let tasks = [
  {
    id: "task-1",
    title: "iThome鐵人賽",
    subtasks: [
      { id: "sub-1", title: "主題發想", status: "completed" },
      { id: "sub-2", title: "撰寫每日文章", status: "in_progress" },
      { id: "sub-3", title: "mockup製作", status: "not_started" }
    ]
  }
];

自動流轉與狀態更新

步驟 1:儲存計時時觸發狀態自動變更

當使用者完成一次計時並點擊「儲存」時,saveSession() 會依據 Modal 上的勾選狀況,自動更新子任務的狀態:

// 儲存計時紀錄時自動流轉狀態
function saveSession() {
  const currentTask = tasks.find((t) => t.id === currentMainTaskId);
  const currentSub = currentTask?.subtasks.find((s) => s.id === currentSubtaskId);

  if (currentSub) {
    // 邏輯 1:如果 Modal 勾選已完成 -> 標記為 completed
    if (modalIsCompleted.checked) {
      currentSub.status = "completed";
    } 
    // 邏輯 2:若原本是未開始,但產生了計時紀錄 -> 自動更改為 in_progress
    else if (currentSub.status === "not_started") {
      currentSub.status = "in_progress";
    }
  }

  // 儲存紀錄邏輯 (略...)
  saveTimerModal.hide();
  resetTimerUI();
  
  showToast("已成功儲存本次計時!");
  renderAll(); // 觸發畫面更新,同步渲染最新狀態 Badge
}

步驟 2:主任務狀態自動推導

除了子任務自身的狀態切換外,主任務的總體進度與狀態也是因應其下的子任務而變化,因此主任務的狀態不寫死在資料結構中,而是在渲染時動態計算。

當所有子任務都標記為 completed 時,主任務自動顯示為全數完成。

// 計算主任務的自動狀態 (自動推導)
function getMainTaskStatus(task) {
  if (!task.subtasks || task.subtasks.length === 0) return "not_started";

  const allCompleted = task.subtasks.every((s) => s.status === "completed");
  if (allCompleted) return "completed";

  const hasStarted = task.subtasks.some((s) => s.status !== "not_started");
  if (hasStarted) return "in_progress";

  return "not_started";
}

步驟 3:UI 狀態 Badge 與列表渲染

根據狀態呈現不同樣式的 Bootstrap Badge 標籤:

// 狀態標籤 UI 對照表
const STATUS_MAP = {
  not_started: { label: "未開始", class: "bg-secondary-subtle text-secondary" },
  in_progress: { label: "進行中", class: "bg-primary-subtle text-primary" },
  completed: { label: "已完成", class: "bg-success-subtle text-success" }
};

// 渲染子任務時帶入狀態標籤
function renderSubtaskList() {
  // ...過濾出當前子任務
  const badge = STATUS_MAP[sub.status || "not_started"];
  
  return `
    <li class="d-flex justify-content-between align-items-center p-2">
      <span>${sub.title}</span>
      <span class="badge ${badge.class}">${badge.label}</span>
    </li>
  `;
}

task status


觀念總結

1. 減少手動操作:
使用者按下停止並儲存計時的那一刻,「進行中」的狀態轉移就已經自動完成,不需要使用者手動切換。

2. 推導狀態優於冗餘資料:
主任務的狀態由子任務動態算出(every / some 陣列方法),能避免子任務全做完了,主任務狀態卻忘記更新的資料同步 Bug。

3. 視覺反饋:
透過 Bootstrap 5 的不同標籤顏色,讓使用者一開啟任務清單就能對整體進度一目了然。


上一篇
DAY 18|任務管理(一):主任務與子任務的 State 管理與 CRUD 實作
下一篇
DAY 20|任務管理(三):將主任務與子任務 CRUD 動態連結至任務清單 Accordion
系列文
從 UI/UX 設計到前端實作:30 天打造專屬的任務學習計時器 共 20 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言