fleetmap-reports 1.0.284 → 1.0.288
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/jsLibraryMappings.xml +1 -1
- package/.idea/modules.xml +1 -1
- package/.idea/vcs.xml +1 -1
- package/{.idea/fleetmap-reports.iml → fleetmap-reports.iml} +1 -2
- package/lang/enGB.js +1 -11
- package/lang/esCL.js +1 -10
- package/lang/index.js +1 -4
- package/lang/ptBR.js +1 -11
- package/lang/ptPT.js +1 -11
- package/package.json +1 -2
- package/src/activity-report.js +206 -542
- package/src/automaticReports.js +1 -1
- package/src/events-report.js +21 -25
- package/src/here.js +1 -1
- package/src/index.js +2 -12
- package/src/index.test.js +25 -18
- package/src/kms-report.js +103 -409
- package/src/location-report.js +18 -22
- package/src/refueling-report.js +1 -11
- package/src/reportStyle.js +0 -26
- package/src/speeding-report.js +180 -239
- package/src/trip-report.js +159 -152
- package/src/util/driver.js +13 -5
- package/src/util/utils.js +1 -67
- package/src/zone-report.js +23 -22
- package/.idea/aws.xml +0 -17
- package/.idea/codeStyles/Project.xml +0 -7
- package/src/idle-report.js +0 -285
- package/src/tests/index.js +0 -22
- package/src/util/pdfDocument.js +0 -58
- package/src/util/traccar.js +0 -72
- package/src/util/trips.js +0 -76
package/src/refueling-report.js
CHANGED
|
@@ -109,31 +109,21 @@ function calculateRefuelingPositions(d, positions) {
|
|
|
109
109
|
let refuelingActivated = false
|
|
110
110
|
let currentValue = null
|
|
111
111
|
let positionsChecked = 0
|
|
112
|
-
let lastRefuelingIndex = 0
|
|
113
112
|
positions.forEach(function(element, index, array){
|
|
114
113
|
if(!element.attributes.ignition && refuelingActivated && !currentValue){
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
//Get 5 position before the ignition off to calculate the current value of the fuel tank level
|
|
118
|
-
//lastRefuelingIndex is used to avoid re-analyzing positions prior to a refueling
|
|
119
|
-
const before = (index > 5 ? array.slice((index-6 < lastRefuelingIndex ? lastRefuelingIndex : index-6), index-1) : array.slice(0, index-1)).filter(b => b.attributes.ignition && b.attributes.fuel)
|
|
114
|
+
const before = (index > 5 ? array.slice(index-6, index-1) : array.slice(0, index-1)).filter(b => b.attributes.ignition && b.attributes.fuel)
|
|
120
115
|
currentValue = Math.round(before.reduce((a, b) => a + b.attributes.fuel, 0) / before.length )
|
|
121
|
-
|
|
122
116
|
positionsChecked = 0
|
|
123
117
|
}
|
|
124
118
|
|
|
125
119
|
if(element.attributes.ignition && refuelingActivated && currentValue) {
|
|
126
|
-
//Ignition is on and Refueling is Active and there is a current value
|
|
127
|
-
//Calculate the value of the fuel tank level after turning the ignition back on
|
|
128
120
|
const after = (array.length > index + 5 ? array.slice(index, index+1) : array.slice(index)).filter(b => b.attributes.ignition && b.attributes.fuel)
|
|
129
121
|
const newValue = Math.round(after.reduce((a, b) => a + b.attributes.fuel, 0) / after.length )
|
|
130
122
|
|
|
131
123
|
const diff = automaticReports.calculateFuelDiff(currentValue, newValue, d)
|
|
132
124
|
if (diff > 20) {
|
|
133
|
-
//New refueling detected
|
|
134
125
|
const value = Math.round(diff * d.attributes.fuel_tank_capacity / 100)
|
|
135
126
|
refuelingPositions.push({position: element, diff: value})
|
|
136
|
-
lastRefuelingIndex = index
|
|
137
127
|
positionsChecked = 6 // to reset values
|
|
138
128
|
}
|
|
139
129
|
|
package/src/reportStyle.js
CHANGED
|
@@ -1,27 +1,3 @@
|
|
|
1
|
-
function getStyle(partnerData) {
|
|
2
|
-
const reportStyleData = {
|
|
3
|
-
pdfHeaderColor: [105, 105, 105],
|
|
4
|
-
pdfHeaderTextColor: [256, 256, 256],
|
|
5
|
-
pdfBodyColor: [256, 256, 256],
|
|
6
|
-
pdfBodyTextColor: [30, 30, 30],
|
|
7
|
-
pdfFooterColor: [210, 210, 210],
|
|
8
|
-
pdfFooterTextColor: [30, 30, 30],
|
|
9
|
-
imgHeight: 0,
|
|
10
|
-
imgWidth: 0,
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if(partnerData && partnerData.reports){
|
|
14
|
-
reportStyleData.pdfHeaderColor = partnerData.reports.mainColor || [105, 105, 105]
|
|
15
|
-
reportStyleData.pdfFooterColor = partnerData.reports.mainColor || [210, 210, 210]
|
|
16
|
-
reportStyleData.pdfFooterTextColor = partnerData.reports.mainColor ? [256, 256, 256] : [30, 30, 30]
|
|
17
|
-
reportStyleData.imgHeight = partnerData.reports.logoHeight || 0
|
|
18
|
-
reportStyleData.imgWidth = partnerData.reports.logoWidth || 0
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return reportStyleData
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
exports.getStyle = getStyle
|
|
25
1
|
|
|
26
2
|
exports.pdfHeaderColor = [105, 105, 105]
|
|
27
3
|
exports.pdfHeaderTextColor = [256, 256, 256]
|
|
@@ -30,5 +6,3 @@ exports.pdfBodyTextColor = [30, 30, 30]
|
|
|
30
6
|
exports.pdfFooterColor = [210, 210, 210]
|
|
31
7
|
exports.pdfFooterTextColor = [30, 30, 30]
|
|
32
8
|
|
|
33
|
-
|
|
34
|
-
|
package/src/speeding-report.js
CHANGED
|
@@ -1,150 +1,119 @@
|
|
|
1
|
+
const automaticReports = require("./automaticReports")
|
|
1
2
|
const messages = require('../lang')
|
|
2
3
|
const jsPDF = require('jspdf')
|
|
3
|
-
const {convertMS
|
|
4
|
-
const {headerFromUser, AmiriRegular} = require("./util/pdfDocument")
|
|
4
|
+
const {convertMS} = require("./util/utils")
|
|
5
5
|
require('jspdf-autotable')
|
|
6
6
|
const { parse } = require('wkt')
|
|
7
7
|
const turf = require('turf')
|
|
8
|
-
const
|
|
8
|
+
const reportStyle = require("./reportStyle")
|
|
9
9
|
const drivers = require("./util/driver")
|
|
10
10
|
const {distance, point} = require('turf')
|
|
11
11
|
const here = require('./here')
|
|
12
|
-
const {getUserPartner} = require("fleetmap-partners");
|
|
13
|
-
const traccar = require("./util/traccar");
|
|
14
12
|
|
|
15
13
|
let traccarInstance
|
|
16
|
-
let userData
|
|
17
14
|
|
|
18
15
|
const fileName = 'SpeedingReport'
|
|
19
|
-
const eventTypes = ['deviceOverspeed']
|
|
20
16
|
|
|
21
|
-
async function createSpeedingReport(from, to,
|
|
22
|
-
console.log('Create SpeedingReport')
|
|
17
|
+
async function createSpeedingReport(from, to, userData, traccar, roadSpeedLimits) {
|
|
23
18
|
traccarInstance = traccar
|
|
24
|
-
userData
|
|
19
|
+
console.log('createSpeedingReport', from, to, userData, traccar, roadSpeedLimits)
|
|
25
20
|
const reportData = []
|
|
26
21
|
|
|
27
|
-
if
|
|
28
|
-
|
|
29
|
-
const allData = await createSpeedingReportByDriver(from, to)
|
|
22
|
+
if(userData.byDriver){
|
|
23
|
+
const allData = await createSpeedingReportByDriver(from, to, userData, roadSpeedLimits)
|
|
30
24
|
reportData.push(allData)
|
|
31
25
|
}
|
|
32
|
-
else if
|
|
26
|
+
else if(userData.byGroup){
|
|
33
27
|
console.log("ByGroup")
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async function createSpeedingReportByGroup(from, to){
|
|
46
|
-
const reportData = []
|
|
47
|
-
for (const g of userData.groups) {
|
|
48
|
-
const devices = userData.devices.filter(d => d.groupId === g.id)
|
|
49
|
-
console.log(g.name + ' devices:' + devices.length)
|
|
50
|
-
if(devices.length > 0) {
|
|
51
|
-
const groupData = {
|
|
52
|
-
devices: [],
|
|
53
|
-
group: g,
|
|
54
|
-
xpert: devices.filter(d => d.attributes.xpert).length > 0
|
|
55
|
-
}
|
|
28
|
+
for (const g of userData.groups) {
|
|
29
|
+
const devices = userData.devices.filter(d => d.groupId === g.id)
|
|
30
|
+
console.log(g.name + ' devices:' + devices.length)
|
|
31
|
+
if(devices.length > 0) {
|
|
32
|
+
const groupData = {
|
|
33
|
+
devices: [],
|
|
34
|
+
group: g,
|
|
35
|
+
xpert: devices.filter(d => d.attributes.xpert).length > 0
|
|
36
|
+
}
|
|
56
37
|
|
|
57
|
-
|
|
58
|
-
const routes = await traccar.getRoute(traccarInstance, from, to, devices)
|
|
38
|
+
const data = await getReportData(from, to, devices)
|
|
59
39
|
|
|
60
|
-
|
|
40
|
+
devices.sort((a, b) => (a.name > b.name) ? 1 : -1)
|
|
61
41
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
42
|
+
if (data.length > 0) {
|
|
43
|
+
groupData.devices = await processDevices(from, to, devices, userData.geofences, userData.drivers, data, roadSpeedLimits)
|
|
44
|
+
reportData.push(groupData)
|
|
45
|
+
}
|
|
65
46
|
}
|
|
66
47
|
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const groupIds = userData.groups.map(g => g.id)
|
|
70
|
-
const withoutGroupDevices = userData.devices.filter(d => !groupIds.includes(d.groupId))
|
|
71
48
|
|
|
72
|
-
|
|
73
|
-
|
|
49
|
+
const withoutGroupData = await createSpeedingReportByDevice(from, to, userData)
|
|
50
|
+
reportData.push(withoutGroupData)
|
|
51
|
+
} else {
|
|
52
|
+
const allData = await createSpeedingReportByDevice(from, to, userData, roadSpeedLimits)
|
|
53
|
+
reportData.push(allData)
|
|
54
|
+
}
|
|
74
55
|
|
|
75
56
|
return reportData
|
|
76
57
|
}
|
|
77
58
|
|
|
78
|
-
async function createSpeedingReportByDevice(from, to,
|
|
79
|
-
|
|
59
|
+
async function createSpeedingReportByDevice(from, to, userData, roadSpeedLimits) {
|
|
60
|
+
const groupIds = userData.groups.map(g => g.id)
|
|
61
|
+
const withoutGroupDevices = userData.byGroup ? userData.devices.filter(d => !groupIds.includes(d.groupId)) : userData.devices
|
|
80
62
|
|
|
81
|
-
|
|
82
|
-
const events = []
|
|
83
|
-
if(!userData.useVehicleSpeedLimit && userData.customSpeed){
|
|
84
|
-
events.push(...await getCustomSpeedLimitEvents(devices, routes))
|
|
85
|
-
} else {
|
|
86
|
-
events.push(...await traccar.getEvents(traccarInstance, from, to, devices, eventTypes))
|
|
87
|
-
}
|
|
63
|
+
withoutGroupDevices.sort((a, b) => (a.name > b.name) ? 1 : -1)
|
|
88
64
|
|
|
89
|
-
|
|
90
|
-
events.push(...await getHereEvents(devices, routes, userData.maxSpeedThreshold))
|
|
91
|
-
}
|
|
65
|
+
const data = await getReportData(from, to, withoutGroupDevices)
|
|
92
66
|
|
|
93
|
-
|
|
94
|
-
//empty report
|
|
95
|
-
return { devices: [] }
|
|
96
|
-
}
|
|
67
|
+
const allData = { devices: [] }
|
|
97
68
|
|
|
98
|
-
|
|
99
|
-
devices
|
|
100
|
-
xpert
|
|
69
|
+
if(data.length > 0 || roadSpeedLimits) {
|
|
70
|
+
allData.devices = await processDevices(from, to, withoutGroupDevices, userData.geofences, userData.drivers, data, roadSpeedLimits)
|
|
71
|
+
allData.xpert = withoutGroupDevices.filter(d => d && d.attributes && d.attributes.xpert).length > 0
|
|
101
72
|
}
|
|
73
|
+
|
|
74
|
+
return allData
|
|
102
75
|
}
|
|
103
76
|
|
|
104
|
-
async function createSpeedingReportByDriver(from, to) {
|
|
105
|
-
const
|
|
106
|
-
console.log(
|
|
77
|
+
async function createSpeedingReportByDriver(from, to, userData) {
|
|
78
|
+
const deviceIds = await drivers.devicesByDriver(traccarInstance, from, to, userData.drivers, userData.devices)
|
|
79
|
+
console.log(deviceIds.length)
|
|
107
80
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
81
|
+
let eventsData = []
|
|
82
|
+
if(deviceIds.length > 0) {
|
|
83
|
+
console.log('getReportData', deviceIds.length)
|
|
84
|
+
const devices = userData.devices.filter(d => deviceIds.includes(d.id))
|
|
85
|
+
eventsData = await getReportData(from, to, devices)
|
|
111
86
|
}
|
|
112
87
|
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
if(!userData.useVehicleSpeedLimit && userData.customSpeed){
|
|
116
|
-
events.push(...await getCustomSpeedLimitEvents(devices, routes))
|
|
117
|
-
} else {
|
|
118
|
-
events.push(...await traccar.getEvents(traccarInstance, from, to, devices, eventTypes))
|
|
88
|
+
const allData = {
|
|
89
|
+
drivers: []
|
|
119
90
|
}
|
|
120
91
|
|
|
121
|
-
|
|
122
|
-
events.push(...await getHereEvents(devices, routes, userData.maxSpeedThreshold))
|
|
123
|
-
}
|
|
92
|
+
console.log(eventsData.length)
|
|
124
93
|
|
|
125
|
-
|
|
126
|
-
//empty report
|
|
127
|
-
return { drivers: [] }
|
|
128
|
-
}
|
|
94
|
+
await getEventsPosition(from , to, userData.devices, userData.geofences, userData.drivers, eventsData)
|
|
129
95
|
|
|
130
|
-
|
|
96
|
+
allData.drivers = await processDrivers(from, to, userData.drivers, eventsData)
|
|
97
|
+
console.log(allData.drivers.length)
|
|
98
|
+
return allData
|
|
131
99
|
}
|
|
132
100
|
|
|
133
|
-
async function processDrivers(from, to,
|
|
101
|
+
async function processDrivers(from, to, drivers, data) {
|
|
102
|
+
console.log(data)
|
|
134
103
|
const driversResult = []
|
|
104
|
+
const alertsWithPosition = data.filter(a => a.position)
|
|
105
|
+
|
|
106
|
+
drivers.forEach(d => {
|
|
107
|
+
const alerts = alertsWithPosition.filter(e => e.position.attributes.driverUniqueId === d.uniqueId)
|
|
135
108
|
|
|
136
|
-
|
|
109
|
+
if (alerts.length > 0) {
|
|
137
110
|
|
|
138
|
-
userData.drivers.forEach(d => {
|
|
139
|
-
const driverEvents = events.filter(e => e.position && e.position.attributes.driverUniqueId === d.uniqueId)
|
|
140
|
-
if (driverEvents.length > 0) {
|
|
141
|
-
driverEvents.sort((a, b) => a.positionId - b.positionId)
|
|
142
111
|
driversResult.push({
|
|
143
112
|
driver: d,
|
|
144
113
|
from: from,
|
|
145
114
|
to: to,
|
|
146
|
-
alerts:
|
|
147
|
-
maxSpeed:
|
|
115
|
+
alerts: alerts,
|
|
116
|
+
maxSpeed: alerts.reduce((a, b) => {
|
|
148
117
|
return a > b.attributes.maxSpeed ? a : b.attributes.maxSpeed
|
|
149
118
|
}, 0),
|
|
150
119
|
})
|
|
@@ -154,20 +123,40 @@ async function processDrivers(from, to, events, routes) {
|
|
|
154
123
|
return driversResult
|
|
155
124
|
}
|
|
156
125
|
|
|
157
|
-
async function
|
|
126
|
+
async function getReportData(from, to, devices) {
|
|
127
|
+
const types = ['deviceOverspeed']
|
|
128
|
+
let data = []
|
|
129
|
+
const arrayOfArrays = automaticReports.sliceArray(devices)
|
|
130
|
+
for (const a of arrayOfArrays) {
|
|
131
|
+
try {
|
|
132
|
+
const devices = a.map(d => d.id)
|
|
133
|
+
console.log('reportsEventsGet', from, to, devices, null, types)
|
|
134
|
+
const response = await traccarInstance.reports.reportsEventsGet(from, to, devices, null, types)
|
|
135
|
+
data = data.concat(response.data)
|
|
136
|
+
} catch (e) {
|
|
137
|
+
console.error(e)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
console.log('Alerts:', data.length)
|
|
141
|
+
return data
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function processDevices(from, to, devices, geofences, drivers, data, roadSpeedLimits) {
|
|
158
145
|
const devicesResult = []
|
|
159
|
-
|
|
146
|
+
|
|
147
|
+
await getEventsPosition(from , to, devices, geofences, drivers, data, roadSpeedLimits)
|
|
160
148
|
|
|
161
149
|
for (const d of devices) {
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
150
|
+
const alerts = data.filter(t => t.deviceId === d.id)
|
|
151
|
+
|
|
152
|
+
if (alerts.length > 0) {
|
|
153
|
+
const alertsWithPosition = alerts.filter(a => a.position).sort((a,b) => a.positionId - b.positionId)
|
|
165
154
|
devicesResult.push({
|
|
166
155
|
device: d,
|
|
167
156
|
from: from,
|
|
168
157
|
to: to,
|
|
169
|
-
alerts:
|
|
170
|
-
maxSpeed:
|
|
158
|
+
alerts: alertsWithPosition,
|
|
159
|
+
maxSpeed: alertsWithPosition.reduce((a, b) => {
|
|
171
160
|
return a > (b && b.attributes && b.attributes.maxSpeed) ? a : (b && b.attributes && b.attributes.maxSpeed)
|
|
172
161
|
}, 0),
|
|
173
162
|
})
|
|
@@ -177,136 +166,93 @@ async function processDevices(from, to, devices, events, routes) {
|
|
|
177
166
|
return devicesResult
|
|
178
167
|
}
|
|
179
168
|
|
|
180
|
-
async function
|
|
169
|
+
async function getEventsPosition(from, to, devices, geofences, drivers, data, roadSpeedLimits){
|
|
181
170
|
for (const d of devices) {
|
|
182
|
-
let deviceEvents = events.filter(e => e.deviceId === d.id && e.positionId)
|
|
183
|
-
if (deviceEvents.length > 0) {
|
|
184
|
-
deviceEvents.sort((a,b) => a.positionId-b.positionId )
|
|
185
|
-
const positions = routes.filter(p => p.deviceId === d.id)
|
|
186
171
|
|
|
187
|
-
|
|
172
|
+
let alerts = data.filter(t => t.deviceId === d.id)
|
|
173
|
+
|
|
174
|
+
if (alerts.length > 0 || roadSpeedLimits) {
|
|
175
|
+
const response = await traccarInstance.reports.reportsRouteGet(from, to, [d.id])
|
|
176
|
+
const positions = response.data
|
|
177
|
+
|
|
178
|
+
if (roadSpeedLimits && positions.length) {
|
|
179
|
+
try {
|
|
180
|
+
await new Promise(res => setTimeout(res, 1000))
|
|
181
|
+
const results = await here.routeMatch(positions)
|
|
182
|
+
const hereAlerts = results.map(r => {
|
|
183
|
+
const position = positions.find(p => new Date(p.fixTime).getTime() === r.timestamp)
|
|
184
|
+
return {
|
|
185
|
+
...r,
|
|
186
|
+
roadSpeedLimit: r.speedLimit,
|
|
187
|
+
deviceId: d.id,
|
|
188
|
+
position,
|
|
189
|
+
positionId: position && position.id,
|
|
190
|
+
attributes: {speedLimit: r.speedLimit, speed: r.currentSpeedKmh / 1.85200}
|
|
191
|
+
}
|
|
192
|
+
})
|
|
193
|
+
console.log('hereAlerts', hereAlerts)
|
|
194
|
+
const reduced = hereAlerts.reduce((acc, cur, idx, src) => {
|
|
195
|
+
if (idx === 1) {
|
|
196
|
+
return [cur]
|
|
197
|
+
}
|
|
198
|
+
if (cur.timestamp - src[idx - 1].timestamp > 300000 || cur.roadSpeedLimit !== src[idx - 1].roadSpeedLimit) {
|
|
199
|
+
return acc.concat(cur)
|
|
200
|
+
}
|
|
201
|
+
return acc
|
|
202
|
+
})
|
|
203
|
+
data.push(...reduced)
|
|
204
|
+
alerts = data.filter(t => t.deviceId === d.id)
|
|
205
|
+
} catch (e) {
|
|
206
|
+
console.error(e)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
for (const a of alerts) {
|
|
188
211
|
let pIndex = positions.findIndex(p => p.id === a.positionId)
|
|
189
212
|
if (pIndex > 0) {
|
|
213
|
+
a.position = positions[pIndex]
|
|
190
214
|
let geofence = null
|
|
215
|
+
|
|
191
216
|
if (a.geofenceId) {
|
|
192
|
-
geofence =
|
|
217
|
+
geofence = geofences.find(g => g.id === a.geofenceId)
|
|
193
218
|
if (geofence) {
|
|
194
219
|
a.geofenceName = geofence.name + ' (' + Math.round(a.attributes.speedLimit * 1.85200) + ' Km/h)'
|
|
195
220
|
}
|
|
196
221
|
}
|
|
197
222
|
|
|
198
|
-
a.position
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if(position.speed > maxSpeed && !eventIsActive){
|
|
218
|
-
const event = {
|
|
219
|
-
positionId: position && position.id,
|
|
220
|
-
deviceId: d.id,
|
|
221
|
-
attributes: {
|
|
222
|
-
speedLimit: maxSpeed,
|
|
223
|
-
speed: position.speed
|
|
223
|
+
let endEventPosition = a.position
|
|
224
|
+
let maxSpeed = a.position.speed
|
|
225
|
+
let dist = 0
|
|
226
|
+
while (pIndex + 1 < positions.length) {
|
|
227
|
+
pIndex++
|
|
228
|
+
|
|
229
|
+
dist += distance(point([endEventPosition.longitude, endEventPosition.latitude]),
|
|
230
|
+
point([positions[pIndex].longitude, positions[pIndex].latitude]))
|
|
231
|
+
endEventPosition = positions[pIndex]
|
|
232
|
+
if (endEventPosition.speed <= a.attributes.speedLimit || (geofence && isOutsideGeofence(geofence, endEventPosition))) {
|
|
233
|
+
a.eventTime = new Date(endEventPosition.fixTime) - new Date(a.position.fixTime)
|
|
234
|
+
a.attributes.maxSpeed = maxSpeed
|
|
235
|
+
a.distance = dist
|
|
236
|
+
break
|
|
237
|
+
} else {
|
|
238
|
+
if (maxSpeed < endEventPosition.speed) {
|
|
239
|
+
maxSpeed = endEventPosition.speed
|
|
240
|
+
}
|
|
241
|
+
}
|
|
224
242
|
}
|
|
225
|
-
}
|
|
226
|
-
events.push(event)
|
|
227
|
-
eventIsActive = true
|
|
228
|
-
} else if (position.speed <= maxSpeed) {
|
|
229
|
-
eventIsActive = false
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
243
|
|
|
234
|
-
|
|
235
|
-
|
|
244
|
+
if (a.position.attributes.driverUniqueId) {
|
|
245
|
+
const driver = drivers.find(d => d.uniqueId === a.position.attributes.driverUniqueId)
|
|
246
|
+
a.driver = driver && driver.name
|
|
247
|
+
}
|
|
236
248
|
|
|
237
|
-
|
|
238
|
-
console.log('here speed limit events')
|
|
239
|
-
const events = []
|
|
240
|
-
let i,j, temporary, chunk = 1;
|
|
241
|
-
for (i = 0,j = devices.length; i < j; i += chunk) {
|
|
242
|
-
temporary = devices.slice(i, i + chunk);
|
|
243
|
-
await Promise.all(temporary.map(d =>
|
|
244
|
-
here.routeMatch(routes.filter(p => p.deviceId === d.id)).then(r => d.results = r)
|
|
245
|
-
))
|
|
246
|
-
}
|
|
249
|
+
a.deviceName = d.name
|
|
247
250
|
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
const results = d.results
|
|
251
|
-
const hereAlerts = results.filter(r => r.currentSpeedKmh > (parseInt(r.speedLimit) + threshold)).map(r => {
|
|
252
|
-
const position = positions.find(p => new Date(p.fixTime).getTime() === r.timestamp)
|
|
253
|
-
return {
|
|
254
|
-
...r,
|
|
255
|
-
roadSpeedLimit: r.speedLimit,
|
|
256
|
-
deviceId: d.id,
|
|
257
|
-
position,
|
|
258
|
-
positionId: position && position.id,
|
|
259
|
-
attributes: {speedLimit: r.speedLimit, speed: r.currentSpeedKmh / 1.85200}
|
|
260
|
-
}
|
|
261
|
-
})
|
|
262
|
-
const reduced = hereAlerts.reduce((acc, cur, idx, src) => {
|
|
263
|
-
if (idx === 1) {
|
|
264
|
-
return [cur]
|
|
265
|
-
}
|
|
266
|
-
if (cur.timestamp - src[idx - 1].timestamp > 300000 || cur.roadSpeedLimit !== src[idx - 1].roadSpeedLimit) {
|
|
267
|
-
return acc.concat(cur)
|
|
251
|
+
positions.slice(pIndex)
|
|
268
252
|
}
|
|
269
|
-
return acc
|
|
270
|
-
})
|
|
271
|
-
events.push(...reduced)
|
|
272
|
-
} catch (e) {
|
|
273
|
-
console.error(e)
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
return events
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
function calculateEventData(positions, pIndex, alert, device, geofence){
|
|
280
|
-
let endEventPosition = alert.position
|
|
281
|
-
let maxSpeed = alert.position.speed
|
|
282
|
-
let dist = 0
|
|
283
|
-
while (pIndex + 1 < positions.length) {
|
|
284
|
-
pIndex++
|
|
285
|
-
|
|
286
|
-
dist += distance(point([endEventPosition.longitude, endEventPosition.latitude]),
|
|
287
|
-
point([positions[pIndex].longitude, positions[pIndex].latitude]))
|
|
288
|
-
endEventPosition = positions[pIndex]
|
|
289
|
-
if (endEventPosition.speed <= alert.attributes.speedLimit || (geofence && isOutsideGeofence(geofence, endEventPosition))) {
|
|
290
|
-
alert.eventTime = new Date(endEventPosition.fixTime) - new Date(alert.position.fixTime)
|
|
291
|
-
alert.attributes.maxSpeed = maxSpeed
|
|
292
|
-
alert.distance = dist
|
|
293
|
-
break
|
|
294
|
-
} else {
|
|
295
|
-
if (maxSpeed < endEventPosition.speed) {
|
|
296
|
-
maxSpeed = endEventPosition.speed
|
|
297
253
|
}
|
|
298
254
|
}
|
|
299
255
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if (alert.position.attributes.driverUniqueId) {
|
|
303
|
-
const driver = userData.drivers.find(d => d.uniqueId === alert.position.attributes.driverUniqueId)
|
|
304
|
-
alert.driver = driver && driver.name
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
alert.deviceName = device.name
|
|
308
|
-
|
|
309
|
-
return pIndex
|
|
310
256
|
}
|
|
311
257
|
|
|
312
258
|
function isOutsideGeofence(geofence, endEventPosition) {
|
|
@@ -315,11 +261,10 @@ function isOutsideGeofence(geofence, endEventPosition) {
|
|
|
315
261
|
return turf.inside(point, v)
|
|
316
262
|
}
|
|
317
263
|
|
|
318
|
-
|
|
264
|
+
function exportSpeedingReportToPDF(userData, reportData) {
|
|
319
265
|
console.log('Export to PDF')
|
|
320
266
|
|
|
321
267
|
const lang = userData.user.attributes.lang
|
|
322
|
-
const timezone = userData.user.attributes.timezone
|
|
323
268
|
const translations = messages[lang] ? messages[lang] : messages['en-GB']
|
|
324
269
|
|
|
325
270
|
const overspeedData = userData.byDriver ? reportData.drivers : reportData.devices
|
|
@@ -333,7 +278,7 @@ async function exportSpeedingReportToPDF(userData, reportData) {
|
|
|
333
278
|
translations.report.duration,
|
|
334
279
|
]
|
|
335
280
|
|
|
336
|
-
if(userData.
|
|
281
|
+
if(userData.useRoadSpeedLimits) {
|
|
337
282
|
headers.splice(2, 0, translations.report.roadSpeedLimit)
|
|
338
283
|
}
|
|
339
284
|
|
|
@@ -346,7 +291,8 @@ async function exportSpeedingReportToPDF(userData, reportData) {
|
|
|
346
291
|
if (overspeedData) {
|
|
347
292
|
let first = true
|
|
348
293
|
const doc = new jsPDF.jsPDF('l');
|
|
349
|
-
|
|
294
|
+
doc.setFontSize(14)
|
|
295
|
+
doc.text(translations.report.titleSpeedingReport, 15, 15 )
|
|
350
296
|
|
|
351
297
|
overspeedData.forEach(d => {
|
|
352
298
|
try {
|
|
@@ -362,13 +308,13 @@ async function exportSpeedingReportToPDF(userData, reportData) {
|
|
|
362
308
|
first = false
|
|
363
309
|
space = 10
|
|
364
310
|
}
|
|
365
|
-
doc.setFontSize(
|
|
311
|
+
doc.setFontSize(12)
|
|
366
312
|
doc.text(name, 20, space+20 )
|
|
367
|
-
doc.setFontSize(
|
|
313
|
+
doc.setFontSize(10)
|
|
368
314
|
doc.text(group ? translations.report.group + ': ' + group.name : '', 150, space+20 )
|
|
369
|
-
doc.text(
|
|
315
|
+
doc.text(new Date(d.from).toLocaleString() + ' - ' + new Date(d.to).toLocaleString(), 20, space+25 )
|
|
370
316
|
if (d.alerts[0] && !userData.byDriver) {
|
|
371
|
-
doc.text(translations.report.speedLimit + ": " +
|
|
317
|
+
doc.text(translations.report.speedLimit + ": " + Math.round(d.alerts[0].attributes.speedLimit * 1.85200) + ' Km/h', 20, space + 30)
|
|
372
318
|
}
|
|
373
319
|
d.alerts.map(a => {
|
|
374
320
|
const temp = [
|
|
@@ -381,7 +327,7 @@ async function exportSpeedingReportToPDF(userData, reportData) {
|
|
|
381
327
|
userData.byDriver ? a.deviceName : a.driver
|
|
382
328
|
]
|
|
383
329
|
|
|
384
|
-
if(userData.
|
|
330
|
+
if(userData.useRoadSpeedLimits){
|
|
385
331
|
temp.splice(2, 0, a.roadSpeedLimit)
|
|
386
332
|
}
|
|
387
333
|
|
|
@@ -397,34 +343,26 @@ async function exportSpeedingReportToPDF(userData, reportData) {
|
|
|
397
343
|
convertMS(d.alerts.reduce((a, b) => a + b.eventTime, 0), true)
|
|
398
344
|
]
|
|
399
345
|
|
|
400
|
-
if(userData.
|
|
346
|
+
if(userData.useRoadSpeedLimits){
|
|
401
347
|
footValues.splice(2, 0, '')
|
|
402
348
|
}
|
|
403
349
|
|
|
404
|
-
doc.addFileToVFS("Amiri-Regular.ttf", AmiriRegular());
|
|
405
|
-
doc.addFont("Amiri-Regular.ttf", "Amiri", "normal");
|
|
406
|
-
|
|
407
|
-
const style = getStyle(getUserPartner(userData.user))
|
|
408
350
|
doc.autoTable({
|
|
409
351
|
head: [headers],
|
|
410
352
|
body: data,
|
|
411
353
|
foot: [footValues],
|
|
412
354
|
showFoot: 'lastPage',
|
|
413
355
|
headStyles: {
|
|
414
|
-
fillColor:
|
|
415
|
-
textColor:
|
|
416
|
-
fontSize: 10
|
|
356
|
+
fillColor: reportStyle.pdfHeaderColor,
|
|
357
|
+
textColor: reportStyle.pdfHeaderTextColor
|
|
417
358
|
},
|
|
418
359
|
bodyStyles: {
|
|
419
|
-
fillColor:
|
|
420
|
-
textColor:
|
|
421
|
-
fontSize: 8,
|
|
422
|
-
font: timezone === 'Asia/Qatar' ? "Amiri" : ''
|
|
360
|
+
fillColor: reportStyle.pdfBodyColor,
|
|
361
|
+
textColor: reportStyle.pdfBodyTextColor
|
|
423
362
|
},
|
|
424
363
|
footStyles: {
|
|
425
|
-
fillColor:
|
|
426
|
-
textColor:
|
|
427
|
-
fontSize: 9
|
|
364
|
+
fillColor: reportStyle.pdfFooterColor,
|
|
365
|
+
textColor: reportStyle.pdfFooterTextColor
|
|
428
366
|
},
|
|
429
367
|
startY: space+35 });
|
|
430
368
|
} catch (e) {
|
|
@@ -460,7 +398,7 @@ function exportSpeedingReportToExcel(userData, reportData) {
|
|
|
460
398
|
userData.byDriver ? {label: translations.report.vehicle, value:'name'} : {label: translations.report.driver, value:'driver'}
|
|
461
399
|
]
|
|
462
400
|
|
|
463
|
-
if (userData.
|
|
401
|
+
if (userData.useRoadSpeedLimits){
|
|
464
402
|
headers.splice(3, 0, {label: translations.report.roadSpeedLimit, value:'roadSpeedLimit'})
|
|
465
403
|
}
|
|
466
404
|
|
|
@@ -496,7 +434,10 @@ function deviceName(device){
|
|
|
496
434
|
}
|
|
497
435
|
|
|
498
436
|
function getAlertDate(row, user) {
|
|
499
|
-
return
|
|
437
|
+
return new Date(row.position.fixTime).toLocaleString(user.attributes.lang, {
|
|
438
|
+
timeZone: user.attributes.timezone,
|
|
439
|
+
hour12: false
|
|
440
|
+
})
|
|
500
441
|
}
|
|
501
442
|
|
|
502
443
|
function getMaxSpeed(data) {
|