feat: 🎨

This commit is contained in:
2025-01-16 12:37:26 +01:00
parent e931e23062
commit f56f931213
16 changed files with 551040 additions and 50 deletions
+16
View File
@@ -33,6 +33,22 @@ print("initialize database")
engine = db_connect() engine = db_connect()
SessionFactory = sessionmaker(bind=engine) SessionFactory = sessionmaker(bind=engine)
session = SessionFactory() session = SessionFactory()
create_table(engine)
print("pushing initial data if not already happened")
try:
defDriver = session.query(Driver).filter(id=1)
defVehicle = session.query(Vehicle).filter(id=1)
if not defDriver and not defVehicle:
defaultVehicle = Vehicle(id=1, name="default", licenseplate="default")
defaultDriver = Driver(id=1, name="default")
session.add(defaultVehicle)
session.add(defaultDriver)
session.commit()
session.flush()
except:
print("default data not pushed as already present")
print("initialize handlers") print("initialize handlers")
gpxHandler = GPXHandler(session) gpxHandler = GPXHandler(session)
+2 -2
View File
@@ -17,8 +17,8 @@ services:
POSTGRES_USER: example POSTGRES_USER: example
POSTGRES_PASSWORD: example POSTGRES_PASSWORD: example
POSTGRES_DB: geotrack POSTGRES_DB: geotrack
volumes: # volumes:
- ./init.sql:/docker-entrypoint-initdb.d/init.sql # - ./init.sql:/docker-entrypoint-initdb.d/init.sql
# web: # web:
# build: . # build: .
# ports: # ports:
+1 -28
View File
@@ -32,7 +32,7 @@ class GPXHandler:
for track in self.__gpx.tracks: for track in self.__gpx.tracks:
# sets track name # sets track name
# if no name is found at a track default to using date # if no name is found at a track default to using date
trackName = track.name or f"Track-{datetime.now().isoformat()}" # todo using time.now might end up being misleading and to be reworked trackName = track.name or f"Track-{datetime.now().isoformat()}"
# initializes track values # initializes track values
self.startTime = None self.startTime = None
@@ -132,33 +132,6 @@ class GPXHandler:
return track_list return track_list
def getTracksInTimeWithGeoData(self, start, end):
# Alle Tracks in der Zeitspanne abfragen
tracks = self.__dbSession.query(Track).filter(Track.date.between(start, end)).all()
# Eine Liste von GeoJSON-Features für alle Tracks
features = []
# Für jedes Track-Objekt die Waypoints abfragen und die GeoJSON-Daten generieren
for track in tracks:
# Waypoints für das Track laden
waypoints = track.waypoints # track.waypoints ist bereits korrekt verknüpft
# Waypoints in GeoJSON-kompatible Koordinaten umwandeln
coordinates = [(wp.lon, wp.lat) for wp in waypoints]
# LineString Feature für das Track erstellen
feature = Feature(geometry=LineString(coordinates))
features.append(feature)
# Ein FeatureCollection erstellen, das alle Track-Features enthält
feature_collection = FeatureCollection(features)
# GeoJSON zurückgeben, das von Leaflet verarbeitet werden kann
return feature_collection
def getTracksInTime(self, start, end): def getTracksInTime(self, start, end):
tracks = self.__dbSession.query(Track).filter(Track.date.between(start, end)).all() tracks = self.__dbSession.query(Track).filter(Track.date.between(start, end)).all()
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -39,7 +39,7 @@ export default defineComponent({
<template> <template>
<div class="appContainer"> <div class="appContainer">
<Navbar></Navbar> <Navbar></Navbar>
<cookiePrompt v-if="showCookiePrompt" @close="showCookiePrompt=false;"></cookiePrompt> <cookiePrompt v-if="showCookiePrompt" @close="showCookiePrompt=false;" style="margin-left:20%;width:90%;"></cookiePrompt>
<RouterView></RouterView> <RouterView></RouterView>
</div> </div>
</template> </template>
+1 -1
View File
@@ -274,7 +274,7 @@ export default defineComponent({
console.log(point.id) console.log(point.id)
// Redirect to /track/:id using Vue Router // Redirect to /track/:id using Vue Router
router.push(`/track/${point.id}`); router.push(`/route/${point.id}`);
} }
}; };
+3 -1
View File
@@ -138,7 +138,9 @@ export default defineComponent({
<td></td> <td></td>
<td><input type="text" placeholder="Driver Name" class="input input-bordered w-full" v-model="driverName" /> <td><input type="text" placeholder="Driver Name" class="input input-bordered w-full" v-model="driverName" />
</td> </td>
<td><a class="btn btn-success w-full" v-on:click="createDriver">Create Driver</a></td> <td><a class="btn btn-success w-full" v-on:click="createDriver"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-lg" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2"/>
</svg> Create Driver</a></td>
</tr> </tr>
<tr v-if="driverList.length == 0"> <tr v-if="driverList.length == 0">
<th> <th>
+29 -11
View File
@@ -1,11 +1,12 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, ref, Ref, SetupContext } from 'vue'; import { defineComponent, ref, Ref, SetupContext, watch } from 'vue';
import PointCloud from '../components/pointcloud.vue'; import PointCloud from '../components/pointcloud.vue';
import VueDatePicker from '@vuepic/vue-datepicker'; import VueDatePicker from '@vuepic/vue-datepicker';
import '@vuepic/vue-datepicker/dist/main.css' import '@vuepic/vue-datepicker/dist/main.css'
import Map from '../components/map.vue'; import Map from '../components/map.vue';
import FileUpload from '../components/fileUpload.vue'; import FileUpload from '../components/fileUpload.vue';
import Message from '../components/message.vue'; import Message from '../components/message.vue';
import { useRoute } from 'vue-router'
type DriverType = { type DriverType = {
id: number id: number
@@ -52,16 +53,22 @@ export default defineComponent({
const renderSearchOnMap: Ref<Boolean> = ref(false); const renderSearchOnMap: Ref<Boolean> = ref(false);
const multipleTracks: Ref<Boolean> = ref(false); const multipleTracks: Ref<Boolean> = ref(false);
const trackid: Ref<number> = ref(0); const trackid: Ref<number> = ref(0);
const isLoading:Ref<boolean> = ref(false);
// values for UI Information distribution // values for UI Information distribution
const messageType: Ref<string> = ref(""); const messageType: Ref<string> = ref("");
const message: Ref<string> = ref(""); const message: Ref<string> = ref("");
const route = useRoute()
watch(() => route.params.id, (id) => {
loadTrack(id)
})
const loadTrack = async (id: number) => { const loadTrack = async (id: number) => {
showMap.value = true;
showCloud.value = false; showCloud.value = false;
search.value = false; search.value = false;
showUpload.value = false; showUpload.value = false;
isLoading.value = true;
trackid.value = id trackid.value = id
@@ -78,11 +85,13 @@ export default defineComponent({
var response = await fetch(request); var response = await fetch(request);
if (response.ok) { if (response.ok) {
// Wenn die Antwort OK ist, die Daten verarbeiten showMap.value = true;
isLoading.value = false;
mapData.value = await response.json(); mapData.value = await response.json();
} else { } else {
alert(`loading tracks failed: ${await response.text()}`) alert(`loading tracks failed: ${await response.text()}`)
isLoading.value = false;
console.log(await response.text()); console.log(await response.text());
messageType.value = "error"; messageType.value = "error";
message.value = `loading tracks failed: ${await response.text()}`; message.value = `loading tracks failed: ${await response.text()}`;
@@ -159,7 +168,7 @@ export default defineComponent({
const headers: Headers = new Headers() const headers: Headers = new Headers()
headers.set('Content-Type', 'application/json') headers.set('Content-Type', 'application/json')
headers.set('Accept', 'application/json') headers.set('Accept', 'application/json')
isLoading.value = true;
showMap.value = false; showMap.value = false;
search.value = false; search.value = false;
showCloud.value = true; showCloud.value = true;
@@ -198,6 +207,7 @@ export default defineComponent({
time: track["time"] time: track["time"]
}) })
} }
isLoading.value = false;
showCloud.value = true; showCloud.value = true;
} else { } else {
@@ -209,6 +219,7 @@ export default defineComponent({
if (renderSearchOnMap.value) { if (renderSearchOnMap.value) {
multipleTracks.value = true; multipleTracks.value = true;
isLoading.value = true;
showMap.value = true; showMap.value = true;
showCloud.value = false; showCloud.value = false;
@@ -217,6 +228,8 @@ export default defineComponent({
await loadTrack(track.id); await loadTrack(track.id);
}, 500) }, 500)
}); });
isLoading.value = false;
} }
} }
@@ -241,7 +254,8 @@ export default defineComponent({
message, message,
messageType, messageType,
deleteTrack, deleteTrack,
getTracks getTracks,
isLoading
}; };
}, },
}); });
@@ -252,7 +266,7 @@ export default defineComponent({
<Message v-if="type == 'none'" :type="messageType" :message="message" @close="message = ''; messageType = 'None'"> <Message v-if="type == 'none'" :type="messageType" :message="message" @close="message = ''; messageType = 'None'">
</Message> </Message>
<FileUpload v-if="showUpload" @close="showUpload = false;" @response="tracks=[]; getTracks();" :drivers="[]" <FileUpload v-if="showUpload" @close="showUpload = false;" @response="tracks=[]; getTracks();" :drivers="[]"
style="position:absolute; top: 30VH; width: 80%;"></FileUpload> style="position:absolute; top: 30VH; width: 60%; left:25%;"></FileUpload>
<div class="grid grid-flow-col auto-cols-max gap-4"> <div class="grid grid-flow-col auto-cols-max gap-4">
<div> <div>
<ul class="menu menu-xs bg-base-200 rounded-lg w-full max-w-xs overscroll-auto"> <ul class="menu menu-xs bg-base-200 rounded-lg w-full max-w-xs overscroll-auto">
@@ -267,18 +281,22 @@ export default defineComponent({
<div class="skeleton h-4 w-full"></div> <div class="skeleton h-4 w-full"></div>
</li> </li>
<li v-for="track in tracks"> <li v-for="track in tracks">
<span><a v-on:click="loadTrack(track.id); multipleTracks = false;"> {{ track.name }}</a> <span><a style="line-height: 50px; height:50px;" v-on:click="loadTrack(track.id); multipleTracks = false; showMap=false;"> {{ track.name }}</a>
<button class="btn btn-error" v-on:click="deleteTrack(track.id); tracks=[]; getTracks();"> <button style="width:50px; float:right;" class="btn btn-error" v-on:click="deleteTrack(track.id); tracks=[]; getTracks();">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
class="bi bi-trash3-fill" viewBox="0 0 16 16"> class="bi bi-trash3-fill" viewBox="0 0 16 16">
<path <path
d="M11 1.5v1h3.5a.5.5 0 0 1 0 1h-.538l-.853 10.66A2 2 0 0 1 11.115 16h-6.23a2 2 0 0 1-1.994-1.84L2.038 3.5H1.5a.5.5 0 0 1 0-1H5v-1A1.5 1.5 0 0 1 6.5 0h3A1.5 1.5 0 0 1 11 1.5m-5 0v1h4v-1a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5M4.5 5.029l.5 8.5a.5.5 0 1 0 .998-.06l-.5-8.5a.5.5 0 1 0-.998.06m6.53-.528a.5.5 0 0 0-.528.47l-.5 8.5a.5.5 0 0 0 .998.058l.5-8.5a.5.5 0 0 0-.47-.528M8 4.5a.5.5 0 0 0-.5.5v8.5a.5.5 0 0 0 1 0V5a.5.5 0 0 0-.5-.5" /> d="M11 1.5v1h3.5a.5.5 0 0 1 0 1h-.538l-.853 10.66A2 2 0 0 1 11.115 16h-6.23a2 2 0 0 1-1.994-1.84L2.038 3.5H1.5a.5.5 0 0 1 0-1H5v-1A1.5 1.5 0 0 1 6.5 0h3A1.5 1.5 0 0 1 11 1.5m-5 0v1h4v-1a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5M4.5 5.029l.5 8.5a.5.5 0 1 0 .998-.06l-.5-8.5a.5.5 0 1 0-.998.06m6.53-.528a.5.5 0 0 0-.528.47l-.5 8.5a.5.5 0 0 0 .998.058l.5-8.5a.5.5 0 0 0-.47-.528M8 4.5a.5.5 0 0 0-.5.5v8.5a.5.5 0 0 0 1 0V5a.5.5 0 0 0-.5-.5" />
</svg> </svg>
</button></span> </button>
</span>
</li> </li>
</ul> </ul>
</div> </div>
<div style="width: 70%; margin-left: 5%;"> <div v-if="isLoading">
<h1 class="title text-center " style="text-align: center;"> map is loading: <span class="loading loading-spinner loading-lg"></span> </h1>
</div>
<div style="width: 65%; margin-left: 5%;">
<PointCloud :routes="searchedTracks" style="border-radius: 10px;" v-if="showCloud && !search"></PointCloud> <PointCloud :routes="searchedTracks" style="border-radius: 10px;" v-if="showCloud && !search"></PointCloud>
</div> </div>
<div v-if="!showMap && !showCloud && search" style="margin-left: 20%; display:flex;"> <div v-if="!showMap && !showCloud && search" style="margin-left: 20%; display:flex;">
@@ -299,7 +317,7 @@ export default defineComponent({
</div> </div>
<div v-if="showMap && !search && !showCloud"> <div v-if="showMap && !search && !showCloud">
<Map :track="trackid" :multiple="multipleTracks" :geoJsonData="mapData" <Map :track="trackid" :multiple="multipleTracks" :geoJsonData="mapData"
style="width: 68vw; margin-left: 10%; border-radius: 10px; border: 1px solid #95a5a6;"></Map> style="width: 68vw; margin-left: 15%; border-radius: 10px; border: 1px solid #95a5a6;"></Map>
</div> </div>
</div> </div>
</template> </template>
+3 -1
View File
@@ -144,7 +144,9 @@ export default defineComponent({
v-model="vehicleName" /></td> v-model="vehicleName" /></td>
<td><input type="text" placeholder="License Plate" class="input input-bordered w-full " <td><input type="text" placeholder="License Plate" class="input input-bordered w-full "
v-model="licensePlate" /></td> v-model="licensePlate" /></td>
<td><a class="btn btn-success w-full" v-on:click="createVehicle">Create Vehicle</a></td> <td><a class="btn btn-success w-full" v-on:click="createVehicle"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-lg" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2"/>
</svg> Create Vehicle</a></td>
</tr> </tr>
<tr v-if="vehicleList.length == 0"> <tr v-if="vehicleList.length == 0">
<th> <th>