diff --git a/src/api/ai/apis.tsx b/src/api/ai/apis.tsx index 097a6ea..4e76ef7 100644 --- a/src/api/ai/apis.tsx +++ b/src/api/ai/apis.tsx @@ -1,5 +1,9 @@ import axiosInstance from "../axiosInstance"; -import { AIPredictionResponse } from "../../types/ai"; +import { + AIPredictionResponse, + FinalRankingResponse, + GamePredictionResponse, +} from "../../types/ai"; export const aiApi = { getWinProbability: async (date: string): Promise => { @@ -12,4 +16,29 @@ export const aiApi = { winProbability: item.winProbability, })); }, + getFinalRank: async (): Promise => { + const { data: raw } = + await axiosInstance.get("/final-rankings"); + return raw.map((item: any) => ({ + id: item.id, + teamName: item.teamName, + rank: item.rank, + currentRank: item.currentRank, + })); + }, + getGamePrediction: async (): Promise => { + const { data: raw } = await axiosInstance.get( + "/api/win-rates/live-prediction", + ); + return raw.map((item: any) => ({ + gameId: item.gameId, + awayTeam: item.awayTeam, + homeTeam: item.homeTeam, + inning: item.inning, + winProbability: item.winProbability, + homeAccumScore: item.homeAccumScore, + awayAccumScore: item.awayAccumScore, + predictedAt: item.predictedAt, + })); + }, }; diff --git a/src/api/ranking/apis.tsx b/src/api/ranking/apis.tsx index 2964252..a5ca6d3 100644 --- a/src/api/ranking/apis.tsx +++ b/src/api/ranking/apis.tsx @@ -4,6 +4,10 @@ import { PitcherSaveDto, PitcherStrikeoutDto, PitcherWinRateDto, + PlayerAVGDto, + PlayerHitDto, + PlayerHRDto, + PlayerRBIDto, RankingDto, } from "../../types/ranking"; import { @@ -41,7 +45,7 @@ export const rankingApi = { return response.data.data.map(item => ({ playerName: item.playerName, backNumber: item.backNumber, - wpct: item.wpct, + wpct: item.value, playerImageUrl: item.playerImageUrl, })); }, @@ -52,7 +56,7 @@ export const rankingApi = { return response.data.data.map(item => ({ playerName: item.playerName, backNumber: item.backNumber, - sv: item.sv, + sv: item.value, playerImageUrl: item.playerImageUrl, })); }, @@ -63,7 +67,7 @@ export const rankingApi = { return response.data.data.map(item => ({ playerName: item.playerName, backNumber: item.backNumber, - so: item.so, + so: item.value, playerImageUrl: item.playerImageUrl, })); }, @@ -74,7 +78,51 @@ export const rankingApi = { return response.data.data.map(item => ({ playerName: item.playerName, backNumber: item.backNumber, - era: item.era, + era: item.value, + playerImageUrl: item.playerImageUrl, + })); + }, + getRankPlayerHR: async () => { + const response = await axiosInstance.get( + "/record/personalRank/hitter/HR", + ); + return response.data.data.map(item => ({ + playerName: item.playerName, + backNumber: item.backNumber, + hr: item.value, + playerImageUrl: item.playerImageUrl, + })); + }, + getRankPlayerRBI: async () => { + const response = await axiosInstance.get( + "/record/personalRank/hitter/rbi", + ); + return response.data.data.map(item => ({ + playerName: item.playerName, + backNumber: item.backNumber, + rbi: item.value, + playerImageUrl: item.playerImageUrl, + })); + }, + getRankPlayerAVG: async () => { + const response = await axiosInstance.get( + "/record/personalRank/hitter/avg", + ); + return response.data.data.map(item => ({ + playerName: item.playerName, + backNumber: item.backNumber, + avg: item.value, + playerImageUrl: item.playerImageUrl, + })); + }, + getRankPlayerHit: async () => { + const response = await axiosInstance.get( + "/record/personalRank/hitter/H", + ); + return response.data.data.map(item => ({ + playerName: item.playerName, + backNumber: item.backNumber, + hit: item.value, playerImageUrl: item.playerImageUrl, })); }, diff --git a/src/pages/Home/components/KoreaMap.tsx b/src/pages/Home/components/KoreaMap.tsx index 88021ef..a64d8f6 100644 --- a/src/pages/Home/components/KoreaMap.tsx +++ b/src/pages/Home/components/KoreaMap.tsx @@ -307,6 +307,10 @@ export default function KoreaMap({ )} + {/* 데이터 출처 */} +
+ (공공데이터 포털 한국환경공단 데이터를 사용 중입니다.) +
); diff --git a/src/pages/Prediction/components/LivePrediction.tsx b/src/pages/Prediction/components/LivePrediction.tsx index 4bd6151..48130d0 100644 --- a/src/pages/Prediction/components/LivePrediction.tsx +++ b/src/pages/Prediction/components/LivePrediction.tsx @@ -1,53 +1,23 @@ import { Zap, RefreshCw } from "lucide-react"; -import { useState } from "react"; +import { useState, useEffect, useCallback } from "react"; import { PieChart, Pie, Cell } from "recharts"; +import { aiApi } from "../../../api/ai/apis"; +import { getEnglishTeamName } from "../../../hooks/TeamNameChanger"; interface Matchup { leftTeam: { name: string; logo: string; percent: number; + score: number; }; rightTeam: { name: string; logo: string; percent: number; + score: number; }; -} - -const initialMatchups: Matchup[] = [ - { - leftTeam: { name: "두산", logo: "doosan", percent: 32 }, - rightTeam: { name: "KIA", logo: "kia", percent: 68 }, - }, - { - leftTeam: { name: "SSG", logo: "ssg", percent: 31 }, - rightTeam: { name: "삼성", logo: "samsung", percent: 69 }, - }, - { - leftTeam: { name: "롯데", logo: "lotte", percent: 73 }, - rightTeam: { name: "키움", logo: "kiwoom", percent: 27 }, - }, - { - leftTeam: { name: "NC", logo: "nc", percent: 35 }, - rightTeam: { name: "LG", logo: "lg", percent: 65 }, - }, - { - leftTeam: { name: "한화", logo: "hanwha", percent: 75 }, - rightTeam: { name: "KT", logo: "kt", percent: 25 }, - }, -]; - -function getRandomizedMatchups() { - return initialMatchups.map(m => { - const left = Math.floor(Math.random() * 71) + 15; - const right = 100 - left; - return { - ...m, - leftTeam: { ...m.leftTeam, percent: left }, - rightTeam: { ...m.rightTeam, percent: right }, - }; - }); + inning: number; } // 팀별 색상 가져오기 함수 @@ -64,11 +34,77 @@ function getTeamColor(teamLogo: string) { } export default function LivePrediction() { - const [matchups, setMatchups] = useState(initialMatchups); + const [matchups, setMatchups] = useState([]); const [selectedIdx, setSelectedIdx] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + const [cooldown, setCooldown] = useState(0); + const [lastManualRefresh, setLastManualRefresh] = useState(0); + + const fetchPredictions = useCallback( + async (isManualRefresh = false) => { + // 수동 새로고침인 경우 쿨다운 체크 + if (isManualRefresh) { + const now = Date.now(); + if (now - lastManualRefresh < 10000) { + // 10초 쿨다운 + return; + } + setLastManualRefresh(now); + setCooldown(10); + } + + try { + setIsLoading(true); + setError(null); + const data = await aiApi.getGamePrediction(); + + const formattedMatchups: Matchup[] = data.map(game => ({ + leftTeam: { + name: game.awayTeam, + logo: getEnglishTeamName(game.awayTeam), + percent: Math.round((1 - game.winProbability) * 100), + score: game.awayAccumScore, + }, + rightTeam: { + name: game.homeTeam, + logo: getEnglishTeamName(game.homeTeam), + percent: Math.round(game.winProbability * 100), + score: game.homeAccumScore, + }, + inning: game.inning, + })); + + setMatchups(formattedMatchups); + } catch (err) { + setError("데이터를 불러오는데 실패했습니다."); + console.error("Failed to fetch predictions:", err); + } finally { + setIsLoading(false); + } + }, + [lastManualRefresh], + ); + + useEffect(() => { + fetchPredictions(); + // 1분마다 자동 갱신 + const interval = setInterval(() => fetchPredictions(false), 60000); + return () => clearInterval(interval); + }, [fetchPredictions]); + + // 쿨다운 타이머 + useEffect(() => { + if (cooldown > 0) { + const timer = setInterval(() => { + setCooldown(prev => prev - 1); + }, 1000); + return () => clearInterval(timer); + } + }, [cooldown]); const handleRefresh = () => { - setMatchups(getRandomizedMatchups()); + fetchPredictions(true); setSelectedIdx(null); }; @@ -149,70 +185,104 @@ export default function LivePrediction() { -

- 현재 진행 중인 경기의 승부 예측 결과입니다. +

+ AI가 분석한 실시간 승률입니다. 이닝 종료 시 자동 갱신됩니다.

-
- {matchups.map((match, idx) => { - const leftWin = match.leftTeam.percent > match.rightTeam.percent; - return ( -
setSelectedIdx(idx)} - > - {/* 왼쪽 팀 */} -
- - {match.leftTeam.name} - - {match.leftTeam.name} -
- {/* 확률 */} -
- - {match.leftTeam.percent}% - - - {match.rightTeam.percent}% - -
- {/* 오른쪽 팀 */} -
- {match.rightTeam.name} - - {match.rightTeam.name} - + {error ? ( +
+ {error} +
+ ) : isLoading ? ( +
+ +
+ ) : ( +
+ {matchups.slice(0, 5).map((match, idx) => { + return ( +
setSelectedIdx(idx)} + > + {/* 왼쪽 팀 */} +
+ + {match.leftTeam.name} + + {match.leftTeam.name} + + {match.leftTeam.score} + +
+ + {/* 이닝 표시 */} +
+
+ + {match.inning}회 + +
+
+ + {/* 오른쪽 팀 */} +
+ + {match.rightTeam.score} + + {match.rightTeam.name} + + {match.rightTeam.name} + +
-
- ); - })} -
+ ); + })} +
+ )} {/* 도넛 차트 */} {selected && (
-
+
{winnerText}
- + -
+
([]); + const [isLoading, setIsLoading] = useState(true); -// 임시 데이터 - 실제로는 API에서 가져올 데이터 -const mockTeams: Team[] = [ - { id: 1, name: "SSG 랜더스", logo: "ssg", prediction: 1 }, - { id: 2, name: "키움 히어로즈", logo: "kiwoom", prediction: 2 }, - { id: 3, name: "LG 트윈스", logo: "lg", prediction: 3 }, - { id: 4, name: "KT 위즈", logo: "kt", prediction: 4 }, - { id: 5, name: "KIA 타이거즈", logo: "kia", prediction: 5 }, - { id: 6, name: "NC 다이노스", logo: "nc", prediction: 6 }, - { id: 7, name: "두산 베어스", logo: "doosan", prediction: 7 }, - { id: 8, name: "롯데 자이언츠", logo: "lotte", prediction: 8 }, - { id: 9, name: "삼성 라이온즈", logo: "samsung", prediction: 9 }, - { id: 10, name: "한화 이글스", logo: "hanwha", prediction: 10 }, -]; + useEffect(() => { + const fetchTeams = async () => { + try { + const data = await aiApi.getFinalRank(); + setTeams(data); + } catch (error) { + console.error("팀 순위 데이터를 불러오는데 실패했습니다:", error); + } finally { + setIsLoading(false); + } + }; + + fetchTeams(); + }, []); + + if (isLoading) { + return ( +
+
+

로딩 중...

+
+
+ ); + } -export default function WinnerPrediction() { return (
@@ -40,30 +51,26 @@ export default function WinnerPrediction() { 현재 순위 - 승률 - {mockTeams.map(team => ( + {teams.map(team => ( - {team.prediction} + {team.rank} {team.name} - {team.name} - - - {team.prediction} + {team.teamName} - {(Math.random() * 0.3 + 0.4).toFixed(3)} + {team.currentRank} ))} diff --git a/src/pages/Profile/ProfileEdit.tsx b/src/pages/Profile/ProfileEdit.tsx index b8c5b06..5e0e4bf 100644 --- a/src/pages/Profile/ProfileEdit.tsx +++ b/src/pages/Profile/ProfileEdit.tsx @@ -2,10 +2,10 @@ import React, { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import BackHeader from "./components/BackHeader"; -import ImageUploader from "./components/ImageUpLoader"; +import ImageUploader from "./components/ImageUploader"; import NicknameField from "./components/NicknameField"; import IntroductionField from "./components/IntroductionField"; -import TeamSelect from "./components/TeamSelect"; +import TeamSelect from "./components/Teamselect"; import SubmitButton from "./components/SubmitButton"; const teamsList = [ @@ -25,7 +25,9 @@ export default function ProfileEdit() { const navigate = useNavigate(); const [nickname, setNickname] = useState(""); - const [checkResult, setCheckResult] = useState<"none" | "available" | "duplicate">("none"); + const [checkResult, setCheckResult] = useState< + "none" | "available" | "duplicate" + >("none"); const [introduction, setIntroduction] = useState(""); const [team, setTeam] = useState(teamsList[0]); @@ -46,7 +48,7 @@ export default function ProfileEdit() { { credentials: "include", headers: { Authorization: `Bearer ${jwt}` }, - } + }, ); if (!res.ok) throw new Error(res.statusText); const data = await res.json(); @@ -82,7 +84,7 @@ export default function ProfileEdit() { Authorization: `Bearer ${jwt}`, }, body: JSON.stringify({ nickname }), - } + }, ); if (res.status === 200) { setCheckResult("available"); @@ -116,7 +118,7 @@ export default function ProfileEdit() { credentials: "include", headers: { Authorization: `Bearer ${jwt}` }, body: form, - } + }, ); if (!res.ok) throw new Error(res.statusText); const body = await res.json(); @@ -145,7 +147,7 @@ export default function ProfileEdit() { Authorization: `Bearer ${jwt}`, }, body: JSON.stringify({ nickname, bio: introduction, cheeringTeamId }), - } + }, ); if (!res.ok) { const err = await res.json(); @@ -167,7 +169,7 @@ export default function ProfileEdit() {
{/* 2) 메인 컨테이너: 화면 중앙에 너비 제한 없이 채움 */} -
+
{/* 3) 카드 배경 없이 바로 폼 콘텐츠 */}
{/* ▷ 이미지 업로더 */} diff --git a/src/pages/Ranking/components/PlayerRankingTable.tsx b/src/pages/Ranking/components/PlayerRankingTable.tsx index 167d05b..1bede84 100644 --- a/src/pages/Ranking/components/PlayerRankingTable.tsx +++ b/src/pages/Ranking/components/PlayerRankingTable.tsx @@ -18,48 +18,42 @@ interface RankingCardProps { function RankingCard({ title, loading, data }: RankingCardProps) { return ( -
-
{title}
+
+
{title}
{loading ? (
로딩 중...
) : data.length === 0 ? (
데이터 없음
) : ( <> -
-
- 1 - {data[0]?.playerName} -
-
{data[0]?.playerName}
-
- #{data[0]?.backNumber} -
-
-
-
-
- {data.map((player, i) => ( -
-
- {i + 1} - {player.playerName} - - #{player.backNumber} - -
- - {player.value !== undefined && player.value !== null - ? player.value - : "-"} - -
- ))} + {/* 1위 선수 */} +
+ {data[0]?.playerName} + 1 + {data[0]?.playerName} + + {data[0]?.value} +
+
+ {/* 2~3위 선수 */} + {data.slice(1, 3).map((player, i) => ( +
+ + {i + 2} + + + {player.playerName} + + + {player.value} + +
+ ))} )}
@@ -71,65 +65,116 @@ export default function PlayerRankingTable() { const [eraData, setEraData] = useState([]); const [soData, setSoData] = useState([]); const [svData, setSvData] = useState([]); + const [hitData, setHitData] = useState([]); + const [hrData, setHrData] = useState([]); + const [rbiData, setRbiData] = useState([]); + const [avgData, setAvgData] = useState([]); const [loading, setLoading] = useState(true); + const [selectedCategory, setSelectedCategory] = useState<"투수" | "타자">( + "투수", + ); useEffect(() => { const fetchAll = async () => { setLoading(true); try { - const [win, era, so, sv] = await Promise.all([ - rankingApi.getRankPitcherWinRate(), - rankingApi.getRankPitcherEra(), - rankingApi.getRankPitcherSo(), - rankingApi.getRankPitcherSv(), - ]); - setWinData( - win.slice(0, 3).map((item: any) => ({ - playerName: item.playerName, - backNumber: item.backNumber, - playerImageUrl: item.playerImageUrl, - value: item.wpct ?? "-", - })), - ); - setEraData( - era.slice(0, 3).map((item: any) => ({ - playerName: item.playerName, - backNumber: item.backNumber, - playerImageUrl: item.playerImageUrl, - value: item.era ?? "-", - })), - ); - setSoData( - so.slice(0, 3).map((item: any) => ({ - playerName: item.playerName, - backNumber: item.backNumber, - playerImageUrl: item.playerImageUrl, - value: item.so ?? "-", - })), - ); - setSvData( - sv.slice(0, 3).map((item: any) => ({ - playerName: item.playerName, - backNumber: item.backNumber, - playerImageUrl: item.playerImageUrl, - value: item.sv ?? "-", - })), - ); + if (selectedCategory === "투수") { + const [win, era, so, sv] = await Promise.all([ + rankingApi.getRankPitcherWinRate(), + rankingApi.getRankPitcherEra(), + rankingApi.getRankPitcherSo(), + rankingApi.getRankPitcherSv(), + ]); + setWinData( + win.slice(0, 3).map((item: any) => ({ + playerName: item.playerName, + backNumber: item.backNumber, + playerImageUrl: item.playerImageUrl, + value: item.wpct ? Number(item.wpct).toFixed(3) : "-", + })), + ); + setEraData( + era.slice(0, 3).map((item: any) => ({ + playerName: item.playerName, + backNumber: item.backNumber, + playerImageUrl: item.playerImageUrl, + value: item.era ?? "-", + })), + ); + setSoData( + so.slice(0, 3).map((item: any) => ({ + playerName: item.playerName, + backNumber: item.backNumber, + playerImageUrl: item.playerImageUrl, + value: item.so ?? "-", + })), + ); + setSvData( + sv.slice(0, 3).map((item: any) => ({ + playerName: item.playerName, + backNumber: item.backNumber, + playerImageUrl: item.playerImageUrl, + value: item.sv ?? "-", + })), + ); + } else { + const [hit, hr, rbi, avg] = await Promise.all([ + rankingApi.getRankPlayerHit(), + rankingApi.getRankPlayerHR(), + rankingApi.getRankPlayerRBI(), + rankingApi.getRankPlayerAVG(), + ]); + setHitData( + hit.slice(0, 3).map((item: any) => ({ + playerName: item.playerName, + backNumber: item.backNumber, + playerImageUrl: item.playerImageUrl, + value: item.hit ?? "-", + })), + ); + setHrData( + hr.slice(0, 3).map((item: any) => ({ + playerName: item.playerName, + backNumber: item.backNumber, + playerImageUrl: item.playerImageUrl, + value: item.hr ?? "-", + })), + ); + setRbiData( + rbi.slice(0, 3).map((item: any) => ({ + playerName: item.playerName, + backNumber: item.backNumber, + playerImageUrl: item.playerImageUrl, + value: item.rbi ?? "-", + })), + ); + setAvgData( + avg.slice(0, 3).map((item: any) => ({ + playerName: item.playerName, + backNumber: item.backNumber, + playerImageUrl: item.playerImageUrl, + value: item.avg ? Number(item.avg).toFixed(3) : "-", + })), + ); + } } catch (e) { - setWinData([]); - setEraData([]); - setSoData([]); - setSvData([]); + if (selectedCategory === "투수") { + setWinData([]); + setEraData([]); + setSoData([]); + setSvData([]); + } else { + setHitData([]); + setHrData([]); + setRbiData([]); + setAvgData([]); + } } finally { setLoading(false); } }; fetchAll(); - }, []); - - const [selectedCategory, setSelectedCategory] = useState<"투수" | "타자">( - "투수", - ); + }, [selectedCategory]); return (
@@ -157,115 +202,250 @@ export default function PlayerRankingTable() {
- - - - + {selectedCategory === "투수" ? ( + <> + + + + + + ) : ( + <> + + + + + + )}
- - - {selectedCategory === "투수" ? ( - - - - - - - - - - - - - - - - - - - - ) : ( - - - - - - - - - - - - - - - - - - - )} - - - {selectedCategory === "투수" - ? pitcherRanks.map(player => ( - - - - - - - - - - - - - - - - - - - - )) - : batterRanks.map(player => ( - - - - - - - - - - - - - - - - - - - ))} - -
순위선수명ERA경기세이브홀드승률이닝피안타피홈런볼넷사구탈삼진WHIP
순위선수명팀명AVGGPAABRH2B3BHRTBRBISACSF
{player.rank} -
- {player.name} -
-
{player.team}{player.era}{player.games}{player.wins}{player.losses}{player.saves}{player.holds}{player.wpct}{player.innings}{player.hits}{player.hr}{player.bb}{player.hbp}{player.so}{player.whip}
{player.rank} -
- {player.name} -
-
{player.team}{player.avg}{player.games}{player.pa}{player.ab}{player.runs}{player.hits}{player.double}{player.triple}{player.hr}{player.tb}{player.rbi}{player.sac}{player.sf}
+
+ + + {selectedCategory === "투수" ? ( + + + + + + + + + + + + + + + + + + + + ) : ( + + + + + + + + + + + + + + + + + + + )} + + + {selectedCategory === "투수" + ? pitcherRanks.map(player => ( + + + + + + + + + + + + + + + + + + + + )) + : batterRanks.map(player => ( + + + + + + + + + + + + + + + + + + + ))} + +
+ 순위 + + 선수명 + + 팀 + + ERA + + 경기 + + 승 + + 패 + + 세이브 + + 홀드 + + 승률 + + 이닝 + + 피안타 + + 피홈런 + + 볼넷 + + 사구 + + 탈삼진 + WHIP
+ 순위 + + 선수명 + + 팀명 + + AVG + + G + + PA + + AB + + R + + H + + 2B + + 3B + + HR + + TB + + RBI + + SAC + SF
+ {player.rank} + +
+ {player.name} +
+
+ {player.team} + + {player.era} + + {player.games} + + {player.wins} + + {player.losses} + + {player.saves} + + {player.holds} + + {player.wpct} + + {player.innings} + + {player.hits} + + {player.hr} + + {player.bb} + + {player.hbp} + + {player.so} + + {player.whip} +
+ {player.rank} + +
+ {player.name} +
+
+ {player.team} + + {player.avg} + + {player.games} + + {player.pa} + + {player.ab} + + {player.runs} + + {player.hits} + + {player.double} + + {player.triple} + + {player.hr} + + {player.tb} + + {player.rbi} + + {player.sac} + {player.sf}
+
); diff --git a/src/pages/Ranking/components/TeamRankingTable.tsx b/src/pages/Ranking/components/TeamRankingTable.tsx index 81aa684..e024801 100644 --- a/src/pages/Ranking/components/TeamRankingTable.tsx +++ b/src/pages/Ranking/components/TeamRankingTable.tsx @@ -41,98 +41,80 @@ export default function TeamRankingTable() { fetchRankings(); }, []); - const handleTeamClick = (teamIdx: number) => { - const englishName = getEnglishTeamName(getTeamNameByIdx(teamIdx)); - navigate(`/team/${englishName.toLowerCase()}`); - }; + // const handleTeamClick = (teamIdx: number) => { + // const englishName = getEnglishTeamName(getTeamNameByIdx(teamIdx)); + // navigate(`/team/${englishName.toLowerCase()}`); + // }; if (isLoading) { return
로딩 중...
; } return ( -
- - - - - - - - - - - - - - - - - {rankings.map(team => ( - - - - - - - - - - - +
+
+
- 팀명 - - 경기 - - 승 - - 무 - - 패 - - 승률 - - 게임차 - - 연속 - - 최근 10경기 -
- {team.rank} - handleTeamClick(team.teamIdx)} - > - {team.teamName} - {team.teamName} - - {team.games} - - {team.wins} - - {team.draws} - - {team.losses} - - {team.winRate.toFixed(3)} - - {team.gameGap} - - {team.streak} - - {team.recentTen} -
+ + + + + + + + + + + + - ))} - -
+ 팀명 + + 경기 + + 승 + + 무 + + 패 + + 승률 + + 게임차 + + 연속 + + 최근10경기 +
+ + + {rankings.map(team => ( + + + {team.rank} + + +
+ {team.teamName} + {team.teamName} +
+ + {team.games} + {team.wins} + {team.draws} + {team.losses} + {team.winRate.toFixed(3)} + {team.gameGap} + {team.streak} + {team.recentTen} + + ))} + + +
); } diff --git a/src/types/ai.ts b/src/types/ai.ts index 212182e..d6c9e67 100644 --- a/src/types/ai.ts +++ b/src/types/ai.ts @@ -5,3 +5,25 @@ export interface AIPredictionDTO { } export type AIPredictionResponse = AIPredictionDTO[]; + +export interface TeamRankDTO { + id: number; + teamName: string; + rank: number; + currentRank: number; +} + +export type FinalRankingResponse = TeamRankDTO[]; + +export interface GamePredictionDTO { + gameId: string; + awayTeam: string; + homeTeam: string; + inning: number; + winProbability: number; + homeAccumScore: number; + awayAccumScore: number; + predictedAt: string; +} + +export type GamePredictionResponse = GamePredictionDTO[]; diff --git a/src/types/ranking.ts b/src/types/ranking.ts index a8671a8..9e3f300 100644 --- a/src/types/ranking.ts +++ b/src/types/ranking.ts @@ -16,54 +16,56 @@ export interface RankingDto { data: TeamRank[]; } -export interface PitcherWinRate { +export interface PitcherRanking { playerName: string; backNumber: number; - wpct: number; playerImageUrl: string; + value: T; } -export interface PitcherWinRateDto { +export interface PitcherRankingDto { success: boolean; message: string; - data: PitcherWinRate[]; + data: PitcherRanking[]; } -export interface PitcherSave { - playerName: string; - backNumber: number; - sv: number; - playerImageUrl: string; -} +// 타입 별칭 정의 +export type PitcherWinRate = PitcherRanking; +export type PitcherWinRateDto = PitcherRankingDto; -export interface PitcherSaveDto { - success: boolean; - message: string; - data: PitcherSave[]; -} +export type PitcherSave = PitcherRanking; +export type PitcherSaveDto = PitcherRankingDto; -export interface PitcherStrikeout { - playerName: string; - backNumber: number; - so: number; - playerImageUrl: string; -} +export type PitcherStrikeout = PitcherRanking; +export type PitcherStrikeoutDto = PitcherRankingDto; -export interface PitcherStrikeoutDto { - success: boolean; - message: string; - data: PitcherStrikeout[]; -} +export type PitcherEra = PitcherRanking; +export type PitcherEraDto = PitcherRankingDto; -export interface PitcherEra { +// 타자 랭킹 관련 인터페이스 +export interface PlayerRanking { playerName: string; backNumber: number; - era: number; + playerIdx: number; playerImageUrl: string; + value: T; } -export interface PitcherEraDto { +export interface PlayerRankingDto { success: boolean; message: string; - data: PitcherEra[]; + data: PlayerRanking[]; } + +// 타자 랭킹 타입 별칭 +export type PlayerHR = PlayerRanking; +export type PlayerHRDto = PlayerRankingDto; + +export type PlayerRBI = PlayerRanking; +export type PlayerRBIDto = PlayerRankingDto; + +export type PlayerAVG = PlayerRanking; +export type PlayerAVGDto = PlayerRankingDto; + +export type PlayerHit = PlayerRanking; +export type PlayerHitDto = PlayerRankingDto;