docs: refresh template documentation and examples

Update README and frontend layering docs to reflect the current template core structure, use relative repository links, and remove outdated demo guidance.

Add expanded API response examples for common features and ignore local Codex configuration.docs: refresh template documentation and examples

Update README and frontend layering docs to reflect the current template core structure, use relative repository links, and remove outdated demo guidance.

Add expanded API response examples for common features and ignore local Codex configuration.
This commit is contained in:
skytek_xinliang
2026-05-11 15:45:31 +08:00
parent 71683482e1
commit a45563685f
8 changed files with 946 additions and 193 deletions
+337
View File
@@ -0,0 +1,337 @@
# 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`。 |
+430
View File
@@ -0,0 +1,430 @@
# 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`。 |