import { splitOperation } from '@/utils/promise.js'
import moment from 'moment'
import { getNestedValue } from '../utils/object'
import { getQueryStringValue } from '@/utils/querystring'
import { getFormattedAddress } from '@/utils/address.js'
import api from '@/api'
import i18n from '@/i18n'
import { getAPIV3Pooling } from '@/api'
import { getEnvValue } from '@/services/env-service.js'
import APIUrls, {
APIV3RequestDatetimeFormat,
} from '@/config/simpliciti-apis.js'
export async function getEventTypesCategories(onData = () => {}) {
let types = {
exploitation: 'operation_message',
anomalie: 'anomaly',
statut: 'status',
}
return await getAPIV3Pooling({
uri: `${APIUrls.APIV3_EVENTS_ANOMALIES}?page=1&itemsPerPage=40`,
callback: onData,
transform(item) {
return {
id: item.id,
code: item.code,
label: item.description,
type: types[item.type] || item.type,
}
},
})
}
export async function fetchEventDetailsById(aggregateId) {
return normalizeAPIV3Item(
(await api.v3.get(APIUrls.APIV3_AGGREGATE_EVENTS + '/' + aggregateId)).data
)
}
export async function fetchVehicleEvents(vehicleId, dates = [], filters = {}) {
console.log('fetchVehicleEvents', filters)
let filtersValue = []
if (filters.anomaly) {
filtersValue.push(0)
}
if (filters.eventExploitation) {
filtersValue.push(1)
}
if (filters.status) {
filtersValue.push(3)
}
const payload = {
vehicleId: vehicleId,
'multipleDate[between][datetime][start]': dates.map((date) =>
moment(date)
.hour(0)
.minutes(0)
.seconds(0)
.format(APIV3RequestDatetimeFormat)
),
'multipleDate[between][datetime][end]': dates.map((date) =>
moment(date)
.hour(23)
.minutes(59)
.seconds(59)
.format(APIV3RequestDatetimeFormat)
),
type: filtersValue,
group: 'all',
}
const result =
(await api.v3.get(APIUrls.APIV3_AGGREGATE_EVENTS, payload)).data || []
console.log('fetchVehicleEvents', result)
return result.map((item) => {
return normalizeAPIV3Item(item)
})
}
/**
* Used by events module.
* - Data used for: Map markers and table
*
* Split: 5 element, then 1 date (i.g: 1 request per vehicle/date)
*
* @TODO To be able to stop the search (i.g user stop an automatic search)
*
* @param {Array} options.elementIds Vehicle or circuit ids [1,2,3]
* @param {Array} options.dates Dates ['2022-04-29'] or [Moment]
* @param {Object} options.filters Custom querystring parameters
* @param {String} options.elementType Helps build the uri (vehicle/circuit)
* @param {Object} options.fetchOptions Give options to axios
* @param {Function} options.handleResults (results)=>({}) Each time results are available
*/
export async function fetchEvents(options = {}) {
/* options = {
...options,
handleResults: options.handleResults || (results)=>({})
} */
return await splitOperation({
sequential: false,
generateSubsets() {
let subsets = []
let single = {}
options.elementIds.forEach((id) => {
single.elementIds = single.elementIds || []
single.elementIds.push(id)
if (single.elementIds.length >= 5) {
single.dates = options.dates
subsets.push(single)
single = {}
}
})
if (single.elementIds) {
single.dates = options.dates
subsets.push(single)
}
return subsets
},
async handleSubset(subset) {
console.log('fetchEvents:splitOperation:handleSubset')
//Split by date (API supports 1 date at time)
await splitOperation({
sequential: true,
generateSubsets() {
return subset.dates.map((date) => {
return {
...subset,
dates: [date],
}
})
},
async handleSubset(subset) {
console.log(
'fetchEvents:splitOperation:handleSubset:splitOperation:handleSubset'
)
let dates = subset.dates
let fetchOptions = options.fetchOptions || {}
let elementParamName = {
vehicle: 'vehicleId',
circuit: 'roundId',
}
let res = await api.v3.get(
APIUrls.APIV3_AGGREGATE_EVENTS,
{
[elementParamName[options.elementType || 'vehicle']]:
subset.elementIds,
'multipleDate[between][datetime][start]': dates.map((date) =>
moment(date)
.hour(0)
.minute(0)
.second(0)
.format(APIV3RequestDatetimeFormat)
),
'multipleDate[between][datetime][end]': dates.map((date) =>
moment(date)
.hour(23)
.minute(59)
.second(59)
.format(APIV3RequestDatetimeFormat)
),
//other filters goes here
...(options.filters || {}),
},
fetchOptions
)
res = (res.data || []).map(normalizeAPIV3Item)
return res
},
withSubsetResult: (results) => {
options.handleResults(results || [])
},
})
},
})
}
/**
* @todo Immatriculation
* @param {Object} item Object to transform
* @returns
*/
export function normalizeAPIV3Item(item = {}) {
const colors = {
0: 'red', //anomaly
1: 'orange', //Message d’exploitation
3: 'green', //status
}
let photos = (item.files || []).map((file) => file.url)
return {
id: item.id,
lat: item.latitude,
lng: item.longitude,
...(item.datetime
? {
date: item.datetime,
timestamp: moment(item.datetime)._d.getTime(),
formattedDate: moment(item.datetime).format('DD-MM-YYYY'),
formattedTime: moment(item.datetime).format('HH:mm:ss'),
}
: {}),
immat: '',
address: getFormattedAddress(item.mapMatch || {}, {
city: 'nocity',
}),
city: getNestedValue(item, 'mapMatch.city'),
fullAddress: getFormattedAddress(item.mapMatch || {}, {}),
comment: item.comment,
label: item.anomalyLabel,
photos,
hasPhotos:
getNestedValue(item, ['totalFiles', 'filesNumber'], photos.length) > 0,
type: item.type,
color: colors[item.type] || 'red',
vehicleName: item.vehicleName,
vehicleId: item.vehicleId,
isAPIV3Item: true,
circuitName: item.roundName || '',
puceNumber: getNestedValue(item, 'binCollection.tagNumber'),
binCollectionSide: getNestedValue(item, 'binCollection.side'),
binCollectionSideLabel: getNestedValue(item, 'binCollection.side', '', {
allowZero: true,
transform(sideNumber, originalValue, rootValue) {
return (
{
0: i18n.t('events.table_column_side_left'), //gauche
1: i18n.t('events.table_column_side_right'), //droite
2: i18n.t('events.table_column_side_combine'), //combiné
3: i18n.t('events.table_column_side_bicomp'), //bicomp
5: i18n.t('events.table_column_side_arm'), //bras
9: i18n.t('events.table_column_side_pedestrian'), //pieton
}[sideNumber.toString()] || ''
)
},
}),
}
}
export function normalizeAPIV2Array(data) {
let normalizedData = []
const colors = {
0: 'red', //anomaly
1: 'orange', //Message d’exploitation
3: 'green', //status
}
data.forEach((item) => {
let streetNum =
item.evenement_num_rue !== '' && item.evenement_num_rue !== '0'
? item.evenement_num_rue + ' '
: ''
let streetName =
item.evenement_adresse !== '' ? item.evenement_adresse + ' ' : ''
let formatAddress = streetNum + streetName
normalizedData.push({
id: item.evenement_id,
lat: item.evenement_latitude_wgs84,
lng: item.evenement_longitude_wgs84,
date: item.evenement_dateheure,
timestamp: moment(item.evenement_dateheure)._d.getTime(),
formattedDate: moment(item.evenement_dateheure).format('DD-MM-YYYY'),
formattedTime: moment(item.evenement_dateheure).format('HH:mm:ss'),
immat: item.nom_vehicule,
address: formatAddress,
city: item.evenement_commune,
fullAddress: formatAddress + item.evenement_commune,
comment: item.evenement_tud150,
label: item.anomalie_libelle,
photos: item.photos ? (item.photos.photo || []).map((i) => i.url) : [],
type: item.evenement_type,
color: colors[item.evenement_type] || 'red',
vehicleName: item.nom_vehicule,
vehicleId: item.vehicule_id,
})
})
return normalizedData
}
function getLabelByType(type) {
return (
{
0: i18n.te('events.types.anomaly')
? i18n.t('events.types.anomaly')
: 'anomaly', //anomaly
1: i18n.te('events.types.message_exploitation')
? i18n.t('events.types.message_exploitation')
: 'Message d’exploitation', //Message d’exploitation
3: i18n.te('events.types.status')
? i18n.t('events.types.status')
: 'status', //status
}[type] ||
(i18n.te('events.types.unknown')
? i18n.t('events.types.unknown')
: '(No name)')
)
}
/**
* Replace JSON mock with hardcoded/auto-generated mock inside the code source (Optimize)
* @param {*} elementIds
* @param {*} dates
* @param {*} options
* @returns
*/
export async function fetchEventsCumulation(elementIds, dates, options = {}) {
console.log('event-service::fetchEventsCumulation', {
elementIds,
dates,
options,
})
let res =
(getQueryStringValue('mockapi') === '1' &&
require('@/api/mocks/v3/geored/events/service/cumulation/events_service_cumulation_berto_prolians.json')) ||
(
await api.v3.get(APIUrls.APIV3_EVENTS_CUMULATION, {
format: {
vehicle: 'vehicle',
circuit: 'round',
}[options.elementType || 'vehicle'],
page: 1,
itemsPerPage: 30,
//vehicule_id/circuit_id
[{
vehicle: 'vehicleId',
circuit: 'roundId',
}[options.elementType || 'vehicle']]: elementIds,
'multipleDate[between][datetime][start]': dates.map((date) =>
moment(date)
.hour(0)
.minutes(0)
.seconds(0)
.format(APIV3RequestDatetimeFormat)
),
'multipleDate[between][datetime][end]': dates.map((date) =>
moment(date)
.hour(23)
.minutes(59)
.seconds(59)
.format(APIV3RequestDatetimeFormat)
),
...(options.filters || {}),
})
).data
function mapResponseItems(root, onSingleMapHandler = null) {
let items = []
Object.keys(root).forEach((label) => {
let singleItemRaw = root[label]
let codesObject = singleItemRaw.types || singleItemRaw.codes || []
let singleItem = {
id: singleItemRaw.id || label,
label: label,
count: singleItemRaw.total,
items: Object.keys(codesObject).map((eventGroupKey) => {
let eventGroup = codesObject[eventGroupKey]
return {
id: eventGroup.code,
code: eventGroup.code,
label: eventGroup.label,
count: eventGroup.count,
type: eventGroup.type,
typeLabel: getLabelByType(eventGroup.type),
}
}),
}
onSingleMapHandler && onSingleMapHandler(singleItem, singleItemRaw)
items.push(singleItem)
})
return items
}
return mapResponseItems(res, (dateItem, rawItem) => {
//@todo: format using i18n date wrapper
dateItem.label = moment(dateItem.label).format(`DD/MM/YYYY`)
dateItem.subItems = mapResponseItems(
rawItem.vehicles || rawItem.rounds || []
)
dateItem.timestamp = moment(dateItem.label)._d.getTime()
return dateItem
})
}
export function getEventsSearchSelectionLimit() {
const getEnvValueFloat = (n) =>
getEnvValue(n, '', {
transform: (value) => parseFloat(value),
})
return (
getEnvValueFloat('VUE_APP_EVENTS_MODULE_SEARCH_SELECTION_LIMIT') ||
getEnvValueFloat('VUE_APP_SEARCH_SELECTION_LIMIT') ||
100
)
}
export default {
fetchEvents,
fetchEventDetailsById,
fetchEventsCumulation,
fetchVehicleEvents,
getEventsSearchSelectionLimit,
getEventTypesCategories,
normalizeAPIV2Array,
normalizeAPIV3Item,
}
Source