Prace s mapu, zobrazeni GPX, editace kopilota, skeletony

This commit is contained in:
Michal Kváček
2023-08-07 23:22:28 +02:00
parent 09d2f25523
commit c4603cf090
55 changed files with 891 additions and 408 deletions
+12 -12
View File
@@ -1,6 +1,7 @@
<script setup>
import {flight} from "src/composables/objects/flight";
import {formatDatetime, minutesToHumanReadable} from "src/composables/datetimeUtils";
import WeatherInfo from "components/weather/WeatherInfo.vue";
const props = defineProps({
flight: {
@@ -20,7 +21,11 @@ const props = defineProps({
<q-icon name="flight_takeoff"/>
</q-item-section>
<q-item-section>
{{ flight.takeoffAirport.name }}
<div>
{{ flight.takeoffAirport.name }}
<WeatherInfo class="q-mx-sm" v-if="flight.takeoffWeatherInfo" :weather="flight.takeoffWeatherInfo"/>
</div>
</q-item-section>
</q-item>
@@ -38,7 +43,10 @@ const props = defineProps({
<q-icon name="flight_land"/>
</q-item-section>
<q-item-section>
{{ flight.landingAirport.name }}
<div>
{{ flight.landingAirport.name }}
<WeatherInfo class="q-mx-sm" v-if="flight.landingWeatherInfo" :weather="flight.landingWeatherInfo"/>
</div>
</q-item-section>
</q-item>
</q-list>
@@ -61,20 +69,12 @@ const props = defineProps({
{{ minutesToHumanReadable(flight.durationMinCalculated) }}
</q-item-section>
</q-item>
<q-item>
<q-item-section avatar>
<q-icon name="thermostat"/>
</q-item-section>
<q-item-section>
Clouds: few, Wind: 220/12kt, Temp: 12°C
</q-item-section>
</q-item>
<q-item v-if="!flight.solo">
<q-item v-if="flight.copilot">
<q-item-section avatar>
<q-icon name="people"/>
</q-item-section>
<q-item-section>
<router-link :to="{name: 'pilotDetail', params: {id: flight.copilot.id}}">
<router-link :to="{name: 'copilotDetail', params: {id: flight.copilot.id}}">
{{ flight.copilot.name }}
</router-link>
</q-item-section>
+27 -29
View File
@@ -15,34 +15,32 @@ const props = defineProps({
</script>
<template>
<div class="row">
<div class="col-12 col-md-6 col-lg-4" v-for="flight of items" :key="flight">
<q-list bordered separator class="q-mx-md q-my-md">
<q-item v-for="flight of items" :key="flight" ripple clickable :to="{name: 'flightDetail', params:{id: flight.id}}">
<q-item-section avatar>
<q-card class="q-my-sm q-mx-sm" >
<q-img :src="flight.coverPhoto.thumbnailUrl" v-if="flight.coverPhoto">
<div class="absolute-bottom text-center text-h6">
<router-link :to="{name: 'flightDetail', params:{id: flight.id}}" class="text-white">
{{ flightName(flight) }}
</router-link>
</div>
</q-img>
<q-card-section>
<div class="text-h6" v-if="!flight.coverPhoto">
<router-link :to="{name: 'flightDetail', params:{id: flight.id}}">
{{ flightName(flight) }}
</router-link>
</div>
<div class="text-subtitle2">{{ minutesToHumanReadable(flight.durationMinCalculated) }}</div>
<div class="text-secondary">
<q-icon name="today"/>
{{ formatDatetime(flight.takeoffDatetime) }}
</div>
<div class="text-secondary">
<q-icon name="plane"/>
{{ flight.aircraft.callSign }}
</div>
</q-card-section>
</q-card>
</div>
</div>
<q-avatar size="100px">
<div v-if="flight.coverPhoto" :style="`width: 100px; height: 100px; background-image: url('${flight.coverPhoto.thumbnailUrl}'); background-size: cover`"></div>
</q-avatar>
</q-item-section>
<q-item-section>
{{ flightName(flight) }}
<div class="text-secondary">
<q-icon name="flight_takeoff"/>
{{ formatDatetime(flight.takeoffDatetime) }}
</div>
<div class="text-secondary">
<q-icon name="schedule" />
{{ minutesToHumanReadable(flight.durationMinCalculated) }}
</div>
<div class="text-secondary">
<q-icon name="flight"/>
{{ flight.aircraft.callSign }}
</div>
</q-item-section>
</q-item>
</q-list>
</template>
+20 -1
View File
@@ -1,3 +1,22 @@
<script setup>
import {randomInt} from "src/composables/random";
</script>
<template>
Skeleton
<q-list bordered separator class="q-mx-md q-my-md">
<q-item v-for="i in randomInt(5, 10)" :key="i" ripple>
<q-item-section avatar>
<q-avatar size="100px">
<q-skeleton type="QAvatar" size="100px"></q-skeleton>
</q-avatar>
</q-item-section>
<q-item-section>
<q-skeleton :width="randomInt(30,50)+'%'"/>
<q-skeleton type="text" :width="randomInt(10,15)+'%'"/>
<q-skeleton type="text" :width="randomInt(5,10)+'%'"/>
<q-skeleton type="text" width="8%"/>
</q-item-section>
</q-item>
</q-list>
</template>
-52
View File
@@ -1,52 +0,0 @@
<script setup>
import {computed, onMounted, ref} from "vue";
import {setDefaultData} from "src/composables/form/formHandling";
import DialogWrapper from "components/DialogWrapper.vue";
import FormWrapper from "components/FormWrapper.vue";
const props = defineProps({
photo: {
type: Object
},
locations: {
type: Array
}
});
const photoId = computed(() => props.photo?.id || null);
const formData = ref({
name: "",
description: "",
pointOfInterestId: null,
isFlightCover: false
});
const setup = (() => {
setDefaultData(formData.value, props.photo || {});
})
</script>
<template>
<DialogWrapper :formData="formData" :object-id="photoId" @show="setup">
<q-img :src="photo.thumbnailUrl"/>
<q-card-section>
<FormWrapper :save-button="false">
<q-input v-model="formData.name" label="Název"/>
<q-input type="textarea" v-model="formData.description" label="Popis"/>
<q-select
:options="locations"
option-label="name"
option-value="id"
emit-value
map-options
v-model="formData.pointOfInterestId"
label="POI"
/>
<q-checkbox v-model="formData.isFlightCover" label="Úvodní fotografie k letu?" />
</FormWrapper>
</q-card-section>
</DialogWrapper>
</template>
+58 -42
View File
@@ -1,9 +1,10 @@
<script setup>
import {onMounted, reactive, ref, watch} from "vue";
import {computed, onMounted, reactive, ref, watch} from "vue";
import FormWrapper from "components/FormWrapper.vue";
import {setDefaultData} from "src/composables/form/formHandling";
import DatetimePicker from "components/inputs/DatetimePicker.vue";
import AirportLocationInput from "components/inputs/AirportLocationInput.vue";
import ComboboxInput from "components/inputs/ComboboxInput.vue";
import {commonProps} from "src/composables/inputs";
const props = defineProps({
aircrafts: {
@@ -21,16 +22,14 @@ const props = defineProps({
}
)
const formData = reactive({
aircraftId: 43,
takeoffAirportId: null,
landingAirportId: null,
aircraft: null,
takeoffAirport: null,
landingAirport: null,
takeoffDatetime: null,
landingDatetime: null,
landings: 1,
solo: true,
name: "",
description: ""
description: "",
})
const recalculateDuration = (data) => {
@@ -47,55 +46,72 @@ const isMounted = ref(false);
onMounted(() => {
if (props.flight) {
setDefaultData(formData, props.flight);
formData.aircraft = {id: formData.aircraft.id, name: formData.aircraft.callSign};
formData.takeoffAirport = {id: formData.takeoffAirport.id, name: formData.takeoffAirport.name}
formData.landingAirport = {id: formData.landingAirport.id, name: formData.landingAirport.name}
}
isMounted.value = true;
});
const aircrafts = computed(() => {
return props.aircrafts.map(a => ({id: a.id, name: a.callSign}));
});
watch(() => formData.takeoffAirport, () => {
if (!formData.landingAirport) {
formData.landingAirport = {...formData.takeoffAirport};
}
});
</script>
<template>
<FormWrapper v-model="formData" v-if="isMounted">
<div class="row">
<div class="col">
<q-select
v-model="formData.aircraftId"
option-label="callSign"
option-value="id"
emit-value
map-options
:rules="rules.aircraft"
<ComboboxInput
v-bind="commonProps"
:options="aircrafts"
v-model="formData.aircraft"
:key="formData.aircraft"
label="Letadlo"
>
<template #prepend>
<q-icon name="flight" />
</template>
</q-select>
/>
</div>
</div>
<template v-if="formData.aircraftId">
<div class="row">
<div class="col col-12 col-md-6">
<h3>Vzlet</h3>
<DatetimePicker v-model="formData.takeoffDatetime" label="Datum a čas vzletu: "/>
<AirportLocationInput v-model="formData.takeoffAirportId" :airports="airports" label="Letiště vzletu" takeoff/>
</div>
<div class="col col-12 col-md-6" v-if="!!formData.takeoffDatetime && !!formData.takeoffAirportId">
<h3>Přistání</h3>
<DatetimePicker v-model="formData.landingDatetime" label="Datum a čas přistání"/>
<AirportLocationInput v-model="formData.landingAirportId" :airports="airports" label="Letiště přistání" landing/>
</div>
<div class="row">
<div class="col col-12 col-md-6">
<h3>Vzlet</h3>
<DatetimePicker
v-model="formData.takeoffDatetime"
label="Datum a čas vzletu: "
v-bind="commonProps"
/>
<ComboboxInput
:options="airports"
v-model="formData.takeoffAirport"
label="Letiště vzletu"
v-bind="commonProps"
:enable-new-values="false"
/>
</div>
<div class="col col-12 col-md-6">
<div class="row" v-if="formData.landingAirportId">
<div class="col">
<q-checkbox v-model="formData.solo" label="Solo?"/>
</div>
<div class="col">
<q-input v-model.number="formData.landings" label="Počet přistání" type="number" min="1"/>
</div>
<h3>Přistání</h3>
<DatetimePicker
v-model="formData.landingDatetime"
:min-date="formData.takeoffDatetime"
label="Datum a čas přistání"
v-bind="commonProps"
/>
<ComboboxInput
:options="airports"
v-model="formData.landingAirport"
label="Letiště přistání"
v-bind="commonProps"
:enable-new-values="false"
/>
</div>
</template>
</div>
</FormWrapper>
</template>
@@ -1,5 +1,5 @@
<script setup>
import {onMounted, reactive, ref} from "vue";
import {onMounted, reactive, ref, watch} from "vue";
import FormWrapper from "components/FormWrapper.vue";
import {setDefaultData} from "src/composables/form/formHandling";
import ComboboxInput from "components/inputs/ComboboxInput.vue";
@@ -16,14 +16,20 @@ const props = defineProps({
});
const formData = reactive({
solo: true,
withInstructor: false,
copilot: null,
})
const solo = ref(true);
watch(() => solo.value, (newVal) => {
if (!newVal) {
formData.copilot = null;
}
});
onMounted(() => {
if (props.flight) {
setDefaultData(formData, props.flight);
solo.value = !formData.copilot;
}
})
@@ -32,9 +38,15 @@ onMounted(() => {
<template>
<FormWrapper v-model="formData">
<q-btn-toggle spread no-caps v-model="formData.solo" toggle-color="primary" :options="[{label: 'Solo', value: true}, {label: 'S někým', value: false}]"/>
<q-btn-toggle
spread
no-caps
v-model="solo"
toggle-color="primary"
:options="[{label: 'Solo', value: true}, {label: 'S někým', value: false}]"
/>
<div v-if="!formData.solo">
<div v-if="!solo">
<ComboboxInput
class="q-my-lg"
outlined
@@ -45,9 +57,6 @@ onMounted(() => {
:clearable="true"
label="Druhy pilot"
/>
<!-- <q-checkbox v-model="formData.withInstructor" v-if="formData.copilot" label="Instruktor"/>-->
<!-- <q-input v-model="formData.picTime" label="PIC time"/>-->
</div>
</FormWrapper>
@@ -3,6 +3,7 @@ import {onMounted, ref} from "vue";
import FormWrapper from "components/FormWrapper.vue";
import {setDefaultData} from "src/composables/form/formHandling";
import RichTextEditor from "components/inputs/RichTextEditor.vue";
import {commonProps} from "src/composables/inputs";
const props = defineProps({
flight: {
@@ -28,7 +29,7 @@ onMounted(() => {
<template>
<FormWrapper v-model="formData" v-if="isMounted">
<q-input type="text" v-model="formData.name" label="Název"/>
<RichTextEditor v-model="formData.description" label="Popis letu, poznámky, ..." />
<q-input type="text" v-model="formData.name" label="Jméno letu" v-bind="commonProps" />
<RichTextEditor v-model="formData.description" v-bind="commonProps" label="Popis letu, poznámky, ..." />
</FormWrapper>
</template>
@@ -2,6 +2,7 @@
import FormWrapper from "components/FormWrapper.vue";
import {onMounted, reactive, ref, watch} from "vue";
import ComboboxInput from "components/inputs/ComboboxInput.vue";
import {commonProps} from "src/composables/inputs";
const props = defineProps({
modelValue: {
@@ -18,7 +19,8 @@ const props = defineProps({
});
const formData = reactive({
track: []
track: [],
gpxTrack: null
});
const removeTrackItem = (index) => {
formData.track.splice(index, 1);
@@ -48,16 +50,22 @@ onMounted(() => {
<template>
<FormWrapper v-model="formData">
<q-file v-model="formData.gpxTrack" v-bind="commonProps" label="Trasa v GPX" hint="Slouží pro vykreslení kompletní a detailní trasy"/>
<template v-if="flight.gpxTrackUrl">
<q-icon name="check" color="green" /> Trasa nahrána
</template>
<ComboboxInput
outlined
standout
class="q-my-lg"
v-bind="commonProps"
v-model="poi"
:key="formData.track.length"
:options="locations"
@select="addTrackItem"
clearable
label="Otočný bod"
hint="Nastav významné otočné body"
/>
<q-list bordered>