docs: update LLM guides for completed architecture phase
Refresh the development guidance to point to layered src GUIDE files and document Phase 4 completion, including AppShell extraction and page driver/component adoption for non-maintenance pages.docs: update LLM guides for completed architecture phase Refresh the development guidance to point to layered src GUIDE files and document Phase 4 completion, including AppShell extraction and page driver/component adoption for non-maintenance pages.
This commit is contained in:
@@ -397,10 +397,16 @@ views/xxx.vue
|
||||
4. [x] 通用方向已落地為「每頁 page driver + page component」與既有 `useCrudCommands()`。
|
||||
- Phase 3 未再抽出跨 A/B/C 的大型共用 driver,避免在 demo 變體尚未收斂前建立過早抽象。
|
||||
|
||||
### Phase 4:非 maintenance 頁面統一
|
||||
### Phase 4:非 maintenance 頁面統一 ✅ 已完成
|
||||
|
||||
1. `Home.vue`、`Settings.vue`、`FncPage.vue` 套用 Page Driver + Page Component 模式。
|
||||
2. `App.vue` 最終只保留 layout 切換與 `GlobalOverlays` 掛載。
|
||||
1. [x] `Home.vue`、`Settings.vue`、`FncPage.vue` 套用 Page Driver + Page Component 模式。
|
||||
- `src/views/Home.vue` 縮減為 17 行,新增 `src/components/pages/PageHome.vue` 與 `src/composables/page-drivers/useHomePage.ts`。
|
||||
- `src/views/Settings.vue` 縮減為 10 行,新增 `src/components/pages/PageSettings.vue` 與 `src/composables/page-drivers/useSettingsPage.ts`。
|
||||
- `src/views/FncPage.vue` 縮減為 10 行,新增 `src/components/pages/PageFunction.vue` 與 `src/composables/page-drivers/useFunctionPage.ts`。
|
||||
2. [x] `App.vue` 最終只保留 shell 掛載。
|
||||
- `src/App.vue` 縮減為 7 行,只掛載 `AppShell`。
|
||||
- `src/shell/AppShell.vue` 承接 layout 切換、layout props/events、breadcrumb actions、tabs router-view 與 `GlobalOverlays` 掛載。
|
||||
- `src/composables/layout/useAppShell.ts` 承接 menu 合併、favorite、breadcrumb、layout action、手動/強制登出流程。
|
||||
|
||||
---
|
||||
|
||||
|
||||
+50
-304
@@ -2,332 +2,78 @@
|
||||
|
||||
## 文件目的
|
||||
|
||||
本專案是給其他 Vue/Vuetify 專案使用的 template。LLM 在協助修改時,主要工作應集中在 `src` 底下新增或修改頁面、元件、store、service 與 composable,並讓一般頁面自然被 `MainLayout` 包住。
|
||||
本專案是給其他 Vue/Vuetify 專案使用的 template。LLM 協助修改時,預設應在 `src` 底下依分層規則新增或修改頁面、元件、store、service 與 composable。
|
||||
|
||||
本文件描述的是後續 LLM 依照 template 修改專案時的預設操作規則,不是目前對話 session 的永久限制。若使用者明確要求修改 template shell 或登入頁入口,可依需求處理。
|
||||
本文件只保留全域操作順序與導覽。各層細節規範放在 `src/**/GUIDE.md`,避免重複維護。
|
||||
|
||||
建議閱讀順序:
|
||||
## 建議閱讀順序
|
||||
|
||||
1. `README.md`
|
||||
2. `src/README.md`
|
||||
3. `docs/add-page-example.md`
|
||||
4. `docs/architecture-strategy.md`(新增功能與重構的最高準則)
|
||||
5. `docs/frontend-layering.md`(歷史參考,已被 `architecture-strategy.md` 取代)
|
||||
2. `docs/architecture-strategy.md`
|
||||
3. `src/GUIDE.md`
|
||||
4. 依變更範圍閱讀對應的 `src/**/GUIDE.md`
|
||||
5. `docs/add-page-example.md`(需要新增頁面時)
|
||||
|
||||
## 預設不可修改的檔案
|
||||
`docs/frontend-layering.md` 是歷史參考,後續以 `docs/architecture-strategy.md` 與 `src/**/GUIDE.md` 為準。
|
||||
|
||||
以下檔案視為 template 核心邊界。LLM 依本文件處理一般功能需求時,不應修改:
|
||||
## GUIDE 索引
|
||||
|
||||
- `src/components/layouts/MainLayout.vue`
|
||||
- `src/views/Login.vue`
|
||||
| 範圍 | 指南 |
|
||||
|------|------|
|
||||
| `src` 總覽、資料流、template core、demo 邊界 | `src/GUIDE.md` |
|
||||
| route view 與薄 view 規則 | `src/views/GUIDE.md` |
|
||||
| maintenance demo view | `src/views/maint/GUIDE.md` |
|
||||
| Vue component 分層 | `src/components/GUIDE.md` |
|
||||
| layout 邊界 | `src/components/layouts/GUIDE.md` |
|
||||
| page driver、command、layout composable | `src/composables/GUIDE.md` |
|
||||
| route 與 guard | `src/router/GUIDE.md` |
|
||||
| AppShell、tabs、global overlays | `src/shell/GUIDE.md` |
|
||||
| Pinia store | `src/stores/GUIDE.md` |
|
||||
| HTTP service / ky / API module | `src/services/GUIDE.md` |
|
||||
| i18n 文案 | `src/language/GUIDE.md` |
|
||||
|
||||
如果一般功能需求看起來需要修改上述檔案,先停下來回報原因,並改從可修改檔案尋找解法。只有在使用者明確指定要調整 layout shell 或登入頁入口時,才可以修改。
|
||||
## 預設修改策略
|
||||
|
||||
## 優先修改的位置
|
||||
|
||||
一般功能需求應優先落在:
|
||||
一般功能需求優先修改:
|
||||
|
||||
- `src/views/*`
|
||||
- `src/views/<feature>/*`
|
||||
- `src/components/<feature>/*`
|
||||
- `src/composables/<feature>/*`
|
||||
- `src/components/pages/*`
|
||||
- `src/components/sections/*`
|
||||
- `src/components/items/*`
|
||||
- `src/composables/page-drivers/*`
|
||||
- `src/composables/commands/*`
|
||||
- `src/stores/*`
|
||||
- `src/services/*`
|
||||
- `src/services/modules/*`
|
||||
- `src/router/routes.ts`
|
||||
- `src/language/*.json`
|
||||
|
||||
新增頁面時,通常只需要新增 view、必要的 feature components,並在 `src/router/routes.ts` 加入 route。
|
||||
除非使用者明確要求,避免先修改 template core。template core 清單與 demo/example 邊界見 `src/GUIDE.md`。
|
||||
|
||||
## 依循 `src/` 既有慣例
|
||||
## 常用判斷
|
||||
|
||||
開始實作前,先檢查需求最接近的既有檔案,並沿用目前 `src/` 的責任分工、命名方式、資料流與 import 寫法。不要另起一套資料夾結構、狀態管理方式或 API 呼叫方式。
|
||||
|
||||
目前主要資料流是:
|
||||
|
||||
```txt
|
||||
router -> AppShell -> layout -> view(Page Driver) -> Page Component -> Section -> Item
|
||||
↓
|
||||
page driver / command composable -> store -> service
|
||||
```
|
||||
|
||||
判斷原則:
|
||||
|
||||
- `router` 決定 route、layout meta、auth meta 與錯誤頁入口
|
||||
- `AppShell` 組裝 layout props、全域 UI 與 layout event
|
||||
- `views` 承接路由入口、頁面資料協調與頁面事件協調,應維持薄層
|
||||
- `components/pages` 組裝完整頁面與 page-level slot
|
||||
- `components/sections` 承接容器佈局,例如搜尋區、表格、dialog shell
|
||||
- `components/items` 承接單一資料單位或欄位群組呈現
|
||||
- `composables/page-drivers` 承接頁面資料協調與 page model 組裝
|
||||
- `composables/commands` 承接命令式副作用流程,例如 create/edit/save/delete
|
||||
- `composables` 其他子目錄承接可重用流程、頁面狀態機或較複雜的 UI state
|
||||
- `stores` 承接跨頁共享狀態、快取與全域顯示狀態
|
||||
- `services` 承接 HTTP client、API 模組、token、session 與錯誤處理
|
||||
|
||||
新增功能時,優先找相同類型的現有範例再修改:
|
||||
|
||||
- 新 route:參考 `src/router/routes.ts`
|
||||
- 一般被主 layout 包住的頁面:參考 `src/views/Home.vue`、`src/views/maint/EditableGrid.vue`
|
||||
- 登入相關 UI:參考 `src/components/PageLogin.vue` 與 `src/components/login/*`
|
||||
- 維護頁:優先參考 `src/views/maint/SingleRecord.vue`、`src/views/maint/EditableGrid.vue`、`src/views/maint/MasterDetailA.vue`、`src/views/maint/MasterDetailB.vue`、`src/views/maint/MasterDetailC.vue` 與對應的 `src/components/pages/*Maintenance.vue`、`src/composables/page-drivers/*MaintenancePage.ts`
|
||||
- 單筆維護欄位/表格/dialog 拆分:參考 `src/components/sections/*`、`src/components/items/*`、`src/composables/commands/useCrudCommands.ts`
|
||||
- 維護頁範本選擇:參考 `src/views/maint/README.md`
|
||||
- API 呼叫:參考 `src/services/modules/*` 與使用它們的 store/composable
|
||||
- 全域提示:參考 `src/stores/snackbar.ts` 與 `src/composables/useApiCall.ts`
|
||||
|
||||
## Template Core 與 Demo 邊界
|
||||
|
||||
一般功能需求應避免先修改 template core。這些檔案支撐 app shell、route/layout、登入、全域狀態與 API 基礎設施:
|
||||
|
||||
- `src/main.ts`
|
||||
- `src/App.vue`
|
||||
- `src/router/index.ts`
|
||||
- `src/router/guards.ts`
|
||||
- `src/components/layouts/*`
|
||||
- `src/views/Login.vue`
|
||||
- `src/plugins/*`
|
||||
- `src/styles/*`
|
||||
- `src/services/client.ts`
|
||||
- `src/services/interceptors.ts`
|
||||
- `src/services/token.ts`
|
||||
- `src/services/session.ts`
|
||||
- `src/services/error.ts`
|
||||
- `src/services/http-error.ts`
|
||||
- `src/services/http-toast.ts`
|
||||
- `src/stores/auth.ts`
|
||||
- `src/stores/menu.ts`
|
||||
- `src/stores/breadcrumbs.ts`
|
||||
- `src/stores/favorites.ts`
|
||||
- `src/stores/messages.ts`
|
||||
- `src/stores/snackbar.ts`
|
||||
- `src/stores/app.ts`
|
||||
- `src/composables/layout/*`
|
||||
|
||||
以下內容偏向 demo/example,建立正式專案時可依需求替換或刪除:
|
||||
|
||||
- `src/views/Home.vue`
|
||||
- `src/components/PageIndex.vue`
|
||||
- `src/views/maint/*`
|
||||
- `src/components/maint/*`
|
||||
- `src/components/pages/PageMaintenance.vue`
|
||||
- `src/components/sections/*`
|
||||
- `src/components/items/*`
|
||||
- `src/composables/maint/*`
|
||||
- `src/composables/page-drivers/*`
|
||||
- `src/composables/commands/*`
|
||||
- `src/components/PageMaint.vue`
|
||||
- `src/stores/students.ts`
|
||||
- `src/stores/semesters.ts`
|
||||
- `src/views/FncPage.vue`
|
||||
- `src/views/Settings.vue`
|
||||
- `src/assets/logo.png`
|
||||
- `src/assets/logo.svg`
|
||||
- `src/assets/robot-svgrepo-com.svg`
|
||||
|
||||
`maint` 是可參考的 demo feature,不是所有新專案都必須保留的核心功能。
|
||||
|
||||
移除 demo/example 時,同步清理 `src/router/routes.ts`、相關 menu/favorites/breadcrumb 流程、語系文案、assets 與 import。
|
||||
|
||||
## 新增一般頁面的流程
|
||||
|
||||
1. 在 `src/views` 或 `src/views/<feature>` 新增頁面檔案。
|
||||
2. 若頁面超過單一簡單畫面,將主要 UI 拆到 `src/components/<feature>`。
|
||||
3. 若有可重用或狀態較多的流程,放到 `src/composables/<feature>`。
|
||||
4. 若資料需要跨頁共享,才新增或修改 `src/stores`。
|
||||
5. 在 `src/router/routes.ts` 新增 route。
|
||||
6. 一般頁面的 route 必須使用 `meta: { layout: 'default' }`。
|
||||
|
||||
範例:
|
||||
|
||||
```ts
|
||||
{
|
||||
path: '/reports',
|
||||
name: 'reports',
|
||||
component: () => import('@/views/reports/Reports.vue'),
|
||||
meta: { layout: 'default' },
|
||||
}
|
||||
```
|
||||
|
||||
使用 `layout: 'default'` 的頁面會由 `App.vue` 放進 `MainLayout` 的預設 slot,不需要也不可以直接 import 或包裝 `MainLayout.vue`。
|
||||
|
||||
完整範例見 `docs/add-page-example.md`。
|
||||
|
||||
## 何時使用 `layout: 'none'`
|
||||
|
||||
只有下列頁面應使用 `meta: { layout: 'none' }`:
|
||||
|
||||
- 登入頁
|
||||
- 錯誤頁
|
||||
- 維護中頁
|
||||
- 明確要求不要被主框架包住的獨立頁
|
||||
|
||||
不要為了一般功能頁使用 `layout: 'none'`。
|
||||
|
||||
## Layout 邊界
|
||||
|
||||
`MainLayout` 只負責 app shell:
|
||||
|
||||
- drawer
|
||||
- app bar
|
||||
- breadcrumb
|
||||
- favorites
|
||||
- toolbar actions
|
||||
- 主內容 slot
|
||||
|
||||
頁面專屬業務流程、資料規則、表單、列表、對話框、查詢條件與 CRUD 行為都不應放進 layout。
|
||||
|
||||
如果頁面需要在主內容區呈現特定畫面,請修改該 route 對應的 view 或 feature component。
|
||||
|
||||
如果頁面需要影響 breadcrumb、favorites、menu 或 toolbar,優先使用現有 store、route meta 或 `App.vue` 已經提供的 layout props/event 流程,不要修改 `MainLayout.vue`。
|
||||
|
||||
## Login 邊界
|
||||
|
||||
`src/views/Login.vue` 是登入頁入口。一般功能需求預設不修改這個檔案。
|
||||
|
||||
若需求是調整登入頁內部區塊,優先檢查並修改:
|
||||
|
||||
- `src/components/PageLogin.vue`
|
||||
- `src/components/login/*`
|
||||
- `src/stores/auth.ts`
|
||||
- `src/stores/loginAnnouncements.ts`
|
||||
- `src/services/modules/auth.ts`
|
||||
|
||||
若需求明確要求改變登入頁 route、guard 或登入後導向,優先檢查:
|
||||
|
||||
- `src/router/routes.ts`
|
||||
- `src/router/guards.ts`
|
||||
- `src/stores/auth.ts`
|
||||
|
||||
## View 與 Component 分工
|
||||
|
||||
`views` 是路由入口,負責:
|
||||
|
||||
- 接 route params/query
|
||||
- 組合頁面資料
|
||||
- 串接 store、service、composable
|
||||
- 管理頁面專屬事件
|
||||
- 組裝頁面主 component
|
||||
|
||||
`components/<feature>` 負責:
|
||||
|
||||
- 呈現頁面區塊
|
||||
- 接 props
|
||||
- emit 使用者事件
|
||||
- 拆分表單、列表、工具列、dialog 等 UI
|
||||
|
||||
不要把完整功能長期塞在單一 view。當畫面有多個區塊、表單、列表、dialog 或重複 UI 時,應拆到 page / section / item components。
|
||||
|
||||
維護頁分層優先順序:
|
||||
|
||||
1. `views/maint/*.vue`:只做 route-level wiring,目標 < 80 行。
|
||||
2. `components/pages/PageMaintenance.vue`:組裝維護頁外殼與主要 slot。
|
||||
3. `components/sections/*`:管理搜尋、表格、dialog shell 等區塊佈局。
|
||||
4. `components/items/*`:管理欄位群組或單一資料呈現,不直接呼叫 store/service。
|
||||
5. `composables/page-drivers/*`:集中 page model、分頁、搜尋、表單狀態與事件 wiring。
|
||||
6. `composables/commands/*`:集中新增、載入、儲存、刪除等 command 流程。
|
||||
|
||||
## Router 安排規則
|
||||
|
||||
route 集中放在 `src/router/routes.ts`。不要在 view 或 component 裡臨時建立 route 設定。
|
||||
|
||||
一般 route 應包含:
|
||||
|
||||
- `path`
|
||||
- `name`
|
||||
- `component`
|
||||
- `meta.layout`
|
||||
|
||||
需要登入才可進入的頁面使用既有 `requiresAuth` meta。訪客專用頁面使用既有 `guestOnly` meta。導航守衛流程放在 `src/router/guards.ts`,不要散落在頁面 component。
|
||||
|
||||
## Composable 使用規則
|
||||
|
||||
只有在邏輯有下列特性時才新增 composable:
|
||||
|
||||
- 會被多個元件使用
|
||||
- 狀態流程明顯
|
||||
- 有副作用或非簡單 UI 邏輯
|
||||
- 從 component 抽出後可讓 component 責任更清楚
|
||||
|
||||
目前既有 composable 的使用定位:
|
||||
|
||||
- `src/composables/useApiCall.ts`:包裝可重用 API 呼叫狀態與錯誤提示流程
|
||||
- `src/composables/layout/useAdminLayoutState.ts`:提供 layout shell 所需的狀態組裝
|
||||
- `src/composables/layout/useThemeToggle.ts`:提供主題切換流程
|
||||
- `src/composables/page-drivers/useMaintenancePage.ts`:提供通用 maintenance page model 基礎狀態
|
||||
- `src/composables/page-drivers/useSingleRecordMaintenancePage.ts`:協調單筆維護 demo 頁面的 page model、section props/events、表單、表格與 command
|
||||
- `src/composables/page-drivers/useEditableGridMaintenancePage.ts`:協調可編輯表格 demo 頁面的 page model
|
||||
- `src/composables/page-drivers/useMasterDetailAMaintenancePage.ts`:協調主從維護 A demo 的 page model、主檔/明細狀態與 dialog event wiring
|
||||
- `src/composables/page-drivers/useMasterDetailBMaintenancePage.ts`:協調主從維護 B demo 的 page model、主檔/明細狀態與 dialog event wiring
|
||||
- `src/composables/page-drivers/useMasterDetailCMaintenancePage.ts`:協調主從維護 C demo 的 page model、主檔/明細狀態與 dialog event wiring
|
||||
- `src/composables/commands/useCrudCommands.ts`:提供 CRUD command 流程,讓 view 不直接執行 store mutation 細節
|
||||
- `src/composables/maint/useMaintenanceCrudFlow.ts`:提供維護頁 CRUD 流程狀態
|
||||
- `src/composables/maint/useStudentMaintenanceForm.ts`:提供學生維護表單狀態
|
||||
- `src/composables/maint/useEditableStudentGrid.ts`:提供 editable grid 狀態
|
||||
|
||||
新增 composable 時,用 `useXxx.ts` 命名。若是頁面資料協調,放在 `src/composables/page-drivers`;若是命令式副作用流程,放在 `src/composables/commands`;若只服務單一 feature,放在 `src/composables/<feature>`;若確定跨 feature 使用,才放在 `src/composables` 根目錄。
|
||||
|
||||
## Store 與 Service 資料流規則
|
||||
|
||||
只有在資料或狀態跨頁共享時才使用 store。單一頁面的暫時 UI 狀態應留在 view、feature component 或 composable。
|
||||
|
||||
store 檔案直接放在 `src/stores/*.ts`。不要建立 `src/stores/stores/*` 或其他重複巢狀 store 目錄。
|
||||
|
||||
service 放在 `src/services`,負責外部 API 與 HTTP 細節。component 不應直接處理底層 HTTP client、token、hooks 或錯誤正規化。
|
||||
|
||||
資料流優先順序:
|
||||
|
||||
1. component 透過 props/emits 與 view 或 page component 溝通。
|
||||
2. view 或 composable 協調頁面流程。
|
||||
3. 跨頁共享狀態由 store 管理。
|
||||
4. store 或 composable 呼叫 service。
|
||||
5. service 回傳資料,不持有 UI 狀態。
|
||||
|
||||
不要讓 service import component、view 或 store。不要讓 component 直接繞過既有 store/composable 去操作 token、session 或 HTTP hooks。
|
||||
|
||||
## 環境變數規則
|
||||
|
||||
template 提供 `.env.example` 作為範本。不要提交實際 `.env` 或 `.env.*.local`。
|
||||
|
||||
常用變數:
|
||||
|
||||
- `VITE_API_BASE_URL`:API base URL,預設使用 `/service/api` 搭配 Vite proxy。
|
||||
- `VITE_SKIP_LOGIN`:登入示範開關,只有專案明確支援時才使用。
|
||||
- `VITE_DEV_DEFAULT_USER_ID`、`VITE_DEV_DEFAULT_PASSWORD`:本機開發示範帳號,放在本機 env,不要寫進程式。
|
||||
|
||||
## Vuetify 使用規則
|
||||
|
||||
優先使用 Vuetify 原生元件、props、slots 與事件。當需求直接牽涉 Vuetify 元件行為、DOM、可及性輸出或 slot 結構時,先查官方 Vuetify API 文件,再修改實作。
|
||||
|
||||
icon 使用 `@mdi/js`:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { mdiAccount } from '@mdi/js'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-icon :icon="mdiAccount" />
|
||||
</template>
|
||||
```
|
||||
- 新 route:讀 `src/router/GUIDE.md`。
|
||||
- 一般頁面:讀 `src/views/GUIDE.md`、`src/components/GUIDE.md`、`src/composables/GUIDE.md`。
|
||||
- 維護頁:讀 `src/views/maint/GUIDE.md`。
|
||||
- layout / AppShell / tabs / global overlay:讀 `src/shell/GUIDE.md` 與 `src/components/layouts/GUIDE.md`。
|
||||
- API 串接:讀 `src/services/GUIDE.md`。
|
||||
- 跨頁共享狀態:讀 `src/stores/GUIDE.md`。
|
||||
- 語系文案:讀 `src/language/GUIDE.md`。
|
||||
|
||||
## 修改前檢查
|
||||
|
||||
開始改檔前先確認:
|
||||
|
||||
- 是否會碰到禁止修改檔案
|
||||
- 是否只需要新增或修改 view
|
||||
- 是否需要新增 route
|
||||
- 是否需要拆 feature component
|
||||
- 是否已閱讀 `docs/architecture-strategy.md`
|
||||
- 是否已參考 `src/` 裡相同類型的既有範例
|
||||
- 是否符合 Vue 3、Composition API、`<script setup lang="ts">` 的既有寫法
|
||||
- 是否碰到 template core。
|
||||
- 是否已有同類型範例可沿用。
|
||||
- 是否需要新增 route。
|
||||
- 是否應拆成 page / section / item。
|
||||
- 是否應新增 page driver 或 command composable。
|
||||
- 是否需要 store,或只需要頁面內 state。
|
||||
- 是否需要更新語系、menu、breadcrumb、favorites。
|
||||
|
||||
## 完成前驗證
|
||||
|
||||
修改完成後,至少執行與變更範圍相符的檢查:
|
||||
|
||||
- TypeScript 或 Vue 結構有變更:`pnpm type-check`
|
||||
- 需要確認產物可建置:`pnpm build`
|
||||
- route、layout 或主要畫面流程有變更:啟動 dev server 並用瀏覽器確認頁面被正確包在主 layout 中
|
||||
- Vue / TypeScript 結構有變更:`pnpm -s type-check`
|
||||
- 需要確認產物可建置:`pnpm -s build`
|
||||
- Markdown 或大量搬移:`git diff --check`
|
||||
- route、layout 或主要畫面流程有變更:啟動 dev server 並用瀏覽器確認,除非使用者明確不需要。
|
||||
|
||||
如果無法執行驗證,回報原因,不要宣稱已驗證。
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# Src Guide
|
||||
|
||||
`src` 是 template 使用者主要修改的區域。新增功能時,先從 route view、page component 與 page driver 開始,除非需求明確牽涉 app shell、登入、router guard 或 HTTP core,否則不要先改 template core。
|
||||
|
||||
## 資料流
|
||||
|
||||
```txt
|
||||
router -> AppShell -> layout -> view(Page Driver) -> Page Component -> Section -> Item
|
||||
↓
|
||||
page driver / command composable -> store -> service
|
||||
```
|
||||
|
||||
## 主要目錄
|
||||
|
||||
- `views/`:route entry,維持薄層,只做 route wiring 與 page driver 掛載。詳見 `src/views/GUIDE.md`。
|
||||
- `components/`:Vue UI 元件,依 pages / sections / items / layouts / base 分層。詳見 `src/components/GUIDE.md`。
|
||||
- `composables/`:page driver、command flow、layout flow 與可重用狀態流程。詳見 `src/composables/GUIDE.md`。
|
||||
- `router/`:route、layout meta、auth meta 與 guard。詳見 `src/router/GUIDE.md`。
|
||||
- `shell/`:AppShell、tabs、global overlays。詳見 `src/shell/GUIDE.md`。
|
||||
- `stores/`:跨頁共享狀態與快取。詳見 `src/stores/GUIDE.md`。
|
||||
- `services/`:HTTP client、API module、token/session、錯誤處理。詳見 `src/services/GUIDE.md`。
|
||||
- `language/`:Vue I18n 文案。詳見 `src/language/GUIDE.md`。
|
||||
|
||||
## Template Core
|
||||
|
||||
一般功能需求預設不修改:
|
||||
|
||||
- `main.ts`
|
||||
- `App.vue`
|
||||
- `shell/*`
|
||||
- `components/layouts/*`
|
||||
- `views/Login.vue`
|
||||
- `router/index.ts`
|
||||
- `router/guards.ts`
|
||||
- `plugins/*`
|
||||
- `styles/*`
|
||||
- `services/client.ts`
|
||||
- `services/interceptors.ts`
|
||||
- `services/token.ts`
|
||||
- `services/session.ts`
|
||||
- `stores/auth.ts`
|
||||
- `stores/menu.ts`
|
||||
- `stores/breadcrumbs.ts`
|
||||
- `stores/favorites.ts`
|
||||
- `stores/messages.ts`
|
||||
- `stores/snackbar.ts`
|
||||
- `stores/app.ts`
|
||||
- `composables/layout/*`
|
||||
|
||||
只有需求明確要求調整 template shell、登入、router guard、HTTP core 或全域狀態時才修改上述檔案。
|
||||
|
||||
## Demo / Example
|
||||
|
||||
下列檔案偏向示範功能,正式專案可依需求替換或移除:
|
||||
|
||||
- `views/Home.vue`
|
||||
- `views/FncPage.vue`
|
||||
- `views/Settings.vue`
|
||||
- `views/maint/*`
|
||||
- `components/PageIndex.vue`
|
||||
- `components/PageMaint.vue`
|
||||
- `components/maint/*`
|
||||
- `components/pages/*Maintenance.vue`
|
||||
- `components/sections/*`
|
||||
- `components/items/*`
|
||||
- `composables/page-drivers/*MaintenancePage.ts`
|
||||
- `composables/maint/*`
|
||||
- `composables/commands/*`
|
||||
- `stores/students.ts`
|
||||
- `stores/semesters.ts`
|
||||
- demo assets 與 demo language keys
|
||||
|
||||
移除 demo 時,同步清理 route、menu/favorites/breadcrumb 流程、語系文案與不再使用的 import。
|
||||
|
||||
## 新功能流程
|
||||
|
||||
1. 新增或修改 `views/*` route entry。
|
||||
2. 若有完整頁面 UI,新增 `components/pages/PageXxx.vue`。
|
||||
3. 若有頁面資料協調或 route param 轉換,新增 `composables/page-drivers/useXxxPage.ts`。
|
||||
4. 若畫面有獨立區塊,拆到 `components/sections/*`。
|
||||
5. 若區塊內有欄位群組或單筆資料呈現,拆到 `components/items/*`。
|
||||
6. 跨頁共享狀態才新增或修改 `stores/*`。
|
||||
7. 外部 API 放在 `services/modules/*`。
|
||||
8. 在 `router/routes.ts` 新增 route。
|
||||
|
||||
## 驗證
|
||||
|
||||
- Vue / TypeScript 結構變更:`pnpm -s type-check`
|
||||
- 需要確認產物:`pnpm -s build`
|
||||
- route、layout 或主要畫面流程變更:啟動 dev server 並做瀏覽器檢查,除非使用者明確不需要。
|
||||
@@ -0,0 +1,29 @@
|
||||
# Components Guide
|
||||
|
||||
`components` 放 Vue UI 元件。元件以 props 接收資料,以 emits 回報事件;不要直接處理 route、HTTP client、token/session 或全域流程。
|
||||
|
||||
## 分層
|
||||
|
||||
- `pages/`:完整頁面組裝,檔名使用 `Page` 前綴。
|
||||
- `sections/`:頁面區塊容器,例如搜尋區、表格、dialog shell、panel。
|
||||
- `items/`:單筆資料、欄位群組或原子級呈現。
|
||||
- `layouts/`:app shell layout。詳見 `src/components/layouts/GUIDE.md`。
|
||||
- `base/`:真正跨頁共用且不屬於特定 domain 的基礎元件。
|
||||
- `login/`:登入頁專用 UI。
|
||||
- `maint/`:maintenance demo 舊有或領域型 UI 元件。
|
||||
|
||||
## 規則
|
||||
|
||||
- 不假設元件全域註冊;使用時明確 import。
|
||||
- route component 放在 `views`,不要放在 `components`。
|
||||
- `pages` 可組合 sections/items,但不直接處理 API。
|
||||
- `sections` 決定布局與區塊互動,不知道 route。
|
||||
- `items` 不知道自己在表格、grid 或 dialog 中。
|
||||
- 只服務單一 domain 的元件放在 domain/feature 目錄,不放進 `base`。
|
||||
|
||||
## 命名
|
||||
|
||||
- Page component:`PageXxx.vue`
|
||||
- Section component:`SectionXxx.vue`
|
||||
- Item component:`ItemXxx.vue`
|
||||
- Layout component:依 shell/區塊命名,例如 `MainLayout.vue`
|
||||
@@ -1,337 +0,0 @@
|
||||
# PageIndex 規格表
|
||||
|
||||
來源元件:`src/components/PageIndex.vue`
|
||||
|
||||
`PageIndex` 是首頁主畫面展示元件,負責組合歡迎區、最新消息、訊息中心入口、快速存取與最新消息 dialog。元件本身不直接呼叫後端 API;所有資料都透過 props 傳入,互動則透過 emit 交給外層 view 處理。
|
||||
|
||||
目前使用位置:`src/views/Home.vue`
|
||||
|
||||
## 功能總覽
|
||||
|
||||
| 功能區塊 | 功能說明 | 主要輸入 | 主要輸出事件 | 需要後端 API |
|
||||
|---|---|---|---|---|
|
||||
| 歡迎區 | 顯示固定歡迎文字與操作提示。 | 無 | 無 | 否,目前為靜態文案。 |
|
||||
| 最新消息列表 | 以 `v-data-iterator` 顯示消息清單,包含日期、月份、標題、NEW 標籤、摘要、單位與瀏覽次數。 | `newsItems` | `news(item)` | 一般需要;現況由 `Home.vue` 靜態陣列提供。 |
|
||||
| 最新消息詳情 dialog | 顯示被選取消息的標題、日期、單位、瀏覽次數與內容。開關狀態由外層控制。 | `selectedNews`, `isNewsDialogOpen` | `update:isNewsDialogOpen` | 視需求;若列表已含完整內容可不另打詳情 API,若需完整內文或附件則建議補 API。 |
|
||||
| 訊息中心入口 | 顯示訊息中心卡片與未讀文字,點擊後通知外層開啟訊息中心。 | 無 | `message-center` | 一般需要;現況文字 `12 筆未讀` 為靜態內容,點擊後只開啟共用 dialog。 |
|
||||
| 快速存取 | 顯示常用操作入口卡片。 | `quickItems` | `quick(item)` | 視需求;現況由 `Home.vue` 靜態陣列提供,點擊只顯示 snackbar。 |
|
||||
|
||||
## 現況資料來源
|
||||
|
||||
| 資料 | 目前來源 | 說明 | 後端需求 |
|
||||
|---|---|---|---|
|
||||
| `newsItems` | `src/views/Home.vue` 靜態陣列 | 包含 3 筆示意最新消息。 | 現況否;正式系統通常需要。 |
|
||||
| `quickItems` | `src/views/Home.vue` 靜態陣列 | 包含線上加選、線上退選、成績查詢、個人課表、網路請假、場地借用。 | 視需求。 |
|
||||
| `selectedNews` | `src/views/Home.vue` 本機 `ref` | 點擊消息後設定。 | 否。 |
|
||||
| `isNewsDialogOpen` | `src/views/Home.vue` 本機 `ref` | 控制消息 dialog 開關。 | 否。 |
|
||||
| 訊息中心開關 | `src/stores/messages.ts` | store 只管理 dialog 開關狀態,不包含訊息資料。 | 否,但訊息內容正式化時需要。 |
|
||||
| 訊息中心未讀文字 | `PageIndex.vue` 靜態文案 | 固定顯示 `12 筆未讀`。 | 正式系統建議需要。 |
|
||||
|
||||
## 一般建議補齊的 API 配合清單
|
||||
|
||||
這份清單是以一般後台首頁實作來看,列出 `PageIndex` 常見會需要後端配合的資料。現況沒有任何 API 直接供應 `PageIndex`;所有資料都是外層靜態資料或本機狀態。
|
||||
|
||||
| 類別 | 建議 API | 對應首頁功能 | 必要性 | 說明 |
|
||||
|---|---|---|---|---|
|
||||
| 最新消息列表 | `Announcement/GetLatest` 或 `News/GetLatest` | 最新消息列表 `newsItems` | 建議 | 回傳首頁要顯示的最新消息,通常需支援發布狀態、排序、置頂、有效日期與使用者可見範圍。 |
|
||||
| 最新消息詳情 | `Announcement/GetDetail` 或 `News/GetDetail` | 最新消息詳情 dialog | 視需求 | 若列表只回摘要,點擊後應用 detail API 取得完整內容、附件、連結或已讀狀態。 |
|
||||
| 消息瀏覽次數 | `Announcement/AddView` 或由 detail API 自動累計 | `views` 顯示 | 視需求 | 若瀏覽次數要準確,通常由後端統計;目前 `views` 是靜態文字。 |
|
||||
| 訊息未讀數 | `Message/GetUnreadCount` 或 `Notification/GetUnreadCounts` | 訊息中心入口未讀文字 | 建議 | 首頁卡片與 layout toolbar badge 可共用同一份未讀數 API。 |
|
||||
| 訊息清單 | `Message/GetMessages` | 訊息中心 dialog | 建議 | 點擊首頁訊息中心後應取得訊息列表;現況只開啟共用 dialog,訊息內容在 `App.vue` 仍是示意資料。 |
|
||||
| 訊息已讀 | `Message/MarkAsRead`, `Message/MarkAllAsRead` | 訊息中心互動與未讀數歸零 | 視需求 | 若訊息中心有未讀狀態,通常需要已讀更新 API。 |
|
||||
| 快速存取查詢 | `Shortcut/GetHomeShortcuts` 或 `Menu/GetQuickAccess` | 快速存取 `quickItems` | 視需求 | 若快速存取要依角色、權限或個人偏好變動,應由後端或既有選單資料推導。 |
|
||||
| 快速存取維護 | `Shortcut/SaveHomeShortcuts`, `Shortcut/UpdateOrder` | 自訂首頁快捷入口 | 可選 | 只有開放使用者自訂首頁快捷時才需要。 |
|
||||
| 快速存取導頁 | 可沿用 `Menu/GetMenu` 回傳路徑 | 快速存取點擊後導頁 | 建議 | 現況 `quickItems` 沒有 path,點擊只顯示 snackbar;正式系統應提供可導頁資訊。 |
|
||||
| 首頁統計摘要 | `Dashboard/GetSummary` | 未來若加入待辦、申請、課程、公告統計卡片 | 可選 | 目前 `PageIndex` 沒有統計卡片;只有產品需要首頁 dashboard 時才補。 |
|
||||
|
||||
## API 優先順序建議
|
||||
|
||||
| 優先順序 | API / 功能 | 建議理由 |
|
||||
|---|---|---|
|
||||
| 1 | `Announcement/GetLatest` | 最新消息是首頁主要內容,正式系統不應長期使用靜態資料。 |
|
||||
| 2 | `Message/GetUnreadCount` 或共用 `Notification/GetUnreadCounts` | 首頁訊息中心入口目前有固定未讀數,需改為真實資料。 |
|
||||
| 3 | `Message/GetMessages` | 點擊訊息中心後應顯示真實訊息清單。 |
|
||||
| 4 | 快速存取 path / 導頁資料 | 現況快速存取無法真的導頁,只顯示 snackbar。 |
|
||||
| 5 | `Announcement/GetDetail` | 若列表資料不足以顯示完整內容,再補詳情 API。 |
|
||||
| 6 | 快速存取自訂與排序 API | 屬個人化體驗,不影響首頁基本可用性,可後續處理。 |
|
||||
|
||||
## 建議 API 回傳格式
|
||||
|
||||
以下格式是給後端製作 API 時的建議契約。若沿用現有 service 包裝,前端實際讀取位置可能是 `res.data.data`;欄位命名可配合既有後端規範調整,但資料語意應保持一致。
|
||||
|
||||
### `Announcement/GetLatest` 或 `News/GetLatest`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "113學年度第2學期加退選開始",
|
||||
"summary": "加退選時間為1月29日至2月9日止,請同學把握時間完成選課作業。",
|
||||
"departmentId": "academic",
|
||||
"departmentName": "教務處",
|
||||
"publishedAt": "2026-01-29T09:00:00+08:00",
|
||||
"views": 1234,
|
||||
"isNew": true,
|
||||
"isPinned": false
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Announcement/GetDetail` 或 `News/GetDetail`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"title": "113學年度第2學期加退選開始",
|
||||
"content": "加退選時間為1月29日至2月9日止,請同學把握時間完成選課作業。",
|
||||
"summary": "加退選時間為1月29日至2月9日止。",
|
||||
"departmentId": "academic",
|
||||
"departmentName": "教務處",
|
||||
"publishedAt": "2026-01-29T09:00:00+08:00",
|
||||
"views": 1235,
|
||||
"isNew": true,
|
||||
"attachments": [
|
||||
{
|
||||
"id": "file-1",
|
||||
"fileName": "加退選說明.pdf",
|
||||
"url": "/service/files/file-1"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"title": "前往選課系統",
|
||||
"url": "/course-add"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Announcement/AddView`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"views": 1235
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Message/GetUnreadCount`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"unreadCount": 12
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Notification/GetUnreadCounts`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"notifications": 3,
|
||||
"messages": 12
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Message/GetMessages`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": "msg-1",
|
||||
"title": "系統維護提醒",
|
||||
"summary": "系統將於週六凌晨維護。",
|
||||
"sender": "資訊中心",
|
||||
"sentAt": "2026-05-07T09:00:00+08:00",
|
||||
"isRead": false,
|
||||
"link": "/messages/msg-1"
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"unreadCount": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Message/MarkAsRead`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "已標記為已讀",
|
||||
"data": {
|
||||
"id": "msg-1",
|
||||
"isRead": true,
|
||||
"unreadCount": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Message/MarkAllAsRead`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "已全部標記為已讀",
|
||||
"data": {
|
||||
"unreadCount": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Shortcut/GetHomeShortcuts` 或 `Menu/GetQuickAccess`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": [
|
||||
{
|
||||
"id": "course-add",
|
||||
"title": "線上加選",
|
||||
"path": "/course-add",
|
||||
"icon": "mdiPlus",
|
||||
"sort": 1,
|
||||
"source": "menu"
|
||||
},
|
||||
{
|
||||
"id": "score-query",
|
||||
"title": "成績查詢",
|
||||
"path": "/score-query",
|
||||
"icon": "mdiChartBar",
|
||||
"sort": 2,
|
||||
"source": "menu"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `Shortcut/SaveHomeShortcuts`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "快捷已儲存",
|
||||
"data": [
|
||||
{
|
||||
"id": "course-add",
|
||||
"title": "線上加選",
|
||||
"path": "/course-add",
|
||||
"icon": "mdiPlus",
|
||||
"sort": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `Shortcut/UpdateOrder`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "排序已更新",
|
||||
"data": [
|
||||
{
|
||||
"id": "course-add",
|
||||
"sort": 1
|
||||
},
|
||||
{
|
||||
"id": "score-query",
|
||||
"sort": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `Dashboard/GetSummary`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"todoCount": 2,
|
||||
"pendingApplicationCount": 1,
|
||||
"todayCourseCount": 4,
|
||||
"unreadMessageCount": 12,
|
||||
"latestAnnouncementCount": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 可維持前端處理的功能
|
||||
|
||||
| 功能 | 原因 |
|
||||
|---|---|
|
||||
| 最新消息 dialog 開關 | 純 UI 狀態,使用 `selectedNews` 與 `isNewsDialogOpen` 即可。 |
|
||||
| 最新消息列表解包 `resolveNewsItem` | 只是處理 Vuetify `v-data-iterator` wrapper,不需後端配合。 |
|
||||
| 歡迎區文案 | 若各角色顯示相同文字,可維持靜態。 |
|
||||
| 快速存取卡片排版 | 展示方式屬前端 UI,不需後端參與。 |
|
||||
| 點擊快速存取後的前端導頁 | 只要資料含 path,router push 可由前端處理。 |
|
||||
|
||||
## Props 與狀態來源
|
||||
|
||||
| Prop / 狀態 | 用途 | 預設值或目前來源 | 後端需求 |
|
||||
|---|---|---|---|
|
||||
| `newsItems` | 最新消息列表資料。 | `Home.vue` 靜態陣列。 | 正式系統建議來自最新消息 API。 |
|
||||
| `quickItems` | 快速存取卡片資料。 | `Home.vue` 靜態陣列。 | 視需求,可由選單、權限或快捷 API 提供。 |
|
||||
| `selectedNews` | 最新消息 dialog 顯示的目前消息。 | `Home.vue` 點擊消息後設定。 | 否。 |
|
||||
| `isNewsDialogOpen` | 最新消息 dialog 開關。 | `Home.vue` 本機 `ref`。 | 否。 |
|
||||
|
||||
## 建議資料結構
|
||||
|
||||
### 最新消息 `NewsItem`
|
||||
|
||||
| 欄位 | 型別 | 用途 | API 建議 |
|
||||
|---|---|---|---|
|
||||
| `id` | `number` | 列表 key 與詳情查詢識別。 | 後端提供。 |
|
||||
| `date` | `string` | 日期 badge 的日期。 | 可由後端直接提供,或前端由發布日期格式化。 |
|
||||
| `month` | `string` | 日期 badge 的月份。 | 可由後端直接提供,或前端由發布日期格式化。 |
|
||||
| `title` | `string` | 消息標題。 | 後端提供。 |
|
||||
| `desc` | `string` | 消息摘要或內容。 | 列表 API 可回摘要;詳情 API 可回完整內容。 |
|
||||
| `dept` | `string` | 發布單位。 | 後端提供。 |
|
||||
| `views` | `string` | 瀏覽次數顯示文字。 | 建議後端回 number,前端格式化。 |
|
||||
| `isNew` | `boolean` | 是否顯示 NEW 標籤。 | 可由後端提供,或前端依發布日期推導。 |
|
||||
|
||||
### 快速存取 `QuickItem`
|
||||
|
||||
| 欄位 | 型別 | 用途 | API 建議 |
|
||||
|---|---|---|---|
|
||||
| `icon` | `string` | 卡片圖示文字。 | 若正式使用 MDI icon,建議改為 icon key 或路徑。 |
|
||||
| `title` | `string` | 卡片標題。 | 後端或前端設定提供。 |
|
||||
| `path` | `string` | 目前型別尚未定義;正式導頁建議補上。 | 建議由後端或 `Menu/GetMenu` 對應功能提供。 |
|
||||
|
||||
## 事件契約
|
||||
|
||||
| 事件 | 觸發時機 | 外層目前處理 |
|
||||
|---|---|---|
|
||||
| `news(item)` | 點擊最新消息卡片。 | `Home.vue` 設定 `selectedNews` 並開啟 dialog。 |
|
||||
| `message-center` | 點擊訊息中心卡片。 | `Home.vue` 呼叫 `messageStore.open()`。 |
|
||||
| `quick(item)` | 點擊快速存取卡片。 | `Home.vue` 顯示 snackbar:`前往:${item.title}`。 |
|
||||
| `update:isNewsDialogOpen(value)` | dialog 開關狀態變更或點擊關閉。 | `Home.vue` 寫回 `isNewsDialogOpen`。 |
|
||||
@@ -0,0 +1,22 @@
|
||||
# Layouts Guide
|
||||
|
||||
`components/layouts` 是 app shell layout。一般功能需求不應修改這裡。
|
||||
|
||||
## MainLayout 責任
|
||||
|
||||
- drawer
|
||||
- app bar
|
||||
- breadcrumb
|
||||
- favorites
|
||||
- toolbar actions
|
||||
- 主內容 slot
|
||||
|
||||
## 禁止放入
|
||||
|
||||
- 頁面專屬業務流程
|
||||
- 查詢條件、表單、列表、CRUD
|
||||
- 特定 dialog 內容
|
||||
- API 呼叫
|
||||
- domain-specific 狀態
|
||||
|
||||
如果頁面要影響 breadcrumb、favorites、menu 或 toolbar,優先使用 route meta、store 或 `shell/AppShell.vue` 已提供的 props/events。
|
||||
@@ -1,430 +0,0 @@
|
||||
# MainLayout 規格表
|
||||
|
||||
來源元件:`src/components/layouts/MainLayout.vue`
|
||||
|
||||
`MainLayout` 是預設後台版型的 app shell,負責組合側邊選單、頂部工具列、常用功能列、breadcrumb、內容區與輔助視窗。元件本身不直接呼叫後端 API;所有資料都透過 props 傳入,互動則透過 emit 交給外層處理。
|
||||
|
||||
## 功能總覽
|
||||
|
||||
| 功能區塊 | 功能說明 | 主要輸入 | 主要輸出事件 | 需要後端 API |
|
||||
|---|---|---|---|---|
|
||||
| 系統品牌區 | 顯示系統標題、副標題,或由 `title` slot 覆蓋。 | `systemTitle`, `systemSubtitle`, `title` slot | 無 | 否,目前為 props/default。 |
|
||||
| 使用者資訊 | 顯示使用者頭像文字、姓名、角色。可用 feature toggle 關閉。 | `userProfile`, `features.showUserInfo` | 無 | 否,目前為 props/default。 |
|
||||
| 側邊選單 | 桌面版顯示多層 drawer menu;支援展開群組、收合 rail、選單項目導頁。 | `menuItems`, `isRail`, `drawerConfig` | `select`, `toggle-sidebar`, `update:isRail` | 是,`menuItems` 目前由 `GetMenu` 取得後轉換。 |
|
||||
| 行動版選單 | 行動版 drawer 使用階層式選單面板,點擊有子層項目會進入下一層,點擊葉節點會選取並關閉 drawer。 | `menuItems`, Vuetify display 狀態 | `select`, `toggle-sidebar` | 是,資料同 `menuItems`,目前由 `GetMenu` 取得後轉換。 |
|
||||
| 行動版階層導覽 | 在 drawer 上方顯示「主選單」與目前進入的選單層級,可返回任一層。 | `menuItems` 衍生出的 `mobileMenuLevels` | 無 | 是,層級內容間接來自 `GetMenu`。 |
|
||||
| 常用功能列 | 桌面版顯示常用功能 chip,可選取、移除,也可顯示新增按鈕。 | `favoriteItems`, `favoritesConfig`, `favoritesBarVisible`, `features.showFavorites` | `select`, `add-favorite`, `remove-favorite`, `update:favoritesBarVisible` | 否,目前不是由後端提供;`GetFavorite` 已有 service/store 方法但登入流程中未啟用。 |
|
||||
| 行動版常用功能 | 行動版 drawer 可切換到常用功能面板並選取項目。 | `favoriteItems`, `features.showFavorites` | `select` | 否,目前不是由後端提供。 |
|
||||
| 搜尋列 | 輸入關鍵字後,按 Enter 或按鈕才觸發搜尋;觸發後清空輸入。 | `searchConfig`, `features.showSearch` | `search` | 否,`MainLayout` 只送出關鍵字;目前外層用已載入的選單做前端比對。 |
|
||||
| 工具列通知 | 顯示通知按鈕與 badge 數量。 | `toolbarActions.notificationsLabel`, `toolbarCounts.notifications` | `action('notifications')` | 否,目前只是按鈕與 props 數字。 |
|
||||
| 工具列訊息 | 顯示訊息按鈕與 badge 數量。 | `toolbarActions.messagesLabel`, `toolbarCounts.messages` | `action('messages')` | 否,目前外層開啟示意訊息 dialog,沒有 API。 |
|
||||
| 工具列設定 | 顯示設定 menu,可切換常用功能列與 breadcrumb 顯示狀態。 | `showFavoritesBar`, `breadcrumbBarVisible` | `update:favoritesBarVisible`, `update:breadcrumbBarVisible` | 否,屬本機 UI 狀態。 |
|
||||
| 登出 | 顯示登出按鈕,點擊後交由外層處理。 | `logoutLabel` | `logout` | 否,layout 本身不呼叫 API。 |
|
||||
| 主題切換 | feature 開啟時顯示主題切換按鈕,透過 `useThemeToggle` 切換 Vuetify theme。 | `features.showThemeToggle`, `themeToggleLabel` | `toggle-theme` | 否,本機 theme 狀態。 |
|
||||
| Breadcrumb | 桌面版顯示目前頁面路徑;未傳入項目時顯示預設首頁。可插入 `breadcrumb-actions` slot。 | `breadcrumbItems`, `breadcrumbConfig`, `breadcrumbBarVisible`, `features.showBreadcrumb` | `update:breadcrumbBarVisible`, `update:favoritesBarVisible` | 否,目前由外層依路由與已載入選單推導。 |
|
||||
| 內容區 | 以 `slot` 承載各頁面內容,並依 app bar 高度動態設定 `v-main` padding。 | default slot | 無 | 否。 |
|
||||
| 操作說明浮窗 | 收到 `help` action 時顯示暫時說明內容,可關閉。 | `toolbarActions.helpLabel` | `action('help')` | 否,目前內容為靜態文字,且 help 按鈕在子元件中未顯示。 |
|
||||
|
||||
## 後端 API 需求
|
||||
|
||||
| API | 目前狀態 | 呼叫位置 | 提供給 `MainLayout` 的資料 | Request | Response 對應 |
|
||||
|---|---|---|---|---|---|
|
||||
| `Menu/GetMenu` | 已啟用 | `src/views/Login.vue` 登入成功後呼叫 `menuStore.getMenu(authStore.user?.id ?? '')` | `menuItems` | `{ userID: string }` | `res.data.data` 存入 `menuStore.menu`,再由 `toLayoutMenuItems()` 轉成 layout 選單。 |
|
||||
| `Menu/GetFavorite` | 未啟用 | service/store 已存在,但登入流程呼叫被註解 | 無 | `{ userID: string }` | 若未來啟用,可轉成 `favoriteItems`;目前不列為後端需求。 |
|
||||
|
||||
## 一般建議補齊的 API 配合清單
|
||||
|
||||
這份清單是以一般後台系統實作來看,列出 `MainLayout` 常見會需要後端配合的資料。現況仍只有 `Menu/GetMenu` 已接上;其餘項目可依產品需求決定是否實作。
|
||||
|
||||
| 類別 | 建議 API | 對應 layout 功能 | 必要性 | 說明 |
|
||||
|---|---|---|---|---|
|
||||
| 選單與權限 | `Menu/GetMenu` | 側邊選單、行動版選單、前端選單搜尋、breadcrumb 推導 | 必要,已啟用 | 依使用者、角色、權限回傳可用功能。 |
|
||||
| 使用者資訊 | `User/GetCurrentUser` 或 `User/GetProfile` | 使用者資訊區 `userProfile` | 建議 | 回傳姓名、角色、單位、頭像文字或頭像 URL。現況使用 default props。 |
|
||||
| 常用功能查詢 | `Menu/GetFavorite` 或 `Favorite/GetFavorites` | 常用功能列、行動版常用功能 | 建議 | 若常用功能要跨裝置保存,就應由後端提供。現況 service/store 已有 `Menu/GetFavorite`,但登入流程未啟用。 |
|
||||
| 常用功能維護 | `Favorite/AddFavorite`, `Favorite/RemoveFavorite`, `Favorite/UpdateFavoriteOrder` | 新增常用、移除常用、常用排序 | 建議 | 現況常用功能主要由前端本機 store 處理;若要保存到帳號需補 API。 |
|
||||
| 未讀數量 | `Notification/GetUnreadCounts` | 通知 badge、訊息 badge `toolbarCounts` | 建議 | 可一次回傳 `{ notifications, messages }`,避免 layout 分別打多支 API。現況預設皆為 `0`。 |
|
||||
| 通知清單 | `Notification/GetNotifications` | 通知按鈕點擊後的通知列表 | 視需求 | 目前 layout 只 emit `action('notifications')`,外層尚未實作通知 UI。 |
|
||||
| 通知已讀 | `Notification/MarkAsRead`, `Notification/MarkAllAsRead` | 通知清單互動、badge 歸零 | 視需求 | 若有通知列表,通常需要搭配已讀狀態更新。 |
|
||||
| 訊息清單 | `Message/GetMessages` | 訊息按鈕點擊後的訊息 dialog | 建議 | 現況 `App.vue` 使用示意資料,不含 API。 |
|
||||
| 訊息已讀 | `Message/MarkAsRead`, `Message/MarkAllAsRead` | 訊息清單互動、badge 歸零 | 視需求 | 若訊息中心要顯示未讀數,通常需要已讀 API。 |
|
||||
| 搜尋 | `Search/SearchMenu` 或 `Search/GlobalSearch` | 搜尋列 | 視需求 | 只搜尋目前已載入選單可維持前端搜尋;若要搜尋公告、頁面、業務資料或權限內功能,應補後端搜尋 API。 |
|
||||
| 登出 | `Auth/Logout` 或 `Auth/RevokeToken` | 登出按鈕 | 視認證架構 | 若後端有 session、refresh token 或 token revoke 機制,需要呼叫後端;若只是清 local token,可維持前端處理。 |
|
||||
| 使用者偏好 | `UserPreference/GetLayoutSettings`, `UserPreference/SaveLayoutSettings` | 側欄收合、常用列顯示、breadcrumb 顯示、主題 | 可選 | 目前可用 localStorage/store 處理;只有需要跨裝置同步時才需要 API。 |
|
||||
| 操作說明 | `Help/GetPageHelp` 或 CMS API | 操作說明浮窗 | 可選 | 現況為靜態暫時文字,且 help 按鈕未顯示;若說明內容需依頁面、角色或版本管理才需要 API。 |
|
||||
|
||||
## API 優先順序建議
|
||||
|
||||
| 優先順序 | API / 功能 | 建議理由 |
|
||||
|---|---|---|
|
||||
| 1 | `Menu/GetMenu` | layout 最核心資料,決定使用者可見功能與導頁入口。 |
|
||||
| 2 | `User/GetCurrentUser` | 使用者資訊區不應長期使用假資料,且常被其他功能共用。 |
|
||||
| 3 | `Favorite/GetFavorites` 與常用功能維護 API | 常用功能若要符合使用者帳號體驗,需要後端保存。 |
|
||||
| 4 | `Notification/GetUnreadCounts` / `Message/GetMessages` | toolbar badge 與訊息中心目前是 demo 狀態,若要上線需補。 |
|
||||
| 5 | `Search/GlobalSearch` | 只有當搜尋範圍超過目前選單時才需要。 |
|
||||
| 6 | `UserPreference` 類 API | 屬體驗同步,不影響核心操作,可最後處理。 |
|
||||
|
||||
## 建議 API 回傳格式
|
||||
|
||||
以下格式是給後端製作 API 時的建議契約。若沿用現有 service 包裝,前端實際讀取位置可能是 `res.data.data`;欄位命名可配合既有後端規範調整,但資料語意應保持一致。
|
||||
|
||||
### `Menu/GetMenu`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": [
|
||||
{
|
||||
"mdl_id": "student",
|
||||
"mdl_name": "學生資訊",
|
||||
"children": [
|
||||
{
|
||||
"unt_id": "course",
|
||||
"unt_name": "選課作業",
|
||||
"children": [
|
||||
{
|
||||
"fnc_id": "course-add",
|
||||
"fnc_name": "線上加選"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `User/GetCurrentUser` 或 `User/GetProfile`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"id": "A123456789",
|
||||
"name": "王小明",
|
||||
"role": "資訊工程系 - 學生",
|
||||
"avatarText": "王",
|
||||
"departmentId": "CS",
|
||||
"departmentName": "資訊工程系"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Menu/GetFavorite` 或 `Favorite/GetFavorites`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": [
|
||||
{
|
||||
"id": "fav-1",
|
||||
"title": "線上加選",
|
||||
"path": "/course-add",
|
||||
"icon": "mdiPlus",
|
||||
"sort": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `Favorite/AddFavorite`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "新增成功",
|
||||
"data": {
|
||||
"id": "fav-1",
|
||||
"title": "線上加選",
|
||||
"path": "/course-add",
|
||||
"icon": "mdiPlus",
|
||||
"sort": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Favorite/RemoveFavorite`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "移除成功",
|
||||
"data": {
|
||||
"id": "fav-1",
|
||||
"path": "/course-add"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Favorite/UpdateFavoriteOrder`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "排序已更新",
|
||||
"data": [
|
||||
{
|
||||
"id": "fav-1",
|
||||
"path": "/course-add",
|
||||
"sort": 1
|
||||
},
|
||||
{
|
||||
"id": "fav-2",
|
||||
"path": "/score-query",
|
||||
"sort": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `Notification/GetUnreadCounts`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"notifications": 3,
|
||||
"messages": 12
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Notification/GetNotifications`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": "notice-1",
|
||||
"title": "系統維護提醒",
|
||||
"content": "系統將於週六凌晨維護。",
|
||||
"source": "資訊中心",
|
||||
"publishedAt": "2026-05-07T09:00:00+08:00",
|
||||
"isRead": false,
|
||||
"link": "/announcements/notice-1"
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"unreadCount": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Notification/MarkAsRead`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "已標記為已讀",
|
||||
"data": {
|
||||
"id": "notice-1",
|
||||
"isRead": true,
|
||||
"unreadCount": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Notification/MarkAllAsRead`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "已全部標記為已讀",
|
||||
"data": {
|
||||
"unreadCount": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Message/GetMessages`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": "msg-1",
|
||||
"title": "教務處公告",
|
||||
"summary": "加退選時間即將開始。",
|
||||
"sender": "教務處",
|
||||
"sentAt": "2026-05-07T10:30:00+08:00",
|
||||
"isRead": false,
|
||||
"link": "/messages/msg-1"
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"unreadCount": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Message/MarkAsRead`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "已標記為已讀",
|
||||
"data": {
|
||||
"id": "msg-1",
|
||||
"isRead": true,
|
||||
"unreadCount": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Message/MarkAllAsRead`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "已全部標記為已讀",
|
||||
"data": {
|
||||
"unreadCount": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Search/SearchMenu` 或 `Search/GlobalSearch`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"id": "course-add",
|
||||
"type": "menu",
|
||||
"title": "線上加選",
|
||||
"path": "/course-add",
|
||||
"parents": ["學生資訊", "選課作業"],
|
||||
"icon": "mdiPlus"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Auth/Logout` 或 `Auth/RevokeToken`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "登出成功",
|
||||
"data": {
|
||||
"revoked": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `UserPreference/GetLayoutSettings`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"isRail": false,
|
||||
"favoritesBarVisible": true,
|
||||
"breadcrumbBarVisible": true,
|
||||
"themeName": "light"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `UserPreference/SaveLayoutSettings`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "設定已儲存",
|
||||
"data": {
|
||||
"isRail": false,
|
||||
"favoritesBarVisible": true,
|
||||
"breadcrumbBarVisible": true,
|
||||
"themeName": "light",
|
||||
"updatedAt": "2026-05-07T10:30:00+08:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `Help/GetPageHelp`
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {
|
||||
"pageKey": "home",
|
||||
"title": "操作說明",
|
||||
"content": "這裡顯示目前頁面的操作說明。",
|
||||
"updatedAt": "2026-05-07T10:30:00+08:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 可維持前端處理的功能
|
||||
|
||||
| 功能 | 原因 |
|
||||
|---|---|
|
||||
| Breadcrumb 顯示與路徑推導 | 可由目前 route、`menuItems`、`favoriteItems` 推導,不一定要後端提供。 |
|
||||
| 側欄收合狀態 | 屬使用者介面偏好,localStorage 即可;除非要求跨裝置同步。 |
|
||||
| 常用列顯示 / breadcrumb 顯示 | 屬畫面偏好,localStorage/store 即可。 |
|
||||
| 主題切換 | 本機 theme 狀態即可;除非要求登入後跨裝置一致。 |
|
||||
| 前端選單搜尋 | 若搜尋範圍只限已載入的 `menuItems`,不需要後端 API。 |
|
||||
|
||||
## `GetMenu` 欄位轉換
|
||||
|
||||
| 後端節點層級 | 後端欄位 | Layout 欄位 | 說明 |
|
||||
|---|---|---|---|
|
||||
| 模組層 | `mdl_name` | `title` | 第一層選單標題。 |
|
||||
| 模組層 | `children` | `subItems` | 第二層單元清單。 |
|
||||
| 單元層 | `unt_name` | `title` | 第二層選單標題。 |
|
||||
| 單元層 | `children` | `subItems` | 第三層功能清單。 |
|
||||
| 功能層 | `fnc_name` | `title` | 葉節點功能名稱。 |
|
||||
| 功能層 | `fnc_id` | `path` | 有值時轉成 `/${fnc_id}`,作為 router path。 |
|
||||
| 模組層與單元層 | 無 | `navigable: false` | 群組節點預設不可導頁。 |
|
||||
|
||||
## Props 與狀態來源
|
||||
|
||||
| Prop / 狀態 | 用途 | 預設值或目前來源 | 後端需求 |
|
||||
|---|---|---|---|
|
||||
| `menuItems` | 桌面與行動版主選單。 | `App.vue` 使用 `menuStore.menuItems` 加上固定選單合併後傳入。 | 是,來自 `GetMenu`。 |
|
||||
| `favoriteItems` | 常用功能列與行動版常用面板。 | `App.vue` 合併 `menuStore.favoriteItems` 與 `favoritesStore.layoutItems`;目前 `GetFavorite` 未啟用。 | 否。 |
|
||||
| `breadcrumbItems` | Breadcrumb 顯示。 | `breadcrumbStore` 依 route、`menuItems`、`favoriteItems` 推導。 | 否。 |
|
||||
| `userProfile` | 使用者資訊區。 | `MainLayout` default props。 | 否。 |
|
||||
| `toolbarCounts` | 通知、訊息 badge。 | `MainLayout` default props,預設皆為 `0`。 | 否。 |
|
||||
| `searchConfig` | 搜尋 placeholder 與 label。 | `MainLayout` default props。 | 否。 |
|
||||
| `toolbarActions` | 通知、訊息、說明、設定 label。 | `MainLayout` default props。 | 否。 |
|
||||
| `favoritesConfig` | 常用列 label、新增按鈕 label、是否顯示新增。 | `MainLayout` default props。 | 否。 |
|
||||
| `breadcrumbConfig` | 首頁 breadcrumb label、disabled、icon。 | `MainLayout` default props。 | 否。 |
|
||||
| `features` | 控制主題切換、常用列、breadcrumb、搜尋、工具列、使用者資訊是否顯示。 | `MainLayout` default props。 | 否。 |
|
||||
| `drawerConfig` | drawer 寬度與 rail 寬度。 | `MainLayout` default props。 | 否。 |
|
||||
| `isRail` | 桌面側欄是否收合。 | `App.vue` 以 `v-model:is-rail` 綁定 `menuStore.isRail`,store 會寫入 localStorage。 | 否。 |
|
||||
| `favoritesBarVisible` | 常用功能列是否顯示。 | `App.vue` 以 `v-model:favorites-bar-visible` 綁定 `favoritesStore`。 | 否。 |
|
||||
| `breadcrumbBarVisible` | Breadcrumb 是否顯示。 | `App.vue` 以 `v-model:breadcrumb-bar-visible` 綁定 `favoritesStore`。 | 否。 |
|
||||
|
||||
## 事件契約
|
||||
|
||||
| 事件 | 觸發時機 | 外層目前處理 |
|
||||
|---|---|---|
|
||||
| `select(item)` | 選取側邊選單、常用功能或搜尋結果延伸選取時。 | `App.vue` 呼叫 `router.push(item.path)`。 |
|
||||
| `search(keyword)` | 搜尋列按 Enter 或搜尋按鈕。 | `App.vue` 以已載入的合併選單做前端搜尋並顯示 dialog。 |
|
||||
| `action(type)` | 點擊通知、訊息、說明等工具列 action。 | `messages` 會開啟訊息 dialog;其他目前無處理。 |
|
||||
| `logout` | 點擊登出按鈕。 | `App.vue` 清除 auth、tabs,導回 login。 |
|
||||
| `toggle-sidebar(payload)` | 點擊 drawer 收合/展開按鈕。 | 目前外層未綁定。 |
|
||||
| `toggle-theme(themeName)` | 切換主題成功。 | 目前外層未綁定。 |
|
||||
| `add-favorite` | 點擊常用功能新增按鈕。 | 目前外層未綁定。 |
|
||||
| `remove-favorite(item)` | 點擊常用 chip close。 | `App.vue` 從本機常用清單切換移除。 |
|
||||
| `update:isRail(value)` | 受控模式下更新側欄 rail 狀態。 | `v-model:is-rail` 寫回 `menuStore.isRail`。 |
|
||||
| `update:favoritesBarVisible(value)` | 更新常用列顯示狀態。 | `v-model:favorites-bar-visible` 寫回 `favoritesStore`。 |
|
||||
| `update:breadcrumbBarVisible(value)` | 更新 breadcrumb 顯示狀態。 | `v-model:breadcrumb-bar-visible` 寫回 `favoritesStore`。 |
|
||||
@@ -0,0 +1,39 @@
|
||||
# Composables Guide
|
||||
|
||||
`composables` 放可重用流程、page driver、command flow 與較複雜 UI state。簡單模板顯示不要為了形式新增 composable。
|
||||
|
||||
## 子目錄
|
||||
|
||||
- `page-drivers/`:頁面資料協調與 page model 組裝。
|
||||
- `commands/`:命令式副作用流程,例如 create/edit/save/delete。
|
||||
- `layout/`:AppShell / layout 狀態與事件協調。
|
||||
- `maint/`:maintenance demo 的表單、CRUD、editable grid 狀態。
|
||||
|
||||
## 新增規則
|
||||
|
||||
- 用 `useXxx.ts` 命名。
|
||||
- 參數較多時使用 options object。
|
||||
- source state 盡量集中,衍生值用 `computed`。
|
||||
- 副作用放在明確 action 或 watcher,不放在 computed。
|
||||
- 不 import component 或 view。
|
||||
- 不持有 service module 的底層 HTTP 細節。
|
||||
|
||||
## Page Driver
|
||||
|
||||
Page driver 負責:
|
||||
|
||||
- route param/query 轉成頁面資料
|
||||
- 組裝 page model
|
||||
- 組裝 page component 需要的 props/events
|
||||
- 協調 store、command composable、表單 composable
|
||||
|
||||
View 只呼叫 page driver 並掛載 page component。
|
||||
|
||||
## Commands
|
||||
|
||||
Command composable 負責副作用流程,不負責畫面布局:
|
||||
|
||||
- 新增 / 編輯 / 刪除 / 儲存
|
||||
- 儲存前確認
|
||||
- 成功後重新載入或 highlight
|
||||
- 與 store/service 的 mutation 流程
|
||||
@@ -0,0 +1,10 @@
|
||||
# Language Guide
|
||||
|
||||
`language` 放 Vue I18n 文案。新增可見 UI 文案時,若該文字屬於產品功能或會被重用,優先放進語系檔。
|
||||
|
||||
## 規則
|
||||
|
||||
- 同步維護 `zh-TW.json` 與 `en-US.json`。
|
||||
- key 命名以 feature/domain 分組。
|
||||
- 移除 demo 頁或 feature 時,同步清理不再使用的文案。
|
||||
- 不把大型靜態資料塞進語系檔;語系檔只放文案。
|
||||
@@ -0,0 +1,31 @@
|
||||
# Router Guide
|
||||
|
||||
`router` 集中管理 route、layout meta、auth meta 與 navigation guard。
|
||||
|
||||
## routes.ts
|
||||
|
||||
新增 route 時包含:
|
||||
|
||||
- `path`
|
||||
- `name`
|
||||
- `component`
|
||||
- `meta.layout`
|
||||
|
||||
一般頁面使用:
|
||||
|
||||
```ts
|
||||
meta: { layout: 'default' }
|
||||
```
|
||||
|
||||
只有登入頁、錯誤頁、維護中頁或明確要求獨立頁面時使用:
|
||||
|
||||
```ts
|
||||
meta: { layout: 'none' }
|
||||
```
|
||||
|
||||
## Guards
|
||||
|
||||
- 登入需求使用既有 `requiresAuth` meta。
|
||||
- 訪客專用頁使用既有 `guestOnly` meta。
|
||||
- guard 流程放在 `guards.ts`,不要散落在 view/component。
|
||||
- catch-all route 保持在最後。
|
||||
@@ -0,0 +1,26 @@
|
||||
# Services Guide
|
||||
|
||||
`services` 是 HTTP 與外部 API 邊界。service 回傳資料,不持有 UI 狀態。
|
||||
|
||||
## 資料流
|
||||
|
||||
```txt
|
||||
component/view -> store/composable -> service module -> httpClient -> hooks
|
||||
```
|
||||
|
||||
## 規則
|
||||
|
||||
- 新 API 放在 `services/modules/<domain>.ts`。
|
||||
- 使用 `httpClient`,不要直接建立新的 ky instance。
|
||||
- 不 import component、view 或 store。
|
||||
- 不管理 loading、dialog、snackbar、AbortController lifecycle。
|
||||
- request option 可接收 `signal`。
|
||||
- 錯誤正規化交給既有 error/http hooks 流程。
|
||||
|
||||
## ky 注意事項
|
||||
|
||||
- 本專案使用 ky,不使用 axios。
|
||||
- JSON response 用 `.json<T>()`。
|
||||
- JSON payload 用 `json`,FormData 用 `body`。
|
||||
- 取消請求使用原生 `AbortController` 與 `signal`。
|
||||
- token 注入與 401 force logout 集中在 hooks,不在單一 API module 重寫。
|
||||
@@ -0,0 +1,16 @@
|
||||
# Shell Guide
|
||||
|
||||
`shell` 是 App Shell 層,負責 route layout 切換、tabs、global overlays 與 layout event wiring。一般頁面需求不應修改這裡。
|
||||
|
||||
## 檔案
|
||||
|
||||
- `AppShell.vue`:layout 切換、layout props/events、breadcrumb actions、tabs router-view、`GlobalOverlays` 掛載。
|
||||
- `AppTabs.vue`:default layout 下的 tabs 與 keep-alive router-view 容器。
|
||||
- `GlobalOverlays.vue`:全域 snackbar、搜尋 dialog、訊息 dialog。
|
||||
|
||||
## 規則
|
||||
|
||||
- 不放頁面專屬表單、表格或 CRUD 流程。
|
||||
- 不直接寫 domain-specific dialog 內容,除非是 template 全域 overlay。
|
||||
- shell 狀態協調放在 `composables/layout/useAppShell.ts`。
|
||||
- 登出、force logout、HTTP toast 等全域流程可以在 shell composable 中協調。
|
||||
@@ -0,0 +1,23 @@
|
||||
# Stores Guide
|
||||
|
||||
`stores` 使用 Pinia 管理跨頁共享狀態、快取與全域顯示狀態。單一頁面暫時 UI 狀態應留在 page driver、component 或 composable。
|
||||
|
||||
## 放進 Store 的情況
|
||||
|
||||
- auth/session
|
||||
- menu/favorites/breadcrumbs
|
||||
- snackbar/messages
|
||||
- 跨頁共享資料快取
|
||||
- 多個頁面都需要讀寫的 domain state
|
||||
|
||||
## 不放進 Store 的情況
|
||||
|
||||
- dialog visible
|
||||
- 單一頁搜尋條件
|
||||
- 單一頁分頁狀態
|
||||
- 單一表單 dirty / validation
|
||||
- 單一頁 loading/error
|
||||
|
||||
## 資料流
|
||||
|
||||
store 可以呼叫 service module。component 不應繞過 store/composable 直接處理 token、session 或 HTTP hooks。
|
||||
@@ -0,0 +1,32 @@
|
||||
# Views Guide
|
||||
|
||||
`views` 是 route entry。View 應維持薄層,負責掛載 page driver 與 page component,不承載大段 UI、dialog、表單欄位或 store mutation 細節。
|
||||
|
||||
## 規則
|
||||
|
||||
- 使用 `<script setup lang="ts">`。
|
||||
- 直接 route component 放在 `src/views` 或 `src/views/<feature>`。
|
||||
- 一般 view 目標 < 80 行。
|
||||
- route params/query 的解析可在 view 做簡單轉換;超過簡單轉換時放進 page driver。
|
||||
- 不直接 import 或包住 `MainLayout.vue`。
|
||||
- 不直接定義大型 `<v-dialog>`、`<v-overlay>`、大型表格或大型表單。
|
||||
|
||||
## 建議形狀
|
||||
|
||||
```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" />
|
||||
</template>
|
||||
```
|
||||
|
||||
## 子目錄
|
||||
|
||||
- `views/maint` 是 maintenance demo route entry。詳見 `src/views/maint/GUIDE.md`。
|
||||
- `views/errors` 是錯誤頁入口,通常使用 `meta.layout = 'none'`。
|
||||
@@ -0,0 +1,23 @@
|
||||
# Maintenance Views Guide
|
||||
|
||||
`views/maint` 是維護頁 demo。所有檔案都應是薄 route entry,實際 UI 與流程分別放在 `components/pages`、`components/sections`、`components/items` 與 `composables/page-drivers`。
|
||||
|
||||
## 目前範本
|
||||
|
||||
- `SingleRecord.vue`:單主檔 CRUD + dialog。
|
||||
- `EditableGrid.vue`:可編輯表格。
|
||||
- `MasterDetailA.vue`:主檔 + 側邊明細 panel。
|
||||
- `MasterDetailB.vue`:主檔 + collapse / full-height 明細。
|
||||
- `MasterDetailC.vue`:主檔 + 簡化明細清單。
|
||||
|
||||
## 複製規則
|
||||
|
||||
複製維護頁時同步調整:
|
||||
|
||||
- `router/routes.ts` 的 `path`、`name`、`component`、`meta.layout`
|
||||
- page driver 名稱與 import
|
||||
- page component 名稱與 import
|
||||
- 頁面標題、查詢欄位、表格欄位、form 型別、驗證規則
|
||||
- store、service、model、語系、menu/favorites/breadcrumb 相關資料
|
||||
|
||||
正式 domain 不應長期塞在 `maint`,複製後優先移到自己的 feature 目錄。
|
||||
Reference in New Issue
Block a user