Source

components/reference-circuit/CircuitExecutionDetails.vue

<template lang="pug">
.circuit-execution-details(:class="{loading:loading}")
    b-spinner(
        v-if="loading"
        class="loader"
        variant="info"
        style="width: 3rem; height: 3rem; margin: 0 auto; display:block;"
    )
    div(v-if="!loading && (!headInfos || !stepsInfos)") 
      .row
        .col-12
          .alert.alert-info.p-2 {{$t('location_module.no_results')}}
    

    div(v-if="!loading && !!headInfos&&!!stepsInfos")
      
      .head_infos(v-if="['circuit','driver'].includes(item.type)" style="justify-content: flex-start;")
        .info_item
            label.info_item_label Vehicle:
            .info_item_value {{item.vehicleName}}
        .info_item
            //@TODO: If no active circuit, print the circuit name here

      .head_infos(v-if="!!headInfos && headInfos.sameDay")
          .info_item(v-show="headInfos.circuitName")
            label.info_item_label {{$t('common.Circuit')}}:
            .info_item_value {{headInfos.circuitName}}
          .info_item()
              label.info_item_label {{$t('common.date')}}:
              .info_item_value {{headInfos.dateFrom}}
          .info_item
              label.info_item_label {{$t('common.debut')}}:
              .info_item_value {{headInfos.timeFrom}}
          .info_item()
              label.info_item_label {{$t('common.fin')}}:
              .info_item_value {{headInfos.timeTo}}
      .head_infos(v-if="!!headInfos && !headInfos.sameDay")
          .info_item
              label.info_item_label {{$t('common.debut')}}:
              .info_item_value {{headInfos.dateFrom}} {{headInfos.timeFrom}}
          .info_item()
              label.info_item_label {{$t('common.fin')}}:
              .info_item_value {{headInfos.dateTo}} {{headInfos.timeTo}}
      .head_infos(v-if="!!headInfos")
          .info_item
              label.info_item_label {{$t('common.distance')}}:
              .info_item_value {{headInfos.distance}}Km
          .info_item
              label.info_item_label {{$t('common.Réalisation')}}:
              .info_item_value {{headInfos.donePercentage}}%
          .info_item
      .steps_filter_wrapper()
        CircuitExecutionStepsFilter(v-model="stepsFilter")
      VerticalChart(v-if="!!stepsInfos" :nodes="stepsInfos"
        @nodeclick="nodeclick"
        @nodeclickright="nodeclickright"
        :activeNodeId="activeNodeId"
      )
          template(v-slot:node_icon="slotProps")
              NodeIcon(:color="slotProps.node.color")
          template(v-slot:node_content="slotProps")
              span(v-if="slotProps.node.date") {{slotProps.node.date}}
              
              .row.m-0
                .col-6.p-0
                  .label {{$t('location.details.circuit_tab.label_step_number')}} {{slotProps.node.id}}
                .col-6.p-0
                  .label {{$t('location.details.circuit_tab.label_distance')}}: 
                    span.value {{(slotProps.node.distance_theorique*1000).toFixed(2)}}m
              .row.m-0
                .col-12.p-0
                  .label {{$t('location.details.circuit_tab.label_action')}}: 
                    span.value {{slotProps.node.activite_nom}}
              .row.m-0
                .col-6.p-0()
                  .label {{$t('location.details.circuit_tab.label_duration')}}: 
                    span.value {{slotProps.node.duration}}
                .col-6.p-0
                  .label {{$t('location.details.circuit_tab.label_done_perc')}}: 
                    em.fa.fa-check(v-show="slotProps.node.realise" style="color:var(--color-silver-tree)") 
                    em.fa.fa-times(v-show="!slotProps.node.realise" style="color:var(--color-coral-red)") 

  
</template>
<script>
import Vue from 'vue'
import moment from 'moment'
import VerticalChart from '@c/shared/SearchResults/Submenu/VerticalChart.vue'
import NodeIcon from '@c/shared/SearchResults/Submenu/CircuitExecutionStepIcon.vue'
import TableButton from '@c/shared/TableButton.vue'
import MapIcon from '@c/shared/TableModesToolbar/MapIcon.vue'
import { formatSeconds } from '@/utils/dates.js'
import CircuitExecutionStepsFilter from '@c/shared/CircuitExecutionStepsFilter.vue'
import { createCircuitExecutionStepsFilter } from '@c/location/mixins/circuit-execution-mixin.js'
import { APIV2RequestDatetimeFormat } from '@/config/simpliciti-apis.js'

function getFormattedTimeFromApiDate(date) {
  let m = moment(date, APIV2RequestDatetimeFormat)
  return (m.isValid() && Vue.$date.formatTimeWithSeconds(m)) || '...'
}

/**
 * Used by Circuit reference feature to render circuit execution details (List mode)
 *
 * Main search - history by circuit - circuit tab
 * Main search - realtime by [all] - circuit tab (last circuit)
 * @namespace components
 * @category components
 * @subcategory reference-circuit
 * @module CircuitExecutionDetails
 **/
export default {
  name: 'CircuitExecutionDetails',
  components: {
    CircuitExecutionStepsFilter,
    VerticalChart,
    NodeIcon,
    TableButton,
    MapIcon,
  },
  props: {
    /**
     * selected item (From real-time/history search)
     */
    item: {
      type: Object,
      default: () => ({}),
    },
    /**
     * Used by: Location - History - Circuit tab - (Multiple circuit executions for the same vehicle)
     */
    circuitDetailsFromAPI: {
      type: Object,
      default: () => null,
    },
    /**
     * Used by: Location - History - Circuit tab - (Multiple circuit executions for the same vehicle)
     */
    circuitExecutionStepsFromAPI: {
      type: Object,
      default: () => null,
    },
    loading: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      activeNodeId: null,
      stepsFilter: 'EXECUTION',
    }
  },
  computed: {
    bottomProps() {
      return {
        circuitExecutionSteps: this.circuitExecutionSteps,
        circuitDetails: this.circuitDetails,
      }
    },
    circuitDetails() {
      return this.circuitDetailsFromAPI
    },
    circuitExecutionSteps() {
      return this.circuitExecutionStepsFromAPI
    },
    headInfos() {
      const item = this.circuitDetails
      return (
        (item &&
          !!item.circuit_id &&
          Object.keys(item).length > 0 && {
            circuitName: item.circuit_nom_court || '',
            dateFrom: this.$date.formatDate(item.dateFrom),
            timeFrom: getFormattedTimeFromApiDate(item.dateFrom),
            dateTo: this.$date.formatDate(item.dateTo),
            timeTo: getFormattedTimeFromApiDate(item.dateTo),
            sameDay: moment(item.dateFrom).isSame(moment(item.dateTo), 'day'),
            distance: item.lg_realisee_circuit || '...',
            donePercentage: item.taux_realisation_circuit || '...',
          }) ||
        null
      )
    },
    unfilteredStepsInfos() {
      return (this.circuitExecutionSteps.troncons || []).map((t) =>
        Object.freeze({
          ...t,
          date: this.$date.formatTime(t.dateheure_debut, {
            fallbackValue: '...',
          }),
          duration: formatSeconds(t.duree_sec),
          color: t.realise ? t.activite_couleur || '#70BD95' : '#FF4545',
        })
      )
    },
    stepsInfos() {
      return (
        (this.unfilteredStepsInfos || []).filter(
          createCircuitExecutionStepsFilter(this.stepsFilter)
        ) || []
      )
    },
  },
  destroyed() {
    this.$store.dispatch(
      'simpliciti_map/highlightCircuitExecPolylineSection',
      null
    )
  },
  methods: {
    nodeclick(node) {
      if (this.activeNodeId) {
        this.activeNodeId = null
        this.$emit('onUnhighlight')
        return
      }
      this.$emit('onHighlight', {
        stepNumber: node.id,
      })
      this.activeNodeId = node.id
    },
    nodeclickright({ event, node }) {
      event.stopPropagation()
      this.activeNodeId = node.id
      this.$emit('onHighlightAndFlyToBounds', {
        stepNumber: node.id,
      })
    },
  },
}
</script>
<style lang="scss" scoped>
.circuit-execution-details {
  max-height: 560px;
  overflow: auto;
  padding-bottom: 50px;

  &.loading {
    min-width: 230px;
    display: flex;
    justify-content: center;
    align-items: center;
  }
}
.info_item_value {
  text-align: left;
  font: normal normal normal 12px/18px Open Sans;
  letter-spacing: 0px;
  color: var(--color-tundora);
}
.info_item_label {
  text-align: left;
  font: normal normal normal 11px/18px Open Sans;
  letter-spacing: 0px;
  color: var(--color-metal-rock);
  margin-right: 5px;
}
.info_item {
  display: flex;
  flex-grow: 1;
  min-width: 41px;
}
.head_infos {
  display: flex;
  justify-content: flex-start;
  column-gap: 5px;
  margin: 0px 5px;
  flex-wrap: wrap;
}
.toolbar {
  display: flex;
  justify-content: flex-end;
  column-gap: 5px;
}
.node,
.node_content {
  display: flex;
  justify-content: flex-start;
  align-items: center;
}
.node_content {
  flex-direction: column;
}
.node_union {
  width: 4px;
  background-color: var(--color-dark-blue);
  height: 1px;
  margin-left: 10px;
}
.steps_filter_wrapper {
  display: flex;
  align-items: center;
}
</style>