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