# T516 — fe-radar-watches-page > Status: `done` > Milestone: `M1` > Kind: `feat` > Est. change: `~200 lines` ## Goal 完成後系統應:`/app/radar/watches` 可建立/編修/暫停/恢復/封存雷達訂閱,並可採用 AI 關鍵字建議。 ## Depends on - T502、T503、T513、T514 ## Inputs - Spec:`../spec.md` §4.2、§5.3、§9.1 - 既有頁面骨架:`apps/web/src/pages/ScoutPage.tsx`、路由設定 `src/App.tsx` ## Outputs ### 程式變更(預期路徑) | 路徑 | 動作 | 說明 | |------|------|------| | `apps/web/src/pages/RadarWatchesPage.tsx` | add | 列表+新增/編輯抽屜+狀態動作 | | `apps/web/src/components/radar/WatchSuggestPanel.tsx` | add | 建議清單,逐條採用/全採用 | | `apps/web/src/App.tsx` | edit | 註冊 `/app/radar/watches` 路由 | | `apps/web/src/data/live/radarRepos.ts` | edit | watches CRUD/pause/resume/suggest 實作 | | `apps/web/src/styles/radar.css` | edit | 列表與抽屜樣式 | ### 行為變更 - 未建服務檔案時,頁面顯示引導並停用「新增」,附連結到 `/app/brands` 服務檔案分頁。 - 觸到 `max_active_watches` 時直接顯示後端 message(含上限與升級提示),不用前端自行推測文案。 - 每列顯示 `terms`、地區、狀態、`last_swept_at`。 ## Out of scope - 手動觸發即時巡的 UI(T533 提供 API,UI 併入 T552 或此頁後續) - 今日商機頁(T551) ## Acceptance - [x] 無服務檔案時「新增」被停用並有引導 - [x] 建立→暫停→恢復→封存的狀態變化正確反映 - [x] 指令: ```bash cd apps/web && npm run build && npm run check:tokens && npm run test && npm run lint ``` ## Notes ### 實作落點 - `apps/web/src/pages/RadarWatchesPage.tsx`:清單(關鍵字/排除詞 chip、狀態 badge、地區、`last_swept_at`)+狀態篩選+分頁+新增/編輯表單。 - `apps/web/src/components/radar/WatchSuggestPanel.tsx`:按下才問 AI(避免開頁就燒 credit),逐條/全部採用,已在表單裡的詞顯示「已採用」並停用按鈕。 - `apps/web/src/App.tsx`:`/app/radar/watches` lazy 路由。側欄項在 T553。 - `apps/web/src/styles/radar.css`:`.hb-radar-form`、`.hb-radar-suggest*`。 ### 決策 - **採用建議不等於建立訂閱**:建議只往表單塞字,仍要按儲存才會打 API。使用者可以先刪掉不要的再送。 - **關鍵字用換行/逗號/頓號都能分隔**:使用者常直接從別處貼一整串過來。 - **每個動作後重讀清單**:暫停/恢復會連動 `active_count` 與配額提示,局部改 state 很容易和後端對不起來。 - **配額與缺服務檔案的文案來自後端**:`403003`(含「1 of 1 on your plan」與升級提示)與 `400100` 都直接顯示後端 message,前端不自行推測上限。 - **建立失敗時表單不關**:使用者可以改成「不立刻啟用」或先去暫停別的再送。 - 封存列不再顯示任何動作按鈕(狀態機的終點),避免點了才發現不能恢復。 ### 測試 `src/pages/RadarWatchesPage.test.tsx`(5 案):無服務檔案停用新增+指路、建立→暫停→恢復→封存的狀態與配額連動、配額滿顯示後端原句且表單留著、建議逐條採用分流到關鍵字/排除詞、建議失敗說原因。