import { getArea } from '@/services/address'; import React, { useEffect, useState } from 'react'; import { ActivityIndicator, Dimensions, Modal, ScrollView, StyleSheet, Text, TouchableOpacity, View, } from 'react-native'; interface AreaItem { id: string; name: string; pid?: number; } interface RegionPickerProps { visible: boolean; onClose: () => void; onSelect: (province: string, city: string, district: string) => void; } const { width, height } = Dimensions.get('window'); export const RegionPicker: React.FC = ({ visible, onClose, onSelect, }) => { const [loading, setLoading] = useState(false); const [tabs, setTabs] = useState(['请选择', '', '']); const [activeTab, setActiveTab] = useState(0); const [provinces, setProvinces] = useState([]); const [cities, setCities] = useState([]); const [districts, setDistricts] = useState([]); const [selectedProvince, setSelectedProvince] = useState(null); const [selectedCity, setSelectedCity] = useState(null); // District selection ends the flow useEffect(() => { if (visible && provinces.length === 0) { loadProvinces(); } }, [visible]); const loadProvinces = async () => { setLoading(true); try { // 省级节点的 pid 通常为 1(中国节点),先尝试 1,空则回退 0 let list = await getArea(1); if (!list || list.length === 0) { list = await getArea(0); } setProvinces(list || []); } catch (e) { console.error('加载省份数据失败:', e); } setLoading(false); }; const handleSelect = async (item: AreaItem) => { if (activeTab === 0) { // Province selected setSelectedProvince(item); setTabs([item.name, '请选择', '']); setActiveTab(1); setLoading(true); const list = await getArea(Number(item.id)); setCities(list || []); setLoading(false); } else if (activeTab === 1) { // City selected setSelectedCity(item); setTabs([selectedProvince!.name, item.name, '请选择']); setActiveTab(2); setLoading(true); const list = await getArea(Number(item.id)); setDistricts(list || []); setLoading(false); } else { // District selected onSelect(selectedProvince!.name, selectedCity!.name, item.name); onClose(); } }; const handleTabPress = (index: number) => { // Only allow going back to previous tabs if data exists if (index < activeTab) { setActiveTab(index); } }; const renderList = () => { let data : AreaItem[] = []; if (activeTab === 0) data = provinces; else if (activeTab === 1) data = cities; else data = districts; // Filter out invalid items if strictly needed, but let's trust API return ( {data.map((item) => { const isSelected = (activeTab === 0 && item.id === selectedProvince?.id) || (activeTab === 1 && item.id === selectedCity?.id); return ( handleSelect(item)} > {item.name} {isSelected && } )})} ); }; return ( 配送至 {tabs.map((tab, index) => ( tab ? ( handleTabPress(index)} style={[styles.tabItem, activeTab === index && styles.tabItemActive]} disabled={!tab || (index > activeTab)} > {tab} {activeTab === index && } ) : null ))} {loading ? ( ) : ( renderList() )} ); }; const styles = StyleSheet.create({ mask: { flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'flex-end', }, maskClickable: { flex: 1, }, container: { height: height * 0.7, // 70% height backgroundColor: '#fff', borderTopLeftRadius: 16, borderTopRightRadius: 16, }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', // Title centered height: 50, borderBottomWidth: 1, borderBottomColor: '#eee', position: 'relative', }, title: { fontSize: 16, fontWeight: 'bold', color: '#333', }, closeBtn: { position: 'absolute', right: 15, top: 0, bottom: 0, justifyContent: 'center', paddingHorizontal: 10, }, closeText: { fontSize: 18, color: '#999', }, tabs: { flexDirection: 'row', borderBottomWidth: 1, borderBottomColor: '#eee', paddingHorizontal: 15, }, tabItem: { marginRight: 25, height: 44, justifyContent: 'center', position: 'relative', }, tabItemActive: {}, tabText: { fontSize: 14, color: '#333', }, tabTextActive: { color: '#e79018', fontWeight: 'bold', }, tabLine: { position: 'absolute', bottom: 0, left: '10%', width: '80%', height: 2, backgroundColor: '#e79018', }, loadingBox: { flex: 1, justifyContent: 'center', alignItems: 'center', }, listContent: { paddingBottom: 40, }, item: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingVertical: 14, paddingHorizontal: 15, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: '#f5f5f5', }, itemText: { fontSize: 14, color: '#333', }, itemTextActive: { color: '#e79018', }, checkIcon: { color: '#e79018', fontSize: 16, }, });