chooseCity.vue 3.91 KB
<template>
	<view class="popup_wrapper">
		<view class="picker-container">
			<view class="picker-header">
				<text class="picker-cancel" @click="closePopup">取消</text>
				<text class="picker-title">请选择城市</text>
				<text class="picker-confirm" @click="confirmSelection">确认</text>
			</view>

			<picker-view class="picker-body" :value="pickerValue" @change="handlePickerChange">
				<picker-view-column>
					<view class="picker-item" v-for="(province, index) in provinces" :key="index">
						{{ province.areaName }}
					</view>
				</picker-view-column>
				<picker-view-column>
					<view class="picker-item" v-for="(city, index) in currentCities" :key="index">
						{{ city.areaName }}
					</view>
				</picker-view-column>
			</picker-view>
		</view>
	</view>
</template>

<script setup lang="ts">
	import { ref, computed, watch, onMounted } from 'vue'
	import type { Ref } from 'vue'

	interface Province {
		areaName : string
		children : City[]
		harborAreaId: string
	}

	interface City {
		areaName : string
		harborAreaId: string
	}

	const props = defineProps({
		modelValue: {
			type: String,
			default: ''
		},
		data: {
			type: Array<Province>,
			default: []
		}
	})

	const emit = defineEmits(['update:modelValue', 'change', 'cancel'])

	// 省市数据
	const provinces : Ref<Province[]> = ref([])

	// 当前选中的城市
	const selectedCity : Ref<string> = ref(props.modelValue)

	// 选择器值
	const pickerValue : Ref<number[]> = ref([0, 0])

	// 当前显示的城市列表
	const currentCities = computed(() => {
		return provinces.value[pickerValue.value[0]]?.children || []
	})
	onMounted(() => {
		provinces.value = props.data
	})
	// 关闭弹窗
	const closePopup = () => {
		emit('cancel')
	}

	// 处理选择器变化
	const handlePickerChange = (e : any) => {
		const [provinceIndex, cityIndex] = e.detail.value
		pickerValue.value = [provinceIndex, cityIndex]
	}

	// 确认选择
	const confirmSelection = () => {
		const provinceIndex = pickerValue.value[0]
		const cityIndex = pickerValue.value[1]

		const province = provinces.value[provinceIndex].areaName
		const city = provinces.value[provinceIndex].children[cityIndex].areaName
		const provinceId = provinces.value[provinceIndex].harborAreaId
		const cityId = provinces.value[provinceIndex].children[cityIndex].harborAreaId
		selectedCity.value = `${province} ${city}`
		emit('update:modelValue', selectedCity.value)
		emit('change', selectedCity.value, provinceId, cityId)
		closePopup()
	}

	// 监听外部值变化
	watch(() => props.modelValue, (newVal) => {
		selectedCity.value = newVal
	})
</script>

<style scoped>
	.popup_wrapper {
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background: rgba(0, 0, 0, 0.5);
		display: flex;
		/* justify-content: center;
		align-items: center; */
		z-index: 999;
		overflow: hidden;
		flex-direction: column;
	}
	/* 输入项样式 */
	.input-item {
		padding: 20rpx 30rpx;
		background-color: #fff;
		border-bottom: 1rpx solid #f5f5f5;
	}

	.label {
		font-size: 28rpx;
		color: #333;
		display: block;
		margin-bottom: 10rpx;
	}

	.input-content {
		display: flex;
		align-items: center;
		height: 80rpx;
	}

	.placeholder {
		font-size: 28rpx;
		color: #999;
	}

	.value {
		font-size: 28rpx;
		color: #333;
	}

	/* 选择器样式 */
	.picker-container {
		background-color: #fff;
		border-radius: 20rpx 20rpx 0 0;
		position: fixed;
		left: 0;
		right: 0;
		bottom: 0;
		padding-bottom: env(safe-area-inset-bottom);
	}

	.picker-header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: 20rpx 30rpx;
		border-bottom: 1rpx solid #f5f5f5;
	}

	.picker-cancel,
	.picker-confirm {
		font-size: 28rpx;
		color: #666;
	}

	.picker-title {
		font-size: 32rpx;
		color: #333;
		font-weight: bold;
	}

	.picker-body {
		height: 500rpx;
	}

	.picker-item {
		display: flex;
		justify-content: center;
		align-items: center;
		font-size: 28rpx;
		color: #333;
		height: 80rpx;
	}
</style>