Finished entire frontend

This commit is contained in:
2025-05-07 16:14:06 +02:00
parent 66f2919b6f
commit b10b135b39
10 changed files with 110 additions and 279 deletions

View File

@@ -2,6 +2,8 @@ import express from 'express';
import cors from 'cors';
import pathRoutes from './routes/parkRoutes.js';
import coasterRoutes from './routes/coasterRoutes.js';
import fs from 'fs';
import path from 'path';
const app = express();
const port = 3000;
@@ -15,6 +17,22 @@ app.use(cors());
app.use('/api/parks', pathRoutes);
app.use('/api/coasters', coasterRoutes);
app.get('/api/filesize', (req, res) => {
const dbPath = path.join('./database.db');
fs.stat(dbPath, (err, stats) => {
if (err) {
console.error('Fehler beim Abrufen der Dateigröße:', err);
return res.status(500).json({ error: 'Dateigröße konnte nicht ermittelt werden' });
}
res.json({
sizeBytes: stats.size,
sizeMB: (stats.size / (1024 * 1024)).toFixed(2)
});
});
});
// Start des Servers
app.listen(port, () => {
console.log(`Server läuft auf http://localhost:${port}`);

View File

@@ -45,26 +45,8 @@ export default {
<li class="mb-4">
<a href="https://github.com/MiauRizius/CoasterDB" target="_blank" class="hover:underline ">GitHub</a>
</li>
<!--
<li>
<a href="https://discord.gg/7fVXR2g7DG" target="_blank" class="hover:underline">Discord</a>
</li>
-->
</ul>
</div>
<!--
<div>
<h2 class="mb-6 text-sm font-semibold text-gray-900 uppercase dark:text-white">Rechtliches</h2>
<ul class="text-gray-600 dark:text-gray-400">
<li class="mb-4">
<a href="#" class="hover:underline">Hier könnte was stehe, tut's aber nicht</a>
</li>
<li>
<a href="#" class="hover:underline">Gleiches gilt hier</a>
</li>
</ul>
</div>
-->
</div>
</div>
<hr class="my-6 border-gray-200 sm:mx-auto dark:border-gray-700 lg:my-8" />

View File

@@ -238,79 +238,8 @@ export default {
>Technische Infos</a
>
</li>
<!--
<li>
<a
href="/database/admin"
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
>Admin-Panel</a
>
</li>
-->
</ul>
</li>
<!-- <li>
<button
type="button"
class="flex items-center p-2 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
aria-controls="dropdown-authentication"
data-collapse-toggle="dropdown-authentication"
id="dropdown-authentication-button"
>
<svg
aria-hidden="true"
class="flex-shrink-0 w-6 h-6 text-gray-500 transition duration-75 group-hover:text-gray-900 dark:text-gray-400 dark:group-hover:text-white"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
clip-rule="evenodd"
></path>
</svg>
<span class="flex-1 ml-3 text-left whitespace-nowrap"
>Authentication</span
>
<svg
aria-hidden="true"
class="w-6 h-6"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clip-rule="evenodd"
></path>
</svg>
</button>
<ul id="dropdown-authentication" class="hidden py-2 space-y-2">
<li>
<a
href="#"
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
>Sign In</a
>
</li>
<li>
<a
href="#"
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
>Sign Up</a
>
</li>
<li>
<a
href="#"
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
>Forgot Password</a
>
</li>
</ul>
</li>-->
</ul>
<ul
class="pt-5 mt-5 space-y-2 border-t border-gray-200 dark:border-gray-700"
@@ -362,52 +291,5 @@ export default {
</li>
</ul>
</div>
<!-- <div
class="hidden absolute bottom-0 left-0 justify-center p-4 space-x-4 w-full lg:flex bg-white dark:bg-gray-800 z-20"
>
<a
href="#"
class="inline-flex justify-center p-2 text-gray-500 rounded cursor-pointer dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-600"
>
<svg
aria-hidden="true"
class="w-6 h-6"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5 4a1 1 0 00-2 0v7.268a2 2 0 000 3.464V16a1 1 0 102 0v-1.268a2 2 0 000-3.464V4zM11 4a1 1 0 10-2 0v1.268a2 2 0 000 3.464V16a1 1 0 102 0V8.732a2 2 0 000-3.464V4zM16 3a1 1 0 011 1v7.268a2 2 0 010 3.464V16a1 1 0 11-2 0v-1.268a2 2 0 010-3.464V4a1 1 0 011-1z"
></path>
</svg>
</a>
<a
href="#"
data-tooltip-target="tooltip-settings"
class="inline-flex justify-center p-2 text-gray-500 rounded cursor-pointer dark:text-gray-400 dark:hover:text-white hover:text-gray-900 hover:bg-gray-100 dark:hover:bg-gray-600"
>
<svg
aria-hidden="true"
class="w-6 h-6"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z"
clip-rule="evenodd"
></path>
</svg>
</a>
<div
id="tooltip-settings"
role="tooltip"
class="inline-block absolute invisible z-10 py-2 px-3 text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm opacity-0 transition-opacity duration-300 tooltip"
>
Settings page
<div class="tooltip-arrow" data-popper-arrow></div>
</div>
</div>-->
</aside>
</template>

View File

@@ -1,35 +0,0 @@
<script lang="ts">
export default {
components: {
}
}
</script>
<template>
<article class="p-6 bg-white rounded-lg border border-gray-200 shadow-md dark:bg-gray-800 dark:border-gray-700">
<div class="flex justify-between items-center mb-5 text-gray-500">
<span class="bg-primary-100 text-primary-800 text-xs font-medium inline-flex items-center px-2.5 py-0.5 rounded dark:bg-primary-200 dark:text-primary-800">
<svg class="mr-1 w-3 h-3" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 6a2 2 0 012-2h6a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6zM14.553 7.106A1 1 0 0014 8v4a1 1 0 00.553.894l2 1A1 1 0 0018 13V7a1 1 0 00-1.447-.894l-2 1z"></path></svg>
Tutorial
</span>
<span class="text-sm">14 days ago</span>
</div>
<h2 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white"><a href="#">How to quickly deploy a static website</a></h2>
<p class="mb-5 font-light text-gray-500 dark:text-gray-400">Static websites are now used to bootstrap lots of websites and are becoming the basis for a variety of tools that even influence both web designers and developers influence both web designers and developers.</p>
<div class="flex justify-between items-center">
<div class="flex items-center space-x-4">
<img class="w-7 h-7 rounded-full" src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/avatars/jese-leos.png" alt="Jese Leos avatar" />
<span class="font-medium dark:text-white">
Jese Leos
</span>
</div>
<a href="#" class="inline-flex items-center font-medium text-primary-600 dark:text-primary-500 hover:underline">
Read more
<svg class="ml-2 w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</a>
</div>
</article>
</template>

View File

@@ -1,26 +0,0 @@
<script lang="ts">
export default {
props: {
name: String,
park: String,
length: String,
height: String,
speed: String
},
components: {
}
}
</script>
<template>
<tr class="border-b dark:border-gray-700">
<th scope="row" class="px-4 py-3 font-medium text-gray-900 whitespace-nowrap dark:text-white">{{ name }}</th>
<td class="px-4 py-3">{{ park }}</td>
<td class="px-4 py-3">{{ length }}</td>
<td class="px-4 py-3">{{ height }}</td>
<td class="px-4 py-3">{{ speed }}</td>
</tr>
</template>

View File

@@ -1,5 +1,4 @@
<script lang="ts">
import Navbar from '../components/Navbar.vue'
import Footer from '../components/Footer.vue'
@@ -7,6 +6,30 @@ export default {
components: {
Navbar,
Footer
},
data() {
return {
parkCount: 0,
coasterCount: 0
};
},
computed: {
totalEntries(): number {
return this.parkCount + this.coasterCount;
}
},
async mounted() {
try {
const parkRes = await fetch('http://localhost:3000/api/parks');
const parks = await parkRes.json();
this.parkCount = parks.length;
const coasterRes = await fetch('http://localhost:3000/api/coasters');
const coasters = await coasterRes.json();
this.coasterCount = coasters.length;
} catch (error) {
console.error("Fehler beim Laden der Statistiken:", error);
}
}
}
</script>
@@ -23,7 +46,9 @@ export default {
<p class="mb-4 font-medium">In dieser Web-Anwendung findest du viele Fakten, technische Daten und anderes Material zu verschiedene Achterbahnen und Parks in Deutschland.</p>
<a href="/app" class="inline-flex items-center font-medium text-primary-600 hover:text-primary-800 dark:text-primary-500 dark:hover:text-primary-700">
Öffne die Web-App
<svg class="ml-1 w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path></svg>
<svg class="ml-1 w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
</svg>
</a>
</div>
</div>
@@ -32,15 +57,15 @@ export default {
<div class="max-w-screen-xl px-4 py-8 mx-auto text-center lg:py-16 lg:px-6">
<dl class="grid max-w-screen-md gap-8 mx-auto text-gray-900 sm:grid-cols-3 dark:text-white">
<div class="flex flex-col items-center justify-center">
<dt class="mb-2 text-3xl md:text-4xl font-extrabold">27</dt>
<dt class="mb-2 text-3xl md:text-4xl font-extrabold">{{ parkCount }}</dt>
<dd class="font-light text-gray-500 dark:text-gray-400">Parks</dd>
</div>
<div class="flex flex-col items-center justify-center">
<dt class="mb-2 text-3xl md:text-4xl font-extrabold">400</dt>
<dt class="mb-2 text-3xl md:text-4xl font-extrabold">{{ coasterCount }}</dt>
<dd class="font-light text-gray-500 dark:text-gray-400">Achterbahnen</dd>
</div>
<div class="flex flex-col items-center justify-center">
<dt class="mb-2 text-3xl md:text-4xl font-extrabold">785</dt>
<dt class="mb-2 text-3xl md:text-4xl font-extrabold">{{ totalEntries }}</dt>
<dd class="font-light text-gray-500 dark:text-gray-400">Datenbankeinträge</dd>
</div>
</dl>

View File

@@ -12,30 +12,42 @@ export default {
stats: {
totalParks: 0,
totalCoasters: 0,
totalVisitorsPerMonth: 500000, // bleibt statisch, da nicht aus API
averageTicketPrice: 45.99, // bleibt statisch, da nicht aus API
totalInversions: 0
totalVisitorsPerMonth: 0,
averageTicketPrice: 0,
totalInversions: 0,
databaseSize: 0
}
};
},
async mounted() {
try {
// Parks abrufen
const parksRes = await fetch('http://localhost:3000/api/parks');
const parks = await parksRes.json();
this.stats.totalParks = parks.length;
// Coaster abrufen
const totalVisitors = parks.reduce((sum: number, park: any) => sum + Number(park.average_visitor_count), 0);
this.stats.totalVisitorsPerMonth = Math.round(totalVisitors / parks.length);
const totalPrice = parks.reduce((sum: number, park: any) => {
const price = parseFloat(park.ticket_price.replace('€', '').replace(',', '.'));
return sum + price;
}, 0);
this.stats.averageTicketPrice = parseFloat((totalPrice / parks.length).toFixed(2));
const coastersRes = await fetch('http://localhost:3000/api/coasters');
const coasters = await coastersRes.json();
this.stats.totalCoasters = coasters.length;
// Summe der Inversionen berechnen
this.stats.totalInversions = coasters.reduce((sum: number, coaster: any) => sum + coaster.inversions, 0);
const sizeRes = await fetch('http://localhost:3000/api/filesize');
const size = await sizeRes.json();
this.stats.databaseSize = size.sizeMB;
} catch (err) {
console.error('Fehler beim Laden der Statistiken:', err);
}
}
}
};
</script>
@@ -76,6 +88,10 @@ export default {
<p class="text-gray-600 dark:text-gray-300">Anzahl der Inversionen:</p>
<p class="text-lg font-semibold text-gray-900 dark:text-white">{{ stats.totalInversions }}</p>
</div>
<div class="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg shadow-sm">
<p class="text-gray-600 dark:text-gray-300">Größe der Datenbank:</p>
<p class="text-lg font-semibold text-gray-900 dark:text-white">{{ stats.databaseSize }} MB</p>
</div>
</div>
</div>
</div>

View File

@@ -1,18 +1,7 @@
<script lang="ts">
/**
*
* use this for template:
* https://flowbite.com/blocks/
* https://flowbite.com/blocks/marketing/blog/
* https://flowbite.com/blocks/application/advanced-tables/
*
*/
import Header from '../../components/app/AppHeader.vue'
import Sidebar from '../../components/app/AppSidebar.vue'
import ListItem from '../../components/app/ListItem.vue'
import Entry from '../../components/app/Entry.vue'
import Documentation from "../../views/app/Documentation.vue"
import Help from "../../views/app/Help.vue"
@@ -20,8 +9,6 @@ export default {
components: {
Header,
Sidebar,
ListItem,
Entry,
Documentation,
Help
},

View File

@@ -1,14 +1,5 @@
<script lang="ts">
/**
*
* use this for template:
* https://flowbite.com/blocks/
* https://flowbite.com/blocks/marketing/blog/
* https://flowbite.com/blocks/application/advanced-tables/
*
*/
import Header from '../../components/app/AppHeader.vue'
import Sidebar from '../../components/app/AppSidebar.vue'

View File

@@ -1,14 +1,5 @@
<script lang="ts">
/**
*
* use this for template:
* https://flowbite.com/blocks/
* https://flowbite.com/blocks/marketing/blog/
* https://flowbite.com/blocks/application/advanced-tables/
*
*/
import Header from '../../components/app/AppHeader.vue'
import Sidebar from '../../components/app/AppSidebar.vue'