小程序修改
This commit is contained in:
@@ -1,48 +1,185 @@
|
||||
import { View, Text } from '@tarojs/components';
|
||||
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;
|
||||
valueLabel?: string;
|
||||
value: RegionSelection;
|
||||
onClose: () => void;
|
||||
onConfirm?: (label: string) => 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,
|
||||
valueLabel = '郑州市',
|
||||
value,
|
||||
onClose,
|
||||
onConfirm,
|
||||
levels = 3,
|
||||
}: RegionPickerProps) {
|
||||
const [draft, setDraft] = useState<RegionSelection>(value);
|
||||
const [activeTab, setActiveTab] = useState<PickerLevel>('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 (
|
||||
<View className="region-picker-mask" onClick={onClose}>
|
||||
<View className="region-picker-overlay" onClick={onClose}>
|
||||
<View className="region-picker-sheet" onClick={(e) => e.stopPropagation()}>
|
||||
<View className="region-picker-head">
|
||||
<Text className="region-picker-cancel" onClick={onClose}>
|
||||
取消
|
||||
</Text>
|
||||
<Text className="region-picker-title">选择区域</Text>
|
||||
<View className="region-picker-toolbar">
|
||||
<View className="region-picker-tabs">
|
||||
{tabs.map((tab) => {
|
||||
const disabled =
|
||||
(tab.key === 'city' && !draft.province) ||
|
||||
(tab.key === 'district' && (!draft.province || !draft.city));
|
||||
return (
|
||||
<Text
|
||||
key={tab.key}
|
||||
className={`region-picker-tab${activeTab === tab.key ? ' active' : ''}${disabled ? ' disabled' : ''}`}
|
||||
onClick={() => !disabled && onTabClick(tab.key)}
|
||||
>
|
||||
{tabLabel(tab.key, draft, tab.label)}
|
||||
</Text>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
<Text
|
||||
className="region-picker-ok"
|
||||
onClick={() => {
|
||||
onConfirm?.(valueLabel);
|
||||
onClose();
|
||||
}}
|
||||
className={`region-picker-confirm${canConfirm ? ' ready' : ''}`}
|
||||
onClick={() => canConfirm && handleConfirm()}
|
||||
>
|
||||
确定
|
||||
</Text>
|
||||
</View>
|
||||
<View className="region-picker-body">
|
||||
<Text className="region-picker-item region-picker-item--active">{valueLabel}</Text>
|
||||
<Text className="u-muted" style={{ display: 'block', marginTop: 12, textAlign: 'center' }}>
|
||||
完整省市区级联后续接入
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<ScrollView className="region-picker-list" scrollY>
|
||||
{listItems.map((item) => (
|
||||
<View
|
||||
key={item}
|
||||
className={`region-picker-option${selectedValue === item ? ' selected' : ''}${
|
||||
item === REGION_ALL ? ' region-picker-option--all' : ''
|
||||
}`}
|
||||
onClick={() => onSelectItem(item)}
|
||||
>
|
||||
<Text>{item}</Text>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user