Commit 4c761710 authored by 22stmo1bif's avatar 22stmo1bif
Browse files

Refactor sensor schemas for improved data structure; update...

Refactor sensor schemas for improved data structure; update RoomDataRangeResponse to use nested dictionaries
Add authentication handling and logout functionality in NavBar component
Enhance AboutView with additional project details and links
Revamp ChartView for better data loading and display; implement default time window and improved styling
Update HomeView styles for better readability; remove deprecated HomeViewOLD component
parent 7e8ad6c5
...@@ -2,9 +2,6 @@ from ninja import Schema ...@@ -2,9 +2,6 @@ from ninja import Schema
from typing import List, Dict, Optional from typing import List, Dict, Optional
from datetime import datetime
class SensorData(Schema): class SensorData(Schema):
co2: int co2: int
humidity: float humidity: float
...@@ -13,7 +10,7 @@ class SensorData(Schema): ...@@ -13,7 +10,7 @@ class SensorData(Schema):
class RoomDataRangeResponse(Schema): class RoomDataRangeResponse(Schema):
room: str room: str
data: Dict[datetime, SensorData] data: Dict[str, Dict[str, float]]
class RoomDataPoint(Schema): class RoomDataPoint(Schema):
......
<script setup lang="ts"> <script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router' import { RouterLink, RouterView } from 'vue-router'
import { useAuthStore } from '../stores/auth'
import { useRouter } from 'vue-router'
const authStore = useAuthStore()
const router = useRouter()
const logout = async () => {
try {
await authStore.logout(router)
} catch (error) {
console.error('Logout error:', error)
}
}
</script> </script>
<template> <template>
...@@ -14,10 +27,20 @@ import { RouterLink, RouterView } from 'vue-router' ...@@ -14,10 +27,20 @@ import { RouterLink, RouterView } from 'vue-router'
<nav> <nav>
<RouterLink to="/">Home</RouterLink> <RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink> <RouterLink to="/about">About</RouterLink>
<!-- Nur anzeigen wenn NICHT eingeloggt -->
<template v-if="!authStore.isAuthenticated">
<RouterLink to="/login">Login</RouterLink> <RouterLink to="/login">Login</RouterLink>
<RouterLink to="/register">Registrieren</RouterLink> <RouterLink to="/register">Registrieren</RouterLink>
</template>
<!-- Nur anzeigen wenn eingeloggt -->
<template v-if="authStore.isAuthenticated">
<RouterLink to="/buildingsView">Gebäude</RouterLink> <RouterLink to="/buildingsView">Gebäude</RouterLink>
<RouterLink to="/dashboard">Device Dashboard</RouterLink> <RouterLink to="/dashboard">Device Dashboard</RouterLink>
<span class="user-info">{{ authStore.user?.username }}</span>
<button @click="logout" class="logout-btn">Logout</button>
</template>
</nav> </nav>
</div> </div>
</header> </header>
...@@ -66,6 +89,28 @@ nav a:hover { ...@@ -66,6 +89,28 @@ nav a:hover {
color: darkred; color: darkred;
} }
.user-info {
margin-left: 1rem;
color: #333;
font-weight: 500;
}
.logout-btn {
margin-left: 1rem;
padding: 0.4rem 0.8rem;
background: #dc3545;
color: white;
border: none;
border-radius: 4px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.2s;
}
.logout-btn:hover {
background: #c82333;
}
main { main {
padding-top: 80px; /* Abstand für den festen Header */ padding-top: 80px; /* Abstand für den festen Header */
} }
......
...@@ -51,17 +51,30 @@ ...@@ -51,17 +51,30 @@
<h2>Projektteam</h2> <h2>Projektteam</h2>
<p> <p>
Das Projekt wurde an der HFT Stuttgart unter anderem von Eric Duminil, Tobias Erhart, Das Ursprüngliche Projekt wurde an der HFT Stuttgart unter anderem von Eric Duminil, Tobias Erhart,
Myriam Guedey, Nathalie Heimsch, Benjamin Hueber, Robert Otto und Jonas Stave entwickelt. Myriam Guedey, Nathalie Heimsch, Benjamin Hueber, Robert Otto und Jonas Stave entwickelt.
</p>
<p>Die Implementierung dieser Webseite und eines Servers mit MQTT-Broker, Stream-Processing,
InfluxDB Datenbank, django backend, vue.js frontend
entsand in einem Team-Projekt im Pervasive Computing Wahlpflichfach.
</p> </p>
<p> <p>
Weitere Infos und Bauanleitungen unter: Weitere Infos und zum ursprünglichen Projekt unter:
<a href="https://transfer.hft-stuttgart.de/gitlab/co2ampel" target="_blank"> <a href="https://transfer.hft-stuttgart.de/gitlab/co2ampel" target="_blank">
https://transfer.hft-stuttgart.de/gitlab/co2ampel https://transfer.hft-stuttgart.de/gitlab/co2ampel
</a> </a>
</p> </p>
<p>
Weitere Infos zum weiterführenden Projekt:
<a href="https://transfer.hft-stuttgart.de/gitlab/co2ampel2" target="_blank">
https://transfer.hft-stuttgart.de/gitlab/co2ampel2
</a>
</p>
<h2>Technologie</h2> <h2>Technologie</h2>
<ul> <ul>
......
<template>
<div class="chart-view">
<h2>Daten für Raum: {{ room }}</h2>
<div class="time-form">
<label>
Start:
<input class="datetime" type="datetime-local" v-model="start" />
</label>
<label>
Stop:
<input class="datetime" type="datetime-local" v-model="stop" />
</label>
<button @click="loadData">Zeitraum aktualisieren</button>
<button @click="loadDataWithDefaultWindow" class="default-btn">Zeige die letzte Woche</button>
</div>
<div class="chart-grid">
<ChartCard
title="CO₂ Verlauf"
:labels="displayLabels"
:data="co2Data"
borderColor="#ff6384"
/>
<ChartCard
title="Temperatur Verlauf"
:labels="displayLabels"
:data="temperatureData"
borderColor="#36a2eb"
/>
<ChartCard
title="Luftfeuchtigkeit Verlauf"
:labels="displayLabels"
:data="humidityData"
borderColor="#4bc0c0"
/>
</div>
</div>
</template>
<script lang="ts"> <script lang="ts">
import { defineComponent, ref, onMounted, computed } from 'vue' import { defineComponent, ref, onMounted, computed } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import ChartCard from '../components/ChartCard.vue' import ChartCard from '../components/ChartCard.vue'
import api from '@/services/apiClient' // Axios instance
export default defineComponent({ export default defineComponent({
name: 'ChartView', name: 'ChartView',
...@@ -19,12 +58,16 @@ export default defineComponent({ ...@@ -19,12 +58,16 @@ export default defineComponent({
const start = ref('') const start = ref('')
const stop = ref('') const stop = ref('')
// Computed property for displaying max 6 labels
const displayLabels = computed(() => { const displayLabels = computed(() => {
const total = labels.value.length const total = labels.value.length
if (total <= 6) return labels.value if (total <= 6) return labels.value
const result: string[] = Array(total).fill('') const result: string[] = []
for (let i = 0; i < total; i++) {
result.push('')
}
for (let i = 0; i < 6; i++) { for (let i = 0; i < 6; i++) {
const idx = Math.round((i * (total - 1)) / 5) const idx = Math.round(i * (total - 1) / 5)
result[idx] = labels.value[idx] result[idx] = labels.value[idx]
} }
return result return result
...@@ -42,6 +85,7 @@ export default defineComponent({ ...@@ -42,6 +85,7 @@ export default defineComponent({
const now = new Date() const now = new Date()
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000) const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000)
// Format dates properly for datetime-local inputs
const formatForInput = (date: Date) => { const formatForInput = (date: Date) => {
const year = date.getFullYear() const year = date.getFullYear()
const month = ('0' + (date.getMonth() + 1)).slice(-2) const month = ('0' + (date.getMonth() + 1)).slice(-2)
...@@ -66,16 +110,16 @@ export default defineComponent({ ...@@ -66,16 +110,16 @@ export default defineComponent({
return return
} }
const url = `http://localhost:8000/api/room_data_range?room=${encodeURIComponent(
room
)}&start=${startISO}&stop=${stopISO}`
try { try {
const response = await api.get('/room_data_range', { const response = await fetch(url)
params: { if (!response.ok) throw new Error('Fehler beim Laden')
room,
start: startISO,
stop: stopISO,
},
})
const entries = Object.entries(response.data.data).sort( const json = await response.json()
const entries = Object.entries(json.data).sort(
([a], [b]) => new Date(a).getTime() - new Date(b).getTime() ([a], [b]) => new Date(a).getTime() - new Date(b).getTime()
) )
...@@ -88,14 +132,18 @@ export default defineComponent({ ...@@ -88,14 +132,18 @@ export default defineComponent({
}) })
) )
co2Data.value = entries.map(([, values]: any) => Number(values.co2)) co2Data.value = entries.map(([, values]: any) => Number(values.co2))
temperatureData.value = entries.map(([, values]: any) => Number(values.temperature)) temperatureData.value = entries.map(([, values]: any) =>
humidityData.value = entries.map(([, values]: any) => Number(values.humidity)) Number(values.temperature)
} catch (err: any) { )
humidityData.value = entries.map(([, values]: any) =>
Number(values.humidity)
)
} catch (err) {
console.error('❌ Fehler beim Laden der Daten:', err) console.error('❌ Fehler beim Laden der Daten:', err)
alert('Fehler beim Laden der Daten')
} }
} }
// Function to load data with default last week window
async function loadDataWithDefaultWindow() { async function loadDataWithDefaultWindow() {
setDefaultTimeWindow() setDefaultTimeWindow()
await loadData() await loadData()
...@@ -120,3 +168,55 @@ export default defineComponent({ ...@@ -120,3 +168,55 @@ export default defineComponent({
}, },
}) })
</script> </script>
<style scoped>
.chart-view {
padding: 2rem;
color: #1a1a1a;
}
.time-form {
display: flex;
gap: 1rem;
margin-bottom: 2rem;
align-items: center;
flex-wrap: wrap;
}
.time-form input {
padding: 0.5rem;
font-size: 1rem;
border-radius: 5px;
}
.time-form button {
background: #007bff;
color: white;
padding: 0.6rem 1.2rem;
border: none;
border-radius: 4px;
font-weight: bold;
cursor: pointer;
transition: background-color 0.2s ease;
}
.time-form button:hover {
background-color: #0056b3;
}
.time-form .default-btn {
background: #28a745;
}
.time-form .default-btn:hover {
background-color: #218838;
}
.chart-grid {
display: flex;
flex-wrap: nowrap;
gap: 2rem;
justify-content: flex-start;
flex-direction: row;
}
</style>
...@@ -66,11 +66,13 @@ export default { ...@@ -66,11 +66,13 @@ export default {
border-radius: 12px; border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
text-align: center; text-align: center;
color: #333333;
} }
h1 { h1 {
font-size: 2rem; font-size: 2rem;
margin-bottom: 1rem; margin-bottom: 1rem;
color: #222222;
} }
.status-box { .status-box {
...@@ -79,6 +81,7 @@ h1 { ...@@ -79,6 +81,7 @@ h1 {
background-color: #ffffff; background-color: #ffffff;
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 8px; border-radius: 8px;
color: #333333;
} }
button { button {
......
<script setup lang="ts">
import TheWelcome from '../components/TheWelcome.vue'
</script>
<template>
<main>
<TheWelcome />
</main>
</template>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment