diff --git a/src/utils/coordinate.js b/src/utils/coordinate.js index b4654fb..01e7df3 100644 --- a/src/utils/coordinate.js +++ b/src/utils/coordinate.js @@ -13,6 +13,92 @@ const coordinateRanges = { }, }; +/** WGS-84 → GCJ-02(高德)偏移算法常量 */ +const WGS84_TO_GCJ02_PI = Math.PI; +const WGS84_TO_GCJ02_A = 6378245.0; +const WGS84_TO_GCJ02_EE = 0.00669342162296594323; + +const isOutOfChina = (longitude, latitude) => + longitude < 72.004 || longitude > 137.8347 || latitude < 0.8293 || latitude > 55.8271; + +const transformLatitude = (longitude, latitude) => { + let result = + -100.0 + + 2.0 * longitude + + 3.0 * latitude + + 0.2 * latitude * latitude + + 0.1 * longitude * latitude + + 0.2 * Math.sqrt(Math.abs(longitude)); + result += + ((20.0 * Math.sin(6.0 * longitude * WGS84_TO_GCJ02_PI) + + 20.0 * Math.sin(2.0 * longitude * WGS84_TO_GCJ02_PI)) * + 2.0) / + 3.0; + result += + ((20.0 * Math.sin(latitude * WGS84_TO_GCJ02_PI) + + 40.0 * Math.sin((latitude / 3.0) * WGS84_TO_GCJ02_PI)) * + 2.0) / + 3.0; + result += + ((160.0 * Math.sin((latitude / 12.0) * WGS84_TO_GCJ02_PI) + + 320 * Math.sin((latitude * WGS84_TO_GCJ02_PI) / 30.0)) * + 2.0) / + 3.0; + return result; +}; + +const transformLongitude = (longitude, latitude) => { + let result = + 300.0 + + longitude + + 2.0 * latitude + + 0.1 * longitude * longitude + + 0.1 * longitude * latitude + + 0.1 * Math.sqrt(Math.abs(longitude)); + result += + ((20.0 * Math.sin(6.0 * longitude * WGS84_TO_GCJ02_PI) + + 20.0 * Math.sin(2.0 * longitude * WGS84_TO_GCJ02_PI)) * + 2.0) / + 3.0; + result += + ((20.0 * Math.sin(longitude * WGS84_TO_GCJ02_PI) + + 40.0 * Math.sin((longitude / 3.0) * WGS84_TO_GCJ02_PI)) * + 2.0) / + 3.0; + result += + ((150.0 * Math.sin((longitude / 12.0) * WGS84_TO_GCJ02_PI) + + 300.0 * Math.sin((longitude / 30.0) * WGS84_TO_GCJ02_PI)) * + 2.0) / + 3.0; + return result; +}; + +/** + * WGS-84(GPS / LBS)转 GCJ-02(高德/国测局),供高德地图绘制使用。 + * 中国境外坐标不做偏移,原样返回。 + * @param {number} longitude + * @param {number} latitude + * @returns {[number, number]} [经度, 纬度] + */ +export const wgs84ToGcj02 = (longitude, latitude) => { + const lng = Number(longitude); + const lat = Number(latitude); + if (!Number.isFinite(lng) || !Number.isFinite(lat) || isOutOfChina(lng, lat)) { + return [lng, lat]; + } + let dLat = transformLatitude(lng - 105.0, lat - 35.0); + let dLng = transformLongitude(lng - 105.0, lat - 35.0); + const radLat = (lat / 180.0) * WGS84_TO_GCJ02_PI; + let magic = Math.sin(radLat); + magic = 1 - WGS84_TO_GCJ02_EE * magic * magic; + const sqrtMagic = Math.sqrt(magic); + dLat = + (dLat * 180.0) / + (((WGS84_TO_GCJ02_A * (1 - WGS84_TO_GCJ02_EE)) / (magic * sqrtMagic)) * WGS84_TO_GCJ02_PI); + dLng = (dLng * 180.0) / ((WGS84_TO_GCJ02_A / sqrtMagic) * Math.cos(radLat) * WGS84_TO_GCJ02_PI); + return [lng + dLng, lat + dLat]; +}; + export const normalizeCoordinateInput = value => { const rawValue = String(value ?? '').replace(/[^\d.-]/g, ''); const isNegative = rawValue.startsWith('-'); diff --git a/src/views/business/components/waybill-manage-page.vue b/src/views/business/components/waybill-manage-page.vue index d46a264..a565f62 100644 --- a/src/views/business/components/waybill-manage-page.vue +++ b/src/views/business/components/waybill-manage-page.vue @@ -3642,6 +3642,7 @@ import { addressTypeOptions } from '@/option/base/common-address'; import { packageOptions } from '@/option/business/common'; import { formatUpdateUserName } from '@/utils/audit'; import { getToken, isAdministrator } from '@/utils/auth'; +import { wgs84ToGcj02 } from '@/utils/coordinate'; import { openImportDialog } from '@/utils/import-excel'; import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search'; import { loadMeasurementUnitOptions } from '@/utils/measurement-unit'; @@ -6306,12 +6307,14 @@ export default { } }, async renderWaybillLocateMap(locateInfo) { - const longitude = Number(locateInfo?.longitude); - const latitude = Number(locateInfo?.latitude); - if (!Number.isFinite(longitude) || !Number.isFinite(latitude)) { + const rawLongitude = Number(locateInfo?.longitude); + const rawLatitude = Number(locateInfo?.latitude); + if (!Number.isFinite(rawLongitude) || !Number.isFinite(rawLatitude)) { this.$message.warning('定位坐标无效,无法在地图上展示'); return; } + // LBS 返回 WGS-84,高德地图使用 GCJ-02,绘制前需转换 + const [longitude, latitude] = wgs84ToGcj02(rawLongitude, rawLatitude); try { await this.loadAmap(); await this.$nextTick(); @@ -6332,7 +6335,7 @@ export default { `