'use client' import { useCallback, useEffect, useMemo, useState } from 'react' import { useRouter } from 'next/navigation' import { createBirthProfile, createNatalChart, getCnCities, getCnCounties, getCnProvinces, getHealth, PlaceItem, } from '../../lib/apiClient' import { Button, Card, Field, InlineMessage, Input, PageShell, Select } from '../../components/ui' type TimeConfidence = 'exact' | 'approximate' | 'unknown' | 'rectified' type HouseSystem = 'whole_sign' | 'equal' | 'porphyry' | 'placidus' export default function CreateClient() { const router = useRouter() const [error, setError] = useState(null) const [backendError, setBackendError] = useState(null) const [submitting, setSubmitting] = useState(false) const [name, setName] = useState('我') const [birthDate, setBirthDate] = useState('2000-01-01') const [birthTime, setBirthTime] = useState('12:00:00') const [timeConfidence, setTimeConfidence] = useState('exact') const [houseSystem, setHouseSystem] = useState('placidus') const [provinces, setProvinces] = useState([]) const [cities, setCities] = useState([]) const [counties, setCounties] = useState([]) const [loadingCities, setLoadingCities] = useState(false) const [loadingCounties, setLoadingCounties] = useState(false) const [provinceCode, setProvinceCode] = useState('') const [cityCode, setCityCode] = useState('') const [countyCode, setCountyCode] = useState('') const [countyFilter, setCountyFilter] = useState('') const filteredCounties = useMemo(() => { const q = countyFilter.trim() if (!q) return counties return counties.filter((x) => x.name.includes(q)) }, [counties, countyFilter]) const selectCity = useCallback(async (code: string) => { setCityCode(code) setCounties([]) setCountyCode('') setCountyFilter('') if (!code) return setLoadingCounties(true) try { const xs = await getCnCounties(code) setCounties(xs) setCountyCode(xs[0]?.code ?? '') } catch (e: unknown) { setError(e instanceof Error ? e.message : 'load_counties_failed') } finally { setLoadingCounties(false) } }, []) const selectProvince = useCallback( async (code: string) => { setProvinceCode(code) setCities([]) setCityCode('') setCounties([]) setCountyCode('') setCountyFilter('') if (!code) return setLoadingCities(true) try { const xs = await getCnCities(code) setCities(xs) const firstCity = xs[0]?.code ?? '' await selectCity(firstCity) } catch (e: unknown) { setError(e instanceof Error ? e.message : 'load_cities_failed') } finally { setLoadingCities(false) } }, [selectCity] ) useEffect(() => { let aborted = false getHealth() .then(() => { if (aborted) return setBackendError(null) }) .catch(() => { if (aborted) return setBackendError('后端不可访问:请确认后端服务已启动,或检查前端的后端地址配置。') }) getCnProvinces() .then((xs) => { if (aborted) return setProvinces(xs) const first = xs[0]?.code ?? '' if (first) selectProvince(first) }) .catch((e: unknown) => { if (aborted) return setError(e instanceof Error ? e.message : 'load_provinces_failed') }) return () => { aborted = true } }, [selectProvince]) async function submit() { setError(null) setSubmitting(true) try { if (!countyCode) throw new Error('county_required') const bp = await createBirthProfile({ name, birth_date: birthDate, birth_time: timeConfidence === 'unknown' ? null : birthTime, time_confidence: timeConfidence, birth_place_adcode: countyCode, }) const chart = await createNatalChart({ profile_id: bp.profile_id, calculation_profile: { ephemeris: 'DE440', zodiac: 'tropical', house_system: houseSystem, orb_profile: 'western_default_v1', position_type: 'apparent', ecliptic_epoch: 'date', }, }) router.push(`/charts/${encodeURIComponent(chart.chart_id)}`) } catch (e: unknown) { setError(e instanceof Error ? e.message : 'submit_failed') } finally { setSubmitting(false) } } return ( {backendError ? {backendError} : null}
setName(e.target.value)} />
setBirthDate(e.target.value)} placeholder="YYYY-MM-DD" /> setBirthTime(e.target.value)} placeholder="HH:MM:SS" disabled={timeConfidence === 'unknown'} />
setCountyFilter(e.target.value)} placeholder="输入关键字筛选县/区" />
{error ? {error} : null}
{countyCode ? `已选择:${countyCode}` : '请选择县/区后再创建'}
) }