feat(ui): 接入股票名称展示,实装表单币种自动绑定及编辑删除功能
This commit is contained in:
@@ -37,8 +37,9 @@ export async function syncAllStockPrices() {
|
||||
const latestPrice = dataArr[3];
|
||||
|
||||
if (latestPrice && !isNaN(Number(latestPrice)) && Number(latestPrice) > 0) {
|
||||
const stockName = dataArr[1] || null;
|
||||
await db.update(assets)
|
||||
.set({ latestPrice: latestPrice })
|
||||
.set({ latestPrice: latestPrice, name: stockName })
|
||||
.where(eq(assets.id, asset.id));
|
||||
successCount++;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { desc, eq } from 'drizzle-orm';
|
||||
interface Position {
|
||||
assetId: string;
|
||||
symbol: string;
|
||||
name: string | null;
|
||||
type: string;
|
||||
quantity: string;
|
||||
baseCurrency: string;
|
||||
@@ -82,6 +83,7 @@ export async function getPortfolioPositions(): Promise<Position[]> {
|
||||
txCurrency: transactions.txCurrency,
|
||||
assetId: transactions.assetId,
|
||||
assetSymbol: assets.symbol,
|
||||
assetName: assets.name,
|
||||
assetType: assets.type,
|
||||
assetBaseCurrency: assets.baseCurrency,
|
||||
assetLatestPrice: assets.latestPrice,
|
||||
@@ -101,6 +103,7 @@ export async function getPortfolioPositions(): Promise<Position[]> {
|
||||
const holdings = new Map<string, {
|
||||
assetId: string;
|
||||
symbol: string;
|
||||
name: string | null;
|
||||
type: string;
|
||||
quantity: Big;
|
||||
baseCurrency: string;
|
||||
@@ -117,6 +120,7 @@ export async function getPortfolioPositions(): Promise<Position[]> {
|
||||
holdings.set(tx.assetId, {
|
||||
assetId: tx.assetId,
|
||||
symbol: tx.assetSymbol || tx.assetId,
|
||||
name: tx.assetName,
|
||||
type: tx.assetType || 'CASH',
|
||||
quantity: new Big('0'),
|
||||
baseCurrency: tx.assetBaseCurrency || '',
|
||||
@@ -190,6 +194,7 @@ export async function getPortfolioPositions(): Promise<Position[]> {
|
||||
result.push({
|
||||
assetId: holding.assetId,
|
||||
symbol: holding.symbol,
|
||||
name: holding.name,
|
||||
type: holding.type,
|
||||
quantity: holding.quantity.toString(),
|
||||
baseCurrency: holding.baseCurrency,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useTransition } from 'react';
|
||||
import { useState, useTransition, useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useWatch } from 'react-hook-form';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -61,10 +62,26 @@ export function AddAssetDialog() {
|
||||
symbol: '',
|
||||
type: 'STOCK' as const,
|
||||
exchange: 'US',
|
||||
baseCurrency: '',
|
||||
baseCurrency: 'USD',
|
||||
},
|
||||
});
|
||||
|
||||
const exchangeValue = useWatch({ control: form.control, name: 'exchange' });
|
||||
|
||||
useEffect(() => {
|
||||
if (!exchangeValue) return;
|
||||
const currencyMap: Record<string, string> = {
|
||||
'US': 'USD',
|
||||
'HKEX': 'HKD',
|
||||
'SSE': 'CNY',
|
||||
'SZSE': 'CNY',
|
||||
};
|
||||
const currency = currencyMap[exchangeValue];
|
||||
if (currency) {
|
||||
form.setValue('baseCurrency', currency, { shouldValidate: true });
|
||||
}
|
||||
}, [exchangeValue, form]);
|
||||
|
||||
function onSubmit(values: AddAssetForm) {
|
||||
startTransition(async () => {
|
||||
const result = await createAsset(values);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useTransition } from 'react';
|
||||
import { useState, useTransition, useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useWatch } from 'react-hook-form';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -49,8 +50,10 @@ type AddTransactionForm = z.infer<typeof addTransactionSchema>;
|
||||
interface Asset {
|
||||
id: string;
|
||||
symbol: string;
|
||||
name: string | null;
|
||||
type: string;
|
||||
baseCurrency: string;
|
||||
exchange: string | null;
|
||||
}
|
||||
|
||||
interface AddTransactionDialogProps {
|
||||
@@ -65,6 +68,13 @@ const txTypeLabels: Record<string, string> = {
|
||||
FEE: '手续费 (FEE)',
|
||||
};
|
||||
|
||||
const exchangeToCurrencyMap: Record<string, string> = {
|
||||
'US': 'USD',
|
||||
'HKEX': 'HKD',
|
||||
'SSE': 'CNY',
|
||||
'SZSE': 'CNY',
|
||||
};
|
||||
|
||||
export function AddTransactionDialog({ assets }: AddTransactionDialogProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [isPending, startTransition] = useTransition();
|
||||
@@ -83,6 +93,17 @@ export function AddTransactionDialog({ assets }: AddTransactionDialogProps) {
|
||||
},
|
||||
});
|
||||
|
||||
const selectedAssetId = useWatch({ control: form.control, name: 'assetId' });
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedAssetId) return;
|
||||
const selectedAsset = assets.find((a) => a.id === selectedAssetId);
|
||||
if (selectedAsset) {
|
||||
const currency = exchangeToCurrencyMap[selectedAsset.exchange || ''] || selectedAsset.baseCurrency || 'USD';
|
||||
form.setValue('txCurrency', currency, { shouldValidate: true });
|
||||
}
|
||||
}, [selectedAssetId, assets, form]);
|
||||
|
||||
function onSubmit(values: AddTransactionForm) {
|
||||
startTransition(async () => {
|
||||
const result = await createTransaction({
|
||||
@@ -136,7 +157,7 @@ export function AddTransactionDialog({ assets }: AddTransactionDialogProps) {
|
||||
) : (
|
||||
assets.map((asset) => (
|
||||
<SelectItem key={asset.id} value={asset.id}>
|
||||
{asset.symbol}
|
||||
{asset.symbol}{asset.name ? ` (${asset.name})` : ''}
|
||||
</SelectItem>
|
||||
))
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user