Combobox, POI
This commit is contained in:
@@ -1,10 +1,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import DatetimePicker from "components/inputs/DatetimePicker.vue";
|
|
||||||
import {onMounted, reactive, ref, watch} from "vue";
|
import {onMounted, reactive, ref, watch} from "vue";
|
||||||
import FormWrapper from "components/FormWrapper.vue";
|
import FormWrapper from "components/FormWrapper.vue";
|
||||||
import {setDefaultData} from "src/composables/form/formHandling";
|
import {setDefaultData} from "src/composables/form/formHandling";
|
||||||
import {formatDatetime, parseDate} from "src/composables/datetimeUtils";
|
import DatetimePicker from "components/inputs/DatetimePicker.vue";
|
||||||
import AnotherDatetimePicker from "components/inputs/AnotherDatetimePicker.vue";
|
|
||||||
import AirportLocationInput from "components/inputs/AirportLocationInput.vue";
|
import AirportLocationInput from "components/inputs/AirportLocationInput.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -77,7 +75,7 @@ onMounted(() => {
|
|||||||
label="Letadlo"
|
label="Letadlo"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<q-icon name="flight"></q-icon>
|
<q-icon name="flight" />
|
||||||
</template>
|
</template>
|
||||||
</q-select>
|
</q-select>
|
||||||
</div>
|
</div>
|
||||||
@@ -87,13 +85,13 @@ onMounted(() => {
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col col-12 col-md-6">
|
<div class="col col-12 col-md-6">
|
||||||
<h3>Vzlet</h3>
|
<h3>Vzlet</h3>
|
||||||
<AnotherDatetimePicker v-model="formData.takeoffDatetime" label="Datum a čas vzletu: "/>
|
<DatetimePicker v-model="formData.takeoffDatetime" label="Datum a čas vzletu: "/>
|
||||||
<AirportLocationInput v-model="formData.takeoffAirportId" :airports="airports" label="Letiště vzletu" takeoff/>
|
<AirportLocationInput v-model="formData.takeoffAirportId" :airports="airports" label="Letiště vzletu" takeoff/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-12 col-md-6" v-if="!!formData.takeoffDatetime && !!formData.takeoffAirportId">
|
<div class="col col-12 col-md-6" v-if="!!formData.takeoffDatetime && !!formData.takeoffAirportId">
|
||||||
|
|
||||||
<h3>Přistání</h3>
|
<h3>Přistání</h3>
|
||||||
<AnotherDatetimePicker v-model="formData.landingDatetime" label="Datum a čas přistání"/>
|
<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/>
|
<AirportLocationInput v-model="formData.landingAirportId" :airports="airports" label="Letiště přistání" landing/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {onMounted, reactive} from "vue";
|
import {onMounted, reactive, ref} from "vue";
|
||||||
import FormWrapper from "components/FormWrapper.vue";
|
import FormWrapper from "components/FormWrapper.vue";
|
||||||
import {setDefaultData} from "src/composables/form/formHandling";
|
import {setDefaultData} from "src/composables/form/formHandling";
|
||||||
|
import ComboboxInput from "components/inputs/ComboboxInput.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
flight: {
|
flight: {
|
||||||
@@ -17,7 +18,7 @@ const props = defineProps({
|
|||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
solo: true,
|
solo: true,
|
||||||
withInstructor: false,
|
withInstructor: false,
|
||||||
copilotId: null,
|
copilot: null,
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -25,18 +26,22 @@ onMounted(() => {
|
|||||||
setDefaultData(formData, props.flight);
|
setDefaultData(formData, props.flight);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FormWrapper v-model="formData">
|
<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="formData.solo" toggle-color="primary" :options="[{label: 'Solo', value: true}, {label: 'S někým', value: false}]"/>
|
||||||
|
|
||||||
<div v-if="!formData.solo">
|
{{ formData.copilot }}
|
||||||
<q-input type="text" v-model="formData.secondPilot" label="Druhý pilot"/>
|
|
||||||
<q-checkbox v-model="formData.withInstructor" v-if="formData.secondPilot !== ''" label="Instruktor"/>
|
|
||||||
<!-- <q-input v-model="formData.picTime" label="PIC time"/>-->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</FormWrapper>
|
<div v-if="!formData.solo">
|
||||||
|
<ComboboxInput :options="copilots" v-model="formData.copilot" :key="formData.copilot" 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>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<script setup>
|
||||||
|
import FormWrapper from "components/FormWrapper.vue";
|
||||||
|
import {onMounted, reactive, ref} from "vue";
|
||||||
|
import ComboboxInput from "components/inputs/ComboboxInput.vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: [Number, String],
|
||||||
|
},
|
||||||
|
locations: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
flight: {
|
||||||
|
type: Object,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const formData = reactive({
|
||||||
|
track: []
|
||||||
|
});
|
||||||
|
const removeTrackItem = (index) => {
|
||||||
|
formData.track.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const poi = ref(null);
|
||||||
|
const addTrackItem = (item) => {
|
||||||
|
formData.track.push(item);
|
||||||
|
poi.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
for (const i in props.flight.track) {
|
||||||
|
const poiInfo = props.flight.track[i].pointOfInterest;
|
||||||
|
formData.track.push({
|
||||||
|
id: poiInfo.id,
|
||||||
|
name: poiInfo.name
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FormWrapper v-model="formData">
|
||||||
|
|
||||||
|
{{ flight.track }}
|
||||||
|
|
||||||
|
<q-list>
|
||||||
|
<q-item>{{ flight.takeoffAirport.name }}</q-item>
|
||||||
|
|
||||||
|
<q-item v-for="(item, index) in formData.track" :key="item">
|
||||||
|
{{ index + 1 }}. {{ item.name }}
|
||||||
|
|
||||||
|
<q-btn @click="removeTrackItem(index)" icon="delete" text-color="red"/>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-item>{{ flight.landingAirport.name }}</q-item>
|
||||||
|
|
||||||
|
</q-list>
|
||||||
|
|
||||||
|
<ComboboxInput v-model="poi" :options="locations" clearable label="Location">
|
||||||
|
<template #after>
|
||||||
|
<q-btn @click="addTrackItem(poi)" v-if="poi" rounded>+</q-btn>
|
||||||
|
</template>
|
||||||
|
</ComboboxInput>
|
||||||
|
</FormWrapper>
|
||||||
|
</template>
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import {computed, onMounted, ref} from "vue";
|
|
||||||
import {FORMAT_DATETIME_LONG, FORMAT_ISO, formatDatetime, parseDate} from "src/composables/datetimeUtils";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: [String, Date]
|
|
||||||
},
|
|
||||||
mask: {
|
|
||||||
type: [String, Boolean],
|
|
||||||
required: false,
|
|
||||||
default: FORMAT_DATETIME_LONG
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
let dateModel = ref("");
|
|
||||||
let timeModel = ref("");
|
|
||||||
|
|
||||||
let originalTime, originalDate;
|
|
||||||
onMounted(() => {
|
|
||||||
let emitDefaultValue = false;
|
|
||||||
if (props.modelValue) {
|
|
||||||
let modelVal = props.modelValue;
|
|
||||||
if (typeof modelVal === 'string') {
|
|
||||||
modelVal = parseDate(props.modelValue);
|
|
||||||
emitDefaultValue = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
dateModel.value = formatDatetime(modelVal, "YYYY-MM-DD");
|
|
||||||
timeModel.value = formatDatetime(modelVal, "HH:mm:ss");
|
|
||||||
}
|
|
||||||
|
|
||||||
setOriginalValues();
|
|
||||||
if (emitDefaultValue) {
|
|
||||||
emitModelUpdate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const publicModel = computed(() => {
|
|
||||||
if (!dateModel.value) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
const dateObject = parseDate(model.value, FORMAT_ISO);
|
|
||||||
return formatDatetime(dateObject, props.mask);
|
|
||||||
});
|
|
||||||
|
|
||||||
const popupProxy = ref(null);
|
|
||||||
|
|
||||||
const model = computed(() => dateModel.value + "T" + timeModel.value);
|
|
||||||
const emit = defineEmits(['update:modelValue']);
|
|
||||||
const emitModelUpdate = () => {
|
|
||||||
const val = parseDate(model.value);
|
|
||||||
emit("update:modelValue", val);
|
|
||||||
popupProxy.value.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
const containsAnyOf = (needles, haystack) => {
|
|
||||||
for (const i in needles) {
|
|
||||||
if (haystack.includes(needles[i])) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const showDatePicker = computed(() => containsAnyOf(["YY", "M", "D"], props.mask));
|
|
||||||
const showTimePicker = computed(() => containsAnyOf(["H", "h", "m"], props.mask));
|
|
||||||
|
|
||||||
const setOriginalValues = () => {
|
|
||||||
originalDate = dateModel.value;
|
|
||||||
originalTime = timeModel.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cancelSelection = () => {
|
|
||||||
dateModel.value = originalDate;
|
|
||||||
timeModel.value = originalTime;
|
|
||||||
popupProxy.value.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
const myLocale = {
|
|
||||||
/* starting with Sunday */
|
|
||||||
days: ["Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"],
|
|
||||||
daysShort: ["Po", "Út", "St", "Čt", "Pá", "So", "Ne"],
|
|
||||||
months: [
|
|
||||||
"Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad",
|
|
||||||
"Prosinec"
|
|
||||||
],
|
|
||||||
monthsShort: ["led.", "úno.", "bře.", "dub.", "kvě.", "čvn.", "čvc.", "srp.", "zář.", "říj.", "lis.", "pro."],
|
|
||||||
firstDayOfWeek: 1, // 0-6, 0 - Sunday, 1 Monday, ...
|
|
||||||
format24h: true,
|
|
||||||
pluralDay: 'dny'
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://quasar.dev/vue-composables/use-form-child - mozna resi ohack s onMounted()?
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<q-input readonly v-model="publicModel">
|
|
||||||
<template #append>
|
|
||||||
<q-icon name="event"/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default>
|
|
||||||
<q-popup-proxy ref="popupProxy" @hide="emitModelUpdate" @show="setOriginalValues">
|
|
||||||
<div class="proxy-wrapper">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-12 col-sm-6" v-if="showDatePicker">
|
|
||||||
<q-date square v-model="dateModel" :today-btn="true" flat mask="YYYY-MM-DD" :locale="myLocale"/>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-sm-6" v-if="showTimePicker">
|
|
||||||
<q-time square v-model="timeModel" format24h flat mask="HH:mm"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row q-mb-sm">
|
|
||||||
<div class="col">
|
|
||||||
<q-btn color="secondary" class="q-ml-sm" @click="cancelSelection">Zrušit</q-btn>
|
|
||||||
</div>
|
|
||||||
<div class="col text-right">
|
|
||||||
<q-btn color="primary" class="q-mr-sm" @click="emitModelUpdate">Nastavit</q-btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</q-popup-proxy>
|
|
||||||
</template>
|
|
||||||
</q-input>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.proxy-wrapper {
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-date, .q-time {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
<script setup>
|
||||||
|
import {onMounted, ref, watch} from "vue";
|
||||||
|
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: [Object, Array]
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
type: Array,
|
||||||
|
required: false,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
let model = ref({});
|
||||||
|
watch(() => props.modelValue, (newVal) => {
|
||||||
|
model.value = newVal;
|
||||||
|
console.log("zmena!", newVal);
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
model.value = props.modelValue;
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
watch(model, (val) => {
|
||||||
|
if (!val) return;
|
||||||
|
const value = val.name ? val : {name: val};
|
||||||
|
emit("update:modelValue", value);
|
||||||
|
})
|
||||||
|
|
||||||
|
let availableOptions = ref([]);
|
||||||
|
const filterFn = (val, update, abort) => {
|
||||||
|
update(() => {
|
||||||
|
if (!val || val === "") {
|
||||||
|
availableOptions.value = props.options;
|
||||||
|
} else {
|
||||||
|
const needle = val.toLowerCase();
|
||||||
|
availableOptions.value = props.options.filter(v => {
|
||||||
|
return v.name.toLowerCase().indexOf(needle) > -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
availableOptions.value = availableOptions.value.map(i => ({id: i.id, name: i.name}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-select
|
||||||
|
v-model="model"
|
||||||
|
use-input
|
||||||
|
input-debounce="100"
|
||||||
|
:display-value="`${model.name}`"
|
||||||
|
:rules="rules"
|
||||||
|
@filter="filterFn"
|
||||||
|
:options="availableOptions"
|
||||||
|
option-label="name"
|
||||||
|
option-value="id"
|
||||||
|
new-value-mode="add"
|
||||||
|
>
|
||||||
|
<template #before>
|
||||||
|
<slot name="before"/>
|
||||||
|
</template>
|
||||||
|
<template #after>
|
||||||
|
<slot name="after"/>
|
||||||
|
</template>
|
||||||
|
<template #append>
|
||||||
|
<slot name="append"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- <template>-->
|
||||||
|
<!-- </template>-->
|
||||||
|
|
||||||
|
<template v-slot:no-option>
|
||||||
|
<q-item>
|
||||||
|
<q-item-section class="text-grey">
|
||||||
|
Add new option
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</template>
|
||||||
|
</q-select>
|
||||||
|
</template>
|
||||||
@@ -1,31 +1,25 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {computed, onMounted, ref, watch} from "vue";
|
import {computed, onMounted, ref} from "vue";
|
||||||
import {parseDate} from "src/composables/datetimeUtils";
|
import {FORMAT_DATETIME_LONG, FORMAT_ISO, formatDatetime, parseDate} from "src/composables/datetimeUtils";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: [String, Date]
|
type: [String, Date]
|
||||||
},
|
},
|
||||||
dateMask: {
|
mask: {
|
||||||
type: [String, Boolean],
|
type: [String, Boolean],
|
||||||
required: false,
|
required: false,
|
||||||
default: "YYYY-MM-DD"
|
default: FORMAT_DATETIME_LONG
|
||||||
},
|
|
||||||
timeMask: {
|
|
||||||
type: [String, Boolean],
|
|
||||||
required: false,
|
|
||||||
default: "HH:mm"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
let dateModel = ref("");
|
let dateModel = ref("");
|
||||||
let timeModel = ref("");
|
let timeModel = ref("");
|
||||||
|
|
||||||
|
let originalTime, originalDate;
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let date = "";
|
|
||||||
let time = "";
|
|
||||||
let emitDefaultValue = false;
|
let emitDefaultValue = false;
|
||||||
|
|
||||||
if (props.modelValue) {
|
if (props.modelValue) {
|
||||||
let modelVal = props.modelValue;
|
let modelVal = props.modelValue;
|
||||||
if (typeof modelVal === 'string') {
|
if (typeof modelVal === 'string') {
|
||||||
@@ -33,56 +27,113 @@ onMounted(() => {
|
|||||||
emitDefaultValue = true;
|
emitDefaultValue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
date = props.dateMask
|
dateModel.value = formatDatetime(modelVal, "YYYY-MM-DD");
|
||||||
.replace("YYYY", modelVal.getFullYear().toString())
|
timeModel.value = formatDatetime(modelVal, "HH:mm:ss");
|
||||||
.replace("MM", ('0' + modelVal.getMonth()).slice(-2))
|
|
||||||
.replace("DD", ('0' + modelVal.getDate()).slice(-2));
|
|
||||||
|
|
||||||
time = props.timeMask
|
|
||||||
.replace("HH", ('0' + modelVal.getHours()).slice(-2))
|
|
||||||
.replace("mm", ('0' + modelVal.getMinutes()).slice(-2))
|
|
||||||
.replace("ss", ('0' + modelVal.getSeconds()).slice(-2))
|
|
||||||
|
|
||||||
// if (time === '') {
|
|
||||||
// time = "00:00";
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dateModel.value = date;
|
setOriginalValues();
|
||||||
timeModel.value = time;
|
|
||||||
|
|
||||||
if (emitDefaultValue) {
|
if (emitDefaultValue) {
|
||||||
emitModelUpdate();
|
emitModelUpdate();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const model = computed(() => dateModel.value + " " + timeModel.value);
|
const publicModel = computed(() => {
|
||||||
|
if (!dateModel.value) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const dateObject = parseDate(model.value, FORMAT_ISO);
|
||||||
|
return formatDatetime(dateObject, props.mask);
|
||||||
|
});
|
||||||
|
|
||||||
|
const popupProxy = ref(null);
|
||||||
|
|
||||||
|
const model = computed(() => dateModel.value + "T" + timeModel.value);
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(['update:modelValue']);
|
||||||
const emitModelUpdate = () => {
|
const emitModelUpdate = () => {
|
||||||
const now = new Date();
|
|
||||||
const val = parseDate(model.value);
|
const val = parseDate(model.value);
|
||||||
// val.setHours(val.getHours() + now.getTimezoneOffset());
|
|
||||||
emit("update:modelValue", val);
|
emit("update:modelValue", val);
|
||||||
|
popupProxy.value.hide();
|
||||||
}
|
}
|
||||||
watch([dateModel, timeModel], emitModelUpdate)
|
|
||||||
|
const containsAnyOf = (needles, haystack) => {
|
||||||
|
for (const i in needles) {
|
||||||
|
if (haystack.includes(needles[i])) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const showDatePicker = computed(() => containsAnyOf(["YY", "M", "D"], props.mask));
|
||||||
|
const showTimePicker = computed(() => containsAnyOf(["H", "h", "m"], props.mask));
|
||||||
|
|
||||||
|
const setOriginalValues = () => {
|
||||||
|
originalDate = dateModel.value;
|
||||||
|
originalTime = timeModel.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancelSelection = () => {
|
||||||
|
dateModel.value = originalDate;
|
||||||
|
timeModel.value = originalTime;
|
||||||
|
popupProxy.value.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
const myLocale = {
|
||||||
|
/* starting with Sunday */
|
||||||
|
days: ["Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota", "Neděle"],
|
||||||
|
daysShort: ["Po", "Út", "St", "Čt", "Pá", "So", "Ne"],
|
||||||
|
months: [
|
||||||
|
"Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad",
|
||||||
|
"Prosinec"
|
||||||
|
],
|
||||||
|
monthsShort: ["led.", "úno.", "bře.", "dub.", "kvě.", "čvn.", "čvc.", "srp.", "zář.", "říj.", "lis.", "pro."],
|
||||||
|
firstDayOfWeek: 1, // 0-6, 0 - Sunday, 1 Monday, ...
|
||||||
|
format24h: true,
|
||||||
|
pluralDay: 'dny'
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://quasar.dev/vue-composables/use-form-child - mozna resi ohack s onMounted()?
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-input v-model="model" readonly>
|
<q-input readonly v-model="publicModel">
|
||||||
<template #append>
|
<template #append>
|
||||||
<q-icon name="event">
|
<q-icon name="event"/>
|
||||||
<q-popup-proxy cover>
|
</template>
|
||||||
|
|
||||||
|
<template #default>
|
||||||
|
<q-popup-proxy ref="popupProxy" @hide="emitModelUpdate" @show="setOriginalValues">
|
||||||
|
<div class="proxy-wrapper">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col" v-if="dateMask">
|
<div class="col-12 col-sm-6" v-if="showDatePicker">
|
||||||
<q-date v-model="dateModel" :mask="dateMask"/>
|
<q-date square v-model="dateModel" :today-btn="true" flat mask="YYYY-MM-DD" :locale="myLocale"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col" v-if="timeMask">
|
<div class="col-12 col-sm-6" v-if="showTimePicker">
|
||||||
<q-time v-model="timeModel" format24h :mask="timeMask"/>
|
<q-time square v-model="timeModel" format24h flat mask="HH:mm"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-popup-proxy>
|
<div class="row q-mb-sm">
|
||||||
</q-icon>
|
<div class="col">
|
||||||
|
<q-btn color="secondary" class="q-ml-sm" @click="cancelSelection">Zrušit</q-btn>
|
||||||
|
</div>
|
||||||
|
<div class="col text-right">
|
||||||
|
<q-btn color="primary" class="q-mr-sm" @click="emitModelUpdate">Nastavit</q-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-popup-proxy>
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.proxy-wrapper {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-date, .q-time {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import {onMounted, ref, toRefs, watch} from "vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: [Number, String]
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
type: Array,
|
|
||||||
required: false,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
locations: {
|
|
||||||
type: Array,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
prependIcon: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
appendIcon: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const emit = defineEmits(['update:modelValue']);
|
|
||||||
|
|
||||||
let selectedLocationModel = ref("");
|
|
||||||
onMounted(() => {
|
|
||||||
selectedLocationModel.value = props.modelValue;
|
|
||||||
});
|
|
||||||
watch(selectedLocationModel, (newVal) => {
|
|
||||||
// TODO: rozdelit emit na dva modely - jeden na emit existujici lokality, druhy na emit nove vytvarene
|
|
||||||
if (!newVal) return;
|
|
||||||
|
|
||||||
let value, eventName;
|
|
||||||
if (newVal instanceof String) {
|
|
||||||
eventName = "update:modelValue";
|
|
||||||
value = newVal;
|
|
||||||
} else {
|
|
||||||
eventName = "update:modelValue";
|
|
||||||
value = newVal.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(eventName, value);
|
|
||||||
})
|
|
||||||
|
|
||||||
const {locations} = toRefs(props);
|
|
||||||
let availableLocations = ref([]);
|
|
||||||
|
|
||||||
const filterFn = (val, update, abort) => {
|
|
||||||
update(() => {
|
|
||||||
if (!val || val === "") {
|
|
||||||
availableLocations.value = locations.value;
|
|
||||||
} else {
|
|
||||||
const needle = val.toLowerCase();
|
|
||||||
availableLocations.value = locations.value.filter(v => {
|
|
||||||
return v.name.toLowerCase().indexOf(needle) > -1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<q-select
|
|
||||||
v-model="selectedLocationModel"
|
|
||||||
:label=label
|
|
||||||
use-input
|
|
||||||
input-debounce="100"
|
|
||||||
:rules="rules"
|
|
||||||
:options="availableLocations"
|
|
||||||
option-label="name"
|
|
||||||
option-value="id"
|
|
||||||
clearable
|
|
||||||
new-value-mode="add"
|
|
||||||
use-chips
|
|
||||||
@filter="filterFn"
|
|
||||||
>
|
|
||||||
<template #before v-if="prependIcon">
|
|
||||||
<q-icon :name="prependIcon"/>
|
|
||||||
</template>
|
|
||||||
<template #after v-if="appendIcon">
|
|
||||||
<q-icon :name="appendIcon"/>
|
|
||||||
</template>
|
|
||||||
<template v-slot:selected v-if="!props.multiple">
|
|
||||||
<q-chip
|
|
||||||
v-if="selectedLocationModel"
|
|
||||||
square
|
|
||||||
>
|
|
||||||
<q-avatar color="primary" text-color="white" :icon="selectedLocationModel.type === 'airport' ? 'flight' : 'marker'"/>
|
|
||||||
{{ selectedLocationModel.name }}
|
|
||||||
</q-chip>
|
|
||||||
</template>
|
|
||||||
<template #append>
|
|
||||||
<slot name="append"></slot>
|
|
||||||
</template>
|
|
||||||
<template v-slot:no-option>
|
|
||||||
<q-item>
|
|
||||||
<q-item-section class="text-grey">
|
|
||||||
Add new option
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</template>
|
|
||||||
</q-select>
|
|
||||||
|
|
||||||
<!-- @input-value u q-select - nelze pouzit misto watche?-->
|
|
||||||
</template>
|
|
||||||
@@ -18,6 +18,13 @@ fragment flightFullInfo on Flight {
|
|||||||
...airportInfo
|
...airportInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
track {
|
||||||
|
pointOfInterest {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
landingAirport {
|
landingAirport {
|
||||||
...airportInfo
|
...airportInfo
|
||||||
}
|
}
|
||||||
@@ -71,6 +78,10 @@ fragment flightEditIds on Flight {
|
|||||||
takeoffAirportId
|
takeoffAirportId
|
||||||
aircraftId
|
aircraftId
|
||||||
copilotId
|
copilotId
|
||||||
|
copilot {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import gql from "graphql-tag";
|
||||||
|
|
||||||
|
export const FRAGMENT_POI_LIST_INFO = gql`
|
||||||
|
fragment pointOfInterestListInfo on PointOfInterest {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import gql from "graphql-tag";
|
||||||
|
import {FRAGMENT_POI_LIST_INFO} from "src/graphql/fragments/poi";
|
||||||
|
|
||||||
|
export const CREATE_POI = gql`
|
||||||
|
mutation createPointOfInterest($input: CreatePointOfInterestInput!) {
|
||||||
|
createPointOfInterest(input: $input) {
|
||||||
|
...pointOfInterestListInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${FRAGMENT_POI_LIST_INFO}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import gql from "graphql-tag";
|
||||||
|
import {FRAGMENT_POI_LIST_INFO} from "src/graphql/fragments/poi";
|
||||||
|
|
||||||
|
export const POI_LIST = gql`
|
||||||
|
query poiList {
|
||||||
|
pointsOfInterest {
|
||||||
|
...pointOfInterestListInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${FRAGMENT_POI_LIST_INFO}
|
||||||
|
`;
|
||||||
@@ -18,6 +18,7 @@ import {usePhotosStore} from "stores/Photo";
|
|||||||
import PhotosList from "components/photos/PhotosList.vue";
|
import PhotosList from "components/photos/PhotosList.vue";
|
||||||
import {confirmObject, successObject} from "src/composables/dialog";
|
import {confirmObject, successObject} from "src/composables/dialog";
|
||||||
import PhotoForm from "components/flights/PhotoForm.vue";
|
import PhotoForm from "components/flights/PhotoForm.vue";
|
||||||
|
import FlightFormTrack from "components/flights/form/FlightFormTrack.vue";
|
||||||
|
|
||||||
useMeta({title: "Editace letu"});
|
useMeta({title: "Editace letu"});
|
||||||
|
|
||||||
@@ -56,6 +57,7 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleFlightEdit = (data) => {
|
const handleFlightEdit = (data) => {
|
||||||
|
console.log(data);
|
||||||
useFlightsStore().update(flightId, data).then(() => {
|
useFlightsStore().update(flightId, data).then(() => {
|
||||||
$q.notify(successObject("Úspěšně upraveno"));
|
$q.notify(successObject("Úspěšně upraveno"));
|
||||||
fetchFlight(flightId);
|
fetchFlight(flightId);
|
||||||
@@ -129,6 +131,15 @@ const openPhotoEdit = (photo) => {
|
|||||||
<FlightFormCopilot @save="handleFlightEdit" :flight="flight" :copilots="copilots"/>
|
<FlightFormCopilot @save="handleFlightEdit" :flight="flight" :copilots="copilots"/>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
|
|
||||||
|
<q-tab-panel name="track">
|
||||||
|
<FlightFormTrack
|
||||||
|
v-if="locations"
|
||||||
|
:flight="flight"
|
||||||
|
:locations="locations"
|
||||||
|
@save="handleFlightEdit"
|
||||||
|
/>
|
||||||
|
</q-tab-panel>
|
||||||
|
|
||||||
<q-tab-panel name="photos">
|
<q-tab-panel name="photos">
|
||||||
<PhotosList
|
<PhotosList
|
||||||
:photos="flight.photos"
|
:photos="flight.photos"
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ export const useFlightsStore = defineStore('Flights', {
|
|||||||
return apolloWrapper.query(FLIGHT_DETAIL, {id}).then(result => result.data.flight);
|
return apolloWrapper.query(FLIGHT_DETAIL, {id}).then(result => result.data.flight);
|
||||||
},
|
},
|
||||||
fetch() {
|
fetch() {
|
||||||
console.log("flights fetch");
|
|
||||||
return apolloWrapper
|
return apolloWrapper
|
||||||
.query(FLIGHTS_LIST)
|
.query(FLIGHTS_LIST)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
@@ -44,17 +43,6 @@ export const useFlightsStore = defineStore('Flights', {
|
|||||||
|
|
||||||
return result.data.flights;
|
return result.data.flights;
|
||||||
});
|
});
|
||||||
// if (this.items.length > 0) return;
|
|
||||||
//
|
|
||||||
// this.$patch({
|
|
||||||
// items: [
|
|
||||||
// {id: 1, takeOffLocation: "LKLT", titlePhotoUrl: null, landingLocation: "LKLC", date: "2023-03-03", aircraft: {id: 1, name: "OK-AUR28"}, flightDurationMinutes: 63},
|
|
||||||
// {id: 2, takeOffLocation: "LKLT", titlePhotoUrl: "https://cdn.quasar.dev/img/mountains.jpg", landingLocation: "LKLT", date: "2023-02-01", aircraft: {id: 1, name: "OK-AUR28"}, flightDurationMinutes: 76},
|
|
||||||
// {id: 3, takeOffLocation: "LKLT", titlePhotoUrl: null, landingLocation: "LKLC", date: "2023-04-03", aircraft: {id: 1, name: "OK-AUR28"}, flightDurationMinutes: 53},
|
|
||||||
// {id: 4, takeOffLocation: "LKLT", titlePhotoUrl: null, landingLocation: "LKMB", date: "2023-03-04", aircraft: {id: 1, name: "OK-AUR28"}, flightDurationMinutes: 75},
|
|
||||||
// {id: 5, takeOffLocation: "LKLT", titlePhotoUrl: null, landingLocation: "LKMH", date: "2023-01-46", aircraft: {id: 1, name: "OK-AUR28"}, flightDurationMinutes: 23},
|
|
||||||
// ]
|
|
||||||
// });
|
|
||||||
},
|
},
|
||||||
deleteItem(id) {
|
deleteItem(id) {
|
||||||
const idx = this.items.indexOf(this.items.find(f => f.id === id));
|
const idx = this.items.indexOf(this.items.find(f => f.id === id));
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import {defineStore} from 'pinia'
|
import {defineStore} from 'pinia'
|
||||||
|
import {apolloWrapper} from "src/graphql/apollo";
|
||||||
|
import {POI_LIST} from "src/graphql/queries/poi";
|
||||||
|
|
||||||
export const usePointsOfInterestStore = defineStore('PointsOfInterest', {
|
export const usePointsOfInterestStore = defineStore('PointsOfInterest', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
@@ -16,23 +18,23 @@ export const usePointsOfInterestStore = defineStore('PointsOfInterest', {
|
|||||||
console.log('item', item);
|
console.log('item', item);
|
||||||
return item;
|
return item;
|
||||||
},
|
},
|
||||||
pointTypeName() {
|
// pointTypeName() {
|
||||||
return (typeName) => {
|
// return (typeName) => {
|
||||||
const typeToNameMap = {
|
// const typeToNameMap = {
|
||||||
poi: "General POI",
|
// poi: "General POI",
|
||||||
airport: "Airport",
|
// airport: "Airport",
|
||||||
}
|
// }
|
||||||
return typeToNameMap[typeName] || "Unknown";
|
// return typeToNameMap[typeName] || "Unknown";
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
groupByTypes() {
|
// groupByTypes() {
|
||||||
const groupedByType = {};
|
// const groupedByType = {};
|
||||||
for (const item of this.items) {
|
// for (const item of this.items) {
|
||||||
if (!groupedByType[item.type]) groupedByType[item.type] = [];
|
// if (!groupedByType[item.type]) groupedByType[item.type] = [];
|
||||||
groupedByType[item.type].push(item);
|
// groupedByType[item.type].push(item);
|
||||||
}
|
// }
|
||||||
return groupedByType;
|
// return groupedByType;
|
||||||
}
|
// }
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
@@ -41,12 +43,17 @@ export const usePointsOfInterestStore = defineStore('PointsOfInterest', {
|
|||||||
this.items.push({id: poiId, "name": "Zamek " + poiId, "type": "poi", "location": {"lat": 50, "lng": 10}});
|
this.items.push({id: poiId, "name": "Zamek " + poiId, "type": "poi", "location": {"lat": 50, "lng": 10}});
|
||||||
},
|
},
|
||||||
fetch() {
|
fetch() {
|
||||||
console.log("fetch poi");
|
return apolloWrapper.query(POI_LIST).then(result => {
|
||||||
this.items = [
|
this.items = result.data.pointsOfInterest;
|
||||||
{id: 1, "name": "LKLT", private: false, "type": "airport", "location": {"lat": 50, "lng": 10}},
|
return result.data.pointsOfInterest;
|
||||||
{id: 2, "name": "Hrad", "type": "poi", "location": {"lat": 50, "lng": 10}},
|
});
|
||||||
{id: 3, "name": "Zamek", "type": "poi", "location": {"lat": 50, "lng": 10}},
|
|
||||||
]
|
// console.log("fetch poi");
|
||||||
|
// this.items = [
|
||||||
|
// {id: 1, "name": "LKLT", private: false, "type": "airport", "location": {"lat": 50, "lng": 10}},
|
||||||
|
// {id: 2, "name": "Hrad", "type": "poi", "location": {"lat": 50, "lng": 10}},
|
||||||
|
// {id: 3, "name": "Zamek", "type": "poi", "location": {"lat": 50, "lng": 10}},
|
||||||
|
// ]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user