"use client"; import { useState } from "react"; import { readStreamableValue } from "ai/rsc"; import { Compass, ListRestart } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; import Result from "@/components/result"; import ResultAI from "@/components/result-ai"; import DateTimePicker, { nowDateString, nowTimeString, } from "@/components/shared/datetime-picker"; import HexagramInput from "@/components/shared/hexagram-input"; import RegionSelect, { useRegionLocation, } from "@/components/shared/region-select"; import { getLiuyaoAnswer } from "@/app/actions/liuyao"; import type { GuaResult } from "@/lib/calc/hexagram"; import { ERROR_PREFIX } from "@/lib/constant"; import todayJson from "@/lib/data/today.json"; const todayData: string[] = todayJson; export default function LiuyaoForm() { const [question, setQuestion] = useState(""); const [provinceCode, setProvinceCode] = useState(""); const [cityCode, setCityCode] = useState(""); const [calcDate, setCalcDate] = useState(nowDateString); const [calcTime, setCalcTime] = useState(nowTimeString); const [castMode, setCastMode] = useState<"online" | "offline">("online"); const [guaData, setGuaData] = useState(null); const [completion, setCompletion] = useState(""); const [error, setError] = useState(""); const [isLoading, setIsLoading] = useState(false); const [showAi, setShowAi] = useState(false); const location = useRegionLocation(provinceCode, cityCode); const formReady = question.trim() !== "" && location !== null; function validate(): string | null { if (!question.trim()) { return "请输入问事"; } if (!location) { return "请选择起卦地域"; } if (!guaData) { return "请先完成起卦(线上摇卦或线下录入)"; } return null; } async function handleAnalyze() { const err = validate(); if (err) { setError(err); return; } setError(""); setCompletion(""); setIsLoading(true); setShowAi(true); try { const { data, error: apiError } = await getLiuyaoAnswer({ question, calcDate, calcTime, locationName: location!.name, longitude: location!.longitude, guaMark: guaData!.result.guaMark, guaTitle: guaData!.result.guaTitle, guaResult: guaData!.result.guaResult, guaChange: guaData!.result.guaChange, }); if (apiError) { setError(apiError); return; } if (data) { let ret = ""; for await (const delta of readStreamableValue(data)) { if (typeof delta === "string" && delta.startsWith(ERROR_PREFIX)) { setError(delta.slice(ERROR_PREFIX.length)); return; } ret += delta ?? ""; setCompletion(ret); } } } catch (e) { setError(e instanceof Error ? e.message : String(e)); } finally { setIsLoading(false); } } function handleReset() { setQuestion(""); setProvinceCode(""); setCityCode(""); setCalcDate(nowDateString()); setCalcTime(nowTimeString()); setGuaData(null); setCompletion(""); setError(""); setShowAi(false); setIsLoading(false); } function handleGuaResult(data: GuaResult) { setGuaData(data); setShowAi(false); setCompletion(""); } return (