rework Menu Bar / Rework socketioStore

This commit is contained in:
2026-03-21 07:33:12 -04:00
parent 8214f0543a
commit 3f3a5136eb
24 changed files with 1278 additions and 526 deletions

View File

@@ -1,106 +1,65 @@
<script setup lang="ts">
import { useLeafletStore } from 'stores/leaflet';
import type { coords } from 'src/types';
import type { Control, coords, CtrlAttr, CtrlAttrs } from 'components/models';
import { storeToRefs } from 'pinia';
import { socket } from 'boot/socket';
import { socket } from 'boot/socketio';
import ConfirmCommandDialog from 'components/ConfirmCommandDiaglog.vue';
import { useQuasar } from 'quasar';
import { useRoute } from 'vue-router';
import { useSocketioStore } from 'stores/socketio';
import { ref } from 'vue';
import { favorites } from 'constants/favorites';
import { controls } from 'constants/controls';
const route = useRoute();
const $q = useQuasar();
const leafletStore = useLeafletStore();
const socketStore = useSocketioStore();
const { center, markerLatLng } = storeToRefs(leafletStore);
const home = {
name: 'Home',
coords: {
lat: 40.71278,
lng: -74.00594,
},
icon: 'home',
};
interface Control {
id: number;
name: string;
cmd: string;
icon: string;
confirm: boolean;
}
const { simulationRunning, simulationState, simulationQueueLength } = storeToRefs(socketStore);
const controls: Control[] = [
{
id: 1,
name: 'Start Location Sim',
cmd: 'start_location_simulation',
icon: 'play_arrow',
confirm: false,
},
{
id: 3,
name: 'End Location Sim',
cmd: 'end_location_simulation',
icon: 'stop',
confirm: true,
},
{
id: 3,
name: 'Shutdown',
cmd: 'shutdown',
icon: 'power_settings_new',
confirm: true,
},
];
const menuOpen = ref();
const favorites = [
{
id: 1,
name: 'Central Park',
coords: {
lat: 40.785091,
lng: -73.968285,
},
icon: 'park',
},
{
id: 2,
name: 'Times Square',
coords: {
lat: 40.758896,
lng: -73.98513,
},
icon: 'star',
},
{
id: 3,
name: 'Empire State Building',
coords: {
lat: 40.748817,
lng: -73.985428,
},
icon: 'building',
},
];
function handleFavClick(coords: coords) {
center.value = [coords.lat, coords.lng];
markerLatLng.value = [coords.lat, coords.lng];
}
function handleControlClick(ctrl: Control) {
if (ctrl.confirm) {
function handleControlClick(cmdAttr: CtrlAttr) {
if (cmdAttr.cnfrm) {
$q.dialog({
component: ConfirmCommandDialog,
componentProps: {
name: ctrl.name,
name: cmdAttr.name,
},
})
.onOk(() => {
socket.emit('command', ctrl.cmd, (response) => {
console.log(response.status);
});
if (cmdAttr.cmdClass === 'simulation_control') {
try {
const ack = socketStore.simulationControl(cmdAttr.cmd, cmdAttr.delay);
$q.notify({ type: 'positive', message: ack });
} catch (error: unknown) {
if (error instanceof Error) {
console.error('Simulation Command ERROR: ', error.message);
const ack = `Simulation Command Error: ${error.message}`;
$q.notify({ type: 'negative', message: ack });
} else {
console.error('Simmulation Command Error: ', error);
const ack = 'Simulation Command Error: Unknow error';
$q.notify({ type: 'negative', message: ack });
}
}
}
if (ctrl.cmdClass === 'device_control') {
socket.emit('device_control', { command: ctrl.cmd, delay: 0 }, (response) => {
console.log(response.status, response.command);
});
}
})
.onCancel(() => {
console.log('Dialog cancelled');
@@ -109,9 +68,25 @@ function handleControlClick(ctrl: Control) {
console.log('Dialog dismissed');
});
} else {
socket.emit('command', ctrl.cmd, (response) => {
console.log(response.status);
});
if (ctrl.cmdClass === 'simulation_control') {
try {
const response = socketStore.simulationControl(ctrl.cmd);
$q.notify({ type: 'positive', message: response });
} catch (error: unknown) {
if (error instanceof Error) {
console.error('Error: ' + error.message);
$q.notify({ type: 'negative', message: error.toString() });
} else {
console.error('Error setting location:', error);
$q.notify({ type: 'negative', message: error.toString() });
}
}
}
if (ctrl.cmdClass === 'device_control') {
socket.emit('device_control', { command: ctrl.cmd, delay: 0 }, (response) => {
console.log(response.status, response.command);
});
}
}
}
</script>
@@ -119,49 +94,148 @@ function handleControlClick(ctrl: Control) {
<template>
<q-toolbar class="bg-primary text-white">
<q-btn @click="$emit('drawer')" flat round dense icon="menu" class="q-mr-sm" />
<q-separator dark vertical inset />
<q-separator dark inset />
<q-space />
<q-btn
stretch
flat
:icon="home.icon"
@click="handleFavClick(home.coords)"
v-if="route.name === 'Leaflet'"
/>
<q-btn-dropdown stretch flat label="Favorites" v-if="route.name === 'Leaflet'">
<q-list>
<q-item
v-for="fav in favorites"
:key="fav.id"
clickable
v-ripple
v-close-popup
@click="handleFavClick(fav.coords)"
>
<q-item-section avatar>
<q-avatar :icon="fav.icon" color="primary" text-color="white" />
</q-item-section>
<q-item-section>
<q-item-label>{{ fav.name }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<q-btn :icon-right="menuOpen ? 'arrow_drop_up' : 'arrow_drop_down'" stretch flat label="Favorites" v-if="route.name === 'Leaflet'">
<q-menu @show="menuOpen = true" @hide="menuOpen = false" anchor="bottom end" self="top end">
<q-list>
<template v-for="fav, index) in favorites" :key="index">
<q-item
v-if="fav.coords"
clickable
v-ripple
v-close-popup
@click="handleFavClick(fav.coords)"
>
<q-item-section avatar>
<q-avatar :icon="fav.icon" color="primary" text-color="white" />
</q-item-section>
<q-item-section>
<q-item-label>{{ fav.name }}</q-item-label>
</q-item-section>
</q-item>
<q-item v-else clickable v-ripple>
<q-item-section avatar>
<q-avatar :icon="fav.icon" color="primary" text-color="white" />
</q-item-section>
<q-item-section>
<q-item-label>{{ fav.name }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-icon name="keyboard_arrow_right" />
</q-item-section>
<q-menu anchor="top end" self="top start">
<q-list>
<q-item
v-for="(f, indx) in fav.subitems"
:key="indx"
clickable
v-ripple
v-close-popup
@click="handleFavClick(f.coords)"
>
<q-item-section avatar>
<q-avatar :icon="f.icon" color="primary" text-color="white" />
</q-item-section>
<q-item-section>
<q-item-label>{{ f.name }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-item>
</template>
</q-list>
</q-menu>
</q-btn>
<q-btn-dropdown stretch flat label="Controls">
<q-list>
<q-item-label header>Simulation Controls</q-item-label>
<q-item
v-for="ctrl in controls"
:key="ctrl.id"
v-if="!simulationRunning"
clickable
v-ripple
v-close-popup
@click="handleControlClick(ctrl)"
>
@click="handleControlClick(controls.sim_start)">
<q-item-section avatar>
<q-avatar :icon="ctrl.icon" color="primary" text-color="white" />
<q-avatar :icon="controls.sim_start.icon" color="primary" text-color="white" />
</q-item-section>
<q-item-section>
<q-item-label>{{ ctrl.name }}</q-item-label>
<q-item-label> {{ controls.sim_start.name }} </q-item-label>
</q-item-section>
</q-item>
<q-item
v-if="simulationState === 'RUNNING' && simulationRunning"
clickable
v-ripple
v-close-popup
@click="handleControlClick(controls.sim_pause)"
>
<q-item-section avatar>
<q-avatar :icon="controls.sim_pause.icon" color="primary" text-color="white" />
</q-item-section>
<q-item-section>
<q-item-label> {{ controls.sim_pause.name }} </q-item-label>
</q-item-section>
</q-item>
<q-item
v-if="simulationState === 'PAUSED'"
clickable
v-ripple
v-close-popup
@click="handleControlClick(controls.sim_resume)"
>
<q-item-section avatar>
<q-avatar :icon="controls.sim_resume.icon" color="primary" text-color="white" />
</q-item-section>
<q-item-section>
<q-item-label> {{ controls.sim_resume.name }} </q-item-label>
</q-item-section>
</q-item>
<q-item
v-if="simulationQueueLength > 0"
clickable
v-ripple
v-close-popup
@click="handleControlClick(controls.sim_clear)"
>
<q-item-section avatar>
<q-avatar :icon="controls.sim_clear.icon" color="primary" text-color="white" />
</q-item-section>
<q-item-section>
<q-item-label> {{ controls.sim_clear.name }} </q-item-label>
</q-item-section>
</q-item>
<q-item
v-if="simulationRunning"
clickable
v-ripple
v-close-popup
@click="handleControlClick(controls.sim_end)"
>
<q-item-section avatar>
<q-avatar :icon="controls.sim_end.icon" color="primary" text-color="white" />
</q-item-section>
<q-item-section>
<q-item-label> {{ controls.sim_end.name }} </q-item-label>
</q-item-section>
</q-item>
<q-separator spaced />
<q-item-label header>Device Controls</q-item-label>
<q-item clickable v-ripple v-close-popup @click="handleControlClick(controls.dev_reboot)">
<q-item-section avatar>
<q-avatar :icon="controls.dev_reboot.icon" color="primary" text-color="white" />
</q-item-section>
<q-item-section>
<q-item-label> {{ controls.dev_reboot.name }} </q-item-label>
</q-item-section>
</q-item>
<q-item clickable v-ripple v-close-popup @click="handleControlClick(controls.dev_shutdown)">
<q-item-section avatar>
<q-avatar :icon="controls.dev_shutdown.icon" color="primary" text-color="white" />
</q-item-section>
<q-item-section>
<q-item-label> {{ controls.dev_shutdown.name }} </q-item-label>
</q-item-section>
</q-item>
</q-list>