|
1
|
|
|
import React, { createRef, Fragment, useEffect, useState } from 'react';
|
|
2
|
|
|
import {
|
|
3
|
|
|
Breadcrumb,
|
|
4
|
|
|
BreadcrumbItem,
|
|
5
|
|
|
Card,
|
|
6
|
|
|
CardBody,
|
|
7
|
|
|
Col,
|
|
8
|
|
|
Form,
|
|
9
|
|
|
FormGroup,
|
|
10
|
|
|
Input,
|
|
11
|
|
|
Label,
|
|
12
|
|
|
Row,
|
|
13
|
|
|
Spinner,
|
|
14
|
|
|
Pagination,
|
|
15
|
|
|
PaginationItem,
|
|
16
|
|
|
PaginationLink
|
|
17
|
|
|
} from 'reactstrap';
|
|
18
|
|
|
import Cascader from 'rc-cascader';
|
|
19
|
|
|
import RealtimeChart from './RealtimeChart';
|
|
20
|
|
|
import { getCookieValue, createCookie } from '../../../helpers/utils';
|
|
21
|
|
|
import withRedirect from '../../../hoc/withRedirect';
|
|
22
|
|
|
import { withTranslation } from 'react-i18next';
|
|
23
|
|
|
import uuid from 'uuid/v1';
|
|
24
|
|
|
import { toast } from 'react-toastify';
|
|
25
|
|
|
import { APIBaseURL } from '../../../config';
|
|
26
|
|
|
|
|
27
|
|
|
const MeterRealtime = ({ setRedirect, setRedirectUrl, t }) => {
|
|
28
|
|
|
const [cursor, setCursor] = useState(0);
|
|
29
|
|
|
const [maxCursor, setMaxCursor] = useState(0);
|
|
30
|
|
|
const [selectMeterList, setSelectMeterList] = useState([]);
|
|
31
|
|
|
const len = 8;
|
|
32
|
|
|
const ran = 1;
|
|
33
|
|
|
|
|
34
|
|
|
useEffect(() => {
|
|
35
|
|
|
let is_logged_in = getCookieValue('is_logged_in');
|
|
36
|
|
|
let user_name = getCookieValue('user_name');
|
|
37
|
|
|
let user_display_name = getCookieValue('user_display_name');
|
|
38
|
|
|
let user_uuid = getCookieValue('user_uuid');
|
|
39
|
|
|
let token = getCookieValue('token');
|
|
40
|
|
|
if (is_logged_in === null || !is_logged_in) {
|
|
41
|
|
|
setRedirectUrl(`/authentication/basic/login`);
|
|
42
|
|
|
setRedirect(true);
|
|
43
|
|
|
} else {
|
|
44
|
|
|
//update expires time of cookies
|
|
45
|
|
|
createCookie('is_logged_in', true, 1000 * 60 * 60 * 8);
|
|
46
|
|
|
createCookie('user_name', user_name, 1000 * 60 * 60 * 8);
|
|
47
|
|
|
createCookie('user_display_name', user_display_name, 1000 * 60 * 60 * 8);
|
|
48
|
|
|
createCookie('user_uuid', user_uuid, 1000 * 60 * 60 * 8);
|
|
49
|
|
|
createCookie('token', token, 1000 * 60 * 60 * 8);
|
|
50
|
|
|
}
|
|
51
|
|
|
});
|
|
52
|
|
|
let table = createRef();
|
|
53
|
|
|
// State
|
|
54
|
|
|
const [selectedSpaceName, setSelectedSpaceName] = useState(undefined);
|
|
55
|
|
|
const [cascaderOptions, setCascaderOptions] = useState(undefined);
|
|
56
|
|
|
const [meterList, setMeterList] = useState([]);
|
|
57
|
|
|
const [spinnerHidden, setSpinnerHidden] = useState(false);
|
|
58
|
|
|
|
|
59
|
|
|
useEffect(() => {
|
|
60
|
|
|
//begin of getting space tree
|
|
61
|
|
|
let isResponseOK = false;
|
|
62
|
|
|
fetch(APIBaseURL + '/spaces/tree', {
|
|
63
|
|
|
method: 'GET',
|
|
64
|
|
|
headers: {
|
|
65
|
|
|
'Content-type': 'application/json',
|
|
66
|
|
|
'User-UUID': getCookieValue('user_uuid'),
|
|
67
|
|
|
Token: getCookieValue('token')
|
|
68
|
|
|
},
|
|
69
|
|
|
body: null
|
|
70
|
|
|
})
|
|
71
|
|
|
.then(response => {
|
|
72
|
|
|
console.log(response);
|
|
73
|
|
|
if (response.ok) {
|
|
74
|
|
|
isResponseOK = true;
|
|
75
|
|
|
}
|
|
76
|
|
|
return response.json();
|
|
77
|
|
|
})
|
|
78
|
|
|
.then(json => {
|
|
79
|
|
|
console.log(json);
|
|
80
|
|
|
if (isResponseOK) {
|
|
81
|
|
|
// rename keys
|
|
82
|
|
|
json = JSON.parse(
|
|
83
|
|
|
JSON.stringify([json])
|
|
84
|
|
|
.split('"id":')
|
|
85
|
|
|
.join('"value":')
|
|
86
|
|
|
.split('"name":')
|
|
87
|
|
|
.join('"label":')
|
|
88
|
|
|
);
|
|
89
|
|
|
setCascaderOptions(json);
|
|
90
|
|
|
// set the default space
|
|
91
|
|
|
setSelectedSpaceName([json[0]].map(o => o.label));
|
|
92
|
|
|
let selectedSpaceID = [json[0]].map(o => o.value);
|
|
93
|
|
|
//begin of getting meters of the default space
|
|
94
|
|
|
let isSecondResponseOK = false;
|
|
95
|
|
|
fetch(APIBaseURL + '/spaces/' + selectedSpaceID + '/meters', {
|
|
96
|
|
|
method: 'GET',
|
|
97
|
|
|
headers: {
|
|
98
|
|
|
'Content-type': 'application/json',
|
|
99
|
|
|
'User-UUID': getCookieValue('user_uuid'),
|
|
100
|
|
|
Token: getCookieValue('token')
|
|
101
|
|
|
},
|
|
102
|
|
|
body: null
|
|
103
|
|
|
})
|
|
104
|
|
|
.then(response => {
|
|
105
|
|
|
if (response.ok) {
|
|
106
|
|
|
isSecondResponseOK = true;
|
|
107
|
|
|
}
|
|
108
|
|
|
return response.json();
|
|
109
|
|
|
})
|
|
110
|
|
|
.then(json => {
|
|
111
|
|
|
if (isSecondResponseOK) {
|
|
112
|
|
|
json = JSON.parse(JSON.stringify([json]));
|
|
113
|
|
|
console.log(json);
|
|
114
|
|
|
setMeterList(json[0]);
|
|
115
|
|
|
setSpinnerHidden(true);
|
|
116
|
|
|
} else {
|
|
117
|
|
|
toast.error(json.description);
|
|
118
|
|
|
}
|
|
119
|
|
|
})
|
|
120
|
|
|
.catch(err => {
|
|
121
|
|
|
console.log(err);
|
|
122
|
|
|
});
|
|
123
|
|
|
//end of getting meters of the default space
|
|
124
|
|
|
} else {
|
|
125
|
|
|
toast.error(json.description);
|
|
126
|
|
|
}
|
|
127
|
|
|
})
|
|
128
|
|
|
.catch(err => {
|
|
129
|
|
|
console.log(err);
|
|
130
|
|
|
});
|
|
131
|
|
|
//end of getting space tree
|
|
132
|
|
|
}, []);
|
|
133
|
|
|
|
|
134
|
|
|
const labelClasses = 'ls text-uppercase text-600 font-weight-semi-bold mb-0';
|
|
135
|
|
|
|
|
136
|
|
|
let onSpaceCascaderChange = (value, selectedOptions) => {
|
|
137
|
|
|
setSelectedSpaceName(selectedOptions.map(o => o.label).join('/'));
|
|
138
|
|
|
let selectedSpaceID = value[value.length - 1];
|
|
139
|
|
|
setSpinnerHidden(false);
|
|
140
|
|
|
//begin of getting meters of the selected space
|
|
141
|
|
|
let isResponseOK = false;
|
|
142
|
|
|
fetch(APIBaseURL + '/spaces/' + selectedSpaceID + '/meters', {
|
|
143
|
|
|
method: 'GET',
|
|
144
|
|
|
headers: {
|
|
145
|
|
|
'Content-type': 'application/json',
|
|
146
|
|
|
'User-UUID': getCookieValue('user_uuid'),
|
|
147
|
|
|
Token: getCookieValue('token')
|
|
148
|
|
|
},
|
|
149
|
|
|
body: null
|
|
150
|
|
|
})
|
|
151
|
|
|
.then(response => {
|
|
152
|
|
|
if (response.ok) {
|
|
153
|
|
|
isResponseOK = true;
|
|
154
|
|
|
}
|
|
155
|
|
|
return response.json();
|
|
156
|
|
|
})
|
|
157
|
|
|
.then(json => {
|
|
158
|
|
|
if (isResponseOK) {
|
|
159
|
|
|
json = JSON.parse(JSON.stringify([json]));
|
|
160
|
|
|
console.log(json);
|
|
161
|
|
|
setMeterList(json[0]);
|
|
162
|
|
|
|
|
163
|
|
|
setSpinnerHidden(true);
|
|
164
|
|
|
} else {
|
|
165
|
|
|
toast.error(json.description);
|
|
166
|
|
|
}
|
|
167
|
|
|
})
|
|
168
|
|
|
.catch(err => {
|
|
169
|
|
|
console.log(err);
|
|
170
|
|
|
});
|
|
171
|
|
|
//end of getting meters of the selected space
|
|
172
|
|
|
};
|
|
173
|
|
|
|
|
174
|
|
|
useEffect(() => {
|
|
175
|
|
|
const meterLen = meterList.length;
|
|
176
|
|
|
const maxCursor = Math.ceil(meterLen / len);
|
|
177
|
|
|
|
|
178
|
|
|
setCursor(1);
|
|
179
|
|
|
setMaxCursor(maxCursor);
|
|
180
|
|
|
|
|
181
|
|
|
document.getElementById("cursor_2").hidden=true;
|
|
182
|
|
|
document.getElementById("cursor_3").hidden=true;
|
|
183
|
|
|
document.getElementById("cursor_4").hidden=true;
|
|
184
|
|
|
if(maxCursor == 2){
|
|
185
|
|
|
document.getElementById("cursor_2").hidden=false;
|
|
186
|
|
|
}
|
|
187
|
|
|
if(maxCursor == 3){
|
|
188
|
|
|
document.getElementById("cursor_2").hidden=false;
|
|
189
|
|
|
document.getElementById("cursor_3").hidden=false;
|
|
190
|
|
|
}
|
|
191
|
|
|
if(maxCursor>=4)
|
|
192
|
|
|
{
|
|
193
|
|
|
document.getElementById("cursor_2").hidden=false;
|
|
194
|
|
|
document.getElementById("cursor_3").hidden=false;
|
|
195
|
|
|
document.getElementById("cursor_4").hidden=false;
|
|
196
|
|
|
}
|
|
197
|
|
|
|
|
198
|
|
|
}, [meterList]);
|
|
199
|
|
|
|
|
200
|
|
|
useEffect(() => {
|
|
201
|
|
|
setSelectMeterList(meterList.slice(cursor * len - 8, cursor * len));
|
|
202
|
|
|
|
|
203
|
|
|
|
|
204
|
|
|
}, [cursor, meterList]);
|
|
205
|
|
|
|
|
206
|
|
|
function getCursor(location){
|
|
207
|
|
|
switch (location){
|
|
208
|
|
|
case 1:
|
|
209
|
|
|
return cursor > maxCursor-3&&maxCursor - 3 >= 0 ? maxCursor-3 : cursor;
|
|
210
|
|
|
case 2:
|
|
211
|
|
|
return cursor > maxCursor-3&&maxCursor - 3 >= 0 ? maxCursor -2 : cursor +1;
|
|
212
|
|
|
case 3:
|
|
213
|
|
|
return cursor > maxCursor-3&&maxCursor - 3 >= 0 ? maxCursor -1: cursor +2;
|
|
214
|
|
|
case 4:
|
|
215
|
|
|
return cursor > maxCursor-3&&maxCursor - 3 >= 0 ? maxCursor : cursor+3;
|
|
216
|
|
|
}
|
|
217
|
|
|
}
|
|
218
|
|
|
|
|
219
|
|
|
return (
|
|
220
|
|
|
<Fragment>
|
|
221
|
|
|
<div>
|
|
222
|
|
|
<Breadcrumb>
|
|
223
|
|
|
<BreadcrumbItem>{t('Meter Data')}</BreadcrumbItem>
|
|
224
|
|
|
<BreadcrumbItem active>{t('Meter Realtime')}</BreadcrumbItem>
|
|
225
|
|
|
</Breadcrumb>
|
|
226
|
|
|
</div>
|
|
227
|
|
|
<Card className="bg-light mb-3">
|
|
228
|
|
|
<CardBody className="p-3">
|
|
229
|
|
|
<Form>
|
|
230
|
|
|
<Row form>
|
|
231
|
|
|
<Col xs={6} sm={3}>
|
|
232
|
|
|
<FormGroup className="form-group">
|
|
233
|
|
|
<Label className={labelClasses} for="space">
|
|
234
|
|
|
{t('Space')}
|
|
235
|
|
|
</Label>
|
|
236
|
|
|
<br />
|
|
237
|
|
|
<Cascader
|
|
238
|
|
|
options={cascaderOptions}
|
|
239
|
|
|
onChange={onSpaceCascaderChange}
|
|
240
|
|
|
changeOnSelect
|
|
241
|
|
|
expandTrigger="hover"
|
|
242
|
|
|
>
|
|
243
|
|
|
<Input value={selectedSpaceName || ''} readOnly />
|
|
244
|
|
|
</Cascader>
|
|
245
|
|
|
</FormGroup>
|
|
246
|
|
|
</Col>
|
|
247
|
|
|
<Col xs="auto">
|
|
248
|
|
|
<FormGroup>
|
|
249
|
|
|
<br />
|
|
250
|
|
|
<Spinner color="primary" hidden={spinnerHidden} />
|
|
251
|
|
|
</FormGroup>
|
|
252
|
|
|
</Col>
|
|
253
|
|
|
</Row>
|
|
254
|
|
|
</Form>
|
|
255
|
|
|
</CardBody>
|
|
256
|
|
|
</Card>
|
|
257
|
|
|
<Row noGutters>
|
|
258
|
|
|
{selectMeterList.map(meter => (
|
|
259
|
|
|
<Col lg="3" className="pr-lg-2" key={uuid()}>
|
|
260
|
|
|
<RealtimeChart meterId={meter['id']} meterName={meter['name']} />
|
|
261
|
|
|
</Col>
|
|
262
|
|
|
))}
|
|
263
|
|
|
</Row>
|
|
264
|
|
|
<Pagination>
|
|
265
|
|
|
<PaginationItem>
|
|
266
|
|
|
<PaginationLink first href="#" onClick={() => setCursor(1)} />
|
|
267
|
|
|
</PaginationItem>
|
|
268
|
|
|
|
|
269
|
|
|
<PaginationItem>
|
|
270
|
|
|
<PaginationLink previous href="#" onClick={() => (cursor - 1 >= 1 ? setCursor(cursor - 1) : null)} />
|
|
271
|
|
|
</PaginationItem>
|
|
272
|
|
|
<PaginationItem>
|
|
273
|
|
|
<PaginationLink href="#" onClick={() => (setCursor(getCursor(1)))}>{getCursor(1)}</PaginationLink>
|
|
274
|
|
|
</PaginationItem>
|
|
275
|
|
|
<PaginationItem id="cursor_2">
|
|
276
|
|
|
<PaginationLink href="#" onClick={() => (setCursor(getCursor(2)))}>{getCursor(2)}</PaginationLink>
|
|
277
|
|
|
</PaginationItem>
|
|
278
|
|
|
<PaginationItem id="cursor_3">
|
|
279
|
|
|
<PaginationLink href="#" onClick={() => (setCursor(getCursor(3)))}>{getCursor(3)}</PaginationLink>
|
|
280
|
|
|
</PaginationItem>
|
|
281
|
|
|
<PaginationItem id="cursor_4">
|
|
282
|
|
|
<PaginationLink href="#" onClick={() => (setCursor(getCursor(4)))}>{getCursor(4)}</PaginationLink>
|
|
283
|
|
|
</PaginationItem>
|
|
284
|
|
|
<PaginationItem >
|
|
285
|
|
|
<PaginationLink next href="#" onClick={() => (cursor + 1 <= maxCursor ? setCursor(cursor + 1) : null)} />
|
|
286
|
|
|
</PaginationItem>
|
|
287
|
|
|
<PaginationItem>
|
|
288
|
|
|
<PaginationLink last href="#" onClick={() => setCursor(maxCursor)} />
|
|
289
|
|
|
</PaginationItem>
|
|
290
|
|
|
</Pagination>
|
|
291
|
|
|
</Fragment>
|
|
292
|
|
|
);
|
|
293
|
|
|
};
|
|
294
|
|
|
|
|
295
|
|
|
export default withTranslation()(withRedirect(MeterRealtime)); |