20251226:首页百度地图完全可用
This commit is contained in:
parent
bec58ecbf2
commit
9ebb0d0986
@ -300,7 +300,7 @@ import CountTo from 'vue-count-to';
|
|||||||
import { loadBMap } from '@/utils/map.js';
|
import { loadBMap } from '@/utils/map.js';
|
||||||
//安装的是echarts完整包,里面包含百度地图扩展,路径为 echarts/extension/bmap/bmap.js,将其引入
|
//安装的是echarts完整包,里面包含百度地图扩展,路径为 echarts/extension/bmap/bmap.js,将其引入
|
||||||
//ECharts的百度地图扩展,可以在百度地图上展现点图,线图,热力图等可视化
|
//ECharts的百度地图扩展,可以在百度地图上展现点图,线图,热力图等可视化
|
||||||
require('echarts/extension/bmap/bmap');
|
// 注意:bmap扩展需要在BMap加载后再引入
|
||||||
import { getServer } from '@/api/monitor/server';
|
import { getServer } from '@/api/monitor/server';
|
||||||
import { listAllDeviceShort } from '@/api/iot/device';
|
import { listAllDeviceShort } from '@/api/iot/device';
|
||||||
import 'echarts-liquidfill';
|
import 'echarts-liquidfill';
|
||||||
@ -362,6 +362,8 @@ export default {
|
|||||||
cityInput: '',
|
cityInput: '',
|
||||||
// 常用城市列表
|
// 常用城市列表
|
||||||
commonCities: ['北京市', '上海市', '广州市', '深圳市', '杭州市', '南京市', '成都市', '武汉市', '西安市', '重庆市', '天津市', '苏州市', '郑州市', '长沙市', '东莞市', '佛山市', '宁波市', '无锡市', '青岛市', '大连市'],
|
commonCities: ['北京市', '上海市', '广州市', '深圳市', '杭州市', '南京市', '成都市', '武汉市', '西安市', '重庆市', '天津市', '苏州市', '郑州市', '长沙市', '东莞市', '佛山市', '宁波市', '无锡市', '青岛市', '大连市'],
|
||||||
|
// 天气刷新定时器
|
||||||
|
weatherTimer: null,
|
||||||
// mqtt状态数据
|
// mqtt状态数据
|
||||||
stats: {},
|
stats: {},
|
||||||
// mqtt统计信息
|
// mqtt统计信息
|
||||||
@ -437,16 +439,27 @@ export default {
|
|||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.stopScroll();
|
this.stopScroll();
|
||||||
|
// 清除天气刷新定时器
|
||||||
|
if (this.weatherTimer) {
|
||||||
|
clearInterval(this.weatherTimer);
|
||||||
|
this.weatherTimer = null;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.init();
|
this.init();
|
||||||
this.getAllDevice();
|
this.getAllDevice();
|
||||||
this.getNoticeList();
|
this.getNoticeList();
|
||||||
this.getDeviceStatistic();
|
this.getDeviceStatistic();
|
||||||
this.fetchWeather();
|
// 先尝试获取浏览器位置,然后获取天气
|
||||||
|
this.getLocationAndWeather();
|
||||||
|
|
||||||
this.getMqttStats();
|
this.getMqttStats();
|
||||||
this.statisticMqtt();
|
this.statisticMqtt();
|
||||||
|
|
||||||
|
// 设置天气自动刷新(每30分钟刷新一次)
|
||||||
|
this.weatherTimer = setInterval(() => {
|
||||||
|
this.fetchWeather();
|
||||||
|
}, 30 * 60 * 1000); // 30分钟
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 公告栏滚动
|
// 公告栏滚动
|
||||||
@ -627,96 +640,297 @@ export default {
|
|||||||
option && myChart.setOption(option);
|
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) {
|
async fetchWeather(cityName) {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
// 获取当前日期和星期作为默认值
|
|
||||||
const { date, week } = getCurrentDateAndWeek();
|
const { date, week } = getCurrentDateAndWeek();
|
||||||
|
|
||||||
// 使用传入的城市名或当前保存的城市
|
|
||||||
const city = cityName || this.weatherData.city;
|
const city = cityName || this.weatherData.city;
|
||||||
|
|
||||||
try {
|
// 尝试多个免费天气API(按优先级)
|
||||||
// 尝试使用城市参数调用API,如果API不支持则使用默认调用
|
const apis = [
|
||||||
let apiUrl = 'https://api.vvhan.com/api/weather';
|
// API 1: wttr.in - 完全免费,无需API key,支持中文城市
|
||||||
// 某些天气API支持城市参数,这里尝试添加
|
async () => {
|
||||||
// 如果API不支持,可以尝试其他天气API或使用IP定位
|
const cityParam = encodeURIComponent(city);
|
||||||
try {
|
const response = await axios.get(`https://wttr.in/${cityParam}?format=j1&lang=zh`, {
|
||||||
// 尝试带城市参数的API调用
|
timeout: 8000
|
||||||
const response = await axios.get(apiUrl, {
|
});
|
||||||
params: { city: city }
|
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) {
|
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) {
|
throw new Error('备用API失败');
|
||||||
// 如果带参数的调用失败,尝试不带参数的调用
|
|
||||||
console.log('带城市参数的API调用失败,尝试默认调用');
|
|
||||||
}
|
}
|
||||||
|
];
|
||||||
|
|
||||||
// 默认API调用(可能不支持城市参数,使用IP定位)
|
// 按顺序尝试各个API
|
||||||
const response = await axios.get(apiUrl);
|
for (let i = 0; i < apis.length; i++) {
|
||||||
if (response.data && response.data.success) {
|
try {
|
||||||
// 如果API返回的城市与设置的城市不同,使用设置的城市名称
|
const result = await apis[i]();
|
||||||
const apiCity = response.data.city || city;
|
if (result && result.success) {
|
||||||
this.updateWeatherData(response.data, date, week, city);
|
this.weatherData = result;
|
||||||
} else {
|
const background = this.getBackgroundColor(result.data.type);
|
||||||
// API返回失败,使用当前日期更新
|
document.documentElement.style.setProperty('--background-start', background.start);
|
||||||
this.weatherData.data.date = date;
|
document.documentElement.style.setProperty('--background-end', background.end);
|
||||||
this.weatherData.data.week = week;
|
this.isLoading = false;
|
||||||
this.weatherData.city = city; // 保持用户设置的城市
|
return;
|
||||||
this.error = '获取天气数据失败,请稍后重试。';
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
if (i === apis.length - 1) {
|
||||||
// API调用失败,使用当前日期更新
|
// 所有API都失败
|
||||||
this.weatherData.data.date = date;
|
this.weatherData.data.date = date;
|
||||||
this.weatherData.data.week = week;
|
this.weatherData.data.week = week;
|
||||||
this.weatherData.city = city; // 保持用户设置的城市
|
this.weatherData.city = city;
|
||||||
this.error = '无法连接到天气服务,请检查网络或稍后再试。';
|
this.error = '无法获取天气数据,请检查网络连接';
|
||||||
} finally {
|
}
|
||||||
this.isLoading = false;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isLoading = false;
|
||||||
},
|
},
|
||||||
// 更新天气数据
|
// 翻译天气类型(英文转中文)
|
||||||
updateWeatherData(responseData, date, week, city) {
|
translateWeatherType(englishType) {
|
||||||
this.weatherData = {
|
const typeMap = {
|
||||||
success: true,
|
'Sunny': '晴',
|
||||||
city: city, // 使用用户设置的城市
|
'Clear': '晴',
|
||||||
data: {
|
'Partly cloudy': '多云',
|
||||||
date: responseData.data?.date || date,
|
'Cloudy': '阴',
|
||||||
week: responseData.data?.week || week,
|
'Overcast': '阴',
|
||||||
type: responseData.data.type,
|
'Mist': '雾',
|
||||||
typeIcon: this.getTypeIcon(responseData.data.type),
|
'Fog': '雾',
|
||||||
low: responseData.data.low,
|
'Light rain': '小雨',
|
||||||
high: responseData.data.high,
|
'Moderate rain': '中雨',
|
||||||
fengxiang: responseData.data.fengxiang,
|
'Heavy rain': '大雨',
|
||||||
fengli: responseData.data.fengli,
|
'Light snow': '小雪',
|
||||||
night: {
|
'Moderate snow': '中雪',
|
||||||
type: responseData.data.night.type,
|
'Heavy snow': '大雪',
|
||||||
fengxiang: responseData.data.night.fengxiang,
|
'Thunderstorm': '雷阵雨',
|
||||||
fengli: responseData.data.night.fengli,
|
'Shower': '阵雨',
|
||||||
},
|
|
||||||
},
|
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
// 动态设置背景颜色
|
return typeMap[englishType] || '晴';
|
||||||
const background = this.getBackgroundColor(responseData.data.type);
|
},
|
||||||
document.documentElement.style.setProperty('--background-start', background.start);
|
// 翻译天气代码(WMO代码转中文)
|
||||||
document.documentElement.style.setProperty('--background-end', background.end);
|
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() {
|
openCityDialog() {
|
||||||
@ -794,7 +1008,6 @@ export default {
|
|||||||
return backgrounds[type] || { start: '#F5F9FF', end: '#FBFBFD' }; // 默认柔和的蓝白色背景
|
return backgrounds[type] || { start: '#F5F9FF', end: '#FBFBFD' }; // 默认柔和的蓝白色背景
|
||||||
},
|
},
|
||||||
getTypeIcon(type) {
|
getTypeIcon(type) {
|
||||||
console.log(type);
|
|
||||||
// 根据天气类型返回对应的图标路径
|
// 根据天气类型返回对应的图标路径
|
||||||
const icons = {
|
const icons = {
|
||||||
晴: require('../../src/assets/icons/qing.png'),
|
晴: require('../../src/assets/icons/qing.png'),
|
||||||
@ -864,10 +1077,21 @@ export default {
|
|||||||
loadMap() {
|
loadMap() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
loadBMap().then(() => {
|
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) => {
|
}).catch((error) => {
|
||||||
console.error('百度地图加载失败:', error);
|
this.$message.error('百度地图加载失败,请检查API Key配置');
|
||||||
this.$message.error('百度地图加载失败,请检查API Key配置。错误信息:' + error.message);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -924,6 +1148,15 @@ export default {
|
|||||||
|
|
||||||
/** 地图 */
|
/** 地图 */
|
||||||
getmap() {
|
getmap() {
|
||||||
|
if (typeof BMap === 'undefined') {
|
||||||
|
this.$message.error('百度地图API未正确加载,请刷新页面重试');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.$refs.map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var myChart = this.$echarts.init(this.$refs.map);
|
var myChart = this.$echarts.init(this.$refs.map);
|
||||||
var option;
|
var option;
|
||||||
|
|
||||||
@ -963,11 +1196,63 @@ export default {
|
|||||||
}
|
}
|
||||||
return res;
|
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 = {
|
option = {
|
||||||
title: {
|
title: {
|
||||||
text: this.$t('home.onlineDevice') + this.deviceList.filter((x) => x.status == 3).length + ')',
|
text: this.$t('home.onlineDevice') + this.deviceList.filter((x) => x.status == 3).length + ')',
|
||||||
subtext: '岩安测控数据平台',
|
subtext: '岩安测控数据平台',
|
||||||
sublink: 'https://iot.fastbee.cn', // todo 替换为延安测控的官网
|
sublink: 'https://yack.cc', // todo 替换为延安测控的官网
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: '#333',
|
color: '#333',
|
||||||
@ -1017,125 +1302,15 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
bmap: {
|
bmap: {
|
||||||
center: [133, 38],
|
center: mapConfig.center,
|
||||||
zoom: 5,
|
zoom: mapConfig.zoom,
|
||||||
roam: true,
|
roam: true,
|
||||||
mapStyle: {
|
// 确保地图正确初始化
|
||||||
styleJson: [
|
enableMapClick: true,
|
||||||
{
|
// 暂时不使用自定义样式,确保地图能正常显示
|
||||||
featureType: 'water',
|
// mapStyle: {
|
||||||
elementType: 'all',
|
// styleJson: [...]
|
||||||
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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
series: [
|
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() {
|
drawPieCpu() {
|
||||||
@ -1302,15 +1528,12 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
label: {
|
label: {
|
||||||
normal: {
|
formatter: (value) => {
|
||||||
formatter: (value) => {
|
return (value.value * 100).toFixed(0) + '%';
|
||||||
return (value.value * 100).toFixed(0) + '%';
|
|
||||||
},
|
|
||||||
textStyle: {
|
|
||||||
fontSize: 20,
|
|
||||||
color: '#333',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
// ECharts 4.0+ 规范:textStyle属性直接放在label下
|
||||||
|
fontSize: 20,
|
||||||
|
color: '#333',
|
||||||
},
|
},
|
||||||
outline: {
|
outline: {
|
||||||
show: true,
|
show: true,
|
||||||
@ -1401,15 +1624,12 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
label: {
|
label: {
|
||||||
normal: {
|
formatter: (value) => {
|
||||||
formatter: (value) => {
|
return (value.value * 100).toFixed(0) + '%';
|
||||||
return (value.value * 100).toFixed(0) + '%';
|
|
||||||
},
|
|
||||||
textStyle: {
|
|
||||||
fontSize: 20,
|
|
||||||
color: '#333',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
// ECharts 4.0+ 规范:textStyle属性直接放在label下
|
||||||
|
fontSize: 20,
|
||||||
|
color: '#333',
|
||||||
},
|
},
|
||||||
outline: {
|
outline: {
|
||||||
show: true,
|
show: true,
|
||||||
@ -1506,15 +1726,12 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
label: {
|
label: {
|
||||||
normal: {
|
formatter: (value) => {
|
||||||
formatter: (value) => {
|
return (value.value * 100).toFixed(0) + '%';
|
||||||
return (value.value * 100).toFixed(0) + '%';
|
|
||||||
},
|
|
||||||
textStyle: {
|
|
||||||
fontSize: 20,
|
|
||||||
color: '#333',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
// ECharts 4.0+ 规范:textStyle属性直接放在label下
|
||||||
|
fontSize: 20,
|
||||||
|
color: '#333',
|
||||||
},
|
},
|
||||||
outline: {
|
outline: {
|
||||||
show: true,
|
show: true,
|
||||||
@ -1680,16 +1897,13 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
label: {
|
label: {
|
||||||
normal: {
|
formatter: (value) => {
|
||||||
formatter: (value) => {
|
return (value.value * 100).toFixed(0) + '%';
|
||||||
return (value.value * 100).toFixed(0) + '%';
|
|
||||||
},
|
|
||||||
position: ['53.3%', '40%'],
|
|
||||||
textStyle: {
|
|
||||||
fontSize: 21,
|
|
||||||
color: '#233d7d',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
position: ['53.3%', '40%'],
|
||||||
|
// ECharts 4.0+ 规范:textStyle属性直接放在label下
|
||||||
|
fontSize: 21,
|
||||||
|
color: '#233d7d',
|
||||||
},
|
},
|
||||||
outline: {
|
outline: {
|
||||||
show: true,
|
show: true,
|
||||||
@ -1890,16 +2104,13 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
label: {
|
label: {
|
||||||
normal: {
|
formatter: (value) => {
|
||||||
formatter: (value) => {
|
return (value.value * 100).toFixed(0) + '%';
|
||||||
return (value.value * 100).toFixed(0) + '%';
|
|
||||||
},
|
|
||||||
position: ['53.3%', '40%'],
|
|
||||||
textStyle: {
|
|
||||||
fontSize: 21,
|
|
||||||
color: '#73545c',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
position: ['53.3%', '40%'],
|
||||||
|
// ECharts 4.0+ 规范:textStyle属性直接放在label下
|
||||||
|
fontSize: 21,
|
||||||
|
color: '#73545c',
|
||||||
},
|
},
|
||||||
outline: {
|
outline: {
|
||||||
show: true,
|
show: true,
|
||||||
@ -1977,35 +2188,31 @@ export default {
|
|||||||
radius: '55%',
|
radius: '55%',
|
||||||
|
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
normal: {
|
width: 8,
|
||||||
width: 8,
|
color: {
|
||||||
color: {
|
type: 'linear',
|
||||||
type: 'linear',
|
colorStops: [
|
||||||
colorStops: [
|
{
|
||||||
{
|
offset: 0,
|
||||||
offset: 0,
|
color: '#A9F387', // 0% 处的颜色
|
||||||
color: '#A9F387', // 0% 处的颜色
|
},
|
||||||
},
|
{
|
||||||
{
|
offset: 1,
|
||||||
offset: 1,
|
color: '#48D8BF', // 100% 处的颜色
|
||||||
color: '#48D8BF', // 100% 处的颜色
|
},
|
||||||
},
|
],
|
||||||
],
|
globalCoord: false, // 缺省为 false
|
||||||
globalCoord: false, // 缺省为 false
|
|
||||||
},
|
|
||||||
shadowColor: 'rgba(72,216,191, 0.3)',
|
|
||||||
shadowBlur: 10,
|
|
||||||
shadowOffsetY: 20,
|
|
||||||
},
|
},
|
||||||
|
shadowColor: 'rgba(72,216,191, 0.3)',
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowOffsetY: 20,
|
||||||
},
|
},
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
normal: {
|
color: 'rgba(72,216,191, 0.3)',
|
||||||
color: 'rgba(72,216,191, 0.3)',
|
borderWidth: 10,
|
||||||
borderWidth: 10,
|
/*shadowColor: 'rgba(72,216,191, 0.3)',
|
||||||
/*shadowColor: 'rgba(72,216,191, 0.3)',
|
shadowBlur: 100,*/
|
||||||
shadowBlur: 100,*/
|
borderColor: '#A9F387',
|
||||||
borderColor: '#A9F387',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
smooth: true,
|
smooth: true,
|
||||||
},
|
},
|
||||||
@ -2524,17 +2731,32 @@ $aqi-unhealthy-color: #f44336;
|
|||||||
|
|
||||||
.map-container {
|
.map-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 500px; /* 减少高度 */
|
height: 500px;
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
overflow: hidden;
|
overflow: hidden; /* 改为hidden,避免内容溢出 */
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
.map {
|
.map {
|
||||||
width: 100%;
|
width: 100% !important;
|
||||||
height: 100%;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 响应式设计 */
|
/* 响应式设计 */
|
||||||
|
|||||||
@ -1,98 +1,211 @@
|
|||||||
<template>
|
<!DOCTYPE html>
|
||||||
<div class="dashboard-editor-container">
|
<html>
|
||||||
|
<head>
|
||||||
<panel-group @handleSetLineChartData="handleSetLineChartData" />
|
<title>百度地图测试页面</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
|
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
|
||||||
<line-chart :chart-data="lineChartData" />
|
<style type="text/css">
|
||||||
</el-row>
|
html, body {
|
||||||
|
width: 100%;
|
||||||
<el-row :gutter="32">
|
height: 100%;
|
||||||
<el-col :xs="24" :sm="24" :lg="8">
|
margin: 0;
|
||||||
<div class="chart-wrapper">
|
padding: 20px;
|
||||||
<raddar-chart />
|
box-sizing: border-box;
|
||||||
</div>
|
background-color: #f5f5f5;
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="24" :lg="8">
|
|
||||||
<div class="chart-wrapper">
|
|
||||||
<pie-chart />
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="24" :lg="8">
|
|
||||||
<div class="chart-wrapper">
|
|
||||||
<bar-chart />
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import PanelGroup from './dashboard/PanelGroup'
|
|
||||||
import LineChart from './dashboard/LineChart'
|
|
||||||
import RaddarChart from './dashboard/RaddarChart'
|
|
||||||
import PieChart from './dashboard/PieChart'
|
|
||||||
import BarChart from './dashboard/BarChart'
|
|
||||||
|
|
||||||
const lineChartData = {
|
|
||||||
newVisitis: {
|
|
||||||
expectedData: [100, 120, 161, 134, 105, 160, 165],
|
|
||||||
actualData: [120, 82, 91, 154, 162, 140, 145]
|
|
||||||
},
|
|
||||||
messages: {
|
|
||||||
expectedData: [200, 192, 120, 144, 160, 130, 140],
|
|
||||||
actualData: [180, 160, 151, 106, 145, 150, 130]
|
|
||||||
},
|
|
||||||
purchases: {
|
|
||||||
expectedData: [80, 100, 121, 104, 105, 90, 100],
|
|
||||||
actualData: [120, 90, 100, 138, 142, 130, 130]
|
|
||||||
},
|
|
||||||
shoppings: {
|
|
||||||
expectedData: [130, 140, 141, 142, 145, 150, 160],
|
|
||||||
actualData: [120, 82, 91, 154, 162, 140, 130]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Index',
|
|
||||||
components: {
|
|
||||||
PanelGroup,
|
|
||||||
LineChart,
|
|
||||||
RaddarChart,
|
|
||||||
PieChart,
|
|
||||||
BarChart
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
lineChartData: lineChartData.newVisitis
|
|
||||||
}
|
}
|
||||||
},
|
.container {
|
||||||
methods: {
|
width: 100%;
|
||||||
handleSetLineChartData(type) {
|
height: 600px;
|
||||||
this.lineChartData = lineChartData[type]
|
background-color: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
#map-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #e3f2fd;
|
||||||
|
border-radius: 5px;
|
||||||
|
border-left: 4px solid #2196F3;
|
||||||
|
}
|
||||||
|
.info h3 {
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
color: #1976D2;
|
||||||
|
}
|
||||||
|
.info p {
|
||||||
|
margin: 5px 0;
|
||||||
|
color: #424242;
|
||||||
|
}
|
||||||
|
.status {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.status.success {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.status.error {
|
||||||
|
background-color: #f44336;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.status.loading {
|
||||||
|
background-color: #FF9800;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="info">
|
||||||
|
<h3>百度地图测试页面</h3>
|
||||||
|
<p>AK配置: <span id="ak-status" class="status loading">检查中...</span></p>
|
||||||
|
<p>BMap状态: <span id="bmap-status" class="status loading">等待加载...</span></p>
|
||||||
|
<p>地图容器: <span id="container-status" class="status loading">检查中...</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div id="map-container"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
// 从环境变量获取AK(这里需要手动设置,因为这是静态HTML文件)
|
||||||
|
// 实际项目中应该从 process.env.VUE_APP_BAI_DU_AK 获取
|
||||||
|
const AK = 's9mUXN9a7bKgVu6U6Z3bXhKSxtz97YPI'; // 请替换为您的AK
|
||||||
|
|
||||||
|
// 更新状态显示
|
||||||
|
function updateStatus(elementId, text, className) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
element.textContent = text;
|
||||||
|
element.className = 'status ' + className;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查AK
|
||||||
|
if (AK && AK !== 'your_baidu_map_ak_here') {
|
||||||
|
updateStatus('ak-status', '已配置', 'success');
|
||||||
|
} else {
|
||||||
|
updateStatus('ak-status', '未配置', 'error');
|
||||||
|
document.getElementById('map-container').innerHTML = '<div style="display:flex;align-items:center;justify-content:center;height:100%;color:#f44336;">请在代码中配置百度地图AK</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查容器
|
||||||
|
const container = document.getElementById('map-container');
|
||||||
|
if (container) {
|
||||||
|
updateStatus('container-status', '存在 (' + container.offsetWidth + 'x' + container.offsetHeight + ')', 'success');
|
||||||
|
} else {
|
||||||
|
updateStatus('container-status', '不存在', 'error');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载百度地图API
|
||||||
|
console.log('[测试页面] 开始加载百度地图API...');
|
||||||
|
console.log('[测试页面] AK:', AK);
|
||||||
|
|
||||||
|
// 使用callback方式加载
|
||||||
|
window.onBMapCallback = function() {
|
||||||
|
console.log('[测试页面] 百度地图API加载成功');
|
||||||
|
updateStatus('bmap-status', '已加载', 'success');
|
||||||
|
|
||||||
|
if (typeof BMap === 'undefined') {
|
||||||
|
console.error('[测试页面] BMap未定义');
|
||||||
|
updateStatus('bmap-status', 'BMap未定义', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 创建地图实例
|
||||||
|
var map = new BMap.Map("map-container");
|
||||||
|
console.log('[测试页面] 地图实例创建成功');
|
||||||
|
|
||||||
|
// 创建中心点坐标(北京天安门)
|
||||||
|
var point = new BMap.Point(116.404, 39.915);
|
||||||
|
console.log('[测试页面] 中心点:', point);
|
||||||
|
|
||||||
|
// 初始化地图,设置中心点和缩放级别
|
||||||
|
map.centerAndZoom(point, 15);
|
||||||
|
console.log('[测试页面] 地图中心点和缩放级别已设置');
|
||||||
|
|
||||||
|
// 启用一些交互功能
|
||||||
|
map.enableScrollWheelZoom(true);
|
||||||
|
map.enableDoubleClickZoom();
|
||||||
|
console.log('[测试页面] 地图交互功能已启用');
|
||||||
|
|
||||||
|
// 添加默认缩放平移控件
|
||||||
|
map.addControl(new BMap.NavigationControl());
|
||||||
|
console.log('[测试页面] 地图控件已添加');
|
||||||
|
|
||||||
|
// 添加标记点
|
||||||
|
var marker = new BMap.Marker(point);
|
||||||
|
map.addOverlay(marker);
|
||||||
|
console.log('[测试页面] 标记点已添加');
|
||||||
|
|
||||||
|
// 添加信息窗口
|
||||||
|
var infoWindow = new BMap.InfoWindow(
|
||||||
|
'<div style="padding:10px;">' +
|
||||||
|
'<h3 style="margin:0 0 10px 0;">天安门广场</h3>' +
|
||||||
|
'<p style="margin:5px 0;">位于北京市中心,是世界上最大的城市广场之一。</p>' +
|
||||||
|
'<p style="margin:5px 0;">坐标:116.404, 39.915</p>' +
|
||||||
|
'</div>',
|
||||||
|
{ width: 250, height: 150 }
|
||||||
|
);
|
||||||
|
|
||||||
|
// 标记点点击事件
|
||||||
|
marker.addEventListener("click", function() {
|
||||||
|
map.openInfoWindow(infoWindow, point);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('[测试页面] 地图初始化完成');
|
||||||
|
|
||||||
|
// 检查地图是否正常显示
|
||||||
|
setTimeout(function() {
|
||||||
|
const mapContainer = map.getContainer();
|
||||||
|
const tiles = mapContainer.querySelectorAll('img');
|
||||||
|
console.log('[测试页面] 地图瓦片数量:', tiles.length);
|
||||||
|
if (tiles.length > 0) {
|
||||||
|
console.log('[测试页面] ✓ 地图瓦片已加载,地图应该正常显示');
|
||||||
|
} else {
|
||||||
|
console.warn('[测试页面] ⚠ 地图瓦片未加载,可能存在问题');
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[测试页面] 地图初始化失败:', error);
|
||||||
|
updateStatus('bmap-status', '初始化失败: ' + error.message, 'error');
|
||||||
|
document.getElementById('map-container').innerHTML =
|
||||||
|
'<div style="display:flex;align-items:center;justify-content:center;height:100%;color:#f44336;">' +
|
||||||
|
'地图初始化失败: ' + error.message +
|
||||||
|
'</div>';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 如果AK已配置,加载百度地图API
|
||||||
|
if (AK && AK !== 'your_baidu_map_ak_here') {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.type = 'text/javascript';
|
||||||
|
const protocol = document.location.protocol === 'https:' ? 'https:' : 'http:';
|
||||||
|
const apiUrl = protocol + '//api.map.baidu.com/api?v=2.0&ak=' + AK + '&callback=onBMapCallback';
|
||||||
|
script.src = apiUrl;
|
||||||
|
console.log('[测试页面] 正在加载:', apiUrl);
|
||||||
|
|
||||||
|
script.onerror = function(error) {
|
||||||
|
console.error('[测试页面] 脚本加载失败:', error);
|
||||||
|
updateStatus('bmap-status', '脚本加载失败', 'error');
|
||||||
|
};
|
||||||
|
|
||||||
|
script.onload = function() {
|
||||||
|
console.log('[测试页面] 脚本标签加载完成,等待回调...');
|
||||||
|
};
|
||||||
|
|
||||||
|
document.head.appendChild(script);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.dashboard-editor-container {
|
|
||||||
padding: 32px;
|
|
||||||
background-color: rgb(240, 242, 245);
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.chart-wrapper {
|
|
||||||
background: #fff;
|
|
||||||
padding: 16px 16px 0;
|
|
||||||
margin-bottom: 32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width:1024px) {
|
|
||||||
.chart-wrapper {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user