feat: ✨ implemented visual messaging
This commit is contained in:
parent
20ac0faa75
commit
5769fabce4
318
app.py
318
app.py
@ -40,182 +40,200 @@ gpxHandler = GPXHandler(session)
|
|||||||
driverHandler = DriverHandler(session)
|
driverHandler = DriverHandler(session)
|
||||||
vehicleHandler = VehicleHandler(session)
|
vehicleHandler = VehicleHandler(session)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
@cross_origin()
|
@cross_origin()
|
||||||
def serve_vue_app():
|
def serve_vue_app():
|
||||||
return send_from_directory(app.static_folder, 'index.html')
|
return send_from_directory(app.static_folder, 'index.html')
|
||||||
|
|
||||||
@app.route("/track", methods=['GET'])
|
|
||||||
|
@app.route("/track", methods=['GET', 'DELETE'])
|
||||||
@cross_origin()
|
@cross_origin()
|
||||||
def getTrack():
|
def getTrack():
|
||||||
|
|
||||||
app.logger.debug(f"found arguments {request.args}")
|
app.logger.debug(f"found arguments {request.args}")
|
||||||
|
|
||||||
if ("start" in request.args and "end" in request.args) or ("id" in request.args):
|
|
||||||
if "start" in request.args and "end" in request.args:
|
|
||||||
if "asMap" in request.args:
|
|
||||||
# get tracks by filter
|
|
||||||
start = request.args["start"]
|
|
||||||
end = request.args["end"]
|
|
||||||
|
|
||||||
# Die GeoJSON-Daten aus der Datenbank abrufen
|
|
||||||
geojson_data = gpxHandler.getTracksInTimeWithGeoData(start, end)
|
|
||||||
app.logger.debug(f"returned track {geojson_data}")
|
|
||||||
|
|
||||||
# Die GeoJSON-Daten als JSON zurückgeben
|
match request.method:
|
||||||
return jsonify(geojson_data)
|
case "GET":
|
||||||
|
if ("start" in request.args and "end" in request.args) or ("id" in request.args):
|
||||||
# get tracks by filter
|
if "start" in request.args and "end" in request.args:
|
||||||
start = request.args["start"]
|
if "asMap" in request.args:
|
||||||
end = request.args["end"]
|
# get tracks by filter
|
||||||
try:
|
start = request.args["start"]
|
||||||
return gpxHandler.getTracksInTime(start, request.args["end"]), 200
|
end = request.args["end"]
|
||||||
except Exception as e:
|
|
||||||
app.logger.debug(f"failed to search tracks error {e} values: start={start}, end={end}")
|
|
||||||
return f"error {e}", 500
|
|
||||||
|
|
||||||
elif "id" in request.args:
|
# Die GeoJSON-Daten aus der Datenbank abrufen
|
||||||
# get track by id
|
geojson_data = gpxHandler.getTracksInTimeWithGeoData(
|
||||||
trackID = int(request.args["id"])
|
start, end)
|
||||||
try:
|
app.logger.debug(f"returned track {geojson_data}")
|
||||||
app.logger.debug(f"Request args: {request.args}")
|
|
||||||
app.logger.debug(f"track id {trackID}")
|
# Die GeoJSON-Daten als JSON zurückgeben
|
||||||
track = gpxHandler.getTrack(trackID)
|
return jsonify(geojson_data)
|
||||||
|
|
||||||
app.logger.debug(f"returned track {track}")
|
# get tracks by filter
|
||||||
|
start = request.args["start"]
|
||||||
return jsonify(track), 200
|
end = request.args["end"]
|
||||||
except Exception as e:
|
try:
|
||||||
app.logger.debug(f"fetching track failed with error {e}")
|
return gpxHandler.getTracksInTime(start, request.args["end"]), 200
|
||||||
return f"error {e}", 500
|
except Exception as e:
|
||||||
else:
|
app.logger.debug(f"failed to search tracks error {
|
||||||
try:
|
e} values: start={start}, end={end}")
|
||||||
tracks = gpxHandler.getTracks()
|
return f"error {e}", 500
|
||||||
if len(tracks) > 0:
|
|
||||||
# gets all tracks as list
|
elif "id" in request.args:
|
||||||
return tracks, 200
|
# get track by id
|
||||||
|
trackID = int(request.args["id"])
|
||||||
|
try:
|
||||||
|
app.logger.debug(f"Request args: {request.args}")
|
||||||
|
app.logger.debug(f"track id {trackID}")
|
||||||
|
track = gpxHandler.getTrack(trackID)
|
||||||
|
|
||||||
|
app.logger.debug(f"returned track {track}")
|
||||||
|
|
||||||
|
return jsonify(track), 200
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.debug(f"fetching track failed with error {e}")
|
||||||
|
return f"error {e}", 500
|
||||||
else:
|
else:
|
||||||
return [], 200
|
try:
|
||||||
except Exception as e:
|
tracks = gpxHandler.getTracks()
|
||||||
app.logger.debug(f"fetching all tracks failed with error {e}")
|
if len(tracks) > 0:
|
||||||
return f"error {e}", 500
|
# gets all tracks as list
|
||||||
|
return tracks, 200
|
||||||
|
else:
|
||||||
|
return [], 200
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.debug(f"fetching all tracks failed with error {e}")
|
||||||
|
return f"error {e}", 500
|
||||||
|
case "DELETE":
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@app.route("/track/meta", methods=['GET'])
|
@app.route("/track/meta", methods=['GET'])
|
||||||
@cross_origin()
|
@cross_origin()
|
||||||
def getTrackMeta():
|
def getTrackMeta():
|
||||||
|
|
||||||
app.logger.debug(f"found arguments {request.args}")
|
app.logger.debug(f"found arguments {request.args}")
|
||||||
|
|
||||||
if "id" in request.args:
|
|
||||||
# get track by id
|
|
||||||
trackID = int(request.args["id"])
|
|
||||||
try:
|
|
||||||
app.logger.debug(f"Request args: {request.args}")
|
|
||||||
app.logger.debug(f"track id {trackID}")
|
|
||||||
track = gpxHandler.getTrackMeta(trackID)
|
|
||||||
|
|
||||||
app.logger.debug(f"returned track {track}")
|
|
||||||
|
|
||||||
return jsonify(track), 200
|
|
||||||
except Exception as e:
|
|
||||||
app.logger.debug(f"fetching track failed with error {e}")
|
|
||||||
return f"error {e}", 500
|
|
||||||
|
|
||||||
@app.route("/driver", methods=['GET', 'POST'])
|
if "id" in request.args:
|
||||||
|
# get track by id
|
||||||
|
trackID = int(request.args["id"])
|
||||||
|
try:
|
||||||
|
app.logger.debug(f"Request args: {request.args}")
|
||||||
|
app.logger.debug(f"track id {trackID}")
|
||||||
|
track = gpxHandler.getTrackMeta(trackID)
|
||||||
|
|
||||||
|
app.logger.debug(f"returned track {track}")
|
||||||
|
|
||||||
|
return jsonify(track), 200
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.debug(f"fetching track failed with error {e}")
|
||||||
|
return f"error {e}", 500
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/driver", methods=['GET', 'POST', 'PUT', 'DELETE'])
|
||||||
@cross_origin()
|
@cross_origin()
|
||||||
def handleDriverRoute():
|
def handleDriverRoute():
|
||||||
|
|
||||||
if request.method == "GET":
|
match request.method:
|
||||||
if 'driver' in request.args:
|
case "GET":
|
||||||
|
if 'driver' in request.args:
|
||||||
|
|
||||||
|
try:
|
||||||
|
driver = driverHandler.getDriver(int(request.args["driver"]))
|
||||||
|
return driver, 200
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.debug(f"getting driver failed with error {e}")
|
||||||
|
return "error" + " " + str(e), 500
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
try:
|
||||||
|
drivers = driverHandler.getDrivers()
|
||||||
|
if len(drivers) > 0:
|
||||||
|
return drivers, 200
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.debug(f"getting drivers failed with error {e}")
|
||||||
|
return "error" + " " + str(e), 500
|
||||||
|
case "POST":
|
||||||
|
# grabbing json from request
|
||||||
|
data = request.get_json()
|
||||||
|
app.logger.debug(f"json request payload: {data}")
|
||||||
|
|
||||||
|
if "name" not in data:
|
||||||
|
app.logger.debug(f"no driver name was found in request")
|
||||||
|
return "missing name", 400
|
||||||
|
|
||||||
|
app.logger.debug(f"driver name has passed check {data["name"]}")
|
||||||
|
|
||||||
|
# handle creating vehicle
|
||||||
try:
|
try:
|
||||||
driver = driverHandler.getDriver(int(request.args["driver"]))
|
app.logger.debug(f"json request name: {data["name"]}")
|
||||||
return driver, 200
|
driver = driverHandler.createDriver(data["name"])
|
||||||
|
return jsonify({"name": driver.name, "id": driver.id}), 200
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
app.logger.debug(f"getting driver failed with error {e}")
|
app.logger.debug(f"creating drivers failed with error {e}")
|
||||||
return "error" + " " + str(e), 500
|
return "error" + " " + str(e), 500
|
||||||
|
case "PUT":
|
||||||
else:
|
pass
|
||||||
|
case "DELETE":
|
||||||
try:
|
pass
|
||||||
drivers = driverHandler.getDrivers()
|
|
||||||
if len(drivers) > 0:
|
|
||||||
return drivers, 200
|
|
||||||
except Exception as e:
|
|
||||||
app.logger.debug(f"getting drivers failed with error {e}")
|
|
||||||
return "error" + " " + str(e), 500
|
|
||||||
|
|
||||||
elif request.method == "POST":
|
|
||||||
|
|
||||||
# grabbing json from request
|
|
||||||
data = request.get_json()
|
|
||||||
app.logger.debug(f"json request payload: {data}")
|
|
||||||
|
|
||||||
if "name" not in data:
|
|
||||||
app.logger.debug(f"no driver name was found in request")
|
|
||||||
return "missing name", 400
|
|
||||||
|
|
||||||
app.logger.debug(f"driver name has passed check {data["name"]}")
|
|
||||||
|
|
||||||
# handle creating vehicle
|
|
||||||
try:
|
|
||||||
app.logger.debug(f"json request name: {data["name"]}")
|
|
||||||
driver = driverHandler.createDriver(data["name"])
|
|
||||||
return jsonify({"name": driver.name, "id": driver.id}), 200
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
app.logger.debug(f"creating drivers failed with error {e}")
|
|
||||||
return "error" + " " + str(e), 500
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/vehicle", methods=['GET', 'POST'])
|
@app.route("/vehicle", methods=['GET', 'POST', 'PUT', 'DELETE'])
|
||||||
@cross_origin()
|
@cross_origin()
|
||||||
def handleVehicleRoute():
|
def handleVehicleRoute():
|
||||||
|
|
||||||
if request.method == "GET":
|
match request.method:
|
||||||
if 'vehicle' in request.args:
|
case "GET":
|
||||||
app.logger.debug(f"no vehicle id was found in request")
|
if 'vehicle' in request.args:
|
||||||
vehicle = int(request.args["vehicle"])
|
app.logger.debug(f"no vehicle id was found in request")
|
||||||
|
vehicle = int(request.args["vehicle"])
|
||||||
|
|
||||||
|
try:
|
||||||
|
foundVehicle = vehicleHandler.getVehicle(vehicle)
|
||||||
|
return foundVehicle, 200
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.debug(f"getting vehicle {vehicle} failed with error {e}")
|
||||||
|
return "error" + " " + str(e), 500
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
try:
|
||||||
|
foundVehicles = vehicleHandler.getVehicles()
|
||||||
|
return foundVehicles, 200
|
||||||
|
except Exception as e:
|
||||||
|
app.logger.debug(
|
||||||
|
f"getting all vehicles failed with error {e}")
|
||||||
|
return "error" + " " + str(e), 500
|
||||||
|
case "POST":
|
||||||
|
data = request.get_json()
|
||||||
|
app.logger.debug(f"json request payload: {data}")
|
||||||
|
|
||||||
|
if "name" not in data:
|
||||||
|
return "missing name", 400
|
||||||
|
|
||||||
|
licenseplate = ""
|
||||||
|
|
||||||
|
if "licensePlate" not in data:
|
||||||
|
licenseplate = "N/A"
|
||||||
|
else:
|
||||||
|
licenseplate = data["licensePlate"]
|
||||||
|
name = data["name"]
|
||||||
|
|
||||||
|
# handle creating vehicle
|
||||||
try:
|
try:
|
||||||
foundVehicle = vehicleHandler.getVehicle(vehicle)
|
vehicle = vehicleHandler.createVehicle(name, licenseplate)
|
||||||
return foundVehicle, 200
|
return jsonify({"id": vehicle.id, "name": vehicle.name}), 200
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
app.logger.debug(f"getting vehicle {vehicle} failed with error {e}")
|
app.logger.debug(f"creating vehicle with name {name} failed with error {e}")
|
||||||
return "error" + " " + str(e), 500
|
return "error" + " " + str(e), 500
|
||||||
|
case "PUT":
|
||||||
else:
|
pass
|
||||||
|
case "DELETE":
|
||||||
try:
|
pass
|
||||||
foundVehicles = vehicleHandler.getVehicles()
|
|
||||||
return foundVehicles, 200
|
|
||||||
except Exception as e:
|
|
||||||
app.logger.debug(f"getting all vehicles failed with error {e}")
|
|
||||||
return "error" + " " + str(e), 500
|
|
||||||
|
|
||||||
elif request.method == "POST":
|
|
||||||
data = request.get_json()
|
|
||||||
app.logger.debug(f"json request payload: {data}")
|
|
||||||
|
|
||||||
if "name" not in data:
|
|
||||||
return "missing name", 400
|
|
||||||
|
|
||||||
licenseplate = ""
|
|
||||||
|
|
||||||
if "licensePlate" not in data:
|
|
||||||
licenseplate = "N/A"
|
|
||||||
else:
|
|
||||||
licenseplate = data["licensePlate"]
|
|
||||||
name = data["name"]
|
|
||||||
|
|
||||||
# handle creating vehicle
|
|
||||||
try:
|
|
||||||
vehicle = vehicleHandler.createVehicle(name, licenseplate)
|
|
||||||
return jsonify({"id": vehicle.id, "name": vehicle.name}), 200
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
app.logger.debug(f"creating vehicle with name {name} failed with error {e}")
|
|
||||||
return "error" + " " + str(e), 500
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/upload', methods=['POST'])
|
@app.route('/upload', methods=['POST'])
|
||||||
@ -231,29 +249,29 @@ def uploadFile():
|
|||||||
return "no file selected", 400
|
return "no file selected", 400
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
app.logger.debug(f"Received file: {file.filename}, size: {len(file.read())} bytes")
|
app.logger.debug(f"Received file: {file.filename}, size: {len(file.read())} bytes")
|
||||||
file.seek(0) # Setzt den Datei-Zeiger zurück, nachdem die Größe abgerufen wurde.
|
|
||||||
|
file.seek(0)
|
||||||
|
|
||||||
file_path = f'./uploads/{file.filename}'
|
file_path = f'./uploads/{file.filename}'
|
||||||
with open(file_path, 'wb') as f:
|
with open(file_path, 'wb') as f:
|
||||||
f.write(file.read())
|
f.write(file.read())
|
||||||
|
|
||||||
driverID = int(request.form.get('driverID'))
|
driverID = int(request.form.get('driverID'))
|
||||||
vehicleID = int(request.form.get('vehicleID'))
|
vehicleID = int(request.form.get('vehicleID'))
|
||||||
|
|
||||||
driver = driverHandler.getDriver(driverID)
|
driver = driverHandler.getDriver(driverID)
|
||||||
vehicle = vehicleHandler.getVehicle(vehicleID)
|
vehicle = vehicleHandler.getVehicle(vehicleID)
|
||||||
|
|
||||||
app.logger.debug(f"driver {driver.id}")
|
app.logger.debug(f"driver {driver.id}")
|
||||||
app.logger.debug(f"vehicle {vehicle.id}")
|
app.logger.debug(f"vehicle {vehicle.id}")
|
||||||
|
|
||||||
if not driver or not vehicle:
|
if not driver or not vehicle:
|
||||||
raise ValueError("Driver or vehicle not found")
|
raise ValueError("Driver or vehicle not found")
|
||||||
|
|
||||||
app.logger.debug(f"attempting to parse file: {file.filename}")
|
app.logger.debug(f"attempting to parse file: {file.filename}")
|
||||||
gpxHandler.parse(file.filename, driver, vehicle)
|
gpxHandler.parse(file.filename, driver, vehicle)
|
||||||
|
|
||||||
return "file stored succesfull", 200
|
return "file stored succesfull", 200
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
app.logger.debug(f"storing gpx file failed with error {e}")
|
app.logger.debug(f"storing gpx file failed with error {e}")
|
||||||
|
@ -1,214 +1,244 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, SetupContext, ref, Ref } from 'vue';
|
import { defineComponent, SetupContext, ref, Ref } from 'vue';
|
||||||
import GetLocalizedText from "../classes/language";
|
import GetLocalizedText from "../classes/language";
|
||||||
|
import Message from "./message.vue";
|
||||||
|
|
||||||
type driver = {
|
type driver = {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type vehicle = {
|
type vehicle = {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
emits: ['close', 'response'],
|
emits: ['close', 'response'],
|
||||||
name: 'settings',
|
components: { Message },
|
||||||
props: ["drivers"],
|
name: 'settings',
|
||||||
setup(props, { emit }: SetupContext) {
|
props: ["drivers"],
|
||||||
|
setup(props, { emit }: SetupContext) {
|
||||||
|
|
||||||
const file = ref<File | null>();
|
const file = ref<File | null>();
|
||||||
const form = ref<HTMLFormElement>();
|
const form = ref<HTMLFormElement>();
|
||||||
const drivers: Ref<driver[]> = ref([])
|
const drivers: Ref<driver[]> = ref([])
|
||||||
const vehicles: Ref<vehicle[]> = ref([])
|
const vehicles: Ref<vehicle[]> = ref([])
|
||||||
const selectedDriverID: Ref<number> = ref(0);
|
const selectedDriverID: Ref<number> = ref(0);
|
||||||
const selectedVehicleID: Ref<number> = ref(0);
|
const selectedVehicleID: Ref<number> = ref(0);
|
||||||
const selectedDriverName: Ref<String> = ref("N/A");
|
const selectedDriverName: Ref<String> = ref("N/A");
|
||||||
const selectedVehicleName: Ref<String> = ref("N/A");
|
const selectedVehicleName: Ref<String> = ref("N/A");
|
||||||
|
|
||||||
props.drivers.forEach((d: driver) => {
|
// button text
|
||||||
drivers.value.push({ id: d.id, name: d.name })
|
const buttonText: Ref<string> = ref('Upload');
|
||||||
});
|
|
||||||
|
|
||||||
// localized text
|
// values for UI Information distribution
|
||||||
// if there is time left this gets moved out to its own class
|
const messageType: Ref<string> = ref("None ");
|
||||||
var localizedUploadHeader: Ref<string> = ref("")
|
const message:Ref<string> = ref("");
|
||||||
async function getLocalization() {
|
|
||||||
localizedUploadHeader.value = await GetLocalizedText("localizedUploadHeader")
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileInputChange = async ($event: Event) => {
|
props.drivers.forEach((d: driver) => {
|
||||||
const target = $event.target as HTMLInputElement;
|
drivers.value.push({ id: d.id, name: d.name })
|
||||||
if (target && target.files) {
|
});
|
||||||
file.value = target.files[0];
|
|
||||||
console.log(`selected file: ${file.value}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handles sending webrequests to the backend
|
// localized text
|
||||||
const getDrivers = async () => {
|
// if there is time left this gets moved out to its own class
|
||||||
|
var localizedUploadHeader: Ref<string> = ref("")
|
||||||
|
async function getLocalization() {
|
||||||
|
localizedUploadHeader.value = await GetLocalizedText("localizedUploadHeader")
|
||||||
|
}
|
||||||
|
|
||||||
const headers: Headers = new Headers()
|
var fileInputChange = async ($event: Event) => {
|
||||||
|
const target = $event.target as HTMLInputElement;
|
||||||
|
if (target && target.files) {
|
||||||
|
file.value = target.files[0];
|
||||||
|
console.log(`selected file: ${file.value}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
headers.set('Content-Type', 'application/json')
|
// handles sending webrequests to the backend
|
||||||
headers.set('Accept', 'application/json')
|
const getDrivers = async () => {
|
||||||
|
|
||||||
const request: RequestInfo = new Request("http://localhost:5000/driver", {
|
const headers: Headers = new Headers()
|
||||||
method: "GET",
|
|
||||||
headers: headers
|
|
||||||
})
|
|
||||||
|
|
||||||
var response = await fetch(request)
|
headers.set('Content-Type', 'application/json')
|
||||||
|
headers.set('Accept', 'application/json')
|
||||||
|
|
||||||
// make sure the request was successfull
|
const request: RequestInfo = new Request("http://localhost:5000/driver", {
|
||||||
if (response.ok) {
|
method: "GET",
|
||||||
|
headers: headers
|
||||||
|
})
|
||||||
|
|
||||||
var jsonBody = await response.json()
|
var response = await fetch(request)
|
||||||
|
|
||||||
// convert vehicles from json response to processable data
|
// make sure the request was successfull
|
||||||
for (let i = 0; i < jsonBody.length; i++) {
|
if (response.ok) {
|
||||||
drivers.value.push({ id: jsonBody[i]["id"], name: jsonBody[i]["name"] })
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log(await response.text())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handles getting all existing drivers
|
var jsonBody = await response.json()
|
||||||
const getVehicles = async () => {
|
|
||||||
const headers: Headers = new Headers()
|
|
||||||
headers.set('Content-Type', 'application/json')
|
|
||||||
headers.set('Accept', 'application/json')
|
|
||||||
|
|
||||||
const request: RequestInfo = new Request("http://localhost:5000/vehicle", {
|
// convert vehicles from json response to processable data
|
||||||
method: "GET",
|
for (let i = 0; i < jsonBody.length; i++) {
|
||||||
headers: headers
|
drivers.value.push({ id: jsonBody[i]["id"], name: jsonBody[i]["name"] })
|
||||||
})
|
}
|
||||||
|
} else {
|
||||||
|
console.log(await response.text())
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `upload failed: ${await response.statusText}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var response = await fetch(request)
|
// handles getting all existing drivers
|
||||||
// make sure the request was successfull
|
const getVehicles = async () => {
|
||||||
if (response.ok) {
|
const headers: Headers = new Headers()
|
||||||
var jsonBody = await response.json()
|
headers.set('Content-Type', 'application/json')
|
||||||
|
headers.set('Accept', 'application/json')
|
||||||
|
|
||||||
// convert vehicles from json response to processable data
|
const request: RequestInfo = new Request("http://localhost:5000/vehicle", {
|
||||||
for (let i = 0; i < jsonBody.length; i++) {
|
method: "GET",
|
||||||
vehicles.value.push({ id: jsonBody[i]["id"], name: jsonBody[i]["name"] })
|
headers: headers
|
||||||
}
|
})
|
||||||
} else {
|
|
||||||
console.log(await response.text())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var save = async () => {
|
var response = await fetch(request)
|
||||||
|
// make sure the request was successfull
|
||||||
|
if (response.ok) {
|
||||||
|
var jsonBody = await response.json()
|
||||||
|
|
||||||
if (!file.value) {
|
// convert vehicles from json response to processable data
|
||||||
alert("Bitte wählen Sie eine Datei aus, bevor Sie sie hochladen.");
|
for (let i = 0; i < jsonBody.length; i++) {
|
||||||
return;
|
vehicles.value.push({ id: jsonBody[i]["id"], name: jsonBody[i]["name"] })
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.log(await response.text())
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `upload failed: ${await response.text()}`;
|
||||||
|
buttonText.value = "Upload";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const formData = new FormData();
|
var save = async () => {
|
||||||
formData.append("file", file.value);
|
|
||||||
formData.append("driverID", selectedDriverID.value.toString());
|
|
||||||
formData.append("vehicleID", selectedVehicleID.value.toString());
|
|
||||||
|
|
||||||
try {
|
if (!file.value) {
|
||||||
|
messageType.value = "warning";
|
||||||
|
message.value = "please fill all values";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Request Body:', formData);
|
const formData = new FormData();
|
||||||
|
formData.append("file", file.value);
|
||||||
|
formData.append("driverID", selectedDriverID.value.toString());
|
||||||
|
formData.append("vehicleID", selectedVehicleID.value.toString());
|
||||||
|
|
||||||
const response = await fetch('http://localhost:5000/upload', {
|
buttonText.value = 'Loading <span class="loading loading-spinner loading-xs"></span>';
|
||||||
method: 'POST',
|
|
||||||
body: formData,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
try {
|
||||||
const result = await response.json();
|
|
||||||
emit("response", result);
|
|
||||||
alert("Datei erfolgreich hochgeladen!");
|
|
||||||
} else {
|
|
||||||
console.error('Fehler beim Hochladen:', response.statusText);
|
|
||||||
alert("Fehler beim Hochladen der Datei.");
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
console.log('Request Body:', formData);
|
||||||
console.error("upload failed:", error);
|
|
||||||
alert("failed to upload file.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
const response = await fetch('http://localhost:5000/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
});
|
||||||
|
|
||||||
getVehicles()
|
if (response.ok) {
|
||||||
getDrivers()
|
const result = await response.json();
|
||||||
getLocalization()
|
emit("response", result);
|
||||||
const close = () => {
|
messageType.value = "success";
|
||||||
emit("close");
|
message.value = `upload successfull`;
|
||||||
};
|
buttonText.value = "Upload";
|
||||||
|
} else {
|
||||||
|
console.error('upload failed: ', await response.statusText);
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `upload failed: ${await response.statusText}`;
|
||||||
|
buttonText.value = "Upload";
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `upload failed: ${error}`;
|
||||||
|
buttonText.value = "Upload";
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
}
|
||||||
close,
|
|
||||||
fileInputChange,
|
getVehicles()
|
||||||
selectedDriverID,
|
getDrivers()
|
||||||
selectedVehicleID,
|
getLocalization()
|
||||||
selectedDriverName,
|
const close = () => {
|
||||||
selectedVehicleName,
|
emit("close");
|
||||||
save,
|
};
|
||||||
drivers,
|
|
||||||
vehicles,
|
return {
|
||||||
localizedUploadHeader
|
close,
|
||||||
};
|
fileInputChange,
|
||||||
},
|
selectedDriverID,
|
||||||
|
selectedVehicleID,
|
||||||
|
selectedDriverName,
|
||||||
|
selectedVehicleName,
|
||||||
|
save,
|
||||||
|
drivers,
|
||||||
|
vehicles,
|
||||||
|
localizedUploadHeader,
|
||||||
|
buttonText,
|
||||||
|
messageType,
|
||||||
|
message
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="card bg-base-100 w-full shadow-xl" style="">
|
<div class="card bg-base-100 w-full shadow-xl" style="">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
<h2 class="card-title">File Upload</h2>
|
<h2 class="card-title">File Upload</h2>
|
||||||
|
<Message v-if="type=='none'" :type="messageType" :message="message" @close="message=''; messageType='None'"></Message>
|
||||||
<button class="btn btn-error close round" @click="close()">
|
<button class="btn btn-error close round" @click="close()">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
|
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px"
|
||||||
<path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z" />
|
fill="#e8eaed">
|
||||||
</svg>
|
<path
|
||||||
</button>
|
d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z" />
|
||||||
<label class="form-control w-full max-w-xs">
|
</svg>
|
||||||
<div class="label">
|
</button>
|
||||||
<span class="label-text">Upload a GPX File</span>
|
<label class="form-control w-full max-w-xs">
|
||||||
</div>
|
<div class="label">
|
||||||
<input type="file" ref="file" v-on:change="fileInputChange($event)"
|
<span class="label-text">Upload a GPX File</span>
|
||||||
class="file-input file-input-bordered w-full max-w-xs" />
|
</div>
|
||||||
</label>
|
<input type="file" ref="file" v-on:change="fileInputChange($event)"
|
||||||
<div class="dropdown dropdown-bottom">
|
class="file-input file-input-bordered w-full max-w-xs" />
|
||||||
select Driver: <div tabindex="0" role="button" class="btn m-1"> {{ selectedDriverName }}</div>
|
</label>
|
||||||
<ul tabindex="0" class="dropdown-content menu bg-base-100 rounded-box z-[1] w-52 p-2 shadow">
|
<div class="dropdown dropdown-bottom">
|
||||||
<li v-for="driver in drivers"><a v-on:click="selectedDriverID = driver.id; selectedDriverName=driver.name">{{ driver.name }}</a></li>
|
select Driver: <div tabindex="0" role="button" class="btn m-1"> {{ selectedDriverName }}</div>
|
||||||
</ul>
|
<ul tabindex="0" class="dropdown-content menu bg-base-100 rounded-box z-[1] w-52 p-2 shadow">
|
||||||
</div>
|
<li v-for="driver in drivers"><a
|
||||||
<div class="dropdown dropdown-bottom">
|
v-on:click="selectedDriverID = driver.id; selectedDriverName = driver.name">{{ driver.name
|
||||||
select Vehicle: <div tabindex="0" role="button" class="btn m-1"> {{ selectedVehicleName }}</div>
|
}}</a></li>
|
||||||
<ul tabindex="0" class="dropdown-content menu bg-base-100 rounded-box z-[1] w-52 p-2 shadow">
|
</ul>
|
||||||
<li v-for="vehicle in vehicles"><a v-on:click="selectedVehicleID = vehicle.id; selectedVehicleName=vehicle.name">{{ vehicle.name }}</a></li>
|
</div>
|
||||||
</ul>
|
<div class="dropdown dropdown-bottom">
|
||||||
</div>
|
select Vehicle: <div tabindex="0" role="button" class="btn m-1"> {{ selectedVehicleName }}</div>
|
||||||
<button class="btn btn-success" v-on:click="save">Upload</button>
|
<ul tabindex="0" class="dropdown-content menu bg-base-100 rounded-box z-[1] w-52 p-2 shadow">
|
||||||
</div>
|
<li v-for="vehicle in vehicles"><a
|
||||||
</div>
|
v-on:click="selectedVehicleID = vehicle.id; selectedVehicleName = vehicle.name">{{
|
||||||
|
vehicle.name }}</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-success" v-on:click="save" v-html="buttonText"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.settingsBody {
|
.settingsBody {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin: 10% 10% 0 10%;
|
margin: 10% 10% 0 10%;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn.close {
|
.btn.close {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 30px;
|
right: 30px;
|
||||||
top: 30px;
|
top: 30px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -4,174 +4,203 @@ import "leaflet/dist/leaflet.css";
|
|||||||
import L from "leaflet";
|
import L from "leaflet";
|
||||||
|
|
||||||
type Track = {
|
type Track = {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
driver: string
|
driver: string
|
||||||
vehicle: {
|
vehicle: {
|
||||||
name: string
|
name: string
|
||||||
licenseplate: string
|
licenseplate: string
|
||||||
}
|
}
|
||||||
distance: number
|
distance: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Map',
|
name: 'Map',
|
||||||
props: {
|
props: {
|
||||||
track: {
|
track: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
require: true,
|
require: true,
|
||||||
},
|
},
|
||||||
geoJsonData: {
|
geoJsonData: {
|
||||||
type: Object as PropType<any>,
|
type: Object as PropType<any>,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
multiple: {
|
multiple: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const mapDiv = ref<HTMLElement | null>(null); // ref to map container element
|
const mapDiv = ref<HTMLElement | null>(null); // ref to map container element
|
||||||
const mapInstance = ref<any>(null); // reference for the Leaflet map
|
const mapInstance = ref<any>(null); // reference for the Leaflet map
|
||||||
const track: Ref<Track> = ref({ id: 0, name: "N/A", driver: "N/A", vehicle: { name: "N/A", licenseplate: "N/A" }, distance: 0.0 })
|
const track: Ref<Track> = ref({ id: 0, name: "N/A", driver: "N/A", vehicle: { name: "N/A", licenseplate: "N/A" }, distance: 0.0 })
|
||||||
const multiple:Ref<boolean> = ref(props.multiple);
|
const multiple: Ref<boolean> = ref(props.multiple);
|
||||||
|
|
||||||
const initializeMap = () => {
|
// values for UI Information distribution
|
||||||
if (mapDiv.value) {
|
const messageType: Ref<string> = ref("None");
|
||||||
mapInstance.value = L.map(mapDiv.value, {
|
const message: Ref<string> = ref("");
|
||||||
center: [51.4819, 7.2162],
|
|
||||||
zoom: 13,
|
|
||||||
});
|
|
||||||
|
|
||||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {}).addTo(mapInstance.value);
|
const initializeMap = () => {
|
||||||
}
|
if (mapDiv.value) {
|
||||||
};
|
mapInstance.value = L.map(mapDiv.value, {
|
||||||
|
center: [51.4819, 7.2162],
|
||||||
|
zoom: 13,
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {}).addTo(mapInstance.value);
|
||||||
console.log(props.geoJsonData)
|
}
|
||||||
initializeMap();
|
};
|
||||||
});
|
|
||||||
|
|
||||||
const clearMap = () => {
|
onMounted(() => {
|
||||||
if (mapInstance.value) {
|
console.log(props.geoJsonData)
|
||||||
mapInstance.value.eachLayer((layer: any) => {
|
initializeMap();
|
||||||
if (!(layer instanceof L.TileLayer)) {
|
});
|
||||||
mapInstance.value.removeLayer(layer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getTrackMeta = async (id: number) => {
|
const clearMap = () => {
|
||||||
|
if (mapInstance.value) {
|
||||||
|
mapInstance.value.eachLayer((layer: any) => {
|
||||||
|
if (!(layer instanceof L.TileLayer)) {
|
||||||
|
mapInstance.value.removeLayer(layer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const headers: Headers = new Headers()
|
const getTrackMeta = async (id: number) => {
|
||||||
headers.set('Content-Type', 'application/json')
|
|
||||||
headers.set('Accept', 'application/json')
|
|
||||||
|
|
||||||
const request: RequestInfo = new Request(`http://localhost:5000/track/meta?id=${id}`, {
|
const headers: Headers = new Headers()
|
||||||
method: "GET",
|
headers.set('Content-Type', 'application/json')
|
||||||
headers: headers
|
headers.set('Accept', 'application/json')
|
||||||
})
|
|
||||||
|
|
||||||
var response = await fetch(request)
|
const request: RequestInfo = new Request(`http://localhost:5000/track/meta?id=${id}`, {
|
||||||
// make sure the request was successfull
|
method: "GET",
|
||||||
if (response.ok) {
|
headers: headers
|
||||||
var jsonBody = await response.json()
|
})
|
||||||
console.log(jsonBody)
|
|
||||||
track.value = {
|
|
||||||
id: jsonBody["id"],
|
|
||||||
name: jsonBody["name"],
|
|
||||||
driver: jsonBody["driver"]["name"],
|
|
||||||
vehicle: {
|
|
||||||
name: jsonBody["vehicle"]["name"],
|
|
||||||
licenseplate: jsonBody["vehicle"]["licenseplate"] ?? "N/A"
|
|
||||||
},
|
|
||||||
distance: jsonBody["distance"]
|
|
||||||
}
|
|
||||||
console.log(track.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(() => props.geoJsonData, (newData) => {
|
var response = await fetch(request)
|
||||||
if (newData) {
|
// make sure the request was successfull
|
||||||
console.log("loading GeoJSON:", newData);
|
if (response.ok) {
|
||||||
|
var jsonBody = await response.json()
|
||||||
|
console.log(jsonBody)
|
||||||
|
track.value = {
|
||||||
|
id: jsonBody["id"],
|
||||||
|
name: jsonBody["name"],
|
||||||
|
driver: jsonBody["driver"]["name"],
|
||||||
|
vehicle: {
|
||||||
|
name: jsonBody["vehicle"]["name"],
|
||||||
|
licenseplate: jsonBody["vehicle"]["licenseplate"] ?? "N/A"
|
||||||
|
},
|
||||||
|
distance: jsonBody["distance"]
|
||||||
|
}
|
||||||
|
console.log(track.value)
|
||||||
|
} else {
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `"failed to load track meta with error: ${await response.statusText}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mapInstance.value) {
|
watch(() => props.geoJsonData, (newData) => {
|
||||||
if (!props.multiple){
|
if (newData) {
|
||||||
clearMap();
|
console.log("loading GeoJSON:", newData);
|
||||||
}
|
|
||||||
|
|
||||||
var geoJsonLayer = L.geoJSON(newData).addTo(mapInstance.value);
|
if (mapInstance.value) {
|
||||||
|
if (!props.multiple) {
|
||||||
|
clearMap();
|
||||||
|
}
|
||||||
|
|
||||||
// pull meta data for for a single track
|
var geoJsonLayer = L.geoJSON(newData).addTo(mapInstance.value);
|
||||||
// function wont be called if multiple tracks are loaded
|
|
||||||
if (!props.multiple) {
|
|
||||||
getTrackMeta(props.track);
|
|
||||||
}
|
|
||||||
|
|
||||||
// move camera view according to loaded track
|
// pull meta data for for a single track
|
||||||
const bounds = geoJsonLayer.getBounds();
|
// function wont be called if multiple tracks are loaded
|
||||||
mapInstance.value.fitBounds(bounds);
|
if (!props.multiple) {
|
||||||
} else {
|
getTrackMeta(props.track);
|
||||||
console.error("Map or GeoJSON data not available.");
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
// move camera view according to loaded track
|
||||||
mapDiv,
|
const bounds = geoJsonLayer.getBounds();
|
||||||
multiple,
|
mapInstance.value.fitBounds(bounds);
|
||||||
track
|
} else {
|
||||||
};
|
console.error("Map or GeoJSON data not available.");
|
||||||
},
|
messageType.value = "error";
|
||||||
|
message.value = `"Map or GeoJSON data not available.`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
mapDiv,
|
||||||
|
multiple,
|
||||||
|
track,
|
||||||
|
message,
|
||||||
|
messageType
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div ref="mapDiv" style="width: 70vw; height: 75vh; overflow: hidden;"></div>
|
<Message v-if="type == 'none'" :type="messageType" :message="message" @close="message = ''; messageType = 'None'"></Message>
|
||||||
<br>
|
<div ref="mapDiv" style="width: 70vw; height: 75vh; overflow: hidden;"></div>
|
||||||
<div class="overflow-x-auto" style="width: 70vw;" v-if="!multiple">
|
<br>
|
||||||
<table class="table">
|
<div class="overflow-x-auto" style="width: 70vw;" v-if="!multiple">
|
||||||
<!-- head -->
|
<table class="table">
|
||||||
<thead>
|
<!-- head -->
|
||||||
<tr>
|
<thead>
|
||||||
<th>track name</th>
|
<tr>
|
||||||
<th>driver</th>
|
<th>track name</th>
|
||||||
<th>vehicle</th>
|
<th>driver</th>
|
||||||
<th>License Plate</th>
|
<th>vehicle</th>
|
||||||
<th>distance</th>
|
<th>License Plate</th>
|
||||||
</tr>
|
<th>distance</th>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody>
|
</thead>
|
||||||
<!-- row 1 -->
|
<tbody>
|
||||||
<tr class="bg-base-200">
|
<!-- row 1 -->
|
||||||
<th>{{ track.name }}</th>
|
<tr v-if="track.id == 0" class="bg-base-200">
|
||||||
<td>{{ track.driver }}</td>
|
<th>{{ track.name }}</th>
|
||||||
<td>{{ track.vehicle.name }}</td>
|
<td>
|
||||||
<td>{{ track.vehicle.licenseplate }}</td>
|
<div class="skeleton h-4 w-full"></div>
|
||||||
<td>{{ Math.round((track.distance / 1000) * 100) / 100 }}KM</td>
|
</td>
|
||||||
</tr>
|
<td>
|
||||||
</tbody>
|
<div class="skeleton h-4 w-full"></div>
|
||||||
</table>
|
</td>
|
||||||
</div>
|
<td>
|
||||||
|
<div class="skeleton h-4 w-full"></div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="skeleton h-4 w-full"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr v-if="track.id != 0" class="bg-base-200">
|
||||||
|
<th>{{ track.name }}</th>
|
||||||
|
<td>{{ track.driver }}</td>
|
||||||
|
<td>{{ track.vehicle.name }}</td>
|
||||||
|
<td>{{ track.vehicle.licenseplate }}</td>
|
||||||
|
<td>{{ Math.round((track.distance / 1000) * 100) / 100 }}KM</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
#mapDiv {
|
#mapDiv {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 70vh;
|
height: 70vh;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
46
web/src/components/message.vue
Normal file
46
web/src/components/message.vue
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, SetupContext, Ref, ref } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Navbar',
|
||||||
|
emits: ['close'],
|
||||||
|
props:["type", "message"],
|
||||||
|
setup(props, { emit }: SetupContext) {
|
||||||
|
|
||||||
|
const type:Ref<string> = ref(props.type);
|
||||||
|
const message:Ref<string> = ref(props.message);
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
emit("close");
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
close,
|
||||||
|
type,
|
||||||
|
message,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div v-if="type==='info'" role="alert" class="alert alert-info alert-soft">
|
||||||
|
<span>{{ message }}</span>
|
||||||
|
<button class="btn btn-soft btn-info" v-on:click="close">Close</button>
|
||||||
|
</div>
|
||||||
|
<div v-if="type==='success'" role="alert" class="alert alert-success alert-soft">
|
||||||
|
<span>{{ message }}</span>
|
||||||
|
<button class="btn btn-soft btn-success" v-on:click="close">Close</button>
|
||||||
|
</div>
|
||||||
|
<div v-if="type==='warning'" role="alert" class="alert alert-warning alert-soft">
|
||||||
|
<span>{{ message }}</span>
|
||||||
|
<button class="btn btn-soft btn-warning" v-on:click="close">Close</button>
|
||||||
|
</div>
|
||||||
|
<div v-if="type==='error'" role="alert" class="alert error alert-soft">
|
||||||
|
<span>{{ message }}</span>
|
||||||
|
<button class="btn btn-soft btn-error" v-on:click="close">Close</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
@ -13,7 +13,7 @@ type Route = {
|
|||||||
name: string;
|
name: string;
|
||||||
id: number;
|
id: number;
|
||||||
time: Date;
|
time: Date;
|
||||||
driver: {id:number, name:string}
|
driver: { id: number, name: string }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -21,12 +21,12 @@ export default defineComponent({
|
|||||||
emits: ['close', 'response'],
|
emits: ['close', 'response'],
|
||||||
name: 'settings',
|
name: 'settings',
|
||||||
props: {
|
props: {
|
||||||
routes: {
|
routes: {
|
||||||
type: Array as () => Route[],
|
type: Array as () => Route[],
|
||||||
default: () => [], // Standard: leeres Array
|
default: () => [], // Standard: leeres Array
|
||||||
required: true,
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
setup(props, { emit }: SetupContext) {
|
setup(props, { emit }: SetupContext) {
|
||||||
console.log(props)
|
console.log(props)
|
||||||
if (!props.routes || props.routes.length <= 0) alert("no points to show");
|
if (!props.routes || props.routes.length <= 0) alert("no points to show");
|
||||||
@ -37,8 +37,12 @@ export default defineComponent({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const legend = ref<Record<string, string>>({});
|
const legend = ref<Record<string, string>>({});
|
||||||
const driverColors = ref<Record<string, string>>({});
|
const driverColors = ref<Record<string, string>>({});
|
||||||
var drivers:driver[] = [];
|
var drivers: driver[] = [];
|
||||||
const points:Route[] = props.routes;
|
const points: Route[] = props.routes;
|
||||||
|
|
||||||
|
// values for UI Information distribution
|
||||||
|
const messageType: Ref<string> = ref("None");
|
||||||
|
const message: Ref<string> = ref("");
|
||||||
|
|
||||||
// handles sending webrequests to the backend
|
// handles sending webrequests to the backend
|
||||||
const getDrivers = async () => {
|
const getDrivers = async () => {
|
||||||
@ -72,18 +76,20 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(await response.text())
|
console.log(await response.text())
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `failed to get drivers with error: ${await response.statusText}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// assigns a driver to a point based on the points driver id
|
// assigns a driver to a point based on the points driver id
|
||||||
const assignDriverToPoint = (points:Route[]) => {
|
const assignDriverToPoint = (points: Route[]) => {
|
||||||
return points.reduce((acc, point) => {
|
return points.reduce((acc, point) => {
|
||||||
|
|
||||||
const driverId = point.driver.id;
|
const driverId = point.driver.id;
|
||||||
console.log(`driverid: ${driverId}`)
|
console.log(`driverid: ${driverId}`)
|
||||||
acc[driverId] = acc[driverId] || [];
|
acc[driverId] = acc[driverId] || [];
|
||||||
acc[driverId].push(point);
|
acc[driverId].push(point);
|
||||||
return acc;
|
return acc;
|
||||||
}, {} as Record<number, Route[]>);
|
}, {} as Record<number, Route[]>);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,13 +103,13 @@ export default defineComponent({
|
|||||||
console.log(`routes: ${props.routes}`)
|
console.log(`routes: ${props.routes}`)
|
||||||
|
|
||||||
const scene = new THREE.Scene();
|
const scene = new THREE.Scene();
|
||||||
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
|
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||||
const renderer = new THREE.WebGLRenderer({ canvas: canvasRef.value, antialias: true, });
|
const renderer = new THREE.WebGLRenderer({ canvas: canvasRef.value, antialias: true, });
|
||||||
|
|
||||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
const controls = new OrbitControls(camera, renderer.domElement);
|
const controls = new OrbitControls(camera, renderer.domElement);
|
||||||
const raycaster = new THREE.Raycaster();
|
const raycaster = new THREE.Raycaster();
|
||||||
const mouse = new THREE.Vector2();
|
const mouse = new THREE.Vector2();
|
||||||
|
|
||||||
const groupedPoints = assignDriverToPoint(points)
|
const groupedPoints = assignDriverToPoint(points)
|
||||||
|
|
||||||
@ -112,11 +118,9 @@ export default defineComponent({
|
|||||||
const colors: number[] = [];
|
const colors: number[] = [];
|
||||||
|
|
||||||
const totalPoints = points.length;
|
const totalPoints = points.length;
|
||||||
const offsetXStep = 2; // Wir setzen den Abstand pro Gruppe
|
const offsetXStep = 2;
|
||||||
|
|
||||||
let offsetX = 0;
|
let offsetX = 0;
|
||||||
|
|
||||||
// Berechnungen für den Mittelpunkt der Punktwolke
|
|
||||||
let sumX = 0, sumY = 0, sumZ = 0;
|
let sumX = 0, sumY = 0, sumZ = 0;
|
||||||
|
|
||||||
const getColorForDriver = (driverId: number) => {
|
const getColorForDriver = (driverId: number) => {
|
||||||
@ -128,7 +132,12 @@ export default defineComponent({
|
|||||||
return color;
|
return color;
|
||||||
};
|
};
|
||||||
|
|
||||||
// complicated math things
|
/**
|
||||||
|
* complicated math things (i am scared of this part)
|
||||||
|
*
|
||||||
|
* calculates a points position and ensures that all points grouped by the same driver are placed together
|
||||||
|
* a point is a uploaded track and during this step it gets applied its color material which was generated whiles getting drivers
|
||||||
|
*/
|
||||||
Object.entries(groupedPoints).forEach(([driverIdStr, driverPoints], index) => {
|
Object.entries(groupedPoints).forEach(([driverIdStr, driverPoints], index) => {
|
||||||
const driverId = parseInt(driverIdStr, 10);
|
const driverId = parseInt(driverIdStr, 10);
|
||||||
console.log("Driver Colors:", driverColors.value[driverIdStr]);
|
console.log("Driver Colors:", driverColors.value[driverIdStr]);
|
||||||
@ -137,7 +146,7 @@ export default defineComponent({
|
|||||||
console.error(`Missing color for Driver ID: ${driverId}`);
|
console.error(`Missing color for Driver ID: ${driverId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const color = new THREE.Color(driverColors.value[driverId]);
|
const color = new THREE.Color(driverColors.value[driverId]);
|
||||||
console.log(`Color for Driver ${driverId}:`, driverColors.value[driverId]);
|
console.log(`Color for Driver ${driverId}:`, driverColors.value[driverId]);
|
||||||
|
|
||||||
// calculate offset base on driverid
|
// calculate offset base on driverid
|
||||||
@ -158,8 +167,8 @@ export default defineComponent({
|
|||||||
colors.push(color.r, color.g, color.b);
|
colors.push(color.r, color.g, color.b);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mittelpunkt der Punktwolke berechnen
|
// calculate clouds centerpoint
|
||||||
const centerX = sumX / totalPoints;
|
const centerX = sumX / totalPoints;
|
||||||
const centerY = sumY / totalPoints;
|
const centerY = sumY / totalPoints;
|
||||||
const centerZ = sumZ / totalPoints;
|
const centerZ = sumZ / totalPoints;
|
||||||
@ -194,7 +203,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
animate();
|
animate();
|
||||||
|
|
||||||
// handles mouse actions
|
/**
|
||||||
|
* handles mouse events and moves 3D space
|
||||||
|
* @param event the event triggered when the mouse is moved inside the canvas
|
||||||
|
*/
|
||||||
const onMouseMove = (event: MouseEvent) => {
|
const onMouseMove = (event: MouseEvent) => {
|
||||||
if (!canvasRef.value || !tooltipRef.value) return;
|
if (!canvasRef.value || !tooltipRef.value) return;
|
||||||
|
|
||||||
@ -211,22 +223,24 @@ export default defineComponent({
|
|||||||
|
|
||||||
tooltipRef.value.style.display = "block";
|
tooltipRef.value.style.display = "block";
|
||||||
|
|
||||||
// 3D-Koordinaten des Punktes holen
|
|
||||||
|
/**
|
||||||
|
* getting coordinates and calculating 2D coordinates from them
|
||||||
|
* this is done for the tooltip to be positions at the cursor
|
||||||
|
*/
|
||||||
const positionArray = pointCloud.geometry.attributes.position.array;
|
const positionArray = pointCloud.geometry.attributes.position.array;
|
||||||
const x = positionArray[intersectIndex * 3];
|
const x = positionArray[intersectIndex * 3];
|
||||||
const y = positionArray[intersectIndex * 3 + 1];
|
const y = positionArray[intersectIndex * 3 + 1];
|
||||||
const z = positionArray[intersectIndex * 3 + 2];
|
const z = positionArray[intersectIndex * 3 + 2];
|
||||||
|
|
||||||
// 3D-Koordinaten in 2D Bildschirmkoordinaten umrechnen
|
|
||||||
const screenPosition = new THREE.Vector3(x, y, z);
|
const screenPosition = new THREE.Vector3(x, y, z);
|
||||||
screenPosition.project(camera);
|
screenPosition.project(camera);
|
||||||
|
|
||||||
// Umrechnung von NDC (Normalized Device Coordinates) zu Pixeln
|
|
||||||
const tooltipX = (screenPosition.x * 0.5 + 0.5) * window.innerWidth;
|
const tooltipX = (screenPosition.x * 0.5 + 0.5) * window.innerWidth;
|
||||||
const tooltipY = (screenPosition.y * -0.5 + 0.5) * window.innerHeight;
|
const tooltipY = (screenPosition.y * -0.5 + 0.5) * window.innerHeight;
|
||||||
|
|
||||||
tooltipRef.value.style.left = `${tooltipX + 10}px`; // 10px Abstand zum Punkt
|
tooltipRef.value.style.left = `${tooltipX + 10}px`;
|
||||||
tooltipRef.value.style.top = `${tooltipY + 10}px`; // 10px Abstand zum Punkt
|
tooltipRef.value.style.top = `${tooltipY + 10}px`;
|
||||||
|
|
||||||
tooltipText.value = `${point.driver.name}: ${point.name} (${point.time.toLocaleString()})`;
|
tooltipText.value = `${point.driver.name}: ${point.name} (${point.time.toLocaleString()})`;
|
||||||
} else {
|
} else {
|
||||||
@ -250,6 +264,8 @@ export default defineComponent({
|
|||||||
tooltipText,
|
tooltipText,
|
||||||
legend,
|
legend,
|
||||||
driverColors,
|
driverColors,
|
||||||
|
message,
|
||||||
|
messageType
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -257,6 +273,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<Message v-if="type == 'none'" :type="messageType" :message="message" @close="message = ''; messageType = 'None'"></Message>
|
||||||
<div class="pointcloud-container relative">
|
<div class="pointcloud-container relative">
|
||||||
<canvas ref="canvasRef"></canvas>
|
<canvas ref="canvasRef"></canvas>
|
||||||
<div ref="tooltipRef" class="tooltip hidden fixed z-50 px-2 py-1 bg-base-200 text-base-content rounded">
|
<div ref="tooltipRef" class="tooltip hidden fixed z-50 px-2 py-1 bg-base-200 text-base-content rounded">
|
||||||
@ -264,7 +281,7 @@ export default defineComponent({
|
|||||||
</div>
|
</div>
|
||||||
<!-- Legende -->
|
<!-- Legende -->
|
||||||
<div class="legend absolute top-10 left-10 bg-base-200 p-4 rounded shadow-lg z-50">
|
<div class="legend absolute top-10 left-10 bg-base-200 p-4 rounded shadow-lg z-50">
|
||||||
<h3 class="font-bold mb-2">Fahrer Legende</h3>
|
<h3 class="font-bold mb-2">Drivers</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="(driverName, driverId) in legend" :key="driverId" class="flex items-center mb-1">
|
<li v-for="(driverName, driverId) in legend" :key="driverId" class="flex items-center mb-1">
|
||||||
<div class="w-4 h-4" :style="{ backgroundColor: driverColors[driverId] }"></div>
|
<div class="w-4 h-4" :style="{ backgroundColor: driverColors[driverId] }"></div>
|
||||||
@ -276,52 +293,52 @@ export default defineComponent({
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.pointcloud-container {
|
.pointcloud-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(90vh);
|
height: calc(90vh);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
.tooltip {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 50;
|
z-index: 50;
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
background-color: rgba(0, 0, 0, 0.7);
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.legend {
|
.legend {
|
||||||
width: auto;
|
width: auto;
|
||||||
max-width: 250px;
|
max-width: 250px;
|
||||||
background-color: rgba(0, 0, 0, 0.7);
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
color: white;
|
color: white;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.legend ul {
|
.legend ul {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.legend li {
|
.legend li {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.legend .color-box {
|
.legend .color-box {
|
||||||
width: 15px;
|
width: 15px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -13,6 +13,11 @@ export default defineComponent({
|
|||||||
const driverName: Ref<string> = ref("")
|
const driverName: Ref<string> = ref("")
|
||||||
const driverList: Ref<driver[]> = ref([])
|
const driverList: Ref<driver[]> = ref([])
|
||||||
|
|
||||||
|
// values for UI Information distribution
|
||||||
|
const messageType: Ref<string> = ref("");
|
||||||
|
const message: Ref<string> = ref("");
|
||||||
|
|
||||||
|
|
||||||
// handles sending webrequests to the backend
|
// handles sending webrequests to the backend
|
||||||
const getDrivers = async () => {
|
const getDrivers = async () => {
|
||||||
|
|
||||||
@ -39,6 +44,8 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(await response.text())
|
console.log(await response.text())
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `upload failed: ${response.text()}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +71,8 @@ export default defineComponent({
|
|||||||
driverList.value.push({ id: jsonBody["body"], name: driverName.value })
|
driverList.value.push({ id: jsonBody["body"], name: driverName.value })
|
||||||
} else {
|
} else {
|
||||||
console.log(await response.text())
|
console.log(await response.text())
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `upload failed: ${response.text()}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +80,9 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
createDriver,
|
createDriver,
|
||||||
driverName,
|
driverName,
|
||||||
driverList
|
driverList,
|
||||||
|
message,
|
||||||
|
messageType
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -79,6 +90,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<Message v-if="type == 'none'" :type="messageType" :message="message" @close="message = ''; messageType = 'None'"></Message>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<!-- head -->
|
<!-- head -->
|
||||||
@ -92,9 +104,18 @@ export default defineComponent({
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td><input type="text" placeholder="Driver Name" class="input input-bordered w-full max-w-xs"
|
<td><input type="text" placeholder="Driver Name" class="input input-bordered w-full" v-model="driverName" />
|
||||||
v-model="driverName" /></td>
|
</td>
|
||||||
<td><a class="btn btn-success" v-on:click="createDriver">Create Driver</a></td>
|
<td><a class="btn btn-success w-full" v-on:click="createDriver">Create Driver</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="driverList.length == 0">
|
||||||
|
<th>
|
||||||
|
<div class="skeleton h-4 w-full"></div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<div class="skeleton h-4 w-full"></div>
|
||||||
|
</td>
|
||||||
|
<td><a class="btn btn-error w-full" v-on:click="createVehicle">Delete Vehicle</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="driver in driverList">
|
<tr v-for="driver in driverList">
|
||||||
<th>{{ driver.id }}</th>
|
<th>{{ driver.id }}</th>
|
||||||
|
@ -5,6 +5,7 @@ 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';
|
||||||
|
|
||||||
type DriverType = {
|
type DriverType = {
|
||||||
id: number
|
id: number
|
||||||
@ -37,7 +38,7 @@ type GeoJSON = {
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'map',
|
name: 'map',
|
||||||
components: { PointCloud, VueDatePicker, Map, FileUpload },
|
components: { PointCloud, VueDatePicker, Map, FileUpload, Message },
|
||||||
setup(_, { emit }: SetupContext) {
|
setup(_, { emit }: SetupContext) {
|
||||||
const showMap: Ref<boolean> = ref(false);
|
const showMap: Ref<boolean> = ref(false);
|
||||||
const showCloud: Ref<boolean> = ref(false);
|
const showCloud: Ref<boolean> = ref(false);
|
||||||
@ -52,6 +53,10 @@ export default defineComponent({
|
|||||||
const multipleTracks: Ref<Boolean> = ref(false);
|
const multipleTracks: Ref<Boolean> = ref(false);
|
||||||
const trackid: Ref<number> = ref(0)
|
const trackid: Ref<number> = ref(0)
|
||||||
|
|
||||||
|
// values for UI Information distribution
|
||||||
|
const messageType: Ref<string> = ref("");
|
||||||
|
const message: Ref<string> = ref("");
|
||||||
|
|
||||||
const loadTrack = async (id: number) => {
|
const loadTrack = async (id: number) => {
|
||||||
showMap.value = true;
|
showMap.value = true;
|
||||||
showCloud.value = false;
|
showCloud.value = false;
|
||||||
@ -75,12 +80,15 @@ export default defineComponent({
|
|||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
// Wenn die Antwort OK ist, die Daten verarbeiten
|
// Wenn die Antwort OK ist, die Daten verarbeiten
|
||||||
mapData.value = await response.json();
|
mapData.value = await response.json();
|
||||||
console.log("GeoJSON-Daten erfolgreich geladen", mapData.value);
|
|
||||||
} else {
|
} else {
|
||||||
console.log(await response.text());
|
console.log(await response.text());
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `loading tracks failed: ${await response.text()}`;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Fehler beim Laden der Track-Daten:", error);
|
console.error("loading tracks failed with error:", error);
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `loading tracks failed with error: ${error}`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -106,6 +114,8 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(await response.text())
|
console.log(await response.text())
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `loading track list failed with error: ${error}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +131,8 @@ export default defineComponent({
|
|||||||
multipleTracks.value = false;
|
multipleTracks.value = false;
|
||||||
|
|
||||||
if (startSearchDate.value == null || endSearchDate.value == null) {
|
if (startSearchDate.value == null || endSearchDate.value == null) {
|
||||||
alert("please give all required infos")
|
messageType.value = "error";
|
||||||
|
message.value = "please give all required infos";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +166,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.log(await response.text())
|
console.log(await response.text())
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `searching tracks failed: ${await response.text()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (renderSearchOnMap.value) {
|
if (renderSearchOnMap.value) {
|
||||||
@ -188,6 +201,8 @@ export default defineComponent({
|
|||||||
showUpload,
|
showUpload,
|
||||||
multipleTracks,
|
multipleTracks,
|
||||||
trackid,
|
trackid,
|
||||||
|
message,
|
||||||
|
messageType
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -195,6 +210,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<Message v-if="type == 'none'" :type="messageType" :message="message" @close="message = ''; messageType = 'None'"></Message>
|
||||||
<FileUpload v-if="showUpload" @close="showUpload = false;" :drivers="[]"
|
<FileUpload v-if="showUpload" @close="showUpload = false;" :drivers="[]"
|
||||||
style="position:absolute; top: 30VH; width: 80%;"></FileUpload>
|
style="position:absolute; top: 30VH; width: 80%;"></FileUpload>
|
||||||
<div class="grid grid-flow-col auto-cols-max gap-4">
|
<div class="grid grid-flow-col auto-cols-max gap-4">
|
||||||
@ -207,6 +223,9 @@ export default defineComponent({
|
|||||||
<li>
|
<li>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
</li>
|
</li>
|
||||||
|
<li v-if="tracks.length == 0">
|
||||||
|
<div class="skeleton h-4 w-full"></div>
|
||||||
|
</li>
|
||||||
<li v-for="track in tracks"> <a v-on:click="loadTrack(track.id); multipleTracks = false;"> {{ track.name }} </a>
|
<li v-for="track in tracks"> <a v-on:click="loadTrack(track.id); multipleTracks = false;"> {{ track.name }} </a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -217,11 +236,11 @@ export default defineComponent({
|
|||||||
<div v-if="!showMap && !showCloud && search" style="margin-left: 20%; display:flex;">
|
<div v-if="!showMap && !showCloud && search" style="margin-left: 20%; display:flex;">
|
||||||
<div>
|
<div>
|
||||||
start time
|
start time
|
||||||
<input class="datepicker" type="date" id="birthday" name="birthday" v-model="startSearchDate">
|
<input class="datepicker" type="date" id="startdate" name="startdate" v-model="startSearchDate">
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-left: 5%;">
|
<div style="margin-left: 5%;">
|
||||||
end time
|
end time
|
||||||
<input class="datepicker" type="date" id="birthday" name="birthday" v-model="endSearchDate">
|
<input class="datepicker" type="date" id="enddate" name="enddate" v-model="endSearchDate">
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-left: 5%;">
|
<div style="margin-left: 5%;">
|
||||||
show on map:
|
show on map:
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {defineComponent, Ref, ref, SetupContext} from 'vue';
|
import { defineComponent, Ref, ref, SetupContext } from 'vue';
|
||||||
|
|
||||||
type vehicle = {
|
type vehicle = {
|
||||||
id:number
|
id: number
|
||||||
name:string
|
name: string
|
||||||
licenseplate: string
|
licenseplate: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11,9 +11,13 @@ export default defineComponent({
|
|||||||
name: 'map',
|
name: 'map',
|
||||||
setup(_, { emit }: SetupContext) {
|
setup(_, { emit }: SetupContext) {
|
||||||
|
|
||||||
const vehicleName:Ref<string> = ref("")
|
const vehicleName: Ref<string> = ref("")
|
||||||
const licensePlate:Ref<string> = ref("")
|
const licensePlate: Ref<string> = ref("")
|
||||||
const vehicleList:Ref<vehicle[]> = ref([])
|
const vehicleList: Ref<vehicle[]> = ref([])
|
||||||
|
|
||||||
|
// values for UI Information distribution
|
||||||
|
const messageType: Ref<string> = ref("");
|
||||||
|
const message: Ref<string> = ref("");
|
||||||
|
|
||||||
// handles getting all existing drivers
|
// handles getting all existing drivers
|
||||||
const getVehicles = async () => {
|
const getVehicles = async () => {
|
||||||
@ -22,27 +26,29 @@ export default defineComponent({
|
|||||||
headers.set('Accept', 'application/json')
|
headers.set('Accept', 'application/json')
|
||||||
|
|
||||||
const request: RequestInfo = new Request("http://localhost:5000/vehicle", {
|
const request: RequestInfo = new Request("http://localhost:5000/vehicle", {
|
||||||
method:"GET",
|
method: "GET",
|
||||||
headers:headers
|
headers: headers
|
||||||
})
|
})
|
||||||
|
|
||||||
var response = await fetch(request)
|
var response = await fetch(request)
|
||||||
// make sure the request was successfull
|
// make sure the request was successfull
|
||||||
if (response.ok){
|
if (response.ok) {
|
||||||
var jsonBody = await response.json()
|
var jsonBody = await response.json()
|
||||||
|
|
||||||
// convert vehicles from json response to processable data
|
// convert vehicles from json response to processable data
|
||||||
for(let i = 0; i < jsonBody.length; i++) {
|
for (let i = 0; i < jsonBody.length; i++) {
|
||||||
let plate = "N/A"
|
let plate = "N/A"
|
||||||
let vehicle = jsonBody[i]
|
let vehicle = jsonBody[i]
|
||||||
if (vehicle["licensePlate"] != undefined) {
|
if (vehicle["licensePlate"] != undefined) {
|
||||||
plate = vehicle["licensePlate"];
|
plate = vehicle["licensePlate"];
|
||||||
}
|
}
|
||||||
|
|
||||||
vehicleList.value.push({id: vehicle["id"], name: vehicle["name"], licenseplate: plate})
|
vehicleList.value.push({ id: vehicle["id"], name: vehicle["name"], licenseplate: plate })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(await response.text())
|
console.log(await response.text())
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `loading vehicles failed with error: ${await response.text()}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,27 +62,31 @@ export default defineComponent({
|
|||||||
const requestBody = JSON.stringify({ name: vehicleName.value, licensePlate: licensePlate.value });
|
const requestBody = JSON.stringify({ name: vehicleName.value, licensePlate: licensePlate.value });
|
||||||
|
|
||||||
const request: RequestInfo = new Request("http://localhost:5000/vehicle", {
|
const request: RequestInfo = new Request("http://localhost:5000/vehicle", {
|
||||||
method:"POST",
|
method: "POST",
|
||||||
headers:headers,
|
headers: headers,
|
||||||
body: requestBody
|
body: requestBody
|
||||||
})
|
})
|
||||||
|
|
||||||
var response = await fetch(request)
|
var response = await fetch(request)
|
||||||
// make sure the request was successfull
|
// make sure the request was successfull
|
||||||
if (response.ok){
|
if (response.ok) {
|
||||||
var jsonBody = await response.json()
|
var jsonBody = await response.json()
|
||||||
vehicleList.value.push({id: jsonBody["body"], name: vehicleName.value, licenseplate: "N/A"})
|
vehicleList.value.push({ id: jsonBody["body"], name: vehicleName.value, licenseplate: "N/A" })
|
||||||
} else {
|
} else {
|
||||||
console.log(await response.text())
|
console.log(await response.text())
|
||||||
|
messageType.value = "error";
|
||||||
|
message.value = `creating vehicle failed with error: ${error}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getVehicles()
|
getVehicles()
|
||||||
return {
|
return {
|
||||||
createVehicle,
|
createVehicle,
|
||||||
vehicleName,
|
vehicleName,
|
||||||
licensePlate,
|
licensePlate,
|
||||||
vehicleList
|
vehicleList,
|
||||||
|
message,
|
||||||
|
messageType
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -84,6 +94,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<Message v-if="type == 'none'" :type="messageType" :message="message" @close="message = ''; messageType = 'None'"></Message>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<!-- head -->
|
<!-- head -->
|
||||||
@ -97,20 +108,34 @@ export default defineComponent({
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td><input type="text" placeholder="Vehicle Name" class="input input-bordered w-full max-w-xs" v-model="vehicleName"/></td>
|
<td><input type="text" placeholder="Vehicle Name" class="input input-bordered w-full "
|
||||||
<td><input type="text" placeholder="License Plate" class="input input-bordered w-full max-w-xs" v-model="licensePlate"/></td>
|
v-model="vehicleName" /></td>
|
||||||
<td><a class="btn btn-success" v-on:click="createVehicle">Create Vehicle</a></td>
|
<td><input type="text" placeholder="License Plate" class="input input-bordered w-full "
|
||||||
|
v-model="licensePlate" /></td>
|
||||||
|
<td><a class="btn btn-success w-full" v-on:click="createVehicle">Create Vehicle</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="vehicleList.length == 0">
|
||||||
|
<th>
|
||||||
|
<div class="skeleton h-4 w-full"></div>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<div class="skeleton h-4 w-full"></div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="skeleton h-4 w-full"></div>
|
||||||
|
</td>
|
||||||
|
<td><a class="btn btn-error w-full" v-on:click="createVehicle">Delete Vehicle</a></td>
|
||||||
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="vehicle in vehicleList">
|
<tr v-for="vehicle in vehicleList">
|
||||||
<th>{{ vehicle.id }}</th>
|
<th>{{ vehicle.id }}</th>
|
||||||
<td>{{ vehicle.name }}</td>
|
<td>{{ vehicle.name }}</td>
|
||||||
<td>{{ vehicle.licenseplate }}</td>
|
<td>{{ vehicle.licenseplate }}</td>
|
||||||
<td></td>
|
<td><a class="btn btn-error w-full" v-on:click="createVehicle">Delete Vehicle</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
</style>
|
|
@ -1 +1 @@
|
|||||||
{"root":["./theme-manager.config.ts","./vite.config.ts","./src/app.vue","./src/leatflet.d.ts","./src/main.ts","./src/vite-env.d.ts","./src/classes/debugger.ts","./src/classes/language.ts","./src/components/settings.vue","./src/components/cookieprompt.vue","./src/components/fileupload.vue","./src/components/map.vue","./src/components/navbar.vue","./src/components/pointcloud.vue","./src/views/driver.vue","./src/views/home.vue","./src/views/login.vue","./src/views/register.vue","./src/views/route.vue","./src/views/settings.vue","./src/views/vehicle.vue"],"version":"5.6.2"}
|
{"root":["./theme-manager.config.ts","./vite.config.ts","./src/app.vue","./src/leatflet.d.ts","./src/main.ts","./src/vite-env.d.ts","./src/classes/debugger.ts","./src/classes/language.ts","./src/components/settings.vue","./src/components/cookieprompt.vue","./src/components/fileupload.vue","./src/components/map.vue","./src/components/navbar.vue","./src/components/pointcloud.vue","./src/views/driver.vue","./src/views/home.vue","./src/views/login.vue","./src/views/register.vue","./src/views/route.vue","./src/views/settings.vue","./src/views/vehicle.vue"],"errors":true,"version":"5.6.2"}
|
Loading…
x
Reference in New Issue
Block a user