mirror of
https://github.com/vkaelin/LeagueStats.git
synced 2026-03-25 12:57:28 +00:00
feat: live game tab
This commit is contained in:
parent
305818be23
commit
b0169576c9
14 changed files with 484 additions and 75 deletions
|
|
@ -22,4 +22,31 @@
|
||||||
rgba(44, 82, 130, 0) 45%
|
rgba(44, 82, 130, 0) 45%
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ban::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
top: 50%;
|
||||||
|
width: calc(100% + 1px);
|
||||||
|
height: 2px;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ban-blue::after {
|
||||||
|
background: #38b2ac;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ban-red::after {
|
||||||
|
background: #f56565;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ban-img {
|
||||||
|
filter: grayscale(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ban-order {
|
||||||
|
left: -7px;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
/* purgecss end ignore */
|
/* purgecss end ignore */
|
||||||
|
|
|
||||||
|
|
@ -104,32 +104,3 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.ban::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
left: 0px;
|
|
||||||
top: 50%;
|
|
||||||
width: calc(100% + 1px);
|
|
||||||
height: 2px;
|
|
||||||
transform: rotate(-45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ban-blue::after {
|
|
||||||
background: #38b2ac;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ban-red::after {
|
|
||||||
background: #f56565;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ban-img {
|
|
||||||
filter: grayscale(100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ban-order {
|
|
||||||
left: -7px;
|
|
||||||
top: -5px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -51,46 +51,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { compareSummonernames } from '@/helpers/functions.js'
|
import { liveGame } from '@/mixins/liveGame'
|
||||||
import { gameModes } from '@/data/data.js'
|
|
||||||
import { mapState } from 'vuex'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
mixins: [liveGame],
|
||||||
return {
|
|
||||||
gameLength: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
allyTeam() {
|
|
||||||
return this.current.participants.filter(p => p.teamId === this.teamColor)
|
|
||||||
},
|
|
||||||
enemyTeam() {
|
|
||||||
return this.current.participants.filter(p => p.teamId !== this.teamColor)
|
|
||||||
},
|
|
||||||
gamemode() {
|
|
||||||
return gameModes[this.current.gameQueueConfigId]
|
|
||||||
},
|
|
||||||
teamColor() {
|
|
||||||
return this.current.participants.find(p => compareSummonernames(p.summonerName, this.$route.params.name)).teamId
|
|
||||||
},
|
|
||||||
...mapState({
|
|
||||||
current: state => state.summoner.basic.current,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
this.gameLength = this.current.gameLength
|
|
||||||
|
|
||||||
setInterval(() => {
|
|
||||||
this.gameLength++
|
|
||||||
}, 1000)
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
compareSummonernames
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
226
client/src/components/Summoner/Live/LiveTeam.vue
Normal file
226
client/src/components/Summoner/Live/LiveTeam.vue
Normal file
|
|
@ -0,0 +1,226 @@
|
||||||
|
<template>
|
||||||
|
<div class="mt-2 bg-blue-800 px-5 py-4 rounded-lg">
|
||||||
|
<table
|
||||||
|
class="w-full table-fixed text-center leading-none"
|
||||||
|
style="border-collapse:separate; border-spacing:0 0.5rem;"
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr class="text-left">
|
||||||
|
<th
|
||||||
|
:class="[ally ? 'text-teal-400 ' : 'text-red-400 ']"
|
||||||
|
class="w-team font-semibold"
|
||||||
|
>{{ ally ? 'Ally' : 'Enemy' }} Team</th>
|
||||||
|
<th class="w-ranked text-blue-200 text-sm font-normal">SoloQ Stats</th>
|
||||||
|
<th class="w-ranked text-blue-200 text-sm font-normal">Flex Stats</th>
|
||||||
|
<th class="w-bans px-2 text-right text-blue-200 text-sm font-normal">Bans</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody v-if="liveLoaded">
|
||||||
|
<tr
|
||||||
|
v-for="(player, index) in team"
|
||||||
|
:key="player.summonerId"
|
||||||
|
:style="{
|
||||||
|
backgroundImage:
|
||||||
|
`linear-gradient(90deg, rgba(42, 67, 101, 0.3) 0%, rgba(42, 67, 101, 0.8) 40%, rgba(42, 67, 101, 1) 100%),
|
||||||
|
url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-splashes/${player.championId}/${player.championId}000.jpg')`
|
||||||
|
}"
|
||||||
|
class="bg-cover bg-center"
|
||||||
|
>
|
||||||
|
<td class="py-1 pl-2 rounded-l-lg">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<div
|
||||||
|
:style="{backgroundImage: `url('${player.runes.primaryRune}')`}"
|
||||||
|
class="w-6 h-6 bg-cover bg-center"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
:style="{backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/perk-images/styles/7202_sorcery.png')`}"
|
||||||
|
class="mt-1 w-3 h-3 bg-cover bg-center"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
:style="{backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${player.championId}.png')`}"
|
||||||
|
:class="[ally ? 'border-teal-400' : 'border-red-400']"
|
||||||
|
class="ml-2 w-12 h-12 bg-cover bg-center bg-blue-1000 border-2 rounded-full"
|
||||||
|
></div>
|
||||||
|
<div class="ml-2 flex flex-col">
|
||||||
|
<div
|
||||||
|
:style="{backgroundImage: `url(${getSummonerLink(player.spell1Id)})`}"
|
||||||
|
class="w-4 h-4 bg-blue-1000 rounded-md bg-center bg-cover"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
:style="{backgroundImage: `url(${getSummonerLink(player.spell2Id)})`}"
|
||||||
|
class="mt-1 w-4 h-4 bg-blue-1000 rounded-md bg-center bg-cover"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div class="ml-3 text-left text-sm leading-tight">
|
||||||
|
<router-link
|
||||||
|
v-if="!player.bot"
|
||||||
|
:to="{ name: 'summoner', params: { region: $route.params.region, name: player.summonerName }}"
|
||||||
|
class="font-semibold hover:text-blue-200"
|
||||||
|
>{{ player.summonerName }}</router-link>
|
||||||
|
<div class="text-xs">Level {{ player.level }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="py-1 text-left">
|
||||||
|
<div class="px-2">
|
||||||
|
<div v-if="player.rank.soloQ" class="flex items-center">
|
||||||
|
<div class="inline-block text-center">
|
||||||
|
<svg class="w-5 h-5">
|
||||||
|
<use :xlink:href="`#rank-${player.rank.soloQ.tier.toLowerCase()}`" />
|
||||||
|
</svg>
|
||||||
|
<div
|
||||||
|
class="mt-2px text-blue-300 text-xs font-semibold"
|
||||||
|
>{{ player.rank.soloQ.shortName }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="ml-5 text-center">
|
||||||
|
<div class="font-semibold">{{ player.rank.soloQ.winrate }}</div>
|
||||||
|
<div
|
||||||
|
class="mt-1 text-xs text-blue-300"
|
||||||
|
>{{ player.rank.soloQ.wins + player.rank.soloQ.losses }} games</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="w-5 h-5">
|
||||||
|
<div class="-mt-1 text-blue-300 text-2xl">-</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="py-1 text-left">
|
||||||
|
<div class="px-2">
|
||||||
|
<div v-if="player.rank.flex5v5" class="flex items-center">
|
||||||
|
<div class="inline-block text-center">
|
||||||
|
<svg class="w-5 h-5">
|
||||||
|
<use :xlink:href="`#rank-${player.rank.flex5v5.tier.toLowerCase()}`" />
|
||||||
|
</svg>
|
||||||
|
<div
|
||||||
|
class="mt-2px text-blue-300 text-xs font-semibold"
|
||||||
|
>{{ player.rank.flex5v5.shortName }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="ml-5 text-center">
|
||||||
|
<div class="font-semibold">{{ player.rank.flex5v5.winrate }}</div>
|
||||||
|
<div
|
||||||
|
class="mt-1 text-xs text-blue-300"
|
||||||
|
>{{ player.rank.flex5v5.wins + player.rank.flex5v5.losses }} games</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="w-5 h-5">
|
||||||
|
<div class="-mt-1 text-blue-300 text-2xl">-</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="py-1 text-right">
|
||||||
|
<div class="px-2 inline-block">
|
||||||
|
<div
|
||||||
|
v-if="live.bannedChampions.length"
|
||||||
|
:class="[ally ? 'ban-blue border-teal-500' : 'ban-red border-red-500']"
|
||||||
|
class="relative ban border-2 rounded-full"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:style="[
|
||||||
|
banChamp(index, player.teamId) ?
|
||||||
|
{backgroundImage: `url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-icons/${banChamp(index, player.teamId).championId}.png')`}
|
||||||
|
: ''
|
||||||
|
]"
|
||||||
|
class="ban-img w-6 h-6 bg-cover bg-center bg-blue-1000 rounded-full"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
:class="[ally ? 'text-teal-100 bg-teal-500' : 'text-red-100 bg-red-500']"
|
||||||
|
class="absolute ban-order w-4 h-4 flex items-center justify-center text-xs font-bold rounded-full"
|
||||||
|
>{{ banChamp(index, player.teamId).pickTurn }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="w-5 h-5">
|
||||||
|
<div class="-mt-1 text-blue-300 text-2xl">-</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tbody v-else>
|
||||||
|
<tr v-for="index in 5" :key="index" class="bg-blu">
|
||||||
|
<td colspan="4" class="bg-blue-760 rounded-lg">
|
||||||
|
<content-loader
|
||||||
|
:height="54"
|
||||||
|
:width="1160"
|
||||||
|
:speed="2"
|
||||||
|
primary-color="#17314f"
|
||||||
|
secondary-color="#2b6cb0"
|
||||||
|
>
|
||||||
|
<rect x="12" y="12" rx="3" ry="3" width="14" height="14" />
|
||||||
|
<rect x="12" y="32" rx="3" ry="3" width="14" height="14" />
|
||||||
|
<circle cx="64" cy="28" r="24" />
|
||||||
|
<rect x="96" y="10" rx="3" ry="3" width="16" height="16" />
|
||||||
|
<rect x="96" y="31" rx="3" ry="3" width="16" height="16" />
|
||||||
|
<rect x="124" y="32" rx="3" ry="3" width="50" height="12" />
|
||||||
|
<rect x="124" y="13" rx="3" ry="3" width="70" height="14" />
|
||||||
|
<rect x="640" y="35" rx="3" ry="3" width="40" height="10" />
|
||||||
|
<rect x="691" y="33" rx="3" ry="3" width="55" height="10" />
|
||||||
|
<rect x="647" y="8" rx="3" ry="3" width="25" height="20" />
|
||||||
|
<rect x="696" y="12" rx="3" ry="3" width="41" height="15" />
|
||||||
|
<rect x="860" y="35" rx="3" ry="3" width="40" height="10" />
|
||||||
|
<rect x="911" y="33" rx="3" ry="3" width="55" height="10" />
|
||||||
|
<rect x="867" y="8" rx="3" ry="3" width="25" height="20" />
|
||||||
|
<rect x="916" y="12" rx="3" ry="3" width="41" height="15" />
|
||||||
|
<circle cx="1137" cy="27" r="14" />
|
||||||
|
</content-loader>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
import { getSummonerLink } from '@/helpers/summoner.js'
|
||||||
|
import { ContentLoader } from 'vue-content-loader'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ContentLoader,
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
team: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
ally: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
live: state => state.summoner.live.match,
|
||||||
|
liveLoaded: state => state.summoner.live.liveLoaded,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
banChamp(index, teamId) {
|
||||||
|
index++
|
||||||
|
|
||||||
|
if (teamId === 200) {
|
||||||
|
index += 5
|
||||||
|
}
|
||||||
|
return this.live.bannedChampions.find(b => b.pickTurn === index)
|
||||||
|
},
|
||||||
|
getSummonerLink,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.w-team {
|
||||||
|
width: 40rem;
|
||||||
|
}
|
||||||
|
.w-ranked {
|
||||||
|
width: 13.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-bans {
|
||||||
|
width: 5rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -92,7 +92,7 @@ export function getRankImg(leagueData) {
|
||||||
return `https://res.cloudinary.com/kln/image/upload/v1571671133/ranks/${leagueData.tier}_${leaguesNumbers[leagueData.rank]}.png`
|
return `https://res.cloudinary.com/kln/image/upload/v1571671133/ranks/${leagueData.tier}_${leaguesNumbers[leagueData.rank]}.png`
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSummonerLink(id) {
|
export function getSummonerLink(id) {
|
||||||
if (id === 0) return null
|
if (id === 0) return null
|
||||||
const spellName = summonersJSON.find(s => s.id === id).iconPath.split('/assets/')[1].toLowerCase()
|
const spellName = summonersJSON.find(s => s.id === id).iconPath.split('/assets/')[1].toLowerCase()
|
||||||
return `https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/${spellName}`
|
return `https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/${spellName}`
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,11 @@
|
||||||
class="ml-4 pb-2 border-b-2 border-transparent text-blue-300 cursor-pointer hover:text-blue-100"
|
class="ml-4 pb-2 border-b-2 border-transparent text-blue-300 cursor-pointer hover:text-blue-100"
|
||||||
exact
|
exact
|
||||||
>records</router-link>
|
>records</router-link>
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'summonerLive', params: { region: $route.params.region, name: $route.params.name }}"
|
||||||
|
class="ml-4 pb-2 border-b-2 border-transparent text-blue-300 cursor-pointer hover:text-blue-100"
|
||||||
|
exact
|
||||||
|
>live game</router-link>
|
||||||
</template>
|
</template>
|
||||||
<!-- View -->
|
<!-- View -->
|
||||||
<transition :name="tabTransition">
|
<transition :name="tabTransition">
|
||||||
|
|
|
||||||
42
client/src/mixins/liveGame.js
Normal file
42
client/src/mixins/liveGame.js
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { compareSummonernames } from '@/helpers/functions.js'
|
||||||
|
import { gameModes } from '@/data/data.js'
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
|
export const liveGame = {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
gameLength: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
allyTeam() {
|
||||||
|
return this.current.participants.filter(p => p.teamId === this.teamColor)
|
||||||
|
},
|
||||||
|
enemyTeam() {
|
||||||
|
return this.current.participants.filter(p => p.teamId !== this.teamColor)
|
||||||
|
},
|
||||||
|
gamemode() {
|
||||||
|
return gameModes[this.current.gameQueueConfigId]
|
||||||
|
},
|
||||||
|
teamColor() {
|
||||||
|
return this.current.participants.find(p => p.summonerId === this.account.id).teamId
|
||||||
|
},
|
||||||
|
...mapState({
|
||||||
|
account: state => state.summoner.basic.account,
|
||||||
|
current: state => state.summoner.basic.current,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.gameLength = this.current ? this.current.gameLength : 0
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
this.gameLength++
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
compareSummonernames,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ import { axios } from './plugins/axios'
|
||||||
import Home from '@/views/Home.vue'
|
import Home from '@/views/Home.vue'
|
||||||
import Summoner from '@/views/Summoner.vue'
|
import Summoner from '@/views/Summoner.vue'
|
||||||
import SummonerChampions from '@/views/SummonerChampions.vue'
|
import SummonerChampions from '@/views/SummonerChampions.vue'
|
||||||
|
import SummonerLive from '@/views/SummonerLive.vue'
|
||||||
import SummonerRecords from '@/views/SummonerRecords.vue'
|
import SummonerRecords from '@/views/SummonerRecords.vue'
|
||||||
|
|
||||||
Vue.use(Router)
|
Vue.use(Router)
|
||||||
|
|
@ -36,6 +37,11 @@ const router = new Router({
|
||||||
name: 'summonerRecords',
|
name: 'summonerRecords',
|
||||||
component: SummonerRecords
|
component: SummonerRecords
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/summoner/:region/:name/live',
|
||||||
|
name: 'summonerLive',
|
||||||
|
component: SummonerLive
|
||||||
|
},
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@ export const state = {
|
||||||
list: [],
|
list: [],
|
||||||
recordsLoaded: false
|
recordsLoaded: false
|
||||||
},
|
},
|
||||||
|
live: {
|
||||||
|
match: {},
|
||||||
|
liveLoaded: false
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mutations = {
|
export const mutations = {
|
||||||
|
|
@ -43,6 +47,10 @@ export const mutations = {
|
||||||
state.champions.list = champions
|
state.champions.list = champions
|
||||||
state.champions.championsLoaded = true
|
state.champions.championsLoaded = true
|
||||||
},
|
},
|
||||||
|
LIVE_FOUND(state, { live }) {
|
||||||
|
state.live.match = live
|
||||||
|
state.live.liveLoaded = true
|
||||||
|
},
|
||||||
MATCHES_LOADING(state) {
|
MATCHES_LOADING(state) {
|
||||||
state.overview.matchesLoading = true
|
state.overview.matchesLoading = true
|
||||||
},
|
},
|
||||||
|
|
@ -114,6 +122,13 @@ export const actions = {
|
||||||
|
|
||||||
commit('CHAMPIONS_FOUND', { champions: resp.data })
|
commit('CHAMPIONS_FOUND', { champions: resp.data })
|
||||||
},
|
},
|
||||||
|
async liveMatchRequest({ commit, rootState }) {
|
||||||
|
const resp = await axios(({ url: 'summoner-live', data: { account: state.basic.account, region: rootState.currentRegion }, method: 'POST' })).catch(() => { })
|
||||||
|
console.log('---LIVE---')
|
||||||
|
console.log(resp.data)
|
||||||
|
|
||||||
|
commit('LIVE_FOUND', { live: resp.data })
|
||||||
|
},
|
||||||
async moreMatches({ commit }) {
|
async moreMatches({ commit }) {
|
||||||
commit('MATCHES_LOADING')
|
commit('MATCHES_LOADING')
|
||||||
|
|
||||||
|
|
|
||||||
75
client/src/views/SummonerLive.vue
Normal file
75
client/src/views/SummonerLive.vue
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
<template>
|
||||||
|
<div key="live-game">
|
||||||
|
<div v-if="playing || summonerLoading">
|
||||||
|
<div v-if="playing" class="flex items-center justify-end text-blue-200 text-base">
|
||||||
|
<div>{{ gamemode.type }} {{ gamemode.name }}</div>
|
||||||
|
<div class="mx-2">-</div>
|
||||||
|
<div>{{ gameLength|secToTime(true) }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="flex items-center justify-end text-blue-200 text-base">
|
||||||
|
<div>Loading</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<LiveTeam :team="allyTeam" :ally="true" />
|
||||||
|
<LiveTeam :team="enemyTeam" :ally="false" class="mt-4" />
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="mt-16 flex justify-center">
|
||||||
|
<div class="bg-gradient px-4 py-3 rounded-lg text-center text-lg text-blue-100 font-bold">
|
||||||
|
<div>This summoner is not in game.</div>
|
||||||
|
<div>🕊</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapGetters, mapState } from 'vuex'
|
||||||
|
import { liveGame } from '@/mixins/liveGame'
|
||||||
|
import LiveTeam from '@/components/Summoner/Live/LiveTeam.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
LiveTeam,
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [liveGame],
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
allyTeam() {
|
||||||
|
return this.live.participants ? this.live.participants.filter(p => p.teamId === this.teamColor) : []
|
||||||
|
},
|
||||||
|
enemyTeam() {
|
||||||
|
return this.live.participants ? this.live.participants.filter(p => p.teamId !== this.teamColor) : []
|
||||||
|
},
|
||||||
|
...mapGetters('summoner', ['summonerLoading', 'summonerFound']),
|
||||||
|
...mapState({
|
||||||
|
current: state => state.summoner.basic.current,
|
||||||
|
live: state => state.summoner.live.match,
|
||||||
|
liveLoaded: state => state.summoner.live.liveLoaded,
|
||||||
|
playing: state => state.summoner.basic.playing,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
summonerFound() {
|
||||||
|
this.fetchData()
|
||||||
|
this.gameLength = this.current ? this.current.gameLength : 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
fetchData() {
|
||||||
|
if (this.playing && !this.liveLoaded && this.summonerFound) {
|
||||||
|
this.liveMatchRequest()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...mapActions('summoner', ['liveMatchRequest']),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const Jax = use('Jax')
|
const Jax = use('Jax')
|
||||||
|
const LiveMatchTransformer = use('App/Transformers/LiveMatchTransformer')
|
||||||
const MatchRepository = make('App/Repositories/MatchRepository')
|
const MatchRepository = make('App/Repositories/MatchRepository')
|
||||||
const MatchService = use('App/Services/MatchService')
|
const MatchService = use('App/Services/MatchService')
|
||||||
const SummonerService = use('App/Services/SummonerService')
|
const SummonerService = use('App/Services/SummonerService')
|
||||||
|
|
@ -115,6 +116,27 @@ class SummonerController {
|
||||||
console.timeEnd('recordsRequest')
|
console.timeEnd('recordsRequest')
|
||||||
return response.json(records[0])
|
return response.json(records[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST - Return live match details
|
||||||
|
*/
|
||||||
|
async liveMatchDetails({ request, response }) {
|
||||||
|
console.time('liveMatchDetails')
|
||||||
|
const account = request.input('account')
|
||||||
|
const region = request.input('region')
|
||||||
|
|
||||||
|
// CURRENT GAME
|
||||||
|
let currentGame = await Jax.Spectator.summonerID(account.id, region)
|
||||||
|
|
||||||
|
if (!currentGame) {
|
||||||
|
response.json(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentGame = await LiveMatchTransformer.transform(currentGame, { region })
|
||||||
|
console.timeEnd('liveMatchDetails')
|
||||||
|
|
||||||
|
return response.json(currentGame)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = SummonerController
|
module.exports = SummonerController
|
||||||
|
|
|
||||||
44
server/app/Transformers/LiveMatchTransformer.js
Normal file
44
server/app/Transformers/LiveMatchTransformer.js
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const MatchTransformer = use('App/Transformers/MatchTransformer')
|
||||||
|
const SummonerService = use('App/Services/SummonerService')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LiveMatchTransformer class
|
||||||
|
*
|
||||||
|
* @class LiveMatchTransformer
|
||||||
|
*/
|
||||||
|
class LiveMatchTransformer extends MatchTransformer {
|
||||||
|
async _getPlayerDatq(participant, region) {
|
||||||
|
const account = await SummonerService.getAccount(participant.summonerName, region)
|
||||||
|
if (account) {
|
||||||
|
participant.level = account.summonerLevel
|
||||||
|
const ranked = await SummonerService.getRanked(account, region)
|
||||||
|
participant.rank = ranked
|
||||||
|
} else {
|
||||||
|
participant.rank = null
|
||||||
|
}
|
||||||
|
|
||||||
|
return participant
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform raw data from Riot API
|
||||||
|
* @param match data from Riot API, one live match
|
||||||
|
*/
|
||||||
|
async transform(match, { region }) {
|
||||||
|
await super.getContext()
|
||||||
|
|
||||||
|
// Perks
|
||||||
|
for (const participant of match.participants) {
|
||||||
|
participant.runes = super.getPerksImages(participant.perks.perkIds[0], participant.perks.perkSubStyle)
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestsParticipants = match.participants.map(p => this._getPlayerDatq(p, region))
|
||||||
|
match.participants = await Promise.all(requestsParticipants)
|
||||||
|
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new LiveMatchTransformer()
|
||||||
|
|
@ -111,13 +111,7 @@ class MatchTransformer {
|
||||||
let primaryRune = null
|
let primaryRune = null
|
||||||
let secondaryRune = null
|
let secondaryRune = null
|
||||||
if (player.stats.perkPrimaryStyle) {
|
if (player.stats.perkPrimaryStyle) {
|
||||||
const firstRune = this.perks.find(p => p.id === player.stats.perk0)
|
({ primaryRune, secondaryRune } = this.getPerksImages(player.stats.perk0, player.stats.perkSubStyle))
|
||||||
const firstRuneUrl = firstRune.iconPath.split('/assets/')[1].toLowerCase()
|
|
||||||
primaryRune = `https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/${firstRuneUrl}`
|
|
||||||
|
|
||||||
const secondRuneStyle = this.perkstyles.find(p => p.id === player.stats.perkSubStyle)
|
|
||||||
const secondRuneStyleUrl = secondRuneStyle.iconPath.split('/assets/')[1].toLowerCase()
|
|
||||||
secondaryRune = `https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/${secondRuneStyleUrl}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = []
|
const items = []
|
||||||
|
|
@ -157,6 +151,23 @@ class MatchTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the icons of the primary rune and secondary category
|
||||||
|
* @param perk0 primary perks id
|
||||||
|
* @param perkSubStyle secondary perks category
|
||||||
|
*/
|
||||||
|
getPerksImages(perk0, perkSubStyle) {
|
||||||
|
const firstRune = this.perks.find(p => p.id === perk0)
|
||||||
|
const firstRuneUrl = firstRune.iconPath.split('/assets/')[1].toLowerCase()
|
||||||
|
const primaryRune = `https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/${firstRuneUrl}`
|
||||||
|
|
||||||
|
const secondRuneStyle = this.perkstyles.find(p => p.id === perkSubStyle)
|
||||||
|
const secondRuneStyleUrl = secondRuneStyle.iconPath.split('/assets/')[1].toLowerCase()
|
||||||
|
const secondaryRune = `https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/${secondRuneStyleUrl}`
|
||||||
|
|
||||||
|
return { primaryRune, secondaryRune }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the lane of the summoner according to timeline
|
* Return the lane of the summoner according to timeline
|
||||||
* @param timeline from Riot Api
|
* @param timeline from Riot Api
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ Route.post('/summoner-basic', 'SummonerController.basic')
|
||||||
Route.post('/summoner-overview', 'SummonerController.overview')
|
Route.post('/summoner-overview', 'SummonerController.overview')
|
||||||
Route.post('/summoner-champions', 'SummonerController.champions')
|
Route.post('/summoner-champions', 'SummonerController.champions')
|
||||||
Route.post('/summoner-records', 'SummonerController.records')
|
Route.post('/summoner-records', 'SummonerController.records')
|
||||||
|
Route.post('/summoner-live', 'SummonerController.liveMatchDetails')
|
||||||
Route.post('/ddragon', 'DDragonController.index')
|
Route.post('/ddragon', 'DDragonController.index')
|
||||||
Route.post('/match', 'MatchController.index')
|
Route.post('/match', 'MatchController.index')
|
||||||
Route.post('/match-details', 'MatchController.show')
|
Route.post('/match-details', 'MatchController.show')
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue