Detail planovace, verejne planovain
This commit is contained in:
@@ -3,8 +3,10 @@ import {commonProps} from "src/composables/inputs";
|
|||||||
import DatetimePicker from "components/inputs/DatetimePicker.vue";
|
import DatetimePicker from "components/inputs/DatetimePicker.vue";
|
||||||
import ComboboxInput from "components/inputs/ComboboxInput.vue";
|
import ComboboxInput from "components/inputs/ComboboxInput.vue";
|
||||||
import FormWrapper from "components/FormWrapper.vue";
|
import FormWrapper from "components/FormWrapper.vue";
|
||||||
import {onMounted, reactive} from "vue";
|
import {reactive} from "vue";
|
||||||
import {setDefaultData} from "src/composables/form/formHandling";
|
import CopyLinkButton from "components/inputs/CopyLinkButton.vue";
|
||||||
|
import {useLoggedUserStore} from "stores/LoggedUser";
|
||||||
|
import {storeToRefs} from "pinia";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
flightPlan: {
|
flightPlan: {
|
||||||
@@ -31,7 +33,10 @@ const formData = reactive({
|
|||||||
id: props.flightPlan.aircraft.id, name: props.flightPlan.aircraft.callSign
|
id: props.flightPlan.aircraft.id, name: props.flightPlan.aircraft.callSign
|
||||||
} : null,
|
} : null,
|
||||||
plannedSpeed: props.flightPlan.plannedSpeed || 150,
|
plannedSpeed: props.flightPlan.plannedSpeed || 150,
|
||||||
|
description: props.flightPlan.description || null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {user} = storeToRefs(useLoggedUserStore());
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -39,7 +44,15 @@ const formData = reactive({
|
|||||||
<q-input v-model="formData.name" label="Jméno letu" v-if="!formData.isDefaultName" v-bind="commonProps"/>
|
<q-input v-model="formData.name" label="Jméno letu" v-if="!formData.isDefaultName" v-bind="commonProps"/>
|
||||||
<q-checkbox v-model="formData.isDefaultName" label="Použít automatické jméno"/>
|
<q-checkbox v-model="formData.isDefaultName" label="Použít automatické jméno"/>
|
||||||
|
|
||||||
<!-- <q-checkbox v-model="formData.isPublic" label="Zveřejnit"/>-->
|
<q-checkbox v-model="formData.isPublic" label="Zveřejnit"/>
|
||||||
|
|
||||||
|
<CopyLinkButton
|
||||||
|
v-if="flightPlan.isPublic"
|
||||||
|
:route="{name: 'publicFlightPlanDetail', params: {username: user.publicUsername, id: flightPlan.id}}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-editor v-model="formData.description" label="Popis" v-bind="commonProps" />
|
||||||
|
|
||||||
<!-- <q-checkbox v-model="formData.isEditableByCopilot" label="Kopilot může upravovat"/>-->
|
<!-- <q-checkbox v-model="formData.isEditableByCopilot" label="Kopilot může upravovat"/>-->
|
||||||
<DatetimePicker v-model="formData.plannedTakeoffDatetime" label="Plánovaný datum a čas vzletu" v-bind="commonProps"/>
|
<DatetimePicker v-model="formData.plannedTakeoffDatetime" label="Plánovaný datum a čas vzletu" v-bind="commonProps"/>
|
||||||
<ComboboxInput v-model="formData.aircraft" :options="aircrafts" label="Letadlo" v-bind="commonProps"/>
|
<ComboboxInput v-model="formData.aircraft" :options="aircrafts" label="Letadlo" v-bind="commonProps"/>
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
insertPosition: {
|
insertPosition: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: false,
|
||||||
|
default: null
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const emits = defineEmits(["markers-changed", "change-insert-position"]);
|
const emits = defineEmits(["markers-changed", "change-insert-position"]);
|
||||||
@@ -92,7 +93,7 @@ const handleMarkerMove = async (idx, event) => {
|
|||||||
:fullscreen-control="false"
|
:fullscreen-control="false"
|
||||||
:show-info-window="true"
|
:show-info-window="true"
|
||||||
:show-layer-controls="true"
|
:show-layer-controls="true"
|
||||||
:allow-add-marker="true"
|
:allow-add-marker="insertPosition !== null"
|
||||||
@add-to-route="addMarker"
|
@add-to-route="addMarker"
|
||||||
@remove-from-route="removeMarker"
|
@remove-from-route="removeMarker"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const columns = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const {getDuration, getTotalTime, getTotalDistance} = useFlightPlanCalculations();
|
const {getDuration, getTotalDuration, getTotalDistance} = useFlightPlanCalculations();
|
||||||
|
|
||||||
const data = computed(() => props.flightPlan.track.map((item) => ({
|
const data = computed(() => props.flightPlan.track.map((item) => ({
|
||||||
from: textEllipsis(item.from.name, 30),
|
from: textEllipsis(item.from.name, 30),
|
||||||
@@ -73,7 +73,7 @@ const {screen} = useQuasar();
|
|||||||
<tr class="summary">
|
<tr class="summary">
|
||||||
<td v-for="col in cols" :key="col.field" :class="{'text-right': col.align === 'right'}">
|
<td v-for="col in cols" :key="col.field" :class="{'text-right': col.align === 'right'}">
|
||||||
<template v-if="col.field === 'duration'">
|
<template v-if="col.field === 'duration'">
|
||||||
{{ minutesToHumanReadable(getTotalTime(flightPlan, plannedSpeed)) }}
|
{{ minutesToHumanReadable(getTotalDuration(flightPlan, plannedSpeed)) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="col.field === 'distance'">
|
<template v-else-if="col.field === 'distance'">
|
||||||
{{ getTotalDistance(flightPlan) }} km
|
{{ getTotalDistance(flightPlan) }} km
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emits = defineEmits(["open", "change-insert-position", "fullscren-toggle"])
|
const emits = defineEmits(["open", "change-insert-position", "fullscren-toggle"])
|
||||||
|
|
||||||
const {getDuration, getTotalDistance, getTotalTime} = useFlightPlanCalculations();
|
const {getDuration, getTotalDistance, getTotalDuration} = useFlightPlanCalculations();
|
||||||
const totalDistance = computed(() => getTotalDistance(props.flightPlan));
|
const totalDistance = computed(() => getTotalDistance(props.flightPlan));
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -109,7 +109,7 @@ const totalDistance = computed(() => getTotalDistance(props.flightPlan));
|
|||||||
<q-item-section>
|
<q-item-section>
|
||||||
Celková vzdálenost: {{ totalDistance }} km
|
Celková vzdálenost: {{ totalDistance }} km
|
||||||
<br>
|
<br>
|
||||||
Plánovaná doba letu: {{ minutesToHumanReadable(getTotalTime(props.flightPlan, props.flightPlan.plannedSpeed)) }}
|
Plánovaná doba letu: {{ minutesToHumanReadable(getTotalDuration(props.flightPlan, props.flightPlan.plannedSpeed)) }}
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -32,13 +32,13 @@ export const useFlightPlanCalculations = () => {
|
|||||||
return Math.round(flightPlan.track.map(t => t.distance).reduce((a, b) => a + b));
|
return Math.round(flightPlan.track.map(t => t.distance).reduce((a, b) => a + b));
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTotalTime = (flightPlan, plannedSpeed) => {
|
const getTotalDuration = (flightPlan, plannedSpeed) => {
|
||||||
if (!flightPlan.track.length) return null;
|
if (!flightPlan.track.length) return null;
|
||||||
|
|
||||||
return flightPlan.track.map(t => getDuration(t.distance, plannedSpeed)).reduce((a, b) => a + b)
|
return flightPlan.track.map(t => getDuration(t.distance, plannedSpeed)).reduce((a, b) => a + b)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {getDuration, getTotalDistance, getTotalTime}
|
return {getDuration, getTotalDistance, getTotalDuration}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useFlightPlanObjects = () => {
|
export const useFlightPlanObjects = () => {
|
||||||
|
|||||||
@@ -19,11 +19,16 @@ fragment flightPlanFullInfo on FlightPlan {
|
|||||||
isDefaultName
|
isDefaultName
|
||||||
isPublic
|
isPublic
|
||||||
isEditableByCopilot
|
isEditableByCopilot
|
||||||
|
description
|
||||||
|
|
||||||
aircraft {
|
aircraft {
|
||||||
id
|
id
|
||||||
callSign
|
callSign
|
||||||
seats
|
seats
|
||||||
|
isPublic
|
||||||
|
titlePhoto {
|
||||||
|
thumbnailUrl
|
||||||
|
}
|
||||||
}
|
}
|
||||||
track {
|
track {
|
||||||
bearing
|
bearing
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ ${FRAGMENT_FLIGHT_PLAN_LIST_INFO}
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const FLIGHT_PLAN_DETAIL = gql`
|
export const FLIGHT_PLAN_DETAIL = gql`
|
||||||
query flightPlansDetail($id: Int!) {
|
query flightPlansDetail($id: Int!, $username: String, $public: Boolean) {
|
||||||
flightPlan(id: $id) {
|
flightPlan(id: $id, username: $username, public: $public) {
|
||||||
...flightPlanFullInfo
|
...flightPlanFullInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<script>
|
||||||
|
import {useFlightPlansStore} from "stores/FlightPlans";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
preFetch({store, currentRoute}) {
|
||||||
|
return useFlightPlansStore(store).fetchPublicDetail({
|
||||||
|
id: currentRoute.params.id,
|
||||||
|
username: currentRoute.params.username
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script setup>
|
||||||
|
import {storeToRefs} from "pinia";
|
||||||
|
import {useAppStore} from "stores/App";
|
||||||
|
import {publicProfileBreadcrumbs} from "src/composables/breadcrumbs";
|
||||||
|
import FlightPlanMap from "components/flightPlans/FlightPlanMap.vue";
|
||||||
|
import {computed, onMounted, ref} from "vue";
|
||||||
|
import {useAirspacesStore} from "stores/Airspaces";
|
||||||
|
import {usePointsOfInterestStore} from "stores/PointsOfInterest";
|
||||||
|
import {useAirportsStore} from "stores/Airports";
|
||||||
|
import {formatDatetime, minutesToHumanReadable} from "src/composables/datetimeUtils";
|
||||||
|
import {useFlightPlanCalculations} from "src/composables/flightPlan";
|
||||||
|
import FlightPlanRouteTable from "components/flightPlans/FlightPlanRouteTable.vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
pilot: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const {flightPlan} = storeToRefs(useFlightPlansStore());
|
||||||
|
|
||||||
|
|
||||||
|
useAppStore().setPageTitle(flightPlan.value.name);
|
||||||
|
useAppStore().setBreadcrumbs([
|
||||||
|
...publicProfileBreadcrumbs(props.pilot),
|
||||||
|
{label: `Plán: ${flightPlan.value.name}`},
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
useAirspacesStore().fetch();
|
||||||
|
usePointsOfInterestStore().fetchPublic({limit: 10000});
|
||||||
|
useAirportsStore().fetch();
|
||||||
|
});
|
||||||
|
|
||||||
|
const {pointsOfInterest} = storeToRefs(usePointsOfInterestStore());
|
||||||
|
const {airspaces: airspacesData, areAirspacesLoading: isQueryRunning} = storeToRefs(useAirspacesStore())
|
||||||
|
const {airports} = storeToRefs(useAirportsStore());
|
||||||
|
|
||||||
|
const openedTab = ref("map");
|
||||||
|
|
||||||
|
const {getTotalDistance, getTotalDuration} = useFlightPlanCalculations();
|
||||||
|
|
||||||
|
const showInfoCard = computed(() => flightPlan.value.aircraft || flightPlan.value.plannedTakeoffDatetime || flight.value.description);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-tabs v-model="openedTab">
|
||||||
|
<q-tab name="map">Mapa</q-tab>
|
||||||
|
<q-tab name="trackTable">Trasa</q-tab>
|
||||||
|
<q-tab name="info" v-if="showInfoCard">Informace</q-tab>
|
||||||
|
</q-tabs>
|
||||||
|
|
||||||
|
<q-tab-panels v-model="openedTab" class="q-mb-lg">
|
||||||
|
<q-tab-panel name="map">
|
||||||
|
<FlightPlanMap
|
||||||
|
:airspace-data="airspacesData"
|
||||||
|
:airports="airports"
|
||||||
|
:points-of-interest="pointsOfInterest"
|
||||||
|
:flight-plan="flightPlan"
|
||||||
|
/>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<q-chip size="lg">
|
||||||
|
<q-icon class="q-mx-md" name="mdi-map-marker-distance"/>
|
||||||
|
{{ getTotalDistance(flightPlan) }} km
|
||||||
|
</q-chip>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col text-right">
|
||||||
|
<q-chip size="lg">
|
||||||
|
<q-icon name="mdi-clock-outline"/>
|
||||||
|
{{ minutesToHumanReadable(getTotalDuration(flightPlan, flightPlan.plannedSpeed)) }}
|
||||||
|
</q-chip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="trackTable">
|
||||||
|
<FlightPlanRouteTable :planned-speed="flightPlan.plannedSpeed" :flight-plan="flightPlan"/>
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="info" v-if="showInfoCard">
|
||||||
|
<div v-if="flightPlan.plannedTakeoffDatetime">
|
||||||
|
Plánovaný vzlet: {{ formatDatetime(flightPlan.plannedTakeoffDatetime) }}
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<div v-if="flightPlan.aircraft">
|
||||||
|
<q-avatar v-if="flightPlan.aircraft.titlePhoto" class="q-ma-md">
|
||||||
|
<img :src="flightPlan.aircraft.titlePhoto.thumbnailUrl" alt=""/>
|
||||||
|
</q-avatar>
|
||||||
|
<router-link v-if="flightPlan.aircraft.isPublic" :to="{name: 'publicAircraftDetail', params: {callSign: flightPlan.aircraft.callSign}}">
|
||||||
|
{{ flightPlan.aircraft.callSign }}
|
||||||
|
</router-link>
|
||||||
|
<template v-else>
|
||||||
|
{{ flightPlan.aircraft.callSign }}
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div v-html="flightPlan.description"/>
|
||||||
|
</q-tab-panel>
|
||||||
|
</q-tab-panels>
|
||||||
|
</template>
|
||||||
@@ -38,6 +38,7 @@ const routes = [
|
|||||||
{path: 'a/:copilotSlug', name: "publicCopilotDetail", component: () => import('pages/public/pilotProfile/CopilotDetailPage.vue')},
|
{path: 'a/:copilotSlug', name: "publicCopilotDetail", component: () => import('pages/public/pilotProfile/CopilotDetailPage.vue')},
|
||||||
{path: 'udalosti', name: "publicEventsList", component: () => import('pages/public/pilotProfile/EventsListPage.vue')},
|
{path: 'udalosti', name: "publicEventsList", component: () => import('pages/public/pilotProfile/EventsListPage.vue')},
|
||||||
{path: 'udalosti/:eventSlug', name: "publicEventDetail", component: () => import('pages/public/pilotProfile/EventDetailPage.vue')},
|
{path: 'udalosti/:eventSlug', name: "publicEventDetail", component: () => import('pages/public/pilotProfile/EventDetailPage.vue')},
|
||||||
|
{path: 'plan/:id', name: "publicFlightPlanDetail", component: () => import("pages/public/pilotProfile/FlightPlanDetail.vue")}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -18,6 +18,14 @@ export const useFlightPlansStore = defineStore('FlightPlans', () => {
|
|||||||
}).then(item => flightPlan.value = item);
|
}).then(item => flightPlan.value = item);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchPublicDetail = ({username, id}) => {
|
||||||
|
return query({
|
||||||
|
isQueryRunning,
|
||||||
|
query: FLIGHT_PLAN_DETAIL,
|
||||||
|
variables: {username, id, public: true},
|
||||||
|
}).then(item => flightPlan.value = item);
|
||||||
|
}
|
||||||
|
|
||||||
const fetch = () => {
|
const fetch = () => {
|
||||||
return query({
|
return query({
|
||||||
isQueryRunning,
|
isQueryRunning,
|
||||||
@@ -50,6 +58,7 @@ export const useFlightPlansStore = defineStore('FlightPlans', () => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
flightPlan, flightPlans, isMutationRunning, isQueryRunning,
|
flightPlan, flightPlans, isMutationRunning, isQueryRunning,
|
||||||
fetch, fetchDetail, create, update
|
fetch, fetchDetail, create, update,
|
||||||
|
fetchPublicDetail
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user