aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modern/src/App.js2
-rw-r--r--modern/src/MainToolbar.js2
-rw-r--r--modern/src/reports/EventReportPage.js86
-rw-r--r--modern/src/reports/ReportFilter.js109
-rw-r--r--modern/src/reports/ReportLayoutPage.js46
-rw-r--r--modern/src/reports/RouteReportPage.js192
6 files changed, 285 insertions, 152 deletions
diff --git a/modern/src/App.js b/modern/src/App.js
index 243489e..f4de837 100644
--- a/modern/src/App.js
+++ b/modern/src/App.js
@@ -14,6 +14,7 @@ import NotificationPage from './settings/NotificationPage';
import GroupsPage from './settings/GroupsPage';
import GroupPage from './settings/GroupPage';
import PositionPage from './PositionPage';
+import EventReportPage from './reports/EventReportPage';
import ReplayPage from './reports/ReplayPage';
import { useSelector } from 'react-redux';
import { LinearProgress } from '@material-ui/core';
@@ -42,6 +43,7 @@ const App = () => {
<Route exact path='/settings/group/:id?' component={GroupPage} />
<Route exact path='/admin/server' component={ServerPage} />
<Route exact path='/admin/users' component={UsersPage} />
+ <Route exact path='/reports/event' component={EventReportPage} />
</Switch>
)}
</Route>
diff --git a/modern/src/MainToolbar.js b/modern/src/MainToolbar.js
index 942aac6..b853dc4 100644
--- a/modern/src/MainToolbar.js
+++ b/modern/src/MainToolbar.js
@@ -117,7 +117,7 @@ const MainToolbar = () => {
</ListItemIcon>
<ListItemText primary={t('reportRoute')} />
</ListItem>
- <ListItem button disabled>
+ <ListItem button onClick={() => history.push('/reports/event')}>
<ListItemIcon>
<NotificationsActiveIcon />
</ListItemIcon>
diff --git a/modern/src/reports/EventReportPage.js b/modern/src/reports/EventReportPage.js
new file mode 100644
index 0000000..e9bca4e
--- /dev/null
+++ b/modern/src/reports/EventReportPage.js
@@ -0,0 +1,86 @@
+import React, { useState } from 'react';
+import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, Paper } from '@material-ui/core';
+import { FormControl, InputLabel, Select, MenuItem } from '@material-ui/core';
+import t from '../common/localization';
+import { formatPosition } from '../common/formatter';
+import ReportFilter from './ReportFilter';
+import ReportLayoutPage from './ReportLayoutPage';
+
+const ReportFilterForm = ({ onResult }) => {
+ const [eventType, setEventType] = useState(['allEvents']);
+
+ const handleSubmit = async (deviceId, from, to) => {
+ const query = new URLSearchParams({
+ deviceId,
+ from: from.toISOString(),
+ to: to.toISOString(),
+ });
+ eventType.map(t=>query.append('type',t));
+ const response = await fetch(`/api/reports/events?${query.toString()}`, { headers: { Accept: 'application/json' } });
+ if(response.ok) {
+ onResult(await response.json());
+ }
+ }
+ return (
+ <ReportFilter handleSubmit={handleSubmit}>
+ <FormControl variant="filled" margin="normal" fullWidth>
+ <InputLabel>{t('reportEventTypes')}</InputLabel>
+ <Select value={eventType} onChange={(e) => setEventType(e.target.value)} multiple>
+ <MenuItem value="allEvents">{t('eventAll')}</MenuItem>
+ <MenuItem value="deviceOnline">{t('eventDeviceOnline')}</MenuItem>
+ <MenuItem value="deviceUnknown">{t('eventDeviceUnknown')}</MenuItem>
+ <MenuItem value="deviceOffline">{t('eventDeviceOffline')}</MenuItem>
+ <MenuItem value="deviceInactive">{t('eventDeviceInactive')}</MenuItem>
+ <MenuItem value="deviceMoving">{t('eventDeviceMoving')}</MenuItem>
+ <MenuItem value="deviceStopped">{t('eventDeviceStopped')}</MenuItem>
+ <MenuItem value="deviceOverspeed">{t('eventDeviceOverspeed')}</MenuItem>
+ <MenuItem value="deviceFuelDrop">{t('eventDeviceFuelDrop')}</MenuItem>
+ <MenuItem value="commandResult">{t('eventCommandResult')}</MenuItem>
+ <MenuItem value="geofenceEnter">{t('eventGeofenceEnter')}</MenuItem>
+ <MenuItem value="geofenceExit">{t('eventGeofenceExit')}</MenuItem>
+ <MenuItem value="alarm">{t('eventAlarm')}</MenuItem>
+ <MenuItem value="ignitionOn">{t('eventIgnitionOn')}</MenuItem>
+ <MenuItem value="ignitionOff">{t('eventIgnitionOff')}</MenuItem>
+ <MenuItem value="maintenance">{t('eventMaintenance')}</MenuItem>
+ <MenuItem value="textMessage">{t('eventTextMessage')}</MenuItem>
+ <MenuItem value="driverChanged">{t('eventDriverChanged')}</MenuItem>
+ </Select>
+ </FormControl>
+ </ReportFilter>
+ );
+}
+
+const EventReportPage = () => {
+ const [items, setItems] = useState([]);
+
+ return (
+ <ReportLayoutPage reportFilterForm={ReportFilterForm} setItems={setItems}>
+ <TableContainer component={Paper}>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell>{t('positionFixTime')}</TableCell>
+ <TableCell>{t('sharedType')}</TableCell>
+ <TableCell>{t('sharedGeofence')}</TableCell>
+ <TableCell>{t('sharedMaintenance')}</TableCell>
+ </TableRow>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell>
+ {formatPosition(item, 'serverTime')}
+ </TableCell>
+ <TableCell>{item.type}</TableCell>
+ <TableCell>{}</TableCell>
+ <TableCell>{}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </TableContainer>
+ </ReportLayoutPage>
+ );
+}
+
+export default EventReportPage;
diff --git a/modern/src/reports/ReportFilter.js b/modern/src/reports/ReportFilter.js
new file mode 100644
index 0000000..0d3223f
--- /dev/null
+++ b/modern/src/reports/ReportFilter.js
@@ -0,0 +1,109 @@
+import React, { useState } from 'react';
+import { FormControl, InputLabel, Select, MenuItem, Button, TextField } from '@material-ui/core';
+import t from '../common/localization';
+import { useSelector } from 'react-redux';
+import moment from 'moment';
+
+const ReportFilter = (props) => {
+ const devices = useSelector((state) => Object.values(state.devices.items));
+ const [deviceId, setDeviceId] = useState();
+ const [period, setPeriod] = useState('today');
+ const [from, setFrom] = useState(moment().subtract(1, 'hour'));
+ const [to, setTo] = useState(moment());
+
+ const handleShow = () => {
+ let selectedFrom;
+ let selectedTo;
+ switch (period) {
+ case 'today':
+ selectedFrom = moment().startOf('day');
+ selectedTo = moment().endOf('day');
+ break;
+ case 'yesterday':
+ selectedFrom = moment().subtract(1, 'day').startOf('day');
+ selectedTo = moment().subtract(1, 'day').endOf('day');
+ break;
+ case 'thisWeek':
+ selectedFrom = moment().startOf('week');
+ selectedTo = moment().endOf('week');
+ break;
+ case 'previousWeek':
+ selectedFrom = moment().subtract(1, 'week').startOf('week');
+ selectedTo = moment().subtract(1, 'week').endOf('week');
+ break;
+ case 'thisMonth':
+ selectedFrom = moment().startOf('month');
+ selectedTo = moment().endOf('month');
+ break;
+ case 'previousMonth':
+ selectedFrom = moment().subtract(1, 'month').startOf('month');
+ selectedTo = moment().subtract(1, 'month').endOf('month');
+ break;
+ default:
+ selectedFrom = from;
+ selectedTo = to;
+ break;
+ }
+
+ props.handleSubmit(deviceId, selectedFrom, selectedTo);
+ }
+
+ return (
+ <>
+ <FormControl variant="filled" margin="normal" fullWidth>
+ <InputLabel>{t('reportDevice')}</InputLabel>
+ <Select value={deviceId} onChange={(e) => setDeviceId(e.target.value)}>
+ {devices.map((device) => (
+ <MenuItem value={device.id}>{device.name}</MenuItem>
+ ))}
+ </Select>
+ </FormControl>
+
+ {props.children}
+
+ <FormControl variant="filled" margin="normal" fullWidth>
+ <InputLabel>{t('reportPeriod')}</InputLabel>
+ <Select value={period} onChange={(e) => setPeriod(e.target.value)}>
+ <MenuItem value="today">{t('reportToday')}</MenuItem>
+ <MenuItem value="yesterday">{t('reportYesterday')}</MenuItem>
+ <MenuItem value="thisWeek">{t('reportThisWeek')}</MenuItem>
+ <MenuItem value="previousWeek">{t('reportPreviousWeek')}</MenuItem>
+ <MenuItem value="thisMonth">{t('reportThisMonth')}</MenuItem>
+ <MenuItem value="previousMonth">{t('reportPreviousMonth')}</MenuItem>
+ <MenuItem value="custom">{t('reportCustom')}</MenuItem>
+ </Select>
+ </FormControl>
+ {period === 'custom' && (
+ <TextField
+ margin="normal"
+ variant="filled"
+ label={t('reportFrom')}
+ type="datetime-local"
+ value={from.format(moment.HTML5_FMT.DATETIME_LOCAL)}
+ onChange={(e) =>
+ setFrom(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))
+ }
+ fullWidth />
+ )}
+ {period === 'custom' && (
+ <TextField
+ margin="normal"
+ variant="filled"
+ label={t('reportTo')}
+ type="datetime-local"
+ value={to.format(moment.HTML5_FMT.DATETIME_LOCAL)}
+ onChange={(e) =>
+ setTo(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))
+ }
+ fullWidth />
+ )}
+ <FormControl margin="normal" fullWidth>
+ <Button type="button" color="primary" variant="contained" disabled={!deviceId} onClick={handleShow}>
+ {t('reportShow')}
+ </Button>
+ </FormControl>
+ </>
+ );
+}
+
+export default ReportFilter;
diff --git a/modern/src/reports/ReportLayoutPage.js b/modern/src/reports/ReportLayoutPage.js
new file mode 100644
index 0000000..57a2cef
--- /dev/null
+++ b/modern/src/reports/ReportLayoutPage.js
@@ -0,0 +1,46 @@
+import React, { useState } from 'react';
+import { Grid, Paper, makeStyles } from '@material-ui/core';
+import MainToolbar from '../MainToolbar';
+
+const useStyles = makeStyles(theme => ({
+ root: {
+ height: '100%',
+ display: 'flex',
+ flexDirection: 'column',
+ },
+ content: {
+ flex: 1,
+ overflow: 'auto',
+ padding: theme.spacing(2),
+ },
+ form: {
+ padding: theme.spacing(1, 2, 2),
+ },
+}));
+
+const ReportLayoutPage = ({ reportFilterForm:ReportFilterForm, setItems, ...rest }) => {
+ const classes = useStyles();
+
+ const onResult = (data) => {
+ setItems(data);
+ }
+ return (
+ <div className={classes.root}>
+ <MainToolbar />
+ <div className={classes.content}>
+ <Grid container spacing={2}>
+ <Grid item xs={12} md={3} lg={2}>
+ <Paper className={classes.form}>
+ <ReportFilterForm onResult={ onResult } />
+ </Paper>
+ </Grid>
+ <Grid item xs={12} md={9} lg={10}>
+ {rest.children}
+ </Grid>
+ </Grid>
+ </div>
+ </div>
+ );
+}
+
+export default ReportLayoutPage;
diff --git a/modern/src/reports/RouteReportPage.js b/modern/src/reports/RouteReportPage.js
index 5e57783..0f8d98a 100644
--- a/modern/src/reports/RouteReportPage.js
+++ b/modern/src/reports/RouteReportPage.js
@@ -1,165 +1,55 @@
import React, { useState } from 'react';
-import MainToolbar from '../MainToolbar';
-import { Grid, TableContainer, Table, TableRow, TableCell, TableHead, TableBody, Paper, makeStyles, FormControl, InputLabel, Select, MenuItem, Button, TextField } from '@material-ui/core';
+import { TableContainer, Table, TableRow, TableCell, TableHead, TableBody, Paper } from '@material-ui/core';
import t from '../common/localization';
-import { useSelector } from 'react-redux';
-import moment from 'moment';
import { formatPosition } from '../common/formatter';
+import ReportFilter from './ReportFilter';
+import ReportLayoutPage from './ReportLayoutPage';
-const useStyles = makeStyles(theme => ({
- root: {
- height: '100%',
- display: 'flex',
- flexDirection: 'column',
- },
- content: {
- flex: 1,
- overflow: 'auto',
- padding: theme.spacing(2),
- },
- form: {
- padding: theme.spacing(1, 2, 2),
- },
-}));
+const ReportFilterForm = ({ onResult }) => {
-const RouteReportPage = () => {
- const classes = useStyles();
- const devices = useSelector(state => Object.values(state.devices.items));
- const [deviceId, setDeviceId] = useState();
- const [period, setPeriod] = useState('today');
- const [from, setFrom] = useState(moment().subtract(1, 'hour'));
- const [to, setTo] = useState(moment());
- const [data, setData] = useState([]);
-
- const handleShow = () => {
- let selectedFrom;
- let selectedTo;
- switch (period) {
- case 'today':
- selectedFrom = moment().startOf('day');
- selectedTo = moment().endOf('day');
- break;
- case 'yesterday':
- selectedFrom = moment().subtract(1, 'day').startOf('day');
- selectedTo = moment().subtract(1, 'day').endOf('day');
- break;
- case 'thisWeek':
- selectedFrom = moment().startOf('week');
- selectedTo = moment().endOf('week');
- break;
- case 'previousWeek':
- selectedFrom = moment().subtract(1, 'week').startOf('week');
- selectedTo = moment().subtract(1, 'week').endOf('week');
- break;
- case 'thisMonth':
- selectedFrom = moment().startOf('month');
- selectedTo = moment().endOf('month');
- break;
- case 'previousMonth':
- selectedFrom = moment().subtract(1, 'month').startOf('month');
- selectedTo = moment().subtract(1, 'month').endOf('month');
- break;
- default:
- selectedFrom = from;
- selectedTo = to;
- break;
- }
+ const handleSubmit = async (deviceId, from, to) => {
const query = new URLSearchParams({
deviceId,
- from: selectedFrom.toISOString(),
- to: selectedTo.toISOString(),
+ from: from.toISOString(),
+ to: to.toISOString(),
});
- fetch(`/api/reports/route?${query.toString()}`, { headers: { 'Accept': 'application/json' } })
- .then(response => {
- if (response.ok) {
- response.json().then(setData);
- }
- });
+ const response = await fetch(`/api/reports/route?${query.toString()}`, { headers: { Accept: 'application/json' } });
+ if(response.ok) {
+ onResult(await response.json());
+ }
}
+ return <ReportFilter handleSubmit={handleSubmit} />;
+}
+const RouteReportPage = () => {
+ const [items, setItems] = useState([]);
return (
- <div className={classes.root}>
- <MainToolbar />
- <div className={classes.content}>
- <Grid container spacing={2}>
- <Grid item xs={12} md={3} lg={2}>
- <Paper className={classes.form}>
- <FormControl variant='filled' margin='normal' fullWidth>
- <InputLabel>{t('reportDevice')}</InputLabel>
- <Select value={deviceId} onChange={e => setDeviceId(e.target.value)}>
- {devices.map((device) => (
- <MenuItem value={device.id}>{device.name}</MenuItem>
- ))}
- </Select>
- </FormControl>
- <FormControl variant='filled' margin='normal' fullWidth>
- <InputLabel>{t('reportPeriod')}</InputLabel>
- <Select value={period} onChange={e => setPeriod(e.target.value)}>
- <MenuItem value='today'>{t('reportToday')}</MenuItem>
- <MenuItem value='yesterday'>{t('reportYesterday')}</MenuItem>
- <MenuItem value='thisWeek'>{t('reportThisWeek')}</MenuItem>
- <MenuItem value='previousWeek'>{t('reportPreviousWeek')}</MenuItem>
- <MenuItem value='thisMonth'>{t('reportThisMonth')}</MenuItem>
- <MenuItem value='previousMonth'>{t('reportPreviousMonth')}</MenuItem>
- <MenuItem value='custom'>{t('reportCustom')}</MenuItem>
- </Select>
- </FormControl>
- {period === 'custom' &&
- <TextField
- margin='normal'
- variant='filled'
- label={t('reportFrom')}
- type='datetime-local'
- value={from.format(moment.HTML5_FMT.DATETIME_LOCAL)}
- onChange={e => setFrom(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))}
- fullWidth />
- }
- {period === 'custom' &&
- <TextField
- margin='normal'
- variant='filled'
- label={t('reportTo')}
- type='datetime-local'
- value={to.format(moment.HTML5_FMT.DATETIME_LOCAL)}
- onChange={(e) => setTo(moment(e.target.value, moment.HTML5_FMT.DATETIME_LOCAL))}
- fullWidth />
- }
- <FormControl margin='normal' fullWidth>
- <Button type='button' color='primary' variant='contained' disabled={!deviceId} onClick={handleShow}>
- {t('reportShow')}
- </Button>
- </FormControl>
- </Paper>
- </Grid>
- <Grid item xs={12} md={9} lg={10}>
- <TableContainer component={Paper}>
- <Table>
- <TableHead>
- <TableRow>
- <TableCell>{t('positionFixTime')}</TableCell>
- <TableCell>{t('positionLatitude')}</TableCell>
- <TableCell>{t('positionLongitude')}</TableCell>
- <TableCell>{t('positionSpeed')}</TableCell>
- <TableCell>{t('positionAddress')}</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {data.map((item) => (
- <TableRow key={item.id}>
- <TableCell>{formatPosition(item, 'fixTime')}</TableCell>
- <TableCell>{formatPosition(item, 'latitude')}</TableCell>
- <TableCell>{formatPosition(item, 'longitude')}</TableCell>
- <TableCell>{formatPosition(item, 'speed')}</TableCell>
- <TableCell>{formatPosition(item, 'address')}</TableCell>
- </TableRow>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
- </Grid>
- </Grid>
- </div>
- </div>
+ <ReportLayoutPage reportFilterForm={ReportFilterForm} setItems={setItems}>
+ <TableContainer component={Paper}>
+ <Table>
+ <TableHead>
+ <TableRow>
+ <TableCell>{t('positionFixTime')}</TableCell>
+ <TableCell>{t('positionLatitude')}</TableCell>
+ <TableCell>{t('positionLongitude')}</TableCell>
+ <TableCell>{t('positionSpeed')}</TableCell>
+ <TableCell>{t('positionAddress')}</TableCell>
+ </TableRow>
+ </TableHead>
+ <TableBody>
+ {items.map((item) => (
+ <TableRow key={item.id}>
+ <TableCell>{formatPosition(item, 'fixTime')}</TableCell>
+ <TableCell>{formatPosition(item, 'latitude')}</TableCell>
+ <TableCell>{formatPosition(item, 'longitude')}</TableCell>
+ <TableCell>{formatPosition(item, 'speed')}</TableCell>
+ <TableCell>{formatPosition(item, 'address')}</TableCell>
+ </TableRow>
+ ))}
+ </TableBody>
+ </Table>
+ </TableContainer>
+ </ReportLayoutPage>
);
}