Files
a620906209 ad2c05779d feat:實作 Admin Panel — 平台管理後台
後端:
- AdminStatsController:總會員/教練/課程數統計 API
- AdminUserController:會員與教練列表、詳情、啟用/停用、教練驗證(toggle 反轉語意)
- AdminOfferController:全平台課程列表與刪除
- routes/api.php:新增 /api/admin/stats、members、providers、offers 等路由

前端(frontend/):
- adminAuth store、adminAxios(第三套獨立認證)
- /admin/* 路由群組 + requiresAdmin guard
- AdminNavBar、AdminLayout
- App.vue:isCoachPage → isBackofficePage(/coach/* 和 /admin/* 皆隱藏會員 NavBar)
- LoginView、DashboardView(統計卡片)
- MembersView、ProvidersView(含驗證操作)、OffersView(含刪除確認)

OpenSpec:
- 新增 specs:admin-auth / admin-user-management / admin-offer-management / admin-stats / admin-panel-ui
- 歸檔:openspec/changes/archive/2026-05-10-admin-panel

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-10 04:07:13 +08:00

81 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 1. [後端] Admin Auth — 確認現有方法可用
- [x] 1.1 `loginAdmin()` ✅ 直接可用,確認 role=admin 驗證邏輯正確
- [x] 1.2 `logoutAdmin()` ✅ 直接可用,不需改動
- [x] 1.3 `adminProfile()` ✅ 直接可用,不需改動
- [x] 1.4 用 Postman 建立測試用 admin 帳號:`docker exec cfdive-app php artisan tinker`,建立 role=admin 的 User + AdminProfile,測試 login → profile → logout
## 2. [後端] AdminStatsController
- [x] 2.1 建立 `AdminStatsController`,實作 `index()`:驗證 role=admin,查詢 `User::where('role','member')->count()``User::where('role','provider')->count()``DivingOffer::count()`,回傳統計數據
- [x] 2.2 在 `routes/api.php` 的 admin middleware group 新增 `GET /stats` 路由
## 3. [後端] AdminUserController
- [x] 3.1 建立 `AdminUserController`,宣告 private `checkAdmin()` helper(驗證 role=admin,不符回傳 403
- [x] 3.2 實作 `members(Request $request)`:搜尋 role=member 用戶(q 參數 LIKE name/email),load memberProfile,分頁 15 筆
- [x] 3.3 實作 `member(int $id)`find role=member 用戶,不存在回 404load memberProfile 後回傳
- [x] 3.4 實作 `toggleMemberActive(int $id)`find → 404,反轉 is_active,回傳新狀態與對應訊息
- [x] 3.5 實作 `providers(Request $request)`:同 members,查 role=providerload providerProfile
- [x] 3.6 實作 `provider(int $id)`:同 member,查 role=providerload providerProfile
- [x] 3.7 實作 `toggleProviderActive(int $id)`:同 toggleMemberActive,查 role=provider
- [x] 3.8 實作 `toggleProviderVerified(int $id)`find role=provider → 404,取得 providerProfile,反轉 is_verified,儲存,回傳新狀態
- [x] 3.9 在 `routes/api.php` admin group 新增路由:
- `GET /members``GET /members/{id}``PUT /members/{id}/toggle-active`
- `GET /providers``GET /providers/{id}``PUT /providers/{id}/toggle-active``PUT /providers/{id}/toggle-verified`
## 4. [後端] AdminOfferController
- [x] 4.1 建立 `AdminOfferController`,實作 `index()`:驗證 admin,搜尋所有課程(q 參數 LIKE title/location),分頁 15 筆
- [x] 4.2 實作 `destroy(int $id)`find → 404,刪除,回傳 200
- [x] 4.3 在 routes 新增 `GET /offers``DELETE /offers/{id}`
## 5. [前端] Admin 基礎設施
- [x] 5.1 建立 `frontend/src/stores/adminAuth.js`:管理 `admin_token` / `admin_user`,實作 `init()` / `setAuth()` / `logout()`
- [x] 5.2 建立 `frontend/src/api/adminAxios.js`:獨立 Axios instancerequest interceptor 讀 `admin_token`
- [x] 5.3 在 `frontend/src/router/index.js` 新增 `/admin/*` 路由:loginpublic+ dashboard / members / providers / offers / profilerequiresAdmin
- [x] 5.4 router `beforeEach` 加入 `requiresAdmin` guard,未登入導向 `/admin/login`
- [x] 5.5 在 `App.vue``onMounted` 加入 `adminAuth.init()`,並擴充 `isCoachPage``isBackofficePage`(涵蓋 `/coach/*``/admin/*`),會員 NavBar 在這兩個路徑下都不顯示
## 6. [前端] Admin Layout 與導覽
- [x] 6.1 建立 `frontend/src/components/AdminNavBar.vue`:顯示管理員姓名、「儀表板」、「會員管理」、「教練管理」、「課程管理」連結與登出按鈕
- [x] 6.2 建立 `frontend/src/layouts/AdminLayout.vue`:包含 AdminNavBar + `<RouterView>`
## 7. [前端] 管理員登入頁
- [x] 7.1 建立 `frontend/src/views/admin/LoginView.vue`email/password 表單,送出呼叫 `POST /api/admin/login`,成功存 token 至 adminAuth store 並導向 `/admin/dashboard`,失敗顯示錯誤
## 8. [前端] 儀表板
- [x] 8.1 建立 `frontend/src/views/admin/DashboardView.vue`:掛載時呼叫 `GET /api/admin/stats`,以三個數字卡片顯示總會員數、總教練數、總課程數
## 9. [前端] 會員管理頁
- [x] 9.1 建立 `frontend/src/views/admin/MembersView.vue`:掛載時呼叫 `GET /api/admin/members`,以表格顯示姓名、email、帳號狀態(啟用/停用 badge)
- [x] 9.2 新增搜尋框,輸入後按 Enter 重新呼叫 API(帶 q 參數)
- [x] 9.3 每列新增啟用/停用按鈕,呼叫 `PUT /api/admin/members/{id}/toggle-active`,成功後更新該列狀態
## 10. [前端] 教練管理頁
- [x] 10.1 建立 `frontend/src/views/admin/ProvidersView.vue`:掛載時呼叫 `GET /api/admin/providers`,顯示姓名、email、工作室名稱、驗證狀態、帳號狀態
- [x] 10.2 新增搜尋框
- [x] 10.3 每列新增啟用/停用按鈕(呼叫 toggle-active)與驗證/取消驗證按鈕(呼叫 toggle-verified),成功後更新對應欄位
## 11. [前端] 課程管理頁
- [x] 11.1 建立 `frontend/src/views/admin/OffersView.vue`:掛載時呼叫 `GET /api/admin/offers`,顯示課程標題、地點、地區、價格、provider_id
- [x] 11.2 新增搜尋框
- [x] 11.3 每列新增刪除按鈕:顯示確認 dialog,確認後呼叫 `DELETE /api/admin/offers/{id}`,成功後重新載入列表
## 12. [整合測試] 端對端驗證
- [x] 12.1 驗證管理員登入流程:tinker 建立 admin 帳號 → 登入 → 顯示 AdminNavBar → 登出
- [x] 12.2 驗證 Dashboard 統計數據正確顯示
- [x] 12.3 驗證會員管理:搜尋 → 停用 → 確認帳號無法登入 → 重新啟用
- [x] 12.4 驗證教練驗證:切換 is_verified → 確認 /coach/profile 顯示狀態更新
- [x] 12.5 驗證課程刪除:Admin 刪除課程 → 確認 /courses 列表消失
- [x] 12.6 驗證 route guard:未登入訪問 `/admin/dashboard` 自動跳轉 `/admin/login`
- [x] 12.7 驗證 `/admin/*` 路由不顯示會員 NavBar