From 48e834e3383805673293f8c24f6fc53eac834b3f Mon Sep 17 00:00:00 2001 From: kennethcheng Date: Tue, 28 Apr 2026 13:21:28 +0800 Subject: [PATCH] =?UTF-8?q?feat(api):=20=E6=8E=A5=E5=85=A5=E5=B8=81?= =?UTF-8?q?=E5=AE=89=E5=85=AC=E5=85=B1=E6=8E=A5=E5=8F=A3=EF=BC=8C=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E4=B8=BA=E8=82=A1=E7=A5=A8+=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=E8=B4=A7=E5=B8=81=E7=9A=84=E5=8F=8C=E8=BD=A8=E5=88=B6=E5=85=A8?= =?UTF-8?q?=E5=B8=82=E5=9C=BA=E8=A1=8C=E6=83=85=E5=BC=95=E6=93=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions/market.ts | 57 ++++++++++++++-------- src/components/assets/add-asset-dialog.tsx | 10 +++- src/components/assets/sync-button.tsx | 6 +-- 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/actions/market.ts b/src/actions/market.ts index be29705..72000fd 100644 --- a/src/actions/market.ts +++ b/src/actions/market.ts @@ -17,33 +17,50 @@ function getTencentSymbol(asset: { symbol: string; exchange: string | null }): s } } -export async function syncAllStockPrices() { - const stockAssets = await db +export async function syncAllMarketPrices() { + const allAssets = await db .select() - .from(assets) - .where(eq(assets.type, 'STOCK')); + .from(assets); let successCount = 0; - for (const asset of stockAssets) { + for (const asset of allAssets) { try { - const tCode = getTencentSymbol(asset); - const response = await fetch(`https://qt.gtimg.cn/q=${tCode}`, { cache: 'no-store' }); - const arrayBuffer = await response.arrayBuffer(); - const decoder = new TextDecoder('gbk'); - const text = decoder.decode(arrayBuffer); + if (asset.type === 'STOCK') { + const tCode = getTencentSymbol(asset); + const response = await fetch(`https://qt.gtimg.cn/q=${tCode}`, { cache: 'no-store' }); + const arrayBuffer = await response.arrayBuffer(); + const decoder = new TextDecoder('gbk'); + const text = decoder.decode(arrayBuffer); - const match = text.match(/="([^"]+)"/); - if (match && match[1]) { - const dataArr = match[1].split('~'); - const latestPrice = dataArr[3]; + const match = text.match(/="([^"]+)"/); + if (match && match[1]) { + const dataArr = match[1].split('~'); + const latestPrice = dataArr[3]; - if (latestPrice && !isNaN(Number(latestPrice)) && Number(latestPrice) > 0) { - const stockName = dataArr[1] || null; - await db.update(assets) - .set({ latestPrice: latestPrice, name: stockName }) - .where(eq(assets.id, asset.id)); - successCount++; + if (latestPrice && !isNaN(Number(latestPrice)) && Number(latestPrice) > 0) { + const stockName = dataArr[1] || null; + await db.update(assets) + .set({ latestPrice: latestPrice, name: stockName }) + .where(eq(assets.id, asset.id)); + successCount++; + } + } + } else if (asset.type === 'CRYPTO') { + const cryptoSymbol = asset.symbol.trim().toUpperCase() + 'USDT'; + const response = await fetch(`https://api.binance.com/api/v3/ticker/price?symbol=${cryptoSymbol}`, { cache: 'no-store' }); + + if (response.ok) { + const data = await response.json(); + if (data.price) { + await db.update(assets) + .set({ + latestPrice: data.price, + name: asset.symbol.toUpperCase(), + }) + .where(eq(assets.id, asset.id)); + successCount++; + } } } } catch (error) { diff --git a/src/components/assets/add-asset-dialog.tsx b/src/components/assets/add-asset-dialog.tsx index 5234b21..8de169d 100644 --- a/src/components/assets/add-asset-dialog.tsx +++ b/src/components/assets/add-asset-dialog.tsx @@ -67,6 +67,7 @@ export function AddAssetDialog() { }); const exchangeValue = useWatch({ control: form.control, name: 'exchange' }); + const typeValue = useWatch({ control: form.control, name: 'type' }); useEffect(() => { if (!exchangeValue) return; @@ -82,6 +83,13 @@ export function AddAssetDialog() { } }, [exchangeValue, form]); + useEffect(() => { + if (typeValue === 'CRYPTO') { + form.setValue('exchange', 'CRYPTO', { shouldValidate: true }); + form.setValue('baseCurrency', 'USD', { shouldValidate: true }); + } + }, [typeValue, form]); + function onSubmit(values: AddAssetForm) { startTransition(async () => { const result = await createAsset(values); @@ -149,7 +157,7 @@ export function AddAssetDialog() { render={({ field }) => ( 交易所 / 市场 (Exchange) - diff --git a/src/components/assets/sync-button.tsx b/src/components/assets/sync-button.tsx index d416187..3eff066 100644 --- a/src/components/assets/sync-button.tsx +++ b/src/components/assets/sync-button.tsx @@ -3,21 +3,21 @@ import { useState, useTransition } from 'react'; import { Button } from '@/components/ui/button'; import { RefreshCw } from 'lucide-react'; -import { syncAllStockPrices } from '@/actions/market'; +import { syncAllMarketPrices } from '@/actions/market'; export function SyncButton() { const [isPending, startTransition] = useTransition(); function handleClick() { startTransition(async () => { - await syncAllStockPrices(); + await syncAllMarketPrices(); }); } return ( ); }