特易招,招聘小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

280 lines
5.9 KiB

<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>