232 lines
9.6 KiB
HTML
232 lines
9.6 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-TW">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>CFDive平台 - Google登入測試</title>
|
||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||
<style>
|
||
.container { max-width: 800px; margin-top: 50px; }
|
||
.card { margin-bottom: 20px; }
|
||
pre { background-color: #f8f9fa; padding: 15px; border-radius: 5px; max-height: 300px; overflow: auto; }
|
||
.btn-google { background-color: #4285F4; color: white; }
|
||
.hidden { display: none; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1 class="mb-4">CFDive平台 - Google登入測試</h1>
|
||
|
||
<!-- 登入卡片 -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
會員登入選項
|
||
</div>
|
||
<div class="card-body">
|
||
<h5 class="card-title">選擇登入方式</h5>
|
||
<p class="card-text">您可以使用以下方式登入系統:</p>
|
||
|
||
<!-- Google登入按鈕 -->
|
||
<a href="/api/auth/google/redirect" class="btn btn-google mb-3">
|
||
<i class="bi bi-google"></i> 使用Google帳號登入
|
||
</a>
|
||
|
||
<!-- 一般登入表單 -->
|
||
<div class="mt-4">
|
||
<h6>或使用電子郵件登入</h6>
|
||
<form id="loginForm" class="mt-3">
|
||
<div class="mb-3">
|
||
<label for="email" class="form-label">電子郵件</label>
|
||
<input type="email" class="form-control" id="email" required>
|
||
</div>
|
||
<div class="mb-3">
|
||
<label for="password" class="form-label">密碼</label>
|
||
<input type="password" class="form-control" id="password" required>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary">登入</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Token顯示區域 -->
|
||
<div id="tokenCard" class="card hidden">
|
||
<div class="card-header">
|
||
授權Token
|
||
</div>
|
||
<div class="card-body">
|
||
<h5 class="card-title">登入成功</h5>
|
||
<p class="card-text">您已成功登入系統,可以使用以下token進行API測試:</p>
|
||
<pre id="tokenInfo"></pre>
|
||
<button id="copyToken" class="btn btn-sm btn-secondary">複製Token</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- API測試區域 -->
|
||
<div id="apiTestCard" class="card hidden">
|
||
<div class="card-header">
|
||
API測試
|
||
</div>
|
||
<div class="card-body">
|
||
<h5 class="card-title">測試會員API</h5>
|
||
<p class="card-text">使用您的授權token測試以下API:</p>
|
||
|
||
<div class="mb-3">
|
||
<button id="getProfile" class="btn btn-info">獲取個人資料</button>
|
||
<button id="updateProfile" class="btn btn-warning">更新個人資料</button>
|
||
<button id="logout" class="btn btn-danger">登出</button>
|
||
</div>
|
||
|
||
<h6 class="mt-4">API回應結果:</h6>
|
||
<pre id="apiResponse">尚未執行API請求</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 檢查URL參數,處理登入後的回調
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 檢查URL是否包含登入成功的資訊
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
if (urlParams.has('login_success')) {
|
||
try {
|
||
// 從localStorage獲取用戶資訊
|
||
const userInfo = JSON.parse(localStorage.getItem('user_info'));
|
||
if (userInfo && userInfo.token) {
|
||
showTokenInfo(userInfo);
|
||
}
|
||
} catch (e) {
|
||
console.error('無法解析用戶資訊', e);
|
||
}
|
||
}
|
||
|
||
// 檢查URL是否包含完整的用戶資訊(從callback獲取)
|
||
const hashParams = new URLSearchParams(window.location.hash.substring(1));
|
||
if (hashParams.has('user_info')) {
|
||
try {
|
||
const userInfo = JSON.parse(decodeURIComponent(hashParams.get('user_info')));
|
||
if (userInfo && userInfo.token) {
|
||
// 儲存到localStorage以便重新整理後仍可使用
|
||
localStorage.setItem('user_info', JSON.stringify(userInfo));
|
||
showTokenInfo(userInfo);
|
||
|
||
// 清除URL中的hash,避免重新整理後重複處理
|
||
history.replaceState(null, document.title, window.location.pathname + '?login_success=true');
|
||
}
|
||
} catch (e) {
|
||
console.error('無法解析用戶資訊', e);
|
||
}
|
||
}
|
||
});
|
||
|
||
// 一般登入表單處理
|
||
document.getElementById('loginForm').addEventListener('submit', function(e) {
|
||
e.preventDefault();
|
||
|
||
const email = document.getElementById('email').value;
|
||
const password = document.getElementById('password').value;
|
||
|
||
fetch('/api/member/login', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({ email, password })
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.status && data.data && data.data.token) {
|
||
const userInfo = {
|
||
user: data.data.user,
|
||
token: data.data.token,
|
||
token_type: data.data.token_type
|
||
};
|
||
localStorage.setItem('user_info', JSON.stringify(userInfo));
|
||
showTokenInfo(userInfo);
|
||
} else {
|
||
alert('登入失敗:' + (data.message || '未知錯誤'));
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('登入錯誤', error);
|
||
alert('登入過程發生錯誤,請檢查網路連線');
|
||
});
|
||
});
|
||
|
||
// 顯示Token資訊
|
||
function showTokenInfo(userInfo) {
|
||
document.getElementById('tokenCard').classList.remove('hidden');
|
||
document.getElementById('apiTestCard').classList.remove('hidden');
|
||
|
||
const tokenInfo = document.getElementById('tokenInfo');
|
||
tokenInfo.textContent = JSON.stringify(userInfo, null, 2);
|
||
|
||
// 設定複製按鈕功能
|
||
document.getElementById('copyToken').addEventListener('click', function() {
|
||
navigator.clipboard.writeText(userInfo.token)
|
||
.then(() => alert('Token已複製到剪貼簿'))
|
||
.catch(err => console.error('複製失敗', err));
|
||
});
|
||
|
||
// 設定API測試按鈕
|
||
setupApiButtons(userInfo.token);
|
||
}
|
||
|
||
// 設定API測試按鈕
|
||
function setupApiButtons(token) {
|
||
// 獲取個人資料
|
||
document.getElementById('getProfile').addEventListener('click', function() {
|
||
callApi('/api/member/profile', 'GET', null, token);
|
||
});
|
||
|
||
// 更新個人資料
|
||
document.getElementById('updateProfile').addEventListener('click', function() {
|
||
const newName = prompt('請輸入新的姓名', '');
|
||
if (newName) {
|
||
callApi('/api/member/profile', 'PUT', { name: newName }, token);
|
||
}
|
||
});
|
||
|
||
// 登出
|
||
document.getElementById('logout').addEventListener('click', function() {
|
||
callApi('/api/member/logout', 'POST', null, token)
|
||
.then(() => {
|
||
localStorage.removeItem('user_info');
|
||
document.getElementById('tokenCard').classList.add('hidden');
|
||
document.getElementById('apiTestCard').classList.add('hidden');
|
||
alert('已成功登出');
|
||
});
|
||
});
|
||
}
|
||
|
||
// 呼叫API
|
||
function callApi(url, method, data, token) {
|
||
const headers = {
|
||
'Authorization': `Bearer ${token}`,
|
||
'Content-Type': 'application/json'
|
||
};
|
||
|
||
const options = {
|
||
method: method,
|
||
headers: headers
|
||
};
|
||
|
||
if (data && (method === 'POST' || method === 'PUT')) {
|
||
options.body = JSON.stringify(data);
|
||
}
|
||
|
||
return fetch(url, options)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
document.getElementById('apiResponse').textContent = JSON.stringify(data, null, 2);
|
||
return data;
|
||
})
|
||
.catch(error => {
|
||
console.error('API錯誤', error);
|
||
document.getElementById('apiResponse').textContent = `錯誤: ${error.message}`;
|
||
});
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|