Show eventlog in live view
This commit is contained in:
parent
c2a7f487f1
commit
06529f7187
@ -23,13 +23,26 @@
|
|||||||
:id="'v-pills-' + inverter.serial" role="tabpanel"
|
:id="'v-pills-' + inverter.serial" role="tabpanel"
|
||||||
:aria-labelledby="'v-pills-' + inverter.serial + '-tab'" tabindex="0">
|
:aria-labelledby="'v-pills-' + inverter.serial + '-tab'" tabindex="0">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header text-white bg-primary" :class="{
|
<div class="card-header text-white bg-primary d-flex justify-content-between align-items-center"
|
||||||
'bg-danger': inverter.age_critical,
|
:class="{
|
||||||
'bg-primary': !inverter.age_critical,
|
'bg-danger': inverter.age_critical,
|
||||||
}">
|
'bg-primary': !inverter.age_critical,
|
||||||
|
}">
|
||||||
{{ inverter.name }} (Inverter Serial Number:
|
{{ inverter.name }} (Inverter Serial Number:
|
||||||
{{ inverter.serial }}) (Data Age:
|
{{ inverter.serial }}) (Data Age:
|
||||||
{{ inverter.data_age }} seconds)
|
{{ inverter.data_age }} seconds)
|
||||||
|
|
||||||
|
<button v-if="inverter.events >= 0" type="button"
|
||||||
|
class="btn btn-sm btn-secondary position-relative"
|
||||||
|
@click="onShowEventlog(inverter.serial)"
|
||||||
|
title="Show Eventlog">
|
||||||
|
<BIconJournalText style="font-size:24px;" />
|
||||||
|
<span
|
||||||
|
class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
|
||||||
|
{{ inverter.events }}
|
||||||
|
<span class="visually-hidden">unread messages</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row flex-row-reverse flex-wrap-reverse align-items-end g-3">
|
<div class="row flex-row-reverse flex-wrap-reverse align-items-end g-3">
|
||||||
@ -47,6 +60,33 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<div class="modal" id="eventView" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Event Log</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="text-center" v-if="eventLogLoading">
|
||||||
|
<div class="spinner-border" role="status">
|
||||||
|
<span class="visually-hidden">Loading...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<EventLog v-if="!eventLogLoading" :eventLogList="eventLogList" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" @click="onHideEventlog"
|
||||||
|
data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -54,17 +94,20 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import InverterChannelInfo from "@/components/partials/InverterChannelInfo.vue";
|
import InverterChannelInfo from "@/components/partials/InverterChannelInfo.vue";
|
||||||
import * as bootstrap from 'bootstrap';
|
import * as bootstrap from 'bootstrap';
|
||||||
|
import EventLog from '@/components/partials/EventLog.vue';
|
||||||
|
|
||||||
declare interface Inverter {
|
declare interface Inverter {
|
||||||
serial: number,
|
serial: number,
|
||||||
name: string,
|
name: string,
|
||||||
age_critical: boolean,
|
age_critical: boolean,
|
||||||
data_age: 0
|
data_age: 0,
|
||||||
|
events: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
InverterChannelInfo,
|
InverterChannelInfo,
|
||||||
|
EventLog
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -73,11 +116,17 @@ export default defineComponent({
|
|||||||
waitForData: true,
|
waitForData: true,
|
||||||
inverterData: [] as Inverter[],
|
inverterData: [] as Inverter[],
|
||||||
isFirstFetchAfterConnect: true,
|
isFirstFetchAfterConnect: true,
|
||||||
|
eventLogView: {} as bootstrap.Modal,
|
||||||
|
eventLogList: {},
|
||||||
|
eventLogLoading: true
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.initSocket();
|
this.initSocket();
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.eventLogView = new bootstrap.Modal('#eventView');
|
||||||
|
},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
this.closeSocket();
|
this.closeSocket();
|
||||||
},
|
},
|
||||||
@ -140,6 +189,20 @@ export default defineComponent({
|
|||||||
this.heartInterval && clearTimeout(this.heartInterval);
|
this.heartInterval && clearTimeout(this.heartInterval);
|
||||||
this.isFirstFetchAfterConnect = true;
|
this.isFirstFetchAfterConnect = true;
|
||||||
},
|
},
|
||||||
|
onHideEventlog() {
|
||||||
|
this.eventLogView.hide();
|
||||||
|
},
|
||||||
|
onShowEventlog(serial: number) {
|
||||||
|
this.eventLogLoading = true;
|
||||||
|
fetch("/api/eventlog/status")
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
this.eventLogList = data[serial];
|
||||||
|
this.eventLogLoading = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.eventLogView.show();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
57
webapp/src/components/partials/EventLog.vue
Normal file
57
webapp/src/components/partials/EventLog.vue
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<template>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<th scope="col">Start</th>
|
||||||
|
<th scope="col">Stop</th>
|
||||||
|
<th scope="col">ID</th>
|
||||||
|
<th scope="col">Message</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<template v-for="event in eventLogList.count" :key="event">
|
||||||
|
<tr>
|
||||||
|
<td>{{ timeInHours(eventLogList.events[event - 1].start_time) }}</td>
|
||||||
|
<td>{{ timeInHours(eventLogList.events[event - 1].end_time) }}</td>
|
||||||
|
<td>{{ eventLogList.events[event - 1].message_id }}</td>
|
||||||
|
<td>{{ eventLogList.events[event - 1].message }}</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
declare interface EventData {
|
||||||
|
message_id: number,
|
||||||
|
message: string,
|
||||||
|
start_time: number,
|
||||||
|
end_time: number
|
||||||
|
}
|
||||||
|
|
||||||
|
declare interface EventLogData {
|
||||||
|
count: number,
|
||||||
|
events: { [key: number]: EventData }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
eventLogList: { type: Object as () => EventLogData, required: true },
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
timeInHours() {
|
||||||
|
return (value: number) => {
|
||||||
|
const hours = Math.floor((value) / 3600);
|
||||||
|
const minutes = Math.floor((value - hours * 3600) / 60);
|
||||||
|
const seconds = (value - hours * 3600 + minutes * 60) % 60;
|
||||||
|
|
||||||
|
const dHours = hours > 9 ? hours : "0" + hours;
|
||||||
|
const dMins = minutes > 9 ? minutes : "0" + minutes;
|
||||||
|
const dSecs = seconds > 9 ? seconds : "0" + seconds;
|
||||||
|
|
||||||
|
return dHours + ":" + dMins + ":" + dSecs;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
Loading…
Reference in New Issue
Block a user