java-mall-app/address/selectShippingAddress.vue
2025-09-29 19:59:57 +08:00

898 lines
24 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="address-container">
<view class="hander">
<uni-nav-bar
title=""
:fixed="true"
:statusBar="false"
:border="false"
:left-width="'132rpx'"
:right-width="'0rpx'"
>
<block slot="left">
<view class="left-block" @click="handerSkip">
<text class="iconfontAili icon-dingwei1"></text>
<text class="city-block">{{
originalData.result.addressComponent.city
}}</text>
<text class="iconfontAili icon-xiala"></text>
</view>
</block>
<view class="input-view">
<uni-icons
type="search"
size="22"
color="#666666"
style="line-height: 60rpx"
/>
<input
confirm-type="search"
class="input"
type="text"
placeholder="请输入收货地址"
@click="onSearch"
@input="handerAddress"
/>
</view>
</uni-nav-bar>
</view>
<scroll-view
v-if="!showSearchAddress"
class="uni-swiper-list"
scroll-y
@scroll="onScroll"
scroll-with-animation="true"
:scroll-top="scrollTop"
>
<view class="address-block">
<view class="address-box">
<view class="address-left-block">{{
originalData.result.sematic_description
}}</view>
<view class="address-right-block" @click="anewLoction">
<text class="iconfontAili icon-zhongxindingwei"></text>
<view style="padding-left: 8rpx">重新定位</view>
</view>
</view>
</view>
<view
class="list-block"
v-if="userInfo.token && formatAddreesList.length > 0"
>
<view class="list-title-block">
<text class="iconfontAili icon-dianpu"></text>
<text class="title-block">我的收货地址</text>
</view>
<view
class="list-item"
v-for="(item, index) of formatAddreesList"
:key="index"
@click="handerSetAddress(item, 'my')"
>
<view class="item-info">
<text
:class="['item-lable', lableCalss(item.ud_label)]"
v-if="
item.ud_label == 1 || item.ud_label == 2 || item.ud_label == 3
"
>{{ labelList[item.ud_label] }}</text
>
<text class="item-address">{{ item.ud_marker }}</text>
<text class="item-detailed-address">{{ item.ud_street_no }}</text>
</view>
<view class="item-role-info">
<text class="item-name">{{ item.ud_name }}</text>
<text class="item-sex">{{ item.sex == 0 ? "先生" : "女士" }}</text>
<text class="item-mobile">{{ item.ud_mobile }}</text>
</view>
</view>
<view
class="tips"
@click="handerList"
v-if="formatAddreesList.length > 4"
>
{{ showFormatAddreesList ? "收起全部地址" : "展开更多地址" }}
<text
:class="[
'iconfontAili ',
showFormatAddreesList ? 'icon-top' : 'icon-xiala',
]"
></text>
</view>
</view>
<view class="list-block">
<view class="list-title-block">
<text class="iconfontAili icon-dingwei1"></text>
<text class="title-block">附近地址</text>
</view>
<view
class="list-item"
v-for="(item, index) of nearbyAddressList"
:key="index"
>
<view class="item-info" @click="handerSetAddress(item)">
<text class="item-address">{{ item.name }}</text>
</view>
</view>
</view>
<uMask :show="showMask" :zIndex="2" @click="showMask = false"></uMask>
</scroll-view>
<scroll-view
v-if="showSearchAddress && searchAddress.length > 0"
class="uni-swiper-list"
scroll-y
@scroll="onScroll"
scroll-with-animation="true"
:scroll-top="scrollTop"
>
<view class="search-address-list">
<view
class="search-address-item"
v-for="(item, index) of searchAddress"
:key="index"
>
<view
class="search-address-item-left"
@click="handerSetAddress(item)"
>
<view class="item-left-name" v-html="item.searchName"></view>
<view class="item-left-address">{{
item.detailedInformation
}}</view>
</view>
<view class="search-address-item-right">{{ item.distance }}km</view>
</view>
</view>
</scroll-view>
<view class="u-btn u-btn-default" @click="AddAddress">
<text class="iconfontAili icon-zengjiatianjiajiahao"></text>
<text>新增收货地址</text>
</view>
<loginPopup :show="showLoginPopup" @close="closeLoginPopup"></loginPopup>
</view>
</template>
<script>
import uMask from "./umask.vue";
import BMapLib from "../helpers/GeoUtils.js";
import { mapState, mapMutations } from "vuex";
import loginPopup from "@/components/loginPopup.vue";
var bmap = require("../libs/bmap-wx.js");
export default {
components: {
uMask,
loginPopup,
},
data() {
return {
scrollTop: 0,
showMask: false,
originalData: {
result: {
addressComponent: {
city: "正在定位",
},
sematic_description: "定位中..",
},
},
addressList: [],
formatAddreesList: [],
showFormatAddreesList: false,
nearbyAddressList: [],
showSearchAddress: false,
time: 0,
searchAddress: [],
labelList: ["", "家", "公司", "学校"],
options: {},
showLoginPopup: false,
};
},
computed: mapState([
"Config",
"StateCode",
"notice",
"plantformInfo",
"shopInfo",
"userInfo",
"hasLogin",
]),
onLoad(options) {
console.log("options", options);
if (options && options.isShopList) {
this.options = options;
}
},
onShow() {
if (this.userInfo.token) {
this.getAddressList();
}
let city = uni.getStorageSync("city");
if (!city) {
this.isPhoneLocationEnabled();
} else {
this.originalData.result.addressComponent.city = city;
}
},
onUnload() {
uni.switchTab({
url: `/pages/index/index`,
});
uni.removeStorageSync("city");
},
methods: {
...mapMutations([
"login",
"logout",
"getPlantformInfo",
"forceUserInfo",
"getUserInfo",
"setCartNum",
]),
closeLoginPopup() {
this.showLoginPopup = false;
},
lableCalss(number) {
if (number == 1) {
return "item-lable-1";
}
if (number == 2) {
return "item-lable-2";
}
if (number == 3) {
return "item-lable-3";
}
},
getAddressList() {
let that = this;
that.$.request({
url: that.Config.URL.user.address_lists,
data: {},
success: function (data, status, msg, code) {
if (200 == status) {
if (data.items.length > 0) {
console.log(that.addressList);
that.addressList = data.items;
that.formatAddreesList = that.addressList.slice(0, 4);
} else {
that.setData({
isdata: false,
});
}
}
uni.stopPullDownRefresh();
},
});
},
AddAddress() {
if (!this.hasLogin) {
this.showLoginPopup = true;
return;
}
uni.navigateTo({
url: "/member/address/manage",
});
},
handerSetAddress(item, type) {
if (type == "my") {
let group = {
name: item.ud_marker,
location: {
lat: item.ud_latitude,
lng: item.ud_longitude,
},
...item,
};
uni.setStorageSync("currentAddress", group);
} else {
uni.setStorageSync("currentAddress", item);
}
if (this.options && this.options.isShopList) {
uni.navigateTo({
url: `/member/member/supermarketlList`,
});
} else {
uni.switchTab({
url: "/pages/index/index",
});
}
},
anewLoction() {
uni.removeStorageSync("currentAddress");
uni.switchTab({
url: "/pages/index/index",
});
},
isPhoneLocationEnabled() {
let _this = this;
// 获取用户手机系统信息
uni.getSystemInfo({
success: (res) => {
const locationEnabled = res.locationEnabled;
if (locationEnabled) {
// 手机GPS定位已开启则判断微信APP是否已获取访问定位信息的权限
_this.isAppAuthorized();
} else {
// 手机GPS定位未开启则引导用户手动前往开启
uni.showModal({
title: "提示",
content:
'小程序需要基于您的手机定位信息为您提供服务,当前检测到您的手机并未打开定位开关,请关闭小程序后前往 "设置 - 定位服务/位置信息" 开启手机定位,然后重新进入小程序~',
showCancel: false,
confirmText: "我已知悉",
});
}
},
fail: (err) => {
console.log("用户手机系统信息获取失败", err);
},
});
},
isAuthorized(a = "scope.userLocation") {
// 检查当前是否已经授权访问scope属性
let _this = this;
uni.getSetting({
success: (res) => {
let userLocation = res.authSetting[a];
if (!userLocation) {
// 判断当前是否获得授权,如果没有就去申请授权
_this.getAuthorize();
} else {
_this.getLocation();
}
},
fail: (err) => {
_this.openSetting();
},
});
},
isAppAuthorized() {
let _this = this;
// 微信APP授权设置
const appAuthorizeSetting = uni.getAppAuthorizeSetting();
// 是否允许微信使用定位信息的开关
let locationAuthorized = appAuthorizeSetting.locationAuthorized;
switch (locationAuthorized) {
case "authorized":
_this.isAuthorized();
break;
case "denied":
uni.showModal({
title: "提示",
content:
"已拒绝微信获取定位权限,即将打开权限管理页面,请把定位权限设置为允许~",
confirmText: "前往设置",
success: (res) => {
if (res.confirm) {
_this.openAppAuthorizeSetting();
} else if (res.cancel) {
_this.rejectGetLocation();
}
},
});
break;
case "not determined":
uni.showModal({
title: "提示",
content: "请授权微信获取定位权限~",
confirmText: "同意授权",
success: (res) => {
if (res.confirm) {
_this.openAppAuthorizeSetting();
} else if (res.cancel) {
_this.rejectGetLocation();
}
},
});
break;
}
},
getAuthorize(a = "scope.userLocation") {
let _this = this;
// uniapp弹窗弹出获取授权地理个人微信信息等授权信息弹窗
uni.authorize({
scope: a,
success: () => {
_this.getLocation();
},
fail: () => {
_this.openSetting();
},
});
},
openSetting() {
let _this = this;
uni.showModal({
title: "提示",
content: "我们需要获取您的位置信息,为您提供服务~",
success: (res) => {
if (res.confirm) {
uni.openSetting({
success: (res) => {
if (res.authSetting["scope.userLocation"] === true) {
_this.getLocation();
} else {
_this.rejectGetLocation();
}
},
fail: (err) => {
console.log("小程序授权弹窗打开失败", err);
},
});
} else if (res.cancel) {
_this.rejectGetLocation();
}
},
});
},
rejectGetLocation() {
uni.showToast({
title: "您拒绝了位置授权,小程序无法继续提供出行服务~",
icon: "none",
duration: 3000,
});
},
openAppAuthorizeSetting() {
let _this = this;
uni.openAppAuthorizeSetting({
success: (res) => {
console.log("打开系统微信授权管理页成功", res);
_this.isAuthorized();
},
fail: (err) => {
console.log("打开系统微信授权管理页失败", err);
},
});
},
getLocation() {
var that = this;
let location = "";
let currentAddress = uni.getStorageSync("currentAddress");
if (currentAddress) {
if (currentAddress.point) {
location = currentAddress.point.y + "," + currentAddress.point.x;
} else {
location =
currentAddress.location.lat + "," + currentAddress.location.lng;
}
let BMap = new bmap.BMapWX({
// ak: "LkqqCMB1qZmjYEkzx0Y1PTfmAUrkWPog",
ak: that.bdMapAk,
});
let fail = function (res) {
console.log("fail", res);
};
let success = function (res) {
console.log("结果地址", res);
that.originalData = res.originalData;
that.originalData.result.sematic_description = currentAddress.name;
let city = uni.getStorageSync("city");
if (city) {
that.originalData.result.addressComponent.city = city;
}
that.nearbyAddressList = res.originalData.result.pois;
};
BMap.regeocoding({
location: location,
coordtype: "gcj02ll",
ret_coordtype: "gcj02ll",
fail: fail,
success: success,
});
} else {
uni.getLocation({
type: "wgs84",
isHighAccuracy: true,
success: function (res) {
location = res.latitude + "," + res.longitude;
let BMap = new bmap.BMapWX({
// ak: "LkqqCMB1qZmjYEkzx0Y1PTfmAUrkWPog",
ak: that.bdMapAk,
});
let fail = function (res) {
console.log("fail", res);
};
let success = function (res) {
console.log("结果地址", res);
that.address = res.originalData.result.sematic_description;
that.originalData = res.originalData;
let city = uni.getStorageSync("city");
if (city) {
that.originalData.result.addressComponent.city = city;
}
that.nearbyAddressList = res.originalData.result.pois;
};
BMap.regeocoding({
location: location,
coordtype: "wgs84ll",
ret_coordtype: "gcj02ll",
fail: fail,
success: success,
});
},
fail: function (error) {
console.error("获取位置失败:", error);
},
});
}
},
handerSkip() {
uni.navigateTo({
url: `/address/selectCity`,
});
},
onSearch() {
this.showMask = true;
},
handerList() {
this.showFormatAddreesList = !this.showFormatAddreesList;
if (this.showFormatAddreesList) {
this.formatAddreesList = this.addressList;
} else {
this.formatAddreesList = this.addressList.slice(0, 4);
}
},
onScroll() {},
// 搜索地址
handerAddress(e) {
let that = this;
let value = e.target.value;
if (value.length == 0) {
this.showSearchAddress = false;
} else {
this.showSearchAddress = true;
}
var fail = function (res) {
console.log("fail", res);
};
var currentPoint = {
lat: that.originalData.result.location.lat,
lng: that.originalData.result.location.lng,
};
var metersToKilometers = function (meters) {
let kilometers = meters / 1000;
// 保留两位小数
return kilometers.toFixed(2);
};
var success = function (res) {
console.log("结果地址", res);
if (res.data.status != 0) {
uni.showToast({
title: res.message,
icon: "none",
duration: 3000,
});
return;
}
that.searchAddress = res.data.result
.filter((item) => "location" in item)
.map((item) => {
let obj = {
...item,
name: item.name,
detailedInformation: item.address.replace(/-/g, ""),
distance: metersToKilometers(
BMapLib.GeoUtils.getDistance(currentPoint, item.location)
),
};
return obj;
});
console.log("that.searchAddress", that.searchAddress);
that.searchAddress.forEach((item) => {
if (item.name.indexOf(value) >= 0) {
item.searchName = item.name.replaceAll(
value,
"<font style='color:#ee852f;padding:0 4px'>" + value + "</font>"
);
} else {
item.searchName = item.name;
}
});
console.log("searchAddress", that.searchAddress);
};
let params = {
query: value,
region: this.originalData.result.addressComponent.city,
output: "json",
city_limit: true,
ret_coordtype: "gcj02ll",
// ak: "qWKt2xbrqXsp2yK35YYXVBNZgrbiCG5v",
ak: that.bdMapAk,
};
let city = that.originalData.result.addressComponent.city;
if (city) {
params.center = "";
}
if (this.time !== null) {
clearTimeout(this.time);
}
this.time = setTimeout(() => {
uni.request({
url: `https://api.map.baidu.com/place/v2/suggestion`,
data: params,
success: success,
fail: fail,
});
}, 600);
},
},
};
</script>
<style lang="scss">
.address-container {
height: calc(100vh - 88rpx);
background: #fff;
overflow: hidden;
.item-lable-1 {
background: #fdf3da;
color: #de8a48;
}
.item-lable-2 {
background: #e5eefb;
color: #4687e4;
}
.item-lable-3 {
background: #eff9e7;
color: #6eb768;
}
.hander {
.uni-navbar__header {
align-items: center;
padding: 10rpx 20rpx !important;
}
.left-block {
display: flex;
align-items: center;
line-height: 60rpx;
}
.city-block {
white-space: nowrap; /* 确保文本在一行内显示 */
overflow: hidden; /* 隐藏超出容器的文本 */
text-overflow: ellipsis; /* 使用省略符号表示文本超出 */
max-width: 140rpx;
padding-right: 4rpx;
}
.icon-dingwei {
font-size: 40rpx;
}
.icon-right {
font-size: 24rpx;
}
}
.address-block {
margin: 20rpx 0;
padding: 20rpx 32rpx;
border-top: 2rpx solid #f0f0f0;
border-bottom: 2rpx solid #f0f0f0;
.address-box {
display: flex;
justify-content: space-between;
align-items: center;
.address-left-block {
font-size: 32rpx;
white-space: nowrap; /* 确保文本在一行内显示 */
overflow: hidden; /* 隐藏超出容器的文本 */
text-overflow: ellipsis; /* 使用省略符号表示文本超出 */
max-width: 520rpx;
}
.address-right-block {
display: flex;
align-items: center;
color: #de8a48;
}
}
}
.list-block {
padding: 0 32rpx;
border-bottom: 2rpx solid #f8f8f8;
.list-title-block {
position: sticky;
top: 0;
padding: 12rpx 0;
background: #fff;
.title-block {
font-size: 28rpx;
padding-left: 6rpx;
}
}
.list-item {
margin: 0 32rpx;
padding: 20rpx 0;
border-bottom: 2rpx solid #f0f0f0;
.item-lable {
display: inline-block;
margin-right: 9px;
padding: 0px 8px;
width: 32px;
border-radius: 4px;
text-align: center;
font-weight: 700;
}
.item-address {
margin-right: 8rpx;
font-weight: 700;
font-size: 30rpx;
}
.item-detailed-address {
font-weight: 700;
font-size: 30rpx;
}
.item-role-info {
color: #848484;
font-size: 24rpx;
.item-name {
padding-right: 20rpx;
}
.item-mobile {
margin-left: 40rpx;
}
}
}
.tips {
display: flex;
align-items: center;
margin: 20rpx 32rpx;
font-size: 24rpx;
}
}
.icon-zengjiatianjiajiahao {
font-size: 40rpx;
color: #3579ff;
margin-right: 12rpx;
}
.search-address-list {
margin: 40rpx;
.search-address-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 0;
border-bottom: 2rpx solid #f0f0f0;
.search-address-item-left {
width: 80%;
}
.search-address-item-right {
color: #d7d7d7;
width: 20%;
text-align: right;
}
rich-text {
// max-width: 90%;
max-height: 27px;
overflow: hidden;
word-break: break-all; /* break-all(允许在单词内换行) */
text-overflow: ellipsis; /* 超出部分省略号 */
display: -webkit-box; /** 对象作为伸缩盒子模型显示 **/
-webkit-box-orient: vertical; /** 设置或检索伸缩盒对象的子元素的排列方式 **/
-webkit-line-clamp: 2; /** 显示的行数 **/
}
// .item-left-name rich-text {
// white-space: nowrap; /* 确保文本在一行内显示 */
// overflow: hidden; /* 隐藏超出容器的文本 */
// text-overflow: ellipsis; /* 使用省略符号表示文本超出 */
// -webkit-box-orient: vertical;
// max-width: 90%;
// display: -webkit-box;
// box-sizing: border-box;
// }
.item-left-address {
font-size: 24rpx;
color: #848484;
white-space: nowrap; /* 确保文本在一行内显示 */
overflow: hidden; /* 隐藏超出容器的文本 */
text-overflow: ellipsis; /* 使用省略符号表示文本超出 */
max-width: 90%;
}
}
}
.input-view {
width: 92%;
display: flex;
background-color: #f5f5f5;
height: 60rpx;
border-radius: 30rpx;
padding: 0 4%;
flex-wrap: nowrap;
margin: 10rpx 0;
line-height: 60rpx;
margin-left: 10rpx;
color: #b9b9b9;
}
.input-view .uni-icon {
line-height: 60rpx !important;
font-size: 24rpx;
}
.input-view .uni-icons {
font-size: 32rpx !important;
}
.input-view .input {
height: 60rpx;
line-height: 60rpx;
width: 94%;
padding: 0 2%;
font-size: 24rpx;
}
.uni-swiper-list {
height: calc(100vh - 98px);
}
.u-btn-default {
position: fixed;
left: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
background: #fff;
color: #000;
z-index: 1;
margin: 0;
height: 120rpx;
line-height: 120rpx;
bottom: constant(safe-area-inset-bottom);
// bottom: env(safe-area-inset-bottom);
}
}
</style>.