added Chat-History to matches
All checks were successful
CSGOWTF/csgowtf/pipeline/head This commit looks good
All checks were successful
CSGOWTF/csgowtf/pipeline/head This commit looks good
This commit is contained in:
139
src/components/MatchChatHistory.vue
Normal file
139
src/components/MatchChatHistory.vue
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<template>
|
||||||
|
<div class="chat-history mt-2">
|
||||||
|
<table class="table table-borderless">
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="(m, id) in data.chat" :key="id">
|
||||||
|
<td>
|
||||||
|
{{ ConvertTickToTime(m.tick) }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<img :class="'team-color-' + m.color"
|
||||||
|
:src="constructAvatarUrl(m.avatar)"
|
||||||
|
alt="Player avatar"
|
||||||
|
class="avatar">
|
||||||
|
</td>
|
||||||
|
<td class="name"
|
||||||
|
@click="GoToPlayer(m.steamid64)"
|
||||||
|
:class="m.startSide === 1 ? 'text-info' : 'text-warning'">
|
||||||
|
<i v-if="m.tracked" class="fa fa-dot-circle-o text-success tracked" title="Tracked user"></i>
|
||||||
|
{{ m.player }}
|
||||||
|
<i class="fa fa-external-link"></i>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td class="message">
|
||||||
|
{{ m.message }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {useStore} from "vuex";
|
||||||
|
import {onMounted, reactive} from "vue";
|
||||||
|
import {GetChatHistory, constructAvatarUrl, GoToPlayer, ConvertTickToTime} from "@/utils";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MatchChatHistory",
|
||||||
|
setup() {
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
chat: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
const getChatHistory = async () => {
|
||||||
|
const resData = await GetChatHistory(store, store.state.matchDetails.match_id)
|
||||||
|
if (resData !== null) {
|
||||||
|
data.chat = await setPlayer(sortChatHistory(resData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortChatHistory = (res = {}) => {
|
||||||
|
let arr = []
|
||||||
|
if (res !== {}) {
|
||||||
|
Object.keys(res).forEach(i => {
|
||||||
|
res[i].forEach(o => {
|
||||||
|
let obj = Object.assign({
|
||||||
|
player: i,
|
||||||
|
tick: o.tick,
|
||||||
|
all_chat: o.all_chat,
|
||||||
|
message: o.message
|
||||||
|
})
|
||||||
|
arr.push(obj)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
arr.sort((a, b) => a.tick - b.tick)
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
const setPlayer = async (chat) => {
|
||||||
|
let arr = []
|
||||||
|
for (const o of chat) {
|
||||||
|
for (const p of store.state.matchDetails.stats) {
|
||||||
|
console.log(p)
|
||||||
|
if (o.player === p.player.steamid64) {
|
||||||
|
const obj = Object.assign({
|
||||||
|
player: p.player.name,
|
||||||
|
steamid64: p.player.steamid64,
|
||||||
|
avatar: p.player.avatar,
|
||||||
|
color: p.color,
|
||||||
|
startSide: p.team_id,
|
||||||
|
tracked: p.player.tracked,
|
||||||
|
tick: o.tick,
|
||||||
|
all_chat: o.all_chat,
|
||||||
|
message: o.message
|
||||||
|
})
|
||||||
|
arr.push(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getChatHistory()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {data, constructAvatarUrl, GoToPlayer, ConvertTickToTime}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
table td {
|
||||||
|
padding: .5rem;
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 75%;
|
||||||
|
height: 75%;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
width: 200px;
|
||||||
|
max-width: 200px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
.tracked {
|
||||||
|
font-size: .8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-external-link {
|
||||||
|
color: white;
|
||||||
|
font-size: .8rem;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
width: 40ch;
|
||||||
|
max-width: 40ch;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -63,7 +63,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {constructAvatarUrl, DisplayRank, FormatVacDate, GetHLTV_1, GoToPlayer} from "../utils";
|
import {constructAvatarUrl, DisplayRank, FormatVacDate, GetHLTV_1, GoToPlayer} from "@/utils";
|
||||||
import {useStore} from "vuex";
|
import {useStore} from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -203,39 +203,6 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.team-color-blue,
|
|
||||||
.team-color-orange,
|
|
||||||
.team-color-green,
|
|
||||||
.team-color-purple,
|
|
||||||
.team-color-yellow,
|
|
||||||
.team-color-grey {
|
|
||||||
outline: 3px solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.team-color-grey {
|
|
||||||
outline-color: var(--csgo-grey);
|
|
||||||
}
|
|
||||||
|
|
||||||
.team-color-orange {
|
|
||||||
outline-color: var(--csgo-orange);
|
|
||||||
}
|
|
||||||
|
|
||||||
.team-color-blue {
|
|
||||||
outline-color: var(--csgo-blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
.team-color-yellow {
|
|
||||||
outline-color: var(--csgo-yellow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.team-color-purple {
|
|
||||||
outline-color: var(--csgo-purple);
|
|
||||||
}
|
|
||||||
|
|
||||||
.team-color-green {
|
|
||||||
outline-color: var(--csgo-green);
|
|
||||||
}
|
|
||||||
|
|
||||||
.player__vac,
|
.player__vac,
|
||||||
.vac-placeholder {
|
.vac-placeholder {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
|
@@ -74,17 +74,17 @@ const routes = [
|
|||||||
score: lazyLoadComponent('FlashChart')
|
score: lazyLoadComponent('FlashChart')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'utility',
|
|
||||||
components: {
|
|
||||||
score: lazyLoadComponent('UtilityChart')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'damage',
|
path: 'damage',
|
||||||
components: {
|
components: {
|
||||||
score: lazyLoadComponent('DamageSite')
|
score: lazyLoadComponent('DamageSite')
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'chat-history',
|
||||||
|
components: {
|
||||||
|
score: lazyLoadComponent('MatchChatHistory')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@@ -24,6 +24,39 @@
|
|||||||
animation: placeholder-wave-alt 2.5s linear infinite;
|
animation: placeholder-wave-alt 2.5s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.team-color-blue,
|
||||||
|
.team-color-orange,
|
||||||
|
.team-color-green,
|
||||||
|
.team-color-purple,
|
||||||
|
.team-color-yellow,
|
||||||
|
.team-color-grey {
|
||||||
|
outline: 3px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-color-grey {
|
||||||
|
outline-color: var(--csgo-grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-color-orange {
|
||||||
|
outline-color: var(--csgo-orange);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-color-blue {
|
||||||
|
outline-color: var(--csgo-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-color-yellow {
|
||||||
|
outline-color: var(--csgo-yellow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-color-purple {
|
||||||
|
outline-color: var(--csgo-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-color-green {
|
||||||
|
outline-color: var(--csgo-green);
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes placeholder-wave-alt {
|
@keyframes placeholder-wave-alt {
|
||||||
100% {
|
100% {
|
||||||
mask-position: -200% 0%;
|
mask-position: -200% 0%;
|
||||||
|
@@ -299,6 +299,45 @@ export const GetWeaponDmg = async (store, match_id) => {
|
|||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /match/<id>/chat GET returns chat history for match <id>
|
||||||
|
export const GetChatHistory = async (store, match_id) => {
|
||||||
|
let response = null
|
||||||
|
|
||||||
|
await axios
|
||||||
|
.get(`${API_URL}/match/${match_id}/chat`)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === STATUS.OK)
|
||||||
|
response = res.data
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
let message = ''
|
||||||
|
|
||||||
|
switch (err.response.status) {
|
||||||
|
case STATUS.BAD_REQUEST:
|
||||||
|
message = 'Bad request'
|
||||||
|
break
|
||||||
|
case STATUS.NOT_FOUND:
|
||||||
|
message = 'Weapon damage not found'
|
||||||
|
break
|
||||||
|
case STATUS.INTERNAL_SERVER_ERROR:
|
||||||
|
message = 'Unable to get weapon damage'
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
message = 'An unknown error occurred'
|
||||||
|
}
|
||||||
|
store.commit({
|
||||||
|
type: 'changeInfoState',
|
||||||
|
data: {
|
||||||
|
statuscode: err.response.status,
|
||||||
|
message: message,
|
||||||
|
type: 'error'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
// /matches GET returns last 20 matches in DB
|
// /matches GET returns last 20 matches in DB
|
||||||
export const GetMatches = async (store) => {
|
export const GetMatches = async (store) => {
|
||||||
let response = null
|
let response = null
|
||||||
|
@@ -1,5 +1,14 @@
|
|||||||
import {DateTime, Duration} from "luxon/build/es6/luxon";
|
import {DateTime, Duration} from "luxon/build/es6/luxon";
|
||||||
|
|
||||||
|
export const ConvertTickToTime = (tick, rate = 64) => {
|
||||||
|
const time = Duration.fromObject({hours: 0, minutes: 0, seconds: tick / rate || 0})
|
||||||
|
|
||||||
|
if (time.hours > 1)
|
||||||
|
return time.toFormat('hh:mm:ss')
|
||||||
|
else if (time.hours < 1)
|
||||||
|
return time.toFormat('mm:ss')
|
||||||
|
}
|
||||||
|
|
||||||
export const FormatDuration = (d) => {
|
export const FormatDuration = (d) => {
|
||||||
const duration = Duration.fromObject({hours: 0, minutes: 0, seconds: d}).normalize().toObject()
|
const duration = Duration.fromObject({hours: 0, minutes: 0, seconds: d}).normalize().toObject()
|
||||||
|
|
||||||
|
@@ -4,7 +4,8 @@ import {
|
|||||||
FormatFullDate,
|
FormatFullDate,
|
||||||
FormatFullDuration,
|
FormatFullDuration,
|
||||||
FormatVacDate,
|
FormatVacDate,
|
||||||
MatchNotParsedTime
|
MatchNotParsedTime,
|
||||||
|
ConvertTickToTime
|
||||||
} from "./DateTime";
|
} from "./DateTime";
|
||||||
import {GoToLink, GoToMatch, GoToPlayer} from "./GoTo";
|
import {GoToLink, GoToMatch, GoToPlayer} from "./GoTo";
|
||||||
import {SaveLastVisitedToLocalStorage} from "./LocalStorage";
|
import {SaveLastVisitedToLocalStorage} from "./LocalStorage";
|
||||||
@@ -19,6 +20,7 @@ import {
|
|||||||
GetWeaponDmg,
|
GetWeaponDmg,
|
||||||
LoadMoreMatches,
|
LoadMoreMatches,
|
||||||
LoadMoreMatchesExplore,
|
LoadMoreMatchesExplore,
|
||||||
|
GetChatHistory,
|
||||||
TrackMe
|
TrackMe
|
||||||
} from "./ApiRequests";
|
} from "./ApiRequests";
|
||||||
import {
|
import {
|
||||||
@@ -40,6 +42,8 @@ import {
|
|||||||
|
|
||||||
export {
|
export {
|
||||||
MatchNotParsedTime,
|
MatchNotParsedTime,
|
||||||
|
GetChatHistory,
|
||||||
|
ConvertTickToTime,
|
||||||
FormatDate,
|
FormatDate,
|
||||||
FormatFullDuration,
|
FormatFullDuration,
|
||||||
FormatFullDate,
|
FormatFullDate,
|
||||||
|
@@ -129,6 +129,13 @@
|
|||||||
replace>Damage
|
replace>Damage
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
|
<li :title="!data.matchDetails.parsed ? 'This demo has not been parsed' : ''"
|
||||||
|
class="list-item nav-item">
|
||||||
|
<router-link :class="!data.matchDetails.parsed ? 'disabled' : ''" :disabled="!data.matchDetails.parsed"
|
||||||
|
:to="'/match/' + data.matchDetails.match_id + '/chat-history'" class="nav-link"
|
||||||
|
replace>Chat-History
|
||||||
|
</router-link>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user