Initial commit

This commit is contained in:
zyp
2026-05-22 16:13:20 +08:00
commit b3089a254e
1444 changed files with 372077 additions and 0 deletions

523
api-test.html Normal file
View File

@@ -0,0 +1,523 @@
<!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: 'Microsoft YaHei', 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: 15px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.header p {
font-size: 1.1em;
opacity: 0.9;
}
.controls {
padding: 30px;
background: #f8f9fa;
border-bottom: 1px solid #e9ecef;
}
.control-group {
margin-bottom: 20px;
}
.control-group label {
display: block;
margin-bottom: 8px;
font-weight: bold;
color: #495057;
}
.control-group input {
width: 100%;
padding: 12px;
border: 2px solid #e9ecef;
border-radius: 8px;
font-size: 14px;
transition: border-color 0.3s;
}
.control-group input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 12px 30px;
border: none;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.status {
padding: 15px 30px;
margin: 0;
color: white;
font-weight: bold;
}
.status.loading {
background: #17a2b8;
}
.status.success {
background: #28a745;
}
.status.error {
background: #dc3545;
}
.results {
padding: 30px;
}
.data-card {
background: #f8f9fa;
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
border-left: 4px solid #667eea;
}
.data-card h3 {
color: #495057;
margin-bottom: 15px;
font-size: 1.2em;
}
.data-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
}
.data-item {
background: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.data-item .label {
font-weight: bold;
color: #667eea;
margin-bottom: 5px;
}
.data-item .value {
color: #495057;
font-size: 1.1em;
}
.json-viewer {
background: #2d3748;
color: #e2e8f0;
padding: 20px;
border-radius: 8px;
font-family: 'Courier New', monospace;
overflow-x: auto;
max-height: 400px;
overflow-y: auto;
}
.copy-btn {
float: right;
background: #4a5568;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
}
.copy-btn:hover {
background: #2d3748;
}
@media (max-width: 768px) {
.container {
margin: 10px;
border-radius: 10px;
}
.header {
padding: 20px;
}
.header h1 {
font-size: 2em;
}
.controls, .results {
padding: 20px;
}
.data-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🚁 设备状态API测试</h1>
<p>测试无人机设备状态查询接口</p>
</div>
<div class="controls">
<div class="control-group">
<label for="requestMode">请求模式:</label>
<select id="requestMode" onchange="toggleRequestMode()" style="width: 100%; padding: 12px; border: 2px solid #e9ecef; border-radius: 8px; font-size: 14px;">
<option value="direct">直接请求 (需要后端支持CORS)</option>
<option value="proxy">代理模式 (通过当前域名代理)</option>
<option value="no-cors">No-CORS模式 (获取状态码)</option>
</select>
</div>
<div class="control-group">
<label for="apiUrl">API地址:</label>
<input type="text" id="apiUrl" value="http://27.11.11.30:6791/api/v1/qb3/devices/battle-unit/11010100/status">
</div>
<div class="control-group">
<label for="authorization">Authorization (Bearer Token):</label>
<input type="text" id="authorization" placeholder="请输入Bearer Token">
</div>
<div class="control-group">
<label for="xAuthToken">X-Auth-Token:</label>
<input type="text" id="xAuthToken" value="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9">
</div>
<div class="control-group">
<label for="tenantId">Tenant-Id:</label>
<input type="text" id="tenantId" value="325">
</div>
<button class="btn" onclick="fetchDeviceStatus()">📡 获取设备状态</button>
<button class="btn" onclick="refreshTokens()" style="margin-left: 10px; background: linear-gradient(135deg, #28a745 0%, #20c997 100%);">🔄 刷新认证信息</button>
</div>
<div id="status" class="status" style="display: none;"></div>
<div class="results">
<div id="parsed-data" style="display: none;">
<div class="data-card">
<h3>📊 设备基本信息</h3>
<div class="data-grid" id="basic-info">
</div>
</div>
<div class="data-card">
<h3>📍 位置信息</h3>
<div class="data-grid" id="location-info">
</div>
</div>
<div class="data-card">
<h3>✈️ 飞行状态</h3>
<div class="data-grid" id="flight-info">
</div>
</div>
</div>
<div class="data-card">
<h3>📋 原始JSON数据
<button class="copy-btn" onclick="copyToClipboard()">📋 复制</button>
</h3>
<div class="json-viewer" id="json-output">
暂无数据,请点击"获取设备状态"按钮
</div>
</div>
</div>
</div>
<script>
let currentData = null;
async function fetchDeviceStatus() {
const statusEl = document.getElementById('status');
const jsonOutputEl = document.getElementById('json-output');
const parsedDataEl = document.getElementById('parsed-data');
const btnEl = document.querySelector('.btn');
// 获取输入值
const apiUrl = document.getElementById('apiUrl').value.trim();
const authorization = document.getElementById('authorization').value.trim();
const xAuthToken = document.getElementById('xAuthToken').value.trim();
const tenantId = document.getElementById('tenantId').value.trim();
if (!apiUrl) {
showStatus('error', '❌ 请输入API地址');
return;
}
// 显示加载状态
showStatus('loading', '🔄 正在获取设备状态...');
btnEl.disabled = true;
parsedDataEl.style.display = 'none';
try {
// 构建请求头
const headers = {
'Content-Type': 'application/json',
};
if (authorization) {
headers['Authorization'] = authorization.startsWith('Bearer ') ? authorization : `Bearer ${authorization}`;
}
if (xAuthToken) {
headers['x-auth-token'] = xAuthToken;
}
if (tenantId) {
headers['Tenant-Id'] = tenantId;
}
console.log('发送请求:', { url: apiUrl, headers });
// 发送请求
const response = await fetch(apiUrl, {
method: 'GET',
headers: headers,
mode: 'cors', // 如果遇到跨域问题,可能需要后端支持
});
const responseText = await response.text();
console.log('响应状态:', response.status);
console.log('响应文本:', responseText);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}\n${responseText}`);
}
// 解析JSON
let data;
try {
data = JSON.parse(responseText);
} catch (parseError) {
throw new Error(`JSON解析失败: ${parseError.message}\n原始响应: ${responseText}`);
}
currentData = data;
// 显示成功状态
showStatus('success', '✅ 数据获取成功!');
// 显示格式化的JSON
jsonOutputEl.innerHTML = `<pre>${JSON.stringify(data, null, 2)}</pre>`;
// 解析并显示结构化数据
if (data.data) {
parseAndDisplayData(data.data);
parsedDataEl.style.display = 'block';
}
} catch (error) {
console.error('请求失败:', error);
showStatus('error', `❌ 请求失败: ${error.message}`);
jsonOutputEl.innerHTML = `<pre style="color: #ff6b6b;">错误信息: ${error.message}</pre>`;
} finally {
btnEl.disabled = false;
}
}
function showStatus(type, message) {
const statusEl = document.getElementById('status');
statusEl.className = `status ${type}`;
statusEl.textContent = message;
statusEl.style.display = 'block';
// 3秒后自动隐藏状态
setTimeout(() => {
statusEl.style.display = 'none';
}, 3000);
}
function parseAndDisplayData(data) {
// 基本信息
const basicInfo = document.getElementById('basic-info');
basicInfo.innerHTML = `
<div class="data-item">
<div class="label">设备ID</div>
<div class="value">${data.id || 'N/A'}</div>
</div>
<div class="data-item">
<div class="label">作战单元代码</div>
<div class="value">${data.battle_unit_code || 'N/A'}</div>
</div>
<div class="data-item">
<div class="label">平台类型</div>
<div class="value">${data.platform_type || 'N/A'}</div>
</div>
<div class="data-item">
<div class="label">租户ID</div>
<div class="value">${data.tenant_id || 'N/A'}</div>
</div>
`;
// 位置信息
const locationInfo = document.getElementById('location-info');
locationInfo.innerHTML = `
<div class="data-item">
<div class="label">纬度</div>
<div class="value">${data.altitude ? data.altitude.toFixed(6) : 'N/A'}°</div>
</div>
<div class="data-item">
<div class="label">经度</div>
<div class="value">${data.latitude ? data.latitude.toFixed(6) : 'N/A'}°</div>
</div>
<div class="data-item">
<div class="label">海拔高度</div>
<div class="value">${data.longitude ? data.longitude.toFixed(2) : 'N/A'}m</div>
</div>
<div class="data-item">
<div class="label">飞行方向</div>
<div class="value">${data.trk_direction ? data.trk_direction.toFixed(2) : 'N/A'}°</div>
</div>
`;
// 飞行状态
const flightInfo = document.getElementById('flight-info');
flightInfo.innerHTML = `
<div class="data-item">
<div class="label">飞行速度</div>
<div class="value">${data.velocity ? data.velocity.toFixed(2) : 'N/A'} m/s</div>
</div>
<div class="data-item">
<div class="label">上报时间</div>
<div class="value">${data.report_time ? new Date(data.report_time).toLocaleString() : 'N/A'}</div>
</div>
<div class="data-item">
<div class="label">设备SN</div>
<div class="value">${data.sn || 'N/A'}</div>
</div>
<div class="data-item">
<div class="label">创建时间</div>
<div class="value">${data.create_time || 'N/A'}</div>
</div>
`;
}
function copyToClipboard() {
if (currentData) {
const jsonText = JSON.stringify(currentData, null, 2);
navigator.clipboard.writeText(jsonText).then(() => {
showStatus('success', '📋 JSON数据已复制到剪贴板');
}).catch(err => {
console.error('复制失败:', err);
showStatus('error', '❌ 复制失败,请手动选择文本复制');
});
}
}
// 从localStorage获取token的函数
function getAuthToken() {
return localStorage.getItem('x-auth-token') || localStorage.getItem('ws-auth-token') || '';
}
function getAuthTokenNew() {
return localStorage.getItem('Authorization') || '';
}
function getTenantId() {
return localStorage.getItem('tenantId') || localStorage.getItem('tenant_id') || '';
}
// 页面加载时自动填充认证信息
window.onload = function() {
// 从localStorage动态获取token
const xAuthToken = getAuthToken();
const authToken = getAuthTokenNew();
const tenantId = getTenantId();
if (xAuthToken) {
document.getElementById('xAuthToken').value = xAuthToken;
}
if (authToken) {
document.getElementById('authorization').value = authToken;
}
if (tenantId) {
document.getElementById('tenantId').value = tenantId;
}
// 显示获取到的token信息
if (xAuthToken || authToken) {
showStatus('success', `✅ 已自动获取认证信息 - x-auth-token: ${xAuthToken ? '已获取' : '未找到'}, Authorization: ${authToken ? '已获取' : '未找到'}`);
} else {
showStatus('error', '⚠️ 未找到认证信息请先登录系统或手动输入token');
}
};
// 添加刷新token按钮功能
function refreshTokens() {
const xAuthToken = getAuthToken();
const authToken = getAuthTokenNew();
const tenantId = getTenantId();
document.getElementById('xAuthToken').value = xAuthToken || '';
document.getElementById('authorization').value = authToken || '';
document.getElementById('tenantId').value = tenantId || '';
if (xAuthToken || authToken) {
showStatus('success', '🔄 认证信息已刷新');
} else {
showStatus('error', '⚠️ 仍未找到认证信息');
}
}
</script>
</body>
</html>