Compare commits

...

341 Commits

Author SHA1 Message Date
Jordan Hsu 9c45ab8caa Merge branch 'testing/trigger' into testing/security 2022-01-10 16:18:31 +08:00
Jordan Hsu 8c53573857 [add] trigger will save param when start 2022-01-06 16:42:18 +08:00
Jordan Hsu 9a77e6dcff [modify] neulive 3.5 sti constraint 2022-01-06 13:09:52 +08:00
Jordan Hsu c8644f320a [fix] display bug when F5 2022-01-05 16:42:35 +08:00
Jordan Hsu 8b6348e77e bug fix and modify trigger mode option default to output 2022-01-05 16:04:37 +08:00
Jordan Hsu 48555dd793 [modify] trigger will automatically open chart when starting 2022-01-05 12:51:48 +08:00
Jordan Hsu 02617bbb86 [fix] trigger display order bug 2022-01-05 12:50:19 +08:00
peterlu14 5328bd76ba [fix] sd data from api 2022-01-04 14:13:38 +08:00
Jordan Hsu 9d19fd3fc9 add neu 3.1 sample rate option 2022-01-04 11:14:46 +08:00
Alan Lin 1e2bf182bf neu31 update adc_clk ratio formula 2022-01-04 11:03:23 +08:00
Alan Lin 288f9b325c update download SD function 2021-12-27 18:22:03 +08:00
Jordan Hsu e4a8f1e8d3 bug fix 2021-12-27 17:41:29 +08:00
Jordan Hsu 48ce6e6342 [add] chart hide initially and adjust x axis 2021-12-24 16:39:28 +08:00
TommyXin 7f0564a3ca Merge remote-tracking branch 'origin/neulive_hide_gimer' into testing/trigger 2021-12-24 12:05:05 +08:00
Jordan Hsu aa9c8c21b7 [modify] trigger mqtt route 2021-12-24 11:40:23 +08:00
TommyXin 0924c20e9e Merge remote-tracking branch 'origin/neulive_hide_gimer' into testing/trigger 2021-12-22 18:21:59 +08:00
Jordan Hsu a239223361 [add] trigger chart 2021-12-22 17:33:03 +08:00
peterlu14 444663def3 Merge branch 'feature/dpv' into testing/security 2021-12-22 13:36:39 +08:00
Jordan Hsu e0341356c8 [add] trigger list ui with mqtt 2021-12-21 16:26:45 +08:00
Jordan Hsu b56c753063 [add] trigger list ui layout 2021-12-21 10:12:39 +08:00
Jordan Hsu 04741d8a77 [modify] triggerList to vuex 2021-12-21 10:10:34 +08:00
Jordan Hsu 3721e4a515 [add] device overview with trigger 2021-12-20 16:11:01 +08:00
Alan Lin 0afd9edd7b [fix] download & sd_card click 2021-12-15 17:32:51 +08:00
TommyXin 44d2ba6b41 fix google font error 2021-12-14 18:50:53 +08:00
TommyXin d567186240 fix sti3.5ex channel display 2021-12-07 13:38:46 +08:00
TommyXin cbb81add56 fix 3.5 sti ex ch error 2021-12-07 13:31:50 +08:00
TommyXin c8dded35f5 neulive3.5 sti ex 2021-12-06 18:26:50 +08:00
TommyXin d5dac7a9b3 Merge branch 'neulive_hide_gimer' into testing/security 2021-12-01 16:31:27 +08:00
TommyXin 1a183322ab fix device id not found 2021-12-01 10:55:54 +08:00
TommyXin 7e401621c7 fix default chart generator only consider RECORDING_CH 2021-12-01 10:45:10 +08:00
TommyXin 1485eba2b3 fix check ch number 2021-11-30 10:31:59 +08:00
TommyXin e908f73857 fix file can not show data 2021-11-29 18:40:30 +08:00
TommyXin f587f2b689 fix sd-card api 2021-11-29 18:20:32 +08:00
TommyXin 12eb41fcad fix sd-card icon 2021-11-29 17:38:34 +08:00
TommyXin 4a2b3f6a94 fix font error & auto get controller id 2021-11-29 17:03:34 +08:00
TommyXin 8e9dd79002 change id 2021-11-26 10:34:33 +08:00
TommyXin ea2f9c6748 Merge branch 'neulive_hide_gimer' into testing/security 2021-11-26 10:31:42 +08:00
TommyXin 4af2178225 Merge remote-tracking branch 'origin/feature/AS_wish' into testing/security 2021-11-26 10:31:26 +08:00
peterlu14 cc451f53cc [update] fix realtime filter channel & collapse open 2021-11-25 15:15:14 +08:00
Jordan Hsu 419b8e373f [add] sti pattern sketch map 2021-11-25 15:13:55 +08:00
peterlu14 ffd2b611d3 [update] fix realtime filter channel & collapse open 2021-11-25 14:43:57 +08:00
Jordan Hsu e05fa1c26b [add] chart pointer 2021-11-25 11:00:19 +08:00
Jordan Hsu 98d431fac0 [modify] filter popup without confirm button 2021-11-25 10:31:50 +08:00
Jordan Hsu c1fb4e3488 [add] select all / inverse select button 2021-11-24 18:17:55 +08:00
Jordan Hsu 3239728b0d [add] auto-resize real-time grid 2021-11-24 17:54:06 +08:00
Jordan Hsu 8941e827c1 [add] individual grid iir filter 2021-11-24 15:14:06 +08:00
Jordan Hsu d2eb180381 tmp 2021-11-23 18:14:59 +08:00
peterlu14 01a55781dd [update] sdcard filename change & modal style 2021-11-23 16:39:39 +08:00
warren30815 c2e8aaae06 fix EliteDataReplay overview bug 2021-11-23 02:04:50 +00:00
peterlu14 594fc9da13 [update] update message & api server fail not show 2021-11-22 18:38:06 +08:00
Jordan Hsu 721bab177b [fix] replay bug 2021-11-22 17:11:55 +08:00
peterlu14 6b7828a944 [update] sd card upload show message 2021-11-19 18:03:14 +08:00
Roy c388474952 update global chart lib 2021-11-19 11:42:52 +08:00
peterlu14 75db0a3c13 [update] new module vue notification 2021-11-18 20:42:15 +08:00
Alan Lin 802d6f7d3a swap stop all ins 2021-11-18 17:22:10 +08:00
peterlu14 830e93d9d1 [update] notify rebuild 2021-11-18 14:15:52 +08:00
Jordan Hsu 09c46a282b Merge remote-tracking branch 'origin/feature/download_offline' into neulive_hide_gimer 2021-11-18 12:04:44 +08:00
peterlu14 50693075f9 [update] add sercurity feature 2021-11-17 19:06:48 +08:00
Jordan Hsu 9d22f80c0e [add] elite replay can set window start and size 2021-11-16 16:32:05 +08:00
Jordan Hsu 41a7991255 Merge remote-tracking branch 'origin/feature/dpv' into feature/dpv 2021-11-16 16:31:06 +08:00
peterlu14 623ff914bf Merge branch 'feature/download_offline' into feature/dpv 2021-11-16 14:49:53 +08:00
peterlu14 99dc8d7996 [update] excel format fix 2021-11-16 14:47:36 +08:00
peterlu14 e30416e910 Merge branch 'feature/download_offline' into feature/dpv 2021-11-16 11:37:35 +08:00
peterlu14 72a9ded776 [update] recover controller id 2021-11-15 15:59:06 +08:00
peterlu14 dfbbcdedf1 [update] remove download time limit 2021-11-12 11:01:30 +08:00
Jordan Hsu 1bcbfa953d [add] dpv cycle & check E final 2021-11-11 16:53:39 +08:00
peterlu14 282e435217 [update] add user guide 2021-11-10 16:22:23 +08:00
peterlu14 23d45cfa2f [update] remove device store 2021-11-10 16:19:02 +08:00
peterlu14 da4049bf77 [update] remove guide doc 2021-11-10 16:08:52 +08:00
peterlu14 73ccc68220 [update] connection timeout 2021-11-10 13:24:36 +08:00
Jordan Hsu 25f36a54dd [fix] pdf path error 2021-11-10 11:59:31 +08:00
peterlu14 0bfba093fd [update] download 2021-11-10 10:49:16 +08:00
Jordan Hsu 5e0b14c8e0 [add] device guideline pdf 2021-11-09 20:23:50 +08:00
Jordan Hsu df6e05c8c0 fix trigger UI bug 2021-11-08 14:33:00 +08:00
peterlu14 36c72e27a6 Merge branch 'feature/download_offline' into neulive_hide_gimer 2021-11-05 18:40:24 +08:00
peterlu14 a141535fc9 Merge remote-tracking branch 'origin/feature/neulive31_35_sti_1104' into neulive_hide_gimer 2021-11-05 18:40:11 +08:00
peterlu14 50a2254d44 [update] hide gimer icon 2021-11-05 18:39:55 +08:00
Jordan Hsu 3aaefa6529 bug fix 2021-11-05 17:53:50 +08:00
peterlu14 74d8fdb077 [update] add package file-saver 2021-11-04 22:25:38 +08:00
peterlu14 5b655b2cd0 [update] offline download 2021-11-04 21:51:22 +08:00
Jordan Hsu 8e7f0ecb71 [modify] neulive 3.1/3.5 sti 2021-11-04 14:08:16 +08:00
peterlu14 c8aae625e5 [update] remove offline download directory 2021-11-04 13:58:17 +08:00
peterlu14 a1bb7517f7 [update] offline download excel format & memory & data loss 2021-11-03 10:12:29 +08:00
TommyXin fc65108051 fix bug repeat interval 2021-11-02 17:05:12 +08:00
TommyXin ff0be97176 hide repeatNumber when unlimit cycle 2021-11-02 17:00:29 +08:00
TommyXin 6cdd0f772e fix check recording channels 2021-11-02 16:29:34 +08:00
TommyXin b61f51cab2 cycle unlimited no setStiTimeout & check recording one channel at least 2021-11-02 15:43:26 +08:00
Jordan Hsu b00649f03e bug fix 2021-11-01 18:34:45 +08:00
Jordan Hsu 755525dc28 [fix] elite replay cycle bug 2021-11-01 17:36:34 +08:00
Jordan Hsu 91929c0a34 Merge branch 'release/AS_1027' into feature/dpv 2021-11-01 17:04:30 +08:00
Jordan Hsu 389040a98a [add] elite replay param table 2021-11-01 16:49:50 +08:00
Jordan Hsu 2908f2c510 [modify] replay UI layout 2021-11-01 16:04:32 +08:00
Jordan Hsu 08c732ace8 toggle color to green 2021-10-29 18:54:19 +08:00
Jordan Hsu 73fbaf92ab adjust trigger UI 2021-10-29 18:50:49 +08:00
Jordan Hsu 80d8bdf7f9 [add] trigger block 2021-10-29 17:15:53 +08:00
Jordan Hsu 40c09de1dd [modify] UI disable mode color 2021-10-29 16:00:17 +08:00
Jordan Hsu 1541a57b1b [modify] dpv UI and switch 2021-10-29 15:32:19 +08:00
Jordan Hsu 2f5ef791e4 [modify] dpv rule 2021-10-29 15:18:25 +08:00
Jordan Hsu cc64f62335 Merge branch 'feature/elite_trigger' into feature/dpv 2021-10-28 14:52:33 +08:00
Jordan Hsu 66c19ab51b [modify] dpv slider two pins 2021-10-28 14:51:48 +08:00
Jordan Hsu fa7b51143b [update] neulive 3.5 repeatIntervalCheck with cycle 2021-10-28 09:54:45 +08:00
peterlu14 7c300a4ce2 [update] neulive3.5 repeatIntervalCheck 2021-10-28 00:04:32 +08:00
TommyXin e6a9a3fbd6 Merge branch 'neulive_sunpower' into release/AS_1027 2021-10-27 22:16:35 +08:00
TommyXin f523c189dc remove console.log 2021-10-27 22:15:42 +08:00
TommyXin bc86b2f541 Merge branch 'neulive_sunpower' into release/gimer_1026 2021-10-27 22:14:05 +08:00
peterlu14 5ea023df43 [update] remove filetable get sd card uuidList 2021-10-27 22:08:57 +08:00
TommyXin ebf912a971 clear stiTimeOut 2021-10-27 21:59:15 +08:00
TommyXin d440dfbe39 clear stiTimeOut 2021-10-27 21:51:52 +08:00
Jordan Hsu 8257a30118 [modify] elite replay layout 2021-10-27 16:29:50 +08:00
Jordan Hsu 68cec7d482 [fix] abs toggle bug 2021-10-27 16:28:42 +08:00
TommyXin e61d4340a7 gimer id 2021-10-27 16:12:33 +08:00
TommyXin 810e8c46e9 update 2021-10-27 16:12:12 +08:00
TommyXin 1c32850990 remove gimer routes 2021-10-27 16:02:46 +08:00
TommyXin 21bb7440f1 Merge remote-tracking branch 'origin/release/gimer_1026' into release/gimer_1026 2021-10-27 15:50:32 +08:00
TommyXin 505a2a9e03 Merge branch 'neulive_sunpower' into release/gimer_1026 2021-10-27 15:48:13 +08:00
TommyXin f6a6c4101d update gimer icon 2021-10-27 15:47:34 +08:00
TommyXin c4fc506f9f ch number for filter 2021-10-27 15:28:20 +08:00
TommyXin 3a8315339a Merge remote-tracking branch 'origin/neulive_sunpower' into neulive_sunpower 2021-10-27 15:27:06 +08:00
TommyXin 08b3904cb9 channel number & amplitude change 2021-10-27 15:26:55 +08:00
peterlu14 b2ba658e6e [update] add library name list 2021-10-27 15:12:21 +08:00
peterlu14 76a16cae1a [update] ampgain diff from library 2021-10-27 15:01:21 +08:00
peterlu14 04d564afd8 [update] offline download 2021-10-27 14:49:47 +08:00
TommyXin 9c42c05621 [bug] sti ex time = interval * number 2021-10-27 14:46:33 +08:00
Jordan Hsu 42925bec2d Merge branch 'release/neulive_elite_1012' into feature/dpv 2021-10-27 13:56:51 +08:00
Jordan Hsu 5be30fc910 [modify] elite replay abs button style 2021-10-27 13:55:36 +08:00
Jordan Hsu c26a72749e [fix] dpv bug 2021-10-27 13:21:23 +08:00
Jordan Hsu ca41619338 [modify] elite replay UI layout 2021-10-27 12:10:28 +08:00
Jordan Hsu 4e119b5eaf [modify] dpv UI layout 2021-10-27 11:16:56 +08:00
TommyXin 468c5a2567 regular 3.5 check sti done 2021-10-27 11:01:43 +08:00
TommyXin 70651f55c0 [update] neulive regular 3.5 UI 2021-10-27 10:33:19 +08:00
Jordan Hsu 02aff9f02c [fix] typo 2021-10-27 10:21:42 +08:00
Jordan Hsu c1dbf93d65 [add] missing formula 2021-10-27 00:29:26 +08:00
Jordan Hsu 6effc08904 [init] trigger UI 2021-10-27 00:03:39 +08:00
TommyXin f237efc430 Merge remote-tracking branch 'origin/feature/sd_card_check_and_init' into release/gimer_1026 2021-10-26 18:45:34 +08:00
TommyXin ab15129100 Merge branch 'neulive_sunpower' into release/gimer_1026 2021-10-26 18:43:46 +08:00
TommyXin 38f440ea67 add gimer icon to app sidebar 2021-10-26 18:32:18 +08:00
peterlu14 6c9fb2e513 [update] update transmission_type status 2021-10-26 17:15:05 +08:00
peterlu14 92e8c15308 [update] restruct download 2021-10-26 17:13:42 +08:00
TommyXin 7c6a05ecc4 amplitude * 10 (for UI) 2021-10-26 16:15:54 +08:00
TommyXin f63fca5fc4 remove console.log 2021-10-26 14:46:21 +08:00
TommyXin b59262643f Merge remote-tracking branch 'origin/feature/sd_card_check_and_init' into neulive_sunpower 2021-10-26 14:36:20 +08:00
TommyXin 2650ba10fb Merge branch 'feature/dpv' into neulive_sunpower 2021-10-26 14:35:56 +08:00
TommyXin 578578a312 multi filter & check stimulation 2021-10-26 14:35:04 +08:00
peterlu14 6e700e7201 [update] disable device_update_usb 2021-10-26 11:31:01 +08:00
TommyXin 99ef7bfe04 Merge branch 'neulive_sunpower' into feature/dpv 2021-10-26 11:07:52 +08:00
TommyXin 0d88866001 sti check exTime 2021-10-26 11:07:25 +08:00
TommyXin 0150eebb0c fix amp gain bug 2021-10-26 10:36:31 +08:00
Jordan Hsu f885812258 [add] missing code 2021-10-26 09:21:40 +08:00
Jordan Hsu 21f5c75836 [init] dpv front end with formula 2021-10-25 16:34:38 +08:00
TommyXin bf20a50107 realtime filter [notch] 2021-10-25 15:36:28 +08:00
TommyXin d72e59bb81 amp gain change 500&300 2021-10-22 22:00:48 +08:00
TommyXin 69058bd0f0 deviceList vuex 2021-10-22 21:25:45 +08:00
TommyXin 6639560dd4 Merge remote-tracking branch 'origin/release/neulive_elite_1012' into neulive_sunpower 2021-10-22 17:26:42 +08:00
Jordan Hsu 3ed4253b13 [update] gimer / 3.5 t range constraint rule 2021-10-22 11:27:25 +08:00
Jordan Hsu c6555cb4f3 Merge branch 'neulive_sunpower' into release/neulive_elite_1012 2021-10-21 14:18:55 +08:00
TommyXin 62d4b634c2 set power enable while record 2021-10-21 14:09:35 +08:00
Jordan Hsu a8e2ec509e [add] repeat interval rule 2021-10-21 13:51:24 +08:00
Jordan Hsu 5c35bff99f [add] gimer t range rule 2021-10-20 18:15:01 +08:00
TommyXin 2e76071ea6 Merge branch 'iir_filter' into neulive_sunpower 2021-10-20 15:21:38 +08:00
TommyXin ce9cac1f02 gimer ui 2021-10-20 15:20:18 +08:00
Jordan Hsu feb9c84488 [add] abs toggle 2021-10-19 19:37:04 +08:00
TommyXin ac0aef6109 [TODO] filter by chart and detect device from ch (get fs) 2021-10-19 18:47:47 +08:00
Jordan Hsu 1b424bcfd2 [fix] elite replay param panel mode bug 2021-10-19 15:15:05 +08:00
Jordan Hsu 05b33bd9bf [fix] neulive replay missing code 2021-10-19 15:14:12 +08:00
Jordan Hsu 62424e3438 [modify] replay axis log scale 2021-10-19 14:46:57 +08:00
TommyXin 16799a85bd Merge branch 'neulive_sunpower' into iir_filter 2021-10-19 14:11:35 +08:00
TommyXin 7f295cc86e Merge remote-tracking branch 'origin/feature/sd_card_check_and_init' into iir_filter 2021-10-19 14:11:16 +08:00
TommyXin 5651cb68a5 fix button 256 2021-10-19 08:57:43 +08:00
TommyXin 80e1841776 repeat num 255 2021-10-18 19:17:26 +08:00
TommyXin af337bdde6 check stimulating & auto close save power node while recording 2021-10-18 16:27:20 +08:00
TommyXin 9e59da8fd1 gimer start condition 2021-10-18 14:23:45 +08:00
TommyXin df2815eb0e sti check recording status 2021-10-15 19:05:11 +08:00
TommyXin 70750de23d taskDeviceList doesn't destroy deviceList 2021-10-15 18:12:57 +08:00
TommyXin 89f45520d3 fix hide device panel bug 2021-10-15 17:31:17 +08:00
peterlu14 8b08cd899b [update] usb & rename api & check sd usb when connect 2021-10-15 16:02:11 +08:00
TommyXin e808352244 electrode site support double color button 2021-10-15 16:00:19 +08:00
TommyXin 4e777fff1b check device status 2021-10-14 19:00:19 +08:00
peterlu14 3e9db25dad [update] recover controller id 2021-10-14 11:03:51 +08:00
peterlu14 033088ddde [update] sdcard check and init 2021-10-13 22:01:50 +08:00
peterlu14 47712e5ff1 [update] fix spike first timemark 2021-10-13 21:59:26 +08:00
Alan Lin 5e883ef672 Merge branch 'neulive_sunpower' of gitlab.com:bioproscientific/bioprovue into neulive_sunpower 2021-10-13 16:17:07 +08:00
Alan Lin a7591860cf update T2, T4 counter 2021-10-13 16:16:44 +08:00
Jordan Hsu 68510b3c42 [fix] import path error 2021-10-13 16:11:21 +08:00
TommyXin 1f102c3816 route task Gimer 2021-10-13 15:27:16 +08:00
Alan Lin 1b1ee5f58a update Giner STI.vue 2021-10-13 13:55:20 +08:00
Jordan Hsu a20f24c45f [fix] t range rounding and GM channel bug 2021-10-13 11:55:17 +08:00
peterlu14 e29e0caee6 Merge branch 'feature/spike_UI_enhance' into release/neulive_elite_1012 2021-10-12 17:38:41 +08:00
peterlu14 715f1ef1d0 [update] align controller_id 2021-10-12 17:30:40 +08:00
Jordan Hsu 537b668d1e click stop to click native stop 2021-10-12 16:03:12 +08:00
Jordan Hsu a658203c0a Protect recording channels button add parasend event 2021-10-12 15:50:12 +08:00
Alan Lin 63e00b91f6 update t3t4 counter formula 2021-10-12 15:08:52 +08:00
peterlu14 cc7e2adc81 Merge branch 'feature/add_sd_icon' into feature/spike_UI_enhance 2021-10-12 12:16:05 +08:00
peterlu14 98738bcb10 [update] remove export info 2021-10-12 12:09:02 +08:00
peterlu14 e34605c488 [update] spike update 2021-10-12 11:29:19 +08:00
TommyXin 887ebc0907 real time iir filter 2021-10-08 18:08:11 +08:00
Jordan Hsu 91e4acbcb0 [fix] real time chart mode 2021-10-08 17:11:57 +08:00
Jordan Hsu 4bb59d5c87 [add] elite replay circle dot 2021-10-08 16:54:23 +08:00
peterlu14 ed3d8a81ff Merge branch 'feature/neulive3.5-sti-amp' into feature/spike_UI_enhance 2021-10-08 10:14:55 +08:00
peterlu14 87c9cba03c [update] spike data mqtt add 2021-10-08 10:09:25 +08:00
Jordan Hsu 1a08d7ff28 [modify] 3.5 & gm t range 2021-10-08 10:08:18 +08:00
TommyXin 641b001b88 fix realtime lose data 2021-10-07 19:44:02 +08:00
Jordan Hsu aeb265b206 [fix] eis param bug 2021-10-07 18:39:54 +08:00
Jordan Hsu 932b8c8025 [fix] freq start and end bug 2021-10-07 17:42:10 +08:00
Alan Lin f040150ac3 updata repeat time formula 2021-10-07 17:02:45 +08:00
Alan Lin 956f84476f Merge branch 'neulive_sunpower' of gitlab.com:bioproscientific/bioprovue into neulive_sunpower 2021-10-07 16:46:25 +08:00
TommyXin c028d14ade repeat number & interval 2021-10-07 16:44:54 +08:00
Alan Lin 5108c7ffd9 Merge branch 'neulive_sunpower' of gitlab.com:bioproscientific/bioprovue into neulive_sunpower 2021-10-07 15:38:33 +08:00
TommyXin 33f78b0f83 save power mode bool to number 2021-10-07 15:36:36 +08:00
Alan Lin c12ded4834 Merge branch 'neulive_sunpower' of gitlab.com:bioproscientific/bioprovue into neulive_sunpower 2021-10-07 15:34:06 +08:00
TommyXin ad3553a68e fix save power mode 2021-10-07 15:33:50 +08:00
Alan Lin 6608ee9e86 Merge branch 'neulive_sunpower' of gitlab.com:bioproscientific/bioprovue into neulive_sunpower 2021-10-07 15:17:53 +08:00
Alan Lin 2388e82c5d T3, T4 counter use correct formula 2021-10-07 15:17:42 +08:00
TommyXin 72d87712b3 save power mode & protect channels 2021-10-07 15:15:42 +08:00
Alan Lin 2e1c3237f4 add new parameter 2021-10-07 14:08:10 +08:00
Jordan Hsu dec21dfee0 [modify] eis ui 2021-10-07 14:06:02 +08:00
Jordan Hsu 7bde032cf6 [fix] eis param typo 2021-10-07 13:49:21 +08:00
Jordan Hsu f83ad1efbf Merge branch 'feature/eis_replay' into release/elite_1007 2021-10-07 13:47:24 +08:00
TommyXin b04d9ff29e fix Trange_CH0 cannot refresh 2021-10-06 15:57:46 +08:00
TommyXin 86e3cee7ec add save power mode / protect channel 2021-10-06 15:03:46 +08:00
TommyXin 6a96620549 fix bug 2021-10-05 18:15:20 +08:00
TommyXin 1d5813c8fa window 2021-10-05 18:00:39 +08:00
TommyXin b717bf8906 electrode site 2021-10-05 16:42:17 +08:00
peterlu14 de8fbc9bbe [update] spike button eventproof 2021-10-05 15:33:33 +08:00
peterlu14 403be30139 Merge branch 'release/merge_SD_card_UI_0924_2' into feature/neulive3.5-sti-amp 2021-10-05 11:09:59 +08:00
Jordan Hsu c307735dc3 [done] eis replay 2021-10-04 18:39:01 +08:00
TommyXin f88e28616e sti pos 2021-10-04 18:00:22 +08:00
TommyXin a102567dea recording site 2021-10-04 17:51:23 +08:00
peterlu14 46017134d8 [update] spike optimize 2021-10-01 14:21:12 +08:00
peterlu14 e2298a6ccc [update] download excel bug fix 2021-09-27 20:21:01 +08:00
peterlu14 5a61e24495 [update] icon usb to sd card & remove ! 2021-09-24 19:37:38 +08:00
peterlu14 c4007b7930 Merge branch 'feature/SD_card_UI' into release/merge_SD_card_UI_0924 2021-09-24 12:52:21 +08:00
peterlu14 2fe1cd6e00 [update] add progress bar & controller sd_uploading check 2021-09-24 12:50:29 +08:00
peterlu14 4cc7b9e12f [update] mac address change & get sync to async 2021-09-22 14:33:06 +08:00
peterlu14 8b4f210f95 Merge commit '1af50d0bfc7ec75a6aaf1aa493b31b29fc20882a' into feature/SD_card_UI 2021-09-22 14:31:46 +08:00
peterlu14 1af50d0bfc [update] databatch 2021-09-17 13:26:36 +08:00
TommyXin 99b2b9dfce remove check param 2021-09-16 17:05:24 +08:00
TommyXin 1004c7075e [update] EIS unit ch4&8, window by elite lib ver. 2021-09-16 17:05:16 +08:00
peterlu14 8f4cbc0eeb Merge remote-tracking branch 'origin/feature/neulive_replay_wish' into release/neulive_elite_0913 2021-09-15 19:07:12 +08:00
TommyXin f741a2d018 fix x-axis unit 2021-09-15 19:06:46 +08:00
TommyXin 008897830d fix source X 2021-09-15 19:06:41 +08:00
TommyXin 5c297687f1 multi channel & unit 2021-09-15 19:06:32 +08:00
Jordan Hsu 213caf9796 [fix] replay window can't zoom bug 2021-09-15 17:10:21 +08:00
peterlu14 0fda2141dd [update] add record_in_sd option 2021-09-15 02:36:16 +08:00
peterlu14 3761493ec1 [update] remove sd card delete 2021-09-15 01:04:18 +08:00
peterlu14 87300e7a43 Merge remote-tracking branch 'origin/feature/SD_card_UI' into release/neulive_elite_0913 2021-09-15 00:59:47 +08:00
peterlu14 85103f5f12 [update] expand action width & change order 2021-09-15 00:56:58 +08:00
Jordan Hsu 1059a98c27 [add] sd button confirm modal before uploading 2021-09-14 15:54:57 +08:00
Jordan Hsu 8150afc624 Merge remote-tracking branch 'origin/feature/SD_card_UI' into feature/SD_card_UI 2021-09-14 14:13:30 +08:00
Jordan Hsu b0de357d89 [add] replay check if sd uploaded 2021-09-14 14:12:53 +08:00
peterlu14 44c1a41d99 Merge branch 'feature/SD_card_UI' into release/neulive_elite_0913 2021-09-14 14:00:28 +08:00
peterlu14 a6a9b64da2 [update] getSDuuidList 2021-09-14 13:05:05 +08:00
Jordan Hsu a4ccee71a8 [fix] sd card UI bug 2021-09-14 11:47:45 +08:00
Jordan Hsu 2cbdab696c Merge branch 'feature/neulive_replay_wish' into release/neulive_elite_0913 2021-09-13 18:48:35 +08:00
Jordan Hsu 3fe5e4af0c adjust UI 2021-09-13 18:42:51 +08:00
Jordan Hsu 577cf09951 [add] replay custom window start and size 2021-09-13 17:48:11 +08:00
peterlu14 0c18ce1829 Merge remote-tracking branch 'origin/feature/elite_replay_down_scale' into release/neulive_0913 2021-09-13 14:52:03 +08:00
peterlu14 7c336d4bd3 Merge remote-tracking branch 'origin/feature/neulive_replay_wish' into release/neulive_0913 2021-09-13 14:51:31 +08:00
Jordan Hsu 95955e23e0 [add] lock button 2021-09-13 14:07:44 +08:00
peterlu14 d387f83f87 [update] setting pic update & display fix 2021-09-10 20:03:13 +08:00
Jordan Hsu 0e1695bb4e [modify] elite replay will detect resample rate and auto down rate 2021-09-10 20:02:53 +08:00
peterlu14 fba42100d8 Merge branch 'feature/setting_update' into devlop/neulive_merge_sd_card 2021-09-10 12:39:56 +08:00
peterlu14 acd1b300d7 Merge branch 'feature/SD_card_UI' into devlop/neulive_merge_sd_card 2021-09-10 12:39:26 +08:00
Jordan Hsu 3f4d5de662 [modify] nprogress color to red 2021-09-10 12:09:49 +08:00
Jordan Hsu 56f4f0274c [remove] elite sd card button 2021-09-10 11:51:31 +08:00
Jordan Hsu e6aeb9203d [fix] sd card UI won't re-render after changing page bug 2021-09-09 21:02:41 +08:00
Jordan Hsu da7581de63 [update] shell script readme 2021-09-09 18:29:14 +08:00
Jordan Hsu 6d9294775d clean up sd card code 2021-09-09 18:08:14 +08:00
Jordan Hsu 3a7d685d31 [fix] monophasic checkpoint bug 2021-09-09 17:50:51 +08:00
peterlu14 16df8514ba [update] setting pic update & display fix 2021-09-09 13:39:21 +08:00
Jordan Hsu a5085cbbe6 sd card UI 2021-09-08 21:29:55 +08:00
peterlu14 1fbf8c0022 [update] download replay data 2021-09-08 20:07:28 +08:00
peterlu14 0f5cbaf778 [update] sd_data download & replay 2021-09-08 16:26:49 +08:00
Jordan Hsu 2b5b42dd61 tmp for api debug 2021-09-08 13:52:59 +08:00
Jordan Hsu 4221a35f00 Merge remote-tracking branch 'origin/develop/neulive_0901' into feature/SD_card_UI 2021-09-08 11:06:41 +08:00
peterlu14 c3fc287b0f [update] add sdcard api & get sd data 2021-09-08 11:02:44 +08:00
Jordan Hsu 047a72e9c6 [add] SD card init func 2021-09-07 16:56:29 +08:00
Jordan Hsu b79a4a2091 [init] SD card UI 2021-09-07 15:44:44 +08:00
Jordan Hsu 4a8be436ce [fix] monophasic bug 2021-09-06 15:53:52 +08:00
peterlu14 102d39b4b5 [update] add sample rate 2021-09-06 14:11:14 +08:00
peterlu14 e8479f80ca [update] support past replay & data:axis 75:1 2021-09-06 13:18:17 +08:00
peterlu14 3aa5db1455 [update] sti channel support 16 channel 2021-09-06 11:44:47 +08:00
peterlu14 2e33ef7abb [update] fix download bug & add 0 ~ 11 device 2021-09-06 11:41:28 +08:00
Jordan Hsu 78ec2fd492 [modify] spike UI with lttb algo. 2021-09-03 21:09:09 +08:00
peterlu14 d12084324a [update] spike ui save 2021-09-03 19:14:18 +08:00
Jordan Hsu b3580bfa76 [modify] neulive replay unit uV and clear redundant code 2021-09-03 16:15:18 +08:00
peterlu14 5b57e40575 [update] remove 3.5 rf & led 2021-09-02 20:26:38 +08:00
peterlu14 14679182df [update] move mem RF & RF & led to setting 2021-09-02 20:20:44 +08:00
peterlu14 db0111d1db [update] amplitude rebuild & fix STI_T4 2021-09-01 10:57:35 +08:00
peterlu14 21cb382a1f [update] replace ADC_CLOCK to SAMPLE_RATE & 3.5 RECORDING_CH 2021-09-01 10:55:58 +08:00
peterlu14 1d8ef94ec6 Merge remote-tracking branch 'origin/feature/spike_UI' into release/0824_test 2021-08-27 19:08:52 +08:00
peterlu14 e49b6fb791 [update] export fix & subplot message & download 2021-08-27 19:07:57 +08:00
peterlu14 52e3d70dc8 [update] neulive ui switch & STI cycle amplitude T1-T4 fix 2021-08-26 16:59:39 +08:00
Roy a33bbd0581 fix current input value 2021-08-26 11:58:43 +08:00
Roy cd97260230 fix volt input value 2021-08-26 11:38:38 +08:00
Roy b9242764ab Merge branch 'e_0824_func_gen_bug' into release/0824_test 2021-08-26 10:46:36 +08:00
Jordan Hsu e8d75b9877 [init] spike ui 2021-08-26 02:03:30 +08:00
TommyXin 433e567e74 neulive 3.5 UI 2021-08-25 20:44:28 +08:00
TommyXin fbbebb3423 fix grid uV 2021-08-25 16:33:40 +08:00
Roy 6f2aab5276 OCP mode add current range button 2021-08-25 16:12:44 +08:00
TommyXin d82b1cb735 grid support input 'auto' 2021-08-25 01:17:07 +08:00
Roy 8aa87d587f update elite1.5 button 2021-08-24 17:40:32 +08:00
TommyXin 38503e198e EIS volt range 2021-08-24 04:35:02 +08:00
Jordan Hsu 8b78cdcdbd Merge remote-tracking branch 'origin/release/0812_test' into feature/spike_UI 2021-08-20 16:08:37 +08:00
peterlu14 94feff568a Merge remote-tracking branch 'origin/release/0812_test' into release/0812_test 2021-08-20 15:49:07 +08:00
peterlu14 06336bbd61 [update] add api spikeDetect 2021-08-20 15:48:18 +08:00
TommyXin 33b041a31b Merge remote-tracking branch 'origin/release/0812_test' into release/0812_test 2021-08-19 10:40:27 +08:00
TommyXin 14dda58fac neulive uV 2021-08-19 10:40:12 +08:00
Jordan Hsu f9bf41980b [modify] neulive replay function name 2021-08-18 14:55:45 +08:00
Jordan Hsu 6b20902c74 [fix] neulive stimulation phasic bug 2021-08-18 14:16:45 +08:00
peterlu14 ced0362910 Merge remote-tracking branch 'origin/release/0812_test' into release/0812_test 2021-08-17 16:59:13 +08:00
peterlu14 467016140f [update] real-time axis setting & edf format 2021-08-17 16:58:40 +08:00
Jordan Hsu f6e642cd5f Merge remote-tracking branch 'origin/release/0812_test' into release/0812_test 2021-08-13 16:00:48 +08:00
Jordan Hsu 7c5aed4dbc [fix] sti t range check bug 2021-08-13 15:54:55 +08:00
peterlu14 c069354415 [fix] EIS download 2021-08-13 13:14:10 +08:00
Jordan Hsu 738b58fded [modify] speed up neulive replay 2021-08-12 18:59:19 +08:00
Jordan Hsu f7c89585ac [modify] elite chart sampling method to lttb algo. and fix overview scale bug 2021-08-12 18:06:34 +08:00
peterlu14 36ed59816d Merge branch '0809_release_version' into release/0812_test 2021-08-12 17:01:34 +08:00
Jordan Hsu 516d20333c Merge remote-tracking branch 'origin/0809_release_version' into 0809_release_version 2021-08-12 17:00:56 +08:00
Jordan Hsu 74b8472c1d [modify] replay resampling method 2021-08-12 17:00:34 +08:00
peterlu14 ecb9e02610 [update] about to setting 2021-08-12 16:54:44 +08:00
peterlu14 74dea74476 Merge remote-tracking branch 'origin/0809_release_version' into release/0812_test 2021-08-12 14:40:47 +08:00
TommyXin 588a791bc1 Merge remote-tracking branch 'origin/0809_release_version' into 0809_release_version 2021-08-12 14:20:48 +08:00
TommyXin cd3e6f08f5 time 500ms&neulive uV&device panel height 2021-08-12 14:20:06 +08:00
peterlu14 1370e5659e [update] axis data divide 100 2021-08-12 13:42:48 +08:00
peterlu14 e18fa916b5 Merge branch 'download_rebuild' into 0809_release_version 2021-08-12 13:11:04 +08:00
peterlu14 b5a920338a [update] remove old download routes 2021-08-12 13:10:19 +08:00
peterlu14 6c4660966c [update] adjust tooltip formatter 2021-08-12 12:57:27 +08:00
peterlu14 0db13d3404 [update] remove old download pages 2021-08-12 12:55:45 +08:00
TommyXin 8b96a7308c fix stop button 2021-08-12 11:06:05 +08:00
peterlu14 d7e69e250e Merge remote-tracking branch 'origin/0809_release_version' into download_rebuild 2021-08-12 10:30:25 +08:00
TommyXin 14217aa1ea fix EIS freq max 2021-08-12 09:50:50 +08:00
peterlu14 506080c518 [update] replay download url fix 2021-08-12 04:23:53 +08:00
peterlu14 794b71cc9f [update] rebuild download structure 2021-08-12 04:16:40 +08:00
Jordan Hsu 7e355448e0 [fix] replay change scale bug 2021-08-10 19:53:37 +08:00
TommyXin 1bcf0d99e9 Merge remote-tracking branch 'origin/0809_release_version' into 0809_release_version 2021-08-10 19:28:48 +08:00
TommyXin af094ad93a fix subplot deviceOpions lose time 2021-08-10 19:28:37 +08:00
Jordan Hsu 062023bd95 [add] replay overview sampling function 2021-08-10 18:43:20 +08:00
Jordan Hsu fcef23b199 [fix] delete bug 2021-08-10 17:59:31 +08:00
Jordan Hsu 56051c881a [fix] replay layout bug 2021-08-10 17:29:19 +08:00
TommyXin 9bc027b445 fix subplot multi device selection 2021-08-10 16:27:57 +08:00
TommyXin 06528addc7 remove some style 2021-08-10 16:17:24 +08:00
301 changed files with 21970 additions and 6752 deletions
+25
View File
@@ -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",
@@ -7536,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",
@@ -12106,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",
@@ -17250,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",
+5
View File
@@ -13,6 +13,8 @@
"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",
@@ -27,6 +29,7 @@
"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",
@@ -35,6 +38,7 @@
"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",
@@ -54,6 +58,7 @@
"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",
Binary file not shown.
-3
View File
@@ -3,9 +3,6 @@
<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>BioPro Scientific</title>
+1 -1
View File
@@ -10,5 +10,5 @@ burn_to_raspberry.sh
```shell
sh ./burn_to_raspberry.sh <HOST> <PASSWORD>
e.g. sh ./burn_to_raspberry.sh pi@192.168.3.53 raspberry
e.g. sh ./burn_to_raspberry.sh pi@192.168.2.1 raspberry
```
+10 -2
View File
@@ -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,11 +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://' + location.href.split('/')[2] + ':8083')
// Vue.use(VueMqtt, 'ws://' + '192.168.151.125' + ':8083')
Vue.use(VueMqtt, 'ws://' + '192.168.3.48' + ':8083')
// Vue.use(VueMqtt, 'ws://' + '192.168.3.211' + ':8083')
Vue.prototype.GLOBAL = global_
+1
View File
@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

+3 -3
View File
@@ -136,7 +136,7 @@ export default {
</style>
<style lang='scss'>
.layout.gutter--xl {
padding: 0.5rem;
}
// .layout.gutter--xl {
// padding: 0.5rem;
// }
</style>
@@ -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>
@@ -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',
@@ -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,7 +1,7 @@
<template>
<div>
<div class="row row-equal">
<div class="flex md12 xl3 xs12 sm12 area-style">
<div class="flex md12 xl3 xs12 sm12">
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-accordion>
@@ -9,7 +9,7 @@
<span slot="header">Control Panel</span>
<div slot="body">
<div>
<top-control-panel :ref="'top_control_panel'" @refreshChart="setOption" @changeAxis="changeAxis"/>
<top-control-panel :ref="'top_control_panel'" @refreshChart="setOption" @changeAxis="changeAxis" @changeOverviewDataZoom="changeOverviewDataZoom"/>
</div>
</div>
</va-collapse>
@@ -18,11 +18,11 @@
</div>
</div>
<div :class="chartAreaClass" class="area-style">
<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'" @dblclick.native="distribute()" :cardheight="'88vh'" :chartheight="detailchartheight" :data="chartDetailData" />
<elite-replay-chart :ref="'chart_detail'" :cardheight="'88vh'" :chartheight="detailchartheight" :data="chartDetailData" />
<change-channel-value-min-max :ref="'set_min_max'"/>
</div>
</div>
@@ -51,14 +51,27 @@ export default {
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',
@@ -90,8 +103,6 @@ export default {
detailchartheight: '88vh',
dataInfo: {},
maxTime: 0,
startTime: 0,
endTime: 0,
zoomTime: 0,
initDone: false,
chartAreaClass: ['flex', 'xs12', 'sm12', 'md12', 'xl9', 'pa-0'],
@@ -156,7 +167,7 @@ export default {
})
let _gridNumber = 0
const register = this.metaList.map(meta => {
const setting = this.GLOBAL.getDefaultChartTypeByMode(meta.parameter_set.MODE)
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
@@ -220,21 +231,75 @@ export default {
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
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 = this.maxTime * e.start / 100
this.endTime = this.maxTime * e.end / 100
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) {
@@ -244,23 +309,9 @@ export default {
metaInfo = _meta
}
})
let scale = '100'
let scale = '1'
if (this.axisXDataType.description === 'Time') {
const sampleRate = metaInfo.parameter_set.SAMPLE_RATE / 10
scale = (((parseInt(metaInfo.time_duration) / 100000) * sampleRate) / 4000) * 0.1
console.log(scale)
// console.log(metaInfo.time_duration)
if (scale > 500) {
scale = '1000'
} else if (scale > 200) {
scale = '100'
} else if (scale > 30) {
scale = '10'
} else {
scale = '1'
}
} else {
scale = '1' // [TODO] select by user
scale = await this.computeResampleScale(metaInfo, metaInfo.time_duration)
}
console.log('overview scale:', scale)
// download data
@@ -284,6 +335,7 @@ export default {
// 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)
@@ -305,30 +357,21 @@ export default {
}
})
let scale = '100'
let scale = '1'
if (this.axisXDataType.description === 'Time') {
const sampleRate = metaInfo.parameter_set.SAMPLE_RATE / 10
scale = (((timeDur / 100000) * sampleRate) / 4000) * 0.1
console.log(scale)
// console.log(timeDur)
if (scale > 500) {
scale = '1000'
} else if (scale > 200) {
scale = '100'
} else if (scale > 30) {
scale = '10'
} else {
scale = '1'
}
} else {
scale = '1' // [TODO] select by user
scale = await this.computeResampleScale(metaInfo, timeDur)
}
// scale = '1000'
// 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: function (frame) { return frame[0] } })
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
@@ -341,10 +384,10 @@ export default {
const channelY = parseInt(this.axisYDataType.id)
const dataListY = this.dataInfo[meta][channelY][scale]
const isThisModeHasCycle = this.GLOBAL.hasCycleMode(metaInfo.parameter_set.MODE)
let startTime
let endTime
if (isThisModeHasCycle === true && this.axisXDataType.description !== 'Time') { // if有cycle的mode且目前x軸不為時間,抓出第一圈所在的時間段,初始化時先畫第一圈就好,加快初始時間
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 = []
@@ -357,21 +400,21 @@ export default {
}
}
const cycleDict = this.getCycleDictRec()(cycleDataList)
startTime = cycleDict[1][0] // [1]: 第一圈
endTime = cycleDict[1][1] // [1]: 第一圈
_startTime = cycleDict[1][0] // [1]: 第一圈
_endTime = cycleDict[1][1] // [1]: 第一圈
} else {
startTime = this.startTimeCurrent
endTime = this.endTimeCurrent
_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)) {
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)) {
if (_endTime >= parseInt(dataListY[i].start_time) && _endTime <= parseInt(dataListY[i].end_time)) {
endIndex = i
}
}
@@ -384,20 +427,26 @@ export default {
}
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 = JSON.parse(JSON.stringify(data[j]))
if (parseInt(data[j][0]) >= _startTime && parseInt(data[j][0]) <= _endTime) {
const processedData = data[j]
if (dataX !== undefined) {
processedData[0] = dataX[j][1]
}
// console.log(data)
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 = this.startTimeCurrent
this.chartDetailData.xAxis[_gridNumber].max = this.endTimeCurrent
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'
@@ -416,6 +465,7 @@ export default {
this.turnOffAxisEventHandler('click', this.showMinMaxPanel, { axis: 'x' })
this.turnOnAxisEventHandler('click', 'yAxis.axisLabel', this.showMinMaxPanel, { axis: 'y' })
}
this.hideChartLoading()
},
checkDataZoom: function () {
@@ -425,18 +475,22 @@ export default {
this.startTimeCurrent = this.startTime
this.endTimeCurrent = this.endTime
this.drawDetailData()
this.$refs.top_control_panel.resetScale()
}
}
},
changeAxis (gridIndex) {
if (this.initDone) {
const libName = this.metaList[gridIndex].device.library_name
let xType
let xValue // 1: I, 2: V, 3: R
let xValue
if (this.axisXDataType.description === 'Time') {
xType = 'Time'
} else {
xType = 'Elite'
if (libName === 'EliteZM15') {
xType = 'Elite'
} else if (libName === 'EliteEIS') {
xType = 'EliteEIS'
}
xValue = this.axisXDataType.id + 1
}
this.updateRegisteredChart({
@@ -446,52 +500,26 @@ export default {
deviceNameX: xType,
deviceIDX: this.metaList[gridIndex].name,
channelX: xValue,
deviceNameY: 'Elite',
deviceNameY: libName === 'EliteEIS' ? 'EliteEIS' : 'Elite',
deviceIDY: '',
channelY: this.axisYDataType.id + 1,
})
}
if (this.axisXDataType.description === 'Time') {
this.drawOverviewData()
}
this.drawDetailData() // reDraw
},
distribute: function () {
// if (this.chartDetailData.grid.length === 1) {
// this.chartDetailData.xAxis[0].axisLabel.show = false
// this.updateGridListChart({
// chartAllData: this.chartData,
// chartID: this.chartDetailData.chartID,
// gridLength: 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 {
// this.updateGridListChart({
// chartAllData: this.chartData,
// chartID: this.chartDetailData.chartID,
// gridLength: 1,
// })
// this.chartDetailData.series.forEach(series => {
// series.xAxisIndex = 0
// series.yAxisIndex = 0
// })
// this.chartDetailData.xAxis[0].axisLabel.show = true
// }
},
...mapActions('replay', [types.chart.init, types.chart.register, types.chart.clear, types.chart.updateGridList, types.chart.updateDataZoom]),
...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]),
...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]),
},
// use watch because va-select with @change will have bug
watch: {
},
async mounted () {
this.showChartLoading()
const metaIDList = this.$route.params.metaList.split('-')
@@ -502,7 +530,7 @@ export default {
console.log(this.metaList)
console.log(this.dataInfo)
await this.register()
this.drawOverviewData()
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' })
@@ -510,6 +538,7 @@ export default {
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 () {
@@ -522,27 +551,12 @@ export default {
delete this.chartData[id]
}
this.clearChart({ chartAllData: this.chartData })
this.startTime = 0
this.endTime = 0
this.windowLength = 0
},
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;
}
}
.layout.gutter--xl .row .flex {
padding: 0.4rem 0.5rem 0.1rem 0.5rem;
}
</style>
@@ -54,6 +54,9 @@ 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)
},
@@ -1,20 +1,71 @@
<template>
<div>
<va-card>
<edit-file-name style="display: inline;" :ref="'edit_file_name'"/>
<download-file style="display: inline;"/>
<delete-file style="display: inline;"/>
<br/>
<change-axis class="box_inline-block" :ref="'change_axis_x'" deviceName="elite" axis="x" @changeAxis="changeAxis" @changeUnit="changeUnit" @clearCycle="clearCycle" @resetScale="resetScale"/>
<change-unit class="box_inline-block" :ref="'change_unit_x'" deviceName="elite" axis="x" @refreshChart="refreshChart"/>
<change-scale class="box_inline-block" :ref="'change_scale_x'" deviceName="elite" axis="x" @refreshChart="refreshChart" @clearCycle="clearCycle"/>
<br/>
<change-axis class="box_inline-block" :ref="'change_axis_y'" deviceName="elite" axis="y" @changeAxis="changeAxis" @changeUnit="changeUnit" @clearCycle="clearCycle" @resetScale="resetScale"/>
<change-unit class="box_inline-block" :ref="'change_unit_y'" deviceName="elite" axis="y" @refreshChart="refreshChart"/>
<change-scale class="box_inline-block" :ref="'change_scale_y'" deviceName="elite" axis="y" @refreshChart="refreshChart" @clearCycle="clearCycle"/>
<change-cycle v-show="showCyclePanel" style="margin: 3px;" :ref="'change_cycle'" @refreshChart="refreshChart"/>
<show-resample-rate style="margin: 3px;"/>
<show-parameter style="margin: 3px;" :ref="'show_param'" deviceName="elite"/>
<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>
@@ -25,10 +76,13 @@ 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 {
@@ -39,13 +93,17 @@ export default {
ChangeUnit,
ChangeScale,
ChangeCycle,
AbsToggle,
DownloadFile,
DeleteFile,
EditFileName,
ShowParameter,
LockDataZoom,
ChangeWindowStartAndSize,
},
computed: {
...mapFields('replay', [
'metaList',
'showCyclePanel',
]),
},
@@ -55,6 +113,7 @@ export default {
},
data () {
return {
deviceName: '',
showCycle: false,
}
},
@@ -62,15 +121,22 @@ export default {
},
methods: {
init () {
this.$refs.change_axis_x.init()
this.$refs.change_axis_y.init()
this.$refs.change_unit_x.init()
this.$refs.change_unit_y.init()
this.$refs.change_scale_x.init()
this.$refs.change_scale_y.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.$refs.show_param.init(this.deviceName)
this.$refs.change_window_start_and_size.init()
},
changeOverviewDataZoom () {
this.$emit('changeOverviewDataZoom')
},
refreshChart (options) {
this.$emit('refreshChart', options)
@@ -88,13 +154,6 @@ export default {
clearCycle () {
this.$refs.change_cycle.clear()
},
resetScale () {
this.$refs.change_scale_x.reset()
this.$refs.change_scale_y.reset()
},
},
// use watch because va-select with @change will have bug
watch: {
},
mounted () {
},
@@ -102,9 +161,8 @@ export default {
</script>
<style lang="scss">
.box_inline-block {
padding: 2px;
margin: 2px;
display: inline-block;
.flex-container {
display: flex;
align-items: center;
}
</style>
@@ -1,7 +1,7 @@
<template>
<div>
<div class="row row-equal">
<div class="flex md12 xl3 xs12 sm12 area-style">
<div class="flex md12 xl3 xs12 sm12">
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-accordion>
@@ -9,7 +9,7 @@
<span slot="header">Control Panel</span>
<div slot="body">
<div>
<top-control-panel :ref="'top_control_panel'" @refreshChart="setOption"/>
<top-control-panel :ref="'top_control_panel'" @refreshChart="setOption" @changeOverviewDataZoom="changeOverviewDataZoom"/>
</div>
</div>
</va-collapse>
@@ -18,7 +18,7 @@
</div>
</div>
<div :class="chartAreaClass" class="area-style">
<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)"/>
@@ -51,14 +51,27 @@ export default {
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: {
@@ -86,8 +99,6 @@ export default {
metaList: null,
dataInfo: {},
maxTime: 0,
startTime: 0,
endTime: 0,
zoomTime: 0,
chartAreaClass: ['flex', 'xs12', 'sm12', 'md12', 'xl9', 'pa-0'],
dataZoomStart: 0,
@@ -133,7 +144,12 @@ export default {
},
getData: async function (scale, sampleMethod, id, channel, meta) {
if (scale === 1) {
return await download.rawByIDChannels(id, channel, meta)
// [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)
@@ -204,7 +220,7 @@ export default {
})
},
updateMarkArea: function (e) {
console.log(e)
// console.log(e)
if (e.batch != null) {
// console.log(e.batch)
e.batch.forEach(dataZoom => {
@@ -239,16 +255,22 @@ export default {
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
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 = this.maxTime * e.start / 100
this.endTime = this.maxTime * e.end / 100
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)
}
}
@@ -256,7 +278,14 @@ export default {
this.chartOverviewData.series[0].markArea.data[0][1].xAxis = this.startTime + ((this.endTime - this.startTime) * (this.dataZoomEnd / 100))
this.zoomTime = 0
},
drawOverviewData: async function () {
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
@@ -265,43 +294,39 @@ export default {
metaInfo = _meta
}
})
const sampleRate = (800000 / metaInfo.parameter_set.ADC_CLOCK)
let scale = (((metaInfo.time_duration / 100000) * sampleRate) / 4000) * 0.1
if (scale > 500) {
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 (scale > 200) {
} else if (dataPointNum > 2e5) { // 2000 (points) * 100 (resample) = 2e5
scale = '100'
} else if (scale > 30) {
} 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++) {
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),
})
}
_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)
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.chartOverviewData.series[seriesIndex].data.push(...dataList[i].data)
}
seriesIndex++
}
}
this.hideChartLoading()
},
@@ -315,19 +340,21 @@ export default {
metaInfo = _meta
}
})
const sampleRate = (800000 / metaInfo.parameter_set.ADC_CLOCK)
let scale = (((timeDur / 100000) * sampleRate) / 4000) * 0.1
if (scale > 500) {
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 (scale > 200) {
} else if (dataPointNum > 2e5) { // 2000 (points) * 100 (resample) = 2e5
scale = '100'
} else if (scale > 30) {
} 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]
@@ -343,12 +370,30 @@ export default {
}
}
// 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) {
this.chartDetailData.series[seriesIndex].data.push(data[j])
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++) {
@@ -367,7 +412,6 @@ export default {
this.startTimeCurrent = this.startTime
this.endTimeCurrent = this.endTime
this.drawDetailData()
this.$refs.top_control_panel.resetScale()
}
}
},
@@ -440,7 +484,7 @@ export default {
...mapActions('replay', [types.meta.init]),
...mapActions('replay', [types.rec.init, types.rec.intoData, types.rec.initDisplaySetting, types.rec.updateDisplaySetting]),
...mapMutations('replay', [types.chart.updateAxisLabel]),
...mapMutations('replay', [types.chart.updateAxisLabel, types.chart.updateChartSampling, types.chart.setOverviewDataZoomStartAndEnd]),
...mapMutations('replay', [types.meta.updateByIndex]),
...mapGetters('replay', [types.meta.getAll]),
@@ -459,12 +503,13 @@ export default {
console.log(this.metaList)
console.log(this.dataInfo)
await this.register()
this.drawOverviewData()
this.drawDetailData()
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 () {
@@ -483,21 +528,3 @@ export default {
},
}
</script>
<style lang="scss">
.area-style {
height: auto;
overflow-y: hidden;
overflow-x: hidden;
@include media-breakpoint-only(xl) {
height: 93vh;
overflow-y: scroll;
overflow-x: hidden;
}
}
.layout.gutter--xl .row .flex {
padding: 0.75rem 0.5rem 0.1rem 0.5rem;
}
</style>
@@ -54,6 +54,9 @@ 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)
},
@@ -1,16 +1,23 @@
<template>
<div>
<va-card>
<edit-file-name style="display: inline;" :ref="'edit_file_name'"/>
<download-file style="display: inline;"/>
<delete-file style="display: inline;"/>
<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/>
<change-axis v-show="showXAxis" :ref="'change_axis_x'" deviceName="neulive" axis="x"/>
<change-axis v-show="showYAxis" :ref="'change_axis_y'" deviceName="neulive" axis="y"/>
<change-unit v-show="showXUnit" :ref="'change_unit_x'" deviceName="neulive" axis="x" @refreshChart="refreshChart"/>
<change-unit :ref="'change_unit_y'" deviceName="neulive" axis="y" @refreshChart="refreshChart"/>
<change-scale :ref="'change_scale_y'" deviceName="neulive" axis="y"/>
<show-parameter :ref="'show_param'" deviceName="neulive"/>
<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>
@@ -24,6 +31,10 @@ 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',
@@ -36,15 +47,21 @@ export default {
DeleteFile,
EditFileName,
ShowParameter,
SdCardToggle,
LockDataZoom,
ChangeWindowStartAndSize,
},
computed: {
},
props: {
...mapFields('replay', [
'metaList',
'showCyclePanel',
]),
},
async created () {
},
data () {
return {
deviceName: '',
showXAxis: false,
showYAxis: false,
showXUnit: false,
@@ -54,20 +71,23 @@ export default {
},
methods: {
init () {
this.$refs.change_axis_x.init()
this.$refs.change_axis_y.init()
this.$refs.change_unit_x.init()
this.$refs.change_unit_y.init()
this.$refs.change_scale_y.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.$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)
},
resetScale () {
this.$refs.change_scale_y.reset()
},
},
// use watch because va-select with @change will have bug
watch: {
@@ -78,4 +98,29 @@ export default {
</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>
@@ -1,19 +1,48 @@
<template>
<div>
<span> {{ axis }} axis: </span>
<div v-if="axis === 'x'" style="display: inline;">
<select v-model="channelFormat" @change="changeAxis()">
<option v-for="option in channelOptions" :key="option.id" :value="option">
{{ option.description }}
</option>
</select>
<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'" style="display: inline;">
<select v-model="channelFormat" @change="changeAxis()">
<option v-for="option in channelYOptions" :key="option.id" :value="option">
{{ option.description }}
</option>
</select>
<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>
@@ -26,9 +55,6 @@ export default {
components: {
},
props: {
deviceName: {
type: String, // elite or neulive
},
axis: {
type: String, // x or y
},
@@ -49,17 +75,18 @@ export default {
]),
},
methods: {
init () {
if (this.deviceName === 'neulive') {
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 === 'elite') {
} 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)
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]
@@ -70,6 +97,53 @@ export default {
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]
@@ -85,7 +159,9 @@ export default {
} else if (this.axis === 'y') {
settingType = yType
settingValue = yValue
if (settingType === 'Elite') {
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]
@@ -105,23 +181,22 @@ export default {
}
},
changeAxis () {
if (this.deviceName === 'neulive') {
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 === 'elite') {
// 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.axisXDataType.description !== 'Time' && this.metaList[this.metaIndex].parameter_set.CYCLE_NUMBER > 0) {
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('resetScale')
this.$emit('clearCycle')
}
},
@@ -130,6 +205,7 @@ export default {
},
data () {
return {
deviceName: '',
channelFormat: {},
channelOptions: [
{
@@ -144,6 +220,10 @@ export default {
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',
@@ -162,6 +242,74 @@ export default {
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',
},
],
}
},
@@ -170,3 +318,11 @@ export default {
}
</script>
<style lang="scss">
.va-select-without-margin {
.va-select {
margin-bottom: 0;
}
}
</style>
@@ -34,13 +34,28 @@ export default {
return {
showPanel: false,
metaID: 0,
showWhichCycles: '1',
cycleNum: 0,
cycleDataID: 3, // [TODO] manage by data type factory
}
},
computed: {
slices: function () {
...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 ''
@@ -58,28 +73,13 @@ export default {
}
const cycleSet = new Set(cycleList)
const sortedCycleList = [...cycleSet].sort() // ref: https://stackoverflow.com/questions/33089695/how-can-i-sort-an-es6-set
// console.log(sortedCycleList)
return sortedCycleList
},
...mapFields('replay', [
'chartData',
'recInfo',
'metaList',
'currentScale',
'sampleMethod',
'axisXDataType',
'axisYDataType',
'axisXLabelScale',
'axisYLabelScale',
]),
},
watch: {
},
methods: {
init () {
this.isThisModeHasCycle = this.GLOBAL.hasCycleMode(this.metaList[this.metaIndex].parameter_set.MODE)
this.cycleNum = this.metaList[this.metaIndex].parameter_set.CYCLE_NUMBER
this.metaID = this.metaList[this.metaIndex].id
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 {
@@ -103,13 +103,18 @@ export default {
}
}
const cycleDict = this.getCycleDictRec()(cycleDataList)
const dataXList = this.recInfo[this.metaID][this.axisXDataType.id][this.currentScale]
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())) {
if (this.slices() === '' || this.slices().includes((sliceIndex + 1).toString())) {
// slice data
const value = cycleDict[sliceIndex + 1]
const startTime = value[0]
@@ -134,12 +139,12 @@ export default {
let x
let y
if (this.axisXLabelScale.description === 'Log') {
x = Math.log10(Math.abs(dataX[j][1]))
x = Math.abs(dataX[j][1])
} else if (this.axisXLabelScale.description === 'Linear') {
x = dataX[j][1]
}
if (this.axisYLabelScale.description === 'Log') {
y = Math.log10(Math.abs(dataY[j][1]))
y = Math.abs(dataY[j][1])
} else if (this.axisYLabelScale.description === 'Linear') {
y = dataY[j][1]
}
@@ -150,7 +155,7 @@ export default {
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.log10(Math.abs(dataY[j][1]))
dataY[j][1] = Math.abs(dataY[j][1])
} else if (this.axisYLabelScale.description === 'Linear') {
// do nothing
}
@@ -165,6 +170,13 @@ export default {
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])
}
}
@@ -1,15 +1,19 @@
<template>
<div>
<select v-model="scaleFormat" @change="changeScale()">
<option v-for="option in scaleOptions" :key="option.id" :value="option">
{{ option.description }}
</option>
</select>
<va-select
@input="changeScale()"
:label="''"
v-model="scaleFormat"
textBy="description"
class="va-select-without-margin"
:options="scaleOptions"
:noClear='true'
/>
</div>
</template>
<script>
import { mapMutations, mapGetters } from 'vuex'
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'
@@ -19,9 +23,6 @@ export default {
components: {
},
props: {
deviceName: {
type: String, // elite or neulive
},
chartID: {
type: Number, // detail data
default: 1,
@@ -37,6 +38,13 @@ export default {
created () {
},
computed: {
displayType () {
return {
x: this.axisXLabelScale.description === 'Log' ? 'log' : 'value',
y: this.axisYLabelScale.description === 'Log' ? 'log' : 'value',
}
},
...mapFields('replay', [
'chartData',
'recInfo',
@@ -45,6 +53,7 @@ export default {
'axisYLabelScale',
'axisXDataType',
'axisYDataType',
'absToggleStatus',
'startTimeCurrent',
'endTimeCurrent',
'currentScale',
@@ -52,7 +61,8 @@ export default {
]),
},
methods: {
init () {
init (deviceName) {
this.deviceName = deviceName
this.metaInfo = this.metaList[this.metaIndex]
this.metaID = this.metaInfo.id
if (this.axis === 'x') {
@@ -69,7 +79,7 @@ export default {
} else if (this.axis === 'y') {
this.axisYLabelScale = this.scaleFormat
}
if (this.deviceName === 'neulive') {
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]
@@ -77,7 +87,7 @@ export default {
this.calculateScaleHelper(gridIndex, ch)
}
}
} else if (this.deviceName === 'elite') {
} else if (this.deviceName === 'EliteZM15' || this.deviceName === 'EliteEIS') {
this.calculateScaleHelper(this.metaIndex, -1) // [TODO] elite tmp use metaIndex for grid index
}
},
@@ -87,14 +97,19 @@ export default {
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.log10(Math.abs(seriesData[i][0]))
seriesData[i][0] = Math.abs(seriesData[i][0])
} else if (this.axis === 'y') {
seriesData[i][1] = Math.log10(Math.abs(seriesData[i][1]))
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 === 'neulive') {
if (this.deviceName.startsWith('Neulive')) {
// [Region] get the subfile index
seriesData = []
const dataYList = this.recInfo[this.metaID][ch][this.currentScale]
@@ -114,94 +129,22 @@ export default {
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.axisXLabelScale.description === 'Log') {
processedData[0] = Math.log10(Math.abs(processedData[0]))
if (this.displayType.x === 'log' || this.absToggleStatus.x === true) {
processedData[0] = Math.abs(processedData[0])
}
if (this.axisYLabelScale.description === 'Log') {
processedData[1] = Math.log10(Math.abs(processedData[1]))
}
seriesData.push(processedData)
}
}
}
} else if (this.deviceName === 'elite') {
seriesData = []
const cycleNum = this.metaInfo.parameter_set.CYCLE_NUMBER
let startTime
let endTime
if (cycleNum > 0 && this.axisXDataType.description !== 'Time') { // if有cycle的mode且目前x軸不為時間,抓出第一圈所在的時間段,初始化時先畫第一圈就好,加快初始時間
const cycleDataID = 3 // recorded cycle 所在的channel index
const dataCycleList = this.recInfo[this.metaID][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, this.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]: 第一圈
this.$emit('clearCycle')
} else {
startTime = this.startTimeCurrent
endTime = this.endTimeCurrent
}
const dataYList = this.recInfo[this.metaID][this.axisYDataType.id][this.currentScale]
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
}
}
// [EndRegion]
for (let i = startIndex; i <= endIndex; i++) {
const dataY = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataYList[i].id, this.axisYDataType.id, this.metaInfo)
let dataX
if (this.axisXDataType.description !== 'Time') {
const dataXList = this.recInfo[this.metaID][this.axisXDataType.id][this.currentScale]
dataX = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataXList[i].id, this.axisXDataType.id, this.metaInfo)
}
for (let j = 0, len = dataY.length; j < len; j++) {
if (parseInt(dataY[j][0]) >= startTime && parseInt(dataY[j][0]) <= endTime) {
const processedData = dataY[j]
if (this.axisXDataType.description !== 'Time') {
processedData[0] = dataX[j][1]
}
if (this.axisXLabelScale.description === 'Log') {
processedData[0] = Math.log10(Math.abs(processedData[0]))
}
if (this.axisYLabelScale.description === 'Log') {
processedData[1] = Math.log10(Math.abs(processedData[1]))
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.updateSeriesChart({
chartID: this.chartID,
seriesIndex: gridIndex,
data: seriesData,
})
},
reset () {
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
}
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) {
@@ -214,6 +157,7 @@ export default {
}
}
},
...mapActions('replay', [types.chart.setAxisDisplay]),
...mapMutations('replay', [types.chart.updateSeries]),
...mapGetters('replay', [types.rec.getCycleDict]),
},
@@ -221,6 +165,7 @@ export default {
},
data () {
return {
deviceName: '',
metaID: 0,
metaInfo: null,
scaleFormat: { id: 0, description: 'Linear' },
@@ -241,3 +186,11 @@ export default {
}
</script>
<style lang="scss">
.va-select-without-margin {
.va-select {
margin-bottom: 0;
}
}
</style>
@@ -1,10 +1,25 @@
<template>
<div>
<select v-model="valueFormat" @change="changeUnit()">
<option v-for="option in valueFormatOptions[dataType]" :key="option.id" :value="option">
{{ option.unit }}
</option>
</select>
<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>
@@ -18,9 +33,6 @@ export default {
components: {
},
props: {
deviceName: {
type: String, // elite or neulive
},
axis: {
type: String, // x or y
},
@@ -42,17 +54,35 @@ export default {
]),
},
methods: {
init () {
if (this.deviceName === 'neulive') {
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 === 'elite') {
} 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)
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]
@@ -68,6 +98,48 @@ export default {
}
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'
@@ -81,10 +153,10 @@ export default {
}
}
if (this.axis === 'x') {
this.valueFormatX = this.valueFormatOptions[this.dataType][0]
this.valueFormatX = this.initDefaultUnit(this.axis)
this.valueFormat = this.valueFormatX
} else if (this.axis === 'y') {
this.valueFormatY = this.valueFormatOptions[this.dataType][0] // 0 mean use default unit
this.valueFormatY = this.initDefaultUnit(this.axis)
this.valueFormat = this.valueFormatY
}
this.changeUnit()
@@ -96,7 +168,7 @@ export default {
this.valueFormatY = this.valueFormat
}
const chartID = 1 // detail data
if (this.deviceName === 'neulive') {
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]
@@ -107,7 +179,7 @@ export default {
channel: parseInt(key),
})
}
} else if (this.deviceName === 'elite') {
} else if (this.deviceName === 'EliteZM15' || this.deviceName === 'EliteEIS') {
this.updateAxisLabelChart({
chartID: chartID,
axis: this.axis,
@@ -127,6 +199,16 @@ export default {
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') {
@@ -135,9 +217,23 @@ export default {
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'
}
}
this.valueFormat = this.valueFormatOptions[this.dataType][0]
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
@@ -147,6 +243,7 @@ export default {
},
data () {
return {
deviceName: '',
dataType: '',
valueFormat: {},
valueFormatOptions: { // below id: 0 mean default
@@ -206,6 +303,13 @@ export default {
unitScale: 1000000000,
},
],
cycle: [ // Time
{
id: 0,
unit: 'cycle',
unitScale: 1,
},
],
time: [ // Time
{
id: 0,
@@ -214,6 +318,85 @@ export default {
},
],
},
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 () {
@@ -221,3 +404,11 @@ export default {
}
</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>
@@ -1,6 +1,6 @@
<template>
<div>
<va-button flat small class="resize-va-button" color="gray" icon="fa fa-trash" @click.stop="deleteFileConfirm()"/>
<va-button flat small color="gray" icon="fa fa-trash" @click.stop="deleteFileConfirm()"/>
<va-modal
v-model="showModal.deleteFile"
size="small"
@@ -71,20 +71,8 @@ export default {
deleteFile: async function () {
for (let i = 0; i < this.deleteInfoList.length; i++) {
const deleteInfo = this.deleteInfoList[i]
for (const item of deleteInfo.rawChannelAndIDArrays) {
const channel = item[0]
const id = item[1]
await api.raw.update(channel, id, { deleted: true })
await api.raw.clearDel(channel, id)
}
for (const item of deleteInfo.miniChannelAndIDArrays) {
const channel = item[0]
const id = item[1]
await api.mini.update(channel, id, { deleted: true })
await api.mini.clearDel(channel, id)
}
await api.meta.update(deleteInfo.metaID, { deleted: true })
await api.meta.clearDel(deleteInfo.metaID)
await api.meta.clearDel()
}
await this.deleteFileDone()
},
@@ -102,15 +90,3 @@ export default {
}
</script>
<style lang="scss">
.resize-va-button {
.va-button {
margin: 0.375rem 0.5rem 0.375rem 0.1px;
}
.va-button--small {
padding: 0.1px;
}
}
</style>
@@ -1,6 +1,6 @@
<template>
<div>
<va-button flat small class="resize-va-button" color="gray" icon="fa fa-download" @click.stop="downloadCSV()"/>
<va-button flat small color="gray" icon="fa fa-download" @click.stop="downloadCSV()"/>
</div>
</template>
@@ -32,9 +32,10 @@ export default {
downloadCSV: async function () {
for (let i = 0; i < this.metaList.length; i++) {
const meta = this.metaList[i]
window.open('http://' + location.href.split('/')[2].split(':')[0] + '/#/download/neulive/csv/' + meta.id + '/raw/true', 'raw')
if (JSON.parse(meta.channels).some(el => el >= 256)) {
window.open('http://' + location.href.split('/')[2].split(':')[0] + '/#/download/neulive/csv/' + meta.id + '/acc/true', 'acc')
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)
}
}
},
@@ -46,15 +47,3 @@ export default {
}
</script>
<style lang="scss">
.resize-va-button {
.va-button {
margin: 0.375rem 0.5rem 0.375rem 0.1px;
}
.va-button--small {
padding: 0.1px;
}
}
</style>
@@ -1,6 +1,6 @@
<template>
<div>
<va-button flat small class="resize-va-button" color="gray" icon="fa fa-file-text-o" @click.stop="editFileConfirm()"> {{ filename }} </va-button>
<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"
@@ -139,15 +139,3 @@ export default {
}
</script>
<style lang="scss">
.resize-va-button {
.va-button {
margin: 0.375rem 0.5rem 0.375rem 0.1px;
}
.va-button--small {
padding: 0.1px;
}
}
</style>
@@ -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>
@@ -8,15 +8,13 @@
<script>
import { mapFields } from 'vuex-map-fields'
import paramTable from '@/data/param-table/index.js'
export default {
name: 'show-parameter',
components: {
},
props: {
deviceName: {
type: String, // elite or neulive
},
metaIndex: {
type: Number, // which meta file
default: 0,
@@ -26,7 +24,9 @@ export default {
},
data () {
return {
deviceName: '',
content: '',
showDict: {},
// [region] for neulive
ampGainOptions: [
{
@@ -46,38 +46,6 @@ export default {
description: '800',
},
],
neuliveSampleRateOptions: [
{
id: 0,
value: 800,
description: '1k',
},
{
id: 1,
value: 400,
description: '2k',
},
{
id: 2,
value: 200,
description: '4k',
},
{
id: 3,
value: 160,
description: '5k',
},
{
id: 4,
value: 100,
description: '8k',
},
{
id: 5,
value: 80,
description: '10k',
},
],
stimulateElectrodeOptions: [
{
label: 'Monopolar',
@@ -271,19 +239,20 @@ export default {
watch: {
},
methods: {
init () {
init (deviceName) {
this.deviceName = deviceName
const meta = this.metaList[this.metaIndex]
const params = meta.parameter_set
this.content += 'Duration: ' + parseInt(parseInt(meta.time_duration / 1000000) / 60) + ' m ' + parseInt((meta.time_duration % 60000000) / 1000000) + ' s<br/>'
this.content += 'Duration: ' + parseInt(parseInt(meta.time_duration / 1e6) / 60) + ' m ' + parseInt((meta.time_duration % 6e7) / 1e6) + ' s<br/>'
this.content += '<br/>Parameter: <br/>'
this.content += '<br/> Recording: <br/>'
if (this.deviceName === 'neulive') {
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 === 'ADC_CLOCK') {
if (key === 'RECORDING_CH' || key === 'AXIS_CH' || key === 'AMP_GAIN' || key === 'SAMPLE_RATE') {
if (key === 'RECORDING_CH') {
showKey = 'Channels'
// convert decimal to binary
@@ -328,13 +297,9 @@ export default {
showValue = this.ampGainOptions[i].description
}
}
} else if (key === 'ADC_CLOCK') {
} 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
}
}
showValue = value
}
this.content += ' ' + showKey + ': ' + showValue + '<br/>'
}
@@ -412,103 +377,47 @@ export default {
this.content += ' Frequency: ' + String(1000 / period) + ' Hz' + '<br/>' // 1000 is cuz 1s = 1000ms
this.content += ' Period: ' + String(period) + ' ms' + '<br/>'
}
} else if (this.deviceName === 'elite') {
for (const [key, value] of Object.entries(params)) {
let showKey = ''
let showValue = value
if (key === 'MODE') {
showKey = 'MODE'
for (let i = 0; i < this.workingModeOptions.length; i++) {
if (this.workingModeOptions[i].id === value) {
showValue = this.workingModeOptions[i].description
} 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])
}
}
} else if (key === 'ADC_LEVEL') {
showKey = 'Current Range'
for (let i = 0; i < this.currentRangeOptions.length; i++) {
if (this.currentRangeOptions[i].value === value) {
showValue = this.currentRangeOptions[i].label
}
}
} else if (key === 'VOLT_ORIGIN') {
showKey = 'Volt start'
showValue = (value / 5000) - 5 + 'V'
} else if (key === 'VOLT_FINAL') {
showKey = 'Volt stop'
showValue = (value / 5000) - 5 + 'V'
} else if (key === 'VOLT_STEP') {
showKey = 'Volt step'
showValue = ((value * 2) + 2) / 10 + 'mV'
} else if (key === 'STEP_TIME') {
showKey = 'Step time'
for (let i = 0; i < this.stepTimeOptions.length; i++) {
if (this.stepTimeOptions[i].value === value) {
showValue = this.stepTimeOptions[i].label
}
}
} else if (key === 'CYCLE_NUMBER') {
showKey = 'Cycle number'
showValue = value
} else if (key === 'DAC_VOLT') {
showKey = 'Volt out'
showValue = (value / 5000) - 5 + 'V'
} else if (key === 'Resister_LEVEL') {
showKey = 'Resister Range'
for (let i = 0; i < this.resisterRangeOptions.length; i++) {
if (this.resisterRangeOptions[i].value === value) {
showValue = this.resisterRangeOptions[i].label
}
}
} else if (key === 'SAMPLE_RATE') {
showKey = 'Sample rate'
for (let i = 0; i < this.eliteSampleRateOptions.length; i++) {
if (this.eliteSampleRateOptions[i].value === value) {
showValue = this.eliteSampleRateOptions[i].label
}
}
} else if (key === 'Const_Current_value') {
showKey = 'Current'
showValue = value + 'μA'
} else if (key === 'VOLTSTOP_MAX') {
showKey = 'Volt max stop'
showValue = (value / 5000) - 5 + 'V'
} else if (key === 'VOLTSTOP_MIN') {
showKey = 'Volt min stop'
showValue = (value / 5000) - 5 + 'V'
} else if (key === 'Charge') {
showKey = 'Charge'
for (let i = 0; i < this.chargeOptions.length; i++) {
if (this.chargeOptions[i].value === value) {
showValue = this.chargeOptions[i].label
}
}
} else if (key === 'VOLT_INITIAL') {
showKey = 'E-Initial'
showValue = (value / 5000) - 5 + 'V'
} else if (key === 'VOLT_MAX') {
showKey = 'Volt max stop'
showValue = (value / 5000) - 5 + 'V'
} else if (key === 'VOLT_MIN') {
showKey = 'Volt min stop'
showValue = (value / 5000) - 5 + 'V'
} else if (key === 'Scan_Rate') {
showKey = 'ScanRate'
showValue = (value / 100) + 0.01 + 'mV/s'
} else if (key === 'Data_Resolution_Scan') {
showKey = 'Resolution'
showValue = (value / 10) + 0.1 + 'sps'
} else if (key === 'VOLT_EFINAL') {
showKey = 'E-Final'
showValue = (value / 5000) - 5 + 'V'
} else if (key === 'VOLT_VSCAN') {
showKey = 'VScan'
showValue = (value / 5000) - 5 + 'V'
} else {
continue
}
this.content += ' ' + showKey + ': ' + showValue + '<br/>'
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/>'
}
},
},
}
@@ -1,6 +1,6 @@
<template>
<div>
<span> Resample: {{ currentScale }} to 1 </span>
<p class="display-6"> Resample: {{ currentScale }} to 1 <p/>
</div>
</template>
@@ -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>
+436
View File
@@ -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>
+91 -4
View File
@@ -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'">
@@ -94,6 +94,35 @@
</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>
</div>
</div>
</div>
@@ -138,14 +167,20 @@
<script>
import api from '@/data/api/index'
import { taskInfo } from '../../data/task/TaskInfo'
import { taskInfo } from '@/data/task/TaskInfo'
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
import { mapFields } from 'vuex-map-fields'
export default {
name: 'devices-overview',
components: {
FulfillingBouncingCircleSpinner,
},
computed: {
...mapFields('device', [
'triggerList',
]),
},
created () {
},
data () {
@@ -189,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,
@@ -247,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(':')
@@ -287,6 +361,10 @@ export default {
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]),
@@ -341,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,
@@ -374,6 +452,7 @@ export default {
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 () {
@@ -384,6 +463,7 @@ export default {
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 () {
@@ -398,6 +478,11 @@ export default {
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')
})
},
@@ -419,6 +504,7 @@ export default {
this.mqttPub(controller.id + '_user', JSON.stringify({
header: 'hardware_scan/0',
}))
this.mqttPub(controller.id + '/client/trigger_manager/scan', '{}')
}
}
})
@@ -508,6 +594,7 @@ export default {
watch: {
},
async mounted () {
await taskInfo.updateTaskInfo()
await this.getControllerList()
this.pageMqttSub()
+190 -539
View File
@@ -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,391 +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()
/*
** download all
*/
if (parseInt(info.time_duration) < 18e8) {
const rawData = await download.getAllRawDatas(info)
exportData.exportCSV(info, rawData)
} else {
for (const channelID in info.raw_data) {
const rawDataIDList = info.raw_data[channelID]
while (rawDataIDList.length > 1000) {
const _list = rawDataIDList.splice(0, 1000)
const rawData = await download.getIndexRawDatas(info, channelID, _list)
exportData.exportCSV(info, rawData)
}
const rawData = await download.getIndexRawDatas(info, channelID, rawDataIDList)
exportData.exportCSV(info, rawData, channelID)
rawData[channelID].length = 0
// const rawData = await download.getAllRawDatas(info)
// console.timeEnd('download')
}
}
// console.time('download')
// const rawData = await download.getAllRawDatas(info)
// console.timeEnd('download')
// exportData.exportCSV(info, rawData)
/*
** download split
*/
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)
} 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 {
}
},
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
// })
},
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,
@@ -539,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()
+239
View File
@@ -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,159 +0,0 @@
<template>
<div>
</div>
</template>
<script>
import api from '@/data/api/index'
import types from '@/store/modules/file/download/elite/csv/types'
import { mapActions, mapGetters, mapMutations } from 'vuex'
// import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
export default {
name: 'Download',
components: {
// FulfillingBouncingCircleSpinner,
},
data: () => {
return {
controllerList: [],
spliceDataNumsLimit: 20,
}
},
computed: {
getByIndex (index) {
return this.getByIndexDownload(index)
},
getDownloading () {
return this.getDownloadingDownload()
},
getRemainIDLength (index) {
return this.getRemainIDLengthDownload(index)
},
},
methods: {
getControllerList: async function () {
const update = async () => {
this.controllerList.push({
id: 'tommy_test',
mac: '',
status: 'loading',
isScan: true,
files: [],
})
}
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/+')
})
},
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/+')
})
},
notify (name) {
this.showToast(`done ${name}`, {
position: 'bottom-right',
})
},
...mapActions('eliteCsv',
[
types.download.init,
types.download.rawDataByIDs,
types.export.createHeadersString,
types.export.createTitlesString,
types.export.createDataString,
types.export.closeFileStream,
],
),
...mapMutations('eliteCsv',
[
types.download.setDownloading,
types.download.removeDownloadBuffer,
],
),
...mapGetters('eliteCsv',
[
types.download.getByIndex,
types.download.getDownloading,
types.download.getAll,
types.download.getRemainIDLength,
],
),
},
watch: {
},
async mounted () {
await this.getControllerList()
// TODO authorization
this.pageMqttSub()
const metaIDList = this.$route.params.metaList.split('-')
const recoverData = this.$route.params.recover
await this.initDownload({ metaIDList: metaIDList, api: api })
// let first file download in download List
this.setDownloadingDownload()
const downloadingFile = this.getDownloading
downloadingFile.recoverData = recoverData
let spliceDataNums = 0
// console.log('downloadingFile', downloadingFile)
// console.log(this.getRemainIDLength(0))
// create headers and title
this.createHeadersStringExport()
this.createTitlesStringExport()
// loop until each channel's rawID List empty
while (this.getRemainIDLength(0)) {
// forEach channel in raw_data
for (const channel in downloadingFile.raw_data) {
// get spliceDataNumsLimit numbers of ID to download once time
if (downloadingFile.raw_data[channel].length >= this.spliceDataNumsLimit) {
spliceDataNums = this.spliceDataNumsLimit
} else {
spliceDataNums = downloadingFile.raw_data[channel].length
}
const rawID = downloadingFile.raw_data[channel].splice(0, spliceDataNums)
// console.log('rawID', channel, rawID)
// download data and save into dataBuffer by rawDataIDList
await this.rawDataByIDsDownload({
channel: channel,
rawDataIDList: rawID,
api: api,
})
}
// export data
this.createDataStringExport()
// this.removeDownloadBufferDownload()
}
this.closeFileStreamExport()
},
destroyed () {
this.pageMqttUnSub()
},
}
</script>
<style>
.filter-button {
text-align: center;
}
</style>
@@ -1,216 +0,0 @@
<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>
</div>
</div>
</div>
</template>
<script>
import api from '@/data/api/index'
import types from '@/store/modules/file/download/elite/excel/types'
import { mapActions, mapGetters, mapMutations } from 'vuex'
// import { file } from '../../data/file/File'
// import { download } from '../../data/download/Download'
// import { exportData } from '../../data/export/export'
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
export default {
name: 'Download',
components: {
FulfillingBouncingCircleSpinner,
},
data: () => {
return {
controllerList: [],
}
},
computed: {
getByIndex (index) {
return this.getByIndexDownload(index)
},
getDownloading () {
return this.getDownloadingDownload()
},
getRemainIDLength (index) {
return this.getRemainIDLengthDownload(index)
},
// transTime (min,max) {
// return this.getTimeInFormat(min) + ' - ' + this.getTimeInFormat(max)
// },
loaded () {
return this.loadingPercent + '%'
},
},
methods: {
transTime (timeRange) {
return this.getTimeInFormat(timeRange[0]) + ' - ' + this.getTimeInFormat(timeRange[1])
},
notify (name) {
this.showToast(`done ${name}`, {
position: 'bottom-right',
})
},
getControllerList: async function () {
const update = async () => {
this.controllerList.push({
id: 'tommy_test',
mac: '',
status: 'loading',
isScan: true,
files: [],
})
}
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/+')
})
},
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/+')
})
},
...mapActions('eliteExcel',
[
types.download.init,
types.download.rawDataByIDs,
types.export.createHeadersString,
types.export.createTitlesString,
types.export.createDataString,
types.export.closeFileStream,
],
),
...mapMutations('eliteExcel',
[
types.download.setDownloading,
types.download.removeDownloadBuffer,
],
),
...mapGetters('eliteExcel',
[
types.download.getByIndex,
types.download.getDownloading,
types.download.getAll,
types.download.getRemainIDLength,
],
),
},
openPortal () {
this.windowRef = window.open('', '', 'width=600,height=400,left=200,top=200')
this.windowRef.document.body.appendChild(this.$el)
// copyStyles(window.document, this.windowRef.document)
this.windowRef.addEventListener('beforeunload', this.closePortal)
},
closePortal () {
if (this.windowRef) {
this.windowRef.close()
this.windowRef = null
this.$emit('close')
}
},
// watch: {
// loadingPercent(val) {
// if (val >= 100) {
// console.log('complete');
// clearInterval(this.interval)
// }
// }
// },
async mounted () {
await this.getControllerList()
// TODO authorization
this.pageMqttSub()
const metaIDList = this.$route.params.metaList.split('-')
await this.initDownload({ metaIDList: metaIDList, api: api })
this.setDownloadingDownload()
const downloadingFile = this.getDownloading
// create headers and title
this.createHeadersStringExport()
this.createTitlesStringExport()
// let spliceDataNums = 0
let rowIndex = 0
// let columnIndex = 0
// // while (this.getRemainIDLength(0)) {
while (rowIndex < downloadingFile.needRows) {
for (const channel in downloadingFile.downloadIDList) {
const rawID = downloadingFile.downloadIDList[channel][rowIndex]
// console.log('rawID', channel, rawID)
if (rawID !== undefined) {
await this.rawDataByIDsDownload({
channel: channel,
rawDataIDList: rawID,
api: api,
})
}
}
rowIndex += 1
this.createDataStringExport({ lastPartData: (rowIndex === downloadingFile.needRows) })
// this.removeDownloadBufferDownload()
// console.log('end', downloadingFile)
}
this.closeFileStreamExport()
await new Promise(resolve => setTimeout(resolve, 2000)) // sleep
window.close()
// }
// if (downloadingFile.raw_data[channel].length >= 10) {
// spliceDataNums = 10
// } else {
// spliceDataNums = downloadingFile.raw_data[channel].length
// }
// const rawID = downloadingFile.raw_data[channel].splice(0, spliceDataNums)
// console.log('rawID', channel, rawID)
// await this.rawDataByIDsDownload({
// channel: channel,
// rawDataIDList: rawID,
// api: api,
// })
// }
// // console.log('end', downloadingFile)
// // export data
// this.createDataStringExport({})
// this.removeDownloadBufferDownload()
// }
// const rawData = await download.getAllRawDatas(meta.data[0])
// exportData.exportCSV(meta.data[0], rawData)
// await this.initMeta({ metaIDList: metaIDList, api: api })
},
destroyed () {
this.pageMqttUnSub()
},
}
</script>
<style>
.filter-button {
text-align: center;
}
</style>
@@ -1,182 +0,0 @@
<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>
</div>
</div>
</div>
</template>
<script>
import api from '@/data/api/index'
import types from '@/store/modules/file/download/neulive/csv/types'
import { mapActions, mapGetters, mapMutations } from 'vuex'
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
export default {
name: 'Download',
components: {
FulfillingBouncingCircleSpinner,
},
data: () => {
return {
controllerList: [],
spliceDataNumsLimit: 1,
}
},
computed: {
getByIndex (index) {
return this.getByIndexDownload(index)
},
getDownloading () {
return this.getDownloadingDownload()
},
getRemainIDLength (index) {
return this.getRemainIDLengthDownload(index)
},
},
methods: {
getControllerList: async function () {
const update = async () => {
this.controllerList.push({
id: 'tommy_test',
mac: '',
status: 'loading',
isScan: true,
files: [],
})
}
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/+')
})
},
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/+')
})
},
notify (name) {
this.showToast(`done ${name}`, {
position: 'bottom-right',
})
},
...mapActions('neuliveCsv',
[
types.download.init,
types.download.rawDataByIDs,
types.export.createHeadersString,
types.export.createTitlesString,
types.export.createDataString,
types.export.closeFileStream,
],
),
...mapMutations('neuliveCsv',
[
types.download.setDownloading,
types.download.removeDownloadBuffer,
],
),
...mapGetters('neuliveCsv',
[
types.download.getByIndex,
types.download.getDownloading,
types.download.getAll,
types.download.getRemainIDLength,
],
),
},
watch: {
},
async mounted () {
await this.getControllerList()
// TODO authorization
this.pageMqttSub()
const metaIDList = this.$route.params.metaList.split('-')
const recoverData = this.$route.params.recover
const rawData = this.$route.params.rawData
await this.initDownload({ metaIDList: metaIDList, api: api })
// let first file download in download List
this.setDownloadingDownload()
const downloadingFile = this.getDownloading
downloadingFile.recoverData = recoverData
if (rawData === 'acc') {
downloadingFile.name += '-axis'
}
let spliceDataNums = 0
// console.log(this.getRemainIDLength(0))
const channelArray = Object.keys(downloadingFile.raw_data)
const filterChannelArray = (rawData === 'acc') ? channelArray.filter(ch => parseInt(ch) >= 256) : channelArray.filter(ch => parseInt(ch) < 256)
// create headers and title
this.createHeadersStringExport({ rawData: rawData })
this.createTitlesStringExport({ rawData: rawData })
// loop until each channel's rawID List empty
while (this.getRemainIDLength(0, filterChannelArray)) {
const lastPartData = ((this.getRemainIDLength(0, filterChannelArray) - this.spliceDataNumsLimit) <= 0)
// forEach channel in raw_data
for (const channel of filterChannelArray) {
// get spliceDataNumsLimit numbers of ID to download once time
if (downloadingFile.raw_data[channel].length >= this.spliceDataNumsLimit) {
spliceDataNums = this.spliceDataNumsLimit
} else {
spliceDataNums = downloadingFile.raw_data[channel].length
}
const rawID = downloadingFile.raw_data[channel].splice(0, spliceDataNums)
// download data and save into dataBuffer by rawDataIDList
await this.rawDataByIDsDownload({
channel: channel,
rawDataIDList: rawID,
api: api,
})
}
// export data
this.createDataStringExport({ lastPartData: lastPartData, rawData: rawData })
// if (this.spliceDataNumsLimit <= 10) {
// this.spliceDataNumsLimit += 1
// }
// console.log('removeNeuliveCSV')
// this.removeDownloadBufferDownload()
}
this.closeFileStreamExport()
await new Promise(resolve => setTimeout(resolve, 2000)) // sleep
window.close()
},
destroyed () {
this.pageMqttUnSub()
},
}
</script>
<style>
.filter-button {
text-align: center;
}
</style>
@@ -1,207 +0,0 @@
<template>
<div>
</div>
</template>
<script>
import api from '@/data/api/index'
import types from '@/store/modules/file/download/neulive/excel/types'
import { mapActions, mapGetters, mapMutations } from 'vuex'
// import { file } from '../../data/file/File'
// import { download } from '../../data/download/Download'
// import { exportData } from '../../data/export/export'
// import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
export default {
name: 'Download',
components: {
// FulfillingBouncingCircleSpinner,
},
data: () => {
return {
controllerList: [],
}
},
computed: {
getByIndex (index) {
return this.getByIndexDownload(index)
},
getDownloading () {
return this.getDownloadingDownload()
},
getRemainIDLength (index) {
return this.getRemainIDLengthDownload(index)
},
// transTime (min,max) {
// return this.getTimeInFormat(min) + ' - ' + this.getTimeInFormat(max)
// },
loaded () {
return this.loadingPercent + '%'
},
},
methods: {
transTime (timeRange) {
return this.getTimeInFormat(timeRange[0]) + ' - ' + this.getTimeInFormat(timeRange[1])
},
notify (name) {
this.showToast(`done ${name}`, {
position: 'bottom-right',
})
},
getControllerList: async function () {
const update = async () => {
this.controllerList.push({
id: 'tommy_test',
mac: '',
status: 'loading',
isScan: true,
files: [],
})
}
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/+')
})
},
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/+')
})
},
...mapActions('neuliveExcel',
[
types.download.init,
types.download.rawDataByIDs,
types.export.createHeadersString,
types.export.createTitlesString,
types.export.createDataString,
types.export.closeFileStream,
],
),
...mapMutations('neuliveExcel',
[
types.download.setDownloading,
types.download.removeDownloadBuffer,
],
),
...mapGetters('neuliveExcel',
[
types.download.getByIndex,
types.download.getDownloading,
types.download.getAll,
types.download.getRemainIDLength,
],
),
},
openPortal () {
this.windowRef = window.open('', '', 'width=600,height=400,left=200,top=200')
this.windowRef.document.body.appendChild(this.$el)
// copyStyles(window.document, this.windowRef.document)
this.windowRef.addEventListener('beforeunload', this.closePortal)
},
closePortal () {
if (this.windowRef) {
this.windowRef.close()
this.windowRef = null
this.$emit('close')
}
},
// watch: {
// loadingPercent(val) {
// if (val >= 100) {
// console.log('complete');
// clearInterval(this.interval)
// }
// }
// },
async mounted () {
await this.getControllerList()
// TODO authorization
this.pageMqttSub()
const metaIDList = this.$route.params.metaList.split('-')
await this.initDownload({ metaIDList: metaIDList, api: api })
this.setDownloadingDownload()
const downloadingFile = this.getDownloading
console.log('downloadingFile', downloadingFile)
console.log(this.getRemainIDLength(0))
// create headers and title
this.createHeadersStringExport()
this.createTitlesStringExport()
// let spliceDataNums = 0
let rowIndex = 0
// let columnIndex = 0
// // while (this.getRemainIDLength(0)) {
while (rowIndex < downloadingFile.needRows) {
for (const channel in downloadingFile.downloadIDList) {
const rawID = downloadingFile.downloadIDList[channel][rowIndex]
// console.log('rawID', channel, rawID)
if (rawID !== undefined) {
await this.rawDataByIDsDownload({
channel: channel,
rawDataIDList: rawID,
api: api,
})
}
}
this.createDataStringExport()
this.removeDownloadBufferDownload()
// console.log('end', downloadingFile)
rowIndex += 1
}
this.closeFileStreamExport()
// }
// if (downloadingFile.raw_data[channel].length >= 10) {
// spliceDataNums = 10
// } else {
// spliceDataNums = downloadingFile.raw_data[channel].length
// }
// const rawID = downloadingFile.raw_data[channel].splice(0, spliceDataNums)
// console.log('rawID', channel, rawID)
// await this.rawDataByIDsDownload({
// channel: channel,
// rawDataIDList: rawID,
// api: api,
// })
// }
// // console.log('end', downloadingFile)
// // export data
// this.createDataStringExport({})
// this.removeDownloadBufferDownload()
// }
// const rawData = await download.getAllRawDatas(meta.data[0])
// exportData.exportCSV(meta.data[0], rawData)
// await this.initMeta({ metaIDList: metaIDList, api: api })
},
destroyed () {
this.pageMqttUnSub()
},
}
</script>
<style>
.filter-button {
text-align: center;
}
</style>
+4 -1
View File
@@ -9,6 +9,7 @@ import FileTable from './file-table/FileTable.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: {
@@ -23,10 +24,11 @@ export default {
getControllerList: async function () {
const update = async () => {
this.controllerList.push({
id: 'tommy_test',
id: taskInfo.getTaskInfo().controllerID,
mac: '',
status: 'loading',
isScan: true,
devices: [],
})
}
await update()
@@ -78,6 +80,7 @@ export default {
},
},
async mounted () {
await taskInfo.updateTaskInfo()
await this.getControllerList()
await api.auth.getJwtData()
console.log(await api.meta.getByParentWithLimit('folder', 2, 5, 0, 'DESC'))
+71 -30
View File
@@ -173,15 +173,31 @@
{{transDeviceInfo(props.rowData.configuration)}}
</template>
<template slot="actions" slot-scope="props" >
<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'" @click.stop="downloadExcel(props.rowData)"/>
<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>
@@ -199,16 +215,18 @@ 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: '160',
perPage: '80',
perPageOptions: ['20', '40', '80', '160'],
fileLists: [],
@@ -255,6 +273,8 @@ export default {
height: '2rem',
},
},
SDuuidList: [],
controllerList: [],
}
},
computed: {
@@ -310,7 +330,7 @@ export default {
{
name: '__slot:actions',
dataClass: 'text-right',
width: '20%',
width: '25%',
},
]
},
@@ -554,20 +574,8 @@ export default {
}
},
async deleteSingleFileByDeleteInfo () {
for (const item of this.deleteInfo.rawChannelAndIDArrays) {
const channel = item[0]
const id = item[1]
await api.raw.update(channel, id, { deleted: true })
await api.raw.clearDel(channel, id)
}
for (const item of this.deleteInfo.miniChannelAndIDArrays) {
const channel = item[0]
const id = item[1]
await api.mini.update(channel, id, { deleted: true })
await api.mini.clearDel(channel, id)
}
await api.meta.update(this.deleteInfo.metaID, { deleted: true })
await api.meta.clearDel(this.deleteInfo.metaID)
await api.meta.clearDel()
},
deleteFileConfirm: function (info) {
this.fillDeleteInfo(info)
@@ -653,25 +661,48 @@ export default {
},
downloadCsv: async function (meta) {
const href = location.href.split('/')[2]
if (meta.device.library_name.indexOf('Elite') >= 0) {
window.open('http://' + href + '/#/download/elite/csv/' + meta.id)
} else if (meta.device.library_name.indexOf('Neulive') >= 0) {
window.open('http://' + href + '/#/download/neulive/csv/' + meta.id + '/raw', 'raw')
if (JSON.parse(meta.channels).some(el => el >= 256)) {
setTimeout(() => {
window.open('http://' + href + '/#/download/neulive/csv/' + meta.id + '/acc', 'acc')
}, 1000)
}
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) {
window.open('http://' + href + '/#/download/elite/excel/' + meta.id)
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) {
window.open('http://' + href + '/#/download/neulive/csv/' + meta.id + '/raw/true', 'raw')
if (JSON.parse(meta.channels).some(el => el >= 256)) {
window.open('http://' + href + '/#/download/neulive/csv/' + meta.id + '/acc/true', 'acc')
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
}
}
}
},
@@ -688,8 +719,18 @@ export default {
})
}
},
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>
+148
View File
@@ -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>
+35
View File
@@ -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()
},
}
@@ -11,16 +11,16 @@
<!-- {{ controller }} -->
<va-item :key="controller.device_mac" class="pa-0 ma-0"
>
<va-item-section avatar class="ml-2 mr-2">
<va-item-section avatar class="ml-4 mr-4">
<img
:src="getImageUrl()"
:alt="'BPS-CONTROLLER'"
width="300px"
height="300px"
width="200px"
height="200px"
contain
/>
</va-item-section>
<va-item-section class="ml-4" >
<va-item-section class="ml-5 mr-4" >
<va-item-label style="font-size: 2rem;">
{{ controller.wifi_name }}
</va-item-label>
@@ -46,8 +46,8 @@
<script>
import { mapActions, mapGetters, mapMutations } from 'vuex'
import api from '@/data/api/index'
import types from '@/store/modules/about/types'
import eliteImgUrl from '@/assets/img/elite_img.png'
import types from '@/store/modules/setting/types'
import controllerImgUrl from '@/assets/img/controller.png'
export default {
name: 'controller-info',
@@ -90,11 +90,11 @@ export default {
},
methods: {
getImageUrl () {
return eliteImgUrl
return controllerImgUrl
},
...mapActions('about', [types.controller.init]),
...mapMutations('about', [types.controller.set, types.controller.updateByIndex]),
...mapGetters('about', [types.controller.getAll]),
...mapActions('setting', [types.controller.init]),
...mapMutations('setting', [types.controller.set, types.controller.updateByIndex]),
...mapGetters('setting', [types.controller.getAll]),
},
async mounted () {
this.initController({ api: api })
@@ -106,8 +106,8 @@ export default {
</script>
<style lang="scss">
.area-style {
height: 100%;
.area-style-setting-controller {
height: auto;
overflow-y: hidden;
overflow-x: hidden;
@@ -1,10 +1,11 @@
<template>
<div class="device-info">
<div class="row flex">
<draggable class="flex d-flex sm12 xl12 md12 xs12" v-model="devices" @start="drag=true" @end="drag=false" >
<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 md4 xs12 ma-0 area-style-info "
v-for="(device, index) in devices" :key="device.id"
class="flex d-flex sm12 xl3 md6 xs12 ma-0"
v-for="(device, index) in devicesList" :key="device.id"
>
<va-card
:noPadding="true"
@@ -21,7 +22,7 @@
class="mr-1"
color="#babfc2"
style="cursor: pointer;"
@click.native.stop="removeCheck(index, device)"
@click.native.stop="remove(index, device)"
/>
</div>
</div>
@@ -30,7 +31,7 @@
<p> {{ device.name }} </p>
</div>
<div class="center-medium">
<p> {{ macArrayToString(device.mac_address) }} </p>
<p> {{ device.mac_address }} </p>
</div>
<div class="mt-4 mb-4" style="text-align: center;">
<img
@@ -48,26 +49,27 @@
<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 >User Guide</va-button>
<va-button @click="openGuide(device.library)">User Guide</va-button>
</div>
</va-card>
</div>
</draggable>
</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/about/types'
import types from '@/store/modules/setting/types'
import neuliveImgUrl from '@/assets/img/neulive_img.png'
import eliteImgUrl from '@/assets/img/elite_img.png'
import draggable from 'vuedraggable'
import eliteImgUrl from '@/assets/img/elite_img_v2.png'
// import draggable from 'vuedraggable'
export default {
name: 'device-info',
components: {
draggable,
},
created () {
},
@@ -76,6 +78,9 @@ export default {
}
},
computed: {
...mapFields('setting', [
'devicesList',
]),
devices: {
get () {
return this.getAllDevice()
@@ -94,7 +99,7 @@ export default {
timeStampToLocaleTime: function (time) {
return this.GLOBAL.dateToStr(time)
},
getImageUrl (libraryName) {
getImageUrl: function (libraryName) {
if (libraryName !== null) {
if (libraryName.indexOf('Neulive') >= 0) {
return neuliveImgUrl
@@ -104,40 +109,41 @@ export default {
}
return null
},
autoConnect (index, device) {
autoConnect: async function (index, device) {
device.auto_connect = !device.auto_connect
this.updateDatabaseByIDDevice({
id: device.id,
request: { auto_connect: device.auto_connect },
api: api,
})
this.updateByIndexDevice({ index: index, item: { auto_connect: device.auto_connect } })
await api.device.update(device.id, { auto_connect: device.auto_connect })
},
removeCheck (index, device) {
/**
* TODO remove modal
*/
this.removeDevice({ id: device.id, index: index, device, deviceList: this.devices, api: api })
remove (index, device) {
console.log('removeDevcie', index, device)
this.removeDevice({ id: device.id, index: index, api: api })
},
...mapActions('about', [types.device.init, types.device.remove, types.device.reorder, types.device.updateDatabaseByID]),
...mapMutations('about', [types.device.set, types.device.updateByIndex]),
...mapGetters('about', [types.device.getAll]),
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 () {
this.initDevice({ api: api })
const devices = await api.device.getAll()
if (devices.status === 200) {
this.devicesList = devices.data
}
},
destroyed () {
},
}
</script>
<style lang="scss">
.area-style-info {
.area-style-setting-device {
height: auto;
overflow-y: hidden;
overflow-x: hidden;
@include media-breakpoint-only(xl) {
height: 48vh;
height: auto;
overflow-y: scroll;
overflow-x: hidden;
}
@@ -163,4 +169,10 @@ export default {
text-align: center;
font-size: 28px;
}
.flex-wrap-setting {
display: flex;
flex-direction: horizontal;
flex-wrap: wrap;
}
</style>
@@ -1,7 +1,15 @@
<template>
<div class="about">
<controller-info/>
<device-info/>
<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>
+130 -48
View File
@@ -21,7 +21,7 @@
/>
<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" />
@@ -33,17 +33,18 @@
</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>
</template> -->
<va-button class="no-dark-style-va-button" v-if="!showDeviceSetting" color="primary" target="_blank" @click="showDeviceSettingClick()" small>
SHOW DEVICES
</va-button>
@@ -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,11 @@ import { chartData } from '../../../data/task/ChartsManagement'
import { taskInfo } from '../../../data/task/TaskInfo'
import CanvasChart from './chart/CanvasChart'
import TaskDevices from './controller/TaskDevices'
// import api from '../../../data/api'
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
@@ -109,11 +123,18 @@ export default {
components: {
CanvasChart,
TaskDevices,
TriggerChart,
// TaskFormula,
},
// async created () {
// await taskInfo.updateTaskInfo(this.$route.params.taskID)
// },
computed: {
...mapFields('taskContent', [
'deviceList',
]),
...mapFields('device', [
'triggerList',
'chartKey',
]),
},
data () {
return {
// modal
@@ -123,27 +144,23 @@ 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,
deviceList: {},
}
},
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))
@@ -154,7 +171,7 @@ export default {
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) {
@@ -163,7 +180,7 @@ export default {
// for (const d2 in this.deviceList) {
// const addr2 = this.deviceList[d2].info.device_address.join()
// if (addr1 === addr2) {
// console.log(this.deviceList[d2].parameterSet)
// // console.log(this.deviceList[d2].parameterSet)
// for (const p in this.deviceList[d2].parameterSet) {
// if (p !== 'STIMULATING') {
// if (parameter == null) {
@@ -185,7 +202,7 @@ export default {
// }
// }
// }
// console.log('****', parameter, content)
// // console.log('****', parameter, content)
// // this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
// // header: 'device_parameter/0',
// // device: parseInt(d1),
@@ -204,19 +221,73 @@ export default {
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(taskInfo.getDeviceIDByRaw(parseInt(topicSplit[3])), null, 'device')) {
taskInfo.deviceStart(parseInt(topicSplit[3]))
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(':')
@@ -246,14 +317,14 @@ export default {
taskInfo.deviceConnected(mes[1])
break
case 'shutdown':
taskInfo.controllerShutdown()
taskInfo.controllerShutdown(this.deviceList)
this.showShutdownModal = true
break
case 'start':
if (!taskInfo.getDeviceInfoByRawID(parseInt(parseInt(mes[1]))).info.isSync) {
taskInfo.deviceStart(parseInt(mes[1]))
if (chartData.defaultChartGenerator(taskInfo.getDeviceIDByRaw(parseInt(parseInt(mes[1]))), null, 'device')) {
taskInfo.deviceStart(parseInt(parseInt(mes[1])))
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
@@ -261,7 +332,7 @@ export default {
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.')
@@ -277,7 +348,7 @@ export default {
default:
break
}
console.log(String.fromCharCode.apply(null, data), topic)
// console.log(String.fromCharCode.apply(null, data), topic)
},
},
methods: {
@@ -297,6 +368,8 @@ export default {
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) {
@@ -308,6 +381,8 @@ export default {
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) {
@@ -321,10 +396,13 @@ export default {
// 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) {
@@ -450,7 +528,6 @@ export default {
// if have chart with device ID
for (const chart in chartData.getAllChartsData()) {
if (chartData.getAllChartsData()[chart].mappingID === deviceID) {
console.log('000')
return false
}
}
@@ -510,7 +587,7 @@ export default {
this.pageToast('The formula [' + formulaID + '] has been removed.')
},
startAllClick: async function () {
for (const device of taskInfo.getDeviceListRegister()) {
for (const device of this.deviceList) {
if (this.$refs.devices_ref === undefined) {
this.startDevice(device)
} else {
@@ -521,7 +598,7 @@ export default {
this.pageToast('The all devices have been started')
},
startDevice: async function (device) {
chartData.defaultChartGenerator(device.id, null, '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({
@@ -530,7 +607,7 @@ export default {
instruction: 'record',
}))
} else if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Elite')) {
console.log('elite')
// console.log('elite')
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(device.id),
@@ -541,11 +618,11 @@ export default {
device.isSync = true
// this.$emit('refreshSetting')
// ### show device info
console.log(taskInfo.getDeviceInfo(device.id))
// console.log(taskInfo.getDeviceInfo(device.id))
}
},
stopAllClick: function () {
for (const device of taskInfo.getDeviceListRegister()) {
for (const device of this.deviceList) {
if (this.$refs.devices_ref === undefined) {
this.stopDevice(device)
} else {
@@ -573,20 +650,25 @@ export default {
device.stopping = true
}
},
checkStiStatus: function () {
this.$refs.devices_ref.checkStiStatus()
},
exit: function () {
this.$router.push({
path: '/',
})
},
...mapActions('device', [deviceTypes.triggerChart.setDisplay]),
},
watch: {
},
async mounted () {
this.deviceList = 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)
// console.log(taskInfo.getTaskInfo().controllerID)
await this.pageInit()
// this.chartNumber = taskInfo.getTaskInfo().chartNumber
@@ -599,7 +681,7 @@ export default {
// }
},
destroyed () {
taskInfo.destroyed()
taskInfo.destroyed(this.deviceList)
for (const chart in chartData.getAllChartsData()) {
this.removeChart(chart)
}
@@ -611,17 +693,17 @@ export default {
</script>
<style lang="scss">
.area-style {
height: 100%;
overflow-y: hidden;
overflow-x: hidden;
// .area-style {
// height: 100%;
// overflow-y: hidden;
// overflow-x: hidden;
@include media-breakpoint-only(xl) {
height: 94vh;
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 {
@@ -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>
+203 -122
View File
@@ -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,97 +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 from device.
</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">
<div class="flex row xs12 md12 xl12 sm12" style="text-align: center;" >
<!-- <va-select
class="ma-1"
:on-change="mappingSelectChange()"
small
:label="'MAPPING'"
v-model="mappingSelect"
textBy="name"
:options="mappingOptions"
/> -->
<va-input
v-if="data.chartXMode === 'time'"
class="ma-1"
@keyup.enter="timeIntervalChange(timeIntervalInput)"
@blur="timeIntervalChange(timeIntervalInput)"
v-model="timeIntervalInput"
:label="'time-interval'"
>
<p slot="append" style="margin-right: 0;" small>
ms
</p>
</va-input>
<va-input
v-if="data.chartXMode === 'value'"
class="ma-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="ma-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="ma-1"
@keyup.enter="threeAxisIntervalChange(threeAxisIntervalInput)"
@blur="threeAxisIntervalChange(threeAxisIntervalInput)"
v-model="threeAxisIntervalInput"
:label="'3axis-interval'"
>
<p slot="append" style="margin-right: 0;" small>
g
</p>
</va-input>
<!-- <va-button class="no-dark-style-va-button" small @click="init()">INIT</va-button> -->
<va-button small color="dark" @click="remove()">REMOVE</va-button>
</div>
<!-- <div class="xs2 md2 xl2 sm2" style="text-align: center;" >
<va-button class="no-dark-style-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'
@@ -110,8 +114,10 @@ import { chartData } from '../../../../data/task/ChartsManagement'
export default {
name: 'CanvasChart',
components: {
CanvasChartSetting,
// CanvasChartSetting,
CanvasChartSource,
CanvasChartFilter,
CanvasChartFilterPopup,
},
props: {
chartID: {
@@ -158,58 +164,88 @@ export default {
},
methods: {
timeIntervalChange: function (val) {
chartData.getAllChartsData()[this.chartID].xAxis.forEach(x => {
if (x.type === 'time') {
x.interval = val * 1000
}
})
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) {
chartData.getAllChartsData()[this.chartID].xAxis.forEach(x => {
if (x.type === 'value') {
x.interval = val * 1000
// const maxList = []
// const minList = []
// x.seriesIndex.forEach(i => {
// maxList.push(Math.max(...chartData.getAllChartsData()[this.chartID].series[i].data.map(p => p[0])))
// minList.push(Math.min(...chartData.getAllChartsData()[this.chartID].series[i].data.map(p => p[0])))
// })
// const max = Math.max(maxList)
// const min = Math.min(minList)
// const center = (max + min) / 2
// x.max = center + (max - min)
// x.min = center - (max - min)
// x.max = (parseInt(x.max / (val * 1000)) + 1) * (val * 1000)
// x.min = (parseInt(x.min / (val * 1000)) - 1) * (val * 1000)
}
})
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) {
chartData.getAllChartsData()[this.chartID].yAxis.forEach(y => {
if (parseInt(y.channel) <= 255) {
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 / (val * 1000)) + 1) * (val * 1000)
y.min = (parseInt(y.min / (val * 1000)) - 1) * (val * 1000)
}
})
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) {
chartData.getAllChartsData()[this.chartID].yAxis.forEach(y => {
if (parseInt(y.channel) >= 255) {
y.interval = val * 1
}
})
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 = ''
@@ -262,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)
@@ -277,6 +352,12 @@ export default {
</script>
<style lang="scss">
.circle-button {
height: 25px;
width: 25px;
border-radius: '50%';
}
.no-dark-style-va-button {
&:focus {
filter: brightness(100%);
@@ -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>
@@ -176,7 +176,12 @@ export default {
})
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({
@@ -200,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({
@@ -238,8 +243,13 @@ export default {
})
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,
@@ -291,20 +301,28 @@ 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.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())
}
@@ -325,17 +343,17 @@ export default {
value: String(i),
})
}
console.log(chartData.getAllChartsData()[this.chartID])
// console.log(chartData.getAllChartsData()[this.chartID])
},
checkSourceAddStatus () {
if (this.sourceList.indexOf([this.deviceSelectX.name, this.deviceSelectX.id, this.channelSelectX.id].toString()) >= 0) {
this.error = 'some source have been registered'
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 = 'some source have been registered'
this.error = 'The same source has been selected in a subplot.'
return
}
this.error = ''
@@ -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,7 +10,7 @@
@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"
>
@@ -28,17 +28,31 @@
</va-avatar>
</va-item-section>
<va-item-section class="ml-3">
<va-item-section class="ml-3" caption>
<va-item-label>
{{ device.name }}
</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">
@@ -57,7 +71,7 @@
</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 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> -->
@@ -82,7 +96,7 @@
import EliteParameterWindow from '../parameter/EliteParameterWindow'
import NeuliveParameterWindow from '../parameter/NeuliveParameterWindow'
import FileControlWindow from '../meta/FileControlWindow'
import { mapGetters } from 'vuex'
import { mapActions } from 'vuex'
import types from '@/store/modules/task/content/types'
export default {
@@ -108,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
@@ -115,44 +135,41 @@ export default {
remove: function () {
this.$emit('remove', this.selectDevice)
},
start: function (device) {
const checkParam = this.getIsParamSetDoneParam()(device.type)
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)
}
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) {
if (!device.stopping) {
this.$emit('stop', device)
this.pageToast('The device ' + device.name + ' has been stopped.')
}
this.$emit('stop', device)
this.pageToast('The device ' + device.name + ' has been stopped.')
},
record: function (device) {
const checkParam = this.getIsRecordingParamSetDoneParam()(device.type)
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)
}
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) {
device.stopping = true
this.$emit('stopRecord', device)
this.pageToast('The device ' + device.name + ' has been stopped.')
},
@@ -197,8 +214,8 @@ export default {
this.$emit('detect', device)
this.pageToast('The device ' + device.name + ' has been detect.')
},
stimulate: function (device) {
const checkParam = this.getIsStimulationParamSetDoneParam()
stimulate: async function (device) {
const checkParam = await this.checkIfStimulationSetDoneParam({ device: device })
const status = checkParam.status
const message = checkParam.message
if (status === true) {
@@ -219,10 +236,10 @@ export default {
recoverDetectButton () {
document.getElementById('detectButton').className += ' no-dark-style-va-button'
},
...mapGetters('taskContent', [types.param.getIsRecordingParamSetDone, types.param.getIsStimulationParamSetDone, types.param.getIsParamSetDone]),
...mapActions('taskContent', [types.param.checkIfRecordingSetDone, types.param.checkIfStimulationSetDone, types.param.checkIfDeviceSetDone]),
},
destroyed () {
this.deviceList.length = 0
// this.deviceList.length = 0
},
}
</script>
@@ -22,10 +22,12 @@
@stop="stopDevice($event)"
@record="record($event)"
@stopRecord="stopRecord($event)"
@sti="sti($event)" @sti_stop="stiStop($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;">
@@ -46,22 +48,49 @@
</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>
</div>
</template>
<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: {
@@ -71,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: {
@@ -105,22 +140,28 @@ export default {
// }
// }
// }
console.log(this.deviceOptions)
for (let i = 4; i <= 7; i++) {
// // 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 {
console.log(this.deviceList)
const index = this.deviceList.findIndex(d => taskInfo.getRawDeviceID(d.id) === i)
console.log(index)
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)
@@ -130,9 +171,9 @@ export default {
// }
},
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),
@@ -153,20 +194,35 @@ export default {
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.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))
// // console.log(taskInfo.getDeviceInfo(device.id))
}
},
stopDevice: async function (device) {
@@ -176,12 +232,12 @@ export default {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(device.id),
instruction: 'stop_record',
instruction: 'stop_stimulate',
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(device.id),
instruction: 'stop_stimulate',
instruction: 'stop_record',
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
@@ -197,7 +253,7 @@ export default {
instruction: 'interrupt',
}))
}
device.stopping = true
// device.stopping = true
}
},
detectDevice: function (device) {
@@ -216,7 +272,11 @@ export default {
}, 5000)
},
record: async function (device) {
await chartData.defaultChartGenerator(device.id, null, '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',
@@ -224,29 +284,27 @@ export default {
instruction: 'record',
}))
device.isSync = true
device.stopping = false
// 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))
}
},
stopRecord: function (device) {
if (!device.stopping) {
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
device.stopping = true
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
// device.stopping = true
},
sti: function (device) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
@@ -266,6 +324,13 @@ export default {
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({
@@ -280,6 +345,7 @@ export default {
content: 0,
}))
device.isStimulate = false
clearTimeout(this.stiTimeOut)
},
fastSettle: function (device) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
@@ -288,37 +354,32 @@ export default {
instruction: 'FAST_SET',
}))
},
// 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)
// 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)
// },
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
@@ -347,11 +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,
isStimulate: taskInfo.getDeviceInfoByRawID(selectID).info.isStimulate,
stopping: false,
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 = ''
@@ -380,6 +446,23 @@ export default {
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)
},
@@ -395,6 +478,16 @@ export default {
}
})
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
async mounted () {
// this.pageMqttSub()
@@ -404,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,83 +0,0 @@
<template>
<div>
<fieldset>
<va-radio-button
option="Auto"
v-model="optionValue"
label="Auto"
/>
<br v-if="optionValue === 'Auto'"/>
<auto-block v-if="optionValue === 'Auto'" :ref="'AutoBlock'" :deviceID="deviceID"/>
<va-radio-button
option="Advanced"
v-model="optionValue"
label="Advanced"
/>
<br v-if="optionValue === 'Advanced'"/>
<advanced-block v-if="optionValue === 'Advanced'" :ref="'AdvancedBlock'" :deviceID="deviceID"/>
</fieldset>
</div>
</template>
<script>
import { taskInfo } from '../../../../data/task/TaskInfo'
import AutoBlock from '../parameter/item/DPV/AutoBlock'
import AdvancedBlock from '../parameter/item/DPV/AdvancedBlock'
export default {
name: 'EliteParameterRecordingEliteDPV',
components: {
AutoBlock,
AdvancedBlock,
},
props: {
deviceID: {
type: Number,
required: true,
},
deviceName: {
type: String,
default: 'Elite',
},
},
created () {
},
data () {
return {
optionValue: 'Auto',
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
// Array[String of Parameter Nmae, Value]
deviceParameterChange: function (e) {
console.log('e[0],e[1]', e[0], ',', e[1])
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: e[0],
content: e[1],
}))
},
refresh () {
if (this.$refs.AutoBlock != null) {
this.$refs.AutoBlock.refresh()
}
if (this.$refs.AdvancedBlock != null) {
this.$refs.AdvancedBlock.refresh()
}
},
},
mounted () {
},
watch: {
},
destroyed () {
},
}
</script>
@@ -41,71 +41,71 @@
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">Current Range<p/>
</div>
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0" >
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<level-button :ref="'currentRangeSelect'" :deviceID="deviceID" :options="currentRangeOptions" :parameterName="'ADC_LEVEL_I_15'" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm4 xl4 md4 xs4 pa-0 ma-0">
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">Voltage Range<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 pa-0 ma-0" >
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<level-button :ref="'voltageInRangeSelect'" :deviceID="deviceID" :options="voltageInRangeOptions" :parameterName="'ADC_LEVEL_V_IN_15'" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm4 xl4 md4 xs4 pa-0 ma-0">
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">High Z<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 pa-0 ma-0" >
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<level-button :ref="'highzSelect'" :deviceID="deviceID" :options="highzOptions" :parameterName="'CTRL_HIGH_Z_15'" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm4 xl4 md4 xs4 pa-0 ma-0">
<p class="display-6">Voltage Initial<p/>
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">E Initial<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 pa-0 ma-0" >
<volt-range :ref="'voltInitialNumber'" :deviceID="deviceID" :parameterName="'VOLT_INITIAL'" :minValue="-5" :maxValue="5" @parameterChange="deviceParameterChange($event)" />
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<volt-range :ref="'voltInitialNumber'" :deviceID="deviceID" :parameterName="'VOLT_INITIAL'" :minValue="-1.8" :maxValue="2" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm4 xl4 md4 xs4 pa-0 ma-0">
<p class="display-6">Voltage Max<p/>
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">E1<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 pa-0 ma-0" >
<volt-range :ref="'voltMaxNumber'" :deviceID="deviceID" :parameterName="'VOLT_MAX'" :minValue="-5" :maxValue="5" @parameterChange="deviceParameterChange($event)" />
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<volt-range :ref="'voltMaxNumber'" :deviceID="deviceID" :parameterName="'VOLT_MAX'" :minValue="-1.8" :maxValue="2" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm4 xl4 md4 xs4 pa-0 ma-0">
<p class="display-6">Voltage Min<p/>
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">E2<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 pa-0 ma-0" >
<volt-range :ref="'voltMinNumber'" :deviceID="deviceID" :parameterName="'VOLT_MIN'" :minValue="-5" :maxValue="5" @parameterChange="deviceParameterChange($event)" />
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<volt-range :ref="'voltMinNumber'" :deviceID="deviceID" :parameterName="'VOLT_MIN'" :minValue="-1.8" :maxValue="2" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm4 xl4 md4 xs4 pa-0 ma-0">
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">Voltage Scan Rate<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 pa-0 ma-0" >
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<scan-rate-range :ref="'voltScanRateNumber'" :deviceID="deviceID" :parameterName="'Scan_Rate'" :minValue="0.01" :maxValue="1000" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm4 xl4 md4 xs4 pa-0 ma-0">
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">Resolution<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 pa-0 ma-0" >
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<resolution-range :ref="'sampleRateNumber'" :deviceID="deviceID" :parameterName="'SAMPLE_RATE'" :minValue="0.1" :maxValue="100" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm4 xl4 md4 xs4 pa-0 ma-0">
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">Cycle<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 pa-0 ma-0" >
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<cycle-range :ref="'cycleNoNumber'" :deviceID="deviceID" :parameterName="'CYCLE_NUMBER'" :minValue="1" :maxValue="50000" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
@@ -370,7 +370,7 @@ export default {
},
// Array[String of Parameter Nmae, Value]
deviceParameterChange: function (e) {
console.log('e[0],e[1]', e[0], ',', e[1])
// console.log('e[0],e[1]', e[0], ',', e[1])
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
@@ -395,6 +395,7 @@ export default {
this.measureEocButton.status = false
},
refresh () {
// taskInfo.getDeviceInfo(this.deviceID).parameterSet.CHANNEL_LABEL = ['Z_image_Raw', 'Z_Real_Raw', 'Frequency', 'Cycle', 'Z_imag', 'Z_real', 'Impedance', 'Phase', 'Current', 'Level gain']
this.workingModeSelect = this.workingModeOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.MODE]
if (this.workingModeSelect != null) {
this.workingModeSelectChange(this.workingModeSelect)
@@ -425,11 +426,11 @@ export default {
}
this.FreqStart = String(parseFloat(Math.round(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.FREQ_START * 0.0149) * 100)) / 100).toFixed(1)) === '0.0' ? '0.015' : String(parseFloat(Math.round(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.FREQ_START * 0.0149) * 100)) / 100).toFixed(1))
if (this.$refs.FreqRange != null) {
this.$refs.FreqRange.itemChangeMin(this.FreqStart)
this.$refs.FreqRange.itemChangeMax(this.FreqStart)
}
this.FreqStop = String(parseFloat(Math.round(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.FREQ_STOP * 0.0149) * 100)) / 100).toFixed(1)) === '0.0' ? '0.015' : String(parseFloat(Math.round(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.FREQ_STOP * 0.0149) * 100)) / 100).toFixed(1))
if (this.$refs.FreqRange != null) {
this.$refs.FreqRange.itemChangeMax(this.FreqStop)
this.$refs.FreqRange.itemChangeMin(this.FreqStop)
}
this.PointsPerDecades = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.PPD)))
if (this.$refs.PointsPerDecades != null) {
@@ -488,7 +489,7 @@ export default {
if (this.workingModeSelect.id !== taskInfo.getDeviceInfo(this.deviceID).parameterSet.MODE) {
this.deviceParameterChange(['MODE', this.workingModeSelect.id])
console.log(this.workingModeSelect.id, this.workingModeSelect.description)
// console.log(this.workingModeSelect.id, this.workingModeSelect.description)
}
},
instruParameterChange: function (e) {
@@ -0,0 +1,106 @@
<template>
<div class="flex px-0 mx-0 my-0 py-0">
<va-tree-root class="flex sm12 xl12 md12 xs12 px-0 mx-0 my-0 py-0">
<div class="flex sm12 xl12 md12 xs12 px-0 mx-0 my-0 py-0">
<va-select
@input="workingModeSelectChange(workingModeSelect)"
:label="'WORKING MODE'"
v-model="workingModeSelect"
textBy="description"
:options="workingModeOptions"
style="width: 300px;"
noClear
/>
</div>
<div v-if="workingModeSelect != null && workingModeSelect.id == 0">
<elite-parameter-recording-elite-a-c-c :ref="'CurrentControl'" :deviceID="deviceID" :deviceName="deviceName"/>
</div>
</va-tree-root>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
import EliteParameterRecordingEliteACC from '../parameter/item/AnalogCurrentControl/EliteParameterRecordingEliteACC'
export default {
name: 'EliteParameterRecordingEliteTrigger',
components: {
EliteParameterRecordingEliteACC,
},
props: {
deviceID: {
type: Number,
required: true,
},
deviceName: {
type: String,
default: 'Elite',
},
},
created () {
},
data () {
return {
workingModeSelect: {
id: -1,
description: 'Init',
},
workingModeOptions: [
{
id: 0,
description: 'Analog Current Control (ACC)',
},
],
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
// Array[String of Parameter Nmae, Value]
deviceParameterChange: function (e) {
console.log('e[0],e[1]', e[0], ',', e[1])
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: e[0],
content: e[1],
}))
},
refresh () {
this.workingModeSelect = this.workingModeOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.MODE]
if (this.workingModeSelect != null) {
this.workingModeSelectChange(this.workingModeSelect)
}
if (this.$refs.CurrentControl != null) {
this.$refs.CurrentControl.refresh()
}
},
workingModeSelectChange (val) {
if (this.workingModeSelect.id === -1) {
return false
}
this.workingModeSelect = val
if (this.workingModeSelect.id !== taskInfo.getDeviceInfo(this.deviceID).parameterSet.MODE) {
this.deviceParameterChange(['MODE', this.workingModeSelect.id])
console.log(this.workingModeSelect.id, this.workingModeSelect.description)
}
},
},
mounted () {
this.refresh()
},
watch: {
},
destroyed () {
},
}
</script>
@@ -1,39 +1,37 @@
<template>
<div class="flex">
<va-tree-root>
<div class="row pt-0 pb-0">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="workingModeSelectChange(workingModeSelect)"
:label="'WORKING MODE'"
v-model="workingModeSelect"
textBy="description"
:options="workingModeOptions"
noClear
style="width: 200px;"
/>
<va-button
v-if="!measureEocButton.status && workingModeSelect != null && (workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9)"
color="primary"
target="_blank"
@click="measureEoc()"
small>
{{measureEocButton.start}}
</va-button>
<va-button
v-if="measureEocButton.status && workingModeSelect != null && (workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9)"
color="danger"
target="_blank"
@click="measureEocStop()"
small>
{{measureEocButton.stop}}
</va-button>
</div>
<div class="flex px-0 mx-0 my-0 py-0">
<va-tree-root class="flex sm12 xl12 md12 xs12 px-0 mx-0 my-0 py-0">
<div class="flex sm12 xl12 md12 xs12 px-0 mx-0 my-0 py-0">
<va-select
@input="workingModeSelectChange(workingModeSelect)"
:label="'WORKING MODE'"
v-model="workingModeSelect"
textBy="description"
:options="workingModeOptions"
noClear
style="width: 300px;"
/>
<va-button
v-if="!measureEocButton.status && workingModeSelect != null && (workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9)"
color="primary"
target="_blank"
@click="measureEoc()"
small>
{{measureEocButton.start}}
</va-button>
<va-button
v-if="measureEocButton.status && workingModeSelect != null && (workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9)"
color="danger"
target="_blank"
@click="measureEocStop()"
small>
{{measureEocButton.stop}}
</va-button>
</div>
<!-- 1.5ui -->
<va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 0 || workingModeSelect.id == 1 || workingModeSelect.id == 5 || workingModeSelect.id == 6 || workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9 || workingModeSelect.id == 11"
v-if="workingModeSelect != null && workingModeSelect.id == 0 || workingModeSelect.id == 1 || workingModeSelect.id == 2 || workingModeSelect.id == 4 || workingModeSelect.id == 5 || workingModeSelect.id == 6 || workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9 || workingModeSelect.id == 11 || workingModeSelect.id == 13"
style="font-size: 20px;"
:label="'Range ( ' + currentRangeOptions[currentRangeSelect].label + ' )'">
<va-tree-node>
@@ -42,7 +40,7 @@
</va-tree-category>
<va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 0 || workingModeSelect.id == 1 || workingModeSelect.id == 4 ||workingModeSelect.id == 6 || workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9 || workingModeSelect.id == 11 || workingModeSelect.id == 13"
v-if="workingModeSelect != null && workingModeSelect.id == 0 || workingModeSelect.id == 1 || workingModeSelect.id == 2 || workingModeSelect.id == 4 || workingModeSelect.id == 5 || workingModeSelect.id == 6 || workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9 || workingModeSelect.id == 11 || workingModeSelect.id == 13"
style="font-size: 20px;"
:label="'Range ( ' + voltageInRangeOptions[voltageInRangeSelect].label + ' )'">
<va-tree-node>
@@ -239,7 +237,7 @@
</va-tree-node>
</va-tree-category>
<va-tree-category
<!-- <va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 13"
style="font-size: 20px;"
:label="'Duration ( ' + duration + timeOptions[timeUnit].label + ' )'">
@@ -256,7 +254,7 @@
</div>
</div>
</va-tree-node>
</va-tree-category>
</va-tree-category> -->
<va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 12"
@@ -381,8 +379,8 @@ import OppLevelButton from '../parameter/item/OppLevelButton'
import MicroAmpereRange from '../parameter/item/MicroAmpereRange'
import ScanRateRange from '../parameter/item/ScanRateRange'
import ResolutionRange from '../parameter/item/ResolutionRange'
import EliteParameterRecordingElitePulseSensing from './EliteParameterRecordingElitePulseSensing'
import EliteParameterRecordingEliteDPV from './EliteParameterRecordingEliteDPV'
import EliteParameterRecordingElitePulseSensing from '../parameter/item/PulseSensing/EliteParameterRecordingElitePulseSensing'
import EliteParameterRecordingEliteDPV from '../parameter/item/DPV/EliteParameterRecordingEliteDPV'
export default {
name: 'EliteParameterRecordingElitezm15',
@@ -629,7 +627,7 @@ export default {
},
// Array[String of Parameter Nmae, Value]
deviceParameterChange: function (e) {
console.log('e[0],e[1]', e[0], ',', e[1])
// console.log('e[0],e[1]', e[0], ',', e[1])
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
@@ -777,7 +775,7 @@ export default {
if (this.workingModeSelect.id !== taskInfo.getDeviceInfo(this.deviceID).parameterSet.MODE) {
this.deviceParameterChange(['MODE', this.workingModeSelect.id])
console.log(this.workingModeSelect.id, this.workingModeSelect.description)
// console.log(this.workingModeSelect.id, this.workingModeSelect.description)
}
},
measureEoc () {
@@ -1,13 +1,10 @@
<template>
<div>
<elite-parameter-recording v-if="eliteVer=='1'" :ref="'rec_ref'" :deviceID="deviceID"/>
<!-- <elite-parameter-recording-elitezm15 :ref="'rec_ref'" :deviceID="deviceID"/> -->
<!--<elite-parameter-recording :ref="'rec_ref'" :deviceID="deviceID"/>-->
<elite-parameter-recording-elitezm15 v-else-if="eliteVer=='2'" :ref="'rec_ref'" :deviceID="deviceID"/>
<elite-parameter-recording-elite-e-i-s v-else :ref="'rec_ref'" :deviceID="deviceID"/>
<!--<elite-parameter-recording :ref="'rec_ref'" :deviceID="deviceID"/>-->
<elite-parameter-recording v-if="eliteVer=='1'" :ref="'rec_ref_1'" :deviceID="deviceID"/>
<elite-parameter-recording-elitezm15 v-else-if="eliteVer=='2'" :ref="'rec_ref_2'" :deviceID="deviceID"/>
<elite-parameter-recording-elite-e-i-s v-else-if="eliteVer=='4'" :ref="'rec_ref_4'" :deviceID="deviceID"/>
<elite-parameter-recording-elite-trigger v-else-if="eliteVer=='5'" :ref="'rec_ref_5'" :deviceID="deviceID"/>
<elite-parameter-recording-elite-e-i-s v-else :ref="'rec_ref_4'" :deviceID="deviceID"/>
</div>
</template>
@@ -16,6 +13,7 @@
import EliteParameterRecording from './EliteParameterRecording'
import EliteParameterRecordingElitezm15 from './EliteParameterRecordingElitezm15'
import EliteParameterRecordingEliteEIS from './EliteParameterRecordingEliteEIS'
import EliteParameterRecordingEliteTrigger from './EliteParameterRecordingEliteTrigger'
import { taskInfo } from '../../../../data/task/TaskInfo'
export default {
@@ -24,6 +22,7 @@ export default {
EliteParameterRecording,
EliteParameterRecordingElitezm15,
EliteParameterRecordingEliteEIS,
EliteParameterRecordingEliteTrigger,
},
props: {
deviceID: {
@@ -53,6 +52,12 @@ export default {
} else if (JSON.stringify(ver.slice(0, 4)) === JSON.stringify([0, 2, 1, 7])) {
this.eliteVer = '3' // megafly
// console.log('3:', JSON.stringify(ver.slice(0, 4)), ',', JSON.stringify([0, 2, 1, 7]))
} else if (JSON.stringify(ver.slice(0, 4)) === JSON.stringify([0, 4, 1, 0])) {
this.eliteVer = '4' // eis
} else if (JSON.stringify(ver.slice(0, 4)) === JSON.stringify([0, 5, 1, 0])) {
this.eliteVer = '5' // trigger
} else {
this.eliteVer = '4'
}
},
mqttPub: function (topic, mes) {
@@ -70,11 +75,42 @@ export default {
this.compareEliteVer(taskInfo.getDeviceInfo(this.deviceID).info.serial_number)
},
refresh: function () {
this.$nextTick(() => {
if (this.$refs.rec_ref != null) {
this.$refs.rec_ref.refresh()
}
})
// console.log(this.eliteVer)
switch (this.eliteVer) {
case '1':
this.$nextTick(() => {
if (this.$refs.rec_ref_1 != null) {
this.$refs.rec_ref_1.refresh()
}
})
break
case '2':
this.$nextTick(() => {
if (this.$refs.rec_ref_2 != null) {
this.$refs.rec_ref_2.refresh()
}
})
break
case '4':
this.$nextTick(() => {
if (this.$refs.rec_ref_4 != null) {
this.$refs.rec_ref_4.refresh()
}
})
break
case '5':
this.$nextTick(() => {
if (this.$refs.rec_ref_5 != null) {
this.$refs.rec_ref_5.refresh()
}
})
break
}
// this.$nextTick(() => {
// if (this.$refs.rec_ref != null) {
// this.$refs.rec_ref.refresh()
// }
// })
// console.log('window:3,refresh(this.$nextTick:', this.$nextTick, ',this.$refs:', this.$refs, ')')
},
@@ -1,30 +1,8 @@
<template>
<div class="flex" >
<!-- <div>
<div class="row sm12 xl12 md12 xs12">
<va-button
class="mx-1 px-2 mb-3"
color="success"
v-if="!recordOn"
@click="recordClick"
small
>
Record
</va-button>
<va-button
class="mx-1 px-2 mb-3"
color="danger"
v-else
@click="recordClick"
small
>
Stop
</va-button>
</div>
</div> -->
<va-tree-root >
<va-tree-category
isOpen
style="font-size: 20px;"
:label="'Channels'">
<va-tree-node>
@@ -128,62 +106,6 @@
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Radio Frequency'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="radioFrequencySelectChange()"
:label="''"
v-model="radioFrequencySelect"
textBy="description"
:options="radioFrequencyOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Mem Radio Frequency'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="memRadioFrequencySelectChange()"
:label="''"
v-model="memRadioFrequencySelect"
textBy="description"
:options="memRadioFrequencyOptions"
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Led Brightness'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="ledBrightnessSelectChange()"
:label="''"
v-model="ledBrightnessSelect"
textBy="description"
:options="ledBrightnessOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Accelerator Sensitivity'">
@@ -202,54 +124,13 @@
</div>
</va-tree-node>
</va-tree-category>
<!-- <va-tree-category
style="font-size: 20px;"
:label="'Sample rate'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="sampleRateChange(4)">
4
</va-button>
<va-input
@keyup.enter="sampleRateChange(sampleRateInput)"
v-model="sampleRateInput"
class="mb-0"
style="width: 100px;"
>
<p slot="append" style="margin-right: 0;" small>
Hz
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="sampleRateChange(1000)">
1000
</va-button>
</div>
<va-slider
@mouseup.native="sampleRateChange(sampleRate)"
@mouseleave.native="sampleRateChange(sampleRate)"
@touchend.native="sampleRateChange(sampleRate)"
class="flex sm12 xl12 md12 xs12"
value-visible
v-model="sampleRate"
:min="4"
:max="1000"
/>
</div>
</div>
</va-tree-node>
</va-tree-category> -->
</va-tree-root>
</div>
</template>
<script>
import { taskInfo } from '../../../../data/task/TaskInfo'
import { chartData } from '../../../../data/task/ChartsManagement'
import { mapFields } from 'vuex-map-fields'
export default {
name: 'NeuliveParameterRecording',
@@ -267,6 +148,7 @@ export default {
},
data () {
return {
channelList: [],
ampGainSelect: null,
ampGainOptions: [
// {
@@ -290,142 +172,48 @@ export default {
sampleRateOptions: [
{
id: 0,
value: 800,
value: 1000,
description: '1k',
},
{
id: 1,
value: 400,
value: 2000,
description: '2k',
},
{
id: 2,
value: 200,
value: 4000,
description: '4k',
},
{
id: 3,
value: 160,
value: 5000,
description: '5k',
},
{
id: 4,
value: 100,
value: 8000,
description: '8k',
},
{
id: 5,
value: 80,
value: 10000,
description: '10k',
},
{
id: 6,
value: 40,
value: 20000,
description: '20k',
},
],
radioFrequencySelect: null,
radioFrequencyOptions: [
{
id: 0,
value: -20,
description: '-20',
},
{
id: 1,
value: -16,
description: '-16',
},
{
id: 2,
value: -12,
description: '-12',
},
{
id: 3,
value: -8,
description: '-8',
},
{
id: 4,
value: -4,
description: '-4',
},
{
id: 5,
value: 0,
description: '0',
},
{
id: 6,
value: 4,
description: '4',
},
{
id: 7,
value: 8,
description: '8',
},
],
memRadioFrequencySelect: null,
memRadioFrequencyOptions: [
{
id: 0,
value: -20,
description: '-20',
value: 25000,
description: '25k',
},
{
id: 1,
value: -16,
description: '-16',
},
{
id: 2,
value: -12,
description: '-12',
},
{
id: 3,
value: -8,
description: '-8',
},
{
id: 4,
value: -4,
description: '-4',
},
{
id: 5,
value: 0,
description: '0',
},
{
id: 6,
value: 4,
description: '4',
},
{
id: 7,
value: 8,
description: '8',
},
],
ledBrightnessSelect: null,
ledBrightnessOptions: [
{
id: 0,
value: 0,
description: 'off',
},
{
id: 1,
value: 1,
description: 'bright',
},
{
id: 2,
value: 2,
description: 'normal',
id: 8,
value: 31250,
description: '31.25k',
},
],
acceleratorSensitivitySelect: null,
@@ -457,11 +245,6 @@ export default {
axisChannelList: [],
}
},
computed: {
...mapFields('taskContent', [
'channelList',
]),
},
mqtt: {
},
methods: {
@@ -470,14 +253,18 @@ export default {
},
refresh () {
this.channelList.length = 0
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_LIST = Array(16).fill(0)
const channelSet = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RECORDING_CH.toString(2).split('').reverse()
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_NUMBER = 0
channelSet.forEach((element, index) => {
if (parseInt(element) > 0) {
this.channelList.push(index + 1)
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_LIST[index] = 1
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_NUMBER += 1
}
})
this.ampGainSelect = this.ampGainOptions[(taskInfo.getDeviceInfo(this.deviceID).parameterSet.AMP_GAIN) % 4]
this.sampleRateSelect = this.sampleRateOptions[this.sampleRateOptions.findIndex(ele => ele.value === taskInfo.getDeviceInfo(this.deviceID).parameterSet.ADC_CLOCK)]
this.sampleRateSelect = this.sampleRateOptions[this.sampleRateOptions.findIndex(ele => ele.value === taskInfo.getDeviceInfo(this.deviceID).parameterSet.SAMPLE_RATE)]
this.recordOn = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RECORDING
this.axisChannelList.length = 0
const axisChannelSet = taskInfo.getDeviceInfo(this.deviceID).parameterSet.AXIS_CH.toString(2).split('').reverse()
@@ -494,10 +281,6 @@ export default {
}
}
})
this.radioFrequencySelect = this.radioFrequencyOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.RADIO_FREQUENCY]
this.memRadioFrequencySelect = this.memRadioFrequencyOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.MEM_RADIO_FREQUENCY]
this.ledBrightnessSelect = this.ledBrightnessOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.LED_BRIGHTNESS]
this.acceleratorSensitivitySelect = this.acceleratorSensitivityOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.ACCELERATOR_S]
},
channelClickAdd (val) {
@@ -559,57 +342,13 @@ export default {
}
},
sampleRateSelectChange () {
if (this.sampleRateSelect != null && this.sampleRateSelect.value !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.ADC_CLOCK))) {
if (this.sampleRateSelect != null && this.sampleRateSelect.value !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.SAMPLE_RATE))) {
const adcClock = 1e6 / this.sampleRateSelect.value
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'ADC_CLOCK',
content: this.sampleRateSelect.value,
}))
}
},
radioFrequencySelectChange () {
if (this.radioFrequencySelect != null && this.radioFrequencySelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.RADIO_FREQUENCY))) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RADIO_FREQUENCY',
content: this.radioFrequencySelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_update_radio_frequency/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.radioFrequencySelect.value,
}))
}
},
memRadioFrequencySelectChange () {
if (this.memRadioFrequencySelect != null && this.memRadioFrequencySelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.MEM_RADIO_FREQUENCY))) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'MEM_RADIO_FREQUENCY',
content: this.memRadioFrequencySelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_set_central_rf/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.memRadioFrequencySelect.value,
}))
}
},
ledBrightnessSelectChange () {
if (this.ledBrightnessSelect != null && this.ledBrightnessSelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.LED_BRIGHTNESS))) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'LED_BRIGHTNESS',
content: this.ledBrightnessSelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_update_led_brightness/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.ledBrightnessSelect.value,
parameter: 'SAMPLE_RATE|ADC_CLOCK',
content: `${this.sampleRateSelect.value}|${String(adcClock)}`,
}))
}
},
@@ -649,35 +388,18 @@ export default {
for (const chartID in charts) {
for (const seriesIndex in charts[chartID].series) {
if (charts[chartID].series[seriesIndex].yAxisSource[1] >= 256 && charts[chartID].series[seriesIndex].yAxisSource[1] <= 260) {
charts[chartID].yAxis[seriesIndex].min = -scaleRange
charts[chartID].yAxis[seriesIndex].max = scaleRange
if (parseInt(charts[chartID].series[seriesIndex].yAxisSource[1]) === 260) {
charts[chartID].yAxis[seriesIndex].min = 0
charts[chartID].yAxis[seriesIndex].max = Math.ceil(Math.sqrt(Math.pow(scaleRange, 2) * 3))
} else {
charts[chartID].yAxis[seriesIndex].min = -scaleRange
charts[chartID].yAxis[seriesIndex].max = scaleRange
}
}
}
}
}
},
// sampleRateChange (val) {
// if (this.sampleRate == null) {
// return false
// }
// if (isNaN(val) || parseInt(val) > 1000 || parseInt(val) < 4) {
// this.sampleRateInput = '1000'
// this.sampleRate = 1000
// return false
// }
// if (parseInt(this.sampleRateInput) !== this.sampleRate || this.sampleRate !== parseInt(val)) {
// this.sampleRateInput = String(val)
// this.sampleRate = parseInt(val)
// }
// if (this.sampleRate !== parseInt(200 / parseFloat(taskInfo.getDeviceInfo(this.deviceID).parameterSet.ADC_CLOCK / 1000))) {
// this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
// header: 'device_parameter/0',
// device: taskInfo.getRawDeviceID(this.deviceID),
// parameter: 'ADC_CLOCK',
// content: parseInt(parseFloat(1 / parseFloat(this.sampleRate / 200)) * 1000),
// }))
// }
// },
recordClick () {
this.recordOn = !this.recordOn
if (this.recordOn) {
@@ -0,0 +1,607 @@
<template>
<div class="flex" >
<va-tree-root >
<va-tree-category
style="font-size: 20px;"
:label="'Channels'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div
style='display: inline-block;'
v-for="channel in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]"
:key="channel"
>
<va-button
class="ma-1 pa-0 circle-button"
v-if="channelList != null && channelList.indexOf(channel) >= 0"
@click="channelClickRemove(channel)"
small
>
{{channel}}
</va-button>
<va-button
class="ma-1 pa-0 circle-button"
v-if="channelList == null || channelList.indexOf(channel) < 0"
@click="channelClickAdd(channel)"
small outline
>
{{channel}}
</va-button>
</div>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'3-AXIS'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div
style='display: inline-block;'
v-for="axisChannel in ['x','y','z','m']"
:key="axisChannel"
>
<va-button
class="ma-1 pa-0 circle-button"
v-if="axisChannelList != null && axisChannelList.indexOf(axisChannel) >= 0"
@click="axisChannelClickRemove(axisChannel)"
small
>
{{axisChannel}}
</va-button>
<va-button
class="ma-1 pa-0 circle-button"
v-if="axisChannelList == null || axisChannelList.indexOf(axisChannel) < 0"
@click="axisChannelClickAdd(axisChannel)"
small outline
>
{{axisChannel}}
</va-button>
</div>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Amp gain'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="ampGainSelectChange()"
:label="''"
v-model="ampGainSelect"
textBy="description"
:options="ampGainOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Sample Rate'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="sampleRateSelectChange()"
:label="''"
v-model="sampleRateSelect"
textBy="description"
:options="sampleRateOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Accelerator Sensitivity'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="acceleratorSensitivitySelectChange()"
:label="''"
v-model="acceleratorSensitivitySelect"
textBy="description"
:options="acceleratorSensitivityOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
</va-tree-root>
</div>
</template>
<script>
import { taskInfo } from '../../../../data/task/TaskInfo'
import { chartData } from '../../../../data/task/ChartsManagement'
export default {
name: 'NeuliveParameterRecording',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
deviceName: {
type: String,
default: 'Neulive',
},
},
data () {
return {
channelList: [],
ampGainSelect: null,
ampGainOptions: [
// {
// id: 0,
// description: '25',
// },
{
id: 0,
description: '100',
},
{
id: 2,
description: '300',
},
{
id: 1,
description: '500',
},
],
sampleRateSelect: null,
sampleRateOptions: [
{
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: 16000,
description: '16k',
},
{
id: 7,
value: 20000,
description: '20k',
},
{
id: 8,
value: 25000,
description: '25k',
},
{
id: 9,
value: 32000,
description: '32k',
},
{
id: 10,
value: 40000,
description: '40k',
},
{
id: 11,
value: 50000,
description: '50k',
},
{
id: 12,
value: 64000,
description: '64k',
},
{
id: 13,
value: 80000,
description: '80k',
},
{
id: 14,
value: 100000,
description: '100k',
},
],
acceleratorSensitivitySelect: null,
acceleratorSensitivityOptions: [
{
id: 0,
value: 3,
description: '2G',
},
{
id: 1,
value: 5,
description: '4G',
},
{
id: 2,
value: 8,
description: '8G',
},
{
id: 3,
value: 12,
description: '16G',
},
],
// sampleRateInput: '1000',
// sampleRate: null,
recordOn: false,
axisChannelList: [],
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
refresh () {
this.channelList.length = 0
// todo RECORDING_CH to RECORDING_CH_H & L
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_LIST = Array(32).fill(0)
const channelSetLow = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RECORDING_CH_L.toString(2).split('').reverse()
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_NUMBER = 0
channelSetLow.forEach((element, index) => {
if (parseInt(element) > 0) {
this.channelList.push(index + 1)
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_LIST[index + 0] = 1
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_NUMBER += 1
}
})
const channelSetHight = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RECORDING_CH_H.toString(2).split('').reverse()
channelSetHight.forEach((element, index) => {
if (parseInt(element) > 0) {
this.channelList.push(index + 17)
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_LIST[index + 16] = 1
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_NUMBER += 1
}
})
this.ampGainOptions.forEach(option => {
if (option.id === taskInfo.getDeviceInfo(this.deviceID).parameterSet.AMP_GAIN) {
this.ampGainSelect = option
}
})
this.sampleRateSelect = this.sampleRateOptions[this.sampleRateOptions.findIndex(ele => ele.value === taskInfo.getDeviceInfo(this.deviceID).parameterSet.SAMPLE_RATE)]
this.recordOn = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RECORDING
this.axisChannelList.length = 0
const axisChannelSet = taskInfo.getDeviceInfo(this.deviceID).parameterSet.AXIS_CH.toString(2).split('').reverse()
axisChannelSet.forEach((element, index) => {
if (parseInt(element) === 1) {
if (index === 0) {
this.axisChannelList.push('x')
} else if (index === 1) {
this.axisChannelList.push('y')
} else if (index === 2) {
this.axisChannelList.push('z')
} else if (index === 3) {
this.axisChannelList.push('m')
}
}
})
this.acceleratorSensitivitySelect = this.acceleratorSensitivityOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.ACCELERATOR_S]
},
channelClickAdd (val) {
if (this.channelList.indexOf(val) < 0 && val <= 16 && val > 0) {
this.channelList.push(val)
let channelSet = ''
for (let i = 16; i >= 1; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_L) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING_CH_L',
content: channelValue,
}))
}
this.recordingChannelReset(this.channelList)
} else if (this.channelList.indexOf(val) < 0 && val <= 32 && val > 16) {
this.channelList.push(val)
let channelSet = ''
for (let i = 32; i >= 17; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_H) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING_CH_H',
content: channelValue,
}))
}
this.recordingChannelReset(this.channelList)
} else {
this.pageToast('Recording channels cannot choose more than 32.')
}
},
channelClickRemove (val) {
if (this.channelList.indexOf(val) >= 0 && val <= 16 && val > 0) {
this.channelList.splice(this.channelList.indexOf(val), 1)
let channelSet = ''
for (let i = 16; i >= 1; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_L) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING_CH_L',
content: channelValue,
}))
}
this.recordingChannelReset(this.channelList)
} else if (this.channelList.indexOf(val) >= 0 && val <= 32 && val > 16) {
this.channelList.splice(this.channelList.indexOf(val), 1)
let channelSet = ''
for (let i = 32; i >= 17; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_H) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING_CH_H',
content: channelValue,
}))
}
this.recordingChannelReset(this.channelList)
}
},
recordingChannelReset (channelList) {
let channelSet = ''
for (let i = 32; i >= 1; i--) {
if (channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING_CH',
content: channelValue,
}))
}
},
ampGainSelectChange () {
if (this.ampGainSelect != null && this.ampGainSelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.AMP_GAIN) % 4)) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'AMP_GAIN',
content: ((this.ampGainSelect.id) % 4),
}))
}
},
sampleRateSelectChange () {
if (this.sampleRateSelect != null && this.sampleRateSelect.value !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.SAMPLE_RATE))) {
const adcClock = 8e6 / this.sampleRateSelect.value
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'SAMPLE_RATE|ADC_CLOCK',
content: `${this.sampleRateSelect.value}|${String(adcClock)}`,
}))
}
},
acceleratorSensitivitySelectChange () {
if (this.acceleratorSensitivitySelect != null && this.acceleratorSensitivitySelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.ACCELERATOR_S))) {
let scaleRange
switch (this.acceleratorSensitivitySelect.id) {
case 0:
scaleRange = 200
break
case 1:
scaleRange = 400
break
case 2:
scaleRange = 800
break
case 3:
scaleRange = 1600
break
default:
scaleRange = 0
break
}
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'ACCELERATOR_S',
content: this.acceleratorSensitivitySelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_update_accelerator_sensitivity/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.acceleratorSensitivitySelect.value,
}))
const charts = chartData.getAllChartsData()
for (const chartID in charts) {
for (const seriesIndex in charts[chartID].series) {
if (charts[chartID].series[seriesIndex].yAxisSource[1] >= 256 && charts[chartID].series[seriesIndex].yAxisSource[1] <= 260) {
if (parseInt(charts[chartID].series[seriesIndex].yAxisSource[1]) === 260) {
charts[chartID].yAxis[seriesIndex].min = 0
charts[chartID].yAxis[seriesIndex].max = Math.ceil(Math.sqrt(Math.pow(scaleRange, 2) * 3))
} else {
charts[chartID].yAxis[seriesIndex].min = -scaleRange
charts[chartID].yAxis[seriesIndex].max = scaleRange
}
}
}
}
}
},
recordClick () {
this.recordOn = !this.recordOn
if (this.recordOn) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'record',
}))
this.$emit('record')
} else {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'stop_record',
}))
this.$emit('record_stop')
}
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING',
content: this.recordOn,
}))
},
axisChannelClickAdd (val) {
if (this.axisChannelList.indexOf(val) < 0) {
const axisChannel = ['m', 'z', 'y', 'x']
this.axisChannelList.push(val)
let axisChannelSet = ''
for (const axis of axisChannel) {
if (this.axisChannelList.indexOf(axis) >= 0) {
axisChannelSet += '1'
} else {
axisChannelSet += '0'
}
}
const axisChannelValue = parseInt(axisChannelSet, 2)
if (axisChannelValue !== taskInfo.getDeviceInfo(this.deviceID).AXIS_CH) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'AXIS_CH',
content: axisChannelValue,
}))
}
}
},
axisChannelClickRemove (val) {
if (this.axisChannelList.indexOf(val) >= 0) {
const axisChannel = ['m', 'z', 'y', 'x']
this.axisChannelList.splice(this.axisChannelList.indexOf(val), 1)
let axisChannelSet = ''
for (const axis of axisChannel) {
if (this.axisChannelList.indexOf(axis) >= 0) {
axisChannelSet += '1'
} else {
axisChannelSet += '0'
}
}
const axisChannelValue = parseInt(axisChannelSet, 2)
if (axisChannelValue !== taskInfo.getDeviceInfo(this.deviceID).AXIS_CH) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'AXIS_CH',
content: axisChannelValue,
}))
}
}
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
mounted () {
this.refresh()
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.circle-button {
height: 25px;
width: 25px;
border-radius: '50%';
}
</style>
@@ -0,0 +1,584 @@
<template>
<div class="flex" >
<va-tree-root >
<va-tree-category
style="font-size: 20px;"
:label="'Channels'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div
style='display: inline-block;'
v-for="channel in channelArray"
:key="channel"
>
<va-button
class="ma-1 pa-0 circle-button"
v-if="channelList != null && channelList.indexOf(channel) >= 0"
@click="channelClickRemove(channel)"
small
>
{{channel}}
</va-button>
<va-button
class="ma-1 pa-0 circle-button"
v-if="channelList == null || channelList.indexOf(channel) < 0"
@click="channelClickAdd(channel)"
small outline
>
{{channel}}
</va-button>
</div>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'3-AXIS'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div
style='display: inline-block;'
v-for="axisChannel in ['x','y','z','m']"
:key="axisChannel"
>
<va-button
class="ma-1 pa-0 circle-button"
v-if="axisChannelList != null && axisChannelList.indexOf(axisChannel) >= 0"
@click="axisChannelClickRemove(axisChannel)"
small
>
{{axisChannel}}
</va-button>
<va-button
class="ma-1 pa-0 circle-button"
v-if="axisChannelList == null || axisChannelList.indexOf(axisChannel) < 0"
@click="axisChannelClickAdd(axisChannel)"
small outline
>
{{axisChannel}}
</va-button>
</div>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Amp gain'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="ampGainSelectChange()"
:label="''"
v-model="ampGainSelect"
textBy="description"
:options="ampGainOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Sample Rate'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="sampleRateSelectChange()"
:label="''"
v-model="sampleRateSelect"
textBy="description"
:options="sampleRateOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Accelerator Sensitivity'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="acceleratorSensitivitySelectChange()"
:label="''"
v-model="acceleratorSensitivitySelect"
textBy="description"
:options="acceleratorSensitivityOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
</va-tree-root>
</div>
</template>
<script>
import { taskInfo } from '../../../../data/task/TaskInfo'
import { chartData } from '../../../../data/task/ChartsManagement'
export default {
name: 'NeuliveParameterRecording',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
deviceName: {
type: String,
default: 'Neulive',
},
},
data () {
return {
channelArray: Array.from({ length: 64 }, (_, i) => i + 1),
channelList: [],
ampGainSelect: null,
ampGainOptions: [
// {
// id: 0,
// description: '25',
// },
{
id: 0,
description: '100',
},
{
id: 2,
description: '300',
},
{
id: 1,
description: '500',
},
],
sampleRateSelect: null,
sampleRateOptions: [
{
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: 30000,
description: '30k',
},
{
id: 8,
value: 40000,
description: '40k',
},
{
id: 9,
value: 50000,
description: '50k',
},
{
id: 10,
value: 60000,
description: '60k',
},
{
id: 11,
value: 70000,
description: '70k',
},
{
id: 12,
value: 80000,
description: '80k',
},
{
id: 13,
value: 90000,
description: '90k',
},
{
id: 14,
value: 100000,
description: '100k',
},
],
acceleratorSensitivitySelect: null,
acceleratorSensitivityOptions: [
{
id: 0,
value: 3,
description: '2G',
},
{
id: 1,
value: 5,
description: '4G',
},
{
id: 2,
value: 8,
description: '8G',
},
{
id: 3,
value: 12,
description: '16G',
},
],
// sampleRateInput: '1000',
// sampleRate: null,
recordOn: false,
axisChannelList: [],
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
refresh () {
this.channelList.length = 0
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_LIST = Array(64).fill(0)
const channelSetLow = taskInfo.getDeviceInfo(this.deviceID).parameterSet.REC_CH_DEV00.toString(2).split('').reverse()
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_NUMBER = 0
channelSetLow.forEach((element, index) => {
if (parseInt(element) > 0) {
this.channelList.push(index + 1)
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_LIST[index + 0] = 1
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_NUMBER += 1
}
})
const channelSetHight = taskInfo.getDeviceInfo(this.deviceID).parameterSet.REC_CH_DEV01.toString(2).split('').reverse()
channelSetHight.forEach((element, index) => {
if (parseInt(element) > 0) {
this.channelList.push(index + 33)
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_LIST[index + 32] = 1
taskInfo.getDeviceInfo(this.deviceID).parameterSet.CH_NUMBER += 1
}
})
this.ampGainOptions.forEach(option => {
if (option.id === taskInfo.getDeviceInfo(this.deviceID).parameterSet.AMP_GAIN) {
this.ampGainSelect = option
}
})
this.sampleRateSelect = this.sampleRateOptions[this.sampleRateOptions.findIndex(ele => ele.value === taskInfo.getDeviceInfo(this.deviceID).parameterSet.SAMPLE_RATE)]
this.recordOn = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RECORDING
this.axisChannelList.length = 0
const axisChannelSet = taskInfo.getDeviceInfo(this.deviceID).parameterSet.AXIS_CH.toString(2).split('').reverse()
axisChannelSet.forEach((element, index) => {
if (parseInt(element) === 1) {
if (index === 0) {
this.axisChannelList.push('x')
} else if (index === 1) {
this.axisChannelList.push('y')
} else if (index === 2) {
this.axisChannelList.push('z')
} else if (index === 3) {
this.axisChannelList.push('m')
}
}
})
this.acceleratorSensitivitySelect = this.acceleratorSensitivityOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.ACCELERATOR_S]
},
channelClickAdd (val) {
if (this.channelList.indexOf(val) < 0 && val <= 32 && val > 0) {
this.channelList.push(val)
let channelSet = ''
for (let i = 32; i >= 1; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_L) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'REC_CH_DEV00',
content: channelValue,
}))
}
} else if (this.channelList.indexOf(val) < 0 && val <= 64 && val > 32) {
this.channelList.push(val)
let channelSet = ''
for (let i = 64; i >= 33; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_H) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'REC_CH_DEV01',
content: channelValue,
}))
}
} else {
this.pageToast('Recording channels cannot choose more than 64.')
}
},
channelClickRemove (val) {
if (this.channelList.indexOf(val) >= 0 && val <= 32 && val > 0) {
this.channelList.splice(this.channelList.indexOf(val), 1)
let channelSet = ''
for (let i = 32; i >= 1; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_L) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'REC_CH_DEV00',
content: channelValue,
}))
}
} else if (this.channelList.indexOf(val) >= 0 && val <= 64 && val > 32) {
this.channelList.splice(this.channelList.indexOf(val), 1)
let channelSet = ''
for (let i = 64; i >= 33; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_H) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'REC_CH_DEV01',
content: channelValue,
}))
}
}
},
ampGainSelectChange () {
if (this.ampGainSelect != null && this.ampGainSelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.AMP_GAIN) % 4)) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'AMP_GAIN',
content: ((this.ampGainSelect.id) % 4),
}))
}
},
sampleRateSelectChange () {
if (this.sampleRateSelect != null && this.sampleRateSelect.value !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.SAMPLE_RATE))) {
const adcClock = 8e6 / this.sampleRateSelect.value
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'SAMPLE_RATE|ADC_CLOCK',
content: `${this.sampleRateSelect.value}|${String(adcClock)}`,
}))
}
},
acceleratorSensitivitySelectChange () {
if (this.acceleratorSensitivitySelect != null && this.acceleratorSensitivitySelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.ACCELERATOR_S))) {
let scaleRange
switch (this.acceleratorSensitivitySelect.id) {
case 0:
scaleRange = 200
break
case 1:
scaleRange = 400
break
case 2:
scaleRange = 800
break
case 3:
scaleRange = 1600
break
default:
scaleRange = 0
break
}
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'ACCELERATOR_S',
content: this.acceleratorSensitivitySelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_update_accelerator_sensitivity/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.acceleratorSensitivitySelect.value,
}))
const charts = chartData.getAllChartsData()
for (const chartID in charts) {
for (const seriesIndex in charts[chartID].series) {
if (charts[chartID].series[seriesIndex].yAxisSource[1] >= 256 && charts[chartID].series[seriesIndex].yAxisSource[1] <= 260) {
if (parseInt(charts[chartID].series[seriesIndex].yAxisSource[1]) === 260) {
charts[chartID].yAxis[seriesIndex].min = 0
charts[chartID].yAxis[seriesIndex].max = Math.ceil(Math.sqrt(Math.pow(scaleRange, 2) * 3))
} else {
charts[chartID].yAxis[seriesIndex].min = -scaleRange
charts[chartID].yAxis[seriesIndex].max = scaleRange
}
}
}
}
}
},
recordClick () {
this.recordOn = !this.recordOn
if (this.recordOn) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'record',
}))
this.$emit('record')
} else {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'stop_record',
}))
this.$emit('record_stop')
}
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING',
content: this.recordOn,
}))
},
axisChannelClickAdd (val) {
if (this.axisChannelList.indexOf(val) < 0) {
const axisChannel = ['m', 'z', 'y', 'x']
this.axisChannelList.push(val)
let axisChannelSet = ''
for (const axis of axisChannel) {
if (this.axisChannelList.indexOf(axis) >= 0) {
axisChannelSet += '1'
} else {
axisChannelSet += '0'
}
}
const axisChannelValue = parseInt(axisChannelSet, 2)
if (axisChannelValue !== taskInfo.getDeviceInfo(this.deviceID).AXIS_CH) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'AXIS_CH',
content: axisChannelValue,
}))
}
}
},
axisChannelClickRemove (val) {
if (this.axisChannelList.indexOf(val) >= 0) {
const axisChannel = ['m', 'z', 'y', 'x']
this.axisChannelList.splice(this.axisChannelList.indexOf(val), 1)
let axisChannelSet = ''
for (const axis of axisChannel) {
if (this.axisChannelList.indexOf(axis) >= 0) {
axisChannelSet += '1'
} else {
axisChannelSet += '0'
}
}
const axisChannelValue = parseInt(axisChannelSet, 2)
if (axisChannelValue !== taskInfo.getDeviceInfo(this.deviceID).AXIS_CH) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'AXIS_CH',
content: axisChannelValue,
}))
}
}
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
mounted () {
this.refresh()
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.circle-button {
height: 25px;
width: 25px;
border-radius: '50%';
}
</style>
@@ -0,0 +1,264 @@
<template>
<div class="flex" >
<va-tree-root >
<va-tree-category
style="font-size: 20px;"
:label="'Radio Frequency'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="radioFrequencySelectChange()"
:label="''"
v-model="radioFrequencySelect"
textBy="description"
:options="radioFrequencyOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Mem Radio Frequency'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="memRadioFrequencySelectChange()"
:label="''"
v-model="memRadioFrequencySelect"
textBy="description"
:options="memRadioFrequencyOptions"
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Led Brightness'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="ledBrightnessSelectChange()"
:label="''"
v-model="ledBrightnessSelect"
textBy="description"
:options="ledBrightnessOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
</va-tree-root>
</div>
</template>
<script>
import { taskInfo } from '../../../../data/task/TaskInfo'
export default {
name: 'NeuliveParameterRecording',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
deviceName: {
type: String,
default: 'Neulive',
},
},
data () {
return {
radioFrequencySelect: null,
radioFrequencyOptions: [
{
id: 0,
value: -20,
description: '-20',
},
{
id: 1,
value: -16,
description: '-16',
},
{
id: 2,
value: -12,
description: '-12',
},
{
id: 3,
value: -8,
description: '-8',
},
{
id: 4,
value: -4,
description: '-4',
},
{
id: 5,
value: 0,
description: '0',
},
{
id: 6,
value: 4,
description: '4',
},
{
id: 7,
value: 8,
description: '8',
},
],
memRadioFrequencySelect: null,
memRadioFrequencyOptions: [
{
id: 0,
value: -20,
description: '-20',
},
{
id: 1,
value: -16,
description: '-16',
},
{
id: 2,
value: -12,
description: '-12',
},
{
id: 3,
value: -8,
description: '-8',
},
{
id: 4,
value: -4,
description: '-4',
},
{
id: 5,
value: 0,
description: '0',
},
{
id: 6,
value: 4,
description: '4',
},
{
id: 7,
value: 8,
description: '8',
},
],
ledBrightnessSelect: null,
ledBrightnessOptions: [
{
id: 0,
value: 0,
description: 'off',
},
{
id: 1,
value: 1,
description: 'bright',
},
{
id: 2,
value: 2,
description: 'normal',
},
],
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
refresh () {
this.radioFrequencySelect = this.radioFrequencyOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.RADIO_FREQUENCY]
this.memRadioFrequencySelect = this.memRadioFrequencyOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.MEM_RADIO_FREQUENCY]
this.ledBrightnessSelect = this.ledBrightnessOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.LED_BRIGHTNESS]
},
radioFrequencySelectChange () {
if (this.radioFrequencySelect != null && this.radioFrequencySelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.RADIO_FREQUENCY))) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RADIO_FREQUENCY',
content: this.radioFrequencySelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_update_radio_frequency/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.radioFrequencySelect.value,
}))
}
},
memRadioFrequencySelectChange () {
if (this.memRadioFrequencySelect != null && this.memRadioFrequencySelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.MEM_RADIO_FREQUENCY))) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'MEM_RADIO_FREQUENCY',
content: this.memRadioFrequencySelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_set_central_rf/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.memRadioFrequencySelect.value,
}))
}
},
ledBrightnessSelectChange () {
if (this.ledBrightnessSelect != null && this.ledBrightnessSelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.LED_BRIGHTNESS))) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'LED_BRIGHTNESS',
content: this.ledBrightnessSelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_update_led_brightness/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.ledBrightnessSelect.value,
}))
}
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
mounted () {
this.refresh()
},
destroyed () {
},
watch: {
},
}
</script>
@@ -167,6 +167,7 @@
v-model="amplitudeNumber"
:min="5"
:max="4000"
:step="5"
/>
</div>
</div>
@@ -205,7 +206,7 @@
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex sm12 xl6 md6 xs12">
<div class="flex row align--center">
<va-input
v-model="frequencyNumberInput"
@@ -219,10 +220,7 @@
</va-input>
</div>
</div>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex sm12 xl6 md6 xs12">
<div class="flex row align--center">
<va-input
v-model="periodNumberInput"
@@ -295,7 +293,7 @@
0.1
</va-button> -->
<va-input
@keyup.enter="timeRangeChange(3, t3RangeInput)"
readonly
v-model="t3RangeInput"
class="mb-0"
:label="'T3 RANGE'"
@@ -320,7 +318,6 @@
0
</va-button> -->
<va-input
@keyup.enter="timeRangeChange(4, t4RangeInput)"
readonly
v-model="t4RangeInput"
class="mb-0"
@@ -361,9 +358,6 @@
<script>
import { taskInfo } from '../../../../data/task/TaskInfo'
import { mapActions, mapMutations } from 'vuex'
import { mapFields } from 'vuex-map-fields'
import types from '@/store/modules/task/content/types'
export default {
name: 'NeuliveParameterStimulation',
@@ -383,6 +377,9 @@ export default {
return {
showGuideLineModal: { ELECTRODE: false, PATTERN: false },
stimulationOn: false,
posChannelList: [2],
negChannelList: [1],
stimulateElectrodeSelect: null,
stimulateElectrodeOptions: [
{
label: 'Monopolar',
@@ -393,14 +390,15 @@ export default {
value: 1,
},
],
TRangeErrorMsgList: [{ id: 1, showError: false, errorMsg: [''] }, { id: 2, showError: false, errorMsg: [''] }, { id: 3, showError: false, errorMsg: [''] }, { id: 4, showError: false, errorMsg: [''] }],
cycleNumberSelect: null,
cycleNumberOptions: [
{
label: 'limite',
label: 'limited',
value: 0,
},
{
label: 'Unlimite',
label: 'Unlimited',
value: 1,
},
],
@@ -456,12 +454,6 @@ export default {
}
},
computed: {
...mapFields('taskContent', [
'posChannelList',
'negChannelList',
'stimulateElectrodeSelect',
'TRangeErrorMsgList',
]),
stimulateDisable () {
// posChannel and negChannel at least one && t1 ~ t4 > 0
const totalStiTime = (this.t1Range + this.t2Range + this.t3Range + this.t4Range) * 10
@@ -471,6 +463,20 @@ export default {
return true
}
},
TRangeStatusCheck () {
let flag = true
for (let i = 0; i < this.TRangeErrorMsgList.length; i++) {
if (this.TRangeErrorMsgList[i].showError === true) {
flag = false
break
}
}
if (flag === true) {
return true
} else {
return false
}
},
},
mqtt: {
},
@@ -487,24 +493,22 @@ export default {
},
refreshPattern () {
this.patternModeSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_PATTERN ? 1 : 0
this.t1Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T1[0]
this.t1RangeInput = String((this.t1Range * 10) / this.unitMultiply)
this.t1RangeArray.fill(this.t1Range, 0)
this.t2Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T2[0]
this.t2RangeInput = String((this.t2Range * 10) / this.unitMultiply)
this.t2RangeArray.fill(this.t2Range, 0)
this.t3Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T3[0]
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
this.t3RangeArray.fill(this.t3Range, 0)
this.t4Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T4[0]
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
this.t4RangeArray.fill(this.t4Range, 0)
if (this.patternModeSelect === 0) {
this.periodNumber = (this.t1Range + this.t4Range) * 10
} else {
this.periodNumber = (this.t1Range + this.t2Range + this.t3Range + this.t4Range) * 10
if (this.TRangeStatusCheck === true) { // if t1~t4 is not valid input, not need to refresh
this.t1Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T1[0]
this.t1RangeInput = String((this.t1Range * 10) / this.unitMultiply)
this.t1RangeArray.fill(this.t1Range, 0)
this.t2Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T2[0]
this.t2RangeInput = String((this.t2Range * 10) / this.unitMultiply)
this.t2RangeArray.fill(this.t2Range, 0)
this.t3Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T3[0]
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
this.t3RangeArray.fill(this.t3Range, 0)
this.t4Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T4[0]
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
this.t4RangeArray.fill(this.t4Range, 0)
}
this.periodNumber = (this.t1Range + this.t2Range + this.t3Range + this.t4Range) * 10
this.periodNumberInput = String((this.periodNumber) / this.unitMultiply)
if (this.periodNumber !== 0) {
@@ -531,11 +535,6 @@ export default {
}
}
})
// }
// console.log('cha',stiChannelSet)
// console.log('pol',stiPolaritySet)
// console.log('pos',this.posChannelList)
// console.log('neg',this.negChannelList)
this.stimulateElectrodeSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_H_BRIDGE ? 1 : 0
this.cycleNumberSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.CONTINUOUS_STI ? 1 : 0
this.cycleNumber = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_CYCLE_LIST[0]
@@ -545,17 +544,6 @@ export default {
this.amplitudeNumberInput = String(this.amplitudeNumber)
this.refreshPattern()
// console.log('STI_CONTINUOUS', this.cycleNumberSelect)
// console.log('STI_H_BRIDGE', this.stimulateElectrodeSelect)
// console.log('STI_PATTERN', this.patternModeSelect)
// console.log('STI_T1', taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T1[0])
// console.log('STI_T2', taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T2[0])
// console.log('STI_T3', taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T3[0])
// console.log('STI_T4', taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T4[0])
// console.log(this.periodNumber)
// console.log(this.periodNumberInput)
// console.log(this.frequencyNumber)
// console.log(this.frequencyNumberInput)
},
transUnit () {
if (this.unitSelect === 0) { // s
@@ -649,24 +637,21 @@ export default {
if (this.amplitudeNumber == null) {
return false
}
if (typeof (val) === 'string') {
if (isNaN(val) || parseInt(val) > 4000 || parseInt(val) < 5) {
this.amplitudeNumberInput = '50'
this.amplitudeNumber = 50
}
if (parseInt(this.amplitudeNumberInput) !== parseInt(this.amplitudeNumber)) {
this.amplitudeNumber = parseInt(val)
}
val = parseInt(val)
const remainder = val % 5
if (remainder >= 3) {
val += (5 - remainder)
} else {
if (isNaN(val) || parseInt(val) > 4000 || parseInt(val) < 5) {
this.amplitudeNumberInput = '50'
this.samplitudeNumber = 50
}
if (parseInt(this.amplitudeNumberInput) !== parseInt(this.amplitudeNumber) || this.amplitudeNumber !== val) {
this.amplitudeNumberInput = String(val)
this.amplitudeNumber = val
}
val -= remainder
}
if (isNaN(val) || val > 4000 || val < 5) {
val = 50
}
this.amplitudeNumberInput = String(val)
this.amplitudeNumber = val
if (parseInt(this.amplitudeNumber / 5) !== parseInt(taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_AMPLITUDE)) {
const content = parseInt(this.amplitudeNumber / 5)
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
@@ -677,6 +662,8 @@ export default {
}))
}
},
// [Region] Neulive sti pattern block
patternModeSelectChange () {
if (this.patternModeSelect == null) {
return false
@@ -689,11 +676,26 @@ export default {
content: this.patternModeSelect,
}))
if (this.patternModeSelect === 0) {
this.t2Range = 0
this.t3Range = 0
} else if (this.patternModeSelect === 1) {
this.t2Range = 0
this.t3Range = this.t1Range
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
}
this.autoComputeT4()
const check1 = this.checkIndividualTRange(1, this.t1Range)
const check2 = this.checkIndividualTRange(2, this.t2Range)
const check3 = this.checkIndividualTRange(3, this.t3Range)
const check4 = this.checkIndividualTRange(4, this.t4Range)
if (check4) {
// if pass, call this.updateTimeRange(), if any fail, call updateErrorMsg in this.checkIndividualTRange()
if (check1 === true && check2 === true && check3 === true && check4 === true) {
this.updateTimeRange()
}
this.updateStiTRangeCheckParam()
},
frequencyNumberChange (val) {
if (this.frequencyNumberInput == null || isNaN(val)) {
@@ -716,16 +718,18 @@ export default {
this.periodNumber = (1e6 / this.frequencyNumber).toFixed(3) // us
this.periodNumberInput = String(this.periodNumber / this.unitMultiply)
this.autoResetAllTRange()
this.autoComputeT4()
const check1 = this.checkIndividualTRange(1, this.t1Range)
const check2 = this.checkIndividualTRange(2, this.t2Range)
const check3 = this.checkIndividualTRange(3, this.t3Range)
const check4 = this.checkIndividualTRange(4, this.t4Range)
// if pass, call this.updateTimeRange(), if any fail, call updateErrorMsg in this.checkIndividualTRange()
if (check1 && check2 && check3 && check4) {
if (check1 === true && check2 === true && check3 === true && check4 === true) {
this.updateTimeRange()
}
this.updateStiTRangeCheckParam()
},
periodNumberChange (val) {
const usVal = parseFloat(val * this.unitMultiply) // us
@@ -749,16 +753,64 @@ export default {
this.frequencyNumber = parseInt(1e6 / this.periodNumber)
this.frequencyNumberInput = String(this.frequencyNumber)
this.autoResetAllTRange()
this.autoComputeT4()
const check1 = this.checkIndividualTRange(1, this.t1Range)
const check2 = this.checkIndividualTRange(2, this.t2Range)
const check3 = this.checkIndividualTRange(3, this.t3Range)
const check4 = this.checkIndividualTRange(4, this.t4Range)
// if pass, call this.updateTimeRange(), if any fail, call updateErrorMsg in this.checkIndividualTRange()
if (check1 && check2 && check3 && check4) {
if (check1 === true && check2 === true && check3 === true && check4 === true) {
this.updateTimeRange()
}
this.updateStiTRangeCheckParam()
},
timeRangeChange (stiIimeSelect, inputVal) {
let tRangeInput = parseFloat(inputVal * this.unitMultiply)
const remainder = tRangeInput % 10
if (remainder >= 5) {
tRangeInput += (10 - remainder)
} else {
tRangeInput -= remainder
}
switch (stiIimeSelect) {
case 1:
this.t1RangeInput = String(tRangeInput / this.unitMultiply)
this.t1Range = parseFloat(tRangeInput / 10)
if (this.patternModeSelect === 1) { // biphasic
this.t3RangeInput = this.t1RangeInput
this.t3Range = this.t1Range
}
this.autoComputeT4()
break
case 2:
this.t2RangeInput = String(tRangeInput / this.unitMultiply)
this.t2Range = parseFloat(tRangeInput / 10)
this.autoComputeT4()
break
// T3 / T4 will be set automatically
}
const status1 = this.checkIndividualTRange(1, this.t1Range)
const status2 = this.checkIndividualTRange(2, this.t2Range)
const status3 = this.checkIndividualTRange(3, this.t3Range)
const status4 = this.checkIndividualTRange(4, this.t4Range)
if (status1 && status2 && status3 && status4) {
this.resetAllTRangeErrorMsg({ totalT: 4 })
this.updateTimeRange()
}
this.updateStiTRangeCheckParam()
},
updateStiTRangeCheckParam () {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'sti_trange_set_done',
content: this.TRangeStatusCheck,
}))
},
autoResetAllTRange () {
if (this.patternModeSelect === 0) { // Monophasic
@@ -771,121 +823,99 @@ export default {
this.t1RangeInput = String((this.t1Range * 10) / this.unitMultiply)
this.t2Range = 10
this.t2RangeInput = String((this.t2Range * 10) / this.unitMultiply)
this.t3Range = 10
this.t3Range = this.t1Range
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
this.t4Range = this.periodNumber / 10 - this.t1Range - this.t2Range - this.t3Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
}
},
timeRangeChange (stiIimeSelect, inputVal) {
inputVal = parseFloat(inputVal)
switch (stiIimeSelect) {
case 1:
this.t1RangeInput = inputVal
this.t1Range = parseFloat((inputVal * this.unitMultiply) / 10)
this.autoComputeT4()
break
case 2:
this.t2RangeInput = inputVal
this.t2Range = parseFloat((inputVal * this.unitMultiply) / 10)
this.autoComputeT4()
break
case 3:
this.t3RangeInput = inputVal
this.t3Range = parseFloat((inputVal * this.unitMultiply) / 10)
this.autoComputeT4()
break
case 4:
this.t4RangeInput = inputVal
this.t4Range = parseFloat((inputVal * this.unitMultiply) / 10)
break
}
const overallStatus = this.checkOverallTRange()
const status1 = this.checkIndividualTRange(1, this.t1Range)
const status2 = this.checkIndividualTRange(2, this.t2Range)
const status3 = this.checkIndividualTRange(3, this.t3Range)
const status4 = this.checkIndividualTRange(4, this.t4Range)
if (overallStatus && status1 && status2 && status3 && status4) {
this.resetAllTRangeErrorMsgParam({ totalT: 4 })
this.updateTimeRange()
}
},
autoComputeT4 () {
if (this.patternModeSelect === 0) {
this.t4Range = (this.periodNumber / 10) - this.t1Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
this.pageToast('Auto complete T4 value')
} else if (this.patternModeSelect === 1) {
this.t4Range = (this.periodNumber / 10) - this.t1Range - this.t2Range - this.t3Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
this.pageToast('Auto complete T4 value')
this.t4Range = (this.periodNumber / 10) - this.t1Range - this.t2Range - this.t3Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
if (this.t4Range >= 0) {
this.pageToast(`T4 = ${(this.t4Range / 100).toFixed(1)} ms`)
} else {
this.pageToast('T4 can not be negative. Please check T1~T3 setting.')
}
},
checkOverallTRange () {
let status = true
if (this.t1Range > this.periodNumber) {
this.updateTRangeErrorMsgParam({ stiIimeSelect: 1, status: true, msg: 'T1 > Period' })
status = false
// [SubRegion] check sti T range setting helper function
// update individual t range error msg
updateTRangeErrorMsg (payload) {
const index = payload.stiIimeSelect - 1
this.TRangeErrorMsgList[index].showError = payload.status
this.TRangeErrorMsgList[index].errorMsg[0] = payload.msg
},
resetAllTRangeErrorMsg (payload) {
for (let i = 1; i <= payload.totalT; i++) {
this.updateTRangeErrorMsg({ stiIimeSelect: i, status: false, msg: '' })
}
if (this.t2Range > this.periodNumber) {
this.updateTRangeErrorMsgParam({ stiIimeSelect: 2, status: true, msg: 'T2 > Period' })
status = false
}
if (this.t3Range > this.periodNumber) {
this.updateTRangeErrorMsgParam({ stiIimeSelect: 3, status: true, msg: 'T3 > Period' })
status = false
}
if (this.t4Range > this.periodNumber) {
this.updateTRangeErrorMsgParam({ stiIimeSelect: 4, status: true, msg: 'T4 > Period' })
status = false
}
return status
},
checkIndividualTRange (stiIimeSelect, val) {
// val unit: us
val = parseFloat(val) * 10 // UI us
if (val < 0 || isNaN(val)) {
this.updateTRangeErrorMsgParam({ stiIimeSelect: stiIimeSelect, status: true, msg: 'T > 0' })
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: `T${stiIimeSelect} can not be negative. Please check your setting.` })
return false
}
switch (stiIimeSelect) {
case 1:
if (val < 100 || val > 10230) { // us
this.updateTRangeErrorMsgParam({ stiIimeSelect: stiIimeSelect, status: true, msg: '0.1ms <= T1 <= 10.23ms' })
if (val < 10 || val > 10230) { // us
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: '0.01ms <= T1 <= 10.23ms' })
return false
} else if (val > this.periodNumber) {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: 'T1 > PERIOD' })
return false
} else {
this.updateTRangeErrorMsgParam({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
return true
}
case 2:
if (val < 0 || val > 10230) { // us
this.updateTRangeErrorMsgParam({ stiIimeSelect: stiIimeSelect, status: true, msg: '0ms <= T2 <= 10.23ms' })
return false
} else {
this.updateTRangeErrorMsgParam({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
if (this.patternModeSelect === 1) { // biphasic
if (val < 0 || val > 10230) { // us
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: '0ms <= T2 <= 10.23ms' })
return false
} else if (val > this.periodNumber) {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: 'T2 > PERIOD' })
return false
} else {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
return true
}
} else { // monophasic not need t2
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
return true
}
case 3:
if (val < 100 || val > 10230) { // us
this.updateTRangeErrorMsgParam({ stiIimeSelect: stiIimeSelect, status: true, msg: '0.1ms <= T3 <= 10.23ms' })
return false
} else {
this.updateTRangeErrorMsgParam({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
if (this.patternModeSelect === 1) { // biphasic
if (val < 10 || val > 10230) { // us
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: '0.01ms <= T3 <= 10.23ms' })
return false
} else if (val > this.periodNumber) {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: 'T3 > PERIOD' })
return false
} else {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
return true
}
} else { // monophasic not need t3
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
return true
}
case 4:
if (val < 0 || val > 1310710) { // us
this.updateTRangeErrorMsgParam({ stiIimeSelect: stiIimeSelect, status: true, msg: '0ms <= T4 <= 1310.71ms' })
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: '0ms <= T4 <= 1310.71ms' })
return false
} else {
this.updateTRangeErrorMsgParam({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
return true
}
}
},
// [EndSubRegion]
// [EndRegion]
updateStiChannel () {
// stiChannelSet (+,-), stiPolaritySet (+)
let stiChannelSet = ''
@@ -960,12 +990,6 @@ export default {
},
)
},
...mapActions('taskContent', [types.param.resetAllTRangeErrorMsg]),
...mapMutations('taskContent', [types.param.initTRangeErrorMsgList, types.param.updateTRangeErrorMsg]),
},
created () {
this.initTRangeErrorMsgListParam({ totalT: 4 })
},
mounted () {
this.refresh()
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More