523 lines
25 KiB
HTML
523 lines
25 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平台 - 管理員與服務提供者註冊測試</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; }
|
|
.tab-content { padding: 20px; border: 1px solid #dee2e6; border-top: none; }
|
|
.form-control { margin-bottom: 15px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1 class="mb-4">CFDive平台 - 管理員與服務提供者註冊測試</h1>
|
|
|
|
<ul class="nav nav-tabs" id="userTypeTabs" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link active" id="admin-tab" data-bs-toggle="tab" data-bs-target="#admin" type="button" role="tab">管理員註冊</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="provider-tab" data-bs-toggle="tab" data-bs-target="#provider" type="button" role="tab">服務提供者註冊</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="login-tab" data-bs-toggle="tab" data-bs-target="#login" type="button" role="tab">登入</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="logout-tab" data-bs-toggle="tab" data-bs-target="#logout" type="button" role="tab">登出</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="check-user-tab" data-bs-toggle="tab" data-bs-target="#check-user" type="button" role="tab">查詢會員/教練</button>
|
|
</li>
|
|
</ul>
|
|
|
|
<div class="tab-content" id="userTypeTabContent">
|
|
<!-- 管理員註冊表單 -->
|
|
<div class="tab-pane fade show active" id="admin" role="tabpanel">
|
|
<h3>管理員註冊</h3>
|
|
<form id="adminForm">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<label for="adminName" class="form-label">姓名</label>
|
|
<input type="text" class="form-control" id="adminName" value="測試管理員" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="adminEmail" class="form-label">電子郵件</label>
|
|
<input type="email" class="form-control" id="adminEmail" value="admin@example.com" required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<label for="adminPassword" class="form-label">密碼</label>
|
|
<input type="password" class="form-control" id="adminPassword" value="Admin123!" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="adminPasswordConfirmation" class="form-label">確認密碼</label>
|
|
<input type="password" class="form-control" id="adminPasswordConfirmation" value="Admin123!" required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<label for="adminPhone" class="form-label">電話</label>
|
|
<input type="text" class="form-control" id="adminPhone" value="0912345678">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label for="adminPosition" class="form-label">職位</label>
|
|
<input type="text" class="form-control" id="adminPosition" value="系統管理員" required>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label for="adminDepartment" class="form-label">部門</label>
|
|
<input type="text" class="form-control" id="adminDepartment" value="資訊部門" required>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-primary">註冊管理員</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- 教練註冊表單 -->
|
|
<div class="tab-pane fade" id="provider" role="tabpanel">
|
|
<h3>服務提供者註冊</h3>
|
|
<form id="providerForm">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<label for="providerName" class="form-label">姓名</label>
|
|
<input type="text" class="form-control" id="providerName" value="測試服務提供者" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="providerEmail" class="form-label">電子郵件</label>
|
|
<input type="email" class="form-control" id="providerEmail" value="provider@example.com" required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<label for="providerPassword" class="form-label">密碼</label>
|
|
<input type="password" class="form-control" id="providerPassword" value="Provider123!" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="providerPasswordConfirmation" class="form-label">確認密碼</label>
|
|
<input type="password" class="form-control" id="providerPasswordConfirmation" value="Provider123!" required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<label for="providerPhone" class="form-label">電話</label>
|
|
<input type="text" class="form-control" id="providerPhone" value="0987654321">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label for="businessName" class="form-label">業者名稱</label>
|
|
<input type="text" class="form-control" id="businessName" value="藍海潛水中心" required>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label for="contactPerson" class="form-label">聯絡人</label>
|
|
<input type="text" class="form-control" id="contactPerson" value="王大師" required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<label for="contactEmail" class="form-label">聯絡電子郵件</label>
|
|
<input type="email" class="form-control" id="contactEmail" value="contact@bluedive.com">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="address" class="form-label">營業地址</label>
|
|
<input type="text" class="form-control" id="address" value="台灣屏東縣恆春鎮大路123號">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="description" class="form-label">業者描述</label>
|
|
<textarea class="form-control" id="description" rows="3" required>專業潛水中心,提供各種潛水服務、潛水行程和潛水課程</textarea>
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-success">註冊服務提供者</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- 登入表單 -->
|
|
<div class="tab-pane fade" id="login" role="tabpanel">
|
|
<h3>登入</h3>
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<select class="form-select mb-3" id="loginType">
|
|
<option value="admin">管理員</option>
|
|
<option value="provider">服務提供者</option>
|
|
<option value="member">會員</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<form id="loginForm">
|
|
<div class="mb-3">
|
|
<label for="loginEmail" class="form-label">電子郵件</label>
|
|
<input type="email" class="form-control" id="loginEmail" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="loginPassword" class="form-label">密碼</label>
|
|
<input type="password" class="form-control" id="loginPassword" required>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">登入</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- 登出測試 -->
|
|
<div class="tab-pane fade" id="logout" role="tabpanel">
|
|
<h3>登出測試</h3>
|
|
<div class="mb-3">
|
|
<label for="logoutType" class="form-label">用戶類型</label>
|
|
<select class="form-select" id="logoutType">
|
|
<option value="member">會員</option>
|
|
<option value="provider">服務提供者</option>
|
|
<option value="admin">管理員</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="logoutToken" class="form-label">認證 Token</label>
|
|
<input type="text" class="form-control" id="logoutToken" placeholder="輸入或從下拉選單選擇 Token">
|
|
<div class="form-text">可以使用下方選單選擇已儲存的 Token</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="savedTokens" class="form-label">已儲存的 Token</label>
|
|
<select class="form-select" id="savedTokens">
|
|
<option value="">-- 選擇儲存的 Token --</option>
|
|
</select>
|
|
</div>
|
|
<div class="d-flex gap-2">
|
|
<button id="logoutButton" class="btn btn-danger">登出</button>
|
|
<button id="clearAllTokensButton" type="button" class="btn btn-warning">清除所有 Token</button>
|
|
</div>
|
|
<div class="mt-3">
|
|
<div class="alert alert-secondary">
|
|
<strong>如何測試 Token 是否真的失效?</strong>
|
|
<ol class="mt-2 mb-0">
|
|
<li>登入並獲取 Token</li>
|
|
<li>使用該 Token 呼叫需要認證的 API(如查詢個人資料)</li>
|
|
<li>使用登出按鈕登出</li>
|
|
<li>再次使用相同 Token 呼叫相同 API,應該會收到 401 未授權錯誤</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 查詢會員/教練測試 -->
|
|
<div class="tab-pane fade" id="check-user" role="tabpanel">
|
|
<h3>查詢會員/教練資料</h3>
|
|
<div class="alert alert-info">
|
|
<i class="bi bi-info-circle"></i> 此功能為管理員專用,可查詢會員或服務提供者的詳細資料。請先以管理員身份登入才能使用此功能。
|
|
</div>
|
|
<form id="checkUserForm">
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<label for="checkUserType" class="form-label">用戶類型</label>
|
|
<select class="form-select" id="checkUserType">
|
|
<option value="member">會員</option>
|
|
<option value="provider">服務提供者</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label for="checkUserId" class="form-label">用戶 ID</label>
|
|
<input type="number" class="form-control" id="checkUserId" min="1" required>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="adminToken" class="form-label">管理員認證 Token</label>
|
|
<input type="text" class="form-control" id="adminToken" required>
|
|
<div class="form-text">可以使用已儲存的管理員 Token</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="savedAdminTokens" class="form-label">已儲存的管理員 Token</label>
|
|
<select class="form-select" id="savedAdminTokens">
|
|
<option value="">-- 選擇儲存的管理員 Token --</option>
|
|
</select>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">查詢密碼</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 結果顯示區域 -->
|
|
<div class="card mt-4">
|
|
<div class="card-header">
|
|
API 回應結果
|
|
</div>
|
|
<div class="card-body">
|
|
<pre id="responseResult">尚未執行任何操作</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Token顯示區域 -->
|
|
<div id="tokenCard" class="card mt-3" style="display:none;">
|
|
<div class="card-header">
|
|
Token 資訊
|
|
</div>
|
|
<div class="card-body">
|
|
<pre id="tokenInfo"></pre>
|
|
<button id="copyToken" class="btn btn-sm btn-secondary">複製Token</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script>
|
|
// 頁面載入時加載已儲存的token
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
loadSavedTokens();
|
|
});
|
|
|
|
// 管理員註冊
|
|
document.getElementById('adminForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const data = {
|
|
name: document.getElementById('adminName').value,
|
|
email: document.getElementById('adminEmail').value,
|
|
password: document.getElementById('adminPassword').value,
|
|
password_confirmation: document.getElementById('adminPasswordConfirmation').value,
|
|
phone: document.getElementById('adminPhone').value,
|
|
position: document.getElementById('adminPosition').value,
|
|
department: document.getElementById('adminDepartment').value
|
|
};
|
|
|
|
callApi('/api/admin/register', 'POST', data);
|
|
});
|
|
|
|
// 服務提供者註冊
|
|
document.getElementById('providerForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const data = {
|
|
name: document.getElementById('providerName').value,
|
|
email: document.getElementById('providerEmail').value,
|
|
password: document.getElementById('providerPassword').value,
|
|
password_confirmation: document.getElementById('providerPasswordConfirmation').value,
|
|
phone: document.getElementById('providerPhone').value,
|
|
business_name: document.getElementById('businessName').value,
|
|
description: document.getElementById('description').value,
|
|
contact_person: document.getElementById('contactPerson').value,
|
|
contact_email: document.getElementById('contactEmail').value,
|
|
address: document.getElementById('address').value
|
|
};
|
|
|
|
callApi('/api/provider/register', 'POST', data);
|
|
});
|
|
|
|
// 登入
|
|
document.getElementById('loginForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const loginType = document.getElementById('loginType').value;
|
|
const data = {
|
|
email: document.getElementById('loginEmail').value,
|
|
password: document.getElementById('loginPassword').value
|
|
};
|
|
|
|
callApi(`/api/${loginType}/login`, 'POST', data);
|
|
});
|
|
|
|
// 登出
|
|
document.getElementById('logoutButton').addEventListener('click', function() {
|
|
const logoutType = document.getElementById('logoutType').value;
|
|
const token = document.getElementById('logoutToken').value;
|
|
|
|
if (!token) {
|
|
alert('請輸入或選擇認證 Token');
|
|
return;
|
|
}
|
|
|
|
fetch(`/api/${logoutType}/logout`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
// 顯示API回應
|
|
document.getElementById('responseResult').textContent = JSON.stringify(result, null, 2);
|
|
|
|
// 移除已用過的token
|
|
removeTokenFromStorage(token);
|
|
loadSavedTokens(); // 重新載入已儲存token列表
|
|
})
|
|
.catch(error => {
|
|
console.error('登出錯誤:', error);
|
|
document.getElementById('responseResult').textContent = `驗證失敗或結束已過期的工作階段: ${error.message}`;
|
|
});
|
|
});
|
|
|
|
// 已儲存tokens選擇事件
|
|
document.getElementById('savedTokens').addEventListener('change', function() {
|
|
if (this.value) {
|
|
document.getElementById('logoutToken').value = this.value;
|
|
}
|
|
});
|
|
|
|
// 已儲存管理員tokens選擇事件
|
|
document.getElementById('savedAdminTokens').addEventListener('change', function() {
|
|
if (this.value) {
|
|
document.getElementById('adminToken').value = this.value;
|
|
}
|
|
});
|
|
|
|
// 清除所有 Token 按鈕事件
|
|
document.getElementById('clearAllTokensButton').addEventListener('click', function() {
|
|
if (confirm('確定要清除所有已儲存的 Token 嗎?此操作不可還原。')) {
|
|
// 清除所有 auth_token_ 開頭的項目
|
|
const tokenKeys = Object.keys(localStorage).filter(key =>
|
|
key.startsWith('auth_token_'));
|
|
|
|
if (tokenKeys.length > 0) {
|
|
tokenKeys.forEach(key => localStorage.removeItem(key));
|
|
alert(`已清除 ${tokenKeys.length} 個 Token`);
|
|
} else {
|
|
alert('無已儲存的 Token');
|
|
}
|
|
|
|
// 重新載入選項列表
|
|
loadSavedTokens();
|
|
}
|
|
});
|
|
|
|
// 查詢會員/教練表單提交
|
|
document.getElementById('checkUserForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const userType = document.getElementById('checkUserType').value;
|
|
const userId = document.getElementById('checkUserId').value;
|
|
const adminToken = document.getElementById('adminToken').value;
|
|
|
|
if (!adminToken) {
|
|
alert('請輸入管理員認證 Token');
|
|
return;
|
|
}
|
|
|
|
if (!userId) {
|
|
alert('請輸入用戶 ID');
|
|
return;
|
|
}
|
|
|
|
fetch(`/api/admin/check-${userType}/${userId}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Authorization': `Bearer ${adminToken}`,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
})
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
// 顯示API回應
|
|
document.getElementById('responseResult').textContent = JSON.stringify(result, null, 2);
|
|
})
|
|
.catch(error => {
|
|
console.error('查詢密碼錯誤:', error);
|
|
document.getElementById('responseResult').textContent = `錯誤: ${error.message}`;
|
|
});
|
|
});
|
|
|
|
// 複製Token
|
|
document.getElementById('copyToken').addEventListener('click', function() {
|
|
const tokenInfo = JSON.parse(document.getElementById('tokenInfo').textContent);
|
|
navigator.clipboard.writeText(tokenInfo.token)
|
|
.then(() => alert('Token已複製到剪貼簿'))
|
|
.catch(err => console.error('複製失敗', err));
|
|
});
|
|
|
|
// 載入儲存的tokens
|
|
function loadSavedTokens() {
|
|
const savedTokensSelect = document.getElementById('savedTokens');
|
|
// 清空現有選項,保留第一個預設選項
|
|
savedTokensSelect.innerHTML = '<option value="">-- 選擇儲存的 Token --</option>';
|
|
|
|
// 取得已儲存的token
|
|
const tokenKeys = Object.keys(localStorage).filter(key =>
|
|
key.startsWith('auth_token_'));
|
|
|
|
tokenKeys.forEach(key => {
|
|
try {
|
|
const authInfo = JSON.parse(localStorage.getItem(key));
|
|
if (authInfo && authInfo.token) {
|
|
const option = document.createElement('option');
|
|
option.value = authInfo.token;
|
|
option.textContent = `${authInfo.user.name} (${authInfo.user.email}) - ${authInfo.user.role}`;
|
|
savedTokensSelect.appendChild(option);
|
|
}
|
|
} catch (e) {
|
|
console.error('解析已儲存token錯誤:', e);
|
|
}
|
|
});
|
|
|
|
// 清空輸入框
|
|
document.getElementById('logoutToken').value = '';
|
|
}
|
|
|
|
// 移除已使用的token
|
|
function removeTokenFromStorage(token) {
|
|
const tokenKeys = Object.keys(localStorage).filter(key =>
|
|
key.startsWith('auth_token_'));
|
|
|
|
tokenKeys.forEach(key => {
|
|
try {
|
|
const authInfo = JSON.parse(localStorage.getItem(key));
|
|
if (authInfo && authInfo.token === token) {
|
|
localStorage.removeItem(key);
|
|
}
|
|
} catch (e) {
|
|
console.error('移除token錯誤:', e);
|
|
}
|
|
});
|
|
}
|
|
|
|
// API呼叫函數
|
|
function callApi(url, method, data) {
|
|
fetch(url, {
|
|
method: method,
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(data)
|
|
})
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
// 顯示API回應
|
|
document.getElementById('responseResult').textContent = JSON.stringify(result, null, 2);
|
|
|
|
// 如果登入/註冊成功,顯示token
|
|
if (result.status && result.data && result.data.token) {
|
|
const tokenCard = document.getElementById('tokenCard');
|
|
const tokenInfo = document.getElementById('tokenInfo');
|
|
|
|
tokenCard.style.display = 'block';
|
|
tokenInfo.textContent = JSON.stringify({
|
|
token: result.data.token,
|
|
token_type: result.data.token_type
|
|
}, null, 2);
|
|
|
|
// 儲存到localStorage
|
|
const authKey = `auth_token_${Date.now()}`;
|
|
localStorage.setItem(authKey, JSON.stringify({
|
|
token: result.data.token,
|
|
token_type: result.data.token_type,
|
|
user: result.data.user
|
|
}));
|
|
|
|
// 重新載入選項列表
|
|
loadSavedTokens();
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('API錯誤:', error);
|
|
document.getElementById('responseResult').textContent = `錯誤: ${error.message}`;
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|