From a45bd56ad0239e890c1abdcd1405560932dd76cf Mon Sep 17 00:00:00 2001 From: MarkLo127 Date: Wed, 11 Mar 2026 17:46:07 +0800 Subject: [PATCH] --- backend/app/api/user.py | 7 ++++++- backend/app/db/database.py | 10 +++++++++ backend/app/db/models.py | 7 +++++-- frontend/app/history/page.tsx | 38 ++++------------------------------- 4 files changed, 25 insertions(+), 37 deletions(-) diff --git a/backend/app/api/user.py b/backend/app/api/user.py index 28a86120..c58fe346 100644 --- a/backend/app/api/user.py +++ b/backend/app/api/user.py @@ -38,6 +38,7 @@ class ReportCreate(BaseModel): market_type: str # us, twse, tpex analysis_date: str result: dict + language: Optional[str] = None class ReportResponse(BaseModel): @@ -47,6 +48,7 @@ class ReportResponse(BaseModel): market_type: str analysis_date: str result: dict + language: Optional[str] = None created_at: str @@ -166,6 +168,7 @@ async def get_reports( market_type=r.market_type, analysis_date=r.analysis_date, result=r.result, + language=r.language, created_at=r.created_at.isoformat() + "Z" ) for r in reports @@ -184,7 +187,8 @@ async def create_report( ticker=report_data.ticker, market_type=report_data.market_type, analysis_date=report_data.analysis_date, - result=report_data.result + result=report_data.result, + language=report_data.language ) db.add(report) await db.commit() @@ -223,6 +227,7 @@ async def get_report( market_type=report.market_type, analysis_date=report.analysis_date, result=report.result, + language=report.language, created_at=report.created_at.isoformat() + "Z" ) diff --git a/backend/app/db/database.py b/backend/app/db/database.py index 76433405..66dd2b6a 100644 --- a/backend/app/db/database.py +++ b/backend/app/db/database.py @@ -62,6 +62,16 @@ async def init_db(): async with engine.begin() as conn: # Create all tables await conn.run_sync(Base.metadata.create_all) + + # Manual migrations for existing databases + try: + # Add language column if it doesn't exist + await conn.execute(text("ALTER TABLE reports ADD COLUMN IF NOT EXISTS language VARCHAR(10);")) + # Add indexes to optimize queries + await conn.execute(text("CREATE INDEX IF NOT EXISTS ix_reports_user_id ON reports (user_id);")) + await conn.execute(text("CREATE INDEX IF NOT EXISTS ix_reports_created_at ON reports (created_at);")) + except Exception as e: + print(f"Skipping manual migration (might be SQLite or syntax not supported): {e}") print("Database tables initialized successfully") diff --git a/backend/app/db/models.py b/backend/app/db/models.py index d3e7e6d4..64f0abc6 100644 --- a/backend/app/db/models.py +++ b/backend/app/db/models.py @@ -85,17 +85,20 @@ class Report(Base): user_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), - nullable=False + nullable=False, + index=True ) ticker: Mapped[str] = mapped_column(String(20), nullable=False) market_type: Mapped[str] = mapped_column(String(10), nullable=False) # us, twse, tpex analysis_date: Mapped[str] = mapped_column(String(10), nullable=False) # YYYY-MM-DD # Store full result as JSONB result: Mapped[dict] = mapped_column(JSON, nullable=False) + language: Mapped[Optional[str]] = mapped_column(String(10), nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime, default=datetime.utcnow, - nullable=False + nullable=False, + index=True ) # Relationship diff --git a/frontend/app/history/page.tsx b/frontend/app/history/page.tsx index de727b3f..27a1b678 100644 --- a/frontend/app/history/page.tsx +++ b/frontend/app/history/page.tsx @@ -574,43 +574,18 @@ export default function HistoryPage() { new Date(b.saved_at).getTime() - new Date(a.saved_at).getTime(), ); - // Filter by current language - const languageFiltered = merged.filter((report) => { - // Use stored language if available - if (report.language) { - return report.language === locale; - } - // Fallback: detect from content for old reports without language field - return detectReportLanguage(report.result?.reports) === locale; - }); - - setReports(languageFiltered); + setReports(merged); setIsCloudData(true); return; } } - // If no cloud data or not authenticated, use local only - // Filter by current language - const languageFiltered = localData.filter((report) => { - if (report.language) { - return report.language === locale; - } - return detectReportLanguage(report.result?.reports) === locale; - }); - setReports(languageFiltered); + setReports(localData); setIsCloudData(false); } catch (error) { console.error("Failed to load reports:", error); - // Fall back to local on error const data = await getReportsByMarketType(activeTab); - const languageFiltered = data.filter((report) => { - if (report.language) { - return report.language === locale; - } - return detectReportLanguage(report.result?.reports) === locale; - }); - setReports(languageFiltered); + setReports(data as SavedReport[]); setIsCloudData(false); } finally { setLoading(false); @@ -621,12 +596,7 @@ export default function HistoryPage() { try { // Helper to filter reports by language const filterByLanguage = (reports: SavedReport[]) => { - return reports.filter(report => { - if (report.language) { - return report.language === locale; - } - return detectReportLanguage(report.result?.reports) === locale; - }); + return reports; }; if (isAuthenticated && isCloudSyncEnabled()) {