You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2230 lines
76 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// 智慧河道管理平台 - JavaScript 主文件
// 全局变量
let map;
let currentTab = 'monitor';
let workorderData = [];
let deviceData = [];
let warningData = [];
let dashboardData = {
realTimeStatus: {
online: 12,
warning: 3,
processing: 2
},
waterQuality: {
excellent: 8,
good: 4,
warning: 1
},
efficiency: {
daily: 85,
weekly: 78,
monthly: 82
},
alerts: [
{id: 1, type: 'high', title: '水质异常', desc: '湘江中路段检测到污染物超标', time: '2分钟前'},
{id: 2, type: 'medium', title: '设备故障', desc: '橘子洲头摄像头离线', time: '15分钟前'},
{id: 3, type: 'low', title: '清理完成', desc: '杜甫江阁段垃圾清理完毕', time: '1小时前'}
],
envData: {
temperature: 24,
windSpeed: 3.2,
visibility: 8.5
}
};
// 初始化应用
document.addEventListener('DOMContentLoaded', function() {
// The initializeApp function will be called by onTdtMapApiLoaded
});
function initializeApp() {
initializeNavigation();
initializeDashboard();
initializeTime();
initializeMap();
initializeCharts();
startRealTimeUpdates();
// 初始化其他模块
initializeWorkorder();
initializeDevice();
initializeWarning();
initializeStatistics();
// 启用大屏模式
enableFullscreenMode();
}
function onTdtMapApiLoaded() {
window.T = T; // Expose T to the global scope
initializeApp();
}
// 初始化大屏仪表板
function initializeDashboard() {
updateRealTimeStatus();
updateWaterQuality();
updateEfficiencyStats();
updateAlerts();
updateEnvironmentData();
updateWeatherInfo();
}
// 导航系统
function initializeNavigation() {
const navButtons = document.querySelectorAll('.nav-btn');
const tabContents = document.querySelectorAll('.tab-content');
navButtons.forEach(button => {
button.addEventListener('click', function() {
const targetTab = this.getAttribute('data-tab');
switchTab(targetTab);
});
});
}
function switchTab(tabName) {
// 如果已经是当前标签页,则不执行任何操作
if (currentTab === tabName) return;
// 更新导航按钮状态
document.querySelectorAll('.nav-btn').forEach(btn => {
btn.classList.remove('active');
});
document.querySelector(`[data-tab="${tabName}"]`).classList.add('active');
// 更新内容区域
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
});
document.getElementById(tabName).classList.add('active');
currentTab = tabName;
// 大屏模式控制
if (tabName === 'monitor') {
enableFullscreenMode();
} else {
disableFullscreenMode();
}
// 根据不同标签页执行特定初始化
switch(tabName) {
case 'monitor':
if (map) {
setTimeout(() => map.invalidateSize(), 100);
}
// 刷新监控管理一张图的图表
refreshMonitorCharts();
break;
case 'workorder':
refreshWorkorderTable();
break;
case 'device':
refreshDeviceGrid();
break;
case 'warning':
refreshWarningData();
break;
case 'statistics':
refreshCharts();
break;
}
}
// 启用大屏模式
function enableFullscreenMode() {
document.body.classList.add('fullscreen-mode');
// 添加ESC键退出大屏模式的监听
document.addEventListener('keydown', handleEscapeKey);
}
// 禁用大屏模式
function disableFullscreenMode() {
document.body.classList.remove('fullscreen-mode');
document.removeEventListener('keydown', handleEscapeKey);
}
// 处理ESC键退出大屏模式
function handleEscapeKey(event) {
if (event.key === 'Escape' && document.body.classList.contains('fullscreen-mode')) {
// 切换到统计分析页面
switchTab('statistics');
}
}
// 添加大屏模式切换按钮功能
function toggleFullscreenMode() {
if (document.body.classList.contains('fullscreen-mode')) {
disableFullscreenMode();
} else {
enableFullscreenMode();
}
}
// 时间显示
function initializeTime() {
updateTime();
setInterval(updateTime, 1000);
}
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'
});
const datetimeElement = document.getElementById('datetime');
if (datetimeElement) {
datetimeElement.textContent = timeString;
}
}
// 更新实时状态
function updateRealTimeStatus() {
const statusGrid = document.querySelector('.status-grid');
if (!statusGrid) return;
const statusData = dashboardData.realTimeStatus;
const statusCards = [
{key: 'online', label: '在线设备', value: statusData.online, class: 'online'},
{key: 'warning', label: '告警设备', value: statusData.warning, class: 'warning'},
{key: 'processing', label: '处理中', value: statusData.processing, class: 'processing'}
];
statusGrid.innerHTML = statusCards.map(card => `
<div class="status-card ${card.class}">
<div class="status-icon">
<i class="fas fa-${card.key === 'online' ? 'check-circle' : card.key === 'warning' ? 'exclamation-triangle' : 'cog'}"></i>
</div>
<div class="status-info">
<div class="status-value">${card.value}</div>
<div class="status-label">${card.label}</div>
</div>
</div>
`).join('');
}
// 更新水质监测
function updateWaterQuality() {
const qualityData = dashboardData.waterQuality;
const qualityItems = document.querySelectorAll('.quality-item');
const items = [
{element: qualityItems[0], key: 'excellent', label: '优秀', class: 'excellent'},
{element: qualityItems[1], key: 'good', label: '良好', class: 'good'},
{element: qualityItems[2], key: 'warning', label: '预警', class: 'warning'}
];
items.forEach(item => {
if (item.element) {
item.element.className = `quality-item ${item.class}`;
item.element.innerHTML = `
<div class="quality-value">${qualityData[item.key]}</div>
<div class="quality-text">${item.label}</div>
<div class="quality-status">监测点</div>
`;
}
});
}
// 更新清理效率统计
function updateEfficiencyStats() {
const efficiencyData = dashboardData.efficiency;
const statRows = document.querySelectorAll('.stat-row');
const stats = [
{element: statRows[0], label: '日清理率', value: efficiencyData.daily},
{element: statRows[1], label: '周清理率', value: efficiencyData.weekly},
{element: statRows[2], label: '月清理率', value: efficiencyData.monthly}
];
stats.forEach(stat => {
if (stat.element) {
stat.element.innerHTML = `
<span class="stat-label">${stat.label}</span>
<span class="stat-value">${stat.value}%</span>
`;
}
});
}
// 更新告警信息
function updateAlerts() {
const alertList = document.querySelector('.alert-list');
if (!alertList) return;
const alerts = dashboardData.alerts;
alertList.innerHTML = alerts.map(alert => `
<div class="alert-item ${alert.type}">
<div class="alert-icon">
<i class="fas fa-${alert.type === 'high' ? 'exclamation-circle' : alert.type === 'medium' ? 'exclamation-triangle' : 'info-circle'}"></i>
</div>
<div class="alert-content">
<div class="alert-title">${alert.title}</div>
<div class="alert-desc">${alert.desc}</div>
<div class="alert-time">${alert.time}</div>
</div>
</div>
`).join('');
}
// 更新环境数据
function updateEnvironmentData() {
const envData = dashboardData.envData;
const envItems = document.querySelectorAll('.env-item');
const items = [
{element: envItems[0], icon: 'thermometer-half', label: '水温', value: envData.temperature, unit: '°C'},
{element: envItems[1], icon: 'wind', label: '风速', value: envData.windSpeed, unit: 'm/s'},
{element: envItems[2], icon: 'eye', label: '能见度', value: envData.visibility, unit: 'km'}
];
items.forEach(item => {
if (item.element) {
item.element.innerHTML = `
<div class="env-icon">
<i class="fas fa-${item.icon}"></i>
</div>
<div class="env-info">
<div class="env-label">${item.label}</div>
<div class="env-value">${item.value}${item.unit}</div>
</div>
`;
}
});
}
// 更新天气信息
function updateWeatherInfo() {
const weatherElement = document.getElementById('weather');
if (weatherElement) {
weatherElement.innerHTML = `
<i class="fas fa-sun"></i>
<span>晴 24°C</span>
`;
}
}
// 地图系统
function initializeMap() {
// 初始化天地图
const mapElement = document.getElementById('map');
if (!mapElement) return;
map = new T.Map('map');
const point = new T.LngLat(112.9388, 28.2282); // 长沙坐标
map.centerAndZoom(point, 12);
// 启用地图功能
map.enableScrollWheelZoom();
map.addControl(new T.Control.Zoom());
map.addControl(new T.Control.Scale());
map.addControl(new T.Control.MapType());
// 添加湘江河道轮廓
addRiverOverlay();
// 添加设备标记
addDeviceMarkers();
// 添加垃圾污染点
addGarbageMarkers();
// 地图控制事件
const toggleLayerBtn = document.getElementById('toggleLayer');
const fullscreenBtn = document.getElementById('fullscreen');
if (toggleLayerBtn) {
toggleLayerBtn.addEventListener('click', toggleMapLayers);
}
if (fullscreenBtn) {
fullscreenBtn.addEventListener('click', toggleFullscreen);
}
}
// 初始化图表
function initializeCharts() {
initializeTrendChart();
initializeMonitorCharts();
}
// 初始化趋势图表
function initializeTrendChart() {
const canvas = document.getElementById('trendChart');
if (!canvas) return;
// 销毁已存在的图表实例
destroyChart('trendChart');
const ctx = canvas.getContext('2d');
// 创建渐变
const gradient1 = ctx.createLinearGradient(0, 0, 0, 200);
gradient1.addColorStop(0, 'rgba(255, 68, 68, 0.3)');
gradient1.addColorStop(1, 'rgba(255, 68, 68, 0)');
const gradient2 = ctx.createLinearGradient(0, 0, 0, 200);
gradient2.addColorStop(0, 'rgba(0, 212, 255, 0.3)');
gradient2.addColorStop(1, 'rgba(0, 212, 255, 0)');
const gradient3 = ctx.createLinearGradient(0, 0, 0, 200);
gradient3.addColorStop(0, 'rgba(0, 255, 136, 0.3)');
gradient3.addColorStop(1, 'rgba(0, 255, 136, 0)');
window.chartInstances['trendChart'] = new Chart(ctx, {
type: 'line',
data: {
labels: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00'],
datasets: [{
label: '告警数量',
data: [12, 8, 15, 6, 10, 4],
borderColor: '#ff4444',
backgroundColor: gradient1,
borderWidth: 2,
fill: true,
tension: 0.4
}, {
label: '处理数量',
data: [8, 12, 10, 18, 14, 16],
borderColor: '#00d4ff',
backgroundColor: gradient2,
borderWidth: 2,
fill: true,
tension: 0.4
}, {
label: '完成数量',
data: [6, 10, 8, 15, 12, 14],
borderColor: '#00ff88',
backgroundColor: gradient3,
borderWidth: 2,
fill: true,
tension: 0.4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
x: {
grid: {
color: 'rgba(255, 255, 255, 0.1)'
},
ticks: {
color: '#b0c4de',
font: {
size: 10
}
}
},
y: {
grid: {
color: 'rgba(255, 255, 255, 0.1)'
},
ticks: {
color: '#b0c4de',
font: {
size: 10
}
}
}
},
elements: {
point: {
radius: 3,
hoverRadius: 6
}
}
}
});
}
// 开始实时更新
function startRealTimeUpdates() {
// 每30秒更新一次数据
setInterval(() => {
updateDashboardData();
updateChartData();
}, 30000);
}
// 更新仪表板数据
function updateDashboardData() {
// 模拟数据变化
dashboardData.realTimeStatus.online += Math.floor(Math.random() * 3) - 1;
dashboardData.realTimeStatus.warning += Math.floor(Math.random() * 2) - 1;
dashboardData.realTimeStatus.processing += Math.floor(Math.random() * 2) - 1;
// 确保数据在合理范围内
dashboardData.realTimeStatus.online = Math.max(8, Math.min(15, dashboardData.realTimeStatus.online));
dashboardData.realTimeStatus.warning = Math.max(0, Math.min(5, dashboardData.realTimeStatus.warning));
dashboardData.realTimeStatus.processing = Math.max(0, Math.min(5, dashboardData.realTimeStatus.processing));
// 更新环境数据
dashboardData.envData.temperature += (Math.random() - 0.5) * 2;
dashboardData.envData.windSpeed += (Math.random() - 0.5) * 1;
dashboardData.envData.visibility += (Math.random() - 0.5) * 2;
// 确保环境数据在合理范围内
dashboardData.envData.temperature = Math.max(15, Math.min(35, dashboardData.envData.temperature));
dashboardData.envData.windSpeed = Math.max(0, Math.min(10, dashboardData.envData.windSpeed));
dashboardData.envData.visibility = Math.max(3, Math.min(15, dashboardData.envData.visibility));
// 更新界面
updateRealTimeStatus();
updateEnvironmentData();
}
// 更新图表数据
function updateChartData() {
if (window.chartInstances.trendChart) {
const datasets = window.chartInstances.trendChart.data.datasets;
datasets.forEach(dataset => {
// 移除第一个数据点,添加新的数据点
dataset.data.shift();
dataset.data.push(Math.floor(Math.random() * 20) + 5);
});
window.chartInstances.trendChart.update('none');
}
}
function addRiverOverlay() {
// 湘江长沙段轮廓(简化坐标)
const riverPoints = [
new T.LngLat(112.9200, 28.3000),
new T.LngLat(112.9300, 28.2800),
new T.LngLat(112.9400, 28.2600),
new T.LngLat(112.9500, 28.2400),
new T.LngLat(112.9600, 28.2200),
new T.LngLat(112.9700, 28.2000),
new T.LngLat(112.9800, 28.1800)
];
const polyline = new T.Polyline(riverPoints, {
color: '#3498db',
weight: 8,
opacity: 0.7
});
map.addOverLay(polyline);
// 添加信息窗口
const infoWindow = new T.InfoWindow();
infoWindow.setContent('湘江长沙段');
polyline.addEventListener('click', function() {
infoWindow.openInfoWindow(map, riverPoints[Math.floor(riverPoints.length/2)]);
});
}
function addDeviceMarkers() {
// 摄像头标记
const cameras = [
{lat: 28.2282, lng: 112.9388, name: '摄像头01-橘子洲头', status: 'online'},
{lat: 28.2150, lng: 112.9450, name: '摄像头02-杜甫江阁', status: 'online'},
{lat: 28.2400, lng: 112.9300, name: '摄像头03-湘江中路', status: 'warning'},
{lat: 28.2600, lng: 112.9200, name: '摄像头04-猴子石大桥', status: 'online'}
];
cameras.forEach(camera => {
const point = new T.LngLat(camera.lng, camera.lat);
const marker = new T.Marker(point);
// 创建自定义图标
const icon = new T.Icon({
iconUrl: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30">
<circle cx="15" cy="15" r="12" fill="white" stroke="#ddd" stroke-width="2"/>
<text x="15" y="20" text-anchor="middle" font-family="FontAwesome" font-size="14" fill="${getStatusColor(camera.status)}">&#xf03d;</text>
</svg>
`)}`,
iconSize: new T.Point(30, 30)
});
marker.setIcon(icon);
map.addOverLay(marker);
const infoWindow = new T.InfoWindow();
infoWindow.setContent(`${camera.name}<br>状态: ${getStatusText(camera.status)}`);
marker.addEventListener('click', function() {
infoWindow.openInfoWindow(map, point);
});
});
// 无人船标记
const ships = [
{lat: 28.2200, lng: 112.9400, name: '无人船01', status: 'working'},
{lat: 28.2500, lng: 112.9350, name: '无人船02', status: 'working'},
{lat: 28.2350, lng: 112.9420, name: '无人船03', status: 'idle'}
];
ships.forEach(ship => {
const point = new T.LngLat(ship.lng, ship.lat);
const marker = new T.Marker(point);
const icon = new T.Icon({
iconUrl: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30">
<circle cx="15" cy="15" r="12" fill="white" stroke="#ddd" stroke-width="2"/>
<text x="15" y="20" text-anchor="middle" font-family="FontAwesome" font-size="14" fill="${getStatusColor(ship.status)}">&#xf21a;</text>
</svg>
`)}`,
iconSize: new T.Point(30, 30)
});
marker.setIcon(icon);
map.addOverLay(marker);
const infoWindow = new T.InfoWindow();
infoWindow.setContent(`${ship.name}<br>状态: ${getStatusText(ship.status)}`);
marker.addEventListener('click', function() {
infoWindow.openInfoWindow(map, point);
});
});
// 无人机标记
const drones = [
{lat: 28.2300, lng: 112.9380, name: '无人机01', status: 'flying'},
{lat: 28.2450, lng: 112.9320, name: '无人机02', status: 'charging'}
];
drones.forEach(drone => {
const point = new T.LngLat(drone.lng, drone.lat);
const marker = new T.Marker(point);
const icon = new T.Icon({
iconUrl: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30">
<circle cx="15" cy="15" r="12" fill="white" stroke="#ddd" stroke-width="2"/>
<text x="15" y="20" text-anchor="middle" font-family="FontAwesome" font-size="14" fill="${getStatusColor(drone.status)}">&#xf533;</text>
</svg>
`)}`,
iconSize: new T.Point(30, 30)
});
marker.setIcon(icon);
map.addOverLay(marker);
const infoWindow = new T.InfoWindow();
infoWindow.setContent(`${drone.name}<br>状态: ${getStatusText(drone.status)}`);
marker.addEventListener('click', function() {
infoWindow.openInfoWindow(map, point);
});
});
}
function addGarbageMarkers() {
const garbagePoints = [
{lat: 28.2250, lng: 112.9410, type: 'water', severity: 'high', description: '大量漂浮垃圾'},
{lat: 28.2180, lng: 112.9460, type: 'beach', severity: 'medium', description: '滩涂堆积物'},
{lat: 28.2420, lng: 112.9330, type: 'water', severity: 'low', description: '少量枯枝'},
{lat: 28.2380, lng: 112.9390, type: 'illegal', severity: 'high', description: '违法倾倒点'}
];
garbagePoints.forEach(point => {
const mapPoint = new T.LngLat(point.lng, point.lat);
const marker = new T.Marker(mapPoint);
const icon = new T.Icon({
iconUrl: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 25 25">
<circle cx="12.5" cy="12.5" r="10" fill="white" stroke="#ddd" stroke-width="2"/>
<text x="12.5" y="17" text-anchor="middle" font-family="FontAwesome" font-size="12" fill="${getSeverityColor(point.severity)}">&#xf2ed;</text>
</svg>
`)}`,
iconSize: new T.Point(25, 25)
});
marker.setIcon(icon);
map.addOverLay(marker);
const infoWindow = new T.InfoWindow();
infoWindow.setContent(`${point.description}<br>类型: ${getTypeText(point.type)}<br>严重程度: ${point.severity}`);
marker.addEventListener('click', function() {
infoWindow.openInfoWindow(map, mapPoint);
});
});
}
function getStatusColor(status) {
const colors = {
'online': '#2ecc71',
'offline': '#e74c3c',
'warning': '#f39c12',
'working': '#3498db',
'idle': '#95a5a6',
'flying': '#9b59b6',
'charging': '#f1c40f'
};
return colors[status] || '#95a5a6';
}
function getStatusText(status) {
const texts = {
'online': '在线',
'offline': '离线',
'warning': '警告',
'working': '作业中',
'idle': '待机',
'flying': '飞行中',
'charging': '充电中'
};
return texts[status] || '未知';
}
function getSeverityColor(severity) {
const colors = {
'high': '#e74c3c',
'medium': '#f39c12',
'low': '#f1c40f'
};
return colors[severity] || '#95a5a6';
}
function getTypeText(type) {
const texts = {
'water': '水面垃圾',
'beach': '滩涂垃圾',
'illegal': '违法倾倒'
};
return texts[type] || '未知';
}
function toggleMapLayers() {
// 图层切换逻辑
console.log('切换地图图层');
}
function toggleFullscreen() {
const mapContainer = document.querySelector('.map-container');
if (!document.fullscreenElement) {
mapContainer.requestFullscreen().then(() => {
setTimeout(() => map.invalidateSize(), 100);
});
} else {
document.exitFullscreen();
}
}
// 工单系统
function initializeWorkorderSystem() {
// 创建工单按钮
document.getElementById('createWorkorder').addEventListener('click', showCreateWorkorderModal);
// 导出数据按钮
document.getElementById('exportWorkorder').addEventListener('click', exportWorkorderData);
// 筛选器事件
document.querySelectorAll('.filter-select').forEach(select => {
select.addEventListener('change', filterWorkorders);
});
// 搜索框事件
document.querySelector('.search-input').addEventListener('input', searchWorkorders);
// 初始化工单表格
refreshWorkorderTable();
}
function showCreateWorkorderModal() {
const modalBody = document.getElementById('modalBody');
modalBody.innerHTML = `
<div class="modal-header">
<h2>创建新工单</h2>
<button class="close" onclick="closeModal()">&times;</button>
</div>
<div class="modal-body">
<form id="createWorkorderForm">
<div class="form-group">
<label>垃圾类型:</label>
<select name="type" required>
<option value="water">水面垃圾</option>
<option value="beach">滩涂垃圾</option>
<option value="illegal">违法倾倒</option>
</select>
</div>
<div class="form-group">
<label>位置描述:</label>
<input type="text" name="location" required placeholder="请输入具体位置">
</div>
<div class="form-group">
<label>严重程度:</label>
<select name="severity" required>
<option value="low">低</option>
<option value="medium">中</option>
<option value="high">高</option>
</select>
</div>
<div class="form-group">
<label>描述:</label>
<textarea name="description" rows="3" placeholder="请描述垃圾情况"></textarea>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">创建工单</button>
<button type="button" class="btn btn-secondary" onclick="closeModal()">取消</button>
</div>
</form>
</div>
`;
document.getElementById('modal').style.display = 'block';
// 表单提交事件
document.getElementById('createWorkorderForm').addEventListener('submit', function(e) {
e.preventDefault();
createWorkorder(new FormData(this));
});
}
function createWorkorder(formData) {
const workorder = {
id: 'WO' + Date.now(),
type: formData.get('type'),
location: formData.get('location'),
severity: formData.get('severity'),
description: formData.get('description'),
status: 'pending',
assignee: '待分配',
createTime: new Date().toLocaleString('zh-CN'),
discoveryMethod: '手动创建'
};
workorderData.unshift(workorder);
refreshWorkorderTable();
closeModal();
showNotification('工单创建成功', 'success');
}
function refreshWorkorderTable() {
const tbody = document.getElementById('workorderTableBody');
if (!tbody) return;
tbody.innerHTML = '';
workorderData.forEach(workorder => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${workorder.id}</td>
<td>${getTypeText(workorder.type)}</td>
<td>${workorder.location}</td>
<td>${workorder.discoveryMethod}</td>
<td><span class="badge ${getStatusBadgeClass(workorder.status)}">${getStatusText(workorder.status)}</span></td>
<td>${workorder.assignee}</td>
<td>${workorder.createTime}</td>
<td>
<button class="btn btn-sm" onclick="viewWorkorder('${workorder.id}')">查看</button>
<button class="btn btn-sm" onclick="editWorkorder('${workorder.id}')">编辑</button>
</td>
`;
tbody.appendChild(row);
});
}
function getStatusBadgeClass(status) {
const classes = {
'pending': 'warning',
'processing': 'info',
'completed': 'success',
'cancelled': 'danger'
};
return classes[status] || 'secondary';
}
function filterWorkorders() {
// 筛选逻辑
refreshWorkorderTable();
}
function searchWorkorders() {
// 搜索逻辑
refreshWorkorderTable();
}
function exportWorkorderData() {
// 导出数据逻辑
console.log('导出工单数据');
showNotification('数据导出成功', 'success');
}
function viewWorkorder(id) {
const workorder = workorderData.find(w => w.id === id);
if (!workorder) return;
const modalBody = document.getElementById('modalBody');
modalBody.innerHTML = `
<h3>工单详情 - ${workorder.id}</h3>
<div class="workorder-details">
<div class="detail-item">
<label>类型:</label>
<span>${getTypeText(workorder.type)}</span>
</div>
<div class="detail-item">
<label>位置:</label>
<span>${workorder.location}</span>
</div>
<div class="detail-item">
<label>状态:</label>
<span class="badge ${getStatusBadgeClass(workorder.status)}">${getStatusText(workorder.status)}</span>
</div>
<div class="detail-item">
<label>负责人:</label>
<span>${workorder.assignee}</span>
</div>
<div class="detail-item">
<label>创建时间:</label>
<span>${workorder.createTime}</span>
</div>
<div class="detail-item">
<label>描述:</label>
<span>${workorder.description || '无'}</span>
</div>
</div>
<div class="form-actions">
<button type="button" class="btn btn-secondary" onclick="closeModal()">关闭</button>
</div>
`;
document.getElementById('modal').style.display = 'block';
}
function editWorkorder(id) {
// 编辑工单逻辑
console.log('编辑工单:', id);
}
// 设备管理
function initializeDeviceManagement() {
// 添加设备按钮
document.getElementById('addDevice').addEventListener('click', showAddDeviceModal);
// 维护计划按钮
document.getElementById('deviceMaintenance').addEventListener('click', showMaintenanceModal);
// 设备分类切换
document.querySelectorAll('.category-card').forEach(card => {
card.addEventListener('click', function() {
document.querySelectorAll('.category-card').forEach(c => c.classList.remove('active'));
this.classList.add('active');
filterDevicesByCategory(this.getAttribute('data-category'));
});
});
// 初始化设备网格
refreshDeviceGrid();
}
function showAddDeviceModal() {
const modalBody = document.getElementById('modalBody');
modalBody.innerHTML = `
<div class="modal-header">
<h2>添加新设备</h2>
<button class="close" onclick="closeModal()">&times;</button>
</div>
<div class="modal-body">
<form id="addDeviceForm">
<div class="form-group">
<label>设备类型:</label>
<select name="category" required>
<option value="camera">智能摄像头</option>
<option value="ship">无人船</option>
<option value="drone">无人机</option>
<option value="sensor">传感器</option>
</select>
</div>
<div class="form-group">
<label>设备名称:</label>
<input type="text" name="name" required placeholder="请输入设备名称">
</div>
<div class="form-group">
<label>设备型号:</label>
<input type="text" name="model" required placeholder="请输入设备型号">
</div>
<div class="form-group">
<label>安装位置:</label>
<input type="text" name="location" required placeholder="请输入安装位置">
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">添加设备</button>
<button type="button" class="btn btn-secondary" onclick="closeModal()">取消</button>
</div>
</form>
</div>
`;
document.getElementById('modal').style.display = 'block';
document.getElementById('addDeviceForm').addEventListener('submit', function(e) {
e.preventDefault();
addDevice(new FormData(this));
});
}
function addDevice(formData) {
const device = {
id: 'DEV' + Date.now(),
category: formData.get('category'),
name: formData.get('name'),
model: formData.get('model'),
location: formData.get('location'),
status: 'online',
battery: Math.floor(Math.random() * 100),
lastMaintenance: new Date().toLocaleDateString('zh-CN'),
installDate: new Date().toLocaleDateString('zh-CN')
};
deviceData.push(device);
refreshDeviceGrid();
closeModal();
showNotification('设备添加成功', 'success');
}
function refreshDeviceGrid() {
const grid = document.getElementById('deviceGrid');
if (!grid) return;
grid.innerHTML = '';
deviceData.forEach(device => {
const card = document.createElement('div');
card.className = 'device-card';
card.innerHTML = `
<div class="device-header">
<div class="device-icon">
<i class="fas ${getDeviceIcon(device.category)}"></i>
</div>
<div class="device-info">
<h4>${device.name}</h4>
<span class="device-model">${device.model}</span>
</div>
<div class="device-status">
<span class="status-indicator ${device.status}"></span>
<span class="status-text">${getStatusText(device.status)}</span>
</div>
</div>
<div class="device-body">
<div class="device-detail">
<span class="detail-label">位置:</span>
<span class="detail-value">${device.location}</span>
</div>
<div class="device-detail">
<span class="detail-label">电量:</span>
<span class="detail-value">${device.battery}%</span>
<div class="progress">
<div class="progress-bar" style="width: ${device.battery}%"></div>
</div>
</div>
<div class="device-detail">
<span class="detail-label">上次维护:</span>
<span class="detail-value">${device.lastMaintenance}</span>
</div>
</div>
<div class="device-actions">
<button class="btn btn-sm" onclick="viewDevice('${device.id}')">详情</button>
<button class="btn btn-sm" onclick="controlDevice('${device.id}')">控制</button>
<button class="btn btn-sm" onclick="maintainDevice('${device.id}')">维护</button>
</div>
`;
grid.appendChild(card);
});
}
function getDeviceIcon(category) {
const icons = {
'camera': 'fa-video',
'ship': 'fa-ship',
'drone': 'fa-helicopter',
'sensor': 'fa-satellite-dish'
};
return icons[category] || 'fa-cog';
}
function filterDevicesByCategory(category) {
// 设备分类筛选逻辑
refreshDeviceGrid();
}
function viewDevice(id) {
const device = deviceData.find(d => d.id === id);
if (!device) return;
const modalBody = document.getElementById('modalBody');
modalBody.innerHTML = `
<h3>设备详情 - ${device.name}</h3>
<div class="device-details">
<div class="detail-item">
<label>设备ID:</label>
<span>${device.id}</span>
</div>
<div class="detail-item">
<label>设备类型:</label>
<span>${getCategoryText(device.category)}</span>
</div>
<div class="detail-item">
<label>设备型号:</label>
<span>${device.model}</span>
</div>
<div class="detail-item">
<label>安装位置:</label>
<span>${device.location}</span>
</div>
<div class="detail-item">
<label>设备状态:</label>
<span class="badge ${getStatusBadgeClass(device.status)}">${getStatusText(device.status)}</span>
</div>
<div class="detail-item">
<label>电池电量:</label>
<span>${device.battery}%</span>
</div>
<div class="detail-item">
<label>安装日期:</label>
<span>${device.installDate}</span>
</div>
<div class="detail-item">
<label>上次维护:</label>
<span>${device.lastMaintenance}</span>
</div>
</div>
<div class="form-actions">
<button type="button" class="btn btn-secondary" onclick="closeModal()">关闭</button>
</div>
`;
document.getElementById('modal').style.display = 'block';
}
function getCategoryText(category) {
const texts = {
'camera': '智能摄像头',
'ship': '无人船',
'drone': '无人机',
'sensor': '传感器'
};
return texts[category] || '未知';
}
function controlDevice(id) {
console.log('控制设备:', id);
showNotification('设备控制指令已发送', 'info');
}
function maintainDevice(id) {
console.log('维护设备:', id);
showNotification('维护任务已创建', 'success');
}
function showMaintenanceModal() {
const modalBody = document.getElementById('modalBody');
modalBody.innerHTML = `
<div class="modal-header">
<h2>设备维护计划</h2>
<button class="close" onclick="closeModal()">&times;</button>
</div>
<div class="modal-body">
<div class="maintenance-schedule">
<div class="schedule-item">
<div class="schedule-date">2024-01-15</div>
<div class="schedule-device">无人船-001</div>
<div class="schedule-type">定期保养</div>
<div class="schedule-status pending">待执行</div>
</div>
<div class="schedule-item">
<div class="schedule-date">2024-01-18</div>
<div class="schedule-device">摄像头-025</div>
<div class="schedule-type">故障维修</div>
<div class="schedule-status processing">进行中</div>
</div>
<div class="schedule-item">
<div class="schedule-date">2024-01-20</div>
<div class="schedule-device">无人机-003</div>
<div class="schedule-type">电池更换</div>
<div class="schedule-status completed">已完成</div>
</div>
</div>
<div class="form-actions">
<button type="button" class="btn btn-primary">添加维护计划</button>
<button type="button" class="btn btn-secondary" onclick="closeModal()">关闭</button>
</div>
</div>
`;
document.getElementById('modal').style.display = 'block';
}
// 预警系统
function initializeWarningSystem() {
// 预警设置按钮
document.getElementById('warningSettings').addEventListener('click', showWarningSettingsModal);
// 历史记录按钮
document.getElementById('warningHistory').addEventListener('click', showWarningHistoryModal);
// 初始化预警数据
refreshWarningData();
}
function refreshWarningData() {
// 更新天气信息
updateWeatherInfo();
// 更新垃圾堆积预警
updateGarbageAlerts();
// 更新设备故障预警
updateDeviceAlerts();
}
function updateWeatherInfo() {
// 模拟天气数据更新
const weatherItems = document.querySelectorAll('.weather-item .weather-value');
if (weatherItems.length >= 3) {
weatherItems[0].textContent = '多云 ' + (20 + Math.floor(Math.random() * 10)) + '°C';
weatherItems[1].textContent = Math.floor(Math.random() * 5 + 1) + '级';
weatherItems[2].textContent = Math.floor(Math.random() * 100) + '%';
}
}
function updateGarbageAlerts() {
// 更新垃圾堆积预警数据
console.log('更新垃圾堆积预警');
}
function updateDeviceAlerts() {
// 更新设备故障预警数据
console.log('更新设备故障预警');
}
function showWarningSettingsModal() {
const modalBody = document.getElementById('modalBody');
modalBody.innerHTML = `
<div class="modal-header">
<h2>预警设置</h2>
<button class="close" onclick="closeModal()">&times;</button>
</div>
<div class="modal-body">
<form id="warningSettingsForm">
<div class="settings-section">
<h4>天气预警</h4>
<div class="form-group">
<label>风力预警阈值:</label>
<select name="windThreshold">
<option value="3">3级</option>
<option value="4" selected>4级</option>
<option value="5">5级</option>
</select>
</div>
<div class="form-group">
<label>降雨预警阈值:</label>
<select name="rainThreshold">
<option value="50">50%</option>
<option value="70" selected>70%</option>
<option value="80">80%</option>
</select>
</div>
</div>
<div class="settings-section">
<h4>设备预警</h4>
<div class="form-group">
<label>电量预警阈值:</label>
<select name="batteryThreshold">
<option value="10">10%</option>
<option value="20" selected>20%</option>
<option value="30">30%</option>
</select>
</div>
<div class="form-group">
<label>离线预警时间:</label>
<select name="offlineThreshold">
<option value="5">5分钟</option>
<option value="10" selected>10分钟</option>
<option value="15">15分钟</option>
</select>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">保存设置</button>
<button type="button" class="btn btn-secondary" onclick="closeModal()">取消</button>
</div>
</form>
</div>
`;
document.getElementById('modal').style.display = 'block';
document.getElementById('warningSettingsForm').addEventListener('submit', function(e) {
e.preventDefault();
saveWarningSettings(new FormData(this));
});
}
function saveWarningSettings(formData) {
// 保存预警设置
console.log('保存预警设置');
closeModal();
showNotification('预警设置已保存', 'success');
}
function showWarningHistoryModal() {
const modalBody = document.getElementById('modalBody');
modalBody.innerHTML = `
<div class="modal-header">
<h2>预警历史记录</h2>
<button class="close" onclick="closeModal()">&times;</button>
</div>
<div class="modal-body">
<div class="warning-history">
<div class="history-item critical">
<div class="history-time">2024-01-10 14:30</div>
<div class="history-type">设备故障</div>
<div class="history-message">无人船-001电池电量严重不足</div>
<div class="history-status resolved">已处理</div>
</div>
<div class="history-item high">
<div class="history-time">2024-01-09 09:15</div>
<div class="history-type">天气预警</div>
<div class="history-message">预计下午有大风,建议暂停水面作业</div>
<div class="history-status resolved">已处理</div>
</div>
<div class="history-item medium">
<div class="history-time">2024-01-08 16:45</div>
<div class="history-type">垃圾堆积</div>
<div class="history-message">橘子洲头弯道垃圾堆积超过阈值</div>
<div class="history-status pending">处理中</div>
</div>
</div>
<div class="form-actions">
<button type="button" class="btn btn-secondary" onclick="closeModal()">关闭</button>
</div>
</div>
`;
document.getElementById('modal').style.display = 'block';
}
// 统计分析事件绑定
function bindStatisticsEvents() {
// 时间范围选择
const timeRangeSelect = document.querySelector('.time-range');
if (timeRangeSelect) {
timeRangeSelect.addEventListener('change', function() {
refreshCharts();
});
}
// 导出报告按钮
const exportBtn = document.getElementById('exportReport');
if (exportBtn) {
exportBtn.addEventListener('click', exportReport);
}
}
// 重复的chart初始化代码已被完全移除
// 现在统计分析页面的charts由setupStatisticsCharts()函数统一管理
// 初始化监控管理一张图的图表
function initializeMonitorCharts() {
// 垃圾清理统计柱状图
const cleanupChartCtx = document.getElementById('cleanupChart');
if (cleanupChartCtx) {
// 销毁已存在的图表实例
destroyChart('cleanupStats');
window.chartInstances.cleanupStats = new Chart(cleanupChartCtx, {
type: 'bar',
data: {
labels: ['今日', '昨日', '本周', '上周', '本月'],
datasets: [{
label: '清理量(kg)',
data: [156, 142, 1200, 980, 4500],
backgroundColor: [
'rgba(52, 152, 219, 0.8)',
'rgba(46, 204, 113, 0.8)',
'rgba(155, 89, 182, 0.8)',
'rgba(241, 196, 15, 0.8)',
'rgba(231, 76, 60, 0.8)'
],
borderColor: [
'#3498db',
'#2ecc71',
'#9b59b6',
'#f1c40f',
'#e74c3c'
],
borderWidth: 2
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
x: {
ticks: {
color: '#b0c4de',
font: {
size: 10
}
},
grid: {
color: 'rgba(176, 196, 222, 0.1)'
}
},
y: {
beginAtZero: true,
ticks: {
color: '#b0c4de',
font: {
size: 10
}
},
grid: {
color: 'rgba(176, 196, 222, 0.1)'
}
}
}
}
});
}
// 实时数据趋势线图
const trendChartCtx = document.getElementById('trendChart');
if (trendChartCtx) {
// 销毁已存在的图表实例
destroyChart('trendChart');
window.chartInstances['trendChart'] = new Chart(trendChartCtx, {
type: 'line',
data: {
labels: ['00:00', '04:00', '08:00', '12:00', '16:00', '20:00', '24:00'],
datasets: [
{
label: '垃圾检测数量',
data: [5, 3, 8, 12, 15, 9, 6],
borderColor: '#e74c3c',
backgroundColor: 'rgba(231, 76, 60, 0.1)',
tension: 0.4,
fill: false
},
{
label: '清理完成数量',
data: [3, 2, 6, 10, 13, 8, 5],
borderColor: '#3498db',
backgroundColor: 'rgba(52, 152, 219, 0.1)',
tension: 0.4,
fill: false
},
{
label: '设备在线率(%)',
data: [95, 92, 98, 96, 94, 97, 95],
borderColor: '#2ecc71',
backgroundColor: 'rgba(46, 204, 113, 0.1)',
tension: 0.4,
fill: false,
yAxisID: 'y1'
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
x: {
ticks: {
color: '#b0c4de',
font: {
size: 9
}
},
grid: {
color: 'rgba(176, 196, 222, 0.1)'
}
},
y: {
type: 'linear',
display: true,
position: 'left',
beginAtZero: true,
ticks: {
color: '#b0c4de',
font: {
size: 9
}
},
grid: {
color: 'rgba(176, 196, 222, 0.1)'
}
},
y1: {
type: 'linear',
display: true,
position: 'right',
min: 0,
max: 100,
ticks: {
color: '#b0c4de',
font: {
size: 9
}
},
grid: {
drawOnChartArea: false
}
}
}
}
});
}
}
function refreshCharts() {
// 刷新所有图表数据
Object.values(window.chartInstances).forEach(chart => {
if (chart && chart.update) {
chart.update();
}
});
}
// 刷新监控管理一张图的图表
function refreshMonitorCharts() {
// 更新垃圾清理统计数据
if (window.chartInstances.cleanupStats) {
const newData = {
labels: ['今日', '昨日', '本周', '上周', '本月'],
datasets: [{
label: '清理量(kg)',
data: [
Math.floor(Math.random() * 50) + 130, // 今日: 130-180
Math.floor(Math.random() * 40) + 120, // 昨日: 120-160
Math.floor(Math.random() * 400) + 1000, // 本周: 1000-1400
Math.floor(Math.random() * 300) + 800, // 上周: 800-1100
Math.floor(Math.random() * 1000) + 4000 // 本月: 4000-5000
],
backgroundColor: [
'rgba(52, 152, 219, 0.8)',
'rgba(46, 204, 113, 0.8)',
'rgba(155, 89, 182, 0.8)',
'rgba(241, 196, 15, 0.8)',
'rgba(231, 76, 60, 0.8)'
],
borderColor: [
'#3498db',
'#2ecc71',
'#9b59b6',
'#f1c40f',
'#e74c3c'
],
borderWidth: 2
}]
};
window.chartInstances.cleanupStats.data = newData;
window.chartInstances.cleanupStats.update();
}
// 更新实时数据趋势
if (window.chartInstances.trendStats) {
const currentHour = new Date().getHours();
const timeLabels = [];
const detectionData = [];
const cleanupData = [];
const onlineRateData = [];
// 生成过去24小时的数据
for (let i = 6; i >= 0; i--) {
const hour = (currentHour - i * 4 + 24) % 24;
timeLabels.push(String(hour).padStart(2, '0') + ':00');
detectionData.push(Math.floor(Math.random() * 10) + 3);
cleanupData.push(Math.floor(Math.random() * 8) + 2);
onlineRateData.push(Math.floor(Math.random() * 8) + 92);
}
window.chartInstances.trendStats.data.labels = timeLabels;
window.chartInstances.trendStats.data.datasets[0].data = detectionData;
window.chartInstances.trendStats.data.datasets[1].data = cleanupData;
window.chartInstances.trendStats.data.datasets[2].data = onlineRateData;
window.chartInstances.trendStats.update();
}
}
function exportReport() {
console.log('导出统计报告');
showNotification('报告导出成功', 'success');
}
// 模态框系统
function initializeModal() {
const modal = document.getElementById('modal');
const closeBtn = document.querySelector('.close');
// 点击关闭按钮
closeBtn.addEventListener('click', closeModal);
// 点击模态框外部关闭
window.addEventListener('click', function(event) {
if (event.target === modal) {
closeModal();
}
});
// ESC键关闭
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape') {
closeModal();
}
});
}
function closeModal() {
document.getElementById('modal').style.display = 'none';
}
// 通知系统
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.innerHTML = `
<div class="notification-content">
<i class="fas ${getNotificationIcon(type)}"></i>
<span>${message}</span>
</div>
<button class="notification-close" onclick="this.parentElement.remove()">
<i class="fas fa-times"></i>
</button>
`;
// 添加样式
notification.style.cssText = `
position: fixed;
top: 100px;
right: 20px;
background: white;
border-radius: 8px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
padding: 1rem;
z-index: 2001;
display: flex;
align-items: center;
justify-content: space-between;
min-width: 300px;
border-left: 4px solid ${getNotificationColor(type)};
animation: slideInRight 0.3s ease;
`;
document.body.appendChild(notification);
// 自动移除
setTimeout(() => {
if (notification.parentElement) {
notification.remove();
}
}, 5000);
}
function getNotificationIcon(type) {
const icons = {
'success': 'fa-check-circle',
'error': 'fa-exclamation-circle',
'warning': 'fa-exclamation-triangle',
'info': 'fa-info-circle'
};
return icons[type] || 'fa-info-circle';
}
function getNotificationColor(type) {
const colors = {
'success': '#2ecc71',
'error': '#e74c3c',
'warning': '#f39c12',
'info': '#3498db'
};
return colors[type] || '#3498db';
}
// 数据加载
function loadMockData() {
// 加载模拟工单数据
workorderData = [
{
id: 'WO202401001',
type: 'water',
location: '橘子洲头弯道',
discoveryMethod: 'AI自动识别',
status: 'processing',
assignee: '张三',
createTime: '2024-01-10 09:30:00',
description: '发现大量漂浮垃圾'
},
{
id: 'WO202401002',
type: 'beach',
location: '湘江中路段滩涂',
discoveryMethod: '巡查员上报',
status: 'completed',
assignee: '李四',
createTime: '2024-01-09 14:15:00',
description: '滩涂堆积物清理'
},
{
id: 'WO202401003',
type: 'illegal',
location: '猴子石大桥下',
discoveryMethod: '公众反馈',
status: 'pending',
assignee: '待分配',
createTime: '2024-01-11 16:45:00',
description: '疑似违法倾倒垃圾'
}
];
// 加载模拟设备数据
deviceData = [
{
id: 'CAM001',
category: 'camera',
name: '摄像头01',
model: 'HC-AI-8000',
location: '橘子洲头',
status: 'online',
battery: 95,
lastMaintenance: '2024-01-01',
installDate: '2023-06-15'
},
{
id: 'SHIP001',
category: 'ship',
name: '无人船01',
model: 'AS-3500',
location: '湘江中段',
status: 'working',
battery: 78,
lastMaintenance: '2024-01-05',
installDate: '2023-08-20'
},
{
id: 'DRONE001',
category: 'drone',
name: '无人机01',
model: 'DJI-M300',
location: '监控中心',
status: 'charging',
battery: 45,
lastMaintenance: '2024-01-08',
installDate: '2023-09-10'
}
];
}
// 实时数据更新
function startRealTimeUpdates() {
// 每30秒更新一次实时数据
setInterval(() => {
updateRealTimeData();
}, 30000);
}
function updateRealTimeData() {
// 更新设备状态
deviceData.forEach(device => {
// 随机更新电池电量
if (device.status === 'working' || device.status === 'flying') {
device.battery = Math.max(0, device.battery - Math.floor(Math.random() * 3));
} else if (device.status === 'charging') {
device.battery = Math.min(100, device.battery + Math.floor(Math.random() * 5));
}
});
// 如果当前在设备管理页面,刷新显示
if (currentTab === 'device') {
refreshDeviceGrid();
}
// 更新地图标记
if (map && currentTab === 'monitor') {
// 这里可以添加地图标记更新逻辑
}
// 更新预警数据
if (currentTab === 'warning') {
refreshWarningData();
}
}
// 工具函数
function formatDate(date) {
return new Date(date).toLocaleDateString('zh-CN');
}
function formatDateTime(date) {
return new Date(date).toLocaleString('zh-CN');
}
function generateId(prefix = 'ID') {
return prefix + Date.now() + Math.floor(Math.random() * 1000);
}
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
// 错误处理
window.addEventListener('error', function(event) {
console.error('JavaScript错误:', event.error);
showNotification('系统发生错误,请刷新页面重试', 'error');
});
// 网络状态监测
window.addEventListener('online', function() {
showNotification('网络连接已恢复', 'success');
});
window.addEventListener('offline', function() {
showNotification('网络连接已断开', 'warning');
});
// 页面可见性变化处理
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
// 页面隐藏时暂停某些更新
console.log('页面隐藏,暂停实时更新');
} else {
// 页面显示时恢复更新
console.log('页面显示,恢复实时更新');
updateRealTimeData();
}
});
// 工单系统初始化
function initializeWorkorder() {
loadWorkorderData();
setupWorkorderEvents();
}
// 设备管理初始化
function initializeDevice() {
loadDeviceData();
setupDeviceEvents();
}
// 告警系统初始化
function initializeWarning() {
loadWarningData();
setupWarningEvents();
}
// 统计分析初始化
function initializeStatistics() {
loadStatisticsData();
bindStatisticsEvents();
setupStatisticsCharts();
}
// 加载工单数据
function loadWorkorderData() {
const workorderTableBody = document.getElementById('workorderTableBody');
if (!workorderTableBody) return;
const workorders = [
{id: 'WO001', type: '垃圾清理', location: '黄浦江段A区', method: '无人机发现', status: 'created', assignee: '张三', createTime: '2024-01-15 09:30', priority: '高', responseTime: '2024-01-15 11:30'},
{id: 'WO002', type: '水质异常', location: '苏州河段B区', method: '传感器监测', status: 'assigned', assignee: '李四', createTime: '2024-01-15 10:15', priority: '中', responseTime: '2024-01-15 14:15'},
{id: 'WO003', type: '设备维护', location: '黄浦江段C区', method: '定期巡检', status: 'completed', assignee: '王五', createTime: '2024-01-14 14:20', priority: '低', responseTime: '2024-01-15 02:20'},
{id: 'WO004', type: '垃圾清理', location: '苏州河段D区', method: '市民举报', status: 'dispatched', assignee: '赵六', createTime: '2024-01-15 11:45', priority: '高', responseTime: '2024-01-15 13:45'},
{id: 'WO005', type: '水质监测', location: '黄浦江段E区', method: '无人船巡检', status: 'arrived', assignee: '钱七', createTime: '2024-01-15 13:10', priority: '中', responseTime: '2024-01-15 17:10'},
{id: 'WO006', type: '设备故障', location: '苏州河段F区', method: '传感器报警', status: 'departed', assignee: '孙八', createTime: '2024-01-15 14:20', priority: '高', responseTime: '2024-01-15 16:20'},
{id: 'WO007', type: '垃圾清理', location: '黄浦江段G区', method: '巡检发现', status: 'processed', assignee: '周九', createTime: '2024-01-15 15:30', priority: '中', responseTime: '2024-01-15 19:30'},
{id: 'WO008', type: '水质异常', location: '苏州河段H区', method: '市民举报', status: 'transported', assignee: '吴十', createTime: '2024-01-15 16:45', priority: '低', responseTime: '2024-01-16 04:45'}
];
const statusMap = {
'created': {text: '新建', class: 'status-created'},
'assigned': {text: '待分配', class: 'status-assigned'},
'dispatched': {text: '待出发', class: 'status-dispatched'},
'departed': {text: '已出发', class: 'status-departed'},
'arrived': {text: '已抵达', class: 'status-arrived'},
'processed': {text: '已处理', class: 'status-processed'},
'transported': {text: '已转运', class: 'status-transported'},
'completed': {text: '已完成', class: 'status-completed'}
};
workorderTableBody.innerHTML = workorders.map(wo => `
<tr>
<td><input type="checkbox" value="${wo.id}"></td>
<td>${wo.id}</td>
<td>${wo.method}</td>
<td>${wo.type}</td>
<td>${wo.location}</td>
<td><span class="priority-badge priority-${wo.priority || 'medium'}">${wo.priority || '中'}</span></td>
<td><span class="status-badge ${statusMap[wo.status].class}">${statusMap[wo.status].text}</span></td>
<td>${wo.assignee}</td>
<td>${wo.createTime}</td>
<td>${wo.responseTime || '待设定'}</td>
<td>
<button class="btn btn-sm btn-primary" onclick="viewWorkorder('${wo.id}')">查看</button>
<button class="btn btn-sm btn-secondary" onclick="editWorkorder('${wo.id}')">编辑</button>
</td>
</tr>
`).join('');
}
// 加载设备数据
function loadDeviceData() {
const deviceGrid = document.getElementById('deviceGrid');
if (!deviceGrid) return;
const devices = [
{id: 'CAM001', name: '监控摄像头-01', type: 'camera', status: 'online', location: '黄浦江段A区', battery: 85},
{id: 'DRONE001', name: '清理无人机-01', type: 'drone', status: 'online', location: '苏州河段B区', battery: 92},
{id: 'SHIP001', name: '巡检无人船-01', type: 'ship', status: 'offline', location: '黄浦江段C区', battery: 23},
{id: 'SENSOR001', name: '水质传感器-01', type: 'sensor', status: 'online', location: '苏州河段D区', battery: 78},
{id: 'CAM002', name: '监控摄像头-02', type: 'camera', status: 'warning', location: '黄浦江段E区', battery: 45},
{id: 'DRONE002', name: '清理无人机-02', type: 'drone', status: 'online', location: '苏州河段F区', battery: 88}
];
const statusMap = {
'online': {text: '在线', class: 'device-online'},
'offline': {text: '离线', class: 'device-offline'},
'warning': {text: '告警', class: 'device-warning'}
};
const typeIcons = {
'camera': 'fas fa-video',
'drone': 'fas fa-helicopter',
'ship': 'fas fa-ship',
'sensor': 'fas fa-thermometer-half'
};
deviceGrid.innerHTML = devices.map(device => `
<div class="device-card ${statusMap[device.status].class}">
<div class="device-header">
<div class="device-icon">
<i class="${typeIcons[device.type]}"></i>
</div>
<div class="device-status">
<span class="status-dot"></span>
${statusMap[device.status].text}
</div>
</div>
<div class="device-info">
<h4>${device.name}</h4>
<p class="device-id">${device.id}</p>
<p class="device-location">${device.location}</p>
<div class="device-battery">
<span>电量: ${device.battery}%</span>
<div class="battery-bar">
<div class="battery-fill" style="width: ${device.battery}%"></div>
</div>
</div>
</div>
<div class="device-actions">
<button class="btn btn-sm btn-primary" onclick="controlDevice('${device.id}')">控制</button>
<button class="btn btn-sm btn-secondary" onclick="deviceDetail('${device.id}')">详情</button>
</div>
</div>
`).join('');
}
// 加载告警数据
function loadWarningData() {
loadWaterQualityWarnings();
loadDeviceWarnings();
}
function loadWaterQualityWarnings() {
const container = document.getElementById('waterQualityWarnings');
if (!container) return;
const warnings = [
{id: 'WQ001', location: '黄浦江段A区', parameter: 'pH值', value: '8.9', threshold: '6.5-8.5', level: 'medium', time: '10分钟前'},
{id: 'WQ002', location: '苏州河段B区', parameter: '溶解氧', value: '3.2mg/L', threshold: '>5mg/L', level: 'high', time: '25分钟前'},
{id: 'WQ003', location: '黄浦江段C区', parameter: '浊度', value: '15NTU', threshold: '<10NTU', level: 'low', time: '1小时前'}
];
container.innerHTML = warnings.map(warning => `
<div class="warning-item ${warning.level}">
<div class="warning-header">
<span class="warning-location">${warning.location}</span>
<span class="warning-time">${warning.time}</span>
</div>
<div class="warning-content">
<div class="warning-parameter">${warning.parameter}: ${warning.value}</div>
<div class="warning-threshold">标准: ${warning.threshold}</div>
</div>
</div>
`).join('');
}
function loadDeviceWarnings() {
const container = document.getElementById('deviceWarnings');
if (!container) return;
const warnings = [
{id: 'DW001', device: '清理无人机-01', issue: '电量不足', level: 'high', location: '苏州河段B区', time: '5分钟前'},
{id: 'DW002', device: '水质传感器-02', issue: '通信异常', level: 'critical', location: '黄浦江段D区', time: '15分钟前'},
{id: 'DW003', device: '监控摄像头-03', issue: '图像模糊', level: 'medium', location: '苏州河段F区', time: '30分钟前'}
];
container.innerHTML = warnings.map(warning => `
<div class="warning-item ${warning.level}">
<div class="warning-header">
<span class="warning-device">${warning.device}</span>
<span class="warning-time">${warning.time}</span>
</div>
<div class="warning-content">
<div class="warning-issue">${warning.issue}</div>
<div class="warning-location">${warning.location}</div>
</div>
</div>
`).join('');
}
// 加载统计数据
function loadStatisticsData() {
// 统计数据已在HTML中静态显示这里可以添加动态更新逻辑
}
// 全局图表实例存储
window.chartInstances = window.chartInstances || {};
// 销毁图表实例的辅助函数
function destroyChart(chartId) {
if (window.chartInstances[chartId]) {
window.chartInstances[chartId].destroy();
delete window.chartInstances[chartId];
}
}
// 设置统计图表
function setupStatisticsCharts() {
setupCleanupTrendChart();
setupDeviceUsageChart();
setupAreaDistributionChart();
setupEfficiencyChart();
}
function setupCleanupTrendChart() {
const canvas = document.getElementById('cleanupTrendChart');
if (!canvas) return;
// 销毁已存在的图表实例
destroyChart('cleanupTrendChart');
const ctx = canvas.getContext('2d');
window.chartInstances['cleanupTrendChart'] = new Chart(ctx, {
type: 'line',
data: {
labels: ['1月', '2月', '3月', '4月', '5月', '6月'],
datasets: [{
label: '清理量(吨)',
data: [120, 150, 180, 220, 190, 250],
borderColor: '#64b5f6',
backgroundColor: 'rgba(100, 181, 246, 0.1)',
tension: 0.4
}]
},
options: {
responsive: true,
plugins: {
legend: {
labels: { color: '#e0e0e0' }
}
},
scales: {
x: { ticks: { color: '#b0bec5' } },
y: { ticks: { color: '#b0bec5' } }
}
}
});
}
function setupDeviceUsageChart() {
const canvas = document.getElementById('deviceUsageChart');
if (!canvas) return;
// 销毁已存在的图表实例
destroyChart('deviceUsageChart');
const ctx = canvas.getContext('2d');
window.chartInstances['deviceUsageChart'] = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['摄像头', '无人机', '无人船', '传感器'],
datasets: [{
data: [35, 25, 20, 20],
backgroundColor: ['#64b5f6', '#42a5f5', '#2196f3', '#1976d2']
}]
},
options: {
responsive: true,
plugins: {
legend: {
labels: { color: '#e0e0e0' }
}
}
}
});
}
function setupAreaDistributionChart() {
const canvas = document.getElementById('areaDistributionChart');
if (!canvas) return;
// 销毁已存在的图表实例
destroyChart('areaDistributionChart');
const ctx = canvas.getContext('2d');
window.chartInstances['areaDistributionChart'] = new Chart(ctx, {
type: 'bar',
data: {
labels: ['黄浦江段', '苏州河段', '长江口段', '其他水域'],
datasets: [{
label: '清理次数',
data: [45, 38, 22, 15],
backgroundColor: '#64b5f6'
}]
},
options: {
responsive: true,
plugins: {
legend: {
labels: { color: '#e0e0e0' }
}
},
scales: {
x: { ticks: { color: '#b0bec5' } },
y: { ticks: { color: '#b0bec5' } }
}
}
});
}
function setupEfficiencyChart() {
const canvas = document.getElementById('efficiencyChart');
if (!canvas) return;
// 销毁已存在的图表实例
destroyChart('efficiencyChart');
const ctx = canvas.getContext('2d');
window.chartInstances['efficiencyChart'] = new Chart(ctx, {
type: 'radar',
data: {
labels: ['响应速度', '清理效率', '设备利用率', '成本控制', '环保指标'],
datasets: [{
label: '当前指标',
data: [85, 92, 78, 88, 95],
borderColor: '#64b5f6',
backgroundColor: 'rgba(100, 181, 246, 0.2)'
}]
},
options: {
responsive: true,
plugins: {
legend: {
labels: { color: '#e0e0e0' }
}
},
scales: {
r: {
ticks: { color: '#b0bec5' },
grid: { color: '#2a3f5f' }
}
}
}
});
}
// 设置事件监听器
function setupWorkorderEvents() {
// 工单相关事件处理
const createBtn = document.getElementById('createWorkorder');
if (createBtn) {
createBtn.addEventListener('click', () => {
console.log('创建新工单');
});
}
}
function setupDeviceEvents() {
// 设备分类按钮事件
const categoryBtns = document.querySelectorAll('.category-btn');
categoryBtns.forEach(btn => {
btn.addEventListener('click', (e) => {
categoryBtns.forEach(b => b.classList.remove('active'));
e.target.classList.add('active');
filterDevices(e.target.dataset.category);
});
});
}
function setupWarningEvents() {
// 告警相关事件处理
}
// 工具函数
function editWorkorder(id) {
console.log('编辑工单:', id);
}
function controlDevice(id) {
console.log('控制设备:', id);
}
function deviceDetail(id) {
console.log('设备详情:', id);
}
function filterDevices(category) {
console.log('筛选设备类型:', category);
}
// 导出全局函数供HTML调用
window.switchTab = switchTab;
window.closeModal = closeModal;
window.viewWorkorder = viewWorkorder;
window.editWorkorder = editWorkorder;
window.controlDevice = controlDevice;
window.deviceDetail = deviceDetail;
window.filterDevices = filterDevices;
window.editWorkorder = editWorkorder;
window.viewDevice = viewDevice;
window.controlDevice = controlDevice;
window.maintainDevice = maintainDevice;
window.showNotification = showNotification;
console.log('智慧河道管理平台初始化完成');