Ver código fonte

feat(system): 添加地图坐标点击获取中文地址功能

- 实现点击地图更新坐标并自动获取详细地址
- 集成 OpenCageData API 进行地理编码查询
- 添加 GCJ-02 到 WGS-84 坐标转换功能
- 实现中文地址格式清理和优化显示
- 支持编辑模式下地址自动填充逻辑
fugui 1 mês atrás
pai
commit
aa5c8b0915
1 arquivos alterados com 128 adições e 2 exclusões
  1. 128 2
      src/views/system/physical/store/index.vue

+ 128 - 2
src/views/system/physical/store/index.vue

@@ -718,7 +718,6 @@ const loadAmapApi = (): Promise<void> => {
   });
 };
 
-// 初始化高德地图
 // 初始化高德地图
 const initMap = async () => {
   try {
@@ -784,7 +783,8 @@ const initMap = async () => {
 
     mapInstance.add(markerInstance);
 
-    mapInstance.on('click', (e: any) => {
+    // 点击地图事件 - 更新坐标并获取地址
+    mapInstance.on('click', async (e: any) => {
       const lng = e.lnglat.getLng();
       const lat = e.lnglat.getLat();
 
@@ -793,18 +793,144 @@ const initMap = async () => {
       selectedCoordinate.value = `纬度: ${lat.toFixed(6)}, 经度: ${lng.toFixed(6)} (GCJ-02)`;
       form.value.latitude = lat;
       form.value.longitude = lng;
+
+      // 使用 OpenCageData API 获取中文地址(需要将 GCJ-02 转换为 WGS-84)
+      await setSelectedLocationWithConversion(lat, lng);
     });
 
     if (hasCoordinates) {
       const lat = Number(form.value.latitude || markerPos[1]);
       const lng = Number(form.value.longitude || markerPos[0]);
       selectedCoordinate.value = `纬度: ${lat.toFixed(6)}, 经度: ${lng.toFixed(6)} (GCJ-02)`;
+
+      // 如果编辑模式且已有地址,不需要重新获取
+      if (!form.value.address) {
+        // 如果是新增模式或地址为空,尝试获取地址
+        await setSelectedLocationWithConversion(lat, lng);
+      }
     }
   } catch (error) {
     console.error('地图初始化失败:', error);
     proxy?.$modal.msgError('地图加载失败');
   }
 };
+
+/**
+ * 使用 OpenCageData API 获取地址(GCJ-02 → WGS-84 转换)
+ */
+const setSelectedLocationWithConversion = async (gcjLat: number, gcjLon: number) => {
+  const coordsText = `纬度:${gcjLat.toFixed(6)}, 经度:${gcjLon.toFixed(6)}`;
+
+  try {
+    // 关键步骤:将 GCJ-02 转换为 WGS-84
+    const wgs84Coords = convertGcj02ToWgs84(gcjLat, gcjLon);
+
+    console.log('坐标转换:', {
+      '原始GCJ-02': `${gcjLat}, ${gcjLon}`,
+      '转换WGS-84': `${wgs84Coords.lat}, ${wgs84Coords.lng}`
+    });
+
+    // 使用 WGS-84 坐标调用 OpenCageData API
+    const response = await fetch(
+      `https://api.opencagedata.com/geocode/v1/json?q=${wgs84Coords.lat}+${wgs84Coords.lng}&key=82827937f9614a6eb17c772efa63d75d&language=zh&no_annotations=1`
+    );
+
+    if (response.ok) {
+      const data = await response.json();
+      if (data && data.results && data.results.length > 0) {
+        const address = data.results[0].formatted;
+        // 清理地址格式:移除开头的邮编和逗号
+        const cleanedAddress = cleanChineseAddress(address);
+
+        // 将地址填充到表单中(注意:数据库中仍然存储 GCJ-02 坐标)
+        form.value.address = cleanedAddress;
+
+        console.log('详细地址:', cleanedAddress);
+        proxy?.$modal.msgSuccess(`已获取地址:${cleanedAddress}`);
+      } else {
+        form.value.address = coordsText;
+        proxy?.$modal.msgWarning('未能获取详细地址,请手动输入');
+      }
+    } else {
+      form.value.address = coordsText;
+      proxy?.$modal.msgWarning('地址解析服务异常,请手动输入');
+    }
+  } catch (error) {
+    console.error('地址解析失败:', error);
+    form.value.address = coordsText;
+    proxy?.$modal.msgWarning('地址解析失败,请手动输入');
+  }
+};
+
+/**
+ * GCJ-02 → WGS-84(前端简易版)
+ */
+const convertGcj02ToWgs84 = (gcjLat: number, gcjLon: number): { lat: number; lng: number } => {
+  const PI = 3.1415926535897932384626;
+  const A = 6378245.0;
+  const EE = 0.00669342162296594323;
+
+  const outOfChina = (lat: number, lon: number): boolean => {
+    return lon < 72.004 || lon > 137.8347 || lat < 0.8293 || lat > 55.8271;
+  };
+
+  const transformLat = (x: number, y: number): number => {
+    let 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.0 * Math.sin((y * PI) / 30.0)) * 2.0) / 3.0;
+    return ret;
+  };
+
+  const transformLon = (x: number, y: number): number => {
+    let 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;
+  };
+
+  if (outOfChina(gcjLat, gcjLon)) {
+    return { lat: gcjLat, lng: gcjLon };
+  }
+
+  let dLat = transformLat(gcjLon - 105.0, gcjLat - 35.0);
+  let dLon = transformLon(gcjLon - 105.0, gcjLat - 35.0);
+  const radLat = (gcjLat / 180.0) * PI;
+  let magic = Math.sin(radLat);
+  magic = 1 - EE * magic * magic;
+  const sqrtMagic = Math.sqrt(magic);
+  dLat = (dLat * 180.0) / (((A * (1 - EE)) / (magic * sqrtMagic)) * PI);
+  dLon = (dLon * 180.0) / ((A / sqrtMagic) * Math.cos(radLat) * PI);
+
+  return {
+    lat: gcjLat - dLat, // 注意:这里是减法,与 WGS→GCJ 相反
+    lng: gcjLon - dLon
+  };
+};
+
+/**
+ * 清理中文地址格式
+ */
+const cleanChineseAddress = (address: string): string => {
+  if (!address) return address;
+
+  // 移除开头的邮编(如 "410000 湖南省..." → "湖南省...")
+  let cleaned = address.replace(/^\d{5,}\s*/, '');
+
+  // 处理重复的省市名称(如:湖南省长沙市长沙市 → 湖南省长沙市)
+  cleaned = cleaned.replace(/([\u4e00-\u9fa5]+市)\1/g, '$1');
+
+  // 移除多余的逗号、空格
+  cleaned = cleaned.replace(/[,,\s]+/g, '').replace(/\s+/g, '');
+
+  // 移除 "中国" 前缀(OpenCageData 通常会包含)
+  cleaned = cleaned.replace(/^中国/, '');
+
+  return cleaned;
+};
+
+// ... existing code ...
 // WGS-84转GCJ-02(前端简易版)
 const convertWgs84ToGcj02 = (wgsLat: number, wgsLon: number): { lat: number; lng: number } => {
   const PI = 3.1415926535897932384626;