Add indoor summary

This commit is contained in:
2024-03-15 00:28:54 +00:00
parent e4ee81ca3e
commit 05c0d49a93
7 changed files with 136 additions and 21 deletions

View File

@@ -0,0 +1,84 @@
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { createIndoorStore } from '@/stores/indoorStore';
import ReadingsAggregate from '@/models/environment/readingsAggregate';
import { ConvertPascalToInchesOfMercury } from '@/pressureConverter';
import { ConvertCToF } from '@/temperatureConverter';
const props = defineProps({
name: { type: String, required: true },
title: { type: String, required: true },
start: { type: Date, required: true },
end: { type: Date, required: true }
});
const readingAggregates = ref<ReadingsAggregate | undefined>();
const indoorStore = createIndoorStore(props.name);
const load = () => {
indoorStore.getReadingsAggregate(props.name, props.start, props.end).then((newReadingAggregates) => {
readingAggregates.value = newReadingAggregates;
});
};
watch(
() => [props.start, props.end],
() => load
);
load();
</script>
<template>
<DashboardItem :title="props.title">
<div className="reading-summary">
<div v-if="!readingAggregates">Loading...</div>
<table v-else>
<tbody>
<tr>
<th></th>
<th>Minimum</th>
<th>Average</th>
<th>Maximum</th>
</tr>
<tr>
<td class="reading-summary-header">Temperature</td>
<td>{{ ConvertCToF(readingAggregates!.minimumTemperature).toFixed(2) }}°F</td>
<td>{{ ConvertCToF(readingAggregates!.averageTemperature).toFixed(2) }}°F</td>
<td>{{ ConvertCToF(readingAggregates!.maximumTemperature).toFixed(2) }}°F</td>
</tr>
<tr>
<td class="reading-summary-header">Humidity</td>
<td>{{ readingAggregates!.minimumHumidity.toFixed(2) }}%</td>
<td>{{ readingAggregates!.averageHumidity.toFixed(2) }}%</td>
<td>{{ readingAggregates!.maximumHumidity.toFixed(2) }}%</td>
</tr>
<tr>
<td class="reading-summary-header">Pressure</td>
<td>{{ ConvertPascalToInchesOfMercury(readingAggregates!.minimumPressure).toFixed(2) }}"</td>
<td>{{ ConvertPascalToInchesOfMercury(readingAggregates!.averagePressure).toFixed(2) }}"</td>
<td>{{ ConvertPascalToInchesOfMercury(readingAggregates!.maximumPressure).toFixed(2) }}"</td>
</tr>
</tbody>
</table>
</div>
</DashboardItem>
</template>
<style scoped>
.reading-summary {
font-size: 14px;
padding: 6px 12px;
}
.reading-summary-header {
font-weight: 500;
text-align: right;
padding-right: 10px;
}
th {
padding-right: 30px;
}
</style>

View File

@@ -0,0 +1,12 @@
export default interface ReadingsAggregate {
name: string;
minimumTemperature: number;
averageTemperature: number;
maximumTemperature: number;
minimumPressure: number;
averagePressure: number;
maximumPressure: number;
minimumHumidity: number;
averageHumidity: number;
maximumHumidity: number;
}

View File

@@ -30,6 +30,20 @@
:start="start"
:end="end"></WeatherSummary>
</v-card>
<v-card class="main-summary">
<IndoorSummary
name="main"
title="Upstairs"
:start="start"
:end="end"></IndoorSummary>
</v-card>
<v-card class="basement-summary">
<IndoorSummary
name="basement"
title="Downstairs"
:start="start"
:end="end"></IndoorSummary>
</v-card>
</v-container>
</template>
@@ -42,41 +56,34 @@
@media (min-width: 1024px) {
.container {
display: grid;
grid-template-columns: repeat(3, max-content);
grid-template-columns: repeat(2, max-content);
grid-template-rows: repeat(2, max-content);
gap: 15px 15px;
grid-auto-flow: row;
grid-template-areas:
'weather-summary weather-summary weather-summary'
'weather-summary weather-summary weather-summary';
grid-template-areas: 'weather-summary .' 'main-summary basement-summary';
}
}
@media (max-width: 1024px) {
.container {
display: grid;
grid-template-columns: repeat(3, max-content);
grid-template-rows: repeat(2, max-content);
gap: 15px 15px;
grid-auto-flow: row;
grid-template-areas:
'weather-summary weather-summary weather-summary'
'weather-summary weather-summary weather-summary';
}
}
@media (max-width: 768px) {
.container {
padding: 7px;
display: grid;
grid-template-columns: repeat(1, max-content);
grid-template-rows: repeat(1, max-content);
grid-template-rows: repeat(3, max-content);
gap: 10px 0px;
grid-template-areas: 'weather-summary';
grid-template-areas: 'weather-summary' 'main-summary' 'basement-summary';
}
}
.weather-summary {
grid-area: weather-summary;
}
.main-summary {
grid-area: main-summary;
}
.basement-summary {
grid-area: basement-summary;
}
</style>

View File

@@ -2,8 +2,9 @@ import { defineStore } from 'pinia';
import axios from 'axios';
import Environment from '@/environment';
import { HubConnection, HubConnectionBuilder } from '@microsoft/signalr';
import { LatestReadings } from '@/models/environment.ts/latestReadings';
import { ReadingsGrouped } from '@/models/environment.ts/readingsGrouped';
import { LatestReadings } from '@/models/environment/latestReadings';
import { ReadingsGrouped } from '@/models/environment/readingsGrouped';
import ReadingsAggregate from '@/models/environment/readingsAggregate';
export function createIndoorStore(name: string) {
return defineStore(`indoor-${name}`, {
@@ -56,6 +57,16 @@ export function createIndoorStore(name: string) {
);
return response.data;
},
async getReadingsAggregate(name: string, start: Date, end: Date): Promise<ReadingsAggregate | undefined> {
const startString = start.toISOString();
const endString = end.toISOString();
const response = await axios.get<ReadingsAggregate[]>(
Environment.getUrlPrefix() + `/api/environment/readings/aggregate?start=${startString}&end=${endString}`
);
return response.data.find((aggregate) => aggregate.name === name);
}
}
})();