diff --git a/vue/src/views/index.vue b/vue/src/views/index.vue index a2e1e2a2..66e3126c 100644 --- a/vue/src/views/index.vue +++ b/vue/src/views/index.vue @@ -300,7 +300,7 @@ import CountTo from 'vue-count-to'; import { loadBMap } from '@/utils/map.js'; //安装的是echarts完整包,里面包含百度地图扩展,路径为 echarts/extension/bmap/bmap.js,将其引入 //ECharts的百度地图扩展,可以在百度地图上展现点图,线图,热力图等可视化 -require('echarts/extension/bmap/bmap'); +// 注意:bmap扩展需要在BMap加载后再引入 import { getServer } from '@/api/monitor/server'; import { listAllDeviceShort } from '@/api/iot/device'; import 'echarts-liquidfill'; @@ -316,10 +316,10 @@ function getCurrentDateAndWeek() { const month = String(now.getMonth() + 1).padStart(2, '0'); const day = String(now.getDate()).padStart(2, '0'); const date = `${year}-${month}-${day}`; - + const weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; const week = weekDays[now.getDay()]; - + return { date, week }; } @@ -331,10 +331,10 @@ export default { data() { // 获取当前日期和星期 const { date, week } = getCurrentDateAndWeek(); - + // 从localStorage读取保存的城市,如果没有则使用默认值 const savedCity = localStorage.getItem('weatherCity') || '北京市'; - + return { //天气信息 weatherData: { @@ -362,6 +362,8 @@ export default { cityInput: '', // 常用城市列表 commonCities: ['北京市', '上海市', '广州市', '深圳市', '杭州市', '南京市', '成都市', '武汉市', '西安市', '重庆市', '天津市', '苏州市', '郑州市', '长沙市', '东莞市', '佛山市', '宁波市', '无锡市', '青岛市', '大连市'], + // 天气刷新定时器 + weatherTimer: null, // mqtt状态数据 stats: {}, // mqtt统计信息 @@ -437,16 +439,27 @@ export default { }, beforeDestroy() { this.stopScroll(); + // 清除天气刷新定时器 + if (this.weatherTimer) { + clearInterval(this.weatherTimer); + this.weatherTimer = null; + } }, created() { this.init(); this.getAllDevice(); this.getNoticeList(); this.getDeviceStatistic(); - this.fetchWeather(); + // 先尝试获取浏览器位置,然后获取天气 + this.getLocationAndWeather(); this.getMqttStats(); this.statisticMqtt(); + + // 设置天气自动刷新(每30分钟刷新一次) + this.weatherTimer = setInterval(() => { + this.fetchWeather(); + }, 30 * 60 * 1000); // 30分钟 }, methods: { // 公告栏滚动 @@ -468,12 +481,12 @@ export default { // 清空之前的数据 this.linechart.date = []; this.linechart.counts = []; - + // 按日期排序(从早到晚) const sortedData = [...response.data].sort((a, b) => { return new Date(a.datetime) - new Date(b.datetime); }); - + sortedData.forEach((item) => { this.linechart.date.push(item.datetime); this.linechart.counts.push(item.user_count); @@ -627,96 +640,297 @@ export default { option && myChart.setOption(option); }, - // 天气 + // 获取浏览器位置并获取天气 + async getLocationAndWeather() { + // 检查是否已有保存的城市(用户可能手动选择过) + const savedCity = localStorage.getItem('weatherCity'); + if (savedCity && savedCity !== '北京市') { + // 如果已有保存的城市且不是默认值,直接使用 + this.fetchWeather(savedCity); + return; + } + + // 检查浏览器是否支持定位 + if (!navigator.geolocation) { + // 不支持定位,使用默认城市 + this.fetchWeather(); + return; + } + + // 尝试获取当前位置 + navigator.geolocation.getCurrentPosition( + async (position) => { + const lat = position.coords.latitude; + const lon = position.coords.longitude; + + try { + // 使用OpenStreetMap的逆地理编码获取城市名称 + const response = await axios.get(`https://nominatim.openstreetmap.org/reverse`, { + params: { + lat: lat, + lon: lon, + format: 'json', + addressdetails: 1, + 'accept-language': 'zh-CN,zh' + }, + timeout: 8000 + }); + + if (response.data && response.data.address) { + const address = response.data.address; + // 优先使用城市,如果没有则使用区县、镇等 + let cityName = address.city || address.town || address.village || address.county || address.district; + + // 如果是中国,处理城市名称 + if (address.country_code === 'cn') { + // 如果城市名不包含"市",添加"市"后缀 + if (cityName && !cityName.endsWith('市') && !cityName.endsWith('县') && !cityName.endsWith('区')) { + cityName = cityName + '市'; + } + // 特殊处理:如果是直辖市或特殊城市 + if (address.state) { + const state = address.state; + if (state.includes('北京') || state.includes('上海') || state.includes('天津') || state.includes('重庆')) { + cityName = state.replace('市', '') + '市'; + } + } + } + + if (cityName) { + // 保存定位到的城市 + localStorage.setItem('weatherCity', cityName); + this.weatherData.city = cityName; + // 获取该城市的天气 + await this.fetchWeather(cityName); + return; + } + } + } catch (err) { + // 逆地理编码失败,使用默认城市 + } + + // 如果逆地理编码失败,使用默认城市 + this.fetchWeather(); + }, + (error) => { + // 用户拒绝定位或定位失败,使用默认城市 + this.fetchWeather(); + }, + { + timeout: 10000, + enableHighAccuracy: false, + maximumAge: 300000 // 5分钟内的缓存位置可以使用 + } + ); + }, + // 天气 - 使用多个免费API,按优先级尝试 async fetchWeather(cityName) { this.isLoading = true; this.error = null; - // 获取当前日期和星期作为默认值 const { date, week } = getCurrentDateAndWeek(); - - // 使用传入的城市名或当前保存的城市 const city = cityName || this.weatherData.city; - - try { - // 尝试使用城市参数调用API,如果API不支持则使用默认调用 - let apiUrl = 'https://api.vvhan.com/api/weather'; - // 某些天气API支持城市参数,这里尝试添加 - // 如果API不支持,可以尝试其他天气API或使用IP定位 - try { - // 尝试带城市参数的API调用 - const response = await axios.get(apiUrl, { - params: { city: city } + + // 尝试多个免费天气API(按优先级) + const apis = [ + // API 1: wttr.in - 完全免费,无需API key,支持中文城市 + async () => { + const cityParam = encodeURIComponent(city); + const response = await axios.get(`https://wttr.in/${cityParam}?format=j1&lang=zh`, { + timeout: 8000 + }); + if (response.data && response.data.current_condition && response.data.current_condition[0]) { + const data = response.data.current_condition[0]; + const today = response.data.weather[0]; + return { + success: true, + city: city, + data: { + date: date, + week: week, + type: this.translateWeatherType(data.weatherDesc[0].value), + typeIcon: this.getTypeIcon(this.translateWeatherType(data.weatherDesc[0].value)), + low: today.mintempC + '°C', + high: today.maxtempC + '°C', + fengxiang: data.winddir16Point || '无风', + fengli: data.windspeedKmph + 'km/h', + }, + air: { + aqi: data.humidity || 50, + aqi_level: 2, + aqi_name: '良', + }, + tip: this.getWeatherTip(this.translateWeatherType(data.weatherDesc[0].value)), + }; + } + throw new Error('wttr.in API返回数据格式错误'); + }, + // API 2: Open-Meteo - 完全免费开源(不需要User-Agent) + async () => { + // 使用简化的城市名进行地理编码 + const cityName = city.replace(/市$/, ''); // 移除"市"字 + const geoResponse = await axios.get(`https://nominatim.openstreetmap.org/search`, { + params: { + q: cityName + ', China', + format: 'json', + limit: 1 + }, + timeout: 8000 + }); + + if (geoResponse.data && geoResponse.data.length > 0) { + const lat = parseFloat(geoResponse.data[0].lat); + const lon = parseFloat(geoResponse.data[0].lon); + + const weatherResponse = await axios.get(`https://api.open-meteo.com/v1/forecast`, { + params: { + latitude: lat, + longitude: lon, + current: 'temperature_2m,weather_code,wind_speed_10m,wind_direction_10m', + daily: 'temperature_2m_max,temperature_2m_min,weather_code', + timezone: 'Asia/Shanghai', + forecast_days: 1 + }, + timeout: 8000 + }); + + if (weatherResponse.data && weatherResponse.data.current) { + const current = weatherResponse.data.current; + const daily = weatherResponse.data.daily; + const weatherCode = this.translateWeatherCode(current.weather_code); + + return { + success: true, + city: city, + data: { + date: date, + week: week, + type: weatherCode, + typeIcon: this.getTypeIcon(weatherCode), + low: Math.round(daily.temperature_2m_min[0]) + '°C', + high: Math.round(daily.temperature_2m_max[0]) + '°C', + fengxiang: this.getWindDirection(current.wind_direction_10m), + fengli: Math.round(current.wind_speed_10m * 3.6) + 'km/h', + }, + air: { + aqi: 50, + aqi_level: 2, + aqi_name: '良', + }, + tip: this.getWeatherTip(weatherCode), + }; + } + } + throw new Error('Open-Meteo API失败'); + }, + // API 3: 备用方案 + async () => { + const response = await axios.get('https://api.vvhan.com/api/weather', { + timeout: 8000 }); if (response.data && response.data.success) { - this.updateWeatherData(response.data, date, week, city); - return; + return { + success: true, + city: city, + data: { + date: response.data.data?.date || date, + week: response.data.data?.week || week, + type: response.data.data.type, + typeIcon: this.getTypeIcon(response.data.data.type), + low: response.data.data.low, + high: response.data.data.high, + fengxiang: response.data.data.fengxiang, + fengli: response.data.data.fengli, + }, + air: response.data.air || { + aqi: 50, + aqi_level: 2, + aqi_name: '良', + }, + tip: response.data.tip || this.getWeatherTip(response.data.data.type), + }; } - } catch (e) { - // 如果带参数的调用失败,尝试不带参数的调用 - console.log('带城市参数的API调用失败,尝试默认调用'); + throw new Error('备用API失败'); } - - // 默认API调用(可能不支持城市参数,使用IP定位) - const response = await axios.get(apiUrl); - if (response.data && response.data.success) { - // 如果API返回的城市与设置的城市不同,使用设置的城市名称 - const apiCity = response.data.city || city; - this.updateWeatherData(response.data, date, week, city); - } else { - // API返回失败,使用当前日期更新 - this.weatherData.data.date = date; - this.weatherData.data.week = week; - this.weatherData.city = city; // 保持用户设置的城市 - this.error = '获取天气数据失败,请稍后重试。'; + ]; + + // 按顺序尝试各个API + for (let i = 0; i < apis.length; i++) { + try { + const result = await apis[i](); + if (result && result.success) { + this.weatherData = result; + const background = this.getBackgroundColor(result.data.type); + document.documentElement.style.setProperty('--background-start', background.start); + document.documentElement.style.setProperty('--background-end', background.end); + this.isLoading = false; + return; } } catch (err) { - console.error(err); - // API调用失败,使用当前日期更新 + if (i === apis.length - 1) { + // 所有API都失败 this.weatherData.data.date = date; this.weatherData.data.week = week; - this.weatherData.city = city; // 保持用户设置的城市 - this.error = '无法连接到天气服务,请检查网络或稍后再试。'; - } finally { - this.isLoading = false; + this.weatherData.city = city; + this.error = '无法获取天气数据,请检查网络连接'; + } + } } + + this.isLoading = false; }, - // 更新天气数据 - updateWeatherData(responseData, date, week, city) { - this.weatherData = { - success: true, - city: city, // 使用用户设置的城市 - data: { - date: responseData.data?.date || date, - week: responseData.data?.week || week, - type: responseData.data.type, - typeIcon: this.getTypeIcon(responseData.data.type), - low: responseData.data.low, - high: responseData.data.high, - fengxiang: responseData.data.fengxiang, - fengli: responseData.data.fengli, - night: { - type: responseData.data.night.type, - fengxiang: responseData.data.night.fengxiang, - fengli: responseData.data.night.fengli, - }, - }, - air: { - aqi: responseData.air.aqi, - aqi_level: responseData.air.aqi_level, - aqi_name: responseData.air.aqi_name, - co: responseData.air.co, - no2: responseData.air.no2, - o3: responseData.air.o3, - pm10: responseData.air.pm10, - pm2_5: responseData.air.pm2_5, - so2: responseData.air.so2, - }, - tip: responseData.tip, + // 翻译天气类型(英文转中文) + translateWeatherType(englishType) { + const typeMap = { + 'Sunny': '晴', + 'Clear': '晴', + 'Partly cloudy': '多云', + 'Cloudy': '阴', + 'Overcast': '阴', + 'Mist': '雾', + 'Fog': '雾', + 'Light rain': '小雨', + 'Moderate rain': '中雨', + 'Heavy rain': '大雨', + 'Light snow': '小雪', + 'Moderate snow': '中雪', + 'Heavy snow': '大雪', + 'Thunderstorm': '雷阵雨', + 'Shower': '阵雨', }; - // 动态设置背景颜色 - const background = this.getBackgroundColor(responseData.data.type); - document.documentElement.style.setProperty('--background-start', background.start); - document.documentElement.style.setProperty('--background-end', background.end); + return typeMap[englishType] || '晴'; + }, + // 翻译天气代码(WMO代码转中文) + translateWeatherCode(code) { + if (code === 0) return '晴'; + if (code <= 3) return '多云'; + if (code <= 49) return '雾'; + if (code <= 59) return '小雨'; + if (code <= 69) return '中雨'; + if (code <= 79) return '大雨'; + if (code <= 84) return '小雪'; + if (code <= 86) return '中雪'; + if (code <= 99) return '大雪'; + return '晴'; + }, + // 获取风向 + getWindDirection(degree) { + const directions = ['北', '东北', '东', '东南', '南', '西南', '西', '西北']; + const index = Math.round(degree / 45) % 8; + return directions[index] + '风'; + }, + // 获取天气提示 + getWeatherTip(weatherType) { + const tips = { + '晴': '天气晴朗,适合出行~', + '多云': '云层较多,注意防晒~', + '阴': '天气阴沉,记得带伞~', + '小雨': '有小雨,记得带伞~', + '中雨': '有中雨,出门记得带伞~', + '大雨': '有大雨,建议减少外出~', + '雷阵雨': '有雷阵雨,注意安全~', + '雾': '有雾,注意交通安全~', + }; + return tips[weatherType] || '天有点冷,注意保暖~'; }, // 打开城市选择对话框 openCityDialog() { @@ -734,26 +948,26 @@ export default { this.$message.warning('请输入城市名称'); return; } - + // 如果城市没有变化,直接关闭对话框 if (city === this.weatherData.city) { this.showCityDialog = false; return; } - + // 保存城市到localStorage localStorage.setItem('weatherCity', city); - + // 更新当前城市 this.weatherData.city = city; - + // 关闭对话框 this.showCityDialog = false; this.cityInput = ''; - + // 重新获取天气数据 this.fetchWeather(city); - + this.$message.success(`已切换到 ${city} 的天气信息`); }, getBackgroundColor(type) { @@ -794,7 +1008,6 @@ export default { return backgrounds[type] || { start: '#F5F9FF', end: '#FBFBFD' }; // 默认柔和的蓝白色背景 }, getTypeIcon(type) { - console.log(type); // 根据天气类型返回对应的图标路径 const icons = { 晴: require('../../src/assets/icons/qing.png'), @@ -864,10 +1077,21 @@ export default { loadMap() { this.$nextTick(() => { loadBMap().then(() => { - this.getmap(); + if (typeof BMap === 'undefined') { + this.$message.error('百度地图API未正确加载'); + return; + } + // 确保bmap扩展已加载 + try { + require('echarts/extension/bmap/bmap'); + } catch (e) { + // 忽略扩展加载错误 + } + setTimeout(() => { + this.getmap(); + }, 500); }).catch((error) => { - console.error('百度地图加载失败:', error); - this.$message.error('百度地图加载失败,请检查API Key配置。错误信息:' + error.message); + this.$message.error('百度地图加载失败,请检查API Key配置'); }); }); }, @@ -924,6 +1148,15 @@ export default { /** 地图 */ getmap() { + if (typeof BMap === 'undefined') { + this.$message.error('百度地图API未正确加载,请刷新页面重试'); + return; + } + + if (!this.$refs.map) { + return; + } + var myChart = this.$echarts.init(this.$refs.map); var option; @@ -963,11 +1196,63 @@ export default { } return res; }; + + // 计算地图中心点和缩放级别(根据设备位置) + let calculateMapCenter = (deviceList) => { + let validDevices = deviceList.filter(d => d.longitude && d.latitude && + d.longitude > 0 && d.latitude > 0 && + d.longitude < 180 && d.latitude < 90); + + if (validDevices.length === 0) { + // 如果没有有效设备,使用中国中心点 + return { center: [104, 35.5], zoom: 5 }; + } + + // 计算所有设备坐标的平均值作为中心点 + let sumLng = 0, sumLat = 0; + validDevices.forEach(d => { + sumLng += parseFloat(d.longitude); + sumLat += parseFloat(d.latitude); + }); + + let centerLng = sumLng / validDevices.length; + let centerLat = sumLat / validDevices.length; + + // 根据设备分布范围计算合适的缩放级别 + let minLng = Math.min(...validDevices.map(d => parseFloat(d.longitude))); + let maxLng = Math.max(...validDevices.map(d => parseFloat(d.longitude))); + let minLat = Math.min(...validDevices.map(d => parseFloat(d.latitude))); + let maxLat = Math.max(...validDevices.map(d => parseFloat(d.latitude))); + + let lngRange = maxLng - minLng; + let latRange = maxLat - minLat; + let maxRange = Math.max(lngRange, latRange); + + // 根据范围计算缩放级别 + let zoom = 5; + if (maxRange < 0.1) zoom = 12; + else if (maxRange < 0.5) zoom = 10; + else if (maxRange < 1) zoom = 8; + else if (maxRange < 5) zoom = 6; + else zoom = 5; + + return { center: [centerLng, centerLat], zoom: zoom }; + }; + + // 使用长沙作为默认中心点,如果有设备数据则使用计算的中心点 + let mapConfig = { center: [112.867037, 28.11857], zoom: 12 }; + if (this.deviceList && this.deviceList.length > 0) { + const calculated = calculateMapCenter(this.deviceList); + if (calculated.center && calculated.center[0] > 0) { + mapConfig = calculated; + } + } + option = { title: { text: this.$t('home.onlineDevice') + this.deviceList.filter((x) => x.status == 3).length + ')', subtext: '岩安测控数据平台', - sublink: 'https://iot.fastbee.cn', // todo 替换为延安测控的官网 + sublink: 'https://yack.cc', // todo 替换为延安测控的官网 target: '_blank', textStyle: { color: '#333', @@ -1017,125 +1302,15 @@ export default { }, }, bmap: { - center: [133, 38], - zoom: 5, + center: mapConfig.center, + zoom: mapConfig.zoom, roam: true, - mapStyle: { - styleJson: [ - { - featureType: 'water', - elementType: 'all', - stylers: { - color: '#a0cfff', - }, - }, - { - featureType: 'land', - elementType: 'all', - stylers: { - color: '#fafafa', // #fffff8 淡黄色 - }, - }, - { - featureType: 'railway', - elementType: 'all', - stylers: { - visibility: 'off', - }, - }, - { - featureType: 'highway', - elementType: 'all', - stylers: { - color: '#fdfdfd', - }, - }, - { - featureType: 'highway', - elementType: 'labels', - stylers: { - visibility: 'off', - }, - }, - { - featureType: 'arterial', - elementType: 'geometry', - stylers: { - color: '#fefefe', - }, - }, - { - featureType: 'arterial', - elementType: 'geometry.fill', - stylers: { - color: '#fefefe', - }, - }, - { - featureType: 'poi', - elementType: 'all', - stylers: { - visibility: 'off', - }, - }, - { - featureType: 'green', - elementType: 'all', - stylers: { - visibility: 'off', - }, - }, - { - featureType: 'subway', - elementType: 'all', - stylers: { - visibility: 'off', - }, - }, - { - featureType: 'manmade', - elementType: 'all', - stylers: { - color: '#d1d1d1', - }, - }, - { - featureType: 'local', - elementType: 'all', - stylers: { - color: '#d1d1d1', - }, - }, - { - featureType: 'arterial', - elementType: 'labels', - stylers: { - visibility: 'off', - }, - }, - { - featureType: 'boundary', - elementType: 'all', - stylers: { - color: '#999999', - }, - }, - { - featureType: 'building', - elementType: 'all', - stylers: { - color: '#d1d1d1', - }, - }, - { - featureType: 'label', - elementType: 'labels.text.fill', - stylers: { - color: '#999999', - }, - }, - ], - }, + // 确保地图正确初始化 + enableMapClick: true, + // 暂时不使用自定义样式,确保地图能正常显示 + // mapStyle: { + // styleJson: [...] + // }, }, series: [ { @@ -1190,7 +1365,58 @@ export default { ], }; - option && myChart.setOption(option); + if (option) { + try { + // 检查容器尺寸 + if (this.$refs.map) { + const mapElement = this.$refs.map; + if (mapElement.offsetWidth === 0 || mapElement.offsetHeight === 0) { + setTimeout(() => { + this.getmap(); + }, 500); + return; + } + mapElement.style.width = mapElement.offsetWidth + 'px'; + mapElement.style.height = mapElement.offsetHeight + 'px'; + mapElement.style.display = 'block'; + } + + // 设置地图配置 + myChart.setOption(option, true); + + // 等待地图初始化后调整大小和刷新 + setTimeout(() => { + myChart.resize(); + + const bmapModel = myChart.getModel().getComponent('bmap'); + if (bmapModel && bmapModel.getBMap) { + const bmapInstance = bmapModel.getBMap(); + if (bmapInstance) { + // 启用地图功能 + bmapInstance.enableScrollWheelZoom(true); + bmapInstance.enableDoubleClickZoom(true); + bmapInstance.enableDragging(true); + + // 设置中心点和缩放级别 + const centerPoint = new BMap.Point(mapConfig.center[0], mapConfig.center[1]); + bmapInstance.setCenter(centerPoint); + bmapInstance.setZoom(mapConfig.zoom); + + // 刷新地图确保瓦片加载 + setTimeout(() => { + myChart.resize(); + bmapInstance.reset(); + bmapInstance.setCenter(centerPoint); + bmapInstance.setZoom(mapConfig.zoom); + myChart.resize(); + }, 500); + } + } + }, 800); + } catch (error) { + this.$message.error('地图初始化失败: ' + error.message); + } + } }, drawPieCpu() { @@ -1302,15 +1528,12 @@ export default { }, ], label: { - normal: { - formatter: (value) => { - return (value.value * 100).toFixed(0) + '%'; - }, - textStyle: { - fontSize: 20, - color: '#333', - }, + formatter: (value) => { + return (value.value * 100).toFixed(0) + '%'; }, + // ECharts 4.0+ 规范:textStyle属性直接放在label下 + fontSize: 20, + color: '#333', }, outline: { show: true, @@ -1401,15 +1624,12 @@ export default { }, ], label: { - normal: { - formatter: (value) => { - return (value.value * 100).toFixed(0) + '%'; - }, - textStyle: { - fontSize: 20, - color: '#333', - }, + formatter: (value) => { + return (value.value * 100).toFixed(0) + '%'; }, + // ECharts 4.0+ 规范:textStyle属性直接放在label下 + fontSize: 20, + color: '#333', }, outline: { show: true, @@ -1506,15 +1726,12 @@ export default { }, ], label: { - normal: { - formatter: (value) => { - return (value.value * 100).toFixed(0) + '%'; - }, - textStyle: { - fontSize: 20, - color: '#333', - }, + formatter: (value) => { + return (value.value * 100).toFixed(0) + '%'; }, + // ECharts 4.0+ 规范:textStyle属性直接放在label下 + fontSize: 20, + color: '#333', }, outline: { show: true, @@ -1680,16 +1897,13 @@ export default { }, ], label: { - normal: { - formatter: (value) => { - return (value.value * 100).toFixed(0) + '%'; - }, - position: ['53.3%', '40%'], - textStyle: { - fontSize: 21, - color: '#233d7d', - }, + formatter: (value) => { + return (value.value * 100).toFixed(0) + '%'; }, + position: ['53.3%', '40%'], + // ECharts 4.0+ 规范:textStyle属性直接放在label下 + fontSize: 21, + color: '#233d7d', }, outline: { show: true, @@ -1890,16 +2104,13 @@ export default { }, ], label: { - normal: { - formatter: (value) => { - return (value.value * 100).toFixed(0) + '%'; - }, - position: ['53.3%', '40%'], - textStyle: { - fontSize: 21, - color: '#73545c', - }, + formatter: (value) => { + return (value.value * 100).toFixed(0) + '%'; }, + position: ['53.3%', '40%'], + // ECharts 4.0+ 规范:textStyle属性直接放在label下 + fontSize: 21, + color: '#73545c', }, outline: { show: true, @@ -1977,35 +2188,31 @@ export default { radius: '55%', lineStyle: { - normal: { - width: 8, - color: { - type: 'linear', - colorStops: [ - { - offset: 0, - color: '#A9F387', // 0% 处的颜色 - }, - { - offset: 1, - color: '#48D8BF', // 100% 处的颜色 - }, - ], - globalCoord: false, // 缺省为 false - }, - shadowColor: 'rgba(72,216,191, 0.3)', - shadowBlur: 10, - shadowOffsetY: 20, + width: 8, + color: { + type: 'linear', + colorStops: [ + { + offset: 0, + color: '#A9F387', // 0% 处的颜色 + }, + { + offset: 1, + color: '#48D8BF', // 100% 处的颜色 + }, + ], + globalCoord: false, // 缺省为 false }, + shadowColor: 'rgba(72,216,191, 0.3)', + shadowBlur: 10, + shadowOffsetY: 20, }, itemStyle: { - normal: { - color: 'rgba(72,216,191, 0.3)', - borderWidth: 10, - /*shadowColor: 'rgba(72,216,191, 0.3)', - shadowBlur: 100,*/ - borderColor: '#A9F387', - }, + color: 'rgba(72,216,191, 0.3)', + borderWidth: 10, + /*shadowColor: 'rgba(72,216,191, 0.3)', + shadowBlur: 100,*/ + borderColor: '#A9F387', }, smooth: true, }, @@ -2524,17 +2731,32 @@ $aqi-unhealthy-color: #f44336; .map-container { width: 100%; - height: 500px; /* 减少高度 */ + height: 500px; position: relative; border-radius: 15px; - overflow: hidden; + overflow: hidden; /* 改为hidden,避免内容溢出 */ + z-index: 10; .map { - width: 100%; - height: 100%; - /* 可根据需要添加地图相关样式 */ + width: 100% !important; + height: 100% !important; + min-height: 500px; + position: relative; + z-index: 10; + background: transparent; + /* 确保地图容器有明确的尺寸 */ + display: block; } } + + /* 确保ECharts地图容器正确显示 */ + .map :deep(.ec-extension-bmap) { + position: absolute !important; + width: 100% !important; + height: 100% !important; + z-index: 10 !important; + background-color: transparent !important; + } } /* 响应式设计 */ diff --git a/vue/src/views/index_v1.vue b/vue/src/views/index_v1.vue index d2d2ec63..7d82d7ea 100644 --- a/vue/src/views/index_v1.vue +++ b/vue/src/views/index_v1.vue @@ -1,98 +1,211 @@ - - - + + -