昨天我們已經把「完成任務」和「刪除任務」搬到網頁上。
現在打開 Todo 頁面,不只能看到 MySQL 裡的任務,也可以直接按:
完成任務 刪除
不用再回到 Postman 手動呼叫 API。
那今天就是要繼續把「新增」和「修改」也搬進網頁。
如果這兩個功能完成,前面做過的 CRUD 就真的全部可以直接在 Todo 頁面操作了。
首先在 Todo 頁面上方加入:
<button class="add-btn" onclick="showAddForm()">
+ 新增任務
</button>
接著準備一個新增任務的表單:
<div class="task-form" id="add-form">
<h2>新增任務</h2>
<label>任務名稱</label>
<input type="text" id="new-title">
<label>任務描述</label>
<textarea id="new-description"></textarea>
<label>截止日期</label>
<input type="datetime-local" id="new-deadline">
<label>重要程度</label>
<select id="new-importance">
<option value="1">1</option>
<option value="2">2</option>
<option value="3" selected>3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<label>預估時間</label>
<input type="number" id="new-estimated-minutes">
<div class="form-actions">
<button onclick="addTask()">新增</button>
<button onclick="hideAddForm()">取消</button>
</div>
</div>
這裡先把新增表單隱藏起來:
.task-form {
display: none;
background: white;
padding: 20px;
margin-bottom: 20px;
border-radius: 10px;
}
等使用者按下 「+新增任務」 時,再透過 JavaScript 顯示:
function showAddForm() {
document.getElementById("add-form").style.display = "block";
}
function hideAddForm() {
document.getElementById("add-form").style.display = "none";
}
這樣平常不會一直看到一大堆輸入框,需要新增任務時再把表單打開。
表單有了之後,下一步就是把使用者輸入的內容送到 Flask。
這裡使用前面已經做過的POST /tasks
JavaScript:
async function addTask() {
const title = document.getElementById("new-title").value;
const description = document.getElementById("new-description").value;
const deadline = document.getElementById("new-deadline").value;
const importance = document.getElementById("new-importance").value;
const estimatedMinutes =
document.getElementById("new-estimated-minutes").value;
if (!title) {
alert("請輸入任務名稱");
return;
}
try {
const response = await fetch("/tasks", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: title,
description: description,
deadline: deadline,
importance: Number(importance),
estimated_minutes: Number(estimatedMinutes)
})
});
const data = await response.json();
if (response.ok) {
location.reload();
} else {
alert(data.error || "新增任務失敗");
}
} catch (error) {
console.error(error);
alert("發生錯誤");
}
}
這裡跟昨天完成、刪除任務的做法其實很像,都是使用 fetch() 呼叫前面已經寫好的 API。
只是這次除了指定:method: "POST"
還需要透過:JSON.stringify()
把使用者輸入的資料整理成 JSON 傳給 Flask。
新增成功之後:
location.reload();
重新載入頁面,就可以直接看到剛剛新增的任務。
整個流程變成:
填寫新增表單
↓
addTask()
↓
POST /tasks
↓
Flask
↓
MySQL
↓
新增任務
↓
重新整理網頁
到這裡,新增 Todo 已經不需要 Postman 了。
新增成功之後,接下來處理修改任務。
先在昨天的「完成任務」和「刪除」中間加入:
<button
class="edit-btn"
onclick="showEditForm({{ task.task_id }})"
>
編輯
</button>
現在每張 Todo 就會有:完成任務 編輯 刪除
例如任務名稱:
<input
type="text"
id="edit-title-{{ task.task_id }}"
value="{{ task.title }}"
>
重要程度:
<select id="edit-importance-{{ task.task_id }}">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
進度則可以直接修改:
<input
type="number"
id="edit-progress-{{ task.task_id }}"
value="{{ task.progress }}"
min="0"
max="100"
>
跟新增表單一樣,編輯表單平常也是隱藏的。
按下「編輯」之後才顯示:
function showEditForm(taskId) {
document
.getElementById(`edit-form-${taskId}`)
.style.display = "block";
}
function hideEditForm(taskId) {
document
.getElementById(`edit-form-${taskId}`)
.style.display = "none";
}

這裡再次用到 task_id,讓 JavaScript 知道現在到底是在編輯哪一筆任務。
使用者修改完成後,就可以呼叫前面做好的:
PUT /tasks/<task_id>
JavaScript 先取得表單裡的新資料:
const title =
document.getElementById(`edit-title-${taskId}`).value;
const description =
document.getElementById(`edit-description-${taskId}`).value;
const deadline =
document.getElementById(`edit-deadline-${taskId}`).value;
const importance =
document.getElementById(`edit-importance-${taskId}`).value;
const estimatedMinutes =
document.getElementById(`edit-estimated-${taskId}`).value;
const progress =
document.getElementById(`edit-progress-${taskId}`).value;
再透過 fetch() 送給 Flask:
const response = await fetch(`/tasks/${taskId}`, {
method: "PUT",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: title,
description: description,
estimated_minutes: Number(estimatedMinutes),
importance: Number(importance),
deadline: deadline,
progress: Number(progress),
status: "todo"
})
});
修改成功之後一樣:location.reload();
重新整理頁面,就可以看到更新後的資料。
流程變成:
按下編輯
↓
修改任務資料
↓
儲存修改
↓
PUT /tasks/<task_id>
↓
Flask
↓
UPDATE tasks
↓
MySQL
↓
重新整理
今天最後實際從網頁新增一筆任務。
輸入:
任務名稱
任務描述
截止日期
重要程度
預估時間
按下「新增」後,任務會直接寫入 MySQL,重新整理後也還是存在。
接著按下任務旁邊的「編輯」,修改:
任務名稱
任務描述
截止日期
重要程度
預估時間
目前進度
按下「儲存修改」後,頁面重新載入,也可以看到修改後的新資料。
加上昨天完成的「完成任務」和「刪除」,現在終於可以直接在網頁完成:
新增
讀取
修改
刪除
也就是前面一直在做的 CRUD。
做到今天,終於可以暫時跟 Postman 說再見了。
一開始建立 API 時,新增、查看、修改、刪除任務幾乎全部都要在 Postman 一個一個測試。
但經過這幾天慢慢把功能搬進網頁,現在已經可以直接在 Todo 頁面新增任務、修改資料、完成任務和刪除任務。
Day 29,就把 Gemini 正式搬進 Todo 網頁。