fleetmap-reports 1.0.287 → 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/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/jsLibraryMappings.xml +6 -0
- 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 +2 -12
- 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 +27 -60
- 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 -232
- 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/runConfigurations.xml +0 -10
- package/.idea/shelf/Uncommitted_changes_before_Update_at_13_01_2022,_12_06_[Changes]/shelved.patch +0 -111
- package/.idea/shelf/Uncommitted_changes_before_Update_at_13_01_2022__12_06__Changes_.xml +0 -4
- package/.idea/workspace.xml +0 -515
- 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
48
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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)
|
|
135
105
|
|
|
136
|
-
|
|
106
|
+
drivers.forEach(d => {
|
|
107
|
+
const alerts = alertsWithPosition.filter(e => e.position.attributes.driverUniqueId === d.uniqueId)
|
|
108
|
+
|
|
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,129 +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
|
-
|
|
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
|
+
}
|
|
242
|
+
}
|
|
211
243
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
for (const position of positions) {
|
|
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
|
|
244
|
+
if (a.position.attributes.driverUniqueId) {
|
|
245
|
+
const driver = drivers.find(d => d.uniqueId === a.position.attributes.driverUniqueId)
|
|
246
|
+
a.driver = driver && driver.name
|
|
224
247
|
}
|
|
225
|
-
}
|
|
226
|
-
events.push(event)
|
|
227
|
-
eventIsActive = true
|
|
228
|
-
} else if (position.speed <= maxSpeed) {
|
|
229
|
-
eventIsActive = false
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
248
|
|
|
234
|
-
|
|
235
|
-
}
|
|
249
|
+
a.deviceName = d.name
|
|
236
250
|
|
|
237
|
-
|
|
238
|
-
console.log('here speed limit events')
|
|
239
|
-
const events = []
|
|
240
|
-
for (const d of devices) {
|
|
241
|
-
const positions = routes.filter(p => p.deviceId === d.id)
|
|
242
|
-
try {
|
|
243
|
-
const results = await here.routeMatch(positions)
|
|
244
|
-
const hereAlerts = results.filter(r => r.currentSpeedKmh > (parseInt(r.speedLimit) + threshold)).map(r => {
|
|
245
|
-
const position = positions.find(p => new Date(p.fixTime).getTime() === r.timestamp)
|
|
246
|
-
return {
|
|
247
|
-
...r,
|
|
248
|
-
roadSpeedLimit: r.speedLimit,
|
|
249
|
-
deviceId: d.id,
|
|
250
|
-
position,
|
|
251
|
-
positionId: position && position.id,
|
|
252
|
-
attributes: {speedLimit: r.speedLimit, speed: r.currentSpeedKmh / 1.85200}
|
|
253
|
-
}
|
|
254
|
-
})
|
|
255
|
-
const reduced = hereAlerts.reduce((acc, cur, idx, src) => {
|
|
256
|
-
if (idx === 1) {
|
|
257
|
-
return [cur]
|
|
258
|
-
}
|
|
259
|
-
if (cur.timestamp - src[idx - 1].timestamp > 300000 || cur.roadSpeedLimit !== src[idx - 1].roadSpeedLimit) {
|
|
260
|
-
return acc.concat(cur)
|
|
251
|
+
positions.slice(pIndex)
|
|
261
252
|
}
|
|
262
|
-
return acc
|
|
263
|
-
})
|
|
264
|
-
events.push(...reduced)
|
|
265
|
-
} catch (e) {
|
|
266
|
-
console.error(e)
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
return events
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function calculateEventData(positions, pIndex, alert, device, geofence){
|
|
273
|
-
let endEventPosition = alert.position
|
|
274
|
-
let maxSpeed = alert.position.speed
|
|
275
|
-
let dist = 0
|
|
276
|
-
while (pIndex + 1 < positions.length) {
|
|
277
|
-
pIndex++
|
|
278
|
-
|
|
279
|
-
dist += distance(point([endEventPosition.longitude, endEventPosition.latitude]),
|
|
280
|
-
point([positions[pIndex].longitude, positions[pIndex].latitude]))
|
|
281
|
-
endEventPosition = positions[pIndex]
|
|
282
|
-
if (endEventPosition.speed <= alert.attributes.speedLimit || (geofence && isOutsideGeofence(geofence, endEventPosition))) {
|
|
283
|
-
alert.eventTime = new Date(endEventPosition.fixTime) - new Date(alert.position.fixTime)
|
|
284
|
-
alert.attributes.maxSpeed = maxSpeed
|
|
285
|
-
alert.distance = dist
|
|
286
|
-
break
|
|
287
|
-
} else {
|
|
288
|
-
if (maxSpeed < endEventPosition.speed) {
|
|
289
|
-
maxSpeed = endEventPosition.speed
|
|
290
253
|
}
|
|
291
254
|
}
|
|
292
255
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
if (alert.position.attributes.driverUniqueId) {
|
|
296
|
-
const driver = userData.drivers.find(d => d.uniqueId === alert.position.attributes.driverUniqueId)
|
|
297
|
-
alert.driver = driver && driver.name
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
alert.deviceName = device.name
|
|
301
|
-
|
|
302
|
-
return pIndex
|
|
303
256
|
}
|
|
304
257
|
|
|
305
258
|
function isOutsideGeofence(geofence, endEventPosition) {
|
|
@@ -308,11 +261,10 @@ function isOutsideGeofence(geofence, endEventPosition) {
|
|
|
308
261
|
return turf.inside(point, v)
|
|
309
262
|
}
|
|
310
263
|
|
|
311
|
-
|
|
264
|
+
function exportSpeedingReportToPDF(userData, reportData) {
|
|
312
265
|
console.log('Export to PDF')
|
|
313
266
|
|
|
314
267
|
const lang = userData.user.attributes.lang
|
|
315
|
-
const timezone = userData.user.attributes.timezone
|
|
316
268
|
const translations = messages[lang] ? messages[lang] : messages['en-GB']
|
|
317
269
|
|
|
318
270
|
const overspeedData = userData.byDriver ? reportData.drivers : reportData.devices
|
|
@@ -326,7 +278,7 @@ async function exportSpeedingReportToPDF(userData, reportData) {
|
|
|
326
278
|
translations.report.duration,
|
|
327
279
|
]
|
|
328
280
|
|
|
329
|
-
if(userData.
|
|
281
|
+
if(userData.useRoadSpeedLimits) {
|
|
330
282
|
headers.splice(2, 0, translations.report.roadSpeedLimit)
|
|
331
283
|
}
|
|
332
284
|
|
|
@@ -339,7 +291,8 @@ async function exportSpeedingReportToPDF(userData, reportData) {
|
|
|
339
291
|
if (overspeedData) {
|
|
340
292
|
let first = true
|
|
341
293
|
const doc = new jsPDF.jsPDF('l');
|
|
342
|
-
|
|
294
|
+
doc.setFontSize(14)
|
|
295
|
+
doc.text(translations.report.titleSpeedingReport, 15, 15 )
|
|
343
296
|
|
|
344
297
|
overspeedData.forEach(d => {
|
|
345
298
|
try {
|
|
@@ -355,13 +308,13 @@ async function exportSpeedingReportToPDF(userData, reportData) {
|
|
|
355
308
|
first = false
|
|
356
309
|
space = 10
|
|
357
310
|
}
|
|
358
|
-
doc.setFontSize(
|
|
311
|
+
doc.setFontSize(12)
|
|
359
312
|
doc.text(name, 20, space+20 )
|
|
360
|
-
doc.setFontSize(
|
|
313
|
+
doc.setFontSize(10)
|
|
361
314
|
doc.text(group ? translations.report.group + ': ' + group.name : '', 150, space+20 )
|
|
362
|
-
doc.text(
|
|
315
|
+
doc.text(new Date(d.from).toLocaleString() + ' - ' + new Date(d.to).toLocaleString(), 20, space+25 )
|
|
363
316
|
if (d.alerts[0] && !userData.byDriver) {
|
|
364
|
-
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)
|
|
365
318
|
}
|
|
366
319
|
d.alerts.map(a => {
|
|
367
320
|
const temp = [
|
|
@@ -374,7 +327,7 @@ async function exportSpeedingReportToPDF(userData, reportData) {
|
|
|
374
327
|
userData.byDriver ? a.deviceName : a.driver
|
|
375
328
|
]
|
|
376
329
|
|
|
377
|
-
if(userData.
|
|
330
|
+
if(userData.useRoadSpeedLimits){
|
|
378
331
|
temp.splice(2, 0, a.roadSpeedLimit)
|
|
379
332
|
}
|
|
380
333
|
|
|
@@ -390,34 +343,26 @@ async function exportSpeedingReportToPDF(userData, reportData) {
|
|
|
390
343
|
convertMS(d.alerts.reduce((a, b) => a + b.eventTime, 0), true)
|
|
391
344
|
]
|
|
392
345
|
|
|
393
|
-
if(userData.
|
|
346
|
+
if(userData.useRoadSpeedLimits){
|
|
394
347
|
footValues.splice(2, 0, '')
|
|
395
348
|
}
|
|
396
349
|
|
|
397
|
-
doc.addFileToVFS("Amiri-Regular.ttf", AmiriRegular());
|
|
398
|
-
doc.addFont("Amiri-Regular.ttf", "Amiri", "normal");
|
|
399
|
-
|
|
400
|
-
const style = getStyle(getUserPartner(userData.user))
|
|
401
350
|
doc.autoTable({
|
|
402
351
|
head: [headers],
|
|
403
352
|
body: data,
|
|
404
353
|
foot: [footValues],
|
|
405
354
|
showFoot: 'lastPage',
|
|
406
355
|
headStyles: {
|
|
407
|
-
fillColor:
|
|
408
|
-
textColor:
|
|
409
|
-
fontSize: 10
|
|
356
|
+
fillColor: reportStyle.pdfHeaderColor,
|
|
357
|
+
textColor: reportStyle.pdfHeaderTextColor
|
|
410
358
|
},
|
|
411
359
|
bodyStyles: {
|
|
412
|
-
fillColor:
|
|
413
|
-
textColor:
|
|
414
|
-
fontSize: 8,
|
|
415
|
-
font: timezone === 'Asia/Qatar' ? "Amiri" : ''
|
|
360
|
+
fillColor: reportStyle.pdfBodyColor,
|
|
361
|
+
textColor: reportStyle.pdfBodyTextColor
|
|
416
362
|
},
|
|
417
363
|
footStyles: {
|
|
418
|
-
fillColor:
|
|
419
|
-
textColor:
|
|
420
|
-
fontSize: 9
|
|
364
|
+
fillColor: reportStyle.pdfFooterColor,
|
|
365
|
+
textColor: reportStyle.pdfFooterTextColor
|
|
421
366
|
},
|
|
422
367
|
startY: space+35 });
|
|
423
368
|
} catch (e) {
|
|
@@ -453,7 +398,7 @@ function exportSpeedingReportToExcel(userData, reportData) {
|
|
|
453
398
|
userData.byDriver ? {label: translations.report.vehicle, value:'name'} : {label: translations.report.driver, value:'driver'}
|
|
454
399
|
]
|
|
455
400
|
|
|
456
|
-
if (userData.
|
|
401
|
+
if (userData.useRoadSpeedLimits){
|
|
457
402
|
headers.splice(3, 0, {label: translations.report.roadSpeedLimit, value:'roadSpeedLimit'})
|
|
458
403
|
}
|
|
459
404
|
|
|
@@ -489,7 +434,10 @@ function deviceName(device){
|
|
|
489
434
|
}
|
|
490
435
|
|
|
491
436
|
function getAlertDate(row, user) {
|
|
492
|
-
return
|
|
437
|
+
return new Date(row.position.fixTime).toLocaleString(user.attributes.lang, {
|
|
438
|
+
timeZone: user.attributes.timezone,
|
|
439
|
+
hour12: false
|
|
440
|
+
})
|
|
493
441
|
}
|
|
494
442
|
|
|
495
443
|
function getMaxSpeed(data) {
|