<template>
|
|
<uv-popup ref="popup" mode="bottom" :round="30"
|
|
:safeAreaInsetBottom="false" @close="handleClose">
|
|
<view class="address-picker">
|
|
<view class="header">
|
|
<view class="title">选择地址</view>
|
|
<view class="close-btn" @click="close">
|
|
<uv-icon name="close" size="40rpx"></uv-icon>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="content">
|
|
<!-- 左侧一级地址列表 -->
|
|
<view class="left-panel">
|
|
<scroll-view scroll-y class="scroll-view">
|
|
<view
|
|
class="address-item"
|
|
:class="{ active: selectedProvince && selectedProvince.id === item.id }"
|
|
v-for="item in addressList"
|
|
:key="item.id"
|
|
@click="selectProvince(item)">
|
|
{{ item.adress }}
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<!-- 右侧二三级地址列表 -->
|
|
<view class="right-panel">
|
|
<scroll-view scroll-y class="scroll-view">
|
|
<!-- 二级地址 -->
|
|
<template v-if="selectedProvince && !selectedCity">
|
|
<view
|
|
class="address-item"
|
|
v-for="item in cityList"
|
|
:key="item.id"
|
|
@click="selectCity(item)">
|
|
{{ item.adress }}
|
|
</view>
|
|
</template>
|
|
|
|
<!-- 三级地址 -->
|
|
<template v-if="selectedCity">
|
|
<view
|
|
class="address-item back-item"
|
|
@click="backToCity">
|
|
<uv-icon name="arrow-left" size="30rpx"></uv-icon>
|
|
返回{{ selectedProvince.adress }}
|
|
</view>
|
|
<view
|
|
class="address-item"
|
|
v-for="item in districtList"
|
|
:key="item.id"
|
|
@click="selectDistrict(item)">
|
|
{{ item.adress }}
|
|
</view>
|
|
</template>
|
|
</scroll-view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</uv-popup>
|
|
</template>
|
|
|
|
<script>
|
|
import { mapState } from 'vuex'
|
|
|
|
export default {
|
|
name: 'AddressPicker',
|
|
props: {
|
|
// 是否只选择到市级,不选择区县
|
|
onlyCity: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
selectedProvince: null, // 选中的省份
|
|
selectedCity: null, // 选中的城市
|
|
selectedDistrict: null, // 选中的区县
|
|
cityList: [], // 城市列表
|
|
districtList: [], // 区县列表
|
|
}
|
|
},
|
|
computed: {
|
|
...mapState(['addressList'])
|
|
},
|
|
methods: {
|
|
// 打开弹窗
|
|
open() {
|
|
this.$refs.popup.open()
|
|
},
|
|
|
|
// 关闭弹窗
|
|
close() {
|
|
this.$refs.popup.close()
|
|
},
|
|
|
|
// 弹窗关闭时重置状态
|
|
handleClose() {
|
|
this.selectedProvince = null
|
|
this.selectedCity = null
|
|
this.selectedDistrict = null
|
|
this.cityList = []
|
|
this.districtList = []
|
|
},
|
|
|
|
// 选择省份
|
|
async selectProvince(province) {
|
|
this.selectedProvince = province
|
|
this.selectedCity = null
|
|
this.selectedDistrict = null
|
|
this.districtList = []
|
|
|
|
// 获取城市列表
|
|
try {
|
|
this.cityList = await this.$store.dispatch('getChildAddressList', province.id)
|
|
// 如果没有下级城市,直接确认选择
|
|
if (this.cityList.length === 0) {
|
|
this.confirm()
|
|
}
|
|
} catch (error) {
|
|
console.error('获取城市列表失败:', error)
|
|
this.cityList = []
|
|
// 获取失败时也直接确认
|
|
this.confirm()
|
|
}
|
|
},
|
|
|
|
// 选择城市
|
|
async selectCity(city) {
|
|
this.selectedCity = city
|
|
this.selectedDistrict = null
|
|
|
|
// 如果只选择到市级,直接确认
|
|
if (this.onlyCity) {
|
|
this.confirm()
|
|
return
|
|
}
|
|
|
|
// 获取区县列表
|
|
try {
|
|
this.districtList = await this.$store.dispatch('getChildAddressList', city.id)
|
|
// 如果没有下级地址,直接确认
|
|
if (this.districtList.length === 0) {
|
|
this.confirm()
|
|
}
|
|
} catch (error) {
|
|
console.error('获取区县列表失败:', error)
|
|
this.districtList = []
|
|
// 获取失败时也直接确认
|
|
this.confirm()
|
|
}
|
|
},
|
|
|
|
// 选择区县
|
|
selectDistrict(district) {
|
|
this.selectedDistrict = district
|
|
this.confirm()
|
|
},
|
|
|
|
// 返回城市选择
|
|
backToCity() {
|
|
this.selectedCity = null
|
|
this.selectedDistrict = null
|
|
this.districtList = []
|
|
},
|
|
|
|
// 确认选择
|
|
confirm() {
|
|
const result = {
|
|
province: this.selectedProvince,
|
|
city: this.selectedCity,
|
|
district: this.selectedDistrict
|
|
}
|
|
|
|
// 生成完整地址文本
|
|
let fullAddress = ''
|
|
if (this.selectedProvince) {
|
|
fullAddress += this.selectedProvince.adress
|
|
}
|
|
if (this.selectedCity) {
|
|
fullAddress += this.selectedCity.adress
|
|
}
|
|
if (this.selectedDistrict) {
|
|
fullAddress += this.selectedDistrict.adress
|
|
}
|
|
|
|
result.fullAddress = fullAddress
|
|
result.selectedAddress = this.selectedDistrict || this.selectedCity || this.selectedProvince
|
|
|
|
this.$emit('confirm', result)
|
|
this.close()
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.address-picker {
|
|
height: 70vh;
|
|
background: #fff;
|
|
|
|
.header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 30rpx;
|
|
border-bottom: 1px solid #eee;
|
|
|
|
.title {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.close-btn {
|
|
padding: 10rpx;
|
|
}
|
|
}
|
|
|
|
.content {
|
|
display: flex;
|
|
height: calc(70vh - 160rpx);
|
|
|
|
.left-panel {
|
|
width: 240rpx;
|
|
border-right: 1px solid #eee;
|
|
background: #f8f8f8;
|
|
}
|
|
|
|
.right-panel {
|
|
flex: 1;
|
|
}
|
|
|
|
.scroll-view {
|
|
height: 100%;
|
|
}
|
|
|
|
.address-item {
|
|
padding: 30rpx 20rpx;
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
&.active {
|
|
background: #fff;
|
|
color: $uni-color;
|
|
font-weight: bold;
|
|
position: relative;
|
|
|
|
&::after {
|
|
content: '';
|
|
position: absolute;
|
|
right: 0;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 6rpx;
|
|
background: $uni-color;
|
|
}
|
|
}
|
|
|
|
&.back-item {
|
|
display: flex;
|
|
align-items: center;
|
|
color: $uni-color;
|
|
background: #f8f8f8;
|
|
|
|
uv-icon {
|
|
margin-right: 10rpx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|