milestones

This commit is contained in:
2026-06-10 11:00:10 -04:00
parent ddaf682d16
commit 1c3ec92b1f
50 changed files with 7314 additions and 2320 deletions
+136 -91
View File
@@ -3,69 +3,42 @@ import { storeToRefs } from 'pinia';
import { useSimulationStore } from 'stores/simulation';
import { computed, onMounted, onUnmounted, ref } from 'vue';
import type { NominatimResponse } from 'components/models';
import { Icon, PinCirclePanel, PinStarPanel } from 'leaflet-extra-markers';
import {
Icon,
PinCirclePanel,
PinStarPanel,
PointCircle,
TackDiamondBorder,
} from 'leaflet-extra-markers';
import FormattedAddress from 'components/FormattedAddress.vue';
//import NestedKnob from 'components/NestedKnob.vue';
const simulationStore = useSimulationStore();
const { currentLocation, locationQueueOrder, locationQueueData, simulationRunning } =
storeToRefs(simulationStore);
const {
currentLocation,
locationQueueOrder,
locationQueueData,
locationQueueDeletedItems,
simulationRunning,
} = storeToRefs(simulationStore);
const props = defineProps({
address: {
type: Object as () => NominatimResponse,
required: false,
},
latitude: {
type: Number,
required: true,
},
longitude: {
type: Number,
required: true,
},
icon: {
type: String,
default: 'mdi-map-marker',
},
start: {
type: String,
required: true,
},
end: {
type: String,
required: false,
},
delay: {
type: Number,
default: 0,
},
active: {
type: Boolean,
default: false,
},
isCurrentDelay: {
type: Boolean,
default: false,
},
loc_id: {
type: String,
required: true,
},
isLast: {
type: Boolean,
default: false,
},
index: {
type: Number,
default: 0,
},
status: {
type: String,
default: 'queued',
},
});
const props = defineProps<{
address?: NominatimResponse | undefined;
latitude: number;
longitude: number;
icon?: string;
start: string;
end?: string | undefined;
delay: number;
active: boolean;
isCurrentDelay: boolean;
loc_id: string;
isLast: boolean;
index: number;
status?: string | undefined;
type?: string | undefined;
instruction?: string | undefined;
}>();
// Define custom events that this component can emit
const emit = defineEmits(['item-clicked']);
@@ -75,6 +48,14 @@ function itemClicked() {
emit('item-clicked', param1);
}
const myData = computed(() => {
return simulationStore.getLocationData(props.loc_id);
});
const isDeleted = computed(() => {
return myData.value.status === 'deleted' ? true : false;
});
const currentTime = ref(new Date());
let timerId: number;
@@ -103,7 +84,24 @@ function formatInAgo(seconds: number) {
const calculateDeltaTime = computed(() => {
let delta;
if (props.active) {
delta = 'now';
const startTime = new Date(props.start);
const nowMs: number = currentTime.value.getTime();
const pastMs: number = startTime.getTime();
const diffMs: number = Math.abs(nowMs - pastMs);
const seconds: number = Math.floor(diffMs / 1000);
const minutes: number = Math.floor(seconds / 60);
const remainderSeconds: number = seconds % 60;
const hours: number = Math.floor(minutes / 60);
const days: number = Math.floor(hours / 24);
if (days > 0) {
delta = `for ${days} d${days > 1 ? 's' : ''}`;
} else if (hours > 0) {
delta = `for ${hours} h${hours > 1 ? 's' : ''}`;
} else if (minutes > 0) {
delta = `for ${minutes}:${remainderSeconds}`;
} else {
delta = `for ${seconds} s${seconds > 1 ? 's' : ''}`;
}
} else if (props.end && props.end !== '') {
const pastTime: Date = new Date(props.end);
const nowMs: number = currentTime.value.getTime();
@@ -124,7 +122,7 @@ const calculateDeltaTime = computed(() => {
}
} else {
let startSlice;
if (currentIndex.value > 0) {
if (currentIndex.value && currentIndex.value > 0) {
startSlice = currentIndex.value;
} else {
startSlice = 0;
@@ -175,15 +173,26 @@ const humanReadableDateTime = (iso: string) => {
};
const currentIndex = computed(() => {
return currentLocation.value ? locationQueueOrder.value.indexOf(currentLocation.value.loc_id) : 0;
return currentLocation.value.loc_id
? locationQueueOrder.value.indexOf(currentLocation.value.loc_id)
: null;
});
const myIndex = computed(() => {
return locationQueueOrder.value.indexOf(props.loc_id);
if (isDeleted.value) {
return locationQueueDeletedItems.value.indexOf(props.loc_id);
} else {
return locationQueueOrder.value.indexOf(props.loc_id);
}
});
const myUpdatedIndex = computed(() => {
return myIndex.value - currentIndex.value;
if (isDeleted.value) {
return myIndex.value + 1;
} else {
if (currentIndex.value === null) return myIndex.value + 1;
return myIndex.value - currentIndex.value;
}
});
const itemClass = computed(() => {
@@ -193,33 +202,66 @@ const itemClass = computed(() => {
});
const customIcon = computed(() => {
if (myUpdatedIndex.value > 0) {
return new Icon({
color: 'blue',
accentColor: 'firebrick',
content: myUpdatedIndex.value.toString(),
contentColor: 'white',
scale: 1,
svg: PinCirclePanel,
});
} else if (myUpdatedIndex.value < 0) {
if (myData.value.status === 'deleted') {
return new Icon({
color: 'black',
accentColor: 'grey',
accentColor: 'black',
content: myUpdatedIndex.value.toString(),
contentColor: 'white',
scale: 1,
svg: PinCirclePanel,
svg: TackDiamondBorder,
});
} else {
return new Icon({
color: 'pink',
accentColor: 'black',
content: '*',
contentColor: 'black',
scale: 1,
svg: PinStarPanel,
});
if (myUpdatedIndex.value > 0) {
if (props.type === 'coord') {
return new Icon({
color: 'blue',
accentColor: 'firebrick',
content: myUpdatedIndex.value.toString(),
contentColor: 'white',
scale: 0.25,
svg: PointCircle,
});
} else {
return new Icon({
color: 'blue',
accentColor: 'firebrick',
content: myUpdatedIndex.value.toString(),
contentColor: 'white',
scale: 1,
svg: PinCirclePanel,
});
}
} else if (myUpdatedIndex.value < 0) {
if (props.type === 'coord') {
return new Icon({
color: 'black',
accentColor: 'grey',
content: myUpdatedIndex.value.toString(),
contentColor: 'white',
scale: 0.25,
svg: PointCircle,
});
} else {
return new Icon({
color: 'black',
accentColor: 'grey',
content: myUpdatedIndex.value.toString(),
contentColor: 'white',
scale: 1,
svg: PinCirclePanel,
});
}
} else {
return new Icon({
color: 'pink',
accentColor: 'black',
content: '*',
contentColor: 'black',
scale: 1,
svg: PinStarPanel,
});
}
}
});
@@ -310,14 +352,16 @@ const delayInputMask = computed(() => {
*/
const displayDelay = computed(() => {
if (currentIndex.value === null) return true;
return props.index > currentIndex.value;
});
const delayActive = computed(() => {
return props.index === currentIndex.value + 1;
return props.index === currentIndex.value;
});
const canDrag = computed(() => {
if (currentIndex.value === null) return true;
return props.index > currentIndex.value + 1;
});
@@ -330,8 +374,8 @@ onUnmounted(() => {
<q-item
v-if="displayDelay"
:active="delayActive"
:class="delayActive ? 'text-orange bg-dark' : ''"
active-class="text-orange bg-dark"
:class="delayActive ? 'text-orange' : ''"
active-class="text-orange"
>
<q-item-section class="flex flex-center">
<q-input
@@ -368,18 +412,19 @@ onUnmounted(() => {
:active="active"
@click="itemClicked"
:class="itemClass"
active-class="text-orange bg-dark"
active-class="text-orange"
>
<q-item-section style="width: 70%">
<q-item-label v-if="address">
<FormattedAddress :address="props.address" />
<q-tooltip> {{ latitude }}, {{ longitude }} </q-tooltip>
</q-item-label>
<q-item-label v-else-if="instruction" lines="2">{{ instruction }}</q-item-label>
<q-item-label v-else> {{ latitude }}, {{ longitude }} </q-item-label>
<q-item-label caption lines="1" v-if="start && simulationRunning">
<q-item-label caption lines="1" v-if="start && simulationRunning && !isDeleted">
start: {{ humanReadableDateTime(start) }}
</q-item-label>
<q-item-label caption lines="1" v-if="end && simulationRunning">
<q-item-label caption lines="1" v-if="end && simulationRunning && !isDeleted">
end: {{ humanReadableDateTime(end) }}
</q-item-label>
<q-item-label caption lines="1" v-if="!active && !end">
@@ -389,7 +434,7 @@ onUnmounted(() => {
<q-item-section
side
style="
padding: 30px 0 0 10px;
padding: 30px 0 0 0;
height: 100%;
width: 35%;
display: flex;
@@ -398,7 +443,7 @@ onUnmounted(() => {
"
>
<q-icon :class="{ 'drag-handle': canDrag }" v-html="iconElement.outerHTML" />
<q-item-label caption lines="1" v-if="simulationRunning">
<q-item-label caption lines="1" v-if="simulationRunning && !isDeleted">
{{ calculateDeltaTime }}
</q-item-label>
</q-item-section>