Files
member-platform/frontend/src/pages/AuthCallbackPage.vue
Chris c4b9789df7 Upgrade frontend to Schema V2: Admin management pages
新增功能:
- OIDC 登入流程完整實現(LoginPage → AuthCallbackPage)
- 6 個管理頁面:系統、模組、公司、站台、會員、權限群組
- 權限群組管理:群組 CRUD + 綁定會員 + 群組授權/撤銷
- 新 API 層:systems、modules、companies、sites、members、permission-groups
- admin store:統一管理公共清單資料

調整既有頁面:
- PermissionSnapshotPage:表格新增 system 欄位
- PermissionAdminPage:
  - 新增 system 必填欄位
  - scope_type 改為 company/site 下拉選單
  - module 改為選填(空值代表系統層權限)
- Router:補 6 條新管理路由
- App.vue:導覽列新增管理員群組下拉菜單

驗收條件達成:
✓ 可新增 system/module/company/site
✓ 可做用戶直接 grant/revoke(新 payload)
✓ 可建立 permission-group、加會員、群組 grant/revoke
✓ /me/permissions/snapshot 表格可顯示 system + module + action

Build:成功(0 errors)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-30 02:37:46 +08:00

74 lines
2.1 KiB
Vue
Raw 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.
<template>
<div class="flex items-center justify-center min-h-[70vh]">
<el-card class="w-full max-w-md shadow-md">
<div class="text-center">
<el-icon class="text-3xl text-blue-600 mb-3">
<Loading />
</el-icon>
<h2 class="text-lg font-bold text-gray-800 mb-2">正在登入...</h2>
<p v-if="!error" class="text-sm text-gray-500">
正在驗證身份請稍候
</p>
<p v-if="error" class="text-sm text-red-600 font-medium">
{{ error }}
</p>
</div>
</el-card>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { exchangeOidcCode } from '@/api/auth'
import { Loading } from '@element-plus/icons-vue'
const router = useRouter()
const route = useRoute()
const authStore = useAuthStore()
const error = ref('')
onMounted(async () => {
try {
const code = route.query.code
const state = route.query.state
if (!code) {
error.value = '缺少驗證代碼,登入失敗'
setTimeout(() => router.push('/login'), 2000)
return
}
const redirectUri = `${window.location.origin}/auth/callback`
const res = await exchangeOidcCode(code, redirectUri)
const { access_token } = res.data
if (!access_token) {
error.value = '無法取得 access token'
setTimeout(() => router.push('/login'), 2000)
return
}
// 存 token 並取得使用者資料
authStore.setToken(access_token)
await authStore.fetchMe()
// 導向原頁面或預設的 /me
const redirect = sessionStorage.getItem('post_login_redirect') || '/me'
sessionStorage.removeItem('post_login_redirect')
router.push(redirect)
} catch (err) {
const detail = err.response?.data?.detail
if (detail === 'invalid_authorization_code') {
error.value = '授權代碼無效,請重新登入'
} else if (detail) {
error.value = `登入失敗:${detail}`
} else {
error.value = '登入過程出錯,請重新登入'
}
setTimeout(() => router.push('/login'), 3000)
}
})
</script>