Compare commits
705 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c53573857 | |||
| c8644f320a | |||
| 8b6348e77e | |||
| 48555dd793 | |||
| 02617bbb86 | |||
| e4a8f1e8d3 | |||
| 48ce6e6342 | |||
| 7f0564a3ca | |||
| aa9c8c21b7 | |||
| 0924c20e9e | |||
| a239223361 | |||
| 444663def3 | |||
| e0341356c8 | |||
| b56c753063 | |||
| 04741d8a77 | |||
| 3721e4a515 | |||
| 0afd9edd7b | |||
| 44d2ba6b41 | |||
| d567186240 | |||
| cbb81add56 | |||
| c8dded35f5 | |||
| d5dac7a9b3 | |||
| 1a183322ab | |||
| 7e401621c7 | |||
| 1485eba2b3 | |||
| e908f73857 | |||
| f587f2b689 | |||
| 12eb41fcad | |||
| 4a2b3f6a94 | |||
| 8e9dd79002 | |||
| ea2f9c6748 | |||
| 4af2178225 | |||
| cc451f53cc | |||
| 419b8e373f | |||
| ffd2b611d3 | |||
| e05fa1c26b | |||
| 98d431fac0 | |||
| c1fb4e3488 | |||
| 3239728b0d | |||
| 8941e827c1 | |||
| d2eb180381 | |||
| 01a55781dd | |||
| c2e8aaae06 | |||
| 594fc9da13 | |||
| 721bab177b | |||
| 6b7828a944 | |||
| c388474952 | |||
| 75db0a3c13 | |||
| 802d6f7d3a | |||
| 830e93d9d1 | |||
| 09c46a282b | |||
| 50693075f9 | |||
| 9d22f80c0e | |||
| 41a7991255 | |||
| 623ff914bf | |||
| 99dc8d7996 | |||
| e30416e910 | |||
| 72a9ded776 | |||
| dfbbcdedf1 | |||
| 1bcbfa953d | |||
| 282e435217 | |||
| 23d45cfa2f | |||
| da4049bf77 | |||
| 73ccc68220 | |||
| 25f36a54dd | |||
| 0bfba093fd | |||
| 5e0b14c8e0 | |||
| df6e05c8c0 | |||
| 36c72e27a6 | |||
| a141535fc9 | |||
| 50a2254d44 | |||
| 3aaefa6529 | |||
| 74d8fdb077 | |||
| 5b655b2cd0 | |||
| 8e7f0ecb71 | |||
| c8aae625e5 | |||
| a1bb7517f7 | |||
| fc65108051 | |||
| ff0be97176 | |||
| 6cdd0f772e | |||
| b61f51cab2 | |||
| b00649f03e | |||
| 755525dc28 | |||
| 91929c0a34 | |||
| 389040a98a | |||
| 2908f2c510 | |||
| 08c732ace8 | |||
| 73fbaf92ab | |||
| 80d8bdf7f9 | |||
| 40c09de1dd | |||
| 1541a57b1b | |||
| 2f5ef791e4 | |||
| cc64f62335 | |||
| 66c19ab51b | |||
| fa7b51143b | |||
| 7c300a4ce2 | |||
| e6a9a3fbd6 | |||
| f523c189dc | |||
| bc86b2f541 | |||
| 5ea023df43 | |||
| ebf912a971 | |||
| d440dfbe39 | |||
| 8257a30118 | |||
| 68cec7d482 | |||
| e61d4340a7 | |||
| 810e8c46e9 | |||
| 1c32850990 | |||
| 21bb7440f1 | |||
| 505a2a9e03 | |||
| f6a6c4101d | |||
| c4fc506f9f | |||
| 3a8315339a | |||
| 08b3904cb9 | |||
| b2ba658e6e | |||
| 76a16cae1a | |||
| 04d564afd8 | |||
| 9c42c05621 | |||
| 42925bec2d | |||
| 5be30fc910 | |||
| c26a72749e | |||
| ca41619338 | |||
| 4e119b5eaf | |||
| 468c5a2567 | |||
| 70651f55c0 | |||
| 02aff9f02c | |||
| c1dbf93d65 | |||
| 6effc08904 | |||
| f237efc430 | |||
| ab15129100 | |||
| 38f440ea67 | |||
| 6c9fb2e513 | |||
| 92e8c15308 | |||
| 7c6a05ecc4 | |||
| f63fca5fc4 | |||
| b59262643f | |||
| 2650ba10fb | |||
| 578578a312 | |||
| 6e700e7201 | |||
| 99ef7bfe04 | |||
| 0d88866001 | |||
| 0150eebb0c | |||
| f885812258 | |||
| 21f5c75836 | |||
| bf20a50107 | |||
| d72e59bb81 | |||
| 69058bd0f0 | |||
| 6639560dd4 | |||
| 3ed4253b13 | |||
| c6555cb4f3 | |||
| 62d4b634c2 | |||
| a8e2ec509e | |||
| 5c35bff99f | |||
| 2e76071ea6 | |||
| ce9cac1f02 | |||
| feb9c84488 | |||
| ac0aef6109 | |||
| 1b424bcfd2 | |||
| 05b33bd9bf | |||
| 62424e3438 | |||
| 16799a85bd | |||
| 7f295cc86e | |||
| 5651cb68a5 | |||
| 80e1841776 | |||
| af337bdde6 | |||
| 9e59da8fd1 | |||
| df2815eb0e | |||
| 70750de23d | |||
| 89f45520d3 | |||
| 8b08cd899b | |||
| e808352244 | |||
| 4e777fff1b | |||
| 3e9db25dad | |||
| 033088ddde | |||
| 47712e5ff1 | |||
| 5e883ef672 | |||
| a7591860cf | |||
| 68510b3c42 | |||
| 1f102c3816 | |||
| 1b1ee5f58a | |||
| a20f24c45f | |||
| e29e0caee6 | |||
| 715f1ef1d0 | |||
| 537b668d1e | |||
| a658203c0a | |||
| 63e00b91f6 | |||
| cc7e2adc81 | |||
| 98738bcb10 | |||
| e34605c488 | |||
| 887ebc0907 | |||
| 91e4acbcb0 | |||
| 4bb59d5c87 | |||
| ed3d8a81ff | |||
| 87c9cba03c | |||
| 1a08d7ff28 | |||
| 641b001b88 | |||
| aeb265b206 | |||
| 932b8c8025 | |||
| f040150ac3 | |||
| 956f84476f | |||
| c028d14ade | |||
| 5108c7ffd9 | |||
| 33f78b0f83 | |||
| c12ded4834 | |||
| ad3553a68e | |||
| 6608ee9e86 | |||
| 2388e82c5d | |||
| 72d87712b3 | |||
| 2e1c3237f4 | |||
| dec21dfee0 | |||
| 7bde032cf6 | |||
| f83ad1efbf | |||
| b04d9ff29e | |||
| 86e3cee7ec | |||
| 6a96620549 | |||
| 1d5813c8fa | |||
| b717bf8906 | |||
| de8fbc9bbe | |||
| 403be30139 | |||
| c307735dc3 | |||
| f88e28616e | |||
| a102567dea | |||
| 46017134d8 | |||
| e2298a6ccc | |||
| 5a61e24495 | |||
| c4007b7930 | |||
| 2fe1cd6e00 | |||
| 4cc7b9e12f | |||
| 8b4f210f95 | |||
| 1af50d0bfc | |||
| 99b2b9dfce | |||
| 1004c7075e | |||
| 8f4cbc0eeb | |||
| f741a2d018 | |||
| 008897830d | |||
| 5c297687f1 | |||
| 213caf9796 | |||
| 0fda2141dd | |||
| 3761493ec1 | |||
| 87300e7a43 | |||
| 85103f5f12 | |||
| 1059a98c27 | |||
| 8150afc624 | |||
| b0de357d89 | |||
| 44c1a41d99 | |||
| a6a9b64da2 | |||
| a4ccee71a8 | |||
| 2cbdab696c | |||
| 3fe5e4af0c | |||
| 577cf09951 | |||
| 0c18ce1829 | |||
| 7c336d4bd3 | |||
| 95955e23e0 | |||
| d387f83f87 | |||
| 0e1695bb4e | |||
| fba42100d8 | |||
| acd1b300d7 | |||
| 3f4d5de662 | |||
| 56f4f0274c | |||
| e6aeb9203d | |||
| da7581de63 | |||
| 6d9294775d | |||
| 3a7d685d31 | |||
| 16df8514ba | |||
| a5085cbbe6 | |||
| 1fbf8c0022 | |||
| 0f5cbaf778 | |||
| 2b5b42dd61 | |||
| 4221a35f00 | |||
| c3fc287b0f | |||
| 047a72e9c6 | |||
| b79a4a2091 | |||
| 4a8be436ce | |||
| 102d39b4b5 | |||
| e8479f80ca | |||
| 3aa5db1455 | |||
| 2e33ef7abb | |||
| 78ec2fd492 | |||
| d12084324a | |||
| b3580bfa76 | |||
| 5b57e40575 | |||
| 14679182df | |||
| db0111d1db | |||
| 21cb382a1f | |||
| 1d8ef94ec6 | |||
| e49b6fb791 | |||
| 52e3d70dc8 | |||
| a33bbd0581 | |||
| cd97260230 | |||
| b9242764ab | |||
| e8d75b9877 | |||
| 433e567e74 | |||
| fbbebb3423 | |||
| 6f2aab5276 | |||
| d82b1cb735 | |||
| 8aa87d587f | |||
| 38503e198e | |||
| 8b78cdcdbd | |||
| 94feff568a | |||
| 06336bbd61 | |||
| 33b041a31b | |||
| 14dda58fac | |||
| f9bf41980b | |||
| 6b20902c74 | |||
| ced0362910 | |||
| 467016140f | |||
| f6e642cd5f | |||
| 7c5aed4dbc | |||
| c069354415 | |||
| 738b58fded | |||
| f7c89585ac | |||
| 36ed59816d | |||
| 516d20333c | |||
| 74b8472c1d | |||
| ecb9e02610 | |||
| 74dea74476 | |||
| 588a791bc1 | |||
| cd3e6f08f5 | |||
| 1370e5659e | |||
| e18fa916b5 | |||
| b5a920338a | |||
| 6c4660966c | |||
| 0db13d3404 | |||
| 8b96a7308c | |||
| d7e69e250e | |||
| 14217aa1ea | |||
| 506080c518 | |||
| 794b71cc9f | |||
| 7e355448e0 | |||
| 1bcf0d99e9 | |||
| af094ad93a | |||
| 062023bd95 | |||
| fcef23b199 | |||
| 56051c881a | |||
| 9bc027b445 | |||
| 06528addc7 | |||
| 279a1056f4 | |||
| 0ef305c434 | |||
| 2161b37932 | |||
| 6b63b2b406 | |||
| ccdc193067 | |||
| 2ba4644a78 | |||
| 72dbb2abf5 | |||
| 7f498c01ed | |||
| d9f7813a3c | |||
| 35c436ee67 | |||
| 2f82138097 | |||
| e4d2186d86 | |||
| 749fd86c65 | |||
| 95bb4afa49 | |||
| 6c5c832fde | |||
| 256070ae76 | |||
| 7edde3d7b2 | |||
| 8ba6bcb8cb | |||
| 1398ffad4c | |||
| e82d17ab4f | |||
| d116c9951a | |||
| d3e02ee4db | |||
| 2f9cd9fae0 | |||
| cfca599408 | |||
| fecbd4e4da | |||
| 08fcba3f58 | |||
| e4da226a03 | |||
| b68471eff6 | |||
| 5cf83f18c4 | |||
| 11f4793a7a | |||
| 7d615e0e53 | |||
| 589727142c | |||
| 230fb4f8a4 | |||
| 058057dca4 | |||
| 9a13720f04 | |||
| d7fd0426bd | |||
| 5addbef71c | |||
| 9f988edd63 | |||
| e5ff49333d | |||
| 2b70a54a07 | |||
| 9b64a5484e | |||
| e6dcb0d389 | |||
| 8a2f001f28 | |||
| 4fa122c754 | |||
| 1ebfa0b343 | |||
| 076f8111eb | |||
| dd895bb177 | |||
| e3b9a00071 | |||
| 8697e94aa7 | |||
| e786ce437d | |||
| 8b841a8524 | |||
| fabeca30b6 | |||
| 23a430d7e4 | |||
| 979918b31b | |||
| cee179b1f7 | |||
| 758aac1909 | |||
| f7a487d316 | |||
| cf648fe862 | |||
| d3610b3430 | |||
| 5a8147476c | |||
| 9ced5cfcc8 | |||
| b1dd6d1750 | |||
| b27fb72401 | |||
| 2fc79e9e27 | |||
| ac520b5451 | |||
| 6022d01c51 | |||
| 38395fb579 | |||
| 2138e1eafc | |||
| 120553f8c0 | |||
| 054a8a6382 | |||
| e50f2b5efc | |||
| c780fd7a57 | |||
| bd298b73bc | |||
| c3e2f7f6e5 | |||
| 311f89df15 | |||
| b2465c70bc | |||
| 9ec3ee46e6 | |||
| 1a5bd6da85 | |||
| 0915c28917 | |||
| c8c1abc2a5 | |||
| 37e07ec0ed | |||
| 86440bfaba | |||
| 4855ca30d9 | |||
| dc4ae8fb1f | |||
| 9a7d00645d | |||
| ef77084297 | |||
| 5ee2d796cb | |||
| 6689d64b0d | |||
| fe5f52472b | |||
| dd5a8bfe27 | |||
| ac889e5410 | |||
| 9584d751fe | |||
| fd31d41bdb | |||
| 9087f6776b | |||
| 2cdd14d97d | |||
| fca7f1a093 | |||
| e63e40caad | |||
| 68bf3cda73 | |||
| fed196a0da | |||
| 557629fb8c | |||
| 60f4e0fd10 | |||
| c72a55fd5a | |||
| da242910f6 | |||
| 3e62775857 | |||
| 2723d4dbb1 | |||
| f2b828b8af | |||
| 0954c8a778 | |||
| 61616dead0 | |||
| e9c339450f | |||
| 5ef75b972f | |||
| dccc30df3d | |||
| 90f78d2c24 | |||
| 94c265da5d | |||
| df52ad3ff9 | |||
| 341035f8c4 | |||
| 25740a6c82 | |||
| c378dc5749 | |||
| 85be4bb558 | |||
| 7f18bd4672 | |||
| a88833bf87 | |||
| 30b4d3c76b | |||
| 74c58b131f | |||
| 266a227b47 | |||
| 86f965a445 | |||
| 18fa86820d | |||
| c29dded14f | |||
| b72977b35f | |||
| 7391e0a5a0 | |||
| e1a0d996ad | |||
| 2ba5fb2683 | |||
| 671b8ad668 | |||
| 0de6d455a0 | |||
| 9d4836ee28 | |||
| d49dbfda43 | |||
| 73edf21824 | |||
| 486fc067ea | |||
| ad404819b3 | |||
| 8732386d45 | |||
| bed8e72340 | |||
| 67a397c27d | |||
| 51dfcfd335 | |||
| 49896d3465 | |||
| f05581dcf9 | |||
| ed526604b9 | |||
| 94e6e1153f | |||
| 5a4c91e5bc | |||
| 7ea36c565e | |||
| bc38b1bcc8 | |||
| fe6622b86c | |||
| b12332eaac | |||
| 8267dbd302 | |||
| 5653c4d3de | |||
| 227d61d8e4 | |||
| 94b0a795e4 | |||
| d09405755f | |||
| 9c83b6e4f8 | |||
| 38bd091d44 | |||
| 4bf2e529c0 | |||
| 0803b2b8ab | |||
| c6436b205d | |||
| 0796621f3b | |||
| af87e9b122 | |||
| 184ce1af5f | |||
| 2dced2922a | |||
| fd06ce3018 | |||
| 6a4db3512e | |||
| 24d1ac3438 | |||
| 7749d33105 | |||
| 7dd8d5eb77 | |||
| 2d0c865e13 | |||
| a6300e8e40 | |||
| e45ef9d8de | |||
| e6ef637c97 | |||
| 49cf46fe44 | |||
| c7add6f7da | |||
| 4c562e720a | |||
| 05e55d4dbf | |||
| f24f5f6636 | |||
| 6441e5d2ec | |||
| c75089f10e | |||
| d28538cebe | |||
| 5cb9924e7d | |||
| eab9ee944a | |||
| 076469e270 | |||
| 950c5dcc55 | |||
| 0831873136 | |||
| d9700b96d3 | |||
| 7234692e67 | |||
| ca12e1858c | |||
| fae9308bed | |||
| 6b1fee3f5f | |||
| 5834172d96 | |||
| 598fe285bf | |||
| 0580a15e25 | |||
| dece25f2ff | |||
| 2e58d1d9f6 | |||
| 6fe57af6bd | |||
| 35b5c7681b | |||
| bd0517c8d1 | |||
| fd08f45278 | |||
| f0a06f0370 | |||
| 4001bb8f58 | |||
| fc9140115b | |||
| 18800cc142 | |||
| f3aeb8931f | |||
| 6543dc07fa | |||
| 841a2f1f85 | |||
| 805a582b5d | |||
| 6e3548eca0 | |||
| b676987f29 | |||
| 74aba10199 | |||
| 23f0130564 | |||
| 69b2d8b3bd | |||
| 55e7f9b857 | |||
| a4fe50898a | |||
| b290093ad9 | |||
| 675aa7001c | |||
| e9d343461a | |||
| 987a840923 | |||
| f0c811e402 | |||
| 8e87c4492e | |||
| 1e39d25cff | |||
| ff855de99a | |||
| 3a2ae1703f | |||
| 56421aca14 | |||
| 50ae46a8f2 | |||
| 33dd3c6cc8 | |||
| cd52ca351c | |||
| debe6acd73 | |||
| fa4539efc6 | |||
| 3086b2781d | |||
| e05893d606 | |||
| 487d830cd0 | |||
| 7b2d2a7375 | |||
| af3b3fd18f | |||
| cdac8ed871 | |||
| e0bdf00e81 | |||
| b716058f91 | |||
| af405c951f | |||
| adee49335c | |||
| 725413dbe3 | |||
| 890d0aa888 | |||
| 7788bde9be | |||
| 22afaf746f | |||
| 01ed8df633 | |||
| 03662d8762 | |||
| 6e811fafef | |||
| 4ed1b45eb1 | |||
| 2329d9f40f | |||
| 7b832fa5b2 | |||
| 11233ffbf6 | |||
| 53492b5373 | |||
| 1c36aae2ff | |||
| c501485ecd | |||
| d2cd90b593 | |||
| 92dc397d39 | |||
| 483bc7e2c9 | |||
| 4ebe429130 | |||
| 7dabbac852 | |||
| f62e8d6d5b | |||
| 2efa3c50f3 | |||
| 58308232d7 | |||
| 88a41d1376 | |||
| b851476ec1 | |||
| b11dff070f | |||
| 0ae7dd57c9 | |||
| 1d78071615 | |||
| 5a1fd1d769 | |||
| 7d838b591a | |||
| 5fae7722d9 | |||
| 392302e297 | |||
| 77519a2898 | |||
| c9278a96c6 | |||
| c5a02ab3de | |||
| 9f41788605 | |||
| 3d69393be7 | |||
| ef3c656ded | |||
| 15f442207d | |||
| 49509301ab | |||
| 870cc6117d | |||
| d9ad286f02 | |||
| b084ce762d | |||
| ea534a230b | |||
| 20df0040fc | |||
| 818009ad78 | |||
| 2130d43a78 | |||
| 036d09fa90 | |||
| 5e24f2775a | |||
| 189e9b4507 | |||
| 17317f90a0 | |||
| 8efa76b789 | |||
| d4ff7e7d70 | |||
| 64a3c7a788 | |||
| 78ba7af72c | |||
| b589ad8e18 | |||
| b487ec2c32 | |||
| 6215e6faea | |||
| f4a1fcedb8 | |||
| 9f20d040f7 | |||
| b3ff304882 | |||
| 09b6504b6a | |||
| 45c8021203 | |||
| 2cf7a95ed9 | |||
| 78f38d0e1a | |||
| f3d890fe69 | |||
| 5ff367ba26 | |||
| 3a24f1c3d0 | |||
| ae9f34bcc5 | |||
| 8d5ad18726 | |||
| 16b2ac54c7 | |||
| 2fd311fac1 | |||
| 0872253ceb | |||
| 588b863c5e | |||
| 4a0f6e4c8f | |||
| 42a6cc7222 | |||
| 468208697f | |||
| 046821b7d3 | |||
| af5a31289b | |||
| 3978815f9c | |||
| d376a8399b | |||
| 9a5d1a9007 | |||
| 1a03ca4fee | |||
| c09d79a6f5 | |||
| 33b9ce8f01 | |||
| b004434bf9 | |||
| ecc977cb73 | |||
| 7c372c35f9 | |||
| d58941fa41 | |||
| 56ac5630d0 | |||
| 230cc98dab | |||
| eb734aa645 | |||
| 3173e349fb | |||
| 7bb8378762 | |||
| b4c9e04075 | |||
| 4fab05da44 | |||
| ba11499d80 | |||
| 2a09132a16 | |||
| 08061eb23e | |||
| 4c3f36010c | |||
| 700cb94dd5 | |||
| a91e4862c8 | |||
| 8efb8d4dc0 | |||
| 96f8a9ad96 | |||
| 9cba5e2d0e | |||
| b0a3f51cd0 | |||
| a5c7133b84 | |||
| 97889af002 | |||
| 37159bad12 | |||
| 49859eae05 | |||
| 84557194e4 | |||
| 1ad639e2a0 | |||
| 952b04ffe2 | |||
| 9705b2045c | |||
| 419b3d323f | |||
| becedd0fa7 | |||
| 1578a72dee | |||
| 504eee4d73 | |||
| 02a811ecfb | |||
| ab6d52e50b | |||
| 6c96b40e4b | |||
| e28271249c | |||
| 1751af9c31 | |||
| 4b599e06ca | |||
| 750a466707 | |||
| 06c2e70cb7 | |||
| e1da25b549 | |||
| b28dbc6e27 | |||
| e951426d7a | |||
| cb86d14144 | |||
| f6df94228c |
@@ -1168,6 +1168,16 @@
|
||||
"minimist": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"@fontsource/source-code-pro": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/source-code-pro/-/source-code-pro-4.5.0.tgz",
|
||||
"integrity": "sha512-IKB+oQfwjj9DzEM2sc5rO70BZV7+ksmZbB+1KzyiZp2VroPw7Lm1ovXBU2JYWIWXmNY+gDudvyZXZHE+6cG47Q=="
|
||||
},
|
||||
"@fontsource/source-sans-pro": {
|
||||
"version": "4.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/source-sans-pro/-/source-sans-pro-4.5.1.tgz",
|
||||
"integrity": "sha512-JYEldSfnqxoDVUL6QgqT8Fiyjh0p7WlKcqKNevzDylpWabdejVRyFzPhTk2ZceKZd02KEOaL+K462U6u0/PQiA=="
|
||||
},
|
||||
"@hapi/address": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
|
||||
@@ -3012,11 +3022,18 @@
|
||||
"dev": true
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
|
||||
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"requires": {
|
||||
"follow-redirects": "1.5.10"
|
||||
"follow-redirects": "^1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"follow-redirects": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
|
||||
"integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-code-frame": {
|
||||
@@ -3465,9 +3482,9 @@
|
||||
}
|
||||
},
|
||||
"bl": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
||||
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz",
|
||||
"integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==",
|
||||
"requires": {
|
||||
"readable-stream": "^2.3.5",
|
||||
"safe-buffer": "^5.1.1"
|
||||
@@ -5114,9 +5131,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"copy-webpack-plugin": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz",
|
||||
"integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz",
|
||||
"integrity": "sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cacache": "^12.0.3",
|
||||
@@ -5129,7 +5146,7 @@
|
||||
"normalize-path": "^3.0.0",
|
||||
"p-limit": "^2.2.1",
|
||||
"schema-utils": "^1.0.0",
|
||||
"serialize-javascript": "^2.1.2",
|
||||
"serialize-javascript": "^4.0.0",
|
||||
"webpack-log": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -5180,10 +5197,13 @@
|
||||
}
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
|
||||
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
|
||||
"dev": true
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
|
||||
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"randombytes": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"slash": {
|
||||
"version": "1.0.0",
|
||||
@@ -5643,6 +5663,7 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
@@ -6248,24 +6269,24 @@
|
||||
}
|
||||
},
|
||||
"elliptic": {
|
||||
"version": "6.5.3",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
|
||||
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
|
||||
"version": "6.5.4",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
|
||||
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bn.js": "^4.4.0",
|
||||
"brorand": "^1.0.1",
|
||||
"bn.js": "^4.11.9",
|
||||
"brorand": "^1.1.0",
|
||||
"hash.js": "^1.0.0",
|
||||
"hmac-drbg": "^1.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"minimalistic-crypto-utils": "^1.0.0"
|
||||
"hmac-drbg": "^1.0.1",
|
||||
"inherits": "^2.0.4",
|
||||
"minimalistic-assert": "^1.0.1",
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@@ -7482,15 +7503,6 @@
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"faye-websocket": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
|
||||
"integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"websocket-driver": ">=0.5.1"
|
||||
}
|
||||
},
|
||||
"fb-watchman": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
|
||||
@@ -7534,6 +7546,11 @@
|
||||
"schema-utils": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"file-saver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
@@ -7691,6 +7708,7 @@
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
||||
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "=3.1.0"
|
||||
}
|
||||
@@ -8478,6 +8496,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"http-parser-js": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz",
|
||||
"integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==",
|
||||
"dev": true
|
||||
},
|
||||
"http-proxy": {
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
|
||||
@@ -8660,9 +8684,9 @@
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"dev": true
|
||||
},
|
||||
"inquirer": {
|
||||
@@ -10926,9 +10950,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"lodash._reinterpolate": {
|
||||
"version": "3.0.0",
|
||||
@@ -11635,6 +11659,14 @@
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz",
|
||||
"integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ=="
|
||||
},
|
||||
"moment-range": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/moment-range/-/moment-range-4.0.2.tgz",
|
||||
"integrity": "sha512-n8sceWwSTjmz++nFHzeNEUsYtDqjgXgcOBzsHi+BoXQU2FW+eU92LUaK8gqOiSu5PG57Q9sYj1Fz4LRDj4FtKA==",
|
||||
"requires": {
|
||||
"es6-symbol": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
@@ -11806,12 +11838,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz",
|
||||
"integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node-gyp": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
|
||||
@@ -12095,6 +12121,11 @@
|
||||
"set-blocking": "~2.0.0"
|
||||
}
|
||||
},
|
||||
"nprogress": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
|
||||
"integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E="
|
||||
},
|
||||
"nth-check": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
|
||||
@@ -14434,15 +14465,6 @@
|
||||
"integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=",
|
||||
"dev": true
|
||||
},
|
||||
"selfsigned": {
|
||||
"version": "1.10.7",
|
||||
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz",
|
||||
"integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"node-forge": "0.9.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
@@ -14846,57 +14868,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sockjs": {
|
||||
"version": "0.3.20",
|
||||
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.20.tgz",
|
||||
"integrity": "sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"faye-websocket": "^0.10.0",
|
||||
"uuid": "^3.4.0",
|
||||
"websocket-driver": "0.6.5"
|
||||
}
|
||||
},
|
||||
"sockjs-client": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz",
|
||||
"integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^3.2.5",
|
||||
"eventsource": "^1.0.7",
|
||||
"faye-websocket": "~0.11.1",
|
||||
"inherits": "^2.0.3",
|
||||
"json3": "^3.3.2",
|
||||
"url-parse": "^1.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"faye-websocket": {
|
||||
"version": "0.11.3",
|
||||
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz",
|
||||
"integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"websocket-driver": ">=0.5.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"sort-keys": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
|
||||
@@ -14906,6 +14877,11 @@
|
||||
"is-plain-obj": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"sortablejs": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.2.tgz",
|
||||
"integrity": "sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A=="
|
||||
},
|
||||
"source-list-map": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
||||
@@ -15218,6 +15194,11 @@
|
||||
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
|
||||
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
|
||||
},
|
||||
"streamsaver": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/streamsaver/-/streamsaver-2.0.5.tgz",
|
||||
"integrity": "sha512-KIWtBvi8A6FiFZGNSyuIZRZM6C8AvnWTiCx/TYa7so420vC5sQwcBKkdqInuGWoWMfeWy/P+/cRqMtWVf4RW9w=="
|
||||
},
|
||||
"strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
@@ -16933,6 +16914,11 @@
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"dev": true
|
||||
},
|
||||
"v-click-outside": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/v-click-outside/-/v-click-outside-2.1.5.tgz",
|
||||
"integrity": "sha512-VPNCOTZK6WZy73lcWc+R7IW1uaBFEO3/Csrs5CzWVOdvE30V8Y1+BE/BtTlcEmeDGx0eqdE7bSCg55Jj37PMJg=="
|
||||
},
|
||||
"v-tooltip": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/v-tooltip/-/v-tooltip-2.0.3.tgz",
|
||||
@@ -17083,6 +17069,17 @@
|
||||
"tinycolor2": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"vue-ctk-date-time-picker": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-ctk-date-time-picker/-/vue-ctk-date-time-picker-2.5.0.tgz",
|
||||
"integrity": "sha512-s4AO+5xnPlX+LD5UPQcjLBnv8MwcEJKlKUnkTLQeXRV0xqpH9pWRe6aJ8N2+506mEN6b7iwhlFox6uKKdtK+gw==",
|
||||
"requires": {
|
||||
"moment": "^2.24.0",
|
||||
"moment-range": "^4.0.1",
|
||||
"v-click-outside": "^2.0.2",
|
||||
"vue": "^2.6.9"
|
||||
}
|
||||
},
|
||||
"vue-echarts": {
|
||||
"version": "5.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-echarts/-/vue-echarts-5.0.0-beta.0.tgz",
|
||||
@@ -17229,6 +17226,11 @@
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.3.4.tgz",
|
||||
"integrity": "sha512-SdKRBeoXUjaZ9R/8AyxsdTqkOfMcI5tWxPZOUX5Ie1BTL5rPSZ0O++pbiZCeYeythiZIdLEfkDiQPKIaWk5hDg=="
|
||||
},
|
||||
"vue-slicksort": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-slicksort/-/vue-slicksort-1.2.0.tgz",
|
||||
"integrity": "sha512-k1324l+AnYy6MrpySN7PYL165z2EkvZmMe+BS7H/EugzS8IrZYRtoqa3QxSSWB34C7cplV1hj3c+7peKpxpYxg=="
|
||||
},
|
||||
"vue-style-loader": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",
|
||||
@@ -17268,6 +17270,11 @@
|
||||
"resolved": "https://registry.npmjs.org/vue-toasted/-/vue-toasted-1.1.28.tgz",
|
||||
"integrity": "sha512-UUzr5LX51UbbiROSGZ49GOgSzFxaMHK6L00JV8fir/CYNJCpIIvNZ5YmS4Qc8Y2+Z/4VVYRpeQL2UO0G800Raw=="
|
||||
},
|
||||
"vue-toastification": {
|
||||
"version": "1.7.14",
|
||||
"resolved": "https://registry.npmjs.org/vue-toastification/-/vue-toastification-1.7.14.tgz",
|
||||
"integrity": "sha512-khZR8t3NWZ/JJ2MZxXLbesHrRJ8AKa75PY5Zq8yMifF9x8lHq8ljYkC0d2PD9yahooygQB5tcFyRDkbbIPx8hw=="
|
||||
},
|
||||
"vue-worker": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-worker/-/vue-worker-1.2.1.tgz",
|
||||
@@ -17281,6 +17288,14 @@
|
||||
"resolved": "https://registry.npmjs.org/vue-yandex-maps/-/vue-yandex-maps-0.9.0.tgz",
|
||||
"integrity": "sha512-6gXec68eXNHvo5d6m43lGCDMShYRpciWWy55VA1RiFtMkLHIDeK4CJzYmkfAec32vpzYEqdcNBJh9b93wqtp8w=="
|
||||
},
|
||||
"vuedraggable": {
|
||||
"version": "2.24.3",
|
||||
"resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.3.tgz",
|
||||
"integrity": "sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==",
|
||||
"requires": {
|
||||
"sortablejs": "1.10.2"
|
||||
}
|
||||
},
|
||||
"vuestic-ui": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/vuestic-ui/-/vuestic-ui-0.2.2.tgz",
|
||||
@@ -17369,6 +17384,11 @@
|
||||
"resolved": "https://registry.npmjs.org/vuex-i18n/-/vuex-i18n-1.13.1.tgz",
|
||||
"integrity": "sha512-VTy5QAyMI6BJwpRfN5qncWQT0ohKiAYK+iTRW4JxgV9dkNoPMuKKDqExbOm1fzpitdrIoIipC3Zqr5fJ706VQg=="
|
||||
},
|
||||
"vuex-map-fields": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/vuex-map-fields/-/vuex-map-fields-1.4.1.tgz",
|
||||
"integrity": "sha512-jvIcpvoIPqwvJCOfRkPU9Rj0EbjWuk7GlNC5LXU9mCXVGZph6bWGHZssnoUzpLMxJtXQEHoVyZkKf7YQV+/bnQ=="
|
||||
},
|
||||
"vuex-router-sync": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vuex-router-sync/-/vuex-router-sync-5.0.0.tgz",
|
||||
@@ -17665,9 +17685,9 @@
|
||||
}
|
||||
},
|
||||
"webpack-dev-server": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz",
|
||||
"integrity": "sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg==",
|
||||
"version": "3.11.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz",
|
||||
"integrity": "sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-html": "0.0.7",
|
||||
@@ -17690,11 +17710,11 @@
|
||||
"p-retry": "^3.0.1",
|
||||
"portfinder": "^1.0.26",
|
||||
"schema-utils": "^1.0.0",
|
||||
"selfsigned": "^1.10.7",
|
||||
"selfsigned": "^1.10.8",
|
||||
"semver": "^6.3.0",
|
||||
"serve-index": "^1.9.1",
|
||||
"sockjs": "0.3.20",
|
||||
"sockjs-client": "1.4.0",
|
||||
"sockjs": "^0.3.21",
|
||||
"sockjs-client": "^1.5.0",
|
||||
"spdy": "^4.0.2",
|
||||
"strip-ansi": "^3.0.1",
|
||||
"supports-color": "^6.1.0",
|
||||
@@ -17759,12 +17779,21 @@
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"faye-websocket": {
|
||||
"version": "0.11.3",
|
||||
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz",
|
||||
"integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"websocket-driver": ">=0.5.1"
|
||||
}
|
||||
},
|
||||
"fsevents": {
|
||||
@@ -17808,6 +17837,12 @@
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
|
||||
"integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==",
|
||||
"dev": true
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
|
||||
@@ -17830,12 +17865,57 @@
|
||||
"ajv-keywords": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"selfsigned": {
|
||||
"version": "1.10.8",
|
||||
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz",
|
||||
"integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"node-forge": "^0.10.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
},
|
||||
"sockjs": {
|
||||
"version": "0.3.21",
|
||||
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz",
|
||||
"integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"faye-websocket": "^0.11.3",
|
||||
"uuid": "^3.4.0",
|
||||
"websocket-driver": "^0.7.4"
|
||||
}
|
||||
},
|
||||
"sockjs-client": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.1.tgz",
|
||||
"integrity": "sha512-VnVAb663fosipI/m6pqRXakEOw7nvd7TUgdr3PlR/8V2I95QIdwT8L4nMxhyU8SmDBHYXU1TOElaKOmKLfYzeQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^3.2.6",
|
||||
"eventsource": "^1.0.7",
|
||||
"faye-websocket": "^0.11.3",
|
||||
"inherits": "^2.0.4",
|
||||
"json3": "^3.3.3",
|
||||
"url-parse": "^1.5.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
@@ -17854,6 +17934,27 @@
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz",
|
||||
"integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"querystringify": "^2.1.1",
|
||||
"requires-port": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"websocket-driver": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
||||
"integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"http-parser-js": ">=0.5.1",
|
||||
"safe-buffer": ">=5.1.0",
|
||||
"websocket-extensions": ">=0.1.1"
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
|
||||
@@ -17902,15 +18003,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"websocket-driver": {
|
||||
"version": "0.6.5",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
|
||||
"integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"websocket-extensions": ">=0.1.1"
|
||||
}
|
||||
},
|
||||
"websocket-extensions": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
|
||||
@@ -18297,9 +18389,9 @@
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
|
||||
@@ -13,12 +13,14 @@
|
||||
"test:unit": "vue-cli-service test:unit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/source-code-pro": "^4.5.0",
|
||||
"@fontsource/source-sans-pro": "^4.5.1",
|
||||
"@types/jest": "^24.0.11",
|
||||
"amcharts3": "^3.21.14",
|
||||
"ammap3": "^3.21.14",
|
||||
"approximate-number": "^2.0.0",
|
||||
"asva-executors": "^0.1.22",
|
||||
"axios": "^0.19.0",
|
||||
"axios": "^0.21.1",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"chart.js": "^2.9.3",
|
||||
"core-js": "3",
|
||||
@@ -27,17 +29,20 @@
|
||||
"element-resize-detector": "^1.1.15",
|
||||
"epic-spinners": "^1.1.0",
|
||||
"extend": "3.0.2",
|
||||
"file-saver": "^2.0.5",
|
||||
"flag-icon-css": "^3.4.5",
|
||||
"font-awesome": "^4.7.0",
|
||||
"google-maps": "^3.3.0",
|
||||
"ionicons": "^4.6.3",
|
||||
"leaflet-map": "^0.2.1",
|
||||
"lodash": "4.17.15",
|
||||
"lodash": "^4.17.21",
|
||||
"medium-editor": "^5.23.3",
|
||||
"normalize.css": "^8.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"popper.js": "^1.16.0",
|
||||
"regenerator-runtime": "^0.13.3",
|
||||
"register-service-worker": "^1.6.2",
|
||||
"streamsaver": "^2.0.5",
|
||||
"v-tooltip": "^2.0.2",
|
||||
"vee-validate": "^2.2.13",
|
||||
"vue": "^2.6.10",
|
||||
@@ -46,17 +51,22 @@
|
||||
"vue-chartjs": "^3.4.0",
|
||||
"vue-clipboard2": "^0.3.1",
|
||||
"vue-color": "^2.7.0",
|
||||
"vue-ctk-date-time-picker": "^2.5.0",
|
||||
"vue-echarts": "^5.0.0-beta.0",
|
||||
"vue-epic-bus": "^0.1.2",
|
||||
"vue-gtm": "^2.2.0",
|
||||
"vue-mqtt": "^2.0.3",
|
||||
"vue-router": "^3.1.3",
|
||||
"vue-slicksort": "^1.2.0",
|
||||
"vue-toastification": "^1.7.14",
|
||||
"vue-worker": "^1.2.1",
|
||||
"vue-yandex-maps": "^0.9.0",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuestic-ui": "~0.2.2",
|
||||
"vuetable-2": "^1.7.5",
|
||||
"vuex": "^3.1.2",
|
||||
"vuex-i18n": "^1.13.1",
|
||||
"vuex-map-fields": "^1.4.1",
|
||||
"vuex-router-sync": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
|
Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 2.5 KiB |
@@ -3,12 +3,9 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:400" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
|
||||
<title>Vuestic Admin</title>
|
||||
<title>BioPro Scientific</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
* This is shell_script dir
|
||||
|
||||
# 檔案說明
|
||||
burn_to_raspberry.sh : 用scp複製local npm build好的東西 & burn_to_raspberry_util.sh 去遠端(raspberry),然後在raspberry內execute 複製過去的burn_to_raspberry_util.sh
|
||||
|
||||
burn_to_raspberry_util.sh : 給burn_to_raspberry.sh用的,裡面的指令為在raspberry內所有要執行的指令
|
||||
|
||||
# Usage
|
||||
burn_to_raspberry.sh
|
||||
```shell
|
||||
sh ./burn_to_raspberry.sh <HOST> <PASSWORD>
|
||||
|
||||
e.g. sh ./burn_to_raspberry.sh pi@192.168.2.1 raspberry
|
||||
```
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
# sshpass: https://shazi.info/ssh-%E7%94%A8-sshpass-%E5%8F%96%E4%BB%A3-expect-%E8%87%AA%E5%8B%95%E8%BC%B8%E5%85%A5%E5%AF%86%E7%A2%BC/
|
||||
|
||||
HOST=$1 # e.g. "pi@192.168.3.53"
|
||||
PASSWORD=$2 # e.g. raspberry
|
||||
SCP_HOST=$HOST":"
|
||||
|
||||
cd ..
|
||||
npm run build
|
||||
sshpass -p $PASSWORD ssh $HOST "rm -rf dist"
|
||||
sshpass -p $PASSWORD scp -r dist $SCP_HOST
|
||||
sshpass -p $PASSWORD scp shell_script/burn_to_raspberry_util.sh $SCP_HOST
|
||||
sshpass -p $PASSWORD ssh $HOST "sh ./burn_to_raspberry_util.sh"
|
||||
# sshpass -p raspberry scp -r dist pi@192.168.3.53:
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
#run in raspberry
|
||||
|
||||
cd
|
||||
sudo rm -rf /var/www/bioprovuebuild/*
|
||||
sudo cp -r dist/* /var/www/bioprovuebuild/
|
||||
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<div id="app" class="app">
|
||||
<router-view />
|
||||
<keep-alive>
|
||||
<router-view v-if="$route.meta.keepAlive"></router-view>
|
||||
</keep-alive>
|
||||
<router-view v-if="!$route.meta.keepAlive"></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ import 'echarts/lib/chart/line'
|
||||
import 'echarts/lib/component/dataZoom'
|
||||
import 'echarts/lib/component/tooltip'
|
||||
import 'echarts/lib/component/legend'
|
||||
import 'echarts/lib/component/legend/ScrollableLegendModel.js'
|
||||
import 'echarts/lib/component/legend/ScrollableLegendView.js'
|
||||
import 'echarts/lib/component/legend/scrollableLegendAction.js'
|
||||
import 'echarts/lib/component/axisPointer'
|
||||
import 'echarts/lib/component/grid'
|
||||
import 'echarts/lib/component/markArea'
|
||||
@@ -28,6 +31,10 @@ import VueWorker from 'vue-worker'
|
||||
|
||||
import axios from 'axios'
|
||||
import VueAxios from 'vue-axios'
|
||||
import 'nprogress/nprogress.css'
|
||||
|
||||
import Toast from 'vue-toastification'
|
||||
import 'vue-toastification/dist/index.css'
|
||||
|
||||
import '../metrics'
|
||||
import '../registerServiceWorker'
|
||||
@@ -48,9 +55,12 @@ Vue.use(VueClipboard)
|
||||
Vue.component('chart', ECharts)
|
||||
Vue.use(VueWorker)
|
||||
Vue.use(VueAxios, axios)
|
||||
Vue.use(Toast)
|
||||
|
||||
Vue.use(VueMqtt, 'ws://52.194.17.114:8083')
|
||||
// Vue.use(VueMqtt, 'ws://' + location.href.split('/')[2] + ':8083')
|
||||
// Vue.use(VueMqtt, 'ws://52.194.17.114:8083')
|
||||
Vue.use(VueMqtt, 'ws://' + location.href.split('/')[2] + ':8083')
|
||||
// Vue.use(VueMqtt, 'ws://' + '192.168.151.125' + ':8083')
|
||||
// Vue.use(VueMqtt, 'ws://' + '192.168.3.211' + ':8083')
|
||||
|
||||
Vue.prototype.GLOBAL = global_
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="sd-card" class="svg-inline--fa fa-sd-card fa-w-12" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="#6c7fee" d="M320 0H128L0 128v320c0 35.3 28.7 64 64 64h256c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64zM160 160h-48V64h48v96zm80 0h-48V64h48v96zm80 0h-48V64h48v96z"></path></svg>
|
||||
|
After Width: | Height: | Size: 380 B |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 201 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 234 KiB |
|
After Width: | Height: | Size: 202 KiB |
@@ -60,7 +60,7 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
isTopBar: false,
|
||||
minimized: false,
|
||||
minimized: true,
|
||||
mobileWidth: 767,
|
||||
}
|
||||
},
|
||||
@@ -87,7 +87,7 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
|
||||
this.minimized = true
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -134,3 +134,9 @@ export default {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang='scss'>
|
||||
// .layout.gutter--xl {
|
||||
// padding: 0.5rem;
|
||||
// }
|
||||
</style>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default {
|
||||
},
|
||||
updateSidebarState () {
|
||||
if (this.checkIsDesktop()) {
|
||||
this.$emit('update:minimized', false)
|
||||
this.$emit('update:minimized', true)
|
||||
} else {
|
||||
this.$emit('update:minimized', true)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
>
|
||||
<!-- *** icon -->
|
||||
<!-- <va-icon-vuestic /> -->
|
||||
<img v-bind:src="'https://www.bioproweb.com/wp-content/uploads/2020/01/BPS-LOGO_60.png'">
|
||||
<img src='@/assets/img/bps_logo.png'>
|
||||
</router-link>
|
||||
</div>
|
||||
<!-- <img style="height: 40px;" v-bind:src="'https://www.bioproweb.com/wp-content/uploads/2020/01/BPS-LOGO_60.png'"> -->
|
||||
@@ -44,15 +44,6 @@
|
||||
contact@bioproweb.com
|
||||
</a>
|
||||
</span>
|
||||
<!-- <va-button
|
||||
href="https://github.com/epicmaxco/vuestic-admin"
|
||||
color="#000000"
|
||||
class="app-navbar__button"
|
||||
icon="fa fa-github"
|
||||
target="_blank"
|
||||
>
|
||||
{{$t('navbar.repository')}}
|
||||
</va-button> -->
|
||||
</div>
|
||||
<app-navbar-actions
|
||||
class="app-navbar__actions md5 lg4"
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
<template>
|
||||
<div class="app-navbar-actions">
|
||||
<!-- <color-dropdown class="app-navbar-actions__item"/> -->
|
||||
<!-- <message-dropdown class="app-navbar-actions__item"/>
|
||||
<notification-dropdown class="app-navbar-actions__item"/> -->
|
||||
<!-- <settings-dropdown
|
||||
<!-- <color-dropdown class="app-navbar-actions__item"/>
|
||||
<message-dropdown class="app-navbar-actions__item"/>
|
||||
<notification-dropdown class="app-navbar-actions__item"/>
|
||||
<settings-dropdown
|
||||
:is-top-bar.sync="isTopBarProxy"
|
||||
class="app-navbar-actions__item"
|
||||
/> -->
|
||||
<!-- <language-dropdown class="app-navbar-actions__item"/> -->
|
||||
/>
|
||||
<language-dropdown class="app-navbar-actions__item"/> -->
|
||||
<license-check-button :ref="'license_check_button_ref'" @updateLicense="updateLicense"/>
|
||||
<license-update-modal :title="'Update'" :ref="'license_update_modal_ref'" @refresh="refresh"/>
|
||||
<profile-dropdown class="app-navbar-actions__item app-navbar-actions__item--profile">
|
||||
<span>{{userName}}</span>
|
||||
</profile-dropdown>
|
||||
@@ -16,11 +18,13 @@
|
||||
|
||||
<script>
|
||||
// import LanguageDropdown from './dropdowns/LanguageDropdown'
|
||||
import ProfileDropdown from './dropdowns/ProfileDropdown'
|
||||
// import NotificationDropdown from './dropdowns/NotificationDropdown'
|
||||
// import MessageDropdown from './dropdowns/MessageDropdown'
|
||||
// import ColorDropdown from './dropdowns/ColorDropdown'
|
||||
// import SettingsDropdown from './dropdowns/SettingsDropdown'
|
||||
import ProfileDropdown from './dropdowns/ProfileDropdown'
|
||||
import LicenseUpdateModal from './modals/LicenseUpdateModal'
|
||||
import LicenseCheckButton from './buttons/LicenseCheckButton'
|
||||
import { ColorThemeMixin } from '../../../../services/vuestic-ui'
|
||||
|
||||
export default {
|
||||
@@ -33,6 +37,8 @@ export default {
|
||||
// MessageDropdown,
|
||||
// NotificationDropdown,
|
||||
// LanguageDropdown,
|
||||
LicenseCheckButton,
|
||||
LicenseUpdateModal,
|
||||
ProfileDropdown,
|
||||
},
|
||||
props: {
|
||||
@@ -55,6 +61,16 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateLicense () {
|
||||
this.$refs.license_update_modal_ref.show()
|
||||
this.$refs.license_update_modal_ref.licenseUpdate()
|
||||
},
|
||||
refresh () {
|
||||
this.$refs.license_check_button_ref.refresh()
|
||||
this.$refs.license_update_modal_ref.hide()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div v-if="!licenseCheck">
|
||||
<va-button color="warning" class="mb-2" @click="licenseUpdateModalShow" small>
|
||||
Update
|
||||
</va-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from '@/data/api/index'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'license-check-button',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('', [
|
||||
'licenseCheck',
|
||||
]),
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
popoverShow: true,
|
||||
licenseCheckObj: {
|
||||
pass: true,
|
||||
outdated: false,
|
||||
fail: false,
|
||||
},
|
||||
authText: {
|
||||
outdated: 'New version released. Update by pressing the button above.',
|
||||
fail: 'System file is missing, contact us by following as: contact@bioproweb.com.',
|
||||
},
|
||||
toastOptions: {
|
||||
theme: 'none',
|
||||
position: 'bottom-center',
|
||||
className: 'vuestic-toast',
|
||||
iconPack: 'fontawesome',
|
||||
duration: 2500,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
licenseUpdateModalShow () {
|
||||
this.$emit('updateLicense')
|
||||
},
|
||||
showNotify (licenseCheckResponse) {
|
||||
this.$toast(this.authText[licenseCheckResponse], {
|
||||
closeButtonClassName: 'my-button-class',
|
||||
containerClassName: 'my-container-class',
|
||||
toastClassName: 'my-custom-toast-class',
|
||||
timeout: false,
|
||||
icon: 'fa fa-exclamation',
|
||||
})
|
||||
},
|
||||
closeNotify () {
|
||||
this.$toast.clear()
|
||||
},
|
||||
async refresh () {
|
||||
this.closeNotify()
|
||||
const licenseCheckResponse = await api.auth.licenseCheck()
|
||||
this.licenseCheck = this.licenseCheckObj[licenseCheckResponse.data]
|
||||
if (this.licenseCheck === false) {
|
||||
this.showNotify(licenseCheckResponse.data)
|
||||
}
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
await this.refresh()
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.Vue-Toastification__toast--default.my-custom-toast-class {
|
||||
background-color: rgba(255, 214, 82, 1);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.Vue-Toastification__container.top-right {
|
||||
top: 3rem !important;
|
||||
}
|
||||
|
||||
.my-button-class {
|
||||
opacity: 1 !important;
|
||||
color: black !important;
|
||||
}
|
||||
|
||||
.custom-toast {
|
||||
background-color: rgba(255, 214, 82, 1) !important;
|
||||
transform: translateX(50px) translateY(-75px) !important;
|
||||
color: black !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<va-modal
|
||||
class="flex sm12 xl12 md12 xs12"
|
||||
v-model="showModal"
|
||||
:title="title"
|
||||
noOutsideDismiss
|
||||
hideDefaultActions
|
||||
>
|
||||
<div v-if="loading" class="row flex sm12 xl12 md12 xs12">
|
||||
<div class="flex-center spinner-box mt-4 mb-5">
|
||||
<fulfilling-bouncing-circle-spinner
|
||||
:animation-duration="3000"
|
||||
:color="'#6c7fee'"
|
||||
:size="60"
|
||||
>
|
||||
</fulfilling-bouncing-circle-spinner>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="row flex sm12 xl12 md12 xs12">
|
||||
{{ modalMessage }}
|
||||
<div class="row flex-center sm12 xl12 md12 xs12 mt-2">
|
||||
<va-button small @click="hide">close</va-button>
|
||||
</div>
|
||||
</div>
|
||||
</va-modal>
|
||||
</template>
|
||||
<script>
|
||||
import api from '@/data/api/index'
|
||||
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
|
||||
|
||||
export default {
|
||||
name: 'license-check-modal',
|
||||
components: {
|
||||
FulfillingBouncingCircleSpinner,
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showModal: false,
|
||||
hideDefaultActions: false,
|
||||
loading: true,
|
||||
modalMessage: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
show () {
|
||||
this.showModal = true
|
||||
},
|
||||
hide () {
|
||||
this.showModal = false
|
||||
},
|
||||
async licenseUpdate () {
|
||||
this.hideDefaultActions = true
|
||||
this.loading = true
|
||||
const updateResponse = await api.auth.licenseUpdate()
|
||||
console.log('updateResponse', updateResponse)
|
||||
setTimeout(() => {
|
||||
if (updateResponse.status === 200) {
|
||||
this.loading = false
|
||||
this.$emit('refresh')
|
||||
} else if (updateResponse.status === 202 || updateResponse.status === 203) {
|
||||
this.loading = false
|
||||
this.modalMessage = 'An unknown error occurred while updating, please contact us by following as: contact@bioproweb.com'
|
||||
}
|
||||
}, 5000)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -96,7 +96,7 @@ export default {
|
||||
theme: 'info',
|
||||
items: navigationRoutes.routes,
|
||||
hoverState: false,
|
||||
minimized: false,
|
||||
minimized: true,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -40,6 +40,13 @@ export const navigationRoutes = {
|
||||
// },
|
||||
// ],
|
||||
},
|
||||
// {
|
||||
// name: 'task-content-g-m',
|
||||
// displayName: 'Gimer',
|
||||
// meta: {
|
||||
// iconClass: 'vuestic-iconset vuestic-iconset-statistics',
|
||||
// },
|
||||
// },
|
||||
{
|
||||
name: 'file',
|
||||
displayName: 'File',
|
||||
@@ -47,6 +54,13 @@ export const navigationRoutes = {
|
||||
iconClass: 'vuestic-iconset vuestic-iconset-files',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'settings',
|
||||
displayName: 'Settings',
|
||||
meta: {
|
||||
iconClass: 'vuestic-iconset vuestic-iconset-settings',
|
||||
},
|
||||
},
|
||||
// {
|
||||
// name: 'forms',
|
||||
// displayName: 'menu.forms',
|
||||
|
||||
@@ -11,12 +11,26 @@
|
||||
:to="to"
|
||||
:target="target"
|
||||
>
|
||||
<va-icon
|
||||
v-if="icon"
|
||||
class="app-sidebar-link__item-icon"
|
||||
:style="computedIconStyles"
|
||||
:name="icon"
|
||||
/>
|
||||
<template v-if="title == 'Gimer'">
|
||||
<img
|
||||
v-if="this.isHovered || this.isActive"
|
||||
class="app-sidebar-link__item-icon"
|
||||
src="@/assets/img/gimer_white.png"
|
||||
>
|
||||
<img
|
||||
v-else
|
||||
class="app-sidebar-link__item-icon"
|
||||
src="@/assets/img/gimer_gray.png"
|
||||
>
|
||||
</template>
|
||||
<template v-else>
|
||||
<va-icon
|
||||
v-if="icon"
|
||||
class="app-sidebar-link__item-icon"
|
||||
:style="computedIconStyles"
|
||||
:name="icon"
|
||||
/>
|
||||
</template>
|
||||
<div class="app-sidebar-link__item-title" v-if="title">
|
||||
<slot>
|
||||
{{title}}
|
||||
@@ -140,6 +154,21 @@ export default {
|
||||
color: 'white',
|
||||
}
|
||||
},
|
||||
computedGimerIcon () {
|
||||
if (this.contextConfig.invertedColor) {
|
||||
if (this.isHovered || this.isActive) {
|
||||
return 'gimer_white.png'
|
||||
}
|
||||
|
||||
return 'gimer_gray.png'
|
||||
}
|
||||
|
||||
if (this.isHovered || this.isActive) {
|
||||
return 'gimer_white.png'
|
||||
}
|
||||
|
||||
return 'gimer_white.png'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateHoverState (isHovered) {
|
||||
|
||||
@@ -1,412 +0,0 @@
|
||||
<template>
|
||||
<div class="devices-overview">
|
||||
|
||||
<div >
|
||||
<replay-chart-detail class="mb-2" :key="overviewChartKey" :cardheight="'5vh'" :data="chartOverviewData"/>
|
||||
<replay-chart-detail @dblclick.native="distribute()" :cardheight="'72vh'" :data="chartDetailData" @dataZoomEvent="dataZoomEvent($event)"/>
|
||||
<!-- <va-button class="mt-2" color="primary" target="_blank" @click="distribute()" small>
|
||||
DISTRIBUTE
|
||||
</va-button> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ReplayChartDetail from './ReplayChartDetail.vue'
|
||||
import api from '../../../data/api/index'
|
||||
import { chartData } from '../../../data/analysis/replay/ChartsManagement'
|
||||
import { download } from '../../../data/download/Download'
|
||||
|
||||
export default {
|
||||
name: 'data-replay',
|
||||
components: {
|
||||
ReplayChartDetail,
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
metaIDList: this.$route.params.metaList.split('-'),
|
||||
metaList: null,
|
||||
dataInfo: {},
|
||||
// dataInfo format:
|
||||
// {
|
||||
// scale: [
|
||||
// {
|
||||
// id: _id,
|
||||
// start_time: _start_time,
|
||||
// end_time: _end_time,
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
overviewChartKey: 0,
|
||||
chartOverviewData: chartData.init(0, 1),
|
||||
chartDetailData: chartData.init(1, 1),
|
||||
maxTime: 0,
|
||||
startTimeCurrent: 0,
|
||||
endTimeCurrent: 0,
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
zoomTime: 0,
|
||||
maxScaleDefault: '1000',
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
getMetaInfo: async function () {
|
||||
const promises = this.metaIDList.map(async id => {
|
||||
const metaRes = await api.getMetaFilesByID(id)
|
||||
return metaRes.data[0]
|
||||
})
|
||||
this.metaList = await Promise.all(promises)
|
||||
},
|
||||
getDataInfo: async function () {
|
||||
this.metaList.forEach(meta => {
|
||||
this.dataInfo[meta.id] = {}
|
||||
JSON.parse(meta.channels).forEach(ch => {
|
||||
this.dataInfo[meta.id][ch] = {
|
||||
1: [],
|
||||
10: [],
|
||||
100: [],
|
||||
1000: [],
|
||||
}
|
||||
})
|
||||
})
|
||||
const getRawInfo = this.metaList.map(async meta => {
|
||||
const getData = JSON.parse(meta.channels).map(async ch => {
|
||||
const res = await api.getRawFilesAttrByParent(ch, meta.id, 'id-start_time-end_time')
|
||||
res.data.forEach(_data => {
|
||||
_data.load = false
|
||||
_data.data = []
|
||||
if (_data.end_time < 0) {
|
||||
_data.end_time = meta.time_duration
|
||||
}
|
||||
this.dataInfo[meta.id][ch][1].push(_data)
|
||||
})
|
||||
return res.data
|
||||
})
|
||||
return await Promise.all(getData)
|
||||
})
|
||||
await Promise.all(getRawInfo)
|
||||
|
||||
const getMiniInfo = this.metaList.map(async meta => {
|
||||
const getData = JSON.parse(meta.channels).map(async ch => {
|
||||
const res = await api.getMiniFilesAttrByParent(ch, meta.id, 'id-start_time-end_time-scale')
|
||||
res.data.forEach(_data => {
|
||||
_data.load = false
|
||||
_data.data = []
|
||||
if (_data.end_time < 0) {
|
||||
_data.end_time = meta.time_duration
|
||||
}
|
||||
this.dataInfo[meta.id][ch][parseInt(_data.scale)].push(_data)
|
||||
})
|
||||
return res.data
|
||||
})
|
||||
return await Promise.all(getData)
|
||||
})
|
||||
await Promise.all(getMiniInfo)
|
||||
},
|
||||
getData: async function (scale, id, channel) {
|
||||
if (scale === 1) {
|
||||
return await download.rawByIDChannels(id, channel)
|
||||
} else {
|
||||
return await download.miniMeanByIDChannel(id, channel)
|
||||
}
|
||||
},
|
||||
register: async function () {
|
||||
let chNumber = 0
|
||||
this.metaList.forEach(meta => {
|
||||
chNumber += JSON.parse(meta.channels).length
|
||||
})
|
||||
chartData.updateGridList(this.chartDetailData.chartID, chNumber)
|
||||
let _chNumber = 0
|
||||
const register = this.metaList.map(meta => {
|
||||
// if (meta.device.library_name.indexOf('Neulive') >= 0) {
|
||||
this.metaList.map(meta => {
|
||||
JSON.parse(meta.channels).map(ch => {
|
||||
chartData.register(this.chartDetailData.chartID, _chNumber, 'Time', 0, 0, 'Neulive', meta.name, ch, null)
|
||||
chartData.register(this.chartOverviewData.chartID, 0, 'Time', 0, 0, 'Neulive', meta.name, ch, null)
|
||||
_chNumber++
|
||||
})
|
||||
})
|
||||
if (this.maxTime < meta.time_duration) {
|
||||
this.maxTime = meta.time_duration
|
||||
this.endTime = this.endTimeCurrent = this.maxTime
|
||||
}
|
||||
// }
|
||||
})
|
||||
await Promise.all(register)
|
||||
this.chartDetailData.series.forEach((series, index) => {
|
||||
this.chartDetailData.xAxis[series.xAxisIndex].min = 0
|
||||
this.chartDetailData.xAxis[series.xAxisIndex].max = this.maxTime
|
||||
})
|
||||
this.chartOverviewData.series.forEach((series, index) => {
|
||||
this.chartOverviewData.xAxis[series.xAxisIndex].min = 0
|
||||
this.chartOverviewData.xAxis[series.xAxisIndex].max = this.maxTime
|
||||
})
|
||||
this.chartDetailData.xAxis[this.chartDetailData.xAxis.length - 1].axisLabel.show = true
|
||||
this.chartOverviewData.dataZoom = null
|
||||
},
|
||||
dataZoomEvent: function (e) {
|
||||
// console.log(e)
|
||||
if (e.batch != null) {
|
||||
// console.log(e.batch)
|
||||
e.batch.forEach(dataZoom => {
|
||||
const id = parseInt(dataZoom.dataZoomId.substr(dataZoom.dataZoomId.length - 3, dataZoom.dataZoomId.length - 1))
|
||||
if (id === 1) {
|
||||
this.startTime = this.maxTime * dataZoom.start / 100
|
||||
this.endTime = this.maxTime * dataZoom.end / 100
|
||||
// console.log(this.startTime, this.endTime)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const id = parseInt(e.dataZoomId.substr(e.dataZoomId.length - 3, e.dataZoomId.length - 1))
|
||||
if (id === 0) {
|
||||
this.startTime = this.maxTime * e.start / 100
|
||||
this.endTime = this.maxTime * e.end / 100
|
||||
// console.log(this.startTime, this.endTime)
|
||||
}
|
||||
}
|
||||
this.chartOverviewData.series.forEach(series => {
|
||||
if (series.markArea != null) {
|
||||
series.markArea.data[0][0].xAxis = parseInt(this.startTime)
|
||||
series.markArea.data[0][1].xAxis = parseInt(this.endTime)
|
||||
} else {
|
||||
const _markArea = {
|
||||
// silent: true,
|
||||
itemStyle: {
|
||||
color: '#ccc',
|
||||
opacity: 0.1,
|
||||
},
|
||||
data: [
|
||||
[{
|
||||
xAxis: parseInt(this.startTime),
|
||||
}, {
|
||||
xAxis: parseInt(this.endTime),
|
||||
}],
|
||||
],
|
||||
}
|
||||
series.markArea = _markArea
|
||||
}
|
||||
})
|
||||
this.overviewChartKey++
|
||||
this.zoomTime = 0
|
||||
},
|
||||
downloadDataAll: async function () {
|
||||
for (const meta in this.dataInfo) {
|
||||
for (const ch in this.dataInfo[meta]) {
|
||||
const scaleList = this.dataInfo[meta][ch]
|
||||
for (const scale in scaleList) {
|
||||
const dataList = this.dataInfo[meta][ch][scale]
|
||||
for (let i = 0; i < dataList.length; i++) {
|
||||
const data = await this.getData(parseInt(scale), dataList[i].id, ch)
|
||||
dataList[i].data = data
|
||||
dataList[i].load = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
drawData: async function () {
|
||||
const timeZone = this.endTimeCurrent - this.startTimeCurrent
|
||||
let maxScale = '-1'
|
||||
for (const meta in this.dataInfo) {
|
||||
for (const ch in this.dataInfo[meta]) {
|
||||
const scaleList = this.dataInfo[meta][ch]
|
||||
let getMetaScale = false
|
||||
for (const scale in scaleList) {
|
||||
const dataList = this.dataInfo[meta][ch][scale]
|
||||
for (let i = 0; i < dataList.length; i++) {
|
||||
const _timeZone = dataList[i].end_time - dataList[i].start_time
|
||||
if (timeZone <= _timeZone) {
|
||||
this.metaList.forEach(_meta => {
|
||||
if (parseInt(_meta.id) === parseInt(meta)) {
|
||||
_meta.scaleCurrent = scale
|
||||
if (parseInt(scale) > parseInt(maxScale)) {
|
||||
maxScale = scale
|
||||
}
|
||||
}
|
||||
})
|
||||
getMetaScale = true
|
||||
}
|
||||
}
|
||||
if (getMetaScale) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parseInt(maxScale) < 0) {
|
||||
maxScale = this.maxScaleDefault
|
||||
}
|
||||
this.metaList.forEach(_meta => {
|
||||
if (_meta.scaleCurrent == null) {
|
||||
_meta.scaleCurrent = maxScale
|
||||
}
|
||||
})
|
||||
// console.log(this.metaList)
|
||||
|
||||
for (const meta in this.dataInfo) {
|
||||
let scale
|
||||
let metaName
|
||||
this.metaList.forEach(_meta => {
|
||||
if (parseInt(_meta.id) === parseInt(meta)) {
|
||||
metaName = _meta.name
|
||||
scale = _meta.scaleCurrent
|
||||
}
|
||||
})
|
||||
for (const ch in this.dataInfo[meta]) {
|
||||
const dataList = this.dataInfo[meta][ch][scale]
|
||||
for (let i = 0; i < dataList.length; i++) {
|
||||
if ((this.startTimeCurrent >= dataList[i].start_time && this.startTimeCurrent <= dataList[i].end_time) || (this.endTimeCurrent >= dataList[i].start_time && this.endTimeCurrent <= dataList[i].end_time)) {
|
||||
if (dataList[i].data.length === 0) {
|
||||
dataList[i].data = await this.getData(parseInt(scale), dataList[i].id, ch)
|
||||
dataList[i].load = true
|
||||
}
|
||||
const data = dataList[i].data
|
||||
|
||||
this.chartOverviewData.series.forEach(series => {
|
||||
if (series.data.length === 0) {
|
||||
if (series.yAxisSource[0] === metaName && series.yAxisSource[1] === parseInt(ch)) {
|
||||
let deStartIndex = 0
|
||||
let deEndIndex = 0
|
||||
series.data.forEach((_data, index) => {
|
||||
if (_data[0] >= data[0][0] && deStartIndex === 0) {
|
||||
deStartIndex = index
|
||||
} else if (_data[0] > data[data.length - 1][0] && deEndIndex === 0) {
|
||||
deEndIndex = index
|
||||
}
|
||||
})
|
||||
if (deEndIndex === 0) {
|
||||
deEndIndex = series.data.length
|
||||
}
|
||||
series.data.splice(deStartIndex, deEndIndex - deStartIndex, ...data)
|
||||
series.data.sort(function (a, b) {
|
||||
return a[0] - b[0]
|
||||
})
|
||||
}
|
||||
const _markArea = {
|
||||
// silent: true,
|
||||
itemStyle: {
|
||||
color: '#ccc',
|
||||
opacity: 0.1,
|
||||
},
|
||||
data: [
|
||||
[{
|
||||
xAxis: parseInt(this.startTime),
|
||||
}, {
|
||||
xAxis: parseInt(this.endTime),
|
||||
}],
|
||||
],
|
||||
}
|
||||
series.markArea = _markArea
|
||||
// console.log(series.data)
|
||||
}
|
||||
})
|
||||
// console.log(this.chartOverviewData)
|
||||
this.chartDetailData.series.forEach(series => {
|
||||
if (series.yAxisSource[0] === metaName && series.yAxisSource[1] === parseInt(ch)) {
|
||||
let deStartIndex = 0
|
||||
let deEndIndex = 0
|
||||
series.data.forEach((_data, index) => {
|
||||
if (_data[0] >= data[0][0] && deStartIndex === 0) {
|
||||
deStartIndex = index
|
||||
} else if (_data[0] > data[data.length - 1][0] && deEndIndex === 0) {
|
||||
deEndIndex = index
|
||||
}
|
||||
})
|
||||
if (deEndIndex === 0) {
|
||||
deEndIndex = series.data.length
|
||||
}
|
||||
series.data.splice(deStartIndex, deEndIndex - deStartIndex, ...data)
|
||||
series.data.sort(function (a, b) {
|
||||
return a[0] - b[0]
|
||||
})
|
||||
// console.log(series.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
checkDataZoom: function () {
|
||||
this.zoomTime++
|
||||
if (this.zoomTime >= 2) {
|
||||
if (this.startTimeCurrent !== this.startTime || this.endTimeCurrent !== this.endTime) {
|
||||
this.startTimeCurrent = this.startTime
|
||||
this.endTimeCurrent = this.endTime
|
||||
this.drawData()
|
||||
}
|
||||
}
|
||||
},
|
||||
distribute: function () {
|
||||
console.log(this.chartDetailData)
|
||||
if (this.chartDetailData.grid.length === 1) {
|
||||
this.chartDetailData.xAxis[0].axisLabel.show = false
|
||||
chartData.updateGridList(this.chartDetailData.chartID, this.chartDetailData.series.length)
|
||||
this.chartDetailData.series.forEach((series, index) => {
|
||||
series.xAxisIndex = index
|
||||
series.yAxisIndex = index
|
||||
})
|
||||
this.chartDetailData.xAxis[this.chartDetailData.xAxis.length - 1].axisLabel.show = true
|
||||
} else {
|
||||
chartData.updateGridList(this.chartDetailData.chartID, 1)
|
||||
this.chartDetailData.series.forEach(series => {
|
||||
series.xAxisIndex = 0
|
||||
series.yAxisIndex = 0
|
||||
})
|
||||
this.chartDetailData.xAxis[0].axisLabel.show = true
|
||||
}
|
||||
console.log(this.chartDetailData)
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
async mounted () {
|
||||
// this.chartOverviewData.legend.show = false
|
||||
// console.log(this.chartOverviewData)
|
||||
// console.log(this.metaIDList)
|
||||
await this.getMetaInfo()
|
||||
console.log(this.metaList)
|
||||
await this.getDataInfo()
|
||||
// console.log(this.dataInfo)
|
||||
await this.register()
|
||||
// await this.downloadDataAll()
|
||||
console.log(this.dataInfo)
|
||||
this.drawData()
|
||||
this.dataZoomTimer = setInterval(this.checkDataZoom, 1000)
|
||||
console.log(this.chartDetailData)
|
||||
},
|
||||
beforeDestroy () {
|
||||
for (const id in chartData.getAllChartsData()) {
|
||||
for (const _series of chartData.getAllChartsData()[id].series) {
|
||||
_series.length = 0
|
||||
}
|
||||
delete chartData.getAllChartsData()[id]
|
||||
}
|
||||
},
|
||||
destroyed () {
|
||||
clearInterval(this.dataZoomTimer)
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.area-style {
|
||||
height: auto;
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
|
||||
@include media-breakpoint-only(xl) {
|
||||
height: 88vh;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,562 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="row row-equal">
|
||||
<div class="flex md12 xl3 xs12 sm12">
|
||||
<div class="row">
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<va-accordion>
|
||||
<va-collapse class="mb-2" :isOpenDefault="true">
|
||||
<span slot="header">Control Panel</span>
|
||||
<div slot="body">
|
||||
<div>
|
||||
<top-control-panel :ref="'top_control_panel'" @refreshChart="setOption" @changeAxis="changeAxis" @changeOverviewDataZoom="changeOverviewDataZoom"/>
|
||||
</div>
|
||||
</div>
|
||||
</va-collapse>
|
||||
</va-accordion>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :class="chartAreaClass">
|
||||
<div class="row" >
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<elite-replay-overview-chart v-show="showOverviewChart" :ref="'chart_overview'" class="mb-1" :cardheight="'7vh'" :data="chartOverviewData" @dataZoomEvent="dataZoomEvent($event)"/>
|
||||
<elite-replay-chart :ref="'chart_detail'" :cardheight="'88vh'" :chartheight="detailchartheight" :data="chartDetailData" />
|
||||
<change-channel-value-min-max :ref="'set_min_max'"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters, mapMutations } from 'vuex'
|
||||
import EliteReplayChart from './EliteReplayChart.vue'
|
||||
import TopControlPanel from './TopControlPanel.vue'
|
||||
import EliteReplayOverviewChart from './EliteReplayOverviewChart.vue'
|
||||
import ChangeChannelValueMinMax from '@/components/analysis/replay/toolbox/ChangeChannelValueMinMax.vue'
|
||||
import api from '@/data/api/index'
|
||||
import { download } from '@/data/download/Download'
|
||||
import types from '@/store/modules/analysis/replay/types'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'elite-data-replay',
|
||||
components: {
|
||||
TopControlPanel,
|
||||
EliteReplayChart,
|
||||
EliteReplayOverviewChart,
|
||||
ChangeChannelValueMinMax,
|
||||
},
|
||||
computed: {
|
||||
displayType () {
|
||||
return {
|
||||
x: this.axisXLabelScale.description === 'Log' ? 'log' : 'value',
|
||||
y: this.axisYLabelScale.description === 'Log' ? 'log' : 'value',
|
||||
}
|
||||
},
|
||||
|
||||
...mapFields('replay', [
|
||||
'metaList',
|
||||
'chartData',
|
||||
'chartOverviewData',
|
||||
'chartDetailData',
|
||||
'currentScale',
|
||||
'startTime',
|
||||
'endTime',
|
||||
'windowLength',
|
||||
'axisXDataType',
|
||||
'axisYDataType',
|
||||
'axisXLabelScale',
|
||||
'axisYLabelScale',
|
||||
'absToggleStatus',
|
||||
'startTimeCurrent',
|
||||
'endTimeCurrent',
|
||||
'sampleMethod',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
async created () {
|
||||
this.chartOverviewData = await this.initChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: 0,
|
||||
gridLength: 1,
|
||||
type: 'overview',
|
||||
device: 'elite',
|
||||
mode: 0,
|
||||
})
|
||||
this.chartDetailData = await this.initChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: 1,
|
||||
gridLength: 1,
|
||||
type: 'detail',
|
||||
device: 'elite',
|
||||
mode: 0,
|
||||
})
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showOverviewChart: false,
|
||||
detailchartheight: '88vh',
|
||||
dataInfo: {},
|
||||
maxTime: 0,
|
||||
zoomTime: 0,
|
||||
initDone: false,
|
||||
chartAreaClass: ['flex', 'xs12', 'sm12', 'md12', 'xl9', 'pa-0'],
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
turnOnAxisEventHandler (eventName, query, handler, attr) {
|
||||
this.$refs.chart_detail.turnOnAxisEventHandler(eventName, query, handler, attr)
|
||||
},
|
||||
turnOffAxisEventHandler (eventName, handler, attr) {
|
||||
this.$refs.chart_detail.turnOffAxisEventHandler(eventName, handler, attr)
|
||||
},
|
||||
showMinMaxPanel (params) {
|
||||
this.$refs.set_min_max.showPanel(params)
|
||||
},
|
||||
setOption (options) {
|
||||
this.$refs.chart_detail.mergeOptions(options)
|
||||
},
|
||||
showChartLoading: function (chart) {
|
||||
const loadStyle = {
|
||||
text: '',
|
||||
color: '#cccccc',
|
||||
maskColor: 'rgba(255, 255, 255, 0.8)',
|
||||
zlevel: 0,
|
||||
}
|
||||
switch (chart) {
|
||||
case 'overview':
|
||||
this.$refs.chart_overview.showLoading(loadStyle)
|
||||
break
|
||||
case 'detail':
|
||||
this.$refs.chart_detail.showLoading(loadStyle)
|
||||
break
|
||||
default:
|
||||
this.$refs.chart_overview.showLoading(loadStyle)
|
||||
this.$refs.chart_detail.showLoading(loadStyle)
|
||||
break
|
||||
}
|
||||
},
|
||||
hideChartLoading: function () {
|
||||
this.$refs.chart_overview.hideLoading()
|
||||
this.$refs.chart_detail.hideLoading()
|
||||
},
|
||||
getData: async function (scale, sampleMethod, id, channel, meta) {
|
||||
if (scale === 1) {
|
||||
return await download.rawByIDChannels(id, channel, meta)
|
||||
} else {
|
||||
if (sampleMethod === 'mean') {
|
||||
return await download.miniMeanByIDChannel(id, channel, meta)
|
||||
} else if (sampleMethod === 'random') {
|
||||
return await download.miniRandomByIDChannel(id, channel, meta)
|
||||
}
|
||||
}
|
||||
},
|
||||
register: async function () {
|
||||
// [TODO] support data source from different file
|
||||
this.updateGridListChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartDetailData.chartID,
|
||||
gridLength: this.metaList.length,
|
||||
})
|
||||
let _gridNumber = 0
|
||||
const register = this.metaList.map(meta => {
|
||||
const setting = this.GLOBAL.getDefaultChartTypeByMode(meta.parameter_set.MODE, meta.device.library_name)
|
||||
const xType = setting[0] // Elite or Time
|
||||
const yType = setting[2] // Elite or Time
|
||||
const xValue = setting[1] // 1: I, 2: V, 3: R
|
||||
const yValue = setting[3] // 1: I, 2: V, 3: R
|
||||
console.log(setting)
|
||||
this.registerChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartDetailData.chartID,
|
||||
gridIndex: _gridNumber,
|
||||
deviceNameX: xType,
|
||||
deviceIDX: meta.name,
|
||||
channelX: xValue,
|
||||
deviceNameY: yType,
|
||||
deviceIDY: '',
|
||||
channelY: yValue,
|
||||
})
|
||||
JSON.parse(meta.channels).map(ch => {
|
||||
this.registerChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartOverviewData.chartID,
|
||||
gridIndex: 0,
|
||||
deviceNameX: 'Time',
|
||||
deviceNameY: 'Elite',
|
||||
deviceIDY: meta.name,
|
||||
channelY: ch,
|
||||
})
|
||||
})
|
||||
this.chartDetailData.xAxis[_gridNumber].axisLabel.show = true
|
||||
if (this.maxTime < parseInt(meta.time_duration)) {
|
||||
this.maxTime = parseInt(meta.time_duration)
|
||||
this.endTime = this.endTimeCurrent = this.maxTime
|
||||
}
|
||||
if (xType === 'Time') {
|
||||
this.chartDetailData.xAxis[_gridNumber].min = 0
|
||||
this.chartDetailData.xAxis[_gridNumber].max = this.maxTime
|
||||
} else {
|
||||
this.chartDetailData.xAxis[_gridNumber].min = 'dataMin'
|
||||
this.chartDetailData.xAxis[_gridNumber].max = 'dataMax'
|
||||
}
|
||||
this.chartDetailData.yAxis[_gridNumber].min = 'dataMin'
|
||||
this.chartDetailData.yAxis[_gridNumber].max = 'dataMax'
|
||||
_gridNumber++
|
||||
})
|
||||
await Promise.all(register)
|
||||
this.chartOverviewData.series.forEach((series, index) => { // [TODO]
|
||||
this.chartOverviewData.xAxis[series.xAxisIndex].min = 0
|
||||
this.chartOverviewData.xAxis[series.xAxisIndex].max = this.maxTime
|
||||
})
|
||||
this.updateDataZoomChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: 0,
|
||||
})
|
||||
this.updateDataZoomChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: 1,
|
||||
})
|
||||
},
|
||||
dataZoomEvent: function (e) {
|
||||
if (e.batch != null) {
|
||||
// console.log(e.batch)
|
||||
e.batch.forEach(dataZoom => {
|
||||
const id = parseInt(dataZoom.dataZoomId.substr(dataZoom.dataZoomId.length - 3, dataZoom.dataZoomId.length - 1))
|
||||
if (id === 1) {
|
||||
this.startTime = parseInt(this.maxTime * dataZoom.start / 100)
|
||||
this.endTime = parseInt(this.maxTime * dataZoom.end / 100)
|
||||
this.windowLength = this.endTime - this.startTime
|
||||
this.chartOverviewData.dataZoom[0].start = dataZoom.start
|
||||
this.chartOverviewData.dataZoom[0].end = dataZoom.end
|
||||
// console.log(this.startTime, this.endTime)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const id = parseInt(e.dataZoomId.substr(e.dataZoomId.length - 3, e.dataZoomId.length - 1))
|
||||
if (id === 0) {
|
||||
this.startTime = parseInt(this.maxTime * e.start / 100)
|
||||
this.endTime = parseInt(this.maxTime * e.end / 100)
|
||||
this.windowLength = this.endTime - this.startTime
|
||||
this.chartOverviewData.dataZoom[0].start = e.start
|
||||
this.chartOverviewData.dataZoom[0].end = e.end
|
||||
// console.log(this.startTime, this.endTime)
|
||||
}
|
||||
}
|
||||
this.zoomTime = 0
|
||||
},
|
||||
changeOverviewDataZoom () {
|
||||
this.chartOverviewData.dataZoom[0].start = this.startTime * 100 / this.maxTime
|
||||
this.chartOverviewData.dataZoom[0].end = this.endTime * 100 / this.maxTime
|
||||
this.$refs.chart_overview.mergeOptions(this.chartOverviewData)
|
||||
},
|
||||
async computeResampleScale (meta, duration) {
|
||||
const sampleRate = meta.parameter_set.SAMPLE_RATE / 10
|
||||
const dataPointNum = (parseInt(duration) / 1e6) * sampleRate // us -> s: /1e6
|
||||
let scale
|
||||
if (dataPointNum > 2e6) { // 2000 (points) * 1000 (resample) = 2e6
|
||||
scale = '1000'
|
||||
} else if (dataPointNum > 2e5) { // 2000 (points) * 100 (resample) = 2e5
|
||||
scale = '100'
|
||||
} else if (dataPointNum > 2e4) { // 2000 (points) * 10 (resample) = 2e4
|
||||
scale = '10'
|
||||
} else {
|
||||
scale = '1'
|
||||
}
|
||||
let dataExist = false
|
||||
while (dataExist === false) {
|
||||
if (scale === '1') {
|
||||
break
|
||||
} else {
|
||||
let status
|
||||
for (const ch in Object.keys(meta.mini_data)) {
|
||||
let earlyStopFlag = false
|
||||
const dataIDArray = meta.mini_data[ch][scale]
|
||||
for (let i = 0; i < dataIDArray.length; i++) {
|
||||
const dataID = dataIDArray[i]
|
||||
const result = await download.getMiniExistOrNotByID(dataID, ch)
|
||||
status = result.data
|
||||
if (status === false) {
|
||||
earlyStopFlag = true
|
||||
scale = String(parseInt(scale) / 10)
|
||||
break
|
||||
}
|
||||
}
|
||||
if (earlyStopFlag === true) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (status === true) {
|
||||
dataExist = true // break
|
||||
}
|
||||
}
|
||||
}
|
||||
return scale
|
||||
},
|
||||
drawOverviewData: async function () {
|
||||
this.showChartLoading('overview')
|
||||
for (const meta in this.dataInfo) {
|
||||
let metaInfo
|
||||
this.metaList.forEach(_meta => {
|
||||
if (parseInt(_meta.id) === parseInt(meta)) {
|
||||
metaInfo = _meta
|
||||
}
|
||||
})
|
||||
let scale = '1'
|
||||
if (this.axisXDataType.description === 'Time') {
|
||||
scale = await this.computeResampleScale(metaInfo, metaInfo.time_duration)
|
||||
}
|
||||
console.log('overview scale:', scale)
|
||||
// download data
|
||||
const getAllData = async function (_this) {
|
||||
for (const ch in _this.dataInfo[meta]) {
|
||||
const dataList = _this.dataInfo[meta][ch][scale]
|
||||
for (let i = 0; i < dataList.length; i++) {
|
||||
if (dataList[i].data.length === 0) {
|
||||
_this.intoDataRec({
|
||||
index: i,
|
||||
metaID: meta,
|
||||
channel: ch,
|
||||
scale: scale,
|
||||
data: await _this.getData(parseInt(scale), _this.sampleMethod, dataList[i].id, ch, metaInfo),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await getAllData(this)
|
||||
// push downloaded data to chart series
|
||||
let seriesIndex = 0
|
||||
for (const ch in this.dataInfo[meta]) {
|
||||
this.chartOverviewData.series[seriesIndex].data.length = 0
|
||||
const dataList = this.dataInfo[meta][ch][scale]
|
||||
for (let i = 0; i < dataList.length; i++) {
|
||||
this.chartOverviewData.series[seriesIndex].data.push(...dataList[i].data)
|
||||
}
|
||||
seriesIndex++
|
||||
}
|
||||
}
|
||||
this.hideChartLoading()
|
||||
},
|
||||
drawDetailData: async function () {
|
||||
this.showChartLoading('detail')
|
||||
const timeDur = this.endTimeCurrent - this.startTimeCurrent
|
||||
let _gridNumber = 0
|
||||
for (const meta in this.dataInfo) {
|
||||
let metaInfo
|
||||
this.metaList.forEach(_meta => {
|
||||
if (parseInt(_meta.id) === parseInt(meta)) {
|
||||
metaInfo = _meta
|
||||
}
|
||||
})
|
||||
|
||||
let scale = '1'
|
||||
if (this.axisXDataType.description === 'Time') {
|
||||
scale = await this.computeResampleScale(metaInfo, timeDur)
|
||||
}
|
||||
// elite的sample rate不像neulive這麼高,因此試試scale = 100 or 1000時不要再sampling一次了,不然有些形狀(e.g. peak)會不一樣
|
||||
if (scale === '100' || scale === '1000') {
|
||||
this.updateChartSamplingChart({ chartID: this.chartDetailData.chartID, seriesIndex: _gridNumber, method: null })
|
||||
} else {
|
||||
this.updateChartSamplingChart({ chartID: this.chartDetailData.chartID, seriesIndex: _gridNumber, method: 'lttb' })
|
||||
}
|
||||
|
||||
if (metaInfo.device.library_name === 'EliteEIS' && metaInfo.parameter_set.MODE === 0) {
|
||||
this.chartDetailData.series[this.chartDetailData.series.length - 1].showSymbol = true
|
||||
this.chartDetailData.series[this.chartDetailData.series.length - 1].showAllSymbol = true
|
||||
this.chartDetailData.series[this.chartDetailData.series.length - 1].symbolSize = 6
|
||||
}
|
||||
|
||||
this.currentScale = scale
|
||||
this.chartDetailData.series[_gridNumber].data.length = 0
|
||||
let dataListX
|
||||
const channelX = parseInt(this.axisXDataType.id)
|
||||
if (this.axisXDataType.description !== 'Time') {
|
||||
dataListX = this.dataInfo[meta][channelX][scale]
|
||||
}
|
||||
const channelY = parseInt(this.axisYDataType.id)
|
||||
const dataListY = this.dataInfo[meta][channelY][scale]
|
||||
|
||||
const isThisModeHasCycle = this.GLOBAL.hasCycleMode(metaInfo.parameter_set.MODE, metaInfo.device.library_name)
|
||||
let _startTime
|
||||
let _endTime
|
||||
if (isThisModeHasCycle === true) {
|
||||
const cycleDataID = 3 // recorded cycle 所在的channel index
|
||||
const dataCycleList = this.dataInfo[meta][cycleDataID][this.currentScale]
|
||||
const cycleDataList = []
|
||||
for (let i = 0; i < dataCycleList.length; i++) {
|
||||
if (dataCycleList[i].data.length === 0) {
|
||||
const data = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataCycleList[i].id, cycleDataID, metaInfo)
|
||||
cycleDataList.push({ data: data })
|
||||
} else {
|
||||
cycleDataList.push({ data: dataCycleList[i].data })
|
||||
}
|
||||
}
|
||||
const cycleDict = this.getCycleDictRec()(cycleDataList)
|
||||
_startTime = cycleDict[1][0] // [1]: 第一圈
|
||||
_endTime = cycleDict[1][1] // [1]: 第一圈
|
||||
} else {
|
||||
_startTime = this.startTimeCurrent
|
||||
_endTime = this.endTimeCurrent
|
||||
}
|
||||
|
||||
let startIndex = 0
|
||||
let endIndex = 0
|
||||
// get the subfile index
|
||||
for (let i = 0; i < dataListY.length; i++) {
|
||||
if (_startTime >= parseInt(dataListY[i].start_time) && _startTime <= parseInt(dataListY[i].end_time)) {
|
||||
startIndex = i
|
||||
}
|
||||
if (_endTime >= parseInt(dataListY[i].start_time) && _endTime <= parseInt(dataListY[i].end_time)) {
|
||||
endIndex = i
|
||||
}
|
||||
}
|
||||
// download and push into chart
|
||||
for (let i = startIndex; i <= endIndex; i++) {
|
||||
const data = await this.getData(parseInt(scale), this.sampleMethod, dataListY[i].id, channelY, metaInfo)
|
||||
let dataX
|
||||
if (this.axisXDataType.description !== 'Time') {
|
||||
dataX = await this.getData(parseInt(scale), this.sampleMethod, dataListX[i].id, channelX, metaInfo)
|
||||
}
|
||||
for (let j = 0, len = data.length; j < len; j++) {
|
||||
// check which channel and push processed data (i.e. merge two channel data, now data is (time, value) format)
|
||||
if (parseInt(data[j][0]) >= _startTime && parseInt(data[j][0]) <= _endTime) {
|
||||
const processedData = data[j]
|
||||
if (dataX !== undefined) {
|
||||
processedData[0] = dataX[j][1]
|
||||
}
|
||||
if (this.displayType.x === 'log' || this.absToggleStatus.x === true) {
|
||||
processedData[0] = Math.abs(processedData[0])
|
||||
}
|
||||
if (this.displayType.y === 'log' || this.absToggleStatus.y === true) {
|
||||
processedData[1] = Math.abs(processedData[1])
|
||||
}
|
||||
|
||||
this.chartDetailData.series[_gridNumber].data.push(processedData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.axisXDataType.description === 'Time') {
|
||||
this.chartDetailData.xAxis[_gridNumber].min = _startTime
|
||||
this.chartDetailData.xAxis[_gridNumber].max = _endTime
|
||||
} else {
|
||||
this.chartDetailData.xAxis[_gridNumber].min = 'dataMin'
|
||||
this.chartDetailData.xAxis[_gridNumber].max = 'dataMax'
|
||||
}
|
||||
_gridNumber += 1
|
||||
}
|
||||
|
||||
if (this.axisXDataType.description !== 'Time') {
|
||||
this.showOverviewChart = false
|
||||
this.detailchartheight = '88vh'
|
||||
// this.$refs.chart_detail.updateChartHeight()
|
||||
this.turnOnAxisEventHandler('click', 'xAxis.axisLabel', this.showMinMaxPanel, { axis: 'x' })
|
||||
} else {
|
||||
this.showOverviewChart = true
|
||||
this.detailchartheight = '80vh'
|
||||
this.turnOffAxisEventHandler('click', this.showMinMaxPanel, { axis: 'x' })
|
||||
this.turnOnAxisEventHandler('click', 'yAxis.axisLabel', this.showMinMaxPanel, { axis: 'y' })
|
||||
}
|
||||
|
||||
this.hideChartLoading()
|
||||
},
|
||||
checkDataZoom: function () {
|
||||
this.zoomTime++
|
||||
if (this.zoomTime >= 2) {
|
||||
if (this.startTimeCurrent !== this.startTime || this.endTimeCurrent !== this.endTime) {
|
||||
this.startTimeCurrent = this.startTime
|
||||
this.endTimeCurrent = this.endTime
|
||||
this.drawDetailData()
|
||||
}
|
||||
}
|
||||
},
|
||||
changeAxis (gridIndex) {
|
||||
if (this.initDone) {
|
||||
const libName = this.metaList[gridIndex].device.library_name
|
||||
let xType
|
||||
let xValue
|
||||
if (this.axisXDataType.description === 'Time') {
|
||||
xType = 'Time'
|
||||
} else {
|
||||
if (libName === 'EliteZM15') {
|
||||
xType = 'Elite'
|
||||
} else if (libName === 'EliteEIS') {
|
||||
xType = 'EliteEIS'
|
||||
}
|
||||
xValue = this.axisXDataType.id + 1
|
||||
}
|
||||
this.updateRegisteredChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartDetailData.chartID,
|
||||
gridIndex: gridIndex,
|
||||
deviceNameX: xType,
|
||||
deviceIDX: this.metaList[gridIndex].name,
|
||||
channelX: xValue,
|
||||
deviceNameY: libName === 'EliteEIS' ? 'EliteEIS' : 'Elite',
|
||||
deviceIDY: '',
|
||||
channelY: this.axisYDataType.id + 1,
|
||||
})
|
||||
}
|
||||
if (this.axisXDataType.description === 'Time') {
|
||||
this.drawOverviewData()
|
||||
}
|
||||
this.drawDetailData() // reDraw
|
||||
},
|
||||
...mapActions('replay', [types.chart.init, types.chart.register, types.chart.clear, types.chart.updateGridList, types.chart.updateDataZoom, types.chart.setAxisDisplay]),
|
||||
...mapActions('replay', [types.meta.init]),
|
||||
...mapActions('replay', [types.rec.init, types.rec.intoData, types.rec.initDisplaySetting, types.rec.updateDisplaySetting]),
|
||||
|
||||
...mapMutations('replay', [types.chart.updateRegistered, types.chart.updateAxisSplitNumber, types.chart.updateChartSampling, types.chart.setOverviewDataZoomStartAndEnd]),
|
||||
...mapMutations('replay', [types.meta.updateByIndex]),
|
||||
|
||||
...mapGetters('replay', [types.meta.getAll]),
|
||||
...mapGetters('replay', [types.rec.getAll, types.rec.getCycleDict]),
|
||||
},
|
||||
async mounted () {
|
||||
this.showChartLoading()
|
||||
const metaIDList = this.$route.params.metaList.split('-')
|
||||
await this.initMeta({ metaIDList: metaIDList, api: api })
|
||||
this.metaList = this.getAllMeta()
|
||||
await this.initRec({ api: api })
|
||||
this.dataInfo = this.getAllRec()
|
||||
console.log(this.metaList)
|
||||
console.log(this.dataInfo)
|
||||
await this.register()
|
||||
this.setOverviewDataZoomStartAndEndChart()
|
||||
this.$refs.top_control_panel.init() // will call changeAxis() here
|
||||
this.$refs.set_min_max.init()
|
||||
this.turnOnAxisEventHandler('click', 'yAxis.axisLabel', this.showMinMaxPanel, { axis: 'y' })
|
||||
this.updateAxisSplitNumberChart({ chartID: this.chartDetailData.chartID, axis: 'x' })
|
||||
this.updateAxisSplitNumberChart({ chartID: this.chartDetailData.chartID, axis: 'y' })
|
||||
this.dataZoomTimer = setInterval(this.checkDataZoom, 1000)
|
||||
this.initDone = true
|
||||
console.log(this.chartOverviewData)
|
||||
console.log(this.chartDetailData)
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$refs.chart_overview.clear()
|
||||
this.$refs.chart_detail.clear()
|
||||
for (const id in this.chartData) {
|
||||
for (const _series of this.chartData[id].series) {
|
||||
_series.length = 0
|
||||
}
|
||||
delete this.chartData[id]
|
||||
}
|
||||
this.clearChart({ chartAllData: this.chartData })
|
||||
this.startTime = 0
|
||||
this.endTime = 0
|
||||
this.windowLength = 0
|
||||
},
|
||||
destroyed () {
|
||||
clearInterval(this.dataZoomTimer)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="flex" :class="cardclass">
|
||||
<va-card :style="'height: ' + cardheight + ';'">
|
||||
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + chartheight + ';'" :options="data" @dataZoom="updateZoom" :auto-resize="true"></chart>
|
||||
</va-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import types from '@/store/modules/analysis/replay/types'
|
||||
// import { chartData } from '../../../../data/task/ChartsManagement'
|
||||
|
||||
export default {
|
||||
name: 'elite-replay-chart',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
cardclass: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return ['xs12', 'md12', 'xl12', 'sm12']
|
||||
},
|
||||
},
|
||||
cardheight: {
|
||||
type: String,
|
||||
default: '88vh',
|
||||
},
|
||||
cardwidth: {
|
||||
type: String,
|
||||
default: 'auto',
|
||||
},
|
||||
chartheight: {
|
||||
type: String,
|
||||
default: '88vh',
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
resize: function () {
|
||||
if (this.$refs.chart_ref != null) {
|
||||
this.$refs.chart_ref.resize()
|
||||
}
|
||||
},
|
||||
updateZoom: function (e) {
|
||||
this.$emit('dataZoomEvent', e)
|
||||
},
|
||||
mergeOptions (options) {
|
||||
this.$refs.chart_ref.mergeOptions(options)
|
||||
},
|
||||
turnOnAxisEventHandler (eventName, query, handler, attr) {
|
||||
const chartID = 1
|
||||
this.updateAxisEventHandlerChart({
|
||||
chartID: chartID,
|
||||
axis: attr.axis,
|
||||
status: 'on',
|
||||
})
|
||||
// doc: https://echarts.apache.org/zh/api.html#echartsInstance.on
|
||||
this.$refs.chart_ref.chart._zr.on(eventName, query, handler)
|
||||
},
|
||||
turnOffAxisEventHandler (eventName, handler, attr) {
|
||||
const chartID = 1
|
||||
this.updateAxisEventHandlerChart({
|
||||
chartID: chartID,
|
||||
axis: attr.axis,
|
||||
status: 'off',
|
||||
})
|
||||
// doc: https://echarts.apache.org/zh/api.html#echartsInstance.off
|
||||
this.$refs.chart_ref.chart._zr.off(eventName, handler)
|
||||
},
|
||||
showLoading (options) {
|
||||
this.$refs.chart_ref.showLoading(options)
|
||||
},
|
||||
hideLoading () {
|
||||
this.$refs.chart_ref.hideLoading()
|
||||
},
|
||||
clear () {
|
||||
this.$refs.chart_ref.clear()
|
||||
},
|
||||
|
||||
...mapMutations('replay', [types.chart.updateAxisEventHandler]),
|
||||
},
|
||||
async mounted () {
|
||||
this.resizeTimer = setInterval(this.resize, 1000)
|
||||
},
|
||||
destroyed () {
|
||||
clearInterval(this.resizeTimer)
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
.va-card {
|
||||
&__body {
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,10 +1,6 @@
|
||||
<template>
|
||||
<div class="flex" :class="cardclass">
|
||||
<va-card>
|
||||
<template slot="header">
|
||||
<!-- <va-icon name="fa fa-area-chart mr-3" color="primary"/> -->
|
||||
</template>
|
||||
|
||||
<va-card :style="'height: 8vh;'">
|
||||
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="data" @dataZoom="updateZoom" :auto-resize="true"></chart>
|
||||
</va-card>
|
||||
</div>
|
||||
@@ -14,7 +10,7 @@
|
||||
// import { chartData } from '../../../../data/task/ChartsManagement'
|
||||
|
||||
export default {
|
||||
name: 'replay-chart-detail',
|
||||
name: 'elite-replay-overview-chart',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
@@ -32,7 +28,7 @@ export default {
|
||||
},
|
||||
cardheight: {
|
||||
type: String,
|
||||
default: '88vh',
|
||||
default: '82vh',
|
||||
},
|
||||
cardwidth: {
|
||||
type: String,
|
||||
@@ -58,6 +54,18 @@ export default {
|
||||
updateZoom: function (e) {
|
||||
this.$emit('dataZoomEvent', e)
|
||||
},
|
||||
mergeOptions (options) {
|
||||
this.$refs.chart_ref.mergeOptions(options)
|
||||
},
|
||||
showLoading (options) {
|
||||
this.$refs.chart_ref.showLoading(options)
|
||||
},
|
||||
hideLoading () {
|
||||
this.$refs.chart_ref.hideLoading()
|
||||
},
|
||||
clear () {
|
||||
this.$refs.chart_ref.clear()
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
this.resizeTimer = setInterval(this.resize, 1000)
|
||||
@@ -68,3 +76,11 @@ export default {
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
.va-card {
|
||||
&__body {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-card>
|
||||
<div class="flex-container mb-1">
|
||||
<div class="flex sm8 xl8 md8 xs8 px-0 py-0">
|
||||
<edit-file-name :ref="'edit_file_name'"/>
|
||||
</div>
|
||||
<div class="flex sm2 xl2 md2 xs2 px-0 py-0">
|
||||
<download-file style="float: right;" />
|
||||
</div>
|
||||
<div class="flex sm2 xl2 md2 xs2 px-0 py-0">
|
||||
<delete-file />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container mb-2">
|
||||
<div class="flex sm2 xl2 md2 xs2 px-0 py-0">
|
||||
<p class="display-6"> X-axis <p/>
|
||||
</div>
|
||||
<div class="flex sm5 xl5 md5 xs5 pl-1 pr-0 py-0">
|
||||
<change-axis :ref="'change_axis_x'" axis="x" @changeAxis="changeAxis" @changeUnit="changeUnit" @clearCycle="clearCycle"/>
|
||||
</div>
|
||||
<div class="flex sm5 xl5 md5 xs5 pl-1 pr-0 py-0">
|
||||
<change-unit :ref="'change_unit_x'" axis="x" @refreshChart="refreshChart"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-container mb-2">
|
||||
<div class="flex sm2 xl2 md2 xs2 px-0 py-0" />
|
||||
<div class="flex sm5 xl5 md5 xs5 pl-1 pr-0 py-0">
|
||||
<change-scale :ref="'change_scale_x'" axis="x" @refreshChart="refreshChart" @clearCycle="clearCycle" @changeAxis="changeAxis"/>
|
||||
</div>
|
||||
<div class="flex sm5 xl5 md5 xs5 px-0 py-0">
|
||||
<abs-toggle :ref="'abs_x'" axis="x" @changeAxis="changeAxis"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container mb-2">
|
||||
<div class="flex sm2 xl2 md2 xs2 px-0 py-0">
|
||||
<p class="display-6"> Y-axis <p/>
|
||||
</div>
|
||||
<div class="flex sm5 xl5 md5 xs5 pl-1 pr-0 py-0">
|
||||
<change-axis :ref="'change_axis_y'" axis="y" @changeAxis="changeAxis" @changeUnit="changeUnit" @clearCycle="clearCycle"/>
|
||||
</div>
|
||||
<div class="flex sm5 xl5 md5 xs5 pl-1 pr-0 py-0">
|
||||
<change-unit :ref="'change_unit_y'" axis="y" @refreshChart="refreshChart"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-container mb-2">
|
||||
<div class="flex sm2 xl2 md2 xs2 px-0 py-0" />
|
||||
<div class="flex sm5 xl5 md5 xs5 pl-1 pr-0 py-0">
|
||||
<change-scale :ref="'change_scale_y'" axis="y" @refreshChart="refreshChart" @clearCycle="clearCycle" @changeAxis="changeAxis"/>
|
||||
</div>
|
||||
<div class="flex sm5 xl5 md5 xs5 px-0 py-0">
|
||||
<abs-toggle :ref="'abs_y'" axis="y" @changeAxis="changeAxis"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-container mb-2">
|
||||
<div class="flex sm10 xl10 md10 xs10 px-0 py-0">
|
||||
<change-window-start-and-size :ref="'change_window_start_and_size'" @changeOverviewDataZoom="changeOverviewDataZoom"/>
|
||||
</div>
|
||||
<div class="flex sm1 xl1 md1 xs1 px-0 py-0">
|
||||
<lock-data-zoom :chartID="0"/>
|
||||
</div>
|
||||
</div>
|
||||
<change-cycle v-show="showCyclePanel" :ref="'change_cycle'" @refreshChart="refreshChart"/>
|
||||
<show-resample-rate/>
|
||||
<show-parameter :ref="'show_param'"/>
|
||||
</va-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ShowResampleRate from '@/components/analysis/replay/toolbox/ShowResampleRate.vue'
|
||||
import ChangeAxis from '@/components/analysis/replay/toolbox/ChangeAxis.vue'
|
||||
import ChangeUnit from '@/components/analysis/replay/toolbox/ChangeUnit.vue'
|
||||
import ChangeScale from '@/components/analysis/replay/toolbox/ChangeScale.vue'
|
||||
import ChangeCycle from '@/components/analysis/replay/toolbox/ChangeCycle.vue'
|
||||
import AbsToggle from '@/components/analysis/replay/toolbox/AbsToggle.vue'
|
||||
import DownloadFile from '@/components/analysis/replay/toolbox/DownloadFile.vue'
|
||||
import DeleteFile from '@/components/analysis/replay/toolbox/DeleteFile.vue'
|
||||
import EditFileName from '@/components/analysis/replay/toolbox/EditFileName.vue'
|
||||
import ShowParameter from '@/components/analysis/replay/toolbox/ShowParameter.vue'
|
||||
import LockDataZoom from '@/components/analysis/replay/toolbox/LockDataZoom.vue'
|
||||
import ChangeWindowStartAndSize from '@/components/analysis/replay/toolbox/ChangeWindowStartAndSize.vue'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'top-control-panel',
|
||||
components: {
|
||||
ShowResampleRate,
|
||||
ChangeAxis,
|
||||
ChangeUnit,
|
||||
ChangeScale,
|
||||
ChangeCycle,
|
||||
AbsToggle,
|
||||
DownloadFile,
|
||||
DeleteFile,
|
||||
EditFileName,
|
||||
ShowParameter,
|
||||
LockDataZoom,
|
||||
ChangeWindowStartAndSize,
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'metaList',
|
||||
'showCyclePanel',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
async created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
deviceName: '',
|
||||
showCycle: false,
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
this.deviceName = this.metaList[0].device.library_name
|
||||
this.$refs.change_axis_x.init(this.deviceName)
|
||||
this.$refs.change_axis_y.init(this.deviceName)
|
||||
this.$refs.change_unit_x.init(this.deviceName)
|
||||
this.$refs.change_unit_y.init(this.deviceName)
|
||||
this.$refs.change_scale_x.init(this.deviceName)
|
||||
this.$refs.change_scale_y.init(this.deviceName)
|
||||
this.$refs.abs_x.init(this.deviceName)
|
||||
this.$refs.abs_y.init(this.deviceName)
|
||||
this.$refs.change_cycle.init()
|
||||
this.$refs.edit_file_name.init()
|
||||
this.$refs.show_param.init(this.deviceName)
|
||||
this.$refs.change_window_start_and_size.init()
|
||||
},
|
||||
changeOverviewDataZoom () {
|
||||
this.$emit('changeOverviewDataZoom')
|
||||
},
|
||||
refreshChart (options) {
|
||||
this.$emit('refreshChart', options)
|
||||
},
|
||||
changeAxis (gridIndex) {
|
||||
this.$emit('changeAxis', gridIndex)
|
||||
},
|
||||
changeUnit (axis) {
|
||||
if (axis === 'x') {
|
||||
this.$refs.change_unit_x.changeUnitByAxis()
|
||||
} else if (axis === 'y') {
|
||||
this.$refs.change_unit_y.changeUnitByAxis()
|
||||
}
|
||||
},
|
||||
clearCycle () {
|
||||
this.$refs.change_cycle.clear()
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.flex-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,530 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="row row-equal">
|
||||
<div class="flex md12 xl3 xs12 sm12">
|
||||
<div class="row">
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<va-accordion>
|
||||
<va-collapse class="mb-2" :isOpenDefault="true">
|
||||
<span slot="header">Control Panel</span>
|
||||
<div slot="body">
|
||||
<div>
|
||||
<top-control-panel :ref="'top_control_panel'" @refreshChart="setOption" @changeOverviewDataZoom="changeOverviewDataZoom"/>
|
||||
</div>
|
||||
</div>
|
||||
</va-collapse>
|
||||
</va-accordion>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :class="chartAreaClass">
|
||||
<div class="row" >
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<neulive-replay-overview-chart :ref="'chart_overview'" class="mb-1" :cardheight="'7vh'" :data="chartOverviewData" @dataZoomEvent="dataZoomEvent($event)"/>
|
||||
<neulive-replay-chart :ref="'chart_detail'" @dblclick.native="distribute()" :cardheight="'80vh'" :data="chartDetailData" @dataZoomEvent="updateMarkArea($event)" />
|
||||
<change-channel-value-min-max :ref="'set_min_max'"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters, mapMutations } from 'vuex'
|
||||
import NeuliveReplayChart from './NeuliveReplayChart.vue'
|
||||
import NeuliveReplayOverviewChart from './NeuliveReplayOverviewChart.vue'
|
||||
import TopControlPanel from './TopControlPanel.vue'
|
||||
import ChangeChannelValueMinMax from '@/components/analysis/replay/toolbox/ChangeChannelValueMinMax.vue'
|
||||
import api from '@/data/api/index'
|
||||
import { download } from '@/data/download/Download'
|
||||
import types from '@/store/modules/analysis/replay/types'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'neulive-data-replay',
|
||||
components: {
|
||||
NeuliveReplayChart,
|
||||
NeuliveReplayOverviewChart,
|
||||
TopControlPanel,
|
||||
ChangeChannelValueMinMax,
|
||||
},
|
||||
computed: {
|
||||
displayType () {
|
||||
return {
|
||||
x: this.axisXLabelScale.description === 'Log' ? 'log' : 'value',
|
||||
y: this.axisYLabelScale.description === 'Log' ? 'log' : 'value',
|
||||
}
|
||||
},
|
||||
|
||||
...mapFields('replay', [
|
||||
'chartData',
|
||||
'chartOverviewData',
|
||||
'chartDetailData',
|
||||
'currentScale',
|
||||
'startTime',
|
||||
'endTime',
|
||||
'windowLength',
|
||||
'axisXLabelScale',
|
||||
'axisYLabelScale',
|
||||
'startTimeCurrent',
|
||||
'endTimeCurrent',
|
||||
'sampleMethod',
|
||||
'useSdCardData',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
async created () {
|
||||
this.chartOverviewData = await this.initChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: 0,
|
||||
gridLength: 1,
|
||||
type: 'overview',
|
||||
device: 'neulive',
|
||||
mode: 0,
|
||||
})
|
||||
this.chartDetailData = await this.initChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: 1,
|
||||
gridLength: 1,
|
||||
type: 'detail',
|
||||
device: 'neulive',
|
||||
mode: 0,
|
||||
})
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
metaList: null,
|
||||
dataInfo: {},
|
||||
maxTime: 0,
|
||||
zoomTime: 0,
|
||||
chartAreaClass: ['flex', 'xs12', 'sm12', 'md12', 'xl9', 'pa-0'],
|
||||
dataZoomStart: 0,
|
||||
dataZoomEnd: 100,
|
||||
inDistributeMode: false,
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
turnOnAxisEventHandler (eventName, query, handler, attr) {
|
||||
this.$refs.chart_detail.turnOnAxisEventHandler(eventName, query, handler, attr)
|
||||
},
|
||||
showMinMaxPanel (params) {
|
||||
this.$refs.set_min_max.showPanel(params)
|
||||
},
|
||||
setOption (options) {
|
||||
this.$refs.chart_detail.mergeOptions(options)
|
||||
},
|
||||
showChartLoading: function (chart) {
|
||||
const loadStyle = {
|
||||
text: '',
|
||||
color: '#cccccc',
|
||||
maskColor: 'rgba(255, 255, 255, 0.8)',
|
||||
zlevel: 0,
|
||||
}
|
||||
switch (chart) {
|
||||
case 'overview':
|
||||
this.$refs.chart_overview.showLoading(loadStyle)
|
||||
break
|
||||
case 'detail':
|
||||
this.$refs.chart_detail.showLoading(loadStyle)
|
||||
break
|
||||
default:
|
||||
this.$refs.chart_overview.showLoading(loadStyle)
|
||||
this.$refs.chart_detail.showLoading(loadStyle)
|
||||
break
|
||||
}
|
||||
},
|
||||
hideChartLoading: function () {
|
||||
this.$refs.chart_overview.hideLoading()
|
||||
this.$refs.chart_detail.hideLoading()
|
||||
},
|
||||
getData: async function (scale, sampleMethod, id, channel, meta) {
|
||||
if (scale === 1) {
|
||||
// [TODO] 0: assume first meta temporarily
|
||||
if (this.useSdCardData && (this.metaList[0].sd_data_uploaded === true)) {
|
||||
return await download.rawSdDataByIDChannels(id, channel, meta)
|
||||
} else {
|
||||
return await download.rawByIDChannels(id, channel, meta)
|
||||
}
|
||||
} else {
|
||||
if (sampleMethod === 'mean') {
|
||||
return await download.miniMeanByIDChannel(id, channel, meta)
|
||||
} else if (sampleMethod === 'random') {
|
||||
return await download.miniRandomByIDChannel(id, channel, meta)
|
||||
}
|
||||
}
|
||||
},
|
||||
register: async function () {
|
||||
let chNumber = 0
|
||||
this.metaList.forEach(meta => {
|
||||
chNumber += JSON.parse(meta.channels).length
|
||||
})
|
||||
this.updateGridListChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartDetailData.chartID,
|
||||
gridLength: chNumber,
|
||||
})
|
||||
let _chNumber = 0
|
||||
// console.log(this.chartDetailData)
|
||||
|
||||
const register = this.metaList.map(meta => {
|
||||
this.metaList.map(meta => {
|
||||
JSON.parse(meta.channels).map(ch => {
|
||||
this.registerChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartDetailData.chartID,
|
||||
gridIndex: _chNumber,
|
||||
deviceNameX: 'Time',
|
||||
deviceNameY: 'Neulive',
|
||||
deviceIDY: meta.name,
|
||||
channelY: ch,
|
||||
})
|
||||
this.registerChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartOverviewData.chartID,
|
||||
gridIndex: 0,
|
||||
deviceNameX: 'Time',
|
||||
deviceNameY: 'Neulive',
|
||||
deviceIDY: meta.name,
|
||||
channelY: ch,
|
||||
})
|
||||
_chNumber++
|
||||
})
|
||||
})
|
||||
if (this.maxTime < parseInt(meta.time_duration)) {
|
||||
this.maxTime = parseInt(meta.time_duration)
|
||||
this.endTime = this.endTimeCurrent = this.maxTime
|
||||
}
|
||||
})
|
||||
await Promise.all(register)
|
||||
this.chartDetailData.series.forEach((series, index) => {
|
||||
this.chartDetailData.xAxis[series.xAxisIndex].min = 0
|
||||
this.chartDetailData.xAxis[series.xAxisIndex].max = this.maxTime
|
||||
})
|
||||
this.chartOverviewData.series.forEach((series, index) => {
|
||||
this.chartOverviewData.xAxis[series.xAxisIndex].min = 0
|
||||
this.chartOverviewData.xAxis[series.xAxisIndex].max = this.maxTime
|
||||
})
|
||||
this.chartDetailData.xAxis[this.chartDetailData.xAxis.length - 1].axisLabel.show = true
|
||||
this.updateDataZoomChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: 0,
|
||||
})
|
||||
this.updateDataZoomChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: 1,
|
||||
})
|
||||
},
|
||||
updateMarkArea: function (e) {
|
||||
// console.log(e)
|
||||
if (e.batch != null) {
|
||||
// console.log(e.batch)
|
||||
e.batch.forEach(dataZoom => {
|
||||
const id = parseInt(dataZoom.dataZoomId.substr(dataZoom.dataZoomId.length - 3, dataZoom.dataZoomId.length - 1))
|
||||
if (id === 1) {
|
||||
this.dataZoomStart = dataZoom.start
|
||||
this.dataZoomEnd = dataZoom.end
|
||||
const startTime = (this.endTime - this.startTime) * dataZoom.start / 100
|
||||
const endTime = (this.endTime - this.startTime) * dataZoom.end / 100
|
||||
this.chartOverviewData.series[0].markArea.data[0][0].xAxis = this.startTime + startTime
|
||||
this.chartOverviewData.series[0].markArea.data[0][1].xAxis = this.startTime + endTime
|
||||
// console.log(this.startTime, this.endTime)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const id = parseInt(e.dataZoomId.substr(e.dataZoomId.length - 3, e.dataZoomId.length - 1))
|
||||
if (id === 0) {
|
||||
this.dataZoomStart = e.start
|
||||
this.dataZoomEnd = e.end
|
||||
const startTime = (this.endTime - this.startTime) * e.start / 100
|
||||
const endTime = (this.endTime - this.startTime) * e.end / 100
|
||||
this.chartOverviewData.series[0].markArea.data[0][0].xAxis = this.startTime + startTime
|
||||
this.chartOverviewData.series[0].markArea.data[0][1].xAxis = this.startTime + endTime
|
||||
// console.log(this.startTime, this.endTime)
|
||||
}
|
||||
}
|
||||
},
|
||||
dataZoomEvent: function (e) {
|
||||
// console.log(e)
|
||||
if (e.batch != null) {
|
||||
// console.log(e.batch)
|
||||
e.batch.forEach(dataZoom => {
|
||||
const id = parseInt(dataZoom.dataZoomId.substr(dataZoom.dataZoomId.length - 3, dataZoom.dataZoomId.length - 1))
|
||||
if (id === 1) {
|
||||
this.startTime = parseInt(this.maxTime * dataZoom.start / 100)
|
||||
this.endTime = parseInt(this.maxTime * dataZoom.end / 100)
|
||||
this.windowLength = this.endTime - this.startTime
|
||||
this.chartOverviewData.dataZoom[0].start = dataZoom.start
|
||||
this.chartOverviewData.dataZoom[0].end = dataZoom.end
|
||||
// console.log(this.startTime, this.endTime)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const id = parseInt(e.dataZoomId.substr(e.dataZoomId.length - 3, e.dataZoomId.length - 1))
|
||||
if (id === 0) {
|
||||
this.startTime = parseInt(this.maxTime * e.start / 100)
|
||||
this.endTime = parseInt(this.maxTime * e.end / 100)
|
||||
this.windowLength = this.endTime - this.startTime
|
||||
this.chartOverviewData.dataZoom[0].start = e.start
|
||||
this.chartOverviewData.dataZoom[0].end = e.end
|
||||
// console.log(this.startTime, this.endTime)
|
||||
}
|
||||
}
|
||||
this.chartOverviewData.series[0].markArea.data[0][0].xAxis = this.startTime + ((this.endTime - this.startTime) * (this.dataZoomStart / 100))
|
||||
this.chartOverviewData.series[0].markArea.data[0][1].xAxis = this.startTime + ((this.endTime - this.startTime) * (this.dataZoomEnd / 100))
|
||||
this.zoomTime = 0
|
||||
},
|
||||
changeOverviewDataZoom () {
|
||||
this.chartOverviewData.dataZoom[0].start = this.startTime * 100 / this.maxTime
|
||||
this.chartOverviewData.dataZoom[0].end = this.endTime * 100 / this.maxTime
|
||||
this.chartOverviewData.series[0].markArea.data[0][0].xAxis = this.startTime + ((this.endTime - this.startTime) * (this.dataZoomStart / 100))
|
||||
this.chartOverviewData.series[0].markArea.data[0][1].xAxis = this.startTime + ((this.endTime - this.startTime) * (this.dataZoomEnd / 100))
|
||||
this.$refs.chart_overview.mergeOptions(this.chartOverviewData)
|
||||
},
|
||||
drawInitData: async function () {
|
||||
this.showChartLoading('overview')
|
||||
for (const meta in this.dataInfo) {
|
||||
let metaInfo
|
||||
this.metaList.forEach(_meta => {
|
||||
if (parseInt(_meta.id) === parseInt(meta)) {
|
||||
metaInfo = _meta
|
||||
}
|
||||
})
|
||||
let scale = '1000'
|
||||
const sampleRate = (metaInfo.parameter_set.SAMPLE_RATE === 0) ? parseInt(8e5 / metaInfo.parameter_set.ADC_CLOCK) : metaInfo.parameter_set.SAMPLE_RATE // Hz
|
||||
const dataPointNum = (parseInt(metaInfo.time_duration) / 1e6) * sampleRate // us -> s: /1e6
|
||||
if (dataPointNum > 2e6) { // 2000 (points) * 1000 (resample) = 2e6
|
||||
scale = '1000'
|
||||
} else if (dataPointNum > 2e5) { // 2000 (points) * 100 (resample) = 2e5
|
||||
scale = '100'
|
||||
} else if (dataPointNum > 2e4) { // 2000 (points) * 10 (resample) = 2e4
|
||||
scale = '10'
|
||||
} else {
|
||||
scale = '1'
|
||||
}
|
||||
this.currentScale = scale
|
||||
console.log('overview scale:', scale)
|
||||
const getAllData = async function (_this) {
|
||||
let seriesIndex = 0
|
||||
for (const ch in _this.dataInfo[meta]) {
|
||||
const dataList = _this.dataInfo[meta][ch][scale]
|
||||
for (let i = 0; i < dataList.length; i++) {
|
||||
_this.intoDataRec({
|
||||
index: i,
|
||||
metaID: meta,
|
||||
channel: ch,
|
||||
scale: scale,
|
||||
data: await _this.getData(parseInt(scale), _this.sampleMethod, dataList[i].id, ch, metaInfo),
|
||||
})
|
||||
_this.chartOverviewData.series[seriesIndex].data.push(...dataList[i].data)
|
||||
_this.chartDetailData.series[seriesIndex].data.push(...dataList[i].data)
|
||||
}
|
||||
seriesIndex++
|
||||
}
|
||||
}
|
||||
await getAllData(this)
|
||||
}
|
||||
this.hideChartLoading()
|
||||
},
|
||||
drawDetailData: async function () {
|
||||
this.showChartLoading('detail')
|
||||
const timeDur = this.endTimeCurrent - this.startTimeCurrent
|
||||
for (const meta in this.dataInfo) {
|
||||
let metaInfo
|
||||
this.metaList.forEach(_meta => {
|
||||
if (parseInt(_meta.id) === parseInt(meta)) {
|
||||
metaInfo = _meta
|
||||
}
|
||||
})
|
||||
let scale = '1000'
|
||||
const sampleRate = (metaInfo.parameter_set.SAMPLE_RATE === 0) ? parseInt(8e5 / metaInfo.parameter_set.ADC_CLOCK) : metaInfo.parameter_set.SAMPLE_RATE // Hz
|
||||
const dataPointNum = (timeDur / 1e6) * sampleRate // us -> s: /1e6
|
||||
if (dataPointNum > 2e6) { // 2000 (points) * 1000 (resample) = 2e6
|
||||
scale = '1000'
|
||||
} else if (dataPointNum > 2e5) { // 2000 (points) * 100 (resample) = 2e5
|
||||
scale = '100'
|
||||
} else if (dataPointNum > 2e4) { // 2000 (points) * 10 (resample) = 2e4
|
||||
scale = '10'
|
||||
} else {
|
||||
scale = '1'
|
||||
}
|
||||
this.currentScale = scale
|
||||
let seriesIndex = 0
|
||||
this.updateChartSamplingChart({ chartID: this.chartDetailData.chartID, seriesIndex: seriesIndex, method: function (frame) { return frame[0] } })
|
||||
for (const ch in this.dataInfo[meta]) {
|
||||
this.chartDetailData.series[seriesIndex].data.length = 0
|
||||
const dataList = this.dataInfo[meta][ch][scale]
|
||||
let startIndex = 0
|
||||
let endIndex = 0
|
||||
// get the subfile index
|
||||
for (let i = 0; i < dataList.length; i++) {
|
||||
if (this.startTimeCurrent >= parseInt(dataList[i].start_time) && this.startTimeCurrent <= parseInt(dataList[i].end_time)) {
|
||||
startIndex = i
|
||||
}
|
||||
if (this.endTimeCurrent >= parseInt(dataList[i].start_time) && this.endTimeCurrent <= parseInt(dataList[i].end_time)) {
|
||||
endIndex = i
|
||||
}
|
||||
}
|
||||
// download and push into chart
|
||||
let endFlag = false // because data is sorted by time, so if current processed data piece exceeds endTimeCurrent, can early stop
|
||||
for (let i = startIndex; i <= endIndex; i++) {
|
||||
const data = await this.getData(parseInt(scale), this.sampleMethod, dataList[i].id, ch, metaInfo)
|
||||
for (let j = 0, len = data.length; j < len; j++) {
|
||||
if (parseInt(data[j][0]) >= this.startTimeCurrent && parseInt(data[j][0]) <= this.endTimeCurrent) {
|
||||
const processedData = data[j]
|
||||
if (this.displayType.x === 'log') {
|
||||
processedData[0] = Math.abs(processedData[0])
|
||||
}
|
||||
if (this.displayType.y === 'log') {
|
||||
processedData[1] = Math.abs(processedData[1])
|
||||
}
|
||||
|
||||
this.chartDetailData.series[seriesIndex].data.push(processedData)
|
||||
}
|
||||
// early stop
|
||||
if (parseInt(data[j][0]) > this.endTimeCurrent) {
|
||||
endFlag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// early stop
|
||||
if (endFlag === true) {
|
||||
break
|
||||
}
|
||||
}
|
||||
for (let i = 0, len = this.chartDetailData.xAxis.length; i < len; i++) {
|
||||
this.chartDetailData.xAxis[i].min = this.startTimeCurrent
|
||||
this.chartDetailData.xAxis[i].max = this.endTimeCurrent
|
||||
}
|
||||
seriesIndex++
|
||||
}
|
||||
}
|
||||
this.hideChartLoading()
|
||||
},
|
||||
checkDataZoom: function () {
|
||||
this.zoomTime++
|
||||
if (this.zoomTime >= 2) {
|
||||
if (this.startTimeCurrent !== this.startTime || this.endTimeCurrent !== this.endTime) {
|
||||
this.startTimeCurrent = this.startTime
|
||||
this.endTimeCurrent = this.endTime
|
||||
this.drawDetailData()
|
||||
}
|
||||
}
|
||||
},
|
||||
distribute: function () {
|
||||
if (this.inDistributeMode) {
|
||||
let seriesIndex = 0
|
||||
for (const meta in this.dataInfo) {
|
||||
for (const ch in this.dataInfo[meta]) {
|
||||
this.chartDetailData.series[seriesIndex].xAxisIndex = seriesIndex
|
||||
this.chartDetailData.series[seriesIndex].yAxisIndex = seriesIndex
|
||||
this.updateAxisLabelChart({
|
||||
chartID: this.chartDetailData.chartID,
|
||||
axis: 'y',
|
||||
axisIndex: seriesIndex,
|
||||
channel: ch,
|
||||
})
|
||||
seriesIndex++
|
||||
}
|
||||
}
|
||||
this.updateGridListChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartDetailData.chartID,
|
||||
gridLength: seriesIndex,
|
||||
})
|
||||
|
||||
for (let i = 0; i < this.chartDetailData.xAxis.length; i++) {
|
||||
this.chartDetailData.xAxis[i].axisLabel.show = false
|
||||
}
|
||||
this.chartDetailData.xAxis[this.chartDetailData.xAxis.length - 1].axisLabel.show = true
|
||||
this.inDistributeMode = false
|
||||
} else {
|
||||
let gridLength = 1
|
||||
this.chartDetailData.xAxis[0].axisLabel.show = true
|
||||
for (const meta in this.dataInfo) {
|
||||
for (const ch in this.dataInfo[meta]) {
|
||||
if (parseInt(ch) >= 256) { // x, y, z, mag
|
||||
gridLength = 2
|
||||
this.chartDetailData.xAxis[0].axisLabel.show = false
|
||||
this.chartDetailData.xAxis[1].axisLabel.show = true
|
||||
break
|
||||
}
|
||||
}
|
||||
this.updateGridListChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartDetailData.chartID,
|
||||
gridLength: gridLength,
|
||||
})
|
||||
let seriesIndex = 0
|
||||
for (const ch in this.dataInfo[meta]) {
|
||||
if (parseInt(ch) < 256) {
|
||||
this.chartDetailData.series[seriesIndex].xAxisIndex = 0
|
||||
this.chartDetailData.series[seriesIndex].yAxisIndex = 0
|
||||
} else { // x, y, z, mag
|
||||
this.chartDetailData.series[seriesIndex].xAxisIndex = 1
|
||||
this.chartDetailData.series[seriesIndex].yAxisIndex = 1
|
||||
this.updateAxisLabelChart({
|
||||
chartID: this.chartDetailData.chartID,
|
||||
axis: 'y',
|
||||
axisIndex: 1,
|
||||
channel: ch,
|
||||
})
|
||||
}
|
||||
seriesIndex++
|
||||
}
|
||||
}
|
||||
this.inDistributeMode = true
|
||||
}
|
||||
},
|
||||
...mapActions('replay', [types.chart.init, types.chart.register, types.chart.clear, types.chart.updateGridList, types.chart.updateDataZoom]),
|
||||
...mapActions('replay', [types.meta.init]),
|
||||
...mapActions('replay', [types.rec.init, types.rec.intoData, types.rec.initDisplaySetting, types.rec.updateDisplaySetting]),
|
||||
|
||||
...mapMutations('replay', [types.chart.updateAxisLabel, types.chart.updateChartSampling, types.chart.setOverviewDataZoomStartAndEnd]),
|
||||
...mapMutations('replay', [types.meta.updateByIndex]),
|
||||
|
||||
...mapGetters('replay', [types.meta.getAll]),
|
||||
...mapGetters('replay', [types.rec.getAll]),
|
||||
},
|
||||
// use watch because va-select with @change will have bug
|
||||
watch: {
|
||||
},
|
||||
async mounted () {
|
||||
this.showChartLoading()
|
||||
const metaIDList = this.$route.params.metaList.split('-')
|
||||
await this.initMeta({ metaIDList: metaIDList, api: api })
|
||||
this.metaList = this.getAllMeta()
|
||||
await this.initRec({ api: api })
|
||||
this.dataInfo = this.getAllRec()
|
||||
console.log(this.metaList)
|
||||
console.log(this.dataInfo)
|
||||
await this.register()
|
||||
this.setOverviewDataZoomStartAndEndChart()
|
||||
await this.drawInitData()
|
||||
this.dataZoomTimer = setInterval(this.checkDataZoom, 1000)
|
||||
this.$refs.top_control_panel.init()
|
||||
this.$refs.set_min_max.init()
|
||||
this.turnOnAxisEventHandler('click', 'yAxis.axisLabel', this.showMinMaxPanel, { axis: 'y' })
|
||||
console.log(this.chartOverviewData)
|
||||
console.log(this.chartDetailData)
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$refs.chart_overview.clear()
|
||||
this.$refs.chart_detail.clear()
|
||||
for (const id in this.chartData) {
|
||||
for (const _series of this.chartData[id].series) {
|
||||
_series.length = 0
|
||||
}
|
||||
delete this.chartData[id]
|
||||
}
|
||||
this.clearChart({ chartAllData: this.chartData })
|
||||
},
|
||||
destroyed () {
|
||||
clearInterval(this.dataZoomTimer)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div class="flex" :class="cardclass">
|
||||
<va-card :style="'height: ' + cardheight + ';'">
|
||||
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="data" @dataZoom="updateZoom" :auto-resize="true"></chart>
|
||||
</va-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import types from '@/store/modules/analysis/replay/types'
|
||||
// import { chartData } from '../../../../data/task/ChartsManagement'
|
||||
|
||||
export default {
|
||||
name: 'neulive-replay-chart',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
cardclass: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return ['xs12', 'md12', 'xl12', 'sm12']
|
||||
},
|
||||
},
|
||||
cardheight: {
|
||||
type: String,
|
||||
default: '82vh',
|
||||
},
|
||||
cardwidth: {
|
||||
type: String,
|
||||
default: 'auto',
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
resize: function () {
|
||||
if (this.$refs.chart_ref != null) {
|
||||
this.$refs.chart_ref.resize()
|
||||
}
|
||||
},
|
||||
updateZoom: function (e) {
|
||||
this.$emit('dataZoomEvent', e)
|
||||
},
|
||||
mergeOptions (options) {
|
||||
this.$refs.chart_ref.mergeOptions(options)
|
||||
},
|
||||
turnOnAxisEventHandler (eventName, query, handler, attr) {
|
||||
const chartID = 1
|
||||
this.updateAxisEventHandlerChart({
|
||||
chartID: chartID,
|
||||
axis: attr.axis,
|
||||
status: 'on',
|
||||
})
|
||||
// doc: https://echarts.apache.org/zh/api.html#echartsInstance.on
|
||||
this.$refs.chart_ref.chart._zr.on(eventName, query, handler)
|
||||
},
|
||||
turnOffAxisEventHandler (eventName, handler, attr) {
|
||||
const chartID = 1
|
||||
this.updateAxisEventHandlerChart({
|
||||
chartID: chartID,
|
||||
axis: attr.axis,
|
||||
status: 'off',
|
||||
})
|
||||
// doc: https://echarts.apache.org/zh/api.html#echartsInstance.off
|
||||
this.$refs.chart_ref.chart._zr.off(eventName, handler)
|
||||
},
|
||||
showLoading (options) {
|
||||
this.$refs.chart_ref.showLoading(options)
|
||||
},
|
||||
hideLoading () {
|
||||
this.$refs.chart_ref.hideLoading()
|
||||
},
|
||||
clear () {
|
||||
this.$refs.chart_ref.clear()
|
||||
},
|
||||
|
||||
...mapMutations('replay', [types.chart.updateAxisEventHandler]),
|
||||
},
|
||||
async mounted () {
|
||||
this.resizeTimer = setInterval(this.resize, 1000)
|
||||
},
|
||||
destroyed () {
|
||||
clearInterval(this.resizeTimer)
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
.va-card {
|
||||
&__body {
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="flex" :class="cardclass">
|
||||
<va-card :style="'height: 8vh;'">
|
||||
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="data" @dataZoom="updateZoom" :auto-resize="true"></chart>
|
||||
</va-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { chartData } from '../../../../data/task/ChartsManagement'
|
||||
|
||||
export default {
|
||||
name: 'neulive-replay-overview-chart',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
cardclass: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return ['xs12', 'md12', 'xl12', 'sm12']
|
||||
},
|
||||
},
|
||||
cardheight: {
|
||||
type: String,
|
||||
default: '82vh',
|
||||
},
|
||||
cardwidth: {
|
||||
type: String,
|
||||
default: 'auto',
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
resize: function () {
|
||||
if (this.$refs.chart_ref != null) {
|
||||
this.$refs.chart_ref.resize()
|
||||
}
|
||||
},
|
||||
updateZoom: function (e) {
|
||||
this.$emit('dataZoomEvent', e)
|
||||
},
|
||||
mergeOptions (options) {
|
||||
this.$refs.chart_ref.mergeOptions(options)
|
||||
},
|
||||
showLoading (options) {
|
||||
this.$refs.chart_ref.showLoading(options)
|
||||
},
|
||||
hideLoading () {
|
||||
this.$refs.chart_ref.hideLoading()
|
||||
},
|
||||
clear () {
|
||||
this.$refs.chart_ref.clear()
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
this.resizeTimer = setInterval(this.resize, 1000)
|
||||
},
|
||||
destroyed () {
|
||||
clearInterval(this.resizeTimer)
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
.va-card {
|
||||
&__body {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-card>
|
||||
<div class="flex-container">
|
||||
<edit-file-name class="flex-child" :ref="'edit_file_name'"/>
|
||||
<download-file class="flex-child2"/>
|
||||
<delete-file class="flex-child2"/>
|
||||
</div>
|
||||
<show-resample-rate/>
|
||||
<div class="flex-container">
|
||||
<change-window-start-and-size class="flex-child" :ref="'change_window_start_and_size'" @changeOverviewDataZoom="changeOverviewDataZoom"/>
|
||||
<lock-data-zoom class="flex-child2" :chartID="0"/>
|
||||
</div>
|
||||
<change-axis v-show="showXAxis" :ref="'change_axis_x'" axis="x"/>
|
||||
<change-axis v-show="showYAxis" :ref="'change_axis_y'" axis="y"/>
|
||||
<change-unit v-show="showXUnit" :ref="'change_unit_x'" axis="x" @refreshChart="refreshChart"/>
|
||||
<change-unit :ref="'change_unit_y'" class="box_inline-block" axis="y" @refreshChart="refreshChart"/>
|
||||
<change-scale :ref="'change_scale_y'" class="box_inline-block" axis="y"/>
|
||||
<sd-card-toggle :ref="'sd_card_toggle'" :metaIndex="0"/>
|
||||
<show-parameter :ref="'show_param'"/>
|
||||
</va-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ShowResampleRate from '@/components/analysis/replay/toolbox/ShowResampleRate.vue'
|
||||
import ChangeAxis from '@/components/analysis/replay/toolbox/ChangeAxis.vue'
|
||||
import ChangeUnit from '@/components/analysis/replay/toolbox/ChangeUnit.vue'
|
||||
import ChangeScale from '@/components/analysis/replay/toolbox/ChangeScale.vue'
|
||||
import DownloadFile from '@/components/analysis/replay/toolbox/DownloadFile.vue'
|
||||
import DeleteFile from '@/components/analysis/replay/toolbox/DeleteFile.vue'
|
||||
import EditFileName from '@/components/analysis/replay/toolbox/EditFileName.vue'
|
||||
import ShowParameter from '@/components/analysis/replay/toolbox/ShowParameter.vue'
|
||||
import SdCardToggle from '@/components/analysis/replay/toolbox/SdCardToggle.vue'
|
||||
import LockDataZoom from '@/components/analysis/replay/toolbox/LockDataZoom.vue'
|
||||
import ChangeWindowStartAndSize from '@/components/analysis/replay/toolbox/ChangeWindowStartAndSize.vue'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'top-control-panel',
|
||||
components: {
|
||||
ShowResampleRate,
|
||||
ChangeAxis,
|
||||
ChangeUnit,
|
||||
ChangeScale,
|
||||
DownloadFile,
|
||||
DeleteFile,
|
||||
EditFileName,
|
||||
ShowParameter,
|
||||
SdCardToggle,
|
||||
LockDataZoom,
|
||||
ChangeWindowStartAndSize,
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'metaList',
|
||||
'showCyclePanel',
|
||||
]),
|
||||
},
|
||||
async created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
deviceName: '',
|
||||
showXAxis: false,
|
||||
showYAxis: false,
|
||||
showXUnit: false,
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
this.deviceName = this.metaList[0].device.library_name
|
||||
this.$refs.change_axis_x.init(this.deviceName)
|
||||
this.$refs.change_axis_y.init(this.deviceName)
|
||||
this.$refs.change_unit_x.init(this.deviceName)
|
||||
this.$refs.change_unit_y.init(this.deviceName)
|
||||
this.$refs.change_scale_y.init(this.deviceName)
|
||||
this.$refs.edit_file_name.init()
|
||||
this.$refs.show_param.init(this.deviceName)
|
||||
this.$refs.change_window_start_and_size.init()
|
||||
this.$refs.sd_card_toggle.init()
|
||||
},
|
||||
changeOverviewDataZoom () {
|
||||
this.$emit('changeOverviewDataZoom')
|
||||
},
|
||||
refreshChart (options) {
|
||||
this.$emit('refreshChart', options)
|
||||
},
|
||||
},
|
||||
// use watch because va-select with @change will have bug
|
||||
watch: {
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.box_inline-block {
|
||||
padding: 2px;
|
||||
margin: 2px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-child {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.flex-child1 {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.flex-child2 {
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
.flex-child:first-child {
|
||||
margin-right: 1px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-button
|
||||
:color="buttonColor"
|
||||
:key="clickTime"
|
||||
v-model="absToggleStatus[axis]"
|
||||
@click="performABS()"
|
||||
class="round-button px-1 py-1"
|
||||
>
|
||||
ABS
|
||||
</va-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapActions, mapMutations } from 'vuex'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import types from '@/store/modules/analysis/replay/types'
|
||||
|
||||
export default {
|
||||
name: 'AbsToggle',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
displayType () {
|
||||
return {
|
||||
x: this.axisXLabelScale.description === 'Log' ? 'log' : 'value',
|
||||
y: this.axisYLabelScale.description === 'Log' ? 'log' : 'value',
|
||||
}
|
||||
},
|
||||
|
||||
...mapFields('replay', [
|
||||
'chartData',
|
||||
'metaList',
|
||||
'absToggleStatus',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
chartID: {
|
||||
type: Number, // detail data
|
||||
default: 1,
|
||||
},
|
||||
axis: {
|
||||
type: String, // x or y
|
||||
},
|
||||
metaIndex: {
|
||||
type: Number, // which meta file
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
metaID: 0,
|
||||
metaInfo: null,
|
||||
buttonColor: 'gray',
|
||||
clickTime: 0,
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
init (deviceName) {
|
||||
this.deviceName = deviceName
|
||||
this.metaInfo = this.metaList[this.metaIndex]
|
||||
this.metaID = this.metaInfo.id
|
||||
this.absToggleStatus[this.axis] = false
|
||||
},
|
||||
performABS () {
|
||||
this.absToggleStatus[this.axis] = !this.absToggleStatus[this.axis]
|
||||
if (this.deviceName === 'EliteZM15' || this.deviceName === 'EliteEIS') {
|
||||
this.calculateHelper(this.metaIndex) // [TODO] elite tmp use metaIndex for grid index
|
||||
}
|
||||
this.clickTime++
|
||||
this.buttonColor = this.clickTime % 2 === 1 ? 'success' : 'gray'
|
||||
},
|
||||
async calculateHelper (gridIndex) {
|
||||
let seriesData
|
||||
if (this.absToggleStatus[this.axis]) {
|
||||
seriesData = JSON.parse(JSON.stringify(this.chartData[this.chartID].series[gridIndex].data))
|
||||
for (let i = 0; i < seriesData.length; i++) {
|
||||
if (this.axis === 'x') {
|
||||
seriesData[i][0] = Math.abs(seriesData[i][0])
|
||||
} else if (this.axis === 'y') {
|
||||
seriesData[i][1] = Math.abs(seriesData[i][1])
|
||||
}
|
||||
}
|
||||
this.updateSeriesChart({
|
||||
chartID: this.chartID,
|
||||
seriesIndex: gridIndex,
|
||||
data: seriesData,
|
||||
})
|
||||
} else {
|
||||
if (this.deviceName === 'EliteZM15' || this.deviceName === 'EliteEIS') {
|
||||
this.$emit('changeAxis', this.metaIndex) // [TODO] elite tmp use metaIndex for grid index
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
...mapActions('replay', [types.chart.setAxisDisplay]),
|
||||
...mapMutations('replay', [types.chart.updateSeries]),
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.round-button {
|
||||
border-radius: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,328 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="axis === 'x'">
|
||||
<va-select
|
||||
@input="changeAxis()"
|
||||
:label="''"
|
||||
v-if="deviceName!=='EliteEIS'"
|
||||
v-model="channelFormat"
|
||||
textBy="description"
|
||||
class="va-select-without-margin"
|
||||
:options="channelOptions"
|
||||
:noClear='true'
|
||||
/>
|
||||
<va-select
|
||||
@input="changeAxis()"
|
||||
:label="''"
|
||||
v-if="deviceName==='EliteEIS'"
|
||||
v-model="channelFormat"
|
||||
textBy="description"
|
||||
class="va-select-without-margin"
|
||||
:options="eisChannelOptions"
|
||||
:noClear='true'
|
||||
/>
|
||||
</div>
|
||||
<div v-if="axis === 'y'">
|
||||
<va-select
|
||||
@input="changeAxis()"
|
||||
:label="''"
|
||||
v-if="deviceName!=='EliteEIS'"
|
||||
v-model="channelFormat"
|
||||
textBy="description"
|
||||
class="va-select-without-margin"
|
||||
:options="channelYOptions"
|
||||
:noClear='true'
|
||||
/>
|
||||
<va-select
|
||||
@input="changeAxis()"
|
||||
:label="''"
|
||||
v-if="deviceName==='EliteEIS'"
|
||||
v-model="channelFormat"
|
||||
textBy="description"
|
||||
class="va-select-without-margin"
|
||||
:options="eisChannelYOptions"
|
||||
:noClear='true'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'change-axis',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
axis: {
|
||||
type: String, // x or y
|
||||
},
|
||||
metaIndex: {
|
||||
type: Number, // which meta file
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'chartData',
|
||||
'metaList',
|
||||
'axisXDataType',
|
||||
'axisYDataType',
|
||||
'showCyclePanel',
|
||||
]),
|
||||
},
|
||||
methods: {
|
||||
init (deviceName) {
|
||||
this.deviceName = deviceName
|
||||
if (this.deviceName.startsWith('Neulive')) {
|
||||
// now neulive only v-t
|
||||
if (this.axis === 'x') {
|
||||
this.axisXDataType = this.channelOptions[3]
|
||||
} else if (this.axis === 'y') {
|
||||
this.axisYDataType = this.channelOptions[1]
|
||||
}
|
||||
} else if (this.deviceName === 'EliteZM15') {
|
||||
// use state meta to decide which default unit need to be used (like check I-V mode...)
|
||||
const setting = this.GLOBAL.getDefaultChartTypeByMode(this.metaList[this.metaIndex].parameter_set.MODE, this.deviceName)
|
||||
const xType = setting[0]
|
||||
const xValue = setting[1]
|
||||
const yType = setting[2]
|
||||
const yValue = setting[3]
|
||||
let settingType
|
||||
let settingValue
|
||||
if (this.axis === 'x') {
|
||||
settingType = xType
|
||||
settingValue = xValue
|
||||
if (settingType === 'Elite') {
|
||||
// 1: I, 2: V, 3: R
|
||||
if (settingValue === 1) {
|
||||
this.axisXDataType = this.channelOptions[0]
|
||||
} else if (settingValue === 2) {
|
||||
this.axisXDataType = this.channelOptions[1]
|
||||
} else if (settingValue === 3) {
|
||||
this.axisXDataType = this.channelOptions[2]
|
||||
} else if (settingValue === 4) {
|
||||
this.axisXDataType = this.channelOptions[3]
|
||||
}
|
||||
} else if (settingType === 'Time') {
|
||||
this.axisXDataType = this.channelOptions[4]
|
||||
}
|
||||
this.channelFormat = this.axisXDataType
|
||||
} else if (this.axis === 'y') {
|
||||
settingType = yType
|
||||
settingValue = yValue
|
||||
if (settingType === 'Elite') {
|
||||
// 1: I, 2: V, 3: R
|
||||
if (settingValue === 1) {
|
||||
this.axisYDataType = this.channelOptions[0]
|
||||
} else if (settingValue === 2) {
|
||||
this.axisYDataType = this.channelOptions[1]
|
||||
} else if (settingValue === 3) {
|
||||
this.axisYDataType = this.channelOptions[2]
|
||||
} else if (settingValue === 4) {
|
||||
this.axisXDataType = this.channelOptions[3]
|
||||
}
|
||||
} else if (settingType === 'Time') {
|
||||
this.axisYDataType = this.channelOptions[4]
|
||||
}
|
||||
this.channelFormat = this.axisYDataType
|
||||
}
|
||||
} else if (this.deviceName === 'EliteEIS') {
|
||||
const setting = this.GLOBAL.getDefaultChartTypeByMode(this.metaList[this.metaIndex].parameter_set.MODE, this.deviceName)
|
||||
const xType = setting[0]
|
||||
const xValue = setting[1]
|
||||
const yType = setting[2]
|
||||
const yValue = setting[3]
|
||||
let settingType
|
||||
let settingValue
|
||||
if (this.axis === 'x') {
|
||||
settingType = xType
|
||||
settingValue = xValue
|
||||
if (settingType === 'EliteEIS') {
|
||||
this.axisXDataType = this.eisChannelOptions.find(element => element.id === parseInt(settingValue) - 1)
|
||||
} else if (settingType === 'Elite') {
|
||||
// 1: I, 2: V, 3: R
|
||||
if (settingValue === 1) {
|
||||
this.axisXDataType = this.channelOptions[0]
|
||||
} else if (settingValue === 2) {
|
||||
this.axisXDataType = this.channelOptions[1]
|
||||
} else if (settingValue === 3) {
|
||||
this.axisXDataType = this.channelOptions[2]
|
||||
}
|
||||
} else if (settingType === 'Time') {
|
||||
this.axisXDataType = this.channelOptions[3]
|
||||
}
|
||||
this.channelFormat = this.axisXDataType
|
||||
} else if (this.axis === 'y') {
|
||||
settingType = yType
|
||||
settingValue = yValue
|
||||
if (settingType === 'EliteEIS') {
|
||||
this.axisYDataType = this.eisChannelOptions.find(element => element.id === parseInt(settingValue) - 1)
|
||||
} else if (settingType === 'Elite') {
|
||||
// 1: I, 2: V, 3: R
|
||||
if (settingValue === 1) {
|
||||
this.axisYDataType = this.channelOptions[0]
|
||||
} else if (settingValue === 2) {
|
||||
this.axisYDataType = this.channelOptions[1]
|
||||
} else if (settingValue === 3) {
|
||||
this.axisYDataType = this.channelOptions[2]
|
||||
}
|
||||
} else if (settingType === 'Time') {
|
||||
this.axisYDataType = this.channelOptions[3]
|
||||
}
|
||||
this.channelFormat = this.axisYDataType
|
||||
}
|
||||
}
|
||||
if (this.axis === 'y') { // only need to draw once time when init
|
||||
this.changeAxis()
|
||||
}
|
||||
},
|
||||
changeAxis () {
|
||||
if (this.deviceName.startsWith('Neulive')) {
|
||||
// for elite now, cuz neulive now only have v-t graph, for future neulive replay need to adjust'
|
||||
// console.log('(Last updated: 2021/06/19)')
|
||||
} else if (this.deviceName === 'EliteZM15' || this.deviceName === 'EliteEIS') {
|
||||
if (this.axis === 'x') {
|
||||
this.axisXDataType = this.channelFormat
|
||||
} else if (this.axis === 'y') {
|
||||
this.axisYDataType = this.channelFormat
|
||||
}
|
||||
if (this.metaList[this.metaIndex].parameter_set.CYCLE_NUMBER > 0) {
|
||||
this.showCyclePanel = true
|
||||
} else {
|
||||
this.showCyclePanel = false
|
||||
}
|
||||
this.$emit('changeAxis', this.metaIndex) // temporarily use metaIndex for gridIndex
|
||||
this.$emit('changeUnit', this.axis)
|
||||
this.$emit('clearCycle')
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
deviceName: '',
|
||||
channelFormat: {},
|
||||
channelOptions: [
|
||||
{
|
||||
id: 0,
|
||||
description: 'Current',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
description: 'Voltage',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
description: 'Resistance',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
description: 'Cycle',
|
||||
},
|
||||
{
|
||||
id: 100, // no usage, so assign a large number to avoid conflicting with existing channel data
|
||||
description: 'Time',
|
||||
},
|
||||
],
|
||||
channelYOptions: [
|
||||
{
|
||||
id: 0,
|
||||
description: 'Current',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
description: 'Voltage',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
description: 'Resistance',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
description: 'Cycle',
|
||||
},
|
||||
],
|
||||
eisChannelOptions: [ // id 0 (Raw Imag), 1 (Raw Real), 3 (Cycle) 不用給user選
|
||||
{
|
||||
id: 2,
|
||||
description: 'Frequency',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
description: 'Z_imag',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
description: 'Z_real',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
description: 'Impedance',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
description: 'Phase',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
description: 'Current',
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
description: 'Gain Level',
|
||||
},
|
||||
{
|
||||
id: 100, // no usage, so assign a large number to avoid conflicting with existing channel data
|
||||
description: 'Time',
|
||||
},
|
||||
],
|
||||
eisChannelYOptions: [ // id 0 (Raw Imag), 1 (Raw Real), 3 (Cycle) 不用給user選
|
||||
{
|
||||
id: 2,
|
||||
description: 'Frequency',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
description: 'Z_imag',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
description: 'Z_real',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
description: 'Impedance',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
description: 'Phase',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
description: 'Current',
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
description: 'Gain Level',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.va-select-without-margin {
|
||||
.va-select {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-modal
|
||||
class="flex sm12 xl12 md12 xs12"
|
||||
v-model="showModal.minMaxPanel"
|
||||
size="small"
|
||||
:position="position"
|
||||
:title="'Set min max (if blank, will be auto-set)'"
|
||||
:okText=" $t('modal.confirm') "
|
||||
@ok="setMinMax()"
|
||||
>
|
||||
<va-input
|
||||
v-model="minMaxInfo[gridIndex].max"
|
||||
:label="'Max'"
|
||||
/>
|
||||
<va-input
|
||||
v-model="minMaxInfo[gridIndex].min"
|
||||
:label="'Min'"
|
||||
/>
|
||||
</va-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import types from '@/store/modules/analysis/replay/types'
|
||||
|
||||
export default {
|
||||
name: 'change-channel-value-min-max',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
chartID: {
|
||||
type: Number,
|
||||
default: 1, // detail data
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
gridIndex: 0,
|
||||
axis: 'y',
|
||||
showModal: {
|
||||
minMaxPanel: false,
|
||||
},
|
||||
minMaxInfo: { 0: { min: '', max: '' } }, // will be set by init()
|
||||
position: 'center',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'chartData',
|
||||
]),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const len = this.chartData[this.chartID].series.length
|
||||
for (let i = 0; i < len; i++) {
|
||||
this.minMaxInfo[i] = { min: '', max: '' }
|
||||
}
|
||||
},
|
||||
showPanel (params) {
|
||||
if (params.target !== undefined) {
|
||||
if (params.target.eventData.componentType === 'xAxis' && params.target.eventData.targetType === 'axisLabel') {
|
||||
this.gridIndex = params.target.eventData.xAxisIndex
|
||||
this.axis = 'x'
|
||||
this.position = 'bottom'
|
||||
} else if (params.target.eventData.componentType === 'yAxis' && params.target.eventData.targetType === 'axisLabel') {
|
||||
this.gridIndex = params.target.eventData.yAxisIndex
|
||||
this.axis = 'y'
|
||||
this.position = 'left'
|
||||
}
|
||||
this.showModal.minMaxPanel = true
|
||||
}
|
||||
},
|
||||
setMinMax () {
|
||||
this.updateAxisValMinMaxChart({
|
||||
chartID: this.chartID,
|
||||
axis: this.axis,
|
||||
axisIndex: this.gridIndex,
|
||||
minVal: this.minMaxInfo[this.gridIndex].min,
|
||||
maxVal: this.minMaxInfo[this.gridIndex].max,
|
||||
})
|
||||
this.$emit('refreshChart', this.chartData[this.chartID])
|
||||
},
|
||||
...mapMutations('replay', [types.chart.updateAxisValMinMax]),
|
||||
},
|
||||
mounted () {
|
||||
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<div v-if="showPanel">
|
||||
<va-input
|
||||
v-model="showWhichCycles"
|
||||
@change="setCycle"
|
||||
:label="$t('See which cycles')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations, mapGetters } from 'vuex'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import types from '@/store/modules/analysis/replay/types'
|
||||
import { download } from '@/data/download/Download'
|
||||
|
||||
export default {
|
||||
name: 'change-cycle',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
chartID: {
|
||||
type: Number,
|
||||
default: 1, // detail data
|
||||
},
|
||||
metaIndex: {
|
||||
type: Number, // which meta file
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showPanel: false,
|
||||
metaID: 0,
|
||||
cycleNum: 0,
|
||||
cycleDataID: 3, // [TODO] manage by data type factory
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'chartData',
|
||||
'recInfo',
|
||||
'metaList',
|
||||
'currentScale',
|
||||
'sampleMethod',
|
||||
'axisXDataType',
|
||||
'axisYDataType',
|
||||
'axisXLabelScale',
|
||||
'axisYLabelScale',
|
||||
'showWhichCycles',
|
||||
]),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
slices () {
|
||||
const cycleList = this.showWhichCycles.split(',')
|
||||
if (cycleList.length === 1 && cycleList[0] === '') {
|
||||
return ''
|
||||
}
|
||||
for (let i = 0; i < cycleList.length; i++) {
|
||||
const element = cycleList[i]
|
||||
if (element.includes('-')) {
|
||||
const startIndex = element.split('-')[0]
|
||||
const endIndex = element.split('-')[1]
|
||||
cycleList[i] = startIndex
|
||||
for (let j = endIndex; j >= parseInt(startIndex) + 1; j--) {
|
||||
cycleList.splice(i + 1, 0, j.toString()) // arr.splice(index, 0, item); will insert item into arr at the specified index (deleting 0 items first, that is, it's just an insert).
|
||||
}
|
||||
}
|
||||
}
|
||||
const cycleSet = new Set(cycleList)
|
||||
const sortedCycleList = [...cycleSet].sort() // ref: https://stackoverflow.com/questions/33089695/how-can-i-sort-an-es6-set
|
||||
return sortedCycleList
|
||||
},
|
||||
init () {
|
||||
this.cycleNum = this.metaList[this.metaIndex].parameter_set.CYCLE_NUMBER
|
||||
const meta = this.metaList[this.metaIndex]
|
||||
this.metaID = meta.id
|
||||
this.isThisModeHasCycle = this.GLOBAL.hasCycleMode(this.metaList[this.metaIndex].parameter_set.MODE, meta.device.library_name)
|
||||
if (this.isThisModeHasCycle === true) {
|
||||
this.showPanel = true
|
||||
} else {
|
||||
this.showPanel = false
|
||||
}
|
||||
},
|
||||
clear () {
|
||||
this.showWhichCycles = '1'
|
||||
},
|
||||
async setCycle () {
|
||||
console.log('setCycle')
|
||||
if (this.isThisModeHasCycle === true) {
|
||||
const dataCycleList = this.recInfo[this.metaID][this.cycleDataID][this.currentScale]
|
||||
const cycleDataList = []
|
||||
for (let i = 0; i < dataCycleList.length; i++) {
|
||||
if (dataCycleList[i].data.length === 0) {
|
||||
const data = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataCycleList[i].id, this.cycleDataID, this.metaList[this.metaIndex])
|
||||
cycleDataList.push({ data: data })
|
||||
} else {
|
||||
cycleDataList.push({ data: dataCycleList[i].data })
|
||||
}
|
||||
}
|
||||
const cycleDict = this.getCycleDictRec()(cycleDataList)
|
||||
this.cycleNum = Object.keys(cycleDict).length
|
||||
let dataXList
|
||||
if (this.axisXDataType.description !== 'Time') {
|
||||
dataXList = this.recInfo[this.metaID][this.axisXDataType.id][this.currentScale]
|
||||
}
|
||||
const dataYList = this.recInfo[this.metaID][this.axisYDataType.id][this.currentScale]
|
||||
const filteredData = []
|
||||
|
||||
let counter = 0
|
||||
for (let sliceIndex = 0; sliceIndex < this.cycleNum; sliceIndex++) {
|
||||
// console.log(this.slices)
|
||||
if (this.slices() === '' || this.slices().includes((sliceIndex + 1).toString())) {
|
||||
// slice data
|
||||
const value = cycleDict[sliceIndex + 1]
|
||||
const startTime = value[0]
|
||||
const endTime = value[1]
|
||||
let startIndex = 0
|
||||
let endIndex = 0
|
||||
for (let i = 0; i < dataYList.length; i++) {
|
||||
if (startTime >= parseInt(dataYList[i].start_time) && startTime <= parseInt(dataYList[i].end_time)) {
|
||||
startIndex = i
|
||||
}
|
||||
if (endTime >= parseInt(dataYList[i].start_time) && endTime <= parseInt(dataYList[i].end_time)) {
|
||||
endIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = startIndex; i <= endIndex; i++) {
|
||||
const dataY = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataYList[i].id, this.axisYDataType.id, this.metaList[this.metaIndex])
|
||||
if (this.axisXDataType.description !== 'Time') {
|
||||
const dataX = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataXList[i].id, this.axisXDataType.id, this.metaList[this.metaIndex])
|
||||
for (let j = 0, len = dataY.length; j < len; j++) {
|
||||
if (parseInt(dataY[j][0]) >= startTime && parseInt(dataY[j][0]) <= endTime) {
|
||||
let x
|
||||
let y
|
||||
if (this.axisXLabelScale.description === 'Log') {
|
||||
x = Math.abs(dataX[j][1])
|
||||
} else if (this.axisXLabelScale.description === 'Linear') {
|
||||
x = dataX[j][1]
|
||||
}
|
||||
if (this.axisYLabelScale.description === 'Log') {
|
||||
y = Math.abs(dataY[j][1])
|
||||
} else if (this.axisYLabelScale.description === 'Linear') {
|
||||
y = dataY[j][1]
|
||||
}
|
||||
filteredData.push([x, y])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let j = 0, len = dataY.length; j < len; j++) {
|
||||
if (parseInt(dataY[j][0]) >= startTime && parseInt(dataY[j][0]) <= endTime) {
|
||||
if (this.axisYLabelScale.description === 'Log') {
|
||||
dataY[j][1] = Math.abs(dataY[j][1])
|
||||
} else if (this.axisYLabelScale.description === 'Linear') {
|
||||
// do nothing
|
||||
}
|
||||
filteredData.push(dataY[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.updateSeriesChart({
|
||||
chartID: this.chartID,
|
||||
seriesIndex: this.metaIndex,
|
||||
data: filteredData,
|
||||
})
|
||||
if (this.axisXDataType.description === 'Time') {
|
||||
if (counter === 0) {
|
||||
this.chartData[this.chartID].xAxis[this.metaIndex].min = startTime
|
||||
}
|
||||
this.chartData[this.chartID].xAxis[this.metaIndex].max = endTime
|
||||
counter++
|
||||
}
|
||||
// this.$emit('refreshChart', this.chartData[this.chartID])
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getData: async function (scale, sampleMethod, id, channel, meta) {
|
||||
if (scale === 1) {
|
||||
return await download.rawByIDChannels(id, channel, meta)
|
||||
} else {
|
||||
if (sampleMethod === 'mean') {
|
||||
return await download.miniMeanByIDChannel(id, channel, meta)
|
||||
} else if (sampleMethod === 'random') {
|
||||
return await download.miniRandomByIDChannel(id, channel, meta)
|
||||
}
|
||||
}
|
||||
},
|
||||
...mapMutations('replay', [types.chart.updateSeries]),
|
||||
...mapGetters('replay', [types.rec.getCycleDict]),
|
||||
},
|
||||
mounted () {
|
||||
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,196 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-select
|
||||
@input="changeScale()"
|
||||
:label="''"
|
||||
v-model="scaleFormat"
|
||||
textBy="description"
|
||||
class="va-select-without-margin"
|
||||
:options="scaleOptions"
|
||||
:noClear='true'
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapMutations, mapGetters } from 'vuex'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import types from '@/store/modules/analysis/replay/types'
|
||||
import { download } from '@/data/download/Download'
|
||||
|
||||
export default {
|
||||
name: 'change-scale',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
chartID: {
|
||||
type: Number, // detail data
|
||||
default: 1,
|
||||
},
|
||||
axis: {
|
||||
type: String, // x or y
|
||||
},
|
||||
metaIndex: {
|
||||
type: Number, // which meta file
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
computed: {
|
||||
displayType () {
|
||||
return {
|
||||
x: this.axisXLabelScale.description === 'Log' ? 'log' : 'value',
|
||||
y: this.axisYLabelScale.description === 'Log' ? 'log' : 'value',
|
||||
}
|
||||
},
|
||||
|
||||
...mapFields('replay', [
|
||||
'chartData',
|
||||
'recInfo',
|
||||
'metaList',
|
||||
'axisXLabelScale',
|
||||
'axisYLabelScale',
|
||||
'axisXDataType',
|
||||
'axisYDataType',
|
||||
'absToggleStatus',
|
||||
'startTimeCurrent',
|
||||
'endTimeCurrent',
|
||||
'currentScale',
|
||||
'sampleMethod',
|
||||
]),
|
||||
},
|
||||
methods: {
|
||||
init (deviceName) {
|
||||
this.deviceName = deviceName
|
||||
this.metaInfo = this.metaList[this.metaIndex]
|
||||
this.metaID = this.metaInfo.id
|
||||
if (this.axis === 'x') {
|
||||
this.axisXLabelScale = this.scaleOptions[0] // 0 mean use default unit
|
||||
this.scaleFormat = this.axisXLabelScale
|
||||
} else if (this.axis === 'y') {
|
||||
this.axisYLabelScale = this.scaleOptions[0] // 0 mean use default unit
|
||||
this.scaleFormat = this.axisYLabelScale
|
||||
}
|
||||
},
|
||||
changeScale () {
|
||||
if (this.axis === 'x') {
|
||||
this.axisXLabelScale = this.scaleFormat
|
||||
} else if (this.axis === 'y') {
|
||||
this.axisYLabelScale = this.scaleFormat
|
||||
}
|
||||
if (this.deviceName.startsWith('Neulive')) {
|
||||
const keys = Object.keys(this.metaInfo.mini_data)
|
||||
for (let gridIndex = 0; gridIndex < keys.length; gridIndex++) {
|
||||
const ch = keys[gridIndex]
|
||||
if (parseInt(ch) < 256) { // 256: x, 257: y, 258: z, 259: mag
|
||||
this.calculateScaleHelper(gridIndex, ch)
|
||||
}
|
||||
}
|
||||
} else if (this.deviceName === 'EliteZM15' || this.deviceName === 'EliteEIS') {
|
||||
this.calculateScaleHelper(this.metaIndex, -1) // [TODO] elite tmp use metaIndex for grid index
|
||||
}
|
||||
},
|
||||
async calculateScaleHelper (gridIndex, ch) {
|
||||
let seriesData
|
||||
if (this.scaleFormat.description === 'Log') {
|
||||
seriesData = JSON.parse(JSON.stringify(this.chartData[this.chartID].series[gridIndex].data))
|
||||
for (let i = 0; i < seriesData.length; i++) {
|
||||
if (this.axis === 'x') {
|
||||
seriesData[i][0] = Math.abs(seriesData[i][0])
|
||||
} else if (this.axis === 'y') {
|
||||
seriesData[i][1] = Math.abs(seriesData[i][1])
|
||||
}
|
||||
}
|
||||
this.updateSeriesChart({
|
||||
chartID: this.chartID,
|
||||
seriesIndex: gridIndex,
|
||||
data: seriesData,
|
||||
})
|
||||
} else if (this.scaleFormat.description === 'Linear') {
|
||||
// console.log(this.recInfo)
|
||||
if (this.deviceName.startsWith('Neulive')) {
|
||||
// [Region] get the subfile index
|
||||
seriesData = []
|
||||
const dataYList = this.recInfo[this.metaID][ch][this.currentScale]
|
||||
let startIndex = 0
|
||||
let endIndex = 0
|
||||
for (let i = 0; i < dataYList.length; i++) {
|
||||
if (this.startTimeCurrent >= parseInt(dataYList[i].start_time) && this.startTimeCurrent <= parseInt(dataYList[i].end_time)) {
|
||||
startIndex = i
|
||||
}
|
||||
if (this.endTimeCurrent >= parseInt(dataYList[i].start_time) && this.endTimeCurrent <= parseInt(dataYList[i].end_time)) {
|
||||
endIndex = i
|
||||
}
|
||||
}
|
||||
// [EndRegion]
|
||||
for (let i = startIndex; i <= endIndex; i++) {
|
||||
const data = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataYList[i].id, ch, this.metaInfo)
|
||||
for (let j = 0, len = data.length; j < len; j++) {
|
||||
if (parseInt(data[j][0]) >= this.startTimeCurrent && parseInt(data[j][0]) <= this.endTimeCurrent) {
|
||||
const processedData = data[j]
|
||||
if (this.displayType.x === 'log' || this.absToggleStatus.x === true) {
|
||||
processedData[0] = Math.abs(processedData[0])
|
||||
}
|
||||
if (this.displayType.y === 'log' || this.absToggleStatus.y === true) {
|
||||
processedData[1] = Math.abs(processedData[1])
|
||||
}
|
||||
seriesData.push(processedData)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this.deviceName === 'EliteZM15' || this.deviceName === 'EliteEIS') {
|
||||
this.$emit('changeAxis', this.metaIndex)
|
||||
this.$emit('clearCycle')
|
||||
}
|
||||
}
|
||||
this.setAxisDisplayChart({ type: this.displayType[this.axis], axis: this.axis, chartID: this.chartID, gridIndex: gridIndex })
|
||||
},
|
||||
getData: async function (scale, sampleMethod, id, channel, meta) {
|
||||
if (scale === 1) {
|
||||
return await download.rawByIDChannels(id, channel, meta)
|
||||
} else {
|
||||
if (sampleMethod === 'mean') {
|
||||
return await download.miniMeanByIDChannel(id, channel, meta)
|
||||
} else if (sampleMethod === 'random') {
|
||||
return await download.miniRandomByIDChannel(id, channel, meta)
|
||||
}
|
||||
}
|
||||
},
|
||||
...mapActions('replay', [types.chart.setAxisDisplay]),
|
||||
...mapMutations('replay', [types.chart.updateSeries]),
|
||||
...mapGetters('replay', [types.rec.getCycleDict]),
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
deviceName: '',
|
||||
metaID: 0,
|
||||
metaInfo: null,
|
||||
scaleFormat: { id: 0, description: 'Linear' },
|
||||
scaleOptions: [
|
||||
{
|
||||
id: 0,
|
||||
description: 'Linear',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
description: 'Log',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.va-select-without-margin {
|
||||
.va-select {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,414 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-select
|
||||
@input="changeUnit()"
|
||||
:label="''"
|
||||
v-if="deviceName!=='EliteEIS'"
|
||||
v-model="valueFormat"
|
||||
textBy="unit"
|
||||
class="va-select-without-margin"
|
||||
:options="valueFormatOptions[dataType]"
|
||||
:noClear='true'
|
||||
/>
|
||||
<va-select
|
||||
@input="changeUnit()"
|
||||
:label="''"
|
||||
v-if="deviceName==='EliteEIS'"
|
||||
v-model="valueFormat"
|
||||
textBy="unit"
|
||||
class="va-select-without-margin"
|
||||
:options="eisValueFormatOptions[dataType]"
|
||||
:noClear='true'
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import types from '@/store/modules/analysis/replay/types'
|
||||
|
||||
export default {
|
||||
name: 'change-unit',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
axis: {
|
||||
type: String, // x or y
|
||||
},
|
||||
metaIndex: {
|
||||
type: Number, // which meta file
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'chartData',
|
||||
'metaList',
|
||||
'valueFormatX',
|
||||
'valueFormatY',
|
||||
'axisXDataType',
|
||||
'axisYDataType',
|
||||
]),
|
||||
},
|
||||
methods: {
|
||||
initDefaultUnit (axis) {
|
||||
if (this.deviceName.startsWith('Neulive')) {
|
||||
if (axis === 'x') {
|
||||
return this.valueFormatOptions[this.dataType].find(function (item, index, array) {
|
||||
return item.unit === 'auto'
|
||||
})
|
||||
} else if (axis === 'y') {
|
||||
return this.valueFormatOptions[this.dataType].find(function (item, index, array) {
|
||||
return item.unit === 'uV'
|
||||
})
|
||||
}
|
||||
} else if (this.deviceName === 'EliteZM15') {
|
||||
return this.valueFormatOptions[this.dataType][0]
|
||||
} else if (this.deviceName === 'EliteEIS') {
|
||||
return this.eisValueFormatOptions[this.dataType][0]
|
||||
}
|
||||
},
|
||||
init (deviceName) {
|
||||
this.deviceName = deviceName
|
||||
if (this.deviceName.startsWith('Neulive')) {
|
||||
// now neulive only v-t
|
||||
if (this.axis === 'x') {
|
||||
this.dataType = 'time'
|
||||
} else if (this.axis === 'y') {
|
||||
this.dataType = 'voltage'
|
||||
}
|
||||
} else if (this.deviceName === 'EliteZM15') {
|
||||
// use state meta to decide which default unit need to be used (like check I-V mode...)
|
||||
const setting = this.GLOBAL.getDefaultChartTypeByMode(this.metaList[this.metaIndex].parameter_set.MODE, this.deviceName)
|
||||
const xType = setting[0]
|
||||
const xValue = setting[1]
|
||||
const yType = setting[2]
|
||||
const yValue = setting[3]
|
||||
let settingType
|
||||
let settingValue
|
||||
if (this.axis === 'x') {
|
||||
settingType = xType
|
||||
settingValue = xValue
|
||||
} else if (this.axis === 'y') {
|
||||
settingType = yType
|
||||
settingValue = yValue
|
||||
}
|
||||
|
||||
if (settingType === 'Elite') {
|
||||
// 1: I, 2: V, 3: R
|
||||
if (settingValue === 1) {
|
||||
this.dataType = 'current'
|
||||
} else if (settingValue === 2) {
|
||||
this.dataType = 'voltage'
|
||||
} else if (settingValue === 3) {
|
||||
this.dataType = 'resistance'
|
||||
} else if (settingValue === 4) {
|
||||
this.dataType = 'cycle'
|
||||
}
|
||||
} else if (settingType === 'Time') {
|
||||
this.dataType = 'time'
|
||||
}
|
||||
} else if (this.deviceName === 'EliteEIS') {
|
||||
const setting = this.GLOBAL.getDefaultChartTypeByMode(this.metaList[this.metaIndex].parameter_set.MODE, this.deviceName)
|
||||
const xType = setting[0]
|
||||
const xValue = setting[1]
|
||||
const yType = setting[2]
|
||||
const yValue = setting[3]
|
||||
let settingType
|
||||
let settingValue
|
||||
if (this.axis === 'x') {
|
||||
settingType = xType
|
||||
settingValue = xValue
|
||||
} else if (this.axis === 'y') {
|
||||
settingType = yType
|
||||
settingValue = yValue
|
||||
}
|
||||
|
||||
if (settingType === 'EliteEIS') {
|
||||
if (settingValue === 3) {
|
||||
this.dataType = 'frequency'
|
||||
} else if (settingValue === 5 || settingValue === 6 || settingValue === 7) {
|
||||
this.dataType = 'impedance'
|
||||
} else if (settingValue === 8) {
|
||||
this.dataType = 'phase'
|
||||
} else if (settingValue === 9) {
|
||||
this.dataType = 'current'
|
||||
} else if (settingValue === 10) {
|
||||
this.dataType = 'default'
|
||||
}
|
||||
} else if (settingType === 'Elite') {
|
||||
// 1: I, 2: V, 3: R
|
||||
if (settingValue === 1) {
|
||||
this.dataType = 'current'
|
||||
} else if (settingValue === 2) {
|
||||
this.dataType = 'voltage'
|
||||
} else if (settingValue === 3) {
|
||||
this.dataType = 'resistance'
|
||||
}
|
||||
} else if (settingType === 'Time') {
|
||||
this.dataType = 'time'
|
||||
}
|
||||
}
|
||||
if (this.axis === 'x') {
|
||||
this.valueFormatX = this.initDefaultUnit(this.axis)
|
||||
this.valueFormat = this.valueFormatX
|
||||
} else if (this.axis === 'y') {
|
||||
this.valueFormatY = this.initDefaultUnit(this.axis)
|
||||
this.valueFormat = this.valueFormatY
|
||||
}
|
||||
this.changeUnit()
|
||||
},
|
||||
changeUnit () {
|
||||
if (this.axis === 'x') {
|
||||
this.valueFormatX = this.valueFormat
|
||||
} else if (this.axis === 'y') {
|
||||
this.valueFormatY = this.valueFormat
|
||||
}
|
||||
const chartID = 1 // detail data
|
||||
if (this.deviceName.startsWith('Neulive')) {
|
||||
const keys = Object.keys(this.metaList[this.metaIndex].mini_data)
|
||||
for (let axisIndex = 0; axisIndex < keys.length; axisIndex++) {
|
||||
const key = keys[axisIndex]
|
||||
this.updateAxisLabelChart({
|
||||
chartID: chartID,
|
||||
axis: this.axis,
|
||||
axisIndex: axisIndex,
|
||||
channel: parseInt(key),
|
||||
})
|
||||
}
|
||||
} else if (this.deviceName === 'EliteZM15' || this.deviceName === 'EliteEIS') {
|
||||
this.updateAxisLabelChart({
|
||||
chartID: chartID,
|
||||
axis: this.axis,
|
||||
axisIndex: this.metaIndex,
|
||||
channel: -1, // any num < 256, cuz channel only use for determining whether add unit text
|
||||
})
|
||||
}
|
||||
this.$emit('refreshChart', this.chartData[chartID])
|
||||
},
|
||||
changeUnitByAxis () {
|
||||
if (this.axis === 'x') {
|
||||
if (this.axisXDataType.description === 'Current') {
|
||||
this.dataType = 'current'
|
||||
} else if (this.axisXDataType.description === 'Voltage') {
|
||||
this.dataType = 'voltage'
|
||||
} else if (this.axisXDataType.description === 'Resistance') {
|
||||
this.dataType = 'resistance'
|
||||
} else if (this.axisXDataType.description === 'Time') {
|
||||
this.dataType = 'time'
|
||||
} else if (this.axisXDataType.description === 'Cycle') {
|
||||
this.dataType = 'cycle'
|
||||
} else if (this.axisXDataType.description === 'Frequency') {
|
||||
this.dataType = 'frequency'
|
||||
} else if (this.axisXDataType.description === 'Z_imag' || this.axisXDataType.description === 'Z_real' || this.axisXDataType.description === 'Impedance') {
|
||||
this.dataType = 'impedance'
|
||||
} else if (this.axisXDataType.description === 'Phase') {
|
||||
this.dataType = 'phase'
|
||||
} else if (this.axisXDataType.description === 'Gain Level') {
|
||||
this.dataType = 'default'
|
||||
}
|
||||
} else if (this.axis === 'y') {
|
||||
if (this.axisYDataType.description === 'Current') {
|
||||
this.dataType = 'current'
|
||||
} else if (this.axisYDataType.description === 'Voltage') {
|
||||
this.dataType = 'voltage'
|
||||
} else if (this.axisYDataType.description === 'Resistance') {
|
||||
this.dataType = 'resistance'
|
||||
} else if (this.axisYDataType.description === 'Cycle') {
|
||||
this.dataType = 'cycle'
|
||||
} else if (this.axisYDataType.description === 'Frequency') {
|
||||
this.dataType = 'frequency'
|
||||
} else if (this.axisYDataType.description === 'Z_imag' || this.axisYDataType.description === 'Z_real' || this.axisYDataType.description === 'Impedance') {
|
||||
this.dataType = 'impedance'
|
||||
} else if (this.axisYDataType.description === 'Phase') {
|
||||
this.dataType = 'phase'
|
||||
} else if (this.axisYDataType.description === 'Gain Level') {
|
||||
this.dataType = 'default'
|
||||
}
|
||||
}
|
||||
if (this.deviceName === 'EliteZM15') {
|
||||
this.valueFormat = this.valueFormatOptions[this.dataType][0]
|
||||
} else if (this.deviceName === 'EliteEIS') {
|
||||
this.valueFormat = this.eisValueFormatOptions[this.dataType][0]
|
||||
}
|
||||
this.changeUnit()
|
||||
},
|
||||
// call vuex to mutate chart label formatter by unit and axis
|
||||
...mapMutations('replay', [types.chart.updateAxisLabel]),
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
deviceName: '',
|
||||
dataType: '',
|
||||
valueFormat: {},
|
||||
valueFormatOptions: { // below id: 0 mean default
|
||||
current: [
|
||||
{
|
||||
id: 1,
|
||||
unit: 'uA',
|
||||
unitScale: 1000,
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
unit: 'nA',
|
||||
unitScale: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
unit: 'mA',
|
||||
unitScale: 1000000,
|
||||
},
|
||||
],
|
||||
voltage: [ // Voltage
|
||||
{
|
||||
id: 1,
|
||||
unit: 'mV',
|
||||
unitScale: 1000,
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
unit: 'uV',
|
||||
unitScale: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
unit: 'V',
|
||||
unitScale: 1000000,
|
||||
},
|
||||
],
|
||||
resistance: [ // Resistance
|
||||
{
|
||||
id: 1,
|
||||
unit: 'Ω',
|
||||
unitScale: 1000,
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
unit: 'mΩ',
|
||||
unitScale: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
unit: 'kΩ',
|
||||
unitScale: 1000000,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
unit: 'MΩ',
|
||||
unitScale: 1000000000,
|
||||
},
|
||||
],
|
||||
cycle: [ // Time
|
||||
{
|
||||
id: 0,
|
||||
unit: 'cycle',
|
||||
unitScale: 1,
|
||||
},
|
||||
],
|
||||
time: [ // Time
|
||||
{
|
||||
id: 0,
|
||||
unit: 'auto',
|
||||
unitScale: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
eisValueFormatOptions: { // below id: 0 mean default
|
||||
default: [
|
||||
{
|
||||
id: 0,
|
||||
unit: 'default',
|
||||
unitScale: 1,
|
||||
},
|
||||
],
|
||||
current: [
|
||||
{
|
||||
id: 0,
|
||||
unit: 'nA',
|
||||
unitScale: 1,
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
unit: 'uA',
|
||||
unitScale: 1e3,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
unit: 'mA',
|
||||
unitScale: 1e6,
|
||||
},
|
||||
],
|
||||
frequency: [ // Frequency
|
||||
{
|
||||
id: 0,
|
||||
unit: 'mHz',
|
||||
unitScale: 1,
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
unit: 'Hz',
|
||||
unitScale: 1e3,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
unit: 'kHz',
|
||||
unitScale: 1e6,
|
||||
},
|
||||
],
|
||||
impedance: [ // Impedance
|
||||
{
|
||||
id: 1,
|
||||
unit: 'Ω',
|
||||
unitScale: 1,
|
||||
},
|
||||
{
|
||||
id: 0,
|
||||
unit: 'mΩ',
|
||||
unitScale: 1e-3,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
unit: 'kΩ',
|
||||
unitScale: 1e3,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
unit: 'MΩ',
|
||||
unitScale: 1e6,
|
||||
},
|
||||
],
|
||||
time: [ // Time
|
||||
{
|
||||
id: 0,
|
||||
unit: 'auto',
|
||||
unitScale: 1,
|
||||
},
|
||||
],
|
||||
phase: [ // Phase
|
||||
{
|
||||
id: 0,
|
||||
unit: '°',
|
||||
unitScale: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.va-select-without-margin {
|
||||
.va-select {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
|
||||
<div class="flex sm4 xl4 md4 xs4 px-0 mx-0">
|
||||
<p class="display-6">Window size<p/>
|
||||
</div>
|
||||
<div class="flex sm8 xl8 md8 xs8 px-0 mx-0">
|
||||
<va-input
|
||||
@keyup.enter="itemChange(windowSize)"
|
||||
@blur="itemChange(windowSize)"
|
||||
v-model="windowSize"
|
||||
class="mb-0"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
µs
|
||||
</p>
|
||||
</va-input>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'ChangeWindowSize',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'startTimeCurrent',
|
||||
'endTimeCurrent',
|
||||
'windowSize',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
itemChange (val) {
|
||||
this.windowSize = parseInt(val)
|
||||
// this.endTimeCurrent = this.startTimeCurrent + parseInt(val)
|
||||
// this.$emit('reDraw')
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div class="row flex sm12 xl12 md12 xs12 px-0 py-0 mx-0 my-0">
|
||||
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
|
||||
<p class="display-6"> Window Start <p/>
|
||||
<va-input
|
||||
@keyup.enter="startItemChange(startTimeInput)"
|
||||
@blur="startItemChange(startTimeInput)"
|
||||
v-model="startTimeInput"
|
||||
class="mb-0 flex-child"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
ms
|
||||
</p>
|
||||
</va-input>
|
||||
</div>
|
||||
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
|
||||
<p class="display-6"> Window Size <p/>
|
||||
<va-input
|
||||
@keyup.enter="lenItemChange(windowLengthInput)"
|
||||
@blur="lenItemChange(windowLengthInput)"
|
||||
v-model="windowLengthInput"
|
||||
class="mb-0 flex-child"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
ms
|
||||
</p>
|
||||
</va-input>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'change-window-start-and-size',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
},
|
||||
computed: {
|
||||
startTimeInput: {
|
||||
get () {
|
||||
return this.startTime / 1e3
|
||||
},
|
||||
set (val) {
|
||||
this.startTime = val * 1e3
|
||||
this.endTime = this.startTime + this.windowLength
|
||||
},
|
||||
},
|
||||
windowLengthInput: {
|
||||
get () {
|
||||
return this.windowLength / 1e3
|
||||
},
|
||||
set (val) {
|
||||
this.windowLength = val * 1e3
|
||||
this.endTime = this.startTime + this.windowLength
|
||||
},
|
||||
},
|
||||
|
||||
...mapFields('replay', [
|
||||
'startTime',
|
||||
'endTime',
|
||||
'windowLength',
|
||||
]),
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
this.windowLength = parseInt(this.endTime) - parseInt(this.startTime)
|
||||
},
|
||||
startItemChange (val) {
|
||||
this.startTime = parseInt(val * 1e3) // us
|
||||
this.windowLength = parseInt(this.windowLength)
|
||||
this.endTime = this.startTime + this.windowLength
|
||||
this.$emit('changeOverviewDataZoom')
|
||||
},
|
||||
lenItemChange (val) {
|
||||
this.startTime = parseInt(this.startTime)
|
||||
this.windowLength = parseInt(val * 1e3) // us
|
||||
this.endTime = this.startTime + this.windowLength
|
||||
this.$emit('changeOverviewDataZoom')
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.flex-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-child {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.flex-child2 {
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
.flex-child:first-child {
|
||||
margin-right: 1px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-button flat small color="gray" icon="fa fa-trash" @click.stop="deleteFileConfirm()"/>
|
||||
<va-modal
|
||||
v-model="showModal.deleteFile"
|
||||
size="small"
|
||||
:title="'DELETE'"
|
||||
:message="`Delete File?`"
|
||||
:okText=" $t('modal.confirm') "
|
||||
@ok="deleteFile()"
|
||||
>
|
||||
</va-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from '@/data/api/index'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'delete-file',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showModal: {
|
||||
deleteFile: false,
|
||||
},
|
||||
deleteInfoList: [],
|
||||
deleteInfoTemplate: {
|
||||
path: '',
|
||||
name: '',
|
||||
metaID: 0, // id will be set later
|
||||
rawChannelAndIDArrays: [], // list of lists
|
||||
miniChannelAndIDArrays: [], // list of lists
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'metaList',
|
||||
]),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
deleteFileConfirm: function () {
|
||||
for (let i = 0; i < this.metaList.length; i++) {
|
||||
const info = this.metaList[i]
|
||||
this.deleteInfoTemplate.path = info.path
|
||||
this.deleteInfoTemplate.name = info.name
|
||||
this.deleteInfoTemplate.metaID = info.id
|
||||
this.deleteInfoTemplate.rawChannelAndIDArrays = [] // list of lists
|
||||
this.deleteInfoTemplate.miniChannelAndIDArrays = [] // list of lists
|
||||
for (const [channel, idArray] of Object.entries(info.raw_data)) {
|
||||
this.deleteInfoTemplate.rawChannelAndIDArrays.push([channel, idArray[0]])
|
||||
}
|
||||
for (const [channel, scaleObject] of Object.entries(info.mini_data)) {
|
||||
for (const idArray of Object.values(scaleObject)) {
|
||||
this.deleteInfoTemplate.miniChannelAndIDArrays.push([channel, idArray[0]])
|
||||
}
|
||||
}
|
||||
this.deleteInfoList.push(JSON.parse(JSON.stringify(this.deleteInfoTemplate))) // deep copy data
|
||||
}
|
||||
this.showModal.deleteFile = true
|
||||
},
|
||||
deleteFile: async function () {
|
||||
for (let i = 0; i < this.deleteInfoList.length; i++) {
|
||||
const deleteInfo = this.deleteInfoList[i]
|
||||
await api.meta.update(deleteInfo.metaID, { deleted: true })
|
||||
await api.meta.clearDel()
|
||||
}
|
||||
await this.deleteFileDone()
|
||||
},
|
||||
deleteFileDone: async function () {
|
||||
this.showToast('Deleted success', {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
this.$router.go(-1)
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-button flat small color="gray" icon="fa fa-download" @click.stop="downloadCSV()"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { download } from '@/data/download/Download'
|
||||
// import { exportData } from '@/data/export/export'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'download-file',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'metaList',
|
||||
]),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
downloadCSV: async function () {
|
||||
for (let i = 0; i < this.metaList.length; i++) {
|
||||
const meta = this.metaList[i]
|
||||
if (meta.device.library_name.indexOf('Elite') >= 0) {
|
||||
window.open('http://' + location.href.split('/')[2].split(':')[0] + '/#/download/excel/' + meta.id)
|
||||
} else if (meta.device.library_name.indexOf('Neulive') >= 0) {
|
||||
window.open('http://' + location.href.split('/')[2].split(':')[0] + '/#/download/csv/' + meta.id)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-button flat small color="gray" icon="fa fa-file-text-o" @click.stop="editFileConfirm()"> {{ filename }} </va-button>
|
||||
<va-modal
|
||||
class="flex sm12 xl12 md12 xs12"
|
||||
v-model="showModal.editFile"
|
||||
size="small"
|
||||
:title="'CHANGE FILE NAME'"
|
||||
:okText=" $t('modal.confirm') "
|
||||
@ok="editFile()"
|
||||
@cancel="undoEdit()"
|
||||
>
|
||||
<va-input
|
||||
:value="editInfo.changedName"
|
||||
:label="'Name'"
|
||||
:placeholder="editInfo.name"
|
||||
:success="editInfo.success"
|
||||
:error="editInfo.error"
|
||||
:error-messages="editInfo.errorMessages"
|
||||
@input="checkFileNameValidate"
|
||||
removable
|
||||
/>
|
||||
</va-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from '@/data/api/index'
|
||||
import { debounce } from 'lodash'
|
||||
import { file } from '@/data/file/File'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'edit-file-name',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
fileLists: [],
|
||||
showModal: {
|
||||
editFile: false,
|
||||
},
|
||||
editInfo: {
|
||||
info: { id: 0 }, // id will be set in init()
|
||||
changedName: '',
|
||||
success: false,
|
||||
error: false,
|
||||
errorMessagesAll: ['File name contains illegal character', 'File name empty', 'File name exist'],
|
||||
errorMessages: [],
|
||||
},
|
||||
filename: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'metaList',
|
||||
]),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
// [TODO] 0: not sure future UX design
|
||||
const meta = this.metaList[0]
|
||||
this.updateFileLists()
|
||||
this.filename = meta.name
|
||||
this.editInfo.changedName = meta.name
|
||||
this.editInfo.info.id = meta.id
|
||||
},
|
||||
editFileConfirm () {
|
||||
this.updateFileLists()
|
||||
this.showModal.editFile = true
|
||||
},
|
||||
async updateFileLists () {
|
||||
this.fileLists = []
|
||||
// [TODO] 0: not sure future UX design
|
||||
const meta = this.metaList[0]
|
||||
file.clearFileList()
|
||||
const files = await api.meta.getByParent('folder', meta.parent.folder[0])
|
||||
file.updateFileList(files)
|
||||
const tmpFiles = file.getFileList()
|
||||
for (let i = 0; i < tmpFiles.length; i++) {
|
||||
const tmp = tmpFiles[i]
|
||||
this.fileLists.push(tmp)
|
||||
}
|
||||
},
|
||||
editFile: async function () {
|
||||
if (this.editInfo.success === true) {
|
||||
await api.meta.update(this.editInfo.info.id, { name: this.editInfo.changedName })
|
||||
this.editInfo.name = this.editInfo.changedName
|
||||
this.filename = this.editInfo.changedName
|
||||
}
|
||||
},
|
||||
undoEdit: function () {
|
||||
this.editInfo.success = false
|
||||
this.editInfo.error = false
|
||||
this.editInfo.changedName = this.filename
|
||||
this.editInfo.name = ''
|
||||
this.editInfo.path = ''
|
||||
},
|
||||
checkFileNameValidate: debounce(function (term) {
|
||||
const illegalChar = term.match(/[^(\w\-)]+/gm)
|
||||
if (term.length === 0) {
|
||||
// input text empty
|
||||
this.editInfo.error = true
|
||||
this.editInfo.success = false
|
||||
this.editInfo.errorMessages.pop()
|
||||
this.editInfo.errorMessages.push(this.editInfo.errorMessagesAll[1])
|
||||
} else if (illegalChar !== null) {
|
||||
// input text illegal
|
||||
this.editInfo.error = true
|
||||
this.editInfo.success = false
|
||||
this.editInfo.errorMessages.pop()
|
||||
this.editInfo.errorMessages.push(this.editInfo.errorMessagesAll[0] + ' ' + illegalChar[0])
|
||||
} else {
|
||||
const existedFile = this.fileLists.filter(file => file.name.replace('/', '') === term)
|
||||
if (existedFile.length === 0) {
|
||||
this.editInfo.error = false
|
||||
this.editInfo.success = true
|
||||
} else {
|
||||
// file name exist
|
||||
this.editInfo.error = true
|
||||
this.editInfo.success = false
|
||||
this.editInfo.errorMessages.pop()
|
||||
this.editInfo.errorMessages.push(this.editInfo.errorMessagesAll[2])
|
||||
}
|
||||
}
|
||||
this.editInfo.changedName = term
|
||||
}, 200),
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-button :icon="icon" @click="lockDataZoom"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapMutations } from 'vuex'
|
||||
import types from '@/store/modules/analysis/replay/types'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'lock-data-zoom',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
chartID: {
|
||||
type: Number, // detail data
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icon: 'fa fa-unlock',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'chartData',
|
||||
'isLockDataZoom',
|
||||
]),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
lockDataZoom () {
|
||||
this.isLockDataZoom = !this.isLockDataZoom
|
||||
this.lockDataZoomChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: 0,
|
||||
zoomLock: this.isLockDataZoom,
|
||||
})
|
||||
if (this.isLockDataZoom === true) {
|
||||
this.icon = 'fa fa-lock'
|
||||
} else if (this.isLockDataZoom === false) {
|
||||
this.icon = 'fa fa-unlock'
|
||||
}
|
||||
},
|
||||
...mapMutations('replay', [types.chart.lockDataZoom]),
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div>
|
||||
<span class="box_inline-block"> use SD card data </span>
|
||||
<va-toggle :disable="disableToggle" flat small class="box_inline-block" v-model="useSdCardData"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'SdCardToggle',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'metaList',
|
||||
'useSdCardData',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
metaIndex: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
disableToggle: true,
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
if (this.metaList[this.metaIndex].sd_data_uploaded === true) {
|
||||
this.disableToggle = false
|
||||
} else {
|
||||
this.disableToggle = true
|
||||
this.useSdCardData = false
|
||||
}
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.box_inline-block {
|
||||
padding: 1px;
|
||||
margin: 1px;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,481 @@
|
||||
<template>
|
||||
<va-tree-root>
|
||||
<va-tree-category label="Experiment Setting" :isOpen="false">
|
||||
<pre><div style="text-transform: none;" class="title mb-3" :style="{color: this.$themes.primary}" v-html="content"></div></pre>
|
||||
</va-tree-category>
|
||||
</va-tree-root>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import paramTable from '@/data/param-table/index.js'
|
||||
|
||||
export default {
|
||||
name: 'show-parameter',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
metaIndex: {
|
||||
type: Number, // which meta file
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
deviceName: '',
|
||||
content: '',
|
||||
showDict: {},
|
||||
// [region] for neulive
|
||||
ampGainOptions: [
|
||||
{
|
||||
id: 0,
|
||||
description: '25',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
description: '100',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
description: '400',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
description: '800',
|
||||
},
|
||||
],
|
||||
neuliveSampleRateOptions: [
|
||||
{
|
||||
id: 0,
|
||||
value: 1000,
|
||||
description: '1k',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
value: 2000,
|
||||
description: '2k',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
value: 4000,
|
||||
description: '4k',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
value: 5000,
|
||||
description: '5k',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
value: 8000,
|
||||
description: '8k',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
value: 10000,
|
||||
description: '10k',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
value: 20000,
|
||||
description: '20k',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
value: 40000,
|
||||
description: '40k',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
value: 80000,
|
||||
description: '80k',
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
value: 100000,
|
||||
description: '100k',
|
||||
},
|
||||
],
|
||||
stimulateElectrodeOptions: [
|
||||
{
|
||||
label: 'Monopolar',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: 'Bipolar',
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
cycleNumberOptions: [
|
||||
{
|
||||
label: 'limite',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: 'Unlimite',
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
patternModeOptions: [
|
||||
{
|
||||
label: 'Monophasic',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: 'Biphasic',
|
||||
value: 1,
|
||||
},
|
||||
],
|
||||
unitOptions: [
|
||||
{
|
||||
label: 's',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: 'ms',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 'us',
|
||||
value: 2,
|
||||
},
|
||||
],
|
||||
// [Endregion]
|
||||
// [region] for elite
|
||||
workingModeOptions: [
|
||||
{
|
||||
id: 0,
|
||||
description: 'I-V Curve',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
description: 'Cycle I-V',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
description: 'Function Generator',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
description: 'R-T Graph',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
description: 'V-T Graph',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
description: 'I-T Graph',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
description: 'ADC_Test',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
description: 'Constant Current',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
description: 'Cyclic Voltammetry',
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
description: 'Cyclic Voltammetry-hi-cycles',
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
description: 'Linear Sweep Voltammetry',
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
description: 'Chronoamperometric Graph',
|
||||
},
|
||||
],
|
||||
currentRangeOptions: [
|
||||
{
|
||||
value: 0,
|
||||
label: '<40 μA',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '30-1350 μA',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '>1000 μA',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: 'Auto',
|
||||
},
|
||||
],
|
||||
stepTimeOptions: [
|
||||
{
|
||||
value: 0,
|
||||
label: '0.5s',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '1.0s',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '2.0s',
|
||||
},
|
||||
],
|
||||
resisterRangeOptions: [
|
||||
{
|
||||
value: 0,
|
||||
label: '>50 kΩ',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '2-100 kΩ',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '<10 kΩ',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: 'Auto',
|
||||
},
|
||||
],
|
||||
eliteSampleRateOptions: [
|
||||
{
|
||||
value: 0,
|
||||
label: '100',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: '10',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: '5',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: '1',
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
label: '0.1',
|
||||
},
|
||||
{
|
||||
value: 5,
|
||||
label: '0.01',
|
||||
},
|
||||
],
|
||||
chargeOptions: [
|
||||
{
|
||||
value: 0,
|
||||
label: 'Charge',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
label: 'Discharge',
|
||||
},
|
||||
],
|
||||
// [Endregion]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'metaList',
|
||||
]),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
init (deviceName) {
|
||||
this.deviceName = deviceName
|
||||
const meta = this.metaList[this.metaIndex]
|
||||
const params = meta.parameter_set
|
||||
this.content += 'Duration: ' + parseInt(parseInt(meta.time_duration / 1e6) / 60) + ' m ' + parseInt((meta.time_duration % 6e7) / 1e6) + ' s<br/>'
|
||||
this.content += '<br/>Parameter: <br/>'
|
||||
if (this.deviceName.startsWith('Neulive')) {
|
||||
// recording param
|
||||
this.content += '<br/> Recording: <br/>'
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
if (!(key.includes('sti') || key.includes('STI'))) {
|
||||
let showKey = ''
|
||||
let showValue = value
|
||||
if (key === 'RECORDING_CH' || key === 'AXIS_CH' || key === 'AMP_GAIN' || key === 'SAMPLE_RATE') {
|
||||
if (key === 'RECORDING_CH') {
|
||||
showKey = 'Channels'
|
||||
// convert decimal to binary
|
||||
const binaryChannelValue = showValue.toString(2)
|
||||
const channelValue = binaryChannelValue.split('')
|
||||
showValue = ''
|
||||
channelValue.forEach(function (value, i) {
|
||||
if (value === '1') {
|
||||
showValue += `${i + 1} `
|
||||
}
|
||||
})
|
||||
if (showValue === '') {
|
||||
showValue = 'None'
|
||||
}
|
||||
} else if (key === 'AXIS_CH') {
|
||||
showKey = '3-AXIS'
|
||||
// convert decimal to binary
|
||||
const binaryChannelValue = showValue.toString(2)
|
||||
const channelValue = binaryChannelValue.split('').reverse()
|
||||
showValue = ''
|
||||
channelValue.forEach(function (value, i) {
|
||||
if (value === '1') {
|
||||
if (i === 0) {
|
||||
showValue += 'x '
|
||||
} else if (i === 1) {
|
||||
showValue += 'y '
|
||||
} else if (i === 2) {
|
||||
showValue += 'z '
|
||||
} else if (i === 3) {
|
||||
showValue += 'mag '
|
||||
}
|
||||
}
|
||||
})
|
||||
if (showValue === '') {
|
||||
showValue = 'None'
|
||||
}
|
||||
} else if (key === 'AMP_GAIN') {
|
||||
showKey = 'Amp gain'
|
||||
const targetID = (value + 1) % 4
|
||||
for (let i = 0; i < this.ampGainOptions.length; i++) {
|
||||
if (this.ampGainOptions[i].id === targetID) {
|
||||
showValue = this.ampGainOptions[i].description
|
||||
}
|
||||
}
|
||||
} else if (key === 'SAMPLE_RATE') {
|
||||
showKey = 'Sample Rate'
|
||||
for (let i = 0; i < this.neuliveSampleRateOptions.length; i++) {
|
||||
if (this.neuliveSampleRateOptions[i].value === value) {
|
||||
showValue = this.neuliveSampleRateOptions[i].description
|
||||
}
|
||||
}
|
||||
}
|
||||
this.content += ' ' + showKey + ': ' + showValue + '<br/>'
|
||||
}
|
||||
}
|
||||
}
|
||||
// stimulation param
|
||||
this.content += '<br/> Stimulation: <br/>'
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
if (key.includes('sti') || key.includes('STI')) {
|
||||
let showKey = ''
|
||||
let showValue = value
|
||||
if (key === 'STI_H_BRIDGE' || key === 'STI_CHANNEL' || key === 'STI_POLARITY' || key === 'CONTINUOUS_STI' ||
|
||||
key === 'STI_AMPLITUDE' || key === 'STI_PATTERN' || key === 'STI_T1' || key === 'STI_T2' || key === 'STI_T3' || key === 'STI_T4') {
|
||||
if (key === 'STI_H_BRIDGE') {
|
||||
showKey = 'ELECTRODE'
|
||||
if (value === true) {
|
||||
showValue = this.stimulateElectrodeOptions[1].label
|
||||
} else {
|
||||
showValue = this.stimulateElectrodeOptions[0].label
|
||||
}
|
||||
} else if (key === 'STI_CHANNEL' || key === 'STI_POLARITY') {
|
||||
if (key === 'STI_CHANNEL') {
|
||||
showKey = 'Channels'
|
||||
} else {
|
||||
showKey = 'Polarity'
|
||||
}
|
||||
// convert decimal to binary
|
||||
const binaryChannelValue = showValue.toString(2)
|
||||
const channelValue = binaryChannelValue.split('')
|
||||
showValue = ''
|
||||
channelValue.forEach(function (value, i) {
|
||||
if (value === '1') {
|
||||
showValue += `${i + 1} `
|
||||
}
|
||||
})
|
||||
if (showValue === '') {
|
||||
showValue = 'None'
|
||||
}
|
||||
} else if (key === 'CONTINUOUS_STI') {
|
||||
showKey = 'CYCLE NUMBER'
|
||||
if (value === true) {
|
||||
showValue = this.cycleNumberOptions[1].label
|
||||
} else {
|
||||
showValue = this.cycleNumberOptions[0].label
|
||||
}
|
||||
} else if (key === 'STI_AMPLITUDE') {
|
||||
showKey = 'AMPLITUDE (uA)'
|
||||
showValue = value * 5
|
||||
} else if (key === 'STI_PATTERN') {
|
||||
showKey = 'PATTERN'
|
||||
if (value === true) {
|
||||
showValue = this.patternModeOptions[1].label
|
||||
} else {
|
||||
showValue = this.patternModeOptions[0].label
|
||||
}
|
||||
} else if (key === 'STI_T1') {
|
||||
showKey = 'T1 Range'
|
||||
showValue = `${value[0] * 10 / 1000} ms` // 10 is cuz 1 value = 10us, [0] is cuz now all values in array are same
|
||||
} else if (key === 'STI_T2') {
|
||||
showKey = 'T2 Range'
|
||||
showValue = `${value[0] * 10 / 1000} ms` // 10 is cuz 1 value = 10us
|
||||
} else if (key === 'STI_T3') {
|
||||
showKey = 'T3 Range'
|
||||
showValue = `${value[0] * 10 / 1000} ms` // 10 is cuz 1 value = 10us
|
||||
} else if (key === 'STI_T4') {
|
||||
showKey = 'T4 Range'
|
||||
showValue = `${value[0] * 10 / 1000} ms` // 10 is cuz 1 value = 10us
|
||||
}
|
||||
this.content += ' ' + showKey + ': ' + showValue + '<br/>'
|
||||
}
|
||||
}
|
||||
}
|
||||
if ('STI_T1' in params && 'STI_T2' in params && 'STI_T3' in params && 'STI_T4' in params) {
|
||||
const period = (params.STI_T1[0] + params.STI_T2[0] + params.STI_T3[0] + params.STI_T4[0]) * 10 / 1000 // 10 is cuz 1 value = 10us
|
||||
this.content += ' Frequency: ' + String(1000 / period) + ' Hz' + '<br/>' // 1000 is cuz 1s = 1000ms
|
||||
this.content += ' Period: ' + String(period) + ' ms' + '<br/>'
|
||||
}
|
||||
} else if (this.deviceName === 'EliteZM15' || this.deviceName === 'EliteEIS') {
|
||||
const mode = params.MODE
|
||||
const modeName = paramTable[this.deviceName].MODE[mode].name
|
||||
const showParams = paramTable[this.deviceName].MODE[mode].showParameter
|
||||
this.showDict.MODE = modeName
|
||||
if (modeName === 'Pulse Sensing') {
|
||||
const duplicateParam = ['V_initial', 't_pulse', 'CURR_REC_START', 'CURR_REC_END']
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const key = 'segment_order_' + String(i)
|
||||
const order = paramTable[this.deviceName][key].rev_func(params[key])
|
||||
if (parseInt(order) !== 0) { // if === 0, 代表沒有使用這個block
|
||||
for (let key of duplicateParam) {
|
||||
key = key + '_' + String(i)
|
||||
this.fillShowDict(key, params[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
const remainParams = showParams.filter((e) => { // 差集
|
||||
return duplicateParam.indexOf(e) === -1
|
||||
})
|
||||
for (const key of remainParams) {
|
||||
this.fillShowDict(key, params[key])
|
||||
}
|
||||
} else {
|
||||
for (const key of showParams) {
|
||||
this.fillShowDict(key, params[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
this.dump()
|
||||
},
|
||||
fillShowDict (key, value) {
|
||||
const expVal = paramTable[this.deviceName][key].rev_func(value)
|
||||
const name = paramTable[this.deviceName][key].showName
|
||||
const unit = paramTable[this.deviceName][key].defaultUnit
|
||||
this.showDict[name] = unit !== undefined ? expVal.toString() + unit : expVal.toString()
|
||||
},
|
||||
dump () {
|
||||
for (const [showKey, showValue] of Object.entries(this.showDict)) {
|
||||
this.content += ' ' + showKey + ': ' + showValue + '<br/>'
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div>
|
||||
<p class="display-6"> Resample: {{ currentScale }} to 1 <p/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'show-resample-rate',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('replay', [
|
||||
'currentScale',
|
||||
]),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-card>
|
||||
<p style="font-size: 125%; text-decoration: underline;"> Channel </p>
|
||||
<channels/>
|
||||
<p style="font-size: 125%; text-decoration: underline;"> Detect </p>
|
||||
<p :style="{color: this.$themes.primary}" class="display-6"> High pass filter </p>
|
||||
<cutoff-freq/>
|
||||
<filter-order/>
|
||||
<filter-button ref="filterButtonRef" @loadFilterData="loadFilterData"/>
|
||||
<p :style="{color: this.$themes.danger}" class="display-6"> Threshold </p>
|
||||
<threshold/>
|
||||
<br/>
|
||||
<p class="display-6"> Waveform </p>
|
||||
<wave-length/>
|
||||
<prethreshold/>
|
||||
<refractory-period/>
|
||||
<detect-button ref="detectButtonRef" @loadThresholdData="loadThresholdData"/>
|
||||
</va-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Channels from '@/components/analysis/spike/item/Channels.vue'
|
||||
import CutoffFreq from '@/components/analysis/spike/item/CutoffFreq.vue'
|
||||
import FilterOrder from '@/components/analysis/spike/item/FilterOrder.vue'
|
||||
import Prethreshold from '@/components/analysis/spike/item/Prethreshold.vue'
|
||||
import RefractoryPeriod from '@/components/analysis/spike/item/RefractoryPeriod.vue'
|
||||
import Threshold from '@/components/analysis/spike/item/Threshold.vue'
|
||||
import WaveLength from '@/components/analysis/spike/item/WaveLength.vue'
|
||||
import DetectButton from '@/components/analysis/spike/item/DetectButton.vue'
|
||||
import FilterButton from '@/components/analysis/spike/item/FilterButton.vue'
|
||||
|
||||
export default {
|
||||
name: 'control-panel',
|
||||
components: {
|
||||
Channels,
|
||||
CutoffFreq,
|
||||
FilterOrder,
|
||||
FilterButton,
|
||||
Prethreshold,
|
||||
RefractoryPeriod,
|
||||
Threshold,
|
||||
WaveLength,
|
||||
DetectButton,
|
||||
},
|
||||
props: {
|
||||
},
|
||||
async created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
this.enableFilterButton()
|
||||
},
|
||||
refreshChart (options) {
|
||||
this.$emit('refreshChart', options)
|
||||
},
|
||||
loadThresholdData () {
|
||||
this.$emit('loadThresholdData')
|
||||
},
|
||||
loadFilterData () {
|
||||
this.$emit('loadFilterData')
|
||||
},
|
||||
enableFilterButton () {
|
||||
this.$refs.filterButtonRef.enableButton()
|
||||
},
|
||||
disableFilterButton () {
|
||||
this.$refs.filterButtonRef.disableButton()
|
||||
},
|
||||
enableDetectButton () {
|
||||
this.$refs.detectButtonRef.enableButton()
|
||||
},
|
||||
disableDetectButton () {
|
||||
this.$refs.detectButtonRef.disableButton()
|
||||
},
|
||||
},
|
||||
// use watch because va-select with @change will have bug
|
||||
watch: {
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.flex-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-child {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.flex-child1 {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.flex-child2 {
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
.flex-child:first-child {
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,436 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="row row-equal">
|
||||
<div class="flex md12 xl3 xs12 sm12">
|
||||
<div class="row">
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<va-accordion>
|
||||
<va-collapse class="mb-2" :isOpenDefault="true">
|
||||
<span slot="header">Control Panel</span>
|
||||
<div slot="body">
|
||||
<div>
|
||||
<control-panel
|
||||
:ref="'control_panel'"
|
||||
@loadFilterData="loadFilterData"
|
||||
@loadThresholdData="loadThresholdData"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</va-collapse>
|
||||
</va-accordion>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :class="chartAreaClass">
|
||||
<div class="row" >
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<spike-overview-chart :ref="'chart_overview'" :cardheight="'30vh'" :data="chartOverviewData"/>
|
||||
<spike-chart :ref="'chart_detail'" :cardheight="'60vh'" :data="chartDetailData"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters, mapMutations } from 'vuex'
|
||||
import SpikeOverviewChart from './SpikeOverviewChart.vue'
|
||||
import SpikeChart from './SpikeChart.vue'
|
||||
import ControlPanel from './ControlPanel.vue'
|
||||
import api from '@/data/api/index'
|
||||
import { taskInfo } from '@/data/task/TaskInfo'
|
||||
import types from '@/store/modules/analysis/spike/types'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import newSeries from '@/factories/chart/seriesFactory'
|
||||
|
||||
export default {
|
||||
name: 'spike-data-replay',
|
||||
components: {
|
||||
SpikeOverviewChart,
|
||||
SpikeChart,
|
||||
ControlPanel,
|
||||
},
|
||||
computed: {
|
||||
...mapFields('spike', [
|
||||
'chartData',
|
||||
'chartOverviewData',
|
||||
'chartDetailData',
|
||||
'metaList',
|
||||
'selectedChannel',
|
||||
'cutoffFreq',
|
||||
'filterOrder',
|
||||
'selectedThreshold',
|
||||
'upperThreshold',
|
||||
'lowerThreshold',
|
||||
'waveLength',
|
||||
'preThreshold',
|
||||
'refractoryPeriod',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
async created () {
|
||||
this.chartOverviewData = await this.initChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: 0,
|
||||
gridLength: 1,
|
||||
type: 'overview',
|
||||
device: 'neulive',
|
||||
mode: 0,
|
||||
})
|
||||
this.chartDetailData = await this.initChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: 1,
|
||||
gridLength: 1,
|
||||
type: 'detail',
|
||||
device: 'neulive',
|
||||
mode: 0,
|
||||
})
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
dataInfo: {},
|
||||
maxTime: 0,
|
||||
chartAreaClass: ['flex', 'xs12', 'sm12', 'md12', 'xl9', 'pa-0'],
|
||||
randomColorArray: [],
|
||||
controllerList: [],
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
async '+/analysis/spike_detect/+/+/+' (data, topic) {
|
||||
const topicSplitArray = topic.split('/')
|
||||
if (this.metaList.some(e => e.id === parseInt(topicSplitArray[4]))) {
|
||||
if (topicSplitArray[3] === 'data') {
|
||||
const utf8decoder = new TextDecoder()
|
||||
const dataStr = utf8decoder.decode(data)
|
||||
const dataArray = JSON.parse(dataStr)
|
||||
|
||||
this.chartOverviewData.series[0].data.push(...dataArray)
|
||||
} else if (topicSplitArray[3] === 'time_mark') {
|
||||
const utf8decoder = new TextDecoder()
|
||||
const timeMarkStr = JSON.parse(utf8decoder.decode(data))
|
||||
const timeMarkObj = timeMarkStr.split(' ')
|
||||
|
||||
this.drawTimeMark(timeMarkObj)
|
||||
} else if (topicSplitArray[3] === 'detect_signal') {
|
||||
const utf8decoder = new TextDecoder()
|
||||
const detectSignalStr = utf8decoder.decode(data)
|
||||
const detectSignalObj = Object.values(JSON.parse(detectSignalStr))
|
||||
|
||||
this.drawThresholdData(detectSignalObj)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getControllerList: async function () {
|
||||
const update = async () => {
|
||||
this.controllerList.push({
|
||||
id: taskInfo.getTaskInfo().controllerID,
|
||||
mac: '',
|
||||
status: 'loading',
|
||||
isScan: true,
|
||||
})
|
||||
}
|
||||
await update()
|
||||
},
|
||||
mqttSub: function (val) {
|
||||
this.$mqtt.subscribe(val)
|
||||
},
|
||||
mqttUnSub: function (val) {
|
||||
this.$mqtt.unsubscribe(val)
|
||||
},
|
||||
mqttPub: function (topic, mes) {
|
||||
this.$mqtt.publish(topic, mes)
|
||||
},
|
||||
pageMqttSub: function (id) {
|
||||
this.mqttSub(id + '/analysis/spike_detect/+/+/+')
|
||||
},
|
||||
pageMqttUnSub: function (id) {
|
||||
this.mqttUnSub(id + '/analysis/spike_detect/+/+')
|
||||
},
|
||||
showChartLoading: function (chart) {
|
||||
const loadStyle = {
|
||||
text: '',
|
||||
color: '#cccccc',
|
||||
maskColor: 'rgba(255, 255, 255, 0.8)',
|
||||
zlevel: 0,
|
||||
}
|
||||
switch (chart) {
|
||||
case 'overview':
|
||||
this.$refs.chart_overview.showLoading(loadStyle)
|
||||
break
|
||||
case 'detail':
|
||||
this.$refs.chart_detail.showLoading(loadStyle)
|
||||
break
|
||||
default:
|
||||
this.$refs.chart_overview.showLoading(loadStyle)
|
||||
this.$refs.chart_detail.showLoading(loadStyle)
|
||||
break
|
||||
}
|
||||
},
|
||||
hideChartLoading: function (chart) {
|
||||
switch (chart) {
|
||||
case 'overview':
|
||||
this.$refs.chart_overview.hideLoading()
|
||||
break
|
||||
case 'detail':
|
||||
this.$refs.chart_detail.hideLoading()
|
||||
break
|
||||
default:
|
||||
this.$refs.chart_overview.hideLoading()
|
||||
this.$refs.chart_detail.hideLoading()
|
||||
break
|
||||
}
|
||||
},
|
||||
register: async function () {
|
||||
const gridLength = 1
|
||||
this.updateGridListChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartDetailData.chartID,
|
||||
gridLength: gridLength,
|
||||
})
|
||||
const register = this.metaList.map(meta => {
|
||||
this.registerChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartOverviewData.chartID,
|
||||
gridIndex: 0,
|
||||
deviceNameX: 'Time',
|
||||
deviceNameY: 'Neulive',
|
||||
deviceIDY: meta.name,
|
||||
channelY: this.selectedChannel,
|
||||
})
|
||||
this.registerChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: this.chartDetailData.chartID,
|
||||
gridIndex: 0,
|
||||
deviceNameX: 'Time',
|
||||
deviceNameY: 'Neulive',
|
||||
deviceIDY: meta.name,
|
||||
channelY: this.selectedChannel,
|
||||
})
|
||||
if (this.maxTime < parseInt(meta.time_duration)) {
|
||||
this.maxTime = parseInt(meta.time_duration)
|
||||
}
|
||||
})
|
||||
await Promise.all(register)
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
// ID 0 = overview, ID 1 = detail
|
||||
this.updateAxisLabelChart({
|
||||
chartID: i,
|
||||
axis: 'x',
|
||||
axisIndex: 0,
|
||||
channel: this.selectedChannel,
|
||||
})
|
||||
this.updateAxisLabelChart({
|
||||
chartID: i,
|
||||
axis: 'y',
|
||||
axisIndex: 0,
|
||||
channel: this.selectedChannel,
|
||||
})
|
||||
this.updateDataZoomChart({
|
||||
chartAllData: this.chartData,
|
||||
chartID: i,
|
||||
})
|
||||
}
|
||||
|
||||
// this.updateChartSamplingChart({ chartID: this.chartOverviewData.chartID, seriesIndex: 0, method: function (frame) { return frame[0] } })
|
||||
this.chartOverviewData.xAxis[0].min = 0
|
||||
this.chartOverviewData.xAxis[0].max = this.maxTime
|
||||
},
|
||||
loadFilterData: async function () {
|
||||
this.showChartLoading('overview')
|
||||
this.$refs.chart_detail.clear()
|
||||
this.$refs.control_panel.disableDetectButton()
|
||||
|
||||
for (const meta in this.dataInfo) {
|
||||
// reset overview chart
|
||||
|
||||
this.chartOverviewData.series[0].data.length = 0
|
||||
this.chartOverviewData.series[0].markArea.data.length = 0
|
||||
this.chartOverviewData.color = ['#000000'] // black
|
||||
|
||||
await api.analysis.spikeDetect({
|
||||
controller_id: this.controllerList[0].id,
|
||||
meta_id: meta,
|
||||
channel: this.selectedChannel,
|
||||
filter_order: this.filterOrder,
|
||||
cut_off_freq: this.cutoffFreq,
|
||||
data_type: 'filter_data',
|
||||
})
|
||||
|
||||
this.hideChartLoading('overview')
|
||||
this.$refs.control_panel.enableDetectButton()
|
||||
console.log(this.chartOverviewData)
|
||||
}
|
||||
},
|
||||
loadThresholdData: async function () {
|
||||
this.showChartLoading('detail')
|
||||
|
||||
for (const meta in this.dataInfo) {
|
||||
let thresholdValue
|
||||
if (this.selectedThreshold === 'over') {
|
||||
thresholdValue = this.upperThreshold
|
||||
} else if (this.selectedThreshold === 'bellow') {
|
||||
thresholdValue = this.lowerThreshold
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.chartDetailData.series.length; i++) {
|
||||
this.chartDetailData.series[i].name = ''
|
||||
this.chartDetailData.series[i].data.length = 0
|
||||
}
|
||||
|
||||
await api.analysis.spikeDetect({
|
||||
controller_id: this.controllerList[0].id,
|
||||
meta_id: meta,
|
||||
channel: this.selectedChannel,
|
||||
cut_off_freq: this.cutoffFreq,
|
||||
filter_order: this.filterOrder,
|
||||
threshold: [
|
||||
`'${this.selectedThreshold}'`,
|
||||
thresholdValue,
|
||||
],
|
||||
waveForm: [this.waveLength, this.preThreshold, this.refractoryPeriod],
|
||||
ret_data_type: 'threshold_data',
|
||||
})
|
||||
}
|
||||
this.hideChartLoading('detail')
|
||||
},
|
||||
drawThresholdData (detailSignalArray) {
|
||||
if (detailSignalArray.length <= 8) {
|
||||
this.chartDetailData.tooltip.show = true
|
||||
} else {
|
||||
this.chartDetailData.tooltip.show = false
|
||||
}
|
||||
this.chartDetailData.legend.data.length = 0
|
||||
this.chartDetailData.legend.type = 'scroll'
|
||||
this.chartDetailData.legend.top = '0.25%'
|
||||
// this.chartDetailData.legendpageButtonPosition = 'start'
|
||||
this.chartDetailData.animation = false
|
||||
this.chartDetailData.color = []
|
||||
|
||||
for (let i = 0; i < detailSignalArray.length; i++) {
|
||||
const detailSignal = detailSignalArray[i].split(' ')
|
||||
const arrayLength = detailSignal.length
|
||||
const step = parseInt(this.waveLength) / (arrayLength - 1)
|
||||
const xAxisIndex = 0
|
||||
const yAxisIndex = 0
|
||||
const legendName = 'T_' + String(i + 1)
|
||||
if (this.chartDetailData.series.length <= i) {
|
||||
const _series = newSeries('line', legendName, xAxisIndex, yAxisIndex, [-1, -1], ['metaInfo.name', this.selectedChannel], null, null)
|
||||
this.chartDetailData.series.push(_series)
|
||||
}
|
||||
for (let j = 0; j < arrayLength; j++) {
|
||||
this.chartDetailData.series[i].data.push([j * step, detailSignal[j]])
|
||||
}
|
||||
// push legendName
|
||||
this.chartDetailData.legend.data.push(legendName)
|
||||
this.chartDetailData.series[i].name = legendName
|
||||
// set legend and series color
|
||||
this.chartDetailData.color.push(this.randomColorArray[i])
|
||||
}
|
||||
this.chartDetailData.xAxis[0].min = 0
|
||||
this.chartDetailData.xAxis[0].max = parseInt(this.waveLength)
|
||||
this.chartDetailData.xAxis[0].axisLabel.show = true
|
||||
},
|
||||
drawTimeMark (timeMarkArray, period) {
|
||||
// reset overview
|
||||
this.chartOverviewData.series[0].markArea.data.length = 0
|
||||
|
||||
const timeMarkLength = timeMarkArray.length
|
||||
|
||||
for (let i = 0; i < timeMarkLength; i++) {
|
||||
// generate color array for overview markArea and detail chart series
|
||||
const randomColor = '#' + Math.floor(Math.random() * 16777215).toString(16) // ref: https://css-tricks.com/snippets/javascript/random-hex-color/
|
||||
this.randomColorArray.push(randomColor)
|
||||
if (Number.isInteger(parseInt(timeMarkArray[i]))) { // cuz maybe is '' if no any match after filtering
|
||||
const timeMark = parseInt(timeMarkArray[i])
|
||||
|
||||
let startTime = timeMark - parseInt(this.preThreshold)
|
||||
let endTime = timeMark + parseInt(this.refractoryPeriod)
|
||||
if (startTime < 0) {
|
||||
startTime = 0
|
||||
}
|
||||
if (endTime > timeMark) {
|
||||
endTime = timeMark
|
||||
}
|
||||
|
||||
const overviewSignal = this.chartOverviewData.series[0].data
|
||||
|
||||
let startIndex = 0
|
||||
let endIndex = 0
|
||||
|
||||
for (let i = 0; i < overviewSignal.length; i++) {
|
||||
if (startTime <= overviewSignal[i][0]) {
|
||||
startIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < overviewSignal.length; i++) {
|
||||
if (endTime <= overviewSignal[i][0]) {
|
||||
endIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
this.chartOverviewData.series[0].markArea.data.push([
|
||||
{
|
||||
itemStyle: {
|
||||
color: randomColor,
|
||||
borderColor: randomColor,
|
||||
borderWidth: 1,
|
||||
},
|
||||
name: String(i + 1),
|
||||
xAxis: overviewSignal[startIndex][0],
|
||||
},
|
||||
{
|
||||
xAxis: overviewSignal[endIndex][0],
|
||||
},
|
||||
])
|
||||
}
|
||||
}
|
||||
},
|
||||
...mapActions('spike', [types.chart.init, types.chart.initSelectedChannel, types.chart.register, types.chart.clear, types.chart.updateGridList, types.chart.updateDataZoom]),
|
||||
...mapActions('spike', [types.meta.init]),
|
||||
...mapActions('spike', [types.rec.init, types.rec.intoData, types.rec.initDisplaySetting, types.rec.updateDisplaySetting]),
|
||||
|
||||
...mapMutations('spike', [types.chart.updateAxisLabel, types.chart.updateChartSampling]),
|
||||
...mapMutations('spike', [types.meta.updateByIndex]),
|
||||
|
||||
...mapGetters('spike', [types.meta.getAll]),
|
||||
...mapGetters('spike', [types.rec.getAll]),
|
||||
},
|
||||
// use watch because va-select with @change will have bug
|
||||
watch: {
|
||||
},
|
||||
async mounted () {
|
||||
this.getControllerList()
|
||||
this.pageMqttSub(this.controllerList[0].id)
|
||||
|
||||
const metaIDList = this.$route.params.metaList.split('-')
|
||||
await this.initMeta({ metaIDList: metaIDList, api: api })
|
||||
this.metaList = this.getAllMeta()
|
||||
this.initSelectedChannelChart({ metaIndex: 0 })
|
||||
await this.initRec({ api: api })
|
||||
this.dataInfo = this.getAllRec()
|
||||
console.log(this.metaList)
|
||||
console.log(this.dataInfo)
|
||||
await this.register()
|
||||
this.$refs.control_panel.init()
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.pageMqttUnSub(this.controllerList[0].id)
|
||||
this.$refs.chart_detail.clear()
|
||||
for (const id in this.chartData) {
|
||||
for (const _series of this.chartData[id].series) {
|
||||
_series.length = 0
|
||||
}
|
||||
delete this.chartData[id]
|
||||
}
|
||||
this.clearChart({ chartAllData: this.chartData })
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div class="flex" :class="cardclass">
|
||||
<va-card :style="'height: ' + cardheight + ';'">
|
||||
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="data" @dataZoom="updateZoom" :auto-resize="true"></chart>
|
||||
</va-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from 'vuex'
|
||||
import types from '@/store/modules/analysis/spike/types'
|
||||
// import { chartData } from '../../../../data/task/ChartsManagement'
|
||||
|
||||
export default {
|
||||
name: 'spike-replay-chart',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
cardclass: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return ['xs12', 'md12', 'xl12', 'sm12']
|
||||
},
|
||||
},
|
||||
cardheight: {
|
||||
type: String,
|
||||
default: '82vh',
|
||||
},
|
||||
cardwidth: {
|
||||
type: String,
|
||||
default: 'auto',
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
resize: function () {
|
||||
if (this.$refs.chart_ref != null) {
|
||||
this.$refs.chart_ref.resize()
|
||||
}
|
||||
},
|
||||
updateZoom: function (e) {
|
||||
this.$emit('dataZoomEvent', e)
|
||||
},
|
||||
mergeOptions (options) {
|
||||
this.$refs.chart_ref.mergeOptions(options)
|
||||
},
|
||||
turnOnAxisEventHandler (eventName, query, handler, attr) {
|
||||
const chartID = 1
|
||||
this.updateAxisEventHandlerChart({
|
||||
chartID: chartID,
|
||||
axis: attr.axis,
|
||||
status: 'on',
|
||||
})
|
||||
// doc: https://echarts.apache.org/zh/api.html#echartsInstance.on
|
||||
this.$refs.chart_ref.chart._zr.on(eventName, query, handler)
|
||||
},
|
||||
turnOffAxisEventHandler (eventName, handler, attr) {
|
||||
const chartID = 1
|
||||
this.updateAxisEventHandlerChart({
|
||||
chartID: chartID,
|
||||
axis: attr.axis,
|
||||
status: 'off',
|
||||
})
|
||||
// doc: https://echarts.apache.org/zh/api.html#echartsInstance.off
|
||||
this.$refs.chart_ref.chart._zr.off(eventName, handler)
|
||||
},
|
||||
showLoading (options) {
|
||||
this.$refs.chart_ref.showLoading(options)
|
||||
},
|
||||
hideLoading () {
|
||||
this.$refs.chart_ref.hideLoading()
|
||||
},
|
||||
clear () {
|
||||
this.$refs.chart_ref.clear()
|
||||
},
|
||||
|
||||
...mapMutations('spike', [types.chart.updateAxisEventHandler]),
|
||||
},
|
||||
async mounted () {
|
||||
this.resizeTimer = setInterval(this.resize, 1000)
|
||||
},
|
||||
destroyed () {
|
||||
clearInterval(this.resizeTimer)
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
.va-card {
|
||||
&__body {
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="flex" :class="cardclass">
|
||||
<va-card :style="'height: ' + cardheight + ';'">
|
||||
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="data" @dataZoom="updateZoom" :auto-resize="true"></chart>
|
||||
</va-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { chartData } from '../../../../data/task/ChartsManagement'
|
||||
|
||||
export default {
|
||||
name: 'spike-overview-chart',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
cardclass: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return ['xs12', 'md12', 'xl12', 'sm12']
|
||||
},
|
||||
},
|
||||
cardheight: {
|
||||
type: String,
|
||||
default: '82vh',
|
||||
},
|
||||
cardwidth: {
|
||||
type: String,
|
||||
default: 'auto',
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
resize: function () {
|
||||
if (this.$refs.chart_ref != null) {
|
||||
this.$refs.chart_ref.resize()
|
||||
}
|
||||
},
|
||||
mergeOptions (options) {
|
||||
this.$refs.chart_ref.mergeOptions(options)
|
||||
},
|
||||
updateZoom: function (e) {
|
||||
this.$emit('dataZoomEvent', e)
|
||||
},
|
||||
showLoading (options) {
|
||||
this.$refs.chart_ref.showLoading(options)
|
||||
},
|
||||
hideLoading () {
|
||||
this.$refs.chart_ref.hideLoading()
|
||||
},
|
||||
clear () {
|
||||
this.$refs.chart_ref.clear()
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
this.resizeTimer = setInterval(this.resize, 1000)
|
||||
},
|
||||
destroyed () {
|
||||
clearInterval(this.resizeTimer)
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
.va-card {
|
||||
&__body {
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-button-toggle small flat v-model="selectedChannel" :options="selectedChannelOptions" @click.native="reloadData(selectedChannel)"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'Channels',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('spike', [
|
||||
'selectedChannel',
|
||||
'selectedChannelOptions',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
reloadData (val) {
|
||||
this.selectedChannel = val
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
|
||||
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
|
||||
<p>Cut-off Freq<p/>
|
||||
</div>
|
||||
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
|
||||
<va-input
|
||||
@mouseleave.native="itemChange(cutoffFreq)"
|
||||
@keyup.enter="itemChange(cutoffFreq)"
|
||||
@blur="itemChange(cutoffFreq)"
|
||||
v-model="cutoffFreq"
|
||||
class="mb-0"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
Hz
|
||||
</p>
|
||||
</va-input>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'CutoffFreq',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('spike', [
|
||||
'cutoffFreq',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
itemChange (val) {
|
||||
this.cutoffFreq = val
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-button class="right" small @click="startDetect" :disabled="isDisable">
|
||||
Start Detect
|
||||
</va-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import types from '@/store/modules/analysis/spike/types'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import { mapMutations } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Channels',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('spike', [
|
||||
'chartDetailData',
|
||||
'selectedChannel',
|
||||
'waveLength',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isDisable: true,
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
startDetect () {
|
||||
this.$emit('loadThresholdData')
|
||||
},
|
||||
enableButton () {
|
||||
this.isDisable = false
|
||||
},
|
||||
disableButton () {
|
||||
this.isDisable = true
|
||||
},
|
||||
...mapMutations('spike', [types.chart.updateAxisLabel]),
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div class="flex xl12 md12 sm12 xs12 mb-4">
|
||||
<va-button class="right" small @click="startFilter" :disabled="isDisable">
|
||||
Start Filter
|
||||
</va-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import types from '@/store/modules/analysis/spike/types'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import { mapMutations } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'FilterButton',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('spike', [
|
||||
'chartDetailData',
|
||||
'selectedChannel',
|
||||
'waveLength',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isDisable: true,
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
startFilter () {
|
||||
this.$emit('loadFilterData')
|
||||
},
|
||||
enableButton () {
|
||||
this.isDisable = false
|
||||
},
|
||||
disableButton () {
|
||||
this.isDisable = true
|
||||
},
|
||||
...mapMutations('spike', [types.chart.updateAxisLabel]),
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
|
||||
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
|
||||
<p>Filter order<p/>
|
||||
</div>
|
||||
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
|
||||
<va-input
|
||||
@mouseleave.native="itemChange(filterOrder)"
|
||||
@keyup.enter="itemChange(filterOrder)"
|
||||
@blur="itemChange(filterOrder)"
|
||||
v-model="filterOrder"
|
||||
class="mb-0"
|
||||
>
|
||||
</va-input>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'FilterOrder',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('spike', [
|
||||
'filterOrder',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
itemChange (val) {
|
||||
this.filterOrder = val
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
|
||||
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
|
||||
<p>Prethreshold<p/>
|
||||
</div>
|
||||
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
|
||||
<va-input
|
||||
@mouseleave.native="itemChange(preThreshold)"
|
||||
@keyup.enter="itemChange(preThreshold)"
|
||||
@blur="itemChange(preThreshold)"
|
||||
v-model="preThreshold"
|
||||
class="mb-0"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
µs
|
||||
</p>
|
||||
</va-input>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'Prethreshold',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('spike', [
|
||||
'preThreshold',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
itemChange (val) {
|
||||
this.preThreshold = val
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
|
||||
<div class="flex sm7 xl7 md7 xs7 px-0 mx-0">
|
||||
<p>Refractory period<p/>
|
||||
</div>
|
||||
<div class="flex sm5 xl5 md5 xs5 px-0 mx-0">
|
||||
<va-input
|
||||
@mouseleave.native="itemChange(refractoryPeriod)"
|
||||
@keyup.enter="itemChange(refractoryPeriod)"
|
||||
@blur="itemChange(refractoryPeriod)"
|
||||
v-model="refractoryPeriod"
|
||||
class="mb-0"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
µs
|
||||
</p>
|
||||
</va-input>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'RefractoryPeriod',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('spike', [
|
||||
'refractoryPeriod',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
itemChange (val) {
|
||||
this.refractoryPeriod = val
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
|
||||
<va-radio-button
|
||||
v-for="(option, index) in options"
|
||||
:key="index"
|
||||
v-model="selectedThreshold"
|
||||
:option="option"
|
||||
:label="`${option}`"
|
||||
/>
|
||||
<va-input
|
||||
v-if="selectedThreshold === 'over'"
|
||||
@mouseleave.native="itemChange(upperThreshold, 'upper')"
|
||||
@keyup.enter="itemChange(upperThreshold, 'upper')"
|
||||
@blur="itemChange(upperThreshold, 'upper')"
|
||||
v-model="upperThreshold"
|
||||
class="mb-0"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
µV
|
||||
</p>
|
||||
</va-input>
|
||||
<va-input
|
||||
v-if="selectedThreshold === 'bellow'"
|
||||
@mouseleave.native="itemChange(lowerThreshold, 'lower')"
|
||||
@keyup.enter="itemChange(lowerThreshold, 'lower')"
|
||||
@blur="itemChange(lowerThreshold, 'lower')"
|
||||
v-model="lowerThreshold"
|
||||
class="mb-0"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
µV
|
||||
</p>
|
||||
</va-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'Threshold',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('spike', [
|
||||
'selectedThreshold',
|
||||
'upperThreshold',
|
||||
'lowerThreshold',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
options: [
|
||||
// 'Auto',
|
||||
'over',
|
||||
'bellow',
|
||||
],
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
itemChange (val, type) {
|
||||
if (type === 'upper') {
|
||||
this.upperThreshold = val
|
||||
} else if (type === 'lower') {
|
||||
this.lowerThreshold = val
|
||||
}
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
|
||||
<div class="flex sm7 xl7 md7 xs7 px-0 mx-0">
|
||||
<p>Waveform length<p/>
|
||||
</div>
|
||||
<div class="flex sm5 xl5 md5 xs5 px-0 mx-0">
|
||||
<va-input
|
||||
@mouseleave.native="itemChange(waveLength)"
|
||||
@keyup.enter="itemChange(waveLength)"
|
||||
@blur="itemChange(waveLength)"
|
||||
v-model="waveLength"
|
||||
class="mb-0"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
µs
|
||||
</p>
|
||||
</va-input>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'WaveLength',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('spike', [
|
||||
'waveLength',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
itemChange (val) {
|
||||
this.waveLength = val
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div>
|
||||
<span> Resample: {{ currentScale }} to 1 </span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'show-resample-rate',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('spike', [
|
||||
'currentScale',
|
||||
]),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<!-- <va-card
|
||||
class="horizontal-bars"
|
||||
> -->
|
||||
<div class="row">
|
||||
<div class="flex md12 xs12">
|
||||
<va-progress-bar
|
||||
:value="value"
|
||||
>
|
||||
{{ value }} %
|
||||
</va-progress-bar>
|
||||
</div>
|
||||
</div>
|
||||
<!-- </va-card> -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'progress-bar',
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<va-modal
|
||||
class="flex sm12 xl12 md12 xs12"
|
||||
v-model="showProgressModal"
|
||||
size="small"
|
||||
:title="title"
|
||||
hide-default-actions
|
||||
>
|
||||
<progressBar
|
||||
:value="value"
|
||||
:ref="'progressBarRef'"
|
||||
/>
|
||||
</va-modal>
|
||||
</template>
|
||||
<script>
|
||||
import progressBar from '@/components/common/progressBarByValueModal/progressBar.vue'
|
||||
|
||||
export default {
|
||||
name: 'progress-bar-modal',
|
||||
components: {
|
||||
progressBar,
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
showProgressModal: false,
|
||||
value: 0,
|
||||
title: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
show () {
|
||||
this.showProgressModal = true
|
||||
},
|
||||
hide () {
|
||||
this.showProgressModal = false
|
||||
},
|
||||
setTitle (title) {
|
||||
this.title = title
|
||||
},
|
||||
setValue (value) {
|
||||
this.value = value
|
||||
},
|
||||
addValue () {
|
||||
this.value += 1
|
||||
},
|
||||
reset () {
|
||||
this.value = 0
|
||||
},
|
||||
progressDone () {
|
||||
this.$refs.progressBarRef.progressDone()
|
||||
this.hide()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<!-- <va-card
|
||||
class="horizontal-bars"
|
||||
> -->
|
||||
<div class="row">
|
||||
<div class="flex md12 xs12 mb-2 mt-2">
|
||||
<va-progress-bar
|
||||
:value="progressValue"
|
||||
>
|
||||
{{ progressValue }} %
|
||||
</va-progress-bar>
|
||||
</div>
|
||||
</div>
|
||||
<!-- </va-card> -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'progress-bar',
|
||||
data () {
|
||||
return {
|
||||
progressValue: 0,
|
||||
timeInterval: null,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
// unit: sec
|
||||
time: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
animateValues () {
|
||||
this.timeInterval = setInterval(() => {
|
||||
this.progressValue += 1
|
||||
|
||||
if (this.progressValue === 99) {
|
||||
clearInterval(this.timeInterval)
|
||||
}
|
||||
}, parseInt(this.time * 10))
|
||||
},
|
||||
progressDone () {
|
||||
this.progressValue = 100
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.animateValues()
|
||||
},
|
||||
destroyed () {
|
||||
clearInterval(this.timeInterval)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<va-modal
|
||||
class="flex sm12 xl12 md12 xs12"
|
||||
v-model="showProgressModal"
|
||||
size="small"
|
||||
:title="title"
|
||||
:noOutsideDismiss="true"
|
||||
hide-default-actions
|
||||
>
|
||||
<progressBar
|
||||
:time="time"
|
||||
:ref="'progressBarRef'"
|
||||
/>
|
||||
<div class="flex-center sm12 xl12 md12 xs12">
|
||||
<va-button @click="hide">Cancel</va-button>
|
||||
</div>
|
||||
</va-modal>
|
||||
</template>
|
||||
<script>
|
||||
import progressBar from '@/components/common/progressBarModal/progressBar.vue'
|
||||
|
||||
export default {
|
||||
name: 'progress-bar-modal',
|
||||
components: {
|
||||
progressBar,
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// unit: sec
|
||||
time: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showProgressModal: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
show () {
|
||||
this.showProgressModal = true
|
||||
},
|
||||
hide () {
|
||||
this.showProgressModal = false
|
||||
},
|
||||
progressDone () {
|
||||
this.$refs.progressBarRef.progressDone()
|
||||
this.hide()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -12,7 +12,7 @@
|
||||
<div v-if="controller.status === 'running'">
|
||||
<div class="flex xs12 md12 xl12 sm12 mb-3" style="text-align: center;" >
|
||||
|
||||
<va-button color="primary" target="_blank" @click="scan(controller.id)" small :disabled="controller.isScan">
|
||||
<va-button class="no-dark-style-va-button" color="primary" target="_blank" @click="scan(controller.id)" small :disabled="controller.isScan">
|
||||
SCAN
|
||||
</va-button>
|
||||
<va-button color="dark" target="_blank" @click="restartCheck(controller.id, controller.mac)" small>
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
<div class="row flex">
|
||||
<div
|
||||
class="flex sm12 xl6 md12 xs12 ma-0"
|
||||
class="flex sm12 xl12 md12 xs12 ma-0"
|
||||
v-for="device in controller.devices" :key="device.addr"
|
||||
>
|
||||
<div v-if="!controller.isScan || device.status == 'connected'">
|
||||
@@ -53,27 +53,28 @@
|
||||
<va-badge v-if="device.status == 'scanned'" class="px-1 py-0" color="primary">scanned</va-badge>
|
||||
<va-badge v-if="device.status == 'connected'" class="px-1 py-0" color="success">connected</va-badge>
|
||||
</div> -->
|
||||
|
||||
<va-item-section avatar class="ml-1">
|
||||
<va-avatar style="border-radius: 0;">
|
||||
<img :src="device.pic" :alt="device.name">
|
||||
</va-avatar>
|
||||
</va-item-section>
|
||||
|
||||
<va-item-section class="ml-3">
|
||||
|
||||
<va-item-label>
|
||||
{{ device.name }}
|
||||
<va-badge v-if="device.status == 'scanned'" class="px-1 py-0 ml-2 mt-0" color="primary">scanned</va-badge>
|
||||
<va-badge v-if="device.status == 'connected'" class="px-1 py-0 ml-2 mt-0" color="success">connected</va-badge>
|
||||
</va-item-label>
|
||||
|
||||
<va-item-label caption>
|
||||
{{ device.addr }}
|
||||
</va-item-label>
|
||||
</va-item-section>
|
||||
<!--<div>
|
||||
<va-icon name="fa fa-battery-1" style="font-size: 1.5rem;" color="primary"/>
|
||||
</div>-->
|
||||
</va-item>
|
||||
|
||||
<va-item-section side >
|
||||
<va-item class="pa-0 ma-0 mt-2">
|
||||
<va-item-section>
|
||||
<div v-if="device.loading" class="mr-3">
|
||||
<fulfilling-bouncing-circle-spinner
|
||||
:animation-duration="3000"
|
||||
@@ -82,10 +83,42 @@
|
||||
>
|
||||
</fulfilling-bouncing-circle-spinner>
|
||||
</div>
|
||||
<va-button @click.stop="connect(controller.id, device)" v-if="device.status == 'scanned' && !device.loading" class="pl-2 pr-2" color="success" small>CONNECT</va-button>
|
||||
<va-button @click.stop="disconnectCheck(controller.id, device)" :disabled="controller.isScan" v-if="device.status == 'connected' && !device.loading" class="pl-2 pr-2" color="danger" small>DISCONNECT</va-button>
|
||||
<div>
|
||||
<va-button style="width: 100px;" @click.stop="connect(controller.id, device)" v-if="device.status == 'scanned' && !device.loading" class="pl-2 pr-2 mt-2" color="success" small>CONNECT</va-button>
|
||||
<va-button style="width: 100px;" @click.stop="disconnectCheck(controller.id, device)" :disabled="controller.isScan" v-if="device.status == 'connected' && !device.loading" class="pl-2 pr-2 mt-2" color="danger" small>DISCONNECT</va-button>
|
||||
<va-button id="detectButton" @click.stop="detect(controller.id, device)" :disabled="controller.isScan" v-if="device.status == 'connected' && !device.loading && device.library_name.indexOf('Elite') !== -1" class="pl-2 pr-2 mt-2" color="primary" small>DETECT</va-button>
|
||||
</div>
|
||||
</va-item-section>
|
||||
</va-item>
|
||||
|
||||
</va-card>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex sm12 xl6 md12 xs12 ma-0"
|
||||
v-for="trigger in triggerList" :key="trigger.mac"
|
||||
>
|
||||
<div v-if="!controller.isScan">
|
||||
<va-card
|
||||
style="background-color: #f8f8f8; box-shadow: 5px 5px 0 0 #f1f1f1;"
|
||||
class="ma-0 pa-0"
|
||||
>
|
||||
<va-item :key="trigger.mac" class="pa-0 ma-0"
|
||||
>
|
||||
<!-- <va-item-section avatar class="ml-1">
|
||||
<va-avatar style="border-radius: 0;">
|
||||
<img :src="trigger.pic" :alt="trigger.name">
|
||||
</va-avatar>
|
||||
</va-item-section> -->
|
||||
<va-item-section class="ml-3">
|
||||
<va-item-label>
|
||||
{{ trigger.name }}
|
||||
<va-badge class="px-1 py-0 ml-2 mt-0" color="success">connected</va-badge>
|
||||
</va-item-label>
|
||||
<va-item-label caption>
|
||||
{{ trigger.mac }}
|
||||
</va-item-label>
|
||||
</va-item-section>
|
||||
</va-item>
|
||||
</va-card>
|
||||
</div>
|
||||
@@ -133,15 +166,21 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { taskInfo } from '../../data/task/TaskInfo'
|
||||
import api from '@/data/api/index'
|
||||
import { taskInfo } from '@/data/task/TaskInfo'
|
||||
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
|
||||
import api from '../../data/api/index'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'devices-overview',
|
||||
components: {
|
||||
FulfillingBouncingCircleSpinner,
|
||||
},
|
||||
computed: {
|
||||
...mapFields('device', [
|
||||
'triggerList',
|
||||
]),
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
@@ -185,6 +224,7 @@ export default {
|
||||
battery: device.battery,
|
||||
library_name: device.library_name,
|
||||
library_version: device.library_version,
|
||||
record_in_sd: device.record_in_sd,
|
||||
status: device.status,
|
||||
pic: taskInfo.getDevicePic(device.device_name),
|
||||
loading: false,
|
||||
@@ -204,14 +244,27 @@ export default {
|
||||
})
|
||||
// console.log(this.controllerList)
|
||||
},
|
||||
'+/hardware_info/+' (data, topic) {
|
||||
async '+/hardware_info/+' (data, topic) {
|
||||
const topicSplit = topic.split('/')
|
||||
const rawDevices = JSON.parse(String.fromCharCode.apply(null, data)).data
|
||||
this.controllerList.forEach(controller => {
|
||||
for (let i = 0; i < this.controllerList.length; i++) {
|
||||
const controller = this.controllerList[i]
|
||||
if (controller.id === topicSplit[0]) {
|
||||
controller.mac = rawDevices.device_mac.toUpperCase()
|
||||
if (rawDevices.device_mac !== null) {
|
||||
controller.mac = rawDevices.device_mac.toUpperCase()
|
||||
// const info = await api.controller.getByMac(controller.mac)
|
||||
// if (info.data.length === 0) {
|
||||
// const req = {
|
||||
// mac_address: controller.mac,
|
||||
// mqtt_id: controller.id,
|
||||
// status: controller.status,
|
||||
// }
|
||||
// api.controller.create(req)
|
||||
// }
|
||||
// console.log(info)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
// console.log(this.controllerList)
|
||||
},
|
||||
'+/hardware_device_connect/+' (data, topic) {
|
||||
@@ -230,6 +283,44 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
'+/data-server/trigger_manager/#' (data, topic) {
|
||||
const mes = new TextDecoder('utf-8').decode(data)
|
||||
const topicSplit = topic.split('/')
|
||||
const baseIndex = topicSplit.indexOf('trigger_manager')
|
||||
const actionIndex = baseIndex + 1
|
||||
const action = topicSplit[actionIndex]
|
||||
const macIndex = baseIndex + 2
|
||||
let _mac
|
||||
if (topicSplit.length - 1 >= macIndex) {
|
||||
_mac = topicSplit[macIndex]
|
||||
}
|
||||
let foundIndex
|
||||
let mesJson
|
||||
switch (action) {
|
||||
case 'info_all': // control_ID/data-server/trigger_manager/info_all
|
||||
this.triggerList = JSON.parse(mes)
|
||||
break
|
||||
case 'register': // control_ID/data-server/trigger_manager/register
|
||||
mesJson = JSON.parse(mes)
|
||||
foundIndex = this.triggerList.findIndex(o => o.mac === mesJson.mac)
|
||||
if (foundIndex < 0) { // -1: not found
|
||||
this.triggerList.push(mesJson)
|
||||
} else {
|
||||
this.triggerList[foundIndex] = mesJson
|
||||
}
|
||||
break
|
||||
case 'remove': // control_ID/data-server/trigger_manager/remove/device_mac
|
||||
foundIndex = this.triggerList.findIndex(o => o.mac === _mac)
|
||||
this.triggerList.splice(foundIndex, 1)
|
||||
break
|
||||
case 'info': // control_ID/data-server/trigger_manager/info/device_mac
|
||||
foundIndex = this.triggerList.findIndex(o => o.mac === _mac)
|
||||
this.triggerList[foundIndex] = mesJson
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
},
|
||||
async '+/broadcast' (data, topic) {
|
||||
const topicSplit = topic.split('/')
|
||||
const mes = String.fromCharCode.apply(null, data).split(':')
|
||||
@@ -244,6 +335,10 @@ export default {
|
||||
controller.status = 'running'
|
||||
}
|
||||
})
|
||||
this.mqttPub(topicSplit[0] + '_user', JSON.stringify({
|
||||
header: 'hardware_datetime/0',
|
||||
content: String(Date.now()),
|
||||
}))
|
||||
this.mqttPub(topicSplit[0] + '_user', JSON.stringify({
|
||||
header: 'hardware_device/0',
|
||||
}))
|
||||
@@ -262,6 +357,14 @@ export default {
|
||||
this.mqttPub(topicSplit[0] + '_user', JSON.stringify({
|
||||
header: 'hardware_device/0',
|
||||
}))
|
||||
this.mqttPub(topicSplit[0] + '_user', JSON.stringify({
|
||||
header: 'device_update_calibration/0',
|
||||
device: parseInt(mes[1]),
|
||||
}))
|
||||
this.mqttPub(topicSplit[0] + '_user', JSON.stringify({
|
||||
header: 'device_sd_card_status/0',
|
||||
device: parseInt(mes[1]),
|
||||
}))
|
||||
// this.mqttPub(topicSplit[0] + '_user', JSON.stringify({
|
||||
// header: 'device_parent/0',
|
||||
// device: parseInt(mes[1]),
|
||||
@@ -316,14 +419,14 @@ export default {
|
||||
default:
|
||||
break
|
||||
}
|
||||
console.log(String.fromCharCode.apply(null, data), topic)
|
||||
// console.log(String.fromCharCode.apply(null, data), topic)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getControllerList: async function () {
|
||||
const update = async () => {
|
||||
this.controllerList.push({
|
||||
id: 'tommy_test',
|
||||
id: taskInfo.getTaskInfo().controllerID,
|
||||
mac: '',
|
||||
status: 'loading',
|
||||
isScan: true,
|
||||
@@ -343,30 +446,43 @@ export default {
|
||||
},
|
||||
pageMqttSub: function () {
|
||||
this.controllerList.forEach(controller => {
|
||||
this.mqttSub(controller.id + '/hardware_datetime/+')
|
||||
this.mqttSub(controller.id + '/hardware_device/+')
|
||||
this.mqttSub(controller.id + '/hardware_info/+')
|
||||
this.mqttSub(controller.id + '/hardware_device_connect/+')
|
||||
this.mqttSub(controller.id + '/hardware_scan/+')
|
||||
this.mqttSub(controller.id + '/broadcast')
|
||||
this.mqttSub(controller.id + '/data-server/trigger_manager/#')
|
||||
})
|
||||
},
|
||||
pageMqttUnSub: function () {
|
||||
this.controllerList.forEach(controller => {
|
||||
this.mqttUnSub(controller.id + '/hardware_datetime/+')
|
||||
this.mqttUnSub(controller.id + '/hardware_device/+')
|
||||
this.mqttUnSub(controller.id + '/hardware_info/+')
|
||||
this.mqttUnSub(controller.id + '/hardware_device_connect/+')
|
||||
this.mqttUnSub(controller.id + '/hardware_scan/+')
|
||||
this.mqttUnSub(controller.id + '/broadcast')
|
||||
this.mqttUnSub(controller.id + '/data-server/trigger_manager/#')
|
||||
})
|
||||
},
|
||||
pageInitPub: function () {
|
||||
this.controllerList.forEach(controller => {
|
||||
this.mqttPub(controller.id + '_user', JSON.stringify({
|
||||
header: 'hardware_datetime/0',
|
||||
content: String(Date.now()),
|
||||
}))
|
||||
this.mqttPub(controller.id + '_user', JSON.stringify({
|
||||
header: 'hardware_device/0',
|
||||
}))
|
||||
this.mqttPub(controller.id + '_user', JSON.stringify({
|
||||
header: 'hardware_info/0',
|
||||
}))
|
||||
this.mqttPub(controller.id + '/client/trigger_manager/scan', '{}')
|
||||
this.mqttPub(controller.id + '/client/trigger_manager/info_all', '{}')
|
||||
// this.mqttPub(controller.id + '_user', JSON.stringify({
|
||||
// header: 'device_update_usb/0',
|
||||
// }))
|
||||
this.createInitialCollection('admin')
|
||||
})
|
||||
},
|
||||
@@ -388,6 +504,7 @@ export default {
|
||||
this.mqttPub(controller.id + '_user', JSON.stringify({
|
||||
header: 'hardware_scan/0',
|
||||
}))
|
||||
this.mqttPub(controller.id + '/client/trigger_manager/scan', '{}')
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -427,6 +544,21 @@ export default {
|
||||
device: this.selectDevice.id,
|
||||
}))
|
||||
},
|
||||
detect (controllerID, device) {
|
||||
this.mqttPub(controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: device.id,
|
||||
instruction: 'VIS_DEVICE_DETECT',
|
||||
}))
|
||||
setTimeout(() => {
|
||||
this.mqttPub(controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: device.id,
|
||||
instruction: 'VIS_DEVICE_DONE',
|
||||
}))
|
||||
document.getElementById('detectButton').className += ' no-dark-style-va-button'
|
||||
}, 5000)
|
||||
},
|
||||
sleep: function (milliseconds) {
|
||||
var start = new Date().getTime()
|
||||
while (1) {
|
||||
@@ -436,20 +568,21 @@ export default {
|
||||
}
|
||||
},
|
||||
createInitialCollection: async function (user) {
|
||||
const root = await api.getCollectionsByName('root')
|
||||
const root = await api.collection.getByParentName('folder', 0, 'root')
|
||||
if (root.data.length === 0) {
|
||||
await api.createCollection({
|
||||
await api.collection.create({
|
||||
name: 'root',
|
||||
type: 'folder',
|
||||
parent: { folder: [0] },
|
||||
size: 0,
|
||||
})
|
||||
}
|
||||
|
||||
// init check and create collection
|
||||
const _root = await api.getCollectionsByName('root')
|
||||
const USER = await api.getCollectionsByName(user)
|
||||
const _root = await api.collection.getByName('root')
|
||||
const USER = await api.collection.getByName(user)
|
||||
if (USER.data.length === 0) {
|
||||
api.createCollection({
|
||||
api.collection.create({
|
||||
name: user,
|
||||
parent: { folder: [_root.data[0].id] },
|
||||
type: 'folder',
|
||||
@@ -461,6 +594,7 @@ export default {
|
||||
watch: {
|
||||
},
|
||||
async mounted () {
|
||||
await taskInfo.updateTaskInfo()
|
||||
await this.getControllerList()
|
||||
|
||||
this.pageMqttSub()
|
||||
@@ -476,3 +610,11 @@ export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.no-dark-style-va-button {
|
||||
&:focus {
|
||||
filter: brightness(100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,143 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-modal
|
||||
class="flex sm12 xl12 md12 xs12 pa-0 ma-0"
|
||||
v-model="showDownload"
|
||||
size="small"
|
||||
:hideDefaultActions="true"
|
||||
:mobileFullscreen="false"
|
||||
>
|
||||
<template slot="header">
|
||||
<div class="row mb-2">
|
||||
<va-icon name="fa fa-download mr-3 " color="primary"/>
|
||||
<h5 class="mt-0 mb-0">{{'Download'}}</h5>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="downloadOptionsList">
|
||||
<template v-for="(downloadOptions, i) in downloadOptionsList">
|
||||
<va-accordion :key="downloadOptions.filename">
|
||||
<va-collapse>
|
||||
<va-item :key="downloadOptions.filename" slot="header" clickable>
|
||||
<va-item-section avatar>
|
||||
<va-item-label>
|
||||
{{ downloadOptions.filename }}
|
||||
</va-item-label>
|
||||
</va-item-section>
|
||||
|
||||
<va-item-section>
|
||||
<!-- <va-item-label>
|
||||
{{ downloadInfo.minTime }}
|
||||
</va-item-label>
|
||||
|
||||
<va-item-label caption>
|
||||
{{ downloadInfo.maxTime }}
|
||||
</va-item-label> -->
|
||||
</va-item-section>
|
||||
|
||||
<va-item-section v-if="downloadOptions.download.status == 'idle'" side>
|
||||
<va-icon name="fa fa-play" color="gray" @click.native.stop="confirmDownload(downloadOptions.metaPath)"/>
|
||||
</va-item-section>
|
||||
<va-item-section v-else side class="md4 offset--md8">
|
||||
<div class="row flex sm12 xl12 md12 xs12">
|
||||
<div class="flex-center spinner-box">
|
||||
<fulfilling-bouncing-circle-spinner
|
||||
:animation-duration="3000"
|
||||
:color="'#6c7fee'"
|
||||
:size="20"
|
||||
>
|
||||
</fulfilling-bouncing-circle-spinner>
|
||||
<span class="ml-3">{{loaded}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</va-item-section>
|
||||
|
||||
</va-item>
|
||||
<div slot="body">
|
||||
<div v-if="downloadOptions.download.status == 'downloading'" class="row flex sm12 xl12 md12 xs12">
|
||||
<div class="row flex sm12 xl12 md12 xs12">
|
||||
<div class="flex-center spinner-box mt-4 mb-5">
|
||||
<fulfilling-bouncing-circle-spinner
|
||||
:animation-duration="3000"
|
||||
:color="'#6c7fee'"
|
||||
:size="60"
|
||||
>
|
||||
</fulfilling-bouncing-circle-spinner>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="mb-5">
|
||||
<va-item class="flex sm12 xl12 md12 xs12 mr-1 pa-0">
|
||||
<va-icon
|
||||
class="flex sm1 xl1 md1 xs1 start "
|
||||
name="glyphicon glyphicon-filter"
|
||||
size="1.0rem"
|
||||
:fixedWidth = "Boolean('true')"
|
||||
/>
|
||||
<div class="flex sm11 xl11 md11 xs11 row">
|
||||
<div v-for="(item,index) in downloadOptions.channel" :key="item.channel" class="filter-button">
|
||||
<va-button
|
||||
class="mx-1 px-1"
|
||||
v-if="item.checked"
|
||||
@click="channelUnchecked(index,downloadOptions.metaPath)"
|
||||
small
|
||||
>
|
||||
{{item.alias}}
|
||||
</va-button>
|
||||
<va-button
|
||||
class="mx-1 px-1"
|
||||
v-else
|
||||
@click="channelChecked(index,downloadOptions.metaPath)"
|
||||
small outline
|
||||
>
|
||||
{{item.alias}}
|
||||
</va-button>
|
||||
</div>
|
||||
</div>
|
||||
</va-item>
|
||||
</div>
|
||||
<div class="mb-5">
|
||||
<va-item class="flex sm12 xl12 md12 xs12 pa-0">
|
||||
<va-icon
|
||||
class="flex sm1 xl1 md1 xs1 mr-4"
|
||||
:fixedWidth="true"
|
||||
name="va-icon glyphicon glyphicon-time"
|
||||
size="1.0rem"
|
||||
/>
|
||||
<div class="flex">
|
||||
<va-slider
|
||||
class="flex sm11 xl11 md11 xs11 filter-button"
|
||||
value-visible
|
||||
range
|
||||
v-model="downloadOptions.timeRange"
|
||||
@click.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
|
||||
@mouseup.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
|
||||
@mouseleave.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
|
||||
@touchend.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
|
||||
:min="downloadOptions.minTime"
|
||||
:max="downloadOptions.maxTime"
|
||||
/>
|
||||
<span> {{ transTime(downloadOptions.timeRange) }} </span>
|
||||
</div>
|
||||
</va-item>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</va-collapse>
|
||||
</va-accordion>
|
||||
<va-list-separator v-if="i < downloadOptionsList.length - 1" :key="'separator' + downloadOptions.filename" />
|
||||
</template>
|
||||
<div class="row flex sm12 xl12 md12 xs12" style="height: 100vh;">
|
||||
<div class="flex-center spinner-box mt-4 mb-5">
|
||||
<fulfilling-bouncing-circle-spinner
|
||||
:animation-duration="3000"
|
||||
:color="'#6c7fee'"
|
||||
:size="60"
|
||||
>
|
||||
</fulfilling-bouncing-circle-spinner>
|
||||
</div>
|
||||
</va-modal>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { file } from '../../data/file/File'
|
||||
import { download } from '../../data/download/Download'
|
||||
import { exportData } from '../../data/export/export'
|
||||
import api from '@/data/api/index'
|
||||
import types from '@/store/modules/download/types'
|
||||
import { mapActions, mapMutations } from 'vuex'
|
||||
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import newDownload from '@/factories/file/downloadFactory'
|
||||
import newChannel from '@/factories/file/channelFactory'
|
||||
import { taskInfo } from '@/data/task/TaskInfo'
|
||||
|
||||
export default {
|
||||
name: 'Download',
|
||||
@@ -146,381 +30,21 @@ export default {
|
||||
},
|
||||
data: () => {
|
||||
return {
|
||||
showDownload: false,
|
||||
controllerList: [],
|
||||
downloadList: [],
|
||||
downloadListRecord: [],
|
||||
downloadOptionsList: [],
|
||||
// downloadInfo: {
|
||||
// metaPath: '',
|
||||
// previousPath: '',
|
||||
// filenameWithType: '',
|
||||
// filename: '',
|
||||
// channel: [],
|
||||
// timeRange: [0, 0],
|
||||
// minTime: 0,
|
||||
// maxTime: 0,
|
||||
// status: 'idle',
|
||||
// device: '',
|
||||
// },
|
||||
currentlyDownloadInfo: {
|
||||
metaPath: '',
|
||||
previousPath: '',
|
||||
filenameWithType: '',
|
||||
filename: '',
|
||||
channel: [],
|
||||
timeRange: [0, 0],
|
||||
minTime: 0,
|
||||
maxTime: 0,
|
||||
download: {
|
||||
status: 'idle',
|
||||
rate: 0,
|
||||
},
|
||||
device: '',
|
||||
},
|
||||
estimatedTime: 0,
|
||||
fileSegmentIndex: 0,
|
||||
fileSegmentMax: 0,
|
||||
totoalFileSize: 0,
|
||||
loadingPercent: 0,
|
||||
loadTime: 0,
|
||||
interval: null,
|
||||
data: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// transTime (min,max) {
|
||||
// return this.getTimeInFormat(min) + ' - ' + this.getTimeInFormat(max)
|
||||
// },
|
||||
loaded () {
|
||||
return this.loadingPercent + '%'
|
||||
},
|
||||
...mapFields('download', [
|
||||
'metaList',
|
||||
'downloadInfo',
|
||||
'metaInfo',
|
||||
]),
|
||||
},
|
||||
// mqtt: {
|
||||
// async '+/file_segment/+' (data, topic) {
|
||||
// console.log('file_segment')
|
||||
// console.log(String.fromCharCode.apply(null, data))
|
||||
// // console.log(navigator.connection.downlink)
|
||||
// // console.log(this.fileNum)
|
||||
// // console.log(this.downloadOptionsList.length)
|
||||
// // console.log(JSON.parse(String.fromCharCode.apply(null, data)).data.file_size)
|
||||
|
||||
// if (this.downloadOptionsList.length > 0) {
|
||||
// await download.updateFileSegmentInfo(String.fromCharCode.apply(null, data))
|
||||
// this.fileSegmentMax = download.getFileSegmentMaxIndex()
|
||||
// this.checkFileSegmentGetOrNot()
|
||||
// }
|
||||
// },
|
||||
// async '+/file_segment_get/+' (data, topic) {
|
||||
// console.log('file_segment_get')
|
||||
// console.log(JSON.parse(new TextDecoder('utf-8').decode(data)))
|
||||
// if (this.downloadOptionsList.length > 0) {
|
||||
// const segmentData = atob(JSON.parse(new TextDecoder('utf-8').decode(data)).data.segment)
|
||||
// this.data += segmentData
|
||||
|
||||
// this.fileSegmentIndex += 1
|
||||
// this.checkFileSegmentGetOrNot()
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
methods: {
|
||||
transTime (timeRange) {
|
||||
return this.getTimeInFormat(timeRange[0]) + ' - ' + this.getTimeInFormat(timeRange[1])
|
||||
},
|
||||
notify (name) {
|
||||
this.showToast(`done ${name}`, {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
},
|
||||
showDownloadModal: function () {
|
||||
this.showDownload = true
|
||||
},
|
||||
channelChecked: function (channelIndex, path) {
|
||||
download.getDownloadOptions(path).channel[channelIndex].checked = true
|
||||
this.refresh()
|
||||
},
|
||||
channelUnchecked: function (channelIndex, path) {
|
||||
download.getDownloadOptions(path).channel[channelIndex].checked = false
|
||||
this.refresh()
|
||||
},
|
||||
getTimeInFormat: function (time) {
|
||||
if (time < 60) {
|
||||
const second = time
|
||||
return `${second}s`
|
||||
} else if (time < 3600) {
|
||||
const second = time % 60
|
||||
const minute = parseInt(time / 60)
|
||||
return `${minute}m${second}s`
|
||||
} else {
|
||||
const hour = parseInt(time / 3600)
|
||||
const hourRemain = time % 3600
|
||||
const minute = parseInt(hourRemain / 60)
|
||||
const second = hourRemain % 60
|
||||
return `${hour}h${minute}m${second}s`
|
||||
}
|
||||
},
|
||||
getCurrentFullPathName: function () {
|
||||
return this.currentlyDownloadInfo.previousPath + '/' + this.currentlyDownloadInfo.filenameWithType
|
||||
},
|
||||
downloading: async function (info) {
|
||||
this.$emit('download')
|
||||
},
|
||||
addDownloadTask: async function (info) {
|
||||
this.downloading()
|
||||
console.log('download')
|
||||
console.time()
|
||||
const rawData = await download.rawByParentChannels(info.id, info.channels)
|
||||
console.timeEnd()
|
||||
exportData.exportCSV(info, rawData)
|
||||
this.downloading()
|
||||
},
|
||||
_addDownloadTask: function (downloadPath) {
|
||||
if (Array.isArray(downloadPath)) {
|
||||
downloadPath.forEach(path => {
|
||||
this.downloadList.push(path.path)
|
||||
this.updateDownloadInfo(path.path)
|
||||
})
|
||||
} else {
|
||||
this.downloadList.push(downloadPath)
|
||||
this.updateDownloadInfo(downloadPath)
|
||||
}
|
||||
this.confirmDownload()
|
||||
},
|
||||
refresh: function () {
|
||||
this.downloadOptionsList = download.getDownloadOptionsList()
|
||||
console.log(this.downloadOptionsList)
|
||||
},
|
||||
confirmDownload: function (path) {
|
||||
console.log('confirmDownload')
|
||||
console.log(download.getDownloadOptionsList())
|
||||
console.log(download.isFileDownloading())
|
||||
console.log(download.downloadTaskRemain())
|
||||
if (!download.isFileDownloading() && download.downloadTaskRemain()) {
|
||||
const downloadOptionsIndex = download.getDownloadOptionsList().findIndex(downloadInfo => downloadInfo.metaPath === path)
|
||||
// this.downloadBlockList[downloadInfoIndex].status = 'downloading'
|
||||
this.currentlyDownloadInfo = download.getDownloadOptionsList()[downloadOptionsIndex]
|
||||
this.currentlyDownloadInfo.download.status = 'downloading'
|
||||
console.log(this.currentlyDownloadInfo)
|
||||
console.log(download.getDownloadOptionsList())
|
||||
|
||||
download.updateDownloadSubFileList(
|
||||
this.currentlyDownloadInfo.metaPath,
|
||||
this.currentlyDownloadInfo.channel,
|
||||
this.currentlyDownloadInfo.timeRange,
|
||||
)
|
||||
this.calculateFileSize(this.currentlyDownloadInfo.metaPath)
|
||||
console.log('getactualsize')
|
||||
this.subfileListRemain()
|
||||
}
|
||||
// if (this.downloadList.length > 0 && this.currentlyDownloadInfo.status === 'idle') {
|
||||
// this.showDownload()
|
||||
// this.updateDownloadSubFileList(this.downloadList[0])
|
||||
// } else {
|
||||
// /* TODO If file downloading then waiting */
|
||||
// console.log('no download task or file downloading')
|
||||
// }
|
||||
},
|
||||
_confirmDownload: function () {
|
||||
console.log('confirmDownload')
|
||||
console.log(download.getDownloadOptionsList())
|
||||
// if (this.downloadList.length > 0 && this.currentlyDownloadInfo.status === 'idle') {
|
||||
// this.showDownload()
|
||||
// this.updateDownloadSubFileList(this.downloadList[0])
|
||||
// } else {
|
||||
// /* TODO If file downloading then waiting */
|
||||
// console.log('no download task or file downloading')
|
||||
// }
|
||||
},
|
||||
downloadAllSubFileList: async function (path) {
|
||||
this.currentlyDownloadInfo = this.downloadInfo
|
||||
download.downloadAllSubFileList(path)
|
||||
this.subfileListRemain()
|
||||
},
|
||||
// updateDownloadInfo: function (path) {
|
||||
// console.log(path)
|
||||
// const metaInfo = file.getMetaInfo(path)
|
||||
// const downloadInfoIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === path)
|
||||
|
||||
// if (downloadInfoIndex === -1) {
|
||||
// this.downloadInfo.library = metaInfo.configuration._LIBRARY_
|
||||
// this.downloadInfo.channel = metaInfo.channel.map(ch => {
|
||||
// let channel = ''
|
||||
// if (this.downloadInfo.library.includes('Elite')) {
|
||||
// channel = (ch === 0) ? 'current' : (ch === 1) ? 'voltage' : (ch === 2) ? 'resistance' : ''
|
||||
// } else {
|
||||
// channel = 'channel' + ch
|
||||
// }
|
||||
// return {
|
||||
// alias: channel,
|
||||
// channel: ch,
|
||||
// checked: true,
|
||||
// }
|
||||
// })
|
||||
|
||||
// this.downloadInfo.metaPath = path
|
||||
// this.downloadInfo.previousPath = path.split('/').slice(0, -1).join('/')
|
||||
// this.downloadInfo.filename = path.split(/[\/.]+/).slice(0, -1).pop()
|
||||
// this.downloadInfo.minTime = parseInt([...new Set(metaInfo['start-time'])][0] / 1000)
|
||||
// this.downloadInfo.maxTime = parseInt(metaInfo.time_duration / 1000)
|
||||
// this.downloadInfo.timeRange = [this.downloadInfo.minTime, this.downloadInfo.maxTime]
|
||||
// this.downloadInfo.status = 'idle'
|
||||
// this.downloadBlockList.push(JSON.parse(JSON.stringify(this.downloadInfo)))
|
||||
// } else {
|
||||
// for (var item in this.downloadInfo) {
|
||||
// this.downloadInfo[item] = this.downloadBlockList[downloadInfoIndex][item]
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
updatecurrentlyDownloadInfo: function () {
|
||||
const downloadInfoIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === this.currentlyDownloadInfo.metaPath)
|
||||
if (downloadInfoIndex !== -1) {
|
||||
for (var item in this.downloadBlockList[downloadInfoIndex]) {
|
||||
this.downloadBlockList[downloadInfoIndex][item] = this.currentlyDownloadInfo[item]
|
||||
}
|
||||
}
|
||||
},
|
||||
updateMetaDownloadInfo: function () {
|
||||
download.updateDownloadSubFileList(
|
||||
this.currentlyDownloadInfo.metaPath,
|
||||
this.currentlyDownloadInfo.channel,
|
||||
this.currentlyDownloadInfo.timeRange,
|
||||
)
|
||||
},
|
||||
updateDownloadSubFileList: function (path) {
|
||||
console.log('updateDownloadSubFileList')
|
||||
const downloadOptionsIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === path)
|
||||
this.downloadBlockList[downloadOptionsIndex].status = 'downloading'
|
||||
this.currentlyDownloadInfo = this.downloadBlockList[downloadOptionsIndex]
|
||||
this.updatecurrentlyDownloadInfo()
|
||||
|
||||
download.updateDownloadSubFileList(
|
||||
this.currentlyDownloadInfo.metaPath,
|
||||
this.currentlyDownloadInfo.channel,
|
||||
this.currentlyDownloadInfo.timeRange,
|
||||
)
|
||||
this.subfileListRemain()
|
||||
},
|
||||
_updateDownloadSubFileList: function (path) {
|
||||
console.log(path)
|
||||
console.log(this.downloadInfo)
|
||||
const downloadOptionsIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === path)
|
||||
this.downloadBlockList[downloadOptionsIndex].status = 'downloading'
|
||||
this.currentlyDownloadInfo = this.downloadBlockList[downloadOptionsIndex]
|
||||
// this.updatecurrentlyDownloadInfo()
|
||||
|
||||
download.updateDownloadSubFileList(
|
||||
this.currentlyDownloadInfo.metaPath,
|
||||
this.currentlyDownloadInfo.channel,
|
||||
this.currentlyDownloadInfo.timeRange,
|
||||
)
|
||||
this.subfileListRemain()
|
||||
},
|
||||
subfileListRemain: function () {
|
||||
console.log('subfileListRemain')
|
||||
if (download.checkDownloadSubFileList(this.currentlyDownloadInfo.metaPath)) {
|
||||
this.currentlyDownloadInfo.filenameWithType = download.getFirstSubfile(this.currentlyDownloadInfo.metaPath)
|
||||
this.mqttPub('tommy_test_user', JSON.stringify({
|
||||
header: 'file_segment/0',
|
||||
method: 'new',
|
||||
path: this.getCurrentFullPathName(),
|
||||
}))
|
||||
} else {
|
||||
this.loadingPercent = 100
|
||||
console.log(this.currentlyDownloadInfo.filenameWithType + ' download complete')
|
||||
console.log(performance.now())
|
||||
this.exportCSV()
|
||||
this.test(this.downloadDone)
|
||||
// this.currentlyDownloadInfo.status = this.currentlyDownloadInfo.status = 'idle'
|
||||
// this.updatecurrentlyDownloadInfo()
|
||||
// this.loadingPercent = 0
|
||||
}
|
||||
},
|
||||
checkFileSegmentGetOrNot: function () {
|
||||
console.log('checkFileSegmentGetOrNot')
|
||||
if (this.fileSegmentIndex >= this.fileSegmentMax) {
|
||||
const subfile = file.shiftDownloadSubFileList(this.currentlyDownloadInfo.metaPath)
|
||||
file.pushDownloadData(this.currentlyDownloadInfo.metaPath, subfile, this.data)
|
||||
|
||||
this.data = ''
|
||||
this.fileSegmentIndex = 0
|
||||
this.subfileListRemain()
|
||||
} else {
|
||||
this.mqttPub('tommy_test_user', JSON.stringify({
|
||||
header: 'file_segment_get/0',
|
||||
segment: this.fileSegmentIndex,
|
||||
path: this.getCurrentFullPathName(),
|
||||
}))
|
||||
}
|
||||
},
|
||||
exportCSV: function () {
|
||||
exportData.exportCSV(this.currentlyDownloadInfo)
|
||||
},
|
||||
exportTXT: function () {
|
||||
},
|
||||
timeRangeChange: function (timeRange, path) {
|
||||
download.getDownloadOptions(path).timeRange = timeRange
|
||||
this.refresh()
|
||||
},
|
||||
calculateFileSize: function () {
|
||||
this.totoalFileSize = file.getFileSize(this.currentlyDownloadInfo.metaPath)
|
||||
// const allSubfile = download.getAllSubfile(this.currentlyDownloadInfo.metaPath)
|
||||
// this.fileNum = allSubfile.length
|
||||
const downlinkSpeed = this.getNetSpeed('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAABTVBMVEX////qQzU0qFNChfT7vAU/g/RZlPU5gPT7uQCxyPqXufn/vQDpNCLqQTMwp1D7uADpOCfqPS4fo0bpMiD8wADpLxwopUv0paD1q6b86ObpOiv4/Pn+9/b4xcH2ubX1r6rsXVIre/NwvoOf0qvO6NQzqUm/4cf5zMn739zrSz398O/sVEjvdWz2t7PvenP4ycb7wir96Lf+8tb8zFH93pj+9eH//PD92Yvw9v7+7cP80Xb95q6pxPnq9u1PsmigvvlunvaJyZiGrvjD1vvyl5HtamHoJgzwhH3zmpTtXlLvenHuYSzygCL2mxjsUzDwcSf0jx34phH8z2DxfVHX5P38x0KHvnDOtiGjsjJ0rkLhuRW4tCnS4PyMsDtZq0it2bhmmvbO5OE1noBft3U1pWA/jNc8lLk5nJNBieSSy58+j8t5wIo6mKY2o25FrmBHQXgmAAAIJUlEQVR4nO2b2V/bRhCAhbADxJLQYQvwgcE2PsAhEHK0SUxigoGkTdMj6ZXDTdw2JbT+/x9r+QDZllYra8da85vvKU/yfszszO5IEQQEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRDWpLfXSplbqysWq9n1Unk7HfaSmJFey6ycNipGwpDUAZKRSMxt7B6vl7fDXl5QyqvVHdVQk5o8N4osa0nJqDSOSzNrmc7sVlRVk8fl7J4dTbmRXQt7sf5JZ6onkkPknC3VxE52tiJZPtUMjcru0lI1dkthL5uaTMNI0kVvOJLGRnYmCmx2R/IXPpukVFnh3nG9IvkPn81R1bJhKxC5vWME8evHMRO2hitr1URQv65jospp81jRkgz8LJLaStgyDpSfqywC2ENWN7gL48rJpAXUGe3kVthKQ2w3DKZ+c9ZuPOWocZQqrHagHY4yNRuoBbqjaZyc444D90A35AQPmzFdlYD8uorht410Q4UTnJON0A3TOxA15pLE6nUXvOYRlI3wI9gAFZRCFxReQBaZufAjKBwDtgkeioyQZX4UtcFDIyz5PqrJsqYlk2oymdQ8hqhc7MHtih9Ba+4rVTaqp6fHZ2fHp7sNaxDuPk3lQVCo+iijmmQ0zjJr9ncx6e3Syq6WcBk6crAHhVXqTSirJ7sZ53l2unQsGQ6R5GAPCuUT2vCpz28RL7K3q+pIIDlo9B026EYWmlT1vuGVT1X707jYg8IKVauXjQbdDbZctd0wuYjgGtU7peTcOvUTM/KgcPFQZDqnNYo6Khu7fh6ZftENo8yHYCnhLajN+R3NZzsFh489KAg73jk6yZisXNE4EVz3boXG7iSjzrUKH4KC93EtcTzZkzmZAD9a/obsJ0tnYa8xEKm9SPxboqHEwZkrCPuLkUj8JSFRpdOwlxiQg0iH+PJ3boJqNewVBuTOYqSrGH/lLKjtcFIuJuZhz7Dj+L1jldHKYa8wIKnIJfEfHDJVoj+Kcsr+sk1xvG0kZ30T9uvMleNI25DV2fo2zYH7y5FhxZdDhgbfH/vQsL8YGVG0tw15J+z1BefHUcNIPPLqsvsbt8NeX2BSo35DbUPbCHt9wbkzFsJe2+iHkN/P0ai562gYiS9abUPeCHt5DDhwFOy3DZWT62sQ7u+5GVq3DY2bz3sm555zkvYUl38Ke3kM2F92N4wsPqJ8ytKNwLyGMnxAiGFk+T6t4WY0IJtLUIYPSYZ7tE9ZWpgPyMJNKMM3pCR9MD3D6FMgwftxUpLuT89wfh7KkMk2ZGG4CWR4j1RK49SPYWH4FYzh1yTDN1M1BGoXjwhZuvhwqobvYAxdzt09Q+pSysJw4VkIhnevvSHtmY2NIdChhnRom7Lh42tv+AQNJ4OjfRiG4XRraRiG0+2HQJWGnzMNVLcgnksPpmoI1PH5uVtAGXJ0PwQ6efNzx4e6PXEzpwG7AXMzawObYrCalwaftUWhDIkz72XqmffmAg0kwxtQhqT3FrH4z5RPeXeThiOC4cIRlCHh3VPsF0Wpsfyt14QgQh3aBPf3h7HYr6Jo5ln+FGm3QjV8wfXsHYv8Joqicsjyp46i7oZgzcLtPX7sd0W00IsMf4qwDcGG+oLLtxixt2IPpcXul95tuvuBvZixGP+eJhZ5Lw5gGMQj0jYEuv92GfsmKrb34VJQVNrMfmiBtA2Bzt1dRr9r6zQJ0YbeZPQ7pEoanYcrNMJIv+g2iSF0Rj2RVGZAt+Hwwa3XJIZQckx+hXh0Bd2GQ9V00CSGg8gkT28QduH8AtiXGD0ub1Cxtw6CIpOz2xPi7QPs2N2n3/RjsfcOft16mgr6E69JhRTwQ4wBB70M/eAs2DmeBu77xBwFT9JeSxxpEiNbsR7sB0jN3oKNBom98SYxohjokrFEOK/Ng1fSLo/GmwRDxWceEQS8V1whElI0aKI+I1aZTrsHu97bKepehqKem6yiegnCnkmvOPQMYqeiTtIXH296CEb/YO3iTME7iJ1M9n+V8qqinRDCzS+GyZkUivqFv0z9OO8pCDdGHKXmnaZWpio+wpi60D/d8FIEHEGNkqfIUyuMrQLd81J50RS3/vyLrDitXdiFotjQO9bybd16nmL+TVQEe+XkuCiqIHYdD5vk/Vi4UMzB32vrc9S9mi48nY5bH7o87TnquaKLZKpwruj2dNj67x/XMEancZyx0aKopzbJ1nmxVrN5pmq14nnL1EefoihfXBShPk9wpdam24qDlZu6Lh7mLur183r9Itc6FHXddLxDb/3rmKnA4xknaPr+WIDMHopC+PNsfXLqjNPOUYumf0U6ttrjbWNqp5kh6lCKytZo24B7ZUiG5vQ2GVuf5+2bcXrHtRFSfgqqT0V72wAecxMVD8EUTeXL5TwDfvpEUvTVM3wxaBvRKR64HRXBothpG91MhfvPeJSKcHuxd9sIW7CjmINqGt22Eb6gANgXLcWPYdt1aepA9UZRKK/Q4BREkM1otpl+hRSIWgsgUyedugKRZ52pSrD3HwDU2HZGU+RlC9rIk259/lDMOlcZOqCWY5Sq+iGHAexROGTgaJqsvssBoSgGdDTNcy4T1EYzQBwVU6nz0wPdKbbGpoR0fno7Pwt+FoW64jeQiuk+OeaSVDHnMhF10Zud8F3RkRSt2aiHXMdObDVnT69PoZlrm7qzpzUg1s12Ll+YpeR0IFUr5i9abd2iP/M2u/9ut+r5Ym3G7a5IpWqFYrOZt2g2i4VCLXVt3BAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAE4Yf/AZmODCZml4YgAAAAAElFTkSuQmCC', 3)
|
||||
// this.totoalFileSize = (allSubfile.length) * 1000000
|
||||
console.log(downlinkSpeed)
|
||||
console.log(this.totoalFileSize)
|
||||
this.estimatedTime = this.totoalFileSize / (downlinkSpeed * 1024)
|
||||
if (this.totoalFileSize >= 1 * 1024 * 1024) {
|
||||
console.log('size big')
|
||||
this.estimatedTime = this.estimatedTime * 10
|
||||
}
|
||||
console.log(this.estimatedTime)
|
||||
this.loadTime = parseInt((this.estimatedTime / 1000) % 60) * 100
|
||||
console.log(this.loadTime)
|
||||
this.doProgress()
|
||||
// allSubfile.forEach(subfile => {
|
||||
// console.log(subfile)
|
||||
// this.currentlyDownloadInfo.filenameWithType = subfile
|
||||
// this.mqttPub('tommy_test_user', JSON.stringify({
|
||||
// header: 'file_segment/0',
|
||||
// method: 'new',
|
||||
// path: this.getCurrentFullPathName(),
|
||||
// }))
|
||||
// })
|
||||
},
|
||||
doProgress () {
|
||||
const step = this.estimatedTime / 100 * 1000
|
||||
this.interval = setInterval(() => {
|
||||
if (this.loadingPercent >= 99) {
|
||||
console.log('complete')
|
||||
clearInterval(this.interval)
|
||||
this.estimatedTime = 0
|
||||
} else {
|
||||
this.loadingPercent++
|
||||
}
|
||||
}, step)
|
||||
},
|
||||
getNetSpeed (url, times) {
|
||||
const connection = window.navigator.connection
|
||||
if (connection && connection.downlink) {
|
||||
return connection.downlink * 1024 / 8
|
||||
}
|
||||
},
|
||||
test: async function (fn) {
|
||||
return await setTimeout(async function () {
|
||||
await fn()
|
||||
}, 1000)
|
||||
},
|
||||
downloadDone: function () {
|
||||
download.getDownloadOptionsList().shift()
|
||||
this.loadingPercent = 0
|
||||
this.refresh()
|
||||
this.confirmDownload()
|
||||
},
|
||||
getControllerList: async function () {
|
||||
const update = async () => {
|
||||
this.controllerList.push({
|
||||
id: 'tommy_test',
|
||||
id: taskInfo.getTaskInfo().controllerID,
|
||||
mac: '',
|
||||
status: 'loading',
|
||||
isScan: true,
|
||||
@@ -529,43 +53,180 @@ export default {
|
||||
}
|
||||
await update()
|
||||
},
|
||||
mqttPub: function (topic, mes) {
|
||||
this.$mqtt.publish(topic, mes)
|
||||
},
|
||||
mqttSub: function (val) {
|
||||
this.$mqtt.subscribe(val)
|
||||
},
|
||||
mqttUnSub: function (val) {
|
||||
this.$mqtt.unsubscribe(val)
|
||||
},
|
||||
pageMqttSub: function () {
|
||||
this.controllerList.forEach(controller => {
|
||||
// this.mqttSub(controller.id + '/broadcast')
|
||||
this.mqttSub(controller.id + '/file_meta_info/+')
|
||||
this.mqttSub(controller.id + '/file_segment/+')
|
||||
this.mqttSub(controller.id + '/file_segment_get/+')
|
||||
notify (name) {
|
||||
this.showToast(`done ${name}`, {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
},
|
||||
pageMqttUnSub: function () {
|
||||
this.controllerList.forEach(controller => {
|
||||
// this.mqttUnSub(controller.id + '/broadcast')
|
||||
this.mqttUnSub(controller.id + '/file_meta_info/+')
|
||||
this.mqttUnSub(controller.id + '/file_segment/+')
|
||||
this.mqttUnSub(controller.id + '/file_segment_get/+')
|
||||
})
|
||||
chunkArray (rawDataIDArray, chunkSize) {
|
||||
const arrayLength = rawDataIDArray.length
|
||||
const results = []
|
||||
for (let index = 0; index < arrayLength; index += chunkSize) {
|
||||
results.push(rawDataIDArray.slice(index, index + chunkSize))
|
||||
}
|
||||
return results
|
||||
},
|
||||
...mapActions('download',
|
||||
[
|
||||
types.raw.rawDataByID,
|
||||
types.raw.rawDataByIDs,
|
||||
types.raw.rawSdDataByID,
|
||||
types.export.setHeader,
|
||||
types.export.setTitle,
|
||||
types.export.setData,
|
||||
types.download.closeWriter,
|
||||
types.download.setStream,
|
||||
types.download.setSampleRate,
|
||||
types.download.setIDList,
|
||||
types.download.clearStream,
|
||||
],
|
||||
),
|
||||
...mapMutations('download',
|
||||
[
|
||||
types.download.clearIDList,
|
||||
],
|
||||
),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
// watch: {
|
||||
// loadingPercent(val) {
|
||||
// if (val >= 100) {
|
||||
// console.log('complete');
|
||||
// clearInterval(this.interval)
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
async mounted () {
|
||||
await this.getControllerList()
|
||||
this.pageMqttSub()
|
||||
// TODO authorization
|
||||
const format = this.$route.params.format
|
||||
this.metaList = this.$route.params.metaList.split('-')
|
||||
const sd = this.$route.params.sd
|
||||
|
||||
while (this.metaList.length !== 0) {
|
||||
let meta
|
||||
const metaID = this.metaList.pop()
|
||||
const ret = await api.meta.getByID(metaID)
|
||||
|
||||
if (ret.status === 200) {
|
||||
meta = ret.data[0]
|
||||
}
|
||||
if (meta !== undefined) {
|
||||
this.metaInfo = meta
|
||||
const channelArray = JSON.parse(this.metaInfo.channels)
|
||||
const channelList = []
|
||||
|
||||
// split to different subfile by channel
|
||||
if (meta.device.library_name.indexOf('Neulive') >= 0) {
|
||||
if (channelArray.some(el => el >= 256)) {
|
||||
channelList.push(channelArray.filter(el => (el >= 256 && el <= 259)))
|
||||
channelList.push(channelArray.filter(el => el < 256))
|
||||
} else {
|
||||
channelList.push(channelArray)
|
||||
}
|
||||
} else if (meta.device.library_name.indexOf('Elite') >= 0) {
|
||||
channelList.push(channelArray)
|
||||
}
|
||||
|
||||
while (channelList.length > 0) {
|
||||
const channels = channelList.pop()
|
||||
|
||||
let maxSplitFiles = 1
|
||||
let fileIndex = 0
|
||||
|
||||
// find max raw data need sub file
|
||||
for (const rawDataIndex of channels) {
|
||||
const dataLength = meta.raw_data[rawDataIndex].length
|
||||
|
||||
maxSplitFiles = Math.max(maxSplitFiles, Math.ceil(meta.raw_data[rawDataIndex].length / dataLength))
|
||||
meta.raw_data[rawDataIndex] = this.chunkArray(meta.raw_data[rawDataIndex], dataLength)
|
||||
}
|
||||
|
||||
while (fileIndex < maxSplitFiles) {
|
||||
// create new download info & add channel
|
||||
if (this.downloadInfo === null) {
|
||||
this.downloadInfo = newDownload()
|
||||
}
|
||||
this.downloadInfo.channel = channels
|
||||
|
||||
// download format
|
||||
this.downloadInfo.format = format
|
||||
|
||||
// download device and filename
|
||||
if (meta.device.library_name.indexOf('Neulive') >= 0) {
|
||||
this.downloadInfo.device = [meta.device.library_name.slice(0, 7), meta.device.library_name.slice(7)]
|
||||
if (this.downloadInfo.channel.some(el => el >= 256 && el <= 259)) {
|
||||
this.downloadInfo.filename = meta.name + '-accerlate'
|
||||
this.downloadInfo.filename += (sd !== undefined) ? '-sd' : ''
|
||||
this.downloadInfo.size = parseInt(parseInt(meta.size) / (76 * (maxSplitFiles)))
|
||||
} else {
|
||||
this.downloadInfo.filename = meta.name
|
||||
this.downloadInfo.filename += (sd !== undefined) ? '-sd' : ''
|
||||
this.downloadInfo.size = parseInt(meta.size / (maxSplitFiles))
|
||||
}
|
||||
} else if (meta.device.library_name.indexOf('Elite') >= 0) {
|
||||
this.downloadInfo.device = [meta.device.library_name.slice(0, 5), meta.device.library_name.slice(5)]
|
||||
this.downloadInfo.filename = meta.name
|
||||
this.downloadInfo.size = parseInt(meta.size / (maxSplitFiles))
|
||||
}
|
||||
|
||||
// create new channel info & get sample rate
|
||||
for (const channel of this.downloadInfo.channel) {
|
||||
if (this.downloadInfo.channelInfo[channel] === undefined) {
|
||||
this.downloadInfo.channelInfo[channel] = newChannel()
|
||||
this.setSampleRateDownload({ channel: channel })
|
||||
}
|
||||
}
|
||||
|
||||
// set download ID list
|
||||
this.clearIDListDownload()
|
||||
for (const channel of this.downloadInfo.channel) {
|
||||
this.setIDListDownload({ channel: channel, fileIndex: fileIndex })
|
||||
}
|
||||
|
||||
// if create writer
|
||||
this.clearStreamDownload()
|
||||
this.setStreamDownload()
|
||||
|
||||
// set Header
|
||||
if (this.downloadInfo.format !== 'csv-edf') {
|
||||
await this.setHeaderExport()
|
||||
}
|
||||
await this.setTitleExport()
|
||||
|
||||
// start download data
|
||||
let rowIndex = 0
|
||||
|
||||
while (rowIndex < this.downloadInfo.maxRows) {
|
||||
for (const channel of this.downloadInfo.channel) {
|
||||
for (const idx in this.downloadInfo.channelInfo[channel].downloadIDList) {
|
||||
const _idx = parseInt(idx)
|
||||
const rawID = this.downloadInfo.channelInfo[channel].downloadIDList[_idx][rowIndex]
|
||||
// const rawID = this.downloadInfo.channelInfo[channel].downloadIDList[_idx].splice(0, 10).join(',')
|
||||
// console.log(rowIndex, _idx, rawID)
|
||||
if (rawID !== undefined) {
|
||||
if (sd === 'sd') {
|
||||
await this.rawSdDataByIDRaw({
|
||||
channel: channel,
|
||||
rawID: rawID,
|
||||
idx: _idx,
|
||||
api: api,
|
||||
})
|
||||
} else {
|
||||
await this.rawDataByIDRaw({
|
||||
channel: channel,
|
||||
rawID: rawID,
|
||||
idx: _idx,
|
||||
api: api,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await this.setDataExport({ last: (rowIndex >= this.downloadInfo.maxRows - 1) })
|
||||
rowIndex += 1
|
||||
}
|
||||
this.closeWriterDownload()
|
||||
fileIndex += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 2000)) // sleep 2s prevent window close
|
||||
window.close()
|
||||
},
|
||||
destroyed () {
|
||||
this.pageMqttUnSub()
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="row flex sm12 xl12 md12 xs12" style="height: 100vh;">
|
||||
<div class="flex-center spinner-box mt-4 mb-5">
|
||||
<fulfilling-bouncing-circle-spinner
|
||||
:animation-duration="3000"
|
||||
:color="'#6c7fee'"
|
||||
:size="60"
|
||||
>
|
||||
</fulfilling-bouncing-circle-spinner>
|
||||
<progress-modal
|
||||
:ref="'progressModalRef'"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import api from '@/data/api/index'
|
||||
import types from '@/store/modules/download/types'
|
||||
import { mapActions, mapMutations } from 'vuex'
|
||||
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import newDownload from '@/factories/file/downloadFactory'
|
||||
import newChannel from '@/factories/file/channelFactory'
|
||||
import progressModal from '@/components/common/progressBarByValueModal/progressModal.vue'
|
||||
import { taskInfo } from '@/data/task/TaskInfo'
|
||||
|
||||
export default {
|
||||
name: 'DownloadOffline',
|
||||
components: {
|
||||
FulfillingBouncingCircleSpinner,
|
||||
progressModal,
|
||||
},
|
||||
data: () => {
|
||||
return {
|
||||
controllerList: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('download', [
|
||||
'metaList',
|
||||
'downloadInfo',
|
||||
'metaInfo',
|
||||
]),
|
||||
},
|
||||
methods: {
|
||||
getControllerList: async function () {
|
||||
const update = async () => {
|
||||
this.controllerList.push({
|
||||
id: taskInfo.getTaskInfo().controllerID,
|
||||
mac: '',
|
||||
status: 'loading',
|
||||
isScan: true,
|
||||
files: [],
|
||||
})
|
||||
}
|
||||
await update()
|
||||
},
|
||||
notify (name) {
|
||||
this.showToast(`done ${name}`, {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
},
|
||||
chunkArray (rawDataIDArray, chunkSize) {
|
||||
const arrayLength = rawDataIDArray.length
|
||||
const results = []
|
||||
for (let index = 0; index < arrayLength; index += chunkSize) {
|
||||
results.push(rawDataIDArray.slice(index, index + chunkSize))
|
||||
}
|
||||
return results
|
||||
},
|
||||
...mapActions('download',
|
||||
[
|
||||
types.raw.rawDataByID,
|
||||
types.raw.rawDataByIDs,
|
||||
types.raw.rawSdDataByID,
|
||||
types.export.setHeader,
|
||||
types.export.setTitle,
|
||||
types.export.setData,
|
||||
types.export.setAll,
|
||||
types.download.closeWriter,
|
||||
types.download.setStream,
|
||||
types.download.setSampleRate,
|
||||
types.download.setIDList,
|
||||
],
|
||||
),
|
||||
...mapMutations('download',
|
||||
[
|
||||
types.download.clearIDList,
|
||||
],
|
||||
),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
async mounted () {
|
||||
await this.getControllerList()
|
||||
// TODO authorization
|
||||
const format = this.$route.params.format
|
||||
this.metaList = this.$route.params.metaList.split('-')
|
||||
const sd = this.$route.params.sd
|
||||
|
||||
while (this.metaList.length !== 0) {
|
||||
let meta
|
||||
const metaID = this.metaList.pop()
|
||||
const ret = await api.meta.getByID(metaID)
|
||||
|
||||
if (ret.status === 200) {
|
||||
meta = ret.data[0]
|
||||
}
|
||||
if (meta !== undefined) {
|
||||
this.metaInfo = meta
|
||||
const channelArray = JSON.parse(this.metaInfo.channels)
|
||||
const channelList = []
|
||||
|
||||
if (meta.device.library_name.indexOf('Neulive') >= 0) {
|
||||
if (channelArray.some(el => el >= 256)) {
|
||||
channelList.push(channelArray.filter(el => (el >= 256 && el <= 259)))
|
||||
channelList.push(channelArray.filter(el => el < 256))
|
||||
} else {
|
||||
channelList.push(channelArray)
|
||||
}
|
||||
} else if (meta.device.library_name.indexOf('Elite') >= 0) {
|
||||
channelList.push(channelArray)
|
||||
}
|
||||
|
||||
this.$refs.progressModalRef.show()
|
||||
|
||||
while (channelList.length > 0) {
|
||||
const channels = channelList.pop()
|
||||
|
||||
let maxSplitFiles = 1
|
||||
let fileIndex = 0
|
||||
|
||||
// find max raw data need sub file
|
||||
for (const rawDataIndex of Object.keys(meta.raw_data)) {
|
||||
let dataLength = 0
|
||||
if (rawDataIndex >= 256) {
|
||||
dataLength = meta.raw_data[rawDataIndex].length
|
||||
} else {
|
||||
dataLength = 160
|
||||
}
|
||||
|
||||
maxSplitFiles = Math.max(maxSplitFiles, Math.ceil(meta.raw_data[rawDataIndex].length / dataLength))
|
||||
meta.raw_data[rawDataIndex] = this.chunkArray(meta.raw_data[rawDataIndex], dataLength)
|
||||
}
|
||||
|
||||
while (fileIndex < maxSplitFiles) {
|
||||
if (this.downloadInfo === null) {
|
||||
this.downloadInfo = newDownload()
|
||||
}
|
||||
this.downloadInfo.channel = channels
|
||||
// download format
|
||||
this.downloadInfo.format = format
|
||||
|
||||
// download device and filename
|
||||
if (meta.device.library_name.indexOf('Neulive') >= 0) {
|
||||
this.downloadInfo.device = [meta.device.library_name.slice(0, 7), meta.device.library_name.slice(7)]
|
||||
if (this.downloadInfo.channel.some(el => el >= 256 && el <= 259)) {
|
||||
this.downloadInfo.filename = meta.name + '-accerlate-' + format
|
||||
this.downloadInfo.filename += (sd !== undefined) ? '-sd' : ''
|
||||
this.downloadInfo.size = parseInt(parseInt(meta.size) / 76)
|
||||
} else {
|
||||
this.downloadInfo.filename = meta.name + '-' + format
|
||||
this.downloadInfo.filename += (sd !== undefined) ? '-sd' : ''
|
||||
this.downloadInfo.size = parseInt(meta.size)
|
||||
}
|
||||
} else if (meta.device.library_name.indexOf('Elite') >= 0) {
|
||||
this.downloadInfo.device = [meta.device.library_name.slice(0, 5), meta.device.library_name.slice(5)]
|
||||
this.downloadInfo.filename = meta.name + '-' + (fileIndex + 1).toString()
|
||||
this.downloadInfo.size = parseInt(meta.size)
|
||||
}
|
||||
|
||||
this.$refs.progressModalRef.setTitle(this.downloadInfo.filename)
|
||||
|
||||
// get sampleRate && downloadList
|
||||
for (const channel of this.downloadInfo.channel) {
|
||||
if (this.downloadInfo.channelInfo[channel] === undefined) {
|
||||
this.downloadInfo.channelInfo[channel] = newChannel()
|
||||
this.setSampleRateDownload({ channel: channel })
|
||||
}
|
||||
}
|
||||
|
||||
this.clearIDListDownload()
|
||||
for (const channel of this.downloadInfo.channel) {
|
||||
this.setIDListDownload({ channel: channel, fileIndex: fileIndex })
|
||||
}
|
||||
|
||||
// start download data
|
||||
fileIndex += 1
|
||||
let rowIndex = 0
|
||||
|
||||
while (rowIndex < this.downloadInfo.maxRows) {
|
||||
this.$refs.progressModalRef.setValue(parseInt((rowIndex / this.downloadInfo.maxRows) * 100))
|
||||
for (const channel of this.downloadInfo.channel) {
|
||||
for (const idx in this.downloadInfo.channelInfo[channel].downloadIDList) {
|
||||
const _idx = parseInt(idx)
|
||||
const rawID = this.downloadInfo.channelInfo[channel].downloadIDList[_idx][rowIndex]
|
||||
// console.log(rowIndex, _idx, rawID)
|
||||
if (rawID !== undefined) {
|
||||
if (sd === 'sd') {
|
||||
await this.rawSdDataByIDRaw({
|
||||
channel: channel,
|
||||
rawID: rawID,
|
||||
idx: _idx,
|
||||
api: api,
|
||||
})
|
||||
} else {
|
||||
await this.rawDataByIDRaw({
|
||||
channel: channel,
|
||||
rawID: rawID,
|
||||
idx: _idx,
|
||||
api: api,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rowIndex += 1
|
||||
}
|
||||
await this.setAllExport({ last: (rowIndex >= this.downloadInfo.maxRows - 1) })
|
||||
this.$refs.progressModalRef.setValue(100)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 2000)) // sleep
|
||||
window.close()
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.filter-button {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,45 +1,34 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="flex md12 xl12 xs12 sm12" :style="AreaStyle">
|
||||
<file-table :ref="'file_ref'" @download="addDownloadTask"/>
|
||||
</div>
|
||||
<div class="flex md12 xl12 xs12 sm12" :style="AreaStyle">
|
||||
<download :ref="'download_ref'" @download="downloadingFile"></download>
|
||||
</div>
|
||||
</div>
|
||||
<file-table :ref="'file_ref'"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FileTable from './file-table/FileTable.vue'
|
||||
import Download from '../download/Download.vue'
|
||||
// import Download from '../download/Download.vue'
|
||||
import { file } from '../../data/file/File'
|
||||
import api from '../../data/api/index'
|
||||
import { taskInfo } from '@/data/task/TaskInfo'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FileTable,
|
||||
Download,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
controllerList: [],
|
||||
AreaStyle: {
|
||||
height: 'auto',
|
||||
'overflow-y': 'hidden',
|
||||
'overflow-x': 'hidden',
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getControllerList: async function () {
|
||||
const update = async () => {
|
||||
this.controllerList.push({
|
||||
id: 'BPS_FF',
|
||||
id: taskInfo.getTaskInfo().controllerID,
|
||||
mac: '',
|
||||
status: 'loading',
|
||||
isScan: true,
|
||||
devices: [],
|
||||
})
|
||||
}
|
||||
await update()
|
||||
@@ -71,15 +60,15 @@ export default {
|
||||
this.$refs.file_ref.currentPathIndex = file.getPathMaxIndex()
|
||||
file.clearFileList()
|
||||
|
||||
const initCollection = await api.getCollectionsByName('admin')
|
||||
const initCollection = await api.collection.getByName('admin')
|
||||
|
||||
if (initCollection.data !== 0) {
|
||||
file.addPath(initCollection.data[0])
|
||||
this.$refs.file_ref.currentPathIndex = file.getPathMaxIndex()
|
||||
this.$refs.file_ref.currentInfo = initCollection.data[0]
|
||||
|
||||
const folders = await api.getCollectionsByParent('folder', initCollection.data[0].id)
|
||||
const files = await api.getFolderMetaFileByParent('folder', initCollection.data[0].id)
|
||||
const folders = await api.collection.getByParent('folder', initCollection.data[0].id)
|
||||
const files = await api.meta.getByParent('folder', initCollection.data[0].id)
|
||||
file.updateFileList(folders)
|
||||
file.updateFileList(files)
|
||||
|
||||
@@ -91,8 +80,10 @@ export default {
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
await taskInfo.updateTaskInfo()
|
||||
await this.getControllerList()
|
||||
await api.getJwtData()
|
||||
await api.auth.getJwtData()
|
||||
console.log(await api.meta.getByParentWithLimit('folder', 2, 5, 0, 'DESC'))
|
||||
this.pageMqttSub()
|
||||
this.pageInitPub()
|
||||
},
|
||||
@@ -103,5 +94,3 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
</style>
|
||||
|
||||
@@ -45,23 +45,33 @@
|
||||
v-model="showModal.deleteFile"
|
||||
size="small"
|
||||
:title="'DELETE'"
|
||||
:message="`Delete File ${deleteInfo.name}.`"
|
||||
:message="`Delete File ${deleteInfo.name}?`"
|
||||
:okText=" $t('modal.confirm') "
|
||||
@ok="deleteFile()"
|
||||
>
|
||||
</va-modal>
|
||||
|
||||
<va-modal
|
||||
v-model="showModal.deleteMultiFiles"
|
||||
size="small"
|
||||
:title="'DELETE'"
|
||||
:message="'Delete select files?'"
|
||||
:okText=" $t('modal.confirm') "
|
||||
@ok="deleteMultiFiles()"
|
||||
>
|
||||
</va-modal>
|
||||
|
||||
<va-card class="flex sm12 xl12 md12 xs12">
|
||||
<!-- <template slot="header">
|
||||
<template slot="header">
|
||||
<div class="flex sm12 xl12 md12 xs12" style="text-align: end;">
|
||||
<va-button class="" color="success" v-if="selected.length" @click="showrefs" target="_blank" small>
|
||||
<!-- <va-button class="" color="success" v-if="selected.length" @click="downloadSelected" target="_blank" small>
|
||||
DOWNLOAD
|
||||
</va-button>
|
||||
<va-button class="" color="danger" v-if="selected.length" target="_blank" small>
|
||||
</va-button> -->
|
||||
<va-button class="" color="danger" v-if="selected.length" @click="deleteMultiFilesConfirm" target="_blank" small>
|
||||
DELETE
|
||||
</va-button>
|
||||
</div>
|
||||
</template> -->
|
||||
</template>
|
||||
|
||||
<!-- SearchField & perPageSelect-->
|
||||
<div class="row align--center">
|
||||
@@ -137,9 +147,9 @@
|
||||
v-else
|
||||
:ref="'datatable_ref'"
|
||||
>
|
||||
<!-- <template slot="select" slot-scope="props">
|
||||
<template slot="select" slot-scope="props">
|
||||
<va-checkbox :value="props.rowData.checked" @input="select(props.rowData)"/>
|
||||
</template> -->
|
||||
</template>
|
||||
<template slot="name" slot-scope="props">
|
||||
<va-icon
|
||||
:name="(props.rowData.type==='folder')?'fa fa-folder':'fa fa-file'"
|
||||
@@ -163,17 +173,36 @@
|
||||
{{transDeviceInfo(props.rowData.configuration)}}
|
||||
</template>
|
||||
<template slot="actions" slot-scope="props" >
|
||||
<va-popover :message="`download ${props.rowData.name}`" placement="top">
|
||||
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder'" @click.stop="download(props.rowData)"/>
|
||||
<va-popover :message="`sdcard ${props.rowData.name}`" placement="top">
|
||||
<sd-card-button
|
||||
v-if="(props.rowData.type !== 'folder') && (props.rowData.device.library_name.indexOf('Neulive') >= 0) && (props.rowData.sd_data_record === true)"
|
||||
:meta="props.rowData"
|
||||
:uuidList="SDuuidList"
|
||||
:controller="controllerList[0]"
|
||||
@refreshPage="refreshPage"
|
||||
@downloadSdCard="downloadSdCard"
|
||||
/>
|
||||
</va-popover>
|
||||
<va-popover :message="`download ${props.rowData.name} in csv format`" placement="top">
|
||||
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Neulive') >= 0" @click.stop="downloadCsv(props.rowData)"/>
|
||||
</va-popover>
|
||||
<va-popover :message="`download ${props.rowData.name} in excel format`" placement="top">
|
||||
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Elite') >= 0" @click.stop="downloadExcel(props.rowData)"/>
|
||||
</va-popover>
|
||||
<va-popover :message="`download ${props.rowData.name} in csv-edf format`" placement="top">
|
||||
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Neulive') >= 0" @click.stop="downloadExcel(props.rowData)"/>
|
||||
</va-popover>
|
||||
<va-popover :message="`replay ${props.rowData.name}`" placement="top">
|
||||
<va-button flat small color="gray" icon="fa fa-eye" v-if="props.rowData.type !== 'folder'" @click.stop="replay(props.rowData)"/>
|
||||
</va-popover>
|
||||
<va-popover :message="`spike ${props.rowData.name}`" placement="top">
|
||||
<va-button flat small color="gray" icon="fa fa-filter" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Neulive') >= 0" @click.stop="spike(props.rowData)"/>
|
||||
</va-popover>
|
||||
<va-popover :message="`edit ${props.rowData.name}`" placement="top">
|
||||
<va-button flat small color="gray" icon="fa fa-pencil" @click.stop="editFileConfirm(props.rowData)"/>
|
||||
</va-popover>
|
||||
<va-popover :message="`delete ${props.rowData.name}`" placement="top">
|
||||
<va-button flat small color="gray" icon="fa fa-trash" @click.stop="deleteFileConfirm(props.rowData.path, props.rowData.name)"/>
|
||||
<va-button flat small color="gray" icon="fa fa-trash" @click.stop="deleteFileConfirm(props.rowData)"/>
|
||||
</va-popover>
|
||||
</template>
|
||||
</va-data-table>
|
||||
@@ -186,17 +215,19 @@ import { debounce } from 'lodash'
|
||||
import { file } from '../../../data/file/File'
|
||||
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
|
||||
import api from '../../../data/api/index'
|
||||
import SdCardButton from '../sdcard/SdCardButton.vue'
|
||||
|
||||
export default {
|
||||
name: 'FileTable',
|
||||
components: {
|
||||
FulfillingBouncingCircleSpinner,
|
||||
SdCardButton,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
term: null,
|
||||
perPage: '6',
|
||||
perPageOptions: ['4', '6', '10', '20'],
|
||||
perPage: '80',
|
||||
perPageOptions: ['20', '40', '80', '160'],
|
||||
|
||||
fileLists: [],
|
||||
pathLists: [],
|
||||
@@ -208,6 +239,7 @@ export default {
|
||||
showModal: {
|
||||
createFolder: false,
|
||||
deleteFile: false,
|
||||
deleteMultiFiles: false,
|
||||
editFile: false,
|
||||
},
|
||||
|
||||
@@ -230,6 +262,9 @@ export default {
|
||||
deleteInfo: {
|
||||
path: '',
|
||||
name: '',
|
||||
metaID: '',
|
||||
rawChannelAndIDArrays: [], // list of lists
|
||||
miniChannelAndIDArrays: [], // list of lists
|
||||
},
|
||||
|
||||
styleList: {
|
||||
@@ -238,19 +273,22 @@ export default {
|
||||
height: '2rem',
|
||||
},
|
||||
},
|
||||
SDuuidList: [],
|
||||
controllerList: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fields () {
|
||||
return [
|
||||
// {
|
||||
// name: '__slot:select',
|
||||
// },
|
||||
{
|
||||
name: '__slot:select',
|
||||
width: '5%',
|
||||
},
|
||||
{
|
||||
name: '__slot:name',
|
||||
title: 'name',
|
||||
sortField: 'name',
|
||||
width: '20%',
|
||||
width: '15%',
|
||||
titleClass: 'text-center',
|
||||
},
|
||||
// {
|
||||
@@ -292,7 +330,7 @@ export default {
|
||||
{
|
||||
name: '__slot:actions',
|
||||
dataClass: 'text-right',
|
||||
width: '15%',
|
||||
width: '25%',
|
||||
},
|
||||
]
|
||||
},
|
||||
@@ -301,7 +339,9 @@ export default {
|
||||
return this.fileLists
|
||||
}
|
||||
return this.fileLists.filter(item => {
|
||||
return item.name.toLowerCase().includes(this.term.toLowerCase())
|
||||
if (item.name !== null) {
|
||||
return item.name.toLowerCase().includes(this.term.toLowerCase())
|
||||
}
|
||||
})
|
||||
},
|
||||
selected () {
|
||||
@@ -318,7 +358,7 @@ export default {
|
||||
// },
|
||||
select: function (file) {
|
||||
event.stopPropagation()
|
||||
const idx = this.fileLists.findIndex(f => f.name === file.name)
|
||||
const idx = this.fileLists.findIndex(f => f.id === file.id)
|
||||
this.fileLists[idx].checked = !this.fileLists[idx].checked
|
||||
},
|
||||
search: debounce(function (term) {
|
||||
@@ -350,8 +390,8 @@ export default {
|
||||
},
|
||||
|
||||
openFile: async function (info) {
|
||||
this.currentInfo = info
|
||||
if (info.type === 'folder') {
|
||||
this.currentInfo = info
|
||||
this.loadingFiles = true
|
||||
// clear file and add path
|
||||
file.clearFileList()
|
||||
@@ -359,8 +399,8 @@ export default {
|
||||
this.currentPathIndex = file.getPathMaxIndex()
|
||||
|
||||
// call getfolder api and update
|
||||
const folders = await api.getCollectionsByParent('folder', info.id)
|
||||
const files = await api.getFolderMetaFileByParent('folder', info.id)
|
||||
const folders = await api.collection.getByParent('folder', info.id)
|
||||
const files = await api.meta.getByParent('folder', info.id)
|
||||
file.updateFileList(folders)
|
||||
file.updateFileList(files)
|
||||
|
||||
@@ -377,9 +417,10 @@ export default {
|
||||
file.clearFileList()
|
||||
file.slicePathList(index)
|
||||
this.currentPathIndex = file.getPathMaxIndex()
|
||||
this.currentInfo = item
|
||||
// call getfolder api and update
|
||||
const folders = await api.getCollectionsByParent('folder', item.id)
|
||||
const files = await api.getFolderMetaFileByParent('folder', item.id)
|
||||
const folders = await api.collection.getByParent('folder', item.id)
|
||||
const files = await api.meta.getByParent('folder', item.id)
|
||||
file.updateFileList(folders)
|
||||
file.updateFileList(files)
|
||||
|
||||
@@ -395,11 +436,12 @@ export default {
|
||||
this.currentPathIndex = -1
|
||||
|
||||
// call getfolder api and update
|
||||
const initCollection = await api.getCollectionsByName('root')
|
||||
const initCollection = await api.collection.getByParentName('folder', 0, 'root')
|
||||
|
||||
if (initCollection.data !== 0) {
|
||||
const folders = await api.getCollectionsByParent('folder', initCollection.data[0].id)
|
||||
const files = await api.getFolderMetaFileByParent('folder', initCollection.data[0].id)
|
||||
if (initCollection.data.length === 1) {
|
||||
this.currentInfo = initCollection.data[0]
|
||||
const folders = await api.collection.getByParent('folder', initCollection.data[0].id)
|
||||
const files = await api.meta.getByParent('folder', initCollection.data[0].id)
|
||||
file.updateFileList(folders)
|
||||
file.updateFileList(files)
|
||||
this.fileLists = file.getFileList()
|
||||
@@ -417,7 +459,7 @@ export default {
|
||||
this.setInputFieldError(this.createInfo.errorMessagesAll[0] + ' ' + illegalChar[0], this.createInfo)
|
||||
} else {
|
||||
// folder name existed
|
||||
const existedFolder = await api.getCollectionsByName(term)
|
||||
const existedFolder = await api.collection.getByParentName(this.currentInfo.type, this.currentInfo.id, term)
|
||||
if (existedFolder.data.length === 0) {
|
||||
this.setInputFieldSuccess(this.createInfo)
|
||||
} else {
|
||||
@@ -429,17 +471,17 @@ export default {
|
||||
this.setInputFieldError(this.createInfo.errorMessagesAll[1], this.createInfo)
|
||||
}
|
||||
this.createInfo.changedName = term
|
||||
}, 200),
|
||||
}, 250),
|
||||
createFolder: async function () {
|
||||
const parent = [].concat((this.pathLists.length === 0) ? 0 : this.pathLists[this.pathLists.length - 1].id)
|
||||
const parent = [].concat((this.pathLists.length === 0) ? this.currentInfo.id : this.pathLists[this.pathLists.length - 1].id)
|
||||
const type = 'folder'
|
||||
await api.createCollection({
|
||||
await api.collection.create({
|
||||
name: this.createInfo.changedName,
|
||||
parent: { [type]: parent },
|
||||
type: type,
|
||||
size: 0,
|
||||
})
|
||||
this.refreshPage()
|
||||
await this.refreshPage()
|
||||
this.showToast(`Folder ${this.createInfo.changedName} create.`, {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
@@ -458,13 +500,14 @@ export default {
|
||||
editFile: async function () {
|
||||
// TODO editFile
|
||||
if (this.editInfo.type !== 'folder') {
|
||||
await api.updateMetaFile(this.editInfo.info.id, { name: this.editInfo.changedName })
|
||||
await api.meta.update(this.editInfo.info.id, { name: this.editInfo.changedName })
|
||||
} else {
|
||||
}
|
||||
this.editFileDone()
|
||||
await this.editFileDone()
|
||||
},
|
||||
checkFileNameValidate: debounce(function (term) {
|
||||
const illegalChar = term.match(/[^(\w\-)]+/gm)
|
||||
this.editInfo.changedName = term
|
||||
if (term.length === 0) {
|
||||
// input text empty
|
||||
this.editInfo.error = true
|
||||
@@ -478,7 +521,13 @@ export default {
|
||||
this.editInfo.errorMessages.pop()
|
||||
this.editInfo.errorMessages.push(this.editInfo.errorMessagesAll[0] + ' ' + illegalChar[0])
|
||||
} else {
|
||||
const existedFile = this.fileLists.filter(file => file.name.replace('/', '') === term)
|
||||
const existedFile = this.fileLists.filter((file) => {
|
||||
if (file.name != null) {
|
||||
return file.name.replace('/', '') === term
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
if (existedFile.length === 0) {
|
||||
this.editInfo.error = false
|
||||
this.editInfo.success = true
|
||||
@@ -490,10 +539,12 @@ export default {
|
||||
this.editInfo.errorMessages.push(this.editInfo.errorMessagesAll[2])
|
||||
}
|
||||
}
|
||||
this.editInfo.changedName = term
|
||||
}, 200),
|
||||
editFileDone: function () {
|
||||
this.refreshPage()
|
||||
editFileDone: async function () {
|
||||
const tmpCurrentPage = this.$refs.datatable_ref.currentPage
|
||||
await this.refreshPage()
|
||||
this.$refs.datatable_ref.currentPage = tmpCurrentPage
|
||||
this.$refs.datatable_ref.inputPage(tmpCurrentPage)
|
||||
this.showToast(`${this.editInfo.info.name} -> ${this.editInfo.changedName}`, {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
@@ -507,23 +558,51 @@ export default {
|
||||
},
|
||||
removeFileFromList: function () {
|
||||
},
|
||||
deleteFileConfirm: function (path, name) {
|
||||
this.deleteInfo.path = path
|
||||
this.deleteInfo.name = name
|
||||
fillDeleteInfo (info) {
|
||||
this.deleteInfo.path = info.path
|
||||
this.deleteInfo.name = info.name
|
||||
this.deleteInfo.metaID = info.id
|
||||
this.deleteInfo.rawChannelAndIDArrays = [] // list of lists
|
||||
this.deleteInfo.miniChannelAndIDArrays = [] // list of lists
|
||||
for (const [channel, idArray] of Object.entries(info.raw_data)) {
|
||||
this.deleteInfo.rawChannelAndIDArrays.push([channel, idArray[0]])
|
||||
}
|
||||
for (const [channel, scaleObject] of Object.entries(info.mini_data)) {
|
||||
for (const idArray of Object.values(scaleObject)) {
|
||||
this.deleteInfo.miniChannelAndIDArrays.push([channel, idArray[0]])
|
||||
}
|
||||
}
|
||||
},
|
||||
async deleteSingleFileByDeleteInfo () {
|
||||
await api.meta.update(this.deleteInfo.metaID, { deleted: true })
|
||||
await api.meta.clearDel()
|
||||
},
|
||||
deleteFileConfirm: function (info) {
|
||||
this.fillDeleteInfo(info)
|
||||
this.showModal.deleteFile = true
|
||||
},
|
||||
deleteFile: function () {
|
||||
// delete editFile
|
||||
deleteFile: async function () {
|
||||
await this.deleteSingleFileByDeleteInfo()
|
||||
await this.deleteFileDone()
|
||||
},
|
||||
deleteFileDone: function () {
|
||||
deleteFileDone: async function () {
|
||||
const tmpCurrentPage = this.$refs.datatable_ref.currentPage
|
||||
// rebuild table
|
||||
this.fileLists = this.fileLists.filter(file => file.name !== this.deleteInfo.name)
|
||||
|
||||
await this.refreshPage()
|
||||
this.$refs.datatable_ref.currentPage = tmpCurrentPage
|
||||
this.$refs.datatable_ref.inputPage(tmpCurrentPage)
|
||||
// this.loadingFiles = false
|
||||
this.showToast(`deleted ${this.deleteInfo.name}`, {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
},
|
||||
deleteMultiFilesConfirm: function () {
|
||||
this.showModal.deleteMultiFiles = true
|
||||
},
|
||||
deleteMultiFiles: async function () {
|
||||
this.deleteSelected()
|
||||
},
|
||||
inputFieldReset: function (info) {
|
||||
info.name = ''
|
||||
info.changedName = ''
|
||||
@@ -549,8 +628,8 @@ export default {
|
||||
file.clearFileList()
|
||||
|
||||
// call getfolder api and update
|
||||
const folders = await api.getCollectionsByParent('folder', this.currentInfo.id)
|
||||
const files = await api.getFolderMetaFileByParent('folder', this.currentInfo.id)
|
||||
const folders = await api.collection.getByParent('folder', this.currentInfo.id)
|
||||
const files = await api.meta.getByParent('folder', this.currentInfo.id)
|
||||
file.updateFileList(folders)
|
||||
file.updateFileList(files)
|
||||
|
||||
@@ -560,20 +639,98 @@ export default {
|
||||
// this.$refs.datatable_ref.refresh()
|
||||
// this.$refs.datatable_ref.currentPage = 1
|
||||
},
|
||||
showrefs: function () {
|
||||
this.$emit('download', this.selected)
|
||||
// downloadSelected: function () {
|
||||
// for (let i = 0; i < this.selected.length; i++) {
|
||||
// const meta = this.selected[i]
|
||||
// this.downloadCsv(meta)
|
||||
// }
|
||||
// },
|
||||
async deleteSelected () {
|
||||
for (let i = 0; i < this.selected.length; i++) {
|
||||
const meta = this.selected[i]
|
||||
this.fillDeleteInfo(meta)
|
||||
await this.deleteSingleFileByDeleteInfo()
|
||||
this.showToast(`deleted ${this.deleteInfo.name}`, {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
}
|
||||
const tmpCurrentPage = this.$refs.datatable_ref.currentPage
|
||||
await this.refreshPage()
|
||||
this.$refs.datatable_ref.currentPage = tmpCurrentPage
|
||||
this.$refs.datatable_ref.inputPage(tmpCurrentPage)
|
||||
},
|
||||
download: async function (info) {
|
||||
this.$emit('download', info)
|
||||
downloadCsv: async function (meta) {
|
||||
const href = location.href.split('/')[2]
|
||||
const connectCheck = await api.connection.check()
|
||||
if (connectCheck.status === 200) {
|
||||
window.open('http://' + href + '/#/download/online/csv/' + meta.id)
|
||||
} else {
|
||||
window.open('http://' + href + '/#/download/offline/csv/' + meta.id)
|
||||
}
|
||||
},
|
||||
downloadExcel: async function (meta) {
|
||||
const href = location.href.split('/')[2]
|
||||
const connectCheck = await api.connection.check()
|
||||
if (meta.device.library_name.indexOf('Elite') >= 0) {
|
||||
if (connectCheck.status === 200) {
|
||||
window.open('http://' + href + '/#/download/online/excel/' + meta.id)
|
||||
} else {
|
||||
window.open('http://' + href + '/#/download/offline/excel/' + meta.id)
|
||||
}
|
||||
} else if (meta.device.library_name.indexOf('Neulive') >= 0) {
|
||||
if (connectCheck.status === 200) {
|
||||
window.open('http://' + href + '/#/download/online/csv-edf/' + meta.id)
|
||||
} else {
|
||||
window.open('http://' + href + '/#/download/offline/csv-edf/' + meta.id)
|
||||
}
|
||||
}
|
||||
},
|
||||
downloadSdCard: async function (meta) {
|
||||
const href = location.href.split('/')[2]
|
||||
if (meta.device.library_name.indexOf('Neulive') >= 0) {
|
||||
if (window.navigator.onLine) {
|
||||
window.open('http://' + href + '/#/download/online/csv/' + meta.id + '/sd')
|
||||
} else {
|
||||
window.open('http://' + href + '/#/download/offline/csv/' + meta.id + '/sd')
|
||||
}
|
||||
}
|
||||
},
|
||||
async getSDuuidList () {
|
||||
// const uuidList = ['32abdb14-fc0c-11eb-9aa8-dca6326cbc6b', '940ca938-f662-11eb-8a41-dca6326cbc6b']
|
||||
if (this.controllerList.length > 0) {
|
||||
if (this.controllerList[0].sd_uploading === false) {
|
||||
const ret = await api.sdcard.getuuidList()
|
||||
if (ret.status === 200) {
|
||||
this.SDuuidList = ret.data.data
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
replay: function (meta) {
|
||||
console.log(this.$router)
|
||||
this.$router.push({
|
||||
path: '/admin/data-replay/' + meta.id,
|
||||
})
|
||||
if (meta.device.library_name.includes('Neulive') === true) {
|
||||
// window.open('http://' + location.href.split('/')[2].split(':')[0] + '/#/admin/data-replay/' + meta.id)
|
||||
this.$router.push({
|
||||
path: '/admin/data-replay/' + meta.id,
|
||||
})
|
||||
} else if (meta.device.library_name.includes('Elite') === true) {
|
||||
// window.open('http://' + location.href.split('/')[2].split(':')[0] + '/#/admin/data-replay/elite/' + meta.id)
|
||||
this.$router.push({
|
||||
path: '/admin/data-replay/elite/' + meta.id,
|
||||
})
|
||||
}
|
||||
},
|
||||
spike: function (meta) {
|
||||
if (meta.device.library_name.includes('Neulive') === true) {
|
||||
this.$router.push({
|
||||
path: '/admin/data-spike/' + meta.id,
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
async mounted () {
|
||||
const controllerList = await api.controller.getAll()
|
||||
this.controllerList = controllerList.data
|
||||
this.getSDuuidList()
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { apiManager } from './apiManager'
|
||||
|
||||
export default {
|
||||
name: 'SdCardApiAction',
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
metaID: '',
|
||||
mac_address: '',
|
||||
uuid: '',
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
initMetaInfo (meta) {
|
||||
this.metaID = meta.id
|
||||
// bytes array to hex string formamt
|
||||
this.mac_address = meta.device.device_address.map(data =>
|
||||
data.toString(16)
|
||||
.padStart(2, '0')
|
||||
.toUpperCase()).join(':')
|
||||
this.uuid = meta.uuid
|
||||
},
|
||||
// async checkInSD (meta) {
|
||||
// this.initMetaInfo(meta)
|
||||
// this.pageToast('Start checking in SD card...')
|
||||
// apiManager.startProgressBar()
|
||||
// const result = await apiManager.call('Check_in_SD', this.metaID, this.mac_address, this.uuid)
|
||||
// this.checkSDresult = result.data
|
||||
// this.pageToast('In SD card: ' + this.checkSDresult)
|
||||
// apiManager.endProgressBar()
|
||||
// return result.data
|
||||
// },
|
||||
async moveToDB (meta, controller) {
|
||||
this.initMetaInfo(meta)
|
||||
this.pageToast('Start Moving to database...')
|
||||
const result = await apiManager.call('Move_to_DB', controller.id, this.metaID, this.mac_address, this.uuid)
|
||||
return result
|
||||
},
|
||||
async deleteSDCard (meta, controller) {
|
||||
this.initMetaInfo(meta)
|
||||
this.pageToast('Start deleting in SD card...')
|
||||
await apiManager.call('Delete_SD', controller.id, this.metaID, this.mac_address, this.uuid)
|
||||
},
|
||||
pageToast: function (mes) {
|
||||
this.showToast(
|
||||
mes,
|
||||
{
|
||||
icon: 'fa-bell',
|
||||
position: 'bottom-right',
|
||||
duration: 4000,
|
||||
},
|
||||
)
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#nprogress .bar {
|
||||
background: red;
|
||||
}
|
||||
|
||||
#nprogress .spinner-icon {
|
||||
border-top-color: red;
|
||||
border-left-color: red;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- recorded = false, no icon; recorded = true, gray icon; uploaded = true, blue icon; in uuid list: gray icon + red exclam -->
|
||||
<va-button
|
||||
class="va-button--with-left-icon va-button--without-title"
|
||||
v-show="meta.sd_data_record === true"
|
||||
:icon="meta.sd_data_uploaded === true ? 'fa fa-download' : ''"
|
||||
:color="this.$themes.primary"
|
||||
@click.native.stop="performButtonAction()"
|
||||
flat
|
||||
small
|
||||
>
|
||||
<va-icon
|
||||
v-if="meta.sd_data_uploaded === false"
|
||||
class="va-button__content__icon va-button__content__icon-left"
|
||||
name="material-icons"
|
||||
color="grey"
|
||||
@click.native.stop="performButtonAction()"
|
||||
small
|
||||
fixed-width
|
||||
> sd_card
|
||||
</va-icon>
|
||||
</va-button>
|
||||
|
||||
<sd-card-api-action :ref="'sd_card_api'"/>
|
||||
<va-modal
|
||||
class="flex sm12 xl12 md12 xs12"
|
||||
v-model="moveToDBModal"
|
||||
size="small"
|
||||
:title="'UPLOAD SD CARD DATA'"
|
||||
:okText=" $t('modal.confirm') "
|
||||
@ok="moveToDB()"
|
||||
/>
|
||||
<progress-modal
|
||||
title="SD card data uploading"
|
||||
:time="(parseInt(meta.time_duration) / 2e6).toString()"
|
||||
:ref="'progressModalRef'"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SdCardApiAction from './SdCardApiAction.vue'
|
||||
import progressModal from '@/components/common/progressBarModal/progressModal.vue'
|
||||
|
||||
export default {
|
||||
name: 'SdCardButton',
|
||||
components: {
|
||||
SdCardApiAction,
|
||||
progressModal,
|
||||
},
|
||||
props: {
|
||||
controller: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
uuidList: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
meta: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isSdCardDataLoaded: false,
|
||||
moveToDBModal: false,
|
||||
checkSDresult: '',
|
||||
metaID: '',
|
||||
mac_address: '',
|
||||
uuid: '',
|
||||
icon: 'fa fa-usb',
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
this.metaID = this.meta.id
|
||||
this.mac_address = this.meta.device.device_address.map(data =>
|
||||
data.toString(16)
|
||||
.padStart(2, '0')
|
||||
.toUpperCase()).join(':')
|
||||
this.uuid = this.meta.uuid
|
||||
},
|
||||
async performButtonAction () {
|
||||
const recorded = this.meta.sd_data_record // true or false
|
||||
const uploaded = this.meta.sd_data_uploaded // true or false
|
||||
if (recorded === true) {
|
||||
if (uploaded !== true) {
|
||||
if (this.uuidList.includes(this.uuid)) {
|
||||
this.moveToDBModal = true
|
||||
} else {
|
||||
this.pageToast('Can not access data. Please connect your device to hub by usb.')
|
||||
}
|
||||
} else {
|
||||
this.executeDownload()
|
||||
}
|
||||
}
|
||||
},
|
||||
async moveToDB () {
|
||||
await this.executeUpload()
|
||||
this.$emit('refreshPage')
|
||||
},
|
||||
// async executeCheckInSD () {
|
||||
// return await this.$refs.sd_card_api.checkInSD(this.meta)
|
||||
// },
|
||||
async executeUpload () {
|
||||
this.$refs.progressModalRef.show()
|
||||
const result = await this.$refs.sd_card_api.moveToDB(this.meta, this.controller).catch(_ => {
|
||||
this.$refs.progressModalRef.hide()
|
||||
this.pageToast('Upload SD card data error, please connect Neullive to Hub by usb or data corrupted.')
|
||||
})
|
||||
if (result.data === true) {
|
||||
this.pageToast('Upload SD card data done.')
|
||||
} else {
|
||||
this.pageToast('Upload SD card data error, please connect Neullive to Hub by usb or data corrupted.')
|
||||
}
|
||||
this.$refs.progressModalRef.progressDone()
|
||||
// remove delete sd card first, still have problem.
|
||||
// await this.$refs.sd_card_api.deleteSDCard(this.meta, this.controller)
|
||||
},
|
||||
executeDownload () {
|
||||
this.$emit('downloadSdCard', this.meta)
|
||||
},
|
||||
pageToast: function (mes) {
|
||||
this.showToast(
|
||||
mes,
|
||||
{
|
||||
icon: 'fa-bell',
|
||||
position: 'bottom-right',
|
||||
duration: 7000,
|
||||
},
|
||||
)
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
this.init()
|
||||
},
|
||||
watch: { // cuz data table will not call mounted
|
||||
meta: function (val) {
|
||||
this.init()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,35 @@
|
||||
import api from '@/data/api/index'
|
||||
import nProgress from 'nprogress'
|
||||
|
||||
export const apiManager = {
|
||||
call: async (instruction, controllerID, metaID, macAddress, uuid) => {
|
||||
if (instruction === 'Check_in_SD') {
|
||||
return await api.sdcard.exist({
|
||||
controllerID: controllerID,
|
||||
metaID: metaID,
|
||||
mac: macAddress,
|
||||
uuid: uuid,
|
||||
})
|
||||
} else if (instruction === 'Delete_SD') {
|
||||
return await api.sdcard.deleted({
|
||||
controllerID: controllerID,
|
||||
metaID: metaID,
|
||||
mac: macAddress,
|
||||
uuid: uuid,
|
||||
})
|
||||
} else if (instruction === 'Move_to_DB') {
|
||||
return await api.sdcard.upload({
|
||||
controllerID: controllerID,
|
||||
metaID: metaID,
|
||||
mac: macAddress,
|
||||
uuid: uuid,
|
||||
})
|
||||
}
|
||||
},
|
||||
startProgressBar: () => {
|
||||
nProgress.start()
|
||||
},
|
||||
endProgressBar: () => {
|
||||
nProgress.done()
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div class="controller-info">
|
||||
<div class="row flex">
|
||||
<div
|
||||
class="flex sm12 xl12 md12 xs12 ma-2"
|
||||
v-for="controller in controllers" :key="controller.mac_address"
|
||||
>
|
||||
<va-card
|
||||
style="border: 5px solid #78ceff; border-radius: 30px; font-size: 1.5rem;"
|
||||
>
|
||||
<!-- {{ controller }} -->
|
||||
<va-item :key="controller.device_mac" class="pa-0 ma-0"
|
||||
>
|
||||
<va-item-section avatar class="ml-4 mr-4">
|
||||
<img
|
||||
:src="getImageUrl()"
|
||||
:alt="'BPS-CONTROLLER'"
|
||||
width="200px"
|
||||
height="200px"
|
||||
contain
|
||||
/>
|
||||
</va-item-section>
|
||||
<va-item-section class="ml-5 mr-4" >
|
||||
<va-item-label style="font-size: 2rem;">
|
||||
{{ controller.wifi_name }}
|
||||
</va-item-label>
|
||||
<va-item-label>
|
||||
Mac Address :
|
||||
{{ controller.mac_address.toUpperCase() }}
|
||||
</va-item-label>
|
||||
<va-item-label>
|
||||
Build Version : #
|
||||
{{ controller.software_version }}
|
||||
</va-item-label>
|
||||
<va-item-label>
|
||||
Update Time :
|
||||
{{ GLOBAL.dateToStr(controller.updated_at) }}
|
||||
</va-item-label>
|
||||
</va-item-section>
|
||||
</va-item>
|
||||
</va-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapActions, mapGetters, mapMutations } from 'vuex'
|
||||
import api from '@/data/api/index'
|
||||
import types from '@/store/modules/setting/types'
|
||||
import controllerImgUrl from '@/assets/img/controller.png'
|
||||
|
||||
export default {
|
||||
name: 'controller-info',
|
||||
components: {
|
||||
},
|
||||
// props: {
|
||||
// data: {
|
||||
// type: Object,
|
||||
// default: function () {
|
||||
// return {}
|
||||
// },
|
||||
// },
|
||||
// cardclass: {
|
||||
// type: Array,
|
||||
// default: function () {
|
||||
// return ['xs12', 'md12', 'xl12', 'sm12']
|
||||
// },
|
||||
// },
|
||||
// cardheight: {
|
||||
// type: String,
|
||||
// default: '82vh',
|
||||
// },
|
||||
// cardwidth: {
|
||||
// type: String,
|
||||
// default: 'auto',
|
||||
// },
|
||||
// },
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
controllers () {
|
||||
return this.getAllController()
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
getImageUrl () {
|
||||
return controllerImgUrl
|
||||
},
|
||||
...mapActions('setting', [types.controller.init]),
|
||||
...mapMutations('setting', [types.controller.set, types.controller.updateByIndex]),
|
||||
...mapGetters('setting', [types.controller.getAll]),
|
||||
},
|
||||
async mounted () {
|
||||
this.initController({ api: api })
|
||||
console.log(this.getAllController())
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.area-style-setting-controller {
|
||||
height: auto;
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
|
||||
@include media-breakpoint-only(xl) {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.drag-flex {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.font-small {
|
||||
color: rgb(113, 186, 255);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.center-medium {
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.center-large {
|
||||
text-align: center;
|
||||
font-size: 28px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<div class="device-info">
|
||||
<div class="row flex">
|
||||
<div class="flex-wrap-setting sm12 xl12 md12 xs12">
|
||||
<!-- <draggable class="flex d-flex sm12 xl12 md12 xs12" v-model="devicesList" @start="drag=true" @end="drag=false" > -->
|
||||
<div
|
||||
class="flex d-flex sm12 xl3 md6 xs12 ma-0"
|
||||
v-for="(device, index) in devicesList" :key="device.id"
|
||||
>
|
||||
<va-card
|
||||
:noPadding="true"
|
||||
style="border: 5px solid #78ceff; border-radius: 30px;"
|
||||
>
|
||||
<div class="center-large" >
|
||||
<div class="flex d-flex sm12 xl12 md12 xs12 ">
|
||||
<div class="sm11 xl11 md11 xs11 ml-2" style="text-align: start;">
|
||||
{{ device.name }}
|
||||
</div>
|
||||
<div class="sm1 xl1 md1 xs1" style="text-align: right;">
|
||||
<va-icon
|
||||
name="ion ion-md-close"
|
||||
class="mr-1"
|
||||
color="#babfc2"
|
||||
style="cursor: pointer;"
|
||||
@click.native.stop="remove(index, device)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center-medium">
|
||||
<p> {{ device.name }} </p>
|
||||
</div>
|
||||
<div class="center-medium">
|
||||
<p> {{ device.mac_address }} </p>
|
||||
</div>
|
||||
<div class="mt-4 mb-4" style="text-align: center;">
|
||||
<img
|
||||
:src="getImageUrl(device.library)"
|
||||
:alt="device.name"
|
||||
width="150px"
|
||||
height="100px"
|
||||
contain
|
||||
/>
|
||||
</div>
|
||||
<div class="center-medium">
|
||||
<p> {{ device.device_version }} </p>
|
||||
<p> {{ timeStampToLocaleTime(device.updated_at) }} </p>
|
||||
</div>
|
||||
<div class="flex sm12 xl12 md12 xs12" style="text-align: center;">
|
||||
<va-button v-if="device.auto_connect" color="success" @click="autoConnect(index, device)">Auto Connect</va-button>
|
||||
<va-button v-if="!device.auto_connect" color="#babfc2" @click="autoConnect(index, device)" outline>Auto Connect</va-button>
|
||||
<va-button @click="openGuide(device.library)">User Guide</va-button>
|
||||
</div>
|
||||
</va-card>
|
||||
</div>
|
||||
</div>
|
||||
<!-- </draggable> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapActions, mapGetters, mapMutations } from 'vuex'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import api from '@/data/api/index'
|
||||
import types from '@/store/modules/setting/types'
|
||||
import neuliveImgUrl from '@/assets/img/neulive_img.png'
|
||||
import eliteImgUrl from '@/assets/img/elite_img_v2.png'
|
||||
// import draggable from 'vuedraggable'
|
||||
|
||||
export default {
|
||||
name: 'device-info',
|
||||
components: {
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('setting', [
|
||||
'devicesList',
|
||||
]),
|
||||
devices: {
|
||||
get () {
|
||||
return this.getAllDevice()
|
||||
},
|
||||
set (deviceList) {
|
||||
this.reorderDevice({ deviceList: deviceList, api: api })
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
macArrayToString: function (macAddress) {
|
||||
return this.GLOBAL.transMac(JSON.parse(macAddress))
|
||||
},
|
||||
timeStampToLocaleTime: function (time) {
|
||||
return this.GLOBAL.dateToStr(time)
|
||||
},
|
||||
getImageUrl: function (libraryName) {
|
||||
if (libraryName !== null) {
|
||||
if (libraryName.indexOf('Neulive') >= 0) {
|
||||
return neuliveImgUrl
|
||||
} else if (libraryName.indexOf('Elite') >= 0) {
|
||||
return eliteImgUrl
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
autoConnect: async function (index, device) {
|
||||
device.auto_connect = !device.auto_connect
|
||||
await api.device.update(device.id, { auto_connect: device.auto_connect })
|
||||
},
|
||||
remove (index, device) {
|
||||
console.log('removeDevcie', index, device)
|
||||
this.removeDevice({ id: device.id, index: index, api: api })
|
||||
},
|
||||
openGuide: async function (library) {
|
||||
if (library.indexOf('3.1') !== -1) {
|
||||
window.open('http://' + location.href.split('/')[2] + '/NeuLive31_quickstart_patents.pdf')
|
||||
}
|
||||
},
|
||||
...mapActions('setting', [types.device.init, types.device.remove, types.device.reorder]),
|
||||
...mapMutations('setting', [types.device.set, types.device.updateByIndex]),
|
||||
...mapGetters('setting', [types.device.getAll]),
|
||||
},
|
||||
async mounted () {
|
||||
const devices = await api.device.getAll()
|
||||
if (devices.status === 200) {
|
||||
this.devicesList = devices.data
|
||||
}
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.area-style-setting-device {
|
||||
height: auto;
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
|
||||
@include media-breakpoint-only(xl) {
|
||||
height: auto;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.drag-flex {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.font-small {
|
||||
color: rgb(113, 186, 255);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.center-medium {
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.center-large {
|
||||
text-align: center;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.flex-wrap-setting {
|
||||
display: flex;
|
||||
flex-direction: horizontal;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="about">
|
||||
<div class="row">
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<controller-info/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<device-info/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import DeviceInfo from './deviceInfo.vue'
|
||||
import ControllerInfo from './controllerInfo.vue'
|
||||
|
||||
export default {
|
||||
name: 'about-content',
|
||||
components: {
|
||||
ControllerInfo,
|
||||
DeviceInfo,
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
async mounted () {
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -21,42 +21,43 @@
|
||||
/>
|
||||
|
||||
<div class="row row-equal">
|
||||
<div v-if="showDeviceSetting" class="flex md12 xl4 xs12 sm12 area-style">
|
||||
<div v-if="showDeviceSetting" class="flex md12 xl4 xs12 sm12">
|
||||
<div class="row">
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<task-devices :ref="'devices_ref'" @add="addDevice($event)" @remove="removeDevice($event)" @refreshSetting="refreshChartSetting($event)" class="pa-0" />
|
||||
</div>
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<!-- <div class="flex sm12 xl12 md12 xs12">
|
||||
<task-formula :ref="'formula_ref'" @add="addFormula($event)" @remove="removeFormula($event)" class="pa-0" />
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div :class="chartAreaClass" class="area-style">
|
||||
<div :class="chartAreaClass">
|
||||
<div class="row" >
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<div class="flex sm12 xl12 md12 xs12" style="text-align: center;">
|
||||
<va-card
|
||||
class="ma-0 pa-0"
|
||||
stripe="primary"
|
||||
>
|
||||
<template slot="header">
|
||||
<!-- <template slot="header">
|
||||
<va-icon name="fa fa-gears mr-3" color="primary"/>
|
||||
<h5 class="mt-0 mb-0">CONTROL</h5>
|
||||
</template>
|
||||
<va-button class="" v-if="!showDeviceSetting" color="primary" target="_blank" @click="showDeviceSettingClick()" small>
|
||||
</template> -->
|
||||
<va-button class="no-dark-style-va-button" v-if="!showDeviceSetting" color="primary" target="_blank" @click="showDeviceSettingClick()" small>
|
||||
SHOW DEVICES
|
||||
</va-button>
|
||||
<va-button class="" v-if="showDeviceSetting" color="primary" target="_blank" @click="hideDeviceSettingClick()" small>
|
||||
<va-button class="no-dark-style-va-button" v-if="showDeviceSetting" color="primary" target="_blank" @click="hideDeviceSettingClick()" small>
|
||||
HIDE DEVICES
|
||||
</va-button>
|
||||
<va-button class="" color="success" target="_blank" @click="startAllClick()" small>
|
||||
START ALL
|
||||
</va-button>
|
||||
<va-button class="" color="danger" target="_blank" @click="stopAllClick()" small>
|
||||
<va-button class="no-dark-style-va-button" color="danger" target="_blank" @click="stopAllClick()" small>
|
||||
STOP ALL
|
||||
</va-button>
|
||||
<va-button class="" color="primary" target="_blank" @click.stop="addChart()" small>
|
||||
<va-button class="no-dark-style-va-button" color="primary" target="_blank" @click.stop="addChart()" small>
|
||||
ADD CHART
|
||||
</va-button>
|
||||
</va-card>
|
||||
@@ -77,6 +78,15 @@
|
||||
@remove="removeChartCheck(chart.chartID)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-for="trigger in triggerList"
|
||||
:key="trigger.id"
|
||||
>
|
||||
<trigger-chart
|
||||
v-show="trigger.display === true"
|
||||
:mac="trigger.mac"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height: 150px;">
|
||||
@@ -99,7 +109,12 @@ import { chartData } from '../../../data/task/ChartsManagement'
|
||||
import { taskInfo } from '../../../data/task/TaskInfo'
|
||||
import CanvasChart from './chart/CanvasChart'
|
||||
import TaskDevices from './controller/TaskDevices'
|
||||
import TaskFormula from './formula/TaskFormula'
|
||||
import TriggerChart from './chart/TriggerChart'
|
||||
// import api from '@/data/api'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import { mapActions } from 'vuex'
|
||||
import deviceTypes from '@/store/modules/device/types'
|
||||
// import TaskFormula from './formula/TaskFormula'
|
||||
|
||||
// TODO change chart data tag format
|
||||
|
||||
@@ -108,10 +123,17 @@ export default {
|
||||
components: {
|
||||
CanvasChart,
|
||||
TaskDevices,
|
||||
TaskFormula,
|
||||
TriggerChart,
|
||||
// TaskFormula,
|
||||
},
|
||||
async created () {
|
||||
await taskInfo.updateTaskInfo(this.$route.params.taskID)
|
||||
computed: {
|
||||
...mapFields('taskContent', [
|
||||
'deviceList',
|
||||
]),
|
||||
...mapFields('device', [
|
||||
'triggerList',
|
||||
'chartKey',
|
||||
]),
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -122,29 +144,75 @@ export default {
|
||||
dataRefreshTimer: null,
|
||||
// charts data
|
||||
chartDataAll: chartData.getAllChartsData(),
|
||||
// chart refresh key
|
||||
chartKey: 0,
|
||||
chartNumber: taskInfo.getTaskInfo().chartList.length,
|
||||
selectChartID: null,
|
||||
showDeviceSetting: true,
|
||||
chartAreaClass: ['flex', 'xs12', 'sm12', 'md12', 'xl8', 'pa-0'],
|
||||
getParmDone: false,
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
async '+/get_device_info_all/+' (data, topic) {
|
||||
await taskInfo.deviceInfo(String.fromCharCode.apply(null, data))
|
||||
await taskInfo.deviceInfo(String.fromCharCode.apply(null, data), this.deviceList)
|
||||
this.refreshDevicesWindow()
|
||||
},
|
||||
async '+/get_device_info/+' (data, topic) {
|
||||
await taskInfo.deviceInfo(String.fromCharCode.apply(null, data))
|
||||
await taskInfo.deviceInfo(String.fromCharCode.apply(null, data), this.deviceList)
|
||||
this.refreshDevicesWindow()
|
||||
this.getParmDone = true
|
||||
this.checkStiStatus()
|
||||
},
|
||||
async '+/device_parameter/+' (data, topic) {
|
||||
await taskInfo.deviceParameter(String.fromCharCode.apply(null, data))
|
||||
this.refreshDevicesWindow()
|
||||
},
|
||||
async '+/device_parameter_value/+' (data, topic) {
|
||||
await taskInfo.deviceParameter(String.fromCharCode.apply(null, data))
|
||||
this.refreshDevicesWindow()
|
||||
},
|
||||
async '+/hardware_device/+' (data, topic) {
|
||||
await taskInfo.deviceInfo(String.fromCharCode.apply(null, data))
|
||||
await taskInfo.deviceInfo(String.fromCharCode.apply(null, data), this.deviceList)
|
||||
// console.log(this.deviceList)
|
||||
// for (const d1 in taskInfo.getTaskInfo().deviceList) {
|
||||
// if (taskInfo.getTaskInfo().deviceList[d1].info.device_address.length > 0) {
|
||||
// const addr1 = taskInfo.getTaskInfo().deviceList[d1].info.device_address.join()
|
||||
// let parameter, content
|
||||
// for (const d2 in this.deviceList) {
|
||||
// const addr2 = this.deviceList[d2].info.device_address.join()
|
||||
// if (addr1 === addr2) {
|
||||
// // console.log(this.deviceList[d2].parameterSet)
|
||||
// for (const p in this.deviceList[d2].parameterSet) {
|
||||
// if (p !== 'STIMULATING') {
|
||||
// if (parameter == null) {
|
||||
// parameter = p
|
||||
// } else {
|
||||
// parameter = parameter + '|' + p
|
||||
// }
|
||||
// let c
|
||||
// if (Array.isArray(this.deviceList[d2].parameterSet[p])) {
|
||||
// c = '0:' + this.deviceList[d2].parameterSet[p].length + '=' + this.deviceList[d2].parameterSet[p]
|
||||
// } else {
|
||||
// c = this.deviceList[d2].parameterSet[p]
|
||||
// }
|
||||
|
||||
// if (content == null) {
|
||||
// content = c
|
||||
// } else {
|
||||
// content = content + '|' + c
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // console.log('****', parameter, content)
|
||||
// // this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
// // header: 'device_parameter/0',
|
||||
// // device: parseInt(d1),
|
||||
// // parameter: parameter,
|
||||
// // content: content,
|
||||
// // }))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if (this.$refs.devices_ref != null) {
|
||||
await this.$refs.devices_ref.loadingDone()
|
||||
}
|
||||
@@ -152,20 +220,74 @@ export default {
|
||||
// listen datastream [ topic: controllerID/data_server/device_data_stream/deviceID/channel ]
|
||||
async '+/data_server/device_data_stream/+/+' (data, topic) {
|
||||
const topicSplit = topic.split('/')
|
||||
if (!taskInfo.getDeviceInfoByRawID(parseInt(topicSplit[3])).info.isSync) {
|
||||
taskInfo.deviceStart(parseInt(topicSplit[3]))
|
||||
this.$refs.devices_ref.setArchiveSettings()
|
||||
chartData.defaultChartGenerator(taskInfo.getDeviceIDByRaw(parseInt(topicSplit[3])), null, 'device')
|
||||
if (this.getParmDone & !taskInfo.getDeviceInfoByRawID(parseInt(topicSplit[3])).info.isSync) {
|
||||
if (chartData.defaultChartGenerator(this.deviceList, taskInfo.getDeviceIDByRaw(parseInt(topicSplit[3])), null, 'device')) {
|
||||
taskInfo.deviceStart(parseInt(topicSplit[3]), this.deviceList)
|
||||
}
|
||||
}
|
||||
dataStreamBuffer.into(String.fromCharCode.apply(null, data), parseInt(topicSplit[3]), (parseInt(topicSplit[4]) + 1))
|
||||
},
|
||||
'+/device_save_path/+' (data, topic) {
|
||||
taskInfo.deviceSavePath(String.fromCharCode.apply(null, data))
|
||||
console.log(taskInfo.getTaskInfo())
|
||||
// console.log(taskInfo.getTaskInfo())
|
||||
},
|
||||
'+/device_save_path_set/+' (data, topic) {
|
||||
taskInfo.deviceSavePath(String.fromCharCode.apply(null, data))
|
||||
console.log(taskInfo.getTaskInfo())
|
||||
// console.log(taskInfo.getTaskInfo())
|
||||
},
|
||||
async '+/device_sd_card_status/+' (data, topic) {
|
||||
const dataDecode = JSON.parse(String.fromCharCode.apply(null, data))
|
||||
for (const device of this.$refs.devices_ref.deviceList) {
|
||||
if (dataDecode.device === taskInfo.getRawDeviceID(device.id)) {
|
||||
device.sdCardStatus = dataDecode.data
|
||||
}
|
||||
}
|
||||
await taskInfo.updateSdCardStatus(String.fromCharCode.apply(null, data))
|
||||
this.refreshDevicesWindow()
|
||||
},
|
||||
'+/data-server/trigger_manager/#' (data, topic) {
|
||||
let foundIndex
|
||||
let mesJson
|
||||
const mes = new TextDecoder('utf-8').decode(data)
|
||||
const topicSplit = topic.split('/')
|
||||
const baseIndex = topicSplit.indexOf('trigger_manager')
|
||||
const actionIndex = baseIndex + 1
|
||||
const action = topicSplit[actionIndex]
|
||||
const macIndex = baseIndex + 2
|
||||
let _mac
|
||||
if (topicSplit.length - 1 >= macIndex) {
|
||||
_mac = topicSplit[macIndex]
|
||||
foundIndex = this.triggerList.findIndex(o => o.mac === _mac)
|
||||
}
|
||||
switch (action) {
|
||||
case 'info_all': // control_ID/data-server/trigger_manager/info_all
|
||||
this.triggerList = JSON.parse(mes)
|
||||
this.deviceTriggerChartSetDisplay()
|
||||
break
|
||||
case 'register': // control_ID/data-server/trigger_manager/register
|
||||
mesJson = JSON.parse(mes)
|
||||
foundIndex = this.triggerList.findIndex(o => o.mac === mesJson.mac)
|
||||
if (foundIndex < 0) { // -1: not found
|
||||
this.triggerList.push(mesJson)
|
||||
} else {
|
||||
this.triggerList[foundIndex] = mesJson
|
||||
}
|
||||
break
|
||||
case 'remove': // control_ID/data-server/trigger_manager/remove/device_mac
|
||||
this.triggerList.splice(foundIndex, 1)
|
||||
break
|
||||
case 'info': // control_ID/data-server/trigger_manager/info/device_mac
|
||||
this.triggerList[foundIndex] = JSON.parse(mes)
|
||||
this.deviceTriggerChartSetDisplay()
|
||||
break
|
||||
case 'set_parameter': // control_ID/data-server/trigger_manager/set_parameter/device_mac
|
||||
this.triggerList[foundIndex].parameter = JSON.parse(mes)
|
||||
break
|
||||
case 'runtime': // control_ID/data-server/trigger_manager/runtime/device_mac
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
},
|
||||
async '+/broadcast' (data, topic) {
|
||||
const mes = String.fromCharCode.apply(null, data).split(':')
|
||||
@@ -182,6 +304,10 @@ export default {
|
||||
break
|
||||
case 'disconnected':
|
||||
taskInfo.deviceDisconnected(mes[1])
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'get_device_info/0',
|
||||
device: parseInt(mes[1]),
|
||||
}))
|
||||
break
|
||||
case 'connected':
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
@@ -191,28 +317,38 @@ export default {
|
||||
taskInfo.deviceConnected(mes[1])
|
||||
break
|
||||
case 'shutdown':
|
||||
taskInfo.controllerShutdown()
|
||||
taskInfo.controllerShutdown(this.deviceList)
|
||||
this.showShutdownModal = true
|
||||
break
|
||||
case 'start':
|
||||
taskInfo.deviceStart(parseInt(mes[1]))
|
||||
if (!taskInfo.getDeviceInfoByRawID(parseInt(parseInt(mes[1]))).info.isSync) {
|
||||
taskInfo.deviceStart(parseInt(mes[1]), this.deviceList)
|
||||
if (chartData.defaultChartGenerator(this.deviceList, taskInfo.getDeviceIDByRaw(parseInt(parseInt(mes[1]))), null, 'device')) {
|
||||
taskInfo.deviceStart(parseInt(parseInt(mes[1])), this.deviceList)
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'stop':
|
||||
if (mes[1] === 'all') {
|
||||
return false
|
||||
}
|
||||
taskInfo.deviceStop(parseInt(mes[1]))
|
||||
taskInfo.deviceStop(parseInt(mes[1]), this.deviceList)
|
||||
break
|
||||
case 'device_timeout':
|
||||
this.pageToast('The device [' + taskInfo.getDeviceIDByRaw(parseInt(mes[1])) + '] is timeout, please check its status or parameters.')
|
||||
break
|
||||
case 'device_mission_done':
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: parseInt(mes[1]),
|
||||
instruction: 'interrupt',
|
||||
}))
|
||||
this.pageToast('The device [' + taskInfo.getDeviceIDByRaw(parseInt(mes[1])) + '] mission is done.')
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
console.log(String.fromCharCode.apply(null, data), topic)
|
||||
// console.log(String.fromCharCode.apply(null, data), topic)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -231,6 +367,9 @@ export default {
|
||||
this.mqttSub(id + '/get_device_info_all/+')
|
||||
this.mqttSub(id + '/get_device_info/+')
|
||||
this.mqttSub(id + '/device_parameter/+')
|
||||
this.mqttSub(id + '/device_parameter_value/+')
|
||||
this.mqttSub(id + '/device_sd_card_status/+')
|
||||
this.mqttSub(id + '/data-server/trigger_manager/#')
|
||||
},
|
||||
pageMqttUnSub: function (id) {
|
||||
for (const device in taskInfo.getTaskInfo().deviceList) {
|
||||
@@ -241,15 +380,29 @@ export default {
|
||||
this.mqttUnSub(id + '/get_device_info_all/+')
|
||||
this.mqttUnSub(id + '/get_device_info/+')
|
||||
this.mqttUnSub(id + '/device_parameter/+')
|
||||
this.mqttUnSub(id + '/device_parameter_value/+')
|
||||
this.mqttUnSub(id + '/device_sd_card_status/+')
|
||||
this.mqttUnSub(id + '/data-server/trigger_manager/#')
|
||||
},
|
||||
pageInit: async function () {
|
||||
if (await this.$refs.devices_ref != null) {
|
||||
await this.$refs.devices_ref.loadingStart()
|
||||
}
|
||||
// let _parameter, _content
|
||||
|
||||
// this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
// header: 'device_parameter/0',
|
||||
// device: 7,
|
||||
// parameter: 'RECORDING_CH|AXIS_CH',
|
||||
// content: '7|1',
|
||||
// }))
|
||||
console.log(taskInfo.getTaskInfo().controllerID)
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'hardware_device/0',
|
||||
}))
|
||||
await taskInfo.updateChartInfo()
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '/client/trigger_manager/scan', '{}')
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '/client/trigger_manager/info_all', '{}')
|
||||
this.chartNumber = taskInfo.getTaskInfo().chartNumber
|
||||
},
|
||||
pageToast: function (mes) {
|
||||
@@ -269,9 +422,13 @@ export default {
|
||||
}
|
||||
},
|
||||
refreshDevicesWindow: function () {
|
||||
// console.log(taskInfo.getTaskInfo())
|
||||
if (this.$refs.devices_ref != null) {
|
||||
this.$refs.devices_ref.refresh()
|
||||
}
|
||||
// api.task.update({
|
||||
// device_config: taskInfo.getTaskInfo().deviceList,
|
||||
// })
|
||||
},
|
||||
addChart: async function () {
|
||||
const defaultID = {}
|
||||
@@ -367,8 +524,13 @@ export default {
|
||||
this.chartAreaClass[3] = 'md12'
|
||||
this.chartAreaClass[4] = 'xl12'
|
||||
},
|
||||
addDevice: async function (deviceID) {
|
||||
this.mqttSub(taskInfo.getTaskInfo().controllerID + '/data_server/device_data_stream/' + taskInfo.getRawDeviceID(deviceID) + '/+')
|
||||
addMappingChart: async function (deviceID) {
|
||||
// if have chart with device ID
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
if (chartData.getAllChartsData()[chart].mappingID === deviceID) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
const chart = await this.addChart()
|
||||
await this.$nextTick(async () => {
|
||||
chartData.getAllChartsData()[chart].mappingID = deviceID
|
||||
@@ -378,9 +540,19 @@ export default {
|
||||
})
|
||||
}
|
||||
})
|
||||
if (taskInfo.getDeviceInfo(deviceID).info.isSync) {
|
||||
chartData.defaultChartGenerator(deviceID, chart, 'device')
|
||||
}
|
||||
return chart
|
||||
},
|
||||
addDevice: async function (deviceID) {
|
||||
this.mqttSub(taskInfo.getTaskInfo().controllerID + '/data_server/device_data_stream/' + taskInfo.getRawDeviceID(deviceID) + '/+')
|
||||
this.addMappingChart(deviceID)
|
||||
// if (taskInfo.getDeviceInfo(deviceID).info.isSync) {
|
||||
// chartData.defaultChartGenerator(deviceID, chart, 'device')
|
||||
// }
|
||||
// console.log(chartData.getAllChartsData())
|
||||
// console.log(taskInfo.getTaskInfo())
|
||||
// await api.task.update({
|
||||
// device_config: taskInfo.getTaskInfo().deviceList,
|
||||
// })
|
||||
this.pageToast('The device [' + deviceID + '] has been registered.')
|
||||
},
|
||||
removeDevice: function (deviceID) {
|
||||
@@ -414,53 +586,93 @@ export default {
|
||||
}
|
||||
this.pageToast('The formula [' + formulaID + '] has been removed.')
|
||||
},
|
||||
startAllClick: function () {
|
||||
taskInfo.getDeviceListRegister().forEach(device => {
|
||||
chartData.defaultChartGenerator(device.id, null, 'device')
|
||||
if (!taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
startAllClick: async function () {
|
||||
for (const device of this.deviceList) {
|
||||
if (this.$refs.devices_ref === undefined) {
|
||||
this.startDevice(device)
|
||||
} else {
|
||||
await this.$refs.devices_ref.$refs.pdlist_ref.start(device)
|
||||
}
|
||||
}
|
||||
this.refreshDevicesWindow()
|
||||
this.pageToast('The all devices have been started')
|
||||
},
|
||||
startDevice: async function (device) {
|
||||
chartData.defaultChartGenerator(this.deviceList, device.id, null, 'device')
|
||||
if (!taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Neulive')) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'record',
|
||||
}))
|
||||
} else if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Elite')) {
|
||||
// console.log('elite')
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'start',
|
||||
}))
|
||||
device.isSync = true
|
||||
}
|
||||
})
|
||||
this.pageToast('The all devices have been started')
|
||||
device.stopping = false
|
||||
device.isSync = true
|
||||
// this.$emit('refreshSetting')
|
||||
// ### show device info
|
||||
// console.log(taskInfo.getDeviceInfo(device.id))
|
||||
}
|
||||
},
|
||||
stopAllClick: function () {
|
||||
dataStreamBuffer.removeAll()
|
||||
taskInfo.getDeviceListRegister().forEach(device => {
|
||||
if (taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
for (const device of this.deviceList) {
|
||||
if (this.$refs.devices_ref === undefined) {
|
||||
this.stopDevice(device)
|
||||
} else {
|
||||
this.$refs.devices_ref.stopDevice(device)
|
||||
}
|
||||
}
|
||||
this.pageToast('The all devices have been stopped')
|
||||
},
|
||||
stopDevice: async function (device) {
|
||||
dataStreamBuffer.removeByDevice(taskInfo.getRawDeviceID(device.id))
|
||||
if (taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Neulive')) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'stop_record',
|
||||
}))
|
||||
} else if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Elite')) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'interrupt',
|
||||
}))
|
||||
}
|
||||
// device.isSync = false
|
||||
})
|
||||
this.pageToast('The all devices have been stopped')
|
||||
device.stopping = true
|
||||
}
|
||||
},
|
||||
checkStiStatus: function () {
|
||||
this.$refs.devices_ref.checkStiStatus()
|
||||
},
|
||||
exit: function () {
|
||||
this.$router.push({
|
||||
path: '/',
|
||||
})
|
||||
},
|
||||
|
||||
...mapActions('device', [deviceTypes.triggerChart.setDisplay]),
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
async mounted () {
|
||||
// await taskInfo.updateTaskInfo(this.$route.params.taskID)
|
||||
console.log(taskInfo.getTaskInfo())
|
||||
await taskInfo.updateTaskInfo(this.$route.params.taskID)
|
||||
// console.log(taskInfo.getTaskInfo())
|
||||
// this.screenHeight = document.documentElement.clientHeight
|
||||
|
||||
this.pageMqttSub(taskInfo.getTaskInfo().controllerID)
|
||||
// console.log(taskInfo.getTaskInfo().controllerID)
|
||||
await this.pageInit()
|
||||
|
||||
// this.chartNumber = taskInfo.getTaskInfo().chartNumber
|
||||
|
||||
this.dataRefreshTimer = setInterval(this.refreshData, 700)
|
||||
this.dataRefreshTimer = setInterval(this.refreshData, 100)
|
||||
|
||||
// const _this = this
|
||||
// window.onresize = function () { // define the event of window size changing
|
||||
@@ -469,7 +681,7 @@ export default {
|
||||
// }
|
||||
},
|
||||
destroyed () {
|
||||
taskInfo.destroyed()
|
||||
taskInfo.destroyed(this.deviceList)
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
this.removeChart(chart)
|
||||
}
|
||||
@@ -481,15 +693,21 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.area-style {
|
||||
height: auto;
|
||||
overflow-y: hidden;
|
||||
overflow-x: hidden;
|
||||
// .area-style {
|
||||
// height: 100%;
|
||||
// overflow-y: hidden;
|
||||
// overflow-x: hidden;
|
||||
|
||||
@include media-breakpoint-only(xl) {
|
||||
height: 88vh;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
// @include media-breakpoint-only(xl) {
|
||||
// height: 94vh;
|
||||
// overflow-y: scroll;
|
||||
// overflow-x: hidden;
|
||||
// }
|
||||
// }
|
||||
|
||||
.no-dark-style-va-button {
|
||||
&:focus {
|
||||
filter: brightness(100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,595 @@
|
||||
<template>
|
||||
<div class="task-content">
|
||||
|
||||
<va-modal
|
||||
v-model="showShutdownModal"
|
||||
size="small"
|
||||
:title="'SHUTDOWN'"
|
||||
:message="'The controller shutdown.'"
|
||||
:okText=" $t('modal.confirm') "
|
||||
@ok="exit()"
|
||||
@cancel="exit()"
|
||||
/>
|
||||
|
||||
<va-modal
|
||||
v-model="showRemoveChartModal"
|
||||
size="small"
|
||||
:title="'REMOVE CHART'"
|
||||
:message="'The chart will be removed.'"
|
||||
:okText=" $t('modal.confirm') "
|
||||
@ok="removeChart(null)"
|
||||
/>
|
||||
|
||||
<div class="row row-equal">
|
||||
<div v-if="showDeviceSetting" class="flex md12 xl4 xs12 sm12">
|
||||
<div class="row">
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<task-devices-g-m :ref="'devices_ref'" @add="addDevice($event)" @remove="removeDevice($event)" @refreshSetting="refreshChartSetting($event)" class="pa-0" />
|
||||
</div>
|
||||
<!-- <div class="flex sm12 xl12 md12 xs12">
|
||||
<task-formula :ref="'formula_ref'" @add="addFormula($event)" @remove="removeFormula($event)" class="pa-0" />
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div :class="chartAreaClass">
|
||||
<div class="row" >
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<div class="flex sm12 xl12 md12 xs12" style="text-align: center;">
|
||||
<va-card
|
||||
stripe="primary"
|
||||
>
|
||||
<va-button class="no-dark-style-va-button" v-if="!showDeviceSetting" color="primary" target="_blank" @click="showDeviceSettingClick()" small>
|
||||
SHOW DEVICES
|
||||
</va-button>
|
||||
<va-button class="no-dark-style-va-button" v-if="showDeviceSetting" color="primary" target="_blank" @click="hideDeviceSettingClick()" small>
|
||||
HIDE DEVICES
|
||||
</va-button>
|
||||
<!-- <va-button class="" color="success" target="_blank" @click="startAllClick()" small>
|
||||
START ALL
|
||||
</va-button>
|
||||
<va-button class="no-dark-style-va-button" color="danger" target="_blank" @click="stopAllClick()" small>
|
||||
STOP ALL
|
||||
</va-button> -->
|
||||
<va-button class="no-dark-style-va-button" color="primary" target="_blank" @click.stop="addChart()" small>
|
||||
ADD CHART
|
||||
</va-button>
|
||||
</va-card>
|
||||
</div>
|
||||
|
||||
<div :key="chartKey">
|
||||
<div
|
||||
v-for="chart in chartDataAll"
|
||||
:key="chart.chartID"
|
||||
>
|
||||
<canvas-chart
|
||||
:id="'chart' + chart.chartID"
|
||||
:ref="'chart_ref'"
|
||||
:cardheight="'400px'"
|
||||
:cardwidth="'auto'"
|
||||
:chartID="chart.chartID"
|
||||
@init="initChart(chart.chartID)"
|
||||
@remove="removeChartCheck(chart.chartID)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height: 150px;">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<task-content-modal />
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { dataStreamBuffer } from '../../../data/task/DataStreamBuffer'
|
||||
import { chartData } from '../../../data/task/ChartsManagement'
|
||||
import { taskInfo } from '../../../data/task/TaskInfo'
|
||||
import CanvasChart from './chart/CanvasChart'
|
||||
import TaskContentModal from './TaskContentModal.vue'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import TaskDevicesGM from './controller/neulive-gimer/TaskDevicesGM.vue'
|
||||
// import api from '../../../data/api'
|
||||
// import TaskFormula from './formula/TaskFormula'
|
||||
|
||||
// TODO change chart data tag format
|
||||
|
||||
export default {
|
||||
name: 'TaskContent',
|
||||
components: {
|
||||
CanvasChart,
|
||||
TaskDevicesGM,
|
||||
TaskContentModal,
|
||||
// TaskFormula,
|
||||
},
|
||||
// async created () {
|
||||
// await taskInfo.updateTaskInfo(this.$route.params.taskID)
|
||||
// },
|
||||
computed: {
|
||||
...mapFields('taskContent', [
|
||||
'deviceList',
|
||||
'showTaskModal',
|
||||
'taskModalText',
|
||||
]),
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
// modal
|
||||
showShutdownModal: false,
|
||||
showRemoveChartModal: false,
|
||||
// refresh timer
|
||||
dataRefreshTimer: null,
|
||||
// charts data
|
||||
chartDataAll: chartData.getAllChartsData(),
|
||||
// chart refresh key
|
||||
chartKey: 0,
|
||||
chartNumber: taskInfo.getTaskInfo().chartList.length,
|
||||
selectChartID: null,
|
||||
showDeviceSetting: true,
|
||||
chartAreaClass: ['flex', 'xs12', 'sm12', 'md12', 'xl8', 'pa-0'],
|
||||
getParmDone: false,
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
async '+/get_device_info_all/+' (data, topic) {
|
||||
await taskInfo.deviceInfo(String.fromCharCode.apply(null, data), this.deviceList)
|
||||
this.refreshDevicesWindow()
|
||||
},
|
||||
async '+/get_device_info/+' (data, topic) {
|
||||
await taskInfo.deviceInfo(String.fromCharCode.apply(null, data), this.deviceList)
|
||||
this.refreshDevicesWindow()
|
||||
this.getParmDone = true
|
||||
this.checkStiStatus()
|
||||
},
|
||||
async '+/device_parameter/+' (data, topic) {
|
||||
await taskInfo.deviceParameter(String.fromCharCode.apply(null, data))
|
||||
this.refreshDevicesWindow()
|
||||
},
|
||||
async '+/device_parameter_value/+' (data, topic) {
|
||||
await taskInfo.deviceParameter(String.fromCharCode.apply(null, data))
|
||||
this.refreshDevicesWindow()
|
||||
},
|
||||
async '+/hardware_device/+' (data, topic) {
|
||||
await taskInfo.deviceInfo(String.fromCharCode.apply(null, data), this.deviceList)
|
||||
if (this.$refs.devices_ref != null) {
|
||||
await this.$refs.devices_ref.loadingDone()
|
||||
}
|
||||
},
|
||||
// listen datastream [ topic: controllerID/data_server/device_data_stream/deviceID/channel ]
|
||||
async '+/data_server/device_data_stream/+/+' (data, topic) {
|
||||
const topicSplit = topic.split('/')
|
||||
if (this.getParmDone & !taskInfo.getDeviceInfoByRawID(parseInt(topicSplit[3])).info.isSync) {
|
||||
if (chartData.defaultChartGenerator(this.deviceList, taskInfo.getDeviceIDByRaw(parseInt(topicSplit[3])), null, 'device')) {
|
||||
taskInfo.deviceStart(parseInt(topicSplit[3]), this.deviceList)
|
||||
}
|
||||
}
|
||||
dataStreamBuffer.into(String.fromCharCode.apply(null, data), parseInt(topicSplit[3]), (parseInt(topicSplit[4]) + 1))
|
||||
},
|
||||
'+/device_save_path/+' (data, topic) {
|
||||
taskInfo.deviceSavePath(String.fromCharCode.apply(null, data))
|
||||
// console.log(taskInfo.getTaskInfo())
|
||||
},
|
||||
'+/device_save_path_set/+' (data, topic) {
|
||||
taskInfo.deviceSavePath(String.fromCharCode.apply(null, data))
|
||||
// console.log(taskInfo.getTaskInfo())
|
||||
},
|
||||
async '+/broadcast' (data, topic) {
|
||||
const mes = String.fromCharCode.apply(null, data).split(':')
|
||||
// let content
|
||||
switch (mes[0]) {
|
||||
case 'state':
|
||||
switch (mes[1]) {
|
||||
case 'device_available':
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'hardware_device/0',
|
||||
}))
|
||||
break
|
||||
}
|
||||
break
|
||||
case 'disconnected':
|
||||
taskInfo.deviceDisconnected(mes[1])
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'get_device_info/0',
|
||||
device: parseInt(mes[1]),
|
||||
}))
|
||||
break
|
||||
case 'connected':
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'get_device_info/0',
|
||||
device: parseInt(mes[1]),
|
||||
}))
|
||||
taskInfo.deviceConnected(mes[1])
|
||||
break
|
||||
case 'shutdown':
|
||||
taskInfo.controllerShutdown(this.deviceList)
|
||||
this.showShutdownModal = true
|
||||
break
|
||||
case 'start':
|
||||
if (!taskInfo.getDeviceInfoByRawID(parseInt(parseInt(mes[1]))).info.isSync) {
|
||||
taskInfo.deviceStart(parseInt(mes[1]), this.deviceList)
|
||||
if (chartData.defaultChartGenerator(this.deviceList, taskInfo.getDeviceIDByRaw(parseInt(parseInt(mes[1]))), null, 'device')) {
|
||||
taskInfo.deviceStart(parseInt(parseInt(mes[1])), this.deviceList)
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'stop':
|
||||
if (mes[1] === 'all') {
|
||||
return false
|
||||
}
|
||||
taskInfo.deviceStop(parseInt(mes[1]), this.deviceList)
|
||||
break
|
||||
case 'device_timeout':
|
||||
this.pageToast('The device [' + taskInfo.getDeviceIDByRaw(parseInt(mes[1])) + '] is timeout, please check its status or parameters.')
|
||||
break
|
||||
case 'device_mission_done':
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: parseInt(mes[1]),
|
||||
instruction: 'interrupt',
|
||||
}))
|
||||
this.pageToast('The device [' + taskInfo.getDeviceIDByRaw(parseInt(mes[1])) + '] mission is done.')
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
// console.log(String.fromCharCode.apply(null, data), topic)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
mqttSub: function (val) {
|
||||
this.$mqtt.subscribe(val)
|
||||
},
|
||||
mqttUnSub: function (val) {
|
||||
this.$mqtt.unsubscribe(val)
|
||||
},
|
||||
mqttPub: function (topic, mes) {
|
||||
this.$mqtt.publish(topic, mes)
|
||||
},
|
||||
pageMqttSub: function (id) {
|
||||
this.mqttSub(id + '/hardware_device/+')
|
||||
this.mqttSub(id + '/broadcast')
|
||||
this.mqttSub(id + '/get_device_info_all/+')
|
||||
this.mqttSub(id + '/get_device_info/+')
|
||||
this.mqttSub(id + '/device_parameter/+')
|
||||
this.mqttSub(id + '/device_parameter_value/+')
|
||||
},
|
||||
pageMqttUnSub: function (id) {
|
||||
for (const device in taskInfo.getTaskInfo().deviceList) {
|
||||
this.mqttUnSub(id + '/data_server/device_data_stream/' + device + '/+')
|
||||
}
|
||||
this.mqttUnSub(id + '/hardware_device/+')
|
||||
this.mqttUnSub(id + '/broadcast')
|
||||
this.mqttUnSub(id + '/get_device_info_all/+')
|
||||
this.mqttUnSub(id + '/get_device_info/+')
|
||||
this.mqttUnSub(id + '/device_parameter/+')
|
||||
this.mqttUnSub(id + '/device_parameter_value/+')
|
||||
},
|
||||
pageInit: async function () {
|
||||
if (await this.$refs.devices_ref != null) {
|
||||
await this.$refs.devices_ref.loadingStart()
|
||||
}
|
||||
// let _parameter, _content
|
||||
|
||||
// this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
// header: 'device_parameter/0',
|
||||
// device: 7,
|
||||
// parameter: 'RECORDING_CH|AXIS_CH',
|
||||
// content: '7|1',
|
||||
// }))
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'hardware_device/0',
|
||||
}))
|
||||
await taskInfo.updateChartInfo()
|
||||
this.chartNumber = taskInfo.getTaskInfo().chartNumber
|
||||
},
|
||||
pageToast: function (mes) {
|
||||
this.showToast(
|
||||
mes,
|
||||
{
|
||||
icon: 'fa-bell',
|
||||
position: 'bottom-right',
|
||||
duration: 4000,
|
||||
},
|
||||
)
|
||||
},
|
||||
refreshData: function () {
|
||||
// TODO don't need to refresh chart with stop status
|
||||
for (const chart in this.chartDataAll) {
|
||||
chartData.refresh(parseInt(chart))
|
||||
}
|
||||
},
|
||||
refreshDevicesWindow: function () {
|
||||
// console.log(taskInfo.getTaskInfo())
|
||||
if (this.$refs.devices_ref != null) {
|
||||
this.$refs.devices_ref.refresh()
|
||||
}
|
||||
},
|
||||
checkStiStatus: function () {
|
||||
this.$refs.devices_ref.checkStiStatus()
|
||||
},
|
||||
addChart: async function () {
|
||||
const defaultID = {}
|
||||
const update = async () => {
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
defaultID[chart] = chartData.getAllChartsData()[chart].mappingID
|
||||
}
|
||||
chartData.init(this.chartNumber, 4000, 1, 1)
|
||||
this.chartNumber++
|
||||
this.chartKey++
|
||||
}
|
||||
await update()
|
||||
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
chartData.getAllChartsData()[chart].mappingID = defaultID[chart]
|
||||
}
|
||||
|
||||
if (this.$refs.chart_ref != null) {
|
||||
this.$refs.chart_ref.forEach(ref => {
|
||||
ref.refreshMappingSelect()
|
||||
})
|
||||
}
|
||||
// this.pageToast('The chart has been added.')
|
||||
|
||||
return this.chartNumber - 1
|
||||
// chartData.updateGridList(0, 4)
|
||||
},
|
||||
refreshChartSetting: async function () {
|
||||
const defaultID = {}
|
||||
const update = async () => {
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
defaultID[chart] = chartData.getAllChartsData()[chart].mappingID
|
||||
}
|
||||
this.chartKey++
|
||||
}
|
||||
await update()
|
||||
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
chartData.getAllChartsData()[chart].mappingID = defaultID[chart]
|
||||
}
|
||||
|
||||
if (this.$refs.chart_ref != null) {
|
||||
this.$refs.chart_ref.forEach(ref => {
|
||||
ref.refreshMappingSelect()
|
||||
})
|
||||
}
|
||||
},
|
||||
initChart: function (chartID) {
|
||||
chartData.reset(chartID)
|
||||
// this.pageToast('The chart has been Initialized.')
|
||||
},
|
||||
removeChartCheck: function (chartID) {
|
||||
this.selectChartID = chartID
|
||||
this.showRemoveChartModal = true
|
||||
},
|
||||
removeChart: async function (chartID) {
|
||||
if (chartID == null) {
|
||||
chartID = this.selectChartID
|
||||
}
|
||||
dataStreamBuffer.removeByChart(chartID)
|
||||
if (chartData.getAllChartsData()[chartID] != null) {
|
||||
const defaultID = {}
|
||||
const update = async () => {
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
if (chart !== chartID) {
|
||||
defaultID[chart] = chartData.getAllChartsData()[chart].mappingID
|
||||
}
|
||||
}
|
||||
delete chartData.getAllChartsData()[chartID]
|
||||
this.chartKey++
|
||||
}
|
||||
await update()
|
||||
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
chartData.getAllChartsData()[chart].mappingID = defaultID[chart]
|
||||
}
|
||||
|
||||
if (this.$refs.chart_ref != null) {
|
||||
this.$refs.chart_ref.forEach(ref => {
|
||||
ref.refreshMappingSelect()
|
||||
})
|
||||
}
|
||||
}
|
||||
// this.pageToast('The chart has been removed.')
|
||||
},
|
||||
showDeviceSettingClick: function () {
|
||||
this.showDeviceSetting = true
|
||||
this.chartAreaClass[3] = 'md12'
|
||||
this.chartAreaClass[4] = 'xl8'
|
||||
},
|
||||
hideDeviceSettingClick: function () {
|
||||
this.showDeviceSetting = false
|
||||
this.chartAreaClass[3] = 'md12'
|
||||
this.chartAreaClass[4] = 'xl12'
|
||||
},
|
||||
addMappingChart: async function (deviceID) {
|
||||
// if have chart with device ID
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
if (chartData.getAllChartsData()[chart].mappingID === deviceID) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
const chart = await this.addChart()
|
||||
await this.$nextTick(async () => {
|
||||
chartData.getAllChartsData()[chart].mappingID = deviceID
|
||||
if (this.$refs.chart_ref != null) {
|
||||
this.$refs.chart_ref.forEach(ref => {
|
||||
ref.refreshMappingSelect()
|
||||
})
|
||||
}
|
||||
})
|
||||
return chart
|
||||
},
|
||||
addDevice: async function (deviceID) {
|
||||
this.mqttSub(taskInfo.getTaskInfo().controllerID + '/data_server/device_data_stream/' + taskInfo.getRawDeviceID(deviceID) + '/+')
|
||||
this.addMappingChart(deviceID)
|
||||
// if (taskInfo.getDeviceInfo(deviceID).info.isSync) {
|
||||
// chartData.defaultChartGenerator(deviceID, chart, 'device')
|
||||
// }
|
||||
// console.log(chartData.getAllChartsData())
|
||||
// console.log(taskInfo.getTaskInfo())
|
||||
// await api.task.update({
|
||||
// device_config: taskInfo.getTaskInfo().deviceList,
|
||||
// })
|
||||
this.pageToast('The device [' + deviceID + '] has been registered.')
|
||||
},
|
||||
removeDevice: function (deviceID) {
|
||||
this.mqttUnSub(taskInfo.getTaskInfo().controllerID + '/data_server/device_data_stream/' + taskInfo.getRawDeviceID(deviceID) + '/+')
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
if (chartData.getAllChartsData()[chart].mappingID === deviceID) {
|
||||
dataStreamBuffer.removeByChart(chart)
|
||||
this.removeChart(chart)
|
||||
}
|
||||
}
|
||||
this.pageToast('The device [' + deviceID + '] has been removed.')
|
||||
},
|
||||
addFormula: async function (formulaID) {
|
||||
const chart = await this.addChart()
|
||||
await this.$nextTick(async () => {
|
||||
chartData.getAllChartsData()[chart].mappingID = formulaID
|
||||
if (this.$refs.chart_ref != null) {
|
||||
this.$refs.chart_ref.forEach(ref => {
|
||||
ref.refreshMappingSelect()
|
||||
})
|
||||
}
|
||||
})
|
||||
this.pageToast('The formula [' + formulaID + '] has been registered.')
|
||||
},
|
||||
removeFormula: function (formulaID) {
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
if (chartData.getAllChartsData()[chart].mappingID === formulaID) {
|
||||
dataStreamBuffer.removeByChart(chart)
|
||||
this.removeChart(chart)
|
||||
}
|
||||
}
|
||||
this.pageToast('The formula [' + formulaID + '] has been removed.')
|
||||
},
|
||||
startAllClick: async function () {
|
||||
for (const device of this.deviceList) {
|
||||
if (this.$refs.devices_ref === undefined) {
|
||||
this.startDevice(device)
|
||||
} else {
|
||||
await this.$refs.devices_ref.$refs.pdlist_ref.start(device)
|
||||
}
|
||||
}
|
||||
this.refreshDevicesWindow()
|
||||
this.pageToast('The all devices have been started')
|
||||
},
|
||||
startDevice: async function (device) {
|
||||
chartData.defaultChartGenerator(this.deviceList, device.id, null, 'device')
|
||||
if (!taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Neulive')) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'record',
|
||||
}))
|
||||
} else if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Elite')) {
|
||||
// console.log('elite')
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'start',
|
||||
}))
|
||||
}
|
||||
device.stopping = false
|
||||
device.isSync = true
|
||||
// this.$emit('refreshSetting')
|
||||
// ### show device info
|
||||
// console.log(taskInfo.getDeviceInfo(device.id))
|
||||
}
|
||||
},
|
||||
stopAllClick: function () {
|
||||
for (const device of this.deviceList) {
|
||||
if (this.$refs.devices_ref === undefined) {
|
||||
this.stopDevice(device)
|
||||
} else {
|
||||
this.$refs.devices_ref.stopDevice(device)
|
||||
}
|
||||
}
|
||||
this.pageToast('The all devices have been stopped')
|
||||
},
|
||||
stopDevice: async function (device) {
|
||||
dataStreamBuffer.removeByDevice(taskInfo.getRawDeviceID(device.id))
|
||||
if (taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Neulive')) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'stop_record',
|
||||
}))
|
||||
} else if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Elite')) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'interrupt',
|
||||
}))
|
||||
}
|
||||
device.stopping = true
|
||||
}
|
||||
},
|
||||
exit: function () {
|
||||
this.$router.push({
|
||||
path: '/',
|
||||
})
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
async mounted () {
|
||||
await taskInfo.updateTaskInfo(this.$route.params.taskID)
|
||||
// console.log(taskInfo.getTaskInfo())
|
||||
// this.screenHeight = document.documentElement.clientHeight
|
||||
this.pageMqttSub(taskInfo.getTaskInfo().controllerID)
|
||||
// console.log(taskInfo.getTaskInfo().controllerID)
|
||||
await this.pageInit()
|
||||
// this.chartNumber = taskInfo.getTaskInfo().chartNumber
|
||||
|
||||
this.dataRefreshTimer = setInterval(this.refreshData, 100)
|
||||
|
||||
// const _this = this
|
||||
// window.onresize = function () { // define the event of window size changing
|
||||
// // _this.screenWidth = document.documentElement.clientWidth
|
||||
// _this.screenHeight = document.documentElement.clientHeight
|
||||
// }
|
||||
},
|
||||
destroyed () {
|
||||
taskInfo.destroyed(this.deviceList)
|
||||
for (const chart in chartData.getAllChartsData()) {
|
||||
this.removeChart(chart)
|
||||
}
|
||||
clearInterval(this.dataRefreshTimer)
|
||||
this.pageMqttUnSub(taskInfo.getTaskInfo().controllerID)
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
// .area-style {
|
||||
// height: 100%;
|
||||
// overflow-y: hidden;
|
||||
// overflow-x: hidden;
|
||||
|
||||
// @include media-breakpoint-only(xl) {
|
||||
// height: 94vh;
|
||||
// overflow-y: scroll;
|
||||
// overflow-x: hidden;
|
||||
// }
|
||||
// }
|
||||
|
||||
.no-dark-style-va-button {
|
||||
&:focus {
|
||||
filter: brightness(100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<va-modal
|
||||
v-model="showTaskModal"
|
||||
size="small"
|
||||
:title="''"
|
||||
:message="taskModalText"
|
||||
:okText=" $t('modal.confirm') "
|
||||
:cancelText=" $t('modal.cancel') "
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('taskContent', [
|
||||
'showTaskModal',
|
||||
'taskModalText',
|
||||
]),
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -2,8 +2,19 @@
|
||||
<div class="flex" :class="cardclass">
|
||||
<va-card>
|
||||
<template slot="header">
|
||||
<va-icon name="fa fa-area-chart mr-3" color="primary"/>
|
||||
<h5 class="mt-0 mb-0">{{nameCard}}</h5>
|
||||
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
|
||||
<div class="flex sm5 xl5 md5 xs5 px-0 mx-0">
|
||||
<h5 class="mt-0 mb-0"><va-icon name="fa fa-area-chart mr-3" color="primary"/>{{nameCard}}</h5>
|
||||
</div>
|
||||
<div class="flex sm7 xl7 md7 xs7 pa-0 ma-0" style="text-align: right;">
|
||||
<va-button class="pa-0 ma-0 circle-button" small color="dark" @click="remove()">
|
||||
<va-icon
|
||||
name="fa fa-times"
|
||||
color="white"
|
||||
/>
|
||||
</va-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<va-tabs v-model="tabValue" class="mb-3" style="width: 100%; min-width: 100px;">
|
||||
<va-tab>
|
||||
@@ -12,49 +23,90 @@
|
||||
<va-tab>
|
||||
{{'SOURCE'}}
|
||||
</va-tab>
|
||||
<!-- <va-tab>
|
||||
{{'SETTING'}}
|
||||
</va-tab> -->
|
||||
</va-tabs>
|
||||
<div v-if="tabValue == 0" >
|
||||
<div v-if="data.legend.data.length != 0">
|
||||
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="data" :auto-resize="true"></chart>
|
||||
</div>
|
||||
<div v-else>
|
||||
Please add the source or choose a item to mapping.
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="tabValue == 1" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" >
|
||||
<canvas-chart-source :chartID="chartID" :gridInfo="data.grid"></canvas-chart-source>
|
||||
</div>
|
||||
<div v-else :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" >
|
||||
<canvas-chart-setting></canvas-chart-setting>
|
||||
<!-- <canvas-chart-setting :chartID="chartID"></canvas-chart-setting> -->
|
||||
</div>
|
||||
<div class="flex row xs12 md12 xl12 sm12" style="text-align: center;" >
|
||||
<div>
|
||||
<va-select
|
||||
class="xs6 md6 xl6 sm6"
|
||||
:on-change="mappingSelectChange()"
|
||||
small
|
||||
:label="'MAPPING'"
|
||||
v-model="mappingSelect"
|
||||
textBy="name"
|
||||
:options="mappingOptions"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<va-button small @click="init()">INIT</va-button>
|
||||
<va-button small color="dark" @click="remove()">REMOVE</va-button>
|
||||
</div>
|
||||
|
||||
<div v-if="this.$refs.chart_ref != null">
|
||||
<va-button small class="mb-3" @click="selectAllSeries">
|
||||
SELECT ALL
|
||||
</va-button>
|
||||
<va-button small class="mb-3" @click="inverseSelectAllSeries">
|
||||
INVERSE SELECT
|
||||
</va-button>
|
||||
</div>
|
||||
<div class="row flex align--left ma-0 pa-0">
|
||||
<va-input
|
||||
v-if="data.chartXMode === 'time'"
|
||||
class="mx-1"
|
||||
@keyup.enter="timeIntervalChange(timeIntervalInput)"
|
||||
@blur="timeIntervalChange(timeIntervalInput)"
|
||||
v-model="timeIntervalInput"
|
||||
:label="'time-grid'"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
ms
|
||||
</p>
|
||||
</va-input>
|
||||
<va-input
|
||||
v-if="data.chartXMode === 'value'"
|
||||
class="mx-1"
|
||||
@keyup.enter="xIntervalChange(xIntervalInput)"
|
||||
@blur="xIntervalChange(xIntervalInput)"
|
||||
v-model="xIntervalInput"
|
||||
:label="'x-grid'"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
{{data.chartXUnit}}
|
||||
</p>
|
||||
</va-input>
|
||||
<va-input
|
||||
class="mx-1"
|
||||
@keyup.enter="yIntervalChange(yIntervalInput)"
|
||||
@blur="yIntervalChange(yIntervalInput)"
|
||||
v-model="yIntervalInput"
|
||||
:label="'y-grid'"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
{{data.chartYUnit}}
|
||||
</p>
|
||||
</va-input>
|
||||
<va-input
|
||||
v-if="data.chartDevice === 'neulive'"
|
||||
class="mx-1"
|
||||
@keyup.enter="threeAxisIntervalChange(threeAxisIntervalInput)"
|
||||
@blur="threeAxisIntervalChange(threeAxisIntervalInput)"
|
||||
v-model="threeAxisIntervalInput"
|
||||
:label="'3axis-grid'"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
g
|
||||
</p>
|
||||
</va-input>
|
||||
</div>
|
||||
<div class="row flex ma-0 pa-0">
|
||||
<canvas-chart-filter :chartID="chartID" :filterIndex="0" />
|
||||
<canvas-chart-filter :chartID="chartID" :filterIndex="1" />
|
||||
<canvas-chart-filter :chartID="chartID" :filterIndex="2" />
|
||||
</div>
|
||||
</va-card>
|
||||
<canvas-chart-filter-popup :ref="'filter_popup_ref'" :chartID="chartID" :chartRef="this.$refs.chart_ref" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { InitChartsData, getChartsData } from '../../../../../data/task/ChartsManagement'
|
||||
import CanvasChartSetting from './CanvasChartSetting'
|
||||
import CanvasChartFilter from './CanvasChartFilter.vue'
|
||||
import CanvasChartFilterPopup from './CanvasChartFilterPopup.vue'
|
||||
// import CanvasChartSetting from './CanvasChartSetting'
|
||||
import CanvasChartSource from './CanvasChartSource'
|
||||
import { taskInfo } from '../../../../data/task/TaskInfo'
|
||||
import { chartData } from '../../../../data/task/ChartsManagement'
|
||||
@@ -62,8 +114,10 @@ import { chartData } from '../../../../data/task/ChartsManagement'
|
||||
export default {
|
||||
name: 'CanvasChart',
|
||||
components: {
|
||||
CanvasChartSetting,
|
||||
// CanvasChartSetting,
|
||||
CanvasChartSource,
|
||||
CanvasChartFilter,
|
||||
CanvasChartFilterPopup,
|
||||
},
|
||||
props: {
|
||||
chartID: {
|
||||
@@ -98,6 +152,10 @@ export default {
|
||||
mappingOptions: taskInfo.getMappingList(),
|
||||
nameCard: chartData.getAllChartsData()[this.chartID].cardName,
|
||||
initDone: false,
|
||||
timeIntervalInput: 'auto',
|
||||
threeAxisIntervalInput: 'auto',
|
||||
xIntervalInput: 'auto',
|
||||
yIntervalInput: 'auto',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -105,6 +163,90 @@ export default {
|
||||
watch: {
|
||||
},
|
||||
methods: {
|
||||
timeIntervalChange: function (val) {
|
||||
if (!isNaN(parseInt(val))) {
|
||||
chartData.getAllChartsData()[this.chartID].xAxis.forEach(x => {
|
||||
if (x.type === 'time') {
|
||||
x.interval = val * 1000
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.timeIntervalInput = 'auto'
|
||||
chartData.getAllChartsData()[this.chartID].xAxis.forEach(x => {
|
||||
if (x.type === 'time') {
|
||||
x.interval = 500 * 1000
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
xIntervalChange: function (val) {
|
||||
if (!isNaN(parseInt(val))) {
|
||||
chartData.getAllChartsData()[this.chartID].xAxis.forEach(x => {
|
||||
if (x.type === 'value') {
|
||||
x.interval = val * 1000
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.timeIntervalInput = 'auto'
|
||||
chartData.getAllChartsData()[this.chartID].xAxis.forEach(x => {
|
||||
if (x.type === 'value') {
|
||||
x.interval = null
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
yIntervalChange: function (val) {
|
||||
if (!isNaN(parseInt(val))) {
|
||||
chartData.getAllChartsData()[this.chartID].yAxis.forEach(y => {
|
||||
if (parseInt(y.channel) <= 255) {
|
||||
if (chartData.getAllChartsData()[this.chartID].chartYUnit === 'uV') {
|
||||
y.interval = parseInt(val)
|
||||
// console.log(y.interval)
|
||||
} else {
|
||||
y.interval = val * 1000
|
||||
}
|
||||
const maxList = []
|
||||
const minList = []
|
||||
y.seriesIndex.forEach(i => {
|
||||
maxList.push(Math.max(...chartData.getAllChartsData()[this.chartID].series[i].data.map(p => p[1])))
|
||||
minList.push(Math.min(...chartData.getAllChartsData()[this.chartID].series[i].data.map(p => p[1])))
|
||||
})
|
||||
const max = Math.max(maxList)
|
||||
const min = Math.min(minList)
|
||||
const center = (max + min) / 2
|
||||
y.max = center + (max - min)
|
||||
y.min = center - (max - min)
|
||||
y.max = (parseInt(y.max / y.interval) + 1) * y.interval
|
||||
y.min = (parseInt(y.min / y.interval) - 1) * y.interval
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.timeIntervalInput = 'auto'
|
||||
chartData.getAllChartsData()[this.chartID].yAxis.forEach(y => {
|
||||
if (parseInt(y.channel) <= 255) {
|
||||
y.interval = null
|
||||
y.max = 'dataMax'
|
||||
y.min = 'dataMin'
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
threeAxisIntervalChange: function (val) {
|
||||
if (!isNaN(parseInt(val))) {
|
||||
chartData.getAllChartsData()[this.chartID].yAxis.forEach(y => {
|
||||
if (parseInt(y.channel) >= 255) {
|
||||
y.interval = val * 1
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.timeIntervalInput = 'auto'
|
||||
chartData.getAllChartsData()[this.chartID].yAxis.forEach(y => {
|
||||
if (parseInt(y.channel) >= 255) {
|
||||
y.interval = null
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
init: function () {
|
||||
this.mappingSelect = ''
|
||||
this.nameCard = 'chart' + this.chartID
|
||||
@@ -156,12 +298,51 @@ export default {
|
||||
this.$refs.chart_ref.resize()
|
||||
}
|
||||
},
|
||||
showFilterPopup (params) {
|
||||
this.$refs.filter_popup_ref.showPanel(params)
|
||||
},
|
||||
setCursor (params) {
|
||||
this.$refs.chart_ref.chart._zr.setCursorStyle('copy')
|
||||
},
|
||||
legendChange (params) {
|
||||
const activeLegendLen = Object.values(params.selected).filter(val => val === true).length
|
||||
let index = 0
|
||||
for (const [gridIndex, value] of Object.values(params.selected).entries()) { // [TODO] 技術債,目前real time chart一個grid只對應一條series
|
||||
if (value === true) {
|
||||
this.data.grid[gridIndex].height = (85 / activeLegendLen) + '%'
|
||||
this.data.grid[gridIndex].top = index * (85 / activeLegendLen) + 1 + '%'
|
||||
index++
|
||||
} else {
|
||||
this.data.grid[gridIndex].height = '0%'
|
||||
this.data.grid[gridIndex].top = '0%'
|
||||
}
|
||||
}
|
||||
},
|
||||
selectAllSeries () {
|
||||
this.$refs.chart_ref.dispatchAction({
|
||||
type: 'legendAllSelect',
|
||||
})
|
||||
},
|
||||
inverseSelectAllSeries () {
|
||||
this.$refs.chart_ref.dispatchAction({
|
||||
type: 'legendInverseSelect',
|
||||
})
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
this.resizeTimer = setInterval(this.resize, 1000)
|
||||
this.nameCard = chartData.getAllChartsData()[this.chartID].cardName
|
||||
await this.refreshMappingSelect()
|
||||
this.initDone = true
|
||||
if (this.$refs.chart_ref != null) {
|
||||
this.$refs.chart_ref.chart._zr.on('click', this.showFilterPopup)
|
||||
this.$refs.chart_ref.chart._zr.on('mousemove', this.setCursor)
|
||||
this.$refs.chart_ref.chart.on('legendselectchanged', this.legendChange)
|
||||
this.$refs.chart_ref.chart.on('legendselectall', this.legendChange)
|
||||
this.$refs.chart_ref.chart.on('legendinverseselect', this.legendChange)
|
||||
}
|
||||
// this.timeIntervalInput = '500'
|
||||
// this.timeIntervalChange('500')
|
||||
},
|
||||
destroyed () {
|
||||
clearInterval(this.resizeTimer)
|
||||
@@ -169,3 +350,17 @@ export default {
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.circle-button {
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
border-radius: '50%';
|
||||
}
|
||||
|
||||
.no-dark-style-va-button {
|
||||
&:focus {
|
||||
filter: brightness(100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<div class="row flex pa-0 ma-0">
|
||||
<div class="filter-input my-0 pa-0 mx-1">
|
||||
<va-select
|
||||
small
|
||||
noClear
|
||||
:label="'FILTER ' + (filterIndex + 1)"
|
||||
v-model="selectFilter"
|
||||
textBy="name"
|
||||
:options="optionFilter"
|
||||
/>
|
||||
</div>
|
||||
<va-input
|
||||
:label="'order'"
|
||||
class="mx-1 order-input"
|
||||
v-model="order"
|
||||
/>
|
||||
<va-input
|
||||
v-if="[1, 2, 3].indexOf(selectFilter.id) >= 0"
|
||||
:label="'FREQ'"
|
||||
class="mx-1 freq-input"
|
||||
v-model="freq2"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
Hz
|
||||
</p>
|
||||
</va-input>
|
||||
<va-input
|
||||
v-if="selectFilter.id > 3"
|
||||
:label="'FREQ MIN'"
|
||||
class="mx-1 freq-input"
|
||||
v-model="freq0"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
Hz
|
||||
</p>
|
||||
</va-input>
|
||||
<va-input
|
||||
v-if="selectFilter.id > 3"
|
||||
:label="'FREQ MAX'"
|
||||
class="mx-1 freq-input"
|
||||
v-model="freq1"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
Hz
|
||||
</p>
|
||||
</va-input>
|
||||
<va-button
|
||||
flat
|
||||
small
|
||||
:color="buttonColor"
|
||||
class="circle-button pa-0 mx-0 filter-apply-button"
|
||||
:icon="buttonIcon"
|
||||
@click.stop="updateFilterInfo(filterIndex)"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { chartData } from '@/data/task/ChartsManagement'
|
||||
import { taskInfo } from '@/data/task/TaskInfo'
|
||||
import api from '@/data/api'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import { IIRFilter } from '@/data/task/filter/IIRFilter.js'
|
||||
|
||||
export default {
|
||||
name: 'canvas-chart-filter',
|
||||
props: {
|
||||
chartID: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
filterIndex: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapFields('taskContent', [
|
||||
'filter',
|
||||
]),
|
||||
buttonIcon () {
|
||||
if (this.data.series.length > 0 && this.data.series.every(item => item != null)) {
|
||||
return this.data.series.every(item => item.filter[this.filterIndex].filter != null) ? 'fa fa-stop' : 'fa fa-play'
|
||||
}
|
||||
return 'fa fa-play'
|
||||
},
|
||||
buttonColor () {
|
||||
if (this.data.series.length > 0 && this.data.series.every(item => item != null)) {
|
||||
return this.data.series.every(item => item.filter[this.filterIndex].filter != null) ? 'danger' : 'primary'
|
||||
}
|
||||
return 'fa fa-play'
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
data: chartData.getAllChartsData()[this.chartID],
|
||||
selectFilter: {
|
||||
id: 1,
|
||||
name: 'notch',
|
||||
},
|
||||
order: 20,
|
||||
freq0: 60,
|
||||
freq1: 60,
|
||||
freq2: 60,
|
||||
optionFilter: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'notch',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'lowpass',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'highpass',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'bandstop',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'bandpass',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async updateFilterInfo (index) {
|
||||
let closeFilter = false
|
||||
for (let i = 0; i < this.data.series.length; i++) {
|
||||
if (this.data.series[i].filter[this.filterIndex].filter != null) {
|
||||
this.data.series[i].filter[this.filterIndex].filter = null
|
||||
closeFilter = true
|
||||
}
|
||||
}
|
||||
if (closeFilter) {
|
||||
return false
|
||||
}
|
||||
let fs = 0
|
||||
let sos = []
|
||||
for (let i = 0; i < this.data.series.length; i++) {
|
||||
const deviceID = this.data.series[i].yAxisSource[0]
|
||||
// const _fs = taskInfo.getDeviceInfo(deviceID).parameterSet.SAMPLE_RATE
|
||||
const _fs = 1000
|
||||
const _chNum = taskInfo.getDeviceInfo(deviceID).parameterSet.CH_NUMBER
|
||||
// console.log(_fs, _chNum)
|
||||
if (fs !== _fs) {
|
||||
fs = _fs
|
||||
const ret = await api.analysis.IIRFilter({
|
||||
type: this.selectFilter.name,
|
||||
order: this.order,
|
||||
fs: parseFloat(_fs / _chNum),
|
||||
f0: parseFloat(this.freq0),
|
||||
f1: parseFloat(this.freq1),
|
||||
f2: parseFloat(this.freq2),
|
||||
})
|
||||
|
||||
if (ret.status !== 200) {
|
||||
return false
|
||||
}
|
||||
|
||||
const _sosRet = ret.data.split('/')
|
||||
const _sos = []
|
||||
_sosRet.forEach((v, vi) => {
|
||||
const _tmp = v.split(',')
|
||||
const _arr = []
|
||||
_tmp.forEach(s => {
|
||||
_arr.push(parseFloat(s))
|
||||
})
|
||||
_sos.push(_arr)
|
||||
})
|
||||
sos = _sos
|
||||
}
|
||||
this.data.series[i].filter[index].type = this.selectFilter.name
|
||||
this.data.series[i].filter[index].order = this.order
|
||||
// sampling rate changed by channel number
|
||||
this.data.series[i].filter[index].fs = parseFloat(_fs / _chNum)
|
||||
this.data.series[i].filter[index].f0 = parseFloat(this.freq0)
|
||||
this.data.series[i].filter[index].f1 = parseFloat(this.freq1)
|
||||
this.data.series[i].filter[index].f2 = parseFloat(this.freq2)
|
||||
this.data.series[i].filter[index].sos = sos
|
||||
this.data.series[i].filter[index].filter = IIRFilter.init(sos)
|
||||
}
|
||||
// console.log(this.data)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
.filter-input {
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.freq-input {
|
||||
max-width: 80px;
|
||||
}
|
||||
|
||||
.order-input {
|
||||
max-width: 50px;
|
||||
}
|
||||
|
||||
.filter-apply-button {
|
||||
max-width: 25px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-modal
|
||||
class="flex sm12 xl12 md12 xs12"
|
||||
v-model="showModal"
|
||||
:title="'Grid ' + (gridIndex + 1)"
|
||||
:position="position"
|
||||
cancelText=""
|
||||
okText=""
|
||||
size="small"
|
||||
>
|
||||
<div class="row flex ma-0 pa-0">
|
||||
<canvas-chart-individual-filter :chartID="chartID" :seriesIndex="gridIndex" :filterIndex="0" />
|
||||
<canvas-chart-individual-filter :chartID="chartID" :seriesIndex="gridIndex" :filterIndex="1" />
|
||||
<canvas-chart-individual-filter :chartID="chartID" :seriesIndex="gridIndex" :filterIndex="2" />
|
||||
</div>
|
||||
</va-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { chartData } from '@/data/task/ChartsManagement'
|
||||
import CanvasChartIndividualFilter from './CanvasChartIndividualFilter.vue'
|
||||
|
||||
export default {
|
||||
name: 'canvas-chart-filter-popup',
|
||||
components: {
|
||||
CanvasChartIndividualFilter,
|
||||
},
|
||||
props: {
|
||||
chartID: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
chartRef: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showModal: false,
|
||||
position: 'center',
|
||||
data: chartData.getAllChartsData()[this.chartID],
|
||||
gridIndex: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showPanel (params) {
|
||||
// console.log(this.data)
|
||||
if (this.chartRef != null) {
|
||||
let _gridIndex = 0
|
||||
for (_gridIndex = 0; _gridIndex < this.data.grid.length; _gridIndex++) {
|
||||
if (this.chartRef.containPixel({ gridIndex: _gridIndex }, [params.offsetX, params.offsetY])) {
|
||||
this.position = 'left'
|
||||
this.showModal = true
|
||||
break
|
||||
}
|
||||
}
|
||||
this.gridIndex = _gridIndex
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
.filter-input {
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.freq-input {
|
||||
max-width: 80px;
|
||||
}
|
||||
|
||||
.order-input {
|
||||
max-width: 50px;
|
||||
}
|
||||
|
||||
.filter-apply-button {
|
||||
max-width: 25px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="filter-input my-0 pa-0 mx-1">
|
||||
<va-select
|
||||
small
|
||||
noClear
|
||||
:label="'FILTER ' + (filterIndex + 1)"
|
||||
v-model="selectFilter"
|
||||
textBy="name"
|
||||
:options="optionFilter"
|
||||
/>
|
||||
</div>
|
||||
<va-input
|
||||
:label="'order'"
|
||||
class="mx-1 order-input"
|
||||
v-model="order"
|
||||
/>
|
||||
<va-input
|
||||
v-if="[1, 2, 3].indexOf(selectFilter.id) >= 0"
|
||||
:label="'FREQ'"
|
||||
class="mx-1 freq-input"
|
||||
v-model="freq2"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
Hz
|
||||
</p>
|
||||
</va-input>
|
||||
<va-input
|
||||
v-if="selectFilter.id > 3"
|
||||
:label="'FREQ MIN'"
|
||||
class="mx-1 freq-input"
|
||||
v-model="freq0"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
Hz
|
||||
</p>
|
||||
</va-input>
|
||||
<va-input
|
||||
v-if="selectFilter.id > 3"
|
||||
:label="'FREQ MAX'"
|
||||
class="mx-1 freq-input"
|
||||
v-model="freq1"
|
||||
>
|
||||
<p slot="append" style="margin-right: 0;" small>
|
||||
Hz
|
||||
</p>
|
||||
</va-input>
|
||||
<va-button
|
||||
flat
|
||||
small
|
||||
:color="buttonColor"
|
||||
class="circle-button pa-0 mx-0 filter-apply-button"
|
||||
:icon="buttonIcon"
|
||||
@click.stop="updateFilterInfo(filterIndex, seriesIndex)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { chartData } from '@/data/task/ChartsManagement'
|
||||
import { taskInfo } from '@/data/task/TaskInfo'
|
||||
import api from '@/data/api'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import { IIRFilter } from '@/data/task/filter/IIRFilter.js'
|
||||
|
||||
export default {
|
||||
name: 'canvas-chart-filter-individual-filter',
|
||||
props: {
|
||||
chartID: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
seriesIndex: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
filterIndex: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapFields('taskContent', [
|
||||
'filter',
|
||||
]),
|
||||
buttonIcon () {
|
||||
if (this.data.series[this.seriesIndex] != null) {
|
||||
return this.data.series[this.seriesIndex].filter[this.filterIndex].filter != null ? 'fa fa-stop' : 'fa fa-play'
|
||||
}
|
||||
return 'fa fa-play'
|
||||
},
|
||||
buttonColor () {
|
||||
if (this.data.series[this.seriesIndex] != null) {
|
||||
return this.data.series[this.seriesIndex].filter[this.filterIndex].filter != null ? 'danger' : 'primary'
|
||||
}
|
||||
return 'fa fa-play'
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
data: chartData.getAllChartsData()[this.chartID],
|
||||
selectFilter: {
|
||||
id: 1,
|
||||
name: 'notch',
|
||||
},
|
||||
order: 20,
|
||||
freq0: 0,
|
||||
freq1: 0,
|
||||
freq2: 0,
|
||||
optionFilter: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'notch',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'lowpass',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'highpass',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'bandstop',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'bandpass',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async updateFilterInfo (_filterIndex, _seriesIndex) {
|
||||
let closeFilter = false
|
||||
if (this.data.series[_seriesIndex].filter[_filterIndex].filter != null) {
|
||||
this.data.series[_seriesIndex].filter[_filterIndex].filter = null
|
||||
closeFilter = true
|
||||
}
|
||||
if (closeFilter) {
|
||||
return false
|
||||
}
|
||||
let fs = 0
|
||||
let sos = []
|
||||
const deviceID = this.data.series[_seriesIndex].yAxisSource[0]
|
||||
// const _fs = taskInfo.getDeviceInfo(deviceID).parameterSet.SAMPLE_RATE
|
||||
const _fs = 1000
|
||||
const _chNum = taskInfo.getDeviceInfo(deviceID).parameterSet.CH_NUMBER
|
||||
// console.log(_fs, _chNum)
|
||||
if (fs !== _fs) {
|
||||
fs = _fs
|
||||
const ret = await api.analysis.IIRFilter({
|
||||
type: this.selectFilter.name,
|
||||
order: this.order,
|
||||
fs: parseInt(_fs / _chNum),
|
||||
f0: parseInt(this.freq0),
|
||||
f1: parseInt(this.freq1),
|
||||
f2: parseInt(this.freq2),
|
||||
})
|
||||
|
||||
if (ret.status !== 200) {
|
||||
return false
|
||||
}
|
||||
|
||||
const _sosRet = ret.data.split('/')
|
||||
const _sos = []
|
||||
_sosRet.forEach((v, vi) => {
|
||||
const _tmp = v.split(',')
|
||||
const _arr = []
|
||||
_tmp.forEach(s => {
|
||||
_arr.push(parseFloat(s))
|
||||
})
|
||||
_sos.push(_arr)
|
||||
})
|
||||
sos = _sos
|
||||
}
|
||||
this.data.series[_seriesIndex].filter[_filterIndex].type = this.selectFilter.name
|
||||
this.data.series[_seriesIndex].filter[_filterIndex].order = this.order
|
||||
// sampling rate changed by channel number
|
||||
this.data.series[_seriesIndex].filter[_filterIndex].fs = parseInt(_fs / _chNum)
|
||||
this.data.series[_seriesIndex].filter[_filterIndex].f0 = parseInt(this.freq0)
|
||||
this.data.series[_seriesIndex].filter[_filterIndex].f1 = parseInt(this.freq1)
|
||||
this.data.series[_seriesIndex].filter[_filterIndex].f2 = parseInt(this.freq2)
|
||||
this.data.series[_seriesIndex].filter[_filterIndex].sos = sos
|
||||
this.data.series[_seriesIndex].filter[_filterIndex].filter = IIRFilter.init(sos)
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.selectFilter = this.optionFilter.find(item => item.name === this.data.series[this.seriesIndex].filter[this.filterIndex].type)
|
||||
this.freq0 = this.data.series[this.seriesIndex].filter[this.filterIndex].f0
|
||||
this.freq1 = this.data.series[this.seriesIndex].filter[this.filterIndex].f1
|
||||
this.freq2 = this.data.series[this.seriesIndex].filter[this.filterIndex].f2
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
.filter-input {
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.freq-input {
|
||||
max-width: 80px;
|
||||
}
|
||||
|
||||
.order-input {
|
||||
max-width: 50px;
|
||||
}
|
||||
|
||||
.filter-apply-button {
|
||||
max-width: 25px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,90 +1,45 @@
|
||||
<template>
|
||||
<div>
|
||||
<va-tree-root>
|
||||
<va-tree-category isOpen label="Products">
|
||||
<va-tree-node
|
||||
v-for="product in products"
|
||||
:key="product.id"
|
||||
>
|
||||
<div class="flex row align--center">
|
||||
<va-input v-model="product.name" class="mb-0"/>
|
||||
<va-icon
|
||||
name="ion ion-md-close"
|
||||
color="info"
|
||||
class="ml-2 pa-1 shrink"
|
||||
style="cursor: pointer;"
|
||||
@click.native="removeProduct(product)"
|
||||
/>
|
||||
</div>
|
||||
</va-tree-node>
|
||||
<va-tree-node>
|
||||
<va-button class="mb-2" @click="addProduct()">
|
||||
Add new product
|
||||
</va-button>
|
||||
</va-tree-node>
|
||||
</va-tree-category>
|
||||
|
||||
<va-tree-category label="Electronics">
|
||||
<va-tree-node v-for="electronic in electronics" :key="electronic.id">
|
||||
<va-input v-model="electronic.name" class="mb-0"/>
|
||||
</va-tree-node>
|
||||
</va-tree-category>
|
||||
|
||||
<va-tree-category isOpen label="Products">
|
||||
<va-tree-node
|
||||
v-for="product in products"
|
||||
:key="product.id"
|
||||
>
|
||||
<div class="flex row align--center">
|
||||
<va-input v-model="product.name" class="mb-0"/>
|
||||
<va-icon
|
||||
name="ion ion-md-close"
|
||||
color="info"
|
||||
class="ml-2 pa-1 shrink"
|
||||
style="cursor: pointer;"
|
||||
@click.native="removeProduct(product)"
|
||||
/>
|
||||
</div>
|
||||
</va-tree-node>
|
||||
<va-tree-node>
|
||||
<va-button class="mb-2" @click="addProduct()">
|
||||
Add new product
|
||||
</va-button>
|
||||
</va-tree-node>
|
||||
</va-tree-category>
|
||||
|
||||
</va-tree-root>
|
||||
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
|
||||
<div class="flex sm9 xl9 md9 xs9 px-0 mx-0">
|
||||
<p class="display-6">filter<p/>
|
||||
</div>
|
||||
<div class="flex sm3 xl3 md3 xs3 pa-0 ma-0">
|
||||
<va-toggle v-model="data.filter.open" small @click.native="() => {}"/>
|
||||
</div>
|
||||
<!-- <div class="flex sm12 xl12 md12 xs12 px-0 mx-0">
|
||||
<p class="display-6">Protect recording channels<p/>
|
||||
</div>
|
||||
<div class="flex sm12 xl12 md12 xs12 px-0 mx-0">
|
||||
<va-radio-button
|
||||
v-for="(option, index) in optionProtectRec"
|
||||
:key="index"
|
||||
v-model="selectProtectRec"
|
||||
:option="optionProtectRec[index]"
|
||||
:label="optionProtectRec[index]"
|
||||
/>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { chartData } from '../../../../data/task/ChartsManagement'
|
||||
|
||||
export default {
|
||||
name: 'canvas-chart-setting',
|
||||
props: {
|
||||
chartID: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
gridNumber: 8,
|
||||
electronics: [
|
||||
{ id: 1, name: 'Cellphones' },
|
||||
{ id: 2, name: 'Camera Body Kits' },
|
||||
{ id: 3, name: 'External HDDs' },
|
||||
],
|
||||
products: [
|
||||
{ id: 4, name: 'Cables' },
|
||||
{ id: 5, name: 'Monitors' },
|
||||
{ id: 6, name: 'Keyboards' },
|
||||
],
|
||||
data: chartData.getAllChartsData()[this.chartID],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addProduct () {
|
||||
this.products.push({
|
||||
id: Math.floor(Math.random() * 100000),
|
||||
name: 'New product',
|
||||
})
|
||||
},
|
||||
removeProduct (product) {
|
||||
this.products = this.products.filter(productToFilter => productToFilter !== product)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,75 +1,87 @@
|
||||
<template>
|
||||
<div style="height: 350px; overflow-y: scroll; overflow-x: hidden;">
|
||||
<div>
|
||||
<div class="flex row align--center">
|
||||
<div class="flex md3 xl3 xs3 sm3">
|
||||
<va-select
|
||||
small
|
||||
:label="'X SOURCE'"
|
||||
v-model="deviceSelectX"
|
||||
textBy="name"
|
||||
:options="deviceOptions"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex md3 xl3 xs3 sm3">
|
||||
<va-select
|
||||
:on-change="channelSelectXChange()"
|
||||
:label="'X CHANNEL'"
|
||||
v-model="channelSelectX"
|
||||
textBy="channel"
|
||||
:options="channelOptionsX"
|
||||
:disabled="channelSelectDisableX"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex md3 xl3 xs3 sm3">
|
||||
<va-select
|
||||
:label="'Y SOURCE'"
|
||||
v-model="deviceSelectY"
|
||||
textBy="name"
|
||||
:options="deviceOptions"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex md3 xl3 xs3 sm3">
|
||||
<va-select
|
||||
:on-change="channelSelectYChange()"
|
||||
:label="'Y CHANNEL'"
|
||||
v-model="channelSelectY"
|
||||
textBy="channel"
|
||||
:options="channelOptionsY"
|
||||
:disabled="channelSelectDisableY"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex md3 xl3 xs3 sm3">
|
||||
<va-select
|
||||
:label="'SubPlot'"
|
||||
v-model="gridSelection"
|
||||
textBy="value"
|
||||
:options="gridOptions"
|
||||
@click.enter="updateGridOptions()"
|
||||
/>
|
||||
</div>
|
||||
<va-button :disabled="sourceAddStatus" class="flex md3 xl3 xs3 sm3 pa-1" @click="addRegisterDeviceChannel(gridSelection.id)" >
|
||||
Add
|
||||
</va-button><span class="ml-2" style="color: red;">{{error}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<va-tree-root>
|
||||
<va-tree-category
|
||||
style="font-size: 20px;"
|
||||
v-for="grid in grids"
|
||||
:key="grid.index"
|
||||
:label="'GRID ' + grid.index">
|
||||
:label="'Subplot ' + grid.index">
|
||||
<va-tree-node
|
||||
v-for="series in grid.series"
|
||||
v-for="series in gridSource[grid.index]"
|
||||
:key="series.name"
|
||||
>
|
||||
<div class="flex row align--center">
|
||||
<va-badge class="mb-0" style="font-size: 14px;" color="primary">{{series.name}}</va-badge>
|
||||
<va-badge class="mb-0" style="font-size: 14px;" color="primary" outline>{{series.xAxis}}</va-badge>
|
||||
<va-badge class="mb-0" style="font-size: 14px;" color="primary" outline>{{series.yAxis}}</va-badge>
|
||||
<va-icon
|
||||
<!-- <va-icon
|
||||
name="ion ion-md-close"
|
||||
color="info"
|
||||
class="ml-2 pa-1 shrink"
|
||||
style="cursor: pointer;"
|
||||
@click.native="removeProduct(product)"
|
||||
/>
|
||||
</div>
|
||||
</va-tree-node>
|
||||
<va-tree-node>
|
||||
<div class="flex row align--center">
|
||||
<div class="flex md6 xl6 xs6 sm6">
|
||||
<va-select
|
||||
small
|
||||
:label="'X DEVICE'"
|
||||
v-model="deviceSelectX"
|
||||
textBy="name"
|
||||
:options="deviceOptions"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex md6 xl6 xs6 sm6">
|
||||
<va-select
|
||||
:on-change="channelSelectXChange()"
|
||||
:label="'X CHANNEL'"
|
||||
v-model="channelSelectX"
|
||||
textBy="channel"
|
||||
:options="channelOptionsX"
|
||||
:disabled="channelSelectDisableX"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex md6 xl6 xs6 sm6">
|
||||
<va-select
|
||||
:label="'Y DEVICE'"
|
||||
v-model="deviceSelectY"
|
||||
textBy="name"
|
||||
:options="deviceOptions"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex md6 xl6 xs6 sm6">
|
||||
<va-select
|
||||
:on-change="channelSelectYChange()"
|
||||
:label="'Y CHANNEL'"
|
||||
v-model="channelSelectY"
|
||||
textBy="channel"
|
||||
:options="channelOptionsY"
|
||||
:disabled="channelSelectDisableY"
|
||||
/>
|
||||
</div>
|
||||
<va-button :disabled="sourceAddStatus" class="flex md6 xl6 xs6 sm6 pa-1" @click="addRegisterDeviceChannel(grid.index)" >
|
||||
Add
|
||||
</va-button>
|
||||
/> -->
|
||||
</div>
|
||||
</va-tree-node>
|
||||
</va-tree-category>
|
||||
|
||||
</va-tree-root>
|
||||
<va-button @click="addGrid()">
|
||||
Add Subplot
|
||||
</va-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -93,17 +105,16 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
error: '',
|
||||
gridSelection: '',
|
||||
gridOptions: [
|
||||
{
|
||||
id: 0,
|
||||
value: 0,
|
||||
},
|
||||
],
|
||||
grids: this.gridInfo,
|
||||
electronics: [
|
||||
{ id: 1, name: 'Cellphones' },
|
||||
{ id: 2, name: 'Camera Body Kits' },
|
||||
{ id: 3, name: 'External HDDs' },
|
||||
],
|
||||
products: [
|
||||
{ id: 4, name: 'Cables' },
|
||||
{ id: 5, name: 'Monitors' },
|
||||
{ id: 6, name: 'Keyboards' },
|
||||
],
|
||||
gridSource: chartData.getAllChartsData()[this.chartID].gridSource,
|
||||
channelSelectX: '',
|
||||
channelOptionsX: [],
|
||||
channelSelectY: '',
|
||||
@@ -114,6 +125,7 @@ export default {
|
||||
deviceSelectY: '',
|
||||
deviceOptions: taskInfo.getDeviceList(),
|
||||
sourceAddStatus: true,
|
||||
sourceList: [],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -136,9 +148,40 @@ export default {
|
||||
// console.log(index, element)
|
||||
}
|
||||
})
|
||||
const axisChannelSet = taskInfo.getDeviceInfo(this.deviceSelectX.id).parameterSet.AXIS_CH.toString(2).split('').reverse()
|
||||
axisChannelSet.forEach((element, index) => {
|
||||
if (parseInt(element) === 1) {
|
||||
if (index === 0) {
|
||||
channelOptions.push({
|
||||
id: 257,
|
||||
channel: 'X-AXIS',
|
||||
})
|
||||
} else if (index === 1) {
|
||||
channelOptions.push({
|
||||
id: 258,
|
||||
channel: 'Y-AXIS',
|
||||
})
|
||||
} else if (index === 2) {
|
||||
channelOptions.push({
|
||||
id: 259,
|
||||
channel: 'Z-AXIS',
|
||||
})
|
||||
} else if (index === 3) {
|
||||
channelOptions.push({
|
||||
id: 260,
|
||||
channel: 'M-AXIS',
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
this.channelSelectDisableX = false
|
||||
} else if (taskInfo.getDeviceInfo(this.deviceSelectX.id).info.library_name.indexOf('Elite') >= 0) {
|
||||
const channelSet = taskInfo.getDeviceInfo(this.deviceSelectX.id).parameterSet.CHANNEL_LABEL
|
||||
let channelSet
|
||||
if (taskInfo.getDeviceInfo(this.deviceSelectX.id).info.library_name === 'EliteEIS' && taskInfo.getDeviceInfo(this.deviceSelectX.id).parameterSet.MODE === 0) {
|
||||
channelSet = ['Zimag_Raw', 'Zreal_Raw', 'Frequency', 'Cycle', 'Zimag', 'Zreal', 'Impedance', 'Phase', 'Current', 'Level gain']
|
||||
} else {
|
||||
channelSet = taskInfo.getDeviceInfo(this.deviceSelectX.id).parameterSet.CHANNEL_LABEL
|
||||
}
|
||||
// console.log(channelSet)
|
||||
channelSet.forEach((element, index) => {
|
||||
channelOptions.push({
|
||||
@@ -162,7 +205,7 @@ export default {
|
||||
this.channelSelectDisableY = true
|
||||
} else if (taskInfo.getDeviceInfo(this.deviceSelectY.id).info.library_name.indexOf('Neulive') >= 0) {
|
||||
const channelSet = taskInfo.getDeviceInfo(this.deviceSelectY.id).parameterSet.RECORDING_CH.toString(2).split('').reverse()
|
||||
console.log(channelSet)
|
||||
// console.log(channelSet)
|
||||
channelSet.forEach((element, index) => {
|
||||
if (parseInt(element) > 0) {
|
||||
channelOptions.push({
|
||||
@@ -172,10 +215,41 @@ export default {
|
||||
// console.log(index, element)
|
||||
}
|
||||
})
|
||||
const axisChannelSet = taskInfo.getDeviceInfo(this.deviceSelectY.id).parameterSet.AXIS_CH.toString(2).split('').reverse()
|
||||
axisChannelSet.forEach((element, index) => {
|
||||
if (parseInt(element) === 1) {
|
||||
if (index === 0) {
|
||||
channelOptions.push({
|
||||
id: 257,
|
||||
channel: 'X-AXIS',
|
||||
})
|
||||
} else if (index === 1) {
|
||||
channelOptions.push({
|
||||
id: 258,
|
||||
channel: 'Y-AXIS',
|
||||
})
|
||||
} else if (index === 2) {
|
||||
channelOptions.push({
|
||||
id: 259,
|
||||
channel: 'Z-AXIS',
|
||||
})
|
||||
} else if (index === 3) {
|
||||
channelOptions.push({
|
||||
id: 260,
|
||||
channel: 'M-AXIS',
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
this.channelSelectDisableY = false
|
||||
} else if (taskInfo.getDeviceInfo(this.deviceSelectY.id).info.library_name.indexOf('Elite') >= 0) {
|
||||
const channelSet = taskInfo.getDeviceInfo(this.deviceSelectY.id).parameterSet.CHANNEL_LABEL
|
||||
console.log(channelSet)
|
||||
let channelSet
|
||||
if (taskInfo.getDeviceInfo(this.deviceSelectY.id).info.library_name === 'EliteEIS' && taskInfo.getDeviceInfo(this.deviceSelectY.id).parameterSet.MODE === 0) {
|
||||
channelSet = ['Zimag_Raw', 'Zreal_Raw', 'Frequency', 'Cycle', 'Zimag', 'Zreal', 'Impedance', 'Phase', 'Current', 'Level gain']
|
||||
} else {
|
||||
channelSet = taskInfo.getDeviceInfo(this.deviceSelectY.id).parameterSet.CHANNEL_LABEL
|
||||
}
|
||||
// console.log(channelSet)
|
||||
channelSet.forEach((element, index) => {
|
||||
channelOptions.push({
|
||||
id: index + 1,
|
||||
@@ -193,6 +267,15 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateGridOptions () {
|
||||
this.gridOptions = []
|
||||
for (let i = 0; i < this.grids.length; i++) {
|
||||
this.gridOptions.push({
|
||||
id: i,
|
||||
value: String(i),
|
||||
})
|
||||
}
|
||||
},
|
||||
channelSelectYChange: function () {
|
||||
this.checkSourceAddStatus()
|
||||
},
|
||||
@@ -206,6 +289,7 @@ export default {
|
||||
this.channelOptionsY = []
|
||||
this.deviceSelectX = ''
|
||||
this.deviceSelectY = ''
|
||||
this.gridSelection = ''
|
||||
},
|
||||
addRegisterDeviceChannel: function (gridIndex) {
|
||||
let deviceNameX
|
||||
@@ -217,23 +301,66 @@ export default {
|
||||
if (this.deviceSelectX.name.indexOf('Neulive') >= 0) {
|
||||
deviceNameX = 'Neulive'
|
||||
} else if (this.deviceSelectX.name.indexOf('Elite') >= 0) {
|
||||
deviceNameX = 'Elite'
|
||||
if (taskInfo.getDeviceInfo(this.deviceSelectX.id).info.library_name === 'EliteEIS') {
|
||||
deviceNameX = 'EliteEIS'
|
||||
} else {
|
||||
deviceNameX = 'Elite'
|
||||
}
|
||||
} else if (this.deviceSelectX.name.indexOf('Time') >= 0) {
|
||||
deviceNameX = 'Time'
|
||||
}
|
||||
if (this.deviceSelectY.name.indexOf('Neulive') >= 0) {
|
||||
deviceNameY = 'Neulive'
|
||||
} else if (this.deviceSelectY.name.indexOf('Elite') >= 0) {
|
||||
deviceNameY = 'Elite'
|
||||
if (taskInfo.getDeviceInfo(this.deviceSelectY.id).info.library_name === 'EliteEIS') {
|
||||
deviceNameY = 'EliteEIS'
|
||||
} else {
|
||||
deviceNameY = 'Elite'
|
||||
}
|
||||
} else if (this.deviceSelectY.name.indexOf('Time') >= 0) {
|
||||
deviceNameY = 'Time'
|
||||
}
|
||||
chartData.register(this.chartID, gridIndex, deviceNameX, deviceIDX, channelX, deviceNameY, deviceIDY, channelY, null)
|
||||
console.log(this.deviceSelectX, this.channelSelectX, this.deviceSelectY, this.channelSelectY)
|
||||
// console.log(this.chartID, gridIndex, deviceNameX, deviceIDX, channelX, deviceNameY, deviceIDY, channelY, null)
|
||||
// console.log(this.deviceSelectX, this.channelSelectX, this.deviceSelectY, this.channelSelectY)
|
||||
if (deviceNameX !== 'Time') {
|
||||
this.sourceList.push([this.deviceSelectX.name, deviceIDX, channelX].toString())
|
||||
}
|
||||
if (deviceNameY !== 'Time') {
|
||||
this.sourceList.push([this.deviceSelectY.name, deviceIDY, channelY].toString())
|
||||
}
|
||||
this.sourceAddStatus = true
|
||||
this.clearSelectOptions()
|
||||
},
|
||||
addGrid () {
|
||||
chartData.updateGridList(this.chartID, chartData.getAllChartsData()[this.chartID].grid.length + 1)
|
||||
this.grids = chartData.getAllChartsData()[this.chartID].grid
|
||||
this.treeKey++
|
||||
this.gridOptions = []
|
||||
for (let i = 0; i < this.grids.length; i++) {
|
||||
this.gridOptions.push({
|
||||
id: i,
|
||||
value: String(i),
|
||||
})
|
||||
}
|
||||
// console.log(chartData.getAllChartsData()[this.chartID])
|
||||
},
|
||||
checkSourceAddStatus () {
|
||||
if (this.sourceList.indexOf([this.deviceSelectX.name, this.deviceSelectX.id, this.channelSelectX.id].toString()) >= 0) {
|
||||
this.error = 'The same source has been selected in a subplot.'
|
||||
this.sourceAddStatus = true
|
||||
return
|
||||
}
|
||||
if (this.sourceList.indexOf([this.deviceSelectY.name, this.deviceSelectY.id, this.channelSelectY.id].toString()) >= 0) {
|
||||
this.sourceAddStatus = true
|
||||
this.error = 'The same source has been selected in a subplot.'
|
||||
return
|
||||
}
|
||||
this.error = ''
|
||||
if (this.gridSelection.id == null) {
|
||||
this.sourceAddStatus = true
|
||||
return
|
||||
}
|
||||
if (this.channelSelectX.id != null && this.channelSelectY.id != null) {
|
||||
this.sourceAddStatus = false
|
||||
} else if (this.channelSelectX.id != null && this.deviceSelectY.id < 0) {
|
||||
@@ -253,6 +380,8 @@ export default {
|
||||
removeProduct (product) {
|
||||
this.products = this.products.filter(productToFilter => productToFilter !== product)
|
||||
},
|
||||
mounted () {
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
<template>
|
||||
<div class="flex" :class="cardclass">
|
||||
<va-card>
|
||||
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="sketchmapData" :auto-resize="true"></chart>
|
||||
</va-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapActions } from 'vuex'
|
||||
import { taskInfo } from '@/data/task/TaskInfo'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import deviceTypes from '@/store/modules/device/types'
|
||||
|
||||
export default {
|
||||
name: 'TriggerChart',
|
||||
components: {
|
||||
},
|
||||
computed: {
|
||||
...mapFields('device', [
|
||||
'triggerList',
|
||||
'allChannels',
|
||||
]),
|
||||
},
|
||||
props: {
|
||||
mac: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
timer: null,
|
||||
cardclass: ['xs12', 'md12', 'xl12', 'sm12'],
|
||||
cardheight: '400px',
|
||||
cardwidth: 'auto',
|
||||
sketchmapData: {},
|
||||
activeChannels: [],
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
async '+/data-server/trigger_manager/#' (data, topic) {
|
||||
const mes = new TextDecoder('utf-8').decode(data)
|
||||
const topicSplit = topic.split('/')
|
||||
const baseIndex = topicSplit.indexOf('trigger_manager')
|
||||
const actionIndex = baseIndex + 1
|
||||
const action = topicSplit[actionIndex]
|
||||
const macIndex = baseIndex + 2
|
||||
let _mac
|
||||
if (topicSplit.length - 1 >= macIndex) {
|
||||
_mac = topicSplit[macIndex]
|
||||
}
|
||||
if (_mac === this.mac) {
|
||||
switch (action) {
|
||||
case 'set_parameter': // control_ID/data-server/trigger_manager/set_parameter/device_mac
|
||||
await this.initActiveChannels()
|
||||
this.initChart()
|
||||
break
|
||||
case 'runtime': // control_ID/data-server/trigger_manager/runtime/device_mac
|
||||
this.updateTimer(mes)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
'+/data-server/trigger_runtime/#' (data, topic) { // control_ID/data-server/trigger_runtime/pin_event/device_mac/channel
|
||||
const mes = new TextDecoder('utf-8').decode(data)
|
||||
const topicSplit = topic.split('/')
|
||||
const baseIndex = topicSplit.indexOf('trigger_runtime')
|
||||
const actionIndex = baseIndex + 1
|
||||
const action = topicSplit[actionIndex]
|
||||
const macIndex = baseIndex + 2
|
||||
const channelIndex = baseIndex + 3
|
||||
let _mac
|
||||
if (topicSplit.length - 1 >= macIndex) {
|
||||
_mac = topicSplit[macIndex]
|
||||
}
|
||||
let channel
|
||||
if (topicSplit.length - 1 >= channelIndex) {
|
||||
channel = parseInt(topicSplit[channelIndex])
|
||||
}
|
||||
let mesJson
|
||||
if (_mac === this.mac) {
|
||||
switch (action) {
|
||||
case 'pin_event':
|
||||
mesJson = JSON.parse(mes)
|
||||
this.addSketchMapData(mesJson.timestamp, mesJson.status === 'high' ? 3.3 : 0.0, channel)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
addSketchMapData (timestamp, val, channel) {
|
||||
const gridIndex = this.activeChannels.indexOf(channel)
|
||||
this.sketchmapData.series[gridIndex].data.push([parseInt(timestamp), val])
|
||||
if (this.sketchmapData.series[gridIndex].data.length > 1000) {
|
||||
this.sketchmapData.series[gridIndex].data.shift()
|
||||
}
|
||||
},
|
||||
mqttSub: function (val) {
|
||||
this.$mqtt.subscribe(val)
|
||||
},
|
||||
mqttUnSub: function (val) {
|
||||
this.$mqtt.unsubscribe(val)
|
||||
},
|
||||
makeGrid (index, length) {
|
||||
const _height = (100 / length) - 2 + '%'
|
||||
const _top = index * (100 / length) + 2 + '%'
|
||||
const _left = '0%'
|
||||
const _right = '3%'
|
||||
return {
|
||||
index: index,
|
||||
top: _top,
|
||||
height: _height,
|
||||
left: _left,
|
||||
right: _right,
|
||||
containLabel: true,
|
||||
}
|
||||
},
|
||||
makeSeries (xAxisIndex, yAxisIndex) {
|
||||
return {
|
||||
type: 'line',
|
||||
step: 'start',
|
||||
data: [],
|
||||
animation: false,
|
||||
xAxisIndex: xAxisIndex,
|
||||
yAxisIndex: yAxisIndex,
|
||||
}
|
||||
},
|
||||
makeXAxis (gridIndex) {
|
||||
return {
|
||||
show: false,
|
||||
type: 'time',
|
||||
gridIndex: gridIndex,
|
||||
min: 'dataMin',
|
||||
max: 'dataMax',
|
||||
}
|
||||
},
|
||||
makeYAxis (gridIndex) {
|
||||
return {
|
||||
type: 'value',
|
||||
gridIndex: gridIndex,
|
||||
splitNumber: 1,
|
||||
splitLine: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
formatter: function (value) {
|
||||
return value + 'V'
|
||||
},
|
||||
},
|
||||
min: 'dataMin',
|
||||
max: 'dataMax',
|
||||
}
|
||||
},
|
||||
async initActiveChannels () {
|
||||
this.activeChannels = await this.deviceTriggerGetActiveChannels({ mac: this.mac })
|
||||
},
|
||||
initChart () {
|
||||
this.clearChart()
|
||||
const currImplementedChannels = this.activeChannels.filter(ch => ch < 4) // [TODO] now only open 4 channels (2022/01/05)
|
||||
const gridLength = currImplementedChannels.length
|
||||
for (let gridIndex = 0; gridIndex < gridLength; gridIndex++) {
|
||||
this.sketchmapData.grid.push(this.makeGrid(gridIndex, gridLength))
|
||||
this.sketchmapData.xAxis.push(this.makeXAxis(gridIndex))
|
||||
this.sketchmapData.yAxis.push(this.makeYAxis(gridIndex))
|
||||
this.sketchmapData.series.push(this.makeSeries(gridIndex, gridIndex))
|
||||
if (gridIndex === gridLength - 1) {
|
||||
this.sketchmapData.xAxis[gridLength - 1].show = true
|
||||
}
|
||||
}
|
||||
},
|
||||
clearChart () {
|
||||
this.sketchmapData = {
|
||||
xAxis: [],
|
||||
yAxis: [],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
series: [],
|
||||
grid: [],
|
||||
}
|
||||
},
|
||||
updateTimer (status) {
|
||||
if (status === 'start') {
|
||||
if (this.timer === null) {
|
||||
this.timer = setInterval(this.updateCurrentTime, 1000)
|
||||
}
|
||||
} else {
|
||||
clearInterval(this.timer)
|
||||
this.timer = null
|
||||
}
|
||||
},
|
||||
updateCurrentTime () {
|
||||
const currTime = Date.now()
|
||||
this.sketchmapData.xAxis.forEach(axis => {
|
||||
axis.min = currTime - 10000 // 10000ms = 10s
|
||||
axis.max = currTime + 1000
|
||||
})
|
||||
},
|
||||
|
||||
...mapActions('device', [deviceTypes.trigger.getActiveChannels]),
|
||||
},
|
||||
async mounted () {
|
||||
this.mqttSub(taskInfo.getTaskInfo().controllerID + '/data-server/trigger_manager/#')
|
||||
this.mqttSub(taskInfo.getTaskInfo().controllerID + '/data-server/trigger_runtime/#')
|
||||
await this.initActiveChannels()
|
||||
this.initChart()
|
||||
this.updateTimer('start')
|
||||
},
|
||||
destroyed () {
|
||||
this.mqttUnSub(taskInfo.getTaskInfo().controllerID + '/data-server/trigger_manager/#')
|
||||
this.mqttUnSub(taskInfo.getTaskInfo().controllerID + '/data-server/trigger_runtime/#')
|
||||
this.clearChart()
|
||||
this.updateTimer('stop')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -10,17 +10,17 @@
|
||||
@ok="remove()"
|
||||
/>
|
||||
<va-accordion v-for="device in deviceList" :key="device.id">
|
||||
<va-collapse class="mb-2">
|
||||
<va-collapse class="mb-2" :isOpenDefault='true'>
|
||||
<span slot="header" >
|
||||
<va-item :key="device.id" class="pa-0 ma-0"
|
||||
>
|
||||
<va-icon
|
||||
<!-- <va-icon
|
||||
name="ion ion-md-close"
|
||||
color="danger"
|
||||
class="ml-0 mr-3 pa-0 shrink"
|
||||
style="cursor: pointer;"
|
||||
@click.native.stop="removeCheck(device)"
|
||||
/>
|
||||
/> -->
|
||||
|
||||
<va-item-section avatar class="ml-0">
|
||||
<va-avatar style="border-radius: 0;">
|
||||
@@ -28,26 +28,53 @@
|
||||
</va-avatar>
|
||||
</va-item-section>
|
||||
|
||||
<va-item-section class="ml-3">
|
||||
<va-item-section class="ml-3" caption>
|
||||
<va-item-label>
|
||||
{{ device.name }}
|
||||
<va-button @click.stop="start(device)" v-if="!device.isSync" class="px-2 py-0 mr-0" color="success" small>START</va-button>
|
||||
<va-button @click.stop="stop(device)" v-if="device.isSync" :disabled="device.stopping" class="px-2 py-0 mr-0" color="danger" small>STOP</va-button>
|
||||
</va-item-label>
|
||||
|
||||
<va-item-label caption>
|
||||
{{ device.address }}
|
||||
</va-item-label>
|
||||
|
||||
</va-item-section>
|
||||
|
||||
<va-item-section class="mr-3" v-if="device.type == 'Neulive'" side>
|
||||
<i v-if="!device.sdCardStatus" class="i-sd-card mr-3" style="width: 1rem; height: 1rem;"></i>
|
||||
<!-- <va-icon
|
||||
name="fas fa-sd-card"
|
||||
:color="(device.sdCardStatus === true) ? 'primary' : 'grey'"
|
||||
class="mr-3"
|
||||
@click.native.stop="sdCardStatus(device)"
|
||||
>
|
||||
</va-icon> -->
|
||||
<va-icon
|
||||
size="1rem"
|
||||
:name="(device.transmission_type === 0) ? 'fa fa-bluetooth-b' : 'fa fa-usb'"
|
||||
color="primary"
|
||||
>
|
||||
</va-icon>
|
||||
</va-item-section>
|
||||
</va-item>
|
||||
|
||||
<va-item class="pa-0 ma-0 mt-2">
|
||||
<va-item-section class="ml-3">
|
||||
<va-item-label>
|
||||
<va-button @click.stop="start(device)" v-if="(device.type == 'Neulive' && !device.isSync && !device.isStimulate) || (device.type == 'Elite' && !device.isSync)" class="px-2 py-0 mr-0" color="success" small>START</va-button>
|
||||
<va-button @click.stop="stop(device)" v-if="(device.type == 'Neulive' && (device.isSync || device.isStimulate)) || (device.type == 'Elite' && device.isSync)" class="px-2 py-0 mr-0" color="danger" small>STOP</va-button>
|
||||
<va-button id="detectButton" @click.stop="detect(device)" v-if="device.type == 'Elite'" color="primary" class="px-2 py-0 mr-0" small>DETECT</va-button>
|
||||
<va-button @click.stop="record(device)" v-if="device.type == 'Neulive' && !device.isSync" color="primary" class="px-2 py-0 mr-0 no-dark-style-va-button" small>RECORD</va-button>
|
||||
<va-button @click.stop="stopRecord(device)" v-if="device.type == 'Neulive' && device.isSync" color="danger" class="px-2 py-0 mr-0 no-dark-style-va-button" small>STOP REC</va-button>
|
||||
<va-button @click.stop="stimulate(device)" v-if="device.type == 'Neulive' && !device.isStimulate" color="warning" class="px-2 py-0 mr-0 no-dark-style-va-button" small>STIMULATE</va-button>
|
||||
<va-button @click.stop="stopStimulate(device)" v-if="device.type == 'Neulive' && device.isStimulate" color="danger" class="px-2 py-0 mr-0" small>STOP STI</va-button>
|
||||
<va-button @click.stop="fastSettle(device)" v-if="device.type == 'Neulive'" color="info" class="px-2 py-0 mr-0 no-dark-style-va-button" small>R</va-button>
|
||||
</va-item-label>
|
||||
</va-item-section>
|
||||
</va-item>
|
||||
</span>
|
||||
<div slot="body">
|
||||
<div class="mt-0 mb-0" style="height: 350px; overflow-y: scroll; overflow-x: hidden;" :key="'detail' + device.id">
|
||||
<div style="text-align: center;">
|
||||
<va-button @click.stop="generateChart(device)" class="pl-2 pr-2 mr-0" small>GENERATE MAPPING CHART</va-button>
|
||||
</div>
|
||||
<div class="mt-0 mb-0" style="height: 60vh; overflow-y: scroll; overflow-x: hidden;" :key="'detail' + device.id">
|
||||
<!-- <div style="text-align: center;">
|
||||
<va-button @click.stop="generateChart(device)" class="pl-2 pr-2 mr-0 no-dark-style-va-button" small>GENERATE MAPPING CHART</va-button>
|
||||
</div> -->
|
||||
<div>
|
||||
<file-control-window :ref="'fcwindow_ref'" :deviceID="device.id" class="pl-0 pr-0" />
|
||||
</div>
|
||||
@@ -55,7 +82,7 @@
|
||||
<elite-parameter-window :ref="'epwindow_ref'" :deviceID="device.id" class="pl-0 pr-0" />
|
||||
</div>
|
||||
<div v-if="device.type == 'Neulive'">
|
||||
<neulive-parameter-window :ref="'npwindow_ref'" :deviceID="device.id" class="pl-0 pr-0" />
|
||||
<neulive-parameter-window :ref="'npwindow_ref'" :deviceID="device.id" class="pl-0 pr-0" @record="record_start(device)" @record_stop="record_stop(device)"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,6 +96,8 @@
|
||||
import EliteParameterWindow from '../parameter/EliteParameterWindow'
|
||||
import NeuliveParameterWindow from '../parameter/NeuliveParameterWindow'
|
||||
import FileControlWindow from '../meta/FileControlWindow'
|
||||
import { mapActions } from 'vuex'
|
||||
import types from '@/store/modules/task/content/types'
|
||||
|
||||
export default {
|
||||
name: 'TaskDeviceList',
|
||||
@@ -93,6 +122,12 @@ export default {
|
||||
computed: {
|
||||
},
|
||||
methods: {
|
||||
sdCardStatus: function (device) {
|
||||
this.$emit('sd_card_status', {
|
||||
id: device.id,
|
||||
sdCardStatus: device.sdCardStatus,
|
||||
})
|
||||
},
|
||||
removeCheck: function (device) {
|
||||
this.selectDevice = device
|
||||
this.showDeleteModal = true
|
||||
@@ -100,16 +135,44 @@ export default {
|
||||
remove: function () {
|
||||
this.$emit('remove', this.selectDevice)
|
||||
},
|
||||
start: function (device) {
|
||||
this.$emit('start', device)
|
||||
device.stopping = false
|
||||
start: async function (device) {
|
||||
// const checkParam = await this.checkIfDeviceSetDoneParam({ device: device })
|
||||
// const status = checkParam.status
|
||||
// const message = checkParam.message
|
||||
// if (status === true) {
|
||||
this.setArchiveSettings()
|
||||
// this.$emit('start', device)
|
||||
setTimeout(() => {
|
||||
this.$emit('start', device)
|
||||
}, 500)
|
||||
this.pageToast('The device ' + device.name + ' has been started.')
|
||||
// } else {
|
||||
// this.pageToast('The device cannot be started because:' + message)
|
||||
// }
|
||||
},
|
||||
stop: function (device) {
|
||||
device.stopping = true
|
||||
this.$emit('stop', device)
|
||||
this.pageToast('The device ' + device.name + ' has been stopped.')
|
||||
},
|
||||
record: async function (device) {
|
||||
// const checkParam = await this.checkIfRecordingSetDoneParam({ device: device })
|
||||
// const status = checkParam.status
|
||||
// const message = checkParam.message
|
||||
// if (status === true) {
|
||||
// device.stopping = false
|
||||
this.setArchiveSettings()
|
||||
setTimeout(() => {
|
||||
this.$emit('record', device)
|
||||
}, 500)
|
||||
this.pageToast('The device ' + device.name + ' has been started.')
|
||||
// } else {
|
||||
// this.pageToast('Recording cannot be started because:' + message)
|
||||
// }
|
||||
},
|
||||
stopRecord: function (device) {
|
||||
this.$emit('stopRecord', device)
|
||||
this.pageToast('The device ' + device.name + ' has been stopped.')
|
||||
},
|
||||
generateChart: function (device) {
|
||||
this.$emit('generate', device)
|
||||
},
|
||||
@@ -147,6 +210,44 @@ export default {
|
||||
},
|
||||
)
|
||||
},
|
||||
detect: function (device) {
|
||||
this.$emit('detect', device)
|
||||
this.pageToast('The device ' + device.name + ' has been detect.')
|
||||
},
|
||||
stimulate: async function (device) {
|
||||
const checkParam = await this.checkIfStimulationSetDoneParam({ device: device })
|
||||
const status = checkParam.status
|
||||
const message = checkParam.message
|
||||
if (status === true) {
|
||||
this.$emit('sti', device)
|
||||
this.pageToast('The device ' + device.name + ' start stimulate.')
|
||||
} else {
|
||||
this.pageToast('Stimulation cannot be started because:' + message)
|
||||
}
|
||||
},
|
||||
stopStimulate: function (device) {
|
||||
this.$emit('sti_stop', device)
|
||||
this.pageToast('The device ' + device.name + ' stop stimulate.')
|
||||
},
|
||||
fastSettle: function (device) {
|
||||
this.$emit('fast_settle', device)
|
||||
this.pageToast('The device ' + device.name + ' fast settle.')
|
||||
},
|
||||
recoverDetectButton () {
|
||||
document.getElementById('detectButton').className += ' no-dark-style-va-button'
|
||||
},
|
||||
...mapActions('taskContent', [types.param.checkIfRecordingSetDone, types.param.checkIfStimulationSetDone, types.param.checkIfDeviceSetDone]),
|
||||
},
|
||||
destroyed () {
|
||||
// this.deviceList.length = 0
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.no-dark-style-va-button {
|
||||
&:focus {
|
||||
filter: brightness(100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,9 +15,22 @@
|
||||
</div>
|
||||
|
||||
<div v-else class="flex row align--center">
|
||||
<task-device-list :ref="'pdlist_ref'" :deviceList="deviceList" @remove="removeDevice($event)" @start="startDevice($event)" @stop="stopDevice($event)" @generate="generateChart($event)" />
|
||||
<task-device-list
|
||||
:ref="'pdlist_ref'"
|
||||
:deviceList="deviceList"
|
||||
@start="startDevice($event)"
|
||||
@stop="stopDevice($event)"
|
||||
@record="record($event)"
|
||||
@stopRecord="stopRecord($event)"
|
||||
@sti="sti($event)"
|
||||
@sti_stop="stiStop($event)"
|
||||
@fast_settle="fastSettle($event)"
|
||||
@generate="generateChart($event)"
|
||||
@detect="detectDevice($event)"
|
||||
@sd_card_status="sdCardStatus($event)"
|
||||
/>
|
||||
|
||||
<div class="row flex xs12 md12 xl12 sm12 mt-2" style="text-align: center;">
|
||||
<!-- <div class="row flex xs12 md12 xl12 sm12 mt-2" style="text-align: center;">
|
||||
<div class="xs10 md10 xl10 sm10">
|
||||
<va-select
|
||||
small
|
||||
@@ -31,7 +44,29 @@
|
||||
REGISTER
|
||||
</va-button>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
</va-card>
|
||||
<va-card class="mt-2">
|
||||
<template slot="header">
|
||||
<va-icon name="fa fa-bluetooth-b mr-3" color="primary"/>
|
||||
<h5 class="mt-0 mb-0">TRIGGERS</h5>
|
||||
</template>
|
||||
<div v-if="state.LOADING" class="flex-center spinner-box mt-4 mb-5">
|
||||
<fulfilling-bouncing-circle-spinner
|
||||
:animation-duration="3000"
|
||||
:color="this.$themes.primary"
|
||||
:size="60"
|
||||
>
|
||||
</fulfilling-bouncing-circle-spinner>
|
||||
</div>
|
||||
|
||||
<div class="flex row align--center">
|
||||
<trigger-list
|
||||
@start="startTrigger($event)"
|
||||
@stop="stopTrigger($event)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</va-card>
|
||||
@@ -41,15 +76,21 @@
|
||||
<script>
|
||||
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
|
||||
import TaskDeviceList from './TaskDeviceList'
|
||||
import TriggerList from './TriggerList'
|
||||
// import TaskDeviceListGM from './neulive-gimer/TaskDeviceListGM'
|
||||
import { taskInfo } from '../../../../data/task/TaskInfo'
|
||||
import { chartData } from '../../../../data/task/ChartsManagement'
|
||||
import { dataStreamBuffer } from '../../../../data/task/DataStreamBuffer'
|
||||
import api from '@/data/api'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
|
||||
export default {
|
||||
name: 'TaskDevices',
|
||||
components: {
|
||||
// TaskDeviceListGM,
|
||||
FulfillingBouncingCircleSpinner,
|
||||
TaskDeviceList,
|
||||
TriggerList,
|
||||
},
|
||||
props: {
|
||||
cardclass: {
|
||||
@@ -59,16 +100,22 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapFields('taskContent', [
|
||||
'deviceList',
|
||||
]),
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
deviceSelect: '',
|
||||
deviceOptions: taskInfo.getDeviceListNotRegister(),
|
||||
deviceList: taskInfo.getDeviceListRegister(),
|
||||
// deviceList: this.deviceList,
|
||||
state: {
|
||||
LOADING: false,
|
||||
},
|
||||
stiTimeOut: null,
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
@@ -85,77 +132,265 @@ export default {
|
||||
},
|
||||
loadingDone: async function () {
|
||||
this.state.LOADING = false
|
||||
console.log(this.deviceOptions)
|
||||
for (let i = this.deviceOptions.length - 1; i >= 0; i--) {
|
||||
this.deviceSelect = this.deviceOptions[i]
|
||||
await this.addDevice(this.deviceOptions[i].id)
|
||||
// this.sleep(500).then(() => {
|
||||
// this.addDevice(this.deviceOptions[i].id)
|
||||
// })
|
||||
// const ret = await api.task.getAll()
|
||||
// if (ret.data.length > 0) {
|
||||
// for (const device in ret.data[0].device_config) {
|
||||
// if (ret.data[0].device_config[device].device_address) {
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // console.log(this.deviceOptions)
|
||||
for (let i = 0; i <= 11; i++) {
|
||||
if (taskInfo.getDeviceInfoByRawID(i).info.status === 'connected') {
|
||||
const index = this.deviceList.findIndex(d => taskInfo.getRawDeviceID(d.id) === i)
|
||||
if (index < 0) {
|
||||
await this.addDevice(i)
|
||||
}
|
||||
} else {
|
||||
const index = this.deviceList.findIndex(d => taskInfo.getRawDeviceID(d.id) === i)
|
||||
if (index > 0) {
|
||||
await this.removeDevice(this.deviceList[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
taskInfo.getDeviceList().length = 0
|
||||
taskInfo.getDeviceList().push({
|
||||
id: -1,
|
||||
name: 'Time',
|
||||
})
|
||||
taskInfo.getDeviceList().push(...this.deviceList)
|
||||
// // console.log(taskInfo.getDeviceList())
|
||||
// for (let i = this.deviceOptions.length - 1; i >= 0; i--) {
|
||||
// this.deviceSelect = this.deviceOptions[i]
|
||||
// await this.addDevice(this.deviceOptions[i].id)
|
||||
// // this.sleep(500).then(() => {
|
||||
// // this.addDevice(this.deviceOptions[i].id)
|
||||
// // })
|
||||
// }
|
||||
},
|
||||
startDevice: async function (device) {
|
||||
await chartData.defaultChartGenerator(device.id, null, 'device')
|
||||
if (!taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Neulive')) {
|
||||
await chartData.defaultChartGenerator(this.deviceList, device.id, null, 'device')
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'record',
|
||||
}))
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'stimulate',
|
||||
}))
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_parameter/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
parameter: 'STIMULATING',
|
||||
content: 1,
|
||||
}))
|
||||
taskInfo.getTaskInfo().deviceList[(taskInfo.getRawDeviceID(device.id)).toString()].parameterSet.STIMULATING = 1
|
||||
|
||||
device.isStimulate = true
|
||||
} else if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Elite')) {
|
||||
const e1 = parseInt((taskInfo.getDeviceInfo(device.id).parameterSet.DPV_e_1 - 25000) / 5)
|
||||
const e2 = parseInt((taskInfo.getDeviceInfo(device.id).parameterSet.DPV_e_2 - 25000) / 5)
|
||||
const eFinal = parseInt((taskInfo.getDeviceInfo(device.id).parameterSet.DPV_e_final - 25000) / 5)
|
||||
const isDPVMode = taskInfo.getDeviceInfo(device.id).parameterSet.MODE === 15
|
||||
if (isDPVMode) {
|
||||
if (e1 >= e2 && !(e1 >= eFinal && eFinal >= e2)) {
|
||||
this.pageToast('[Error] Please set E Final correctly.')
|
||||
return false
|
||||
} else if (e2 > e1 && !(e2 >= eFinal && eFinal >= e1)) {
|
||||
this.pageToast('[Error] Please set E Final correctly.')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
await chartData.defaultChartGenerator(this.deviceList, device.id, null, 'device')
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'start',
|
||||
}))
|
||||
}
|
||||
// device.stopping = false
|
||||
device.isSync = true
|
||||
this.$emit('refreshSetting')
|
||||
// ### show device info
|
||||
api.task.update({
|
||||
device_config: taskInfo.getTaskInfo().deviceList,
|
||||
})
|
||||
// // console.log(taskInfo.getDeviceInfo(device.id))
|
||||
}
|
||||
},
|
||||
stopDevice: async function (device) {
|
||||
await dataStreamBuffer.removeByDevice(taskInfo.getRawDeviceID(device.id))
|
||||
if (taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Neulive')) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'stop_stimulate',
|
||||
}))
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'stop_record',
|
||||
}))
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_parameter/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
parameter: 'STIMULATING',
|
||||
content: 0,
|
||||
}))
|
||||
device.isStimulate = false
|
||||
} else if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Elite')) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'interrupt',
|
||||
}))
|
||||
}
|
||||
// device.stopping = true
|
||||
}
|
||||
},
|
||||
detectDevice: function (device) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'VIS_DEVICE_DETECT',
|
||||
}))
|
||||
setTimeout(() => {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'VIS_DEVICE_DONE',
|
||||
}))
|
||||
this.$refs.pdlist_ref.recoverDetectButton()
|
||||
}, 5000)
|
||||
},
|
||||
record: async function (device) {
|
||||
if (taskInfo.getDeviceInfo(device.id).parameterSet.CH_NUMBER === 0) {
|
||||
this.pageToast('[Recording] Please select recording channels.')
|
||||
return false
|
||||
}
|
||||
await chartData.defaultChartGenerator(this.deviceList, device.id, null, 'device')
|
||||
if (!taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'start',
|
||||
instruction: 'record',
|
||||
}))
|
||||
device.isSync = true
|
||||
// device.stopping = false
|
||||
this.$emit('refreshSetting')
|
||||
api.task.update({
|
||||
device_config: taskInfo.getTaskInfo().deviceList,
|
||||
})
|
||||
|
||||
// ### show device info
|
||||
console.log(taskInfo.getDeviceInfo(device.id))
|
||||
// // console.log(taskInfo.getDeviceInfo(device.id))
|
||||
}
|
||||
},
|
||||
stopDevice: function (device) {
|
||||
stopRecord: function (device) {
|
||||
dataStreamBuffer.removeByDevice(taskInfo.getRawDeviceID(device.id))
|
||||
if (taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'interrupt',
|
||||
instruction: 'stop_record',
|
||||
}))
|
||||
}
|
||||
// device.isSync = false
|
||||
device.isSync = false
|
||||
// device.stopping = true
|
||||
},
|
||||
// addDevice: async function () {
|
||||
// if (this.deviceSelect.id == null) {
|
||||
// return false
|
||||
// }
|
||||
// await taskInfo.getTaskInfo().deviceAddrList.push(taskInfo.getDeviceInfoByRawID(this.deviceSelect.id).info.device_address)
|
||||
// await taskInfo.getTaskInfo().taskDeviceID.push(this.deviceSelect.id)
|
||||
// const _address = this.GLOBAL.transMac(taskInfo.getDeviceInfoByRawID(this.deviceSelect.id).info.device_address)
|
||||
sti: function (device) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'stimulate',
|
||||
}))
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_parameter/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
parameter: 'STIMULATING',
|
||||
content: 1,
|
||||
}))
|
||||
taskInfo.getTaskInfo().deviceList[(taskInfo.getRawDeviceID(device.id)).toString()].parameterSet.STIMULATING = 1
|
||||
|
||||
// const pic = taskInfo.getDevicePic(taskInfo.getDeviceInfoByRawID(this.deviceSelect.id).info.library_name)
|
||||
// let type = ''
|
||||
// if (taskInfo.getDeviceInfoByRawID(this.deviceSelect.id).info.library_name.indexOf('Elite') >= 0) {
|
||||
// type = 'Elite'
|
||||
// } else if (taskInfo.getDeviceInfoByRawID(this.deviceSelect.id).info.library_name.indexOf('Neulive') >= 0) {
|
||||
// type = 'Neulive'
|
||||
// }
|
||||
|
||||
// const _device = {
|
||||
// id: taskInfo.getTaskInfo().taskDeviceID.indexOf(this.deviceSelect.id),
|
||||
// name: '[' + taskInfo.getTaskInfo().taskDeviceID.indexOf(this.deviceSelect.id) + '] ' + taskInfo.getDeviceInfoByRawID(this.deviceSelect.id).info.device_name,
|
||||
// addr: taskInfo.getDeviceInfoByRawID(this.deviceSelect.id).info.device_address,
|
||||
// address: _address,
|
||||
// picture: pic,
|
||||
// type: type,
|
||||
// isSync: taskInfo.getDeviceInfoByRawID(this.deviceSelect.id).info.isSync,
|
||||
// stopping: false,
|
||||
// }
|
||||
// this.deviceList.push(_device)
|
||||
// this.deviceSelect = ''
|
||||
// taskInfo.updateAllList()
|
||||
// this.$emit('add', _device.id)
|
||||
// },
|
||||
api.task.update({
|
||||
device_config: taskInfo.getTaskInfo().deviceList,
|
||||
})
|
||||
device.isStimulate = true
|
||||
const stiExTime = taskInfo.getDeviceInfo(device.id).parameterSet.REPEAT_INTERVAL_littleEndian * taskInfo.getDeviceInfo(device.id).parameterSet.REPEAT_TIME_littleEndian
|
||||
clearTimeout(this.stiTimeOut)
|
||||
if (taskInfo.getDeviceInfo(device.id).parameterSet.CONTINUOUS_STI < 0) {
|
||||
this.stiTimeOut = setTimeout(() => {
|
||||
this.stiStop(device)
|
||||
}, (stiExTime + 3000))
|
||||
}
|
||||
},
|
||||
stiStop: function (device) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'stop_stimulate',
|
||||
}))
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_parameter/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
parameter: 'STIMULATING',
|
||||
content: 0,
|
||||
}))
|
||||
device.isStimulate = false
|
||||
clearTimeout(this.stiTimeOut)
|
||||
},
|
||||
fastSettle: function (device) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'FAST_SET',
|
||||
}))
|
||||
},
|
||||
sdCardStatus: function (device) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_sd_card_status/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
}))
|
||||
},
|
||||
startTrigger (trigger) {
|
||||
// save automatically when start
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '/client/trigger_manager/set_parameter', JSON.stringify({
|
||||
mac: trigger.mac,
|
||||
parameter_set: trigger.parameter,
|
||||
}),
|
||||
)
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '/client/trigger_manager/runtime', JSON.stringify({
|
||||
mac: trigger.mac,
|
||||
instruction: 'start',
|
||||
}),
|
||||
)
|
||||
},
|
||||
stopTrigger (trigger) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '/client/trigger_manager/runtime', JSON.stringify({
|
||||
mac: trigger.mac,
|
||||
instruction: 'stop',
|
||||
}),
|
||||
)
|
||||
},
|
||||
addDevice: async function (selectID) {
|
||||
if (selectID == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
const addr = taskInfo.getDeviceInfoByRawID(selectID).info.device_address
|
||||
if (addr.length === 0) {
|
||||
return false
|
||||
}
|
||||
if (taskInfo.getTaskInfo().taskDeviceID.indexOf(selectID) > 0) {
|
||||
return false
|
||||
}
|
||||
await taskInfo.getTaskInfo().deviceAddrList.push(taskInfo.getDeviceInfoByRawID(selectID).info.device_address)
|
||||
await taskInfo.getTaskInfo().taskDeviceID.push(selectID)
|
||||
const _address = this.GLOBAL.transMac(taskInfo.getDeviceInfoByRawID(selectID).info.device_address)
|
||||
@@ -173,10 +408,16 @@ export default {
|
||||
name: '[' + taskInfo.getTaskInfo().taskDeviceID.indexOf(selectID) + '] ' + taskInfo.getDeviceInfoByRawID(selectID).info.device_name,
|
||||
addr: taskInfo.getDeviceInfoByRawID(selectID).info.device_address,
|
||||
address: _address,
|
||||
library_name: taskInfo.getDeviceInfoByRawID(selectID).info.library_name,
|
||||
library_version: taskInfo.getDeviceInfoByRawID(selectID).info.library_version,
|
||||
picture: pic,
|
||||
type: type,
|
||||
isSync: taskInfo.getDeviceInfoByRawID(selectID).info.isSync,
|
||||
stopping: false,
|
||||
isStimulate: taskInfo.getDeviceInfoByRawID(selectID).info.isStimulate,
|
||||
sdCardStatus: taskInfo.getDeviceInfoByRawID(selectID).info.sd_card_status,
|
||||
transmission_type: taskInfo.getDeviceInfoByRawID(selectID).info.transmission_type,
|
||||
stimulation_last_time: taskInfo.getDeviceInfoByRawID(selectID).info.stimulation_last_time,
|
||||
// stopping: false,
|
||||
}
|
||||
this.deviceList.push(_device)
|
||||
this.deviceSelect = ''
|
||||
@@ -199,11 +440,36 @@ export default {
|
||||
taskInfo.updateAllList()
|
||||
this.$emit('remove', device.id)
|
||||
},
|
||||
clearDevice: async function () {
|
||||
taskInfo.getTaskInfo().deviceAddrList.length = 0
|
||||
taskInfo.getTaskInfo().taskDeviceID.length = 0
|
||||
this.deviceList.length = 0
|
||||
taskInfo.updateAllList()
|
||||
},
|
||||
checkStiStatus: function () {
|
||||
this.deviceList.forEach(device => {
|
||||
if (device.stimulation_last_time > 0) {
|
||||
const stiExTime = taskInfo.getDeviceInfo(device.id).parameterSet.REPEAT_INTERVAL_littleEndian * taskInfo.getDeviceInfo(device.id).parameterSet.REPEAT_TIME_littleEndian
|
||||
const now = parseInt(Date.now() / 1000)
|
||||
let stiExTimeOut = (stiExTime / 1000) - (now - parseInt(parseFloat(device.stimulation_last_time)))
|
||||
stiExTimeOut = stiExTimeOut > 0 ? stiExTimeOut : 0
|
||||
console.log(stiExTime, now, parseInt(parseFloat(device.stimulation_last_time)), stiExTimeOut)
|
||||
clearTimeout(this.stiTimeOut)
|
||||
if (taskInfo.getDeviceInfo(device.id).parameterSet.CONTINUOUS_STI < 0) {
|
||||
this.stiTimeOut = setTimeout(() => {
|
||||
this.stiStop(device)
|
||||
}, (stiExTimeOut * 1000) + 3000)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
generateChart: function (device) {
|
||||
this.$emit('add', device.id)
|
||||
},
|
||||
setArchiveSettings: function () {
|
||||
this.$refs.pdlist_ref.setArchiveSettings()
|
||||
if (this.$refs.pdlist_ref != null) {
|
||||
this.$refs.pdlist_ref.setArchiveSettings()
|
||||
}
|
||||
},
|
||||
refresh: function () {
|
||||
this.$nextTick(() => {
|
||||
@@ -212,6 +478,16 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
pageToast: function (mes) {
|
||||
this.showToast(
|
||||
mes,
|
||||
{
|
||||
icon: 'fa-bell',
|
||||
position: 'bottom-right',
|
||||
duration: 4000,
|
||||
},
|
||||
)
|
||||
},
|
||||
},
|
||||
async mounted () {
|
||||
// this.pageMqttSub()
|
||||
@@ -221,7 +497,7 @@ export default {
|
||||
// }
|
||||
},
|
||||
destroyed () {
|
||||
this.loadingDone()
|
||||
// this.loadingDone()
|
||||
// this.pageMqttUnSub()
|
||||
},
|
||||
watch: {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<va-accordion v-for="trigger in triggerList" :key="trigger.id">
|
||||
<va-collapse class="mb-2" :isOpenDefault='true'>
|
||||
<span slot="header" >
|
||||
<va-item :key="trigger.id" class="pa-0 ma-0"
|
||||
>
|
||||
<va-item-section class="ml-3" caption>
|
||||
<va-item-label>
|
||||
{{ trigger.name }}
|
||||
</va-item-label>
|
||||
<va-item-label caption>
|
||||
{{ trigger.mac }}
|
||||
</va-item-label>
|
||||
</va-item-section>
|
||||
</va-item>
|
||||
|
||||
<va-item class="pa-0 ma-0 mt-2">
|
||||
<va-item-section class="ml-3">
|
||||
<va-item-label>
|
||||
<va-button @click.stop="start(trigger)" v-if="trigger.status !== 'RUNNING'" class="px-2 py-0 mr-0" color="success" small>START</va-button>
|
||||
<va-button @click.stop="stop(trigger)" v-if="trigger.status === 'RUNNING'" class="px-2 py-0 mr-0" color="danger" small>STOP</va-button>
|
||||
</va-item-label>
|
||||
</va-item-section>
|
||||
</va-item>
|
||||
</span>
|
||||
<div slot="body">
|
||||
<div class="mt-0 mb-0" style="height: 350px; overflow-y: scroll; overflow-x: hidden;" :key="'detail' + trigger.id">
|
||||
<div>
|
||||
<trigger-control-window :mac="trigger.mac" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</va-collapse>
|
||||
</va-accordion>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import TriggerControlWindow from '../trigger/TriggerControlWindow'
|
||||
|
||||
export default {
|
||||
name: 'TriggerList',
|
||||
components: {
|
||||
TriggerControlWindow,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('device', [
|
||||
'triggerList',
|
||||
'chartKey',
|
||||
]),
|
||||
},
|
||||
methods: {
|
||||
start: async function (trigger) {
|
||||
this.$emit('start', trigger)
|
||||
this.triggerList.find(o => o.mac === trigger.mac).display = true
|
||||
this.triggerList.find(o => o.mac === trigger.mac).status = 'RUNNING'
|
||||
this.chartKey++
|
||||
this.pageToast('The trigger ' + trigger.name + ' has been started.')
|
||||
},
|
||||
stop: function (trigger) {
|
||||
this.$emit('stop', trigger)
|
||||
this.triggerList.find(o => o.mac === trigger.mac).status = 'CONNTECTED'
|
||||
this.pageToast('The trigger ' + trigger.name + ' has been stopped.')
|
||||
},
|
||||
pageToast: function (mes) {
|
||||
this.showToast(
|
||||
mes,
|
||||
{
|
||||
icon: 'fa-bell',
|
||||
position: 'bottom-right',
|
||||
duration: 4000,
|
||||
},
|
||||
)
|
||||
},
|
||||
},
|
||||
destroyed () {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,183 @@
|
||||
<template>
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<recording-site :ref="'elewindow_ref'" :deviceList="deviceList" />
|
||||
<va-accordion v-for="device in deviceList" :key="device.id">
|
||||
<va-collapse class="mb-2">
|
||||
<span slot="header" >
|
||||
<va-item :key="device.id" class="pa-0 ma-0"
|
||||
>
|
||||
|
||||
<va-item-section avatar class="ml-0">
|
||||
<va-avatar style="border-radius: 0;">
|
||||
<img :src="device.picture" :alt="device.name">
|
||||
</va-avatar>
|
||||
</va-item-section>
|
||||
|
||||
<va-item-section class="ml-3">
|
||||
<va-item-label>
|
||||
{{ '[' + device.id + '] ' + device.library_name }}
|
||||
</va-item-label>
|
||||
|
||||
<va-item-label caption>
|
||||
{{ device.address }}
|
||||
</va-item-label>
|
||||
|
||||
</va-item-section>
|
||||
|
||||
</va-item>
|
||||
|
||||
<va-item class="pa-0 ma-0 mt-2">
|
||||
<va-item-section class="ml-3">
|
||||
<va-item-label>
|
||||
<va-button @click.stop="record(device)" v-if="device.library_name == 'Neulive3.5-REC' && !device.isSync" color="primary" class="px-2 py-0 mr-0 no-dark-style-va-button" small>RECORD</va-button>
|
||||
<va-button @click.stop="stopRecord(device)" v-if="device.library_name == 'Neulive3.5-REC' && device.isSync" color="danger" class="px-2 py-0 mr-0 no-dark-style-va-button" small>STOP REC</va-button>
|
||||
<va-button @click.stop="stimulate(device)" v-if="device.library_name == 'Neulive3.5-STI' && !device.isStimulate" color="warning" class="px-2 py-0 mr-0 no-dark-style-va-button" small>STIMULATE</va-button>
|
||||
<va-button @click.stop="stopStimulate(device)" v-if="device.library_name == 'Neulive3.5-STI' && device.isStimulate" color="danger" class="px-2 py-0 mr-0" small>STOP STI</va-button>
|
||||
<va-button @click.stop="fastSettle(device)" v-if="device.library_name == 'Neulive3.5-REC'" color="info" class="px-2 py-0 mr-0 no-dark-style-va-button" small>R</va-button>
|
||||
</va-item-label>
|
||||
</va-item-section>
|
||||
</va-item>
|
||||
</span>
|
||||
<div slot="body">
|
||||
<div class="mt-0 mb-0" style="height: 350px; overflow-y: scroll; overflow-x: hidden;" :key="'detail' + device.id">
|
||||
<!-- <div style="text-align: center;">
|
||||
<va-button @click.stop="generateChart(device)" class="pl-2 pr-2 mr-0 no-dark-style-va-button" small>GENERATE MAPPING CHART</va-button>
|
||||
</div> -->
|
||||
<div>
|
||||
<file-control-window :ref="'fcwindow_ref'" :deviceID="device.id" class="pl-0 pr-0" />
|
||||
</div>
|
||||
<div v-if="device.type == 'Neulive'">
|
||||
<neulive-parameter-window-g-m :ref="'npwindow_ref'" :deviceID="device.id" class="pl-0 pr-0" @record="record_start(device)" @record_stop="record_stop(device)"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</va-collapse>
|
||||
</va-accordion>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import NeuliveParameterWindow from '../parameter/NeuliveParameterWindow'
|
||||
import RecordingSite from '@/components/task/content/parameter/neulive-gimer/RecordingSite.vue'
|
||||
import NeuliveParameterWindowGM from '@/components/task/content/parameter/neulive-gimer/NeuliveParameterWindowGM'
|
||||
import FileControlWindow from '../../meta/FileControlWindow'
|
||||
import { mapActions } from 'vuex'
|
||||
import types from '@/store/modules/task/content/types'
|
||||
|
||||
export default {
|
||||
name: 'TaskDeviceList',
|
||||
components: {
|
||||
RecordingSite,
|
||||
NeuliveParameterWindowGM,
|
||||
FileControlWindow,
|
||||
},
|
||||
props: {
|
||||
deviceList: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
showDeleteModal: false,
|
||||
selectDevice: null,
|
||||
deviceStopping: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
methods: {
|
||||
removeCheck: function (device) {
|
||||
this.selectDevice = device
|
||||
this.showDeleteModal = true
|
||||
},
|
||||
remove: function () {
|
||||
this.$emit('remove', this.selectDevice)
|
||||
},
|
||||
record: async function (device) {
|
||||
this.setArchiveSettings()
|
||||
setTimeout(() => {
|
||||
this.$emit('record', device)
|
||||
}, 500)
|
||||
this.pageToast('The device ' + device.name + ' has been started.')
|
||||
},
|
||||
stopRecord: function (device) {
|
||||
this.$emit('stopRecord', device)
|
||||
this.pageToast('The device ' + device.name + ' has been stopped.')
|
||||
},
|
||||
generateChart: function (device) {
|
||||
this.$emit('generate', device)
|
||||
},
|
||||
setArchiveSettings: function () {
|
||||
this.$refs.fcwindow_ref.forEach(ref => {
|
||||
ref.setArchiveSettings()
|
||||
})
|
||||
},
|
||||
refresh: function () {
|
||||
// console.log(this.deviceList)
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.elewindow_ref != null) {
|
||||
this.$refs.elewindow_ref.refresh()
|
||||
}
|
||||
if (this.$refs.fcwindow_ref != null) {
|
||||
this.$refs.fcwindow_ref.forEach(ref => {
|
||||
ref.refresh()
|
||||
})
|
||||
}
|
||||
if (this.$refs.npwindow_ref != null) {
|
||||
this.$refs.npwindow_ref.forEach(ref => {
|
||||
ref.refresh()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
pageToast: function (mes) {
|
||||
this.showToast(
|
||||
mes,
|
||||
{
|
||||
icon: 'fa-bell',
|
||||
position: 'bottom-right',
|
||||
duration: 4000,
|
||||
},
|
||||
)
|
||||
},
|
||||
detect: function (device) {
|
||||
this.$emit('detect', device)
|
||||
this.pageToast('The device ' + device.name + ' has been detect.')
|
||||
},
|
||||
stimulate: async function (device) {
|
||||
const checkParam = await this.checkIfStimulationSetDoneParam({ device: device })
|
||||
const status = checkParam.status
|
||||
const message = checkParam.message
|
||||
if (status === true) {
|
||||
this.$emit('sti', device)
|
||||
} else {
|
||||
this.pageToast('Stimulation cannot be started because:' + message)
|
||||
}
|
||||
},
|
||||
stopStimulate: function (device) {
|
||||
this.$emit('sti_stop', device)
|
||||
this.pageToast('The device ' + device.name + ' stop stimulate.')
|
||||
},
|
||||
fastSettle: function (device) {
|
||||
this.$emit('fast_settle', device)
|
||||
this.pageToast('The device ' + device.name + ' fast settle.')
|
||||
},
|
||||
recoverDetectButton () {
|
||||
document.getElementById('detectButton').className += ' no-dark-style-va-button'
|
||||
},
|
||||
...mapActions('taskContent', [types.param.checkIfRecordingSetDone, types.param.checkIfStimulationSetDone, types.param.checkIfDeviceSetDone]),
|
||||
},
|
||||
destroyed () {
|
||||
// this.deviceList.length = 0
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.no-dark-style-va-button {
|
||||
&:focus {
|
||||
filter: brightness(100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,395 @@
|
||||
<template>
|
||||
<div class="flex" :class="cardclass">
|
||||
<va-card>
|
||||
<template slot="header">
|
||||
<va-icon name="fa fa-bluetooth-b mr-3" color="primary"/>
|
||||
<h5 class="mt-0 mb-0">DEVICES</h5>
|
||||
</template>
|
||||
<div v-if="state.LOADING" class="flex-center spinner-box mt-4 mb-5">
|
||||
<fulfilling-bouncing-circle-spinner
|
||||
:animation-duration="3000"
|
||||
:color="this.$themes.primary"
|
||||
:size="60"
|
||||
>
|
||||
</fulfilling-bouncing-circle-spinner>
|
||||
</div>
|
||||
|
||||
<div v-else class="flex row align--center">
|
||||
<task-device-list-g-m
|
||||
:ref="'pdlist_ref'"
|
||||
:deviceList="deviceList"
|
||||
@record="record($event)"
|
||||
@stopRecord="stopRecord($event)"
|
||||
@sti="sti($event)" @sti_stop="stiStop($event)"
|
||||
@fast_settle="fastSettle($event)"
|
||||
@generate="generateChart($event)"
|
||||
@detect="detectDevice($event)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</va-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
|
||||
// import TaskDeviceList from './TaskDeviceList'
|
||||
import TaskDeviceListGM from './TaskDeviceListGM'
|
||||
import { taskInfo } from '@/data/task/TaskInfo'
|
||||
import { chartData } from '@/data/task/ChartsManagement'
|
||||
import { dataStreamBuffer } from '@/data/task/DataStreamBuffer'
|
||||
import api from '@/data/api'
|
||||
import { mapActions } from 'vuex'
|
||||
import { mapFields } from 'vuex-map-fields'
|
||||
import types from '@/store/modules/task/content/types'
|
||||
|
||||
export default {
|
||||
name: 'TaskDevices',
|
||||
components: {
|
||||
TaskDeviceListGM,
|
||||
FulfillingBouncingCircleSpinner,
|
||||
// TaskDeviceList,
|
||||
},
|
||||
props: {
|
||||
cardclass: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return ['xs12', 'md12', 'xl12', 'sm12']
|
||||
},
|
||||
},
|
||||
},
|
||||
created () {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
deviceSelect: '',
|
||||
deviceOptions: taskInfo.getDeviceListNotRegister(),
|
||||
// deviceList: this.deviceList,
|
||||
state: {
|
||||
LOADING: false,
|
||||
},
|
||||
stiTimeOut: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapFields('taskContent', [
|
||||
'deviceList',
|
||||
]),
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
sleep: async function (time) {
|
||||
return new Promise((resolve) => setTimeout(resolve, time))
|
||||
},
|
||||
mqttPub: function (topic, mes) {
|
||||
this.$mqtt.publish(topic, mes)
|
||||
},
|
||||
loadingStart: async function () {
|
||||
this.state.LOADING = true
|
||||
},
|
||||
loadingDone: async function () {
|
||||
this.state.LOADING = false
|
||||
// console.log(this.deviceOptions)
|
||||
for (let i = 0; i <= 11; i++) {
|
||||
if (taskInfo.getDeviceInfoByRawID(i).info.status === 'connected') {
|
||||
const index = this.deviceList.findIndex(d => taskInfo.getRawDeviceID(d.id) === i)
|
||||
if (index < 0) {
|
||||
await this.addDevice(i)
|
||||
}
|
||||
} else {
|
||||
const index = this.deviceList.findIndex(d => taskInfo.getRawDeviceID(d.id) === i)
|
||||
if (index > 0) {
|
||||
await this.removeDevice(this.deviceList[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
taskInfo.getDeviceList().length = 0
|
||||
taskInfo.getDeviceList().push({
|
||||
id: -1,
|
||||
name: 'Time',
|
||||
})
|
||||
taskInfo.getDeviceList().push(...this.deviceList)
|
||||
// console.log('ppp', taskInfo.getDeviceList(), this.deviceList)
|
||||
// for (let i = this.deviceOptions.length - 1; i >= 0; i--) {
|
||||
// this.deviceSelect = this.deviceOptions[i]
|
||||
// await this.addDevice(this.deviceOptions[i].id)
|
||||
// // this.sleep(500).then(() => {
|
||||
// // this.addDevice(this.deviceOptions[i].id)
|
||||
// // })
|
||||
// }
|
||||
},
|
||||
detectDevice: function (device) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'VIS_DEVICE_DETECT',
|
||||
}))
|
||||
setTimeout(() => {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'VIS_DEVICE_DONE',
|
||||
}))
|
||||
this.$refs.pdlist_ref.recoverDetectButton()
|
||||
}, 5000)
|
||||
},
|
||||
record: async function (device) {
|
||||
const test = await this.taskGimerCheckDeviceStatus({
|
||||
deviceList: this.deviceList,
|
||||
type: 'allFree',
|
||||
libraryNameREC: 'Neulive3.5-REC',
|
||||
libraryNameSTI: 'Neulive3.5-STI',
|
||||
})
|
||||
if (!test) {
|
||||
this.pageToast('[Stimulation] Please connect "Neulive3.5-REC" and "Neulive3.5-STI".')
|
||||
return false
|
||||
}
|
||||
const channelSet = taskInfo.getDeviceInfo(device.id).parameterSet.RECORDING_CH.toString(2).split('')
|
||||
const channelLen = channelSet.filter(function (value) {
|
||||
return parseInt(value) > 0
|
||||
}).length
|
||||
if (channelLen === 0) {
|
||||
this.pageToast('[Recording] Please select recording channels.')
|
||||
return false
|
||||
}
|
||||
await chartData.defaultChartGenerator(this.deviceList, device.id, null, 'device')
|
||||
this.deviceList.forEach(_device => {
|
||||
if (_device.library_name === 'Neulive3.5-STI') {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(_device.id),
|
||||
instruction: 'SET_POWER_SAVE_EN_LOW',
|
||||
}))
|
||||
}
|
||||
})
|
||||
if (!taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'record',
|
||||
}))
|
||||
device.isSync = true
|
||||
// device.stopping = false
|
||||
this.$emit('refreshSetting')
|
||||
api.task.update({
|
||||
device_config: taskInfo.getTaskInfo().deviceList,
|
||||
})
|
||||
|
||||
// ### show device info
|
||||
// console.log(taskInfo.getDeviceInfo(device.id))
|
||||
}
|
||||
},
|
||||
stopRecord: async function (device) {
|
||||
const test = await this.taskGimerCheckDeviceStatus({
|
||||
deviceList: this.deviceList,
|
||||
type: 'stiRun',
|
||||
libraryNameREC: 'Neulive3.5-REC',
|
||||
libraryNameSTI: 'Neulive3.5-STI',
|
||||
})
|
||||
if (test) {
|
||||
this.pageToast('[Recording] Please stop stimulation first.')
|
||||
return false
|
||||
}
|
||||
dataStreamBuffer.removeByDevice(taskInfo.getRawDeviceID(device.id))
|
||||
if (taskInfo.getDeviceInfo(device.id).info.isSync) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'stop_record',
|
||||
}))
|
||||
}
|
||||
device.isSync = false
|
||||
this.deviceList.forEach(_device => {
|
||||
if (_device.library_name === 'Neulive3.5-STI') {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(_device.id),
|
||||
instruction: 'SET_POWER_SAVE',
|
||||
}))
|
||||
}
|
||||
})
|
||||
// device.stopping = true
|
||||
},
|
||||
sti: async function (device) {
|
||||
const test = await this.taskGimerCheckDeviceStatus({
|
||||
deviceList: this.deviceList,
|
||||
type: 'recRun',
|
||||
libraryNameREC: 'Neulive3.5-REC',
|
||||
libraryNameSTI: 'Neulive3.5-STI',
|
||||
})
|
||||
if (!test) {
|
||||
this.pageToast('[Stimulation] Please run recording first.')
|
||||
return false
|
||||
}
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'stimulate',
|
||||
}))
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_parameter/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
parameter: 'STIMULATING',
|
||||
content: 1,
|
||||
}))
|
||||
taskInfo.getTaskInfo().deviceList[(taskInfo.getRawDeviceID(device.id)).toString()].parameterSet.STIMULATING = 1
|
||||
|
||||
api.task.update({
|
||||
device_config: taskInfo.getTaskInfo().deviceList,
|
||||
})
|
||||
device.isStimulate = true
|
||||
const stiExTime = taskInfo.getDeviceInfo(device.id).parameterSet.REPEAT_INTERVAL_littleEndian * taskInfo.getDeviceInfo(device.id).parameterSet.REPEAT_TIME_littleEndian
|
||||
clearTimeout(this.stiTimeOut)
|
||||
this.stiTimeOut = setTimeout(() => {
|
||||
this.stiStop(device)
|
||||
}, (stiExTime + 3000))
|
||||
this.pageToast('The device ' + device.name + ' start stimulate.')
|
||||
},
|
||||
stiStop: function (device) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'stop_stimulate',
|
||||
}))
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_parameter/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
parameter: 'STIMULATING',
|
||||
content: 0,
|
||||
}))
|
||||
device.isStimulate = false
|
||||
clearTimeout(this.stiTimeOut)
|
||||
},
|
||||
fastSettle: function (device) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_instruction/0',
|
||||
device: taskInfo.getRawDeviceID(device.id),
|
||||
instruction: 'FAST_SET',
|
||||
}))
|
||||
},
|
||||
addDevice: async function (selectID) {
|
||||
if (selectID == null) {
|
||||
return false
|
||||
}
|
||||
const addr = taskInfo.getDeviceInfoByRawID(selectID).info.device_address
|
||||
if (addr.length === 0) {
|
||||
return false
|
||||
}
|
||||
if (taskInfo.getTaskInfo().taskDeviceID.indexOf(selectID) > 0) {
|
||||
return false
|
||||
}
|
||||
await taskInfo.getTaskInfo().deviceAddrList.push(taskInfo.getDeviceInfoByRawID(selectID).info.device_address)
|
||||
await taskInfo.getTaskInfo().taskDeviceID.push(selectID)
|
||||
const _address = this.GLOBAL.transMac(taskInfo.getDeviceInfoByRawID(selectID).info.device_address)
|
||||
|
||||
const pic = taskInfo.getDevicePic(taskInfo.getDeviceInfoByRawID(selectID).info.library_name)
|
||||
let type = ''
|
||||
if (taskInfo.getDeviceInfoByRawID(selectID).info.library_name.indexOf('Elite') >= 0) {
|
||||
type = 'Elite'
|
||||
} else if (taskInfo.getDeviceInfoByRawID(selectID).info.library_name.indexOf('Neulive') >= 0) {
|
||||
type = 'Neulive'
|
||||
}
|
||||
|
||||
const _device = {
|
||||
id: taskInfo.getTaskInfo().taskDeviceID.indexOf(selectID),
|
||||
name: '[' + taskInfo.getTaskInfo().taskDeviceID.indexOf(selectID) + '] ' + taskInfo.getDeviceInfoByRawID(selectID).info.device_name,
|
||||
addr: taskInfo.getDeviceInfoByRawID(selectID).info.device_address,
|
||||
address: _address,
|
||||
library_name: taskInfo.getDeviceInfoByRawID(selectID).info.library_name,
|
||||
library_version: taskInfo.getDeviceInfoByRawID(selectID).info.library_version,
|
||||
picture: pic,
|
||||
type: type,
|
||||
isSync: taskInfo.getDeviceInfoByRawID(selectID).info.isSync,
|
||||
isStimulate: taskInfo.getDeviceInfoByRawID(selectID).info.isStimulate,
|
||||
stimulation_last_time: taskInfo.getDeviceInfoByRawID(selectID).info.stimulation_last_time,
|
||||
sdCardStatus: taskInfo.getDeviceInfoByRawID(selectID).info.sd_card_status,
|
||||
// stopping: false,
|
||||
}
|
||||
this.deviceList.push(_device)
|
||||
// console.log('sss', this.deviceList)
|
||||
this.deviceSelect = ''
|
||||
taskInfo.updateAllList()
|
||||
this.$emit('add', _device.id)
|
||||
},
|
||||
removeDevice: async function (device) {
|
||||
taskInfo.getTaskInfo().deviceAddrList.forEach(addr => {
|
||||
if (addr === device.addr) {
|
||||
taskInfo.getTaskInfo().deviceAddrList.splice(taskInfo.getTaskInfo().deviceAddrList.indexOf(addr), 1)
|
||||
}
|
||||
})
|
||||
taskInfo.getTaskInfo().taskDeviceID.forEach(realID => {
|
||||
if (realID === device.id) {
|
||||
taskInfo.getTaskInfo().taskDeviceID.splice(taskInfo.getTaskInfo().taskDeviceID.indexOf(realID), 1)
|
||||
}
|
||||
})
|
||||
this.deviceList.splice(this.deviceList.indexOf(device), 1)
|
||||
this.deviceSelect = ''
|
||||
taskInfo.updateAllList()
|
||||
this.$emit('remove', device.id)
|
||||
},
|
||||
checkStiStatus: function () {
|
||||
this.deviceList.forEach(device => {
|
||||
if (device.stimulation_last_time > 0) {
|
||||
const stiExTime = taskInfo.getDeviceInfo(device.id).parameterSet.REPEAT_INTERVAL_littleEndian * taskInfo.getDeviceInfo(device.id).parameterSet.REPEAT_TIME_littleEndian
|
||||
const now = parseInt(Date.now() / 1000)
|
||||
let stiExTimeOut = (stiExTime / 1000) - (now - parseInt(parseFloat(device.stimulation_last_time)))
|
||||
stiExTimeOut = stiExTimeOut > 0 ? stiExTimeOut : 0
|
||||
console.log(stiExTime, now, parseInt(parseFloat(device.stimulation_last_time)), stiExTimeOut)
|
||||
clearTimeout(this.stiTimeOut)
|
||||
this.stiTimeOut = setTimeout(() => {
|
||||
this.stiStop(device)
|
||||
}, (stiExTimeOut * 1000) + 3000)
|
||||
}
|
||||
})
|
||||
},
|
||||
clearDevice: async function () {
|
||||
taskInfo.getTaskInfo().deviceAddrList.length = 0
|
||||
taskInfo.getTaskInfo().taskDeviceID.length = 0
|
||||
this.deviceList.length = 0
|
||||
taskInfo.updateAllList()
|
||||
},
|
||||
generateChart: function (device) {
|
||||
this.$emit('add', device.id)
|
||||
},
|
||||
setArchiveSettings: function () {
|
||||
if (this.$refs.pdlist_ref != null) {
|
||||
this.$refs.pdlist_ref.setArchiveSettings()
|
||||
}
|
||||
},
|
||||
refresh: function () {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.pdlist_ref != null) {
|
||||
this.$refs.pdlist_ref.refresh()
|
||||
}
|
||||
})
|
||||
},
|
||||
pageToast: function (mes) {
|
||||
this.showToast(
|
||||
mes,
|
||||
{
|
||||
icon: 'fa-bell',
|
||||
position: 'bottom-right',
|
||||
duration: 4000,
|
||||
},
|
||||
)
|
||||
},
|
||||
...mapActions('taskContent', [types.gimer.checkDeviceStatus]),
|
||||
},
|
||||
async mounted () {
|
||||
// console.log('sss', taskInfo.getDeviceList(), this.deviceList)
|
||||
// this.pageMqttSub()
|
||||
// for (const device in this.deviceOptions) {
|
||||
// this.deviceSelect = this.deviceOptions[device]
|
||||
// await this.addDevice()
|
||||
// }
|
||||
},
|
||||
destroyed () {
|
||||
// this.loadingDone()
|
||||
// this.pageMqttUnSub()
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -122,6 +122,7 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
deviceList: [],
|
||||
showFormulaModal: false,
|
||||
formulaSelect: '',
|
||||
formulaOptions: [
|
||||
@@ -176,7 +177,7 @@ export default {
|
||||
switch (formula.type) {
|
||||
case 'Sheet Resistance':
|
||||
formula.dataNow = 0
|
||||
chartData.defaultChartGenerator(formula.id, null, 'formula')
|
||||
chartData.defaultChartGenerator(this.deviceList, formula.id, null, 'formula')
|
||||
break
|
||||
}
|
||||
this.pageToast('The ' + formula.name + 'has been applied.')
|
||||
|
||||
@@ -1,37 +1,25 @@
|
||||
<template>
|
||||
<div class="flex mt-0 pt-0">
|
||||
<div>
|
||||
<div class="row flex sm12 xl12 md12 xs12">
|
||||
<div>
|
||||
<div class="flex">
|
||||
<va-tree-root>
|
||||
<div class="row pt-0 pb-0">
|
||||
<div class="flex sm12 xl12 md12 xs12">
|
||||
<va-input
|
||||
@mouseup.native="fileNameChange(fileNameInput)"
|
||||
@mouseleave.native="fileNameChange(fileNameInput)"
|
||||
@touchend.native="fileNameChange(fileNameInput)"
|
||||
@keyup.enter="fileNameChange(fileNameInput)"
|
||||
v-model="fileNameInput"
|
||||
:label="'FILE NAME'"
|
||||
style="width: 200px;"
|
||||
>
|
||||
</va-input>
|
||||
<va-select
|
||||
:on-change="directorySelect(directory)"
|
||||
:label="'DIRECTORY'"
|
||||
v-model="directory"
|
||||
textBy="name"
|
||||
:options="directoryOptions"
|
||||
noClear
|
||||
style="width: 200px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</va-tree-root>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12">
|
||||
<div class="flex sm6 xl6 md6 xs6">
|
||||
<va-select
|
||||
:on-change="directorySelect(directory)"
|
||||
:label="'DIRECTORY'"
|
||||
v-model="directory"
|
||||
textBy="name"
|
||||
:options="directoryOptions"
|
||||
noClear
|
||||
/>
|
||||
</div>
|
||||
<div class="flex sm6 xl6 md6 xs6">
|
||||
<va-input
|
||||
@mouseup.native="fileNameChange(fileNameInput)"
|
||||
@mouseleave.native="fileNameChange(fileNameInput)"
|
||||
@touchend.native="fileNameChange(fileNameInput)"
|
||||
@keyup.enter="fileNameChange(fileNameInput)"
|
||||
v-model="fileNameInput"
|
||||
:label="'FILE NAME'"
|
||||
>
|
||||
</va-input>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -65,51 +53,94 @@ export default {
|
||||
fileNameInput: '',
|
||||
directory: '',
|
||||
directoryOptions: [],
|
||||
deviceInfo: {},
|
||||
deviceInfo: null,
|
||||
enableSetting: false,
|
||||
enableTimer: null,
|
||||
}
|
||||
},
|
||||
mqtt: {
|
||||
},
|
||||
methods: {
|
||||
fileNameChange: function (name) {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_recording_file_name/0',
|
||||
device: taskInfo.getRawDeviceID(this.deviceID),
|
||||
content: name,
|
||||
}))
|
||||
fileNameChange: async function (name) {
|
||||
if (this.enableSetting) {
|
||||
if (this.deviceInfo.info.isSync === false) {
|
||||
let fileNameCount = await api.meta.getByName(name)
|
||||
if (fileNameCount.data != null) {
|
||||
let duplicateCount = 1
|
||||
let fileName = name
|
||||
while (fileNameCount.data.length !== 0) {
|
||||
const res = name.split('(')[0]
|
||||
fileName = `${res}(${duplicateCount})`
|
||||
fileNameCount = await api.meta.getByName(fileName)
|
||||
duplicateCount += 1
|
||||
}
|
||||
this.fileNameInput = fileName
|
||||
|
||||
if (fileName !== this.deviceInfo.info.recording_file_name) {
|
||||
this.deviceInfo.info.recording_file_name = fileName
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_recording_file_name/0',
|
||||
device: taskInfo.getRawDeviceID(this.deviceID),
|
||||
content: fileName,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
directorySelect: function (directoryInfo) {
|
||||
if (typeof directoryInfo === 'object') {
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_parent/0',
|
||||
device: taskInfo.getRawDeviceID(this.deviceID),
|
||||
content: {
|
||||
folder: [directoryInfo.id],
|
||||
},
|
||||
}))
|
||||
if (this.enableSetting) {
|
||||
if (typeof directoryInfo === 'object') {
|
||||
if (this.deviceInfo.info.parent.folder === undefined || this.deviceInfo.info.parent.folder.indexOf(directoryInfo.id) === -1) {
|
||||
if (this.deviceInfo.info.isSync === false) {
|
||||
this.deviceInfo.info.parent.folder = []
|
||||
this.deviceInfo.info.parent.folder.push(directoryInfo.id)
|
||||
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
|
||||
header: 'device_parent/0',
|
||||
device: taskInfo.getRawDeviceID(this.deviceID),
|
||||
content: {
|
||||
folder: [directoryInfo.id],
|
||||
},
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
enableChangeFile: function () {
|
||||
this.enableSetting = true
|
||||
this.setArchiveSettings()
|
||||
},
|
||||
setArchiveSettings: async function () {
|
||||
this.deviceInfo = taskInfo.getDeviceInfo(this.deviceID)
|
||||
const now = this.getCurrentTime()
|
||||
// filename init
|
||||
// TODO this.deviceInfo.info.isSync is false, beacause refresh is faster than get_device_info response
|
||||
if (this.deviceInfo.info.isSync) {
|
||||
this.fileNameInput = this.deviceInfo.info.recording_file_name
|
||||
} else {
|
||||
this.fileNameInput = now
|
||||
}
|
||||
if (this.enableSetting) {
|
||||
if (this.deviceInfo === null) {
|
||||
this.deviceInfo = taskInfo.getDeviceInfo(this.deviceID)
|
||||
}
|
||||
const now = this.getCurrentTime()
|
||||
// filename init
|
||||
if (this.deviceInfo.info.isSync) {
|
||||
this.fileNameInput = this.deviceInfo.info.recording_file_name
|
||||
} else {
|
||||
if (this.deviceInfo.info.recording_file_name === 'recording_data' || this.deviceInfo.info.recording_file_name.split('-').length === 7) {
|
||||
this.fileNameInput = now
|
||||
} else {
|
||||
this.fileNameInput = this.deviceInfo.info.recording_file_name
|
||||
}
|
||||
}
|
||||
|
||||
// directory init
|
||||
const collection = await api.getCollectionsAll()
|
||||
this.directoryOptions = collection.data.filter(el => el.name !== 'root')
|
||||
this.fileNameChange(this.fileNameInput)
|
||||
|
||||
if (Object.keys(this.deviceInfo.info.parent).length === 0) {
|
||||
this.directory = this.directoryOptions[0]
|
||||
} else {
|
||||
for (const directory of this.directoryOptions) {
|
||||
if (this.deviceInfo.info.parent.folder.includes(directory.id)) {
|
||||
this.directory = directory
|
||||
// directory init
|
||||
const collection = await api.collection.getAll()
|
||||
this.directoryOptions = collection.data.filter(el => el.name !== 'root')
|
||||
|
||||
if (Object.keys(this.deviceInfo.info.parent).length === 0) {
|
||||
this.directory = this.directoryOptions[0]
|
||||
} else {
|
||||
for (const directory of this.directoryOptions) {
|
||||
if (this.deviceInfo.info.parent.folder.includes(directory.id)) {
|
||||
this.directory = directory
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,6 +166,10 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
this.pageInit()
|
||||
this.enableTimer = setTimeout(this.enableChangeFile, 1000)
|
||||
},
|
||||
destroyed () {
|
||||
clearTimeout(this.enableTimer)
|
||||
},
|
||||
watch: {
|
||||
deviceID: function (val) {
|
||||
|
||||