fix: docing
This commit is contained in:
+101
-35
@@ -4,56 +4,99 @@
|
||||
|
||||
範例功能:`reports`
|
||||
|
||||
## 1. 新增 route view
|
||||
目前新增一般頁面的預設資料流:
|
||||
|
||||
```vue
|
||||
<!-- src/views/reports/Reports.vue -->
|
||||
<script setup lang="ts">
|
||||
import ReportsTable from '@/components/reports/ReportsTable.vue'
|
||||
|
||||
const rows = [
|
||||
{ id: 1, title: '學生統計', owner: '教務處' },
|
||||
{ id: 2, title: '課程統計', owner: '課務組' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ReportsTable :rows="rows" />
|
||||
</template>
|
||||
```txt
|
||||
router -> view -> page driver -> page component -> sections/items
|
||||
↓
|
||||
store/composable -> service
|
||||
```
|
||||
|
||||
view 的責任是頁面資料組裝與事件協調。畫面區塊交給 feature component。
|
||||
## 1. 新增 page driver
|
||||
|
||||
## 2. 新增 feature component
|
||||
頁面資料、事件與暫時 UI state 優先放在 page driver,view 只負責掛載。
|
||||
|
||||
```vue
|
||||
<!-- src/components/reports/ReportsTable.vue -->
|
||||
<script setup lang="ts">
|
||||
interface ReportRow {
|
||||
```ts
|
||||
// src/composables/page-drivers/useReportsPage.ts
|
||||
import { computed, ref } from 'vue'
|
||||
import { useSnackbarStore } from '@/stores/snackbar'
|
||||
|
||||
export interface ReportSummary {
|
||||
id: number
|
||||
title: string
|
||||
owner: string
|
||||
}
|
||||
|
||||
export interface ReportsPageModel {
|
||||
title: string
|
||||
rows: ReportSummary[]
|
||||
}
|
||||
|
||||
const initialRows: ReportSummary[] = [
|
||||
{ id: 1, title: '學生統計', owner: '教務處' },
|
||||
{ id: 2, title: '課程統計', owner: '課務組' },
|
||||
]
|
||||
|
||||
export function useReportsPage() {
|
||||
const snackbar = useSnackbarStore()
|
||||
const rows = ref<ReportSummary[]>(initialRows)
|
||||
|
||||
const pageModel = computed<ReportsPageModel>(() => ({
|
||||
title: '報表清單',
|
||||
rows: rows.value,
|
||||
}))
|
||||
|
||||
function openReport(row: ReportSummary) {
|
||||
snackbar.show({ message: `開啟:${row.title}`, color: 'info' })
|
||||
}
|
||||
|
||||
return {
|
||||
pageModel,
|
||||
openReport,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
若資料來自 API,page driver 可呼叫 store 或 composable;底層 HTTP 細節仍放在 `services/modules/*`。
|
||||
|
||||
## 2. 新增 page component
|
||||
|
||||
完整頁面主畫面放在 `src/components/pages`,檔名使用 `Page` 前綴。component 以 props 接收資料,以 emit 回報使用者事件,不直接處理 route 或底層 HTTP。
|
||||
|
||||
```vue
|
||||
<!-- src/components/pages/PageReports.vue -->
|
||||
<script setup lang="ts">
|
||||
import type { ReportSummary, ReportsPageModel } from '@/composables/page-drivers/useReportsPage'
|
||||
|
||||
defineProps<{
|
||||
rows: ReportRow[]
|
||||
page: ReportsPageModel
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
open: [row: ReportSummary]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card flat>
|
||||
<v-card-title class="text-h6">報表清單</v-card-title>
|
||||
<v-card-title class="text-h6">{{ page.title }}</v-card-title>
|
||||
<v-table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名稱</th>
|
||||
<th>負責單位</th>
|
||||
<th class="text-right">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in rows" :key="row.id">
|
||||
<tr v-for="row in page.rows" :key="row.id">
|
||||
<td>{{ row.title }}</td>
|
||||
<td>{{ row.owner }}</td>
|
||||
<td class="text-right">
|
||||
<v-btn color="primary" size="small" variant="text" @click="emit('open', row)">
|
||||
開啟
|
||||
</v-btn>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-table>
|
||||
@@ -61,9 +104,27 @@ defineProps<{
|
||||
</template>
|
||||
```
|
||||
|
||||
component 以 props 接收資料,以 emit 回報事件。不要在 component 裡直接處理 route 或底層 HTTP。
|
||||
若畫面是固定的「篩選條件 + 查詢按鈕 + 結果表格」,優先使用 `components/sections/SectionQueryPage.vue`。若是「表單欄位 + 送出/存檔按鈕」,優先使用 `components/sections/SectionFormPage.vue`。
|
||||
|
||||
## 3. 加入 route
|
||||
## 3. 新增 route view
|
||||
|
||||
view 維持薄層,只呼叫 page driver 並掛載 page component。
|
||||
|
||||
```vue
|
||||
<!-- src/views/reports/Reports.vue -->
|
||||
<script setup lang="ts">
|
||||
import PageReports from '@/components/pages/PageReports.vue'
|
||||
import { useReportsPage } from '@/composables/page-drivers/useReportsPage'
|
||||
|
||||
const page = useReportsPage()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PageReports :page="page.pageModel.value" @open="page.openReport" />
|
||||
</template>
|
||||
```
|
||||
|
||||
## 4. 加入 route
|
||||
|
||||
route 加在 `src/router/routes.ts` 的 `routes` 陣列中,並放在 `/:pathMatch(.*)*` catch-all route 前面。
|
||||
|
||||
@@ -84,9 +145,9 @@ route 加在 `src/router/routes.ts` 的 `routes` 陣列中,並放在 `/:pathMa
|
||||
- menu 來源目前由 `src/stores/menu.ts` 轉換後端選單資料。
|
||||
- breadcrumb 會依 route path、menu/favorite items 與 fallback title 產生。
|
||||
- 新功能若使用後端選單,優先調整後端選單資料或對應 API mock,不要把頁面專屬選單邏輯塞進 layout。
|
||||
- 若只是新增 route,通常不需要修改 `MainLayout.vue`。
|
||||
- 若只是新增 route,通常不需要修改 `MainLayout.vue` 或 `src/shell/*`。
|
||||
|
||||
## 4. 需要 API 時新增 service module
|
||||
## 5. 需要 API 時新增 service module
|
||||
|
||||
```ts
|
||||
// src/services/modules/reports.ts
|
||||
@@ -107,9 +168,11 @@ export const reportsApi = {
|
||||
|
||||
service 只封裝 HTTP 細節,不持有 UI 狀態。
|
||||
|
||||
`httpClient` 的 `baseURL` 來自 `VITE_API_BASE_URL`。template 預設值見 `.env.example`,通常使用 `/service/api` 搭配 Vite proxy。
|
||||
`httpClient` 的 `baseURL` 來自 `VITE_API_BASE_URL`,沒有設定時預設 `/service/api`。開發模式下,Vite proxy 會將 `/service/*` 轉送到 `VITE_PROXY_TARGET`。
|
||||
|
||||
## 5. 需要共享狀態時新增 store
|
||||
## 6. 需要共享狀態時新增 store
|
||||
|
||||
只有跨頁共享、需要快取、或全域狀態才新增 store。單頁暫時狀態留在 view、component 或 composable。
|
||||
|
||||
```ts
|
||||
// src/stores/reports.ts
|
||||
@@ -139,15 +202,18 @@ export const useReportsStore = defineStore('reports', () => {
|
||||
})
|
||||
```
|
||||
|
||||
只有跨頁共享、需要快取、或全域狀態才新增 store。單頁暫時狀態留在 view、component 或 composable。
|
||||
|
||||
## 6. 驗證
|
||||
## 7. 驗證
|
||||
|
||||
至少執行:
|
||||
|
||||
```bash
|
||||
pnpm type-check
|
||||
pnpm build
|
||||
pnpm -s type-check
|
||||
```
|
||||
|
||||
需要確認建置產物時再執行:
|
||||
|
||||
```bash
|
||||
pnpm -s build
|
||||
```
|
||||
|
||||
若有 route、layout 或主要互動流程變更,再啟動 dev server 並用瀏覽器確認。
|
||||
|
||||
Reference in New Issue
Block a user