<template lang="pug">
.diagnostics-analysis
DynamicSections(v-model="dynamicSectionsState")
template(v-slot:details_title="slotProps")
SectionTitle(
:icon="'radar'",
:canCollapse="true",
:collapsed="slotProps.isContentVisible",
textMinWidth="240px"
) {{ slotProps.title }}
template(v-slot:consommation_title="slotProps")
SectionTitle(
:canCollapse="true",
:collapsed="slotProps.isContentVisible",
textMinWidth="240px"
) {{ slotProps.title }}
template(v-slot:icon)
em.fas.fa-gas-pump(style="font-size: 24px")
template(v-slot:chrono_title="slotProps")
SectionTitle(
:canCollapse="true",
:collapsed="slotProps.isContentVisible",
textMinWidth="240px"
) {{ slotProps.title }}
template(v-slot:icon)
em.fas.fa-leaf(style="font-size: 24px")
template(v-slot:sensors_title="slotProps")
SectionTitle(
:icon="'radar'",
:canCollapse="true",
:collapsed="slotProps.isContentVisible",
textMinWidth="240px"
) {{ slotProps.title }}
//Details - Both
template(v-slot:vehicleName)
span {{ isSinglePosition ? ( position?.vehicleName || positionDetails?.vehicleName) : analysis?.vehicleName }}
template(v-slot:vehicleRegistrationPlate)
span {{ isSinglePosition ? (position.vehicleRegistrationPlate || positionDetails.vehicleRegistrationPlate) : analysis.vehicleRegistrationPlate }}
//Details - Position
template(v-slot:datetime)
span {{ datetimeFormatted }}
template(v-slot:address)
span {{ positionDetails.addressFormatted || singlePositionExtraDetails.addressFormatted }}
template(v-slot:lat)
span {{ position.lat }}
template(v-slot:lng)
span {{ position.lng }}
template(v-slot:time)
span {{ positionDetails.timeFormatted }}
template(v-slot:speed)
span {{ positionDetails.speedFormatted }}
//Details - Analysis
template(v-slot:startDatetime)
span {{ analysis.startDatetimeFormatted }}
template(v-slot:startAddress)
span {{ analysis.startAddressFormatted }}
template(v-slot:endDatetime)
span {{ analysis.endDatetimeFormatted }}
template(v-slot:endAddress)
span {{ analysis.endAddressFormatted }}
template(v-slot:duration)
span {{ analysis.durationFormatted }}
template(v-slot:effectiveDuration)
span {{ analysis.effectiveDurationFormatted }}
template(v-slot:distance)
span {{ analysis.distanceFormatted }}
template(v-slot:averageSpeed)
span {{ analysis.speedFormatted }}
//Details - Sensors config
template(v-slot:sensorConfig)
SensorsConfigInfos
//Consumption
template(v-slot:averageCo2)
span {{ $transform.appendUnit('g/Km', analysis.averageCo2) }}
template(v-slot:totalCo2)
span {{ $transform.appendUnit('Kg', analysis.totalCo2) }}
template(v-slot:gauge)
DiagnosticAnalysisGauge(
:value="analysis.averageConsumption"
:refConsumptionOver100km="refConsumptionOver100km"
)
template(v-slot:gauge_right)
.col-12
.row.section_label
span {{ $t('diagnostics.analysis.totalConsumption') }}
.row.section_value
span {{ analysis.totalConsumption }} {{$t('diagnostics.chart.units.liters')}}
.row.section_label
span {{ $t('diagnostics.analysis.averageConsumption') }}
.row.section_value
span {{ analysis.averageConsumption }} {{$t('diagnostics.chart.units.conso100km')}}
.row.section_label
span {{ $t('diagnostics.analysis.referenceConsumption') }}
.row.section_value
span {{ analysis.referenceConsumption }} {{$t('diagnostics.chart.units.conso100km')}}
//Sensors -> Single positioin
template(v-slot:sensors_content)
SensorsInfos(:item="positionDetails" :removeMargin="true")
//Chrono
template(v-slot:chronoChart)
DiagnosticsChronoChartAlternative.mt-2
</template>
<script>
import SectionTitle from '@c/shared/SectionTitle/SectionTitle.vue'
import SectionField from '@c/shared/SectionField.vue'
import DynamicSections from '@c/shared/DynamicSections.vue'
import DiagnosticAnalysisGauge from '@c/diagnostic/DiagnosticAnalysisGauge.vue'
import { queueOperationOnce } from '@/utils/promise.js'
import DiagnosticsChronoChartAlternative from '@c/diagnostic/DiagnosticsChronoChartAlternative.vue'
import {
normalizeAnalyzeHistorySegment,
getVehicleHistoryPositionDetailsFromDateLegacy,
} from '@/services/history-service.js'
import envService from '@/services/env-service.js'
import normalizePositionEntity from '@/services/entities/position-entity'
import SensorsInfos from '@/components/shared/SearchResults/Submenu/SensorsInfos.vue'
import SensorsConfigInfos from '@c/shared/SensorsConfigInfos.vue'
import { getQueryStringValue } from '@/utils/querystring'
import vehicleService from '@/services/vehicle-service.js'
import { isValidPositionId } from '@/services/position-service.js'
/**
* Test dataset: DGD/ISOPROD/8151/2022-03-04
*/
export default {
name: 'DiagnosticsAnalysis',
components: {
SectionTitle,
SectionField,
DynamicSections,
SensorsInfos,
SensorsConfigInfos,
DiagnosticAnalysisGauge,
DiagnosticsChronoChartAlternative,
},
props: {
position: {
type: Object,
default: () => {
return !envService.isProduction() && getQueryStringValue('test') === 1
? normalizePositionEntity({
vehicleName: '1096',
vehicleRegistrationPlate: 'XR230Z',
datetime: '2022-03-04T05:30:08',
vehicleId: 8151,
boxNumber: 203,
serverId: 34,
latitude: 47.94443611111111,
longitude: 1.906036111111111,
hasContactOn: true,
startupFlag: false,
quality: 1,
speed: 0,
altitude: 0,
})
: {}
},
},
analysis: {
type: Object,
default: () =>
!envService.isProduction() && getQueryStringValue('test') === 1
? normalizeAnalyzeHistorySegment({
vehicleId: 8151,
clientId: 248,
vehicleCategoryId: 99,
vehicleName: '1096',
clientName: 'DGD',
vehicleRegistrationPlate: 'FX-578-NB',
vehicleCategoryName: 'BOM',
startDatetime: '2022-03-04T04:28:38',
endDatetime: '2022-03-04T06:30:00',
duration: 0,
effectiveDuration: 46281,
distance: 81810,
speed: 9.09,
totalCo2: 0,
averageCo2: 0,
totalConsumption: 0,
averageConsumption: 0,
referenceConsumption: 70,
averageEngineSpeed: 0,
startAddress: 'Rue du Faubourg Bannier',
startZipCode: '45000',
startCity: 'Orl\u00e9ans',
startLongitude: 1.89815,
startLatitude: 47.92017,
endAddress: 'All\u00e9e Marcel Lerouge',
endZipCode: '45770',
endCity: 'Saran',
endLongitude: 1.90618,
endLatitude: 47.94483,
tor: [
{ number: 1, name: 'Grand Bac', value: '98' },
{ number: 2, name: 'Bac gauche', value: '719' },
{ number: 3, name: 'Bac droit', value: '702' },
{ number: 4, name: 'Porte ouverte', value: '00:05' },
{ number: 5, name: 'Ripeur gauche', value: '08:16' },
{ number: 6, name: 'Ripeur droit', value: '08:11' },
{ number: 8, name: 'Marche arriere', value: '02:30' },
],
ana: [],
})
: {},
},
},
data() {
return {
singlePositionExtraDetails: {},
dynamicSectionsState: {
sections: [
{
name: 'details',
title: this.$t('diagnostics.analysis.title_details'),
rows: [
//Both modes
{
twoColumns: [
{
name: 'vehicleName',
label: this.$t('common.vehicule'),
},
{
name: 'vehicleRegistrationPlate',
label: this.$t('common.matriculation'),
},
],
},
//Position (Single position) ----------------------
{
visible: () => this.isSinglePosition,
twoColumns: [
{
name: 'datetime',
label: this.$t('common.from'),
},
{
name: 'address',
label: this.$t('common.position'),
},
],
},
{
visible: () => this.isSinglePosition,
twoColumns: [
{
name: 'lat',
label: this.$t('common.lat'),
},
{
name: 'lng',
label: this.$t('common.lng'),
},
],
},
{
visible: () => this.isSinglePosition,
twoColumns: [
{
name: 'time',
label: this.$t('common.hour'),
},
{
name: 'speed',
label: this.$t('common.Vitesse'),
},
],
},
//Analysis (Two positions) -----------------------
//De datetime
//Position address
{
visible: () => !this.isSinglePosition,
twoColumns: [
{
name: 'startDatetime',
label: this.$t('common.from'),
},
{
name: 'startAddress',
label: this.$t('common.position'),
},
],
},
//A datetime
//Position address
{
visible: () => !this.isSinglePosition,
twoColumns: [
{
name: 'endDatetime',
label: this.$t('common.to'),
},
{
name: 'endAddress',
label: this.$t('common.position'),
},
],
},
//Duree //Duree effective
{
visible: () => !this.isSinglePosition,
twoColumns: [
{
name: 'duration',
label: this.$t('common.duree'),
},
{
name: 'effectiveDuration',
label: this.$t('diagnostics.analysis.effective_duration'),
},
],
},
//Distance Vitesse moyen
{
visible: () => !this.isSinglePosition,
twoColumns: [
{
name: 'distance',
label: this.$t('common.distance'),
},
{
name: 'averageSpeed',
label: this.$t('common.average_speed'),
},
],
},
//Sensors configuration (Last)
{
//visible:()=>this.isSinglePosition,
name: 'sensorConfig',
singleColumn: {
name: 'sensorConfig',
},
},
],
isContentVisible: true,
},
//Informations Capteurs
{
name: 'sensors',
title: this.$t('diagnostics.analysis.title_sensors'),
rows: [
//Analysis
//Single position
],
isContentVisible: true,
},
//Consommation
{
name: 'consommation',
title: this.$t('diagnostics.analysis.title_consommation'),
rows: [
//Moyenne reject CO2 // Total reject CO2
{
twoColumns: [
{
label: this.$t('diagnostics.analysis.averageCo2'),
name: 'averageCo2',
className: 'col-8',
},
{
label: this.$t('diagnostics.analysis.totalCo2'),
name: 'totalCo2',
className: 'col-4',
},
],
},
{
twoColumns: [
{
name: 'gauge',
label: false,
className: 'col-8',
},
{
name: 'gauge_right',
label: false,
className: 'col-4',
style: `display: flex;
flex-direction: column;
justify-content: center;
position: relative;
top: -10px;`,
},
],
},
//chart consommation //consommation total / moyenne / reference
],
isContentVisible: true,
visible: () =>
!this.isSinglePosition && this.analysis?.averageConsumption,
},
//Chrono
{
name: 'chrono',
title: this.$t('searchModule.tabs.chrono'),
rows: [
{
name: 'chronoChart',
singleColumn: {
name: 'chronoChart',
},
},
],
isContentVisible: true,
visible: () => this.isChronoChartVisible,
},
],
},
}
},
computed: {
datetimeFormatted() {
return this.position?.datetime
? this.$date.formatDatetimeWithSeconds(
new Date(this.position?.datetime)
)
: ''
},
isSinglePosition() {
return Object.keys(this.position || {}).length > 0
},
isChronoChartVisible() {
let chronoData = this.$store.state.diagnostics.chronoData?.synthesis || {}
let hasChronoData = false
Object.keys(chronoData).forEach((key) => {
if (
chronoData[key] !== '' &&
chronoData[key] !== '00h00' &&
chronoData[key] !== 0
) {
hasChronoData = true
}
})
return !this.isSinglePosition && hasChronoData
},
refConsumptionOver100km() {
return this.$store.state.diagnostics?.vehicleConfiguration
?.vehicleGlobalConsumptionRef
},
positionDetails() {
return {
...(this.$store.state.diagnostics?.vehicleHistoryOverview || {}), //vehicleName/vehicleRegistrationPlate
...(this.isSinglePosition ? this.position : this.analysis),
}
},
},
watch: {
position: {
deep: true,
handler() {
//Delay two seconds if replay is playing to avoid calling API dozen of times to retrieve just the address
if (
this.$store.state.diagnostics.chartSelectedItemTrigger === 'replay'
) {
queueOperationOnce(
'diagnostics_analysis_api_fetch',
() => {
this.updateExtraPositionDetails()
},
{
timeout: 1000,
clearPreviousTimeout: true,
}
)
} else {
this.updateExtraPositionDetails()
}
},
},
},
mounted() {
this.updateExtraPositionDetails()
},
methods: {
/**
* Used to retrieve formatted address, which is not present in the available selected position (single position)
*/
async updateExtraPositionDetails() {
if (
!this.isSinglePosition ||
!this.position.vehicleId ||
!this.position.datetime
) {
return
}
let hideLoader =
(this.$loader && this.$loader.showAlternative()) || (() => ({}))
if (isValidPositionId(this.position?.id)) {
this.singlePositionExtraDetails = Object.freeze(
(await vehicleService.getVehiclePosition(this.position.id)) || {}
)
hideLoader()
} else {
getVehicleHistoryPositionDetailsFromDateLegacy(
this.position.vehicleId,
this.position.datetime
)
.then((details) => {
this.singlePositionExtraDetails = Object.freeze({
addressFormatted: details.addressFormatted,
})
})
.finally(() => {
hideLoader()
})
}
},
},
}
</script>
<style lang="scss" scoped>
.section_label {
font: normal normal bold 11px/18px Open Sans;
letter-spacing: 0;
color: var(--color-tundora);
}
.section_value {
font: normal normal normal 12px/18px Open Sans;
color: var(--color-tundora);
}
</style>
Source