在前端開發的領域中,處理「時間」永遠是一門藝術。不管是購物車的限時搶購、倒數計時器,還是有效期限的追蹤,工程師都需要將冷冰冰的日期數據,轉化為使用者一眼就能看懂的視覺語言。
我們的 [Tool 4] 旨在解決醫療與日常保健中的一大痛點:藥品與保養品的「開封效期」管理。
許多藥品(例如眼藥水、眼軟膏或抗生素懸浮液)在未拆封時雖有兩三年的保存期,但一旦開封,使用期限就會瞬間縮短至 28 天或 30 天。如果光憑使用者的記憶去推算「到底打開幾天了」,極易造成誤用過期藥品的風險。今天我們要為 [Tool 4] 注入核心計算大腦,透過動態計算剩餘天數,結合直覺的 CSS 馬卡龍燈號,打造兼具視覺美感與實用性的時間管理模組!
在進入程式碼之前,我們先來拆解核心邏輯與視覺燈號的運算公式:
首先,我們需要取得藥品的開封日期(openDate),計算其與今日(today)的時間差(diffDays)。隨後將使用者自訂的總效期(totalExpiry)扣除已過天數:
剩餘天數 (remainDays) = 總效期 (totalExpiry) - 已過天數 (diffDays)
為了讓使用者在開啟介面時能第一時間察覺危機程度,我們將狀態劃分為三個動態區間:
我們在 /tool4-timer.js 中撰寫動態狀態判斷邏輯,並透過 /components.css 完成膠囊標籤與彈性卡片列的渲染:
/tool4-timer.js
// 兼容舊資料:若以往儲存的項目沒有 expiryDays,自動給予 28 天預設值
const totalExpiry = item.expiryDays || 28;
const remainDays = totalExpiry - diffDays;
// 判定狀態 Badge
let statusBadge = "";
if (remainDays < 0) {
statusBadge = `<span class="badge badge-red">已過期 ${Math.abs(remainDays)} 天</span>`;
} else if (remainDays <= 7) {
statusBadge = `<span class="badge badge-yellow">剩餘 ${remainDays} 天 (儘速使用)</span>`;
} else {
statusBadge = `<span class="badge badge-green">剩餘 ${remainDays} 天</span>`;
}
/components.css
.badge {
display: inline-block;
padding: 3px 10px;
border-radius: 12px;
font-size: 0.8rem;
font-weight: bold;
margin-left: 8px;
background-color: #E9ECEF;
}
.badge-green { background-color: var(--macaron-mint); }
.badge-yellow { background-color: var(--macaron-yellow); }
.badge-red { background-color: var(--macaron-pink); }
.hidden { display: none !important; }
.note { font-size: 0.8rem; color: var(--text-muted); margin-top: 10px; }
/* 表格與列表 */
.table-container { margin-top: 20px; }
.med-table { width: 100%; border-collapse: collapse; text-align: left; }
.med-table th, .med-table td { padding: 12px; border-bottom: 1px solid #E9ECEF; }
.med-table th { background-color: var(--bg-cream); font-size: 0.9rem; }
.btn-del { background: none; border: none; color: #FA5252; cursor: pointer; font-weight: bold; }
/* 定時器清單列 */
.timer-container { margin-top: 20px; display: flex; flex-direction: column; gap: 12px; }
.timer-item {
padding: 15px;
border-radius: var(--radius-sm);
background-color: var(--bg-cream);
display: flex;
justify-content: space-between;
align-items: center;
}
軟體迭代中最怕「新功能上線,舊資料壞掉」。在以往版本中,我們儲存的物件結構可能沒有 expiryDays 這個欄位。
透過 item.expiryDays || 28 這種預設備援寫法(Fallback),當系統讀取到舊版無 expiryDays 屬性的物件時,會自然降級使用 28 天作為算式基礎,避免算出 NaN 導致 UI 崩潰。
當天數小於 0(例如 -3 天)時,若直接拿變數渲染成「已過期 -3 天」,在中文語意上顯得怪異且缺乏專業感。
使用 Math.abs(remainDays) 取得負數的絕對值,動態印出「已過期 3 天」,能大幅提升人機互動的自然度。
在 CSS 處理上,我們將 .badge 的結構(內距、圓角、字體大小)與色彩樣式(.badge-green、.badge-red)進行解耦。
配色更使用了 var(--macaron-mint) 與 var(--macaron-pink) 等馬卡龍主題變數,擺脫傳統高飽和度紅綠色的刺眼感,讓醫療提醒工具呈現溫和且清晰的視覺體驗。
在 .timer-container 中使用 display: flex; flex-direction: column; gap: 12px;,能優雅地建立清單卡片之間的均勻間距,告別以往必須用 :not(:last-child) 處裡 margin-bottom 的繁瑣舊做法。
今天我們成功實作了 [Tool 4] 的核心倒數運算邏輯與動態 CSS 警示燈號,將開瓶時間轉化為清晰易懂的視覺化提示,確保使用者能直覺掌控藥品有效期限。
在明天的 [Day 26] 中,我們將進行 [Tool 4 跨瀏覽器 Local Storage 歷史紀錄同步與動態刪除],讓這些自訂效期的倒數項目能夠妥善持久化儲存,並支援無痛的清理與維護機制!離鐵人賽終點越來越近了,我們明天見!