select-address.vue 10.4 KB
<template>
  <Page name="select-address">
    <template #header>
      <u-search @change="onSearch" :show-action="false" shape="round" :clearabled="true" v-model="query" placeholder="请输入搜索关键字" />
      <view class="page-select-address__toolbar">
        <u-grid align="center" :col="2">
          <u-grid-item @click="getCurrentLocation">
            <view class="grid-item">
              <u-icon name="map-fill" />
              <text>定位</text>
            </view>
          </u-grid-item>
          <u-grid-item @click="openSelectAddressMap">
            <view class="grid-item">
              <u-icon name="pushpin-fill" />
              <text>地图</text>
            </view>
          </u-grid-item>
        </u-grid>
      </view>
    </template>
    <template #content>
      <view class="page-select-address__title">当前位置</view>
      <view class="location">
        <u-cell @click="selectLocation(currentLocation)">
          <template #title>
            <view v-if="locating">定位中...</view>
            <template v-else>
              <template v-if="currentLocation.address"><u-icon name="map-fill" />{{ currentLocation.address }}</template>
              <template v-else><u-icon name="warning-fill" />定位失败,请将GPS设置为开启状态</template>
            </template>
          </template>
        </u-cell>
      </view>
      <template v-if="list.length === 0">
        <template v-if="addressList.length > 0">
          <view class="page-select-address__title">常用地址</view>
          <template v-for="(item, index) in addressList">
            <u-cell :key="index" :label="item | historyLabel" @click="selectAddress(item)" >
              <view slot="title" class="u-slot-title">
                <text class="u-cell-text">{{ item | historyTitle }}</text>
                <view class="tag" v-if="item.defaultFlag">
                  <u-tag text="默认" type="error" plain></u-tag>
                </view>
              </view>
            </u-cell>
          </template>
        </template>
        <template v-if="historyList.length > 0">
          <view class="page-select-address__title">搜索历史</view>
          <template v-for="(item, index) in historyList">
            <u-cell :key="index" :title="item | historyTitle" :label="item | historyLabel" @click="selectHistory(item)" />
          </template>
        </template>
      </template>
      <template v-else>
        <view class="page-select-address__title">查询结果</view>
        <template v-for="(item, index) in list">
          <u-cell :key="index" :title="item.name" :label="`${item.cityname}${item.adname}${item.address}`" @click="selectLocation(item)" />
        </template>
      </template>
    </template>
  </Page>
</template>

<script>
export default {
  data() {
    return {
      query: '',
      list: [],
      addressList: [],
      historyList: [],
      currentLocation: {},
      locating: false,
    }
  },
  filters: {
    historyLabel(item) {
      const { cityName, areaName, address } = item || {};
      const addressArr = address.split('|');
      return `${cityName}${areaName}${addressArr[0]}`;
    },
    historyTitle(item) {
      const { address } = item || {};
      const addressArr = address.split('|');
      return addressArr[1] || addressArr[0];
    },
  },
  onLoad(option) {
    this.loadData();
    this.getCurrentLocation();
  },
  onUnload() {
    uni.$off('select-address');
  },
  methods: {
    async loadData() {
      if (this.$params.type !== 'address') {
        await uni.$u.api.address.page({ pageSize: 10 }).then(response => (this.addressList = response.result || []));
        await uni.$u.api.addressHistory.page({ pageSize: 10 }).then(response => (this.historyList = response.result || []));
      }
    },
    // 打开地图选点
    openSelectAddressMap() {
      uni.$once('webview-message', e => {
        let selected = {};
        // #ifdef MP-DINGTALK
        if (e.type === 'back') uni.navigateBack(); 
        selected = e || {};
        // #endif
        // #ifndef MP-DINGTALK
        selected = e.find(i => i.type === 'select') || {};
        // #endif
        const addressInfo = selected.data || {};
        uni.$emit('select-address', addressInfo);
        uni.navigateBack();
      });
      uni.$u.route({
        url: '/pages/common/webview',
        params: {
          // #ifdef MP-DINGTALK
          url: 'https://zeyi-tms-product.oss-cn-hangzhou.aliyuncs.com/webview/location-dd.html',
          // #endif
          // #ifndef MP-DINGTALK
          url: 'https://zeyi-tms-product.oss-cn-hangzhou.aliyuncs.com/webview/location-wx.html',
          // #endif
          query: JSON.stringify({ auto: false })
        },
      });
    },
    // 查询当前定位
    getCurrentLocation() {
      this.locating = true;
      uni.getLocation({
        // #ifdef MP-WEIXIN
        type: 'gcj02',
        isHighAccuracy: true,
        // #endif
        success: (res) => {
          uni.request({
            url: 'https://restapi.amap.com/v3/geocode/regeo', //逆地理编码接口地址。
            data: {
              key: '1b987a62e5685a58cda5933e1bc66044',
              location: res.longitude + ',' + res.latitude,
            },
            success: (response) => {
              const regeocode = response?.data?.regeocode || {};
              const addressComponent = regeocode?.addressComponent || {};
              const addressInfo = this.getAddress(response?.data);
              this.currentLocation = {
                pcode: addressComponent.pcode,
                pname: addressComponent.pname,
                adcode: addressComponent.adcode,
                adname: addressComponent.district,
                cityname: (!addressComponent.city || addressComponent.city.length === 0 ) ? addressComponent.province : addressComponent.city,
                address: addressInfo.address,
                location: [res.longitude, res.latitude].join(','),
              };
            }
          });
        },
        complete: () => {
          this.locating = false;
        }
      });
    },
    // 格式化地址
    getAddress(geo) {
      const { regeocode = {} } = geo || {};
      const { addressComponent = {} } = regeocode || {};
      const { province, city, district, township, streetNumber } = addressComponent || {};
      const { street, number } = streetNumber || {};
      const formattedAddress = regeocode.formatted_address || regeocode.formattedAddress || '';
      let amapAddress = formattedAddress.replace(province, '');
      amapAddress = amapAddress.replace(city, '');
      amapAddress = amapAddress.replace(district, '');
      amapAddress = amapAddress.replace(township, '');
      amapAddress = amapAddress.replace(street, '');
      amapAddress = amapAddress.replace(number, '');
      return {
        formattedAddress,
        fullAddress: `${province}${city}${district}${township}${street}${number}`,
        address: `${township}${street}${number}${amapAddress}`,
        amapAddress,
        adcode: addressComponent.adcode,
        township,
      };
    },
    selectAddress(item) {
      this.selectHistory(item, 'address');
    },
    selectHistory(item, trigger) {
      let address = item.address.replace(item.provinceName, '');
      address = address.replace(item.cityName, '');
      address = address.replace(item.areaName, '');
      let amapWaypoint = {
        pcode: item.provinceCode,
        pname: item.provinceName,
        adcode: item.areaCode,
        cityname: item.cityName,
        adname: item.areaName,
        address,
        location: [item.lng, item.lat].join(','),
      };
      if (trigger === 'address') {
        amapWaypoint.contactName = item.name;
        amapWaypoint.contactMobile = item.mobile;
      }
      this.selectLocation(amapWaypoint, trigger || 'history');
    },
    selectLocation(item, trigger) {
      if (!item.location) {
        return;
      }
      const lnglatArr = item.location.split(',');
      let waypoint = {
        areaCode: item.adcode,
        areaName: item.adname,
        cityCode: `${item.adcode}`.substring(0, 4) + '00',
        cityName: item.cityname,
        provinceCode: item.pcode,
        provinceName: item.pname,
        address: item.adname === item.address && item.name ? item.name : item.address || item.name,
        lng: lnglatArr[0],
        lat: lnglatArr[1],
      };
      if (`${waypoint.lat}` === '0' && `${waypoint.lng}` === '0') {
        return;
      }
      if (trigger === 'address') {
        waypoint.contactName = item.contactName;
        waypoint.contactMobile = item.contactMobile;
      }
      uni.$emit('select-address', waypoint);
      if (trigger === 'address' || this.$params.type === 'address') {
        uni.navigateBack();
      } else {
        uni.$u.api.addressHistory.add(waypoint).finally(() => {
          uni.navigateBack();
        });
      }
    },
    // 搜索
    onSearch() {
      uni.$u.debounce(this.doSearch, 500);
    },
    // 执行搜索
    doSearch() {
      let params = {
        key: '1b987a62e5685a58cda5933e1bc66044',
        keywords: this.query,
      };
      uni.request({
        url: `https://restapi.amap.com/v5/place/text`,
        method: 'GET',
        data: params,
        success: response => {
          this.list = response?.data?.pois || [];
        }
      });
    },
  }
}
</script>

<style lang="scss">
.page-select-address {
  &__header {
    padding: 0 !important;
    .u-search {
      padding: $padding-md;
      padding-bottom: 0;
    }
  }
  &__toolbar {
    .u-grid {
      border-bottom: 1px solid $color-border;
    }
    .grid-item {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100%;
      padding: $padding-sm $padding-md;
      color: $color-text-minor;
      .u-icon {
        margin-right: $padding-md;
      }
    }
  }
  &__title {
    padding: $padding-sm $padding-md;
    font-weight: bold;
  }
  .location {
    .u-icon {
      display: inline-flex;
      color: $color-text;
    }
  }
  .u-cell {
    background-color: $color-white;
    &__title-text {
      font-size: $font-md !important;
    }
    &__body {
      padding: $padding-xs $padding-md !important;
    }
    &__label {
      margin-top: 0 !important;
      font-size: $font-sm !important;
    }
    .tag {
      display: inline-block;
    	margin-left: $padding-base;
      .u-tag {
        height: $padding-md;
        padding: 0 $padding-base;
        line-height: 1;
        &__text {
          font-size: $font-sm !important;
        }
      }
    }
  }
}
</style>