ApfelNetzwerk/web/src/components/TableCategory.vue

158 lines
4.2 KiB
Vue

<template>
<div class="table-container">
<table class="responsive-table">
<thead>
<tr>
<th>Node/Name</th>
<th>Status</th>
<th>Latitude</th>
<th>Longitude</th>
<th>Battery</th>
<th>Temperature</th>
<th>Runtime</th>
</tr>
</thead>
<tbody>
<tr v-for="(node, index) in tableData" :key="index">
<td>{{ node.name }}</td>
<td>
<span :class="node.sensorData.voltage ? 'status-online' : 'status-offline'">
{{ node.sensorData.voltage ? 'ONLINE' : 'OFFLINE' }}
</span>
</td>
<td
contenteditable="true"
@blur="validateAndUpdateLatLng(node, 'coordla', $event)"
>{{ node.coordla }}</td>
<td
contenteditable="true"
@blur="validateAndUpdateLatLng(node, 'coordlong', $event)"
>{{ node.coordlong }}</td>
<td>{{ calculateBatteryPercentage(node.sensorData.voltage, node.batteryMinimum, node.batteryMaximum) }}%</td>
<td>{{ node.sensorData.temperature }}°C</td>
<td>{{ formatRuntime(node.sensorData.uptime) }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
tableData: [],
};
},
mounted() {
this.fetchNodesAndData();
},
methods: {
async fetchNodesAndData() {
try {
const nodesResponse = await axios.get('http://localhost:8080/api/v1/nodes');
const nodes = nodesResponse.data;
const sensorDataResponse = await axios.get('http://localhost:8080/api/v1/data');
const sensorData = sensorDataResponse.data;
this.tableData = nodes.map((node) => {
const nodeSensorData = sensorData.find((data) => data.id === node.id);
return {
...node,
sensorData: nodeSensorData || {
temperature: 'N/A',
voltage: 'N/A',
uptime: 'N/A',
},
};
});
} catch (error) {
console.error('Error fetching node or sensor data:', error);
}
},
calculateBatteryPercentage(voltage, batteryMinimum, batteryMaximum) {
if (voltage <= batteryMinimum) {
return 0;
} else if (voltage >= batteryMaximum) {
return 100;
} else {
return ((voltage - batteryMinimum) / (batteryMaximum - batteryMinimum) * 100).toFixed(2);
}
},
formatRuntime(uptime) {
const hours = Math.floor(uptime / 3600);
const minutes = Math.floor((uptime % 3600) / 60);
const seconds = uptime % 60;
return `${hours}h ${minutes}m ${seconds}s`;
},
validateAndUpdateLatLng(node, field, event) {
const originalValue = node[field];
let newValue = event.target.innerText;
// Normalize separated values
newValue = newValue.replace(',', '.');
// Check if it's a valid float value
const validNumberRegex = /^-?\d+(\.\d+)?$/;
if (validNumberRegex.test(newValue)) {
const parsedValue = parseFloat(newValue);
// Update if valid
node[field] = parsedValue;
console.log(`Updated ${field} of ${node.name}: ${parsedValue}`);
} else {
// Reset to original value if invalid
event.target.innerText = originalValue;
console.log(`Failed to set ${field} of ${node.name}: Invalid input "${newValue}"`);
}
},
},
};
</script>
<style scoped>
/* Styling remains the same */
.table-container {
background-color: white;
padding: 0.5rem 1rem;
margin: 0 auto;
width: 100%;
overflow-x: auto;
}
.responsive-table {
width: 100%;
border-collapse: collapse;
margin: 0;
table-layout: auto;
}
.responsive-table th,
.responsive-table td {
padding: 0.5rem;
text-align: center;
border-bottom: 1px solid #ddd;
}
.responsive-table th {
font-weight: bold;
}
.responsive-table tr:nth-child(even) {
background-color: #f9f9f9;
}
.status-online {
color: green;
font-weight: bold;
}
.status-offline {
color: red;
font-weight: bold;
}
</style>