Merge pull request #30 from pgiro/add-transactions-to-site
Add team stats to site
This commit is contained in:
commit
e92655fb62
3
components.d.ts
vendored
3
components.d.ts
vendored
@ -18,6 +18,9 @@ declare module '@vue/runtime-core' {
|
|||||||
IconTooling: typeof import('./src/components/icons/IconTooling.vue')['default']
|
IconTooling: typeof import('./src/components/icons/IconTooling.vue')['default']
|
||||||
LastFourGamesBattingTable: typeof import('./src/components/LastFourGamesBattingTable.vue')['default']
|
LastFourGamesBattingTable: typeof import('./src/components/LastFourGamesBattingTable.vue')['default']
|
||||||
LastFourGamesPitchingTable: typeof import('./src/components/LastFourGamesPitchingTable.vue')['default']
|
LastFourGamesPitchingTable: typeof import('./src/components/LastFourGamesPitchingTable.vue')['default']
|
||||||
|
LeaderboardTeamBattingTable: typeof import('./src/components/LeaderboardTeamBattingTable.vue')['default']
|
||||||
|
LeaderboardTeamFieldingTable: typeof import('./src/components/LeaderboardTeamFieldingTable.vue')['default']
|
||||||
|
LeaderboardTeamPitchingTable: typeof import('./src/components/LeaderboardTeamPitchingTable.vue')['default']
|
||||||
NavBar: typeof import('./src/components/NavBar.vue')['default']
|
NavBar: typeof import('./src/components/NavBar.vue')['default']
|
||||||
NewsPreview: typeof import('./src/components/NewsPreview.vue')['default']
|
NewsPreview: typeof import('./src/components/NewsPreview.vue')['default']
|
||||||
PlayerBattingSummaryTable: typeof import('./src/components/PlayerBattingSummaryTable.vue')['default']
|
PlayerBattingSummaryTable: typeof import('./src/components/PlayerBattingSummaryTable.vue')['default']
|
||||||
|
|||||||
154
src/components/LeaderboardTeamBattingTable.vue
Normal file
154
src/components/LeaderboardTeamBattingTable.vue
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
<template>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="table-responsive-xl">
|
||||||
|
<table class="table table-sm table-striped" id="table-batting-stats">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr style="min-width: 75px">
|
||||||
|
<th>Team</th>
|
||||||
|
<th>PA</th>
|
||||||
|
<th>AB</th>
|
||||||
|
<th>R</th>
|
||||||
|
<th>H</th>
|
||||||
|
<th>2B</th>
|
||||||
|
<th>3B</th>
|
||||||
|
<th>HR</th>
|
||||||
|
<th>RBI</th>
|
||||||
|
<th>SB</th>
|
||||||
|
<th>CS</th>
|
||||||
|
<th>BB</th>
|
||||||
|
<th>SO</th>
|
||||||
|
<th>BA</th>
|
||||||
|
<th>OBP</th>
|
||||||
|
<th>SLG</th>
|
||||||
|
<th>OPS</th>
|
||||||
|
<th>wOBA</th>
|
||||||
|
<th>K%</th>
|
||||||
|
<th>BPHR</th>
|
||||||
|
<th>BPFO</th>
|
||||||
|
<th>BP1B</th>
|
||||||
|
<th>BPLO</th>
|
||||||
|
<th>GIDP</th>
|
||||||
|
<th>HBP</th>
|
||||||
|
<th>SAC</th>
|
||||||
|
<th>IBB</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody v-if="battingStats.length" >
|
||||||
|
<tr v-for="stat in battingStats" :key="stat.player.bbref_id">
|
||||||
|
<td>
|
||||||
|
<RouterLink
|
||||||
|
:to="{ name: 'team', params: { seasonNumber: seasonNumber, teamAbbreviation: stat.team.abbrev } }">
|
||||||
|
{{ stat.team.sname }}
|
||||||
|
</RouterLink>
|
||||||
|
</td>
|
||||||
|
<td>{{ stat.pa }}</td>
|
||||||
|
<td>{{ stat.ab }}</td>
|
||||||
|
<td>{{ stat.run }}</td>
|
||||||
|
<td>{{ stat.hit }}</td>
|
||||||
|
<td>{{ stat.double }}</td>
|
||||||
|
<td>{{ stat.triple }}</td>
|
||||||
|
<td>{{ stat.hr }}</td>
|
||||||
|
<td>{{ stat.rbi }}</td>
|
||||||
|
<td>{{ stat.sb }}</td>
|
||||||
|
<td>{{ stat.cs }}</td>
|
||||||
|
<td>{{ stat.bb }}</td>
|
||||||
|
<td>{{ stat.so }}</td>
|
||||||
|
<td>{{ stat.avg.toFixed(3) }}</td>
|
||||||
|
<td>{{ stat.obp.toFixed(3) }}</td>
|
||||||
|
<td>{{ stat.slg.toFixed(3) }}</td>
|
||||||
|
<td>{{ stat.ops.toFixed(3) }}</td>
|
||||||
|
<td>{{ stat.woba.toFixed(3) }}</td>
|
||||||
|
<td>{{ calculateStrikeoutPercent(stat) }}</td>
|
||||||
|
<td>{{ stat.bphr }}</td>
|
||||||
|
<td>{{ stat.bpfo }}</td>
|
||||||
|
<td>{{ stat.bp1b }}</td>
|
||||||
|
<td>{{ stat.bplo }}</td>
|
||||||
|
<td>{{ stat.gidp }}</td>
|
||||||
|
<td>{{ stat.hbp }}</td>
|
||||||
|
<td>{{ stat.sac }}</td>
|
||||||
|
<td>{{ stat.ibb }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot v-if="battingStats.length" >
|
||||||
|
<tr v-if="totalBattingStat">
|
||||||
|
<th>Total</th>
|
||||||
|
<th>{{ totalBattingStat.pa }}</th>
|
||||||
|
<th>{{ totalBattingStat.ab }}</th>
|
||||||
|
<th>{{ totalBattingStat.run }}</th>
|
||||||
|
<th>{{ totalBattingStat.hit }}</th>
|
||||||
|
<th>{{ totalBattingStat.double }}</th>
|
||||||
|
<th>{{ totalBattingStat.triple }}</th>
|
||||||
|
<th>{{ totalBattingStat.hr }}</th>
|
||||||
|
<th>{{ totalBattingStat.rbi }}</th>
|
||||||
|
<th>{{ totalBattingStat.sb }}</th>
|
||||||
|
<th>{{ totalBattingStat.cs }}</th>
|
||||||
|
<th>{{ totalBattingStat.bb }}</th>
|
||||||
|
<th>{{ totalBattingStat.so }}</th>
|
||||||
|
<th>{{ totalBattingStat.avg.toFixed(3) }}</th>
|
||||||
|
<th>{{ totalBattingStat.obp.toFixed(3) }}</th>
|
||||||
|
<th>{{ totalBattingStat.slg.toFixed(3) }}</th>
|
||||||
|
<th>{{ totalBattingStat.ops.toFixed(3) }}</th>
|
||||||
|
<th>{{ totalBattingStat.woba.toFixed(3) }}</th>
|
||||||
|
<th>{{ calculateStrikeoutPercent(totalBattingStat) }}</th>
|
||||||
|
<th>{{ totalBattingStat.bphr }}</th>
|
||||||
|
<th>{{ totalBattingStat.bpfo }}</th>
|
||||||
|
<th>{{ totalBattingStat.bp1b }}</th>
|
||||||
|
<th>{{ totalBattingStat.bplo }}</th>
|
||||||
|
<th>{{ totalBattingStat.gidp }}</th>
|
||||||
|
<th>{{ totalBattingStat.hbp }}</th>
|
||||||
|
<th>{{ totalBattingStat.sac }}</th>
|
||||||
|
<th>{{ totalBattingStat.ibb }}</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { aggregateBattingStats, fetchTeamBattingStatsBySeason, type BattingStat } from '@/services/battingStatsService'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'LeaderboardTeamBattingTable',
|
||||||
|
props: {
|
||||||
|
seasonNumber: { type: Number, required: true }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
battingStats: [] as BattingStat[]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
totalBattingStat(): BattingStat | undefined {
|
||||||
|
if (this.battingStats.length > 0) {
|
||||||
|
return aggregateBattingStats(this.battingStats)
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
seasonNumber(newValue, oldValue) {
|
||||||
|
if (newValue !== oldValue){
|
||||||
|
this.battingStats = []
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchData(): Promise<void> {
|
||||||
|
const unsortedBattingStats: BattingStat[] = await fetchTeamBattingStatsBySeason(this.seasonNumber)
|
||||||
|
this.battingStats = unsortedBattingStats.sort((s1, s2) => s2.team.sname < s1.team.sname ? 1 : -1)
|
||||||
|
},
|
||||||
|
calculateStrikeoutPercent(stat: BattingStat): string {
|
||||||
|
if (!stat.pa) return 'N/A'
|
||||||
|
return (stat.so * 100 / stat.pa).toFixed(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
103
src/components/LeaderboardTeamFieldingTable.vue
Normal file
103
src/components/LeaderboardTeamFieldingTable.vue
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<template>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="table-responsive-xl" style="max-width:40rem">
|
||||||
|
<table class="table table-sm table-striped" id="table-fielding-stats">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Team</th>
|
||||||
|
<th>XCh</th>
|
||||||
|
<th>XH</th>
|
||||||
|
<th>E</th>
|
||||||
|
<th>PB</th>
|
||||||
|
<th>SBa</th>
|
||||||
|
<th>CSc</th>
|
||||||
|
<th>CS%</th>
|
||||||
|
<th>wF%</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody v-if="fieldingStats.length" >
|
||||||
|
<tr v-for="stat in fieldingStats" :key="stat.team.abbrev">
|
||||||
|
<td>
|
||||||
|
<RouterLink
|
||||||
|
:to="{ name: 'team', params: { seasonNumber: seasonNumber, teamAbbreviation: stat.team.abbrev } }">
|
||||||
|
{{ stat.team.sname }}
|
||||||
|
</RouterLink>
|
||||||
|
</td>
|
||||||
|
<td>{{ stat.xCheckCount }}</td>
|
||||||
|
<td>{{ stat.hit }}</td>
|
||||||
|
<td>{{ stat.error }}</td>
|
||||||
|
<td>{{ stat.passedBallCount }}</td>
|
||||||
|
<td>{{ stat.stolenBaseCheckCount }}</td>
|
||||||
|
<td>{{ stat.caughtStealingCount }}</td>
|
||||||
|
<td>{{ formatCaughtStealingPercent(stat) }}</td>
|
||||||
|
<td>{{ formatWeightedFieldingPercent(stat) }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot v-if="fieldingStats.length" >
|
||||||
|
<tr v-for="stat in totalFieldingStat" id="career-fielding-footer" :key="stat.pos">
|
||||||
|
<th>Total</th>
|
||||||
|
<th>{{ stat.xCheckCount }}</th>
|
||||||
|
<th>{{ stat.hit }}</th>
|
||||||
|
<th>{{ stat.error }}</th>
|
||||||
|
<th>{{ stat.passedBallCount }}</th>
|
||||||
|
<th>{{ stat.stolenBaseCheckCount }}</th>
|
||||||
|
<th>{{ stat.caughtStealingCount }}</th>
|
||||||
|
<th>{{ formatCaughtStealingPercent(stat) }}</th>
|
||||||
|
<th>{{ formatWeightedFieldingPercent(stat) }}</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { aggregateFieldingStats, fetchTeamFieldingStatsBySeason, type FieldingStat } from '@/services/fieldingStatsService'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'LeaderboardTeamFieldingTable',
|
||||||
|
props: {
|
||||||
|
seasonNumber: { type: Number, required: true }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fieldingStats: [] as FieldingStat[]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
totalFieldingStat(): FieldingStat[] {
|
||||||
|
if (this.fieldingStats.length > 0) {
|
||||||
|
return aggregateFieldingStats(this.fieldingStats)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
seasonNumber(newValue, oldValue) {
|
||||||
|
if (newValue !== oldValue) {
|
||||||
|
this.fieldingStats = []
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchData(): Promise<void> {
|
||||||
|
const unsortedFieldingStats: FieldingStat[] = await fetchTeamFieldingStatsBySeason(this.seasonNumber)
|
||||||
|
this.fieldingStats = unsortedFieldingStats.sort((s1, s2) => s2.team.sname < s1.team.sname ? 1 : -1)
|
||||||
|
},
|
||||||
|
formatCaughtStealingPercent(stat: FieldingStat): string {
|
||||||
|
if (stat.stolenBaseCheckCount === 0 || Number.isNaN(stat.caughtStealingPercent)) {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${(stat.caughtStealingPercent * 100).toFixed(1)}%`
|
||||||
|
},
|
||||||
|
formatWeightedFieldingPercent(stat: FieldingStat): string {
|
||||||
|
return stat.weightedFieldingPercent.toFixed(3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
168
src/components/LeaderboardTeamPitchingTable.vue
Normal file
168
src/components/LeaderboardTeamPitchingTable.vue
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
<template>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="table-responsive-xl">
|
||||||
|
<table class="table table-sm table-striped" id="table-pitching-stats">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Team</th>
|
||||||
|
<th>W</th>
|
||||||
|
<th>L</th>
|
||||||
|
<th>W-L%</th>
|
||||||
|
<th>ERA</th>
|
||||||
|
<th>G</th>
|
||||||
|
<th>GS</th>
|
||||||
|
<th>SV</th>
|
||||||
|
<th>HD</th>
|
||||||
|
<th>BSV</th>
|
||||||
|
<th>IP</th>
|
||||||
|
<th>H</th>
|
||||||
|
<th>R</th>
|
||||||
|
<th>ER</th>
|
||||||
|
<th>HR</th>
|
||||||
|
<th>BB</th>
|
||||||
|
<th>SO</th>
|
||||||
|
<th>HBP</th>
|
||||||
|
<th>BK</th>
|
||||||
|
<th>WP</th>
|
||||||
|
<th>IR</th>
|
||||||
|
<th>IRS</th>
|
||||||
|
<th>WHIP</th>
|
||||||
|
<th>H/9</th>
|
||||||
|
<th>HR/9</th>
|
||||||
|
<th>BB/9</th>
|
||||||
|
<th>SO/9</th>
|
||||||
|
<th>SO/BB</th>
|
||||||
|
<!-- <th>Last G</th>
|
||||||
|
<th>Last G-2</th> -->
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody v-if="pitchingStats.length">
|
||||||
|
<tr v-for="stat in pitchingStats" :key="stat.player.name">
|
||||||
|
<td>
|
||||||
|
<RouterLink
|
||||||
|
:to="{ name: 'team', params: { seasonNumber: seasonNumber, teamAbbreviation: stat.team.abbrev } }">
|
||||||
|
{{ stat.team.sname }}
|
||||||
|
</RouterLink>
|
||||||
|
</td>
|
||||||
|
<td>{{ stat.win }}</td>
|
||||||
|
<td>{{ stat.loss }}</td>
|
||||||
|
<td>{{ winPercentage(stat) }}</td>
|
||||||
|
<td>{{ stat.era.toFixed(2) }}</td>
|
||||||
|
<td>{{ stat.games }}</td>
|
||||||
|
<td>{{ stat.gs }}</td>
|
||||||
|
<td>{{ stat.save }}</td>
|
||||||
|
<td>{{ stat.hold }}</td>
|
||||||
|
<td>{{ stat.bsave }}</td>
|
||||||
|
<td>{{ outsToInnings(stat) }}</td>
|
||||||
|
<td>{{ stat.hits }}</td>
|
||||||
|
<td>{{ stat.run }}</td>
|
||||||
|
<td>{{ stat.e_run }}</td>
|
||||||
|
<td>{{ stat.hr }}</td>
|
||||||
|
<td>{{ stat.bb }}</td>
|
||||||
|
<td>{{ stat.so }}</td>
|
||||||
|
<td>{{ stat.hbp }}</td>
|
||||||
|
<td>{{ stat.balk }}</td>
|
||||||
|
<td>{{ stat.wp }}</td>
|
||||||
|
<td>{{ stat.ir }}</td>
|
||||||
|
<td>{{ stat.ir_sc }}</td>
|
||||||
|
<td>{{ stat.whip.toFixed(2) }}</td>
|
||||||
|
<td>{{ hitsPer9(stat) }}</td>
|
||||||
|
<td>{{ hrsPer9(stat) }}</td>
|
||||||
|
<td>{{ stat.bbPer9.toFixed(1) }}</td>
|
||||||
|
<td>{{ stat.kPer9.toFixed(1) }}</td>
|
||||||
|
<td>{{ stat.kPerBB.toFixed(1) }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot v-if="pitchingStats.length">
|
||||||
|
<tr v-if="totalPitchingStat">
|
||||||
|
<th>Total</th>
|
||||||
|
<th>{{ totalPitchingStat.win }}</th>
|
||||||
|
<th>{{ totalPitchingStat.loss }}</th>
|
||||||
|
<th>{{ winPercentage(totalPitchingStat) }}</th>
|
||||||
|
<th>{{ totalPitchingStat.era.toFixed(2) }}</th>
|
||||||
|
<th>{{ totalPitchingStat.games }}</th>
|
||||||
|
<th>{{ totalPitchingStat.gs }}</th>
|
||||||
|
<th>{{ totalPitchingStat.save }}</th>
|
||||||
|
<th>{{ totalPitchingStat.hold }}</th>
|
||||||
|
<th>{{ totalPitchingStat.bsave }}</th>
|
||||||
|
<th>{{ outsToInnings(totalPitchingStat) }}</th>
|
||||||
|
<th>{{ totalPitchingStat.hits }}</th>
|
||||||
|
<th>{{ totalPitchingStat.run }}</th>
|
||||||
|
<th>{{ totalPitchingStat.e_run }}</th>
|
||||||
|
<th>{{ totalPitchingStat.hr }}</th>
|
||||||
|
<th>{{ totalPitchingStat.bb }}</th>
|
||||||
|
<th>{{ totalPitchingStat.so }}</th>
|
||||||
|
<th>{{ totalPitchingStat.hbp }}</th>
|
||||||
|
<th>{{ totalPitchingStat.balk }}</th>
|
||||||
|
<th>{{ totalPitchingStat.wp }}</th>
|
||||||
|
<th>{{ totalPitchingStat.ir }}</th>
|
||||||
|
<th>{{ totalPitchingStat.ir_sc }}</th>
|
||||||
|
<th>{{ totalPitchingStat.whip.toFixed(2) }}</th>
|
||||||
|
<th>{{ hitsPer9(totalPitchingStat) }}</th>
|
||||||
|
<th>{{ hrsPer9(totalPitchingStat) }}</th>
|
||||||
|
<th>{{ totalPitchingStat.bbPer9.toFixed(1) }}</th>
|
||||||
|
<th>{{ totalPitchingStat.kPer9.toFixed(1) }}</th>
|
||||||
|
<th>{{ totalPitchingStat.kPerBB.toFixed(1) }}</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { aggregatePitchingStats, fetchTeamPitchingStatsBySeason, type PitchingStat } from '@/services/pitchingStatsService'
|
||||||
|
import { outsToInnings, winPercentage, hitsPer9, hrsPer9 } from '@/services/utilities'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'LeaderboardTeamPitchingTable',
|
||||||
|
props: {
|
||||||
|
seasonNumber: { type: Number, required: true }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pitchingStats: [] as PitchingStat[]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
totalPitchingStat(): PitchingStat | undefined {
|
||||||
|
if (this.pitchingStats.length > 0) {
|
||||||
|
return aggregatePitchingStats(this.pitchingStats)
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
seasonNumber(newValue, oldValue) {
|
||||||
|
if (newValue !== oldValue) {
|
||||||
|
this.pitchingStats = []
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async fetchData(): Promise<void> {
|
||||||
|
const unsortedPitchingStats: PitchingStat[] = await fetchTeamPitchingStatsBySeason(this.seasonNumber)
|
||||||
|
this.pitchingStats = unsortedPitchingStats.sort((s1, s2) => s2.team.sname < s1.team.sname ? 1 : -1)
|
||||||
|
},
|
||||||
|
outsToInnings(stat: PitchingStat): string {
|
||||||
|
return outsToInnings(stat)
|
||||||
|
},
|
||||||
|
winPercentage(stat: PitchingStat): string {
|
||||||
|
return winPercentage(stat)
|
||||||
|
},
|
||||||
|
hitsPer9(stat: PitchingStat): string {
|
||||||
|
return hitsPer9(stat)
|
||||||
|
},
|
||||||
|
hrsPer9(stat: PitchingStat): string {
|
||||||
|
return hrsPer9(stat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -18,7 +18,10 @@
|
|||||||
<RouterLink class="nav-link" to="/standings">Standings</RouterLink>
|
<RouterLink class="nav-link" to="/standings">Standings</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<RouterLink class="nav-link" to="/leaderboards">Leaderboards</RouterLink>
|
<RouterLink class="nav-link" to="/leaderboards">Leaders</RouterLink>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<RouterLink class="nav-link" to="/teamleaderboards">Team Stats</RouterLink>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<RouterLink class="nav-link"
|
<RouterLink class="nav-link"
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="career-fielding-table">
|
<tbody id="career-fielding-table">
|
||||||
<tr v-for="stat in fieldingStats">
|
<tr v-for="stat in fieldingStats" :key="`${stat.player.name}-${stat.pos}`">
|
||||||
<td>
|
<td>
|
||||||
<RouterLink :to="{ name: 'player', params: { seasonNumber: seasonNumber, playerName: stat.player.name } }">
|
<RouterLink :to="{ name: 'player', params: { seasonNumber: seasonNumber, playerName: stat.player.name } }">
|
||||||
{{ stat.player.name }}
|
{{ stat.player.name }}
|
||||||
@ -36,7 +36,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr v-for="stat in totalFieldingStat" id="career-fielding-footer">
|
<tr v-for="stat in totalFieldingStat" id="career-fielding-footer" :key="stat.pos">
|
||||||
<th>Total</th>
|
<th>Total</th>
|
||||||
<th>{{ stat.pos }}</th>
|
<th>{{ stat.pos }}</th>
|
||||||
<th>{{ stat.xCheckCount }}</th>
|
<th>{{ stat.xCheckCount }}</th>
|
||||||
@ -58,7 +58,7 @@ import { aggregateFieldingStats, fetchFieldingStatsBySeasonAndTeamId, totaledFie
|
|||||||
import { POS_MAP } from '@/services/utilities'
|
import { POS_MAP } from '@/services/utilities'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "TeamFieldingTable",
|
name: 'TeamFieldingTable',
|
||||||
props: {
|
props: {
|
||||||
seasonNumber: { type: Number, required: true },
|
seasonNumber: { type: Number, required: true },
|
||||||
teamId: { type: Number, required: true },
|
teamId: { type: Number, required: true },
|
||||||
|
|||||||
@ -36,6 +36,11 @@ export const routes: RouteRecordRaw[] = [
|
|||||||
name: 'leaderboards',
|
name: 'leaderboards',
|
||||||
component: () => import('../views/LeaderboardView.vue')
|
component: () => import('../views/LeaderboardView.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/teamleaderboards',
|
||||||
|
name: 'teamleaderboards',
|
||||||
|
component: () => import('../views/TeamLeaderboardView.vue')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/rules',
|
path: '/rules',
|
||||||
name: 'rules',
|
name: 'rules',
|
||||||
|
|||||||
@ -123,6 +123,25 @@ export async function fetchBattingStatsBySeasonAndTeamId(seasonNumber: number, t
|
|||||||
return battingStatsResponse.stats
|
return battingStatsResponse.stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Differs from fetchBattingStatsBySeasonAndTeamId because it groups stats by team, not individual player stats on a given team
|
||||||
|
export async function fetchTeamBattingStatsBySeason(seasonNumber: number): Promise<BattingStat[]> {
|
||||||
|
// different endpoint for pre-modern stats (/plays) era
|
||||||
|
if (seasonNumber < MODERN_STAT_ERA_START) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/plays/batting?season=${seasonNumber}&group_by=team&s_type=regular`)
|
||||||
|
|
||||||
|
const battingStatsResponse: {
|
||||||
|
count: number
|
||||||
|
stats: BattingStat[]
|
||||||
|
} = await response.json()
|
||||||
|
|
||||||
|
if (battingStatsResponse.count === 0) return []
|
||||||
|
|
||||||
|
return battingStatsResponse.stats
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchLegacyBattingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<BattingStat | undefined> {
|
async function fetchLegacyBattingStatsBySeasonAndPlayerId(seasonNumber: number, playerId: number, isRegularSeason: boolean): Promise<BattingStat | undefined> {
|
||||||
const response = await fetch(`${SITE_URL}/api/v3/battingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`)
|
const response = await fetch(`${SITE_URL}/api/v3/battingstats/totals?season=${seasonNumber}&player_id=${playerId}&s_type=${isRegularSeason ? 'regular' : 'post'}`)
|
||||||
|
|
||||||
|
|||||||
@ -89,6 +89,25 @@ export async function fetchFieldingStatsBySeasonAndTeamId(seasonNumber: number,
|
|||||||
return fieldingStatsResponse.stats.map(normalizeFieldingStat)
|
return fieldingStatsResponse.stats.map(normalizeFieldingStat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchTeamFieldingStatsBySeason(seasonNumber: number): Promise<FieldingStat[]> {
|
||||||
|
// different endpoint for pre-modern stats (/plays) era
|
||||||
|
if (seasonNumber < MODERN_STAT_ERA_START) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO might want to make this playerpositionteam grouping (currently does not exist)
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/plays/fielding?season=${seasonNumber}&group_by=team&s_type=regular`)
|
||||||
|
|
||||||
|
const fieldingStatsResponse: {
|
||||||
|
count: number
|
||||||
|
stats: FieldingStatRaw[]
|
||||||
|
} = await response.json()
|
||||||
|
|
||||||
|
if (fieldingStatsResponse.count === 0) return []
|
||||||
|
|
||||||
|
return fieldingStatsResponse.stats.map(normalizeFieldingStat)
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchFieldingStatsBySeason(seasonNumber: number, isRegularSeason: boolean): Promise<FieldingStat[]> {
|
export async function fetchFieldingStatsBySeason(seasonNumber: number, isRegularSeason: boolean): Promise<FieldingStat[]> {
|
||||||
// different endpoint for pre-modern stats (/plays) era
|
// different endpoint for pre-modern stats (/plays) era
|
||||||
if (seasonNumber < MODERN_STAT_ERA_START) {
|
if (seasonNumber < MODERN_STAT_ERA_START) {
|
||||||
|
|||||||
@ -171,6 +171,24 @@ export async function fetchPitchingStatsBySeasonAndTeamId(seasonNumber: number,
|
|||||||
return pitchingStatsResponse.stats.map(normalizePitchingStat)
|
return pitchingStatsResponse.stats.map(normalizePitchingStat)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchTeamPitchingStatsBySeason(seasonNumber: number): Promise<PitchingStat[]> {
|
||||||
|
// different endpoint for pre-modern stats (/plays) era
|
||||||
|
if (seasonNumber < MODERN_STAT_ERA_START) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(`${SITE_URL}/api/v3/plays/pitching?season=${seasonNumber}&group_by=team&s_type=regular`)
|
||||||
|
|
||||||
|
const pitchingStatsResponse: {
|
||||||
|
count: number
|
||||||
|
stats: PitchingStatRaw[]
|
||||||
|
} = await response.json()
|
||||||
|
|
||||||
|
if (pitchingStatsResponse.count === 0) return []
|
||||||
|
|
||||||
|
return pitchingStatsResponse.stats.map(normalizePitchingStat)
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchPitchingStatsBySeason(seasonNumber: number, isRegularSeason: boolean): Promise<PitchingStat[]> {
|
export async function fetchPitchingStatsBySeason(seasonNumber: number, isRegularSeason: boolean): Promise<PitchingStat[]> {
|
||||||
// different endpoint for pre-modern stats (/plays) era
|
// different endpoint for pre-modern stats (/plays) era
|
||||||
if (seasonNumber < MODERN_STAT_ERA_START) {
|
if (seasonNumber < MODERN_STAT_ERA_START) {
|
||||||
|
|||||||
54
src/views/TeamLeaderboardView.vue
Normal file
54
src/views/TeamLeaderboardView.vue
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<div class="team-leaderboard-view centerDiv">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<h1 id="season-heading">Season {{ seasonNumber }} Team Stats</h1>
|
||||||
|
<h2 id="stat-heading">{{ statType }} Stats</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row" style="padding-bottom: 2ch">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<select name="seasonNumber" id="seasonNumber" v-model="seasonNumber">
|
||||||
|
<option v-for="season in seasonNumbers" :key="season" :value="season">Season {{ season }}</option>
|
||||||
|
</select>
|
||||||
|
<select name="statType" id="statType" v-model="statType">
|
||||||
|
<option key="Batting" value="Batting">Batting</option>
|
||||||
|
<option key="Pitching" value="Pitching">Pitching</option>
|
||||||
|
<option key="Fielding" value="Fielding">Fielding</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<LeaderboardTeamBattingTable v-if="statType == 'Batting'" :season-number="seasonNumber" />
|
||||||
|
<LeaderboardTeamPitchingTable v-if="statType == 'Pitching'" :season-number="seasonNumber" />
|
||||||
|
<LeaderboardTeamFieldingTable v-if="statType == 'Fielding'" :season-number="seasonNumber" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import LeaderboardTeamBattingTable from '@/components/LeaderboardTeamBattingTable.vue'
|
||||||
|
import LeaderboardTeamFieldingTable from '@/components/LeaderboardTeamFieldingTable.vue'
|
||||||
|
import LeaderboardTeamPitchingTable from '@/components/LeaderboardTeamPitchingTable.vue'
|
||||||
|
import { CURRENT_SEASON, MODERN_STAT_ERA_START } from '@/services/utilities'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TeamLeaderboardView',
|
||||||
|
components: {
|
||||||
|
LeaderboardTeamBattingTable,
|
||||||
|
LeaderboardTeamFieldingTable,
|
||||||
|
LeaderboardTeamPitchingTable,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentSeasonNumber: CURRENT_SEASON,
|
||||||
|
seasonNumber: CURRENT_SEASON,
|
||||||
|
statType: 'Batting' as 'Batting' | 'Pitching' | 'Fielding',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
seasonNumbers(): number[] {
|
||||||
|
if (!this.currentSeasonNumber) return []
|
||||||
|
return Array.from({ length: this.currentSeasonNumber - MODERN_STAT_ERA_START + 1 }, (_, i) => i + MODERN_STAT_ERA_START)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
0
src/views/TransactionsView.vue
Normal file
0
src/views/TransactionsView.vue
Normal file
Loading…
Reference in New Issue
Block a user