427 lines
14 KiB
Vue
427 lines
14 KiB
Vue
<template>
|
||
<uni-popup
|
||
ref="popup"
|
||
type="bottom"
|
||
borderRadius="10px 10px 0 0"
|
||
background-color="#FFFFFF"
|
||
:mask-click="maskClick"
|
||
>
|
||
<view class="popup-content">
|
||
<view class="popup-header">
|
||
<view class="btn-cancel" @click="cancel">取消</view>
|
||
<view class="title">{{ title }}</view>
|
||
<view class="btn-confirm" @click="confirm">确认</view>
|
||
</view>
|
||
<view class="popup-list">
|
||
<picker-view
|
||
indicator-style="height: 84rpx;"
|
||
:value="selectedIndex"
|
||
@change="bindChange"
|
||
class="picker-view"
|
||
>
|
||
<!-- 省 -->
|
||
<picker-view-column>
|
||
<view
|
||
v-for="(item, index) in provinceList"
|
||
:key="item.code"
|
||
class="item"
|
||
:class="{ 'item-active': selectedIndex[0] === index }"
|
||
>
|
||
<text>{{ item.name }}</text>
|
||
</view>
|
||
</picker-view-column>
|
||
|
||
<!-- 市 -->
|
||
<picker-view-column>
|
||
<view
|
||
v-for="(item, index) in cityList"
|
||
:key="item.code"
|
||
class="item"
|
||
:class="{ 'item-active': selectedIndex[1] === index }"
|
||
>
|
||
<text>{{ item.name }}</text>
|
||
</view>
|
||
</picker-view-column>
|
||
|
||
<!-- 区县 -->
|
||
<picker-view-column>
|
||
<view
|
||
v-for="(item, index) in districtList"
|
||
:key="item.code"
|
||
class="item"
|
||
:class="{ 'item-active': selectedIndex[2] === index }"
|
||
>
|
||
<text>{{ item.name }}</text>
|
||
</view>
|
||
</picker-view-column>
|
||
|
||
<!-- 街道 -->
|
||
<picker-view-column>
|
||
<view
|
||
v-for="(item, index) in streetList"
|
||
:key="item.code"
|
||
class="item"
|
||
:class="{ 'item-active': selectedIndex[3] === index }"
|
||
>
|
||
<text>{{ item.name }}</text>
|
||
</view>
|
||
</picker-view-column>
|
||
|
||
<!-- 社区/居委会 -->
|
||
<picker-view-column>
|
||
<view
|
||
v-for="(item, index) in communityList"
|
||
:key="item.code"
|
||
class="item"
|
||
:class="{ 'item-active': selectedIndex[4] === index }"
|
||
>
|
||
<text>{{ item.name }}</text>
|
||
</view>
|
||
</picker-view-column>
|
||
</picker-view>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
</template>
|
||
|
||
<script>
|
||
import addressJson from '@/static/json/xinjiang.json';
|
||
export default {
|
||
name: 'AreaCascadePicker',
|
||
data() {
|
||
return {
|
||
maskClick: false,
|
||
title: '选择地址',
|
||
confirmCallback: null,
|
||
cancelCallback: null,
|
||
changeCallback: null,
|
||
selectedIndex: [0, 0, 0, 0, 0],
|
||
// 原始数据
|
||
areaData: [],
|
||
// 各级列表
|
||
provinceList: [],
|
||
cityList: [],
|
||
districtList: [],
|
||
streetList: [],
|
||
communityList: [],
|
||
// 当前选中的项
|
||
selectedProvince: null,
|
||
selectedCity: null,
|
||
selectedDistrict: null,
|
||
selectedStreet: null,
|
||
selectedCommunity: null,
|
||
};
|
||
},
|
||
methods: {
|
||
async open(newConfig = {}) {
|
||
const {
|
||
title,
|
||
success,
|
||
cancel,
|
||
change,
|
||
maskClick = false,
|
||
defaultValue = null,
|
||
} = newConfig;
|
||
|
||
this.reset();
|
||
if (title) this.title = title;
|
||
if (typeof success === 'function') this.confirmCallback = success;
|
||
if (typeof cancel === 'function') this.cancelCallback = cancel;
|
||
if (typeof change === 'function') this.changeCallback = change;
|
||
this.maskClick = maskClick;
|
||
|
||
// 加载地区数据
|
||
await this.loadAreaData();
|
||
|
||
// 初始化列表
|
||
this.initLists();
|
||
|
||
this.$nextTick(() => {
|
||
this.$refs.popup.open();
|
||
});
|
||
},
|
||
|
||
async loadAreaData() {
|
||
try {
|
||
// 尝试调用后端API获取地区数据
|
||
// 如果后端API不存在,将使用模拟数据
|
||
console.log('正在加载地区数据...');
|
||
// const resp = await uni.request({
|
||
// url: '/app/common/area/cascade',
|
||
// method: 'GET'
|
||
// });
|
||
// if (resp.statusCode === 200 && resp.data && resp.data.data) {
|
||
// this.areaData = resp.data.data;
|
||
// }
|
||
|
||
// 暂时使用模拟数据
|
||
this.areaData = this.getMockData();
|
||
} catch (error) {
|
||
console.error('加载地区数据失败:', error);
|
||
// 如果后端API不存在,使用模拟数据
|
||
this.areaData = this.getMockData();
|
||
}
|
||
},
|
||
|
||
initLists() {
|
||
// 初始化省列表
|
||
this.provinceList = this.areaData;
|
||
|
||
if (this.provinceList.length > 0) {
|
||
this.selectedProvince = this.provinceList[0];
|
||
this.updateCityList();
|
||
}
|
||
},
|
||
|
||
updateCityList() {
|
||
if (!this.selectedProvince || !this.selectedProvince.children) {
|
||
this.cityList = [];
|
||
this.districtList = [];
|
||
this.streetList = [];
|
||
this.communityList = [];
|
||
return;
|
||
}
|
||
|
||
this.cityList = this.selectedProvince.children;
|
||
this.selectedIndex[1] = 0;
|
||
|
||
if (this.cityList.length > 0) {
|
||
this.selectedCity = this.cityList[0];
|
||
this.updateDistrictList();
|
||
}
|
||
},
|
||
|
||
updateDistrictList() {
|
||
if (!this.selectedCity || !this.selectedCity.children) {
|
||
this.districtList = [];
|
||
this.streetList = [];
|
||
this.communityList = [];
|
||
return;
|
||
}
|
||
|
||
this.districtList = this.selectedCity.children;
|
||
this.selectedIndex[2] = 0;
|
||
|
||
if (this.districtList.length > 0) {
|
||
this.selectedDistrict = this.districtList[0];
|
||
this.updateStreetList();
|
||
}
|
||
},
|
||
|
||
updateStreetList() {
|
||
if (!this.selectedDistrict || !this.selectedDistrict.children) {
|
||
this.streetList = [];
|
||
this.communityList = [];
|
||
return;
|
||
}
|
||
|
||
this.streetList = this.selectedDistrict.children;
|
||
this.selectedIndex[3] = 0;
|
||
|
||
if (this.streetList.length > 0) {
|
||
this.selectedStreet = this.streetList[0];
|
||
this.updateCommunityList();
|
||
}
|
||
},
|
||
|
||
updateCommunityList() {
|
||
if (!this.selectedStreet || !this.selectedStreet.children) {
|
||
this.communityList = [];
|
||
return;
|
||
}
|
||
|
||
this.communityList = this.selectedStreet.children;
|
||
this.selectedIndex[4] = 0;
|
||
|
||
if (this.communityList.length > 0) {
|
||
this.selectedCommunity = this.communityList[0];
|
||
}
|
||
},
|
||
|
||
bindChange(e) {
|
||
const newIndex = e.detail.value;
|
||
|
||
// 检查哪一列发生了变化
|
||
for (let i = 0; i < 5; i++) {
|
||
if (newIndex[i] !== this.selectedIndex[i]) {
|
||
this.selectedIndex[i] = newIndex[i];
|
||
|
||
// 根据变化的列更新后续列
|
||
if (i === 0) {
|
||
// 省变化
|
||
this.selectedProvince = this.provinceList[newIndex[0]];
|
||
this.updateCityList();
|
||
} else if (i === 1) {
|
||
// 市变化
|
||
this.selectedCity = this.cityList[newIndex[1]];
|
||
this.updateDistrictList();
|
||
} else if (i === 2) {
|
||
// 区县变化
|
||
this.selectedDistrict = this.districtList[newIndex[2]];
|
||
this.updateStreetList();
|
||
} else if (i === 3) {
|
||
// 街道变化
|
||
this.selectedStreet = this.streetList[newIndex[3]];
|
||
this.updateCommunityList();
|
||
} else if (i === 4) {
|
||
// 社区变化
|
||
this.selectedCommunity = this.communityList[newIndex[4]];
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (this.changeCallback) {
|
||
this.changeCallback(this.getSelectedAddress());
|
||
}
|
||
},
|
||
|
||
getSelectedAddress() {
|
||
const parts = [];
|
||
if (this.selectedProvince) parts.push(this.selectedProvince.name);
|
||
if (this.selectedCity) parts.push(this.selectedCity.name);
|
||
if (this.selectedDistrict) parts.push(this.selectedDistrict.name);
|
||
if (this.selectedStreet) parts.push(this.selectedStreet.name);
|
||
if (this.selectedCommunity) parts.push(this.selectedCommunity.name);
|
||
|
||
return {
|
||
address: parts.join('/'),
|
||
province: this.selectedProvince,
|
||
city: this.selectedCity,
|
||
district: this.selectedDistrict,
|
||
street: this.selectedStreet,
|
||
community: this.selectedCommunity,
|
||
};
|
||
},
|
||
|
||
close() {
|
||
this.$refs.popup.close();
|
||
},
|
||
|
||
cancel() {
|
||
this.clickCallback(this.cancelCallback);
|
||
},
|
||
|
||
confirm() {
|
||
this.clickCallback(this.confirmCallback);
|
||
},
|
||
|
||
async clickCallback(callback) {
|
||
if (typeof callback !== 'function') {
|
||
this.$refs.popup.close();
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const result = await callback(this.getSelectedAddress());
|
||
if (result !== false) {
|
||
this.$refs.popup.close();
|
||
}
|
||
} catch (error) {
|
||
console.error('callback 执行出错:', error);
|
||
}
|
||
},
|
||
|
||
reset() {
|
||
this.maskClick = false;
|
||
this.confirmCallback = null;
|
||
this.cancelCallback = null;
|
||
this.changeCallback = null;
|
||
this.selectedIndex = [0, 0, 0, 0, 0];
|
||
this.provinceList = [];
|
||
this.cityList = [];
|
||
this.districtList = [];
|
||
this.streetList = [];
|
||
this.communityList = [];
|
||
},
|
||
|
||
// 模拟数据(用于演示)
|
||
getMockData() {
|
||
return addressJson
|
||
}
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.popup-content {
|
||
color: #000000;
|
||
height: 60vh;
|
||
}
|
||
|
||
.popup-list {
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: nowrap;
|
||
align-items: center;
|
||
justify-content: space-evenly;
|
||
flex: 1;
|
||
overflow: hidden;
|
||
|
||
.picker-view {
|
||
width: 100%;
|
||
height: calc(60vh - 100rpx);
|
||
margin-top: 20rpx;
|
||
|
||
.uni-picker-view-mask {
|
||
background: rgba(0, 0, 0, 0);
|
||
}
|
||
|
||
.item {
|
||
line-height: 84rpx;
|
||
height: 84rpx;
|
||
text-align: center;
|
||
font-weight: 400;
|
||
font-size: 28rpx;
|
||
color: #cccccc;
|
||
padding: 0 4rpx;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.item-active {
|
||
color: #333333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.uni-picker-view-indicator:after {
|
||
border-color: #e3e3e3;
|
||
}
|
||
|
||
.uni-picker-view-indicator:before {
|
||
border-color: #e3e3e3;
|
||
}
|
||
}
|
||
}
|
||
|
||
.popup-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 40rpx 40rpx 10rpx 40rpx;
|
||
|
||
.title {
|
||
font-weight: 500;
|
||
font-size: 36rpx;
|
||
color: #333333;
|
||
text-align: center;
|
||
}
|
||
|
||
.btn-cancel {
|
||
font-weight: 400;
|
||
font-size: 32rpx;
|
||
color: #666d7f;
|
||
line-height: 38rpx;
|
||
}
|
||
|
||
.btn-confirm {
|
||
font-weight: 400;
|
||
font-size: 32rpx;
|
||
color: #256bfa;
|
||
}
|
||
}
|
||
</style>
|
||
|