Fix datetime issues.
This commit is contained in:
parent
4ceb167f5e
commit
10c8069719
|
@ -20,9 +20,6 @@
|
|||
:fields="fields"
|
||||
:api-url="apiUrl"
|
||||
>
|
||||
<template #cell(date_time)="row">
|
||||
{{ formatTimestamp(row.item.timestamp) }}
|
||||
</template>
|
||||
<template #cell(operation)="row">
|
||||
<span
|
||||
v-if="row.item.operation_text === 'insert'"
|
||||
|
@ -135,9 +132,21 @@ const dateRange = ref({
|
|||
});
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
const {timeConfig} = useAzuraCast();
|
||||
|
||||
const fields = [
|
||||
{key: 'date_time', label: $gettext('Date/Time'), sortable: false},
|
||||
{
|
||||
key: 'timestamp',
|
||||
label: $gettext('Date/Time'),
|
||||
sortable: false,
|
||||
formatter: (value) => {
|
||||
return DateTime.fromSeconds(value).toLocaleString(
|
||||
{
|
||||
...DateTime.DATETIME_SHORT, ...timeConfig
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
{key: 'user', label: $gettext('User'), sortable: false},
|
||||
{key: 'operation', isRowHeader: true, label: $gettext('Operation'), sortable: false},
|
||||
{key: 'identifier', label: $gettext('Identifier'), sortable: false},
|
||||
|
@ -160,16 +169,6 @@ const $dataTable = ref(); // DataTable Template Ref
|
|||
const relist = () => {
|
||||
$dataTable.value.relist();
|
||||
};
|
||||
|
||||
const formatTimestamp = (unix_timestamp) => {
|
||||
const {timeConfig} = useAzuraCast();
|
||||
|
||||
return DateTime.fromSeconds(unix_timestamp).toLocaleString(
|
||||
{
|
||||
...DateTime.DATETIME_SHORT, ...timeConfig
|
||||
}
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<h2 class="card-title flex-fill my-0">
|
||||
{{ $gettext('Song Playback Timeline') }}
|
||||
</h2>
|
||||
<div class="flex-shrink">
|
||||
<div class="flex-shrink buttons">
|
||||
<a
|
||||
id="btn-export"
|
||||
class="btn btn-bg"
|
||||
|
@ -26,22 +26,13 @@
|
|||
</div>
|
||||
</div>
|
||||
<data-table
|
||||
ref="datatable"
|
||||
ref="$datatable"
|
||||
responsive
|
||||
paginated
|
||||
select-fields
|
||||
:fields="fields"
|
||||
:api-url="apiUrl"
|
||||
>
|
||||
<template #cell(datetime)="row">
|
||||
{{ formatTimestamp(row.item.played_at) }}
|
||||
</template>
|
||||
<template #cell(datetime_station)="row">
|
||||
{{ formatTimestampStation(row.item.played_at) }}
|
||||
</template>
|
||||
<template #cell(listeners_start)="row">
|
||||
{{ row.item.listeners_start }}
|
||||
</template>
|
||||
<template #cell(delta)="row">
|
||||
<span class="typography-subheading">
|
||||
<template v-if="row.item.delta_total > 0">
|
||||
|
@ -92,116 +83,121 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import Icon from "~/components/Common/Icon";
|
||||
import DataTable from "~/components/Common/DataTable";
|
||||
import DateRangeDropdown from "~/components/Common/DateRangeDropdown";
|
||||
import {DateTime} from 'luxon';
|
||||
import {useAzuraCast} from "~/vendor/azuracast";
|
||||
import {computed, ref} from "vue";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
|
||||
export default {
|
||||
name: 'StationsReportsTimeline',
|
||||
components: {DateRangeDropdown, DataTable, Icon},
|
||||
props: {
|
||||
baseApiUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
stationTimeZone: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
const props = defineProps({
|
||||
baseApiUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
data() {
|
||||
let nowTz = DateTime.now().setZone(this.stationTimeZone);
|
||||
|
||||
return {
|
||||
dateRange: {
|
||||
startDate: nowTz.minus({days: 13}).toJSDate(),
|
||||
endDate: nowTz.toJSDate(),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
key: 'datetime',
|
||||
label: this.$gettext('Date/Time (Browser)'),
|
||||
selectable: true,
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
key: 'datetime_station',
|
||||
label: this.$gettext('Date/Time (Station)'),
|
||||
sortable: false,
|
||||
selectable: true,
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
key: 'listeners_start',
|
||||
label: this.$gettext('Listeners'),
|
||||
selectable: true,
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
key: 'delta',
|
||||
label: this.$gettext('Change'),
|
||||
selectable: true,
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
key: 'song',
|
||||
isRowHeader: true,
|
||||
label: this.$gettext('Song Title'),
|
||||
selectable: true,
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
key: 'source',
|
||||
label: this.$gettext('Source'),
|
||||
selectable: true,
|
||||
sortable: false
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
apiUrl() {
|
||||
let apiUrl = new URL(this.baseApiUrl, document.location);
|
||||
|
||||
let apiUrlParams = apiUrl.searchParams;
|
||||
apiUrlParams.set('start', DateTime.fromJSDate(this.dateRange.startDate).toISO());
|
||||
apiUrlParams.set('end', DateTime.fromJSDate(this.dateRange.endDate).toISO());
|
||||
|
||||
return apiUrl.toString();
|
||||
},
|
||||
exportUrl() {
|
||||
let exportUrl = new URL(this.apiUrl, document.location);
|
||||
let exportUrlParams = exportUrl.searchParams;
|
||||
|
||||
exportUrlParams.set('format', 'csv');
|
||||
|
||||
return exportUrl.toString();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
relist() {
|
||||
this.$refs.datatable.relist();
|
||||
},
|
||||
abs(val) {
|
||||
return Math.abs(val);
|
||||
},
|
||||
formatTimestamp(unix_timestamp) {
|
||||
const {timeConfig} = useAzuraCast();
|
||||
|
||||
return DateTime.fromSeconds(unix_timestamp).toLocaleString(
|
||||
{...DateTime.DATETIME_SHORT, ...timeConfig}
|
||||
);
|
||||
},
|
||||
formatTimestampStation(unix_timestamp) {
|
||||
const {timeConfig} = useAzuraCast();
|
||||
|
||||
return DateTime.fromSeconds(unix_timestamp).setZone(this.stationTimeZone).toLocaleString(
|
||||
{...DateTime.DATETIME_SHORT, ...timeConfig}
|
||||
);
|
||||
}
|
||||
stationTimeZone: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const nowTz = DateTime.now().setZone(props.stationTimeZone);
|
||||
|
||||
const dateRange = ref(
|
||||
{
|
||||
startDate: nowTz.minus({days: 13}).toJSDate(),
|
||||
endDate: nowTz.toJSDate(),
|
||||
}
|
||||
);
|
||||
|
||||
const {$gettext} = useTranslate();
|
||||
const {timeConfig} = useAzuraCast();
|
||||
|
||||
const fields = [
|
||||
{
|
||||
key: 'played_at',
|
||||
label: $gettext('Date/Time (Browser)'),
|
||||
selectable: true,
|
||||
sortable: false,
|
||||
formatter: (value) => {
|
||||
return DateTime.fromSeconds(
|
||||
value,
|
||||
{zone: 'system'}
|
||||
).toLocaleString(
|
||||
{...DateTime.DATETIME_SHORT, ...timeConfig}
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'played_at_station',
|
||||
label: $gettext('Date/Time (Station)'),
|
||||
sortable: false,
|
||||
selectable: true,
|
||||
visible: false,
|
||||
formatter: (value, key, item) => {
|
||||
return DateTime.fromSeconds(
|
||||
item.played_at,
|
||||
{zone: props.stationTimeZone}
|
||||
).toLocaleString(
|
||||
{...DateTime.DATETIME_SHORT, ...timeConfig}
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'listeners_start',
|
||||
label: $gettext('Listeners'),
|
||||
selectable: true,
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
key: 'delta',
|
||||
label: $gettext('Change'),
|
||||
selectable: true,
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
key: 'song',
|
||||
isRowHeader: true,
|
||||
label: $gettext('Song Title'),
|
||||
selectable: true,
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
key: 'source',
|
||||
label: $gettext('Source'),
|
||||
selectable: true,
|
||||
sortable: false
|
||||
}
|
||||
];
|
||||
|
||||
const apiUrl = computed(() => {
|
||||
let apiUrl = new URL(props.baseApiUrl, document.location);
|
||||
|
||||
let apiUrlParams = apiUrl.searchParams;
|
||||
apiUrlParams.set('start', DateTime.fromJSDate(dateRange.value.startDate).toISO());
|
||||
apiUrlParams.set('end', DateTime.fromJSDate(dateRange.value.endDate).toISO());
|
||||
|
||||
return apiUrl.toString();
|
||||
});
|
||||
|
||||
const exportUrl = computed(() => {
|
||||
let exportUrl = new URL(apiUrl.value, document.location);
|
||||
let exportUrlParams = exportUrl.searchParams;
|
||||
|
||||
exportUrlParams.set('format', 'csv');
|
||||
|
||||
return exportUrl.toString();
|
||||
});
|
||||
|
||||
const abs = (val) => {
|
||||
return Math.abs(val);
|
||||
};
|
||||
|
||||
const $datatable = ref(); // Template Ref
|
||||
|
||||
const relist = () => {
|
||||
$datatable.value.relist();
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<b-modal
|
||||
id="streamer_broadcasts"
|
||||
ref="modal"
|
||||
ref="$modal"
|
||||
size="lg"
|
||||
centered
|
||||
:title="$gettext('Streamer Broadcasts')"
|
||||
|
@ -11,12 +11,12 @@
|
|||
style="min-height: 40px;"
|
||||
class="flex-fill text-left bg-primary rounded mb-2"
|
||||
>
|
||||
<inline-player ref="player" />
|
||||
<inline-player ref="$player" />
|
||||
</div>
|
||||
|
||||
<data-table
|
||||
id="station_streamer_broadcasts"
|
||||
ref="datatable"
|
||||
ref="$datatable"
|
||||
:show-toolbar="false"
|
||||
:fields="fields"
|
||||
:api-url="listUrl"
|
||||
|
@ -65,7 +65,8 @@
|
|||
</template>
|
||||
</b-modal>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
<script setup>
|
||||
import DataTable from '~/components/Common/DataTable.vue';
|
||||
import formatFileSize from '~/functions/formatFileSize.js';
|
||||
import InlinePlayer from '~/components/InlinePlayer';
|
||||
|
@ -74,95 +75,108 @@ import PlayButton from "~/components/Common/PlayButton";
|
|||
import {DateTime} from 'luxon';
|
||||
import '~/vendor/sweetalert';
|
||||
import {useAzuraCast} from "~/vendor/azuracast";
|
||||
import {ref} from "vue";
|
||||
import {useTranslate} from "~/vendor/gettext";
|
||||
import {useSweetAlert} from "~/vendor/sweetalert";
|
||||
import {useNotify} from "~/vendor/bootstrapVue";
|
||||
import {useAxios} from "~/vendor/axios";
|
||||
|
||||
export default {
|
||||
name: 'StreamerBroadcastsModal',
|
||||
components: {PlayButton, Icon, InlinePlayer, DataTable},
|
||||
data() {
|
||||
return {
|
||||
listUrl: null,
|
||||
fields: [
|
||||
{
|
||||
key: 'download',
|
||||
label: ' ',
|
||||
sortable: false,
|
||||
class: 'shrink pr-3'
|
||||
},
|
||||
{
|
||||
key: 'timestampStart',
|
||||
label: this.$gettext('Start Time'),
|
||||
sortable: false,
|
||||
formatter: (value) => {
|
||||
const {timeConfig} = useAzuraCast();
|
||||
const listUrl = ref(null);
|
||||
|
||||
return DateTime.fromSeconds(value).toLocaleString(
|
||||
{...DateTime.DATETIME_MED, ...timeConfig}
|
||||
);
|
||||
},
|
||||
class: 'pl-3'
|
||||
},
|
||||
{
|
||||
key: 'timestampEnd',
|
||||
label: this.$gettext('End Time'),
|
||||
sortable: false,
|
||||
formatter: (value) => {
|
||||
if (value === 0) {
|
||||
return this.$gettext('Live');
|
||||
}
|
||||
const {$gettext} = useTranslate();
|
||||
const {timeConfig} = useAzuraCast();
|
||||
|
||||
const {timeConfig} = useAzuraCast();
|
||||
|
||||
return DateTime.fromSeconds(value).toLocaleString(
|
||||
{...DateTime.DATETIME_MED, ...timeConfig}
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'size',
|
||||
label: this.$gettext('Size'),
|
||||
sortable: false,
|
||||
formatter: (value, key, item) => {
|
||||
if (!item.recording?.size) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return formatFileSize(item.recording.size);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: this.$gettext('Actions'),
|
||||
sortable: false,
|
||||
class: 'shrink'
|
||||
}
|
||||
]
|
||||
};
|
||||
const fields = [
|
||||
{
|
||||
key: 'download',
|
||||
label: ' ',
|
||||
sortable: false,
|
||||
class: 'shrink pr-3'
|
||||
},
|
||||
methods: {
|
||||
doDelete (url) {
|
||||
this.$confirmDelete({
|
||||
title: this.$gettext('Delete Broadcast?')
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
this.axios.delete(url).then((resp) => {
|
||||
this.$notifySuccess(resp.data.message);
|
||||
this.$refs.datatable.refresh();
|
||||
});
|
||||
|
||||
this.$refs.datatable.refresh();
|
||||
}
|
||||
});
|
||||
{
|
||||
key: 'timestampStart',
|
||||
label: $gettext('Start Time'),
|
||||
sortable: false,
|
||||
formatter: (value) => {
|
||||
return DateTime.fromSeconds(value).toLocaleString(
|
||||
{...DateTime.DATETIME_MED, ...timeConfig}
|
||||
);
|
||||
},
|
||||
open (listUrl) {
|
||||
this.listUrl = listUrl;
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
close () {
|
||||
this.$refs.player.stop();
|
||||
class: 'pl-3'
|
||||
},
|
||||
{
|
||||
key: 'timestampEnd',
|
||||
label: $gettext('End Time'),
|
||||
sortable: false,
|
||||
formatter: (value) => {
|
||||
if (value === 0) {
|
||||
return $gettext('Live');
|
||||
}
|
||||
|
||||
this.listUrl = null;
|
||||
this.$refs.modal.hide();
|
||||
return DateTime.fromSeconds(value).toLocaleString(
|
||||
{...DateTime.DATETIME_MED, ...timeConfig}
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'size',
|
||||
label: $gettext('Size'),
|
||||
sortable: false,
|
||||
formatter: (value, key, item) => {
|
||||
if (!item.recording?.size) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return formatFileSize(item.recording.size);
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
label: $gettext('Actions'),
|
||||
sortable: false,
|
||||
class: 'shrink'
|
||||
}
|
||||
];
|
||||
|
||||
const {confirmDelete} = useSweetAlert();
|
||||
const {notifySuccess} = useNotify();
|
||||
const {axios} = useAxios();
|
||||
|
||||
const $datatable = ref(); // Template Ref
|
||||
|
||||
const doDelete = (url) => {
|
||||
confirmDelete({
|
||||
title: $gettext('Delete Broadcast?')
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
axios.delete(url).then((resp) => {
|
||||
notifySuccess(resp.data.message);
|
||||
$datatable.value.refresh();
|
||||
});
|
||||
|
||||
$datatable.value.refresh();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const $modal = ref(); // Template Ref
|
||||
|
||||
const open = (newListUrl) => {
|
||||
listUrl.value = newListUrl;
|
||||
$modal.value.show();
|
||||
};
|
||||
|
||||
const $player = ref(); // Template Ref
|
||||
|
||||
const close = () => {
|
||||
$player.value.stop();
|
||||
|
||||
listUrl.value = null;
|
||||
|
||||
$modal.value.hide();
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -5,5 +5,4 @@ const {localeWithDashes} = useAzuraCast();
|
|||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
Settings.defaultLocale = localeWithDashes;
|
||||
Settings.defaultZone = 'UTC';
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue