배치 수정
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { ArrowUpRight, ArrowDownRight, AlertTriangle, Activity, TrendingUp, TrendingDown, DollarSign } from 'lucide-react';
|
||||
import { ArrowUpRight, ArrowDownRight, AlertTriangle, Activity, TrendingUp, TrendingDown, DollarSign, Calendar, BarChart2 } from 'lucide-react';
|
||||
|
||||
interface PortfolioSummaryProps {
|
||||
summary: any;
|
||||
@@ -17,8 +17,8 @@ export const PortfolioSummary = ({ summary, error }: PortfolioSummaryProps) => {
|
||||
|
||||
if (!summary) {
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 animate-pulse">
|
||||
{[...Array(4)].map((_, i) => (
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4 animate-pulse">
|
||||
{[...Array(6)].map((_, i) => (
|
||||
<div key={i} className="bg-gray-800/50 h-24 rounded-xl" />
|
||||
))}
|
||||
</div>
|
||||
@@ -27,72 +27,107 @@ export const PortfolioSummary = ({ summary, error }: PortfolioSummaryProps) => {
|
||||
|
||||
const {
|
||||
total_assets,
|
||||
total_value, // 주식 평가금액
|
||||
total_investment, // 총 매입금액
|
||||
total_value, // 주식 평가금액
|
||||
total_investment, // 총 매입금액
|
||||
total_profit_loss,
|
||||
total_profit_loss_rate,
|
||||
available_cash, // 예수금 (현금)
|
||||
available_cash, // 예수금 (현금)
|
||||
today_profit_loss, // 금일 평가손익
|
||||
today_profit_loss_rate, // 금일 수익률
|
||||
cumulative_realized_pl, // 누적 실현 손익
|
||||
} = summary;
|
||||
const isProfit = (total_profit_loss ?? 0) >= 0;
|
||||
const isTodayProfit = (today_profit_loss ?? 0) >= 0;
|
||||
const isCumulativeProfit = (cumulative_realized_pl ?? 0) >= 0;
|
||||
|
||||
const fmt = (v: number) => Math.round(v || 0).toLocaleString();
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3 mb-6">
|
||||
{/* 총 자산 (예수금 + 주식평가) */}
|
||||
<div className="bg-gray-800/50 backdrop-blur-sm border border-gray-700/50 p-5 rounded-xl">
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<p className="text-gray-400 text-sm font-medium">총 자산</p>
|
||||
<div className="p-2 bg-blue-500/10 rounded-lg text-blue-400">
|
||||
<DollarSign size={18} />
|
||||
<div className="bg-gray-800/50 backdrop-blur-sm border border-gray-700/50 p-4 rounded-xl">
|
||||
<div className="flex justify-between items-start mb-1.5">
|
||||
<p className="text-gray-400 text-xs font-medium">총 자산</p>
|
||||
<div className="p-1.5 bg-blue-500/10 rounded-lg text-blue-400">
|
||||
<DollarSign size={14} />
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-white mb-1">
|
||||
<h3 className="text-lg font-bold text-white mb-1 leading-tight">
|
||||
{fmt(total_assets)}원
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500">예수금 + 주식평가</p>
|
||||
<p className="text-[10px] text-gray-500">예수금 + 주식평가</p>
|
||||
</div>
|
||||
|
||||
{/* 예수금 (현금) */}
|
||||
<div className="bg-gray-800/50 backdrop-blur-sm border border-gray-700/50 p-5 rounded-xl">
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<p className="text-gray-400 text-sm font-medium">예수금</p>
|
||||
<div className="p-2 bg-purple-500/10 rounded-lg text-purple-400">
|
||||
<Activity size={18} />
|
||||
<div className="bg-gray-800/50 backdrop-blur-sm border border-gray-700/50 p-4 rounded-xl">
|
||||
<div className="flex justify-between items-start mb-1.5">
|
||||
<p className="text-gray-400 text-xs font-medium">예수금</p>
|
||||
<div className="p-1.5 bg-purple-500/10 rounded-lg text-purple-400">
|
||||
<Activity size={14} />
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-white mb-1">
|
||||
<h3 className="text-lg font-bold text-white mb-1 leading-tight">
|
||||
{fmt(available_cash)}원
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500">주식평가: {fmt(total_value)}원</p>
|
||||
<p className="text-[10px] text-gray-500">주식평가: {fmt(total_value)}원</p>
|
||||
</div>
|
||||
|
||||
{/* 총 평가손익 */}
|
||||
<div className="bg-gray-800/50 backdrop-blur-sm border border-gray-700/50 p-5 rounded-xl">
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<p className="text-gray-400 text-sm font-medium">총 평가손익</p>
|
||||
<div className={`p-2 rounded-lg ${isProfit ? 'bg-red-500/10 text-red-400' : 'bg-blue-500/10 text-blue-400'}`}>
|
||||
{isProfit ? <TrendingUp size={18} /> : <TrendingDown size={18} />}
|
||||
<div className="bg-gray-800/50 backdrop-blur-sm border border-gray-700/50 p-4 rounded-xl">
|
||||
<div className="flex justify-between items-start mb-1.5">
|
||||
<p className="text-gray-400 text-xs font-medium">총 평가손익</p>
|
||||
<div className={`p-1.5 rounded-lg ${isProfit ? 'bg-red-500/10 text-red-400' : 'bg-blue-500/10 text-blue-400'}`}>
|
||||
{isProfit ? <TrendingUp size={14} /> : <TrendingDown size={14} />}
|
||||
</div>
|
||||
</div>
|
||||
<h3 className={`text-2xl font-bold mb-1 ${isProfit ? 'text-red-400' : 'text-blue-400'}`}>
|
||||
<h3 className={`text-lg font-bold mb-1 leading-tight ${isProfit ? 'text-red-400' : 'text-blue-400'}`}>
|
||||
{(total_profit_loss ?? 0) > 0 ? '+' : ''}{fmt(total_profit_loss)}원
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500">매입: {fmt(total_investment)}원</p>
|
||||
<p className="text-[10px] text-gray-500">매입: {fmt(total_investment)}원</p>
|
||||
</div>
|
||||
|
||||
{/* 수익률 */}
|
||||
<div className="bg-gray-800/50 backdrop-blur-sm border border-gray-700/50 p-5 rounded-xl">
|
||||
<div className="flex justify-between items-start mb-2">
|
||||
<p className="text-gray-400 text-sm font-medium">수익률</p>
|
||||
<div className={`p-2 rounded-lg ${isProfit ? 'bg-red-500/10 text-red-400' : 'bg-blue-500/10 text-blue-400'}`}>
|
||||
{isProfit ? <ArrowUpRight size={18} /> : <ArrowDownRight size={18} />}
|
||||
<div className="bg-gray-800/50 backdrop-blur-sm border border-gray-700/50 p-4 rounded-xl">
|
||||
<div className="flex justify-between items-start mb-1.5">
|
||||
<p className="text-gray-400 text-xs font-medium">수익률</p>
|
||||
<div className={`p-1.5 rounded-lg ${isProfit ? 'bg-red-500/10 text-red-400' : 'bg-blue-500/10 text-blue-400'}`}>
|
||||
{isProfit ? <ArrowUpRight size={14} /> : <ArrowDownRight size={14} />}
|
||||
</div>
|
||||
</div>
|
||||
<h3 className={`text-2xl font-bold mb-1 ${isProfit ? 'text-red-400' : 'text-blue-400'}`}>
|
||||
<h3 className={`text-lg font-bold mb-1 leading-tight ${isProfit ? 'text-red-400' : 'text-blue-400'}`}>
|
||||
{(total_profit_loss_rate ?? 0) > 0 ? '+' : ''}{(total_profit_loss_rate ?? 0).toFixed(2)}%
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500">주식 매입 대비</p>
|
||||
<p className="text-[10px] text-gray-500">주식 매입 대비</p>
|
||||
</div>
|
||||
|
||||
{/* 금일 손익 */}
|
||||
<div className="bg-gray-800/50 backdrop-blur-sm border border-gray-700/50 p-4 rounded-xl">
|
||||
<div className="flex justify-between items-start mb-1.5">
|
||||
<p className="text-gray-400 text-xs font-medium">금일 손익</p>
|
||||
<div className={`p-1.5 rounded-lg ${isTodayProfit ? 'bg-red-500/10 text-red-400' : 'bg-blue-500/10 text-blue-400'}`}>
|
||||
<Calendar size={14} />
|
||||
</div>
|
||||
</div>
|
||||
<h3 className={`text-lg font-bold mb-1 leading-tight ${isTodayProfit ? 'text-red-400' : 'text-blue-400'}`}>
|
||||
{(today_profit_loss ?? 0) > 0 ? '+' : ''}{fmt(today_profit_loss)}원
|
||||
</h3>
|
||||
<p className="text-[10px] text-gray-500">
|
||||
{(today_profit_loss_rate ?? 0) > 0 ? '+' : ''}{(today_profit_loss_rate ?? 0).toFixed(2)}% 전일 대비
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 누적 실현손익 */}
|
||||
<div className="bg-gray-800/50 backdrop-blur-sm border border-gray-700/50 p-4 rounded-xl">
|
||||
<div className="flex justify-between items-start mb-1.5">
|
||||
<p className="text-gray-400 text-xs font-medium">누적 실현손익</p>
|
||||
<div className={`p-1.5 rounded-lg ${isCumulativeProfit ? 'bg-red-500/10 text-red-400' : 'bg-blue-500/10 text-blue-400'}`}>
|
||||
<BarChart2 size={14} />
|
||||
</div>
|
||||
</div>
|
||||
<h3 className={`text-lg font-bold mb-1 leading-tight ${isCumulativeProfit ? 'text-red-400' : 'text-blue-400'}`}>
|
||||
{(cumulative_realized_pl ?? 0) > 0 ? '+' : ''}{fmt(cumulative_realized_pl)}원
|
||||
</h3>
|
||||
<p className="text-[10px] text-gray-500">매도 체결 기준</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -286,10 +286,16 @@ const Dashboard = () => {
|
||||
const liveProfitLoss = liveValue - totalInvestment
|
||||
const liveProfitLossRate = totalInvestment > 0 ? (liveProfitLoss / totalInvestment) * 100 : 0
|
||||
|
||||
// 총 자산 = 예수금(KIS 기준) + 주식 평가금액(live)
|
||||
// KIS API total_assets가 있으면 그 예수금 부분만 분리해서 live 주식값 합산
|
||||
const availableCash = portfolioSummary.available_cash || 0
|
||||
const liveTotal = availableCash + liveValue
|
||||
// 총 자산 = KIS tot_evlu_amt(공식 총평가금액) 기준 + 실시간 주식평가 변동분 반영
|
||||
// KIS tot_evlu_amt는 D+2 정산 등을 포함한 정확한 값이므로 base로 사용하고
|
||||
// 주식 평가분만 live 가격으로 보정 (stock_value_from_api = scts_evlu_amt)
|
||||
const backendStockValue = portfolioSummary.stock_value_from_api || 0
|
||||
const liveTotal = (portfolioSummary.total_assets || 0) + (liveValue - backendStockValue)
|
||||
|
||||
// 금일 손익도 live 주식 변동분 반영
|
||||
const bfdyTotal = portfolioSummary.bfdy_total_assets || 0
|
||||
const liveTodayPL = bfdyTotal > 0 ? liveTotal - bfdyTotal : (portfolioSummary.today_profit_loss || 0)
|
||||
const liveTodayPLRate = bfdyTotal > 0 ? (liveTodayPL / bfdyTotal) * 100 : (portfolioSummary.today_profit_loss_rate || 0)
|
||||
|
||||
return {
|
||||
...portfolioSummary,
|
||||
@@ -298,6 +304,8 @@ const Dashboard = () => {
|
||||
total_profit_loss: liveProfitLoss,
|
||||
total_profit_loss_rate: liveProfitLossRate,
|
||||
total_assets: liveTotal,
|
||||
today_profit_loss: liveTodayPL,
|
||||
today_profit_loss_rate: liveTodayPLRate,
|
||||
}
|
||||
}, [portfolioSummary, portfolio, livePrices])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user