432 lines
14 KiB
HTML
432 lines
14 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>OCDP API camelCase 测试</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
padding: 20px;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
background: white;
|
||
border-radius: 10px;
|
||
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.header {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 30px;
|
||
text-align: center;
|
||
}
|
||
|
||
.header h1 {
|
||
font-size: 2em;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.header p {
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.content {
|
||
padding: 30px;
|
||
}
|
||
|
||
.section {
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
.section h2 {
|
||
color: #333;
|
||
margin-bottom: 15px;
|
||
border-bottom: 2px solid #667eea;
|
||
padding-bottom: 10px;
|
||
}
|
||
|
||
.input-group {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.input-group label {
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
color: #555;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.input-group input {
|
||
width: 100%;
|
||
padding: 10px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 5px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.buttons {
|
||
display: flex;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
button {
|
||
padding: 12px 24px;
|
||
border: none;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
button:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||
}
|
||
|
||
button:disabled {
|
||
opacity: 0.5;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
}
|
||
|
||
.btn-success {
|
||
background: #4CAF50;
|
||
color: white;
|
||
}
|
||
|
||
.btn-info {
|
||
background: #2196F3;
|
||
color: white;
|
||
}
|
||
|
||
.btn-warning {
|
||
background: #FF9800;
|
||
color: white;
|
||
}
|
||
|
||
.btn-danger {
|
||
background: #f44336;
|
||
color: white;
|
||
}
|
||
|
||
.log-container {
|
||
background: #1e1e1e;
|
||
color: #d4d4d4;
|
||
padding: 20px;
|
||
border-radius: 5px;
|
||
min-height: 400px;
|
||
max-height: 600px;
|
||
overflow-y: auto;
|
||
font-size: 13px;
|
||
line-height: 1.6;
|
||
white-space: pre-wrap;
|
||
word-wrap: break-word;
|
||
}
|
||
|
||
.log-success {
|
||
color: #4CAF50;
|
||
}
|
||
|
||
.log-error {
|
||
color: #f44336;
|
||
}
|
||
|
||
.log-warning {
|
||
color: #FF9800;
|
||
}
|
||
|
||
.log-info {
|
||
color: #2196F3;
|
||
}
|
||
|
||
.status {
|
||
padding: 10px;
|
||
margin-bottom: 20px;
|
||
border-radius: 5px;
|
||
text-align: center;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.status.loading {
|
||
background: #FFF3CD;
|
||
color: #856404;
|
||
}
|
||
|
||
.status.success {
|
||
background: #D4EDDA;
|
||
color: #155724;
|
||
}
|
||
|
||
.status.error {
|
||
background: #F8D7DA;
|
||
color: #721C24;
|
||
}
|
||
|
||
.hidden {
|
||
display: none;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="header">
|
||
<h1>🧪 OCDP API camelCase 测试</h1>
|
||
<p>测试前后端 camelCase 通信是否正常</p>
|
||
</div>
|
||
|
||
<div class="content">
|
||
<div class="section">
|
||
<h2>⚙️ 配置</h2>
|
||
<div class="input-group">
|
||
<label for="apiUrl">API 地址:</label>
|
||
<input type="text" id="apiUrl" value="http://localhost:8080/api/v1" />
|
||
</div>
|
||
<div class="input-group">
|
||
<label for="token">Token (登录后自动填充):</label>
|
||
<input type="text" id="token" placeholder="JWT Token" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<h2>🎮 测试操作</h2>
|
||
<div class="buttons">
|
||
<button class="btn-success" onclick="testLogin()">1. 测试登录</button>
|
||
<button class="btn-info" onclick="testListClusters()">2. 获取集群列表</button>
|
||
<button class="btn-warning" onclick="testCreateCluster()">3. 创建集群</button>
|
||
<button class="btn-primary" onclick="testFullFlow()">🚀 完整测试</button>
|
||
<button class="btn-danger" onclick="clearLog()">清除日志</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="status" class="status hidden"></div>
|
||
|
||
<div class="section">
|
||
<h2>📋 测试日志</h2>
|
||
<div id="log" class="log-container">点击按钮开始测试...</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const logEl = document.getElementById('log');
|
||
const statusEl = document.getElementById('status');
|
||
const tokenInput = document.getElementById('token');
|
||
const apiUrlInput = document.getElementById('apiUrl');
|
||
|
||
function getApiUrl() {
|
||
return apiUrlInput.value;
|
||
}
|
||
|
||
function getToken() {
|
||
return tokenInput.value;
|
||
}
|
||
|
||
function setStatus(message, type = 'loading') {
|
||
statusEl.textContent = message;
|
||
statusEl.className = `status ${type}`;
|
||
statusEl.classList.remove('hidden');
|
||
}
|
||
|
||
function hideStatus() {
|
||
statusEl.classList.add('hidden');
|
||
}
|
||
|
||
function log(message, type = 'info') {
|
||
const timestamp = new Date().toLocaleTimeString();
|
||
const className = `log-${type}`;
|
||
logEl.innerHTML += `<span class="${className}">[${timestamp}] ${message}</span>\n`;
|
||
logEl.scrollTop = logEl.scrollHeight;
|
||
}
|
||
|
||
function clearLog() {
|
||
logEl.innerHTML = '';
|
||
hideStatus();
|
||
log('日志已清除', 'info');
|
||
}
|
||
|
||
async function testLogin() {
|
||
clearLog();
|
||
log('🔐 开始测试登录...', 'info');
|
||
setStatus('正在登录...', 'loading');
|
||
|
||
try {
|
||
const response = await fetch(`${getApiUrl()}/auth/login`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
username: 'admin',
|
||
password: 'admin123'
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
log('响应数据:\n' + JSON.stringify(data, null, 2), 'info');
|
||
|
||
if (data.accessToken) {
|
||
log('✅ 登录成功!', 'success');
|
||
tokenInput.value = data.accessToken;
|
||
|
||
// 验证 camelCase
|
||
if ('accessToken' in data) log(' ✓ accessToken 字段存在 (camelCase)', 'success');
|
||
if ('refreshToken' in data) log(' ✓ refreshToken 字段存在 (camelCase)', 'success');
|
||
if ('userId' in data) log(' ✓ userId 字段存在 (camelCase)', 'success');
|
||
|
||
setStatus('✅ 登录成功!', 'success');
|
||
} else {
|
||
log('❌ 登录失败: 未找到 accessToken', 'error');
|
||
setStatus('❌ 登录失败', 'error');
|
||
}
|
||
} catch (error) {
|
||
log(`❌ 请求失败: ${error.message}`, 'error');
|
||
setStatus('❌ 请求失败', 'error');
|
||
}
|
||
}
|
||
|
||
async function testListClusters() {
|
||
log('\n📋 开始获取集群列表...', 'info');
|
||
const token = getToken();
|
||
|
||
if (!token) {
|
||
log('❌ 请先登录获取 Token', 'error');
|
||
return;
|
||
}
|
||
|
||
setStatus('正在获取集群列表...', 'loading');
|
||
|
||
try {
|
||
const response = await fetch(`${getApiUrl()}/clusters`, {
|
||
headers: { 'Authorization': `Bearer ${token}` }
|
||
});
|
||
|
||
const data = await response.json();
|
||
log(`响应数据 (共 ${Array.isArray(data) ? data.length : 0} 个集群):\n` +
|
||
JSON.stringify(data, null, 2), 'info');
|
||
|
||
if (Array.isArray(data)) {
|
||
log('✅ 获取集群列表成功!', 'success');
|
||
|
||
// 验证 camelCase
|
||
if (data.length > 0) {
|
||
const cluster = data[0];
|
||
if ('createdAt' in cluster) log(' ✓ createdAt 字段存在 (camelCase)', 'success');
|
||
if ('updatedAt' in cluster) log(' ✓ updatedAt 字段存在 (camelCase)', 'success');
|
||
if ('hasCaData' in cluster) log(' ✓ hasCaData 字段存在 (camelCase)', 'success');
|
||
}
|
||
|
||
setStatus(`✅ 获取成功!共 ${data.length} 个集群`, 'success');
|
||
} else {
|
||
log('❌ 响应格式错误', 'error');
|
||
setStatus('❌ 响应格式错误', 'error');
|
||
}
|
||
} catch (error) {
|
||
log(`❌ 请求失败: ${error.message}`, 'error');
|
||
setStatus('❌ 请求失败', 'error');
|
||
}
|
||
}
|
||
|
||
async function testCreateCluster() {
|
||
log('\n🚀 开始创建集群 (使用 camelCase)...', 'info');
|
||
const token = getToken();
|
||
|
||
if (!token) {
|
||
log('❌ 请先登录获取 Token', 'error');
|
||
return;
|
||
}
|
||
|
||
setStatus('正在创建集群...', 'loading');
|
||
|
||
const clusterData = {
|
||
name: `test-cluster-${Date.now()}`,
|
||
host: 'https://k8s.test.example.com:6443',
|
||
description: '测试集群 - camelCase 验证',
|
||
caData: 'LS0tLS1CRUdJTi1DRVJUSUZJQ0FURS0tLS0t',
|
||
certData: 'LS0tLS1CRUdJTi1DRVJUSUZJQ0FURS0tLS0t',
|
||
keyData: 'LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVkt'
|
||
};
|
||
|
||
log('请求数据 (camelCase):\n' + JSON.stringify(clusterData, null, 2), 'info');
|
||
|
||
try {
|
||
const response = await fetch(`${getApiUrl()}/clusters`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${token}`
|
||
},
|
||
body: JSON.stringify(clusterData)
|
||
});
|
||
|
||
const data = await response.json();
|
||
log('响应数据:\n' + JSON.stringify(data, null, 2), 'info');
|
||
|
||
if (data.id) {
|
||
log('✅ 创建集群成功!', 'success');
|
||
log(` 集群 ID: ${data.id}`, 'info');
|
||
|
||
// 验证 camelCase
|
||
if ('hasCaData' in data) log(' ✓ hasCaData 字段存在 (camelCase)', 'success');
|
||
if ('hasCertData' in data) log(' ✓ hasCertData 字段存在 (camelCase)', 'success');
|
||
if ('createdAt' in data) log(' ✓ createdAt 字段存在 (camelCase)', 'success');
|
||
|
||
setStatus('✅ 创建成功!', 'success');
|
||
} else {
|
||
log('❌ 创建失败或响应格式错误', 'error');
|
||
setStatus('❌ 创建失败', 'error');
|
||
}
|
||
} catch (error) {
|
||
log(`❌ 请求失败: ${error.message}`, 'error');
|
||
setStatus('❌ 请求失败', 'error');
|
||
}
|
||
}
|
||
|
||
async function testFullFlow() {
|
||
clearLog();
|
||
log('🧪 开始完整测试流程...\n', 'info');
|
||
setStatus('正在执行完整测试...', 'loading');
|
||
|
||
// 步骤 1: 登录
|
||
await testLogin();
|
||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||
|
||
// 步骤 2: 获取集群列表
|
||
await testListClusters();
|
||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||
|
||
// 步骤 3: 创建集群
|
||
await testCreateCluster();
|
||
|
||
log('\n🎉 完整测试流程完成!', 'success');
|
||
log('所有 API 调用成功,camelCase 工作正常!', 'success');
|
||
setStatus('🎉 完整测试通过!', 'success');
|
||
}
|
||
|
||
// 页面加载完成后的初始化
|
||
window.addEventListener('load', () => {
|
||
log('🌐 页面已加载,可以开始测试', 'info');
|
||
log('提示: 点击 "🚀 完整测试" 运行所有测试\n', 'info');
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|
||
|