项目建档:列表页、新建、查看

This commit is contained in:
lix
2025-06-12 17:16:06 +08:00
parent 1b8ef1b5e2
commit 94222c2b89
10 changed files with 1486 additions and 1 deletions

View 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;