refactor(ui): 规范资产卡片术语,智能隐藏同币种双轨制冗余数据

This commit is contained in:
kennethcheng 2026-04-28 19:18:45 +08:00
parent 84d889fbe5
commit 7d7a7804a6
2 changed files with 25 additions and 16 deletions

View File

@ -118,26 +118,30 @@ export default async function DashboardPage() {
{pos.holdingDays} {pos.holdingDays}
</span> </span>
</div> </div>
<div className="flex justify-between"> {pos.baseCurrency !== 'CNY' && (
<span className="text-muted-foreground"> ({pos.baseCurrency})</span> <>
<span className="font-medium"> <div className="flex justify-between">
{formatAmount(pos.totalCostNative)} <span className="text-muted-foreground"> ({pos.baseCurrency})</span>
</span> <span className="font-medium">
</div> {formatAmount(pos.totalCostNative)}
<div className="flex justify-between"> </span>
<span className="text-muted-foreground"> ({pos.baseCurrency})</span> </div>
<span className={`font-semibold ${posPnlNativePositive ? 'text-green-500' : 'text-red-500'}`}> <div className="flex justify-between">
{posPnlNativePositive ? '+' : ''}{formatAmount(pos.pnlNative)} <span className="text-muted-foreground"> ({pos.baseCurrency})</span>
</span> <span className={`font-semibold ${posPnlNativePositive ? 'text-green-500' : 'text-red-500'}`}>
</div> {posPnlNativePositive ? '+' : ''}{formatAmount(pos.pnlNative)}
</span>
</div>
</>
)}
<div className="flex justify-between opacity-50"> <div className="flex justify-between opacity-50">
<span className="text-muted-foreground"> (CNY)</span> <span className="text-muted-foreground"> (CNY)</span>
<span className="font-medium"> <span className="font-medium">
¥{formatAmount(pos.totalCostCny)} ¥{formatAmount(pos.totalCostCny)}
</span> </span>
</div> </div>
<div className="flex justify-between opacity-50"> <div className="flex justify-between opacity-50">
<span className="text-muted-foreground"> (CNY)</span> <span className="text-muted-foreground"> (CNY)</span>
<span className={`font-semibold ${posPnlPositive ? 'text-green-500' : 'text-red-500'}`}> <span className={`font-semibold ${posPnlPositive ? 'text-green-500' : 'text-red-500'}`}>
{posPnlPositive ? '+' : ''}{formattedPosPnl} {posPnlPositive ? '+' : ''}{formattedPosPnl}
</span> </span>

View File

@ -26,6 +26,7 @@ interface Position {
holdingDays: number; holdingDays: number;
exchange: string; exchange: string;
accumulatedDividendsCny: string; accumulatedDividendsCny: string;
accumulatedDividendsNative: string;
} }
interface RawRate { interface RawRate {
@ -159,6 +160,7 @@ export async function getPortfolioPositions(): Promise<Position[]> {
// 已实现盈亏 // 已实现盈亏
realizedPnlCny: Big; realizedPnlCny: Big;
accumulatedDividendsCny: Big; accumulatedDividendsCny: Big;
accumulatedDividendsNative: Big;
// 首次买入日期 // 首次买入日期
firstBuyDate: Date | null; firstBuyDate: Date | null;
}>(); }>();
@ -182,6 +184,7 @@ export async function getPortfolioPositions(): Promise<Position[]> {
totalBuyQuantity: new Big('0'), totalBuyQuantity: new Big('0'),
realizedPnlCny: new Big('0'), realizedPnlCny: new Big('0'),
accumulatedDividendsCny: new Big('0'), accumulatedDividendsCny: new Big('0'),
accumulatedDividendsNative: new Big('0'),
firstBuyDate: null, firstBuyDate: null,
}); });
} }
@ -235,6 +238,7 @@ export async function getPortfolioPositions(): Promise<Position[]> {
const dividendAmountNative = new Big(tx.quantity).times(new Big(tx.price)); const dividendAmountNative = new Big(tx.quantity).times(new Big(tx.price));
const dividendCny = dividendAmountNative.times(new Big(tx.exchangeRate || '1')); const dividendCny = dividendAmountNative.times(new Big(tx.exchangeRate || '1'));
holding.accumulatedDividendsCny = holding.accumulatedDividendsCny.plus(dividendCny); holding.accumulatedDividendsCny = holding.accumulatedDividendsCny.plus(dividendCny);
holding.accumulatedDividendsNative = holding.accumulatedDividendsNative.plus(dividendAmountNative);
} }
if (tx.assetLatestPrice) { if (tx.assetLatestPrice) {
@ -261,7 +265,7 @@ export async function getPortfolioPositions(): Promise<Position[]> {
const totalPnlCny = unrealizedPnlCny.plus(holding.realizedPnlCny).plus(holding.accumulatedDividendsCny); const totalPnlCny = unrealizedPnlCny.plus(holding.realizedPnlCny).plus(holding.accumulatedDividendsCny);
const currentNativeValue = new Big(holding.latestPrice).times(holding.quantity); const currentNativeValue = new Big(holding.latestPrice).times(holding.quantity);
const pnlNative = currentNativeValue.minus(holding.totalBuyCostNative); const pnlNative = currentNativeValue.minus(holding.totalBuyCostNative).plus(holding.accumulatedDividendsNative);
// 平均成本 = 总买入成本 / 总买入数量 // 平均成本 = 总买入成本 / 总买入数量
let avgCost = new Big('0'); let avgCost = new Big('0');
@ -300,8 +304,9 @@ export async function getPortfolioPositions(): Promise<Position[]> {
avgCost: avgCost.toString(), avgCost: avgCost.toString(),
dilutedCost: dilutedCost.toString(), dilutedCost: dilutedCost.toString(),
holdingDays, holdingDays,
exchange: holding.exchange, exchange: holding.exchange,
accumulatedDividendsCny: holding.accumulatedDividendsCny.toString(), accumulatedDividendsCny: holding.accumulatedDividendsCny.toString(),
accumulatedDividendsNative: holding.accumulatedDividendsNative.toString(),
}); });
} }