项目建档:列表页、新建、查看
This commit is contained in:
336
src/components/CitySelect.tsx
Normal file
336
src/components/CitySelect.tsx
Normal file
@ -0,0 +1,336 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Select, Row, Col } from 'antd';
|
||||
import type { FormInstance } from 'antd/lib/form';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
// 省市区数据结构
|
||||
interface District {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
interface City {
|
||||
value: string;
|
||||
label: string;
|
||||
districts: District[];
|
||||
}
|
||||
|
||||
interface Province {
|
||||
value: string;
|
||||
label: string;
|
||||
cities: City[];
|
||||
}
|
||||
|
||||
// 模拟省市区数据
|
||||
const provinceData: Province[] = [
|
||||
{
|
||||
value: 'beijing',
|
||||
label: '北京市',
|
||||
cities: [
|
||||
{
|
||||
value: 'dongcheng',
|
||||
label: '东城区',
|
||||
districts: [
|
||||
{ value: 'chaoyangmen', label: '朝阳门街道' },
|
||||
{ value: 'jianguomennei', label: '建国门内街道' },
|
||||
{ value: 'donghuamen', label: '东华门街道' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'xicheng',
|
||||
label: '西城区',
|
||||
districts: [
|
||||
{ value: 'xichang', label: '西长安街街道' },
|
||||
{ value: 'xinjieku', label: '新街口街道' },
|
||||
{ value: 'yuetan', label: '月坛街道' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'chaoyang',
|
||||
label: '朝阳区',
|
||||
districts: [
|
||||
{ value: 'jianwai', label: '建外街道' },
|
||||
{ value: 'chaowai', label: '朝外街道' },
|
||||
{ value: 'hujialou', label: '呼家楼街道' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'shanghai',
|
||||
label: '上海市',
|
||||
cities: [
|
||||
{
|
||||
value: 'huangpu',
|
||||
label: '黄浦区',
|
||||
districts: [
|
||||
{ value: 'nanking', label: '南京东路街道' },
|
||||
{ value: 'waitan', label: '外滩街道' },
|
||||
{ value: 'yuyuan', label: '豫园街道' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'xuhui',
|
||||
label: '徐汇区',
|
||||
districts: [
|
||||
{ value: 'xujiahui', label: '徐家汇街道' },
|
||||
{ value: 'tianlin', label: '田林街道' },
|
||||
{ value: 'kangjianlou', label: '康健楼街道' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'changning',
|
||||
label: '长宁区',
|
||||
districts: [
|
||||
{ value: 'huayang', label: '华阳路街道' },
|
||||
{ value: 'jiangsu', label: '江苏路街道' },
|
||||
{ value: 'xinhua', label: '新华路街道' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'guangdong',
|
||||
label: '广东省',
|
||||
cities: [
|
||||
{
|
||||
value: 'guangzhou',
|
||||
label: '广州市',
|
||||
districts: [
|
||||
{ value: 'yuexiu', label: '越秀区' },
|
||||
{ value: 'liwan', label: '荔湾区' },
|
||||
{ value: 'haizhu', label: '海珠区' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'shenzhen',
|
||||
label: '深圳市',
|
||||
districts: [
|
||||
{ value: 'futian', label: '福田区' },
|
||||
{ value: 'luohu', label: '罗湖区' },
|
||||
{ value: 'nanshan', label: '南山区' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'zhuhai',
|
||||
label: '珠海市',
|
||||
districts: [
|
||||
{ value: 'xiangzhou', label: '香洲区' },
|
||||
{ value: 'doumen', label: '斗门区' },
|
||||
{ value: 'jinwan', label: '金湾区' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'jiangsu',
|
||||
label: '江苏省',
|
||||
cities: [
|
||||
{
|
||||
value: 'nanjing',
|
||||
label: '南京市',
|
||||
districts: [
|
||||
{ value: 'xuanwu', label: '玄武区' },
|
||||
{ value: 'qinhuai', label: '秦淮区' },
|
||||
{ value: 'jianye', label: '建邺区' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'suzhou',
|
||||
label: '苏州市',
|
||||
districts: [
|
||||
{ value: 'gusu', label: '姑苏区' },
|
||||
{ value: 'wuzhong', label: '吴中区' },
|
||||
{ value: 'xiangcheng', label: '相城区' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export interface CitySelectValue {
|
||||
province?: string;
|
||||
city?: string;
|
||||
district?: string;
|
||||
}
|
||||
|
||||
export interface CitySelectProps {
|
||||
value?: CitySelectValue;
|
||||
onChange?: (value: CitySelectValue) => void;
|
||||
form?: FormInstance;
|
||||
placeholder?: {
|
||||
province?: string;
|
||||
city?: string;
|
||||
district?: string;
|
||||
};
|
||||
disabled?: boolean;
|
||||
size?: 'large' | 'middle' | 'small';
|
||||
}
|
||||
|
||||
const CitySelect: React.FC<CitySelectProps> = ({
|
||||
value = {},
|
||||
onChange,
|
||||
form,
|
||||
placeholder = {
|
||||
province: '请选择省份',
|
||||
city: '请选择城市',
|
||||
district: '请选择区域',
|
||||
},
|
||||
disabled = false,
|
||||
size = 'middle',
|
||||
}) => {
|
||||
const [cities, setCities] = useState<City[]>([]);
|
||||
const [districts, setDistricts] = useState<District[]>([]);
|
||||
const [selectedProvince, setSelectedProvince] = useState<string | undefined>(value.province);
|
||||
const [selectedCity, setSelectedCity] = useState<string | undefined>(value.city);
|
||||
const [selectedDistrict, setSelectedDistrict] = useState<string | undefined>(value.district);
|
||||
|
||||
|
||||
|
||||
// 处理省份选择变化
|
||||
const handleProvinceChange = (provinceValue?: string) => {
|
||||
setSelectedProvince(provinceValue);
|
||||
setSelectedCity(undefined);
|
||||
setSelectedDistrict(undefined);
|
||||
setDistricts([]);
|
||||
|
||||
if (provinceValue) {
|
||||
const province = provinceData.find(p => p.value === provinceValue);
|
||||
setCities(province?.cities || []);
|
||||
} else {
|
||||
setCities([]);
|
||||
}
|
||||
|
||||
// 清空城市和区域的表单字段
|
||||
if (form) {
|
||||
form.setFieldsValue({
|
||||
city: undefined,
|
||||
district: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
// 触发变化回调
|
||||
const newValue: CitySelectValue = {
|
||||
province: provinceValue,
|
||||
city: undefined,
|
||||
district: undefined,
|
||||
};
|
||||
onChange?.(newValue);
|
||||
};
|
||||
|
||||
// 处理城市选择变化
|
||||
const handleCityChange = (cityValue?: string) => {
|
||||
setSelectedCity(cityValue);
|
||||
setSelectedDistrict(undefined);
|
||||
|
||||
if (cityValue && selectedProvince) {
|
||||
const province = provinceData.find(p => p.value === selectedProvince);
|
||||
const city = province?.cities.find(c => c.value === cityValue);
|
||||
setDistricts(city?.districts || []);
|
||||
} else {
|
||||
setDistricts([]);
|
||||
}
|
||||
|
||||
// 清空区域的表单字段
|
||||
if (form) {
|
||||
form.setFieldsValue({
|
||||
district: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
// 触发变化回调
|
||||
const newValue: CitySelectValue = {
|
||||
province: selectedProvince,
|
||||
city: cityValue,
|
||||
district: undefined,
|
||||
};
|
||||
onChange?.(newValue);
|
||||
};
|
||||
|
||||
// 处理区域选择变化
|
||||
const handleDistrictChange = (districtValue?: string) => {
|
||||
setSelectedDistrict(districtValue);
|
||||
|
||||
// 触发变化回调
|
||||
const newValue: CitySelectValue = {
|
||||
province: selectedProvince,
|
||||
city: selectedCity,
|
||||
district: districtValue,
|
||||
};
|
||||
onChange?.(newValue);
|
||||
};
|
||||
|
||||
// 监听外部值变化
|
||||
useEffect(() => {
|
||||
if (value.province !== selectedProvince) {
|
||||
setSelectedProvince(value.province);
|
||||
handleProvinceChange(value.province);
|
||||
}
|
||||
if (value.city !== selectedCity) {
|
||||
setSelectedCity(value.city);
|
||||
handleCityChange(value.city);
|
||||
}
|
||||
if (value.district !== selectedDistrict) {
|
||||
setSelectedDistrict(value.district);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Row gutter={8}>
|
||||
<Col span={8}>
|
||||
<Select
|
||||
placeholder={placeholder.province}
|
||||
value={selectedProvince}
|
||||
onChange={handleProvinceChange}
|
||||
disabled={disabled}
|
||||
size={size}
|
||||
style={{ width: '100%' }}
|
||||
allowClear
|
||||
>
|
||||
{provinceData.map(province => (
|
||||
<Option key={province.value} value={province.value}>
|
||||
{province.label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Select
|
||||
placeholder={placeholder.city}
|
||||
value={selectedCity}
|
||||
onChange={handleCityChange}
|
||||
disabled={disabled || !selectedProvince}
|
||||
size={size}
|
||||
style={{ width: '100%' }}
|
||||
allowClear
|
||||
>
|
||||
{cities.map(city => (
|
||||
<Option key={city.value} value={city.value}>
|
||||
{city.label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Select
|
||||
placeholder={placeholder.district}
|
||||
value={selectedDistrict}
|
||||
onChange={handleDistrictChange}
|
||||
disabled={disabled || !selectedCity}
|
||||
size={size}
|
||||
style={{ width: '100%' }}
|
||||
allowClear
|
||||
>
|
||||
{districts.map(district => (
|
||||
<Option key={district.value} value={district.value}>
|
||||
{district.label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default CitySelect;
|
Reference in New Issue
Block a user