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.
 
 
 
 

429 lines
12 KiB

<template>
<view class="area-picker">
<picker
mode="multiSelector"
:range="newProvinceDataList"
range-key="name"
@change="changeArea"
@columnchange="pickerColumnchange"
:value="multiIndex"
>
<!-- 使用插槽允许父组件自定义显示样式 -->
<slot
:selectedText="selectedText"
:placeholder="placeholder"
:provinceData="newProvinceDataList[0]"
:cityData="newProvinceDataList[1]"
:areaData="newProvinceDataList[2]"
:multiIndex="multiIndex"
:currentSelection="getCurrentSelection()"
>
<!-- 默认显示样式 -->
<view class="picker-display">
<text class="picker-text" :class="{ 'placeholder': !selectedText }">{{ selectedText || placeholder }}</text>
<image
class="dropdown-icon"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iOCIgdmlld0JveD0iMCAwIDEyIDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xIDFMNiA2TDExIDEiIHN0cm9rZT0iIzk5OTk5OSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KPC9zdmc+"
mode="heightFix"
></image>
</view>
</slot>
</picker>
</view>
</template>
<script>
export default {
name: 'AreaPicker',
props: {
// 占位符文本
placeholder: {
type: String,
default: '请选择地区'
},
// 默认选中的省市区ID
defaultValue: {
type: Object,
default: () => ({
provinceId: null,
cityId: null,
areaId: null
})
},
// 是否禁用
disabled: {
type: Boolean,
default: false
},
},
data() {
return {
// 省市区数据
columns: [],
newProvinceDataList: [[], [], []],
multiIndex: [0, 0, 0],
provinceId: null,
cityId: null,
areaId: null,
ready: false,
selectedText: '',
}
},
mounted() {
this.getSeldCityList()
},
watch: {
defaultValue: {
handler(newVal) {
console.log('----有值回显')
if (newVal && newVal.provinceId && this.ready) {
this.setDefaultValue(newVal)
}
},
deep: true,
immediate: true
}
},
methods: {
// 获取省市区数据
getSeldCityList() {
// 尝试多种方式获取数据
let requestMethod = null;
// 1. 尝试使用父组件的 Post 方法
if (this.$parent && this.$parent.Post) {
requestMethod = this.$parent.Post;
}
// 2. 尝试使用全局的 Post 方法(如果通过 mixin 引入)
else if (this.Post) {
requestMethod = this.Post;
}
// 3. 尝试使用 uni.request
else {
this.requestWithUni();
return;
}
requestMethod({}, '/api/areas/getAll').then(res => {
if (res) {
this.processAreaData(res.data)
}
}).catch(err => {
console.warn('省市区数据获取失败:', err)
// 可以在这里设置一些默认数据或提示用户
})
},
// 使用 uni.request 获取数据的备用方法
requestWithUni() {
uni.request({
url: '/api/areas/getAll', // 这里需要根据实际的完整URL调整
method: 'POST',
data: {},
success: (res) => {
if (res.data) {
this.processAreaData(res.data.data || res.data)
}
},
fail: (err) => {
console.warn('省市区数据获取失败:', err)
// 可以提供一些默认的省市区数据或提示用户
uni.showToast({
title: '地区数据加载失败',
icon: 'none'
})
}
})
},
// 处理省市区数据
processAreaData(data) {
var result = {}
for (var i = 0; i < data.length; i++) {
var item = data[i]
if (item.parent_id == 0) {
continue
}
// 获取省
if (item.parent_id == "1") {
result[item.id.toString()] = {}
result[item.id.toString()].children = []
result[item.id.toString()].name = item.name
result[item.id.toString()].id = item.id
} else if (result[item.parent_id.toString()]) {
// 填充市
var t = {
id: item.id,
name: item.name,
children: []
}
result[item.parent_id.toString()].children.push(t)
} else {
// 填充区
var k = {
id: item.id,
name: item.name
}
for (var j = 0; j < result[item.parent_id.toString().substr(0, 2) + "0000"].children.length; j++) {
if (result[item.parent_id.toString().substr(0, 2) + "0000"].children[j].id == item.parent_id) {
result[item.parent_id.toString().substr(0, 2) + "0000"].children[j].children.push(k)
}
}
}
}
var r = []
// 将Object转为Array
for (var i in result) {
r.push(result[i])
}
this.columns = r
this.initPickerData()
this.ready = true
// 如果有默认值,设置默认选中
if (this.defaultValue && this.defaultValue.provinceId) {
this.setDefaultValue(this.defaultValue)
}
},
// 初始化picker数据
initPickerData() {
if (this.columns.length === 0) return
// 初始化省份数据
this.newProvinceDataList[0] = this.columns.map(item => ({
name: item.name,
id: item.id
}))
// 初始化城市数据(默认第一个省份的城市)
if (this.columns[0] && this.columns[0].children) {
this.newProvinceDataList[1] = this.columns[0].children.map(item => ({
name: item.name,
id: item.id
}))
}
// 初始化区县数据(默认第一个城市的区县)
if (this.columns[0] && this.columns[0].children[0] && this.columns[0].children[0].children) {
this.newProvinceDataList[2] = this.columns[0].children[0].children.map(item => ({
name: item.name,
id: item.id
}))
}
},
// 设置默认值
setDefaultValue(defaultValue) {
if (!this.ready || !defaultValue) return
// 查找省份索引
const provinceIndex = this.newProvinceDataList[0].findIndex(item => item.id == defaultValue.provinceId)
if (provinceIndex === -1) return
this.multiIndex[0] = provinceIndex
// 更新城市数据
this.newProvinceDataList[1] = this.columns[provinceIndex].children.map(item => ({
name: item.name,
id: item.id
}))
// 查找城市索引
const cityIndex = this.newProvinceDataList[1].findIndex(item => item.id == defaultValue.cityId)
if (cityIndex !== -1) {
this.multiIndex[1] = cityIndex
// 更新区县数据
this.newProvinceDataList[2] = this.columns[provinceIndex].children[cityIndex].children.map(item => ({
name: item.name,
id: item.id
}))
// 查找区县索引
const areaIndex = this.newProvinceDataList[2].findIndex(item => item.id == defaultValue.areaId)
if (areaIndex !== -1) {
this.multiIndex[2] = areaIndex
}
}
this.updateSelectedText()
},
// 选择完成事件
changeArea(e) {
this.multiIndex = e.detail.value
this.updateSelectedText()
this.emitChange()
},
// 列滑动事件
pickerColumnchange(e) {
const column = e.detail.column
const value = e.detail.value
if (column === 0) {
// 第一列滑动(省份)
this.multiIndex[0] = value
// 更新城市数据
this.newProvinceDataList[1] = this.columns[this.multiIndex[0]].children.map(item => ({
name: item.name,
id: item.id
}))
// 更新区县数据
if (this.columns[this.multiIndex[0]].children.length === 1) {
this.newProvinceDataList[2] = this.columns[this.multiIndex[0]].children[0].children.map(item => ({
name: item.name,
id: item.id
}))
} else {
this.newProvinceDataList[2] = this.columns[this.multiIndex[0]].children[this.multiIndex[1]].children.map(item => ({
name: item.name,
id: item.id
}))
}
// 重置城市和区县索引
this.multiIndex.splice(1, 1, 0)
this.multiIndex.splice(2, 1, 0)
} else if (column === 1) {
// 第二列滑动(城市)
this.multiIndex[1] = value
// 更新区县数据
this.newProvinceDataList[2] = this.columns[this.multiIndex[0]].children[this.multiIndex[1]].children.map(item => ({
name: item.name,
id: item.id
}))
// 重置区县索引
this.multiIndex.splice(2, 1, 0)
} else if (column === 2) {
// 第三列滑动(区县)
this.multiIndex[2] = value
}
},
// 更新选中的省市区ID和显示文本
updateSelectedText() {
if (this.newProvinceDataList[0][this.multiIndex[0]] &&
this.newProvinceDataList[1][this.multiIndex[1]] &&
this.newProvinceDataList[2][this.multiIndex[2]]) {
this.selectedText =
this.newProvinceDataList[1][this.multiIndex[1]].name
this.provinceId = this.newProvinceDataList[0][this.multiIndex[0]].id
this.cityId = this.newProvinceDataList[1][this.multiIndex[1]].id
this.areaId = this.newProvinceDataList[2][this.multiIndex[2]].id
}
},
// 触发change事件
emitChange() {
const selectedText = this.newProvinceDataList[0][this.multiIndex[0]].name +
this.newProvinceDataList[1][this.multiIndex[1]].name +
this.newProvinceDataList[2][this.multiIndex[2]].name
const result = {
provinceId: this.provinceId,
cityId: this.cityId,
areaId: this.areaId,
province: this.newProvinceDataList[0][this.multiIndex[0]]?.name || '',
city: this.newProvinceDataList[1][this.multiIndex[1]]?.name || '',
area: this.newProvinceDataList[2][this.multiIndex[2]]?.name || '',
fullText: selectedText
}
this.$emit('change', result)
},
// 获取当前选中值
getValue() {
const selectedText = this.newProvinceDataList[0][this.multiIndex[0]]?.name +
this.newProvinceDataList[1][this.multiIndex[1]]?.name +
this.newProvinceDataList[2][this.multiIndex[2]]?.name
return {
provinceId: this.provinceId,
cityId: this.cityId,
areaId: this.areaId,
provinceName: this.newProvinceDataList[0][this.multiIndex[0]]?.name || '',
cityName: this.newProvinceDataList[1][this.multiIndex[1]]?.name || '',
areaName: this.newProvinceDataList[2][this.multiIndex[2]]?.name || '',
fullText: selectedText
}
},
// 重置选择
reset() {
this.multiIndex = [0, 0, 0]
this.selectedText = ''
this.provinceId = null
this.cityId = null
this.areaId = null
this.initPickerData()
},
// 获取当前选中的详细信息(供插槽使用)
getCurrentSelection() {
if (!this.newProvinceDataList[0][this.multiIndex[0]] ||
!this.newProvinceDataList[1][this.multiIndex[1]] ||
!this.newProvinceDataList[2][this.multiIndex[2]]) {
return {
province: null,
city: null,
area: null,
fullText: ''
}
}
return {
province: this.newProvinceDataList[0][this.multiIndex[0]],
city: this.newProvinceDataList[1][this.multiIndex[1]],
area: this.newProvinceDataList[2][this.multiIndex[2]],
fullText: this.newProvinceDataList[0][this.multiIndex[0]].name +
this.newProvinceDataList[1][this.multiIndex[1]].name +
this.newProvinceDataList[2][this.multiIndex[2]].name
}
}
}
}
</script>
<style scoped lang="scss">
.area-picker {
width: 100%;
}
.picker-display {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8rpx 16rpx;
border: 2rpx solid #e0e0e0;
border-radius: 8rpx;
background-color: #fff;
min-height: 60rpx;
}
.picker-text {
font-size: 30rpx;
color: #333;
flex: 1;
&.placeholder {
color: #999;
}
}
.dropdown-icon {
width: 24rpx;
height: 16rpx;
margin-left: 8rpx;
}
</style>