| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- import React, { useState, useEffect } from 'react';
- import { useQuery } from '@tanstack/react-query';
- import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
- } from '@/client/components/ui/select';
- import { FormItem, FormLabel, FormControl, FormMessage } from '@/client/components/ui/form';
- import { cityClient } from '@/client/api';
- interface CityCascadeSelectorProps {
- provinceValue?: number;
- cityValue?: number;
- districtValue?: number;
- townValue?: number;
- onProvinceChange?: (value: number) => void;
- onCityChange?: (value: number) => void;
- onDistrictChange?: (value: number) => void;
- onTownChange?: (value: number) => void;
- disabled?: boolean;
- showLabels?: boolean;
- }
- interface City {
- id: number;
- name: string;
- level: number;
- parentId: number;
- }
- export const CityCascadeSelector: React.FC<CityCascadeSelectorProps> = ({
- provinceValue,
- cityValue,
- districtValue,
- townValue,
- onProvinceChange,
- onCityChange,
- onDistrictChange,
- onTownChange,
- disabled = false,
- showLabels = true,
- }) => {
- // 获取省份数据 (level=1)
- const { data: provinces } = useQuery({
- queryKey: ['cities', 'provinces'],
- queryFn: async () => {
- const res = await cityClient.$get({
- query: {
- page: 1,
- pageSize: 100,
- filters: JSON.stringify({ level: 1 }),
- },
- });
- if (res.status !== 200) throw new Error('获取省份数据失败');
- const data = await res.json();
- return data.data as City[];
- },
- });
- // 获取城市数据 (level=2)
- const { data: cities } = useQuery({
- queryKey: ['cities', 'cities', provinceValue],
- queryFn: async () => {
- if (!provinceValue) return [];
- const res = await cityClient.$get({
- query: {
- page: 1,
- pageSize: 100,
- filters: JSON.stringify({ level: 2, parentId: provinceValue }),
- },
- });
- if (res.status !== 200) throw new Error('获取城市数据失败');
- const data = await res.json();
- return data.data as City[];
- },
- enabled: !!provinceValue,
- });
- // 获取区县数据 (level=3)
- const { data: districts } = useQuery({
- queryKey: ['cities', 'districts', cityValue],
- queryFn: async () => {
- if (!cityValue) return [];
- const res = await cityClient.$get({
- query: {
- page: 1,
- pageSize: 100,
- filters: JSON.stringify({ level: 3, parentId: cityValue }),
- },
- });
- if (res.status !== 200) throw new Error('获取区县数据失败');
- const data = await res.json();
- return data.data as City[];
- },
- enabled: !!cityValue,
- });
- // 获取街道数据 (level=4)
- const { data: towns } = useQuery({
- queryKey: ['cities', 'towns', districtValue],
- queryFn: async () => {
- if (!districtValue) return [];
- const res = await cityClient.$get({
- query: {
- page: 1,
- pageSize: 100,
- filters: JSON.stringify({ level: 4, parentId: districtValue }),
- },
- });
- if (res.status !== 200) throw new Error('获取街道数据失败');
- const data = await res.json();
- return data.data as City[];
- },
- enabled: !!districtValue,
- });
- // 清除下级选择器
- useEffect(() => {
- if (!provinceValue && cityValue !== undefined) {
- onCityChange?.(0);
- }
- }, [provinceValue, cityValue]);
- useEffect(() => {
- if (!cityValue && districtValue !== undefined) {
- onDistrictChange?.(0);
- }
- }, [cityValue, districtValue]);
- useEffect(() => {
- if (!districtValue && townValue !== undefined) {
- onTownChange?.(0);
- }
- }, [districtValue, townValue]);
- const renderSelect = (
- label: string,
- value: number | undefined,
- onChange: ((value: number) => void) | undefined,
- options: City[] | undefined,
- placeholder: string
- ) => (
- <FormItem>
- {showLabels && <FormLabel>{label}</FormLabel>}
- <FormControl>
- <Select
- value={value?.toString() || ''}
- onValueChange={(val) => onChange?.(parseInt(val))}
- disabled={disabled || !options?.length}
- >
- <SelectTrigger>
- <SelectValue placeholder={placeholder} />
- </SelectTrigger>
- <SelectContent>
- {options?.map((option) => (
- <SelectItem key={option.id} value={option.id.toString()}>
- {option.name}
- </SelectItem>
- ))}
- </SelectContent>
- </Select>
- </FormControl>
- </FormItem>
- );
- return (
- <div className="grid grid-cols-4 gap-4">
- {renderSelect(
- '省份',
- provinceValue,
- onProvinceChange,
- provinces,
- '选择省份'
- )}
-
- {renderSelect(
- '城市',
- cityValue,
- onCityChange,
- cities,
- provinceValue ? '选择城市' : '请先选择省份'
- )}
-
- {renderSelect(
- '区县',
- districtValue,
- onDistrictChange,
- districts,
- cityValue ? '选择区县' : '请先选择城市'
- )}
-
- {renderSelect(
- '街道',
- townValue,
- onTownChange,
- towns,
- districtValue ? '选择街道' : '请先选择区县'
- )}
- </div>
- );
- };
|