Add login gate, calculation history, and AI markdown download.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import {
|
||||
HISTORY_MAX_ITEMS,
|
||||
HISTORY_STORAGE_KEY,
|
||||
type CalcHistoryEntry,
|
||||
} from "@/lib/history/types";
|
||||
|
||||
export function loadHistory(): CalcHistoryEntry[] {
|
||||
if (typeof window === "undefined") {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
const raw = localStorage.getItem(HISTORY_STORAGE_KEY);
|
||||
if (!raw) {
|
||||
return [];
|
||||
}
|
||||
const parsed = JSON.parse(raw) as CalcHistoryEntry[];
|
||||
return Array.isArray(parsed) ? parsed : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function saveHistoryEntry(
|
||||
entry: Omit<CalcHistoryEntry, "id" | "createdAt">,
|
||||
): CalcHistoryEntry {
|
||||
const full: CalcHistoryEntry = {
|
||||
...entry,
|
||||
id: crypto.randomUUID(),
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
const list = [full, ...loadHistory()].slice(0, HISTORY_MAX_ITEMS);
|
||||
localStorage.setItem(HISTORY_STORAGE_KEY, JSON.stringify(list));
|
||||
return full;
|
||||
}
|
||||
|
||||
export function deleteHistoryEntry(id: string): void {
|
||||
const list = loadHistory().filter((e) => e.id !== id);
|
||||
localStorage.setItem(HISTORY_STORAGE_KEY, JSON.stringify(list));
|
||||
}
|
||||
|
||||
export function downloadMarkdown(content: string, filename: string) {
|
||||
const blob = new Blob([content], { type: "text/markdown;charset=utf-8" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = filename.endsWith(".md") ? filename : `${filename}.md`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
export function buildHistoryMarkdown(entry: CalcHistoryEntry): string {
|
||||
const lines = [
|
||||
`# ${entry.title}`,
|
||||
"",
|
||||
`- 类型:${entry.mode}`,
|
||||
`- 时间:${new Date(entry.createdAt).toLocaleString("zh-CN")}`,
|
||||
`- 问事:${entry.question}`,
|
||||
"",
|
||||
...Object.entries(entry.meta).map(([k, v]) => `- ${k}:${v}`),
|
||||
"",
|
||||
"---",
|
||||
"",
|
||||
entry.completion,
|
||||
];
|
||||
return lines.join("\n");
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
export type CalcMode = "liuyao" | "bazi" | "combined";
|
||||
|
||||
export interface CalcHistoryEntry {
|
||||
id: string;
|
||||
mode: CalcMode;
|
||||
title: string;
|
||||
question: string;
|
||||
summary: string;
|
||||
completion: string;
|
||||
meta: Record<string, string>;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export const HISTORY_STORAGE_KEY = "zhimingge-calc-history";
|
||||
export const HISTORY_MAX_ITEMS = 100;
|
||||
|
||||
export const MODE_LABELS: Record<CalcMode, string> = {
|
||||
liuyao: "六爻算卦",
|
||||
bazi: "生辰八字",
|
||||
combined: "综合测算",
|
||||
};
|
||||
Reference in New Issue
Block a user