a487b17165
Use numeric /learn/{num} routes, register Tailwind coin animations with方孔铜钱 UI, expand to 34 provinces, and surface missing OPENAI_API_KEY clearly.
Co-authored-by: Cursor <cursoragent@cursor.com>
89 lines
2.4 KiB
TypeScript
89 lines
2.4 KiB
TypeScript
"use client";
|
||
|
||
import {
|
||
getProvinces,
|
||
getCities,
|
||
getRegionLocation,
|
||
} from "@/lib/data/regions";
|
||
|
||
interface RegionSelectProps {
|
||
provinceCode: string;
|
||
cityCode: string;
|
||
onProvinceChange: (code: string) => void;
|
||
onCityChange: (code: string) => void;
|
||
label?: string;
|
||
cityOptional?: boolean;
|
||
}
|
||
|
||
export default function RegionSelect({
|
||
provinceCode,
|
||
cityCode,
|
||
onProvinceChange,
|
||
onCityChange,
|
||
label = "出生地域",
|
||
cityOptional = true,
|
||
}: RegionSelectProps) {
|
||
const provinces = getProvinces();
|
||
const cities = provinceCode ? getCities(provinceCode) : [];
|
||
const location = provinceCode
|
||
? getRegionLocation(provinceCode, cityCode)
|
||
: null;
|
||
|
||
function handleProvinceChange(code: string) {
|
||
onProvinceChange(code);
|
||
if (!code) {
|
||
onCityChange("");
|
||
return;
|
||
}
|
||
const list = getCities(code);
|
||
onCityChange(list[0]?.code ?? "");
|
||
}
|
||
|
||
return (
|
||
<div className="space-y-2">
|
||
<label className="text-sm font-medium">{label}</label>
|
||
<div className="grid gap-2 sm:grid-cols-2">
|
||
<select
|
||
className="rounded-md border bg-background px-3 py-2 text-sm"
|
||
value={provinceCode}
|
||
onChange={(e) => handleProvinceChange(e.target.value)}
|
||
>
|
||
<option value="">选择省份</option>
|
||
{provinces.map((p) => (
|
||
<option key={p.code} value={p.code}>
|
||
{p.name}
|
||
</option>
|
||
))}
|
||
</select>
|
||
<select
|
||
className="rounded-md border bg-background px-3 py-2 text-sm disabled:opacity-50"
|
||
value={cityCode}
|
||
onChange={(e) => onCityChange(e.target.value)}
|
||
disabled={!provinceCode || cities.length === 0}
|
||
>
|
||
<option value="">
|
||
{cities.length === 0 ? "该省暂无下级城市" : "选择城市"}
|
||
</option>
|
||
{cities.map((c) => (
|
||
<option key={c.code} value={c.code}>
|
||
{c.name}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
{cityOptional && provinceCode && location && (
|
||
<p className="text-xs text-muted-foreground">
|
||
城市可选;未选城市时使用省份经度。当前:
|
||
{location.name}({location.longitude}°)
|
||
</p>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export function useRegionLocation(provinceCode: string, cityCode: string) {
|
||
return provinceCode
|
||
? getRegionLocation(provinceCode, cityCode)
|
||
: null;
|
||
}
|