<template lang="pug">
.last_circuit_tab
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')}}
.last_circuit_tab__infos(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="isSearchByVehicleOrDriver && 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(v-show="!hasActiveCircuit")
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(v-show="!hasActiveCircuit")
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
.row
.col
.row
.col.steps_filter_wrapper()
CircuitExecutionStepsFilter(v-model="stepsFilter")
.col
.toolbar(v-if="!!stepsInfos")
LocationExportPendulumButton(v-show="$store.getters['location_module/selectedItem'].circuitExecutionId"
fontSize="18px"
)
div(v-b-tooltip.hover :title="$t('location.circuit.button_load_gps_positions')")
b-btn.table_mode_btn.mini-btn(variant="outline-primary"
@click="()=>$emit('loadGPSPositions')"
:disabled="isLoadingGPSPositions"
)
//em.fa.fa-map-pin(style="margin-right:0px!important;")
simple-svg(
width="15px"
height="15px"
fill="var(--color-dark-blue)" fillClassName="cls-1"
:src="require('./assets/view-circ-exec-gps-positions.svg')"
)
div(v-b-tooltip.hover :title="$t('location.circuit.button_load_trip_history')")
b-btn.table_mode_btn.mini-btn(variant="outline-primary"
@click="(e)=>$emit('loadTripHistory') || e.target.blur()"
:disabled="isLoadingTripHistory"
)
simple-svg(
width="15px"
height="15px"
fill="var(--color-dark-blue)" fillClassName="cls-1"
:src="require('./assets/view-trip-history.svg')"
)
//@TODO: refactor into shared/LayoutSwitchModeButton.vue
TableButton(
:title="$t('common.layout.modes.table_and_map_button_tooltip')"
@click="switchToTablePlusMapMode({bottom:'CircuitExecTable',top:'CircuitExecMap',bottomProps})"
icon="table-map")
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 { mapGetters } from 'vuex'
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 locationLayoutModesMixin from '@c/location/mixins/location-layout-modes.js'
import { APIV2RequestDatetimeFormat } from '@/config/simpliciti-apis.js'
import LocationExportPendulumButton from '@c/location/LocationExportPendulumButton.vue'
function getFormattedTimeFromApiDate(date) {
let m = moment(date, APIV2RequestDatetimeFormat)
return (m.isValid() && Vue.$date.formatTimeWithSeconds(m)) || '...'
}
/**
* Used by
* Main search - history by circuit - circuit tab
* Main search - realtime by [all] - circuit tab (last circuit)
* @namespace components
* @category components
* @subcategory location/circuit
* @module CircuitExecDetails
**/
export default {
name: 'CircuitExecDetails',
components: {
CircuitExecutionStepsFilter,
VerticalChart,
NodeIcon,
TableButton,
MapIcon,
LocationExportPendulumButton,
},
mixins: [locationLayoutModesMixin],
inject: {
isLoadingGPSPositions: {
default: false,
},
isLoadingTripHistory: {
default: false,
},
},
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,
},
},
data() {
return {
loading: false,
activeNodeId: null,
stepsFilter: 'EXECUTION',
}
},
computed: {
...mapGetters({
circuitDetailsFromStore: 'location_module/circuitDetails',
circuitExecutionStepsFromStore: 'location_module/circuitExecutionSteps',
}),
bottomProps() {
return {
circuitExecutionSteps: this.circuitExecutionSteps,
circuitDetails: this.circuitDetails,
}
},
circuitDetails() {
return this.circuitDetailsFromAPI || this.circuitDetailsFromStore
},
circuitExecutionSteps() {
return (
this.circuitExecutionStepsFromAPI || this.circuitExecutionStepsFromStore
)
},
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
)
},
isSearchByVehicleOrDriver() {
return ['vehicle', 'driver'].includes(this.item.type)
},
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)
) || []
)
},
hasActiveCircuit() {
return this.item.searchType === 'realtime' && !!this.item.circuitId
},
},
watch: {
item() {
if (!this.circuitDetailsFromAPI) {
this.updateUsingVuex()
}
},
},
async mounted() {
this.switchToListMode({
mapComponent: 'CircuitExecMap',
})
if (!this.circuitDetailsFromAPI) {
this.updateUsingVuex()
}
},
destroyed() {
this.$store.dispatch(
'simpliciti_map/highlightCircuitExecPolylineSection',
null
)
},
methods: {
async updateUsingVuex() {
if (this.loading) {
return false
}
this.loading = true
await this.$store.dispatch(
'location_module/updateCircuitExecutionDetails',
{
vehicleId: this.item.vehicleId,
}
)
this.loading = false
},
nodeclick(node) {
if (this.activeNodeId) {
this.activeNodeId = null
this.$store.dispatch(
'simpliciti_map/highlightCircuitExecPolylineSection',
null
)
return
}
this.$store.dispatch(
'simpliciti_map/highlightCircuitExecPolylineSection',
node.id
)
this.$log.debug('nodeclick', node.id)
this.activeNodeId = node.id
},
nodeclickright({ event, node }) {
event.stopPropagation()
this.activeNodeId = node.id
this.$store.dispatch(
'simpliciti_map/highlightCircuitExecPolylineSection',
node.id
)
this.$mitt.emit('SIMPLICITI_MAP__FLY_TO_POLYLINE', {
stepNumber: node.id,
})
this.$log.debug('nodeclickright', node.id)
},
},
}
</script>
<style lang="scss" scoped>
.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;
align-items: center;
}
.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>
Source