@@ -118,7 +118,7 @@ import { aggregatePitchingStats, fetchPitchingStatsBySeasonAndTeamId, type Pitch
import { outsToInnings, winPercentage, hitsPer9, hrsPer9 } from '@/services/utilities'
export default {
- name: "TeamPitchingTable",
+ name: 'TeamPitchingTable',
props: {
seasonNumber: { type: Number, required: true },
teamId: { type: Number, required: true },
diff --git a/src/router/index.ts b/src/router/index.ts
index 2678e7f..a689d1c 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -53,6 +53,12 @@ export const routes: RouteRecordRaw[] = [
component: () => import('../views/ManagerView.vue'),
props: castManagersRouteParams
},
+ {
+ path: '/games/:seasonNumber/:weekNumber/:gameNumber/:team1Abbreviation/:team2Abbreviation',
+ name: 'games',
+ component: () => import('../views/GameView.vue'),
+ props: castGamesRouteParams
+ },
]
function castTeamsRouteParams(route: { params: { teamAbbreviation: string, seasonNumber: string } }) {
@@ -82,6 +88,16 @@ function castManagersRouteParams(route: { params: { managerName: string } }) {
}
}
+function castGamesRouteParams(route: { params: { seasonNumber: string, weekNumber: string, gameNumber: string, team1Abbreviation: string, team2Abbreviation: string } }) {
+ return {
+ seasonNumber: Number(route.params.seasonNumber),
+ weekNumber: Number(route.params.weekNumber),
+ gameNumber: Number(route.params.gameNumber),
+ team1Abbreviation: route.params.team1Abbreviation,
+ team2Abbreviation: route.params.team2Abbreviation,
+ }
+}
+
const router = createRouter({
history: createWebHistory(), //import.meta.env.BASE_URL),
routes,
diff --git a/src/services/battingStatsService.ts b/src/services/battingStatsService.ts
index b9e31c6..91f2534 100644
--- a/src/services/battingStatsService.ts
+++ b/src/services/battingStatsService.ts
@@ -155,6 +155,22 @@ export async function fetchBattingStatsForLastFourGamesBySeasonAndPlayerId(seaso
return battingStatsResponse.stats
}
+export async function fetchBattingStatsBySeries(seasonNumber: number, weekNumber: number, homeTeamId: number, awayTeamId: number): Promise {
+ // no support for pre-modern games yet
+ if (seasonNumber < MODERN_STAT_ERA_START) {
+ return []
+ }
+
+ const response = await fetch(`${SITE_URL}/api/v3/plays/batting?season=${seasonNumber}&week=${weekNumber}&team_id=${homeTeamId}&team_id=${awayTeamId}&group_by=playergame`)
+
+ const battingStatsResponse: {
+ count: number
+ stats: BattingStat[]
+ } = await response.json()
+
+ return battingStatsResponse.stats
+}
+
export function aggregateBattingStats(battingStats: BattingStat[]): BattingStat {
const totalStat: BattingStat = {
player: battingStats[0].player,
diff --git a/src/services/fieldingStatsService.ts b/src/services/fieldingStatsService.ts
index bacf8cf..8320f98 100644
--- a/src/services/fieldingStatsService.ts
+++ b/src/services/fieldingStatsService.ts
@@ -137,6 +137,22 @@ export async function fetchFieldingStatsForLastFourGamesBySeasonAndPlayerId(seas
return fieldingStatsResponse.stats.map(normalizeFieldingStat)
}
+export async function fetchFieldingStatsBySeries(seasonNumber: number, weekNumber: number, homeTeamId: number, awayTeamId: number): Promise {
+ // no support for pre-modern games yet
+ if (seasonNumber < MODERN_STAT_ERA_START) {
+ return []
+ }
+
+ const response = await fetch(`${SITE_URL}/api/v3/plays/fielding?season=${seasonNumber}&week=${weekNumber}&team_id=${homeTeamId}&team_id=${awayTeamId}&group_by=playerpositiongame`)
+
+ const fieldingStatsResponse: {
+ count: number
+ stats: FieldingStatRaw[]
+ } = await response.json()
+
+ return fieldingStatsResponse.stats.map(normalizeFieldingStat)
+}
+
export function aggregateFieldingStats(fieldingStats: FieldingStat[]): FieldingStat[] {
const fieldingStatsByPosition = fieldingStats.reduce((statsByPos: { [key: string]: FieldingStat }, stat: FieldingStat) => {
if (!statsByPos[stat.pos]) {
diff --git a/src/services/gameService.ts b/src/services/gameService.ts
index 79831aa..96b4775 100644
--- a/src/services/gameService.ts
+++ b/src/services/gameService.ts
@@ -32,3 +32,25 @@ export async function fetchGamesBySeasonAndWeek(seasonNumber: number, weekNumber
return gamesResponse.games
}
+
+export async function fetchSingleGame(seasonNumber: number, weekNumber: number, gameNumber: number, homeTeamId: number, awayTeamId: number): Promise {
+ if (seasonNumber < MODERN_STAT_ERA_START) {
+ console.warn('Cannot use games endpoint to fetch stats before season 8')
+ return undefined
+ }
+
+ const response = await fetch(`${SITE_URL}/api/v3/games?season=${seasonNumber}&week=${weekNumber}&game_num=${gameNumber}&team1_id=${homeTeamId}&team2_id=${awayTeamId}`)
+
+ const gamesResponse: {
+ count: number
+ games: Game[]
+ } = await response.json()
+
+ if (gamesResponse.count !== 1) {
+ throw new Error('gameService.fetchSingleGame - Expected one game, return contained none or many')
+ }
+
+ return gamesResponse.games[0]
+}
+
+// v3/games?season=9&week=1&game_num=1&team1_id=355&team2_id=361&short_output=TRUE
diff --git a/src/services/pitchingStatsService.ts b/src/services/pitchingStatsService.ts
index 60c583a..fdf90c2 100644
--- a/src/services/pitchingStatsService.ts
+++ b/src/services/pitchingStatsService.ts
@@ -222,6 +222,22 @@ export async function fetchPitchingStatsForLastFourGamesBySeasonAndPlayerId(seas
return pitchingStatsResponse.stats.map(normalizePitchingStat)
}
+export async function fetchPitchingStatsBySeries(seasonNumber: number, weekNumber: number, homeTeamId: number, awayTeamId: number): Promise {
+ // no support for pre-modern games yet
+ if (seasonNumber < MODERN_STAT_ERA_START) {
+ return []
+ }
+
+ const response = await fetch(`${SITE_URL}/api/v3/plays/pitching?season=${seasonNumber}&week=${weekNumber}&team_id=${homeTeamId}&team_id=${awayTeamId}&group_by=playergame`)
+
+ const pitchingStatsResponse: {
+ count: number
+ stats: PitchingStat[]
+ } = await response.json()
+
+ return pitchingStatsResponse.stats
+}
+
export function aggregatePitchingStats(pitchingStats: PitchingStat[]): PitchingStat {
const totalStat: PitchingStat = {
player: pitchingStats[0].player,
diff --git a/src/views/GameView.vue b/src/views/GameView.vue
new file mode 100644
index 0000000..5c7acff
--- /dev/null
+++ b/src/views/GameView.vue
@@ -0,0 +1,444 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ finalScore }}
+
+ Season {{ seasonNumber }} - Week {{ weekNumber }} - Game {{ gameNumber }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Player |
+ PA |
+ AB |
+ R |
+ H |
+ 2B |
+ 3B |
+ HR |
+ RBI |
+ SB |
+ CS |
+ BB |
+ SO |
+ GIDP |
+ HBP |
+ SAC |
+ IBB |
+
+
+
+
+ |
+
+ {{ stat.player.name }}
+
+ |
+ {{ stat.pa }} |
+ {{ stat.ab }} |
+ {{ stat.run }} |
+ {{ stat.hit }} |
+ {{ stat.double }} |
+ {{ stat.triple }} |
+ {{ stat.hr }} |
+ {{ stat.rbi }} |
+ {{ stat.sb }} |
+ {{ stat.cs }} |
+ {{ stat.bb }} |
+ {{ stat.so }} |
+ {{ stat.gidp }} |
+ {{ stat.hbp }} |
+ {{ stat.sac }} |
+ {{ stat.ibb }} |
+
+
+
+
+
+
+
+
+
+
+
+
+ | Player |
+ X-Ch |
+ X-Hit |
+ Error |
+ PB |
+ SBa |
+ CSc |
+
+
+
+
+ |
+
+ {{ stat.player.name }}
+
+ |
+ {{ stat.xCheckCount }} |
+ {{ stat.hit }} |
+ {{ stat.error }} |
+ {{ stat.passedBallCount }} |
+ {{ stat.stolenBaseCheckCount }} |
+ {{ stat.caughtStealingCount }} |
+
+
+
+
+
+
+
+
+
+
+
+
+ | Player |
+ W |
+ L |
+ SV |
+ HD |
+ BSV |
+ IP |
+ H |
+ R |
+ ER |
+ HR |
+ BB |
+ SO |
+ HBP |
+ BK |
+ WP |
+
+
+
+
+ |
+
+ {{ stat.player.name }}
+
+ |
+ {{ stat.win }} |
+ {{ stat.loss }} |
+ {{ stat.save }} |
+ {{ stat.hold }} |
+ {{ stat.bsave }} |
+ {{ outsToInnings(stat) }} |
+ {{ stat.hits }} |
+ {{ stat.run }} |
+ {{ stat.e_run }} |
+ {{ stat.hr }} |
+ {{ stat.bb }} |
+ {{ stat.so }} |
+ {{ stat.hbp }} |
+ {{ stat.balk }} |
+ {{ stat.wp }} |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Player |
+ PA |
+ AB |
+ R |
+ H |
+ 2B |
+ 3B |
+ HR |
+ RBI |
+ SB |
+ CS |
+ BB |
+ SO |
+ GIDP |
+ HBP |
+ SAC |
+ IBB |
+
+
+
+
+ |
+
+ {{ stat.player.name }}
+
+ |
+ {{ stat.pa }} |
+ {{ stat.ab }} |
+ {{ stat.run }} |
+ {{ stat.hit }} |
+ {{ stat.double }} |
+ {{ stat.triple }} |
+ {{ stat.hr }} |
+ {{ stat.rbi }} |
+ {{ stat.sb }} |
+ {{ stat.cs }} |
+ {{ stat.bb }} |
+ {{ stat.so }} |
+ {{ stat.gidp }} |
+ {{ stat.hbp }} |
+ {{ stat.sac }} |
+ {{ stat.ibb }} |
+
+
+
+
+
+
+
+
+
+
+
+
+ | Player |
+ X-Ch |
+ X-Hit |
+ Error |
+ PB |
+ SBa |
+ CSc |
+
+
+
+
+ |
+
+ {{ stat.player.name }}
+
+ |
+ {{ stat.xCheckCount }} |
+ {{ stat.hit }} |
+ {{ stat.error }} |
+ {{ stat.passedBallCount }} |
+ {{ stat.stolenBaseCheckCount }} |
+ {{ stat.caughtStealingCount }} |
+
+
+
+
+
+
+
+
+
+
+
+
+ | Player |
+ W |
+ L |
+ SV |
+ HD |
+ BSV |
+ IP |
+ H |
+ R |
+ ER |
+ HR |
+ BB |
+ SO |
+ HBP |
+ BK |
+ WP |
+
+
+
+
+ |
+
+ {{ stat.player.name }}
+
+ |
+ {{ stat.win }} |
+ {{ stat.loss }} |
+ {{ stat.save }} |
+ {{ stat.hold }} |
+ {{ stat.bsave }} |
+ {{ outsToInnings(stat) }} |
+ {{ stat.hits }} |
+ {{ stat.run }} |
+ {{ stat.e_run }} |
+ {{ stat.hr }} |
+ {{ stat.bb }} |
+ {{ stat.so }} |
+ {{ stat.hbp }} |
+ {{ stat.balk }} |
+ {{ stat.wp }} |
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/views/ScheduleView.vue b/src/views/ScheduleView.vue
index 9ecd73f..f3695c1 100644
--- a/src/views/ScheduleView.vue
+++ b/src/views/ScheduleView.vue
@@ -160,7 +160,7 @@ export default {
for (let week = 1; week <= 21; week++) {
const weekStartDate = currentWeekStartDate
- const weekEndDate = this.isLongSeries(week, weekStartDate)
+ const weekEndDate = this.isLongSeries(weekStartDate)
? currentWeekStartDate.add(13, 'd')
: currentWeekStartDate.add(6, 'd')
@@ -195,7 +195,7 @@ export default {
async fetchData(): Promise {
this.weekGames = await fetchGamesBySeasonAndWeek(this.seasonNumber, this.selectedWeekNumber)
},
- isLongSeries(weekNumber: number, weekStartDate: dayjs.Dayjs): boolean {
+ isLongSeries(weekStartDate: dayjs.Dayjs): boolean {
// current 18-week schedule has 2 week series for any game week that falls
// on the week of Thanksgiving or Christmas
return Math.abs(weekStartDate.diff(THANKSGIVING, 'days')) < 6
|