178 lines
6.2 KiB
Vue
178 lines
6.2 KiB
Vue
<template>
|
|
<b-overlay variant="card" :show="loading">
|
|
<div class="card-body py-5" v-if="loading">
|
|
|
|
</div>
|
|
<div class="card-body" v-else>
|
|
<b-row>
|
|
<b-col md="6" class="mb-4">
|
|
<fieldset>
|
|
<legend>
|
|
{{ $gettext('Best Performing Songs') }}
|
|
</legend>
|
|
|
|
<table class="table table-striped table-condensed table-nopadding">
|
|
<colgroup>
|
|
<col width="20%">
|
|
<col width="80%">
|
|
</colgroup>
|
|
<thead>
|
|
<tr>
|
|
<th>
|
|
{{ $gettext('Change') }}
|
|
</th>
|
|
<th>
|
|
{{ $gettext('Song') }}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="row in bestAndWorst.best">
|
|
<td class="text-center text-success">
|
|
<icon icon="keyboard_arrow_up"></icon>
|
|
{{ row.stat_delta }}
|
|
<br>
|
|
<small>{{ row.stat_start }} to {{ row.stat_end }}</small>
|
|
</td>
|
|
<td>
|
|
<span v-html="getSongText(row.song)"></span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</fieldset>
|
|
</b-col>
|
|
<b-col md="6" class="mb-4">
|
|
<fieldset>
|
|
<legend>
|
|
{{ $gettext('Worst Performing Songs') }}
|
|
</legend>
|
|
|
|
<table class="table table-striped table-condensed table-nopadding">
|
|
<colgroup>
|
|
<col width="20%">
|
|
<col width="80%">
|
|
</colgroup>
|
|
<thead>
|
|
<tr>
|
|
<th>
|
|
{{ $gettext('Change') }}
|
|
</th>
|
|
<th>
|
|
{{ $gettext('Song') }}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="row in bestAndWorst.worst">
|
|
<td class="text-center text-danger">
|
|
<icon icon="keyboard_arrow_down"></icon>
|
|
{{ row.stat_delta }}
|
|
<br>
|
|
<small>{{ row.stat_start }} to {{ row.stat_end }}</small>
|
|
</td>
|
|
<td>
|
|
<span v-html="getSongText(row.song)"></span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</fieldset>
|
|
</b-col>
|
|
|
|
<b-col md="12" class="mb-4">
|
|
<fieldset>
|
|
<legend>
|
|
{{ $gettext('Most Played Songs') }}
|
|
</legend>
|
|
|
|
<table class="table table-striped table-condensed table-nopadding">
|
|
<colgroup>
|
|
<col width="10%">
|
|
<col width="90%">
|
|
</colgroup>
|
|
<thead>
|
|
<tr>
|
|
<th>
|
|
{{ $gettext('Plays') }}
|
|
</th>
|
|
<th>
|
|
{{ $gettext('Song') }}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="row in mostPlayed">
|
|
<td class="text-center">
|
|
{{ row.num_plays }}
|
|
</td>
|
|
<td>
|
|
<span v-html="getSongText(row.song)"></span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</fieldset>
|
|
</b-col>
|
|
</b-row>
|
|
</div>
|
|
</b-overlay>
|
|
</template>
|
|
|
|
<script setup>
|
|
import Icon from "~/components/Common/Icon";
|
|
import {get, set, useMounted} from "@vueuse/core";
|
|
import {onMounted, ref, shallowRef, toRef, watch} from "vue";
|
|
import {DateTime} from "luxon";
|
|
import {useAxios} from "~/vendor/axios";
|
|
|
|
const props = defineProps({
|
|
dateRange: Object,
|
|
apiUrl: String,
|
|
});
|
|
|
|
const loading = ref(true);
|
|
const bestAndWorst = shallowRef({
|
|
best: [],
|
|
worst: []
|
|
});
|
|
const mostPlayed = ref([]);
|
|
|
|
const dateRange = toRef(props, 'dateRange');
|
|
const {axios} = useAxios();
|
|
|
|
const relist = () => {
|
|
set(loading, true);
|
|
axios.get(props.apiUrl, {
|
|
params: {
|
|
start: DateTime.fromJSDate(get(dateRange).startDate).toISO(),
|
|
end: DateTime.fromJSDate(get(dateRange).endDate).toISO()
|
|
}
|
|
}).then((response) => {
|
|
set(bestAndWorst, response.data.bestAndWorst);
|
|
set(mostPlayed, response.data.mostPlayed);
|
|
set(loading, false);
|
|
});
|
|
};
|
|
|
|
const isMounted = useMounted();
|
|
|
|
watch(dateRange, () => {
|
|
if (get(isMounted)) {
|
|
relist();
|
|
}
|
|
});
|
|
|
|
onMounted(() => {
|
|
relist();
|
|
});
|
|
|
|
const getSongText = (song) => {
|
|
if (song.title !== '') {
|
|
return '<b>' + song.title + '</b><br>' + song.artist;
|
|
}
|
|
|
|
return song.text;
|
|
};
|
|
</script>
|