pr #3

Merged
pr3xei76a merged 10 commits from xyp.branch into main 6 months ago

File diff suppressed because it is too large Load Diff

@ -0,0 +1,200 @@
// API 基础 URL
const API_BASE_URL = 'http://localhost:5000/api';
// API 调用函数
const api = {
// 登录
login: async (username, password) => {
try {
const response = await fetch(`${API_BASE_URL}/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || '登录失败');
}
return await response.json();
} catch (error) {
throw error;
}
},
// 获取无人机列表
getDrones: async () => {
try {
const response = await fetch(`${API_BASE_URL}/drones`, {
headers: {
'Authorization': `Bearer ${currentUser?.token}`
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || '获取无人机列表失败');
}
return await response.json();
} catch (error) {
throw error;
}
},
// 添加无人机
addDrone: async (droneData) => {
try {
const response = await fetch(`${API_BASE_URL}/drones`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${currentUser?.token}`
},
body: JSON.stringify(droneData)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || '添加无人机失败');
}
return await response.json();
} catch (error) {
throw error;
}
},
// 更新无人机
updateDrone: async (droneId, droneData) => {
try {
const response = await fetch(`${API_BASE_URL}/drones/${droneId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${currentUser?.token}`
},
body: JSON.stringify(droneData)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || '更新无人机失败');
}
return await response.json();
} catch (error) {
throw error;
}
},
// 删除无人机
deleteDrone: async (droneId) => {
try {
const response = await fetch(`${API_BASE_URL}/drones/${droneId}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${currentUser?.token}`
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || '删除无人机失败');
}
return await response.json();
} catch (error) {
throw error;
}
},
// 获取识别记录
getRecords: async (filters = {}) => {
try {
const queryParams = new URLSearchParams(filters).toString();
const response = await fetch(`${API_BASE_URL}/records?${queryParams}`, {
headers: {
'Authorization': `Bearer ${currentUser?.token}`
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || '获取识别记录失败');
}
return await response.json();
} catch (error) {
throw error;
}
},
// 获取记录详情
getRecordDetail: async (recordId) => {
try {
const response = await fetch(`${API_BASE_URL}/records/${recordId}`, {
headers: {
'Authorization': `Bearer ${currentUser?.token}`
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || '获取记录详情失败');
}
return await response.json();
} catch (error) {
throw error;
}
},
// 目标识别
identify: async (formData) => {
try {
const response = await fetch(`${API_BASE_URL}/identify`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${currentUser?.token}`
},
body: formData
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || '目标识别失败');
}
return await response.json();
} catch (error) {
throw error;
}
},
// 信号识别
identifySignal: async (signal) => {
try {
const response = await fetch(`${API_BASE_URL}/signal_identify`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${currentUser?.token}`
},
body: JSON.stringify({ signal })
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || '信号识别失败');
}
return await response.json();
} catch (error) {
throw error;
}
}
};

@ -0,0 +1,732 @@
// 更新时间显示
function updateTime() {
const now = new Date();
const timeString = now.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
});
document.getElementById('current-time').textContent = timeString;
}
// 状态卡片迷你图表
class StatusMiniChart {
constructor(container) {
this.container = container;
this.canvas = document.createElement('canvas');
this.container.appendChild(this.canvas);
this.ctx = this.canvas.getContext('2d');
this.resize();
this.generateData();
this.draw();
}
resize() {
this.canvas.width = this.container.offsetWidth;
this.canvas.height = this.container.offsetHeight;
}
generateData() {
this.data = Array.from({length: 20}, () => Math.random() * 0.8 + 0.2);
}
draw() {
const ctx = this.ctx;
const width = this.canvas.width;
const height = this.canvas.height;
const step = width / (this.data.length - 1);
ctx.clearRect(0, 0, width, height);
// 绘制曲线
ctx.beginPath();
ctx.moveTo(0, height * (1 - this.data[0]));
for (let i = 1; i < this.data.length; i++) {
const x = i * step;
const y = height * (1 - this.data[i]);
if (i === 0) {
ctx.moveTo(x, y);
} else {
const xc = (x + (i - 1) * step) / 2;
const yc = (y + height * (1 - this.data[i - 1])) / 2;
ctx.quadraticCurveTo(xc, yc, x, y);
}
}
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
ctx.lineWidth = 2;
ctx.stroke();
// 填充渐变
const gradient = ctx.createLinearGradient(0, 0, 0, height);
gradient.addColorStop(0, 'rgba(255, 255, 255, 0.2)');
gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
ctx.lineTo(width, height);
ctx.lineTo(0, height);
ctx.fillStyle = gradient;
ctx.fill();
}
update() {
this.data.shift();
this.data.push(Math.random() * 0.8 + 0.2);
this.draw();
}
}
// 雷达扫描效果
class TacticalRadar {
constructor(containerId) {
this.container = document.getElementById(containerId);
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d');
this.container.appendChild(this.canvas);
this.resize();
this.setupRadar();
window.addEventListener('resize', () => this.resize());
}
resize() {
this.canvas.width = this.container.offsetWidth;
this.canvas.height = this.container.offsetHeight;
this.centerX = this.canvas.width / 2;
this.centerY = this.canvas.height / 2;
this.radius = Math.min(this.centerX, this.centerY) * 0.85;
}
setupRadar() {
this.angle = 0;
this.targets = this.generateRandomTargets();
this.fadeOpacity = new Array(360).fill(0);
this.animate();
}
generateRandomTargets() {
const targets = [];
const numTargets = Math.floor(Math.random() * 5) + 3;
for (let i = 0; i < numTargets; i++) {
const distance = Math.random() * 0.8 + 0.1; // 10% - 90% of radius
const angle = Math.random() * Math.PI * 2;
const type = Math.random() < 0.7 ? 'friendly' : 'hostile';
const size = Math.random() * 3 + 2;
targets.push({
x: Math.cos(angle) * this.radius * distance,
y: Math.sin(angle) * this.radius * distance,
type,
size,
blip: 1.0, // 用于闪烁效果
fadeStart: angle // 用于淡出效果
});
}
return targets;
}
drawGrid() {
// 绘制背景
const gradient = this.ctx.createRadialGradient(
this.centerX, this.centerY, 0,
this.centerX, this.centerY, this.radius
);
gradient.addColorStop(0, 'rgba(0, 180, 216, 0.1)');
gradient.addColorStop(1, 'rgba(0, 180, 216, 0)');
this.ctx.fillStyle = gradient;
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.strokeStyle = 'rgba(0, 180, 216, 0.2)';
this.ctx.lineWidth = 1;
// 绘制同心圆
for (let i = 1; i <= 4; i++) {
const radius = this.radius * (i/4);
this.ctx.beginPath();
this.ctx.arc(this.centerX, this.centerY, radius, 0, Math.PI * 2);
this.ctx.stroke();
// 添加距离标记
const distance = (i * 25).toString() + 'km';
this.ctx.fillStyle = 'rgba(0, 180, 216, 0.5)';
this.ctx.font = '12px Noto Sans SC';
this.ctx.fillText(distance, this.centerX + radius + 5, this.centerY);
}
// 绘制方向标记
const directions = ['N', 'E', 'S', 'W'];
this.ctx.font = 'bold 14px Noto Sans SC';
directions.forEach((dir, i) => {
const angle = (i * Math.PI / 2) - Math.PI / 2;
const x = this.centerX + Math.cos(angle) * (this.radius + 20);
const y = this.centerY + Math.sin(angle) * (this.radius + 20);
this.ctx.fillText(dir, x - 6, y + 6);
});
// 绘制刻度线
for (let i = 0; i < 360; i += 30) {
const angle = (i * Math.PI) / 180;
const startRadius = this.radius - 10;
const endRadius = this.radius;
this.ctx.beginPath();
this.ctx.moveTo(
this.centerX + Math.cos(angle) * startRadius,
this.centerY + Math.sin(angle) * startRadius
);
this.ctx.lineTo(
this.centerX + Math.cos(angle) * endRadius,
this.centerY + Math.sin(angle) * endRadius
);
this.ctx.stroke();
}
// 绘制十字线
this.ctx.beginPath();
this.ctx.moveTo(this.centerX - this.radius, this.centerY);
this.ctx.lineTo(this.centerX + this.radius, this.centerY);
this.ctx.moveTo(this.centerX, this.centerY - this.radius);
this.ctx.lineTo(this.centerX, this.centerY + this.radius);
this.ctx.stroke();
}
drawSweep() {
// 更新扫描线渐变效果
const gradient = this.ctx.createLinearGradient(
this.centerX,
this.centerY,
this.centerX + Math.cos(this.angle) * this.radius,
this.centerY + Math.sin(this.angle) * this.radius
);
gradient.addColorStop(0, 'rgba(0, 180, 216, 0.8)');
gradient.addColorStop(0.5, 'rgba(0, 180, 216, 0.3)');
gradient.addColorStop(1, 'rgba(0, 180, 216, 0)');
// 绘制扫描线
this.ctx.beginPath();
this.ctx.moveTo(this.centerX, this.centerY);
this.ctx.lineTo(
this.centerX + Math.cos(this.angle) * this.radius,
this.centerY + Math.sin(this.angle) * this.radius
);
this.ctx.strokeStyle = gradient;
this.ctx.lineWidth = 3;
this.ctx.stroke();
// 扫描扇形
this.ctx.beginPath();
this.ctx.moveTo(this.centerX, this.centerY);
this.ctx.arc(this.centerX, this.centerY, this.radius, this.angle - 0.2, this.angle);
this.ctx.fillStyle = 'rgba(0, 180, 216, 0.1)';
this.ctx.fill();
// 更新淡出效果数组
const currentAngleDeg = (this.angle * 180 / Math.PI) % 360;
this.fadeOpacity[Math.floor(currentAngleDeg)] = 1;
// 绘制历史扫描线
for (let i = 0; i < 360; i++) {
if (this.fadeOpacity[i] > 0) {
const angle = (i * Math.PI) / 180;
this.ctx.beginPath();
this.ctx.moveTo(this.centerX, this.centerY);
this.ctx.lineTo(
this.centerX + Math.cos(angle) * this.radius,
this.centerY + Math.sin(angle) * this.radius
);
this.ctx.strokeStyle = `rgba(0, 180, 216, ${this.fadeOpacity[i] * 0.1})`;
this.ctx.stroke();
this.fadeOpacity[i] *= 0.95;
}
}
}
drawTargets() {
this.targets.forEach(target => {
// 计算目标在画布上的位置
const x = this.centerX + target.x;
const y = this.centerY + target.y;
// 检查是否在扫描线范围内
const targetAngle = Math.atan2(target.y, target.x);
const normalizedTargetAngle = targetAngle < 0 ? targetAngle + Math.PI * 2 : targetAngle;
const normalizedSweepAngle = this.angle % (Math.PI * 2);
if (Math.abs(normalizedTargetAngle - normalizedSweepAngle) < 0.2) {
target.blip = 1.0;
}
// 绘制目标
this.ctx.beginPath();
this.ctx.arc(x, y, target.size, 0, Math.PI * 2);
const color = target.type === 'friendly' ?
`rgba(46, 204, 113, ${target.blip})` :
`rgba(231, 76, 60, ${target.blip})`;
this.ctx.fillStyle = color;
this.ctx.fill();
// 绘制目标光晕
this.ctx.beginPath();
this.ctx.arc(x, y, target.size * 2, 0, Math.PI * 2);
this.ctx.fillStyle = color.replace('1)', '0.3)');
this.ctx.fill();
// 淡出效果
target.blip *= 0.95;
});
}
updateStats() {
const friendlyTargets = this.targets.filter(t => t.type === 'friendly').length;
const hostileTargets = this.targets.filter(t => t.type === 'hostile').length;
document.querySelector('.stat-item:nth-child(2) .value').textContent =
`${friendlyTargets + hostileTargets}`;
}
animate() {
this.ctx.fillStyle = 'rgba(26, 38, 52, 0.3)';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.drawGrid();
this.drawSweep();
this.drawTargets();
this.updateStats();
this.angle += 0.02;
if (this.angle >= Math.PI * 2) {
this.angle = 0;
if (Math.random() < 0.3) {
this.targets = this.generateRandomTargets();
}
}
requestAnimationFrame(() => this.animate());
}
}
// 状态卡片动画
class StatusCards {
constructor() {
this.cards = document.querySelectorAll('.status-card');
this.setupCards();
}
setupCards() {
this.cards.forEach(card => {
const value = card.querySelector('.status-value');
const targetValue = parseInt(value.textContent);
value.textContent = '0';
// 添加数值增长动画
this.animateValue(value, 0, targetValue, 2000);
// 添加图标呼吸效果
const icon = card.querySelector('.status-icon');
this.addPulseEffect(icon);
});
}
animateValue(element, start, end, duration) {
const range = end - start;
const increment = range / (duration / 16);
let current = start;
const animate = () => {
current += increment;
element.textContent = Math.floor(current);
if (current < end) {
requestAnimationFrame(animate);
} else {
element.textContent = end;
}
};
animate();
}
addPulseEffect(element) {
element.style.animation = 'pulse 2s infinite';
}
}
// 威胁分析图表
class ThreatAnalysis {
constructor(containerId) {
this.container = document.getElementById(containerId);
this.setupChart();
}
setupChart() {
// 这里可以使用Chart.js或其他图表库来实现威胁分析图表
this.container.innerHTML = '<div class="text-center p-5">威胁分析图表加载中...</div>';
}
}
// 战场活动播报
class BattlefieldActivity {
constructor(containerId) {
this.container = document.getElementById(containerId);
this.activities = [];
this.setupActivity();
}
setupActivity() {
this.container.innerHTML = `
<div class="activity-list">
<div class="activity-item">
<span class="time">10:30</span>
<span class="type warning">警告</span>
<span class="message">检测到未知信号源位于东北方向距离2.5公里</span>
</div>
<div class="activity-item">
<span class="time">10:28</span>
<span class="type info">信息</span>
<span class="message">友军编队完成例行巡逻任务</span>
</div>
</div>
`;
}
addActivity(activity) {
this.activities.unshift(activity);
this.updateDisplay();
}
updateDisplay() {
// 更新活动列表显示
}
}
// 任务执行统计图表
class MissionStats {
constructor(containerId) {
const ctx = document.getElementById(containerId).getContext('2d');
this.chart = new Chart(ctx, {
type: 'line',
data: {
labels: Array.from({length: 12}, (_, i) => `${i*2}:00`),
datasets: [{
label: '任务完成率',
data: Array.from({length: 12}, () => Math.random() * 40 + 60),
borderColor: '#00b4d8',
backgroundColor: 'rgba(0, 180, 216, 0.1)',
fill: true,
tension: 0.4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: true,
max: 100,
grid: {
color: 'rgba(255, 255, 255, 0.1)'
},
ticks: {
color: '#e9ecef'
}
},
x: {
grid: {
color: 'rgba(255, 255, 255, 0.1)'
},
ticks: {
color: '#e9ecef'
}
}
}
}
});
}
}
// 区域覆盖率图表
class AreaCoverage {
constructor(containerId) {
const ctx = document.getElementById(containerId).getContext('2d');
this.chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['已覆盖', '未覆盖'],
datasets: [{
data: [75, 25],
backgroundColor: [
'rgba(0, 180, 216, 0.8)',
'rgba(255, 255, 255, 0.1)'
],
borderWidth: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
color: '#e9ecef'
}
}
}
}
});
}
}
// 系统状态图表
class SystemStatus {
constructor(containerId) {
const ctx = document.getElementById(containerId).getContext('2d');
this.chart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['CPU', '内存', '存储', '网络'],
datasets: [{
label: '使用率',
data: [65, 45, 30, 80],
backgroundColor: 'rgba(0, 180, 216, 0.8)',
borderRadius: 5
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: true,
max: 100,
grid: {
color: 'rgba(255, 255, 255, 0.1)'
},
ticks: {
color: '#e9ecef'
}
},
x: {
grid: {
display: false
},
ticks: {
color: '#e9ecef'
}
}
}
}
});
}
}
class Radar3D {
constructor(containerId) {
this.container = document.getElementById(containerId);
if (!this.container) {
console.error('Container not found:', containerId);
return;
}
// 清空容器
while (this.container.firstChild) {
this.container.removeChild(this.container.firstChild);
}
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(75, this.container.clientWidth / this.container.clientHeight, 0.1, 1000);
try {
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
console.log('Renderer created successfully');
} catch (error) {
console.error('Failed to create renderer:', error);
return;
}
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
this.renderer.setClearColor(0x000000, 0.1);
this.container.appendChild(this.renderer.domElement);
console.log('Renderer added to container');
// 设置相机位置
this.camera.position.set(50, 30, 50);
this.camera.lookAt(0, 0, 0);
// 创建场景内容
this.createScene();
// 添加事件监听
window.addEventListener('resize', () => this.onWindowResize());
// 开始动画循环
this.animate();
console.log('Animation started');
}
createScene() {
try {
// 添加环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
this.scene.add(ambientLight);
// 添加点光源
const pointLight = new THREE.PointLight(0x00b4d8, 1);
pointLight.position.set(10, 10, 10);
this.scene.add(pointLight);
// 创建地面网格
const gridHelper = new THREE.GridHelper(100, 20, 0x404040, 0x404040);
this.scene.add(gridHelper);
// 创建坐标轴
const axesHelper = new THREE.AxesHelper(50);
this.scene.add(axesHelper);
// 创建雷达平面
const radarGeometry = new THREE.CircleGeometry(40, 64);
const radarMaterial = new THREE.MeshPhongMaterial({
color: 0x00b4d8,
transparent: true,
opacity: 0.3,
side: THREE.DoubleSide
});
this.radarMesh = new THREE.Mesh(radarGeometry, radarMaterial);
this.radarMesh.rotation.x = -Math.PI / 2;
this.scene.add(this.radarMesh);
// 创建扫描线
const lineGeometry = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(40, 0, 0)
]);
const lineMaterial = new THREE.LineBasicMaterial({
color: 0x00ff00,
linewidth: 2
});
this.radarLine = new THREE.Line(lineGeometry, lineMaterial);
this.radarLine.rotation.x = -Math.PI / 2;
this.scene.add(this.radarLine);
// 设置轨道控制器
if (window.OrbitControls) {
this.controls = new window.OrbitControls(this.camera, this.renderer.domElement);
this.controls.enableDamping = true;
this.controls.dampingFactor = 0.05;
console.log('OrbitControls initialized');
} else {
console.error('OrbitControls not available');
}
console.log('Scene created successfully');
} catch (error) {
console.error('Error creating scene:', error);
}
}
addTarget(position, type = 'unknown') {
const colors = {
friendly: 0x2ecc71,
hostile: 0xe74c3c,
unknown: 0xf1c40f
};
const geometry = new THREE.SphereGeometry(1, 16, 16);
const material = new THREE.MeshPhongMaterial({
color: colors[type],
emissive: colors[type],
emissiveIntensity: 0.5
});
const target = new THREE.Mesh(geometry, material);
target.position.set(position.x, position.y, position.z);
this.scene.add(target);
}
onWindowResize() {
if (!this.camera || !this.renderer || !this.container) return;
const width = this.container.clientWidth;
const height = this.container.clientHeight;
this.camera.aspect = width / height;
this.camera.updateProjectionMatrix();
this.renderer.setSize(width, height);
}
animate() {
if (!this.renderer || !this.scene || !this.camera) return;
requestAnimationFrame(() => this.animate());
if (this.radarLine) {
this.radarLine.rotation.z += 0.02;
}
if (this.controls) {
this.controls.update();
}
this.renderer.render(this.scene, this.camera);
}
}
// 初始化
document.addEventListener('DOMContentLoaded', () => {
// 更新时间
updateTime();
setInterval(updateTime, 1000);
// 初始化雷达
const radar = new Radar3D('tacticalRadar');
// 初始化状态卡片迷你图表
const miniCharts = [];
document.querySelectorAll('.mini-chart').forEach(container => {
const chart = new StatusMiniChart(container);
miniCharts.push(chart);
});
// 更新迷你图表
setInterval(() => {
miniCharts.forEach(chart => chart.update());
}, 2000);
// 初始化其他图表
const missionStats = new MissionStats('missionStats');
const areaCoverage = new AreaCoverage('areaCoverage');
const systemStatus = new SystemStatus('systemStatus');
// 添加按钮事件监听
document.querySelectorAll('.radar-controls .btn, .card-tools .btn').forEach(btn => {
btn.addEventListener('click', function() {
// 这里可以添加按钮的具体功能
console.log('Button clicked:', this.querySelector('i').className);
});
});
// 添加示例目标
radar.addTarget({ x: 20, y: 0, z: 20 }, 'friendly');
radar.addTarget({ x: -15, y: 5, z: -25 }, 'hostile');
radar.addTarget({ x: 30, y: 2, z: -10 }, 'unknown');
});

@ -0,0 +1,169 @@
// 全局变量
let currentUser = null;
let threatChart = null;
let radarTargets = []; // 存储雷达上的目标
let radarInterval = null; // 存储雷达更新间隔
// 显示提示消息
function showToast(message, type = 'info') {
// 创建toast容器如果不存在
let toastContainer = document.getElementById('toast-container');
if (!toastContainer) {
toastContainer = document.createElement('div');
toastContainer.id = 'toast-container';
toastContainer.className = 'position-fixed top-0 end-0 p-3';
toastContainer.style.zIndex = '1050';
document.body.appendChild(toastContainer);
}
// 创建toast元素
const toastId = 'toast-' + Date.now();
const toast = document.createElement('div');
toast.className = `toast align-items-center text-white bg-${type} border-0`;
toast.id = toastId;
toast.setAttribute('role', 'alert');
toast.setAttribute('aria-live', 'assertive');
toast.setAttribute('aria-atomic', 'true');
toast.innerHTML = `
<div class="d-flex">
<div class="toast-body">
${message}
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
`;
toastContainer.appendChild(toast);
// 显示toast
const bsToast = new bootstrap.Toast(toast, {
animation: true,
autohide: true,
delay: 3000
});
bsToast.show();
// 自动删除toast元素
toast.addEventListener('hidden.bs.toast', function() {
toast.remove();
});
}
// 处理登录
function handleLogin(event) {
event.preventDefault();
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
// 硬编码的用户验证
if (username === 'admin' && password === '123') {
// 保存登录状态
currentUser = {
username: 'admin',
token: 'dummy-token'
};
// 保存到 localStorage
localStorage.setItem('currentUser', JSON.stringify(currentUser));
// 显示成功消息
showToast('登录成功', 'success');
// 跳转到仪表盘页面
setTimeout(() => {
window.location.href = 'dashboard.html';
}, 1000);
return false;
} else {
showToast('用户名或密码错误', 'danger');
return false;
}
}
// 退出登录
function logout() {
currentUser = null;
localStorage.removeItem('currentUser');
// 清除雷达间隔
if (radarInterval) {
clearInterval(radarInterval);
radarInterval = null;
}
// 重定向到登录页面
window.location.href = 'login.html';
}
// 初始化侧边栏
function initializeSidebar() {
// 处理侧边栏链接点击
document.querySelectorAll('.nav-link').forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
// 处理退出登录
if (this.id === 'logout-tab') {
logout();
return;
}
// 更新活动标签
document.querySelectorAll('.nav-link').forEach(nav => nav.classList.remove('active'));
this.classList.add('active');
// 获取目标页面
const targetPage = this.getAttribute('href');
if (targetPage) {
window.location.href = targetPage;
}
});
});
}
// 检查登录状态
function checkAuth() {
// 从 localStorage 获取用户信息
const savedUser = localStorage.getItem('currentUser');
if (savedUser) {
currentUser = JSON.parse(savedUser);
return true;
}
// 如果不在登录页面,则重定向到登录页面
if (!window.location.pathname.includes('login.html')) {
window.location.href = 'login.html';
}
return false;
}
// 更新用户信息显示
function updateUserInfo() {
if (currentUser) {
const userNameElement = document.getElementById('user-name');
if (userNameElement) {
userNameElement.textContent = currentUser.username;
}
}
}
// 初始化页面
function initializePage() {
// 如果是登录页面,不需要检查认证
if (window.location.pathname.includes('login.html')) {
return;
}
if (!checkAuth()) return;
initializeSidebar();
updateUserInfo();
}
// 在页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
initializePage();
});

@ -0,0 +1,341 @@
// 初始化地图
let map;
let droneMarkers = {};
document.addEventListener('DOMContentLoaded', function() {
// 首先加载无人机列表和其他UI元素
loadDroneData();
// 绑定事件处理器
bindEventHandlers();
// 延迟加载地图和实时更新功能
setTimeout(() => {
initMap();
initRealTimeUpdates();
}, 100);
});
function initMap() {
try {
// 使用百度地图
map = new BMap.Map('map');
// 设置中心点和缩放级别
const point = new BMap.Point(116.4074, 39.9042);
map.centerAndZoom(point, 13);
// 开启鼠标滚轮缩放
map.enableScrollWheelZoom(true);
// 添加地图控件
map.addControl(new BMap.NavigationControl()); // 添加平移缩放控件
map.addControl(new BMap.ScaleControl()); // 添加比例尺控件
map.addControl(new BMap.MapTypeControl()); // 添加地图类型控件
// 设置地图样式 - 暗色主题
map.setMapStyle({
style: 'midnight' // 使用暗色主题
});
} catch (error) {
console.error('地图初始化失败:', error);
document.getElementById('map').innerHTML = '<div class="alert alert-warning">地图加载中,请稍候...</div>';
}
}
function initRealTimeUpdates() {
// 降低更新频率从5秒改为10秒
setInterval(() => {
if (map && Object.keys(droneMarkers).length > 0) {
updateDronePositions();
updateBatteryLevels();
}
}, 10000);
// 告警更新频率降低到30秒
setInterval(() => {
updateAlerts();
}, 30000);
}
function bindEventHandlers() {
// 刷新状态按钮
document.getElementById('refreshStatus').addEventListener('click', () => {
loadDroneData();
});
// 任务分配表单提交
document.getElementById('assignTaskForm').addEventListener('submit', (e) => {
e.preventDefault();
assignTask();
});
// 添加无人机表单保存
document.getElementById('saveDrone').addEventListener('click', () => {
saveDrone();
});
}
function loadDroneData() {
// 添加加载状态指示
const tbody = document.getElementById('dronesList');
tbody.innerHTML = '<tr><td colspan="7" class="text-center">加载中...</td></tr>';
// 模拟从后端加载数据
const drones = [
{
id: 'UAV-001',
model: '侦察者-X1',
status: 'online',
battery: 85,
task: '巡逻任务',
position: {
lng: 116.4074,
lat: 39.9042
}
},
{
id: 'UAV-002',
model: '侦察者-X2',
status: 'mission',
battery: 65,
task: '侦察任务',
position: {
lng: 116.4174,
lat: 39.9142
}
},
{
id: 'UAV-003',
model: '追踪者-A1',
status: 'maintenance',
battery: 45,
task: '维护中',
position: {
lng: 116.4274,
lat: 39.9242
}
}
];
// 立即更新无人机列表
updateDroneList(drones);
// 如果地图已经初始化,则更新标记
if (map) {
updateMapMarkers(drones);
}
}
function updateDroneList(drones) {
const tbody = document.getElementById('dronesList');
tbody.innerHTML = '';
drones.forEach(drone => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${drone.id}</td>
<td>${drone.model}</td>
<td><span class="status-indicator status-${drone.status}"></span>${getStatusText(drone.status)}</td>
<td>
<div class="battery-indicator">
<div class="battery-level" style="width: ${drone.battery}%"></div>
</div>
</td>
<td>${drone.task}</td>
<td>${formatPosition(drone.position)}</td>
<td>
<div class="btn-group">
<button class="btn btn-sm btn-outline-primary" onclick="showDroneDetails('${drone.id}')">
<i class="fas fa-info-circle"></i>
</button>
<button class="btn btn-sm btn-outline-success" onclick="controlDrone('${drone.id}')">
<i class="fas fa-gamepad"></i>
</button>
<button class="btn btn-sm btn-outline-warning" onclick="maintainDrone('${drone.id}')">
<i class="fas fa-tools"></i>
</button>
</div>
</td>
`;
tbody.appendChild(tr);
});
}
function updateMapMarkers(drones) {
// 清除现有标记
map.clearOverlays();
droneMarkers = {};
// 添加新标记
drones.forEach(drone => {
// 创建标记点
const point = new BMap.Point(drone.position.lng, drone.position.lat);
const marker = new BMap.Marker(point);
// 创建信息窗口
const content = `
<div style="padding: 10px;">
<h5>${drone.id}</h5>
<p>型号: ${drone.model}<br>
状态: ${getStatusText(drone.status)}<br>
电量: ${drone.battery}%<br>
任务: ${drone.task}</p>
</div>
`;
const infoWindow = new BMap.InfoWindow(content, {
width: 200,
height: 120,
title: `${drone.id} - ${drone.model}`
});
// 点击标记时显示信息窗口
marker.addEventListener('click', function() {
map.openInfoWindow(infoWindow, point);
});
// 将标记添加到地图
map.addOverlay(marker);
droneMarkers[drone.id] = {
marker: marker,
point: point
};
});
}
function updateDronePositions() {
// 模拟无人机位置更新
Object.keys(droneMarkers).forEach(droneId => {
const markerData = droneMarkers[droneId];
if (markerData && markerData.marker) {
const currentPoint = markerData.point;
// 随机移动位置
const newLng = currentPoint.lng + (Math.random() - 0.5) * 0.01;
const newLat = currentPoint.lat + (Math.random() - 0.5) * 0.01;
const newPoint = new BMap.Point(newLng, newLat);
// 创建动画移动效果
const moveAnimation = new BMap.Animation.Move(markerData.marker, {
points: [currentPoint, newPoint],
duration: 1000
});
moveAnimation.start();
// 更新保存的位置
markerData.point = newPoint;
}
});
}
function updateBatteryLevels() {
// 模拟电池电量更新
document.querySelectorAll('.battery-level').forEach(battery => {
const currentWidth = parseInt(battery.style.width);
if (currentWidth > 0) {
battery.style.width = `${currentWidth - 1}%`;
}
});
}
function updateAlerts() {
// 模拟告警更新
const alertPanel = document.querySelector('.alert-panel ul');
const currentTime = new Date().toLocaleTimeString();
// 随机添加新告警
if (Math.random() < 0.3) {
const alerts = [
'通信信号弱,建议调整位置',
'检测到强风,建议降低飞行高度',
'接近禁飞区域边界',
'发现可疑目标,建议进一步确认'
];
const newAlert = alerts[Math.floor(Math.random() * alerts.length)];
const li = document.createElement('li');
li.innerHTML = `<small class="text-warning">• ${currentTime} - ${newAlert}</small>`;
alertPanel.insertBefore(li, alertPanel.firstChild);
// 限制告警数量
if (alertPanel.children.length > 5) {
alertPanel.removeChild(alertPanel.lastChild);
}
}
}
function showDroneDetails(droneId) {
// 更新详情面板
const detailPanel = document.getElementById('droneDetailPanel');
detailPanel.querySelector('h5').textContent = `无人机详情 - ${droneId}`;
// 模拟加载详细信息
// 实际应用中应该从后端获取数据
}
function controlDrone(droneId) {
// 实现无人机控制逻辑
console.log(`控制无人机: ${droneId}`);
}
function maintainDrone(droneId) {
// 实现维护模式逻辑
console.log(`维护无人机: ${droneId}`);
}
function assignTask() {
const formData = {
droneId: document.getElementById('droneSelect').value,
taskType: document.getElementById('taskType').value,
taskArea: document.getElementById('taskArea').value,
priority: document.getElementById('taskPriority').value,
estimatedTime: document.getElementById('estimatedTime').value
};
// 实际应用中应该发送到后端
console.log('分配任务:', formData);
// 模拟成功响应
alert('任务分配成功!');
}
function saveDrone() {
const formData = {
model: document.getElementById('droneModel').value,
serialNumber: document.getElementById('serialNumber').value,
maxFlightTime: document.getElementById('maxFlightTime').value,
maxPayload: document.getElementById('maxPayload').value,
communicationBand: document.getElementById('communicationBand').value,
hasCamera: document.getElementById('hasCamera').checked,
hasInfrared: document.getElementById('hasInfrared').checked,
hasGPS: document.getElementById('hasGPS').checked
};
// 实际应用中应该发送到后端
console.log('添加无人机:', formData);
// 模拟成功响应
alert('无人机添加成功!');
// 关闭模态框
const modal = bootstrap.Modal.getInstance(document.getElementById('addDroneModal'));
modal.hide();
}
// 辅助函数
function getStatusText(status) {
const statusMap = {
'online': '在线',
'mission': '任务中',
'maintenance': '维护中',
'offline': '离线'
};
return statusMap[status] || status;
}
function formatPosition(position) {
return `N ${position.lat.toFixed(4)}° E ${position.lng.toFixed(4)}°`;
}

@ -0,0 +1,500 @@
// 更新时间显示
function updateTime() {
const now = new Date();
document.getElementById('current-time').textContent = now.toLocaleString();
}
setInterval(updateTime, 1000);
// 初始化图表
function initializeCharts() {
// 置信度历史图表
const confidenceCtx = document.getElementById('confidenceChart').getContext('2d');
const confidenceChart = new Chart(confidenceCtx, {
type: 'line',
data: {
labels: ['10:25', '10:26', '10:27', '10:28', '10:29', '10:30'],
datasets: [{
label: '识别置信度',
data: [65, 75, 82, 78, 85, 88],
borderColor: '#00b4d8',
backgroundColor: 'rgba(0, 180, 216, 0.1)',
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
tooltip: {
mode: 'index',
intersect: false,
backgroundColor: 'rgba(0, 0, 0, 0.8)',
titleColor: '#fff',
bodyColor: '#fff',
borderColor: 'rgba(255, 255, 255, 0.1)',
borderWidth: 1
}
},
scales: {
y: {
beginAtZero: true,
max: 100,
grid: {
color: 'rgba(255, 255, 255, 0.1)'
},
ticks: {
color: 'rgba(255, 255, 255, 0.7)',
callback: function(value) {
return value + '%';
}
}
},
x: {
grid: {
color: 'rgba(255, 255, 255, 0.1)'
},
ticks: {
color: 'rgba(255, 255, 255, 0.7)'
}
}
},
interaction: {
intersect: false,
mode: 'index'
},
animation: {
duration: 1000,
easing: 'easeInOutQuart'
}
}
});
// 目标类型分布图表
const distributionCtx = document.getElementById('typeDistributionChart').getContext('2d');
const distributionChart = new Chart(distributionCtx, {
type: 'doughnut',
data: {
labels: ['友方目标', '敌方目标', '未知目标'],
datasets: [{
data: [4, 3, 2],
backgroundColor: [
'#2ecc71',
'#e74c3c',
'#f1c40f'
],
borderWidth: 0,
hoverOffset: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
labels: {
color: 'rgba(255, 255, 255, 0.7)',
font: {
size: 11
},
padding: 20,
usePointStyle: true,
pointStyle: 'circle'
}
},
tooltip: {
backgroundColor: 'rgba(0, 0, 0, 0.8)',
titleColor: '#fff',
bodyColor: '#fff',
borderColor: 'rgba(255, 255, 255, 0.1)',
borderWidth: 1
}
},
animation: {
animateRotate: true,
animateScale: true
}
}
});
// 导出图表更新函数
window.updateCharts = {
updateConfidence: function(newData) {
confidenceChart.data.datasets[0].data = newData;
confidenceChart.update('none');
},
updateDistribution: function(newData) {
distributionChart.data.datasets[0].data = newData;
distributionChart.update('none');
}
};
}
// 模拟目标检测框
function simulateTargetDetection() {
const videoContainer = document.querySelector('.video-container');
const targetBox = document.querySelector('.target-box');
let isTracking = false;
function updateTargetPosition() {
if (!isTracking) return;
const maxX = videoContainer.clientWidth - 100;
const maxY = videoContainer.clientHeight - 100;
const x = Math.random() * maxX;
const y = Math.random() * maxY;
targetBox.style.display = 'block';
targetBox.style.left = x + 'px';
targetBox.style.top = y + 'px';
// 更新目标信息
updateTargetInfo({
type: ['未知目标', '友方目标', '敌方目标'][Math.floor(Math.random() * 3)],
distance: Math.floor(Math.random() * 5000 + 1000),
confidence: Math.floor(Math.random() * 30 + 70)
});
}
// 开始/停止跟踪
window.toggleTracking = function(start) {
isTracking = start;
if (start) {
targetBox.style.display = 'block';
updateTargetPosition();
} else {
targetBox.style.display = 'none';
}
};
setInterval(updateTargetPosition, 3000);
}
// 更新目标信息
function updateTargetInfo(data) {
const targetType = document.getElementById('targetType');
const confidenceBar = document.querySelector('.progress-bar');
const distance = document.getElementById('distance');
const threatLevel = document.getElementById('threatLevel');
targetType.textContent = data.type;
confidenceBar.style.width = data.confidence + '%';
confidenceBar.textContent = data.confidence + '%';
distance.textContent = (data.distance / 1000).toFixed(1) + 'km';
// 更新威胁等级
const threatLevels = ['低', '中', '高'];
const threatColors = ['success', 'warning', 'danger'];
const threatIndex = Math.floor(Math.random() * 3);
threatLevel.className = `badge bg-${threatColors[threatIndex]}`;
threatLevel.textContent = threatLevels[threatIndex];
}
// 绑定控制按钮事件
function bindControlEvents() {
const startBtn = document.getElementById('startStream');
const stopBtn = document.getElementById('stopStream');
const captureBtn = document.getElementById('captureImage');
const toggleARBtn = document.getElementById('toggleAR');
const toggleNightVisionBtn = document.getElementById('toggleNightVision');
const toggleThermalBtn = document.getElementById('toggleThermal');
let isStreaming = false;
startBtn.addEventListener('click', () => {
isStreaming = true;
document.querySelector('.status-dot').classList.add('active');
window.toggleTracking(true);
showToast('开始目标识别');
});
stopBtn.addEventListener('click', () => {
isStreaming = false;
document.querySelector('.status-dot').classList.remove('active');
window.toggleTracking(false);
showToast('停止目标识别');
});
captureBtn.addEventListener('click', () => {
showToast('已保存截图');
// 添加截图动画效果
const flash = document.createElement('div');
flash.className = 'capture-flash';
document.querySelector('.video-container').appendChild(flash);
setTimeout(() => flash.remove(), 200);
});
const toggleButtons = [
{ btn: toggleARBtn, name: 'AR叠加' },
{ btn: toggleNightVisionBtn, name: '夜视模式' },
{ btn: toggleThermalBtn, name: '热成像' }
];
toggleButtons.forEach(({ btn, name }) => {
btn.addEventListener('click', () => {
const isActive = btn.classList.toggle('active');
showToast(`${name}${isActive ? '开启' : '关闭'}`);
});
});
}
// Toast提示
function showToast(message) {
const toast = document.createElement('div');
toast.className = 'toast-message';
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => {
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => toast.remove(), 300);
}, 2000);
}, 100);
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
initializeCharts();
simulateTargetDetection();
bindControlEvents();
updateTime();
// 添加键盘快捷键
document.addEventListener('keydown', function(e) {
if (e.key === 'F' || e.key === 'f') {
document.getElementById('captureImage').click();
}
});
});
// 初始化筛选器
function initializeFilters() {
const filterForm = document.getElementById('filterForm');
filterForm.addEventListener('submit', function(e) {
e.preventDefault();
loadRecords();
});
// 重置按钮事件
filterForm.addEventListener('reset', function(e) {
setTimeout(() => loadRecords(), 0);
});
// 时间范围选择器事件
const timeRange = document.getElementById('timeRange');
timeRange.addEventListener('change', function() {
if (this.value === 'custom') {
// TODO: 显示自定义日期选择器
}
});
}
// 加载记录数据
async function loadRecords() {
try {
const filters = getFilters();
// TODO: 替换为实际的API调用
const response = await fetch('/api/records?' + new URLSearchParams(filters));
const data = await response.json();
updateRecordsList(data.records);
updatePagination(data.pagination);
updateStats(data.stats);
} catch (error) {
console.error('加载记录失败:', error);
showError('加载记录失败,请稍后重试');
}
}
// 获取筛选条件
function getFilters() {
return {
timeRange: document.getElementById('timeRange').value,
targetType: document.getElementById('targetType').value,
identificationStatus: document.getElementById('identificationStatus').value,
threatLevel: document.getElementById('threatLevel').value,
page: currentPage
};
}
// 更新记录列表
function updateRecordsList(records) {
const tbody = document.getElementById('recordsList');
tbody.innerHTML = records.map(record => `
<tr class="fade-in">
<td>${formatDateTime(record.time)}</td>
<td><span class="badge badge-${record.type.toLowerCase()}">${formatType(record.type)}</span></td>
<td>${record.result}</td>
<td>
<div class="progress" style="height: 6px;">
<div class="progress-bar bg-${getConfidenceColor(record.confidence)}"
role="progressbar"
style="width: ${record.confidence}%">
</div>
</div>
<small class="text-muted">${record.confidence}%</small>
</td>
<td><span class="badge badge-${getThreatClass(record.threatLevel)}">${formatThreatLevel(record.threatLevel)}</span></td>
<td>${formatLocation(record.location)}</td>
<td>
<button class="btn btn-sm btn-primary" onclick="showRecordDetail(${record.id})">
<i class="fas fa-eye"></i>
</button>
</td>
</tr>
`).join('');
}
// 更新分页
function updatePagination(pagination) {
const paginationElement = document.querySelector('.pagination');
paginationElement.innerHTML = `
<li class="page-item ${pagination.currentPage === 1 ? 'disabled' : ''}">
<a class="page-link" href="#" onclick="changePage(${pagination.currentPage - 1})">上一页</a>
</li>
${generatePageNumbers(pagination)}
<li class="page-item ${pagination.currentPage === pagination.totalPages ? 'disabled' : ''}">
<a class="page-link" href="#" onclick="changePage(${pagination.currentPage + 1})">下一页</a>
</li>
`;
}
// 生成页码
function generatePageNumbers(pagination) {
let pages = [];
const current = pagination.currentPage;
const total = pagination.totalPages;
if (total <= 5) {
for (let i = 1; i <= total; i++) {
pages.push(i);
}
} else {
if (current <= 3) {
pages = [1, 2, 3, 4, '...', total];
} else if (current >= total - 2) {
pages = [1, '...', total - 3, total - 2, total - 1, total];
} else {
pages = [1, '...', current - 1, current, current + 1, '...', total];
}
}
return pages.map(page => {
if (page === '...') {
return '<li class="page-item disabled"><span class="page-link">...</span></li>';
}
return `
<li class="page-item ${page === current ? 'active' : ''}">
<a class="page-link" href="#" onclick="changePage(${page})">${page}</a>
</li>
`;
}).join('');
}
// 显示记录详情
function showRecordDetail(recordId) {
// TODO: 替换为实际的API调用
fetch(`/api/records/${recordId}`)
.then(response => response.json())
.then(record => {
document.getElementById('detailTime').textContent = formatDateTime(record.time);
document.getElementById('detailType').innerHTML = `<span class="badge badge-${record.type.toLowerCase()}">${formatType(record.type)}</span>`;
document.getElementById('detailResult').textContent = record.result;
document.getElementById('detailConfidence').innerHTML = `
<div class="progress" style="height: 6px;">
<div class="progress-bar bg-${getConfidenceColor(record.confidence)}"
role="progressbar"
style="width: ${record.confidence}%">
</div>
</div>
<small class="text-muted">${record.confidence}%</small>
`;
document.getElementById('detailThreat').innerHTML = `<span class="badge badge-${getThreatClass(record.threatLevel)}">${formatThreatLevel(record.threatLevel)}</span>`;
document.getElementById('detailLocation').textContent = formatLocation(record.location);
document.getElementById('targetImage').src = record.imageUrl;
const modal = new bootstrap.Modal(document.getElementById('recordDetailModal'));
modal.show();
})
.catch(error => {
console.error('加载记录详情失败:', error);
showError('加载记录详情失败,请稍后重试');
});
}
// 格式化函数
function formatDateTime(timestamp) {
return new Date(timestamp).toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
function formatType(type) {
const types = {
'friendly': '友方',
'hostile': '敌方',
'unknown': '未知'
};
return types[type.toLowerCase()] || type;
}
function formatThreatLevel(level) {
const levels = {
'high': '高',
'medium': '中',
'low': '低'
};
return levels[level.toLowerCase()] || level;
}
function formatLocation(location) {
if (typeof location === 'object') {
return `N ${location.latitude}° E ${location.longitude}°`;
}
return location;
}
// 辅助函数
function getConfidenceColor(confidence) {
if (confidence >= 90) return 'success';
if (confidence >= 70) return 'warning';
return 'danger';
}
function getThreatClass(level) {
const classes = {
'high': 'danger',
'medium': 'warning',
'low': 'success'
};
return classes[level.toLowerCase()] || 'secondary';
}
// 错误提示
function showError(message) {
// TODO: 实现错误提示UI
console.error(message);
}
// 导出功能
document.querySelector('.btn-group .btn-outline-primary').addEventListener('click', function() {
const filters = getFilters();
// TODO: 实现导出功能
window.location.href = '/api/records/export?' + new URLSearchParams(filters);
});
// 打印功能
document.querySelectorAll('.btn-group .btn-outline-primary')[1].addEventListener('click', function() {
window.print();
});

@ -0,0 +1,261 @@
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
initializeSignalCanvas();
initializeControls();
setupEventListeners();
});
let isScanning = false;
let animationFrameId = null;
let scanningData = [];
let currentFrequency = 2400; // MHz
// 初始化信号画布
function initializeSignalCanvas() {
const canvas = document.getElementById('signalCanvas');
const ctx = canvas.getContext('2d');
// 设置画布大小
function resizeCanvas() {
const container = canvas.parentElement;
canvas.width = container.clientWidth;
canvas.height = container.clientHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// 初始化扫描数据
for (let i = 0; i < 100; i++) {
scanningData.push(Math.random() * 0.5);
}
// 开始动画循环
function animate() {
if (!isScanning) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawSignalWaveform(ctx);
animationFrameId = requestAnimationFrame(animate);
}
// 绘制信号波形
function drawSignalWaveform(ctx) {
const width = canvas.width;
const height = canvas.height;
const points = 100;
// 更新扫描数据
scanningData.shift();
scanningData.push(Math.random() * 0.5 + (isScanning ? Math.random() * 0.5 : 0));
// 绘制网格
drawGrid(ctx, width, height);
// 绘制波形
ctx.beginPath();
ctx.strokeStyle = '#00b4d8';
ctx.lineWidth = 2;
for (let i = 0; i < points; i++) {
const x = (i / points) * width;
const y = height - (scanningData[i] * height);
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
ctx.stroke();
// 绘制填充
ctx.lineTo(width, height);
ctx.lineTo(0, height);
ctx.closePath();
const gradient = ctx.createLinearGradient(0, 0, 0, height);
gradient.addColorStop(0, 'rgba(0, 180, 216, 0.2)');
gradient.addColorStop(1, 'rgba(0, 180, 216, 0)');
ctx.fillStyle = gradient;
ctx.fill();
}
// 绘制网格
function drawGrid(ctx, width, height) {
const gridSize = 40;
ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
ctx.lineWidth = 1;
// 绘制垂直线
for (let x = 0; x <= width; x += gridSize) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.stroke();
}
// 绘制水平线
for (let y = 0; y <= height; y += gridSize) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y);
ctx.stroke();
}
}
// 导出动画控制函数
window.startAnimation = function() {
if (!isScanning) {
isScanning = true;
animate();
}
};
window.stopAnimation = function() {
isScanning = false;
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
};
}
// 初始化控制器
function initializeControls() {
const startButton = document.getElementById('startSignalScan');
const stopButton = document.getElementById('stopSignalScan');
const captureButton = document.getElementById('captureSignal');
const frequencyRange = document.getElementById('frequencyRange');
const scanSpeed = document.getElementById('scanSpeed');
// 开始扫描
startButton.addEventListener('click', function() {
startButton.disabled = true;
stopButton.disabled = false;
window.startAnimation();
updateSignalInfo();
});
// 停止扫描
stopButton.addEventListener('click', function() {
startButton.disabled = false;
stopButton.disabled = true;
window.stopAnimation();
});
// 捕获信号
captureButton.addEventListener('click', function() {
captureCurrentSignal();
});
// 频率范围选择
frequencyRange.addEventListener('change', function() {
updateFrequencyRange(this.value);
});
// 扫描速度调节
scanSpeed.addEventListener('input', function() {
updateScanSpeed(this.value);
});
}
// 更新信号信息
function updateSignalInfo() {
if (!isScanning) return;
// 模拟信号数据更新
const frequencyStep = Math.random() * 10 - 5;
currentFrequency = Math.max(300, Math.min(5000, currentFrequency + frequencyStep));
document.getElementById('currentFrequency').textContent = `${(currentFrequency / 1000).toFixed(2)} GHz`;
document.getElementById('signalStrength').textContent = `${-Math.floor(Math.random() * 20 + 60)} dBm`;
document.getElementById('bandwidth').textContent = `${Math.floor(Math.random() * 10 + 15)} MHz`;
document.getElementById('snr').textContent = `${Math.floor(Math.random() * 10 + 25)} dB`;
setTimeout(() => {
if (isScanning) {
updateSignalInfo();
}
}, 1000);
}
// 捕获当前信号
function captureCurrentSignal() {
const signalTypes = ['遥控信号', '数据链路', '图传信号', '干扰信号'];
const modulationTypes = ['QPSK', 'OFDM', '16QAM', 'FHSS'];
const encryptionTypes = ['AES-256', 'RSA-2048', 'ECC', '未加密'];
// 更新信号特征
document.getElementById('signalType').textContent = signalTypes[Math.floor(Math.random() * signalTypes.length)];
document.getElementById('modulationType').textContent = modulationTypes[Math.floor(Math.random() * modulationTypes.length)];
document.getElementById('encryptionType').textContent = encryptionTypes[Math.floor(Math.random() * encryptionTypes.length)];
// 显示捕获成功提示
showToast('信号捕获成功');
}
// 更新频率范围
function updateFrequencyRange(range) {
const ranges = {
'low': { min: 300, max: 1000 },
'mid': { min: 1000, max: 2400 },
'high': { min: 2400, max: 5000 }
};
if (range !== 'all' && ranges[range]) {
currentFrequency = (ranges[range].min + ranges[range].max) / 2;
}
}
// 更新扫描速度
function updateScanSpeed(speed) {
// 实现扫描速度调节逻辑
}
// 设置事件监听器
function setupEventListeners() {
// 全屏切换
document.getElementById('toggleFullscreen').addEventListener('click', function() {
const signalContainer = document.querySelector('.signal-container');
if (!document.fullscreenElement) {
signalContainer.requestFullscreen();
this.innerHTML = '<i class="fas fa-compress"></i>';
} else {
document.exitFullscreen();
this.innerHTML = '<i class="fas fa-expand"></i>';
}
});
// 导出记录
document.querySelector('.btn-outline-primary').addEventListener('click', function() {
// 实现导出功能
showToast('记录导出成功');
});
// 清除记录
document.querySelector('.btn-outline-danger').addEventListener('click', function() {
if (confirm('确定要清除所有记录吗?')) {
// 实现清除功能
showToast('记录已清除');
}
});
}
// 显示提示信息
function showToast(message) {
// 创建提示元素
const toast = document.createElement('div');
toast.className = 'toast-message';
toast.textContent = message;
document.body.appendChild(toast);
// 添加动画类
setTimeout(() => toast.classList.add('show'), 100);
// 自动移除
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => toast.remove(), 300);
}, 3000);
}

@ -0,0 +1,203 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>战场态势 - 无人机敌我识别系统</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.0.0/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
<link href="common/css/style.css" rel="stylesheet">
</head>
<body class="battlefield-theme">
<div class="sidebar">
<div class="sidebar-header">
<h4>
<div class="logo-icon">
<i class="fas fa-drone"></i>
</div>
无人机敌我识别系统
</h4>
</div>
<nav class="nav flex-column">
<a class="nav-link active" href="dashboard.html">
<i class="fas fa-chart-line"></i>战场态势
</a>
<a class="nav-link" href="identification.html">
<i class="fas fa-crosshairs"></i>目标识别
</a>
<a class="nav-link" href="drones.html">
<i class="fas fa-drone"></i>无人机管理
</a>
<a class="nav-link" href="records.html">
<i class="fas fa-history"></i>识别记录
</a>
<a class="nav-link" href="signal.html">
<i class="fas fa-broadcast-tower"></i>信号识别
</a>
</nav>
</div>
<div class="main-content">
<div class="container-fluid">
<div class="battlefield-header">
<div class="header-left">
<h2 class="page-title">战场态势</h2>
<div class="battlefield-time">
<i class="fas fa-clock"></i>
<span id="current-time">2024-01-01 12:00:00</span>
</div>
</div>
<div class="operator-info">
<i class="fas fa-user-shield"></i>
操作员:战术指挥官
<span class="status-badge online">在线</span>
</div>
</div>
<div class="row status-cards">
<div class="col-md-3">
<div class="status-card executing">
<div class="status-info">
<h3>执行中无人机</h3>
<div class="status-value">0</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="status-card identification">
<div class="status-info">
<h3>今日识别数</h3>
<div class="status-value">0</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="status-card friendly">
<div class="status-info">
<h3>友方目标数</h3>
<div class="status-value">0</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="status-card hostile">
<div class="status-info">
<h3>敌方目标数</h3>
<div class="status-value">0</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8">
<div class="card battlefield-card main-radar-card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-radar"></i>实时战术态势
</h5>
<div class="radar-controls">
<button class="btn btn-sm btn-outline-info" id="toggleFullscreen">
<i class="fas fa-expand"></i>
</button>
<button class="btn btn-sm btn-outline-info" id="resetCamera">
<i class="fas fa-sync"></i>
</button>
<button class="btn btn-sm btn-outline-info" id="toggleGrid">
<i class="fas fa-th"></i>
</button>
</div>
</div>
<div class="card-body">
<div class="radar-stats">
<div class="stat-item">
<span class="label">扫描范围</span>
<span class="value">100km</span>
</div>
<div class="stat-item">
<span class="label">目标数量</span>
<span class="value">12</span>
</div>
<div class="stat-item">
<span class="label">信号强度</span>
<span class="value">87%</span>
</div>
<div class="stat-item">
<span class="label">高度范围</span>
<span class="value">10km</span>
</div>
</div>
<div id="tacticalRadar" class="tactical-radar"></div>
<div class="radar-legend">
<div class="legend-item">
<span class="dot friendly"></span>
<span>友军目标</span>
</div>
<div class="legend-item">
<span class="dot hostile"></span>
<span>敌军目标</span>
</div>
<div class="legend-item">
<span class="dot unknown"></span>
<span>未识别目标</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card battlefield-card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-shield-alt"></i>威胁态势分析
</h5>
<div class="card-tools">
<button class="btn btn-sm btn-outline-info">
<i class="fas fa-sync"></i>
</button>
</div>
</div>
<div class="card-body">
<div class="threat-level">
<div class="level-label">当前威胁等级</div>
<div class="level-value low"></div>
<div class="level-indicator">
<div class="indicator-bar" style="width: 20%"></div>
</div>
</div>
<div id="threatAnalysis" class="threat-analysis"></div>
</div>
</div>
<div class="card battlefield-card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-bell"></i>战场活动播报
</h5>
<div class="card-tools">
<button class="btn btn-sm btn-outline-info">
<i class="fas fa-filter"></i>
</button>
</div>
</div>
<div class="card-body">
<div id="battlefieldActivity" class="battlefield-activity"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.158.0/three.min.js"></script>
<script type="module">
import { OrbitControls } from 'https://unpkg.com/three@0.158.0/examples/jsm/controls/OrbitControls.js';
window.OrbitControls = OrbitControls;
</script>
<script src="common/js/api.js"></script>
<script src="common/js/common.js"></script>
<script src="common/js/battlefield.js"></script>
</body>
</html>

@ -0,0 +1,451 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>无人机管理 - 无人机敌我识别系统</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.0.0/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
<link href="common/css/style.css" rel="stylesheet">
<style>
#map {
height: 300px;
border-radius: 8px;
background: #f5f5f5;
position: relative;
}
.drone-status-card {
background: rgba(33, 37, 41, 0.8);
border-radius: 10px;
padding: 15px;
margin-bottom: 20px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.status-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
margin-right: 8px;
}
.status-online { background-color: #28a745; }
.status-mission { background-color: #007bff; }
.status-maintenance { background-color: #ffc107; }
.status-offline { background-color: #dc3545; }
.drone-detail-panel {
background: rgba(33, 37, 41, 0.9);
border-radius: 10px;
padding: 20px;
margin-top: 20px;
}
.mission-timeline {
position: relative;
padding-left: 20px;
}
.mission-timeline::before {
content: '';
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 2px;
background: rgba(255, 255, 255, 0.1);
}
.mission-point {
position: relative;
padding-bottom: 15px;
}
.mission-point::before {
content: '';
position: absolute;
left: -24px;
top: 5px;
width: 10px;
height: 10px;
border-radius: 50%;
background: #007bff;
}
.battery-indicator {
width: 100%;
height: 20px;
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
overflow: hidden;
}
.battery-level {
height: 100%;
background: linear-gradient(90deg, #28a745 0%, #ffc107 50%, #dc3545 100%);
transition: width 0.3s ease;
}
.alert-panel {
background: rgba(220, 53, 69, 0.1);
border: 1px solid rgba(220, 53, 69, 0.2);
border-radius: 8px;
padding: 15px;
margin-top: 20px;
}
</style>
<script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=nSxiPohfziUaCuONe4ViUP2N"></script>
</head>
<body>
<div class="sidebar">
<div class="sidebar-header">
<h4>
<div class="logo-icon">
<i class="fas fa-drone"></i>
</div>
无人机敌我识别系统
</h4>
</div>
<nav class="nav flex-column">
<a class="nav-link" href="dashboard.html">
<i class="fas fa-chart-line"></i>战场态势
</a>
<a class="nav-link" href="identification.html">
<i class="fas fa-crosshairs"></i>目标识别
</a>
<a class="nav-link active" href="drones.html">
<i class="fas fa-drone"></i>无人机管理
</a>
<a class="nav-link" href="records.html">
<i class="fas fa-history"></i>识别记录
</a>
<a class="nav-link" href="signal.html">
<i class="fas fa-broadcast-tower"></i>信号识别
</a>
</nav>
</div>
<div class="main-content">
<div class="container-fluid">
<div class="row mb-4">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center">
<h2>无人机管理</h2>
<div>
<button class="btn btn-outline-primary me-2" id="refreshStatus">
<i class="fas fa-sync-alt"></i> 刷新状态
</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addDroneModal">
<i class="fas fa-plus"></i> 添加无人机
</button>
</div>
</div>
</div>
</div>
<!-- 状态概览卡片 -->
<div class="row mb-4">
<div class="col-md-3">
<div class="drone-status-card">
<h6><i class="fas fa-check-circle text-success"></i> 在线无人机</h6>
<h3>15 <small class="text-muted"></small></h3>
<div class="progress mt-2" style="height: 5px;">
<div class="progress-bar bg-success" style="width: 75%"></div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="drone-status-card">
<h6><i class="fas fa-running text-primary"></i> 执行任务中</h6>
<h3>9 <small class="text-muted"></small></h3>
<div class="progress mt-2" style="height: 5px;">
<div class="progress-bar bg-primary" style="width: 45%"></div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="drone-status-card">
<h6><i class="fas fa-tools text-warning"></i> 维护中</h6>
<h3>3 <small class="text-muted"></small></h3>
<div class="progress mt-2" style="height: 5px;">
<div class="progress-bar bg-warning" style="width: 15%"></div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="drone-status-card">
<h6><i class="fas fa-power-off text-danger"></i> 离线</h6>
<h3>2 <small class="text-muted"></small></h3>
<div class="progress mt-2" style="height: 5px;">
<div class="progress-bar bg-danger" style="width: 10%"></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8">
<!-- 无人机位置地图 -->
<div class="card mb-4">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-map-marked-alt"></i> 无人机位置
</h5>
</div>
<div class="card-body">
<div id="map"></div>
</div>
</div>
<!-- 无人机列表 -->
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0">
<i class="fas fa-list"></i> 无人机列表
</h5>
<div class="btn-group">
<button class="btn btn-sm btn-outline-secondary">
<i class="fas fa-filter"></i> 筛选
</button>
<button class="btn btn-sm btn-outline-secondary">
<i class="fas fa-sort"></i> 排序
</button>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>编号</th>
<th>型号</th>
<th>状态</th>
<th>电量</th>
<th>任务</th>
<th>位置</th>
<th>操作</th>
</tr>
</thead>
<tbody id="dronesList">
<!-- 示例数据 -->
<tr>
<td>UAV-001</td>
<td>侦察者-X1</td>
<td><span class="status-indicator status-online"></span>在线</td>
<td>
<div class="battery-indicator">
<div class="battery-level" style="width: 85%"></div>
</div>
</td>
<td>巡逻任务</td>
<td>N 39°54'25" E 116°23'50"</td>
<td>
<div class="btn-group">
<button class="btn btn-sm btn-outline-primary" onclick="showDroneDetails('UAV-001')">
<i class="fas fa-info-circle"></i>
</button>
<button class="btn btn-sm btn-outline-success" onclick="controlDrone('UAV-001')">
<i class="fas fa-gamepad"></i>
</button>
<button class="btn btn-sm btn-outline-warning" onclick="maintainDrone('UAV-001')">
<i class="fas fa-tools"></i>
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="col-lg-4">
<!-- 无人机详情面板 -->
<div class="drone-detail-panel" id="droneDetailPanel">
<h5 class="mb-4">无人机详情 - UAV-001</h5>
<div class="mb-4">
<h6>基本信息</h6>
<div class="row">
<div class="col-6">
<small class="text-muted">型号</small>
<p>侦察者-X1</p>
</div>
<div class="col-6">
<small class="text-muted">序列号</small>
<p>SN20240101001</p>
</div>
<div class="col-6">
<small class="text-muted">续航时间</small>
<p>4小时</p>
</div>
<div class="col-6">
<small class="text-muted">最大载重</small>
<p>5kg</p>
</div>
</div>
</div>
<div class="mb-4">
<h6>实时状态</h6>
<div class="row">
<div class="col-6">
<small class="text-muted">飞行高度</small>
<p>120m</p>
</div>
<div class="col-6">
<small class="text-muted">飞行速度</small>
<p>15m/s</p>
</div>
<div class="col-12">
<small class="text-muted">电池状态</small>
<div class="battery-indicator mt-2">
<div class="battery-level" style="width: 85%"></div>
</div>
<small class="text-muted">预计剩余时间: 3小时15分钟</small>
</div>
</div>
</div>
<div class="mb-4">
<h6>当前任务</h6>
<div class="mission-timeline">
<div class="mission-point">
<small class="text-muted">09:00</small>
<p>开始巡逻任务</p>
</div>
<div class="mission-point">
<small class="text-muted">09:15</small>
<p>到达指定区域A</p>
</div>
<div class="mission-point">
<small class="text-muted">09:30</small>
<p>执行侦察任务</p>
</div>
</div>
</div>
<!-- 告警信息 -->
<div class="alert-panel">
<h6><i class="fas fa-exclamation-triangle text-danger"></i> 告警信息</h6>
<ul class="list-unstyled mb-0">
<li class="mb-2">
<small class="text-danger">• 电池电量低于20%,建议及时返航</small>
</li>
<li>
<small class="text-warning">• 天气条件转差,建议调整飞行计划</small>
</li>
</ul>
</div>
</div>
<!-- 任务分配面板 -->
<div class="card mt-4">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-tasks"></i> 任务分配
</h5>
</div>
<div class="card-body">
<form id="assignTaskForm">
<div class="mb-3">
<label class="form-label">选择无人机</label>
<select class="form-select" id="droneSelect" required>
<option value="">请选择无人机</option>
<option value="UAV-001">UAV-001 (侦察者-X1)</option>
<option value="UAV-002">UAV-002 (侦察者-X1)</option>
<option value="UAV-003">UAV-003 (追踪者-A2)</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">任务类型</label>
<select class="form-select" id="taskType" required>
<option value="patrol">巡逻任务</option>
<option value="reconnaissance">侦察任务</option>
<option value="tracking">追踪任务</option>
<option value="return">返航任务</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">任务区域</label>
<input type="text" class="form-control" id="taskArea" required>
</div>
<div class="mb-3">
<label class="form-label">任务优先级</label>
<select class="form-select" id="taskPriority" required>
<option value="low"></option>
<option value="medium"></option>
<option value="high"></option>
<option value="urgent">紧急</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">预计执行时间</label>
<input type="number" class="form-control" id="estimatedTime" placeholder="分钟" required>
</div>
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-paper-plane"></i> 分配任务
</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 添加无人机模态框 -->
<div class="modal fade" id="addDroneModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">添加新无人机</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="addDroneForm">
<div class="mb-3">
<label class="form-label">无人机型号</label>
<input type="text" class="form-control" id="droneModel" required>
</div>
<div class="mb-3">
<label class="form-label">序列号</label>
<input type="text" class="form-control" id="serialNumber" required>
</div>
<div class="mb-3">
<label class="form-label">最大续航时间(小时)</label>
<input type="number" class="form-control" id="maxFlightTime" required>
</div>
<div class="mb-3">
<label class="form-label">最大载重kg</label>
<input type="number" class="form-control" id="maxPayload" required>
</div>
<div class="mb-3">
<label class="form-label">通信频段</label>
<input type="text" class="form-control" id="communicationBand" required>
</div>
<div class="mb-3">
<label class="form-label">设备配置</label>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="hasCamera">
<label class="form-check-label">高清摄像头</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="hasInfrared">
<label class="form-check-label">红外传感器</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="hasGPS">
<label class="form-check-label">GPS定位系统</label>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" id="saveDrone">保存</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="common/js/api.js"></script>
<script src="common/js/common.js"></script>
<script src="common/js/drones.js"></script>
</body>
</html>

@ -0,0 +1,266 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>目标识别 - 无人机敌我识别系统</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.0.0/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
<link href="common/css/style.css" rel="stylesheet">
</head>
<body class="battlefield-theme">
<div class="sidebar">
<div class="sidebar-header">
<h4>
<div class="logo-icon">
<i class="fas fa-drone"></i>
</div>
无人机敌我识别系统
</h4>
</div>
<nav class="nav flex-column">
<a class="nav-link" href="dashboard.html">
<i class="fas fa-chart-line"></i>战场态势
</a>
<a class="nav-link active" href="identification.html">
<i class="fas fa-crosshairs"></i>目标识别
</a>
<a class="nav-link" href="drones.html">
<i class="fas fa-drone"></i>无人机管理
</a>
<a class="nav-link" href="records.html">
<i class="fas fa-history"></i>识别记录
</a>
<a class="nav-link" href="signal.html">
<i class="fas fa-broadcast-tower"></i>信号识别
</a>
</nav>
</div>
<div class="main-content">
<div class="container-fluid">
<div class="battlefield-header">
<div class="header-left">
<h2 class="page-title">目标识别</h2>
<div class="battlefield-time">
<i class="fas fa-clock"></i>
<span id="current-time">2024-01-01 12:00:00</span>
</div>
</div>
<div class="operator-info">
<i class="fas fa-user-shield"></i>
操作员:战术指挥官
<span class="status-badge online">在线</span>
</div>
</div>
<div class="row">
<div class="col-lg-8">
<div class="card battlefield-card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0">
<i class="fas fa-camera"></i>实时视频流
</h5>
<div class="stream-status">
<span class="status-dot active"></span>
实时识别中
</div>
</div>
<div class="card-body">
<div class="video-container">
<div id="videoStream" class="video-stream">
<!-- 视频流将通过 JavaScript 加载 -->
</div>
<div class="video-overlay">
<div class="target-box" style="display: none;">
<div class="target-marker"></div>
<div class="target-info">
<span class="target-type">未知目标</span>
<span class="target-distance">距离: 0m</span>
</div>
</div>
<div class="overlay-info">
<div class="info-item">
<i class="fas fa-signal"></i>
信号强度: 85%
</div>
<div class="info-item">
<i class="fas fa-compass"></i>
方位: 235°
</div>
<div class="info-item">
<i class="fas fa-arrows-alt"></i>
目标锁定: 已锁定
</div>
</div>
</div>
</div>
<div class="video-controls mt-3">
<div class="btn-group">
<button class="btn btn-primary" id="startStream">
<i class="fas fa-play"></i>开始识别
</button>
<button class="btn btn-danger" id="stopStream">
<i class="fas fa-stop"></i>停止识别
</button>
<button class="btn btn-success" id="captureImage">
<i class="fas fa-camera"></i>截图
</button>
</div>
<div class="stream-settings">
<button class="btn btn-outline-info" id="toggleAR">
<i class="fas fa-vr-cardboard"></i>AR叠加
</button>
<button class="btn btn-outline-info" id="toggleNightVision">
<i class="fas fa-moon"></i>夜视模式
</button>
<button class="btn btn-outline-info" id="toggleThermal">
<i class="fas fa-temperature-high"></i>热成像
</button>
</div>
</div>
</div>
</div>
<div class="card battlefield-card mt-3">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-chart-bar"></i>识别分析
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="analysis-chart">
<canvas id="confidenceChart"></canvas>
</div>
</div>
<div class="col-md-6">
<div class="analysis-chart">
<canvas id="typeDistributionChart"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card battlefield-card mb-4">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-info-circle"></i>目标信息
</h5>
</div>
<div class="card-body">
<div class="target-details">
<div class="detail-group">
<div class="detail-item">
<label>目标类型</label>
<span id="targetType" class="value">军用无人机</span>
</div>
<div class="detail-item">
<label>置信度</label>
<div class="progress">
<div class="progress-bar bg-success" role="progressbar" style="width: 85%">
85%
</div>
</div>
</div>
</div>
<div class="detail-group">
<div class="detail-item">
<label>距离</label>
<span id="distance" class="value">2.5km</span>
</div>
<div class="detail-item">
<label>速度</label>
<span id="speed" class="value">120km/h</span>
</div>
</div>
<div class="detail-group">
<div class="detail-item">
<label>高度</label>
<span id="altitude" class="value">500m</span>
</div>
<div class="detail-item">
<label>航向</label>
<span id="heading" class="value">235°</span>
</div>
</div>
<div class="detail-group">
<div class="detail-item">
<label>威胁等级</label>
<span id="threatLevel" class="badge bg-danger"></span>
</div>
<div class="detail-item">
<label>目标状态</label>
<span id="targetStatus" class="badge bg-warning">跟踪中</span>
</div>
</div>
<div class="target-actions mt-3">
<button class="btn btn-warning btn-sm">
<i class="fas fa-exclamation-triangle"></i>发送警告
</button>
<button class="btn btn-danger btn-sm">
<i class="fas fa-radiation"></i>标记威胁
</button>
<button class="btn btn-info btn-sm">
<i class="fas fa-share-alt"></i>共享信息
</button>
</div>
</div>
</div>
</div>
<div class="card battlefield-card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0">
<i class="fas fa-history"></i>最近识别
</h5>
<button class="btn btn-sm btn-outline-info">
<i class="fas fa-sync"></i>
</button>
</div>
<div class="card-body">
<div class="recent-identifications">
<div class="identification-item">
<div class="item-time">10:30:15</div>
<div class="item-content">
<div class="item-type hostile">敌方无人机</div>
<div class="item-info">距离: 3.2km / 速度: 150km/h</div>
</div>
<div class="item-status">已确认</div>
</div>
<div class="identification-item">
<div class="item-time">10:28:45</div>
<div class="item-content">
<div class="item-type friendly">友方战机</div>
<div class="item-info">距离: 5.1km / 速度: 280km/h</div>
</div>
<div class="item-status">已确认</div>
</div>
<div class="identification-item">
<div class="item-time">10:25:30</div>
<div class="item-content">
<div class="item-type unknown">未知目标</div>
<div class="item-info">距离: 8.7km / 速度: 90km/h</div>
</div>
<div class="item-status">分析中</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="common/js/api.js"></script>
<script src="common/js/common.js"></script>
<script src="common/js/identification.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>无人机敌我识别系统</title>
<script>
window.location.href = 'login.html';
</script>
</head>
<body>
正在跳转到登录页面...
</body>
</html>

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录 - 无人机敌我识别系统</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.0.0/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
<link href="common/css/style.css" rel="stylesheet">
</head>
<body class="login-page">
<!-- 雷达动画背景 -->
<div class="radar-animation">
<div class="radar-spinner"></div>
<div class="radar-line"></div>
</div>
<div class="login-container">
<div class="login-box">
<div class="login-header">
<div class="logo-icon">
<div class="military-star"></div>
</div>
<h2>无人机敌我识别系统</h2>
<p class="text-muted">军用级安全认证</p>
</div>
<div class="login-form">
<form id="loginForm" onsubmit="return handleLogin(event)">
<div class="form-group">
<div class="input-group">
<span class="input-group-text">
<i class="fas fa-user-shield"></i>
</span>
<input type="text" class="form-control" id="username" placeholder="用户名" required>
</div>
</div>
<div class="form-group">
<div class="input-group">
<span class="input-group-text">
<i class="fas fa-key"></i>
</span>
<input type="password" class="form-control" id="password" placeholder="密码" required>
</div>
</div>
<div class="form-group">
<div class="d-flex justify-content-between align-items-center">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="rememberMe">
<label class="form-check-label" for="rememberMe">记住登录</label>
</div>
<a href="#" class="forgot-password">重置密码</a>
</div>
</div>
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-sign-in-alt me-2"></i>安全登录
</button>
</form>
</div>
<div class="login-footer">
<p class="text-center mb-0">
<small>
<i class="fas fa-shield-alt me-1"></i>
军用级安全加密传输
</small>
</p>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="common/js/api.js"></script>
<script src="common/js/common.js"></script>
</body>
</html>

@ -0,0 +1,310 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>识别记录 - 无人机敌我识别系统</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.0.0/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
<link href="common/css/style.css" rel="stylesheet">
</head>
<body class="battlefield-theme">
<div class="sidebar">
<div class="sidebar-header">
<h4>
<div class="logo-icon">
<i class="fas fa-drone"></i>
</div>
无人机敌我识别系统
</h4>
</div>
<nav class="nav flex-column">
<a class="nav-link" href="dashboard.html">
<i class="fas fa-chart-line"></i>战场态势
</a>
<a class="nav-link" href="identification.html">
<i class="fas fa-crosshairs"></i>目标识别
</a>
<a class="nav-link" href="drones.html">
<i class="fas fa-drone"></i>无人机管理
</a>
<a class="nav-link active" href="records.html">
<i class="fas fa-history"></i>识别记录
</a>
<a class="nav-link" href="signal.html">
<i class="fas fa-broadcast-tower"></i>信号识别
</a>
</nav>
</div>
<div class="main-content records-page">
<div class="container-fluid">
<!-- 统计卡片 -->
<div class="row mb-4">
<div class="col-md-3">
<div class="stats-card fade-in">
<div class="stats-icon">
<i class="fas fa-check-circle"></i>
</div>
<div class="stats-value">2,458</div>
<div class="stats-label">总识别次数</div>
</div>
</div>
<div class="col-md-3">
<div class="stats-card fade-in">
<div class="stats-icon">
<i class="fas fa-shield-alt"></i>
</div>
<div class="stats-value">1,245</div>
<div class="stats-label">友方目标</div>
</div>
</div>
<div class="col-md-3">
<div class="stats-card fade-in">
<div class="stats-icon">
<i class="fas fa-exclamation-triangle"></i>
</div>
<div class="stats-value">892</div>
<div class="stats-label">敌方目标</div>
</div>
</div>
<div class="col-md-3">
<div class="stats-card fade-in">
<div class="stats-icon">
<i class="fas fa-question-circle"></i>
</div>
<div class="stats-value">321</div>
<div class="stats-label">未知目标</div>
</div>
</div>
</div>
<!-- 筛选条件卡片 -->
<div class="row mb-4">
<div class="col-12">
<div class="card slide-in">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-filter"></i> 筛选条件
</h5>
</div>
<div class="card-body">
<form id="filterForm" class="row g-3">
<div class="col-md-3">
<label class="form-label">时间范围</label>
<select class="form-select" id="timeRange">
<option value="today">今天</option>
<option value="week">本周</option>
<option value="month">本月</option>
<option value="custom">自定义</option>
</select>
</div>
<div class="col-md-3">
<label class="form-label">目标类型</label>
<select class="form-select" id="targetType">
<option value="">全部</option>
<option value="friendly">友方</option>
<option value="hostile">敌方</option>
<option value="unknown">未知</option>
</select>
</div>
<div class="col-md-3">
<label class="form-label">识别状态</label>
<select class="form-select" id="identificationStatus">
<option value="">全部</option>
<option value="success">识别成功</option>
<option value="failed">识别失败</option>
<option value="pending">待确认</option>
</select>
</div>
<div class="col-md-3">
<label class="form-label">威胁等级</label>
<select class="form-select" id="threatLevel">
<option value="">全部</option>
<option value="high"></option>
<option value="medium"></option>
<option value="low"></option>
</select>
</div>
<div class="col-12 mt-4">
<button type="submit" class="btn btn-primary">
<i class="fas fa-search"></i> 搜索
</button>
<button type="reset" class="btn btn-secondary ms-2">
<i class="fas fa-redo"></i> 重置
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- 记录列表卡片 -->
<div class="row">
<div class="col-12">
<div class="card slide-in">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="card-title">
<i class="fas fa-list"></i> 识别记录列表
</h5>
<div class="btn-group">
<button class="btn btn-outline-primary">
<i class="fas fa-download"></i> 导出
</button>
<button class="btn btn-outline-primary ms-2">
<i class="fas fa-print"></i> 打印
</button>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>时间</th>
<th>目标类型</th>
<th>识别结果</th>
<th>置信度</th>
<th>威胁等级</th>
<th>位置</th>
<th>操作</th>
</tr>
</thead>
<tbody id="recordsList">
<!-- 示例数据 -->
<tr>
<td>2024-01-15 14:30:25</td>
<td><span class="badge badge-friendly">友方</span></td>
<td>侦察无人机</td>
<td>98%</td>
<td><span class="badge badge-success"></span></td>
<td>N 39°54'25" E 116°23'50"</td>
<td>
<button class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#recordDetailModal">
<i class="fas fa-eye"></i>
</button>
</td>
</tr>
<tr>
<td>2024-01-15 14:28:15</td>
<td><span class="badge badge-hostile">敌方</span></td>
<td>攻击无人机</td>
<td>95%</td>
<td><span class="badge badge-danger"></span></td>
<td>N 39°54'28" E 116°23'52"</td>
<td>
<button class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#recordDetailModal">
<i class="fas fa-eye"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<nav aria-label="Page navigation" class="mt-4">
<ul class="pagination justify-content-center">
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1">上一页</a>
</li>
<li class="page-item active"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item">
<a class="page-link" href="#">下一页</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 记录详情模态框 -->
<div class="modal fade" id="recordDetailModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">识别记录详情</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-6">
<img src="" class="img-fluid mb-3" id="targetImage" alt="目标图像">
</div>
<div class="col-md-6">
<h6 class="text-accent mb-3">基本信息</h6>
<table class="table table-sm">
<tbody>
<tr>
<td width="35%">识别时间:</td>
<td id="detailTime">2024-01-15 14:30:25</td>
</tr>
<tr>
<td>目标类型:</td>
<td id="detailType"><span class="badge badge-friendly">友方</span></td>
</tr>
<tr>
<td>识别结果:</td>
<td id="detailResult">侦察无人机</td>
</tr>
<tr>
<td>置信度:</td>
<td id="detailConfidence">
<div class="progress" style="height: 6px;">
<div class="progress-bar bg-success" role="progressbar" style="width: 98%"></div>
</div>
<small class="text-muted">98%</small>
</td>
</tr>
<tr>
<td>威胁等级:</td>
<td id="detailThreat"><span class="badge badge-success"></span></td>
</tr>
<tr>
<td>位置坐标:</td>
<td id="detailLocation">N 39°54'25" E 116°23'50"</td>
</tr>
</tbody>
</table>
<h6 class="text-accent mb-3">技术参数</h6>
<table class="table table-sm">
<tbody>
<tr>
<td width="35%">飞行高度:</td>
<td>1,200米</td>
</tr>
<tr>
<td>飞行速度:</td>
<td>180km/h</td>
</tr>
<tr>
<td>航向角度:</td>
<td>45°</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary">
<i class="fas fa-download"></i> 导出详情
</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="common/js/identification.js"></script>
</body>
</html>

@ -0,0 +1,33 @@
import http.server
import socketserver
import os
# 设置端口
PORT = 8080
# 自定义处理器添加CORS头
class CORSHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
def end_headers(self):
# 添加CORS头
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
super().end_headers()
def do_OPTIONS(self):
# 处理OPTIONS请求
self.send_response(200)
self.end_headers()
# 打印启动信息
print(f"启动前端服务器,端口: {PORT}")
print(f"请在浏览器中访问: http://localhost:{PORT}")
print("按Ctrl+C终止服务器")
# 启动服务器
with socketserver.TCPServer(("", PORT), CORSHTTPRequestHandler) as httpd:
print("前端服务器正在运行...")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("\n服务器已停止")

@ -0,0 +1,333 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>信号识别 - 无人机敌我识别系统</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.0.0/css/all.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500&display=swap" rel="stylesheet">
<link href="common/css/style.css" rel="stylesheet">
</head>
<body class="battlefield-theme">
<div class="sidebar">
<div class="sidebar-header">
<h4>
<div class="logo-icon">
<i class="fas fa-drone"></i>
</div>
无人机敌我识别系统
</h4>
</div>
<nav class="nav flex-column">
<a class="nav-link" href="dashboard.html">
<i class="fas fa-chart-line"></i>战场态势
</a>
<a class="nav-link" href="identification.html">
<i class="fas fa-crosshairs"></i>目标识别
</a>
<a class="nav-link" href="drones.html">
<i class="fas fa-drone"></i>无人机管理
</a>
<a class="nav-link" href="records.html">
<i class="fas fa-history"></i>识别记录
</a>
<a class="nav-link active" href="signal.html">
<i class="fas fa-broadcast-tower"></i>信号识别
</a>
</nav>
</div>
<div class="main-content signal-page">
<div class="container-fluid">
<!-- 状态卡片 -->
<div class="row mb-4">
<div class="col-md-3">
<div class="status-card fade-in">
<div class="status-icon">
<i class="fas fa-satellite-dish"></i>
</div>
<div class="status-value">24</div>
<div class="status-label">活跃信号源</div>
</div>
</div>
<div class="col-md-3">
<div class="status-card fade-in">
<div class="status-icon">
<i class="fas fa-shield-alt"></i>
</div>
<div class="status-value">12</div>
<div class="status-label">友方信号</div>
</div>
</div>
<div class="col-md-3">
<div class="status-card fade-in">
<div class="status-icon">
<i class="fas fa-exclamation-triangle"></i>
</div>
<div class="status-value">8</div>
<div class="status-label">可疑信号</div>
</div>
</div>
<div class="col-md-3">
<div class="status-card fade-in">
<div class="status-icon">
<i class="fas fa-radiation"></i>
</div>
<div class="status-value">4</div>
<div class="status-label">干扰源</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8">
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="card-title">
<i class="fas fa-wave-square"></i>信号波形分析
</h5>
<div class="card-tools">
<button class="btn btn-sm btn-outline-primary" id="toggleFullscreen">
<i class="fas fa-expand"></i>
</button>
</div>
</div>
</div>
<div class="card-body">
<div class="signal-container">
<div class="signal-controls mb-3">
<div class="btn-group">
<button class="btn btn-primary" id="startSignalScan">
<i class="fas fa-play"></i>开始扫描
</button>
<button class="btn btn-danger" id="stopSignalScan" disabled>
<i class="fas fa-stop"></i>停止扫描
</button>
<button class="btn btn-success" id="captureSignal">
<i class="fas fa-camera"></i>捕获信号
</button>
</div>
<div class="frequency-controls">
<div class="frequency-selector">
<label>频率范围:</label>
<select class="form-select" id="frequencyRange">
<option value="all">全频段</option>
<option value="low">低频段 (300MHz-1GHz)</option>
<option value="mid">中频段 (1GHz-2.4GHz)</option>
<option value="high">高频段 (2.4GHz+)</option>
</select>
</div>
<div class="scan-speed">
<label>扫描速度:</label>
<input type="range" class="form-range" id="scanSpeed" min="1" max="5" value="3">
</div>
</div>
</div>
<div class="signal-display scanning">
<canvas id="signalCanvas"></canvas>
<div class="signal-markers">
<div class="frequency-marker" style="left: 25%">
<div class="marker-line"></div>
<div class="marker-label">1.2 GHz</div>
</div>
<div class="frequency-marker" style="left: 75%">
<div class="marker-line"></div>
<div class="marker-label">2.4 GHz</div>
</div>
</div>
</div>
<div class="signal-info mt-3">
<div class="row">
<div class="col-md-3">
<div class="info-item">
<label>当前频率</label>
<span id="currentFrequency">2.4 GHz</span>
</div>
</div>
<div class="col-md-3">
<div class="info-item">
<label>信号强度</label>
<span id="signalStrength">-65 dBm</span>
</div>
</div>
<div class="col-md-3">
<div class="info-item">
<label>带宽</label>
<span id="bandwidth">20 MHz</span>
</div>
</div>
<div class="col-md-3">
<div class="info-item">
<label>信噪比</label>
<span id="snr">32 dB</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card mb-4">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-fingerprint"></i>信号特征
</h5>
</div>
<div class="card-body">
<div class="signal-features">
<div class="feature-item">
<label>调制方式</label>
<span id="modulationType">QPSK</span>
</div>
<div class="feature-item">
<label>信号类型</label>
<span id="signalType">遥控信号</span>
</div>
<div class="feature-item">
<label>加密类型</label>
<span id="encryptionType">AES-256</span>
</div>
<div class="feature-item">
<label>信号质量</label>
<div class="progress">
<div class="progress-bar bg-success" role="progressbar" style="width: 85%">
<span class="progress-text">85%</span>
</div>
</div>
</div>
<div class="feature-item">
<label>干扰程度</label>
<div class="progress">
<div class="progress-bar bg-warning" role="progressbar" style="width: 25%">
<span class="progress-text">25%</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-shield-alt"></i>威胁分析
</h5>
</div>
<div class="card-body">
<div class="threat-analysis">
<div class="threat-level">
<label>威胁等级</label>
<span class="badge bg-warning">中等</span>
</div>
<div class="threat-details mt-3">
<h6 class="text-accent">威胁详情</h6>
<ul class="list-unstyled">
<li>
<i class="fas fa-exclamation-triangle text-warning"></i>
检测到可疑的加密通信
</li>
<li>
<i class="fas fa-info-circle text-info"></i>
信号特征与已知敌方设备部分匹配
</li>
<li>
<i class="fas fa-shield-alt text-success"></i>
通信协议已被识别
</li>
</ul>
</div>
<div class="recommended-actions mt-3">
<h6 class="text-accent">建议操作</h6>
<button class="btn btn-warning btn-sm mb-2 w-100">
<i class="fas fa-radar"></i>持续监控
</button>
<button class="btn btn-info btn-sm w-100">
<i class="fas fa-file-export"></i>导出分析报告
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-12">
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="card-title">
<i class="fas fa-history"></i>信号记录
</h5>
<div class="btn-group">
<button class="btn btn-sm btn-outline-primary">
<i class="fas fa-download"></i>导出记录
</button>
<button class="btn btn-sm btn-outline-danger">
<i class="fas fa-trash"></i>清除记录
</button>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>时间</th>
<th>频率</th>
<th>信号类型</th>
<th>信号强度</th>
<th>威胁等级</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>2024-01-15 15:30:25</td>
<td>2.4 GHz</td>
<td>遥控信号</td>
<td>-65 dBm</td>
<td><span class="badge bg-warning">中等</span></td>
<td><span class="badge bg-success">已识别</span></td>
<td>
<button class="btn btn-sm btn-primary">
<i class="fas fa-eye"></i>
</button>
</td>
</tr>
<tr>
<td>2024-01-15 15:28:15</td>
<td>1.8 GHz</td>
<td>数据链路</td>
<td>-72 dBm</td>
<td><span class="badge bg-danger"></span></td>
<td><span class="badge bg-warning">分析中</span></td>
<td>
<button class="btn btn-sm btn-primary">
<i class="fas fa-eye"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="common/js/signal.js"></script>
</body>
</html>
Loading…
Cancel
Save