This commit is contained in:
2025-05-11 03:45:17 +08:00
commit 3d7660a24c
70 changed files with 13635 additions and 0 deletions
+231
View File
@@ -0,0 +1,231 @@
<!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>