'use server'; import { db } from '@/db'; import { portfolioSnapshots } from '@/db/schema'; import { getPortfolioPositions } from './portfolio'; import { eq, sql } from 'drizzle-orm'; import Big from 'big.js'; function getTodayInShanghai(): string { const now = new Date(); const utcStr = now.toLocaleString('en-US', { timeZone: 'UTC' }); const utcDate = new Date(utcStr); const shanghaiOffset = 8 * 60 * 60 * 1000; const shanghaiDate = new Date(utcDate.getTime() + shanghaiOffset); const year = shanghaiDate.getFullYear(); const month = String(shanghaiDate.getMonth() + 1).padStart(2, '0'); const day = String(shanghaiDate.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } export async function recordDailySnapshot() { const positions = await getPortfolioPositions(); const totalValueCny = positions.reduce( (sum, pos) => sum.plus(pos.cnyValue || '0'), new Big(0) ).toString(); const totalCostCny = positions.reduce( (sum, pos) => sum.plus(pos.totalCostCny || '0'), new Big(0) ).toString(); const dateStr = getTodayInShanghai(); const existing = await db .select() .from(portfolioSnapshots) .where(eq(portfolioSnapshots.date, dateStr)) .limit(1); const now = new Date(); if (existing.length > 0) { await db .update(portfolioSnapshots) .set({ totalValueCny, totalCostCny, updatedAt: now, }) .where(eq(portfolioSnapshots.date, dateStr)); return { success: true, action: 'updated', date: dateStr, totalValueCny, totalCostCny, }; } await db .insert(portfolioSnapshots) .values({ date: dateStr, totalValueCny, totalCostCny, createdAt: now, updatedAt: now, }); return { success: true, action: 'inserted', date: dateStr, totalValueCny, totalCostCny, }; } export async function getSnapshots(params?: { limit?: number; startDate?: string; endDate?: string; }) { const { limit = 365, startDate, endDate } = params || {}; let query = db .select() .from(portfolioSnapshots) .orderBy(sql`"${date}" DESC`); if (startDate) { query = query.where(sql`"${date}" >= ${startDate}`); } if (endDate) { query = query.where(sql`"${date}" <= ${endDate}`); } const snapshots = await query.limit(limit); return snapshots.reverse(); }