Переглянути джерело

feat: 获取最近服务区逻辑

szr190 1 місяць тому
батько
коміт
8468387de6
4 змінених файлів з 207 додано та 16 видалено
  1. 58 9
      src/components/HySelect.vue
  2. 7 0
      src/pages.json
  3. 10 7
      src/pages/index.vue
  4. 132 0
      src/pages/location.vue

+ 58 - 9
src/components/HySelect.vue

@@ -54,6 +54,42 @@ const selectedOptionText = computed(() => {
54 54
   return selected ? selected.name : ''
55 55
 })
56 56
 
57
+// 计算两点之间的距离(使用Haversine公式)
58
+const calculateDistance = (lat1: any, lon1: any, lat2: any, lon2: any) => {
59
+  const R = 6371 // 地球半径(公里)
60
+  const dLat = ((lat2 - lat1) * Math.PI) / 180
61
+  const dLon = ((lon2 - lon1) * Math.PI) / 180
62
+  const a =
63
+    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
64
+    Math.cos((lat1 * Math.PI) / 180) * Math.cos((lat2 * Math.PI) / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2)
65
+  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
66
+  return R * c
67
+}
68
+
69
+// 根据当前位置匹配最近的服务区
70
+const findNearestParking = (currentPos: any, parkList: any) => {
71
+  if (!currentPos || !parkList || parkList.length === 0) {
72
+    return null
73
+  }
74
+
75
+  let nearestPark = null
76
+  let minDistance = Infinity
77
+
78
+  for (const park of parkList) {
79
+    const distance = calculateDistance(currentPos.latitude, currentPos.longitude, Number(park.latitude), Number(park.longitude))
80
+
81
+    if (distance < minDistance) {
82
+      minDistance = distance
83
+      nearestPark = {
84
+        ...park,
85
+        distance: distance.toFixed(2) // 保留两位小数
86
+      }
87
+    }
88
+  }
89
+
90
+  return nearestPark
91
+}
92
+
57 93
 // 获取全部园区楼宇
58 94
 const getParkWeb = async () => {
59 95
   const res = await getParkWebAPI()
@@ -62,15 +98,28 @@ const getParkWeb = async () => {
62 98
 
63 99
     // 当数据加载完成且没有选中值时,默认选择第一项
64 100
     if (parkList.value.length > 0 && !selectedValue.value) {
65
-      const firstItem = parkList.value[0]
66
-      selectedValue.value = firstItem.id
67
-
68
-      // 存储到本地缓存
69
-      uni.setStorageSync('parkId', firstItem.id)
70
-
71
-      // 触发事件通知父组件
72
-      emit('update:modelValue', firstItem.id)
73
-      emit('change', firstItem)
101
+      uni.getLocation({
102
+        type: 'wgs84',
103
+        success: (res: any) => {
104
+          const position = {
105
+            longitude: res.longitude,
106
+            latitude: res.latitude
107
+          }
108
+          const nearestPark = findNearestParking(position, parkList.value)
109
+          if (nearestPark) {
110
+            selectedValue.value = nearestPark.id
111
+          } else {
112
+            const firstItem = parkList.value[0]
113
+            selectedValue.value = firstItem.id
114
+          }
115
+          // 存储到本地缓存
116
+          uni.setStorageSync('parkId', selectedValue.value)
117
+
118
+          // 触发事件通知父组件
119
+          emit('update:modelValue', selectedValue.value)
120
+          emit('change', nearestPark || parkList.value[0])
121
+        }
122
+      })
74 123
     }
75 124
   }
76 125
 }

+ 7 - 0
src/pages.json

@@ -44,6 +44,13 @@
44 44
         "navigationBarTitleText": "设备信息",
45 45
         "enablePullDownRefresh": false
46 46
       }
47
+    },
48
+    {
49
+      "path": "pages/location",
50
+      "style": {
51
+        "navigationBarTitleText": "定位",
52
+        "enablePullDownRefresh": false
53
+      }
47 54
     }
48 55
   ],
49 56
   "subPackages": [

+ 10 - 7
src/pages/index.vue

@@ -67,11 +67,11 @@ onLoad((options) => {
67 67
     })
68 68
   }
69 69
   // 页面加载时从本地缓存获取园区ID
70
-  const cachedParkId = uni.getStorageSync('parkId')
71
-  if (cachedParkId) {
72
-    selectedValue.value = cachedParkId
73
-    params.value.parkId = cachedParkId
74
-  }
70
+  // const cachedParkId = uni.getStorageSync('parkId')
71
+  // if (cachedParkId) {
72
+  //   selectedValue.value = cachedParkId
73
+  //   params.value.parkId = cachedParkId
74
+  // }
75 75
 })
76 76
 
77 77
 const init = () => {
@@ -102,8 +102,11 @@ const handleParkChange = () => {
102 102
 }
103 103
 
104 104
 onShow(() => {
105
-  // 初始化数据
106
-  init()
105
+  if (selectedValue.value) {
106
+    params.value.parkId = selectedValue.value
107
+    // 初始化数据
108
+    init()
109
+  }
107 110
 })
108 111
 
109 112
 // 获取banner数据

+ 132 - 0
src/pages/location.vue

@@ -0,0 +1,132 @@
1
+<template>
2
+  <view>
3
+    <!-- H5定位必须运行在HTTPS协议下(开发环境localhost除外) -->
4
+    <button @click="getLocation">获取当前位置</button>
5
+    <view v-if="position">经度: {{ position.longitude }}, 纬度: {{ position.latitude }}</view>
6
+    <view v-if="error">{{ error }}</view>
7
+
8
+    <button @click="getLocationUni">获取位置</button>
9
+  </view>
10
+</template>
11
+
12
+<script>
13
+export default {
14
+  data() {
15
+    return {
16
+      position: null,
17
+      error: null,
18
+      parkList: [
19
+        {
20
+          name: '停车场1',
21
+          longitude: 120.312786,
22
+          latitude: 36.064812
23
+        },
24
+        {
25
+          name: '停车场2',
26
+          longitude: 120.426597,
27
+          latitude: 36.242712
28
+        },
29
+        {
30
+          name: '停车场3',
31
+          longitude: 120.095783,
32
+          latitude: 36.359697
33
+        }
34
+      ]
35
+    }
36
+  },
37
+  methods: {
38
+    // 计算两点之间的距离(使用Haversine公式)
39
+    calculateDistance(lat1, lon1, lat2, lon2) {
40
+      const R = 6371 // 地球半径(公里)
41
+      const dLat = ((lat2 - lat1) * Math.PI) / 180
42
+      const dLon = ((lon2 - lon1) * Math.PI) / 180
43
+      const a =
44
+        Math.sin(dLat / 2) * Math.sin(dLat / 2) +
45
+        Math.cos((lat1 * Math.PI) / 180) * Math.cos((lat2 * Math.PI) / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2)
46
+      const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
47
+      return R * c
48
+    },
49
+
50
+    // 根据当前位置匹配最近的停车场
51
+    findNearestParking(currentPos, parkList) {
52
+      if (!currentPos || !parkList || parkList.length === 0) {
53
+        return null
54
+      }
55
+
56
+      let nearestPark = null
57
+      let minDistance = Infinity
58
+
59
+      for (const park of parkList) {
60
+        const distance = this.calculateDistance(currentPos.latitude, currentPos.longitude, park.latitude, park.longitude)
61
+
62
+        if (distance < minDistance) {
63
+          minDistance = distance
64
+          nearestPark = {
65
+            ...park,
66
+            distance: distance.toFixed(2) // 保留两位小数
67
+          }
68
+        }
69
+      }
70
+
71
+      return nearestPark
72
+    },
73
+
74
+    getLocationUni() {
75
+      uni.getLocation({
76
+        type: 'wgs84',
77
+        success: (res) => {
78
+          this.position = {
79
+            longitude: res.longitude,
80
+            latitude: res.latitude
81
+          }
82
+          console.log('🚀 ~ this.position:', this.position)
83
+          // 找到最近的停车场
84
+          const nearestPark = this.findNearestParking(this.position, this.parkList)
85
+          console.log('最近的停车场:', nearestPark)
86
+        },
87
+        fail: (err) => {
88
+          this.error = err.errMsg
89
+        }
90
+      })
91
+    },
92
+
93
+    getLocation() {
94
+      if (navigator.geolocation) {
95
+        navigator.geolocation.getCurrentPosition(
96
+          (pos) => {
97
+            this.position = {
98
+              longitude: pos.coords.longitude,
99
+              latitude: pos.coords.latitude
100
+            }
101
+            // 找到最近的停车场
102
+            const nearestPark = this.findNearestParking(this.position)
103
+            console.log('最近的停车场:', nearestPark)
104
+          },
105
+          (err) => {
106
+            switch (err.code) {
107
+              case err.PERMISSION_DENIED:
108
+                this.error = '用户拒绝了定位请求'
109
+                break
110
+              case err.POSITION_UNAVAILABLE:
111
+                this.error = '位置信息不可用'
112
+                break
113
+              case err.TIMEOUT:
114
+                this.error = '请求超时'
115
+                break
116
+              default:
117
+                this.error = '未知错误'
118
+            }
119
+          },
120
+          {
121
+            enableHighAccuracy: true, // 高精度模式
122
+            timeout: 10000, // 超时时间10秒
123
+            maximumAge: 0 // 不使用缓存位置
124
+          }
125
+        )
126
+      } else {
127
+        this.error = '您的浏览器不支持地理定位'
128
+      }
129
+    }
130
+  }
131
+}
132
+</script>