Store calculation history on server with bazi input and chart snapshots.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import { Download, Trash2 } from "lucide-react";
|
||||
import PageShell from "@/components/page-shell";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ZenCard } from "@/components/ui/zen-card";
|
||||
import BaziChartDisplay from "@/components/modes/bazi-chart";
|
||||
import Markdown from "react-markdown";
|
||||
import {
|
||||
buildHistoryMarkdown,
|
||||
@@ -18,21 +19,46 @@ import { MODE_LABELS, type CalcHistoryEntry } from "@/lib/history/types";
|
||||
export default function HistoryPageClient() {
|
||||
const [items, setItems] = useState<CalcHistoryEntry[]>([]);
|
||||
const [activeId, setActiveId] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const list = loadHistory();
|
||||
setItems(list);
|
||||
setActiveId(list[0]?.id ?? null);
|
||||
let cancelled = false;
|
||||
(async () => {
|
||||
try {
|
||||
const list = await loadHistory();
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
setItems(list);
|
||||
setActiveId(list[0]?.id ?? null);
|
||||
} catch (e) {
|
||||
if (!cancelled) {
|
||||
setError(e instanceof Error ? e.message : String(e));
|
||||
}
|
||||
} finally {
|
||||
if (!cancelled) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const active = items.find((e) => e.id === activeId) ?? null;
|
||||
|
||||
function handleDelete(id: string) {
|
||||
deleteHistoryEntry(id);
|
||||
const next = loadHistory();
|
||||
setItems(next);
|
||||
if (activeId === id) {
|
||||
setActiveId(next[0]?.id ?? null);
|
||||
async function handleDelete(id: string) {
|
||||
try {
|
||||
await deleteHistoryEntry(id);
|
||||
const next = items.filter((item) => item.id !== id);
|
||||
setItems(next);
|
||||
if (activeId === id) {
|
||||
setActiveId(next[0]?.id ?? null);
|
||||
}
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : String(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,11 +67,17 @@ export default function HistoryPageClient() {
|
||||
<div className="mb-6 text-center">
|
||||
<h1 className="text-2xl font-bold tracking-wide">测算历史</h1>
|
||||
<p className="mt-2 text-sm text-muted-foreground">
|
||||
本机浏览器保存,清除缓存后可能丢失
|
||||
保存在服务器,按登录账号区分
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{items.length === 0 ? (
|
||||
{loading ? (
|
||||
<ZenCard className="text-center text-sm text-muted-foreground">
|
||||
加载中…
|
||||
</ZenCard>
|
||||
) : error ? (
|
||||
<ZenCard className="text-center text-sm text-destructive">{error}</ZenCard>
|
||||
) : items.length === 0 ? (
|
||||
<ZenCard className="text-center text-sm text-muted-foreground">
|
||||
<p>暂无测算记录</p>
|
||||
<Link href="/liuyao" className="mt-3 inline-block text-primary underline">
|
||||
@@ -70,6 +102,14 @@ export default function HistoryPageClient() {
|
||||
<p className="mt-1 line-clamp-2 text-xs text-muted-foreground">
|
||||
{item.question}
|
||||
</p>
|
||||
{item.baziChart && (
|
||||
<p className="mt-1 font-mono text-xs text-muted-foreground">
|
||||
{item.baziChart.pillars.year.ganZhi}{" "}
|
||||
{item.baziChart.pillars.month.ganZhi}{" "}
|
||||
{item.baziChart.pillars.day.ganZhi}{" "}
|
||||
{item.baziChart.pillars.time.ganZhi}
|
||||
</p>
|
||||
)}
|
||||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
{MODE_LABELS[item.mode]} ·{" "}
|
||||
{new Date(item.createdAt).toLocaleString("zh-CN")}
|
||||
@@ -87,6 +127,27 @@ export default function HistoryPageClient() {
|
||||
{active.summary && (
|
||||
<p className="text-sm text-muted-foreground">{active.summary}</p>
|
||||
)}
|
||||
{active.baziInput && (
|
||||
<div className="rounded-md border bg-background/50 p-3 text-sm text-muted-foreground">
|
||||
<p>
|
||||
出生:{active.baziInput.birthPlaceName} ·{" "}
|
||||
{active.baziInput.date}{" "}
|
||||
{active.baziInput.unknownHour
|
||||
? "时辰不详"
|
||||
: active.baziInput.time}{" "}
|
||||
· {active.baziInput.gender === "male" ? "男" : "女"}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{active.baziChart && <BaziChartDisplay chart={active.baziChart} />}
|
||||
{active.hexagram && (
|
||||
<div className="rounded-md border bg-background/50 p-3 text-sm">
|
||||
<p className="font-medium">{active.hexagram.guaTitle}</p>
|
||||
<p className="mt-1 text-muted-foreground">
|
||||
{active.hexagram.guaResult}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
|
||||
@@ -92,16 +92,27 @@ export default function BaziForm() {
|
||||
},
|
||||
setCompletion,
|
||||
);
|
||||
saveHistoryEntry({
|
||||
await saveHistoryEntry({
|
||||
mode: "bazi",
|
||||
title: "生辰八字解读",
|
||||
question,
|
||||
summary: activeChart.lunarDate,
|
||||
completion: text,
|
||||
baziInput: {
|
||||
date: input.date,
|
||||
time: input.time,
|
||||
gender: input.gender,
|
||||
longitude: input.longitude,
|
||||
unknownHour: !!input.unknownHour,
|
||||
birthPlaceName: location!.name,
|
||||
},
|
||||
baziChart: activeChart,
|
||||
meta: {
|
||||
出生地域: location!.name,
|
||||
阳历生日: `${input.date} ${input.time}`,
|
||||
阳历生日: `${input.date} ${unknownHour ? "时辰不详" : input.time}`,
|
||||
农历: activeChart.lunarDate,
|
||||
性别: gender === "male" ? "男" : "女",
|
||||
四柱: `${activeChart.pillars.year.ganZhi} ${activeChart.pillars.month.ganZhi} ${activeChart.pillars.day.ganZhi} ${activeChart.pillars.time.ganZhi}`,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@@ -155,16 +155,37 @@ export default function CombinedForm() {
|
||||
},
|
||||
setCompletion,
|
||||
);
|
||||
saveHistoryEntry({
|
||||
await saveHistoryEntry({
|
||||
mode: "combined",
|
||||
title: "综合测算解读",
|
||||
question,
|
||||
summary: activeChart.lunarDate,
|
||||
completion: text,
|
||||
baziInput: {
|
||||
date: birthDate,
|
||||
time: unknownHour ? "12:00" : birthTime,
|
||||
gender,
|
||||
longitude: birthLocation!.longitude,
|
||||
unknownHour,
|
||||
birthPlaceName: birthLocation!.name,
|
||||
},
|
||||
baziChart: activeChart,
|
||||
hexagram:
|
||||
withHexagram && guaData
|
||||
? {
|
||||
guaMark: guaData.result.guaMark,
|
||||
guaTitle: guaData.result.guaTitle,
|
||||
guaResult: guaData.result.guaResult,
|
||||
guaChange: guaData.result.guaChange,
|
||||
}
|
||||
: undefined,
|
||||
meta: {
|
||||
出生地域: birthLocation!.name,
|
||||
当前地域: currentLocation!.name,
|
||||
测算时间: `${calcDate} ${calcTime}`,
|
||||
农历: activeChart.lunarDate,
|
||||
性别: gender === "male" ? "男" : "女",
|
||||
四柱: `${activeChart.pillars.year.ganZhi} ${activeChart.pillars.month.ganZhi} ${activeChart.pillars.day.ganZhi} ${activeChart.pillars.time.ganZhi}`,
|
||||
六爻: withHexagram && guaData ? guaData.result.guaTitle : "无",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -86,12 +86,18 @@ export default function LiuyaoForm() {
|
||||
},
|
||||
setCompletion,
|
||||
);
|
||||
saveHistoryEntry({
|
||||
await saveHistoryEntry({
|
||||
mode: "liuyao",
|
||||
title: guaData!.result.guaTitle,
|
||||
question,
|
||||
summary: guaData!.result.guaResult,
|
||||
completion: text,
|
||||
hexagram: {
|
||||
guaMark: guaData!.result.guaMark,
|
||||
guaTitle: guaData!.result.guaTitle,
|
||||
guaResult: guaData!.result.guaResult,
|
||||
guaChange: guaData!.result.guaChange,
|
||||
},
|
||||
meta: {
|
||||
地域: location!.name,
|
||||
起卦时间: `${calcDate} ${calcTime}`,
|
||||
|
||||
Reference in New Issue
Block a user