Zakladni vytvareni letu na zaklade planu
This commit is contained in:
@@ -30,6 +30,6 @@ const saveForm = () => {
|
||||
<template>
|
||||
<q-form @submit.prevent="saveForm" ref="form">
|
||||
<slot name="default"/>
|
||||
<FormSubmitButton v-if="saveButton" :save-button="saveButton"/>
|
||||
<FormSubmitButton v-if="saveButton" :save-button="saveButton" :is-request-pending="isRequestPending" />
|
||||
</q-form>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup>
|
||||
import {computed} from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
routeAdd: {
|
||||
type: Object,
|
||||
@@ -8,16 +10,44 @@ const props = defineProps({
|
||||
type: String,
|
||||
required: false,
|
||||
default: "Přidat"
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'info'
|
||||
}
|
||||
});
|
||||
|
||||
const bannerClass = computed(() => {
|
||||
const defaultClasses = 'bg-light-blue text-white';
|
||||
const classMap = {
|
||||
info: defaultClasses,
|
||||
warning: 'bg-orange text-white',
|
||||
error: 'bg-red text-white',
|
||||
}
|
||||
|
||||
return classMap[props.color] || defaultClasses;
|
||||
});
|
||||
|
||||
const icon = computed(() => {
|
||||
const iconsMap = {
|
||||
info: "info",
|
||||
warning: "warning",
|
||||
error: "error",
|
||||
}
|
||||
|
||||
return iconsMap[props.color];
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<q-banner class="bg-light-blue text-white">
|
||||
<template v-slot:avatar>
|
||||
<q-icon name="info"/>
|
||||
<q-banner :class=bannerClass>
|
||||
<template v-slot:avatar v-if="icon">
|
||||
<q-icon :name="icon"/>
|
||||
</template>
|
||||
|
||||
<slot/>
|
||||
|
||||
<template v-slot:action v-if="routeAdd">
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<script setup>
|
||||
import DatetimePicker from "components/inputs/DatetimePicker.vue";
|
||||
import {computed, reactive} from "vue";
|
||||
import {commonProps} from "src/composables/inputs";
|
||||
import FormWrapper from "components/FormWrapper.vue";
|
||||
import {useFlightPlanCalculations, useFlightPlanUtils} from "src/composables/flightPlan";
|
||||
|
||||
const props = defineProps({
|
||||
flightPlan: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const {getTotalDuration} = useFlightPlanCalculations();
|
||||
|
||||
const formData = reactive({
|
||||
gpxTrackFile: null,
|
||||
takeoffDatetime: props.flightPlan.plannedTakeoffDatetime,
|
||||
landingDatetime: new Date((new Date(props.flightPlan.plannedTakeoffDatetime)).getTime() + 60 * 1000 * getTotalDuration(props.flightPlan)),
|
||||
copyTrack: true,
|
||||
createPointsOfInterests: true,
|
||||
flightPlan: props.flightPlan,
|
||||
});
|
||||
|
||||
const {getMarkersFrom} = useFlightPlanUtils();
|
||||
|
||||
const hasGeocodeInTrack = computed(() => {
|
||||
return !!getMarkersFrom(props.flightPlan).find(point => point.type === 'geocode');
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormWrapper v-model="formData" :save-button="{label: 'Vytvořit let z plánu', icon: 'save'}">
|
||||
<template v-if="!formData.gpxTrackFile">
|
||||
<DatetimePicker v-model="formData.takeoffDatetime" label="Čas vzletu"/>
|
||||
<DatetimePicker v-model="formData.landingDatetime" label="Čas přistání"/>
|
||||
</template>
|
||||
|
||||
<q-file
|
||||
v-bind="commonProps"
|
||||
v-model="formData.gpxTrackFile"
|
||||
label="Trasa v GPX"
|
||||
hint="Z trasy se načtou letiště a časy vzletu a přistání. Tyto hodnoty je možné později upravit."
|
||||
/>
|
||||
|
||||
<q-checkbox
|
||||
v-model="formData.copyTrack"
|
||||
label="Zkopírovat otočné body (letiště a POI)?"
|
||||
/>
|
||||
</FormWrapper>
|
||||
</template>
|
||||
@@ -32,7 +32,7 @@ const emits = defineEmits(["markers-changed", "change-insert-position"]);
|
||||
|
||||
const {center} = useGeocode();
|
||||
|
||||
const {markerObject, googleMapsMarkerObject, editableNameTypes} = useFlightPlanObjects();
|
||||
const {markerObject, googleMapsMarkerObject, googleMapsCustomMarkerObject, editableNameTypes} = useFlightPlanObjects();
|
||||
const {getMarkersFrom} = useFlightPlanUtils();
|
||||
const {getDuration} = useFlightPlanCalculations();
|
||||
|
||||
@@ -54,8 +54,8 @@ const trackAids = computed(() => props.flightPlan.track.map(p => ({
|
||||
bearing: p.bearing,
|
||||
distance: p.distance,
|
||||
position: {
|
||||
lat: (p.from.gpsLatitude + p.to.gpsLatitude) / 2,
|
||||
lng: (p.from.gpsLongitude + p.to.gpsLongitude) / 2
|
||||
lat: (p.from.gpsLatitude + p.to?.gpsLatitude) / 2,
|
||||
lng: (p.from.gpsLongitude + p.to?.gpsLongitude) / 2
|
||||
}
|
||||
}
|
||||
)));
|
||||
@@ -92,6 +92,7 @@ const handleMarkerMove = async (idx, event) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<MapWrapper
|
||||
ref="mapWrap"
|
||||
style="width: 100%; height: 65vh; min-height: 500px"
|
||||
@@ -130,13 +131,41 @@ const handleMarkerMove = async (idx, event) => {
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template v-if="markers.length > 1">
|
||||
<CustomMarker :options="googleMapsCustomMarkerObject(markers[0], 'CENTER')" class="significant-airport">
|
||||
<q-icon name="flight_takeoff"/>
|
||||
</CustomMarker>
|
||||
|
||||
<CustomMarker :options="googleMapsCustomMarkerObject(markers[markers.length - 1], 'CENTER')" class="significant-airport">
|
||||
<q-icon name="flight_land"/>
|
||||
</CustomMarker>
|
||||
|
||||
</template>
|
||||
|
||||
<template #layersControlsEnd>
|
||||
<q-checkbox v-model="displayTrackAids" label="Zobrazovat navigaci po trase?"/>
|
||||
</template>
|
||||
</MapWrapper>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
<style lang="scss">
|
||||
.significant-airport {
|
||||
position: relative;
|
||||
z-index: 99999;
|
||||
text-align: center;
|
||||
margin-top: -40px;
|
||||
|
||||
.q-icon {
|
||||
color: white;
|
||||
background: #39b6e6;
|
||||
border: solid 1px black;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
font-size: 20px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.track-info {
|
||||
background: rgba(128, 128, 128, 0.5);
|
||||
color: white;
|
||||
|
||||
@@ -30,7 +30,6 @@ const swapMarkers = (idx1, idx2) => {
|
||||
model.value[idx2] = tmp;
|
||||
};
|
||||
const handlePlaceSelect = (modelVal) => {
|
||||
console.log(modelVal);
|
||||
model.value.push(modelVal);
|
||||
}
|
||||
|
||||
@@ -42,10 +41,9 @@ const {getIcon} = useFlightPlanUtils();
|
||||
const {editableNameTypes} = useFlightPlanObjects();
|
||||
|
||||
const allPlacesOptions = computed(() => {
|
||||
|
||||
const reportingPoints = props.airports.map(a => a.reportingPoints.map(r => ({...r, airport: a}))).flat()
|
||||
return [
|
||||
...props.pointsOfInterest.map(poi => ({...poi, type: "poi"})),
|
||||
...props.pointsOfInterest.map(poi => ({...poi, pointOfInterestId: poi.id, type: "poi"})),
|
||||
...reportingPoints.map(r => ({
|
||||
...r,
|
||||
name: `${r.airport.icaoCode}:${r.name}`,
|
||||
@@ -55,6 +53,7 @@ const allPlacesOptions = computed(() => {
|
||||
...airport,
|
||||
name: `${airport.icaoCode} - ${airport.name}`,
|
||||
type: "airport",
|
||||
airportId: airport.id,
|
||||
}))
|
||||
].map(i => ({...i, disabled: !i.gpsLatitude || !i.gpsLongitude}));
|
||||
});
|
||||
|
||||
@@ -104,7 +104,7 @@ const totalDistance = computed(() => getTotalDistance(props.flightPlan));
|
||||
<q-item-section>
|
||||
Celková vzdálenost: {{ totalDistance }} km
|
||||
<br>
|
||||
Plánovaná doba letu: {{ minutesToHumanReadable(getTotalDuration(props.flightPlan, props.flightPlan.plannedSpeed)) }}
|
||||
Plánovaná doba letu: {{ minutesToHumanReadable(getTotalDuration(props.flightPlan)) }}
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
|
||||
@@ -56,6 +56,5 @@ watch(() => props.flight, (newVal) => {
|
||||
:label="i === 1 ? 'Kopilot' : 'Pasažér'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</FormWrapper>
|
||||
</template>
|
||||
|
||||
@@ -30,6 +30,7 @@ const steps = [
|
||||
{name: "track", icon: "route", label: "Trasa"},
|
||||
{name: "photos", icon: "add_a_photo", label: "Fotky"},
|
||||
{name: "notes", icon: "edit_note", label: "Poznámky"},
|
||||
{name: "plan", icon: "pin_drop", label: "Plán"},
|
||||
];
|
||||
|
||||
const emit = defineEmits(["update:modelValue"])
|
||||
|
||||
@@ -50,9 +50,12 @@ const addPoint = () => {
|
||||
} else if (props.infoWindow.airport) {
|
||||
type = "airport";
|
||||
}
|
||||
|
||||
const point = props.infoWindow.marker || {
|
||||
name: title.value,
|
||||
type: type,
|
||||
airportId: props.infoWindow.airport?.id,
|
||||
pointOfInterestId: props.infoWindow.poi?.id,
|
||||
type,
|
||||
gpsLatitude: props.infoWindow.position.lat,
|
||||
gpsLongitude: props.infoWindow.position.lng
|
||||
}
|
||||
@@ -63,7 +66,6 @@ const addPoint = () => {
|
||||
const closeInfoWindow = () => {
|
||||
emits('close');
|
||||
isOpened.value = false;
|
||||
console.log("is opened? ", isOpened.value);
|
||||
}
|
||||
|
||||
const removePoint = () => {
|
||||
|
||||
@@ -180,6 +180,7 @@ defineExpose({
|
||||
});
|
||||
|
||||
const emitMapClick = (data) => {
|
||||
isControlsOpened.value = false;
|
||||
openInfoWindow(data);
|
||||
emits("map-click", data);
|
||||
}
|
||||
@@ -271,6 +272,7 @@ const isControlsOpened = ref(false);
|
||||
|
||||
<template v-for="airport in airportsOnMap" :key="airport.icaoCode">
|
||||
<CustomMarker
|
||||
style="position: relative; z-index: 100"
|
||||
:options="{position: {lat: airport.gpsLatitude, lng: airport.gpsLongitude}, anchorPoint: 'CENTER'}"
|
||||
@click.stop="handleAirportClick(airport)"
|
||||
>
|
||||
@@ -316,7 +318,7 @@ const isControlsOpened = ref(false);
|
||||
|
||||
<Polyline v-if="track" :options="track"/>
|
||||
|
||||
<CustomControl position="TOP" v-if="showLayerControls" style="width: auto; max-width: 200px">
|
||||
<CustomControl position="TOP_LEFT" v-if="showLayerControls" style="width: auto; max-width: 200px">
|
||||
<q-btn
|
||||
@click="isControlsOpened = !isControlsOpened"
|
||||
:icon="isControlsOpened ? 'layers_clear' : 'layers'"
|
||||
|
||||
Reference in New Issue
Block a user