# Code Review — 智慧教室排程系統設計稿 審查對象:`design/Smart Classroom Site.dc.html`(主設計稿)+ `design/HANDOFF.md` 對照文件:`docs/spec-source.txt`(UI/UX 功能規格 V1.2)、`docs/正興國小115學年_自然科教師課表彙整.docx` 初版:2026-08-29 | 最後更新:2026-08-29(B1/B2/B3/H1 已修) 設計稿本身不是要上線的程式碼,但它的**資料模型與互動邏輯會被原封不動抄進實作**,所以以下問題都會直接變成產品的 bug。 ## 狀態總覽 | 編號 | 問題 | 狀態 | | --- | --- | --- | | B1 | 20 週的日期標籤整組偏一天 | ✅ 已修 | | **D1** | **教室指定資料是推測的,與實際課表不符** | 🔴 **待補真實資料** | | B2 | 「自訂地點」是全域字串,所有課共用 | ✅ 已修 | | B3 | 週次切換是假的,教室時段表看不到調課結果 | ✅ 已修 | | H1 | 衝突檢查沒有週次維度 | ✅ 已修(隨 B3 一起) | | H2 | 零鍵盤無障礙 | ⬜ 待處理 | | H3 | 完全沒有手機版 | ⬜ 待設計 | | M1 | 首頁「下一個占用」寫死節次 | ⬜ 待處理 | | M2 | demo 日期與學期週次矛盾 | ✅ 已修(隨 B1 一起) | | M3 | 登入頁預填真實預設密碼 | ⬜ 上線前必清 | | L1 | `freeOf` 與 `usedOf` 不互補 | ⬜ 待處理 | --- ## ✅ B1 — 20 週的日期標籤整組偏一天(已修) `dateOf(w, d)` 的基準原本是 `new Date(2026, 8, 1)`(=2026-09-01),`HANDOFF.md` 也寫「第 1 週星期一 = 2026-09-01」。 **但 2026-09-01 是星期二。** 調課頁 20 週的每個日期都往後偏一天:畫面顯示「第 1 週 9/1–9/5」, 實際對到的是星期二~星期六。老師是照日期在調課的,這會直接調錯天。 **修法**:抽成具名常數並加開機檢查。 ```js const TERM_W1_MONDAY = new Date(2026, 7, 31); // 2026-08-31(星期一) if (TERM_W1_MONDAY.getDay() !== 1) { console.error('[排程] TERM_W1_MONDAY 必須是星期一,目前是 ' + TERM_W1_MONDAY.toDateString()); } ``` 現在第 1 週 = 8/31–9/4,星期一欄位真的是 8/31(星期一)。首頁右上的 demo 日期也一併改成 9/4(第 1 週的星期五), 不再出現「8/28 卻標第 1 週」的矛盾(M2)。 > ⚠ **`2026-08-31` 是暫定值。** 正式開學日請跟學校確認後改這一行——常數只有一處,改完全站跟著動。 ## ✅ B2 — 「自訂地點」是一個全域字串,所有課共用(已修) 原本 `state.custom` 只是單一字串,`label()` 的 CUSTOM 分支直接回傳它。 指定 A 課到某個自訂地點、再改輸入框指定 B 課,**A 課會跟著被改名**。 **修法**:`assign` 的值從字串改成物件,自訂名稱在「按下按鈕的那一刻」快照進去。 ```js // 舊:assign['曾唯誠|1-1'] = 'CUSTOM' // 新:assign['曾唯誠|1-1'] = { code: 'CUSTOM', name: '<按下當下輸入框的值>' } mkValue(code) { return code === 'CUSTOM' ? {code, name: (this.state.custom || '自訂地點')} : {code}; } ``` 配套加了 `codeOf(v)`,`label(v, cls)` 同時吃字串(按鈕、對話框)與物件(課表格子)。 右側那個輸入框現在純粹是**草稿欄位**,改它不會回頭動到已指定的課。 **已實測**:指定第 1 節為 A 名稱 → 把輸入框改成 B 名稱 → 指定第 2 節,兩格各自保留自己的名稱。 > 後端 assignments 資料表要跟著加 `location_name` 欄位。 ## ✅ B3 — 週次切換是假的,教室時段表看不到調課結果(已修) 原本第 92、214 行的「‹ 上週 / 本週 / 下週 ›」是純 ``,**沒有 onClick**; 更底層的問題是 `cell(code, p, d)` 和 `mkWeek(name)` 都不吃週次,`assign` 的 key 也只有 `教師|節-星期`。 結果:老師在調課頁把課移到第 5 週,切到教室時段表看那間教室**跟沒調一樣**。 **修法**: 1. state 加 `roomWeek`、`schWeek` 兩個游標 2. `cell(code, p, d, week)` 與 `mkWeek(name, week)` 改走 `occ()` — `occ()` 本來就會先查 `moves`/`removed` 再回落到固定課表 3. `freeOf(code, week)` / `usedOf(code, week)` 跟著帶週次 4. 兩頁的上週/本週/下週改成真的可點,標題顯示「第 N 週(起–迄)」 5. 首頁「今日課程」也改走 `occ()`,才不會跟調課結果打架(調入的課標「調課移入」) **已實測**:把第 1 週星期二第 1 節的課調到第 3 週星期三第 1 節、指定自然教室一之後—— 自然教室一第 1 週該格是「空閒」,第 3 週該格是「已占用 · 507 班 · 曾唯誠」;我的課表第 1 週來源格清空、 第 3 週出現「↷ 自然 507 · 自然教室一」。 ## ✅ H1 — 衝突檢查沒有週次維度(已修) `clashList()` 原本只掃 `SCHED`(固定課表),不看 `moves`,所以調課不會檢查「其他老師也調課到那個時段」。 **修法**:簽章改成 `clashList(name, code, p, d, week)`,內部改走 `occ()`;調課的檢查用**目標週次** `tgt.w`, 選教室因為是學期範圍指定,用 `CUR_WEEK`。 > 後端的 `GET /assignments/conflicts` 也要加 `week` 參數,否則會漏掉調課製造出來的衝突。 --- ## 🔴 D1 — 教室指定資料是推測的,與實際課表不符(待補真實資料) `initAssign()` 目前把**每位老師的所有課都自動指定到他自己的固定教室**。這個規則是舊 handoff 帶下來的推測, 不是學校的真實資料。 曾唯誠的實際課表(使用者提供的課表圖)顯示事情不是這樣:他**沒有自己的教室,而是逐節借用 341/541/542**, 其中 604 班第三、四節是**分組課,同時使用 541 和 542 兩間**。 把他的真實教室資料填進去,再搭配「其他四位都用自己固定教室」這個推測,會產生 **7 筆衝突**: | 教室 | 時段 | 撞到誰 | | --- | --- | --- | | 341 | 星期四 第 5 節 | 曾唯誠(603) vs 曾喬笠(606) | | 341 | 星期四 第 6 節 | 曾唯誠(602) vs 曾喬笠(606) | | 541 | 星期一 第 5 節 | 曾唯誠(601) vs 彭靖雯(404) | | 541 | 星期二 第 3 節 | 曾唯誠(604) vs 彭靖雯(402) | | 541 | 星期二 第 4 節 | 曾唯誠(604) vs 彭靖雯(402) | | 542 | 星期二 第 3 節 | 曾唯誠(604) vs 柯協佳(505) | | 542 | 星期二 第 4 節 | 曾唯誠(604) vs 柯協佳(505) | 七筆全部涉及曾唯誠,代表**「每位老師所有課都用自己固定教室」這個推測是錯的**——其他四位老師應該也跟曾唯誠一樣, 是逐節各自有教室,只是我們還沒有他們的資料。 **待辦**:取得田麗娟、彭靖雯、柯協佳、曾喬笠四位的課表(含教室欄位),把 `initAssign()` 換成真實的逐節指定。 在那之前,畫面上看到的教室占用狀況都不可信。 **連帶的資料模型問題**:分組課一個時段要對應**兩間教室**,現在 `assign` 一格只能存一間。 ## ⬜ H2 — 零鍵盤無障礙(待處理) 全檔統計:`onClick` 28 個,全部掛在 `
` / `` 上;`