mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-05 08:55:54 +08:00
feat(live-atc): manual flight entry on setup screen
Adds a "Manual flight" card alongside VATSIM and demo so a flight can be entered by hand (callsign, dep, arr, optional aircraft/altitude) without a VATSIM account. Feeds into the same scenario picker. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, computed } from 'vue'
|
||||
import SetupCard from '~/components/live-atc/SetupCard.vue'
|
||||
|
||||
defineProps<{
|
||||
@@ -8,10 +9,36 @@ defineProps<{
|
||||
|
||||
const vatsimId = defineModel<string>('vatsimId', { required: true })
|
||||
|
||||
defineEmits<{
|
||||
const emit = defineEmits<{
|
||||
(e: 'load-flight-plans'): void
|
||||
(e: 'start-demo'): void
|
||||
(e: 'start-manual', plan: { callsign: string; dep: string; arr: string; aircraft: string; altitude: string }): void
|
||||
}>()
|
||||
|
||||
const manual = reactive({
|
||||
callsign: '',
|
||||
dep: '',
|
||||
arr: '',
|
||||
aircraft: '',
|
||||
altitude: '',
|
||||
})
|
||||
|
||||
const manualValid = computed(() =>
|
||||
manual.callsign.trim().length >= 2 &&
|
||||
manual.dep.trim().length >= 3 &&
|
||||
manual.arr.trim().length >= 3
|
||||
)
|
||||
|
||||
const startManual = () => {
|
||||
if (!manualValid.value) return
|
||||
emit('start-manual', {
|
||||
callsign: manual.callsign,
|
||||
dep: manual.dep,
|
||||
arr: manual.arr,
|
||||
aircraft: manual.aircraft,
|
||||
altitude: manual.altitude,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -53,6 +80,85 @@ defineEmits<{
|
||||
</div>
|
||||
</SetupCard>
|
||||
|
||||
<!-- Manual flight entry -->
|
||||
<SetupCard>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold">Manual flight</h2>
|
||||
<p class="text-sm text-[var(--t3)]">Enter a flight by hand — no VATSIM account needed.</p>
|
||||
</div>
|
||||
<v-text-field
|
||||
v-model="manual.callsign"
|
||||
label="Callsign"
|
||||
placeholder="DLH39A"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
color="cyan"
|
||||
prepend-inner-icon="mdi-radio-tower"
|
||||
hide-details
|
||||
@keyup.enter="startManual"
|
||||
/>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<v-text-field
|
||||
v-model="manual.dep"
|
||||
label="From (ICAO)"
|
||||
placeholder="EDDF"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
color="cyan"
|
||||
prepend-inner-icon="mdi-airplane-takeoff"
|
||||
maxlength="4"
|
||||
hide-details
|
||||
@keyup.enter="startManual"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="manual.arr"
|
||||
label="To (ICAO)"
|
||||
placeholder="EDDM"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
color="cyan"
|
||||
prepend-inner-icon="mdi-airplane-landing"
|
||||
maxlength="4"
|
||||
hide-details
|
||||
@keyup.enter="startManual"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<v-text-field
|
||||
v-model="manual.aircraft"
|
||||
label="Aircraft (opt.)"
|
||||
placeholder="A320/L"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
color="cyan"
|
||||
prepend-inner-icon="mdi-airplane"
|
||||
hide-details
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="manual.altitude"
|
||||
label="Cruise ft (opt.)"
|
||||
placeholder="36000"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
color="cyan"
|
||||
prepend-inner-icon="mdi-arrow-expand-vertical"
|
||||
inputmode="numeric"
|
||||
hide-details
|
||||
/>
|
||||
</div>
|
||||
<v-btn
|
||||
block
|
||||
color="cyan"
|
||||
variant="tonal"
|
||||
:disabled="!manualValid"
|
||||
@click="startManual"
|
||||
>
|
||||
Continue with this flight
|
||||
</v-btn>
|
||||
</div>
|
||||
</SetupCard>
|
||||
|
||||
<!-- Demo Mode -->
|
||||
<SetupCard>
|
||||
<div class="space-y-4">
|
||||
|
||||
@@ -713,6 +713,24 @@ export function useLiveAtcSession(
|
||||
currentScreen.value = 'scenario'
|
||||
}
|
||||
|
||||
/** Start from a manually entered flight instead of VATSIM / demo. */
|
||||
const startManualFlight = (plan: {
|
||||
callsign: string
|
||||
dep: string
|
||||
arr: string
|
||||
aircraft?: string
|
||||
altitude?: string
|
||||
}) => {
|
||||
selectedPlan.value = {
|
||||
callsign: plan.callsign.trim().toUpperCase(),
|
||||
aircraft: plan.aircraft?.trim().toUpperCase() || 'A320/L',
|
||||
dep: plan.dep.trim().toUpperCase(),
|
||||
arr: plan.arr.trim().toUpperCase(),
|
||||
altitude: plan.altitude?.trim() || '36000',
|
||||
}
|
||||
currentScreen.value = 'scenario'
|
||||
}
|
||||
|
||||
/** Launch a specific scenario with the current flight plan. */
|
||||
const launchScenario = async (scenario: Scenario) => {
|
||||
if (!selectedPlan.value) return
|
||||
@@ -833,6 +851,7 @@ export function useLiveAtcSession(
|
||||
loadFlightPlans,
|
||||
startMonitoring,
|
||||
startDemoFlight,
|
||||
startManualFlight,
|
||||
launchScenario,
|
||||
flyAgain,
|
||||
backToSetup,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
:error="error"
|
||||
@load-flight-plans="loadFlightPlans"
|
||||
@start-demo="startDemoFlight"
|
||||
@start-manual="startManualFlight"
|
||||
/>
|
||||
|
||||
<FlightSelectStep
|
||||
@@ -603,6 +604,7 @@ const {
|
||||
loadFlightPlans,
|
||||
startMonitoring,
|
||||
startDemoFlight,
|
||||
startManualFlight,
|
||||
launchScenario,
|
||||
flyAgain,
|
||||
backToSetup,
|
||||
|
||||
Reference in New Issue
Block a user