aboutsummaryrefslogtreecommitdiff
path: root/web/app
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2016-08-10 14:06:39 +0300
committerGitHub <noreply@github.com>2016-08-10 14:06:39 +0300
commit40e26cbf38a236f3c92e50dff619b1a29bd413de (patch)
tree450026b9cda50c8cafdf3a15ce07ed3bbccfbc3c /web/app
parent78f8d278276f0826eb302a08213609b083570760 (diff)
parentee5af32f8a9bc1edd7af02dfe3f243ebfdfb8641 (diff)
downloadtraccar-server-40e26cbf38a236f3c92e50dff619b1a29bd413de.tar.gz
traccar-server-40e26cbf38a236f3c92e50dff619b1a29bd413de.tar.bz2
traccar-server-40e26cbf38a236f3c92e50dff619b1a29bd413de.zip
Merge pull request #2197 from Abyss777/reports_web
Initial implementation Report API for web
Diffstat (limited to 'web/app')
-rw-r--r--web/app/Application.js9
-rw-r--r--web/app/controller/Root.js3
-rw-r--r--web/app/model/ReportSummary.js37
-rw-r--r--web/app/store/ReportEvents.js28
-rw-r--r--web/app/store/ReportRoute.js28
-rw-r--r--web/app/store/ReportSummary.js28
-rw-r--r--web/app/store/ReportTypes.js31
-rw-r--r--web/app/view/CommandDialog.js2
-rw-r--r--web/app/view/MapController.js2
-rw-r--r--web/app/view/Report.js63
-rw-r--r--web/app/view/ReportController.js181
-rw-r--r--web/app/view/ServerDialog.js2
-rw-r--r--web/app/view/UserDialog.js2
13 files changed, 356 insertions, 60 deletions
diff --git a/web/app/Application.js b/web/app/Application.js
index ec942d21e..22102f74b 100644
--- a/web/app/Application.js
+++ b/web/app/Application.js
@@ -33,7 +33,8 @@ Ext.define('Traccar.Application', {
'Command',
'Event',
'Geofence',
- 'Notification'
+ 'Notification',
+ 'ReportSummary'
],
stores: [
@@ -56,7 +57,11 @@ Ext.define('Traccar.Application', {
'AllGeofences',
'Notifications',
'AllNotifications',
- 'GeofenceTypes'
+ 'GeofenceTypes',
+ 'ReportRoute',
+ 'ReportEvents',
+ 'ReportSummary',
+ 'ReportTypes'
],
controllers: [
diff --git a/web/app/controller/Root.js b/web/app/controller/Root.js
index 2c565747b..6d18f4073 100644
--- a/web/app/controller/Root.js
+++ b/web/app/controller/Root.js
@@ -73,6 +73,7 @@ Ext.define('Traccar.controller.Root', {
},
loadApp: function () {
+ var attribution;
Ext.getStore('Groups').load();
Ext.getStore('Geofences').load();
Ext.getStore('Devices').load({
@@ -81,7 +82,7 @@ Ext.define('Traccar.controller.Root', {
this.asyncUpdate(true);
}
});
- var attribution = Ext.get('attribution');
+ attribution = Ext.get('attribution');
if (attribution) {
attribution.remove();
}
diff --git a/web/app/model/ReportSummary.js b/web/app/model/ReportSummary.js
new file mode 100644
index 000000000..7821e1c00
--- /dev/null
+++ b/web/app/model/ReportSummary.js
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.model.ReportSummary', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'deviceId',
+ type: 'int'
+ }, {
+ name: 'deviceName',
+ type: 'string'
+ }, {
+ name: 'maxSpeed',
+ type: 'float'
+ }, {
+ name: 'averageSpeed',
+ type: 'float'
+ }, {
+ name: 'distance',
+ type: 'float'
+ }]
+});
diff --git a/web/app/store/ReportEvents.js b/web/app/store/ReportEvents.js
new file mode 100644
index 000000000..bdef7a170
--- /dev/null
+++ b/web/app/store/ReportEvents.js
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.store.ReportEvents', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Event',
+
+ proxy: {
+ type: 'rest',
+ url: '/api/reports/events',
+ headers: {
+ 'Accept': 'application/json'
+ }
+ }
+});
diff --git a/web/app/store/ReportRoute.js b/web/app/store/ReportRoute.js
new file mode 100644
index 000000000..fc96fc022
--- /dev/null
+++ b/web/app/store/ReportRoute.js
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.store.ReportRoute', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Position',
+
+ proxy: {
+ type: 'rest',
+ url: '/api/reports/route',
+ headers: {
+ 'Accept': 'application/json'
+ }
+ }
+});
diff --git a/web/app/store/ReportSummary.js b/web/app/store/ReportSummary.js
new file mode 100644
index 000000000..2e4a8750d
--- /dev/null
+++ b/web/app/store/ReportSummary.js
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.store.ReportSummary', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.ReportSummary',
+
+ proxy: {
+ type: 'rest',
+ url: '/api/reports/summary',
+ headers: {
+ 'Accept': 'application/json'
+ }
+ }
+});
diff --git a/web/app/store/ReportTypes.js b/web/app/store/ReportTypes.js
new file mode 100644
index 000000000..d544a2fda
--- /dev/null
+++ b/web/app/store/ReportTypes.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.store.ReportTypes', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name'],
+
+ data: [{
+ key: 'route',
+ name: Strings.reportRoute
+ }, {
+ key: 'events',
+ name: Strings.reportEvents
+ }, {
+ key: 'summary',
+ name: Strings.reportSummary
+ }]
+});
diff --git a/web/app/view/CommandDialog.js b/web/app/view/CommandDialog.js
index 031815273..8e9a80dbf 100644
--- a/web/app/view/CommandDialog.js
+++ b/web/app/view/CommandDialog.js
@@ -29,7 +29,7 @@ Ext.define('Traccar.view.CommandDialog', {
items: [{
xtype: 'combobox',
name: 'type',
- fieldLabel: Strings.commandType,
+ fieldLabel: Strings.sharedType,
store: 'CommandTypes',
displayField: 'name',
valueField: 'type',
diff --git a/web/app/view/MapController.js b/web/app/view/MapController.js
index 6ef9f91e6..ab7461cf0 100644
--- a/web/app/view/MapController.js
+++ b/web/app/view/MapController.js
@@ -35,7 +35,7 @@ Ext.define('Traccar.view.MapController', {
add: 'updateLatest',
update: 'updateLatest'
},
- '#Positions': {
+ '#ReportRoute': {
load: 'loadReport',
clear: 'clearReport'
}
diff --git a/web/app/view/Report.js b/web/app/view/Report.js
index 4261b9040..7bcfdcb52 100644
--- a/web/app/view/Report.js
+++ b/web/app/view/Report.js
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,12 +24,24 @@ Ext.define('Traccar.view.Report', {
],
controller: 'report',
- store: 'Positions',
title: Strings.reportTitle,
tbar: [{
xtype: 'tbtext',
+ html: Strings.sharedType
+ }, {
+ xtype: 'combobox',
+ reference: 'reportTypeField',
+ store: 'ReportTypes',
+ displayField: 'name',
+ valueField: 'key',
+ typeAhead: true,
+ listeners: {
+ change: 'onTypeChange'
+ }
+ }, '-', {
+ xtype: 'tbtext',
html: Strings.reportDevice
}, {
xtype: 'combobox',
@@ -69,7 +81,12 @@ Ext.define('Traccar.view.Report', {
value: new Date()
}, '-', {
text: Strings.reportShow,
- handler: 'onShowClick'
+ reference: 'showButton',
+ handler: 'onReportClick'
+ }, {
+ text: Strings.reportCsv,
+ reference: 'csvButton',
+ handler: 'onReportClick'
}, {
text: Strings.reportClear,
handler: 'onClearClick'
@@ -77,43 +94,5 @@ Ext.define('Traccar.view.Report', {
listeners: {
selectionchange: 'onSelectionChange'
- },
-
- columns: [{
- text: Strings.positionValid,
- dataIndex: 'valid',
- flex: 1,
- renderer: Traccar.AttributeFormatter.getFormatter('valid')
- }, {
- text: Strings.positionFixTime,
- dataIndex: 'fixTime',
- flex: 1,
- xtype: 'datecolumn',
- renderer: Traccar.AttributeFormatter.getFormatter('fixTime')
- }, {
- text: Strings.positionLatitude,
- dataIndex: 'latitude',
- flex: 1,
- renderer: Traccar.AttributeFormatter.getFormatter('latitude')
- }, {
- text: Strings.positionLongitude,
- dataIndex: 'longitude',
- flex: 1,
- renderer: Traccar.AttributeFormatter.getFormatter('latitude')
- }, {
- text: Strings.positionAltitude,
- dataIndex: 'altitude',
- flex: 1,
- renderer: Traccar.AttributeFormatter.getFormatter('altitude')
- }, {
- text: Strings.positionSpeed,
- dataIndex: 'speed',
- flex: 1,
- renderer: Traccar.AttributeFormatter.getFormatter('speed')
- }, {
- text: Strings.positionAddress,
- dataIndex: 'address',
- flex: 1,
- renderer: Traccar.AttributeFormatter.getFormatter('address')
- }]
+ }
});
diff --git a/web/app/view/ReportController.js b/web/app/view/ReportController.js
index 4fe7c62b8..ecc7b0f91 100644
--- a/web/app/view/ReportController.js
+++ b/web/app/view/ReportController.js
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,15 +29,17 @@ Ext.define('Traccar.view.ReportController', {
}
},
- onShowClick: function () {
- var deviceId, fromDate, fromTime, from, toDate, toTime, to, store;
+ onReportClick: function (button) {
+ var reportType, deviceId, fromDate, fromTime, from, toDate, toTime, to, store, url;
+
+ reportType = this.lookupReference('reportTypeField').getValue();
deviceId = this.lookupReference('deviceField').getValue();
fromDate = this.lookupReference('fromDateField').getValue();
fromTime = this.lookupReference('fromTimeField').getValue();
- if (deviceId) {
+ if (reportType && deviceId) {
from = new Date(
fromDate.getFullYear(), fromDate.getMonth(), fromDate.getDate(),
fromTime.getHours(), fromTime.getMinutes(), fromTime.getSeconds(), fromTime.getMilliseconds());
@@ -49,19 +51,30 @@ Ext.define('Traccar.view.ReportController', {
toDate.getFullYear(), toDate.getMonth(), toDate.getDate(),
toTime.getHours(), toTime.getMinutes(), toTime.getSeconds(), toTime.getMilliseconds());
- store = Ext.getStore('Positions');
- store.load({
- params: {
+ if (button.reference === "showButton") {
+ store = this.getView().getStore();
+ store.load({
+ params: {
+ deviceId: deviceId,
+ type: '%',
+ from: from.toISOString(),
+ to: to.toISOString()
+ }
+ });
+ } else if (button.reference === "csvButton") {
+ url = this.getView().getStore().getProxy().url;
+ this.downloadCsv(url, {
deviceId: deviceId,
+ type: '%',
from: from.toISOString(),
to: to.toISOString()
- }
- });
+ });
+ }
}
},
onClearClick: function () {
- Ext.getStore('Positions').removeAll();
+ this.getView().getStore().removeAll();
},
onSelectionChange: function (selected) {
@@ -77,6 +90,152 @@ Ext.define('Traccar.view.ReportController', {
},
selectReport: function (position, center) {
- this.getView().getSelectionModel().select([position], false, true);
+ if (position instanceof Traccar.model.Position) {
+ this.getView().getSelectionModel().select([position], false, true);
+ }
+ },
+
+ downloadCsv: function (requestUrl, requestParams) {
+ Ext.Ajax.request({
+ url: requestUrl,
+ method: 'GET',
+ params: requestParams,
+ headers: {
+ Accept: 'text/csv'
+ },
+ success: function (response) {
+ var disposition, filename, type, blob, url, downloadUrl, elementA;
+ disposition = response.getResponseHeader('Content-Disposition');
+ filename = disposition.slice(disposition.indexOf("=") + 1, disposition.length);
+ type = response.getResponseHeader('Content-Type');
+ blob = new Blob([response.responseText], { type: type });
+ if (typeof window.navigator.msSaveBlob !== 'undefined') {
+ // IE workaround
+ window.navigator.msSaveBlob(blob, filename);
+ } else {
+ url = window.URL || window.webkitURL;
+ downloadUrl = URL.createObjectURL(blob);
+ if (filename) {
+ elementA = document.createElement("a");
+ elementA.href = downloadUrl;
+ elementA.download = filename;
+ document.body.appendChild(elementA);
+ elementA.click();
+ }
+ setTimeout(function () {
+ url.revokeObjectURL(downloadUrl);
+ }, 100);
+ }
+ }
+ });
+ },
+
+ onTypeChange: function (combobox, newValue, oldValue) {
+ var routeColumns, eventsColumns, summaryColumns;
+ if (oldValue !== null) {
+ this.onClearClick();
+ }
+ routeColumns = [{
+ text: Strings.positionValid,
+ dataIndex: 'valid',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('valid')
+ }, {
+ text: Strings.positionFixTime,
+ dataIndex: 'fixTime',
+ flex: 1,
+ xtype: 'datecolumn',
+ renderer: Traccar.AttributeFormatter.getFormatter('fixTime')
+ }, {
+ text: Strings.positionLatitude,
+ dataIndex: 'latitude',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('latitude')
+ }, {
+ text: Strings.positionLongitude,
+ dataIndex: 'longitude',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('latitude')
+ }, {
+ text: Strings.positionAltitude,
+ dataIndex: 'altitude',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('altitude')
+ }, {
+ text: Strings.positionSpeed,
+ dataIndex: 'speed',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('speed')
+ }, {
+ text: Strings.positionAddress,
+ dataIndex: 'address',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('address')
+ }];
+
+ eventsColumns = [{
+ text: Strings.positionFixTime,
+ dataIndex: 'serverTime',
+ flex: 1,
+ xtype: 'datecolumn',
+ renderer: Traccar.AttributeFormatter.getFormatter('serverTime')
+ }, {
+ text: Strings.reportDeviceName,
+ dataIndex: 'deviceId',
+ flex: 1,
+ renderer: function (value) {
+ return Ext.getStore('Devices').findRecord('id', value).get('name');
+ }
+ }, {
+ text: Strings.sharedType,
+ dataIndex: 'type',
+ flex: 1,
+ renderer: function (value) {
+ var typeKey = 'event' + value.charAt(0).toUpperCase() + value.slice(1);
+ return Strings[typeKey];
+ }
+ }, {
+ text: Strings.sharedGeofence,
+ dataIndex: 'geofenceId',
+ flex: 1,
+ renderer: function (value) {
+ if (value !== 0) {
+ return Ext.getStore('Geofences').findRecord('id', value).get('name');
+ }
+ }
+ }];
+
+ summaryColumns = [{
+ text: Strings.reportDeviceName,
+ dataIndex: 'deviceId',
+ flex: 1,
+ renderer: function (value) {
+ return Ext.getStore('Devices').findRecord('id', value).get('name');
+ }
+ }, {
+ text: Strings.sharedDistance,
+ dataIndex: 'distance',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('distance')
+ }, {
+ text: Strings.reportAverageSpeed,
+ dataIndex: 'averageSpeed',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('speed')
+ }, {
+ text: Strings.reportMaximumSpeed,
+ dataIndex: 'maxSpeed',
+ flex: 1,
+ renderer: Traccar.AttributeFormatter.getFormatter('speed')
+ }];
+
+ if (newValue === 'route') {
+ this.getView().reconfigure('ReportRoute', routeColumns);
+ } else if (newValue === 'events') {
+ this.getView().reconfigure('ReportEvents', eventsColumns);
+ } else if (newValue === 'summary') {
+ this.getView().reconfigure('ReportSummary', summaryColumns);
+ }
}
+
});
diff --git a/web/app/view/ServerDialog.js b/web/app/view/ServerDialog.js
index 1af000042..dd4579168 100644
--- a/web/app/view/ServerDialog.js
+++ b/web/app/view/ServerDialog.js
@@ -54,7 +54,7 @@ Ext.define('Traccar.view.ServerDialog', {
}, {
xtype: 'combobox',
name: 'distanceUnit',
- fieldLabel: Strings.settingsDistanceUnit,
+ fieldLabel: Strings.sharedDistance,
store: 'DistanceUnits',
displayField: 'name',
valueField: 'key'
diff --git a/web/app/view/UserDialog.js b/web/app/view/UserDialog.js
index df8a26e7e..07fc1431f 100644
--- a/web/app/view/UserDialog.js
+++ b/web/app/view/UserDialog.js
@@ -58,7 +58,7 @@ Ext.define('Traccar.view.UserDialog', {
}, {
xtype: 'combobox',
name: 'distanceUnit',
- fieldLabel: Strings.settingsDistanceUnit,
+ fieldLabel: Strings.sharedDistance,
store: 'DistanceUnits',
displayField: 'name',
valueField: 'key'