fix(ui): 修复价格尾零、增加币种下拉框,并重构持仓引擎实现原币种/本位币双轨制盈亏计算

This commit is contained in:
2026-04-28 01:40:29 +08:00
parent 746be06840
commit 67ceb63b08
4 changed files with 48 additions and 12 deletions
+14
View File
@@ -14,6 +14,8 @@ interface Position {
cnyValue: string;
totalCostCny: string;
pnlCny: string;
totalCostNative: string;
pnlNative: string;
}
interface RawRate {
@@ -95,6 +97,7 @@ export async function getPortfolioPositions(): Promise<Position[]> {
baseCurrency: string;
latestPrice: string;
totalCostCny: Big;
totalCostNative: Big;
}>();
for (const tx of allTransactions) {
@@ -110,6 +113,7 @@ export async function getPortfolioPositions(): Promise<Position[]> {
baseCurrency: tx.assetBaseCurrency || '',
latestPrice: tx.assetLatestPrice || '0',
totalCostCny: new Big('0'),
totalCostNative: new Big('0'),
});
}
@@ -118,10 +122,15 @@ export async function getPortfolioPositions(): Promise<Position[]> {
if (tx.txType === 'BUY') {
holding.quantity = holding.quantity.plus(new Big(tx.quantity));
const costPerUnit = new Big(tx.quantity).times(new Big(tx.price));
holding.totalCostNative = holding.totalCostNative.plus(costPerUnit);
const costCny = costPerUnit.times(new Big(tx.exchangeRate || '1'));
holding.totalCostCny = holding.totalCostCny.plus(costCny);
} else if (tx.txType === 'SELL') {
holding.quantity = holding.quantity.minus(new Big(tx.quantity));
const sellCostPerUnit = new Big(tx.quantity).times(new Big(tx.price));
holding.totalCostNative = holding.totalCostNative.minus(sellCostPerUnit);
const sellCostCny = sellCostPerUnit.times(new Big(tx.exchangeRate || '1'));
holding.totalCostCny = holding.totalCostCny.minus(sellCostCny);
} else if (tx.txType === 'AIRDROP') {
holding.quantity = holding.quantity.plus(new Big(tx.quantity));
} else if (tx.txType === 'DIVIDEND') {
@@ -160,6 +169,9 @@ export async function getPortfolioPositions(): Promise<Position[]> {
const pnlCny = cnyValue.minus(holding.totalCostCny);
totalPnlCny = totalPnlCny.plus(pnlCny);
const currentNativeValue = new Big(holding.latestPrice).times(holding.quantity);
const pnlNative = currentNativeValue.minus(holding.totalCostNative);
result.push({
assetId: holding.assetId,
symbol: holding.symbol,
@@ -169,6 +181,8 @@ export async function getPortfolioPositions(): Promise<Position[]> {
cnyValue: cnyValue.toString(),
totalCostCny: holding.totalCostCny.toString(),
pnlCny: pnlCny.toString(),
totalCostNative: holding.totalCostNative.toString(),
pnlNative: pnlNative.toString(),
});
}
@@ -218,9 +218,18 @@ export function AddTransactionDialog({ assets }: AddTransactionDialogProps) {
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<FormControl>
<Input placeholder="USD" type="text" {...field} />
</FormControl>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="选择币种" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="USD">USD</SelectItem>
<SelectItem value="CNY">CNY</SelectItem>
<SelectItem value="HKD">HKD</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}