Source

components/diagnostic/DiagnosticsAnalysis.vue

<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>