feat: 优化页面效果

This commit is contained in:
yarnom 2025-07-04 21:48:26 +08:00
parent 6ecc833a2c
commit efaf5fe8f4
9 changed files with 294 additions and 1535 deletions

View File

@ -36,12 +36,7 @@ var CoordinateUtils = (function() {
return ret; return ret;
} }
/**
* WGS84转GCJ-02坐标系
* @param {number} wgLat - WGS84纬度
* @param {number} wgLon - WGS84经度
* @returns {object} 转换后的坐标 {lat, lon}
*/
function transform(wgLat, wgLon) { function transform(wgLat, wgLon) {
var mars_point = {lon: 0, lat: 0}; var mars_point = {lon: 0, lat: 0};
if (outOfChina(wgLon, wgLat)) { if (outOfChina(wgLon, wgLat)) {
@ -62,13 +57,7 @@ var CoordinateUtils = (function() {
return mars_point; return mars_point;
} }
/**
* 根据地图类型转换坐标
* @param {number} lat - 纬度
* @param {number} lon - 经度
* @param {string} mapType - 地图类型
* @returns {Array} OpenLayers坐标格式
*/
function getMapCoordinates(lat, lon, mapType) { function getMapCoordinates(lat, lon, mapType) {
var coordinates; var coordinates;
if (mapType === 'amap' || mapType === 'amap_satellite') { if (mapType === 'amap' || mapType === 'amap_satellite') {
@ -76,16 +65,16 @@ var CoordinateUtils = (function() {
var gcjCoord = transform(lat, lon); var gcjCoord = transform(lat, lon);
coordinates = ol.proj.fromLonLat([gcjCoord.lon, gcjCoord.lat]); coordinates = ol.proj.fromLonLat([gcjCoord.lon, gcjCoord.lat]);
} else if (mapType.startsWith('google_')) { } else if (mapType.startsWith('google_')) {
// Google地图使用WGS84坐标系,直接使用 // Google地图使用WGS84坐标系
coordinates = ol.proj.fromLonLat([lon, lat]); coordinates = ol.proj.fromLonLat([lon, lat]);
} else { } else {
// 天地图 CGCS20002000国家大地坐标系与WGS84实质一样 // 天地图 CGCS2000与WGS84实质一样
coordinates = ol.proj.fromLonLat([lon, lat]); coordinates = ol.proj.fromLonLat([lon, lat]);
} }
return coordinates; return coordinates;
} }
// 公开API
return { return {
transform: transform, transform: transform,
getMapCoordinates: getMapCoordinates, getMapCoordinates: getMapCoordinates,

View File

@ -5,7 +5,6 @@
var DeviceMarkers = (function() { var DeviceMarkers = (function() {
'use strict'; 'use strict';
// 私有变量
var greenFeatures = []; var greenFeatures = [];
var orangeFeatures = []; var orangeFeatures = [];
var redFeatures = []; var redFeatures = [];
@ -15,28 +14,19 @@ var DeviceMarkers = (function() {
var showDeviceId = true; var showDeviceId = true;
var minZoomForLabels = 4; var minZoomForLabels = 4;
// 外部依赖的引用
var map = null; var map = null;
var vectorSource = null; var vectorSource = null;
var vectorLayer = null; var vectorLayer = null;
/**
* 初始化设备标记管理器
* @param {ol.Map} mapInstance - 地图实例
* @param {ol.source.Vector} vectorSourceInstance - 矢量数据源
* @param {ol.layer.Vector} vectorLayerInstance - 矢量图层
*/
function init(mapInstance, vectorSourceInstance, vectorLayerInstance) { function init(mapInstance, vectorSourceInstance, vectorLayerInstance) {
map = mapInstance; map = mapInstance;
vectorSource = vectorSourceInstance; vectorSource = vectorSourceInstance;
vectorLayer = vectorLayerInstance; vectorLayer = vectorLayerInstance;
} }
/**
* 创建设备标记样式
* @param {ol.Feature} feature - 要素对象
* @returns {ol.style.Style} 样式对象
*/
function createDeviceStyle(feature) { function createDeviceStyle(feature) {
if (feature.get('isMyLocation')) { if (feature.get('isMyLocation')) {
return new ol.style.Style({ return new ol.style.Style({
@ -92,24 +82,18 @@ var DeviceMarkers = (function() {
return style; return style;
} }
/**
* 添加设备标记到地图
* @param {Array} deviceList - 设备列表
*/
function addDeviceMarkers(deviceList) { function addDeviceMarkers(deviceList) {
if (!vectorSource || !deviceList) return; if (!vectorSource || !deviceList) return;
// 保存当前位置标记
var savedMyLocationFeature = myLocationFeature; var savedMyLocationFeature = myLocationFeature;
// 清空现有标记
vectorSource.clear(); vectorSource.clear();
greenFeatures = []; greenFeatures = [];
orangeFeatures = []; orangeFeatures = [];
redFeatures = []; redFeatures = [];
allFeatures = []; allFeatures = [];
// 添加设备标记
for (var i = 0; i < deviceList.length; i++) { for (var i = 0; i < deviceList.length; i++) {
var device = deviceList[i]; var device = deviceList[i];
var currentMapType = getCurrentMapType(); var currentMapType = getCurrentMapType();
@ -137,7 +121,6 @@ var DeviceMarkers = (function() {
vectorSource.addFeature(feature); vectorSource.addFeature(feature);
} }
// 恢复位置标记
if (savedMyLocationFeature) { if (savedMyLocationFeature) {
vectorSource.addFeature(savedMyLocationFeature); vectorSource.addFeature(savedMyLocationFeature);
} }
@ -148,18 +131,13 @@ var DeviceMarkers = (function() {
} }
} }
/**
* 获取当前地图类型
* @returns {string} 地图类型
*/
function getCurrentMapType() { function getCurrentMapType() {
var mapTypeSelect = document.getElementById('mapTypeSelectNew'); var mapTypeSelect = document.getElementById('mapTypeSelectNew');
return mapTypeSelect ? mapTypeSelect.value : 'tianditu_satellite'; return mapTypeSelect ? mapTypeSelect.value : 'tianditu_satellite';
} }
/**
* 显示所有设备
*/
function showAllDevices() { function showAllDevices() {
if (!vectorSource) return; if (!vectorSource) return;
@ -175,9 +153,6 @@ var DeviceMarkers = (function() {
} }
} }
/**
* 只显示一般告警设备
*/
function showWarning1Devices() { function showWarning1Devices() {
if (!vectorSource) return; if (!vectorSource) return;
@ -196,9 +171,7 @@ var DeviceMarkers = (function() {
hideRedFeatures(); hideRedFeatures();
} }
/**
* 只显示严重告警设备
*/
function showWarning2Devices() { function showWarning2Devices() {
if (!vectorSource) return; if (!vectorSource) return;
@ -217,73 +190,47 @@ var DeviceMarkers = (function() {
hideOrangeFeatures(); hideOrangeFeatures();
} }
/**
* 隐藏绿色正常设备
*/
function hideGreenFeatures() { function hideGreenFeatures() {
for (var i = 0; i < greenFeatures.length; i++) { for (var i = 0; i < greenFeatures.length; i++) {
vectorSource.removeFeature(greenFeatures[i]); vectorSource.removeFeature(greenFeatures[i]);
} }
} }
/**
* 隐藏橙色一般告警设备
*/
function hideOrangeFeatures() { function hideOrangeFeatures() {
for (var i = 0; i < orangeFeatures.length; i++) { for (var i = 0; i < orangeFeatures.length; i++) {
vectorSource.removeFeature(orangeFeatures[i]); vectorSource.removeFeature(orangeFeatures[i]);
} }
} }
/**
* 隐藏红色严重告警设备
*/
function hideRedFeatures() { function hideRedFeatures() {
for (var i = 0; i < redFeatures.length; i++) { for (var i = 0; i < redFeatures.length; i++) {
vectorSource.removeFeature(redFeatures[i]); vectorSource.removeFeature(redFeatures[i]);
} }
} }
/**
* 根据设备ID查找设备
* @param {string} deviceId - 设备ID
* @returns {ol.Feature|null} 找到的设备要素
*/
function findDeviceById(deviceId) { function findDeviceById(deviceId) {
for (var i = 0; i < allFeatures.length; i++) { for (var i = 0; i < allFeatures.length; i++) {
var feature = allFeatures[i]; var feature = allFeatures[i];
var deviceInfo = feature.get('deviceInfo'); var deviceInfo = feature.get('deviceInfo');
if (deviceInfo && deviceInfo.deviceid.includes(deviceId)) { if (deviceInfo && deviceInfo.deviceid === deviceId) {
return feature; return feature;
} }
} }
return null; return null;
} }
/**
* 定位到指定设备
* @param {string} deviceId - 设备ID
* @returns {boolean} 是否成功定位
*/
function locateDevice(deviceId) { function locateDevice(deviceId) {
var targetFeature = findDeviceById(deviceId); var feature = findDeviceById(deviceId);
if (feature && map) {
var geometry = feature.getGeometry();
var coordinates = geometry.getCoordinates();
if (targetFeature) { map.getView().animate({
var geometry = targetFeature.getGeometry(); center: coordinates,
var deviceCoord = geometry.getCoordinates(); zoom: Math.max(map.getView().getZoom(), 15),
duration: 1000
if (map) { });
map.getView().animate({
center: deviceCoord,
zoom: 16,
duration: 800
});
}
return true;
} }
return false;
} }
/** /**
@ -291,49 +238,48 @@ var DeviceMarkers = (function() {
*/ */
function getMyLocation() { function getMyLocation() {
if (navigator.geolocation) { if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) { navigator.geolocation.getCurrentPosition(
var lon = position.coords.longitude; function(position) {
var lat = position.coords.latitude; var lat = position.coords.latitude;
var currentMapType = getCurrentMapType(); var lon = position.coords.longitude;
var coordinates = CoordinateUtils.getMapCoordinates(lat, lon, currentMapType);
// 如果已经存在位置标记,则先移除 var currentMapType = getCurrentMapType();
if (myLocationFeature) { var coordinates = CoordinateUtils.getMapCoordinates(lat, lon, currentMapType);
vectorSource.removeFeature(myLocationFeature);
if (myLocationFeature) {
vectorSource.removeFeature(myLocationFeature);
}
myLocationFeature = new ol.Feature({
geometry: new ol.geom.Point(coordinates),
isMyLocation: true
});
vectorSource.addFeature(myLocationFeature);
map.getView().animate({
center: coordinates,
zoom: 15,
duration: 1000
});
},
function(error) {
console.error('获取位置失败:', error);
} }
);
myLocationFeature = new ol.Feature({
geometry: new ol.geom.Point(coordinates),
isMyLocation: true,
originalCoords: {lat: lat, lon: lon}
});
myLocationFeature.setStyle(createDeviceStyle(myLocationFeature));
vectorSource.addFeature(myLocationFeature);
if (map) {
map.getView().setCenter(coordinates);
}
});
} }
} }
/**
* 开始定期更新位置
*/
function startLocationUpdates() { function startLocationUpdates() {
if (myLocationInterval) { if (navigator.geolocation) {
clearInterval(myLocationInterval); myLocationInterval = setInterval(function() {
getMyLocation();
}, 30000);
} }
myLocationInterval = setInterval(function() {
getMyLocation();
}, 10 * 60 * 1000); // 10分钟更新一次
} }
/**
* 停止位置更新
*/
function stopLocationUpdates() { function stopLocationUpdates() {
if (myLocationInterval) { if (myLocationInterval) {
clearInterval(myLocationInterval); clearInterval(myLocationInterval);
@ -341,28 +287,19 @@ var DeviceMarkers = (function() {
} }
} }
/**
* 根据地图类型更新我的位置标记
* @param {string} mapType - 地图类型
*/
function updateMyLocationForMapType(mapType) { function updateMyLocationForMapType(mapType) {
if (myLocationFeature) { if (myLocationFeature) {
var originalCoords = myLocationFeature.get('originalCoords'); var geometry = myLocationFeature.getGeometry();
if (originalCoords) { var coordinates = geometry.getCoordinates();
var coordinates = CoordinateUtils.getMapCoordinates( var lonLat = ol.proj.toLonLat(coordinates);
originalCoords.lat,
originalCoords.lon, var newCoordinates = CoordinateUtils.getMapCoordinates(lonLat[1], lonLat[0], mapType);
mapType
); myLocationFeature.setGeometry(new ol.geom.Point(newCoordinates));
myLocationFeature.getGeometry().setCoordinates(coordinates);
}
} }
} }
/**
* 设置是否显示设备ID
* @param {boolean} show - 是否显示
*/
function setShowDeviceId(show) { function setShowDeviceId(show) {
showDeviceId = show; showDeviceId = show;
if (vectorLayer) { if (vectorLayer) {
@ -370,10 +307,7 @@ var DeviceMarkers = (function() {
} }
} }
/**
* 获取各类设备数量统计
* @returns {Object} 统计信息
*/
function getDeviceStats() { function getDeviceStats() {
return { return {
total: allFeatures.length, total: allFeatures.length,
@ -383,7 +317,6 @@ var DeviceMarkers = (function() {
}; };
} }
// 公开API
return { return {
init: init, init: init,
createDeviceStyle: createDeviceStyle, createDeviceStyle: createDeviceStyle,
@ -403,7 +336,6 @@ var DeviceMarkers = (function() {
setShowDeviceId: setShowDeviceId, setShowDeviceId: setShowDeviceId,
getDeviceStats: getDeviceStats, getDeviceStats: getDeviceStats,
// 获取器方法
getAllFeatures: function() { return allFeatures; }, getAllFeatures: function() { return allFeatures; },
getGreenFeatures: function() { return greenFeatures; }, getGreenFeatures: function() { return greenFeatures; },
getOrangeFeatures: function() { return orangeFeatures; }, getOrangeFeatures: function() { return orangeFeatures; },

View File

@ -5,7 +5,6 @@
var MapCore = (function() { var MapCore = (function() {
'use strict'; 'use strict';
// 私有变量
var map = null; var map = null;
var vectorSource = null; var vectorSource = null;
var vectorLayer = null; var vectorLayer = null;
@ -18,10 +17,7 @@ var MapCore = (function() {
var maxZoomForClustering = 8; var maxZoomForClustering = 8;
var hoveredFeature = null; var hoveredFeature = null;
/**
* 初始化地图
* @param {Array} deviceList - 设备列表
*/
function initialize(deviceList) { function initialize(deviceList) {
// 创建矢量数据源和图层 // 创建矢量数据源和图层
vectorSource = new ol.source.Vector(); vectorSource = new ol.source.Vector();
@ -60,11 +56,9 @@ var MapCore = (function() {
} }
}); });
// 获取初始地图类型
var initialMapType = document.getElementById('mapTypeSelectNew').value || 'tianditu_satellite'; var initialMapType = document.getElementById('mapTypeSelectNew').value || 'tianditu_satellite';
currentBaseLayer = MapLayers.getLayer(initialMapType); currentBaseLayer = MapLayers.getLayer(initialMapType);
// 创建地图
map = new ol.Map({ map = new ol.Map({
target: 'map-container', target: 'map-container',
layers: [ layers: [
@ -78,50 +72,37 @@ var MapCore = (function() {
}) })
}); });
// 初始化各个模块
DeviceMarkers.init(map, vectorSource, vectorLayer); DeviceMarkers.init(map, vectorSource, vectorLayer);
MeasureTools.init(map); MeasureTools.init(map);
WeatherForecast.init(); WeatherForecast.init();
// 添加比例尺控件
var scaleLineControl = new ol.control.ScaleLine(); var scaleLineControl = new ol.control.ScaleLine();
map.addControl(scaleLineControl); map.addControl(scaleLineControl);
// 设置初始图层可见性
var initialZoom = map.getView().getZoom(); var initialZoom = map.getView().getZoom();
updateLayerVisibility(initialZoom); updateLayerVisibility(initialZoom);
// 绑定缩放变化事件
map.getView().on('change:resolution', function() { map.getView().on('change:resolution', function() {
var zoom = map.getView().getZoom(); var zoom = map.getView().getZoom();
updateLayerVisibility(zoom); updateLayerVisibility(zoom);
vectorLayer.changed(); vectorLayer.changed();
}); });
// 绑定鼠标事件
bindMouseEvents(); bindMouseEvents();
// 设置地图中心点
if (deviceList && deviceList.length > 0) { if (deviceList && deviceList.length > 0) {
setCenterFromDevices(deviceList); setCenterFromDevices(deviceList);
} }
// 添加设备标记
DeviceMarkers.addDeviceMarkers(deviceList); DeviceMarkers.addDeviceMarkers(deviceList);
// 获取我的位置并开始位置更新
DeviceMarkers.getMyLocation(); DeviceMarkers.getMyLocation();
DeviceMarkers.startLocationUpdates(); DeviceMarkers.startLocationUpdates();
// 设置初始开关状态
document.getElementById('showDeviceIdSwitch').checked = showDeviceId; document.getElementById('showDeviceIdSwitch').checked = showDeviceId;
document.getElementById('showClusterSwitch').checked = showCluster; document.getElementById('showClusterSwitch').checked = showCluster;
} }
/**
* 更新图层可见性
* @param {number} zoom - 缩放级别
*/
function updateLayerVisibility(zoom) { function updateLayerVisibility(zoom) {
if (showCluster) { if (showCluster) {
if (zoom >= maxZoomForClustering) { if (zoom >= maxZoomForClustering) {
@ -137,11 +118,7 @@ var MapCore = (function() {
} }
} }
/**
* 绑定鼠标事件
*/
function bindMouseEvents() { function bindMouseEvents() {
// 鼠标移动事件
map.on('pointermove', function(evt) { map.on('pointermove', function(evt) {
if (evt.dragging) { if (evt.dragging) {
return; return;
@ -152,7 +129,6 @@ var MapCore = (function() {
map.getTargetElement().style.cursor = hit ? 'pointer' : ''; map.getTargetElement().style.cursor = hit ? 'pointer' : '';
// 处理悬停效果
var feature = map.forEachFeatureAtPixel(pixel, function(feature) { var feature = map.forEachFeatureAtPixel(pixel, function(feature) {
return feature; return feature;
}); });
@ -176,7 +152,6 @@ var MapCore = (function() {
vectorLayer.changed(); vectorLayer.changed();
}); });
// 点击事件
map.on('click', function(evt) { map.on('click', function(evt) {
var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) { var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) {
return feature; return feature;
@ -202,7 +177,6 @@ var MapCore = (function() {
} }
} }
} else if (feature.get('deviceInfo')) { } else if (feature.get('deviceInfo')) {
// 直接点击设备标记
var deviceInfo = feature.get('deviceInfo'); var deviceInfo = feature.get('deviceInfo');
showDeviceInfo(deviceInfo); showDeviceInfo(deviceInfo);
// 如果天气预测开启,显示天气卡片 // 如果天气预测开启,显示天气卡片
@ -214,64 +188,53 @@ var MapCore = (function() {
}); });
} }
/**
* 显示设备信息
* @param {Object} deviceInfo - 设备信息
*/
function showDeviceInfo(deviceInfo) { function showDeviceInfo(deviceInfo) {
var infoMsg = '<div style="padding: 10px; line-height: 1.5;">' + var statusText = '';
'<p><strong>设备编号:</strong> ' + deviceInfo.deviceid + '</p>' +
'<p><strong>坐标:</strong> ' + deviceInfo.latitude.toFixed(6) + ', ' + deviceInfo.longitude.toFixed(6) + '</p>';
if (deviceInfo.warning === 2) { if (deviceInfo.warning === 2) {
infoMsg += '<p><strong>状态:</strong> <span style="color: #f56565;">严重告警</span></p>'; statusText = '严重告警';
} else if (deviceInfo.warning === 1) { } else if (deviceInfo.warning === 1) {
infoMsg += '<p><strong>状态:</strong> <span style="color: #ed8936;">一般告警</span></p>'; statusText = '一般告警';
} else { } else {
infoMsg += '<p><strong>状态:</strong> <span style="color: #48bb78;">正常</span></p>'; statusText = '正常';
} }
infoMsg += '</div>'; var infoMsg = ' 设备: ' + deviceInfo.deviceid +
' | 状态: ' + statusText +
' | 坐标: ' + deviceInfo.latitude.toFixed(4) + ', ' + deviceInfo.longitude.toFixed(4);
if (window.layer && typeof window.layer.open === 'function') { if (window.layer && typeof window.layer.msg === 'function') {
window.layer.open({ window.layer.msg(infoMsg, {
type: 1,
title: '设备信息',
area: ['300px', 'auto'],
shade: 0,
offset: 'auto',
content: infoMsg,
time: 3000, time: 3000,
anim: 2 area: ['auto', 'auto'],
offset: 'auto'
}); });
} }
} }
/**
* 根据设备列表设置地图中心点
* @param {Array} deviceList - 设备列表
*/
function setCenterFromDevices(deviceList) { function setCenterFromDevices(deviceList) {
if (!deviceList || deviceList.length === 0) return; if (!deviceList || deviceList.length === 0) return;
var centerLat = 0; var minLat = deviceList[0].latitude;
var centerLon = 0; var maxLat = deviceList[0].latitude;
var minLon = deviceList[0].longitude;
var maxLon = deviceList[0].longitude;
for (var i = 0; i < deviceList.length; i++) { for (var i = 1; i < deviceList.length; i++) {
centerLat += deviceList[i].latitude; var device = deviceList[i];
centerLon += deviceList[i].longitude; minLat = Math.min(minLat, device.latitude);
maxLat = Math.max(maxLat, device.latitude);
minLon = Math.min(minLon, device.longitude);
maxLon = Math.max(maxLon, device.longitude);
} }
centerLat = centerLat / deviceList.length; var centerLat = (minLat + maxLat) / 2;
centerLon = centerLon / deviceList.length; var centerLon = (minLon + maxLon) / 2;
map.getView().setCenter(ol.proj.fromLonLat([centerLon, centerLat])); map.getView().setCenter(ol.proj.fromLonLat([centerLon, centerLat]));
} }
/**
* 切换地图类型
* @param {string} mapType - 地图类型
*/
function switchMapType(mapType) { function switchMapType(mapType) {
if (!MapLayers.hasLayer(mapType)) { if (!MapLayers.hasLayer(mapType)) {
console.error('未知的地图类型:', mapType); console.error('未知的地图类型:', mapType);
@ -289,9 +252,6 @@ var MapCore = (function() {
DeviceMarkers.addDeviceMarkers(deviceList); DeviceMarkers.addDeviceMarkers(deviceList);
} }
/**
* 切换设备ID显示
*/
function toggleDeviceId() { function toggleDeviceId() {
showDeviceId = document.getElementById('showDeviceIdSwitch').checked; showDeviceId = document.getElementById('showDeviceIdSwitch').checked;
DeviceMarkers.setShowDeviceId(showDeviceId); DeviceMarkers.setShowDeviceId(showDeviceId);
@ -301,9 +261,6 @@ var MapCore = (function() {
} }
} }
/**
* 切换集群显示
*/
function toggleCluster() { function toggleCluster() {
showCluster = document.getElementById('showClusterSwitch').checked; showCluster = document.getElementById('showClusterSwitch').checked;
var zoom = map.getView().getZoom(); var zoom = map.getView().getZoom();
@ -314,9 +271,6 @@ var MapCore = (function() {
} }
} }
/**
* 切换地图功能菜单
*/
function toggleMapFunctionsMenu() { function toggleMapFunctionsMenu() {
var menu = document.getElementById('mapFunctionsMenu'); var menu = document.getElementById('mapFunctionsMenu');
if (menu) { if (menu) {
@ -349,62 +303,47 @@ var MapCore = (function() {
switchMapType(mapType); switchMapType(mapType);
} }
/**
* 告警过滤变化处理
*/
function onWarningFilterChange() { function onWarningFilterChange() {
var filterValue = document.getElementById('warningFilter').value; var filterValue = document.getElementById('warningFilter').value;
switch(filterValue) {
if (filterValue === 'all') { case 'all':
SearchFilter.showAllDevices(); SearchFilter.showAllDevices();
} else if (filterValue === 'warning1') { break;
SearchFilter.showWarning1Devices(); case 'warning1':
} else if (filterValue === 'warning2') { SearchFilter.showWarning1Devices();
SearchFilter.showWarning2Devices(); break;
case 'warning2':
SearchFilter.showWarning2Devices();
break;
} }
} }
/**
* 搜索设备
*/
function searchDeviceNew() { function searchDeviceNew() {
var deviceId = document.getElementById('deviceSearchNew').value.trim(); var searchInput = document.getElementById('deviceSearchNew');
if (searchInput) {
if (!deviceId) { var deviceId = searchInput.value.trim();
if (window.layer && typeof window.layer.msg === 'function') { if (deviceId) {
window.layer.msg('请输入设备编号'); SearchFilter.searchDevice(deviceId);
} else {
if (window.layer && typeof window.layer.msg === 'function') {
window.layer.msg('请输入设备编号');
}
} }
return;
} }
SearchFilter.searchDevice(deviceId);
} }
/**
* 获取地图实例
* @returns {ol.Map} 地图实例
*/
function getMap() { function getMap() {
return map; return map;
} }
/**
* 获取矢量数据源
* @returns {ol.source.Vector} 矢量数据源
*/
function getVectorSource() { function getVectorSource() {
return vectorSource; return vectorSource;
} }
/**
* 获取矢量图层
* @returns {ol.layer.Vector} 矢量图层
*/
function getVectorLayer() { function getVectorLayer() {
return vectorLayer; return vectorLayer;
} }
// 公开API
return { return {
initialize: initialize, initialize: initialize,
switchMapType: switchMapType, switchMapType: switchMapType,

View File

@ -5,12 +5,9 @@
var MapLayers = (function() { var MapLayers = (function() {
'use strict'; 'use strict';
// 天地图 API 密钥 // 天地图 API 密钥 fengyarnom@gmail.com
var TIANDITU_KEY = '0c260b8a094a4e0bc507808812cefdac'; var TIANDITU_KEY = '0c260b8a094a4e0bc507808812cefdac';
/**
* 创建天地图瓦片加载函数包含错误处理
*/
function createTiandituTileLoadFunction() { function createTiandituTileLoadFunction() {
return function(imageTile, src) { return function(imageTile, src) {
imageTile.getImage().src = src; imageTile.getImage().src = src;
@ -25,7 +22,6 @@ var MapLayers = (function() {
if (window.layer && typeof window.layer.msg === 'function') { if (window.layer && typeof window.layer.msg === 'function') {
window.layer.msg('天地图加载失败,已自动切换到高德地图'); window.layer.msg('天地图加载失败,已自动切换到高德地图');
} }
// 重新渲染layui表单
if (window.layui && window.layui.form) { if (window.layui && window.layui.form) {
window.layui.form.render('select'); window.layui.form.render('select');
} }
@ -34,9 +30,7 @@ var MapLayers = (function() {
}; };
} }
/**
* 地图图层配置
*/
var mapLayers = { var mapLayers = {
// 高德地图 // 高德地图
amap: new ol.layer.Tile({ amap: new ol.layer.Tile({
@ -160,33 +154,23 @@ var MapLayers = (function() {
}) })
}; };
/**
* 获取指定类型的地图图层
* @param {string} mapType - 地图类型
* @returns {ol.layer.Base} 地图图层
*/
function getLayer(mapType) { function getLayer(mapType) {
return mapLayers[mapType]; return mapLayers[mapType];
} }
/**
* 获取所有可用的地图图层
* @returns {Object} 所有地图图层对象
*/
function getAllLayers() { function getAllLayers() {
return mapLayers; return mapLayers;
} }
/**
* 检查地图类型是否存在
* @param {string} mapType - 地图类型
* @returns {boolean} 是否存在
*/
function hasLayer(mapType) { function hasLayer(mapType) {
return mapLayers.hasOwnProperty(mapType); return mapLayers.hasOwnProperty(mapType);
} }
// 公开API
return { return {
getLayer: getLayer, getLayer: getLayer,
getAllLayers: getAllLayers, getAllLayers: getAllLayers,

View File

@ -5,7 +5,6 @@
var MeasureTools = (function() { var MeasureTools = (function() {
'use strict'; 'use strict';
// 私有变量
var measureActive = false; var measureActive = false;
var measureDraw = null; var measureDraw = null;
var measureSource = null; var measureSource = null;
@ -18,14 +17,10 @@ var MeasureTools = (function() {
var segmentTooltips = []; var segmentTooltips = [];
var map = null; var map = null;
/**
* 初始化测距工具
* @param {ol.Map} mapInstance - 地图实例
*/
function init(mapInstance) { function init(mapInstance) {
map = mapInstance; map = mapInstance;
// 创建测距专用图层 // 测距专用图层
measureSource = new ol.source.Vector(); measureSource = new ol.source.Vector();
measureLayer = new ol.layer.Vector({ measureLayer = new ol.layer.Vector({
source: measureSource, source: measureSource,
@ -47,9 +42,6 @@ var MeasureTools = (function() {
} }
} }
/**
* 切换测距功能
*/
function toggleMeasureDistance() { function toggleMeasureDistance() {
if (measureActive) { if (measureActive) {
deactivateMeasure(); deactivateMeasure();
@ -63,25 +55,18 @@ var MeasureTools = (function() {
} }
} }
// 关闭地图功能菜单
var menu = document.getElementById('mapFunctionsMenu'); var menu = document.getElementById('mapFunctionsMenu');
if (menu) { if (menu) {
menu.classList.remove('show'); menu.classList.remove('show');
} }
} }
/**
* 完成当前测量
*/
function finishMeasuring() { function finishMeasuring() {
if (measureActive && currentSketch && measureDraw) { if (measureActive && currentSketch && measureDraw) {
measureDraw.finishDrawing(); measureDraw.finishDrawing();
} }
} }
/**
* 激活测距功能
*/
function activateMeasure() { function activateMeasure() {
if (!map || !measureSource) return; if (!map || !measureSource) return;
@ -93,7 +78,6 @@ var MeasureTools = (function() {
measureStatus.style.display = 'flex'; measureStatus.style.display = 'flex';
} }
// 创建绘制交互
measureDraw = new ol.interaction.Draw({ measureDraw = new ol.interaction.Draw({
source: measureSource, source: measureSource,
type: 'LineString', type: 'LineString',
@ -112,7 +96,6 @@ var MeasureTools = (function() {
map.addInteraction(measureDraw); map.addInteraction(measureDraw);
// 添加右键菜单事件监听
map.getViewport().addEventListener('contextmenu', function(e) { map.getViewport().addEventListener('contextmenu', function(e) {
if (measureActive && currentSketch) { if (measureActive && currentSketch) {
e.preventDefault(); e.preventDefault();
@ -120,13 +103,11 @@ var MeasureTools = (function() {
} }
}); });
// 绘制开始事件
measureDraw.on('drawstart', function(evt) { measureDraw.on('drawstart', function(evt) {
currentSketch = evt.feature; currentSketch = evt.feature;
currentMeasureTooltips = []; currentMeasureTooltips = [];
segmentTooltips = []; segmentTooltips = [];
// 监听几何变化
currentListener = currentSketch.getGeometry().on('change', function(e) { currentListener = currentSketch.getGeometry().on('change', function(e) {
var geom = e.target; var geom = e.target;
var coords = geom.getCoordinates(); var coords = geom.getCoordinates();
@ -160,14 +141,13 @@ var MeasureTools = (function() {
}); });
}); });
// 绘制结束事件 // 绘制结束
measureDraw.on('drawend', function(evt) { measureDraw.on('drawend', function(evt) {
var coords = evt.feature.getGeometry().getCoordinates(); var coords = evt.feature.getGeometry().getCoordinates();
clearTemporaryTooltips(); clearTemporaryTooltips();
clearSegmentTooltips(); clearSegmentTooltips();
// 创建永久性的测量标记
var total = 0; var total = 0;
for (var i = 0; i < coords.length; i++) { for (var i = 0; i < coords.length; i++) {
if (i === 0) { if (i === 0) {
@ -185,20 +165,17 @@ var MeasureTools = (function() {
measureFeatures.push(evt.feature); measureFeatures.push(evt.feature);
// 清理监听器
if (currentListener) { if (currentListener) {
ol.Observable.unByKey(currentListener); ol.Observable.unByKey(currentListener);
} }
currentSketch = null; currentSketch = null;
currentListener = null; currentListener = null;
// 隐藏测量状态指示器
var measureStatus = document.getElementById('measureStatus'); var measureStatus = document.getElementById('measureStatus');
if (measureStatus) { if (measureStatus) {
measureStatus.style.display = 'none'; measureStatus.style.display = 'none';
} }
// 移除绘制交互
map.removeInteraction(measureDraw); map.removeInteraction(measureDraw);
measureActive = false; measureActive = false;
@ -208,13 +185,9 @@ var MeasureTools = (function() {
}); });
} }
/**
* 停用测距功能
*/
function deactivateMeasure() { function deactivateMeasure() {
measureActive = false; measureActive = false;
// 隐藏测量状态指示器
var measureStatus = document.getElementById('measureStatus'); var measureStatus = document.getElementById('measureStatus');
if (measureStatus) { if (measureStatus) {
measureStatus.style.display = 'none'; measureStatus.style.display = 'none';
@ -235,13 +208,6 @@ var MeasureTools = (function() {
clearSegmentTooltips(); clearSegmentTooltips();
} }
/**
* 创建测量提示框
* @param {Array} coord - 坐标
* @param {string} text - 显示文本
* @param {boolean} isStatic - 是否为静态提示框
* @returns {ol.Overlay} 覆盖层对象
*/
function createMeasureTooltip(coord, text, isStatic) { function createMeasureTooltip(coord, text, isStatic) {
var elem = document.createElement('div'); var elem = document.createElement('div');
elem.className = isStatic ? 'ol-tooltip ol-tooltip-static' : 'ol-tooltip ol-tooltip-measure'; elem.className = isStatic ? 'ol-tooltip ol-tooltip-static' : 'ol-tooltip ol-tooltip-measure';
@ -262,11 +228,6 @@ var MeasureTools = (function() {
return overlay; return overlay;
} }
/**
* 格式化长度显示
* @param {number} length - 长度
* @returns {string} 格式化后的长度字符串
*/
function formatLength(length) { function formatLength(length) {
if (length > 1000) { if (length > 1000) {
return (Math.round(length / 100) / 10) + ' km'; return (Math.round(length / 100) / 10) + ' km';
@ -275,9 +236,6 @@ var MeasureTools = (function() {
} }
} }
/**
* 清除所有测量提示框
*/
function clearAllMeasureTooltips() { function clearAllMeasureTooltips() {
if (!map) return; if (!map) return;
@ -289,9 +247,6 @@ var MeasureTools = (function() {
clearTemporaryTooltips(); clearTemporaryTooltips();
} }
/**
* 清除临时提示框
*/
function clearTemporaryTooltips() { function clearTemporaryTooltips() {
if (!map) return; if (!map) return;
@ -301,9 +256,6 @@ var MeasureTools = (function() {
currentMeasureTooltips = []; currentMeasureTooltips = [];
} }
/**
* 清除段落提示框
*/
function clearSegmentTooltips() { function clearSegmentTooltips() {
if (!map) return; if (!map) return;
@ -313,9 +265,6 @@ var MeasureTools = (function() {
segmentTooltips = []; segmentTooltips = [];
} }
/**
* 清除所有测量标记
*/
function clearMeasure() { function clearMeasure() {
if (measureSource) { if (measureSource) {
measureSource.clear(); measureSource.clear();
@ -335,23 +284,14 @@ var MeasureTools = (function() {
} }
} }
/**
* 检查测距功能是否激活
* @returns {boolean} 是否激活
*/
function isActive() { function isActive() {
return measureActive; return measureActive;
} }
/**
* 获取测量结果数量
* @returns {number} 测量结果数量
*/
function getMeasureCount() { function getMeasureCount() {
return measureFeatures.length; return measureFeatures.length;
} }
// 公开API
return { return {
init: init, init: init,
toggleMeasureDistance: toggleMeasureDistance, toggleMeasureDistance: toggleMeasureDistance,

View File

@ -5,15 +5,9 @@
var SearchFilter = (function() { var SearchFilter = (function() {
'use strict'; 'use strict';
// 私有变量
var currentSearchedDevice = null; var currentSearchedDevice = null;
var markerState = 3; // 1:all; 2:orange; 3:red var markerState = 3; // 1:all; 2:orange; 3:red
/**
* 搜索设备
* @param {string} deviceId - 设备ID
* @returns {boolean} 是否找到设备
*/
function searchDevice(deviceId) { function searchDevice(deviceId) {
if (!deviceId || !deviceId.trim()) { if (!deviceId || !deviceId.trim()) {
clearSearch(); clearSearch();
@ -47,9 +41,6 @@ var SearchFilter = (function() {
return success; return success;
} }
/**
* 清除搜索
*/
function clearSearch() { function clearSearch() {
currentSearchedDevice = null; currentSearchedDevice = null;
var searchInput = document.getElementById('deviceSearchNew'); var searchInput = document.getElementById('deviceSearchNew');
@ -61,9 +52,6 @@ var SearchFilter = (function() {
applyCurrentFilter(); applyCurrentFilter();
} }
/**
* 应用当前过滤状态
*/
function applyCurrentFilter() { function applyCurrentFilter() {
switch(markerState) { switch(markerState) {
case 1: case 1:
@ -78,9 +66,6 @@ var SearchFilter = (function() {
} }
} }
/**
* 显示所有设备
*/
function showAllDevices() { function showAllDevices() {
currentSearchedDevice = null; currentSearchedDevice = null;
clearSearchInput(); clearSearchInput();
@ -89,9 +74,6 @@ var SearchFilter = (function() {
updateFilterSelect('all'); updateFilterSelect('all');
} }
/**
* 显示一般告警设备
*/
function showWarning1Devices() { function showWarning1Devices() {
currentSearchedDevice = null; currentSearchedDevice = null;
clearSearchInput(); clearSearchInput();
@ -99,10 +81,6 @@ var SearchFilter = (function() {
markerState = 2; markerState = 2;
updateFilterSelect('warning1'); updateFilterSelect('warning1');
} }
/**
* 显示严重告警设备
*/
function showWarning2Devices() { function showWarning2Devices() {
currentSearchedDevice = null; currentSearchedDevice = null;
clearSearchInput(); clearSearchInput();
@ -110,10 +88,6 @@ var SearchFilter = (function() {
markerState = 3; markerState = 3;
updateFilterSelect('warning2'); updateFilterSelect('warning2');
} }
/**
* 清除搜索输入框
*/
function clearSearchInput() { function clearSearchInput() {
var searchInput = document.getElementById('deviceSearchNew'); var searchInput = document.getElementById('deviceSearchNew');
if (searchInput) { if (searchInput) {
@ -121,10 +95,6 @@ var SearchFilter = (function() {
} }
} }
/**
* 更新过滤选择器
* @param {string} filterValue - 过滤值
*/
function updateFilterSelect(filterValue) { function updateFilterSelect(filterValue) {
var filterSelect = document.getElementById('warningFilter'); var filterSelect = document.getElementById('warningFilter');
if (filterSelect) { if (filterSelect) {
@ -132,10 +102,6 @@ var SearchFilter = (function() {
} }
} }
/**
* 根据状态过滤设备
* @param {string} statusType - 状态类型
*/
function filterDevicesByStatus(statusType) { function filterDevicesByStatus(statusType) {
switch(statusType) { switch(statusType) {
case 'warning1': case 'warning1':
@ -157,12 +123,7 @@ var SearchFilter = (function() {
} }
} }
/**
* 查询设备并打开列表页面
* @param {string} statusType - 状态类型
*/
function queryDevices(statusType) { function queryDevices(statusType) {
// 首先过滤地图上的设备显示
filterDevicesByStatus(statusType); filterDevicesByStatus(statusType);
// 打开设备列表弹窗 // 打开设备列表弹窗
@ -181,12 +142,6 @@ var SearchFilter = (function() {
} }
} }
/**
* 直接定位到设备用于外部调用
* @param {string} deviceId - 设备ID
* @param {number} latitude - 纬度可选
* @param {number} longitude - 经度可选
*/
function locateDeviceOnMap(deviceId, latitude, longitude) { function locateDeviceOnMap(deviceId, latitude, longitude) {
currentSearchedDevice = deviceId; currentSearchedDevice = deviceId;
var success = DeviceMarkers.locateDevice(deviceId); var success = DeviceMarkers.locateDevice(deviceId);
@ -198,40 +153,23 @@ var SearchFilter = (function() {
return success; return success;
} }
/**
* 直接定位设备简化版
* @param {string} deviceId - 设备ID
*/
function locateDeviceDirectly(deviceId) { function locateDeviceDirectly(deviceId) {
currentSearchedDevice = deviceId; currentSearchedDevice = deviceId;
return DeviceMarkers.locateDevice(deviceId); return DeviceMarkers.locateDevice(deviceId);
} }
/**
* 获取当前搜索的设备ID
* @returns {string|null} 当前搜索的设备ID
*/
function getCurrentSearchedDevice() { function getCurrentSearchedDevice() {
return currentSearchedDevice; return currentSearchedDevice;
} }
/**
* 获取当前标记状态
* @returns {number} 标记状态
*/
function getMarkerState() { function getMarkerState() {
return markerState; return markerState;
} }
/**
* 设置标记状态
* @param {number} state - 标记状态
*/
function setMarkerState(state) { function setMarkerState(state) {
markerState = state; markerState = state;
} }
// 公开API
return { return {
searchDevice: searchDevice, searchDevice: searchDevice,
clearSearch: clearSearch, clearSearch: clearSearch,

View File

@ -1,31 +1,18 @@
/**
* 天气预报模块
* 提供Windy天气API调用和天气卡片显示功能
*/
var WeatherForecast = (function() { var WeatherForecast = (function() {
'use strict'; 'use strict';
// 私有变量
var weatherApiKey = 'Uxh4IdMuAvhSiBnsf4UUDVGF4e3YAp2B'; var weatherApiKey = 'Uxh4IdMuAvhSiBnsf4UUDVGF4e3YAp2B';
var weatherEnabled = false; var weatherEnabled = false;
var weatherData = null; var weatherData = null;
var currentForecastIndex = 0; var currentForecastIndex = 0;
var currentWeatherDevice = null; var currentWeatherDevice = null;
var isDragging = false;
/**
* 初始化天气预报模块
*/
function init() { function init() {
initWeatherCardDrag(); // 天气预报模块初始化完成
} }
/**
* 切换天气预报功能
*/
function toggleWeatherForecast() { function toggleWeatherForecast() {
// 权限检查 var role = window.userRole || 'USER';
var role = window.userRole || 'USER'; // 从全局变量获取角色
if (role !== 'SUPER_ADMIN') { if (role !== 'SUPER_ADMIN') {
if (window.layer && typeof window.layer.msg === 'function') { if (window.layer && typeof window.layer.msg === 'function') {
window.layer.msg('您没有权限使用此功能'); window.layer.msg('您没有权限使用此功能');
@ -50,22 +37,16 @@ var WeatherForecast = (function() {
closeWeatherCard(); closeWeatherCard();
} }
// 关闭地图功能菜单
var menu = document.getElementById('mapFunctionsMenu'); var menu = document.getElementById('mapFunctionsMenu');
if (menu) { if (menu) {
menu.classList.remove('show'); menu.classList.remove('show');
} }
} }
/**
* 显示天气预报卡片
* @param {Object} deviceInfo - 设备信息
*/
function showWeatherForecast(deviceInfo) { function showWeatherForecast(deviceInfo) {
currentWeatherDevice = deviceInfo; currentWeatherDevice = deviceInfo;
weatherData = null; weatherData = null;
// 权限检查
var role = window.userRole || 'USER'; var role = window.userRole || 'USER';
if (role !== 'SUPER_ADMIN') { if (role !== 'SUPER_ADMIN') {
return; return;
@ -78,7 +59,6 @@ var WeatherForecast = (function() {
return; return;
} }
// 更新设备信息显示
var deviceIdElement = document.getElementById('weatherDeviceId'); var deviceIdElement = document.getElementById('weatherDeviceId');
var deviceCoordsElement = document.getElementById('weatherDeviceCoords'); var deviceCoordsElement = document.getElementById('weatherDeviceCoords');
@ -91,15 +71,11 @@ var WeatherForecast = (function() {
'坐标: ' + deviceInfo.latitude.toFixed(4) + ', ' + deviceInfo.longitude.toFixed(4); '坐标: ' + deviceInfo.latitude.toFixed(4) + ', ' + deviceInfo.longitude.toFixed(4);
} }
// 显示天气卡片
var weatherCard = document.getElementById('weatherForecastCard'); var weatherCard = document.getElementById('weatherForecastCard');
if (weatherCard) { if (weatherCard) {
weatherCard.style.display = 'block'; weatherCard.style.display = 'block';
} }
initWeatherCardDrag();
// 显示加载状态
var contentElement = document.getElementById('weatherForecastContent'); var contentElement = document.getElementById('weatherForecastContent');
if (contentElement) { if (contentElement) {
contentElement.innerHTML = contentElement.innerHTML =
@ -110,7 +86,6 @@ var WeatherForecast = (function() {
'</div>'; '</div>';
} }
// 重置翻页按钮
var prevBtn = document.getElementById('prevForecast'); var prevBtn = document.getElementById('prevForecast');
var nextBtn = document.getElementById('nextForecast'); var nextBtn = document.getElementById('nextForecast');
var timeDisplay = document.getElementById('forecastTimeDisplay'); var timeDisplay = document.getElementById('forecastTimeDisplay');
@ -119,13 +94,9 @@ var WeatherForecast = (function() {
if (nextBtn) nextBtn.disabled = true; if (nextBtn) nextBtn.disabled = true;
if (timeDisplay) timeDisplay.textContent = '--:--'; if (timeDisplay) timeDisplay.textContent = '--:--';
// 调用天气API
fetchWeatherData(deviceInfo.latitude, deviceInfo.longitude); fetchWeatherData(deviceInfo.latitude, deviceInfo.longitude);
} }
/**
* 关闭天气卡片
*/
function closeWeatherCard() { function closeWeatherCard() {
var weatherCard = document.getElementById('weatherForecastCard'); var weatherCard = document.getElementById('weatherForecastCard');
if (weatherCard) { if (weatherCard) {
@ -135,9 +106,6 @@ var WeatherForecast = (function() {
weatherData = null; weatherData = null;
} }
/**
* 显示上一个预报
*/
function showPrevForecast() { function showPrevForecast() {
if (!weatherData || currentForecastIndex <= 0) return; if (!weatherData || currentForecastIndex <= 0) return;
@ -146,9 +114,6 @@ var WeatherForecast = (function() {
updateForecastNavigation(); updateForecastNavigation();
} }
/**
* 显示下一个预报
*/
function showNextForecast() { function showNextForecast() {
if (!weatherData || !weatherData.ts || currentForecastIndex >= weatherData.ts.length - 1) return; if (!weatherData || !weatherData.ts || currentForecastIndex >= weatherData.ts.length - 1) return;
@ -157,9 +122,6 @@ var WeatherForecast = (function() {
updateForecastNavigation(); updateForecastNavigation();
} }
/**
* 更新预报导航按钮
*/
function updateForecastNavigation() { function updateForecastNavigation() {
if (!weatherData || !weatherData.ts) return; if (!weatherData || !weatherData.ts) return;
@ -177,20 +139,15 @@ var WeatherForecast = (function() {
} }
} }
/**
* 获取天气数据
* @param {number} lat - 纬度
* @param {number} lon - 经度
*/
function fetchWeatherData(lat, lon) { function fetchWeatherData(lat, lon) {
var requestBody = { var requestBody = {
"lat": parseFloat(lat.toFixed(2)), "lat": parseFloat(lat.toFixed(2)),
"lon": parseFloat(lon.toFixed(2)), "lon": parseFloat(lon.toFixed(2)),
"model": "gfs", // 使用全球预报系统模型 "model": "gfs",
"parameters": ["temp", "wind", "precip", "pressure", "rh", "windGust"], "parameters": ["temp", "wind", "precip", "pressure", "rh", "windGust"],
"levels": ["surface"], "levels": ["surface"],
"key": weatherApiKey, "key": weatherApiKey,
"hours": 72 // 请求未来72小时的预报数据 "hours": 72
}; };
fetch('https://api.windy.com/api/point-forecast/v2', { fetch('https://api.windy.com/api/point-forecast/v2', {
@ -210,13 +167,11 @@ var WeatherForecast = (function() {
.then(function(data) { .then(function(data) {
weatherData = data; weatherData = data;
// 找到最接近当前时间的预报索引,优先选择未来时间点
var currentTime = new Date().getTime(); var currentTime = new Date().getTime();
var closestIndex = 0; var closestIndex = 0;
var futureIndex = -1; var futureIndex = -1;
if (weatherData.ts && weatherData.ts.length > 0) { if (weatherData.ts && weatherData.ts.length > 0) {
// 首先尝试找到第一个未来时间点
for (var i = 0; i < weatherData.ts.length; i++) { for (var i = 0; i < weatherData.ts.length; i++) {
if (weatherData.ts[i] > currentTime) { if (weatherData.ts[i] > currentTime) {
futureIndex = i; futureIndex = i;
@ -224,11 +179,9 @@ var WeatherForecast = (function() {
} }
} }
// 如果找到了未来时间点,直接使用
if (futureIndex >= 0) { if (futureIndex >= 0) {
closestIndex = futureIndex; closestIndex = futureIndex;
} else { } else {
// 否则找最接近的时间点
var smallestDiff = Number.MAX_VALUE; var smallestDiff = Number.MAX_VALUE;
for (var i = 0; i < weatherData.ts.length; i++) { for (var i = 0; i < weatherData.ts.length; i++) {
var diff = Math.abs(weatherData.ts[i] - currentTime); var diff = Math.abs(weatherData.ts[i] - currentTime);
@ -250,9 +203,6 @@ var WeatherForecast = (function() {
}); });
} }
/**
* 显示当前预报
*/
function displayCurrentForecast() { function displayCurrentForecast() {
if (!weatherData || !weatherData.ts || weatherData.ts.length === 0) { if (!weatherData || !weatherData.ts || weatherData.ts.length === 0) {
displayWeatherError('无可用的天气预测数据'); displayWeatherError('无可用的天气预测数据');
@ -262,13 +212,11 @@ var WeatherForecast = (function() {
var i = currentForecastIndex; var i = currentForecastIndex;
var forecastHtml = '<div class="weather-forecast-item"><div class="weather-param-grid">'; var forecastHtml = '<div class="weather-forecast-item"><div class="weather-param-grid">';
// 温度
if (weatherData['temp-surface'] && weatherData['temp-surface'][i] !== null) { if (weatherData['temp-surface'] && weatherData['temp-surface'][i] !== null) {
var temp = (weatherData['temp-surface'][i] - 273.15).toFixed(1); // 转换为摄氏度 var temp = (weatherData['temp-surface'][i] - 273.15).toFixed(1);
forecastHtml += createWeatherParam('温度', temp + '°C'); forecastHtml += createWeatherParam('温度', temp + '°C');
} }
// 风速和风向
if (weatherData['wind_u-surface'] && weatherData['wind_v-surface'] && if (weatherData['wind_u-surface'] && weatherData['wind_v-surface'] &&
weatherData['wind_u-surface'][i] !== null && weatherData['wind_v-surface'][i] !== null) { weatherData['wind_u-surface'][i] !== null && weatherData['wind_v-surface'][i] !== null) {
var windU = weatherData['wind_u-surface'][i]; var windU = weatherData['wind_u-surface'][i];
@ -279,25 +227,21 @@ var WeatherForecast = (function() {
forecastHtml += createWeatherParam('风向', windDir); forecastHtml += createWeatherParam('风向', windDir);
} }
// 降水
if (weatherData['past3hprecip-surface'] && weatherData['past3hprecip-surface'][i] !== null) { if (weatherData['past3hprecip-surface'] && weatherData['past3hprecip-surface'][i] !== null) {
var precip = weatherData['past3hprecip-surface'][i].toFixed(1); var precip = weatherData['past3hprecip-surface'][i].toFixed(1);
forecastHtml += createWeatherParam('降水', precip + ' mm'); forecastHtml += createWeatherParam('降水', precip + ' mm');
} }
// 湿度
if (weatherData['rh-surface'] && weatherData['rh-surface'][i] !== null) { if (weatherData['rh-surface'] && weatherData['rh-surface'][i] !== null) {
var humidity = weatherData['rh-surface'][i].toFixed(0); var humidity = weatherData['rh-surface'][i].toFixed(0);
forecastHtml += createWeatherParam('湿度', humidity + '%'); forecastHtml += createWeatherParam('湿度', humidity + '%');
} }
// 气压
if (weatherData['pressure-surface'] && weatherData['pressure-surface'][i] !== null) { if (weatherData['pressure-surface'] && weatherData['pressure-surface'][i] !== null) {
var pressure = (weatherData['pressure-surface'][i] / 100).toFixed(0); // 转换为百帕 var pressure = (weatherData['pressure-surface'][i] / 100).toFixed(0);
forecastHtml += createWeatherParam('气压', pressure + ' hPa'); forecastHtml += createWeatherParam('气压', pressure + ' hPa');
} }
// 阵风
if (weatherData['gust-surface'] && weatherData['gust-surface'][i] !== null) { if (weatherData['gust-surface'] && weatherData['gust-surface'][i] !== null) {
var gust = weatherData['gust-surface'][i].toFixed(1); var gust = weatherData['gust-surface'][i].toFixed(1);
forecastHtml += createWeatherParam('阵风', gust + ' m/s'); forecastHtml += createWeatherParam('阵风', gust + ' m/s');
@ -311,10 +255,6 @@ var WeatherForecast = (function() {
} }
} }
/**
* 显示天气错误信息
* @param {string} message - 错误消息
*/
function displayWeatherError(message) { function displayWeatherError(message) {
var contentElement = document.getElementById('weatherForecastContent'); var contentElement = document.getElementById('weatherForecastContent');
if (contentElement) { if (contentElement) {
@ -326,12 +266,6 @@ var WeatherForecast = (function() {
} }
} }
/**
* 创建天气参数HTML
* @param {string} label - 参数标签
* @param {string} value - 参数值
* @returns {string} HTML字符串
*/
function createWeatherParam(label, value) { function createWeatherParam(label, value) {
return '<div class="weather-param">' + return '<div class="weather-param">' +
'<span class="weather-param-label">' + label + '</span>' + '<span class="weather-param-label">' + label + '</span>' +
@ -339,11 +273,6 @@ var WeatherForecast = (function() {
'</div>'; '</div>';
} }
/**
* 格式化日期时间
* @param {Date} date - 日期对象
* @returns {string} 格式化后的日期时间字符串
*/
function formatDateTime(date) { function formatDateTime(date) {
var month = (date.getMonth() + 1).toString().padStart(2, '0'); var month = (date.getMonth() + 1).toString().padStart(2, '0');
var day = date.getDate().toString().padStart(2, '0'); var day = date.getDate().toString().padStart(2, '0');
@ -353,12 +282,6 @@ var WeatherForecast = (function() {
return month + '-' + day + ' ' + hours + ':' + minutes; return month + '-' + day + ' ' + hours + ':' + minutes;
} }
/**
* 获取风向
* @param {number} u - U分量
* @param {number} v - V分量
* @returns {string} 风向字符串
*/
function getWindDirection(u, v) { function getWindDirection(u, v) {
var angle = Math.atan2(-u, -v) * 180 / Math.PI; var angle = Math.atan2(-u, -v) * 180 / Math.PI;
angle = (angle + 360) % 360; angle = (angle + 360) % 360;
@ -368,139 +291,10 @@ var WeatherForecast = (function() {
return directions[index]; return directions[index];
} }
/**
* 初始化天气卡片拖拽功能
*/
function initWeatherCardDrag() {
var weatherCard = document.getElementById('weatherForecastCard');
if (!weatherCard) return;
var startX, startY;
var startLeft, startTop;
var originalStyles = {
top: '55%',
right: '20px',
left: 'auto',
transform: 'translateY(-50%)'
};
var cardHeader = weatherCard.querySelector('.weather-card-header');
if (!cardHeader) return;
// 双击重置位置
cardHeader.addEventListener('dblclick', function() {
weatherCard.style.top = originalStyles.top;
weatherCard.style.right = originalStyles.right;
weatherCard.style.left = originalStyles.left;
weatherCard.style.transform = originalStyles.transform;
});
// 鼠标拖拽
cardHeader.addEventListener('mousedown', function(e) {
if (e.target.tagName === 'BUTTON' ||
e.target.classList.contains('weather-nav-btn') ||
e.target.classList.contains('weather-close-btn')) {
return;
}
e.preventDefault();
startDrag(e.clientX, e.clientY);
});
// 触摸拖拽
cardHeader.addEventListener('touchstart', function(e) {
if (e.target.tagName === 'BUTTON' ||
e.target.classList.contains('weather-nav-btn') ||
e.target.classList.contains('weather-close-btn')) {
return;
}
e.preventDefault();
var touch = e.touches[0];
startDrag(touch.clientX, touch.clientY);
});
function startDrag(clientX, clientY) {
startX = clientX;
startY = clientY;
var rect = weatherCard.getBoundingClientRect();
startLeft = rect.left;
startTop = rect.top;
isDragging = true;
// 设置为绝对定位
if (getComputedStyle(weatherCard).position !== 'absolute') {
weatherCard.style.position = 'absolute';
weatherCard.style.top = rect.top + 'px';
weatherCard.style.left = rect.left + 'px';
weatherCard.style.right = 'auto';
weatherCard.style.transform = 'none';
}
weatherCard.style.opacity = '0.9';
weatherCard.style.boxShadow = '0 12px 48px rgba(0, 0, 0, 0.25)';
weatherCard.style.zIndex = '1200';
document.body.style.userSelect = 'none';
}
// 鼠标移动事件
document.addEventListener('mousemove', function(e) {
if (!isDragging) return;
moveDrag(e.clientX, e.clientY);
});
// 触摸移动事件
document.addEventListener('touchmove', function(e) {
if (!isDragging) return;
e.preventDefault();
var touch = e.touches[0];
moveDrag(touch.clientX, touch.clientY);
});
function moveDrag(clientX, clientY) {
var dx = clientX - startX;
var dy = clientY - startY;
var newLeft = startLeft + dx;
var newTop = startTop + dy;
// 限制在视口内
var maxX = window.innerWidth - weatherCard.offsetWidth;
var maxY = window.innerHeight - weatherCard.offsetHeight;
newLeft = Math.max(0, Math.min(newLeft, maxX));
newTop = Math.max(0, Math.min(newTop, maxY));
weatherCard.style.left = newLeft + 'px';
weatherCard.style.top = newTop + 'px';
}
// 结束拖拽
document.addEventListener('mouseup', endDrag);
document.addEventListener('touchend', endDrag);
function endDrag() {
if (!isDragging) return;
isDragging = false;
weatherCard.style.opacity = '1';
weatherCard.style.boxShadow = '0 8px 32px rgba(0, 0, 0, 0.15)';
document.body.style.userSelect = '';
}
}
/**
* 检查天气功能是否启用
* @returns {boolean} 是否启用
*/
function isEnabled() { function isEnabled() {
return weatherEnabled; return weatherEnabled;
} }
// 公开API
return { return {
init: init, init: init,
toggleWeatherForecast: toggleWeatherForecast, toggleWeatherForecast: toggleWeatherForecast,

View File

@ -1,755 +0,0 @@
(function() {
var map, vectorSource, vectorLayer, currentBaseLayer;
var greenFeatures = [], orangeFeatures = [], redFeatures = [], allFeatures = [];
var marker_state = 3, currentSearchedDevice = null, myLocationFeature = null, myLocationInterval;
var clusterSource, clusterLayer, showDeviceId = true, showCluster = true;
var minZoomForLabels = 4, maxZoomForClustering = 8;
var measureDraw, measureLayer, measureSource, measureTooltipElement, measureTooltip, sketch;
// 天地图的Key
var TIANDITU_KEY = '0c260b8a094a4e0bc507808812cefdac';
// 设备列表
var deviceList = window.deviceList || [];
var pi = 3.14159265358979324, a = 6378245.0, ee = 0.00669342162296594323;
// 判断是否超出中国,如果超出那么就不用转换坐标了
function outOfChina(lon, lat) {
return (lon < 72.004 || lon > 137.8347) && (lat < 0.8293 || lat > 55.8271);
}
function transformLat(x, y) {
var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
return ret;
}
function transformLon(x, y) {
var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
return ret;
}
function transform(wgLat, wgLon) {
var mars_point = { lon: 0, lat: 0 };
if (outOfChina(wgLon, wgLat)) {
mars_point.lat = wgLat;
mars_point.lon = wgLon;
return mars_point;
}
var dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
var dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
var radLat = wgLat / 180.0 * pi;
var magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
var sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
mars_point.lat = wgLat + dLat;
mars_point.lon = wgLon + dLon;
return mars_point;
}
var mapLayers = {
amap: new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://webrd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'
})
}),
amap_satellite: new ol.layer.Group({
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://webst0{1-4}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}'
})
}),
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://webst0{1-4}.is.autonavi.com/appmaptile?style=8&x={x}&y={y}&z={z}'
})
})
]
}),
tianditu_satellite: new ol.layer.Group({
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: tileLoadErrorHandler
})
}),
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: tileLoadErrorHandler
})
})
]
}),
tianditu_normal: new ol.layer.Group({
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: tileLoadErrorHandler
})
}),
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: tileLoadErrorHandler
})
})
]
}),
tianditu_terrain: new ol.layer.Group({
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: tileLoadErrorHandler
})
})
]
}),
tianditu_terrain_hybrid: new ol.layer.Group({
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: tileLoadErrorHandler
})
}),
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://t{0-7}.tianditu.gov.cn/cta_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cta&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=' + TIANDITU_KEY,
tileLoadFunction: tileLoadErrorHandler
})
})
]
})
};
function tileLoadErrorHandler(imageTile, src) {
imageTile.getImage().src = src;
imageTile.getImage().onerror = function() {
var mapTypeSelect = document.getElementById('mapTypeSelect');
if (mapTypeSelect.value.startsWith('tianditu_')) {
mapTypeSelect.value = 'amap';
switchMapType('amap');
layer.msg('天地图加载失败,已自动切换到高德地图');
layui.form.render('select');
}
};
}
function initialize() {
vectorSource = new ol.source.Vector();
vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: function(feature) {
if (!feature.get('isMyLocation')) {
var deviceInfo = feature.get('deviceInfo');
var iconSrc, color = '#000';
if (deviceInfo.warning == 2) iconSrc = '../images/loc1_red.png';
else if (deviceInfo.warning == 1) iconSrc = '../images/loc1_orange.png';
else iconSrc = '../images/loc1_green.png';
var style = new ol.style.Style({
image: new ol.style.Icon({ anchor: [0.5, 1], src: iconSrc, scale: 0.7 })
});
if (showDeviceId && map.getView().getZoom() >= minZoomForLabels) {
style.setText(new ol.style.Text({
text: deviceInfo.deviceid,
offsetY: -30,
fill: new ol.style.Fill({ color: color }),
stroke: new ol.style.Stroke({ color: '#fff', width: 2 }),
font: '12px Arial'
}));
}
return style;
}
return null;
}
});
measureSource = new ol.source.Vector();
measureLayer = new ol.layer.Vector({
source: measureSource,
style: new ol.style.Style({
fill: new ol.style.Fill({ color: 'rgba(255,255,255,0.2)' }),
stroke: new ol.style.Stroke({ color: '#ffcc33', width: 2 }),
image: new ol.style.Circle({ radius: 7, fill: new ol.style.Fill({ color: '#ffcc33' }) })
})
});
clusterSource = new ol.source.Cluster({ distance: 40, source: vectorSource });
clusterLayer = new ol.layer.Vector({
source: clusterSource,
style: function(feature) {
var size = feature.get('features').length;
return new ol.style.Style({
image: new ol.style.Circle({ radius: 15, fill: new ol.style.Fill({ color: '#3399CC' }) }),
text: new ol.style.Text({ text: size.toString(), fill: new ol.style.Fill({ color: '#fff' }) })
});
}
});
var initialMapType = document.getElementById('mapTypeSelect').value;
currentBaseLayer = mapLayers[initialMapType];
map = new ol.Map({
target: 'map-container',
layers: [currentBaseLayer, measureLayer, clusterLayer, vectorLayer],
view: new ol.View({ center: ol.proj.fromLonLat([116.404, 39.915]), zoom: 7 })
});
var scaleLineControl = new ol.control.ScaleLine({ units: 'metric', bar: true, steps: 4, text: true, minWidth: 140 });
map.addControl(scaleLineControl);
function updateMapSize() {
map.updateSize();
}
setTimeout(updateMapSize, 200);
window.addEventListener('resize', function() {
setTimeout(updateMapSize, 200);
});
window.addEventListener('load', function() {
setTimeout(updateMapSize, 500);
});
var measureDistanceBtn = document.getElementById('measure-distance');
var clearMeasureBtn = document.getElementById('clear-measure');
measureDistanceBtn.addEventListener('click', function() {
this.classList.toggle('active');
if (this.classList.contains('active')) {
addMeasureInteraction();
document.getElementById('clear-measure').classList.remove('active');
layer.msg('双击以结束测量');
} else {
map.removeInteraction(measureDraw);
measureSource.clear();
if (measureTooltipElement) measureTooltipElement.parentNode.removeChild(measureTooltipElement);
}
});
clearMeasureBtn.addEventListener('click', function() {
measureSource.clear();
if (measureTooltipElement) measureTooltipElement.parentNode.removeChild(measureTooltipElement);
var overlays = map.getOverlays().getArray();
var measureOverlays = overlays.filter(function(overlay) {
return overlay.getElement() && overlay.getElement().className && overlay.getElement().className.indexOf('ol-tooltip') !== -1;
});
measureOverlays.forEach(function(overlay) {
map.removeOverlay(overlay);
});
measureTooltipElement = null;
measureDistanceBtn.classList.remove('active');
this.classList.add('active');
setTimeout(function() {
document.getElementById('clear-measure').classList.remove('active');
}, 300);
map.removeInteraction(measureDraw);
});
var initialZoom = map.getView().getZoom();
if (showCluster && initialZoom < maxZoomForClustering) {
clusterLayer.setVisible(true);
vectorLayer.setVisible(false);
} else {
clusterLayer.setVisible(false);
vectorLayer.setVisible(true);
}
map.getView().on('change:resolution', function() {
var zoom = map.getView().getZoom();
if (showCluster) {
if (zoom >= maxZoomForClustering) {
clusterLayer.setVisible(false);
vectorLayer.setVisible(true);
} else {
clusterLayer.setVisible(true);
vectorLayer.setVisible(false);
}
}
vectorLayer.changed();
});
map.on('click', function(evt) {
var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) {
return feature;
});
if (feature) {
var features = feature.get('features');
if (features && features.length > 1) {
var extent = vectorSource.getExtent();
map.getView().fit(extent, { padding: [50, 50, 50, 50], duration: 1000 });
}
}
});
if (deviceList.length > 0) {
var centerLat = 0, centerLon = 0;
for (var i = 0; i < deviceList.length; i++) {
centerLat += deviceList[i].latitude;
centerLon += deviceList[i].longitude;
}
centerLat = centerLat / deviceList.length;
centerLon = centerLon / deviceList.length;
map.getView().setCenter(ol.proj.fromLonLat([centerLon, centerLat]));
}
addDeviceMarkers();
myLocation();
startLocationUpdates();
}
function switchMapType(mapType) {
map.removeLayer(currentBaseLayer);
currentBaseLayer = mapLayers[mapType];
map.getLayers().insertAt(0, currentBaseLayer);
updateMyLocationForMapType(mapType);
addDeviceMarkers();
}
function updateMyLocationForMapType(mapType) {
if (myLocationFeature) {
var originalCoords = myLocationFeature.get('originalCoords');
if (originalCoords) {
var lat = originalCoords.lat, lon = originalCoords.lon, coordinates;
if (mapType === 'amap' || mapType === 'amap_satellite') {
var gcjCoord = transform(lat, lon);
coordinates = ol.proj.fromLonLat([gcjCoord.lon, gcjCoord.lat]);
} else {
coordinates = ol.proj.fromLonLat([lon, lat]);
}
myLocationFeature.getGeometry().setCoordinates(coordinates);
}
}
}
function addDeviceMarkers() {
var savedMyLocationFeature = myLocationFeature;
vectorSource.clear();
greenFeatures = [];
orangeFeatures = [];
redFeatures = [];
allFeatures = [];
for (var i = 0; i < deviceList.length; i++) {
var device = deviceList[i];
var mapCoordinates;
var currentMapType = document.getElementById('mapTypeSelect').value;
if (currentMapType === 'amap' || currentMapType === 'amap_satellite') {
var gcjCoord = transform(device.latitude, device.longitude);
mapCoordinates = ol.proj.fromLonLat([gcjCoord.lon, gcjCoord.lat]);
} else {
mapCoordinates = ol.proj.fromLonLat([device.longitude, device.latitude]);
}
var feature = new ol.Feature({
geometry: new ol.geom.Point(mapCoordinates),
deviceInfo: device
});
if (device.warning == 2) redFeatures.push(feature);
else if (device.warning == 1) orangeFeatures.push(feature);
else greenFeatures.push(feature);
allFeatures.push(feature);
vectorSource.addFeature(feature);
}
if (savedMyLocationFeature) vectorSource.addFeature(savedMyLocationFeature);
if (currentSearchedDevice) {
filterByDeviceId(currentSearchedDevice);
} else {
if (marker_state === 2) {
hideGreen();
hideRed();
} else if (marker_state === 3) {
hideGreen();
hideOrange();
}
}
vectorLayer.changed();
}
function myLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var lon = position.coords.longitude;
var lat = position.coords.latitude;
var currentMapType = document.getElementById('mapTypeSelect').value;
var coordinates;
if (currentMapType === 'amap' || currentMapType === 'amap_satellite') {
var gcjCoord = transform(lat, lon);
coordinates = ol.proj.fromLonLat([gcjCoord.lon, gcjCoord.lat]);
} else {
coordinates = ol.proj.fromLonLat([lon, lat]);
}
if (myLocationFeature) {
vectorSource.removeFeature(myLocationFeature);
}
myLocationFeature = new ol.Feature({
geometry: new ol.geom.Point(coordinates),
isMyLocation: true,
originalCoords: { lat: lat, lon: lon }
});
var style = new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: '../images/loc_blue.png',
scale: 0.7
})
});
myLocationFeature.setStyle(style);
vectorSource.addFeature(myLocationFeature);
map.getView().setCenter(coordinates);
});
}
}
function startLocationUpdates() {
if (myLocationInterval) {
clearInterval(myLocationInterval);
}
myLocationInterval = setInterval(function() {
myLocation();
}, 10 * 60 * 1000);
}
function showAll() {
document.getElementById('btn-all').classList.add('active');
document.getElementById('btn-warning1').classList.remove('active');
document.getElementById('btn-warning2').classList.remove('active');
document.getElementById('btn-device-locate').classList.remove('active');
document.getElementById('btn-device-locate').style.display = 'none';
currentSearchedDevice = null;
document.getElementById('deviceSearch').value = '';
var savedMyLocationFeature = myLocationFeature;
vectorSource.clear();
if (savedMyLocationFeature) {
vectorSource.addFeature(savedMyLocationFeature);
}
for (var i = 0; i < allFeatures.length; i++) {
vectorSource.addFeature(allFeatures[i]);
}
marker_state = 1;
}
function showWarning1() {
document.getElementById('btn-all').classList.remove('active');
document.getElementById('btn-warning1').classList.add('active');
document.getElementById('btn-warning2').classList.remove('active');
document.getElementById('btn-device-locate').classList.remove('active');
document.getElementById('btn-device-locate').style.display = 'none';
currentSearchedDevice = null;
document.getElementById('deviceSearch').value = '';
var savedMyLocationFeature = myLocationFeature;
vectorSource.clear();
if (savedMyLocationFeature) {
vectorSource.addFeature(savedMyLocationFeature);
}
for (var i = 0; i < allFeatures.length; i++) {
vectorSource.addFeature(allFeatures[i]);
}
hideGreen();
hideRed();
marker_state = 2;
}
function showWarning2() {
document.getElementById('btn-all').classList.remove('active');
document.getElementById('btn-warning1').classList.remove('active');
document.getElementById('btn-warning2').classList.add('active');
document.getElementById('btn-device-locate').classList.remove('active');
document.getElementById('btn-device-locate').style.display = 'none';
currentSearchedDevice = null;
document.getElementById('deviceSearch').value = '';
var savedMyLocationFeature = myLocationFeature;
vectorSource.clear();
if (savedMyLocationFeature) {
vectorSource.addFeature(savedMyLocationFeature);
}
for (var i = 0; i < allFeatures.length; i++) {
vectorSource.addFeature(allFeatures[i]);
}
hideGreen();
hideOrange();
marker_state = 3;
}
function showGreen() {
for (var i = 0; i < greenFeatures.length; i++) {
if (!vectorSource.hasFeature(greenFeatures[i])) {
vectorSource.addFeature(greenFeatures[i]);
}
}
}
function showOrange() {
for (var i = 0; i < orangeFeatures.length; i++) {
if (!vectorSource.hasFeature(orangeFeatures[i])) {
vectorSource.addFeature(orangeFeatures[i]);
}
}
}
function showRed() {
for (var i = 0; i < redFeatures.length; i++) {
if (!vectorSource.hasFeature(redFeatures[i])) {
vectorSource.addFeature(redFeatures[i]);
}
}
}
function hideGreen() {
for (var i = 0; i < greenFeatures.length; i++) {
vectorSource.removeFeature(greenFeatures[i]);
}
}
function hideOrange() {
for (var i = 0; i < orangeFeatures.length; i++) {
vectorSource.removeFeature(orangeFeatures[i]);
}
}
function hideRed() {
for (var i = 0; i < redFeatures.length; i++) {
vectorSource.removeFeature(redFeatures[i]);
}
}
function searchDevice() {
var deviceId = document.getElementById('deviceSearch').value.trim();
if (!deviceId) {
currentSearchedDevice = null;
vectorSource.clear();
for (var i = 0; i < allFeatures.length; i++) {
vectorSource.addFeature(allFeatures[i]);
}
if (marker_state === 2) {
hideGreen();
hideRed();
} else if (marker_state === 3) {
hideGreen();
hideOrange();
}
document.getElementById('btn-device-locate').style.display = 'none';
updateFilterButtonsState(marker_state);
return;
}
currentSearchedDevice = deviceId;
filterByDeviceId(deviceId);
}
function locateDeviceOnMap(deviceId, latitude, longitude) {
currentSearchedDevice = deviceId;
filterByDeviceId(deviceId);
layer.open({
title: '',
type: 2,
shade: 0.2,
maxmin: true,
shadeClose: true,
anim: 2,
offset: 'rb',
area: ['100%', '50%'],
content: '../page/gnss_q_status?query=' + deviceId
});
}
function updateFilterButtonsState(state) {
document.getElementById('btn-all').classList.remove('active');
document.getElementById('btn-warning1').classList.remove('active');
document.getElementById('btn-warning2').classList.remove('active');
if (state === 1) {
document.getElementById('btn-all').classList.add('active');
} else if (state === 2) {
document.getElementById('btn-warning1').classList.add('active');
} else if (state === 3) {
document.getElementById('btn-warning2').classList.add('active');
}
}
function filterByDeviceId(deviceId) {
var savedMyLocationFeature = myLocationFeature;
vectorSource.clear();
if (savedMyLocationFeature) {
vectorSource.addFeature(savedMyLocationFeature);
}
var found = false;
for (var i = 0; i < allFeatures.length; i++) {
var feature = allFeatures[i];
var deviceInfo = feature.get('deviceInfo');
if (deviceInfo && deviceInfo.deviceid.includes(deviceId)) {
vectorSource.addFeature(feature);
found = true;
var geometry = feature.getGeometry();
var deviceCoord = geometry.getCoordinates();
map.getView().setCenter(deviceCoord);
map.getView().setZoom(15);
}
}
if (!found) {
layer.msg('未找到设备: ' + deviceId);
if (marker_state === 1) {
showAll();
} else if (marker_state === 2) {
showWarning1();
} else if (marker_state === 3) {
showWarning2();
}
}
document.getElementById('current-device-id').textContent = deviceId;
document.getElementById('btn-device-locate').style.display = 'block';
document.getElementById('btn-device-locate').classList.add('active');
document.getElementById('btn-all').classList.remove('active');
document.getElementById('btn-warning1').classList.remove('active');
document.getElementById('btn-warning2').classList.remove('active');
}
function addMeasureInteraction() {
var type = 'LineString';
measureDraw = new ol.interaction.Draw({
source: measureSource,
type: type,
style: new ol.style.Style({
fill: new ol.style.Fill({ color: 'rgba(255, 255, 255, 0.2)' }),
stroke: new ol.style.Stroke({ color: 'rgba(0, 0, 0, 0.5)', lineDash: [10, 10], width: 2 }),
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({ color: 'rgba(0, 0, 0, 0.7)' }),
fill: new ol.style.Fill({ color: 'rgba(255, 255, 255, 0.2)' })
})
})
});
map.addInteraction(measureDraw);
createMeasureTooltip();
var listener;
measureDraw.on('drawstart', function(evt) {
sketch = evt.feature;
listener = sketch.getGeometry().on('change', function(evt) {
var geom = evt.target;
var output = formatLength(geom);
measureTooltipElement.innerHTML = output;
measureTooltip.setPosition(geom.getLastCoordinate());
});
});
measureDraw.on('drawend', function() {
measureTooltipElement.className = 'ol-tooltip ol-tooltip-static';
measureTooltip.setOffset([0, -7]);
sketch = null;
measureTooltipElement = null;
createMeasureTooltip();
ol.Observable.unByKey(listener);
});
}
function createMeasureTooltip() {
if (measureTooltipElement) {
measureTooltipElement.parentNode.removeChild(measureTooltipElement);
}
measureTooltipElement = document.createElement('div');
measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure';
measureTooltip = new ol.Overlay({
element: measureTooltipElement,
offset: [0, -15],
positioning: 'bottom-center',
stopEvent: false
});
map.addOverlay(measureTooltip);
}
function formatLength(line) {
var coordinates = line.getCoordinates();
var length = 0;
for (var i = 0, ii = coordinates.length - 1; i < ii; ++i) {
var c1 = ol.proj.transform(coordinates[i], 'EPSG:3857', 'EPSG:4326');
var c2 = ol.proj.transform(coordinates[i + 1], 'EPSG:3857', 'EPSG:4326');
length += haversineDistance(c1, c2);
}
return length > 1000 ? Math.round((length / 1000) * 100) / 100 + ' 公里' : Math.round(length * 100) / 100 + ' 米';
}
function haversineDistance(coord1, coord2) {
var R = 6371000;
var dLat = (coord2[1] - coord1[1]) * Math.PI / 180;
var dLon = (coord2[0] - coord1[0]) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(coord1[1] * Math.PI / 180) * Math.cos(coord2[1] * Math.PI / 180) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
layui.use(['form'], function() {
var form = layui.form;
form.on('select(mapType)', function(data) {
switchMapType(data.value);
});
form.on('switch(showDeviceId)', function(data) {
showDeviceId = data.elem.checked;
vectorLayer.changed();
});
form.on('switch(showCluster)', function(data) {
showCluster = data.elem.checked;
var zoom = map.getView().getZoom();
if (showCluster) {
if (zoom < maxZoomForClustering) {
clusterLayer.setVisible(true);
vectorLayer.setVisible(false);
} else {
clusterLayer.setVisible(false);
vectorLayer.setVisible(true);
}
} else {
clusterLayer.setVisible(false);
vectorLayer.setVisible(true);
}
});
initialize();
showAll();
});
window.searchDevice = searchDevice;
window.showAll = showAll;
window.showWarning1 = showWarning1;
window.showWarning2 = showWarning2;
window.locateDeviceOnMap = locateDeviceOnMap;
window.queryDevices = function(status_type) {
layer.open({
title: '',
type: 2,
shade: 0.2,
maxmin: true,
shadeClose: true,
anim: 2,
offset: 'rb',
area: ['100%', '50%'],
content: '../page/gnss_q_status?query=' + status_type
});
};
})();

View File

@ -254,7 +254,7 @@
/* 由于不使用layui的元素所以这边还得适配手机端 */ /* 由于不使用layui的元素所以这边还得适配手机端 */
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
.layuimini-main { .layuimini-main {
height: 108vh; height: 120vh;
overflow: hidden; overflow: hidden;
} }
@ -570,13 +570,11 @@
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 12px; margin-bottom: 12px;
cursor: move;
padding: 10px 20px; padding: 10px 20px;
border-bottom: 1px solid rgba(0, 0, 0, 0.05); border-bottom: 1px solid rgba(0, 0, 0, 0.05);
border-radius: 8px 8px 0 0; border-radius: 8px 8px 0 0;
transition: background-color 0.2s ease; transition: background-color 0.2s ease;
margin: -16px -16px 12px -16px; margin: -16px -16px 12px -16px;
user-select: none;
} }
.weather-card-header:hover { .weather-card-header:hover {
@ -796,182 +794,182 @@
<script src="../js/ol.js"></script> <script src="../js/ol.js"></script>
</head> </head>
<body> <body>
<div class="layuimini-main"> <div class="layuimini-main">
<div class="device-overview-bar"> <div class="device-overview-bar">
<div class="overview-stats"> <div class="overview-stats">
<div class="stat-item non-clickable"> <div class="stat-item non-clickable">
<span class="stat-dot dot-green"></span> <span class="stat-dot dot-green"></span>
<span>设备数量</span> <span>设备数量</span>
<span class="stat-number" th:text="${deviceOnlineNum}">1101</span> <span class="stat-number" th:text="${deviceOnlineNum}">1101</span>
</div> </div>
<div class="stat-item non-clickable"> <div class="stat-item non-clickable">
<span class="stat-dot dot-blue"></span> <span class="stat-dot dot-blue"></span>
<span>装机量</span> <span>装机量</span>
<span class="stat-number" th:text="${deviceDeployedNum}">1123</span> <span class="stat-number" th:text="${deviceDeployedNum}">1123</span>
</div> </div>
<div class="stat-item" onclick="queryDevices('offline')" th:if="${deviceOfflineNum > 0}"> <div class="stat-item" onclick="queryDevices('offline')" th:if="${deviceOfflineNum > 0}">
<span class="stat-dot dot-gray"></span> <span class="stat-dot dot-gray"></span>
<span>掉线数</span> <span>掉线数</span>
<span class="stat-number" th:text="${deviceOfflineNum}">22</span> <span class="stat-number" th:text="${deviceOfflineNum}">22</span>
</div> </div>
<div class="stat-item" onclick="queryDevices('no_fwd')" th:if="${deviceNoFwdNum > 0}"> <div class="stat-item" onclick="queryDevices('no_fwd')" th:if="${deviceNoFwdNum > 0}">
<span class="stat-dot dot-orange"></span> <span class="stat-dot dot-orange"></span>
<span>未推送数</span> <span>未推送数</span>
<span class="stat-number" th:text="${deviceNoFwdNum}">11</span> <span class="stat-number" th:text="${deviceNoFwdNum}">11</span>
</div> </div>
<div class="stat-item" onclick="queryDevices('nofixed')" th:if="${noFix > 0}"> <div class="stat-item" onclick="queryDevices('nofixed')" th:if="${noFix > 0}">
<span class="stat-dot dot-red"></span> <span class="stat-dot dot-red"></span>
<span>长期无效解</span> <span>长期无效解</span>
<span class="stat-number" th:text="${noFix}">10</span> <span class="stat-number" th:text="${noFix}">10</span>
</div> </div>
<div class="stat-item" onclick="queryDevices('warning2')" th:if="${warning2Num > 0}"> <div class="stat-item" onclick="queryDevices('warning2')" th:if="${warning2Num > 0}">
<span class="stat-dot dot-red"></span> <span class="stat-dot dot-red"></span>
<span>严重告警</span> <span>严重告警</span>
<span class="stat-number" th:text="${warning2Num}">40</span> <span class="stat-number" th:text="${warning2Num}">40</span>
</div> </div>
<div class="stat-item" onclick="queryDevices('warning1')" th:if="${warning1Num > 0}"> <div class="stat-item" onclick="queryDevices('warning1')" th:if="${warning1Num > 0}">
<span class="stat-dot dot-orange"></span> <span class="stat-dot dot-orange"></span>
<span>一般告警</span> <span>一般告警</span>
<span class="stat-number" th:text="${warning1Num}">79</span> <span class="stat-number" th:text="${warning1Num}">79</span>
</div> </div>
<div class="stat-item" onclick="queryDevices('nogga')" th:if="${noGGA > 0}"> <div class="stat-item" onclick="queryDevices('nogga')" th:if="${noGGA > 0}">
<span class="stat-dot dot-gray"></span> <span class="stat-dot dot-gray"></span>
<span>无GGA告警</span> <span>无GGA告警</span>
<span class="stat-number" th:text="${noGGA}">4</span> <span class="stat-number" th:text="${noGGA}">4</span>
</div>
</div> </div>
</div> </div>
</div>
<div class="map-wrapper"> <div class="map-wrapper">
<div class="map-card"> <div class="map-card">
<div id="map-container"> <div id="map-container">
<div id="weatherForecastCard" class="weather-forecast-card" style="display: none;" th:if="${role=='SUPER_ADMIN'}"> <div id="weatherForecastCard" class="weather-forecast-card" style="display: none;" th:if="${role=='SUPER_ADMIN'}">
<div class="weather-card-header"> <div class="weather-card-header">
<h3 class="weather-card-title"> <h3 class="weather-card-title">
Windy 天气预测 :) Windy 天气预测 :)
</h3> </h3>
<button class="weather-close-btn" onclick="closeWeatherCard()">×</button> <button class="weather-close-btn" onclick="closeWeatherCard()">×</button>
</div> </div>
<div id="weatherDeviceInfo" class="weather-device-info"> <div id="weatherDeviceInfo" class="weather-device-info">
<span id="weatherDeviceId">设备信息</span> <span id="weatherDeviceId">设备信息</span>
<span id="weatherDeviceCoords">坐标信息</span> <span id="weatherDeviceCoords">坐标信息</span>
</div> </div>
<div class="weather-forecast-navigation"> <div class="weather-forecast-navigation">
<button id="prevForecast" class="weather-nav-btn" onclick="showPrevForecast()" disabled> <button id="prevForecast" class="weather-nav-btn" onclick="showPrevForecast()" disabled>
<i class="layui-icon layui-icon-left"></i> <i class="layui-icon layui-icon-left"></i>
</button> </button>
<span id="forecastTimeDisplay" class="forecast-time-display">--:--</span> <span id="forecastTimeDisplay" class="forecast-time-display">--:--</span>
<button id="nextForecast" class="weather-nav-btn" onclick="showNextForecast()"> <button id="nextForecast" class="weather-nav-btn" onclick="showNextForecast()">
<i class="layui-icon layui-icon-right"></i> <i class="layui-icon layui-icon-right"></i>
</button> </button>
</div> </div>
<div id="weatherForecastContent" class="weather-card-content"> <div id="weatherForecastContent" class="weather-card-content">
<div class="weather-loading"> <div class="weather-loading">
<i class="layui-icon layui-icon-loading layui-icon-anim-rotate"></i> <i class="layui-icon layui-icon-loading layui-icon-anim-rotate"></i>
<p>正在获取天气预测数据...</p> <p>正在获取天气预测数据...</p>
</div>
</div> </div>
</div> </div>
</div>
<div class="map-toolbar"> <div class="map-toolbar">
<div class="toolbar-item"> <div class="toolbar-item">
<select id="mapTypeSelectNew" class="toolbar-select" lay-filter="mapTypeNew" onchange="onMapTypeChange()"> <select id="mapTypeSelectNew" class="toolbar-select" lay-filter="mapTypeNew" onchange="onMapTypeChange()">
<option value="tianditu_satellite" selected>天地图-卫星影像</option> <option value="tianditu_satellite" selected>天地图-卫星影像</option>
<option value="tianditu_terrain_hybrid" >天地图-地形混合</option> <option value="tianditu_terrain_hybrid" >天地图-地形混合</option>
<option value="tianditu_normal">天地图-矢量</option> <option value="tianditu_normal">天地图-矢量</option>
<option value="tianditu_terrain">天地图-地形</option> <option value="tianditu_terrain">天地图-地形</option>
<option value="amap_satellite">高德-卫星影像</option> <option value="amap_satellite">高德-卫星影像</option>
<option value="amap">高德-矢量</option> <option value="amap">高德-矢量</option>
<!-- 只能超级管理员使用 --> <!-- 只能超级管理员使用 -->
<option value="google_satellite" th:if="${role=='SUPER_ADMIN'}">谷歌-卫星影像</option> <option value="google_satellite" th:if="${role=='SUPER_ADMIN'}">谷歌-卫星影像</option>
<option value="google_terrain" th:if="${role=='SUPER_ADMIN'}">谷歌-地形图</option> <option value="google_terrain" th:if="${role=='SUPER_ADMIN'}">谷歌-地形图</option>
<option value="google_roadmap" th:if="${role=='SUPER_ADMIN'}">谷歌-道路图</option> <option value="google_roadmap" th:if="${role=='SUPER_ADMIN'}">谷歌-道路图</option>
<option value="google_hybrid" th:if="${role=='SUPER_ADMIN'}">谷歌-混合</option> <option value="google_hybrid" th:if="${role=='SUPER_ADMIN'}">谷歌-混合</option>
</select> </select>
</div> </div>
<div class="toolbar-divider"></div> <div class="toolbar-divider"></div>
<div class="toolbar-item"> <div class="toolbar-item">
<input type="text" id="deviceSearchNew" class="toolbar-input" placeholder="搜索设备编号"> <input type="text" id="deviceSearchNew" class="toolbar-input" placeholder="搜索设备编号">
<button class="toolbar-btn" onclick="searchDeviceNew()">搜索</button> <button class="toolbar-btn" onclick="searchDeviceNew()">搜索</button>
</div> </div>
<div class="toolbar-divider"></div> <div class="toolbar-divider"></div>
<div class="toolbar-item"> <div class="toolbar-item">
<select id="warningFilter" class="toolbar-select" onchange="onWarningFilterChange()"> <select id="warningFilter" class="toolbar-select" onchange="onWarningFilterChange()">
<option value="all">全部设备</option> <option value="all">全部设备</option>
<option value="warning1">一般告警</option> <option value="warning1">一般告警</option>
<option value="warning2" selected>严重告警</option> <option value="warning2" selected>严重告警</option>
</select> </select>
</div> </div>
<div class="toolbar-divider"></div> <div class="toolbar-divider"></div>
<div class="toolbar-item"> <div class="toolbar-item">
<div class="dropdown-container"> <div class="dropdown-container">
<button class="toolbar-btn dropdown-toggle" onclick="toggleMapFunctionsMenu()">地图功能</button> <button class="toolbar-btn dropdown-toggle" onclick="toggleMapFunctionsMenu()">地图功能</button>
<div id="mapFunctionsMenu" class="dropdown-menu"> <div id="mapFunctionsMenu" class="dropdown-menu">
<div class="dropdown-group"> <div class="dropdown-group">
<div class="dropdown-group-title">信息显示</div> <div class="dropdown-group-title">信息显示</div>
<div class="dropdown-item"> <div class="dropdown-item">
<label class="switch-label"> <label class="switch-label">
<span>显示设备信息</span> <span>显示设备信息</span>
<input type="checkbox" id="showDeviceIdSwitch" checked onchange="toggleDeviceId()"> <input type="checkbox" id="showDeviceIdSwitch" checked onchange="toggleDeviceId()">
<span class="switch-slider"></span> <span class="switch-slider"></span>
</label> </label>
</div>
<div class="dropdown-item">
<label class="switch-label">
<span>显示集群</span>
<input type="checkbox" id="showClusterSwitch" checked onchange="toggleCluster()">
<span class="switch-slider"></span>
</label>
</div>
</div> </div>
<div class="dropdown-divider"></div> <div class="dropdown-item">
<div class="dropdown-group"> <label class="switch-label">
<div class="dropdown-group-title">测量工具</div> <span>显示集群</span>
<div class="dropdown-item" onclick="toggleMeasureDistance()"> <input type="checkbox" id="showClusterSwitch" checked onchange="toggleCluster()">
测距 <span class="switch-slider"></span>
</div> </label>
<div class="dropdown-item" onclick="clearMeasure()">
清除测距
</div>
</div> </div>
<div class="dropdown-divider"></div> </div>
<div class="dropdown-group" th:if="${role=='SUPER_ADMIN'}"> <div class="dropdown-divider"></div>
<div class="dropdown-group-title">Windy 天气预测</div> <div class="dropdown-group">
<div class="dropdown-item"> <div class="dropdown-group-title">测量工具</div>
<label class="switch-label"> <div class="dropdown-item" onclick="toggleMeasureDistance()">
<span>启用天气预测(需网络被代理)</span> 测距
<input type="checkbox" id="enableWeatherSwitch" onchange="toggleWeatherForecast()"> </div>
<span class="switch-slider"></span> <div class="dropdown-item" onclick="clearMeasure()">
</label> 清除测距
</div> </div>
</div>
<div class="dropdown-divider"></div>
<div class="dropdown-group" th:if="${role=='SUPER_ADMIN'}">
<div class="dropdown-group-title">Windy 天气预测</div>
<div class="dropdown-item">
<label class="switch-label">
<span>启用天气预测(需网络被代理)</span>
<input type="checkbox" id="enableWeatherSwitch" onchange="toggleWeatherForecast()">
<span class="switch-slider"></span>
</label>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div id="measureStatus" class="toolbar-item" style="display: none;">
<span style="color: #48bb78; font-weight: bold; font-size: 12px;">测量中</span>
<button class="toolbar-btn" onclick="finishMeasuring()" style="background: #f56565; margin-left: 6px;">
<i class="layui-icon layui-icon-close" style="font-size: 12px;"></i>
</button>
</div>
</div> </div>
<div id="measureStatus" class="toolbar-item" style="display: none;">
<span style="color: #48bb78; font-weight: bold; font-size: 12px;">测量中</span>
<button class="toolbar-btn" onclick="finishMeasuring()" style="background: #f56565; margin-left: 6px;">
<i class="layui-icon layui-icon-close" style="font-size: 12px;"></i>
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- JavaScript 依赖 --> <!-- JavaScript 依赖 -->
<script src="../js/ol.js"></script> <script src="../js/ol.js"></script>
<script src="../lib/jquery-3.4.1/jquery-3.4.1.min.js" charset="utf-8"></script> <script src="../lib/jquery-3.4.1/jquery-3.4.1.min.js" charset="utf-8"></script>