# 新增頁面範例 這份文件示範如何用目前 `src/` 慣例新增一個被 `MainLayout` 包住的一般功能頁。 範例功能:`reports` 目前新增一般頁面的預設資料流: ```txt router -> view -> (page driver) -> page component -> sections/items ↓ store/composable -> service ``` Page driver 不是必備層:若頁面邏輯只有簡單的 `computed` page model(無搜尋、無 dialog、無複雜事件協調),直接在 view 裡寫即可,不需要建立 page driver。 ## 1. 新增 view(含 page model) 簡單頁面的 page model 直接在 view 裡用 `computed` 組裝,不需要額外建立 page driver。 ```vue ``` 若頁面需要協調多個 composable(搜尋、表單、CRUD flow、dialog 狀態),才建立 page driver。page driver 的慣例見 `src/composables/GUIDE.md`。 ## 2. 新增 page component 完整頁面主畫面放在 `src/components/pages`,檔名使用 `Page` 前綴。component 以 props 接收資料,以 emit 回報使用者事件,不直接處理 route 或底層 HTTP。 ```vue ``` 若畫面是固定的「篩選條件 + 查詢按鈕 + 結果表格」,優先使用 `components/sections/SectionQueryPage.vue`。若是「表單欄位 + 送出/存檔按鈕」,優先使用 `components/sections/SectionFormPage.vue`。 ## 3. 加入 route route 加在 `src/router/routes.ts` 的 `routes` 陣列中,並放在 `/:pathMatch(.*)*` catch-all route 前面。 ```ts // src/router/routes.ts { path: '/reports', name: 'reports', component: () => import('@/views/reports/Reports.vue'), meta: { layout: 'default', requiresAuth: true }, } ``` `layout: 'default'` 會讓頁面被 `MainLayout` 包住。登入頁、錯誤頁、維護中頁才使用 `layout: 'none'`。 若頁面需要出現在 drawer menu、favorites 或 breadcrumb: - menu 來源目前由 `src/stores/menu.ts` 轉換後端選單資料。 - breadcrumb 會依 route path、menu/favorite items 與 fallback title 產生。 - 新功能若使用後端選單,優先調整後端選單資料或對應 API mock,不要把頁面專屬選單邏輯塞進 layout。 - 若只是新增 route,通常不需要修改 `MainLayout.vue` 或 `src/shell/*`。 ## 4. 需要 API 時新增 service module ```ts // src/services/modules/reports.ts import { httpClient } from '../client' export interface ReportSummary { id: number title: string owner: string } export const reportsApi = { list: async () => ({ data: await httpClient.get('Reports').json(), }), } ``` service 只封裝 HTTP 細節,不持有 UI 狀態。 `httpClient` 的 `baseURL` 來自 `VITE_API_BASE_URL`,沒有設定時預設 `/service/api`。開發模式下,Vite proxy 會將 `/service/*` 轉送到 `VITE_PROXY_TARGET`。 ## 5. 需要共享狀態時新增 store 只有跨頁共享、需要快取、或全域狀態才新增 store。單頁暫時狀態留在 view、component 或 composable。 ```ts // src/stores/reports.ts import { defineStore } from 'pinia' import { ref } from 'vue' import { reportsApi, type ReportSummary } from '@/services/modules/reports' export const useReportsStore = defineStore('reports', () => { const items = ref([]) const loading = ref(false) const load = async () => { loading.value = true try { const { data } = await reportsApi.list() items.value = data } finally { loading.value = false } } return { items, loading, load, } }) ``` ## 6. 驗證 至少執行: ```bash pnpm -s type-check ``` 需要確認建置產物時再執行: ```bash pnpm -s build ``` 若有 route、layout 或主要互動流程變更,再啟動 dev server 並用瀏覽器確認。