Prace s mapu, zobrazeni GPX, editace kopilota, skeletony
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user