312 lines
9.0 KiB
HTML
312 lines
9.0 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>管理后台 API 测试工具</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
min-height: 100vh;
|
||
padding: 20px;
|
||
}
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
background: white;
|
||
border-radius: 12px;
|
||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||
overflow: hidden;
|
||
}
|
||
.header {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 30px;
|
||
text-align: center;
|
||
}
|
||
.header h1 {
|
||
font-size: 28px;
|
||
margin-bottom: 10px;
|
||
}
|
||
.header p {
|
||
opacity: 0.9;
|
||
font-size: 14px;
|
||
}
|
||
.content {
|
||
padding: 30px;
|
||
}
|
||
.button-group {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 15px;
|
||
margin-bottom: 30px;
|
||
}
|
||
button {
|
||
padding: 15px 25px;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
border: none;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
color: white;
|
||
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
||
}
|
||
button:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 6px 20px rgba(0,0,0,0.3);
|
||
}
|
||
button:active {
|
||
transform: translateY(0);
|
||
}
|
||
.btn-login { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
|
||
.btn-users { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); }
|
||
.btn-stats { background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); }
|
||
.btn-clear { background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); }
|
||
.status {
|
||
padding: 15px;
|
||
border-radius: 8px;
|
||
margin-bottom: 20px;
|
||
font-weight: 600;
|
||
}
|
||
.status.success {
|
||
background: #d4edda;
|
||
color: #155724;
|
||
border: 1px solid #c3e6cb;
|
||
}
|
||
.status.error {
|
||
background: #f8d7da;
|
||
color: #721c24;
|
||
border: 1px solid #f5c6cb;
|
||
}
|
||
.status.info {
|
||
background: #d1ecf1;
|
||
color: #0c5460;
|
||
border: 1px solid #bee5eb;
|
||
}
|
||
.result {
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 13px;
|
||
line-height: 1.6;
|
||
max-height: 500px;
|
||
overflow-y: auto;
|
||
white-space: pre-wrap;
|
||
word-wrap: break-word;
|
||
}
|
||
.result:empty::before {
|
||
content: '等待测试结果...';
|
||
color: #6c757d;
|
||
font-style: italic;
|
||
}
|
||
.info-box {
|
||
background: #e7f3ff;
|
||
border-left: 4px solid #2196F3;
|
||
padding: 15px;
|
||
margin-bottom: 20px;
|
||
border-radius: 4px;
|
||
}
|
||
.info-box h3 {
|
||
color: #1976D2;
|
||
margin-bottom: 10px;
|
||
font-size: 16px;
|
||
}
|
||
.info-box ul {
|
||
margin-left: 20px;
|
||
color: #555;
|
||
}
|
||
.info-box li {
|
||
margin: 5px 0;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="header">
|
||
<h1>🔧 管理后台 API 测试工具</h1>
|
||
<p>快速测试后端 API 是否正常工作</p>
|
||
</div>
|
||
|
||
<div class="content">
|
||
<div class="info-box">
|
||
<h3>📋 使用说明</h3>
|
||
<ul>
|
||
<li>1. 确保后端服务运行在 http://localhost:3000</li>
|
||
<li>2. 点击"测试登录"按钮获取 Token</li>
|
||
<li>3. 登录成功后,点击其他按钮测试 API</li>
|
||
<li>4. 查看下方结果区域的响应数据</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div id="status"></div>
|
||
|
||
<div class="button-group">
|
||
<button class="btn-login" onclick="testLogin()">🔐 1. 测试登录</button>
|
||
<button class="btn-users" onclick="testUsers()">👥 2. 测试用户列表</button>
|
||
<button class="btn-stats" onclick="testStats()">📊 3. 测试统计数据</button>
|
||
<button class="btn-clear" onclick="clearResult()">🗑️ 清空结果</button>
|
||
</div>
|
||
|
||
<h3 style="margin-bottom: 15px; color: #333;">📄 测试结果:</h3>
|
||
<div class="result" id="result"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
let token = '';
|
||
const resultEl = document.getElementById('result');
|
||
const statusEl = document.getElementById('status');
|
||
const API_BASE = 'http://localhost:3000';
|
||
|
||
function showStatus(message, type = 'info') {
|
||
statusEl.innerHTML = `<div class="status ${type}">${message}</div>`;
|
||
setTimeout(() => {
|
||
statusEl.innerHTML = '';
|
||
}, 5000);
|
||
}
|
||
|
||
function displayResult(title, data) {
|
||
const timestamp = new Date().toLocaleString('zh-CN');
|
||
resultEl.textContent = `[${timestamp}] ${title}\n\n${JSON.stringify(data, null, 2)}`;
|
||
}
|
||
|
||
async function testLogin() {
|
||
try {
|
||
showStatus('🔄 正在登录...', 'info');
|
||
const res = await fetch(`${API_BASE}/api/v1/admin/login`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
username: 'admin',
|
||
password: 'admin123'
|
||
})
|
||
});
|
||
|
||
if (!res.ok) {
|
||
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
||
}
|
||
|
||
const data = await res.json();
|
||
|
||
if (data.code === 0 && data.data.token) {
|
||
token = data.data.token;
|
||
showStatus('✅ 登录成功!Token 已保存', 'success');
|
||
displayResult('登录成功', {
|
||
admin: data.data.admin,
|
||
token: token.substring(0, 50) + '...',
|
||
message: '✅ 可以继续测试其他 API'
|
||
});
|
||
} else {
|
||
throw new Error(data.message || '登录失败');
|
||
}
|
||
} catch (e) {
|
||
showStatus('❌ 登录失败: ' + e.message, 'error');
|
||
displayResult('登录失败', { error: e.message });
|
||
}
|
||
}
|
||
|
||
async function testUsers() {
|
||
if (!token) {
|
||
showStatus('⚠️ 请先登录获取 Token!', 'error');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
showStatus('🔄 正在获取用户列表...', 'info');
|
||
const res = await fetch(`${API_BASE}/api/v1/admin/users?page=1&limit=20`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`,
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
|
||
if (!res.ok) {
|
||
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
||
}
|
||
|
||
const data = await res.json();
|
||
|
||
if (data.code === 0) {
|
||
const userCount = data.data.users.length;
|
||
const total = data.data.pagination.total;
|
||
showStatus(`✅ 成功获取用户列表!共 ${total} 个用户`, 'success');
|
||
displayResult(`用户列表 (显示 ${userCount}/${total})`, data.data);
|
||
} else {
|
||
throw new Error(data.message || '获取用户列表失败');
|
||
}
|
||
} catch (e) {
|
||
showStatus('❌ 获取用户列表失败: ' + e.message, 'error');
|
||
displayResult('获取用户列表失败', { error: e.message });
|
||
}
|
||
}
|
||
|
||
async function testStats() {
|
||
if (!token) {
|
||
showStatus('⚠️ 请先登录获取 Token!', 'error');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
showStatus('🔄 正在获取统计数据...', 'info');
|
||
const res = await fetch(`${API_BASE}/api/v1/admin/statistics/dashboard`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${token}`,
|
||
'Content-Type': 'application/json'
|
||
}
|
||
});
|
||
|
||
if (!res.ok) {
|
||
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
||
}
|
||
|
||
const data = await res.json();
|
||
|
||
if (data.code === 0) {
|
||
showStatus('✅ 成功获取统计数据!', 'success');
|
||
displayResult('统计数据', {
|
||
总用户数: data.data.totalUsers,
|
||
活跃预约: data.data.activeAppointments,
|
||
待审核提现: data.data.pendingWithdrawals,
|
||
待提现金额: data.data.pendingWithdrawalAmount,
|
||
原始数据: data.data
|
||
});
|
||
} else {
|
||
throw new Error(data.message || '获取统计数据失败');
|
||
}
|
||
} catch (e) {
|
||
showStatus('❌ 获取统计数据失败: ' + e.message, 'error');
|
||
displayResult('获取统计数据失败', { error: e.message });
|
||
}
|
||
}
|
||
|
||
function clearResult() {
|
||
resultEl.textContent = '';
|
||
showStatus('🗑️ 结果已清空', 'info');
|
||
}
|
||
|
||
// 页面加载时显示欢迎信息
|
||
window.onload = function() {
|
||
displayResult('欢迎使用 API 测试工具', {
|
||
说明: '请按顺序点击上方按钮进行测试',
|
||
步骤: [
|
||
'1. 点击"测试登录"获取 Token',
|
||
'2. 点击"测试用户列表"查看用户数据',
|
||
'3. 点击"测试统计数据"查看统计信息'
|
||
],
|
||
后端地址: API_BASE,
|
||
默认账号: { username: 'admin', password: 'admin123' }
|
||
});
|
||
};
|
||
</script>
|
||
</body>
|
||
</html>
|