b37f4363eb
Implement concrete Pinia stores for app UI and domain data instead of placeholder re-exports, including seeded student records and snackbar state. Refresh README guidance for components, plugins, and services to document the current project structure, data flow, and usage conventions.feat(stores): add Pinia domain stores and update docs Implement concrete Pinia stores for app UI and domain data instead of placeholder re-exports, including seeded student records and snackbar state. Refresh README guidance for components, plugins, and services to document the current project structure, data flow, and usage conventions.
2.4 KiB
2.4 KiB
Services
src/services 是資料存取與 HTTP 邊界,負責封裝 axios client、interceptor、token/session、錯誤處理與 API 模組。
目前資料流
component/view -> store/composable -> service module -> httpClient -> interceptor
原則:
- component 不直接處理底層 HTTP client、token、interceptor 或錯誤正規化。
- store 或 composable 負責協調 UI 狀態與呼叫 service。
- service 回傳資料,不持有 UI 狀態。
- service 不 import component、view 或 store。
目前檔案
client.ts:建立單一 axios instance,設定baseURL、timeout、credentials 與 interceptor。interceptors.ts:集中處理 request token 注入與 response 錯誤。error.ts:提供normalizeError()與統一錯誤型別。http-error.ts:提供全域 HTTP 錯誤事件。http-toast.ts:提供 HTTP 錯誤提示相關流程。token.ts:提供 token 單一來源,並同步 localStorage。session.ts:提供 session 相關流程。modules/auth.ts:封裝登入與驗證碼 API。modules/menu.ts:封裝選單與收藏選單 API。
API 模組規則
新增 API 時,優先放在 src/services/modules/<domain>.ts。
API module 應:
- 使用
httpClient發 request。 - 匯出清楚命名的 API 物件,例如
authApi、menuApi。 - 定義與該 module 相關的 request/response 型別。
- 接收
AbortSignal等 request option,但不管理頁面 loading 或 controller 狀態。
HTTP Client 設定
client.ts 的 baseURL 優先使用 VITE_API_BASE_URL,否則使用 /service/api。開發模式下,Vite proxy 會將 /service/* 轉送到後端。
目前 API 呼叫範例:
authApi.getCaptcha()->/Auth/get-captchaauthApi.login()->/Auth/loginmenuApi.getMenu()->/Menu/GetMenumenuApi.getFavorite()->/Menu/GetFavorite
Token 與錯誤處理
token 由 tokenService 作為單一來源:
- store 負責登入成功後寫入 token,以及登出時清除 token。
- interceptor 只讀取 token 並附加到 request。
- 401 或 HTTP 錯誤由 interceptor 與錯誤事件流程集中處理。
錯誤透過 normalizeError() 轉成 UI 可理解的格式。UI 或 store 不需要直接理解 AxiosError。
請求取消
需要取消請求時,由 store 或 composable 建立 AbortController,service module 只接收 signal。不要讓 service module 持有 controller 或 UI 狀態。