diff --git a/src/utils/map.ts b/src/utils/map.ts index 3a5181a..b716ae2 100644 --- a/src/utils/map.ts +++ b/src/utils/map.ts @@ -1,91 +1,224 @@ -// 坐标转换工具函数 -const xPI = (Math.PI * 3000.0) / 180.0 -const PI = Math.PI -const a = 6378245.0 -const ee = 0.00669342162296594323 +// 坐标转换常量定义 +const xPI = (Math.PI * 3000.0) / 180.0; +const PI = Math.PI; +const a = 6378245.0; // 长半轴 +const ee = 0.00669342162296594323; // 扁率 +/** + * 纬度转换辅助函数 + * @param lng 经度 + * @param lat 纬度 + * @returns 转换后的纬度偏差 + */ function transformlat(lng: number, lat: number): number { - let ret = - -100.0 + - 2.0 * lng + - 3.0 * lat + - 0.2 * lat * lat + - 0.1 * lng * lat + - 0.2 * Math.sqrt(Math.abs(lng)) - ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0 - ret += ((20.0 * Math.sin(lat * PI) + 40.0 * Math.sin((lat / 3.0) * PI)) * 2.0) / 3.0 - ret += ((160.0 * Math.sin((lat / 12.0) * PI) + 320 * Math.sin((lat * PI) / 30.0)) * 2.0) / 3.0 - return ret -} - -function transformlng(lng: number, lat: number): number { - let ret = - 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng)) - ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0 - ret += ((20.0 * Math.sin(lng * PI) + 40.0 * Math.sin((lng / 3.0) * PI)) * 2.0) / 3.0 - ret += ((150.0 * Math.sin((lng / 12.0) * PI) + 300.0 * Math.sin((lng / 30.0) * PI)) * 2.0) / 3.0 - return ret -} - -function convertDmToDd(dmValue: any) { - // 确保是字符串类型 - const str = dmValue.toString() - - // 经度处理(dddmm.mmmm) - if (str.length > 11) { - const degrees = parseFloat(str.substring(0, 3)) - const minutes = parseFloat(str.substring(3)) - return degrees + minutes / 60 - } - // 纬度处理(ddmm.mmmm) - else { - const degrees = parseFloat(str.substring(0, 2)) - const minutes = parseFloat(str.substring(2)) - return degrees + minutes / 60 - } -} - -interface CoordInfo { - [key: string]: any - latitude: number - longitude: number + let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng)); + ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0; + ret += ((20.0 * Math.sin(lat * PI) + 40.0 * Math.sin((lat / 3.0) * PI)) * 2.0) / 3.0; + ret += ((160.0 * Math.sin((lat / 12.0) * PI) + 320 * Math.sin((lat * PI) / 30.0)) * 2.0) / 3.0; + return ret; } /** - * WGS84 -> GCJ02 -> BD09 - * @param lng 原始经度 - * @param lat 原始纬度 - * @param extra 需要合并返回的额外信息 - * @returns 返回包含百度坐标系的对象(包含额外字段) + * 经度转换辅助函数 + * @param lng 经度 + * @param lat 纬度 + * @returns 转换后的经度偏差 */ -export function wgs84ToGcj02ToBd09Public( - lng: number, - lat: number, - extra: { [key: string]: any } = {}, -): CoordInfo { - lng = convertDmToDd(lng) - lat = convertDmToDd(lat) - // Step 1: WGS84 -> GCJ02 - let dlat = transformlat(lng - 105.0, lat - 35.0) - let dlng = transformlng(lng - 105.0, lat - 35.0) - let radlat = (lat / 180.0) * PI - let magic = Math.sin(radlat) - magic = 1 - ee * magic * magic - let sqrtmagic = Math.sqrt(magic) - dlat = (dlat * 180.0) / (((a * (1 - ee)) / (magic * sqrtmagic)) * PI) - dlng = (dlng * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI) - let mglat = lat + dlat - let mglng = lng + dlng +function transformlng(lng: number, lat: number): number { + let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng)); + ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0; + ret += ((20.0 * Math.sin(lng * PI) + 40.0 * Math.sin((lng / 3.0) * PI)) * 2.0) / 3.0; + ret += ((150.0 * Math.sin((lng / 12.0) * PI) + 300.0 * Math.sin((lng / 30.0) * PI)) * 2.0) / 3.0; + return ret; +} - // Step 2: GCJ02 -> BD09 - let z = Math.sqrt(mglng * mglng + mglat * mglat) + 0.00002 * Math.sin(mglat * xPI) - let theta = Math.atan2(mglat, mglng) + 0.000003 * Math.cos(mglng * xPI) - let bdlng = z * Math.cos(theta) + 0.0065 - let bdlat = z * Math.sin(theta) + 0.006 +/** + * 将度分格式(DM)转换为十进制度(DD) + * @param dmValue 度分格式的值,可以是字符串或数字 + * @param isLongitude 是否为经度(true为经度,false为纬度) + * @returns 转换后的十进制度值,转换失败返回null + */ +function convertDmToDd(dmValue: string | number, isLongitude: boolean): number | null { + try { + // 确保是字符串类型并去除空白 + const str = dmValue.toString().trim(); - return { - ...extra, - longitude: bdlng, - latitude: bdlat, + // 验证输入是否为有效的数字字符串 + if (!/^\d+(\.\d+)?$/.test(str)) { + throw new Error(`无效的度分格式: ${str}`); + } + + // 根据经纬度类型确定度的位数 + const degreeDigits = isLongitude ? 3 : 2; + + // 处理字符串长度不足的情况 + if (str.length < degreeDigits) { + throw new Error(`度分格式字符串过短: ${str}`); + } + + // 提取度和分 + const degrees = parseFloat(str.substring(0, degreeDigits)); + const minutes = parseFloat(str.substring(degreeDigits)); + + // 验证度和分的范围 + if (isLongitude && (degrees < 0 || degrees > 180)) { + throw new Error(`无效的经度度数: ${degrees}`); + } + if (!isLongitude && (degrees < 0 || degrees > 90)) { + throw new Error(`无效的纬度度数: ${degrees}`); + } + if (minutes < 0 || minutes >= 60) { + throw new Error(`无效的分数值: ${minutes}`); + } + + return degrees + minutes / 60; + } catch (error) { + console.error("度分转十进制度失败:", error); + return null; } } + +/** + * 坐标信息接口定义 + */ +interface CoordInfo { + [key: string]: any; + latitude: number; // 纬度 + longitude: number; // 经度 + success?: boolean; // 转换是否成功 + error?: string; // 错误信息(如果转换失败) +} + +/** + * WGS84转GCJ02坐标系 + * @param lng 经度(十进制度) + * @param lat 纬度(十进制度) + * @returns 转换后的GCJ02坐标 + */ +function wgs84ToGcj02(lng: number, lat: number): { lng: number, lat: number } { + // 如果不在中国境内,直接返回原坐标 + if (outOfChina(lng, lat)) { + return { lng, lat }; + } + + let dlat = transformlat(lng - 105.0, lat - 35.0); + let dlng = transformlng(lng - 105.0, lat - 35.0); + let radlat = (lat / 180.0) * PI; + let magic = Math.sin(radlat); + magic = 1 - ee * magic * magic; + let sqrtmagic = Math.sqrt(magic); + + dlat = (dlat * 180.0) / (((a * (1 - ee)) / (magic * sqrtmagic)) * PI); + dlng = (dlng * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI); + + return { + lng: lng + dlng, + lat: lat + dlat + }; +} + +/** + * GCJ02转BD09坐标系 + * @param lng 经度(十进制度) + * @param lat 纬度(十进制度) + * @returns 转换后的BD09坐标 + */ +function gcj02ToBd09(lng: number, lat: number): { lng: number, lat: number } { + let z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * xPI); + let theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * xPI); + + return { + lng: z * Math.cos(theta) + 0.0065, + lat: z * Math.sin(theta) + 0.006 + }; +} + +/** + * 判断坐标是否在中国境外 + * @param lng 经度 + * @param lat 纬度 + * @returns 是否在境外 + */ +function outOfChina(lng: number, lat: number): boolean { + return (lng < 73.66 || lng > 135.05 || lat < 18.16 || lat > 53.55); +} + +/** + * 直接转换十进制度格式的WGS84坐标到BD09坐标 + * @param lng 经度(十进制度) + * @param lat 纬度(十进制度) + * @param extra 额外信息 + * @returns 转换结果 + */ +export function wgs84ToBd09Direct( + lng: number, + lat: number, + extra: { [key: string]: any } = {} +): CoordInfo { + try { + // 先转换为GCJ02 + const gcj = wgs84ToGcj02(lng, lat); + // 再转换为BD09 + const bd = gcj02ToBd09(gcj.lng, gcj.lat); + + return { + ...extra, + longitude: bd.lng, + latitude: bd.lat, + success: true + }; + } catch (error) { + console.error("坐标转换失败:", error); + return { + ...extra, + longitude: 0, + latitude: 0, + success: false, + error: error instanceof Error ? error.message : "未知错误" + }; + } +} + +/** + * 将度分格式的WGS84坐标转换为BD09坐标 + * @param lng 经度(度分格式) + * @param lat 纬度(度分格式) + * @param extra 额外信息 + * @returns 转换结果 + */ +export function wgs84ToBd09FromDm( + lng: string | number, + lat: string | number, + extra: { [key: string]: any } = {} +): CoordInfo { + try { + // 先将度分格式转换为十进制度 + const longitude = convertDmToDd(lng, true); + const latitude = convertDmToDd(lat, false); + + if (longitude === null || latitude === null) { + throw new Error("度分格式转换失败"); + } + + // 再进行坐标系转换 + return wgs84ToBd09Direct(longitude, latitude, extra); + } catch (error) { + console.error("坐标转换失败:", error); + return { + ...extra, + longitude: 0, + latitude: 0, + success: false, + error: error instanceof Error ? error.message : "未知错误" + }; + } +} + +// 使用示例 +// 1. 转换度分格式的坐标 +// const dmResult = wgs84ToBd09FromDm("1131234.56", "224567.89"); +// console.log("度分格式转换结果:", dmResult); + +// 2. 直接转换十进制度格式的坐标 +// const directResult = wgs84ToBd09Direct(113.8292617797852, 22.60650444030762); +// console.log("直接转换结果:", directResult); diff --git a/src/views/home/map.vue b/src/views/home/map.vue index 0951f5d..891f776 100644 --- a/src/views/home/map.vue +++ b/src/views/home/map.vue @@ -9,7 +9,7 @@ import { getHotList } from 'http/api/equip' import { loginNewApi } from 'http/api/home/index' import { getUserInfoAPI } from 'http/api/login/index' import { ElMessage } from 'element-plus' -import { wgs84ToGcj02ToBd09Public } from 'utils/map' +import { wgs84ToBd09Direct } from 'utils/map' import { getMapData, mapLoginApi, getIotListApi, getBadgeInfoApi } from 'http/api/map' import icon1 from '@/assets/img/work-card.jpg' import icon2 from '@/assets/img/IOT.jpg' @@ -30,6 +30,7 @@ const mapWorkCardData: any = ref({}) // 工牌信息数据 let timer: any = ref() // 标记点 const points: any = ref([]) +const iot: any = ref([]) const mapData = ref() const tagData: any = ref() const tagIndex: any = ref() @@ -60,24 +61,27 @@ const getMapDataList = async () => { try { await getMapData() } catch (res: any) { + console.log('--------------', res) console.log('🚀 ~ getMapDataList ~ res:', res) - if (res) { - let { longitude, latitude } = wgs84ToGcj02ToBd09Public(res.longitude, res.latitude) - mapData.value = res - mapData.value.longitude = longitude - mapData.value.latitude = latitude - console.log('🚀 ~ getMapDataList ~ longitude:', longitude, latitude) - points.value = [ - { - id: 4, + if (res && res.length > 0) { + const point = res.map((item: any) => { + const longitudeNum = Number(item.longitude) + const latitudeNum = Number(item.latitude) + console.log(longitudeNum, latitudeNum) + let { longitude, latitude } = wgs84ToBd09Direct(latitudeNum, longitudeNum) + console.log('🚀 ~ getMapDataList ~ longitude:', longitude, latitude) + return { + id: item.uuid, lng: longitude, lat: latitude, + item: item, isWork: false, - }, - ] + } + }) + points.value = [...JSON.parse(JSON.stringify(points.value)), ...point] } getWorkData() - // initMap() + //initMap() } } @@ -285,11 +289,12 @@ const initMap = () => { } else { // 打开详情弹框 - 目前没有 mapDialog.value = true + mapData.value = item.item tagData.value = mapData.value.aphase tagIndex.value = 1 timer.value = setInterval(() => { loginApi() - }, 3000) + }, 180000) } }) }) @@ -358,7 +363,9 @@ onMounted(async () => {