From cdea2ce608bcf4166165d408d6454600f0f042d5 Mon Sep 17 00:00:00 2001 From: kennethcheng Date: Tue, 28 Apr 2026 21:46:28 +0800 Subject: [PATCH] =?UTF-8?q?fix(ledger):=20=E4=BF=AE=E5=A4=8D=E5=B8=81?= =?UTF-8?q?=E7=A7=8D=E7=AC=A6=E5=8F=B7=E6=98=A0=E5=B0=84=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E6=89=A9=E5=85=85=E5=BC=95=E6=93=8E=E4=B8=8B?= =?UTF-8?q?=E5=8F=91=E6=B5=81=E6=B0=B4=E6=98=8E=E7=BB=86=E6=94=AF=E6=8C=81?= =?UTF-8?q?=20UI=20=E4=B8=8B=E9=92=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Memory.md | 4 ++++ app/dashboard/page.tsx | 10 +++------- src/actions/portfolio.ts | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Memory.md b/Memory.md index 435a012..441a9bf 100644 --- a/Memory.md +++ b/Memory.md @@ -66,6 +66,10 @@ - 修復了 `avgCostFormatted` 的判空邏輯,將 `Big.eq(0)` 修正為 `Big.eq('0')`,確保當 `pos.avgCost` 存在且不為 0 時能正確格式化,不再顯示 `¥-`。 - 在資產卡片中新增「累計分紅」行,展示 `accumulatedDividendsCny` 數據,保持與其它 CNY 數據一致的 `opacity-50` 樣式。 +## 修復幣種符號映射 Bug 與引擎數據擴充 (Task 40) +- 修復了币种符号映射错乱 Bug:`getCurrencySymbol()` 中 CNY 和 HKD 被错误地映射为 `HK$`,现修正为 USD→$、HKD→HK$、CNY→¥。 +- 在 portfolio 引擎中新增了单资产的流水明细数组:`Position` 接口新增 `transactions` 字段,`getPortfolioPositions()` 按资产名下发排序后的原始交易流水,支持前端展开查看。 + ## 持倉引擎 Native 幣種算法重構 (Task 38) - 重構底層盈虧引擎,全面轉向 Native 原生幣種計算,新增浮動/累計盈虧及百分比指標。 - 徹底分離 Native 與 CNY 計算:單隻股票的成本與盈虧全部改用 Native (原幣種) 進行計算。 diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index f0e9317..2fa46e9 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -6,13 +6,9 @@ import { SyncButton } from '@/components/assets/sync-button'; import Big from 'big.js'; function getCurrencySymbol(currency: string): string { - switch (currency) { - case 'USD': return '$'; - case 'CNY': - case 'HKD': return 'HK$'; - case 'JPY': return '¥'; - default: return currency + ' '; - } + if (currency === 'USD') return '$'; + if (currency === 'HKD') return 'HK$'; + return '¥'; } function formatNative(value: string, baseCurrency: string): string { diff --git a/src/actions/portfolio.ts b/src/actions/portfolio.ts index a9298d6..abd5062 100644 --- a/src/actions/portfolio.ts +++ b/src/actions/portfolio.ts @@ -37,6 +37,15 @@ interface Position { floatingPnlPercent: string; cumulativePnlNative: string; cumulativePnlPercent: string; + transactions: TransactionRecord[]; +} + +interface TransactionRecord { + txType: string; + quantity: string; + price: string; + txCurrency: string; + executedAt: Date | null; } interface RawRate { @@ -174,6 +183,8 @@ export async function getPortfolioPositions(): Promise { accumulatedDividendsNative: Big; // 首次买入日期 firstBuyDate: Date | null; + // 原始流水明细 + transactions: TransactionRecord[]; }>(); for (const tx of allTransactions) { @@ -198,6 +209,7 @@ export async function getPortfolioPositions(): Promise { accumulatedDividendsCny: new Big('0'), accumulatedDividendsNative: new Big('0'), firstBuyDate: null, + transactions: [], }); } @@ -265,6 +277,14 @@ export async function getPortfolioPositions(): Promise { if (tx.assetLatestPrice) { holding.latestPrice = tx.assetLatestPrice; } + + holding.transactions.push({ + txType: tx.txType, + quantity: tx.quantity, + price: tx.price, + txCurrency: tx.txCurrency, + executedAt: tx.executedAt, + }); } const today = getTodayInShanghai(); @@ -373,6 +393,7 @@ export async function getPortfolioPositions(): Promise { floatingPnlPercent: floatingPnlPercent.toString(), cumulativePnlNative: cumulativePnlNative.toString(), cumulativePnlPercent: cumulativePnlPercent.toString(), + transactions: holding.transactions, }); }