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

// 智慧河道管理平台 - 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('智慧河道管理平台初始化完成');