feat: add records tab

This commit is contained in:
Valentin Kaelin 2020-01-12 01:31:28 +01:00
parent 304ed03ace
commit 5ab71a0292
8 changed files with 424 additions and 38 deletions

View file

@ -0,0 +1,77 @@
<template>
<div
@mouseenter="hover = true"
@mouseleave="hover = false"
:style="{
backgroundImage:
`${hover ? gradientHover : gradient},
url('https://raw.communitydragon.org/latest/plugins/rcp-be-lol-game-data/global/default/v1/champion-splashes/${record.champion.id}/${record.champion.id}000.jpg')`
}"
class="mt-6 mx-2 record-card w-full bg-cover bg-center p-2 rounded-lg leading-none"
>
<div class="text-5xl">{{ record[property] }}</div>
<div>
<span class="text-gray-500">{{ title.substr(0, title.indexOf(' ')) }}</span>
<span :class="color" class="ml-1">{{ title.substr(title.indexOf(' ') + 1) }}</span>
</div>
<div class="text-sm">
<div class="mt-3">
<span
:class="record.result === 'Win' ? 'text-green-400' : 'text-red-400'"
>{{ record.result === 'Win' ? 'won' : 'lost' }}</span>
<span class="ml-1 font-bold">{{ timeDifference(record.date) }}</span>
</div>
<div class="text-gray-500">
as
<span class="text-white font-bold">{{ record.champion.name }}</span>
</div>
</div>
<div class="mt-3 text-gray-200 text-sm opacity-25">match {{ record.gameId }}</div>
</div>
</template>
<script>
import { timeDifference } from '@/helpers/functions.js'
export default {
props: {
color: {
type: String,
required: true
},
property: {
type: String,
required: true
},
record: {
type: Object,
required: true
},
title: {
type: String,
required: true
},
},
data() {
return {
gradient: 'linear-gradient(180deg, rgba(42, 67, 101, 0.3) 0%, rgba(42, 67, 101, 0.8) 60%, rgba(42, 67, 101, 1) 100%)',
gradientHover: 'linear-gradient(rgba(42, 67, 101, 0.1) 0%, rgba(42, 67, 101, 0.3) 60%, rgba(42, 67, 101, 0.5) 100%)',
hover: false,
}
},
methods: {
timeDifference
}
}
</script>
<style scoped>
.record-card {
max-width: 18rem;
}
.record-card:hover {
filter: brightness(1.2);
}
</style>

View file

@ -73,6 +73,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
>champions</router-link> >champions</router-link>
<router-link
:to="{ name: 'summonerRecords', 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
>records</router-link>
</template> </template>
<!-- View --> <!-- View -->
<transition :name="tabTransition"> <transition :name="tabTransition">

View file

@ -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 SummonerRecords from '@/views/SummonerRecords.vue'
Vue.use(Router) Vue.use(Router)
@ -30,6 +31,11 @@ const router = new Router({
name: 'summonerChampions', name: 'summonerChampions',
component: SummonerChampions component: SummonerChampions
}, },
{
path: '/summoner/:region/:name/records',
name: 'summonerRecords',
component: SummonerRecords
},
] ]
}) })

View file

@ -1,5 +1,5 @@
import { axios } from '@/plugins/axios' import { axios } from '@/plugins/axios'
import { createMatchData, createBasicSummonerData } from '@/helpers/summoner' import { createMatchData, createBasicSummonerData, createRecordsData } from '@/helpers/summoner'
export const namespaced = true export const namespaced = true
@ -23,12 +23,17 @@ export const state = {
list: [], list: [],
championsLoaded: false championsLoaded: false
}, },
records: {
list: [],
recordsLoaded: false
},
} }
export const mutations = { export const mutations = {
BASIC_REQUEST(state) { BASIC_REQUEST(state) {
state.basic.status = 'loading' state.basic.status = 'loading'
state.champions.championsLoaded = false state.champions.championsLoaded = false
state.records.recordsLoaded = false
state.overview.loaded = false state.overview.loaded = false
}, },
CHAMPIONS_NOT_FOUND(state) { CHAMPIONS_NOT_FOUND(state) {
@ -47,6 +52,7 @@ export const mutations = {
state.overview.matchIndex += newMatches.length state.overview.matchIndex += newMatches.length
state.overview.stats = stats state.overview.stats = stats
state.champions.championsLoaded = false state.champions.championsLoaded = false
state.records.recordsLoaded = false
}, },
OVERVIEW_FOUND(state, infos) { OVERVIEW_FOUND(state, infos) {
state.overview.matches = infos.matches state.overview.matches = infos.matches
@ -54,6 +60,10 @@ export const mutations = {
state.overview.stats = infos.stats state.overview.stats = infos.stats
state.overview.loaded = true state.overview.loaded = true
}, },
RECORDS_FOUND(state, { records }) {
state.records.list = records
state.records.recordsLoaded = true
},
SUMMONER_FOUND(state, infos) { SUMMONER_FOUND(state, infos) {
state.basic.account = infos.account state.basic.account = infos.account
state.basic.current = infos.current state.basic.current = infos.current
@ -122,6 +132,14 @@ export const actions = {
console.log(resp.data) console.log(resp.data)
resp.data.matches = createMatchData(resp.data.matchesDetails) resp.data.matches = createMatchData(resp.data.matchesDetails)
commit('OVERVIEW_FOUND', resp.data) commit('OVERVIEW_FOUND', resp.data)
},
async recordsRequest({ commit }) {
const resp = await axios(({ url: 'summoner-records', data: { puuid: state.basic.account.puuid }, method: 'POST' })).catch(() => { })
console.log('---RECORDS---')
console.log(resp.data)
const records = resp.data ? createRecordsData(resp.data) : {}
commit('RECORDS_FOUND', { records })
} }
} }

View file

@ -0,0 +1,197 @@
<template>
<div key="records" class="mt-3">
<template v-if="!recordsLoaded || (recordsLoaded && records.maxKda)">
<div class="mt-4">
<div class="mx-4 text-blue-200 text-2xl border-b-2 border-blue-800 blue-900">basics</div>
<div class="-mx-2 flex flex-wrap">
<template v-if="recordsLoaded">
<RecordCard
color="text-blue-400"
property="kda"
:record="records.maxKda"
title="best kda"
/>
<RecordCard
color="text-green-400"
property="kills"
:record="records.maxKills"
title="most kills"
/>
<RecordCard
color="text-blue-500"
property="assists"
:record="records.maxAssists"
title="most assists"
/>
<RecordCard
color="text-red-500"
property="deaths"
:record="records.maxDeaths"
title="most deaths"
/>
<RecordCard
color="text-yellow-600"
property="gold"
:record="records.maxGold"
title="most gold earned"
/>
<RecordCard
color="text-white"
property="time"
:record="records.maxTime"
title="longest game"
/>
<RecordCard
color="text-pink-500"
property="minions"
:record="records.maxMinions"
title="most minions killed"
/>
</template>
<template v-else>
<div
v-for="index in 7"
:key="index"
style="width: 288px; height: 146px;"
class="mt-6 mx-2"
>
<content-loader
:height="146"
:width="288"
:speed="2"
primary-color="#17314f"
secondary-color="#2b6cb0"
>
<rect x="0" y="0" rx="8" ry="8" width="288" height="146" />
</content-loader>
</div>
</template>
</div>
<div
class="mt-3 mx-4 text-blue-200 text-2xl border-b-2 border-blue-800 blue-900"
>game impact</div>
<div class="-mx-2 flex flex-wrap">
<template v-if="recordsLoaded">
<RecordCard
color="text-yellow-400"
property="dmgTaken"
:record="records.maxDmgTaken"
title="highest damage taken"
/>
<RecordCard
color="text-red-400"
property="dmgChamp"
:record="records.maxDmgChamp"
title="highest damage to champions"
/>
<RecordCard
color="text-yellow-400"
property="dmgObj"
:record="records.maxDmgObj"
title="highest damage to objectives"
/>
<RecordCard
color="text-green-400"
property="kp"
:record="records.maxKp"
title="highest kill participation"
/>
</template>
<template v-else>
<div
v-for="index in 4"
:key="index"
style="width: 288px; height: 146px;"
class="mt-6 mx-2"
>
<content-loader
:height="146"
:width="288"
:speed="2"
primary-color="#17314f"
secondary-color="#2b6cb0"
>
<rect x="0" y="0" rx="8" ry="8" width="288" height="146" />
</content-loader>
</div>
</template>
</div>
<div class="mt-3 mx-4 text-blue-200 text-2xl border-b-2 border-blue-800 blue-900">team work</div>
<div class="-mx-2 flex flex-wrap">
<template v-if="recordsLoaded">
<RecordCard
color="text-blue-500"
property="vision"
:record="records.maxVision"
title="highest vision score"
/>
</template>
<template v-else>
<div
v-for="index in 1"
:key="index"
style="width: 288px; height: 146px;"
class="mt-6 mx-2"
>
<content-loader
:height="146"
:width="288"
:speed="2"
primary-color="#17314f"
secondary-color="#2b6cb0"
>
<rect x="0" y="0" rx="8" ry="8" width="288" height="146" />
</content-loader>
</div>
</template>
</div>
</div>
</template>
<template v-if="recordsLoaded && !records.maxKda">
<div class="mt-4 flex flex-col items-center">
<div>No records have been found.</div>
<div>😕</div>
</div>
</template>
</div>
</template>
<script>
import { mapActions, mapGetters, mapState } from 'vuex'
import { ContentLoader } from 'vue-content-loader'
import RecordCard from '@/components/Summoner/Records/RecordCard.vue'
export default {
components: {
ContentLoader,
RecordCard,
},
computed: {
...mapGetters('summoner', ['summonerFound']),
...mapState({
records: state => state.summoner.records.list,
recordsLoaded: state => state.summoner.records.recordsLoaded,
})
},
watch: {
summonerFound() {
this.fetchData()
}
},
created() {
this.fetchData()
},
methods: {
fetchData() {
if (!this.recordsLoaded && this.summonerFound) {
this.recordsRequest()
}
},
...mapActions('summoner', ['recordsRequest']),
}
}
</script>

View file

@ -104,6 +104,17 @@ class SummonerController {
console.timeEnd('championsRequest') console.timeEnd('championsRequest')
return response.json(championStats) return response.json(championStats)
} }
/**
* POST: get records view summoner data
*/
async records({ request, response }) {
const puuid = request.input('puuid')
console.time('recordsRequest')
const records = await MatchRepository.records(puuid)
console.timeEnd('recordsRequest')
return response.json(records[0])
}
} }
module.exports = SummonerController module.exports = SummonerController

View file

@ -35,12 +35,12 @@ class MatchRepository {
count: { $sum: 1 }, count: { $sum: 1 },
wins: { wins: {
$sum: { $sum: {
$cond: [{ $eq: ["$result", "Win"] }, 1, 0] $cond: [{ $eq: ['$result', 'Win'] }, 1, 0]
} }
}, },
losses: { losses: {
$sum: { $sum: {
$cond: [{ $eq: ["$result", "Fail"] }, 1, 0] $cond: [{ $eq: ['$result', 'Fail'] }, 1, 0]
} }
}, },
...groupParams ...groupParams
@ -57,10 +57,10 @@ class MatchRepository {
*/ */
championStats(puuid, limit = 5) { championStats(puuid, limit = 5) {
const groupParams = { const groupParams = {
champion: { $first: "$champion" }, champion: { $first: '$champion' },
kills: { $sum: "$stats.kills" }, kills: { $sum: '$stats.kills' },
deaths: { $sum: "$stats.deaths" }, deaths: { $sum: '$stats.deaths' },
assists: { $sum: "$stats.assists" }, assists: { $sum: '$stats.assists' },
} }
const finalSteps = [ const finalSteps = [
{ $sort: { 'count': -1 } }, { $sort: { 'count': -1 } },
@ -74,7 +74,7 @@ class MatchRepository {
* @param puuid of the summoner * @param puuid of the summoner
*/ */
championClassStats(puuid) { championClassStats(puuid) {
const groupId = { "$arrayElemAt": ["$champion.roles", 0] } const groupId = { '$arrayElemAt': ['$champion.roles', 0] }
return this._aggregate(puuid, {}, [], groupId, {}, []) return this._aggregate(puuid, {}, [], groupId, {}, [])
} }
@ -88,18 +88,18 @@ class MatchRepository {
gamemode: { $eq: Number(queue) }, gamemode: { $eq: Number(queue) },
} : {} } : {}
const groupParams = { const groupParams = {
time: { $sum: "$time" }, time: { $sum: '$time' },
gameLength: { $avg: "$time" }, gameLength: { $avg: '$time' },
date: { $max: "$date" }, date: { $max: '$date' },
champion: { $first: "$champion" }, champion: { $first: '$champion' },
kills: { $sum: "$stats.kills" }, kills: { $sum: '$stats.kills' },
deaths: { $sum: "$stats.deaths" }, deaths: { $sum: '$stats.deaths' },
assists: { $sum: "$stats.assists" }, assists: { $sum: '$stats.assists' },
minions: { $avg: "$stats.minions" }, minions: { $avg: '$stats.minions' },
gold: { $avg: "$stats.gold" }, gold: { $avg: '$stats.gold' },
dmgChamp: { $avg: "$stats.dmgChamp" }, dmgChamp: { $avg: '$stats.dmgChamp' },
dmgTaken: { $avg: "$stats.dmgTaken" }, dmgTaken: { $avg: '$stats.dmgTaken' },
kp: { $avg: "$stats.kp" }, kp: { $avg: '$stats.kp' },
} }
const finalSteps = [ const finalSteps = [
{ $sort: { 'count': -1 } } { $sort: { 'count': -1 } }
@ -121,17 +121,88 @@ class MatchRepository {
*/ */
globalStats(puuid) { globalStats(puuid) {
const groupParams = { const groupParams = {
time: { $sum: "$time" }, time: { $sum: '$time' },
kills: { $sum: "$stats.kills" }, kills: { $sum: '$stats.kills' },
deaths: { $sum: "$stats.deaths" }, deaths: { $sum: '$stats.deaths' },
assists: { $sum: "$stats.assists" }, assists: { $sum: '$stats.assists' },
minions: { $sum: "$stats.minions" }, minions: { $sum: '$stats.minions' },
vision: { $sum: "$stats.vision" }, vision: { $sum: '$stats.vision' },
kp: { $avg: "$stats.kp" }, kp: { $avg: '$stats.kp' },
} }
return this._aggregate(puuid, {}, [], null, groupParams, []) return this._aggregate(puuid, {}, [], null, groupParams, [])
} }
/**
* Get Summoner's all records
* @param puuid of the summoner
*/
records(puuid) {
return this.Match.query().aggregate([
{
$match: {
summoner_puuid: puuid,
result: { $not: { $eq: 'Remake' } },
'stats.kda': { $not: { $eq: '∞' } },
gamemode: { $nin: [800, 810, 820, 830, 840, 850] },
}
},
{
$group: {
_id: null,
maxKills: { $max: '$stats.kills' },
maxDeaths: { $max: '$stats.deaths' },
maxAssists: { $max: '$stats.assists' },
maxGold: { $max: '$stats.gold' },
maxTime: { $max: '$time' },
maxMinions: { $max: '$stats.minions' },
maxKda: { $max: '$stats.kda' },
maxDmgTaken: { $max: '$stats.dmgTaken' },
maxDmgChamp: { $max: '$stats.dmgChamp' },
maxDmgObj: { $max: '$stats.dmgObj' },
maxKp: { $max: '$stats.kp' },
maxVision: { $max: '$stats.vision' },
docs: {
'$push': {
'champion': '$champion',
'gameId': '$gameId',
'kills': '$stats.kills',
'deaths': '$stats.deaths',
'assists': '$stats.assists',
'gold': '$stats.gold',
'time': '$time',
'minions': '$stats.minions',
'kda': '$stats.kda',
'dmgTaken': '$stats.dmgTaken',
'dmgChamp': '$stats.dmgChamp',
'dmgObj': '$stats.dmgObj',
'kp': '$stats.kp',
'vision': '$stats.vision',
'result': '$result',
'date': '$date',
}
}
}
},
{
$project: {
_id: 0,
maxKills: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.kills', '$maxKills'] } } }, 0] },
maxDeaths: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.deaths', '$maxDeaths'] } } }, 0] },
maxAssists: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.assists', '$maxAssists'] } } }, 0] },
maxGold: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.gold', '$maxGold'] } } }, 0] },
maxTime: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.time', '$maxTime'] } } }, 0] },
maxMinions: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.minions', '$maxMinions'] } } }, 0] },
maxKda: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.kda', '$maxKda'] } } }, 0] },
maxDmgTaken: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.dmgTaken', '$maxDmgTaken'] } } }, 0] },
maxDmgChamp: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.dmgChamp', '$maxDmgChamp'] } } }, 0] },
maxDmgObj: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.dmgObj', '$maxDmgObj'] } } }, 0] },
maxKp: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.kp', '$maxKp'] } } }, 0] },
maxVision: { $arrayElemAt: [{ $filter: { input: '$docs', cond: { $eq: ['$$this.vision', '$maxVision'] } } }, 0] },
}
}
])
}
/** /**
* Get Summoner's statistics for the 5 differnt roles * Get Summoner's statistics for the 5 differnt roles
* @param puuid of the summoner * @param puuid of the summoner
@ -143,10 +214,10 @@ class MatchRepository {
const finalSteps = [ const finalSteps = [
{ {
$project: { $project: {
role: "$_id", role: '$_id',
count: "$count", count: '$count',
wins: "$wins", wins: '$wins',
losses: "$losses", losses: '$losses',
} }
} }
] ]
@ -159,17 +230,17 @@ class MatchRepository {
*/ */
mates(puuid) { mates(puuid) {
const intermediateSteps = [ const intermediateSteps = [
{ $unwind: "$allyTeam" }, { $unwind: '$allyTeam' },
] ]
const groupParams = { const groupParams = {
account_id: { $first: "$account_id" }, account_id: { $first: '$account_id' },
name: { $first: "$allyTeam.name" }, name: { $first: '$allyTeam.name' },
mateId: { $first: "$allyTeam.account_id" }, mateId: { $first: '$allyTeam.account_id' },
} }
const finalSteps = [ const finalSteps = [
{ {
"$addFields": { '$addFields': {
"idEq": { "$eq": ["$mateId", "$account_id"] } 'idEq': { '$eq': ['$mateId', '$account_id'] }
} }
}, },
{ {

View file

@ -28,6 +28,7 @@ Route.get('/', async () => {
Route.post('/summoner-basic', 'SummonerController.basic') 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('/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')