web
2025-07-03 8e5fb21a2bf621291c1ceee396c01e3d42553511
pages/device/index.vue
@@ -1,33 +1,223 @@
<template>
   <view class="device">
      <Navbar title="设备列表"></Navbar>
      <view class="content">
         <view class="list">
            <block v-for="(item,index) in facitilyList" :key="index">
               <view class="item">
                  <view class="item-img">
                     <image v-if="item.facilityUrl" :src="BASE_URL + '/upload' + item.facilityUrl" alt='' mode="aspectFit"></image>
                     <image v-else src="../../static/images/facilityImg.svg" alt='' mode="aspectFit"></image>
                  </view>
                  <view class="item-info">
                     <view class="info-name">
                        <view class="name">{{item.facilityName}}</view>
                        <view class="btn" @click="handleQushui(item.id)">取水</view>
                     </view>
                     <view class="info-addr" @click="openMap(item.lat,item.lon)">
                        <text class="addr-text">地址:{{item.address}}</text>
                        <view>
                           <image src="../../static/images/icon-point.svg" alt=''></image>
                           <text>{{item.distanceValue}}km</text>
                        </view>
                     </view>
                  </view>
               </view>
            </block>
         </view>
      </view>
      <uni-popup ref="qushuiDialog" type="dialog">
         <uni-popup-dialog type="info" cancelText="取消" confirmText="确认" title="请输入取水量"
            @confirm="dialogConfirm"
            @close="dialogClose"
         >
            <view>
               <input v-model="qushuiNum" placeholder="请输入取水量(L)" />
            </view>
         </uni-popup-dialog>
      </uni-popup>
   </view>
</template>
<script setup>
   import{ ref, onMounted } from 'vue'
   import Navbar from '../../components/navbar/navbar.vue'
   import { getFacitily } from '@/api/index.js'
   import { BASE_URL } from '../../config/index.js'
   
   const userLocation = ref()
   const facitilyList = ref([])
   const qushuiDialog = ref()
   const facitilyId = ref()
   const qushuiNum = ref()
   
   const getFacitilyList = () => {
      const data = {
         longitude: userLocation.value?.lon,
         latitude: userLocation.value?.lat,
         limit: 100,
         page: 1
      }
      getFacitily(data).then(res => {
         if(res.code === 200) {
            facitilyList.value = res.data.list
         }
      })
   }
   
   // 根据经纬度计算距离,根据经纬度计算距离,参数分别为第一点的纬度,经度(用户);第二点的纬度,经度(设备)
   const getDistances = (lat1, lon1, lat2, lon2) => {
      let EARTH_RADIUS = 6378.137;// 地球半径
      let radLat1 = lat1 * Math.PI / 180.0; //lat1 * Math.PI / 180.0=>弧度计算
      let radLat2 = lat2 * Math.PI / 180.0;
      let a = radLat1 - radLat2;
      let b = lon1 * Math.PI / 180.0 - lon2 * Math.PI / 180.0;
      let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
      s = s * EARTH_RADIUS;
      s = Math.round(s * 10000) / 10000;// 输出为公里
      return { m: s * 1000, km: Number(s.toFixed(2)) }
   // 取水
   const handleQushui = (id) => {
      facitilyId.value = id
      qushuiDialog.value.open()
   }
   // 取消
   const dialogClose = () => {
      facitilyId.value = ''
      qushuiNum.value = ''
   }
   // 确认
   const dialogConfirm = () => {
   }
   //打开地图导航
   const openMap = (lat,lon) => {
      uni.openLocation({
         latitude: parseFloat(lat),
         longitude: parseFloat(lon),
         scale:18
      })
   }
   //获取用户位置并存储
   const storageLocation = () => {
      uni.getLocation({
         type:'gcj02',
         isHighAccuracy:true,
         success:(res) =>{
            userLocation.value = {
               lat: res.latitude,
               lon: res.longitude
            }
            uni.setStorageSync('userLocation',JSON.stringify(userLocation.value))
         },
         fail:(err) =>{
            locationToast()
         }
      })
   }
   //用户拒绝授权
   const locationToast = () => {
      uni.showModal({
         title: "请求授权当前位置",
         content: "请求获取您的位置,加载附近饮水设备信息!",
         confirmText: "前往设置",
         success: (res) => {
            if (res.confirm) {
               uni.openSetting({
                   success:(res1) =>{ //打开设置成功
                     if (res1.authSetting['scope.userLocation']){
                        setTimeout(() =>{
                           storageLocation()
                        },1000)
                     }
                  },
               })
            }else{
               uni.showToast({
                  title: '请先授权!',
                  duration: 2000,
                  icon:'none'
               });
            }
         },
      });
   }
   
   onMounted(() => {
      userLocation.value = JSON.parse(uni.getStorageSync('userLocation'))
      const location = uni.getStorageSync('userLocation')
      if(location) {
         userLocation.value = JSON.parse(location)
         getFacitilyList()
      }else{
         locationToast()
      }
   })
</script>
<style lang="scss" scoped>
   .content{
      width: 100%;
      height:calc(100vh - 176rpx);
      background:linear-gradient(to top,#FFFFFF,#E8EFFF);
      padding:32rpx 32rpx 100rpx;
      box-sizing: border-box;
      .list{
         width:100%;
         height:100%;
         overflow: scroll;
         // background-color: #f1ffef;
         .item{
            height:200rpx;
            width:100%;
            background-color: #FFFFFF;
            border-radius: 24rpx;
            padding:0 20rpx;
            margin-bottom:20rpx;
            box-sizing: border-box;
            display: flex;
            align-items:center;
            .item-img{
               image{
                  width:130rpx;
                  height: 130rpx;
               }
            }
            .item-info{
               display: flex;
               flex-direction: column;
               margin-left:20rpx;
               justify-content: space-between;
               .info-name{
                  color:#222c35;
                  display: flex;
                  justify-content: space-between;
                  align-items: center;
                  .btn{
                     padding: 10rpx 20rpx;
                     background-color: $uni-primary;
                     border-radius: 10rpx;
                     color: #fff;
                  }
               }
               .info-addr{
                  display: flex;
                  justify-content: space-between;
                  align-items:center;
                  .addr-text{
                     width:340rpx;
                     height:80rpx;
                     color: #6a6e75;
                     font-size:26rpx;
                  }
                  view{
                     display: flex;
                     justify-content: space-between;
                     align-items:center;
                     image{
                        width:50rpx;
                        height:50rpx;
                     }
                     text{
                        color: #6a6e75;
                        font-size:26rpx;
                     }
                  }
               }
            }
         }
      }
   }
</style>