Persist local synastry report history

This commit is contained in:
732642856
2026-07-17 18:42:39 +08:00
parent 4fc98f4e92
commit aeb6852aa7
3 changed files with 46 additions and 2 deletions
+4
View File
@@ -397,6 +397,10 @@ button:disabled { cursor: default; opacity: .45; }
.synastry-report-card strong, .synastry-report-card p { color: var(--color-ink); }
.synastry-report-card strong { display: block; margin-top: 4px; font-size: var(--type-body); font-weight: 500; }
.synastry-report-card p, .synastry-report-card ul { margin: 0; }
.synastry-history-list { display: grid; gap: var(--space-2); }
.synastry-history-list > b { color: var(--color-ink); font-size: var(--type-caption); font-weight: 600; }
.synastry-history-item { display: grid; gap: 3px; padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-canvas); color: var(--color-ink); text-align: left; }
.synastry-history-item small { color: var(--color-ink-secondary); font-size: var(--type-caption); }
input, select { width: 100%; min-height: 44px; padding: 0 12px; border: 1px solid var(--color-border-strong); color: var(--color-ink); border-color: var(--color-border-strong); border-radius: var(--radius-md); background: var(--color-canvas); font-size: 14px; }
input:disabled, select:disabled { color: var(--color-ink-tertiary); background: var(--color-canvas-muted); }
+39 -2
View File
@@ -46,6 +46,7 @@ type ChartLibraryApiRecord = {
updated_at?: string;
};
type SynastryReportCard = {
id: string;
partnerName: string;
score?: number;
maxScore?: number;
@@ -55,6 +56,7 @@ type SynastryReportCard = {
strengths?: string[];
risks?: string[];
nextEvidence?: string[];
createdAt: number;
};
type ChatSession = { id: string; title: string; theme: Theme; modelId: string; messages: Message[]; updatedAt: number };
type RequestError = { sessionId: string; message: string };
@@ -192,6 +194,9 @@ function selectedBirthPlace(profile: Profile): BirthPlace | null {
function chartLibraryStorageKey(accountId: string) {
return `jyotisha_chart_library:${accountId}`;
}
function synastryHistoryStorageKey(accountId: string) {
return `jyotisha_synastry_history:${accountId}`;
}
function profileReadyForLibrary(profile: Profile) {
return !missingProfileStep(profile);
@@ -215,6 +220,14 @@ function readChartLibrary(accountId: string): ChartLibraryRecord[] {
return [];
}
}
function readSynastryHistory(accountId: string): SynastryReportCard[] {
try {
const parsed = JSON.parse(localStorage.getItem(synastryHistoryStorageKey(accountId)) || "[]") as SynastryReportCard[];
return Array.isArray(parsed) ? parsed.filter((record) => record?.id && record?.partnerName).slice(0, 10) : [];
} catch {
return [];
}
}
function normalizeChartLibraryApiRecord(record: ChartLibraryApiRecord): ChartLibraryRecord {
return {
@@ -531,6 +544,7 @@ export default function Home() {
const [chartLibraryOpen, setChartLibraryOpen] = useState(false);
const [otherProfileDraft, setOtherProfileDraft] = useState<Profile>(emptyProfile);
const [synastryReportCard, setSynastryReportCard] = useState<SynastryReportCard | null>(null);
const [synastryHistory, setSynastryHistory] = useState<SynastryReportCard[]>([]);
const [profileOpen, setProfileOpen] = useState(false);
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
const [profileNotice, setProfileNotice] = useState("");
@@ -599,12 +613,14 @@ export default function Home() {
useEffect(() => {
if (!accountId) {
setChartLibrary([]);
setSynastryHistory([]);
chartLibraryLoadedAccount.current = "";
return;
}
if (chartLibraryLoadedAccount.current === accountId) return;
chartLibraryLoadedAccount.current = accountId;
setChartLibrary(upsertSelfChart(readChartLibrary(accountId), profile));
setSynastryHistory(readSynastryHistory(accountId));
void fetchCloudChartLibrary()
.then((cloudLibrary) => {
setChartLibrary((current) => {
@@ -1274,7 +1290,8 @@ export default function Home() {
const max = payload.synastry?.max_score;
const assessment = payload.synastry?.assessment;
const layers = (payload.evidenceLayers || []).join(" / ") || "Ashtakoot / Moon / D9";
setSynastryReportCard({
const reportCard: SynastryReportCard = {
id: `${record.id}-${Date.now()}`,
partnerName: record.profile.name || "对方",
score,
maxScore: max,
@@ -1284,7 +1301,16 @@ export default function Home() {
strengths: payload.relationshipReport?.strengths,
risks: payload.relationshipReport?.risks,
nextEvidence: payload.relationshipReport?.nextEvidence,
});
createdAt: Date.now(),
};
setSynastryReportCard(reportCard);
if (accountId) {
setSynastryHistory((current) => {
const next = [reportCard, ...current].slice(0, 10);
localStorage.setItem(synastryHistoryStorageKey(accountId), JSON.stringify(next));
return next;
});
}
chooseSuggestedQuestion([
baseQuestion,
"",
@@ -2024,6 +2050,17 @@ export default function Home() {
</details>
</article>
)}
{synastryHistory.length > 0 && (
<div className="synastry-history-list" aria-label="合盘历史">
<b></b>
{synastryHistory.slice(0, 5).map((item) => (
<button key={item.id} type="button" className="synastry-history-item" onClick={() => setSynastryReportCard(item)}>
<span>{item.partnerName}</span>
<small>Ashtakoot {item.score ?? "?"}/{item.maxScore ?? "?"} · {item.assessment || item.scoreBand || "待解释"}</small>
</button>
))}
</div>
)}
<form className="profile-form chart-library-form" onSubmit={saveOtherChart}>
<div className="section-heading"><b></b><small></small></div>
<ProfileFields value={otherProfileDraft} onChange={setOtherProfileDraft} nameInputId="other-profile-name" />
@@ -144,7 +144,10 @@ def test_chart_profile_library_has_cloud_table_api_and_local_fallback() -> None:
"buildSynastryQuestion",
"draftSynastryQuestionFromChart",
"synastryReportCard",
"synastryHistory",
"synastryHistoryStorageKey",
"synastry-report-card",
"synastry-history-list",
'fetch("/api/synastry"',
"Ashtakoot",
"chartLibraryStorageKey",