Last modified by Hera Guo on 2024/11/11 17:08

From version 15.1
edited by Hera Guo
on 2024/11/04 15:11
Change comment: There is no comment for this version
To version 64.1
edited by Hera Guo
on 2024/11/11 17:08
Change comment: There is no comment for this version

Summary

Details

Page properties
Content
... ... @@ -1,4 +1,4 @@
1 -**Table of Contents:**
1 + **Table of Contents:**
2 2  
3 3  {{toc/}}
4 4  
... ... @@ -5,6 +5,9 @@
5 5  
6 6  
7 7  
8 +
9 +
10 +
8 8  = 1. About this demo =
9 9  
10 10  This demo is to show the installation for various sensors in Dragino Office, Dragino Facotry & ThingsEye Office. It covers various types of sensors such as Temperature, Humidity, CO2, Water Flow, Vibration & many many.
... ... @@ -57,7 +57,7 @@
57 57  
58 58  **device:**This section displays the specific information collected by the device, and different types of sensors have different display interfaces
59 59  
60 -[[image:1730699212334-960.png]]
63 +[[image:屏幕截图 2024-11-04 134645.png]]
61 61  
62 62  First floor:
63 63  
... ... @@ -82,7 +82,7 @@
82 82  
83 83  High Temperature、Low Temperature、High humidity、Low humidity、Low voltage、Device Disconnected
84 84  
85 -[[image:1730699566023-958.png]]
88 +[[image:屏幕截图 2024-11-04 135045.png]]
86 86  
87 87  = 4.configuration details =
88 88  
... ... @@ -90,17 +90,999 @@
90 90  
91 91  == 4.1 Dashboard configuration details ==
92 92  
93 -1、Configure the interface of the third layer Davies.
96 +=== 4.1.1.Data source (Entity aliases) ===
94 94  
98 +detail:Obtain data based on dashboard status
95 95  
96 -2、Configure the interface of the second layer asset
100 +[[image:1730709424998-915.png||height="729" width="1436"]]
97 97  
102 +Alarm:Obtain alarm information
98 98  
99 -3、Configure the first layer menu interface
104 +[[image:1730709479828-595.png||height="696" width="1435"]]
100 100  
106 +Dragino&GXHL,Ltd:Obtain data through asset types
101 101  
108 +[[image:1730709511861-439.png||height="714" width="1435"]]
109 +
110 +Selected Supermarket:Retrieve devices by device type
111 +
112 +[[image:1730709527720-418.png||height="751" width="1433"]]
113 +
114 +Supermarket Devices:Obtain data through device type
115 +
116 +[[image:1730709555797-383.png||height="726" width="1434"]]
117 +
118 +LHT65N Device:Obtain data based on device type
119 +
120 +[[image:1730857191863-514.png||height="725" width="1433"]]
121 +
122 +=== 4.1.2.Page Configuration ===
123 +
124 +==== 4.1.2.1、Configure the interface of the third layer Davies. ====
125 +
126 +This layer is the display interface of our sensors. In this interface, we need to create a dashboard based on the data we want from our sensors, or import the dashboard of the basic sensors, download the modules, and import them into the third level dashboard
127 +
128 +Addres:[[https:~~/~~/github.com/ThingsEye-io/te-platform/tree/main/Devices/Dragino>>https://github.com/ThingsEye-io/te-platform/tree/main/Devices/Dragino]]
129 +
130 +4.1.2.1.1 Import dashboard widget
131 +
132 +Step1.Open a blank dashboard and click on "Add widget" in the upper right corner
133 +
134 +[[image:1731315784538-942.png||height="777" width="1435"]]
135 +
136 +Step2.Import the widgets you want as shown in the following figure
137 +
138 +[[image:1731315965141-491.png||height="740" width="1432"]]
139 +
140 +==== 4.1.2.2、Configure the interface of the second layer asset ====
141 +
142 +===== 4.1.2.2.1 Equipment distribution diagram: =====
143 +
144 +**Data:**
145 +
146 +[[image:1730770392454-317.png||height="745" width="1439"]]
147 +
148 +**Appearannce:**In this module, we need to arrange our devices in the corresponding positions and use icons to display our devices. Therefore, in the Appearance interface, we need to configure them
149 +
150 +**Tooltip function:**This module displays the current information of the device
151 +
152 +[[image:1730857537965-184.png]]
153 +
154 +{{code language="none"}}
155 +var msg = data
156 +if(msg.Label=="gateway" && msg.type == "gateway"){
157 + var stauts
158 + if (msg.gatewaystauts=="true"){
159 + stauts = "Connect"
160 + }
161 + else{
162 + stauts = "Disconnected"
163 + }
164 + var str = "<b>"+msg.entityName+"</b><br/><b>"+stauts+"</b><br/>"
165 + return str
166 +}
167 +else if(msg.type=="gxhl01" && msg.Label!="gateway"){
168 + var str = "<b>"+msg.entityName+"</b><br/><b>"+msg.Label+"</b><br/><b>Bat:</b>"+msg.BatV+"V<br/><b>Temperature:</b>"+ msg.TempC_SHT+ "°C<br/><b>Humidity:</b>"+msg.Hum_SHT+"%"
169 + return str
170 +}
171 +else{
172 + var str = "<b>"+msg.entityName+"</b><br/><b>"+msg.Label+"</b><br/><b>Bat:</b>"+msg.BatV+"V<br/><b>Temperature:</b>"+ msg.temperature+ "°C<br/><b>Humidity:"+msg.humidity+"%"+"</b><br/>"+
173 + "<b>Co2:"+msg.co2+"</b></br><b>Air_Pressure:"+msg.air_pressure
174 +
175 + return str
176 +}
177 +{{/code}}
178 +
179 +(% class="wikigeneratedid" id="HMarkerimagefunctionFF1A" %)
180 +**Marker image function:**This module can display different icons based on different types of sensors and their status to achieve its functionality
181 +
182 +(% class="wikigeneratedid" %)
183 +[[image:1730857750749-240.png]]
184 +
185 +{{code language="none"}}
186 +var res
187 +var msg = data
188 +if(msg.Label=="gateway" && msg.type=="gateway"){
189 + if (msg.gatewaystauts == "true"){
190 + res = {
191 + url: images[3],
192 + size: 40
193 +}
194 +}
195 +else{
196 + res = {
197 + url: images[2],
198 + size: 40
199 +}
200 +}}
201 +else if(msg.Label!="gateway" && msg.type=="gxhl01" ){
202 + if (msg.active=="false"){
203 + res = {
204 + url: images[1],
205 + size: 40
206 +}}
207 +else{
208 + res = {
209 + url: images[0],
210 + size: 40
211 +}
212 +}
213 +}
214 +else if(msg.type=="LWL02"){
215 + if (msg.WATER_LEAK_STATUS=="0"){
216 + res = {
217 + url: images[6],
218 + size: 40
219 +}}
220 +else{
221 + res = {
222 + url: images[7],
223 + size: 40
224 +}
225 +}
226 +}
227 +else if(msg.type=="LDS02"){
228 + if (msg.DOOR_OPEN_STATUS=="0"){
229 + res = {
230 + url: images[5],
231 + size: 40
232 +}}
233 +else{
234 + res = {
235 + url: images[8],
236 + size: 40
237 +}
238 +}
239 +}
240 +else if(msg.type=="LDS12"){
241 + res = {
242 + url: images[10],
243 + size: 40
244 +}}
245 +else if(msg.type=="SE01"){
246 + res = {
247 + url: images[9],
248 + size: 40
249 +}}
250 +else if(msg.type=="PB01"){
251 + res = {
252 + url: images[11],
253 + size: 40
254 +}}
255 +else if(msg.type=="S31b"){
256 + res = {
257 + url: images[12],
258 + size: 40
259 +}}
260 +else if(msg.type=="LHT65N"){
261 + res = {
262 + url: images[13],
263 + size: 40
264 +}}
265 +else{
266 + res = {
267 + url: images[4],
268 + size: 40
269 +}
270 +}
271 +return res;
272 +{{/code}}
273 +
274 +(% class="wikigeneratedid" %)
275 +[[image:1730770875793-351.png||height="799" width="1474"]]
276 +
277 +(% class="wikigeneratedid" %)
278 +**Actions:**We need to implement the function of entering the details interface through the corresponding device icon, so in this module, we need to add actions to achieve redirection
279 +
280 +{{code language="none"}}
281 +var entitySubType;
282 +var $injector = widgetContext.$scope.$injector;
283 +$injector.get(widgetContext.servicesMap.get('entityService')).getEntity(entityId.entityType, entityId.id)
284 + .subscribe(function(data) {
285 + entitySubType = data.type;
286 + console.log(entitySubType)
287 + if (entitySubType == 'gateway') {
288 + openDashboardStates('gateway_detail');
289 + } else if (entitySubType == 'gxhl01') {
290 + openDashboardStates('detail');
291 + }
292 + else if(entitySubType == 'AQS01-dragino-office'){
293 + openDashboardStates("aqs01_detail")
294 + }
295 + else if (entitySubType == 'LDS12') {
296 + openDashboardStates('lds12_detail');
297 + }
298 + else if (entitySubType == 'LDS02') {
299 + openDashboardStates('lds02_detail');
300 + }
301 + else if (entitySubType == 'SE01') {
302 + openDashboardStates('se01_detail');
303 + }
304 + else if (entitySubType == 'PB01') {
305 + openDashboardStates('pb01_detail');
306 + }
307 + else if (entitySubType == 'LWL02') {
308 + openDashboardStates('lwl02_detail');
309 + }
310 + else if (entitySubType == 'LPS8N') {
311 + openDashboardStates('lps8n_detail');
312 + }
313 + else if (entitySubType == 'LHT65N') {
314 + openDashboardStates('lht65n_detail');
315 + }
316 + else if (entitySubType == 'S31b') {
317 + openDashboardStates('s31b_detail');
318 + }
319 + });
320 +
321 +function openDashboardStates(statedId) {
322 + var stateParams = widgetContext.stateController.getStateParams();
323 + var params = {
324 + entityId: entityId,
325 + entityName: entityName
326 + };
327 +
328 + if (stateParams.city) {
329 + params.city = stateParams.city;
330 + }
331 +
332 + widgetContext.stateController.openState(statedId, params, false);
333 +}
334 +
335 +{{/code}}
336 +
337 +[[image:1730771103096-522.png||height="815" width="1503"]]
338 +
339 +===== 4.1.2.2.2 Device List =====
340 +
341 +(% class="wikigeneratedid" id="HDataFF1A" %)
342 +**Data:**
343 +
344 +[[image:1730771199343-553.png||height="802" width="1501"]]
345 +
346 +**Actions:**Equipment distribution diagram: In this module, functions need to be implemented such as adding devices, editing devices, deleting devices, and jumping to the device details page. Therefore, the following actions need to be added:
347 +
348 +[[image:1730771228766-212.png]]
349 +
350 +(% class="wikigeneratedid" id="HEditdeviceFF1A" %)
351 +**Edit device:**Implementation function: Device editing
352 +
353 +[[image:1730771256045-238.png]]
354 +
355 +{{code language="none"}}
356 +let $injector = widgetContext.$scope.$injector;
357 +let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));
358 +let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));
359 +let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));
360 +
361 +openEditDeviceDialog();
362 +
363 +function openEditDeviceDialog() {
364 + customDialog.customDialog(htmlTemplate, EditDeviceDialogController).subscribe();
365 +}
366 +
367 +function EditDeviceDialogController(instance) {
368 + let vm = instance;
369 +
370 + vm.device = null;
371 + vm.attributes = {};
372 +
373 + vm.editDeviceFormGroup = vm.fb.group({
374 + deviceName: ['', [vm.validators.required]],
375 + deviceType: ['', [vm.validators.required]],
376 + deviceLabel: [''],
377 + attributes: vm.fb.group({
378 + latitude: [null],
379 + longitude: [null]
380 + })
381 + });
382 +
383 + vm.cancel = function() {
384 + vm.dialogRef.close(null);
385 + };
386 +
387 + vm.save = function() {
388 + vm.editDeviceFormGroup.markAsPristine();
389 + if (vm.editDeviceFormGroup.get('deviceType').value !== vm.device.type) {
390 + delete vm.device.deviceProfileId;
391 + }
392 + vm.device.name = vm.editDeviceFormGroup.get('deviceName').value,
393 + vm.device.type = vm.editDeviceFormGroup.get('deviceType').value,
394 + vm.device.label = vm.editDeviceFormGroup.get('deviceLabel').value
395 + deviceService.saveDevice(vm.device).subscribe(
396 + function () {
397 + saveAttributes().subscribe(
398 + function () {
399 + widgetContext.updateAliases();
400 + vm.dialogRef.close(null);
401 + }
402 + );
403 + }
404 + );
405 + };
406 +
407 + getEntityInfo();
408 +
409 + function getEntityInfo() {
410 + deviceService.getDevice(entityId.id).subscribe(
411 + function (device) {
412 + attributeService.getEntityAttributes(entityId, 'SERVER_SCOPE',
413 + ['latitude', 'longitude']).subscribe(
414 + function (attributes) {
415 + for (let i = 0; i < attributes.length; i++) {
416 + vm.attributes[attributes[i].key] = attributes[i].value;
417 + }
418 + vm.device = device;
419 + vm.editDeviceFormGroup.patchValue(
420 + {
421 + deviceName: vm.device.name,
422 + deviceType: vm.device.type,
423 + deviceLabel: vm.device.label,
424 + attributes: {
425 + latitude: vm.attributes.latitude,
426 + longitude: vm.attributes.longitude
427 + }
428 + }, {emitEvent: false}
429 + );
430 + }
431 + );
432 + }
433 + );
434 + }
435 +
436 + function saveAttributes() {
437 + let attributes = vm.editDeviceFormGroup.get('attributes').value;
438 + let attributesArray = [];
439 + for (let key in attributes) {
440 + attributesArray.push({key: key, value: attributes[key]});
441 + }
442 + if (attributesArray.length > 0) {
443 + return attributeService.saveEntityAttributes(entityId, 'SERVER_SCOPE', attributesArray);
444 + } else {
445 + return widgetContext.rxjs.of([]);
446 + }
447 + }
448 +}
449 +{{/code}}
450 +
451 +**Delete device:**Implementation function: Device deletion
452 +
453 +[[image:1730771318657-502.png]]
454 +
455 +{{code language="none"}}
456 +let $injector = widgetContext.$scope.$injector;
457 +let dialogs = $injector.get(widgetContext.servicesMap.get('dialogs'));
458 +let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));
459 +
460 +openDeleteDeviceDialog();
461 +
462 +function openDeleteDeviceDialog() {
463 + let title = "Are you sure you want to delete the device " + entityName + "?";
464 + let content = "Be careful, after the confirmation, the device and all related data will become unrecoverable!";
465 + dialogs.confirm(title, content, 'Cancel', 'Delete').subscribe(
466 + function (result) {
467 + if (result) {
468 + deleteDevice();
469 + }
470 + }
471 + );
472 +}
473 +
474 +function deleteDevice() {
475 + deviceService.deleteDevice(entityId.id).subscribe(
476 + function () {
477 + widgetContext.updateAliases();
478 + }
479 + );
480 +}
481 +
482 +{{/code}}
483 +
484 +**jump:I**mplementation function: Jump to the device details page
485 +
486 +[[image:1730771386258-676.png]]
487 +
488 +{{code language="none"}}
489 +console.log(entityName)
490 +var entitySubType;
491 +var $injector = widgetContext.$scope.$injector;
492 +//console.log($injector)
493 +$injector.get(widgetContext.servicesMap.get('entityService')).getEntity(entityId.entityType, entityId.id)
494 + .subscribe(function(data) {
495 + console.log(data)
496 + entitySubType = data.type;
497 + console.log(entitySubType)
498 + if (entitySubType == 'AQS01-dragino-office') {
499 + openDashboardStates('aqs01_detail');
500 + }else if (entitySubType == 'gateway') {
501 + openDashboardStates('gateway_detail');
502 + } else if (entitySubType == 'gxhl01') {
503 + openDashboardStates('detail');
504 +
505 + } else if (entitySubType == 'tank-type1') {
506 + openDashboardStates('test1');
507 + }
508 + else if (entitySubType == 'LDS12') {
509 + openDashboardStates('lds12_detail');
510 + }
511 + else if (entitySubType == 'LDS02') {
512 + openDashboardStates('lds02_detail');
513 + }
514 + else if (entitySubType == 'SE01') {
515 + openDashboardStates('se01_detail');
516 + }
517 + else if (entitySubType == 'PB01') {
518 + openDashboardStates('pb01_detail');
519 + }
520 + else if (entitySubType == 'LWL02') {
521 + openDashboardStates('lwl02_detail');
522 + }
523 + else if (entitySubType == 'LPS8N') {
524 + openDashboardStates('lps8n_detail');
525 + }
526 + else if (entitySubType == 'LHT65N') {
527 + openDashboardStates('lht65n_detail');
528 + }
529 + else if (entitySubType == 'S31b') {
530 + openDashboardStates('s31b_detail');
531 + }
532 + });
533 +
534 +function openDashboardStates(statedId) {
535 + var stateParams = widgetContext.stateController.getStateParams();
536 + //console.log(stateParams)
537 + var params = {
538 + entityId: entityId,
539 + entityName: entityName
540 + };
541 + widgetContext.stateController.updateState(statedId, params, false);
542 +}
543 +{{/code}}
544 +
545 +(% class="wikigeneratedid" id="H-1" %)
546 +**Add device:**Implementation function: Add device
547 +
548 +[[image:1730771441589-122.png]]
549 +
550 +{{code language="none"}}
551 +let $injector = widgetContext.$scope.$injector;
552 +let customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));
553 +let deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));
554 +let attributeService = $injector.get(widgetContext.servicesMap.get('attributeService'));
555 +
556 +openAddDeviceDialog();
557 +
558 +function openAddDeviceDialog() {
559 + customDialog.customDialog(htmlTemplate, AddDeviceDialogController).subscribe();
560 +}
561 +
562 +function AddDeviceDialogController(instance) {
563 + let vm = instance;
564 +
565 + vm.addDeviceFormGroup = vm.fb.group({
566 + deviceName: ['', [vm.validators.required]],
567 + deviceType: ['', [vm.validators.required]],
568 + deviceLabel: [''],
569 + attributes: vm.fb.group({
570 + latitude: [null],
571 + longitude: [null]
572 + })
573 + });
574 +
575 + vm.cancel = function() {
576 + vm.dialogRef.close(null);
577 + };
578 +
579 + vm.save = function() {
580 + vm.addDeviceFormGroup.markAsPristine();
581 + let device = {
582 + name: vm.addDeviceFormGroup.get('deviceName').value,
583 + type: vm.addDeviceFormGroup.get('deviceType').value,
584 + label: vm.addDeviceFormGroup.get('deviceLabel').value
585 + };
586 + deviceService.saveDevice(device).subscribe(
587 + function (device) {
588 + saveAttributes(device.id).subscribe(
589 + function () {
590 + widgetContext.updateAliases();
591 + vm.dialogRef.close(null);
592 + }
593 + );
594 + }
595 + );
596 + };
597 +
598 + function saveAttributes(entityId) {
599 + let attributes = vm.addDeviceFormGroup.get('attributes').value;
600 + let attributesArray = [];
601 + for (let key in attributes) {
602 + attributesArray.push({key: key, value: attributes[key]});
603 + }
604 + if (attributesArray.length > 0) {
605 + return attributeService.saveEntityAttributes(entityId, "SERVER_SCOPE", attributesArray);
606 + } else {
607 + return widgetContext.rxjs.of([]);
608 + }
609 + }
610 +}
611 +{{/code}}
612 +
613 +===== 4.1.2.2.3 Asset Alarm: =====
614 +
615 +**Data:**
616 +
617 +[[image:1730771504586-433.png||height="762" width="1431"]]
618 +
619 +==== (% id="cke_bm_373849S" style="display:none" %) (%%)4.1.2.3、Configure the first layer menu interface ====
620 +
621 +===== 4.1.2.3.1 Map: =====
622 +
623 +**Data:**
624 +
625 +[[image:1730710271230-716.png||height="729" width="1427"]]
626 +
627 +**Actions**:The map interface has two actions, among which Select supermarket can refresh the device list and related alarms on the right side to enter the location, and Supermarket_detail can jump to the second level physical interface to view the details of the location based on the selected location
628 +
629 +[[image:1730710850458-781.png||height="770" width="1429"]]
630 +
631 +**Select supermarket:**Implementation function: Refresh the side page
632 +
633 +{{code language="none"}}
634 +var params = widgetContext.stateController.getStateParams();
635 +var selectedSupermarket = params['selectedSupermarket'];
636 +if (selectedSupermarket && selectedSupermarket.entityId.id === entityId.id) {
637 + params['selectedSupermarket'] = null;
638 +} else {
639 + params['selectedSupermarket'] = { entityId: entityId, entityName: entityName, entityLabel: entityLabel };
640 +}
641 +widgetContext.stateController.updateState(null, params);
642 +{{/code}}
643 +
644 +[[image:1730710875401-848.png||height="767" width="1429"]]
645 +
646 +**Supermarket_detail:**Implementation function: Jump to the asset details page
647 +
648 +{{code language="none"}}
649 +var params = JSON.parse(JSON.stringify(widgetContext.stateController.getStateParams()));
650 +params['selectedSupermarket'] = {
651 + entityId: entityId,
652 + entityName: entityName,
653 + entityLabel: entityLabel,
654 +};
655 +params['targetEntityParamName'] = 'selectedSupermarket';
656 +params['selectedDevice'] = null;
657 +
658 +widgetContext.stateController.openState('svgmap', params);
659 +{{/code}}
660 +
661 +[[image:1730710990334-601.png||height="772" width="1433"]]
662 +
663 +* (((
664 +In this demo, exclusive map icons were set as follows:
665 +)))
666 +
667 +{{code language="none"}}
668 +var res = {
669 + url: images[0],
670 + size: 66
671 +};
672 +return res;
673 +{{/code}}
674 +
675 +[[image:1730710395303-672.png||height="771" width="1438"]]
676 +
677 +===== 4.1.2.3.2 Asset List: =====
678 +
679 +**Data:**
680 +
681 +[[image:1730710693066-349.png||height="772" width="1439"]]
682 +
683 +**Actions:**The Assets List interface has an action, which is the same as the Supermarket_details in the Map. You can jump to the second level entity interface to view the details of the selected location based on its location
684 +
685 +[[image:1730712335338-750.png||height="751" width="1423"]]
686 +
687 +[[image:1730712473941-913.png||height="781" width="1422"]]
688 +
689 +===== 4.1.2.3.3 All Alarms: =====
690 +
691 +[[image:1730712539209-554.png||height="764" width="1424"]]
692 +
102 102  == 4.2 Alarm configuration details ==
103 103  
695 +=== 4.2.1 High temperature ===
696 +
697 +Creat:
698 +
699 +[[image:1730862483514-101.png||height="750" width="1407"]]
700 +
701 +Clear:
702 +
703 +[[image:1730862584519-902.png||height="758" width="1404"]]
704 +
705 +=== 4.2.2 Low Temperature ===
706 +
707 +Creat:
708 +
709 +[[image:1730863708259-750.png||height="752" width="1403"]]
710 +
711 +Clear:
712 +
713 +[[image:1730863750414-979.png||height="746" width="1403"]]
714 +
715 +=== 4.2.3 High humidity ===
716 +
717 +Creat:
718 +
719 +[[image:1730864045747-876.png||height="752" width="1396"]]
720 +
721 +Clear:
722 +
723 +[[image:1730864077395-395.png||height="735" width="1393"]]
724 +
725 +=== 4.2.4 Low humidity ===
726 +
727 +Creat:
728 +
729 +[[image:1730864117808-484.png||height="741" width="1392"]]
730 +
731 +Clear:
732 +
733 +[[image:1730864159071-895.png||height="745" width="1392"]]
734 +
735 +=== 4.2.5 Low voltage ===
736 +
737 +Creat:
738 +
739 +[[image:1730864207037-477.png||height="740" width="1388"]]
740 +
741 +Clear:
742 +
743 +[[image:1730864250506-111.png||height="735" width="1389"]]
744 +
745 +=== 4.2.6 Device Disconnected ===
746 +
747 +Creat:
748 +
749 +[[image:1730864293216-991.png||height="739" width="1387"]]
750 +
751 +Clear:
752 +
753 +[[image:1730864331859-740.png||height="735" width="1385"]]
754 +
104 104  == 4.3 Rule chain configuration details ==
105 105  
106 -= 5. =
757 +[[image:1730864784118-474.png]]
758 +
759 +**Script:**Email configuration for sending device alarm information
760 +
761 +[[image:1730864676542-406.png||height="732" width="1384"]]
762 +
763 +{{code language="none"}}
764 +function locatime(timenumber){
765 + var date = new Date(timenumber)
766 + return date.toLocaleDateString() + ' ' + date.toLocaleTimeString()
767 +}
768 +var name = msg.name
769 +var devicename = msg.originatorName
770 +var label = msg.originatorLabel
771 +var status = msg.status
772 +var detaildata =JSON.parse(msg.details.data)
773 +var tempswitch
774 +
775 +if (name != "Device Disconnected") {
776 + //detaildata=JSON.parse(msg.details.data)
777 + if (detaildata.Temperature_alarm_switch == true) {
778 + tempswitch = "open"
779 + } else {
780 + tempswitch = "close"
781 + }
782 + var humswitch
783 + if (detaildata.Humidity_alarm_switch == true) {
784 + humswitch = "open"
785 + } else {
786 + humswitch = "close"
787 + }
788 + var batswitch
789 + if (detaildata.Voltage_alarm_switch == true) {
790 + batswitch = "open"
791 + } else {
792 + batswitch = "close"
793 + }
794 + var str2 = "<p>-- Temperature alarm switch status: " +
795 + tempswitch + "</p>" +
796 + "<p>-- Humidity alarm switch status: " + humswitch +
797 + "</p>" +
798 + "<p>-- Voltage alarm switch status: " + batswitch
799 +}
800 +
801 +if (name == "High Temperature" && status ==
802 + "ACTIVE_UNACK") {
803 + var emailstr =
804 + "<div><p><span style='color: black; font-weight: bold'>" +
805 + "Device " + label + " has alarm:</span></p>" +
806 + "<p><span style='color: red; font-weight: bold'>-- High Temperature Alarm</span></p>" +
807 + "<p>-- Current Temperature : " + detaildata
808 + .TempC_SHT + "</p><br>" +
809 + "<p>Device Configure:</p>" +
810 + "<p>-- Temperature Threshold : min: " + detaildata
811 + .Low_temperature_alarm + ", max: " + detaildata
812 + .High_temperature_alarm + "</p>" +
813 + "<p>-- Humidity Threshold: min: " + detaildata
814 + .Low_humidity_alarm + ", max:" + detaildata
815 + .High_humidity_alarm + "</p>" +
816 + "<p>-- Battery threshold: min: " + detaildata
817 + .Low_voltage_alarm + "</p>" + str2 + "</div>"
818 + return {
819 + msg: {
820 + "data": emailstr
821 + },
822 + metadata: metadata,
823 + msgType: msgType
824 + };
825 +} else if (name == "Low Temperature" && status ==
826 + "ACTIVE_UNACK") {
827 + var emailstr =
828 + "<div><p><span style='color: black; font-weight: bold'>" +
829 + "Device " + label + " has alarm:</span></p>" +
830 + "<p><span style='color: red; font-weight: bold'>-- Low Temperature Alarm</span></p>" +
831 + "<p>-- Current Temperature : " + detaildata
832 + .TempC_SHT + "</p><br>" +
833 + "<p>Device Configure:</p>" +
834 + "<p>-- Temperature Threshold : min: " + detaildata
835 + .Low_temperature_alarm + ", max: " + detaildata
836 + .High_temperature_alarm + "</p>" +
837 + "<p>-- Humidity Threshold: min: " + detaildata
838 + .Low_humidity_alarm + ", max:" + detaildata
839 + .High_humidity_alarm + "</p>" +
840 + "<p>-- Battery threshold: min: " + detaildata
841 + .Low_voltage_alarm + "</p>" + str2 + "</div>"
842 +
843 + return {
844 + msg: {
845 + "data": emailstr
846 + },
847 + metadata: metadata,
848 + msgType: msgType
849 + };
850 +
851 +} else if (name == "Device Disconnected" && status ==
852 + "ACTIVE_UNACK") {
853 + var time1 = locatime(Number(detaildata.lastActivityTime))
854 + //var time1 = detaildata.lastActivityTime
855 + // var chazhi = parseInt((detaildata.inactivityAlarmTime-detaildata.lastActivityTime)/1000/60)
856 + // var emailstr =
857 + // "<div><p><span style='color: red; font-weight: bold'>" +
858 + // "Device " + label + " has Alarm</span></p><p>Last activity time: "+time1+"</p><p>Last Uplink: 21"+"minutes ago</p></div>"
859 +
860 + var emailstr ="Device " + label + " has Alarm##Last activity time: "+time1+"##Last Uplink: 21minutes ago"
861 + var newType = "POST_TELEMETRY_REQUEST"
862 + return {
863 + msg:emailstr,
864 + metadata: metadata,
865 + msgType: newType
866 + }
867 +} else if (name == "High humidity" && status ==
868 + "ACTIVE_UNACK") {
869 + var emailstr =
870 + "<div><p><span style='color: black; font-weight: bold'>" +
871 + "Device " + label + " has alarm:</span></p>" +
872 + "<p><span style='color: red; font-weight: bold'>-- High Humidity Alarm</span></p>" +
873 + "<p>-- Current Temperature : " + detaildata
874 + .Hum_SHT + "</p><br>" +
875 + "<p>Device Configure:</p>" +
876 + "<p>-- Temperature Threshold : min: " + detaildata
877 + .Low_temperature_alarm + ", max: " + detaildata
878 + .High_temperature_alarm + "</p>" +
879 + "<p>-- Humidity Threshold: min: " + detaildata
880 + .Low_humidity_alarm + ", max:" + detaildata
881 + .High_humidity_alarm + "</p>" +
882 + "<p>-- Battery threshold: min: " + detaildata
883 + .Low_voltage_alarm + "</p>" + str2 + "</div>"
884 +
885 + return {
886 + msg: {
887 + "data": emailstr
888 + },
889 + metadata: metadata,
890 + msgType: msgType
891 + };
892 +} else if (name == "Low humidity" && status ==
893 + "ACTIVE_UNACK") {
894 + var emailstr =
895 + "<div><p><span style='color: black; font-weight: bold'>" +
896 + "Device " + label + " has alarm:</span></p>" +
897 + "<p><span style='color: red; font-weight: bold'>-- Low Humidity Alarm</span></p>" +
898 + "<p>-- Current Temperature : " + detaildata
899 + .Hum_SHT + "</p><br>" +
900 + "<p>Device Configure:</p>" +
901 + "<p>-- Temperature Threshold : min: " + detaildata
902 + .Low_temperature_alarm + ", max: " + detaildata
903 + .High_temperature_alarm + "</p>" +
904 + "<p>-- Humidity Threshold: min: " + detaildata
905 + .Low_humidity_alarm + ", max:" + detaildata
906 + .High_humidity_alarm + "</p>" +
907 + "<p>-- Battery threshold: min: " + detaildata
908 + .Low_voltage_alarm + "</p>" + str2 + "</div>"
909 +
910 + return {
911 + msg: {
912 + "data": emailstr
913 + },
914 + metadata: metadata,
915 + msgType: msgType
916 + };
917 +} else if (name == "Low voltage" && status ==
918 + "ACTIVE_UNACK") {
919 + var emailstr =
920 + "<div><p><span style='color: black; font-weight: bold'>" +
921 + "Device " + label + " has alarm:</span></p>" +
922 + "<p><span style='color: red; font-weight: bold'>-- Low Voltage Alarm</span></p>" +
923 + "<p>-- Current Temperature : " + detaildata.BatV +
924 + "</p><br>" +
925 + "<p>Device Configure:</p>" +
926 + "<p>-- Temperature Threshold : min: " + detaildata
927 + .Low_temperature_alarm + ", max: " + detaildata
928 + .High_temperature_alarm + "</p>" +
929 + "<p>-- Humidity Threshold: min: " + detaildata
930 + .Low_humidity_alarm + ", max:" + detaildata
931 + .High_humidity_alarm + "</p>" +
932 + "<p>-- Battery threshold: min: " + detaildata
933 + .Low_voltage_alarm + "</p>" + str2 + "</div>"
934 +
935 + return {
936 + msg: {
937 + "data": emailstr
938 + },
939 + metadata: metadata,
940 + msgType: msgType
941 + };
942 +} else if (name == "High Temperature" && status ==
943 + "CLEARED_UNACK") {
944 + var emailstr =
945 + "<div><p><span style='color: green; font-weight: bold'>Device " +
946 + label +
947 + " High Temperature Alarm Cleared</span></p>" +
948 + "<p>-- Current Temperature : " + detaildata
949 + .TempC_SHT + "</p><br>" +
950 + "<p>Device Configure:</p>" +
951 + "<p>-- Temperature Threshold : min: " + detaildata
952 + .Low_temperature_alarm + ", max: " + detaildata
953 + .High_temperature_alarm + "</p>" +
954 + "<p>-- Humidity Threshold: min: " + detaildata
955 + .Low_humidity_alarm + ", max:" + detaildata
956 + .High_humidity_alarm + "</p>" +
957 + "<p>-- Battery threshold: min: " + detaildata
958 + .Low_voltage_alarm + "</p>" + str2 + "</div>"
959 +
960 + return {
961 + msg: {
962 + "data": emailstr
963 + },
964 + metadata: metadata,
965 + msgType: msgType
966 + };
967 +} else if (name == "Low Temperature" && status ==
968 + "CLEARED_UNACK") {
969 + var emailstr =
970 + "<div><p><span style='color: green; font-weight: bold'>Device " +
971 + label +
972 + " Low Temperature Alarm Cleared</span></p>" +
973 + "<p>-- Current Temperature : " + detaildata
974 + .TempC_SHT + "</p><br>" +
975 + "<p>Device Configure:</p>" +
976 + "<p>-- Temperature Threshold : min: " + detaildata
977 + .Low_temperature_alarm + ", max: " + detaildata
978 + .High_temperature_alarm + "</p>" +
979 + "<p>-- Humidity Threshold: min: " + detaildata
980 + .Low_humidity_alarm + ", max:" + detaildata
981 + .High_humidity_alarm + "</p>" +
982 + "<p>-- Battery threshold: min: " + detaildata
983 + .Low_voltage_alarm + "</p>" + str2 + "</div>"
984 +
985 + return {
986 + msg: {
987 + "data": emailstr
988 + },
989 + metadata: metadata,
990 + msgType: msgType
991 + };
992 +} else if (name == "High humidity" && status ==
993 + "CLEARED_UNACK") {
994 + var emailstr =
995 + "<div><p><span style='color: green; font-weight: bold'>Device " +
996 + label + " High Humidity Alarm Cleared</span></p>" +
997 + "<p>-- Current Temperature : " + detaildata
998 + .Hum_SHT + "</p><br>" +
999 + "<p>Device Configure:</p>" +
1000 + "<p>-- Temperature Threshold : min: " + detaildata
1001 + .Low_temperature_alarm + ", max: " + detaildata
1002 + .High_temperature_alarm + "</p>" +
1003 + "<p>-- Humidity Threshold: min: " + detaildata
1004 + .Low_humidity_alarm + ", max:" + detaildata
1005 + .High_humidity_alarm + "</p>" +
1006 + "<p>-- Battery threshold: min: " + detaildata
1007 + .Low_voltage_alarm + "</p>" + str2 + "</div>"
1008 +
1009 + return {
1010 + msg: {
1011 + "data": emailstr
1012 + },
1013 + metadata: metadata,
1014 + msgType: msgType
1015 + };
1016 +} else if (name == "Low humidity" && status ==
1017 + "CLEARED_UNACK") {
1018 + var emailstr =
1019 + "<div><p><span style='color: green; font-weight: bold'>Device " +
1020 + label + " Low Humidity Alarm Cleared</span></p>" +
1021 + "<p>-- Current Temperature : " + detaildata
1022 + .Hum_SHT + "</p><br>" +
1023 + "<p>Device Configure:</p>" +
1024 + "<p>-- Temperature Threshold : min: " + detaildata
1025 + .Low_temperature_alarm + ", max: " + detaildata
1026 + .High_temperature_alarm + "</p>" +
1027 + "<p>-- Humidity Threshold: min: " + detaildata
1028 + .Low_humidity_alarm + ", max:" + detaildata
1029 + .High_humidity_alarm + "</p>" +
1030 + "<p>-- Battery threshold: min: " + detaildata
1031 + .Low_voltage_alarm + "</p>" + str2 + "</div>"
1032 + return {
1033 + msg: {
1034 + "data": emailstr
1035 + },
1036 + metadata: metadata,
1037 + msgType: msgType
1038 + };
1039 +} else if (name == "Low voltage" && status ==
1040 + "CLEARED_UNACK") {
1041 +
1042 + var emailstr =
1043 + "<div><p><span style='color: green; font-weight: bold'>Device " +
1044 + label + " Low Voltage Alarm Cleared</span></p>" +
1045 + "<p>-- Current Temperature : " + detaildata.BatV +
1046 + "</p><br><br>" +
1047 + "<p>Device Configure:</p>" +
1048 + "<p>-- Temperature Threshold : min: " + detaildata
1049 + .Low_temperature_alarm + ", max: " + detaildata
1050 + .High_temperature_alarm + "</p>" +
1051 + "<p>-- Humidity Threshold: min: " + detaildata
1052 + .Low_humidity_alarm + ", max:" + detaildata
1053 + .High_humidity_alarm + "</p>" +
1054 + "<p>-- Battery threshold: min: " + detaildata
1055 + .Low_voltage_alarm + "</p>" + str2 + "</div>"
1056 +
1057 + return {
1058 + msg: {
1059 + "data": emailstr
1060 + },
1061 + metadata: metadata,
1062 + msgType: msgType
1063 + };
1064 +} else if (name == "Device Disconnected" && status ==
1065 + "CLEARED_UNACK") {
1066 + var time1 = locatime(Number(detaildata.lastActivityTime))
1067 + //var time1 = detaildata.lastActivityTime
1068 + // var chazhi = parseInt((detaildata.inactivityAlarmTime-detaildata.lastActivityTime)/1000/60)
1069 + // var emailstr =
1070 + // "<div><p><span style='color: green; font-weight: bold'>" +
1071 + // "Device " + label + " has Alarm Cleared</span></p><p>Last activity time: "+time1+"</p></div>"
1072 + var emailstr ="Device " + label + " has Alarm Cleared##Last activity time: "+time1
1073 + var newType = "POST_TELEMETRY_REQUEST"
1074 + return {
1075 + msg: emailstr,
1076 + metadata: metadata,
1077 + msgType: newType
1078 + }
1079 +}
1080 +{{/code}}
1081 +
1082 +(% class="wikigeneratedid" %)
1083 +**Generate Report:**
1084 +
1085 +(% class="wikigeneratedid" %)
1086 +[[image:1730865053380-293.png]]
1087 +
1088 += 5.other =
1089 +
1090 +* If you want to create a similar dashboard, after understanding the case, you can download and import the dashboard, device profiles, rule chains, etc. of the case on GitHub, and make modifications based on them.
1091 +* GitHub address:[[https:~~/~~/github.com/ThingsEye-io/te-platform/tree/main/case/Dragino%20Office%20%26%20Factory>>https://github.com/ThingsEye-io/te-platform/tree/main/case/Dragino%20Office%20%26%20Factory]]
1730709382428-730.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +480.8 KB
Content
1730709409941-536.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +451.5 KB
Content
1730709424998-915.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +443.4 KB
Content
1730709442773-502.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +448.3 KB
Content
1730709461297-207.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +458.2 KB
Content
1730709479828-595.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +450.7 KB
Content
1730709511861-439.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +470.0 KB
Content
1730709527720-418.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +475.8 KB
Content
1730709542597-321.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +474.8 KB
Content
1730709555797-383.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +463.2 KB
Content
1730710271230-716.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +1.5 MB
Content
1730710395303-672.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +1.6 MB
Content
1730710693066-349.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +94.4 KB
Content
1730710850458-781.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +1.5 MB
Content
1730710875401-848.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +1.0 MB
Content
1730710949358-671.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +1.0 MB
Content
1730710990334-601.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +1.0 MB
Content
1730712335338-750.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +77.1 KB
Content
1730712473941-913.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +135.9 KB
Content
1730712539209-554.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +131.0 KB
Content
1730770392454-317.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +195.6 KB
Content
1730770636230-829.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +290.6 KB
Content
1730770875793-351.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +305.2 KB
Content
1730771103096-522.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +197.9 KB
Content
1730771199343-553.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +108.5 KB
Content
1730771228766-212.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +46.8 KB
Content
1730771256045-238.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +69.1 KB
Content
1730771318657-502.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +60.4 KB
Content
1730771386258-676.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +46.4 KB
Content
1730771441589-122.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +57.6 KB
Content
1730771504586-433.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +151.2 KB
Content
1730857191863-514.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +354.7 KB
Content
1730857537965-184.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +455.1 KB
Content
1730857750749-240.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +285.9 KB
Content
1730862483514-101.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +195.8 KB
Content
1730862584519-902.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +191.1 KB
Content
1730863708259-750.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +220.1 KB
Content
1730863750414-979.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +210.6 KB
Content
1730864045747-876.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +208.9 KB
Content
1730864077395-395.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +201.4 KB
Content
1730864117808-484.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +203.0 KB
Content
1730864159071-895.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +226.6 KB
Content
1730864207037-477.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +215.3 KB
Content
1730864250506-111.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +209.5 KB
Content
1730864293216-991.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +138.5 KB
Content
1730864331859-740.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +134.4 KB
Content
1730864460314-611.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +256.7 KB
Content
1730864617480-221.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +260.8 KB
Content
1730864676542-406.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +227.7 KB
Content
1730864784118-474.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +148.8 KB
Content
1730865053380-293.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +46.7 KB
Content
1731315784538-942.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +50.2 KB
Content
1731315965141-491.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +447.8 KB
Content
屏幕截图 2024-11-04 135045.png
Author
... ... @@ -1,0 +1,1 @@
1 +XWiki.hera
Size
... ... @@ -1,0 +1,1 @@
1 +29.4 KB
Content