<template lang="pug">
.position_marker_popup
MapPopup(:title="$t('popup.realtime.vehicle.title')" :sections="popupSections")
template(v-slot:datetime="")
span {{datetime}}
template(v-slot:address_label="")
span {{$t('location.history_tab.position.address')}}
template(v-slot:address="")
span {{address}}
template(v-slot:speed="")
span {{speedKm}}
template(v-slot:vehicleImmatriculation="")
span {{vehicleRegistrationPlate }}
template(v-slot:driverName="")
span {{driverName||''}}
template(v-slot:gear_area="" v-if="showPositionAnalysisButton&&hasFeatureRight('location_position_analysis')")
.col-12
.row.mb-1
.offset-10
.col-2
img(src="./assets/gear-icon.svg"
style="cursor:pointer;"
@click="openPositionAnalysisPopup")
template(v-slot:sensor="props")
span(v-show="typeof props.value === 'boolean'" :style="props.value?'color:#70BD95':'color:#FF4545'") {{props.value?$t('common.enabled'):$t('common.disabled')}}
span(v-show="typeof props.value !== 'boolean'") {{props.value}}
</template>
<script>
import moment from 'moment'
import CollapsibleSection from './CollapsibleSection.vue'
import Vue from 'vue'
import MapPopup from '@c/shared/MapPopup/MapPopup.vue'
import { mapGetters } from 'vuex'
import sensorsService from '@/services/sensors-service.js'
import vehicleService from '@/services/vehicle-service.js'
import { isValidPositionId } from '@/services/position-service.js'
//import APIUrls from '@/config/simpliciti-apis'
import { APIV2RequestDatetimeFormat } from '@/config/simpliciti-apis.js'
import { getVehicleHistoryPositionDetailsFromDateLegacy } from '@/services/history-service.js'
export default {
name: 'PositionMarkerPopup',
components: {
CollapsibleSection,
MapPopup,
},
mixins: [Vue.$mixins.userRightsMixin],
inject: {
/**
* Hides the gear icon (i.g Diagnostics module)
*/
showPositionAnalysisButton: {
default: true,
},
skipPositionMarkerPopupDetailsFetch: {
default: false,
},
},
props: {
geometry: {
type: Object,
default: () => ({}),
},
},
data() {
return {
torSectionVisible: false,
canSectionVisible: false,
details: {},
popupSections: [
{
title: this.$t('location_module.popup.position_marker.title'),
rows: [
{
singleColumn: {
name: 'datetime',
label: this.$t('common.date'),
},
},
{
singleColumn: {
name: 'address',
},
},
{
singleColumn: {
name: 'speed',
label: 'common.Vitesse',
},
},
],
collapsed: true,
},
{
title: this.$t('popup.realtime.vehicle.vehicle_section_title'),
rows: [
{
twoColumns: [
{
name: 'vehicleImmatriculation',
label: this.$t('common.matriculation'),
},
{
name: 'driverName',
label: this.$t('common.Conducteur'),
},
],
},
],
},
{
name: 'gear_area',
collapsable: false,
header: false,
visible: this.showPositionAnalysisButton,
},
{
title: 'common.capteurs',
name: 'sensors',
visible: false,
rows: [],
},
{
title: 'CAN',
name: 'can',
visible: false,
rows: [],
},
],
}
},
computed: {
...mapGetters({
//Attention: Only for Location module (This component will be also used in Diagnostics module)
selectedItem: 'location_module/selectedItem',
}),
driverName() {
return this.selectedItem.driverName || this.getVal('driverName')
},
canVRM() {
return this.getVal('can_vrm')
},
canInfos() {
const infos = [
[
'sensorCanCruise',
'can_cruise' /*APIV2*/,
'sensorCanCruise' /*normalized*/,
],
[
'sensorCanRPM',
'vrm',
'can_vrm' /*APIV2*/,
'sensorCanRPM' /*normalized*/,
],
['km_fms', 'can_km_fms' /*APIV2*/], //unused (location realtime only?)
[
'sensorCanFuelPerc',
'can_fuel' /*APIV2*/,
'sensorCanFuelPerc' /*normalized*/,
],
['sensorCanFuelLiters', 'sensorCanFuelLiters' /*normalized*/],
['niveau_carburant', 'can_niveau_carburant' /*APIV2*/],
[
'conso',
'can_conso' /*APIV2*/,
'sensorCanConsumptionLiters' /*normalized*/,
],
[
'accelerateur',
'can_accelerateur' /*APIV2*/,
'sensorCanThrottle' /*normalized*/,
],
[
'sensorCanBrakePedal',
'can_freinage' /*APIV2*/,
'sensorCanBrakePedal' /*normalized*/,
],
[
'batterie',
'can_batterie' /*APIV2*/,
'sensorCanBatteryPerc' /*normalized*/,
],
['vehicleDistance', 'vehicleDistance' /*normalized*/],
['canServiceDistanceMeters' /*normalized*/],
['embrayage', 'can_embrayage'], //unused (location realtime only?)
['speHarshBraking' /*normalized*/],
['speHarshAcceleration' /*normalized*/],
['speHarshCornering' /*normalized*/],
['speExcessiveSpeed' /*normalized*/],
]
return infos
.map((propNames) => {
propNames = propNames instanceof Array ? propNames : [propNames]
let code = propNames[0]
let value = null
propNames.forEach((propName) => {
if (value === null && !!this.getVal(propName)) {
value = this.getVal(propName)
}
})
return {
code,
rawValue: value,
name: this.$te(sensorsService.getSensorI18nCode(code))
? this.$t(sensorsService.getSensorI18nCode(code))
: this.$t(`can_sensors.${code}`),
exists: !!value && ![null, 'null', undefined].includes(value),
value: sensorsService.formatSensorValue(code, value),
}
})
.filter((can) => can.exists)
},
anaInfos() {
if (this.getVal('sensorAna')) {
return this.getVal('sensorAna') //Already normalized
}
//From APIV2 response, require normalization
if (this.getVal('ana')) {
return this.getVal('ana', [])
.filter((ana) => {
return (
(ana.etat !== undefined && ana.etat !== null) || ana.val !== null
)
})
.map((ana) => {
return {
name: (ana.nom && `${ana.nom} (ANA)`) || `ANA${ana.num}`,
//enabled: ana.val.toString() !== '0',
value: ana.val.toString(),
}
})
}
return []
},
torInfos() {
//Already normalized
if (this.getVal('sensorTor')) {
return this.getVal('sensorTor', [])
} else {
//From APIV2 response, require normalization
return this.getVal('tor', [])
.filter((tor) => {
return (
(tor.etat !== undefined && tor.etat !== null) || tor.val !== null
)
})
.map((tor) => {
let enabled =
tor.etat === undefined ? tor.val : tor.etat.toString() === '1'
return {
name: tor.nom || `TOR${tor.num}`,
enabled,
}
})
}
},
datetime() {
return this.$date.formatDatetimeWithSeconds(
this.getVal('dateheure') || this.getVal('datetime')
)
},
speedKm() {
return (this.getVal('vitesse', 0) || this.getVal('speed', 0)) + ' Km/h'
},
vehicleRegistrationPlate() {
return (
this.getVal('vehicule_immatriculation') ||
this.getVal('vehicleRegistrationPlate') ||
this.selectedItem.vehicleMatriculation ||
'...'
)
},
address() {
if (this.getVal('addressFormatted')) {
return this.getVal('addressFormatted')
}
let r = this.details?.streetNumber || ''
r = (r ? r + ` ` : r + ``) + (this.details?.street || '')
r = (r ? r + `, ` : r + ``) + (this.details?.zipCode || '')
r = (r ? r + `, ` : r + ``) + (this.details?.city || '')
return r || 'Non renseigné'
},
vehicleId() {
let vehicleId = this.getVal('vehicleId')
//This only applies if Location module
if (!vehicleId) {
vehicleId =
this.$store.getters['location_module/selectedItem'].vehicleId ||
this.$store.getters['location_module/selectedItem'].id
}
return vehicleId
},
},
watch: {
canInfos() {
this.updateCanSection()
},
torInfos() {
this.updateTorAnaSection()
},
anaInfos() {
this.updateTorAnaSection()
},
},
/**
* @todo Remove fixtures feature without braking unit test
*/
async mounted() {
//Diagnostic module: Position already contains sensor information (Unused?)
if (this.skipPositionMarkerPopupDetailsFetch) {
return
}
this.updateTorAnaSection()
this.updateCanSection()
if (this.vehicleId) {
await this.updatePositionDetails()
//Location (Segment analysis): Position analysis can be executed when we select 2nd position.
if (this.$store.getters['location_module/positionAnalysisCanCompare']) {
this.launchLocationModulePositionAnalysis()
}
}
},
methods: {
async getPositionDetailsFromAPIV3(positionId) {
return await vehicleService.getVehiclePosition(positionId)
},
/*async getPositionDetailsFromAPIV2(vehicleId, datetime) {
return getVehicleHistoryPositionDetailsFromDateLegacy(vehicleId, datetime)
console.log('getPositionDetailsFromAPIV2', {
vehicleId,
datetime,
})
const res =
(await this.$api.loadFixtures(
`${APIUrls.APIV2_POSITIONS_GPS.substring(1)}/${vehicleId}_${datetime
.split(' ')
.join('__')
.split(':')
.join('_')}`
)) ||
(
await this.$api.v2.get(
`${APIUrls.APIV2_POSITIONS_GPS}?vehicule_id=${vehicleId}&dateheure_debut=${datetime}&dateheure_fin=${datetime}&groups=infos_complementaires,capteurs,capteurs_details,can,localisation_adresse`
)
).data
return res && res[0] && res[0].positions && res[0].positions.length
? {
...res[0],
...res[0].positions[0],
positions: undefined,
}
: null
},
*/
/**
* Fetch single position details using APIV3.
*
* @todo Remove commented code
*
* 02/02/2023 @JAR If Diagnostics module - Replay - Vehicle marker, id is located at 'positionId'. 'id' is reserved for matching the marker geometry for updates and contains a fixed value 'vehicle'.
*/
async updatePositionDetails() {
let positionId = this.getVal('positionId') || this.getVal('id')
let detailsFromAPI = null
//Diagnostic modules already includes a valid identifier
//if (isValidPositionId(positionId)) {
//Sometimes we generate a fake id starting with id_
detailsFromAPI = await this.getPositionDetailsFromAPIV3(positionId)
//}
/* else {
console.log('passe toujour ici')
const datetime = moment(
this.getVal('dateheure') || this.getVal('datetime')
)
detailsFromAPI = await this.getPositionDetailsFromAPIV2(
this.vehicleId,
datetime
)
} */
if (detailsFromAPI) {
this.details = detailsFromAPI
this.updateTorAnaSection()
this.updateCanSection()
}
},
launchLocationModulePositionAnalysis() {
let promise = this.$store.dispatch('location_module/analyzeSegment', {
vehicleId: this.vehicleId,
positions: [
{
...((this.geometry && this.geometry.properties) || {}),
...(this.details || {}),
},
],
})
this.$loader.show(promise)
},
/**
* Will update popupSections with Tor/Ana information from API
* @function updateTorAnaSection
*/
updateTorAnaSection() {
console.log('position-marker-popup: Update sensors section')
let section = this.popupSections.find((s) => s.name === 'sensors')
const mapTorAnaHandlerToDynamicSectionRowColumn = (sensorItem) => {
return {
singleColumn: {
name: 'sensor',
label: sensorItem.name,
value:
sensorItem.enabled !== undefined
? sensorItem.enabled
: sensorItem.value +
(sensorItem.unit ? ` ${sensorItem.unit}` : ''),
inline: true,
},
}
}
section.rows = this.torInfos
.map(mapTorAnaHandlerToDynamicSectionRowColumn)
.concat(this.anaInfos.map(mapTorAnaHandlerToDynamicSectionRowColumn))
section.visible = section.rows.length > 0
},
/**
* Will update Can section with Can information from API
* @function updateCanSection
*/
updateCanSection() {
let section = this.popupSections.find((s) => s.name === 'can')
section.rows = this.canInfos
.filter((canItem) => !!canItem.value)
.map((canItem) => {
return {
singleColumn: {
label: canItem.name,
value: canItem.value,
inline: true,
},
}
})
section.visible = section.rows.length > 0
},
openPositionAnalysisPopup() {
//Case: Set positions to compare (from, null)
this.$store.dispatch('location_module/positionAnalysisSelectPositions', [
{
...((this.geometry && this.geometry.properties) || {}),
...(this.details || {}),
},
null,
])
//Case: Popup is already open
if (this.$store.getters['location_module/positionAnalysisPopupOpened']) {
return
}
this.$store.dispatch('location_module/togglePositionAnalysisPopup', true)
/*
@deprecated: Instanciates the analysis popup on top of the map. Replaced by: The analysis section is shown directly in a new tab (vehicle details)
const PositionAnalysisPopupClass = Vue.extend(PositionAnalysisPopup);
let instance = new PositionAnalysisPopupClass({
parent: this.$parent.$parent,
propsData: {},
});
instance.$mount();
let simplicitiMapEl = document.querySelector(".simpliciti_map");
let leafletMapEl = simplicitiMapEl.querySelector(".map");
simplicitiMapEl.insertBefore(instance.$el, leafletMapEl);
*/
},
/**
* Get value either from geometry properties or from the position details (positions_gps)
* @private
*/
getVal(name, defaultValue = '') {
//Give priority to available data
if (
this.geometry &&
this.geometry.properties &&
this.geometry.properties[name] !== undefined
) {
return this.geometry.properties[name]
}
//Fallback to new data fetched from API (position details)
if (this.details && this.details[name] !== undefined) {
return this.details[name]
}
return defaultValue
},
},
}
</script>
<style lang="scss" scoped></style>
Source