import { useEffect, useMemo, useState } from 'react'; import { View, Text, ScrollView } from '@tarojs/components'; import { REGION_ALL, getCities, getCitiesForPicker, getDistricts, getDistrictsForPicker, getProvincesForPicker, normalizeRegionSelection, toCityLevelRegion, type RegionSelection, } from '../lib/region-data'; type RegionPickerProps = { open: boolean; value: RegionSelection; onClose: () => void; onConfirm: (region: RegionSelection) => void; levels?: 2 | 3; }; type PickerLevel = 'province' | 'city' | 'district'; const ALL_TABS: Array<{ key: PickerLevel; label: string }> = [ { key: 'province', label: '省份' }, { key: 'city', label: '城市' }, { key: 'district', label: '区县' }, ]; function initialTab(value: RegionSelection, levels: 2 | 3): PickerLevel { const normalized = levels === 2 ? toCityLevelRegion(value) : normalizeRegionSelection(value); if (levels === 2) { return normalized.province && normalized.province !== REGION_ALL ? 'city' : 'province'; } if (normalized.district && normalized.district !== REGION_ALL) return 'district'; if (normalized.city && normalized.city !== REGION_ALL) return 'city'; return 'province'; } function tabLabel(tab: PickerLevel, draft: RegionSelection, fallback: string) { if (tab === 'province') { return draft.province && draft.province !== REGION_ALL ? draft.province : fallback; } if (tab === 'city') { return draft.city && draft.city !== REGION_ALL ? draft.city : fallback; } return draft.district && draft.district !== REGION_ALL ? draft.district : fallback; } export default function RegionPicker({ open, value, onClose, onConfirm, levels = 3, }: RegionPickerProps) { const [draft, setDraft] = useState(value); const [activeTab, setActiveTab] = useState('province'); const tabs = levels === 2 ? ALL_TABS.slice(0, 2) : ALL_TABS; useEffect(() => { if (!open) return; const normalized = levels === 2 ? toCityLevelRegion(value) : normalizeRegionSelection(value); setDraft(normalized); setActiveTab(initialTab(value, levels)); }, [open, value, levels]); const listItems = useMemo(() => { if (activeTab === 'province') return getProvincesForPicker(); if (activeTab === 'city') return getCitiesForPicker(draft.province); return getDistrictsForPicker(draft.province, draft.city); }, [activeTab, draft.province, draft.city]); const selectedValue = activeTab === 'province' ? draft.province : activeTab === 'city' ? draft.city : draft.district; const canConfirm = levels === 2 ? Boolean(draft.province && draft.city) : Boolean(draft.province && draft.city && draft.district); if (!open) return null; function selectProvince(province: string) { if (province === REGION_ALL) { setDraft({ province: REGION_ALL, city: REGION_ALL, district: REGION_ALL }); setActiveTab('city'); return; } const nextCities = getCities(province); const city = nextCities[0] ?? ''; if (levels === 2) { setDraft({ province, city, district: REGION_ALL }); setActiveTab('city'); return; } const nextDistricts = getDistricts(province, city); setDraft({ province, city, district: nextDistricts[0] ?? '' }); setActiveTab('city'); } function selectCity(city: string) { if (city === REGION_ALL) { setDraft({ ...draft, city: REGION_ALL, district: REGION_ALL }); if (levels === 3) setActiveTab('district'); return; } if (levels === 2) { setDraft({ ...draft, city, district: REGION_ALL }); return; } const nextDistricts = getDistricts(draft.province, city); setDraft({ ...draft, city, district: nextDistricts[0] ?? '' }); setActiveTab('district'); } function selectDistrict(district: string) { setDraft({ ...draft, district }); } function onSelectItem(item: string) { if (activeTab === 'province') selectProvince(item); else if (activeTab === 'city') selectCity(item); else selectDistrict(item); } function onTabClick(tab: PickerLevel) { if (tab === 'city' && !draft.province) return; if (tab === 'district' && (!draft.province || !draft.city)) return; setActiveTab(tab); } function handleConfirm() { if (!canConfirm) return; const next = levels === 2 ? toCityLevelRegion(draft) : normalizeRegionSelection(draft); onConfirm(next); onClose(); } return ( e.stopPropagation()}> {tabs.map((tab) => { const disabled = (tab.key === 'city' && !draft.province) || (tab.key === 'district' && (!draft.province || !draft.city)); return ( !disabled && onTabClick(tab.key)} > {tabLabel(tab.key, draft, tab.label)} ); })} canConfirm && handleConfirm()} > 确定 {listItems.map((item) => ( onSelectItem(item)} > {item} ))} ); }