特易招,招聘小程序
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.
 
 
 

470 lines
11 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
v-if="showSelectWholeCity"
class="address-item whole-city-item"
@click="selectWholeProvince">
<uv-icon name="checkmark-circle" size="30rpx" color="#3796F8"></uv-icon>
选择整个{{ selectedProvince.adress }}
</view>
<view
class="address-item"
:class="{
'selected': multiple && isCitySelected(item),
'active': !multiple && selectedCity && selectedCity.id === item.id
}"
v-for="item in cityList"
:key="item.id"
@click="selectCity(item)">
{{ item.adress }}
<uv-icon v-if="multiple && isCitySelected(item)"
name="checkmark-circle" size="30rpx" color="#3796F8"></uv-icon>
</view>
<!-- 多选时的确认按钮 -->
<view v-if="multiple && selectedCities.length > 0"
class="confirm-btn" @click="confirmMultipleCitySelection">
<button class="confirm-button">确认选择城市 ({{ selectedCities.length }})</button>
</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
v-if="showSelectWholeCity"
class="address-item whole-city-item"
@click="selectWholeCity">
<uv-icon name="checkmark-circle" size="30rpx" color="#3796F8"></uv-icon>
选择整个{{ selectedCity.adress }}
</view>
<view
class="address-item"
:class="{
'selected': multiple && isDistrictSelected(item),
'active': !multiple && selectedDistrict && selectedDistrict.id === item.id
}"
v-for="item in districtList"
:key="item.id"
@click="selectDistrict(item)">
{{ item.adress }}
<uv-icon v-if="multiple && isDistrictSelected(item)"
name="checkmark-circle" size="30rpx" color="#3796F8"></uv-icon>
</view>
<!-- 多选时的确认按钮 -->
<view v-if="multiple && selectedDistricts.length > 0"
class="confirm-btn" @click="confirmMultipleSelection">
<button class="confirm-button">确认选择 ({{ selectedDistricts.length }})</button>
</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
},
// 是否支持多选区县
multiple: {
type: Boolean,
default: false
},
// 是否显示"选择整个城市"选项
showSelectWholeCity: {
type: Boolean,
default: false
}
},
data() {
return {
selectedProvince: null, // 选中的省份
selectedCity: null, // 选中的城市
selectedDistrict: null, // 选中的区县
selectedCities: [], // 多选时选中的城市列表
selectedDistricts: [], // 多选时选中的区县列表
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.selectedCities = []
this.selectedDistricts = []
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) {
if (this.multiple) {
// 多选模式
const index = this.selectedCities.findIndex(item => item.id === city.id)
if (index > -1) {
// 取消选择
this.selectedCities.splice(index, 1)
} else {
// 添加选择
this.selectedCities.push(city)
}
} else {
// 单选模式
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) {
if (this.multiple) {
// 多选模式
const index = this.selectedDistricts.findIndex(item => item.id === district.id)
if (index > -1) {
// 取消选择
this.selectedDistricts.splice(index, 1)
} else {
// 添加选择
this.selectedDistricts.push(district)
}
} else {
// 单选模式
this.selectedDistrict = district
this.confirm()
}
},
// 检查城市是否被选中(多选模式)
isCitySelected(city) {
return this.selectedCities.some(item => item.id === city.id)
},
// 检查区县是否被选中(多选模式)
isDistrictSelected(district) {
return this.selectedDistricts.some(item => item.id === district.id)
},
// 选择整个省份
selectWholeProvince() {
this.selectedCity = null
this.selectedCities = []
this.selectedDistrict = null
this.selectedDistricts = []
this.confirm()
},
// 选择整个城市
selectWholeCity() {
this.selectedDistrict = null
this.selectedDistricts = []
this.confirm()
},
// 确认多选城市选择
confirmMultipleCitySelection() {
// 直接返回多选城市的数据
this.confirm()
},
// 确认多选选择
confirmMultipleSelection() {
this.confirm()
},
// 返回城市选择
backToCity() {
this.selectedCity = null
this.selectedDistrict = null
this.districtList = []
},
// 确认选择
confirm() {
const result = {
province: this.selectedProvince,
city: this.selectedCity,
district: this.selectedDistrict,
cities: this.selectedCities,
districts: this.selectedDistricts
}
// 生成完整地址文本
let fullAddress = ''
if (this.selectedProvince) {
fullAddress += this.selectedProvince.adress
}
// 多选城市模式
if (this.multiple && this.selectedCities.length > 0) {
const cityNames = this.selectedCities.map(item => item.adress).join(',')
fullAddress += cityNames
result.selectedAddress = this.selectedProvince // 多选城市时返回省份作为选中地址
result.selectedCities = this.selectedCities
} else if (this.selectedCity) {
fullAddress += this.selectedCity.adress
// 多选区县模式
if (this.multiple && this.selectedDistricts.length > 0) {
const districtNames = this.selectedDistricts.map(item => item.adress).join(',')
fullAddress += districtNames
result.selectedAddress = this.selectedCity // 多选时返回城市作为选中地址
result.selectedDistricts = this.selectedDistricts
} else if (this.selectedDistrict) {
// 单选区县模式
fullAddress += this.selectedDistrict.adress
result.selectedAddress = this.selectedDistrict
} else {
// 选择整个城市
result.selectedAddress = this.selectedCity
}
} else {
// 选择整个省份
result.selectedAddress = this.selectedProvince
}
result.fullAddress = fullAddress
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;
}
}
&.whole-city-item {
display: flex;
align-items: center;
color: #3796F8;
background: rgba(#3796F8, 0.1);
font-weight: bold;
uv-icon {
margin-right: 10rpx;
}
}
&.selected {
background: rgba($uni-color, 0.1);
color: $uni-color;
font-weight: bold;
position: relative;
&::after {
content: '';
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 6rpx;
background: $uni-color;
}
}
}
.confirm-btn {
position: sticky;
bottom: 0;
background: #fff;
padding: 20rpx;
border-top: 1px solid #eee;
.confirm-button {
width: 100%;
background: $uni-color;
color: #fff;
border: none;
border-radius: 10rpx;
padding: 20rpx;
font-size: 28rpx;
}
}
}
}
</style>