lots of changes
This commit is contained in:
3410
package-lock.json
generated
3410
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,8 @@
|
|||||||
"postinstall": "quasar prepare"
|
"postinstall": "quasar prepare"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.16.4",
|
"@lucide/vue": "^1.7.0",
|
||||||
|
"@quasar/extras": "^1.18.0",
|
||||||
"@sentry/tracing": "^7.120.4",
|
"@sentry/tracing": "^7.120.4",
|
||||||
"@sentry/vue": "^10.47.0",
|
"@sentry/vue": "^10.47.0",
|
||||||
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
||||||
@@ -27,14 +28,14 @@
|
|||||||
"leaflet-routing-machine": "^3.2.12",
|
"leaflet-routing-machine": "^3.2.12",
|
||||||
"openrouteservice-js": "^0.4.1",
|
"openrouteservice-js": "^0.4.1",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"quasar": "^2.16.0",
|
"quasar": "^2.19.3",
|
||||||
"socket.io-client": "^4.8.3",
|
"socket.io-client": "^4.8.3",
|
||||||
"vue": "^3.5.22",
|
"vue": "^3.5.22",
|
||||||
"vue-router": "^5.0.0"
|
"vue-router": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.14.0",
|
"@eslint/js": "^9.14.0",
|
||||||
"@quasar/app-vite": "^2.1.0",
|
"@quasar/app-vite": "^2.6.0",
|
||||||
"@types/leaflet": "^1.9.21",
|
"@types/leaflet": "^1.9.21",
|
||||||
"@types/leaflet-contextmenu": "^1.4.4",
|
"@types/leaflet-contextmenu": "^1.4.4",
|
||||||
"@types/node": "^20.5.9",
|
"@types/node": "^20.5.9",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
style="height: 600px; max-width: 800px; width: 100vw"
|
style="height: 600px; max-width: 800px; width: 100vw"
|
||||||
class="rounded-borders"
|
class="rounded-borders"
|
||||||
>
|
>
|
||||||
<q-footer :class="$q.dark.isActive ? 'bg-primary' : 'bg-black'" style="height: 48px">
|
<q-footer :class="$q.dark.isActive ? 'bg-primary' : 'bg-black'" class="z-top" style="height: 48px">
|
||||||
<q-toolbar>
|
<q-toolbar>
|
||||||
<q-btn
|
<q-btn
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
@@ -49,9 +49,9 @@
|
|||||||
</q-footer>
|
</q-footer>
|
||||||
<q-drawer
|
<q-drawer
|
||||||
v-model="qLocDrawer"
|
v-model="qLocDrawer"
|
||||||
|
behavior="mobile"
|
||||||
show-if-above
|
show-if-above
|
||||||
overlay
|
:width="300"
|
||||||
:width="250"
|
|
||||||
side="left"
|
side="left"
|
||||||
:breakpoint="500"
|
:breakpoint="500"
|
||||||
@mouseenter="miniState = false"
|
@mouseenter="miniState = false"
|
||||||
@@ -64,25 +64,48 @@
|
|||||||
><span class="bold">Location Queue: </span> {{ simulationState }}</q-item-label
|
><span class="bold">Location Queue: </span> {{ simulationState }}</q-item-label
|
||||||
>
|
>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
<LocationMark
|
<div
|
||||||
v-for="(key, index) in locationQueueOrder"
|
v-for="(key, index) in locationQueueOrderFiltered"
|
||||||
:key="key"
|
:key="key"
|
||||||
:loc_id="key"
|
@contextmenu.prevent="onDrawerContextMenu($event, key)"
|
||||||
:active="
|
>
|
||||||
(locationQueueData as Record<string, any>)[key]?.loc_id === currentLocation?.loc_id
|
<LocationItem
|
||||||
"
|
:loc_id="key"
|
||||||
:index="index"
|
:active="
|
||||||
:isLast="index != locationQueueOrder.length - 1"
|
(locationQueueData as Record<string, any>)[key]?.loc_id ===
|
||||||
:start="(locationQueueData as Record<string, any>)[key]?.start ?? ''"
|
currentLocation?.loc_id
|
||||||
:address="(locationQueueData as Record<string, any>)[key]?.address ?? ''"
|
"
|
||||||
:latitude="(locationQueueData as Record<string, any>)[key]?.latitude ?? 0"
|
:isCurrentDelay="
|
||||||
:longitude="(locationQueueData as Record<string, any>)[key]?.longitude ?? 0"
|
(locationQueueData as Record<string, any>)[key]?.loc_id ===
|
||||||
:delay="(locationQueueData as Record<string, any>)[key]?.delay ?? 0"
|
locationQueueOrderFiltered[index + 1]
|
||||||
:end="(locationQueueData as Record<string, any>)[key]?.end ?? undefined"
|
"
|
||||||
@item-clicked="zoomToCoods"
|
:index="index"
|
||||||
/>
|
:isLast="index == locationQueueOrderFiltered.length - 1"
|
||||||
|
:start="(locationQueueData as Record<string, any>)[key]?.start ?? ''"
|
||||||
|
:address="(locationQueueData as Record<string, any>)[key]?.address ?? ''"
|
||||||
|
:latitude="(locationQueueData as Record<string, any>)[key]?.latitude ?? 0"
|
||||||
|
:longitude="(locationQueueData as Record<string, any>)[key]?.longitude ?? 0"
|
||||||
|
:delay="(locationQueueData as Record<string, any>)[key]?.delay ?? 0"
|
||||||
|
:end="(locationQueueData as Record<string, any>)[key]?.end ?? undefined"
|
||||||
|
:status="(locationQueueData as Record<string, any>)[key]?.status ?? undefined"
|
||||||
|
@item-clicked="zoomToCoords"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</q-list>
|
</q-list>
|
||||||
</q-scroll-area>
|
</q-scroll-area>
|
||||||
|
<q-menu ref="contextMenu" context-menu touch-position>
|
||||||
|
<q-list>
|
||||||
|
<q-item clickable ripple v-close-popup @click="handleDrawerContextMenu('zoom')">
|
||||||
|
<q-item-section label="Zoom to Location"> Zoom </q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item clickable ripple v-close-popup @click="handleDrawerContextMenu('delete')">
|
||||||
|
<q-item-section label="Zoom to Location"> Delete </q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item clickable ripple v-close-popup @click="handleDrawerContextMenu('gp')">
|
||||||
|
<q-item-section label="Zoom to Location"> Go Now </q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
</q-drawer>
|
</q-drawer>
|
||||||
|
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
@@ -151,7 +174,7 @@
|
|||||||
</L-Layer-Group>
|
</L-Layer-Group>
|
||||||
<L-Layer-Group v-if="locationQueueOrder">
|
<L-Layer-Group v-if="locationQueueOrder">
|
||||||
<L-Marker
|
<L-Marker
|
||||||
v-for="locid in locationQueueOrder"
|
v-for="locid in locationQueueOrderFiltered"
|
||||||
:key="locid"
|
:key="locid"
|
||||||
:icon="getCustomIcon(locid) as any"
|
:icon="getCustomIcon(locid) as any"
|
||||||
:lat-lng="[
|
:lat-lng="[
|
||||||
@@ -174,12 +197,16 @@
|
|||||||
v-if="findMyUpdate"
|
v-if="findMyUpdate"
|
||||||
:icon="fmIcon as any"
|
:icon="fmIcon as any"
|
||||||
:lat-lng="[findMyUpdate.latitude ?? 0, findMyUpdate.longitude ?? 0]"
|
:lat-lng="[findMyUpdate.latitude ?? 0, findMyUpdate.longitude ?? 0]"
|
||||||
></L-Marker>
|
>
|
||||||
|
<L-Tooltip>
|
||||||
|
{{ findMyTimePast }}
|
||||||
|
</L-Tooltip>
|
||||||
|
</L-Marker>
|
||||||
<L-Circle
|
<L-Circle
|
||||||
:fillOpacity="0.5"
|
:fillOpacity="0.5"
|
||||||
:lat-lng="[findMyUpdate.latitude ?? 0, findMyUpdate.longitude ?? 0]"
|
:lat-lng="[findMyUpdate.latitude ?? 0, findMyUpdate.longitude ?? 0]"
|
||||||
:radius="findMyUpdate.horizontalAccuracy"
|
:radius="findMyUpdate.horizontalAccuracy"
|
||||||
color="firebrick"
|
color="#f5bb39"
|
||||||
fillColor="indianred"
|
fillColor="indianred"
|
||||||
></L-Circle>
|
></L-Circle>
|
||||||
</L-Layer-Group>
|
</L-Layer-Group>
|
||||||
@@ -193,33 +220,43 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import { computed, onMounted, reactive, ref } from 'vue';
|
import { computed, markRaw, onMounted, onUnmounted, reactive, ref } from 'vue';
|
||||||
|
|
||||||
// Leaflet imports
|
// Leaflet imports
|
||||||
import { GeoSearchControl, OpenStreetMapProvider } from 'leaflet-geosearch';
|
import { GeoSearchControl, OpenStreetMapProvider } from 'leaflet-geosearch';
|
||||||
import 'leaflet-routing-machine/dist/leaflet-routing-machine.css';
|
import 'leaflet-routing-machine/dist/leaflet-routing-machine.css';
|
||||||
import { Icon, PinCirclePanel, PinStarPanel } from 'leaflet-extra-markers';
|
import {
|
||||||
|
Icon,
|
||||||
|
PinCirclePanel,
|
||||||
|
PinStarPanel,
|
||||||
|
PinTriangle,
|
||||||
|
PinSquare,
|
||||||
|
ChipCircle,
|
||||||
|
} from 'leaflet-extra-markers';
|
||||||
import 'leaflet-geosearch/dist/geosearch.css';
|
import 'leaflet-geosearch/dist/geosearch.css';
|
||||||
import 'leaflet/dist/leaflet.css';
|
import 'leaflet/dist/leaflet.css';
|
||||||
import { LCircle, LLayerGroup, LMap, LMarker, LPopup, LTileLayer } from '@vue-leaflet/vue-leaflet';
|
import {
|
||||||
|
LCircle,
|
||||||
|
LLayerGroup,
|
||||||
|
LMap,
|
||||||
|
LMarker,
|
||||||
|
LPopup,
|
||||||
|
LTileLayer,
|
||||||
|
LTooltip,
|
||||||
|
} from '@vue-leaflet/vue-leaflet';
|
||||||
import * as LeafLet from 'leaflet';
|
import * as LeafLet from 'leaflet';
|
||||||
|
|
||||||
// Custom Components
|
// Custom Components
|
||||||
import LRoutingMachine from 'components/LRoutingMachine.vue';
|
import LRoutingMachine from 'components/LRoutingMachine.vue';
|
||||||
import LocationMark from 'components/LocationMark.vue';
|
import LocationItem from 'components/LocationItem.vue';
|
||||||
import SetLocationDialog from 'components/SetLocationDialog.vue';
|
import SetLocationDialog from 'components/SetLocationDialog.vue';
|
||||||
import { customRouter } from 'functions/serviceURL';
|
import { customRouter } from 'functions/serviceURL';
|
||||||
//import { reverseGeocodeRateLimited } from 'functions/reverseGeocode';
|
|
||||||
import { useRoutingEvents } from '../composables/useRoutingEvents';
|
import { useRoutingEvents } from '../composables/useRoutingEvents';
|
||||||
import { useMarkerContextMenu } from '../composables/useMarkerContextMenu';
|
import { useMarkerContextMenu } from '../composables/useMarkerContextMenu';
|
||||||
import type { IRouter } from 'leaflet-routing-machine';
|
import type { IRouter } from 'leaflet-routing-machine';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type {
|
import type { coords, SearchControlProps } from 'components/models';
|
||||||
coords,
|
|
||||||
SearchControlProps,
|
|
||||||
// NominatimAddress,
|
|
||||||
} from 'components/models';
|
|
||||||
import type { LeafletMouseEvent, Map } from 'leaflet';
|
import type { LeafletMouseEvent, Map } from 'leaflet';
|
||||||
|
|
||||||
// Stores
|
// Stores
|
||||||
@@ -245,6 +282,7 @@ const {
|
|||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
|
|
||||||
|
const now = ref(Date.now());
|
||||||
const mapRef = ref();
|
const mapRef = ref();
|
||||||
const responseMessage = ref('');
|
const responseMessage = ref('');
|
||||||
const miniState = ref(true);
|
const miniState = ref(true);
|
||||||
@@ -295,11 +333,52 @@ const fmIcon = new Icon({
|
|||||||
svg: PinCirclePanel,
|
svg: PinCirclePanel,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const startIcon = new Icon({
|
||||||
|
color: '#006838',
|
||||||
|
accentColor: 'rgba(0,0,0,0.25)',
|
||||||
|
content: 'S',
|
||||||
|
contentColor: 'white',
|
||||||
|
scale: 1,
|
||||||
|
svg: PinTriangle,
|
||||||
|
});
|
||||||
|
|
||||||
|
const endIcon = new Icon({
|
||||||
|
color: '#a23337',
|
||||||
|
accentColor: 'rgba(0,0,0,0.25)',
|
||||||
|
content: 'E',
|
||||||
|
contentColor: 'white',
|
||||||
|
scale: 1,
|
||||||
|
svg: PinSquare,
|
||||||
|
});
|
||||||
|
|
||||||
|
const intermediateIcon = new Icon({
|
||||||
|
color: 'cornflowerblue',
|
||||||
|
accentColor: 'rgba(0,0,0,0.25)',
|
||||||
|
contentColor: 'white',
|
||||||
|
svg: ChipCircle,
|
||||||
|
scale: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
type RoutingWaypoint = {
|
||||||
|
latLng: LeafLet.LatLng;
|
||||||
|
};
|
||||||
|
|
||||||
|
const locationQueueOrderFiltered = computed(() => {
|
||||||
|
if (locationQueueOrder.value) {
|
||||||
|
return locationQueueOrder.value.filter(
|
||||||
|
(loc_id) => locationQueueData.value[loc_id]?.status !== 'deleted',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const getCustomIcon = (locid: string) => {
|
const getCustomIcon = (locid: string) => {
|
||||||
const currentIndex = currentLocation.value
|
const currentIndex = currentLocation.value
|
||||||
? locationQueueOrder.value.indexOf(currentLocation.value.loc_id)
|
? locationQueueOrderFiltered.value.indexOf(currentLocation.value.loc_id)
|
||||||
: 0;
|
: 0;
|
||||||
const locationIndex = locationQueueOrder.value.indexOf(locid);
|
const locationIndex = locationQueueOrderFiltered.value.indexOf(locid);
|
||||||
|
const updatedIndex = (locationIndex - currentIndex);
|
||||||
if (currentLocation.value && currentLocation.value.loc_id === locid) {
|
if (currentLocation.value && currentLocation.value.loc_id === locid) {
|
||||||
return new Icon({
|
return new Icon({
|
||||||
color: 'pink',
|
color: 'pink',
|
||||||
@@ -310,24 +389,52 @@ const getCustomIcon = (locid: string) => {
|
|||||||
svg: PinStarPanel,
|
svg: PinStarPanel,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return new Icon({
|
if(updatedIndex > 0) {
|
||||||
color: 'blue',
|
return new Icon({
|
||||||
accentColor: 'firebrick',
|
color: 'blue',
|
||||||
content: (locationIndex - currentIndex).toString(),
|
accentColor: 'firebrick',
|
||||||
contentColor: 'white',
|
content: updatedIndex.toString(),
|
||||||
scale: 1,
|
contentColor: 'white',
|
||||||
svg: PinCirclePanel,
|
scale: 1,
|
||||||
});
|
svg: PinCirclePanel,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new Icon({
|
||||||
|
color: 'black',
|
||||||
|
accentColor: 'grey',
|
||||||
|
content: updatedIndex.toString(),
|
||||||
|
contentColor: 'white',
|
||||||
|
scale: 1,
|
||||||
|
svg: PinCirclePanel,
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const routingOptions = reactive<{
|
const routingOptions = reactive<{
|
||||||
waypoints: LeafLet.LatLng[];
|
waypoints: LeafLet.LatLng[];
|
||||||
router: IRouter;
|
router: IRouter;
|
||||||
routeWhileDragging: boolean;
|
routeWhileDragging: boolean;
|
||||||
|
createMarker: (i: number, waypoint: RoutingWaypoint, n: number) => LeafLet.Marker | false;
|
||||||
}>({
|
}>({
|
||||||
waypoints: [],
|
createMarker: function (i, waypoint, n) {
|
||||||
router: customRouter as unknown as IRouter,
|
let icon;
|
||||||
|
if (i === 0) {
|
||||||
|
icon = startIcon;
|
||||||
|
} else if (i === n - 1) {
|
||||||
|
icon = endIcon;
|
||||||
|
} else {
|
||||||
|
icon = intermediateIcon;
|
||||||
|
}
|
||||||
|
return LeafLet.marker(waypoint.latLng, {
|
||||||
|
draggable: true,
|
||||||
|
icon,
|
||||||
|
contextmenu: false,
|
||||||
|
contextmenuItems: [],
|
||||||
|
});
|
||||||
|
},
|
||||||
routeWhileDragging: true,
|
routeWhileDragging: true,
|
||||||
|
router: markRaw(customRouter),
|
||||||
|
waypoints: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const { handleRoutesFound } = useRoutingEvents();
|
const { handleRoutesFound } = useRoutingEvents();
|
||||||
@@ -355,7 +462,7 @@ async function routeToQueue() {
|
|||||||
if (routeDirections.value && routeDirections.value.length > 0) {
|
if (routeDirections.value && routeDirections.value.length > 0) {
|
||||||
for (const direction of routeDirections.value) {
|
for (const direction of routeDirections.value) {
|
||||||
if (direction.coordinates) {
|
if (direction.coordinates) {
|
||||||
await setLocation(
|
await addLocation(
|
||||||
{ lat: Number(direction.coordinates.lat), lng: Number(direction.coordinates.lng) },
|
{ lat: Number(direction.coordinates.lat), lng: Number(direction.coordinates.lng) },
|
||||||
direction.time,
|
direction.time,
|
||||||
);
|
);
|
||||||
@@ -415,6 +522,45 @@ const { clickedLatLng, handleMarkerClick, setStartRoute, setEndRoute } = useMark
|
|||||||
closeAllPopups,
|
closeAllPopups,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const selectedItem = ref();
|
||||||
|
const contextMenu = ref();
|
||||||
|
|
||||||
|
function onDrawerContextMenu(e: MouseEvent, item: string) {
|
||||||
|
console.log('onDrawerContextMenu: ', item);
|
||||||
|
selectedItem.value = item;
|
||||||
|
}
|
||||||
|
function handleDrawerContextMenu(command: string) {
|
||||||
|
let notType: string = 'positive';
|
||||||
|
let notMsg: string = '';
|
||||||
|
switch (command) {
|
||||||
|
case 'zoom':
|
||||||
|
zoomTo(selectedItem.value);
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
try {
|
||||||
|
const ack = socketStore.simulationControl('delete', 0, selectedItem.value);
|
||||||
|
if (ack.sts === 'error') {
|
||||||
|
notType = 'negative';
|
||||||
|
}
|
||||||
|
if (ack.msg) {
|
||||||
|
notMsg = ack.msg;
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
notType = 'negative';
|
||||||
|
if (error instanceof Error) {
|
||||||
|
console.error('Simulation Command ERROR: ', error.message);
|
||||||
|
notMsg = `Simulation Command Error: ${error.message}`;
|
||||||
|
} else {
|
||||||
|
console.error('Simulation Command Error: ', error);
|
||||||
|
notMsg = 'Simulation Command Error: Unknow error';
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
$q.notify({ type: notType, message: notMsg });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$q.notify(`context menu: ${command} ${selectedItem.value}`);
|
||||||
|
}
|
||||||
|
|
||||||
function handleAddLocation() {
|
function handleAddLocation() {
|
||||||
if (clickedLatLng.value) {
|
if (clickedLatLng.value) {
|
||||||
const latlng = clickedLatLng.value;
|
const latlng = clickedLatLng.value;
|
||||||
@@ -431,8 +577,8 @@ function handleAddLocation() {
|
|||||||
// address: NomAddress,
|
// address: NomAddress,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.onOk((delay: number) => {
|
.onOk(({ delay, address }) => {
|
||||||
void setLocation({ lat: Number(latlng.lat), lng: Number(latlng.lng) }, delay);
|
void addLocation({ lat: Number(latlng.lat), lng: Number(latlng.lng) }, delay, address);
|
||||||
console.log(
|
console.log(
|
||||||
'Confirmed location add: latitude: ' +
|
'Confirmed location add: latitude: ' +
|
||||||
latlng.lat +
|
latlng.lat +
|
||||||
@@ -470,11 +616,18 @@ async function reverseGeocode(lat: number, lng: number) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async function setLocation(coords: coords, delay: number) {
|
async function addLocation(coords: coords, delay: number, address?: string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let notType: string = 'positive';
|
let notType: string = 'positive';
|
||||||
try {
|
try {
|
||||||
const setCmdRsp = socketStore.simulationControl('add', delay, coords.lat, coords.lng);
|
const setCmdRsp = socketStore.simulationControl(
|
||||||
|
'add',
|
||||||
|
coords.lat,
|
||||||
|
coords.lng,
|
||||||
|
'',
|
||||||
|
delay,
|
||||||
|
address,
|
||||||
|
);
|
||||||
if (setCmdRsp.msg) {
|
if (setCmdRsp.msg) {
|
||||||
responseMessage.value = setCmdRsp.msg;
|
responseMessage.value = setCmdRsp.msg;
|
||||||
}
|
}
|
||||||
@@ -500,7 +653,7 @@ async function setLocation(coords: coords, delay: number) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function zoomToCoods(arg: string) {
|
function zoomToCoords(arg: string) {
|
||||||
const item = locationQueueData.value[arg];
|
const item = locationQueueData.value[arg];
|
||||||
if (!item || item.latitude == null || item.longitude == null) {
|
if (!item || item.latitude == null || item.longitude == null) {
|
||||||
return;
|
return;
|
||||||
@@ -510,6 +663,28 @@ function zoomToCoods(arg: string) {
|
|||||||
qLocDrawer.value = false;
|
qLocDrawer.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const findMyTimePast = computed(() => {
|
||||||
|
if (findMyUpdate.value) {
|
||||||
|
const diffInMs = Math.abs(now.value - findMyUpdate.value.timeStamp);
|
||||||
|
const seconds = Math.floor((diffInMs / 1000) % 60);
|
||||||
|
const minutes = Math.floor((diffInMs / (1000 * 60)) % 60);
|
||||||
|
const hours = Math.floor((diffInMs / (1000 * 60 * 60)) % 24);
|
||||||
|
const days = Math.floor(diffInMs / (1000 * 60 * 60 * 24));
|
||||||
|
|
||||||
|
if (days > 1) {
|
||||||
|
return days + ' days, ' + hours + ' hours, ' + minutes + 'minutes, ' + seconds + 'seconds ago'
|
||||||
|
} else if (hours > 1) {
|
||||||
|
return hours + ' hours, ' + minutes + 'minutes, ' + seconds + 'seconds ago'
|
||||||
|
} else if (minutes > 1) {
|
||||||
|
return minutes + ' minutes, ' + seconds + ' seconds ago';
|
||||||
|
} else {
|
||||||
|
return seconds + ' seconds ago'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 'Find My Location not available';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function zoomTo(loc: string) {
|
function zoomTo(loc: string) {
|
||||||
switch (loc) {
|
switch (loc) {
|
||||||
case 'fmLoc':
|
case 'fmLoc':
|
||||||
@@ -543,6 +718,7 @@ function zoomTo(loc: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const timer = ref();
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (findMyUpdate.value && findMyUpdate.value.latitude && findMyUpdate.value.longitude) {
|
if (findMyUpdate.value && findMyUpdate.value.latitude && findMyUpdate.value.longitude) {
|
||||||
leafletStore.setCenter(findMyUpdate.value.latitude, findMyUpdate.value.longitude);
|
leafletStore.setCenter(findMyUpdate.value.latitude, findMyUpdate.value.longitude);
|
||||||
@@ -551,6 +727,12 @@ onMounted(() => {
|
|||||||
leafletStore.setCenter(favorites.home.coords.lat, favorites.home.coords.lng);
|
leafletStore.setCenter(favorites.home.coords.lat, favorites.home.coords.lng);
|
||||||
}
|
}
|
||||||
socketStore.requestUpdate();
|
socketStore.requestUpdate();
|
||||||
|
timer.value = setInterval(() => {
|
||||||
|
now.value = Date.now();
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearInterval(timer.value);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import { storeToRefs } from 'pinia';
|
|||||||
import { useSocketioStore } from 'stores/socketio';
|
import { useSocketioStore } from 'stores/socketio';
|
||||||
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
||||||
import type { NominatimResponse } from 'components/models';
|
import type { NominatimResponse } from 'components/models';
|
||||||
|
|
||||||
import { Icon, PinCirclePanel } from 'leaflet-extra-markers';
|
import { Icon, PinCirclePanel } from 'leaflet-extra-markers';
|
||||||
|
|
||||||
import FormattedAddress from 'components/FormattedAddress.vue';
|
import FormattedAddress from 'components/FormattedAddress.vue';
|
||||||
|
|
||||||
const socketStore = useSocketioStore();
|
const socketStore = useSocketioStore();
|
||||||
const { currentLocation, locationQueueOrder, simulationRunning } = storeToRefs(socketStore);
|
const { currentLocation, locationQueueOrder, locationQueueData, simulationRunning } =
|
||||||
|
storeToRefs(socketStore);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
address: {
|
address: {
|
||||||
@@ -44,6 +44,10 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
isCurrentDelay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
loc_id: {
|
loc_id: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
@@ -56,6 +60,10 @@ const props = defineProps({
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
},
|
},
|
||||||
|
status: {
|
||||||
|
type: String,
|
||||||
|
default: 'queued',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Define custom events that this component can emit
|
// Define custom events that this component can emit
|
||||||
@@ -69,8 +77,30 @@ function itemClicked() {
|
|||||||
const currentTime = ref(new Date());
|
const currentTime = ref(new Date());
|
||||||
let timerId: number;
|
let timerId: number;
|
||||||
|
|
||||||
const calculateDeltaT = computed(() => {
|
function formatInAgo(seconds: number) {
|
||||||
let delta = '';
|
let delta;
|
||||||
|
if (seconds === 0) {
|
||||||
|
delta = 'now';
|
||||||
|
}
|
||||||
|
if (seconds > 0) {
|
||||||
|
const minutes: number = Math.floor(seconds / 60);
|
||||||
|
const hours: number = Math.floor(minutes / 60);
|
||||||
|
const days: number = Math.floor(hours / 24);
|
||||||
|
if (days > 0) {
|
||||||
|
delta = `in ${days} day${days > 1 ? 's' : ''}`;
|
||||||
|
} else if (hours > 0) {
|
||||||
|
delta = `in ${hours} hour${hours > 1 ? 's' : ''}`;
|
||||||
|
} else if (minutes > 0) {
|
||||||
|
delta = `in ${minutes} minute${minutes > 1 ? 's' : ''}`;
|
||||||
|
} else {
|
||||||
|
delta = `in ${seconds} second${seconds > 1 ? 's' : ''}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
const calculateDeltaTime = computed(() => {
|
||||||
|
let delta;
|
||||||
if (props.active) {
|
if (props.active) {
|
||||||
delta = 'now';
|
delta = 'now';
|
||||||
} else if (props.end && props.end !== '') {
|
} else if (props.end && props.end !== '') {
|
||||||
@@ -85,30 +115,24 @@ const calculateDeltaT = computed(() => {
|
|||||||
if (days > 0) {
|
if (days > 0) {
|
||||||
delta = `${days} day${days > 1 ? 's' : ''} ago`;
|
delta = `${days} day${days > 1 ? 's' : ''} ago`;
|
||||||
} else if (hours > 0) {
|
} else if (hours > 0) {
|
||||||
delta = `${hours} hour${hours > 1 ? 's' : ''} ago`;
|
delta = `${hours} hr${hours > 1 ? 's' : ''} ago`;
|
||||||
} else if (minutes > 0) {
|
} else if (minutes > 0) {
|
||||||
delta = `${minutes} minute${minutes > 1 ? 's' : ''} ago`;
|
delta = `${minutes} min${minutes > 1 ? 's' : ''} ago`;
|
||||||
} else {
|
} else {
|
||||||
delta = `${seconds} second${seconds > 1 ? 's' : ''} ago`;
|
delta = `${seconds} sec${seconds > 1 ? 's' : ''} ago`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const futureTime: Date = new Date(props.start);
|
let startSlice;
|
||||||
const nowMs: number = currentTime.value.getTime();
|
if (currentIndex.value > 0) {
|
||||||
const futureMs: number = futureTime.getTime();
|
startSlice = currentIndex.value;
|
||||||
const diffMs: number = Math.abs(nowMs - futureMs);
|
|
||||||
const seconds: number = Math.floor(diffMs / 1000);
|
|
||||||
const minutes: number = Math.floor(seconds / 60);
|
|
||||||
const hours: number = Math.floor(minutes / 60);
|
|
||||||
const days: number = Math.floor(hours / 24);
|
|
||||||
if (days > 0) {
|
|
||||||
delta = `in ${days} day${days > 1 ? 's' : ''}`;
|
|
||||||
} else if (hours > 0) {
|
|
||||||
delta = `in ${hours} hour${hours > 1 ? 's' : ''}`;
|
|
||||||
} else if (minutes > 0) {
|
|
||||||
delta = `in ${minutes} minute${minutes > 1 ? 's' : ''}`;
|
|
||||||
} else {
|
} else {
|
||||||
delta = `in ${seconds} second${seconds > 1 ? 's' : ''}`;
|
startSlice = 0;
|
||||||
}
|
}
|
||||||
|
const waitingFor = locationQueueOrder.value.slice(startSlice, myIndex.value + 1);
|
||||||
|
const willWait = waitingFor.reduce((sum, loc_id) => {
|
||||||
|
return sum + (locationQueueData.value[loc_id]?.delay || 0);
|
||||||
|
}, 0);
|
||||||
|
delta = formatInAgo(willWait);
|
||||||
}
|
}
|
||||||
return delta;
|
return delta;
|
||||||
});
|
});
|
||||||
@@ -124,8 +148,20 @@ const secondsToTime = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const secondsToTime = (seconds: number) => {
|
||||||
|
const hours = Math.floor(seconds / 3600);
|
||||||
|
const minutes = Math.floor((seconds % 3600) / 60);
|
||||||
|
const remainingSeconds = seconds % 60;
|
||||||
|
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${remainingSeconds
|
||||||
|
.toString()
|
||||||
|
.padStart(2, '0')}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const timeToSeconds = (timeIn: string) => {
|
||||||
|
const a = timeIn.split(':');
|
||||||
|
const seconds = +a[0] * 60 * 60 + +a[1] * 60 + +a[2];
|
||||||
|
return seconds;
|
||||||
|
};
|
||||||
*/
|
*/
|
||||||
const humanReadableDateTime = (iso: string) => {
|
const humanReadableDateTime = (iso: string) => {
|
||||||
return new Date(iso).toLocaleDateString('en-US', {
|
return new Date(iso).toLocaleDateString('en-US', {
|
||||||
@@ -234,14 +270,25 @@ const itemClass = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const customIcon = computed(() => {
|
const customIcon = computed(() => {
|
||||||
return new Icon({
|
if (myUpdatedIndex.value > 0) {
|
||||||
color: 'blue',
|
return new Icon({
|
||||||
accentColor: 'firebrick',
|
color: 'blue',
|
||||||
content: myUpdatedIndex.value.toString(),
|
accentColor: 'firebrick',
|
||||||
contentColor: 'white',
|
content: myUpdatedIndex.value.toString(),
|
||||||
scale: 1,
|
contentColor: 'white',
|
||||||
svg: PinCirclePanel,
|
scale: 1,
|
||||||
});
|
svg: PinCirclePanel,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new Icon({
|
||||||
|
color: 'black',
|
||||||
|
accentColor: 'grey',
|
||||||
|
content: myUpdatedIndex.value.toString(),
|
||||||
|
contentColor: 'white',
|
||||||
|
scale: 1,
|
||||||
|
svg: PinCirclePanel,
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const iconElement = computed(() => {
|
const iconElement = computed(() => {
|
||||||
@@ -256,14 +303,70 @@ onMounted(() => {
|
|||||||
timerId = requestAnimationFrame(update);
|
timerId = requestAnimationFrame(update);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const delayValue = computed({
|
||||||
|
get: () => props.delay,
|
||||||
|
set: (val) => socketStore.updateLocationMark(props.loc_id, 'delay', val),
|
||||||
|
});
|
||||||
|
|
||||||
|
const getDelayAttrs = computed(() => {
|
||||||
|
if (props.delay <= 260) {
|
||||||
|
return { units: 's', delay: props.delay, step: 10, max: 300 } as const;
|
||||||
|
} else if (props.delay <= 3600) {
|
||||||
|
return { units: 'm', delay: props.delay / 60, step: 60, max: 4500 } as const;
|
||||||
|
} else {
|
||||||
|
return { units: 'h', delay: props.delay / 3600, step: 3600, max: 21600 } as const;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const displayDelay = computed(() => {
|
||||||
|
return props.index > currentIndex.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const delayActive = computed(() => {
|
||||||
|
return props.index === currentIndex.value + 1;
|
||||||
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
cancelAnimationFrame(timerId);
|
cancelAnimationFrame(timerId);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-item v-ripple clickable :active="active" @click="itemClicked" :class="itemClass">
|
<q-item v-if="displayDelay" :active="delayActive">
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-icon name="access_time" color="secondary" />
|
||||||
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
|
<q-knob
|
||||||
|
show-value
|
||||||
|
v-model="delayValue"
|
||||||
|
size="50px"
|
||||||
|
color="secondary"
|
||||||
|
track-color="dark-page"
|
||||||
|
:step="getDelayAttrs.step"
|
||||||
|
:max="getDelayAttrs.max"
|
||||||
|
>
|
||||||
|
{{ getDelayAttrs.delay }} {{ getDelayAttrs.units }}
|
||||||
|
</q-knob>
|
||||||
|
<!--
|
||||||
|
<q-slider
|
||||||
|
v-model="delayValue"
|
||||||
|
:min="0"
|
||||||
|
:step="getDelayAttrs.step"
|
||||||
|
:max="getDelayAttrs.max"
|
||||||
|
label
|
||||||
|
markers
|
||||||
|
snap
|
||||||
|
label-always
|
||||||
|
:label-value="getDelayAttrs.delay + getDelayAttrs.units"
|
||||||
|
:marker-labels="markerLabel"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
-->
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-separator inset spaced v-if="displayDelay" />
|
||||||
|
<q-item v-ripple clickable :active="active" @click="itemClicked" :class="itemClass">
|
||||||
|
<q-item-section style="width: 70%">
|
||||||
<q-item-label>
|
<q-item-label>
|
||||||
<FormattedAddress :address="props.address" />
|
<FormattedAddress :address="props.address" />
|
||||||
<q-tooltip> {{ latitude }}, {{ longitude }} </q-tooltip>
|
<q-tooltip> {{ latitude }}, {{ longitude }} </q-tooltip>
|
||||||
@@ -276,16 +379,25 @@ onUnmounted(() => {
|
|||||||
</q-item-label>
|
</q-item-label>
|
||||||
<q-item-label caption lines="1" v-else> delay: {{ delay }} seconds </q-item-label>
|
<q-item-label caption lines="1" v-else> delay: {{ delay }} seconds </q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section side>
|
<q-item-section
|
||||||
|
side
|
||||||
|
style="
|
||||||
|
padding: 30px 0 0 10px;
|
||||||
|
height: 100%;
|
||||||
|
width: 35%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<q-icon v-html="iconElement.outerHTML" />
|
||||||
<q-item-label caption lines="1" v-if="simulationRunning">
|
<q-item-label caption lines="1" v-if="simulationRunning">
|
||||||
{{ calculateDeltaT }}
|
{{ calculateDeltaTime }}
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
<q-icon class="q-mt-lg" v-html="iconElement.outerHTML" />
|
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-separator spaced inset v-if="isLast" />
|
<q-separator spaced inset v-if="!isLast" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="sass" scoped>
|
<style lang="sass" scoped>
|
||||||
.past
|
.past
|
||||||
color: gray
|
color: gray
|
||||||
@@ -19,8 +19,14 @@ const leafletStore = useLeafletStore();
|
|||||||
const socketStore = useSocketioStore();
|
const socketStore = useSocketioStore();
|
||||||
const { center, markerLatLng, zoom } = storeToRefs(leafletStore);
|
const { center, markerLatLng, zoom } = storeToRefs(leafletStore);
|
||||||
|
|
||||||
const { simulationRunning, simulationState, simulationQueueLength, icloudMonitor, testMode } =
|
const {
|
||||||
storeToRefs(socketStore);
|
simulationRunning,
|
||||||
|
simulationState,
|
||||||
|
simulationQueueLength,
|
||||||
|
icloudMonitor,
|
||||||
|
testMode,
|
||||||
|
gpsNoise,
|
||||||
|
} = storeToRefs(socketStore);
|
||||||
|
|
||||||
const menuOpen = ref(false);
|
const menuOpen = ref(false);
|
||||||
const favoritesMap = favorites as Record<string, unknown>;
|
const favoritesMap = favorites as Record<string, unknown>;
|
||||||
@@ -67,6 +73,13 @@ function handleTestToggle() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleGpsNoiseToggle() {
|
||||||
|
const response = socketStore.simulationControl('gps-noise');
|
||||||
|
if (response.sts === 'error') {
|
||||||
|
$q.notify({ type: 'negative', message: response.msg ?? 'Failed to toggle test mode' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleControlClick(cmdAttr: ControlAction) {
|
function handleControlClick(cmdAttr: ControlAction) {
|
||||||
if (cmdAttr.cnfrm) {
|
if (cmdAttr.cnfrm) {
|
||||||
$q.dialog({
|
$q.dialog({
|
||||||
@@ -216,7 +229,7 @@ function handleControlClick(cmdAttr: ControlAction) {
|
|||||||
@click="handleFavClick(favObj.coords)"
|
@click="handleFavClick(favObj.coords)"
|
||||||
>
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="favObj.icon" color="primary" text-color="white" />
|
<q-avatar :icon="favObj.icon" color="secondary" size="sm" text-color="black" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>{{ favObj.name }}</q-item-label>
|
<q-item-label>{{ favObj.name }}</q-item-label>
|
||||||
@@ -224,7 +237,7 @@ function handleControlClick(cmdAttr: ControlAction) {
|
|||||||
</q-item>
|
</q-item>
|
||||||
<q-item v-else-if="hasSubitems(favObj)" clickable v-ripple dense dark>
|
<q-item v-else-if="hasSubitems(favObj)" clickable v-ripple dense dark>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="favObj.icon" color="primary" text-color="white" />
|
<q-avatar :icon="favObj.icon" color="secondary" size="sm" text-color="black" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>{{ favObj.name }}</q-item-label>
|
<q-item-label>{{ favObj.name }}</q-item-label>
|
||||||
@@ -245,7 +258,7 @@ function handleControlClick(cmdAttr: ControlAction) {
|
|||||||
@click="handleFavClick(favSubObj.coords)"
|
@click="handleFavClick(favSubObj.coords)"
|
||||||
>
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-avatar :icon="favSubObj.icon" color="primary" text-color="white" />
|
<q-avatar :icon="favSubObj.icon" color="secondary" size="sm" text-color="black" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>{{ favSubObj.name }}</q-item-label>
|
<q-item-label>{{ favSubObj.name }}</q-item-label>
|
||||||
@@ -276,6 +289,21 @@ function handleControlClick(cmdAttr: ControlAction) {
|
|||||||
<q-item-label>Test Mode</q-item-label>
|
<q-item-label>Test Mode</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
<q-item dense dark tag="label" v-ripple>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-toggle
|
||||||
|
v-model="gpsNoise"
|
||||||
|
size="sm"
|
||||||
|
color="brown"
|
||||||
|
@update:model-value="handleGpsNoiseToggle"
|
||||||
|
dark
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>GPS Noise</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
<q-item
|
<q-item
|
||||||
dense
|
dense
|
||||||
dark
|
dark
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ onMounted(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function onOkClick() {
|
function onOkClick() {
|
||||||
onDialogOK(delay.value);
|
onDialogOK({delay: delay.value, address: address.value});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="sass" scoped>
|
<style lang="sass" scoped>
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ watch(
|
|||||||
},
|
},
|
||||||
{ deep: true },
|
{ deep: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-center col q-ma-lg q-gutter-md">
|
<div class="flex flex-center col q-ma-lg q-gutter-md">
|
||||||
|
|||||||
@@ -3,13 +3,8 @@ import { useSocketioStore } from 'stores/socketio';
|
|||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
const socketioStore = useSocketioStore();
|
const socketioStore = useSocketioStore();
|
||||||
const {
|
const { sockConnected, deviceConnected, tunnelConnected, simulationRunning, icloudMonitor, testMode } =
|
||||||
sockConnected,
|
storeToRefs(socketioStore);
|
||||||
deviceConnected,
|
|
||||||
tunnelConnected,
|
|
||||||
simulationRunning,
|
|
||||||
icloudMonitor,
|
|
||||||
} = storeToRefs(socketioStore);
|
|
||||||
function statusDevColor(state: string | boolean): string {
|
function statusDevColor(state: string | boolean): string {
|
||||||
if (typeof state === 'boolean') {
|
if (typeof state === 'boolean') {
|
||||||
return state ? 'green' : 'red';
|
return state ? 'green' : 'red';
|
||||||
@@ -29,53 +24,57 @@ function statusDevColor(state: string | boolean): string {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-toolbar class="bg-primary text-white">
|
<q-toolbar :class="testMode ? 'bg-warning text-black' : 'bg-primary text-white'">
|
||||||
<div class="flex col q-gutter-md align-center justify-start content-center">
|
<div class="flex col q-gutter-md align-center justify-start content-center">
|
||||||
<q-space />
|
<q-space />
|
||||||
<div style="width: 80vw" class="flex justify-end">
|
<div style="width: 80vw" class="flex justify-end">
|
||||||
<q-btn
|
<q-btn
|
||||||
size="sm"
|
|
||||||
rounded
|
rounded
|
||||||
push
|
push
|
||||||
|
size="sm"
|
||||||
icon="settings"
|
icon="settings"
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
@click="socketioStore.toggleSock()"
|
@click="socketioStore.toggleSock()"
|
||||||
>
|
>
|
||||||
<q-badge :color="statusDevColor(sockConnected)" rounded floating class="q-mr-sm" />
|
<q-badge :color="statusDevColor(sockConnected)" rounded floating class="q-mr-sm" />
|
||||||
</q-btn>
|
</q-btn>
|
||||||
<q-btn size="sm" rounded icon="phone_iphone" class="q-mr-sm">
|
<q-btn
|
||||||
<q-badge
|
rounded
|
||||||
:color="statusDevColor(deviceConnected)"
|
push
|
||||||
@click="socketioStore.requestUpdate()"
|
size="sm"
|
||||||
rounded
|
icon="phone_iphone"
|
||||||
floating
|
class="q-mr-sm"
|
||||||
class="q-mr-sm"
|
@click="socketioStore.requestUpdate()"
|
||||||
/>
|
>
|
||||||
|
<q-badge :color="statusDevColor(deviceConnected)" rounded floating class="q-mr-sm" />
|
||||||
</q-btn>
|
</q-btn>
|
||||||
<q-btn
|
<q-btn
|
||||||
size="sm"
|
|
||||||
@click="socketioStore.requestUpdate()"
|
|
||||||
rounded
|
rounded
|
||||||
|
push
|
||||||
|
size="sm"
|
||||||
icon="subway"
|
icon="subway"
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
|
@click="socketioStore.requestUpdate()"
|
||||||
>
|
>
|
||||||
<q-badge :color="statusDevColor(tunnelConnected)" rounded floating class="q-mr-sm" />
|
<q-badge :color="statusDevColor(tunnelConnected)" rounded floating class="q-mr-sm" />
|
||||||
</q-btn>
|
</q-btn>
|
||||||
<q-btn
|
<q-btn
|
||||||
size="sm"
|
|
||||||
@click="socketioStore.requestUpdate()"
|
|
||||||
rounded
|
rounded
|
||||||
|
push
|
||||||
|
size="sm"
|
||||||
icon="location_on"
|
icon="location_on"
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
|
@click="socketioStore.requestUpdate()"
|
||||||
>
|
>
|
||||||
<q-badge :color="statusDevColor(simulationRunning)" rounded floating class="q-mr-sm" />
|
<q-badge :color="statusDevColor(simulationRunning)" rounded floating class="q-mr-sm" />
|
||||||
</q-btn>
|
</q-btn>
|
||||||
<q-btn
|
<q-btn
|
||||||
size="sm"
|
|
||||||
@click="socketioStore.requestUpdate()"
|
|
||||||
rounded
|
rounded
|
||||||
|
push
|
||||||
|
size="sm"
|
||||||
icon="cloud"
|
icon="cloud"
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
|
@click="socketioStore.icloudMonitorControl('refresh')"
|
||||||
>
|
>
|
||||||
<q-badge :color="statusDevColor(icloudMonitor)" rounded floating class="q-mr-sm" />
|
<q-badge :color="statusDevColor(icloudMonitor)" rounded floating class="q-mr-sm" />
|
||||||
</q-btn>
|
</q-btn>
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ export type SimulationCommands =
|
|||||||
| 'clear'
|
| 'clear'
|
||||||
| 'end'
|
| 'end'
|
||||||
| 'add'
|
| 'add'
|
||||||
| 'test-mode';
|
| 'test-mode'
|
||||||
|
| 'delete'
|
||||||
|
| 'next'
|
||||||
|
| 'gps-noise';
|
||||||
|
|
||||||
export type DeviceCommands = 'start_tunnel' | 'stop_tunnel' | 'shutdown' | 'reboot';
|
export type DeviceCommands = 'start_tunnel' | 'stop_tunnel' | 'shutdown' | 'reboot';
|
||||||
|
|
||||||
@@ -43,14 +46,21 @@ export interface DevCtrlAttr {
|
|||||||
export interface LocationQueue {
|
export interface LocationQueue {
|
||||||
[key: string]: LocationMark;
|
[key: string]: LocationMark;
|
||||||
}
|
}
|
||||||
|
export interface LocationMarkUpdateResponse {
|
||||||
|
command_status: string;
|
||||||
|
command: string;
|
||||||
|
message: string;
|
||||||
|
data: LocationMark;
|
||||||
|
}
|
||||||
|
|
||||||
interface LocationMark {
|
export interface LocationMark {
|
||||||
loc_id: string;
|
loc_id: string;
|
||||||
latitude: number | undefined | null;
|
latitude: number | undefined | null;
|
||||||
longitude: number | undefined | null;
|
longitude: number | undefined | null;
|
||||||
address?: string | undefined | null;
|
address?: string | undefined | null;
|
||||||
delay?: number | undefined | null;
|
delay?: number | undefined | null;
|
||||||
start: string | undefined | null;
|
start: string | undefined | null;
|
||||||
|
status: string | undefined | null;
|
||||||
end?: string | undefined | null;
|
end?: string | undefined | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +69,7 @@ interface LocationMark {
|
|||||||
export interface ServerToClientEvents {
|
export interface ServerToClientEvents {
|
||||||
noArg: () => void;
|
noArg: () => void;
|
||||||
withAck: (a: string, callback: (b: number) => void) => void;
|
withAck: (a: string, callback: (b: number) => void) => void;
|
||||||
|
test_prompt: (callback: (s: string) => void) => void;
|
||||||
simulation_status: (c: SimulationStatus) => void;
|
simulation_status: (c: SimulationStatus) => void;
|
||||||
status: (d: StatusUpdate) => void;
|
status: (d: StatusUpdate) => void;
|
||||||
device_status: (d: DeviceStatus) => void;
|
device_status: (d: DeviceStatus) => void;
|
||||||
@@ -66,6 +77,14 @@ export interface ServerToClientEvents {
|
|||||||
message: (e: string) => void;
|
message: (e: string) => void;
|
||||||
icloud_2fa_request: (callback: (e: number) => void) => void;
|
icloud_2fa_request: (callback: (e: number) => void) => void;
|
||||||
fmf_update: (d: FindMyUpdate) => void;
|
fmf_update: (d: FindMyUpdate) => void;
|
||||||
|
queue_data_update: (d: QueueData) => void;
|
||||||
|
location_item_update: (d: LocationItemUpdate) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface LocationItemUpdate {
|
||||||
|
loc_id: string;
|
||||||
|
data: LocationMark;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SimulationStatus {
|
export interface SimulationStatus {
|
||||||
@@ -78,6 +97,16 @@ export interface SimulationStatus {
|
|||||||
next_move?: number;
|
next_move?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface QueueData {
|
||||||
|
simulation_queue: {
|
||||||
|
active: boolean;
|
||||||
|
data: LocationQueue;
|
||||||
|
order: string[];
|
||||||
|
state: string | undefined | null;
|
||||||
|
worker_task: string | undefined | null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface StatusUpdate {
|
export interface StatusUpdate {
|
||||||
connected_clients: { [key: string]: string };
|
connected_clients: { [key: string]: string };
|
||||||
current_location: {
|
current_location: {
|
||||||
@@ -103,6 +132,7 @@ export interface StatusUpdate {
|
|||||||
[key: string]: LocationMark;
|
[key: string]: LocationMark;
|
||||||
};
|
};
|
||||||
order: string[];
|
order: string[];
|
||||||
|
gps_noise: boolean;
|
||||||
state: string | undefined | null;
|
state: string | undefined | null;
|
||||||
worker_task: string | undefined | null;
|
worker_task: string | undefined | null;
|
||||||
};
|
};
|
||||||
@@ -167,12 +197,15 @@ export interface FindMyUpdate {
|
|||||||
export interface ClientToServerEvents {
|
export interface ClientToServerEvents {
|
||||||
message: (e: string, callback: (b: boolean, r: string) => void) => void;
|
message: (e: string, callback: (b: boolean, r: string) => void) => void;
|
||||||
request_update: (callback: (response: StatusUpdate) => void) => void;
|
request_update: (callback: (response: StatusUpdate) => void) => void;
|
||||||
|
send_test_prompt: (p: string, callback: (response: string) => void) => void;
|
||||||
simulation_control: (
|
simulation_control: (
|
||||||
args: {
|
args: {
|
||||||
command: SimulationCommands;
|
command: SimulationCommands;
|
||||||
latitude?: number | null | undefined;
|
latitude?: number | null | undefined;
|
||||||
longitude?: number | null | undefined;
|
longitude?: number | null | undefined;
|
||||||
delay?: number | undefined;
|
delay?: number | null | undefined;
|
||||||
|
loc_id?: string | null | undefined;
|
||||||
|
address?: string | null | undefined;
|
||||||
},
|
},
|
||||||
callback: (response: SimulationControlResponse) => void,
|
callback: (response: SimulationControlResponse) => void,
|
||||||
) => void;
|
) => void;
|
||||||
@@ -196,18 +229,40 @@ export interface ClientToServerEvents {
|
|||||||
},
|
},
|
||||||
callback?: (response: iCloudMonitorResponse) => void,
|
callback?: (response: iCloudMonitorResponse) => void,
|
||||||
) => void;
|
) => void;
|
||||||
|
location_item_update: (
|
||||||
|
args: {
|
||||||
|
loc_id: string;
|
||||||
|
key: string;
|
||||||
|
value: string | number;
|
||||||
|
},
|
||||||
|
callback?: (response: LocationMarkUpdateResponse) => void,
|
||||||
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SimulationControlResponse {
|
export interface SimulationControlResponse {
|
||||||
status: string;
|
command_status: string;
|
||||||
command: SimulationCommands;
|
command: SimulationCommands;
|
||||||
loc_id: string;
|
command_class: string;
|
||||||
|
data?: SimulationControlResponseData | undefined | null;
|
||||||
|
simulation_noise?: boolean;
|
||||||
message?: string | undefined;
|
message?: string | undefined;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SimulationControlResponseData {
|
||||||
|
simulation_active?: boolean;
|
||||||
|
simulation_queue_state?: string;
|
||||||
|
loc_id?: string;
|
||||||
latitude?: number | undefined | null;
|
latitude?: number | undefined | null;
|
||||||
longitude?: number | undefined | null;
|
longitude?: number | undefined | null;
|
||||||
delay?: number | undefined | null;
|
delay?: number | undefined | null;
|
||||||
start_time?: string | undefined | null;
|
start_time?: string | undefined | null;
|
||||||
end_time?: string | undefined | null;
|
end_time?: string | undefined | null;
|
||||||
|
status?: string | undefined | null;
|
||||||
|
next_move?: number | undefined | null;
|
||||||
|
address?: string | undefined | null;
|
||||||
|
simulation_noise?: boolean;
|
||||||
|
test_mode?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DeviceControlResponse {
|
interface DeviceControlResponse {
|
||||||
@@ -217,11 +272,13 @@ interface DeviceControlResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface iCloudMonitorResponse {
|
export interface iCloudMonitorResponse {
|
||||||
status: string;
|
command_status: string;
|
||||||
command: string;
|
command: string;
|
||||||
|
command_class: string;
|
||||||
icloud_monitor_enabled?: boolean | undefined | null;
|
icloud_monitor_enabled?: boolean | undefined | null;
|
||||||
icloud_monitor_running?: boolean | undefined | null;
|
icloud_monitor_running?: boolean | undefined | null;
|
||||||
message?: string | undefined | null;
|
message?: string | undefined | null;
|
||||||
|
error?: string | undefined | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// END CLIENT TO SERVER
|
// END CLIENT TO SERVER
|
||||||
|
|||||||
@@ -12,14 +12,14 @@
|
|||||||
// to match your app's branding.
|
// to match your app's branding.
|
||||||
// Tip: Use the "Theme Builder" on Quasar's documentation website.
|
// Tip: Use the "Theme Builder" on Quasar's documentation website.
|
||||||
|
|
||||||
$primary: #02006c;
|
$primary: #161B36;
|
||||||
$secondary: #010057;
|
$secondary: #8FA9BF;
|
||||||
$accent: #9c27b0;
|
$accent: #5a728a;
|
||||||
|
|
||||||
$dark: #1d1d1d;
|
$dark: #1d1d1d;
|
||||||
$dark-page: #03002e;
|
$dark-page: #0B1026;
|
||||||
|
|
||||||
$positive: #21ba45;
|
$positive: #4CAF50;
|
||||||
$negative: #c10015;
|
$negative: #EF5350;
|
||||||
$info: #31ccec;
|
$info: #42A5F5;
|
||||||
$warning: #f2c037;
|
$warning: #FFCA28;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Utilities } from '@vue-leaflet/vue-leaflet';
|
import { Utilities } from '@vue-leaflet/vue-leaflet';
|
||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import type { IRouter, LineOptions } from 'leaflet-routing-machine';
|
import type { IRouter, LineOptions } from 'leaflet-routing-machine';
|
||||||
|
import type * as L from 'leaflet';
|
||||||
|
|
||||||
export interface RoutingControlProps {
|
export interface RoutingControlProps {
|
||||||
waypoints: unknown[];
|
waypoints: unknown[];
|
||||||
@@ -9,6 +10,9 @@ export interface RoutingControlProps {
|
|||||||
fitSelectedRoutes?: string | boolean;
|
fitSelectedRoutes?: string | boolean;
|
||||||
lineOptions?: LineOptions | undefined;
|
lineOptions?: LineOptions | undefined;
|
||||||
routeLine?: ((route: unknown) => unknown) | undefined;
|
routeLine?: ((route: unknown) => unknown) | undefined;
|
||||||
|
createMarker?:
|
||||||
|
| ((i: number, waypoint: { latLng: L.LatLng }, n: number) => L.Marker | false)
|
||||||
|
| undefined;
|
||||||
autoRoute?: boolean;
|
autoRoute?: boolean;
|
||||||
routeWhileDragging?: boolean;
|
routeWhileDragging?: boolean;
|
||||||
routeDragInterval?: number;
|
routeDragInterval?: number;
|
||||||
@@ -43,6 +47,12 @@ export const routingControlProps = {
|
|||||||
type: Function as PropType<((route: unknown) => unknown) | undefined>,
|
type: Function as PropType<((route: unknown) => unknown) | undefined>,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
|
createMarker: {
|
||||||
|
type: Function as PropType<
|
||||||
|
((i: number, waypoint: { latLng: L.LatLng }, n: number) => L.Marker | false) | undefined
|
||||||
|
>,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
autoRoute: {
|
autoRoute: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export const customRouter = openrouteserviceV2({
|
|||||||
api_key: '',
|
api_key: '',
|
||||||
profile: 'driving-car',
|
profile: 'driving-car',
|
||||||
geometry_simplify: true,
|
geometry_simplify: true,
|
||||||
host: '/api/proxy/ors/',
|
host: '/api/ors/proxy/ors',
|
||||||
});
|
});
|
||||||
|
|
||||||
//export const customRouter = L.Routing.osrmv1({
|
//export const customRouter = L.Routing.osrmv1({
|
||||||
|
|||||||
@@ -50,8 +50,9 @@ import { useSocketioStore } from 'stores/socketio';
|
|||||||
import MenuBar from 'components/MenuBar.vue';
|
import MenuBar from 'components/MenuBar.vue';
|
||||||
import StatusBar from 'components/StatusBar.vue';
|
import StatusBar from 'components/StatusBar.vue';
|
||||||
|
|
||||||
const socketioStore = useSocketioStore();
|
const socketStore = useSocketioStore();
|
||||||
const drawer = ref(false);
|
const drawer = ref(false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
@@ -114,7 +115,7 @@ const menuList = [
|
|||||||
];
|
];
|
||||||
*/
|
*/
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
socketioStore.bindEvents();
|
socketStore.bindEvents();
|
||||||
socketioStore.connect();
|
socketStore.connect();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
{
|
{
|
||||||
path: 'test',
|
path: 'test',
|
||||||
name: 'Test',
|
name: 'Test',
|
||||||
component: () => import('pages/TestPage.vue')
|
component: () => import('pages/TestPage.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'device-info',
|
path: 'device-info',
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import type {
|
|||||||
FindMyUpdate,
|
FindMyUpdate,
|
||||||
iCloudMonitorResponse,
|
iCloudMonitorResponse,
|
||||||
SimulationStatus,
|
SimulationStatus,
|
||||||
|
LocationMarkUpdateResponse,
|
||||||
|
LocationItemUpdate,
|
||||||
} from 'components/models';
|
} from 'components/models';
|
||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
@@ -23,6 +25,7 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
sockConnected: false as boolean,
|
sockConnected: false as boolean,
|
||||||
socketID: null as string | null | undefined,
|
socketID: null as string | null | undefined,
|
||||||
testMode: null as boolean | undefined | null,
|
testMode: null as boolean | undefined | null,
|
||||||
|
gpsNoise: null as boolean | undefined | null,
|
||||||
deviceConnected: false as boolean,
|
deviceConnected: false as boolean,
|
||||||
tunnelConnected: false as boolean,
|
tunnelConnected: false as boolean,
|
||||||
simulationRunning: false as boolean | string,
|
simulationRunning: false as boolean | string,
|
||||||
@@ -152,7 +155,10 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
socket.on('location_item_update', (inData: LocationItemUpdate): void => {
|
||||||
|
console.log('Location item update received, data: ', inData);
|
||||||
|
this.locationQueueData[inData.loc_id] = inData.data;
|
||||||
|
});
|
||||||
socket.onAny((eventName, ...args) => {
|
socket.onAny((eventName, ...args) => {
|
||||||
console.log('Event received: ', eventName, ' Args: ', args, '');
|
console.log('Event received: ', eventName, ' Args: ', args, '');
|
||||||
/* if (serverToClientKnownEvents.includes(eventName)) {
|
/* if (serverToClientKnownEvents.includes(eventName)) {
|
||||||
@@ -215,8 +221,8 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
'icloud_monitor_control',
|
'icloud_monitor_control',
|
||||||
{ command: 'start' },
|
{ command: 'start' },
|
||||||
(response: iCloudMonitorResponse) => {
|
(response: iCloudMonitorResponse) => {
|
||||||
fnctRtn.sts = response.status;
|
fnctRtn.sts = response.command_status;
|
||||||
if (response.status == 'error') {
|
if (response.command_status == 'ERROR') {
|
||||||
if (response.message) {
|
if (response.message) {
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log(response.message);
|
console.log(response.message);
|
||||||
@@ -227,7 +233,7 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
}
|
}
|
||||||
throw new Error(fnctRtn.msg);
|
throw new Error(fnctRtn.msg);
|
||||||
} else {
|
} else {
|
||||||
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status };
|
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.command_status };
|
||||||
this.icloudMonitor = true;
|
this.icloudMonitor = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -248,8 +254,8 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
'icloud_monitor_control',
|
'icloud_monitor_control',
|
||||||
{ command: 'stop' },
|
{ command: 'stop' },
|
||||||
(response: iCloudMonitorResponse) => {
|
(response: iCloudMonitorResponse) => {
|
||||||
fnctRtn.sts = response.status;
|
fnctRtn.sts = response.command_status;
|
||||||
if (response.status == 'error') {
|
if (response.command_status == 'ERROR') {
|
||||||
if (response.message) {
|
if (response.message) {
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log(response.message);
|
console.log(response.message);
|
||||||
@@ -260,7 +266,7 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
}
|
}
|
||||||
throw new Error(fnctRtn.msg);
|
throw new Error(fnctRtn.msg);
|
||||||
} else {
|
} else {
|
||||||
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.status };
|
fnctRtn = { sts: 'OK', msg: 'iCloud Monitor: ' + response.command_status };
|
||||||
this.icloudMonitor = false;
|
this.icloudMonitor = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -270,15 +276,43 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log('socketStore: got command: icloudMonitor status');
|
console.log('socketStore: got command: icloudMonitor status');
|
||||||
}
|
}
|
||||||
|
socket.emit(
|
||||||
|
'icloud_monitor_control',
|
||||||
|
{ command: 'get' },
|
||||||
|
(response: iCloudMonitorResponse) => {
|
||||||
|
fnctRtn.sts = response.command_status;
|
||||||
|
if (response.command_status == 'error') {
|
||||||
|
if (response.message) {
|
||||||
|
if (debugLog) {
|
||||||
|
console.log(response.message);
|
||||||
|
}
|
||||||
|
fnctRtn.msg = response.message;
|
||||||
|
} else {
|
||||||
|
fnctRtn.msg = 'Error';
|
||||||
|
}
|
||||||
|
throw new Error(fnctRtn.msg);
|
||||||
|
} else {
|
||||||
|
fnctRtn = {
|
||||||
|
sts: 'OK',
|
||||||
|
msg: 'iCloud Location Requested',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.icloudMonitor = !!(
|
||||||
|
response.icloud_monitor_enabled && response.icloud_monitor_running
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'refresh':
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log('Emitting icloud_monitor_control: status');
|
console.log('socketStore: got command: icloudMonitor refresh');
|
||||||
}
|
}
|
||||||
socket.emit(
|
socket.emit(
|
||||||
'icloud_monitor_control',
|
'icloud_monitor_control',
|
||||||
{ command: 'status' },
|
{ command: 'status' },
|
||||||
(response: iCloudMonitorResponse) => {
|
(response: iCloudMonitorResponse) => {
|
||||||
fnctRtn.sts = response.status;
|
fnctRtn.sts = response.command_status;
|
||||||
if (response.status == 'error') {
|
if (response.command_status == 'ERROR') {
|
||||||
if (response.message) {
|
if (response.message) {
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log(response.message);
|
console.log(response.message);
|
||||||
@@ -312,9 +346,11 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
},
|
},
|
||||||
simulationControl(
|
simulationControl(
|
||||||
command: string,
|
command: string,
|
||||||
delay?: number,
|
|
||||||
latitude?: number | null,
|
latitude?: number | null,
|
||||||
longitude?: number | null,
|
longitude?: number | null,
|
||||||
|
loc_id?: string | null,
|
||||||
|
delay?: number,
|
||||||
|
address?: string | null,
|
||||||
) {
|
) {
|
||||||
let fnctRtn: { sts: string; msg?: string | undefined } = { sts: '', msg: '' };
|
let fnctRtn: { sts: string; msg?: string | undefined } = { sts: '', msg: '' };
|
||||||
this.setSockStatus();
|
this.setSockStatus();
|
||||||
@@ -338,14 +374,14 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
'simulation_control',
|
'simulation_control',
|
||||||
{ command: 'start', delay: 0, latitude: null, longitude: null },
|
{ command: 'start', delay: 0, latitude: null, longitude: null },
|
||||||
(response: SimulationControlResponse) => {
|
(response: SimulationControlResponse) => {
|
||||||
if (response.status == 'error') {
|
if (response.command_status == 'ERROR') {
|
||||||
fnctRtn = { sts: 'error', msg: response.message?.toString() };
|
fnctRtn = { sts: 'error', msg: response.message?.toString() };
|
||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
} else {
|
} else {
|
||||||
fnctRtn = { sts: 'OK', msg: response.message?.toString() };
|
fnctRtn = { sts: 'OK', msg: response.message?.toString() };
|
||||||
this.simulationState = response.status;
|
this.simulationState = response.data?.simulation_queue_state;
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log(response.message);
|
console.log('response from simulate_control_start: ', response);
|
||||||
}
|
}
|
||||||
// return response.message;
|
// return response.message;
|
||||||
}
|
}
|
||||||
@@ -357,19 +393,35 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
'simulation_control',
|
'simulation_control',
|
||||||
{ command: 'test-mode' },
|
{ command: 'test-mode' },
|
||||||
(response: SimulationControlResponse) => {
|
(response: SimulationControlResponse) => {
|
||||||
if (response.status === 'error') {
|
if (response.command_status === 'ERROR') {
|
||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
} else {
|
} else {
|
||||||
this.simulationState = response.status;
|
this.simulationState = response.data?.simulation_queue_state
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log(response.message, response);
|
console.log('response from simulate_control_test-mode: ', response);
|
||||||
|
}
|
||||||
|
return response.message;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'gps-noise':
|
||||||
|
socket.emit(
|
||||||
|
'simulation_control',
|
||||||
|
{ command: 'gps-noise' },
|
||||||
|
(response: SimulationControlResponse) => {
|
||||||
|
if (response.command_status === 'ERROR') {
|
||||||
|
throw new Error(response.message);
|
||||||
|
} else {
|
||||||
|
this.gpsNoise = response.simulation_noise;
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('response from simulate_control_gps-noise: ', response);
|
||||||
}
|
}
|
||||||
return response.message;
|
return response.message;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'pause':
|
case 'pause':
|
||||||
if (this.simulationState !== 'RUNNING') {
|
if (this.simulationState !== 'RUNNING') {
|
||||||
throw new Error('Simulation is not running');
|
throw new Error('Simulation is not running');
|
||||||
@@ -378,12 +430,12 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
'simulation_control',
|
'simulation_control',
|
||||||
{ command: 'pause' },
|
{ command: 'pause' },
|
||||||
(response: SimulationControlResponse) => {
|
(response: SimulationControlResponse) => {
|
||||||
if (response.status === 'error') {
|
if (response.command_status === 'ERROR') {
|
||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
} else {
|
} else {
|
||||||
this.simulationState = response.status;
|
this.simulationState = response.data?.simulation_queue_state;
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log(response.message);
|
console.log('response from simulate_control_pause: ', response);
|
||||||
}
|
}
|
||||||
return response.message;
|
return response.message;
|
||||||
}
|
}
|
||||||
@@ -395,12 +447,12 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
throw new Error('Simulation is not paused');
|
throw new Error('Simulation is not paused');
|
||||||
}
|
}
|
||||||
socket.emit('simulation_control', { command: 'resume' }, (response) => {
|
socket.emit('simulation_control', { command: 'resume' }, (response) => {
|
||||||
if (response.status == 'error') {
|
if (response.command_status == 'ERROR') {
|
||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
} else {
|
} else {
|
||||||
this.simulationState = response.status;
|
this.simulationState = response.data?.simulation_queue_state;
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log(response.message);
|
console.log('response from simulate_control_resume: ', response);
|
||||||
}
|
}
|
||||||
return response.message;
|
return response.message;
|
||||||
}
|
}
|
||||||
@@ -411,12 +463,12 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
throw new Error('Simulation queue is empty');
|
throw new Error('Simulation queue is empty');
|
||||||
}
|
}
|
||||||
socket.emit('simulation_control', { command: 'clear' }, (response) => {
|
socket.emit('simulation_control', { command: 'clear' }, (response) => {
|
||||||
if (response.status == 'error') {
|
if (response.command_status == 'ERROR') {
|
||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
} else {
|
} else {
|
||||||
this.simulationState = response.status;
|
this.simulationState = response.data?.simulation_queue_state;
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log(response.message);
|
console.log('response from simulate_control_clear: ', response);
|
||||||
}
|
}
|
||||||
return response.message;
|
return response.message;
|
||||||
}
|
}
|
||||||
@@ -424,35 +476,35 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
break;
|
break;
|
||||||
case 'end':
|
case 'end':
|
||||||
if (this.simulationState == 'ENDED' || !this.simulationRunning) {
|
if (this.simulationState == 'ENDED' || !this.simulationRunning) {
|
||||||
throw new Error('Simulation is already ended');
|
throw new Error('Simulation has already ended');
|
||||||
}
|
}
|
||||||
socket.emit('simulation_control', { command: 'end' }, (response) => {
|
socket.emit('simulation_control', { command: 'end' }, (response) => {
|
||||||
if (response.status == 'error') {
|
if (response.command_status == 'ERROR') {
|
||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
} else {
|
} else {
|
||||||
this.simulationState = response.status;
|
this.simulationState = response.data?.simulation_queue_state;
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log(response.message);
|
console.log('response from simulate_control_end: ', response);
|
||||||
}
|
}
|
||||||
return response.message;
|
return response.message;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'add':
|
case 'add':
|
||||||
// if (this.simulationState == 'ENDED' || !this.simulationRunning) {
|
|
||||||
// throw new Error('Simulation is not running');
|
|
||||||
// }
|
|
||||||
if (!latitude || !longitude) {
|
if (!latitude || !longitude) {
|
||||||
throw new Error('latitude or longitude not set');
|
throw new Error('latitude or longitude not set');
|
||||||
}
|
}
|
||||||
|
if (!address) {
|
||||||
|
address = "{latitude}, {longitude}"
|
||||||
|
}
|
||||||
socket.emit(
|
socket.emit(
|
||||||
'simulation_control',
|
'simulation_control',
|
||||||
{ command: 'add', latitude: latitude, longitude: longitude, delay: delay },
|
{ command: 'add', latitude: latitude, longitude: longitude, delay: delay, address: address },
|
||||||
(response) => {
|
(response) => {
|
||||||
if (response.status == 'error') {
|
if (response.command_status == 'ERROR') {
|
||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
} else {
|
} else {
|
||||||
this.simulationState = response.status;
|
this.simulationState = response.data?.simulation_queue_state;
|
||||||
if (debugLog) {
|
if (debugLog) {
|
||||||
console.log('response from simulate_control_add: ', response);
|
console.log('response from simulate_control_add: ', response);
|
||||||
}
|
}
|
||||||
@@ -461,6 +513,35 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 'delete':
|
||||||
|
if (!loc_id) {
|
||||||
|
throw new Error('loc_id not set.');
|
||||||
|
}
|
||||||
|
socket.emit('simulation_control', { command: 'delete', loc_id: loc_id }, (response) => {
|
||||||
|
if (response.command_status == 'ERROR') {
|
||||||
|
throw new Error(response.message);
|
||||||
|
} else {
|
||||||
|
this.simulationState = response.data?.simulation_queue_state;
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('response from simulate_control_delete: ', response);
|
||||||
|
}
|
||||||
|
return response.message;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 'next':
|
||||||
|
socket.emit('simulation_control', { command: 'next' }, (response) => {
|
||||||
|
if (response.command_status == 'ERROR') {
|
||||||
|
throw new Error(response.message);
|
||||||
|
} else {
|
||||||
|
this.simulationState = response.data?.simulation_queue_state;
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('response from simulate_control_next: ', response);
|
||||||
|
}
|
||||||
|
return response.message;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fnctRtn = { sts: 'error', msg: 'Invalid command' };
|
fnctRtn = { sts: 'error', msg: 'Invalid command' };
|
||||||
throw new Error('Invalid command');
|
throw new Error('Invalid command');
|
||||||
@@ -475,6 +556,7 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
digestUpdate(data: StatusUpdate): void {
|
digestUpdate(data: StatusUpdate): void {
|
||||||
this.deviceConnected = !!(data.udid && data.tunnel);
|
this.deviceConnected = !!(data.udid && data.tunnel);
|
||||||
this.testMode = data.test_mode;
|
this.testMode = data.test_mode;
|
||||||
|
this.gpsNoise = data.simulation_queue.gps_noise;
|
||||||
this.simulationRunning = data.simulation_queue.active;
|
this.simulationRunning = data.simulation_queue.active;
|
||||||
this.simulationState = data.simulation_queue.state;
|
this.simulationState = data.simulation_queue.state;
|
||||||
this.simulationQueueLength = data.simulation_queue.order.length;
|
this.simulationQueueLength = data.simulation_queue.order.length;
|
||||||
@@ -493,6 +575,38 @@ export const useSocketioStore = defineStore('socketio', {
|
|||||||
setDeviceState(state: boolean) {
|
setDeviceState(state: boolean) {
|
||||||
this.deviceConnected = state;
|
this.deviceConnected = state;
|
||||||
},
|
},
|
||||||
|
updateLocationMark(loc_id: string, key: string, value: string | number) {
|
||||||
|
let fnctRtn: { command_status: string, message: string } = { command_status: '', message: '' };
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('socketStore: Update LocationMark request, loc_id: %s, key: %s, new value: %s', loc_id, key, value);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!this.locationQueueData[loc_id]
|
||||||
|
) {
|
||||||
|
fnctRtn = { command_status: 'error', message: 'Location Id: ' + loc_id + ' is not in the simulation queue' };
|
||||||
|
throw new Error('loc_id ' + loc_id + 'not found');
|
||||||
|
}
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('Emitting LocationItem Update');
|
||||||
|
}
|
||||||
|
socket.emit(
|
||||||
|
'location_item_update',
|
||||||
|
{ loc_id: loc_id, key: key, value: value },
|
||||||
|
(response: LocationMarkUpdateResponse) => {
|
||||||
|
if (response.command_status == 'ERROR') {
|
||||||
|
fnctRtn = { command_status: 'error', message: response.message?.toString() };
|
||||||
|
throw new Error(response.message);
|
||||||
|
} else {
|
||||||
|
fnctRtn = { command_status: 'OK', message: response.message?.toString() };
|
||||||
|
if (debugLog) {
|
||||||
|
console.log('response from backend: ', response);
|
||||||
|
}
|
||||||
|
this.locationQueueData[loc_id] = response.data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return fnctRtn;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
9
src/types/leaflet-routing-machine.d.ts
vendored
9
src/types/leaflet-routing-machine.d.ts
vendored
@@ -1,7 +1,14 @@
|
|||||||
declare module 'leaflet-routing-machine' {
|
declare module 'leaflet-routing-machine' {
|
||||||
import type * as L from 'leaflet';
|
import type * as L from 'leaflet';
|
||||||
|
|
||||||
export type IRouter = Record<string, unknown>;
|
export interface IRouter {
|
||||||
|
route(
|
||||||
|
waypoints: Array<{ latLng: L.LatLng }>,
|
||||||
|
callback: (error: unknown, routes?: unknown[]) => void,
|
||||||
|
context?: unknown,
|
||||||
|
options?: unknown,
|
||||||
|
): unknown;
|
||||||
|
}
|
||||||
export type IGeocoder = Record<string, unknown>;
|
export type IGeocoder = Record<string, unknown>;
|
||||||
export type LineOptions = L.PolylineOptions;
|
export type LineOptions = L.PolylineOptions;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user