Compare commits

...

224 Commits

Author SHA1 Message Date
peterlu14 27c1dc6044 Refactor device library check in TaskDeviceListNew.vue 2024-10-01 15:07:03 +08:00
peterlu14 49458ab441 Refactor device library check in TaskDeviceListNew.vue 2024-10-01 11:51:51 +08:00
peterlu14 07ba97c1b0 - Fixed CPG DevMode 2024-09-20 09:48:25 +08:00
peterlu14 1f377b7a0a - Fix text color 2024-09-12 11:35:51 +08:00
peterlu14 9a80d7eceb - Change the timer continuous mode logic 2024-09-12 11:25:53 +08:00
peterlu14 74d64c1234 - Add Info Image
- Fix timer spelling error
2024-09-12 10:55:22 +08:00
peterlu14 0eb35f35ec - Change Pattern mode UI space-evenly 2024-09-12 10:15:44 +08:00
peterlu14 7073734c0d - Fix support font Inter
- Description Eletrical Stimulation add space
- Timer modal add time unit replace placeholder
- Add cursor: pointer & change font-size
- Device name change
2024-09-11 16:45:52 +08:00
peterlu14 23d68aa880 -Add assets 2024-09-11 10:30:10 +08:00
peterlu14 6098d9b84c - Add Electrical Stimulation UI 2024-09-11 10:29:47 +08:00
peterlu14 a170b9ae1d - Complete CPG parameter table 2024-09-11 10:06:29 +08:00
peterlu14 ec23eff0b5 - Add mqtt broadcast "device_refresh"
- Remove the battery for CPG
- Remove the folder and fileName for CPG
- Remove collapse__body padding-x
2024-09-11 10:04:14 +08:00
peterlu14 6a9ad8d554 - Restrict textArea maxlength in 244 bytes 2024-08-21 17:43:12 +08:00
peterlu14 674a88460d -Developer Mode add textarea and support to 255 bytes 2024-08-21 14:59:22 +08:00
peterlu14 8dd8cb52e6 -Allow the CPG start button 2024-08-21 14:58:34 +08:00
peterlu14 a206479d08 - Add CPG Device with Dev Mode 2024-07-31 15:03:55 +08:00
peterlu14 a0315a4e56 - Add PEL Mode 2024-07-30 10:46:40 +08:00
Roy_01 644887a151 modify: libraryNameMappingTable add edc2.0 2024-05-09 09:51:27 +08:00
peterlu14 d7ad076dbe config add elite 2.0 2024-03-08 09:36:25 +08:00
peterlu14 4c24b08d92 -unshow battery when device working 2023-11-21 15:56:29 +08:00
peterlu14 753248826d -update add BAT 2023-10-02 14:43:08 +08:00
peterlu14 57c9972855 - change download default to excel 2023-07-11 15:30:43 +08:00
peterlu14 ba7145be76 - cycle cannot 0 2023-07-05 17:42:04 +08:00
peterlu14 f0fe12bc84 - 需要下拉選單的指示
- enable/disanable 綠色調整
- 開關往下移讓他跟 s 置中對齊
- 5V output 的 on
- 前端/ UI 輸入要做限制,s 輸入最小精度 0.1 s,current 電流輸入最小精度 0.1 mA
- 名稱文字調整
- Fix current range
2023-06-21 16:58:56 +08:00
peterlu14 096ecb4a7e -update folder click 2023-06-14 16:10:40 +08:00
peterlu14 5614bf69ed -fix backend data type error 2023-06-13 13:42:49 +08:00
peterlu14 d60438e952 - update trigger 2023-06-13 09:49:16 +08:00
peterlu14 55dde2a4e4 -remake trigger 2023-06-13 09:31:07 +08:00
peterlu14 0b1afd6f29 -add trigger dev mode 2023-05-15 11:37:40 +08:00
Roy 74f755a966 [update] fix channel unit 2023-04-14 09:03:49 +08:00
peterlu14 1072b37139 - fix folder bug 2023-04-13 16:34:08 +08:00
peterlu14 030e63b8c6 - fix real time channel info 2023-04-13 16:26:48 +08:00
peterlu14 1aa6cc6d31 - config table add physicalQuantity 2023-04-13 16:24:34 +08:00
peterlu14 30db3a9232 - fix folder conflict problem 2023-04-13 11:47:38 +08:00
peterlu14 0d2b97b87e - remove duplicate messages
- prevent multi-user refresh cause chart clear problem
- chart series add lttb
2023-04-13 10:56:24 +08:00
peterlu14 b4169367aa - download display rebuild
- support download
- support offline-download
2023-04-12 18:44:32 +08:00
peterlu14 820d59cb2f Merge remote-tracking branch 'origin/dev/8hstia' into dev/scheduler-datatable-8hstia 2023-04-12 14:57:15 +08:00
peterlu14 c58ec8c907 - fixed download 2023-04-12 14:55:39 +08:00
peterlu14 dcf9d1b98c - fix edit file way
- remove popover message
- remove sd card button
2023-04-11 18:07:00 +08:00
peterlu14 fd4ff2d99d - click outside table unselect all
- fix the select word conflict with shift
- fix delect files page wrong
2023-04-11 17:47:15 +08:00
peterlu14 8bf7a893ae -real time chart unit more flexible
-add source into gridsource
2023-04-11 17:45:35 +08:00
Roy ce4cf4078b [update] up to 8 hstia 2023-04-11 13:12:32 +08:00
peterlu14 cbd45415bd - download selected files 2023-04-10 14:28:26 +08:00
peterlu14 140a564ee7 - create modal for moving folder
- remove check illegal char
- change UI layout
- add hot key to select file ctrl & shift
- fix edit folder name
- fix delete folder inner all files
- fix refs datatable_ref undefined problem
- when selected file the text in table cannot be select
2023-04-07 16:51:46 +08:00
peterlu14 8d24a93f6d -fix checkbox 2023-03-31 11:18:23 +08:00
peterlu14 98135d6ce2 - update file with sorted
- change single click & double click
- fix delete folder
2023-03-31 11:07:22 +08:00
peterlu14 a3ccb942e5 - fix create task 2023-03-25 13:18:41 +08:00
peterlu14 eacc0d9547 - project sort with created time
- new project created time reassign
- copy project created time reassign
- save project (create task, copy task, delete task)
2023-03-25 13:07:46 +08:00
peterlu14 9cc653b761 -auto save ( cycle, device) 2023-03-24 19:22:38 +08:00
peterlu14 0cfc02c939 - reset projecttableselectIndex
- prevent select task null
- fixed parameter is undefined
- fix scheduler change mode reset problem
- auto save
2023-03-24 19:07:42 +08:00
ROY 60252b5cfe [update] update AC_AMP defaultValue of schedule 2023-03-21 16:21:51 +08:00
peterlu14 cc5207ae07 - fix legend name duplicate problem 2023-03-16 17:56:32 +08:00
peterlu14 4ad2b51161 - Elite EDC VOLT_VSCAN to CA_VOLT 2023-03-08 09:37:12 +08:00
ROY 0f32263d12 [update] update bat0.1 and new bat1.0 2023-03-07 18:03:59 +08:00
peterlu14 52db5b818c [update] remove navbar info 2023-02-04 10:56:28 +08:00
peterlu14 507718e3a3 [update] remove trigger battery 2023-01-12 10:04:15 +08:00
peterlu14 1c02ffb934 [update] fix scheduler trigger parameter show & layout 2023-01-10 11:30:00 +08:00
peterlu14 5d594eff06 [update] fix trigger scheduler & todo fix mode select and parameter info 2023-01-09 18:21:50 +08:00
peterlu14 29f7d23d38 [debug] fix delete file working mode error 2023-01-04 15:21:40 +08:00
peterlu14 4d032858a3 [update] trigger add timer 2023-01-03 15:30:03 +08:00
peterlu14 417c4010a9 [update] fix advanced setting 2023-01-03 14:58:48 +08:00
peterlu14 6bf7edad0b [update] recover trigger ui 2023-01-03 14:42:54 +08:00
peterlu14 fafc6620d2 [debug] fix CC Mode csv header wrong information 2022-12-27 11:04:40 +08:00
peterlu14 78d236d9c0 [update] fix scheduler parameter default problem 2022-12-27 11:03:52 +08:00
ROY 6e42dc9333 [update] add debug channel in file 2022-12-07 14:23:19 +08:00
peterlu14 d4d6172645 Merge branch 'dev/scheduler_UI' into dev/test_ac_amp 2022-12-06 16:07:17 +08:00
peterlu14 8685768f42 [update] fix impendance scale & millidegree 2022-12-06 15:58:06 +08:00
peterlu14 8ca0e3fa28 Merge branch 'dev/scheduler_UI' into dev/test_ac_amp 2022-12-06 14:22:32 +08:00
peterlu14 7e61eb6e52 [update] fix phase degree scale error 2022-12-06 14:22:12 +08:00
peterlu14 d16d7b0cb5 Merge branch 'dev/scheduler_UI' into dev/test_ac_amp 2022-12-05 11:57:19 +08:00
peterlu14 c960a8228c [update] fix phase degree scale error 2022-12-05 11:56:39 +08:00
ROY d4423503d6 Merge remote-tracking branch 'origin/dev/scheduler_UI' into dev/test_ac_amp 2022-12-02 17:45:35 +08:00
peterlu14 6c8583e139 [update] fix CF mode name & name PEIS into EIS 2022-12-02 17:40:54 +08:00
peterlu14 f3817694cf [update] scheduler count start from 0 2022-12-02 17:30:13 +08:00
peterlu14 73eced5f52 [update] EIS_AVERAGE_NUM default 3 -> 0 2022-12-02 17:29:54 +08:00
peterlu14 5453928bc1 [update] remove project table cell for cycle 2022-12-02 17:29:29 +08:00
peterlu14 814cfa8b86 [update] fix delete project step 2022-12-02 17:28:56 +08:00
ROY c3f6349c6e [test] print notify_one & notify_two & notify_three 2022-12-01 14:15:12 +08:00
peterlu14 0dc8cc4344 [update] support cancel delete project click anywhere 2022-11-28 10:09:41 +08:00
peterlu14 9358ad7ffa [update] input auto focus & double check delete 2022-11-25 13:27:58 +08:00
peterlu14 95203486e2 [update] add showProjectManagerPanel button 2022-11-25 13:26:07 +08:00
peterlu14 164a658870 [update] fix project copy parameter show error 2022-11-24 18:01:01 +08:00
peterlu14 d4c71fd4f9 [update] update package v-tooltips 2022-11-24 11:21:42 +08:00
peterlu14 4b60975782 [update] show available parameters 2022-11-24 11:19:55 +08:00
peterlu14 d1b8683387 [update] add v-popover to parameter 2022-11-24 11:18:56 +08:00
peterlu14 fd4a677173 [update] fix draggable problem by combine device table row together 2022-11-24 10:13:09 +08:00
peterlu14 6f4d96fb17 [update] project manager filter & table header 2022-11-21 17:44:33 +08:00
peterlu14 3ad822bde1 [update] open cf mode 2022-11-21 16:48:29 +08:00
peterlu14 2b2dd50f41 [update] modify project menu device and table font & fix draggable bug 2022-11-21 16:45:44 +08:00
peterlu14 ca57978763 [update] device not pair coor change & draggable cannot drag while input & table header & cell font-size change 2022-11-21 15:40:35 +08:00
peterlu14 6c41341392 [update] fix getConfigTable & getDevice null error 2022-11-21 11:50:30 +08:00
peterlu14 4a5f07da18 [update] fix project parameter refs init problem 2022-11-21 11:49:12 +08:00
peterlu14 17492ccc98 [update] Vue use v-tooltip 2022-11-18 16:57:11 +08:00
peterlu14 e5603cd80e [update] minor modify to project typography 2022-11-18 15:49:07 +08:00
peterlu14 99898dc862 [update] thead sticky top 2022-11-18 15:44:45 +08:00
peterlu14 66bdf13955 [update] display menu in flexbox layout 2022-11-18 14:22:05 +08:00
peterlu14 89ffad6fbe [update] fix img src, project manager ui change 2022-11-18 13:25:59 +08:00
peterlu14 079ba2023d [update] img resource 2022-11-18 13:21:57 +08:00
peterlu14 9158697bdc [update] device text change place 2022-11-17 16:05:35 +08:00
peterlu14 0b20104133 [update] hover show parameter & add task bottom & table font alter 2022-11-17 16:05:16 +08:00
peterlu14 90f6090edb Merge branch 'release/v1.3.9/scheduler_device' into dev/scheduler_cf 2022-11-16 17:34:41 +08:00
peterlu14 c51c723e5f [update] chart table add new pair T_Impedance, T_Phase, T_Current 2022-11-16 15:41:32 +08:00
peterlu14 e38df250e2 [update] fix cf_mode channel set index error 2022-11-16 15:40:36 +08:00
peterlu14 06d52cabea Merge remote-tracking branch 'origin/dev/cf_mode' into dev/scheduler_cf 2022-11-16 13:47:21 +08:00
ROY 11305159a9 [update] new cf mode, but hide 2022-11-16 11:54:17 +08:00
peterlu14 aef2a48b78 [update] menu font & device font fix 2022-11-16 10:54:00 +08:00
peterlu14 036f4b664e [update] project cycle height 50 px & fix task add show 2022-11-15 17:27:12 +08:00
peterlu14 45653ba7cb [update] fix draggable 2022-11-15 16:59:01 +08:00
ROY 504f4dc32c [update] clean up eis parameter 2022-11-15 16:08:31 +08:00
ROY 28f17e7280 [update] remove ADC_LEVEL_V_IN_15 parameter 2022-11-15 16:08:26 +08:00
ROY 18ba482f3d [update] update VT_MEASURE_VIN_RANGE parameter 2022-11-15 16:03:32 +08:00
ROY e82660bcbe [update] update CA_VOLT parameter 2022-11-15 16:01:07 +08:00
ROY 2441996848 [update] update CV_SCAN_RATE parameter 2022-11-15 15:51:28 +08:00
ROY cabb38be6f [update] update CV_E2 parameter 2022-11-15 15:47:59 +08:00
ROY 8b8094ce3e [update] update CV_E1 parameter 2022-11-15 15:44:33 +08:00
ROY 88ca4b4c62 [update] update CV_E_INITIAL parameter 2022-11-15 15:42:40 +08:00
peterlu14 b45f731f1d [update] project only one device & auto add start 2022-11-15 14:32:23 +08:00
peterlu14 7946ada265 [update] default parameter bug fix 2022-11-15 13:14:34 +08:00
peterlu14 90c722a7c3 [update] project ui & cursor pointer 2022-11-15 13:14:02 +08:00
peterlu14 d6712139f3 [update] add working mode Idle 2022-11-15 11:53:48 +08:00
peterlu14 1d20f9c207 [update] action&condition into start stop & create start in select device & project table ui optimize & add taskAct method 2022-11-15 11:50:23 +08:00
peterlu14 3e3fe59bd2 [update] add start & stop icon and recover menu function 2022-11-15 11:42:57 +08:00
ROY d9ef45a5a2 [update] new lprtia function 2022-11-10 14:11:37 +08:00
peterlu14 9495a17d2d [update] remove folder 2022-11-10 11:43:07 +08:00
peterlu14 120a7d45b1 [update] remove EIS device battery 2022-11-10 11:42:44 +08:00
peterlu14 d8bc49a100 [update] project menu UI update 2022-11-09 13:49:39 +08:00
ROY c4417a6458 [update] update GENERAL_HS_RTIA parameter 2022-11-08 16:13:46 +08:00
ROY 91c02007bc [update] update EIS_AVERAGE_NUM parameter 2022-11-08 15:58:32 +08:00
ROY 023de635fa [update] update EIS_DELAY parameter 2022-11-08 15:45:13 +08:00
ROY 4b410bfb3a [update] update EIS_SCALE parameter 2022-11-08 15:36:40 +08:00
ROY 2c205af6dd [update] update EIS_PPD parameter 2022-11-08 14:49:40 +08:00
ROY e517e9f796 [update] update EIS_AC_AMP parameter 2022-11-08 14:24:41 +08:00
ROY a5a590c007 [update] update EIS_DC_BIAS parameter 2022-11-08 14:18:05 +08:00
ROY 3dae7e644a [update] update EIS_FREQ parameter 2022-11-08 12:07:35 +08:00
ROY 768168c614 [update] delete FREQ_START & FREQ_STOP parameter 2022-11-08 11:05:56 +08:00
ROY 0a4635d648 [update] delete CHANNEL_LABEL parameter 2022-11-08 10:39:16 +08:00
ROY 3eb0e66b01 [update] update RT mode 2022-10-27 17:42:47 +08:00
peterlu14 a44f865d2d [update] disable RT Mode 2022-10-26 13:45:55 +08:00
peterlu14 46cf78cd55 [update] hide scheduler 2022-10-26 10:08:36 +08:00
ROY 200a8d25fa [update] EIS RT Mode 2022-10-25 13:32:37 +08:00
peterlu14 b5908f8815 [update] EIS RT Mode 2022-10-25 10:16:37 +08:00
peterlu14 abf5b0e54b [update] projectTable UI 2022-10-18 11:51:10 +08:00
peterlu14 9637a5365e [update] remove some condition & add device SelectKey in condition & project table UI 2022-10-18 11:42:20 +08:00
peterlu14 2c1e247178 [update&debug] fix rearrange problem & add copy function & auto pair device in task 2022-10-18 11:38:19 +08:00
peterlu14 dbbf30623d [update] task device setting big update & auto register connect device 2022-10-14 17:43:11 +08:00
peterlu14 eeb43694b1 [update] add order property in device 2022-10-14 16:03:42 +08:00
peterlu14 4054a113d0 [update] remove device hide modal 2022-10-14 16:01:15 +08:00
peterlu14 6bcf4b100f [update] remove add device button 2022-10-14 11:10:26 +08:00
peterlu14 a2237aeb0a [update] add detect function 2022-10-14 10:27:55 +08:00
peterlu14 2972fa365c [update] remove old auto get device 2022-10-14 10:14:12 +08:00
peterlu14 75d71099ed [update] device need to pair to run scheduler 2022-10-14 10:13:28 +08:00
peterlu14 2ab96c3bf6 [update] scheduler device big update from array to object & auto pairing 2022-10-14 10:11:17 +08:00
peterlu14 a088b940e6 [update] fix EIS DELAY range & add library EDC EIS 2022-10-14 10:06:13 +08:00
peterlu14 59ce90d348 [update] temp fix many project message error 2022-10-11 10:48:40 +08:00
peterlu14 01f1cf28d5 [update] temp fix project table element key duplicate error 2022-10-11 10:48:08 +08:00
peterlu14 b826442672 [update] fix project copy 2022-10-11 10:47:27 +08:00
ROY 0c385ee212 [update] remove LEVEL_V button and update V_RANGE label name 2022-10-06 16:54:42 +08:00
peterlu14 15eeb513a6 [debug] fix eis replay parameter & eis realtime chart fix 2022-10-05 18:09:11 +08:00
peterlu14 f5f30cbe61 [debug] eis realtime chart source and cache problem 2022-10-05 17:01:58 +08:00
peterlu14 f7dbf43e77 [update] project enable Elite_EDC & Elite_EIS 2022-10-05 12:02:28 +08:00
peterlu14 dba675254d [update] FREQ 13333333 2022-10-05 12:00:28 +08:00
peterlu14 7635f991c1 [update] vt add parameter MEASURE_VIN_RANGE 2022-10-05 11:21:49 +08:00
peterlu14 476a1699a5 [update] add VT_MODE 2022-10-05 10:59:50 +08:00
peterlu14 8131a19e97 [debug] fix copy id 2022-10-04 13:56:47 +08:00
peterlu14 c310cd4253 [update] check action target when create fake action 2022-10-04 13:56:27 +08:00
peterlu14 6c80390917 [debug] dismiss type error 2022-10-04 13:55:00 +08:00
peterlu14 ff0da52db8 [update] remove cycle & text ui & add -> + 2022-09-30 11:37:46 +08:00
peterlu14 4074af8b4f Merge remote-tracking branch 'origin/dev/debug_cp' into release/v1.3.8/cycle 2022-09-30 10:59:53 +08:00
peterlu14 562632e417 [update] replay new page & modal outside-dismiss 2022-09-30 10:42:07 +08:00
peterlu14 782efbf366 [update] project add cycle 2022-09-30 10:40:31 +08:00
ROY 6a1a31d6e3 [update] debug cp 2022-09-20 18:49:49 +08:00
ROY 86c7f2b30d [update] update eis AC_AMP fomula 2022-09-16 10:43:39 +08:00
ROY 97de1cf4e3 [update] update eis AC_AMP & FREQ fomula 2022-09-14 18:22:03 +08:00
peterlu14 91e100319f [update] project parameter duplicate remove 2022-09-14 18:19:29 +08:00
peterlu14 ca3a525332 [update] add slide-out 2022-09-07 09:46:53 +08:00
peterlu14 9d77ba9c01 [update] add fake start action at start & add new action idle & add click css 2022-09-06 19:43:19 +08:00
peterlu14 53ba6ee486 [update] battery 1s -> 1min & Potential force direct to V 2022-09-05 14:48:29 +08:00
peterlu14 cb42635f6a Merge remote-tracking branch 'origin/dev/battery_display' into release/v1.3.6/battery 2022-08-31 10:20:30 +08:00
peterlu14 d43de5927f Merge remote-tracking branch 'origin/dev/sync-parameter' into release/v1.3.5/cached 2022-08-31 10:08:45 +08:00
sss28072637 05ecd69ecd [update] update battery icon & add low battery warning 2022-08-30 18:16:31 +08:00
peterlu14 062938dd0b [update] refresh cache 2022-08-30 15:31:06 +08:00
peterlu14 5e3eb47614 [update] area display fix 2022-08-29 16:48:05 +08:00
peterlu14 1b682421fd [debug] get legend name fail & capture multitimes 2022-08-29 16:36:29 +08:00
peterlu14 aac74382ad Merge remote-tracking branch 'origin/dev/EISReplayFix' into release/v1.3.4/battery&replayEIS 2022-08-29 16:04:11 +08:00
nthu1080112244 0b005638f6 [debug] fix chartAct device undefined 2022-08-29 16:03:43 +08:00
nthu1080112244 f5604b4ad4 [debug] fix typing error 2022-08-29 15:51:03 +08:00
peterlu14 5d772b9d5b Merge remote-tracking branch 'origin/dev/EISReplayFix' into release/v1.3.4/battery&replayEIS 2022-08-29 15:50:26 +08:00
nthu1080112244 857184392c [update] brush delay = 0 2022-08-29 15:46:51 +08:00
nthu1080112244 6c1304bcea [debug] fix specific integral key in bug 2022-08-29 11:40:49 +08:00
nthu1080112244 bcdaecca77 [debug] resolve replay cycle select bug 2022-08-29 11:13:19 +08:00
nthu1080112244 a5330c71dc [debug] fix some typing error 2022-08-29 10:12:41 +08:00
nthu1080112244 a8b6937b72 [update] new setting table, new replay layout 2022-08-26 16:53:23 +08:00
sss28072637 e69e42ac63 [update] adjust the formula of calculating battery, add battery icon & percentage 2022-08-24 17:55:38 +08:00
peterlu14 01f0f45bdd [update] sg_filter scale with sample rate & volt step 2022-08-24 13:27:25 +08:00
ROY 0719284f24 [update] fix VOLT_VSCAN scale 2022-08-23 11:37:02 +08:00
sss28072637 0cecf9abec [update] add battery display 2022-08-22 18:07:06 +08:00
nthu1080112244 93a0ea9b24 Merge branch 'release/v1.3.2/replay_new_function' into dev/EISReplayFix 2022-08-22 17:25:47 +08:00
peterlu14 d3fcf78b45 [refresh] realtime parameter refresh 2022-08-22 11:40:05 +08:00
peterlu14 0d279cb0bf [debug] fix capture data clear problem 2022-08-22 11:38:40 +08:00
peterlu14 44989dd7f7 [debug] fix scheduler parameter not refresh & default MODE = 0 2022-08-22 11:37:56 +08:00
peterlu14 e4c2018e12 Merge remote-tracking branch 'origin/dev/scheduler-function' into release/v1.3.3/merge_scheduler 2022-08-19 18:56:45 +08:00
peterlu14 a0fea97ca7 [update] differential 2022-08-19 18:56:12 +08:00
108000207 20d94f8c09 [debug] project table library bug (auto connect) 2022-08-19 17:57:06 +08:00
108000207 eb80489c41 [update] scheduler cycle UI 2022-08-19 17:11:37 +08:00
108000207 d337afd7b9 [update] show cycle number on project running 2022-08-19 16:54:20 +08:00
peterlu14 82f46030a3 [update] fix realtime unit function type 2022-08-19 16:17:57 +08:00
peterlu14 8052dfcbf4 [update] file table fix 2022-08-19 15:55:14 +08:00
108000207 ec7edb6bd9 Merge remote-tracking branch 'origin/dev/drag_task' into dev/scheduler-function 2022-08-18 18:25:05 +08:00
108000207 4ac9fe32d1 [update] remove cycle save condition 2022-08-18 18:16:38 +08:00
108000207 46def3dab3 [update] change the UI of scheduler cycle 2022-08-18 17:38:12 +08:00
108000207 d08f49548b [update] scheduler cycle v1 ( support nest cycle) 2022-08-17 11:58:32 +08:00
ROY 99f51f4307 Merge remote-tracking branch 'origin/release/v1.3.2/replay_new_function' into dev/sync-parameter 2022-08-17 10:54:29 +08:00
108000207 c85c7b0285 [update] fix cycle count 2022-08-16 14:34:18 +08:00
ROY dec4ad1093 [update] realtime nA support mode [10, 11] 2022-08-16 11:32:14 +08:00
ROY e2735f7782 Merge remote-tracking branch 'origin/release/v1.3.2/replay_new_function' into dev/sync-parameter 2022-08-16 11:30:50 +08:00
108000207 3c14cc552f Merge remote-tracking branch 'origin/dev/scheduler' into dev/scheduler-function 2022-08-16 11:16:58 +08:00
peterlu14 fe723ae897 Merge remote-tracking branch 'origin/dev/delete_actions' into dev/scheduler 2022-08-15 19:10:37 +08:00
JayC319 39bb196db7 message 2022-08-15 17:51:58 +08:00
JayC319 df34998b51 Merge remote-tracking branch 'origin/release/v1.3.2/replay_new_function' into dev/sync-parameter 2022-08-15 17:44:33 +08:00
108000207 a312a32ddc Merge remote-tracking branch 'origin/dev/delete_actions' into dev/scheduler-function 2022-08-15 14:01:48 +08:00
108000207 4005961b8a Merge remote-tracking branch 'origin/release/v1.3.2/replay_new_function-hide_project' into dev/scheduler-function 2022-08-15 09:34:37 +08:00
108000207 8cb9ac007e [update] add scheduler cycle at condition, for setting cycle, cycle_next, and cycle_count 2022-08-15 09:31:21 +08:00
108000207 402dd3a66b [debug] fix the bug of project(scheduler): change task but not refresh real-time axis 2022-08-11 15:36:47 +08:00
peterlu14 e2e0b5609a [update] add -sync-parameter 2022-08-09 14:18:38 +08:00
159 changed files with 9072 additions and 2264 deletions
+48 -9
View File
@@ -1217,6 +1217,11 @@
"@hapi/hoek": "^8.3.0"
}
},
"@hyjiacan/vue-slideout": {
"version": "2.5.9",
"resolved": "https://registry.npmjs.org/@hyjiacan/vue-slideout/-/vue-slideout-2.5.9.tgz",
"integrity": "sha512-SSf0QaENGt9B2We8lL5QF+gNK7/pHqUEA8SiwUKtMTDj2rbjhGYFpCD+grV7oAAynGdiEIhQ3b3Mphh9/+keBg=="
},
"@intervolga/optimize-cssnano-plugin": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@intervolga/optimize-cssnano-plugin/-/optimize-cssnano-plugin-1.0.6.tgz",
@@ -17016,13 +17021,29 @@
"integrity": "sha512-VPNCOTZK6WZy73lcWc+R7IW1uaBFEO3/Csrs5CzWVOdvE30V8Y1+BE/BtTlcEmeDGx0eqdE7bSCg55Jj37PMJg=="
},
"v-tooltip": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/v-tooltip/-/v-tooltip-2.0.3.tgz",
"integrity": "sha512-KZZY3s+dcijzZmV2qoDH4rYmjMZ9YKGBVoUznZKQX0e3c2GjpJm3Sldzz8HHH2Ud87JqhZPB4+4gyKZ6m98cKQ==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/v-tooltip/-/v-tooltip-2.1.3.tgz",
"integrity": "sha512-xXngyxLQTOx/yUEy50thb8te7Qo4XU6h4LZB6cvEfVd9mnysUxLEoYwGWDdqR+l69liKsy3IPkdYff3J1gAJ5w==",
"requires": {
"lodash": "^4.17.15",
"popper.js": "^1.16.0",
"vue-resize": "^0.4.5"
"@babel/runtime": "^7.13.10",
"lodash": "^4.17.21",
"popper.js": "^1.16.1",
"vue-resize": "^1.0.1"
},
"dependencies": {
"@babel/runtime": {
"version": "7.20.1",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz",
"integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==",
"requires": {
"regenerator-runtime": "^0.13.10"
}
},
"regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
}
}
},
"v8-compile-cache": {
@@ -17322,9 +17343,27 @@
}
},
"vue-resize": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-0.4.5.tgz",
"integrity": "sha512-bhP7MlgJQ8TIkZJXAfDf78uJO+mEI3CaLABLjv0WNzr4CcGRGPIAItyWYnP6LsPA4Oq0WE+suidNs6dgpO4RHg=="
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-1.0.1.tgz",
"integrity": "sha512-z5M7lJs0QluJnaoMFTIeGx6dIkYxOwHThlZDeQnWZBizKblb99GSejPnK37ZbNE/rVwDcYcHY+Io+AxdpY952w==",
"requires": {
"@babel/runtime": "^7.13.10"
},
"dependencies": {
"@babel/runtime": {
"version": "7.20.1",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz",
"integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==",
"requires": {
"regenerator-runtime": "^0.13.10"
}
},
"regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
}
}
},
"vue-router": {
"version": "3.3.4",
+2 -1
View File
@@ -15,6 +15,7 @@
"dependencies": {
"@fontsource/source-code-pro": "^4.5.0",
"@fontsource/source-sans-pro": "^4.5.1",
"@hyjiacan/vue-slideout": "^2.5.9",
"@types/jest": "^24.0.11",
"amcharts3": "^3.21.14",
"ammap3": "^3.21.14",
@@ -45,7 +46,7 @@
"regenerator-runtime": "^0.13.3",
"register-service-worker": "^1.6.2",
"streamsaver": "^2.0.5",
"v-tooltip": "^2.0.2",
"v-tooltip": "^2.1.3",
"vee-validate": "^2.2.13",
"vue": "^2.6.10",
"vue-axios": "^3.2.0",
+3
View File
@@ -2,6 +2,9 @@
<html>
<head>
<meta charset="utf-8">
<!-- <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
+11
View File
@@ -30,6 +30,11 @@ import 'vue-toastification/dist/index.css'
import api from '@/data/api/index'
import localforage from 'localforage'
import SlideOut from '@hyjiacan/vue-slideout'
import '@hyjiacan/vue-slideout/lib/slideout.css'
import VTooltip from 'v-tooltip'
import '../metrics'
import '../registerServiceWorker'
@@ -101,6 +106,12 @@ Vue.use(Toast)
// Vue.use(VueMqtt, 'ws://' + '192.168.151.125' + ':8083')
Vue.use(VueMqtt, MqttUrl)
Vue.use(SlideOut, {
// set default props here
})
Vue.use(VTooltip)
Vue.prototype.API = api
Vue.prototype.GLOBAL = global_
@@ -0,0 +1,4 @@
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="13.5" cy="13.5" r="12.5" fill="#37E893" stroke="#37E893" stroke-width="2"/>
<path d="M21.5 12.634C22.1667 13.0189 22.1667 13.9811 21.5 14.366L10.25 20.8612C9.58333 21.2461 8.75 20.765 8.75 19.9952V7.00481C8.75 6.23501 9.58333 5.75388 10.25 6.13878L21.5 12.634Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 392 B

+4
View File
@@ -0,0 +1,4 @@
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="13.5" cy="13.5" r="12.5" fill="#E6E6E6" stroke="#E6E6E6" stroke-width="2"/>
<path d="M21.5 12.634C22.1667 13.0189 22.1667 13.9811 21.5 14.366L10.25 20.8612C9.58333 21.2461 8.75 20.765 8.75 19.9952V7.00481C8.75 6.23501 9.58333 5.75388 10.25 6.13878L21.5 12.634Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 392 B

@@ -0,0 +1,7 @@
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="13.5" cy="13.5" r="12.5" fill="#FF8D8D" stroke="#FF8D8D" stroke-width="2"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="15" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="15" y="7" width="4" height="13" rx="2" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 441 B

+9
View File
@@ -0,0 +1,9 @@
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="13.5" cy="13.5" r="12.5" fill="#E6E6E6" stroke="#E6E6E6" stroke-width="2"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="15" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="15" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
<rect x="8" y="7" width="4" height="13" rx="2" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 565 B

@@ -0,0 +1,3 @@
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 14.0833V9.74996M22.75 6.49996L20.5833 4.33329M10.8333 2.16663H15.1666M13 22.75C10.7014 22.75 8.49704 21.8369 6.87172 20.2116C5.24641 18.5862 4.33331 16.3818 4.33331 14.0833C4.33331 11.7847 5.24641 9.58035 6.87172 7.95503C8.49704 6.32972 10.7014 5.41663 13 5.41663C15.2985 5.41663 17.5029 6.32972 19.1282 7.95503C20.7536 9.58035 21.6666 11.7847 21.6666 14.0833C21.6666 16.3818 20.7536 18.5862 19.1282 20.2116C17.5029 21.8369 15.2985 22.75 13 22.75Z" stroke="#2C4052" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 648 B

+31
View File
@@ -0,0 +1,31 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="640.000000pt" height="320.000000pt" viewBox="0 0 1280.000000 640.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.15, written by Peter Selinger 2001-2017
</metadata>
<g transform="translate(0.000000,640.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M9638 6075 c-772 -93 -1504 -467 -2317 -1184 -198 -174 -334 -303
-657 -624 -230 -229 -264 -258 -281 -249 -11 6 -100 93 -199 194 -1144 1171
-1886 1664 -2745 1822 -560 103 -1141 38 -1669 -186 -885 -376 -1533 -1167
-1714 -2093 -41 -207 -51 -318 -51 -565 0 -392 54 -719 176 -1065 338 -964
1145 -1627 2164 -1779 634 -95 1337 26 1957 335 243 121 448 250 703 441 321
239 556 450 1061 950 176 175 327 318 334 318 8 0 77 -66 154 -146 172 -179
592 -584 770 -743 820 -731 1442 -1055 2226 -1163 58 -8 194 -12 350 -12 213
0 279 4 400 23 650 100 1205 379 1659 832 457 457 742 1045 823 1699 19 155
16 563 -6 720 -78 561 -275 1067 -568 1457 -95 128 -294 332 -425 435 -364
290 -837 486 -1378 570 -172 26 -594 34 -767 13z m-6331 -1199 c336 -71 676
-233 1010 -481 119 -88 297 -234 413 -339 146 -133 880 -850 880 -860 0 -16
-640 -649 -795 -788 -492 -438 -947 -715 -1375 -839 -202 -58 -321 -74 -565
-74 -190 0 -235 3 -334 23 -590 119 -1022 504 -1210 1077 -160 489 -130 953
90 1385 252 496 706 824 1266 915 63 10 146 13 293 10 172 -3 225 -8 327 -29z
m6863 19 c327 -46 605 -171 841 -378 439 -384 649 -1063 517 -1677 -134 -625
-615 -1131 -1229 -1295 -148 -39 -279 -55 -454 -55 -310 0 -559 62 -870 215
-327 160 -642 391 -1037 761 -248 232 -743 719 -746 734 -3 16 466 495 668
681 682 630 1221 933 1800 1014 130 18 382 18 510 0z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+4
View File
@@ -0,0 +1,4 @@
<svg width="270" height="110" viewBox="0 0 270 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="270" height="110" rx="55" fill="#A4A3A3"/>
<path d="M84.9 88.9C80.4 88.9 76.41 88 72.93 86.2C69.45 84.34 66.75 81.73 64.83 78.37C62.97 75.01 62.04 71.14 62.04 66.76V46.24C62.04 41.92 63 38.11 64.92 34.81C66.84 31.45 69.51 28.87 72.93 27.07C76.41 25.21 80.4 24.28 84.9 24.28C89.46 24.28 93.45 25.21 96.87 27.07C100.35 28.87 103.05 31.45 104.97 34.81C106.89 38.11 107.85 41.92 107.85 46.24V66.76C107.85 71.14 106.89 75.01 104.97 78.37C103.05 81.73 100.35 84.34 96.87 86.2C93.45 88 89.46 88.9 84.9 88.9ZM84.9 79.9C88.68 79.9 91.71 78.73 93.99 76.39C96.27 74.05 97.41 70.96 97.41 67.12V46.15C97.41 42.25 96.27 39.13 93.99 36.79C91.71 34.45 88.68 33.28 84.9 33.28C81.18 33.28 78.18 34.45 75.9 36.79C73.62 39.13 72.48 42.25 72.48 46.15V67.12C72.48 70.96 73.62 74.05 75.9 76.39C78.18 78.73 81.18 79.9 84.9 79.9ZM162.038 32.92C162.038 33.22 161.918 33.49 161.678 33.73C161.498 33.91 161.258 34 160.958 34H130.358C130.058 34 129.908 34.15 129.908 34.45V51.28C129.908 51.58 130.058 51.73 130.358 51.73H150.968C151.268 51.73 151.508 51.85 151.688 52.09C151.928 52.27 152.048 52.51 152.048 52.81V59.65C152.048 59.95 151.928 60.22 151.688 60.46C151.508 60.64 151.268 60.73 150.968 60.73H130.358C130.058 60.73 129.908 60.88 129.908 61.18V86.92C129.908 87.22 129.788 87.49 129.548 87.73C129.368 87.91 129.128 88 128.828 88H120.548C120.248 88 119.978 87.91 119.738 87.73C119.558 87.49 119.468 87.22 119.468 86.92V26.08C119.468 25.78 119.558 25.54 119.738 25.36C119.978 25.12 120.248 25 120.548 25H160.958C161.258 25 161.498 25.12 161.678 25.36C161.918 25.54 162.038 25.78 162.038 26.08V32.92ZM212.751 32.92C212.751 33.22 212.631 33.49 212.391 33.73C212.211 33.91 211.971 34 211.671 34H181.071C180.771 34 180.621 34.15 180.621 34.45V51.28C180.621 51.58 180.771 51.73 181.071 51.73H201.681C201.981 51.73 202.221 51.85 202.401 52.09C202.641 52.27 202.761 52.51 202.761 52.81V59.65C202.761 59.95 202.641 60.22 202.401 60.46C202.221 60.64 201.981 60.73 201.681 60.73H181.071C180.771 60.73 180.621 60.88 180.621 61.18V86.92C180.621 87.22 180.501 87.49 180.261 87.73C180.081 87.91 179.841 88 179.541 88H171.261C170.961 88 170.691 87.91 170.451 87.73C170.271 87.49 170.181 87.22 170.181 86.92V26.08C170.181 25.78 170.271 25.54 170.451 25.36C170.691 25.12 170.961 25 171.261 25H211.671C211.971 25 212.211 25.12 212.391 25.36C212.631 25.54 212.751 25.78 212.751 26.08V32.92Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="65" height="65" viewBox="0 0 65 65" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="65" height="65" rx="32.5" fill="#CDCDCD"/>
</svg>

After

Width:  |  Height:  |  Size: 159 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="65" height="65" viewBox="0 0 65 65" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="65" height="65" rx="32.5" fill="#2CE9A4"/>
</svg>

After

Width:  |  Height:  |  Size: 159 B

+4
View File
@@ -0,0 +1,4 @@
<svg width="270" height="110" viewBox="0 0 270 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="270" height="110" rx="55" fill="#FF8989"/>
<path d="M84.9 88.9C80.4 88.9 76.41 88 72.93 86.2C69.45 84.34 66.75 81.73 64.83 78.37C62.97 75.01 62.04 71.14 62.04 66.76V46.24C62.04 41.92 63 38.11 64.92 34.81C66.84 31.45 69.51 28.87 72.93 27.07C76.41 25.21 80.4 24.28 84.9 24.28C89.46 24.28 93.45 25.21 96.87 27.07C100.35 28.87 103.05 31.45 104.97 34.81C106.89 38.11 107.85 41.92 107.85 46.24V66.76C107.85 71.14 106.89 75.01 104.97 78.37C103.05 81.73 100.35 84.34 96.87 86.2C93.45 88 89.46 88.9 84.9 88.9ZM84.9 79.9C88.68 79.9 91.71 78.73 93.99 76.39C96.27 74.05 97.41 70.96 97.41 67.12V46.15C97.41 42.25 96.27 39.13 93.99 36.79C91.71 34.45 88.68 33.28 84.9 33.28C81.18 33.28 78.18 34.45 75.9 36.79C73.62 39.13 72.48 42.25 72.48 46.15V67.12C72.48 70.96 73.62 74.05 75.9 76.39C78.18 78.73 81.18 79.9 84.9 79.9ZM162.038 32.92C162.038 33.22 161.918 33.49 161.678 33.73C161.498 33.91 161.258 34 160.958 34H130.358C130.058 34 129.908 34.15 129.908 34.45V51.28C129.908 51.58 130.058 51.73 130.358 51.73H150.968C151.268 51.73 151.508 51.85 151.688 52.09C151.928 52.27 152.048 52.51 152.048 52.81V59.65C152.048 59.95 151.928 60.22 151.688 60.46C151.508 60.64 151.268 60.73 150.968 60.73H130.358C130.058 60.73 129.908 60.88 129.908 61.18V86.92C129.908 87.22 129.788 87.49 129.548 87.73C129.368 87.91 129.128 88 128.828 88H120.548C120.248 88 119.978 87.91 119.738 87.73C119.558 87.49 119.468 87.22 119.468 86.92V26.08C119.468 25.78 119.558 25.54 119.738 25.36C119.978 25.12 120.248 25 120.548 25H160.958C161.258 25 161.498 25.12 161.678 25.36C161.918 25.54 162.038 25.78 162.038 26.08V32.92ZM212.751 32.92C212.751 33.22 212.631 33.49 212.391 33.73C212.211 33.91 211.971 34 211.671 34H181.071C180.771 34 180.621 34.15 180.621 34.45V51.28C180.621 51.58 180.771 51.73 181.071 51.73H201.681C201.981 51.73 202.221 51.85 202.401 52.09C202.641 52.27 202.761 52.51 202.761 52.81V59.65C202.761 59.95 202.641 60.22 202.401 60.46C202.221 60.64 201.981 60.73 201.681 60.73H181.071C180.771 60.73 180.621 60.88 180.621 61.18V86.92C180.621 87.22 180.501 87.49 180.261 87.73C180.081 87.91 179.841 88 179.541 88H171.261C170.961 88 170.691 87.91 170.451 87.73C170.271 87.49 170.181 87.22 170.181 86.92V26.08C170.181 25.78 170.271 25.54 170.451 25.36C170.691 25.12 170.961 25 171.261 25H211.671C211.971 25 212.211 25.12 212.391 25.36C212.631 25.54 212.751 25.78 212.751 26.08V32.92Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

+4
View File
@@ -0,0 +1,4 @@
<svg width="270" height="110" viewBox="0 0 270 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="270" height="110" rx="55" fill="#41DBA2"/>
<path d="M104.9 88.9C100.4 88.9 96.41 88 92.93 86.2C89.45 84.34 86.75 81.73 84.83 78.37C82.97 75.01 82.04 71.14 82.04 66.76V46.24C82.04 41.92 83 38.11 84.92 34.81C86.84 31.45 89.51 28.87 92.93 27.07C96.41 25.21 100.4 24.28 104.9 24.28C109.46 24.28 113.45 25.21 116.87 27.07C120.35 28.87 123.05 31.45 124.97 34.81C126.89 38.11 127.85 41.92 127.85 46.24V66.76C127.85 71.14 126.89 75.01 124.97 78.37C123.05 81.73 120.35 84.34 116.87 86.2C113.45 88 109.46 88.9 104.9 88.9ZM104.9 79.9C108.68 79.9 111.71 78.73 113.99 76.39C116.27 74.05 117.41 70.96 117.41 67.12V46.15C117.41 42.25 116.27 39.13 113.99 36.79C111.71 34.45 108.68 33.28 104.9 33.28C101.18 33.28 98.18 34.45 95.9 36.79C93.62 39.13 92.48 42.25 92.48 46.15V67.12C92.48 70.96 93.62 74.05 95.9 76.39C98.18 78.73 101.18 79.9 104.9 79.9ZM176.098 26.08C176.098 25.78 176.188 25.54 176.368 25.36C176.608 25.12 176.878 25 177.178 25H185.458C185.758 25 185.998 25.12 186.178 25.36C186.418 25.54 186.538 25.78 186.538 26.08V86.92C186.538 87.22 186.418 87.49 186.178 87.73C185.998 87.91 185.758 88 185.458 88H177.448C176.848 88 176.428 87.76 176.188 87.28L150.268 44.8C150.148 44.62 150.028 44.56 149.908 44.62C149.788 44.62 149.728 44.74 149.728 44.98L149.908 86.92C149.908 87.22 149.788 87.49 149.548 87.73C149.368 87.91 149.128 88 148.828 88H140.548C140.248 88 139.978 87.91 139.738 87.73C139.558 87.49 139.468 87.22 139.468 86.92V26.08C139.468 25.78 139.558 25.54 139.738 25.36C139.978 25.12 140.248 25 140.548 25H148.558C149.158 25 149.578 25.24 149.818 25.72L175.648 68.2C175.768 68.38 175.888 68.47 176.008 68.47C176.128 68.41 176.188 68.26 176.188 68.02L176.098 26.08Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path fill="#FFFFFF" d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>

After

Width:  |  Height:  |  Size: 477 B

+4
View File
@@ -0,0 +1,4 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.3334 1.83337H9.16671C8.15562 1.83337 7.33337 2.65562 7.33337 3.66671V7.33337H3.66671C2.65562 7.33337 1.83337 8.15562 1.83337 9.16671V18.3334C1.83337 19.3445 2.65562 20.1667 3.66671 20.1667H12.8334C13.8445 20.1667 14.6667 19.3445 14.6667 18.3334V14.6667H18.3334C19.3445 14.6667 20.1667 13.8445 20.1667 12.8334V3.66671C20.1667 2.65562 19.3445 1.83337 18.3334 1.83337ZM3.66671 18.3334V9.16671H12.8334L12.8352 18.3334H3.66671ZM18.3334 12.8334H14.6667V9.16671C14.6667 8.15562 13.8445 7.33337 12.8334 7.33337H9.16671V3.66671H18.3334V12.8334Z" fill="#B8C3CC"/>
<path d="M5.5 11H11V12.8333H5.5V11ZM5.5 14.6667H11V16.5H5.5V14.6667Z" fill="#B8C3CC"/>
</svg>

After

Width:  |  Height:  |  Size: 757 B

+4
View File
@@ -0,0 +1,4 @@
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M23.3333 2.33325H11.6666C10.3798 2.33325 9.33331 3.37975 9.33331 4.66659V9.33325H4.66665C3.37981 9.33325 2.33331 10.3798 2.33331 11.6666V23.3333C2.33331 24.6201 3.37981 25.6666 4.66665 25.6666H16.3333C17.6201 25.6666 18.6666 24.6201 18.6666 23.3333V18.6666H23.3333C24.6201 18.6666 25.6666 17.6201 25.6666 16.3333V4.66659C25.6666 3.37975 24.6201 2.33325 23.3333 2.33325ZM4.66665 23.3333V11.6666H16.3333L16.3356 23.3333H4.66665ZM23.3333 16.3333H18.6666V11.6666C18.6666 10.3798 17.6201 9.33325 16.3333 9.33325H11.6666V4.66659H23.3333V16.3333Z" fill="white"/>
<path d="M7 14H14V16.3333H7V14ZM7 18.6667H14V21H7V18.6667Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 743 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="20" height="24" viewBox="0 0 20 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 14.3337H13V10.8337H16V8.50041H13V5.00041H11V8.50041H8V10.8337H11V14.3337ZM6 19.0004C5.45 19.0004 4.97933 18.7721 4.588 18.3156C4.196 17.8582 4 17.3087 4 16.6671V2.66707C4 2.02541 4.196 1.47591 4.588 1.01857C4.97933 0.562018 5.45 0.33374 6 0.33374H18C18.55 0.33374 19.021 0.562018 19.413 1.01857C19.8043 1.47591 20 2.02541 20 2.66707V16.6671C20 17.3087 19.8043 17.8582 19.413 18.3156C19.021 18.7721 18.55 19.0004 18 19.0004H6ZM6 16.6671H18V2.66707H6V16.6671ZM2 23.6671C1.45 23.6671 0.979333 23.4388 0.588 22.9822C0.196 22.5249 0 21.9754 0 21.3337V5.00041H2V21.3337H16V23.6671H2Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 710 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.2132 12.6274L6.97054 8.38479L2.7279 12.6274L1.31369 11.2132L5.55633 6.97058L1.31369 2.72794L2.7279 1.31373L6.97054 5.55637L11.2132 1.31373L12.6274 2.72794L8.38475 6.97058L12.6274 11.2132L11.2132 12.6274Z" fill="#B8C3CC" stroke="#B8C3CC" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 379 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="19" height="21" viewBox="0 0 19 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.87524 20.625C3.25649 20.625 2.72699 20.4049 2.28674 19.9646C1.84574 19.5236 1.62524 18.9938 1.62524 18.375V3.75H0.500244V1.5H6.12524V0.375H12.8752V1.5H18.5002V3.75H17.3752V18.375C17.3752 18.9938 17.1551 19.5236 16.7149 19.9646C16.2739 20.4049 15.744 20.625 15.1252 20.625H3.87524ZM15.1252 3.75H3.87524V18.375H15.1252V3.75ZM6.12524 16.125H8.37524V6H6.12524V16.125ZM10.6252 16.125H12.8752V6H10.6252V16.125Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 536 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 18C2.45 18 1.97933 17.8043 1.588 17.413C1.196 17.021 1 16.55 1 16V3H0V1H5V0H11V1H16V3H15V16C15 16.55 14.8043 17.021 14.413 17.413C14.021 17.8043 13.55 18 13 18H3ZM13 3H3V16H13V3ZM5 14H7V5H5V14ZM9 14H11V5H9V14Z" fill="#FF6C63"/>
</svg>

After

Width:  |  Height:  |  Size: 343 B

+8
View File
@@ -0,0 +1,8 @@
<svg width="36" height="38" viewBox="0 0 36 38" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_3_20" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="36" height="38">
<rect width="36" height="38" fill="#D9D9D9"/>
</mask>
<g mask="url(#mask0_3_20)">
<path d="M25.737 18.6561C25.5543 18.849 25.5543 19.151 25.737 19.3439L30.8113 24.7L29.4 26.1897L22.5888 19L29.4 11.8103L30.8113 13.3L25.737 18.6561ZM5 28V25.8333H23.5V28H5ZM5 20.0833V17.9167H19V20.0833H5ZM5 12.1667V10H23.5V12.1667H5Z" fill="#768B9B" stroke="#768B9B" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 592 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="26" height="30" viewBox="0 0 26 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24.6304 15L1.9413 27.9904V2.00962L24.6304 15Z" fill="white" stroke="white" stroke-width="2.5" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 233 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.75012 18.7498V11.2498H1.25012V8.74976H8.75012V1.24976H11.2501V8.74976H18.7501V11.2498H11.2501V18.7498H8.75012Z" fill="white" stroke="white" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 281 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.25 1.5C2.78587 1.5 2.34075 1.68437 2.01256 2.01256C1.68437 2.34075 1.5 2.78587 1.5 3.25V18.75C1.50001 19.1708 1.65165 19.5775 1.92714 19.8956C2.20263 20.2137 2.58351 20.4219 3 20.482V13.25C3 12.6533 3.23705 12.081 3.65901 11.659C4.08097 11.2371 4.65326 11 5.25 11H16.75C17.3467 11 17.919 11.2371 18.341 11.659C18.7629 12.081 19 12.6533 19 13.25V20.482C19.4165 20.4219 19.7974 20.2137 20.0729 19.8956C20.3483 19.5775 20.5 19.1708 20.5 18.75V5.786C20.5 5.321 20.316 4.876 19.987 4.548L17.452 2.013C17.2895 1.85035 17.0965 1.72133 16.884 1.63331C16.6716 1.54528 16.4439 1.49998 16.214 1.5H16V5.75C16 6.04547 15.9418 6.33805 15.8287 6.61104C15.7157 6.88402 15.5499 7.13206 15.341 7.34099C15.1321 7.54992 14.884 7.71566 14.611 7.82873C14.3381 7.9418 14.0455 8 13.75 8H7.25C6.65326 8 6.08097 7.76295 5.65901 7.34099C5.23705 6.91903 5 6.34674 5 5.75V1.5H3.25ZM6.5 1.5V5.75C6.5 6.164 6.836 6.5 7.25 6.5H13.75C13.9489 6.5 14.1397 6.42098 14.2803 6.28033C14.421 6.13968 14.5 5.94891 14.5 5.75V1.5H6.5ZM17.5 20.5V13.25C17.5 13.0511 17.421 12.8603 17.2803 12.7197C17.1397 12.579 16.9489 12.5 16.75 12.5H5.25C5.05109 12.5 4.86032 12.579 4.71967 12.7197C4.57902 12.8603 4.5 13.0511 4.5 13.25V20.5H17.5ZM0 3.25C0 2.38805 0.34241 1.5614 0.951903 0.951903C1.5614 0.34241 2.38805 0 3.25 0H16.215C17.0769 5.14719e-05 17.9035 0.342495 18.513 0.952L21.048 3.487C21.658 4.097 22 4.924 22 5.786V18.75C22 19.612 21.6576 20.4386 21.0481 21.0481C20.4386 21.6576 19.612 22 18.75 22H3.25C2.38805 22 1.5614 21.6576 0.951903 21.0481C0.34241 20.4386 0 19.612 0 18.75V3.25Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="25" height="22" viewBox="0 0 25 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.7246 13.3226L23.2481 20.2889L22.872 20.6372L15.2354 13.5662L14.627 13.0029L13.9608 13.4964C13.3939 13.9164 12.7313 14.257 11.9636 14.5122C11.2143 14.7612 10.4084 14.8889 9.54002 14.8889C7.37746 14.8889 5.59555 14.2043 4.13159 12.8488C2.66996 11.4954 1.96002 9.88006 1.96002 7.94444C1.96002 6.00883 2.66996 4.39346 4.13159 3.04009C5.59555 1.68457 7.37746 1 9.54002 1C11.7026 1 13.485 1.68458 14.95 3.04027C16.4105 4.39351 17.12 6.00882 17.12 7.94444C17.12 8.7236 16.9867 9.44582 16.7256 10.1191C16.4567 10.8127 16.0964 11.4153 15.6473 11.9351L15.0157 12.6662L15.7246 13.3226ZM14.4273 12.5749L14.4279 12.5744C15.7797 11.3218 16.48 9.76006 16.48 7.94444C16.48 6.12883 15.7797 4.56711 14.4279 3.3145L14.4273 3.31398C13.0775 2.06509 11.4285 1.44444 9.54002 1.44444C7.65159 1.44444 6.00256 2.06509 4.65273 3.31398L4.65217 3.3145C3.30039 4.56711 2.60002 6.12883 2.60002 7.94444C2.60002 9.76006 3.30039 11.3218 4.65217 12.5744L4.65273 12.5749C6.00256 13.8238 7.65158 14.4444 9.54002 14.4444C11.4285 14.4444 13.0775 13.8238 14.4273 12.5749Z" fill="#2C4053" stroke="#B8C3CC" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect rx="5" ry="5" width="25" height="25" style="fill: white;"/>
</svg>

After

Width:  |  Height:  |  Size: 172 B

@@ -25,12 +25,12 @@
>
<!-- *** icon -->
<!-- <va-icon-vuestic /> -->
<img src='@/assets/img/bps_logo.png'>
<!-- <img src='@/assets/img/bps_logo.png'> -->
</router-link>
</div>
<!-- <img style="height: 40px;" v-bind:src="'https://www.bioproweb.com/wp-content/uploads/2020/01/BPS-LOGO_60.png'"> -->
<div class="app-navbar__center lg5 md4">
<span
<!-- <span
class="app-navbar__text"
:style="{color: this.$themes.gray}"
>
@@ -43,7 +43,7 @@
>
contact@bioproweb.com
</a>
</span>
</span> -->
</div>
<app-navbar-actions
class="app-navbar__actions md5 lg4"
@@ -10,6 +10,7 @@
<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"/>
<va-button @click="reload" icon="fa fa-refresh" flat></va-button>
<profile-dropdown class="app-navbar-actions__item app-navbar-actions__item--profile">
<span>{{userName}}</span>
</profile-dropdown>
@@ -70,6 +71,9 @@ export default {
this.$refs.license_check_button_ref.refresh()
this.$refs.license_update_modal_ref.hide()
},
reload () {
window.location.reload(true)
},
},
}
</script>
@@ -61,14 +61,14 @@ export const navigationRoutes = {
iconClass: 'vuestic-iconset vuestic-iconset-settings',
},
},
// {
// name: 'project',
// displayName: 'Scheduler',
// meta: {
// iconClass: 'vuestic-iconset vuestic-iconset-tables',
// // iconClass: 'vuestic-iconset vuestic-iconset-browse-gallery',
// },
// },
{
name: 'project',
displayName: 'Scheduler',
meta: {
iconClass: 'vuestic-iconset vuestic-iconset-tables',
// iconClass: 'vuestic-iconset vuestic-iconset-browse-gallery',
},
},
// {
// name: 'forms',
// displayName: 'menu.forms',
@@ -380,7 +380,7 @@ export default {
// toolbox: ['rect', 'polygon', 'lineX', 'lineY', 'keep', 'clear'],
xAxisIndex: 0,
throttleType: 'debounce',
throttleDelay: 0.1,
throttleDelay: 0,
}
this.showChartLoading('detail')
const timeDur = this.endTimeCurrent - this.startTimeCurrent
@@ -394,7 +394,7 @@ export default {
})
let scale = '1'
if (this.controlPanel.x.type === 'Time') {
if (this.controlPanel.x.axis.description === 'Time') {
scale = await this.computeResampleScale(metaInfo, timeDur)
}
// elite的sample rate不像neulive這麼高,因此試試scale = 100 or 1000時不要再sampling一次了,不然有些形狀(e.g. peak)會不一樣
@@ -413,11 +413,11 @@ export default {
this.currentScale = scale
this.chartDetailData.series[_gridNumber].data.length = 0
let dataListX
const channelX = parseInt(this.controlPanel.x.channel)
if (this.controlPanel.x.type !== 'Time') {
const channelX = parseInt(this.controlPanel.x.axis.channel)
if (this.controlPanel.x.axis.description !== 'Time') {
dataListX = this.dataInfo[meta][channelX][scale]
}
const channelY = parseInt(this.controlPanel.y.channel)
const channelY = parseInt(this.controlPanel.y.axis.channel)
const dataListY = this.dataInfo[meta][channelY][scale]
const isThisModeHasCycle = this.GLOBAL.hasCycleMode(metaInfo.parameter_set.MODE, metaInfo.device.library_name)
@@ -464,7 +464,7 @@ export default {
for (let i = startIndex; i <= endIndex; i++) {
const data = await this.getData(parseInt(scale), this.sampleMethod, dataListY[i].id, channelY, metaInfo)
let dataX
if (this.controlPanel.x.type !== 'Time') {
if (this.controlPanel.x.axis.description !== 'Time') {
dataX = await this.getData(parseInt(scale), this.sampleMethod, dataListX[i].id, channelX, metaInfo)
}
var deltaX = 0
@@ -566,7 +566,7 @@ export default {
}
}
if (this.controlPanel.x.type === 'Time') {
if (this.controlPanel.x.axis.description === 'Time') {
this.chartDetailData.xAxis[_gridNumber].min = _startTime
this.chartDetailData.xAxis[_gridNumber].max = _endTime
} else {
@@ -576,7 +576,7 @@ export default {
_gridNumber += 1
}
if (this.controlPanel.x.type !== 'Time') {
if (this.controlPanel.x.axis.description !== 'Time') {
this.showOverviewChart = false
this.detailchartheight = '88vh'
// this.$refs.chart_detail.updateChartHeight()
@@ -652,8 +652,8 @@ export default {
// tang
if (this.initDone) {
const libName = this.metaList[gridIndex].device.library_name
const xType = (this.controlPanel.x.type === 'Time') ? 'Time' : ((libName === 'EliteZM15' || libName.includes('Elite_EDC') ? 'Elite' : 'EliteEIS'))
const xChannel = (this.controlPanel.x.channel === -1) ? undefined : this.controlPanel.x.channel + 1
const xType = (this.controlPanel.x.axis.description === 'Time') ? 'Time' : ((libName === 'EliteZM15' || libName.includes('Elite_EDC') ? 'Elite' : 'EliteEIS'))
const xChannel = (this.controlPanel.x.axis.channel === -1) ? undefined : this.controlPanel.x.axis.channel + 1
this.updateRegisteredChart({
chartAllData: this.chartData,
chartID: this.chartDetailData.chartID,
@@ -663,10 +663,10 @@ export default {
channelX: xChannel,
deviceNameY: libName.includes('EIS') ? 'EliteEIS' : 'Elite',
deviceIDY: '',
channelY: this.controlPanel.y.channel + 1,
channelY: this.controlPanel.y.axis.channel + 1,
})
}
if (this.controlPanel.x.type === 'Time') {
if (this.controlPanel.x.axis.description === 'Time') {
this.drawOverviewData()
}
this.drawDetailData() // reDraw
@@ -17,12 +17,16 @@
<p class="display-6"> X-Axis </p>
</div>
<div class="flex sm5 xl5 md5 xs5 pl-1 pr-0 py-0">
<control-axis :ref="'axis_x'" axis="x" @changeAxis="changeAxis"/>
<control-axis
:ref="'axis_x'"
coordinate="x"
@changeAxis="changeAxis"
/>
</div>
<div class="flex sm5 xl5 md5 xs5 pl-1 pr-0 py-0">
<control-unit
:ref="'unit_x'"
axis="x"
coordinate="x"
@changeUnit="changeUnit"
style="width: 75px;"
/>
@@ -31,7 +35,11 @@
<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">
<control-funct :ref="'funct_x'" axis="x" @changeFunct="changeFunct"/>
<control-funct
:ref="'funct_x'"
coordinate="x"
@changeFunct="changeFunct"
/>
</div>
</div>
<div class="flex-container mb-2">
@@ -41,14 +49,14 @@
<div class="flex sm5 xl5 md5 xs5 pl-1 pr-0 py-0">
<control-axis
:ref="'axis_y'"
axis="y"
coordinate="y"
@changeAxis="changeAxis"
/>
</div>
<div class="flex sm5 xl5 md5 xs5 pl-1 pr-0 py-0">
<control-unit
:ref="'unit_y'"
axis="y"
coordinate="y"
@changeUnit="changeUnit"
style="width: 75px;"
/>
@@ -59,7 +67,7 @@
<div class="flex sm5 xl5 md5 xs5 pl-1 pr-0 py-0">
<control-funct
:ref="'funct_y'"
axis="y"
coordinate="y"
@changeFunct="changeFunct"/>
</div>
</div>
@@ -95,6 +103,7 @@ import ChangeWindowStartAndSize from '@/components/analysis/replay/toolbox/Chang
import { mapMutations } from 'vuex'
import { mapFields } from 'vuex-map-fields'
import { tableRouter } from '@/components/analysis/replay/toolbox/EliteReplayTable'
import configRouter from '@/components/analysis/replay/toolbox/configTable'
import types from '@/store/modules/analysis/replay/types'
export default {
@@ -123,209 +132,83 @@ export default {
},
data () {
return {
deviceName: '',
libraryName: '',
showCycle: false,
innerCollapse: false,
tableRouter,
configRouter,
}
},
methods: {
...mapMutations('replay', [types.chart.updateAxisLabel]),
// initialize control buttons
init () {
this.deviceName = this.metaList[0].device.library_name
this.initDefaultControlPanel()
this.$refs.axis_x.init()
this.$refs.axis_y.init()
this.$refs.unit_x.init(this.controlPanel.x.type)
this.$refs.unit_y.init(this.controlPanel.y.type)
this.$refs.funct_x.init(this.controlPanel.x.type, this.controlPanel.y.type)
this.$refs.funct_y.init(this.controlPanel.x.type, this.controlPanel.y.type)
// get config information
this.libraryName = this.metaList[0].device.library_name
const setting = this.GLOBAL.getDefaultChartTypeByMode(this.metaList[0].parameter_set.MODE, this.libraryName)
this.controlPanel.x.axis = this.configRouter.getAxis(this.libraryName, setting[0], setting[1])
this.controlPanel.y.axis = this.configRouter.getAxis(this.libraryName, setting[2], setting[3])
this.controlPanel.FSM = this.configRouter.getFSM(this.controlPanel.x.axis.description, this.controlPanel.y.axis.description)
// initialize other blocks
this.$refs.axis_x.init(this.libraryName, setting[0])
this.$refs.axis_y.init(this.libraryName, setting[2])
this.$refs.unit_x.init(this.controlPanel.x.axis.description)
this.$refs.unit_y.init(this.controlPanel.y.axis.description)
this.$refs.funct_x.init(this.controlPanel.x.axis.description, this.controlPanel.y.axis.description)
this.$refs.funct_y.init(this.controlPanel.x.axis.description, this.controlPanel.y.axis.description)
this.$refs.change_cycle.init()
this.$refs.edit_file_name.init()
this.$refs.show_param.init(this.deviceName)
this.$refs.show_param.init(this.libraryName)
this.$refs.change_window_start_and_size.init()
},
// initialize the setting of this control panel
initDefaultControlPanel () {
// use state meta to decide which default unit need to be used (like check I-V mode...)
const setting = this.GLOBAL.getDefaultChartTypeByMode(this.metaList[0].parameter_set.MODE, this.deviceName)
// x-axis
let settingType = setting[0]
let settingValue = setting[1]
if (this.deviceName === 'EliteZM15' || this.deviceName.includes('Elite_EDC')) {
if (settingType === 'Elite') {
// 1: I, 2: V, 3: R, 4: cycle
if (settingValue === 1) {
this.controlPanel.x.type = 'Current'
this.controlPanel.x.channel = 0
} else if (settingValue === 2) {
this.controlPanel.x.type = 'Voltage'
this.controlPanel.x.channel = 1
} else if (settingValue === 3) {
this.controlPanel.x.type = 'Resistance'
this.controlPanel.x.channel = 2
} else if (settingValue === 4) {
this.controlPanel.x.type = 'Cycle'
this.controlPanel.x.channel = 3
}
} else if (settingType === 'Time') {
this.controlPanel.x.type = 'Time'
this.controlPanel.x.channel = undefined
}
} else if (this.deviceName.includes('EIS')) {
if (settingType.includes('EIS')) {
if (settingValue === 3) {
this.controlPanel.x.type = 'Frequency'
this.controlPanel.x.channel = 2
} else if (settingValue === 6 || settingValue === 7) {
this.controlPanel.x.type = 'Z_real'
this.controlPanel.x.channel = 5
} else if (settingValue === 8) {
this.controlPanel.x.type = 'Phase'
this.controlPanel.x.channel = 7
} else if (settingValue === 9) {
this.controlPanel.x.type = 'Current'
this.controlPanel.x.channel = 8
} else if (settingValue === 10) {
this.controlPanel.x.type = 'Default'
this.controlPanel.x.channel = 0
}
} else if (settingType === 'Elite') {
// 1: I, 2: V, 3: R
if (settingValue === 1) {
this.controlPanel.x.type = 'Current'
this.controlPanel.x.channel = 0
} else if (settingValue === 2) {
this.controlPanel.x.type = 'Voltage'
this.controlPanel.x.channel = 1
} else if (settingValue === 3) {
this.controlPanel.x.type = 'Resistance'
this.controlPanel.x.channel = 2
}
} else if (settingType === 'Time') {
this.controlPanel.x.type = 'Time'
this.controlPanel.x.channel = undefined
}
}
// y-axis
settingType = setting[2]
settingValue = setting[3]
if (this.deviceName === 'EliteZM15' || this.deviceName.includes('Elite_EDC')) {
if (settingType === 'Elite') {
// 1: I, 2: V, 3: R, 4: cycle
if (settingValue === 1) {
this.controlPanel.y.type = 'Current'
this.controlPanel.y.channel = 0
} else if (settingValue === 2) {
this.controlPanel.y.type = 'Voltage'
this.controlPanel.y.channel = 1
} else if (settingValue === 3) {
this.controlPanel.y.type = 'Resistance'
this.controlPanel.y.channel = 2
} else if (settingValue === 4) {
this.controlPanel.y.type = 'Cycle'
this.controlPanel.y.channel = 3
}
} else if (settingType === 'Time') {
this.controlPanel.y.type = 'Time'
this.controlPanel.y.channel = undefined
}
} else if (this.deviceName.includes('EIS')) {
if (settingType.includes('EIS')) {
if (settingValue === 3) {
this.controlPanel.y.type = 'Frequency'
this.controlPanel.y.channel = 2
} else if (settingValue === 5 || settingValue === 6 || settingValue === 7) {
this.controlPanel.y.type = 'Impedance'
this.controlPanel.y.channel = 4
} else if (settingValue === 8) {
this.controlPanel.y.type = 'Phase'
this.controlPanel.y.channel = 7
} else if (settingValue === 9) {
this.controlPanel.y.type = 'Current'
this.controlPanel.y.channel = 8
} else if (settingValue === 10) {
this.controlPanel.y.type = 'Default'
this.controlPanel.y.channel = undefined
}
} else if (settingType === 'Elite') {
// 1: I, 2: V, 3: R
if (settingValue === 1) {
this.controlPanel.y.type = 'Current'
this.controlPanel.y.channel = 0
} else if (settingValue === 2) {
this.controlPanel.y.type = 'Voltage'
this.controlPanel.y.channel = 0
} else if (settingValue === 3) {
this.controlPanel.y.type = 'Resistance'
this.controlPanel.y.channel = 0
}
} else if (settingType === 'Time') {
this.controlPanel.y.type = 'Time'
this.controlPanel.y.channel = 0
}
}
this.refreshFormatter('x')
this.refreshFormatter('y')
this.$emit('changeFunctional', 'x', 'Linear')
this.$emit('changeFunctional', 'y', 'Linear')
this.$emit('changeAxis', 0)
this.$refs.specific_integral.checkMeaning(this.controlPanel.x.axis.description, this.controlPanel.y.axis.description)
this.$refs.specific_integral.setDisplayParam(this.controlPanel.x.axis.description, this.controlPanel.x.unit, this.controlPanel.y.axis.description, this.controlPanel.y.unit)
},
/* changeXXX: activate when pressing XXX button */
// trigger when changing the axis type
changeAxis (gridIndex) {
this.$refs.unit_x.init(this.controlPanel.x.type)
this.$refs.unit_y.init(this.controlPanel.y.type)
this.$refs.funct_x.init(this.controlPanel.x.type, this.controlPanel.y.type)
this.$refs.funct_y.init(this.controlPanel.x.type, this.controlPanel.y.type)
this.controlPanel.FSM = this.configRouter.getFSM(this.controlPanel.x.axis.description, this.controlPanel.y.axis.description)
// initialize other blocks
this.$refs.unit_x.init(this.controlPanel.x.axis.description)
this.$refs.unit_y.init(this.controlPanel.y.axis.description)
this.$refs.funct_x.init(this.controlPanel.x.axis.description, this.controlPanel.y.axis.description)
this.$refs.funct_y.init(this.controlPanel.x.axis.description, this.controlPanel.y.axis.description)
this.$refs.change_cycle.init()
this.refreshFormatter('x')
this.refreshFormatter('y')
this.$emit('changeFunctional', 'x', 'Linear')
this.$emit('changeFunctional', 'y', 'Linear')
this.$emit('changeAxis', gridIndex)
this.$refs.specific_integral.checkMean(this.controlPanel.x.type, this.controlPanel.x.funct, this.controlPanel.y.type, this.controlPanel.y.funct)
this.$refs.specific_integral.setDisplayParam(this.controlPanel.x.type, this.controlPanel.x.unit, this.controlPanel.y.type, this.controlPanel.y.unit)
this.$refs.specific_integral.checkMeaning(this.controlPanel.x.axis.description, this.controlPanel.y.axis.description)
this.$refs.specific_integral.setDisplayParam(this.controlPanel.x.axis.description, this.controlPanel.x.unit, this.controlPanel.y.axis.description, this.controlPanel.y.unit)
},
// trigger when changing the unit
changeUnit (axis) {
this.refreshFormatter(axis)
this.$refs.specific_integral.refreshDisplayParam(this.controlPanel.x.type, this.controlPanel.x.unit, this.controlPanel.y.type, this.controlPanel.y.unit)
changeUnit (coordinate) {
this.refreshFormatter(coordinate)
this.$refs.specific_integral.refreshDisplayParam(this.controlPanel.x.axis.description, this.controlPanel.x.unit, this.controlPanel.y.axis.description, this.controlPanel.y.unit)
},
// trigger when press the functional button
changeFunct (axis) {
this.refreshUnit()
this.refreshFormatter(axis)
this.$refs.specific_integral.checkMean(this.controlPanel.x.type, this.controlPanel.x.funct, this.controlPanel.y.type, this.controlPanel.y.funct)
this.$emit('changeFunctional', axis, this.controlPanel[axis].funct)
changeFunct (coordinate) {
if (coordinate === 'y') {
this.controlPanel.y.axis.description = this.controlPanel.FSM[this.controlPanel.y.funct]
this.$refs.unit_y.init(this.controlPanel.y.axis.description)
this.$refs.specific_integral.checkMeaning(this.controlPanel.x.axis.description, this.controlPanel.y.axis.description)
this.refreshFormatter(coordinate)
}
this.$emit('changeFunctional', coordinate, this.controlPanel[coordinate].funct)
this.$emit('changeAxis', 0)
},
/* refreshXXX: passively called by changeXXX function to refresh some setting */
// refresh axis type
refreshAxis () {
const xType = this.controlPanel.x.type
const yType = this.controlPanel.y.type
const xFunct = this.controlPanel.x.funct
const yFunct = this.controlPanel.y.funct
this.$refs.axis_x.refreshAxis(xType, xFunct, yType, yFunct)
this.$refs.axis_y.refreshAxis(xType, xFunct, yType, yFunct)
},
// refresh unit option
refreshUnit (axis) {
const xType = this.controlPanel.x.type
const yType = this.controlPanel.y.type
const xFunct = this.controlPanel.x.funct
const yFunct = this.controlPanel.y.funct
if (axis === 'x') {
this.$refs.unit_x.refreshUnit(xType, xFunct, yType, yFunct)
} else {
this.$refs.unit_y.refreshUnit(xType, xFunct, yType, yFunct)
}
},
// refresh all formatters of charts
refreshFormatter (axis) {
refreshFormatter (coordinate) {
this.updateAxisLabelChart({
chartID: 1,
axis: axis,
axis: coordinate,
type: this.controlPanel[coordinate].axis.description,
axisIndex: 0,
})
},
@@ -78,6 +78,7 @@ export default {
return sortedCycleList
},
init () {
this.showWhichCycles = '1'
this.cycleNum = this.metaList[this.metaIndex].parameter_set.CYCLE_NUMBER
const meta = this.metaList[this.metaIndex]
this.metaID = meta.id
@@ -90,9 +91,6 @@ export default {
this.showPanel = false
}
},
clear () {
this.showWhichCycles = '1'
},
async setCycle () {
if (this.isThisModeHasCycle === true) {
const dataCycleList = this.recInfo[this.metaID][this.cycleDataID][this.currentScale]
@@ -108,15 +106,14 @@ export default {
const cycleDict = this.getCycleDictRec()(cycleDataList)
this.cycleNum = Object.keys(cycleDict).length
let dataXList
if (this.controlPanel.x.type !== 'Time') {
dataXList = this.recInfo[this.metaID][this.controlPanel.x.channel][this.currentScale]
if (this.controlPanel.x.axis.description !== 'Time') {
dataXList = this.recInfo[this.metaID][this.controlPanel.x.axis.channel][this.currentScale]
}
const dataYList = this.recInfo[this.metaID][this.controlPanel.y.channel][this.currentScale]
const dataYList = this.recInfo[this.metaID][this.controlPanel.y.axis.channel][this.currentScale]
const filteredData = []
let counter = 0
for (let sliceIndex = 0; sliceIndex < this.cycleNum; sliceIndex++) {
// console.log(this.slices)
if (this.slices() === '' || this.slices().includes((sliceIndex + 1).toString())) {
// slice data
const value = cycleDict[sliceIndex + 1]
@@ -133,9 +130,9 @@ export default {
}
}
for (let i = startIndex; i <= endIndex; i++) {
const dataY = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataYList[i].id, this.controlPanel.y.channel, this.metaList[this.metaIndex])
if (this.controlPanel.x.type !== 'Time') {
const dataX = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataXList[i].id, this.controlPanel.x.channel, this.metaList[this.metaIndex])
const dataY = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataYList[i].id, this.controlPanel.y.axis.channel, this.metaList[this.metaIndex])
if (this.controlPanel.x.axis.description !== 'Time') {
const dataX = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataXList[i].id, this.controlPanel.x.axis.channel, this.metaList[this.metaIndex])
for (let j = 0, len = dataY.length; j < len; j++) {
if (parseInt(dataY[j][0]) >= startTime && parseInt(dataY[j][0]) <= endTime) {
filteredData.push([dataX[j][1], dataY[j][1]])
@@ -155,14 +152,13 @@ export default {
seriesIndex: this.metaIndex,
data: filteredData,
})
if (this.controlPanel.x.type === 'Time') {
if (this.controlPanel.x.axis.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])
}
}
}
@@ -181,11 +177,6 @@ export default {
...mapMutations('replay', [types.chart.updateSeries]),
...mapGetters('replay', [types.rec.getCycleDict]),
},
mounted () {
},
destroyed () {
},
}
</script>
@@ -1,10 +1,11 @@
<template>
<div>
<va-select
v-model="controlPanel[axis].type"
testBy="name"
v-model="controlPanel[coordinate].axis"
class="va-select-without-margin"
:options="typeOption"
:options="axisOption"
text-by="description"
key-by="description"
:noClear='true'
@input="changeAxis()"
/>
@@ -14,18 +15,20 @@
<script>
import { mapFields } from 'vuex-map-fields'
import { tableRouter } from '@/components/analysis/replay/toolbox/EliteReplayTable'
import configRouter from '@/components/analysis/replay/toolbox/configTable'
export default {
name: 'controlAxis',
props: {
axis: {
coordinate: {
type: String, // x or y
},
},
data () {
return {
typeOption: [],
axisOption: [],
tableRouter,
configRouter,
}
},
computed: {
@@ -34,38 +37,10 @@ export default {
]),
},
methods: {
init (type) {
if (this.axis === 'x') {
this.typeOption = [
'Time',
'Current',
'Voltage',
'Resistance',
]
} else {
this.typeOption = [
'Current',
'Voltage',
'Resistance',
]
}
// init call change Axis
if (this.axis === 'y') {
this.$emit('changeAxis', 0) // temporarily use metaIndex for gridIndex
}
},
refreshAxis (xType, xFunct, yType, yFunct) {
const [xTable, yTable] = this.tableRouter.getTable(xType, xFunct, yType, yFunct)
if (this.axis === 'x') {
this.controlPanel[this.axis].type = xTable.name
this.controlPanel[this.axis].channel = xTable.channel
} else {
this.controlPanel[this.axis].type = yTable.name
this.controlPanel[this.axis].channel = yTable.channel
}
init (library, settingType) {
this.axisOption = this.configRouter.getAxisOption(library, settingType, this.coordinate)
},
changeAxis () {
this.controlPanel[this.axis].channel = tableRouter.getChannel(this.controlPanel[this.axis].type)
this.$emit('changeAxis', 0)
},
},
@@ -2,8 +2,8 @@
<div class="flex row">
<va-radio-button
v-for="(funct, index) in functOption"
v-model="controlPanel[coordinate].funct"
:key="index"
v-model="controlPanel[axis].funct"
:option="funct"
@input="changeFunct()"
@@ -14,11 +14,12 @@
<script>
import { mapFields } from 'vuex-map-fields'
import { tableRouter } from '@/components/analysis/replay/toolbox/EliteReplayTable'
import configRouter from '@/components/analysis/replay/toolbox/configTable'
export default {
name: 'controlFuct',
name: 'controlFunct',
props: {
axis: {
coordinate: {
type: String, // x or y
},
},
@@ -27,6 +28,7 @@ export default {
funct: '',
functOption: [],
tableRouter,
configRouter,
}
},
computed: {
@@ -35,12 +37,12 @@ export default {
]),
},
methods: {
init (xAxis, yAixs) {
this.controlPanel[this.axis].funct = 'Linear'
this.functOption = this.tableRouter.getFunct(xAxis, yAixs, this.axis)
init (xAxis, yAxis) {
this.controlPanel[this.coordinate].funct = 'Linear'
this.functOption = this.configRouter.getFunctOption(xAxis, yAxis, this.coordinate)
},
changeFunct () {
this.$emit('changeFunct', this.axis)
this.$emit('changeFunct', this.coordinate)
},
},
}
@@ -1,11 +1,11 @@
<template>
<div>
<va-select
@input="changeUnit()"
v-model="controlPanel[axis].unit"
v-model="controlPanel[coordinate].unit"
class="va-select-without-margin"
:options="unitOption"
:noClear='true'
@input="changeUnit()"
/>
</div>
</template>
@@ -13,11 +13,12 @@
<script>
import { mapFields } from 'vuex-map-fields'
import { tableRouter } from '@/components/analysis/replay/toolbox/EliteReplayTable'
import configRouter from '@/components/analysis/replay/toolbox/configTable'
export default {
name: 'controlUnit',
props: {
axis: {
coordinate: {
type: String, // x or y
},
},
@@ -26,6 +27,7 @@ export default {
unit: '',
unitOption: [],
tableRouter,
configRouter,
}
},
computed: {
@@ -34,22 +36,12 @@ export default {
]),
},
methods: {
init (type) {
this.controlPanel[this.axis].unit = this.tableRouter.getDefaultUnit(type)
this.unitOption = Object.keys(this.tableRouter.getOption(type))
},
refreshUnit (xType, xFunct, yType, yFunct) {
const [xTable, yTable] = this.tableRouter.getTable(xType, xFunct, yType, yFunct)
if (this.axis === 'x') {
this.controlPanel[this.axis].unit = xTable.defaultUnit
this.unitOption = Object.keys(xTable.option)
} else {
this.controlPanel[this.axis].unit = yTable.defaultUnit
this.unitOption = Object.keys(yTable.option)
}
init (axis) {
this.controlPanel[this.coordinate].unit = this.configRouter.getUnit(axis)
this.unitOption = this.configRouter.getUnitOption(axis)
},
changeUnit () {
this.$emit('changeUnit', this.axis)
this.$emit('changeUnit', this.coordinate)
},
},
}
@@ -2,20 +2,24 @@
<div>
<div class="flex-container mb-2">
<div class="flex sm2 xl2 md2 xs2 px-0 py-0">
<p class="display-6" v-if="ifMean"> Area </p>
<p class="display-6" v-if="ifMeaning"> Area </p>
</div>
<div
class="row sm10 xl10 md10 xs10"
v-show="ifMean"
class="row flex sm10 xl10 md10 xs10"
v-show="ifMeaning"
>
<div class="flow xs6 sm6 lg6 xl6">
<div class="xs6 sm6 lg6 xl6">
<va-input
v-model="specificIntegral"
label="Integral value"
disabled
/>
>
<p slot="append" style="margin-right: 0;" small>
{{ integralResult }}
</p>
</va-input>
</div>
<div class="flow xs2 sm2 lg2 xl2">
<div class="xs2 sm2 lg2 xl2">
<va-select
v-model="integralUnit"
:options="integralOption"
@@ -88,6 +92,7 @@
<script>
import { tableRouter } from '@/components/analysis/replay/toolbox/EliteReplayTable'
import configRouter from '@/components/analysis/replay/toolbox/configTable'
export default {
name: 'SpecificIntegral',
data () {
@@ -101,26 +106,28 @@ export default {
yUnit: '',
xScale: '',
yScale: '',
integralResult: '',
integralUnit: '',
integralOption: [],
integralTable: {},
integralScale: '',
ifMean: true,
ifUserEnter: false,
ifMeaning: true,
ifUserKeyIn: false,
tableRouter,
configRouter,
}
},
methods: {
refreshScale () {
this.integralScale = this.integralTable.option[this.integralUnit]
this.integralScale = this.configRouter.getUnitScale(this.integralResult)[this.integralUnit]
},
userEnter () {
this.ifUserEnter = !this.ifUserEnter
this.ifUserKeyIn = !this.ifUserKeyIn
},
getSpecificIntegral (specificIntegral, boundary) {
this.specificIntegral = specificIntegral / this.integralScale
if (!this.ifUserEnter) {
if (!this.ifUserKeyIn) {
this.x_start = (boundary.x_start / this.xScale).toFixed(3)
this.x_end = (boundary.x_end / this.xScale).toFixed(3)
this.y_start = (boundary.y_start / this.yScale).toFixed(3)
@@ -128,6 +135,10 @@ export default {
}
},
setBrushBoundary () {
if (isNaN(this.x_start)) this.x_start = 0
if (isNaN(this.x_end)) this.x_start = 0
if (isNaN(this.xy_start)) this.y_start = 0
if (isNaN(this.y_end)) this.y_end = 0
var boundary = {
x_start: Number(this.x_start) * this.xScale,
x_end: Number(this.x_end) * this.xScale,
@@ -137,38 +148,29 @@ export default {
this.$emit('setBrushBoundary', boundary)
},
setDisplayParam (xAxis, xUnit, yAxis, yUnit) {
const xOption = this.tableRouter.getOption(xAxis)
const yOption = this.tableRouter.getOption(yAxis)
const xScaleOption = this.configRouter.getUnitScale(xAxis)
const yScaleOption = this.configRouter.getUnitScale(yAxis)
const integralResult = this.configRouter.getFSM(xAxis, yAxis).Integral
this.xUnit = xUnit
this.yUnit = yUnit
this.xScale = xOption[xUnit]
this.yScale = yOption[yUnit]
this.integralTable = this.tableRouter.getTable(xAxis, 'Linear', yAxis, 'Integral')
this.integralTable = this.integralTable[1]
this.integralOption = Object.keys(this.integralTable.option)
this.integralUnit = this.integralTable.defaultUnit
this.integralScale = this.integralTable.option[this.integralUnit]
this.xScale = xScaleOption[xUnit]
this.yScale = yScaleOption[yUnit]
this.integralResult = integralResult
this.integralUnit = this.configRouter.getUnit(integralResult)
this.integralOption = this.configRouter.getUnitOption(integralResult)
this.integralScale = this.configRouter.getUnitScale(integralResult)[this.integralUnit]
},
refreshDisplayParam (xAxis, xUnit, yAxis, yUnit) {
const xOption = this.tableRouter.getOption(xAxis)
const yOption = this.tableRouter.getOption(yAxis)
const xScaleOption = this.configRouter.getUnitScale(xAxis)
const yScaleOption = this.configRouter.getUnitScale(yAxis)
this.xUnit = xUnit
this.yUnit = yUnit
this.xScale = xOption[xUnit]
this.yScale = yOption[yUnit]
this.xScale = xScaleOption[xUnit]
this.yScale = yScaleOption[yUnit]
},
checkMean (xAxis, xFunct, yAxis, yFunct) {
if (yFunct === 'Integral' || yFunct === 'Differential') {
this.ifMean = false
} else {
if ((xAxis === 'Voltage' && yAxis === 'Current') ||
(xAxis === 'Current' && yAxis === 'Voltage') ||
(xAxis === 'Time' && yAxis === 'Current')) {
this.ifMean = true
} else {
this.ifMean = false
}
}
checkMeaning (xAxis, yAxis) {
const functOption = this.configRouter.getFunctOption(xAxis, yAxis)
this.ifMeaning = functOption.includes('Integral')
},
},
}
@@ -0,0 +1,405 @@
// object saving library name mapping table
const libraryNameMappingTable = {
EliteZM15: 'EliteEDC',
'Elite_EDC_1.4': null,
'Elite_EDC_1.5': 'EliteEDC',
'Elite_EDC_1.5re': 'EliteEDC',
'Elite_EDC_1.5r2': 'EliteEDC',
'Elite_BAT_1.0': 'EliteEDC',
'Elite_EIS_1.0': 'EliteEIS',
'Elite_EIS_1.1': 'EliteEIS',
'Elite_EIS_MINI_1.0': 'EliteEIS',
'Elite_TRIG_0.1': null,
'Elite_MEGAFLY_0.1': null,
}
// object saving setting type mapping table
const settingTypeMappingTable = {
EliteEDC: {
Time: {
description: 'Time',
channel: undefined,
},
Elite: {
1: {
description: 'Current',
channel: 0,
},
2: {
description: 'Voltage',
channel: 1,
},
3: {
description: 'Resistance',
channel: 2,
},
// 4: {
// description: 'Cycle',
// channel: 3,
// },
},
},
EliteEIS: {
Time: {
description: 'Time',
channel: undefined,
},
Elite: {
1: {
description: 'Current',
channel: 0,
},
2: {
description: 'Voltage',
channel: 1,
},
3: {
description: 'Resistance',
channel: 2,
},
},
EliteEIS: {
3: {
description: 'Frequency',
channel: 2,
},
5: {
description: 'Z_imag',
channel: 4,
},
6: {
description: 'Z_real',
channel: 5,
},
7: {
description: 'Impedance',
channel: 6,
},
8: {
description: 'Phase',
channel: 7,
},
9: {
description: 'Current',
channel: 8,
},
10: {
description: 'Gain_Level',
channel: 9,
},
},
},
}
// object saving unit information mapping table
const unitInfoMappingTable = {
// Time
Time: {
name: 'Time',
channel: -1,
option: {
auto: 1,
us: 1,
ms: 1e3,
s: 1e6,
min: 60 * 1e6,
hour: 3600 * 1e6,
},
defaultUnit: 'auto',
downloadUnit: 'auto',
},
// Elite
Current: {
name: 'Current',
channel: 0,
option: {
nA: 1,
uA: 1e3,
mA: 1e6,
A: 1e9,
},
defaultUnit: 'mA',
downloadUnit: 'A',
},
Voltage: {
name: 'Voltage',
channel: 1,
option: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'V',
},
Resistance: {
name: 'Resistance',
channel: 2,
option: {
: 1,
Ω: 1e3,
: 1e6,
: 1e9,
},
defaultUnit: 'Ω',
downloadUnit: 'Ω',
},
// Elite after Integral
Charge: {
name: 'Charge',
channel: -1,
option: {
nAh: 3600 * 1e6,
uAh: 1600 * 1e9,
mAh: 3600 * 1e12,
Ah: 3600 * 1e15,
},
defaultUnit: 'mAh',
downloadUnit: 'mAh',
},
Power: {
name: 'Power',
channel: -1,
option: {
mW: 1e12,
W: 1e15,
kW: 1e18,
},
defaultUnit: 'W',
downloadUnit: 'W',
},
// Elite after Differential
Transconductance: {
name: 'Transconductance',
channel: -1,
option: {
'mA/V': 1,
'A/V': 1e3,
'kA/V': 1e6,
},
defaultUnit: 'A/V',
downloadUnit: 'A/V',
},
// EliteEIS
Frequency: {
name: 'Frequency',
chanel: 2,
option: {
mHz: 1,
Hz: 1e3,
kHz: 1e6,
MHz: 1e9,
},
downloadUnit: 'Hz',
defaultUnit: 'Hz',
},
Z_imag: {
name: 'Z_imag',
chanel: 4,
option: {
: 1e-3,
Ω: 1,
: 1e3,
: 1e6,
},
downloadUnit: 'Ω',
defaultUnit: 'Ω',
},
Z_real: {
name: 'Z_real',
chanel: 5,
option: {
: 1e-3,
Ω: 1,
: 1e3,
: 1e6,
},
downloadUnit: 'Ω',
defaultUnit: 'Ω',
},
Impedance: {
name: 'Impedance',
chanel: 6,
option: {
: 1e-3,
Ω: 1,
: 1e3,
: 1e6,
},
downloadUnit: 'Ω',
defaultUnit: 'Ω',
},
Phase: {
name: 'Phase',
chanel: 7,
option: {
'°': 1,
},
downloadUnit: '°',
defaultUnit: '°',
},
Gain_Level: {
name: 'Gain Level',
chanel: 9,
option: {
'#': 1,
},
downloadUnit: '#',
defaultUnit: '#',
},
undefined: {
name: 'not support',
channel: -1,
option: {
none: 1,
},
defaultUnit: 'none',
downloadUnit: 'none',
},
}
// object saving specific functional information mapping table
const functInfoMappingTable = {
// Time
Time: {
},
// Elite
Current: {
Time: {
Linear: 'Current',
Log: 'Current',
Integral: 'Charge',
},
Voltage: {
Linear: 'Current',
Log: 'Current',
Integral: 'Power',
Differential: 'Impedance',
},
},
Voltage: {
Current: {
Linear: 'Voltage',
Log: 'Voltage',
Integral: 'Power',
Differential: 'Transconductance',
},
},
Resistance: {
},
// EliteEIS
Frequency: {
},
Z_imag: {
},
Z_real: {
},
Impedance: {
},
Phase: {
},
Gain_Level: {
},
None: {
},
}
/**
* return axis description and channel by library, type and index
* @param {String} library
* @param {String} type
* @param {String} index
* @returns {Object} : configuration
*/
function getAxis (library, type, index) {
// some physical property || Time
return settingTypeMappingTable[libraryNameMappingTable[library]][type][index] || settingTypeMappingTable[libraryNameMappingTable[library]][type]
}
/**
* retrun default unit by physical property
* @param {String} axis
* @returns {Object} : unit
*/
function getUnit (axis) {
return unitInfoMappingTable[axis].defaultUnit
}
/**
* return axis option by library, type
* @param {String} library
* @param {String} type
* @param {String} coordinate
* @returns {Object} : axisOption
*/
function getAxisOption (library, type, coordinate) {
if (type === 'Time') type = 'Elite'
const axisOption = Object.values(settingTypeMappingTable[libraryNameMappingTable[library]][type]).map((setting) => {
return setting
})
if (coordinate === 'x') {
axisOption.unshift({
description: 'Time',
channel: undefined,
})
}
return axisOption
}
/**
* retrun option of unit by physical property
* @param {String} axis
* @returns {Object} : unitOption
*/
function getUnitOption (axis) {
return Object.keys(unitInfoMappingTable[axis].option)
}
/**
* retrun a dictionary of scale corresponding to unit by physical property
* @param {String} axis
* @returns {Object} : unitScale
*/
function getUnitScale (axis) {
return unitInfoMappingTable[axis].option
}
/**
* retrun option of functionl by both axis physical property
* @param {String} xAxis
* @param {String} yAxis
* @param {String} coordinate
* @returns {Object} : functOption
*/
function getFunctOption (xAxis, yAxis, coordinate) {
if (coordinate === 'x') return ['Linear', 'Log']
else if (functInfoMappingTable[yAxis] === undefined) return ['Linear', 'Log']
else if (functInfoMappingTable[yAxis][xAxis] === undefined) return ['Linear', 'Log']
else return Object.keys(functInfoMappingTable[yAxis][xAxis])
}
/**
* retrun functional correponding physics property
* @param {String} xAxis
* @param {String} yAxis
* @returns {Object} : functOption
*/
function getFSM (xAxis, yAxis) {
return functInfoMappingTable[yAxis][xAxis] || {
Linear: yAxis,
Log: yAxis,
}
}
const configRouter = {
getAxis,
getUnit,
getAxisOption,
getUnitOption,
getUnitScale,
getFunctOption,
getFSM,
}
export default configRouter
+1 -1
View File
@@ -1,6 +1,5 @@
<template>
<div class="devices-overview">
<div >
<va-card
v-for="controller in controllerList" :key="controller.id"
@@ -518,6 +517,7 @@ export default {
async mounted () {
await taskInfo.updateTaskInfo()
await this.getControllerList()
this.GLOBAL.refreshCache()
this.pageMqttSub()
this.pageInitPub()
+177 -172
View File
@@ -1,15 +1,5 @@
<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>
@@ -17,7 +7,6 @@
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'
@@ -27,11 +16,17 @@ import configTable from '@/data/config-table/index'
export default {
name: 'Download',
components: {
FulfillingBouncingCircleSpinner,
},
data: () => {
return {
controllerList: [],
downloadList: [],
format: 'excel',
channel: '',
metaListNew: [],
downloading: false,
fileNums: 0,
count: 0,
}
},
computed: {
@@ -67,6 +62,172 @@ export default {
}
return results
},
writeFiles: async function () {
if (this.metaListNew.length !== 0 && this.downloading === false) {
this.downloading = true
let meta
const metaID = this.metaListNew.pop()
const ret = await api.meta.getByID(metaID)
if (ret.status === 200) {
meta = ret.data[0]
}
if (meta !== undefined) {
this.metaInfo = meta
const channelParamObj = configTable.getModeConfig(meta.device.library_name, meta.parameter_set.MODE).channels
const channelArray = this.channel === 'all' ? JSON.parse(this.metaInfo.channels) : Object.keys(channelParamObj).filter(ele => ele !== 'time')
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 = this.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.size = parseInt(parseInt(meta.size) / (76 * (maxSplitFiles)))
} else {
this.downloadInfo.filename = meta.name
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
let columnNum = 0
const requestArray = []
console.time('download')
// console.log(this.downloadInfo)
while (rowIndex - 10 < this.downloadInfo.maxRows) {
// console.log('rowIndex < this.downloadInfo.maxRows', rowIndex, this.downloadInfo.maxRows)
for (const channel of this.downloadInfo.channel) {
columnNum = this.downloadInfo.channelInfo[channel].downloadIDList.length
for (const idx in this.downloadInfo.channelInfo[channel].downloadIDList) {
const _idx = parseInt(idx)
if (this.downloadInfo.channelInfo[channel].downloadDataBuffer[idx] === undefined) {
this.downloadInfo.channelInfo[channel].downloadDataBuffer[idx] = []
}
// const rawID = this.downloadInfo.channelInfo[channel].downloadIDList[_idx][rowIndex]
const rawIDList = this.downloadInfo.channelInfo[channel].downloadIDList[_idx].slice(rowIndex, rowIndex + 10)
// console.log(channel, rawIDList)
rawIDList.length > 0 && requestArray.push(api.raw.getAttrByIDs(channel, rawIDList, 'id-channel-size-serial_number-start_time-end_time-data'))
if (rawIDList.length === 0) columnNum -= 1
}
}
const responseArray = await Promise.all(requestArray)
for (const responseIndex in responseArray) {
const response = responseArray[responseIndex]
// console.log('response', response)
const idx = responseIndex % columnNum
for (const data of response.data) {
const timeUnitScale = channelParamObj.time.unit[channelParamObj.time.downloadUnit]
const channelUnitScale = channelParamObj[data.channel]?.unit[channelParamObj[data.channel]?.downloadUnit]
// console.log('data', data)
const dataArray = data.data.split('"***"').slice(0, -1)
// console.log('dataArray', dataArray)
for (const raw of dataArray) {
const rawArray = raw.split(' ')
const newArray = rawArray[0] === '' ? [] : rawArray.map((ele, index) => {
// console.log((parseInt(ele) / timeUnitScale).toFixed(Math.log10(timeUnitScale)))
return (index % 2 === 0) ? String((parseInt(ele) / timeUnitScale).toFixed(Math.log10(timeUnitScale))) : channelUnitScale ? String((parseInt(ele) / channelUnitScale).toFixed(Math.log10(channelUnitScale))) : ele
})
this.downloadInfo.channelInfo[data.channel].downloadDataBuffer[idx].push(...newArray)
// console.log('rawArray', rawArray)
}
}
}
requestArray.length = 0
// console.log('this.downloadInfo.channelInfo', this.downloadInfo.channelInfo)
// console.log('this.downloadInfo.maxRows', this.downloadInfo.maxRows)
await this.setDataExport({ last: (rowIndex >= this.downloadInfo.maxRows - 1) })
rowIndex += 10
}
this.closeWriterDownload()
fileIndex += 1
}
console.timeEnd('download')
}
}
this.count += 1
this.downloading = false
this.$emit('download-finish')
if (this.fileNums === 1) {
this.showToast('Download Finish', {
position: 'bottom-right',
})
} else {
this.showToast(`${this.count} / ${this.fileNums} Finish`, {
position: 'bottom-right',
})
}
}
},
...mapActions('download',
[
types.raw.rawDataByID,
@@ -93,169 +254,13 @@ export default {
async mounted () {
await this.getControllerList()
// TODO authorization
const format = this.$route.params.format.split('-')[0]
const allChannel = this.$route.params.format.split('-')[1]
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 channelParamObj = configTable.getModeConfig(meta.device.library_name, meta.parameter_set.MODE).channels
const channelArray = allChannel === 'all' ? JSON.parse(this.metaInfo.channels) : Object.keys(channelParamObj).filter(ele => ele !== 'time')
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
let columnNum = 0
const requestArray = []
console.time('download')
// console.log(this.downloadInfo)
while (rowIndex - 10 < this.downloadInfo.maxRows) {
// console.log('rowIndex < this.downloadInfo.maxRows', rowIndex, this.downloadInfo.maxRows)
for (const channel of this.downloadInfo.channel) {
columnNum = this.downloadInfo.channelInfo[channel].downloadIDList.length
for (const idx in this.downloadInfo.channelInfo[channel].downloadIDList) {
const _idx = parseInt(idx)
if (this.downloadInfo.channelInfo[channel].downloadDataBuffer[idx] === undefined) {
this.downloadInfo.channelInfo[channel].downloadDataBuffer[idx] = []
}
// const rawID = this.downloadInfo.channelInfo[channel].downloadIDList[_idx][rowIndex]
const rawIDList = this.downloadInfo.channelInfo[channel].downloadIDList[_idx].slice(rowIndex, rowIndex + 10)
// console.log(channel, rawIDList)
rawIDList.length > 0 && requestArray.push(api.raw.getAttrByIDs(channel, rawIDList, 'id-channel-size-serial_number-start_time-end_time-data'))
if (rawIDList.length === 0) columnNum -= 1
}
}
const responseArray = await Promise.all(requestArray)
// console.log('responseArray', responseArray)
for (const responseIndex in responseArray) {
const response = responseArray[responseIndex]
// console.log('response', response)
const idx = responseIndex % columnNum
for (const data of response.data) {
const timeUnitScale = channelParamObj.time.unit[channelParamObj.time.downloadUnit]
const channelUnitScale = channelParamObj[data.channel]?.unit[channelParamObj[data.channel]?.downloadUnit]
// console.log('data', data)
const dataArray = data.data.split('"***"').slice(0, -1)
// console.log('dataArray', dataArray)
for (const raw of dataArray) {
const rawArray = raw.split(' ')
const newArray = rawArray[0] === '' ? [] : rawArray.map((ele, index) => {
// console.log((parseInt(ele) / timeUnitScale).toFixed(Math.log10(timeUnitScale)))
return (index % 2 === 0) ? String((parseInt(ele) / timeUnitScale).toFixed(Math.log10(timeUnitScale))) : channelUnitScale ? String((parseInt(ele) / channelUnitScale).toFixed(Math.log10(channelUnitScale))) : ele
})
this.downloadInfo.channelInfo[data.channel].downloadDataBuffer[idx].push(...newArray)
// console.log('rawArray', rawArray)
}
}
}
requestArray.length = 0
// console.log('this.downloadInfo.channelInfo', this.downloadInfo.channelInfo)
// console.log('this.downloadInfo.maxRows', this.downloadInfo.maxRows)
await this.setDataExport({ last: (rowIndex >= this.downloadInfo.maxRows - 1) })
rowIndex += 10
}
this.closeWriterDownload()
fileIndex += 1
}
console.timeEnd('download')
}
}
}
await new Promise(resolve => setTimeout(resolve, 2000)) // sleep 2s prevent window close
window.close()
// await new Promise(resolve => setTimeout(resolve, 2000)) // sleep 2s prevent window close
// window.close()
setInterval(this.writeFiles, 1000)
},
destroyed () {
this.pageMqttUnSub()
// this.pageMqttUnSub()
},
}
</script>
+158 -170
View File
@@ -1,18 +1,8 @@
<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>
<progress-modal
:ref="'progressModalRef'"
/>
</div>
</template>
@@ -20,7 +10,6 @@
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'
@@ -31,12 +20,18 @@ import configTable from '@/data/config-table/index'
export default {
name: 'DownloadOffline',
components: {
FulfillingBouncingCircleSpinner,
progressModal,
},
data: () => {
return {
controllerList: [],
downloadList: [],
format: 'excel',
channel: '',
metaListNew: [],
downloading: false,
fileNums: 0,
count: 0,
}
},
computed: {
@@ -72,6 +67,153 @@ export default {
}
return results
},
writeFiles: async function () {
if (this.metaListNew.length !== 0 && this.downloading === false) {
let meta
const metaID = this.metaListNew.pop()
const ret = await api.meta.getByID(metaID)
if (ret.status === 200) {
meta = ret.data[0]
}
if (meta !== undefined) {
this.metaInfo = meta
const channelParamObj = configTable.getModeConfig(meta.device.library_name, meta.parameter_set.MODE).channels
const channelArray = this.channel === 'all' ? JSON.parse(this.metaInfo.channels) : Object.keys(channelParamObj).filter(ele => ele !== 'time')
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 = 10000
}
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 = this.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.format
this.downloadInfo.size = parseInt(parseInt(meta.size) / 76)
} else {
this.downloadInfo.filename = meta.name + '-' + this.format
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
let columnNum = 0
const requestArray = []
console.time('download')
while (rowIndex - 10 < this.downloadInfo.maxRows) {
this.$refs.progressModalRef.setValue(parseInt((rowIndex / this.downloadInfo.maxRows) * 100))
// console.log('rowIndex < this.downloadInfo.maxRows', rowIndex, this.downloadInfo.maxRows)
for (const channel of this.downloadInfo.channel) {
columnNum = this.downloadInfo.channelInfo[channel].downloadIDList.length
for (const idx in this.downloadInfo.channelInfo[channel].downloadIDList) {
const _idx = parseInt(idx)
if (this.downloadInfo.channelInfo[channel].downloadDataBuffer[idx] === undefined) {
this.downloadInfo.channelInfo[channel].downloadDataBuffer[idx] = []
}
// const rawID = this.downloadInfo.channelInfo[channel].downloadIDList[_idx][rowIndex]
const rawIDList = this.downloadInfo.channelInfo[channel].downloadIDList[_idx].slice(rowIndex, rowIndex + 10)
// console.log(channel, rawIDList)
rawIDList.length > 0 && requestArray.push(api.raw.getAttrByIDs(channel, rawIDList, 'id-channel-size-serial_number-start_time-end_time-data'))
if (rawIDList.length === 0) columnNum -= 1
}
}
const responseArray = await Promise.all(requestArray)
// console.log('responseArray', responseArray)
for (const responseIndex in responseArray) {
const response = responseArray[responseIndex]
// console.log('response', response)
const idx = responseIndex % columnNum
// console.log('response', response)
for (const data of response.data) {
const timeUnitScale = channelParamObj.time.unit[channelParamObj.time.downloadUnit]
const channelUnitScale = channelParamObj[data.channel]?.unit[channelParamObj[data.channel]?.downloadUnit]
// console.log('data', data)
const dataArray = data.data.split('"***"').slice(0, -1)
// console.log('dataArray', dataArray)
for (const raw of dataArray) {
const rawArray = raw.split(' ')
const newArray = rawArray[0] === '' ? [] : rawArray.map((ele, index) => {
return (index % 2 === 0) ? String((parseInt(ele) / timeUnitScale).toFixed(Math.log10(timeUnitScale))) : channelUnitScale ? String((parseInt(ele) / channelUnitScale).toFixed(Math.log10(channelUnitScale))) : ele
})
this.downloadInfo.channelInfo[data.channel].downloadDataBuffer[idx].push(...newArray)
// console.log('rawArray', rawArray)
}
}
}
requestArray.length = 0
// console.log('this.downloadInfo.channelInfo', this.downloadInfo.channelInfo)
// console.log('this.downloadInfo.maxRows', this.downloadInfo.maxRows)
// await this.setDataExport({ last: (rowIndex >= this.downloadInfo.maxRows - 1) })
rowIndex += 10
}
await this.setAllExport({ last: (rowIndex >= this.downloadInfo.maxRows - 1) })
this.$refs.progressModalRef.setValue(100)
}
}
}
}
},
...mapActions('download',
[
types.raw.rawDataByID,
@@ -97,161 +239,7 @@ export default {
},
async mounted () {
await this.getControllerList()
// TODO authorization
const format = this.$route.params.format.split('-')[0]
const allChannel = this.$route.params.format.split('-')[1]
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 channelParamObj = configTable.getModeConfig(meta.device.library_name, meta.parameter_set.MODE).channels
const channelArray = allChannel === 'all' ? JSON.parse(this.metaInfo.channels) : Object.keys(channelParamObj).filter(ele => ele !== 'time')
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 = 10000
}
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
let columnNum = 0
const requestArray = []
console.time('download')
while (rowIndex - 10 < this.downloadInfo.maxRows) {
this.$refs.progressModalRef.setValue(parseInt((rowIndex / this.downloadInfo.maxRows) * 100))
// console.log('rowIndex < this.downloadInfo.maxRows', rowIndex, this.downloadInfo.maxRows)
for (const channel of this.downloadInfo.channel) {
columnNum = this.downloadInfo.channelInfo[channel].downloadIDList.length
for (const idx in this.downloadInfo.channelInfo[channel].downloadIDList) {
const _idx = parseInt(idx)
if (this.downloadInfo.channelInfo[channel].downloadDataBuffer[idx] === undefined) {
this.downloadInfo.channelInfo[channel].downloadDataBuffer[idx] = []
}
// const rawID = this.downloadInfo.channelInfo[channel].downloadIDList[_idx][rowIndex]
const rawIDList = this.downloadInfo.channelInfo[channel].downloadIDList[_idx].slice(rowIndex, rowIndex + 10)
// console.log(channel, rawIDList)
rawIDList.length > 0 && requestArray.push(api.raw.getAttrByIDs(channel, rawIDList, 'id-channel-size-serial_number-start_time-end_time-data'))
if (rawIDList.length === 0) columnNum -= 1
}
}
const responseArray = await Promise.all(requestArray)
// console.log('responseArray', responseArray)
for (const responseIndex in responseArray) {
const response = responseArray[responseIndex]
// console.log('response', response)
const idx = responseIndex % columnNum
// console.log('response', response)
for (const data of response.data) {
const timeUnitScale = channelParamObj.time.unit[channelParamObj.time.downloadUnit]
const channelUnitScale = channelParamObj[data.channel]?.unit[channelParamObj[data.channel]?.downloadUnit]
// console.log('data', data)
const dataArray = data.data.split('"***"').slice(0, -1)
// console.log('dataArray', dataArray)
for (const raw of dataArray) {
const rawArray = raw.split(' ')
const newArray = rawArray[0] === '' ? [] : rawArray.map((ele, index) => {
return (index % 2 === 0) ? String((parseInt(ele) / timeUnitScale).toFixed(Math.log10(timeUnitScale))) : channelUnitScale ? String((parseInt(ele) / channelUnitScale).toFixed(Math.log10(channelUnitScale))) : ele
})
this.downloadInfo.channelInfo[data.channel].downloadDataBuffer[idx].push(...newArray)
// console.log('rawArray', rawArray)
}
}
}
requestArray.length = 0
// console.log('this.downloadInfo.channelInfo', this.downloadInfo.channelInfo)
// console.log('this.downloadInfo.maxRows', this.downloadInfo.maxRows)
// await this.setDataExport({ last: (rowIndex >= this.downloadInfo.maxRows - 1) })
rowIndex += 10
}
await this.setAllExport({ last: (rowIndex >= this.downloadInfo.maxRows - 1) })
this.$refs.progressModalRef.setValue(100)
}
}
}
}
await new Promise(resolve => setTimeout(resolve, 2000)) // sleep
window.close()
setInterval(this.writeFiles, 1000)
},
destroyed () {
},
+377 -149
View File
@@ -1,5 +1,10 @@
<template>
<div class="file-list">
<div class="file-list" @mousedown="unSelectAll">
<!-- Move Folder Modal -->
<download ref="download_ref"></download>
<download-offline ref="download_offline_ref"></download-offline>
<folder-modal ref="folder_modal_ref" @refreshPage="refreshPage"></folder-modal>
<!-- Create Folder Modal -->
<va-modal
class="flex sm12 xl12 md12 xs12"
v-model="showModal.createFolder"
@@ -20,7 +25,7 @@
removable
/>
</va-modal>
<!-- Edit File Modal -->
<va-modal
class="flex sm12 xl12 md12 xs12"
v-model="showModal.editFile"
@@ -33,6 +38,7 @@
editFile()
showModal.editFile = false
}"
:noOutsideDismiss="true"
tabindex="0"
>
<va-input
@@ -47,6 +53,7 @@
removable
/>
</va-modal>
<!-- Delete File Modal-->
<va-modal
v-model="showModal.deleteFile"
size="small"
@@ -63,6 +70,7 @@
<p>Delete File {{ deleteInfo.name }} ? <input type="text" :ref="'delete_input'" style="opacity: 0; line-height: 0;"/></p>
</va-modal>
<!-- Delete MultiFiles Modal -->
<va-modal
v-model="showModal.deleteMultiFiles"
size="small"
@@ -80,17 +88,6 @@
</va-modal>
<va-card class="flex sm12 xl12 md12 xs12">
<template slot="header">
<div class="flex sm12 xl12 md12 xs12" style="text-align: end;">
<va-button class="" color="success" v-if="selected.length" @click="downloadSelected" target="_blank" small>
DOWNLOAD
</va-button>
<va-button class="" color="danger" v-if="selected.length" @click="deleteMultiFilesConfirm" target="_blank" small>
DELETE
</va-button>
</div>
</template>
<!-- SearchField & perPageSelect-->
<div class="row align--center">
<div class="flex xs12 md6">
@@ -115,32 +112,46 @@
</div>
<!-- CreateFolder & FilePath -->
<div class="flex mb-4">
<va-icon
name="fa fa-plus"
size="1rem"
class="mr-2"
style="cursor: pointer;"
:color="'primary'"
@click.native="createFolderConfirm"
/>
<va-icon
name="fa fa-folder-open"
size="0.9rem"
class="mr-2"
style="cursor: pointer;"
:color="(currentPathIndex === -1)?'primary':'dark'"
@click.native="openHome"
/>
<span
class="mt-0 mb-0 mr-2"
v-for="(item, index) in pathLists" :key="index"
:style="{ color:(currentPathIndex === index)?'#6c7fee':'#34495e', cursor:'pointer'}"
@click="openPath(item,index)"
>
<span class="mr-1" style="color: #34495e; cursor: default;">/</span>
{{ item.name }}
</span>
<div class="row">
<div class="flex d-flex xl8 lg8 sm8 xs8" style="align-items: center;">
<div>
<va-icon
name="fa fa-plus"
size="1rem"
class="mr-2"
style="cursor: pointer;"
:color="'primary'"
@click.native="createFolderConfirm"
/>
<va-icon
name="fa fa-folder-open"
size="0.9rem"
class="mr-2"
style="cursor: pointer;"
:color="(currentPathIndex === -1)?'primary':'dark'"
/>
<span
class="mt-0 mb-0 mr-2"
v-for="(item, index) in pathLists" :key="index"
:style="{ color:(currentPathIndex === index)?'#6c7fee':'#34495e', cursor:'pointer'}"
@click="openPath(item,index)"
>
<span class="mr-1" style="color: #34495e; cursor: default;">/</span>
{{ item.name }}
</span>
</div>
</div>
<div class="flex xl4 lg4 sm4 xs4" style="text-align: end;">
<va-button class="" color="primary" @mousedown.stop="showFolderModal" target="_blank" small>
MOVE
</va-button>
<va-button class="" color="success" @mousedown.stop="downloadSelected" target="_blank" small>
DOWNLOAD
</va-button>
<va-button class="" color="danger" @mousedown.stop="deleteMultiFilesConfirm" target="_blank" small>
DELETE
</va-button>
</div>
</div>
<!-- FileListTable -->
@@ -159,14 +170,16 @@
:fields="fields"
:data="filteredData"
:per-page="parseInt(perPage)"
@row-clicked="openFile"
@row-clicked="clickRow"
@mouseup.native="mouseUp"
@mousedown.native.stop="mouseDown"
hoverable
clickable
v-else
:ref="'datatable_ref'"
v-else
>
<template slot="select" slot-scope="props">
<va-checkbox :value="props.rowData.checked" @input="select(props.rowData)"/>
<va-checkbox :value="props.rowData.checked"/>
</template>
<template slot="name" slot-scope="props">
<va-icon
@@ -179,7 +192,7 @@
{{ props.rowData.name }}
</template>
<template slot="parameter_set" slot-scope="props">
{{ (props.rowData.type==='folder') ? '' : getWorkingMode(props.rowData.device.library_name, props.rowData.parameter_set.MODE) }}
{{ getWorkingMode(props.rowData.device, props.rowData.parameter_set) }}
</template>
<template slot="created_at" slot-scope="props">
{{transDate(props.rowData.created_at)}}
@@ -194,7 +207,7 @@
{{transDeviceInfo(props.rowData.device)}}
</template>
<template slot="actions" slot-scope="props" >
<va-popover :message="`sdcard ${props.rowData.name}`" placement="top">
<!-- <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"
@@ -203,26 +216,26 @@
@refreshPage="refreshPage"
@downloadSdCard="downloadSdCard"
/>
</va-popover>
<va-popover :message="`download ${props.rowData.name} in csv format`" placement="top">
</va-popover> -->
<va-popover :message="`Download csv`" placement="top">
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Neulive') >= 0" @click.stop="downloadCsv(props.rowData)"/>
</va-popover>
<va-popover :message="`download ${props.rowData.name} in excel format`" placement="top">
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Elite') >= 0" @click.stop="downloadExcel(props.rowData)"/>
<va-popover :message="`Download excel`" placement="top">
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Elite') >= 0" @click.stop="newDownload(props.rowData)"/>
</va-popover>
<va-popover :message="`download ${props.rowData.name} in csv-edf format`" placement="top">
<va-popover :message="`Download edf`" 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-popover :message="`Replay`" 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-popover :message="`Spike`" 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-popover :message="`Edit`" placement="top">
<va-button flat small color="gray" icon="fa fa-pencil" @click.stop="editFileConfirm(props.rowData)"/>
</va-popover>
<va-popover :message="`delete ${props.rowData.name}`" placement="top">
<va-popover :message="`Delete`" placement="top">
<va-button flat small color="gray" icon="fa fa-trash" @click.stop="deleteFileConfirm(props.rowData)"/>
</va-popover>
</template>
@@ -236,19 +249,25 @@ 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'
// import SdCardButton from '../sdcard/SdCardButton.vue'
import configTable from '@/data/config-table/index.js'
import FolderModal from './FolderModal.vue'
import Download from '../../download/Download.vue'
import DownloadOffline from '../../download/DownloadOffline.vue'
export default {
name: 'FileTable',
components: {
FulfillingBouncingCircleSpinner,
SdCardButton,
// SdCardButton,
FolderModal,
Download,
DownloadOffline,
},
data () {
return {
term: null,
perPage: '80',
perPage: '40',
perPageOptions: ['20', '40', '80', '160'],
fileLists: [],
@@ -295,6 +314,18 @@ export default {
},
SDuuidList: [],
controllerList: [],
// mouse click times
clickCounter: 0,
// record the selected index
clickRecord: [],
// record the target
clickTarget: null,
// mouseup or not
clickStatus: false,
// record shift+click target
shiftIndexRecord: null,
downloadIDList: [],
}
},
computed: {
@@ -371,6 +402,9 @@ export default {
}
})
},
selectedNumber () {
return this.fileLists.filter(file => file.checked).length
},
selected () {
return this.fileLists.filter(file => file.checked)
},
@@ -379,20 +413,28 @@ export default {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
// stopEvent: function (e) {
// console.log(e)
// e.stopPropagation()
// },
select: function (file) {
event.stopPropagation()
const idx = this.fileLists.findIndex(f => f.id === file.id)
showFolderModal: async function () {
this.$refs.folder_modal_ref.selected = this.selected
await this.$refs.folder_modal_ref.refreshCollection()
this.$refs.folder_modal_ref.showModal = true
},
unSelectAll: function () {
this.fileLists.forEach(element => {
element.checked = false
})
},
selectConcat: function (idx) {
this.fileLists[idx].checked = !this.fileLists[idx].checked
},
select: function (idx) {
this.unSelectAll()
this.fileLists[idx].checked = true
},
search: debounce(function (term) {
this.term = term
}, 400),
transFileSize: function (fileSize) {
if (fileSize === undefined) {
if (fileSize === undefined || fileSize === -1) {
return '--'
} else {
return this.GLOBAL.transFileSize(fileSize)
@@ -415,7 +457,98 @@ export default {
return device.device_name + '\n' + this.GLOBAL.transMac(device.device_address)
}
},
clickRow: async function (rowData) {
this.clickCounter += 1
setTimeout(() => { this.clickCounter = 0 }, 500)
if (window.getSelection().toString() !== '' && this.clickEvent.shiftKey === false && this.clickCounter !== 2) return true
window.getSelection().removeAllRanges()
// click target id
const idx = this.fileLists.findIndex(f => f.id === rowData.id)
setTimeout(async () => {
let timeOutTimer
// single click
if (this.clickCounter === 1) {
// meta key or ctrl key
if (this.clickEvent.metaKey === true || this.clickEvent.ctrlKey === true) {
this.selectConcat(idx)
if (this.clickRecord.includes(idx) === false) {
this.clickRecord.push(idx)
}
this.shiftIndexRecord = null
} else if (this.clickEvent.shiftKey === true) {
// shift key
const start = this.clickRecord[this.clickRecord.length - 1]
const end = idx
// if has shift event has trigger before then reset the checked
if (this.shiftIndexRecord !== null) {
if (start > this.shiftIndexRecord) {
for (let i = start; i >= this.shiftIndexRecord; i--) {
this.fileLists[i].checked = false
}
}
if (start < this.shiftIndexRecord) {
for (let i = start; i <= this.shiftIndexRecord; i++) {
this.fileLists[i].checked = false
}
}
}
if (start > end) {
for (let i = start; i >= end; i--) {
this.fileLists[i].checked = true
}
}
if (start < end) {
for (let i = start; i <= end; i++) {
this.fileLists[i].checked = true
}
}
this.shiftIndexRecord = idx
} else {
// without any hotKey
this.shiftIndexRecord = null
this.clickRecord.length = 0
this.selectConcat(idx)
if (this.clickRecord.includes(idx) === false) {
this.clickRecord.push(idx)
}
}
timeOutTimer = setTimeout(() => {
this.clickCounter = 0
}, 300)
} else if (this.clickCounter === 2) {
clearTimeout(timeOutTimer)
this.clickCounter = 0
await this.openFile(rowData)
}
}, 0)
},
mouseDown: async function (e) {
this.clickEvent = e
this.clickStatus = true
},
mouseUp: function () {
this.clickStatus = false
},
mouseMove: async function (e, rowData) {
const idx = this.fileLists.findIndex(f => f.id === rowData.id)
if (e.metaKey === true || e.ctrlKey === true) {
if (this.clickStatus === true) {
const indexOfRecord = this.clickRecord.indexOf(idx)
// if (indexOfRecord === this.clickRecord.length - 1) return
// console.log('indexOfRecord', indexOfRecord)
if (indexOfRecord !== -1) {
console.log(idx, 'false')
this.clickRecord.splice(indexOfRecord, 1)
this.fileLists[idx].checked = false
} else {
console.log(idx, 'true')
this.clickRecord.push(idx)
this.fileLists[idx].checked = true
}
}
}
},
openFile: async function (info) {
if (info.type === 'folder') {
this.currentInfo = info
@@ -427,7 +560,7 @@ export default {
// call getfolder api and update
const folders = await api.collection.getByParent('folder', info.id)
const files = await api.meta.getAttrByParent('folder', info.id, 'id-path-name-parent-description-size-time_duration-uuid-device-channels-created_at')
const files = await api.meta.getAttrByParent('folder', info.id, 'id-path-name-parent-description-size-time_duration-uuid-device-channels-parameter_set-created_at')
file.updateFileList(folders)
file.updateFileList(files)
@@ -447,7 +580,7 @@ export default {
this.currentInfo = item
// call getfolder api and update
const folders = await api.collection.getByParent('folder', item.id)
const files = await api.meta.getAttrByParent('folder', item.id, 'id-path-name-parent-description-size-time_duration-uuid-device-channels-created_at')
const files = await api.meta.getAttrByParent('folder', item.id, 'id-path-name-parent-description-size-time_duration-uuid-device-channels-parameter_set-created_at')
file.updateFileList(folders)
file.updateFileList(files)
@@ -468,7 +601,7 @@ export default {
if (initCollection.data.length === 1) {
this.currentInfo = initCollection.data[0]
const folders = await api.collection.getByParent('folder', initCollection.data[0].id)
const files = await api.meta.getAttrByParent('folder', initCollection.data[0].id, 'id-path-name-parent-description-size-time_duration-uuid-device-channels-created_at')
const files = await api.meta.getAttrByParent('folder', initCollection.data[0].id, 'id-path-name-parent-description-size-time_duration-uuid-device-channels-parameter_set-created_at')
file.updateFileList(folders)
file.updateFileList(files)
this.fileLists = file.getFileList()
@@ -528,56 +661,67 @@ export default {
}, 100)
},
editFile: async function () {
// TODO editFile
if (this.editInfo.type !== 'folder') {
await api.meta.update(this.editInfo.info.id, { name: this.editInfo.changedName })
} else {
}
await this.editFileDone()
},
checkFileNameValidate: debounce(function (term) {
const illegalChar = term.match(/[^(\w\-)]+/gm)
this.editInfo.changedName = term
if (term.length === 0) {
// input text empty
this.editInfo.error = true
this.editInfo.success = false
this.editInfo.errorMessages.pop()
this.editInfo.errorMessages.push(this.editInfo.errorMessagesAll[1])
} else if (illegalChar !== null) {
// input text illegal
this.editInfo.error = true
this.editInfo.success = false
this.editInfo.errorMessages.pop()
this.editInfo.errorMessages.push(this.editInfo.errorMessagesAll[0] + ' ' + illegalChar[0])
} else {
const existedFile = this.fileLists.filter((file) => {
if (file.name != null) {
return file.name.replace('/', '') === term
} else {
return false
}
})
if (existedFile.length === 0) {
this.editInfo.error = false
this.editInfo.success = true
} else {
// file name exist
this.editInfo.error = true
this.editInfo.success = false
this.editInfo.errorMessages.pop()
this.editInfo.errorMessages.push(this.editInfo.errorMessagesAll[2])
}
}
}, 200),
editFileDone: async function () {
const tmpCurrentPage = this.$refs.datatable_ref.currentPage
await this.refreshPage()
this.$refs.datatable_ref.currentPage = tmpCurrentPage
this.$refs.datatable_ref.inputPage(tmpCurrentPage)
this.showToast(`${this.editInfo.info.name} -> ${this.editInfo.changedName}`, {
position: 'bottom-right',
})
// TODO editFile
if (this.editInfo.info.type === 'folder') {
await api.collection.update(this.editInfo.info.id, { name: this.editInfo.changedName })
const folder = this.fileLists.find((file) => {
if (file.type === 'folder' && this.editInfo.info.id === file.id) return true
})
folder.name = this.editInfo.changedName
} else {
await api.meta.update(this.editInfo.info.id, { name: this.editInfo.changedName })
const meta = this.fileLists.find((file) => {
if (file.type === undefined && this.editInfo.info.id === file.id) return true
})
meta.name = this.editInfo.changedName
}
// await this.editFileDone()
},
checkFileNameValidate: debounce(function (term) {
// const illegalChar = term.match(/[^(\w\-)]+/gm)
this.editInfo.changedName = term
// if (term.length === 0) {
// // input text empty
// this.editInfo.error = true
// this.editInfo.success = false
// this.editInfo.errorMessages.pop()
// this.editInfo.errorMessages.push(this.editInfo.errorMessagesAll[1])
// } else if (illegalChar !== null) {
// // input text illegal
// this.editInfo.error = true
// this.editInfo.success = false
// this.editInfo.errorMessages.pop()
// this.editInfo.errorMessages.push(this.editInfo.errorMessagesAll[0] + ' ' + illegalChar[0])
// } else {
// const existedFile = this.fileLists.filter((file) => {
// if (file.name != null) {
// return file.name.replace('/', '') === term
// } else {
// return false
// }
// })
// if (existedFile.length === 0) {
// this.editInfo.error = false
// this.editInfo.success = true
// } else {
// // file name exist
// this.editInfo.error = true
// this.editInfo.success = false
// this.editInfo.errorMessages.pop()
// this.editInfo.errorMessages.push(this.editInfo.errorMessagesAll[2])
// }
// }
}, 200),
editFileDone: async function () {
// const tmpCurrentPage = this.$refs.datatable_ref.currentPage
// await this.refreshPage()
// if (this.$refs.datatable_ref) {
// this.$refs.datatable_ref.currentPage = tmpCurrentPage
// this.$refs.datatable_ref.inputPage(tmpCurrentPage)
// }
},
undoEdit: function () {
this.editInfo.success = false
@@ -590,6 +734,7 @@ export default {
},
fillDeleteInfo: function (info) {
if (info.type === 'folder') {
this.deleteInfo.metaID = undefined
this.deleteInfo.folderID = info.id
this.deleteInfo.name = info.name
} else {
@@ -600,10 +745,19 @@ export default {
},
deleteFolder: async function (id) {
await api.collection.update(id, { deleted: true })
const childrenCollection = await api.collection.getByParent('folder', id)
const childrenMeta = await api.meta.getByParent('folder', id)
for (const collection of childrenCollection.data) {
await this.deleteFolder(collection.id)
}
for (const meta of childrenMeta.data) {
await this.deleteSingleFileByDeleteInfo(meta.id)
}
await api.collection.clearDel()
},
deleteSingleFileByDeleteInfo: async function () {
await api.meta.update(this.deleteInfo.metaID, { deleted: true })
deleteSingleFileByDeleteInfo: async function (metaID) {
if (metaID === undefined) metaID = this.deleteInfo.metaID
await api.meta.update(metaID, { deleted: true })
await api.meta.clearDel()
},
deleteFileConfirm: function (info) {
@@ -627,10 +781,23 @@ export default {
deleteFileDone: async function () {
const tmpCurrentPage = this.$refs.datatable_ref.currentPage
// rebuild table
this.fileLists = this.fileLists.filter(file => file.name !== this.deleteInfo.name)
await this.refreshPage()
this.$refs.datatable_ref.currentPage = tmpCurrentPage
this.$refs.datatable_ref.inputPage(tmpCurrentPage)
if (this.deleteInfo.metaID) {
this.fileLists = this.fileLists.filter(file => {
return file.id !== this.deleteInfo.metaID
})
}
if (this.deleteInfo.folderID) {
this.fileLists = this.fileLists.filter(file => {
if (file.type === 'folder') {
return file.id !== this.deleteInfo.folderID
}
return true
})
}
// await this.refreshPage()
await this.$refs.datatable_ref.inputPage(1)
await this.$refs.datatable_ref.inputPage(tmpCurrentPage)
// this.$refs.datatable_ref.inputPage(tmpCurrentPage)
// this.loadingFiles = false
this.showToast(`deleted ${this.deleteInfo.name}`, {
position: 'bottom-right',
@@ -646,7 +813,7 @@ export default {
this.showToast('deleting file...', {
position: 'bottom-right',
})
this.deleteSelected()
await this.deleteSelected()
},
inputFieldReset: function (info) {
info.name = ''
@@ -674,7 +841,7 @@ export default {
// call getfolder api and update
const folders = await api.collection.getByParent('folder', this.currentInfo.id)
const files = await api.meta.getAttrByParent('folder', this.currentInfo.id, 'id-path-name-parent-description-size-time_duration-uuid-device-channels-created_at')
const files = await api.meta.getAttrByParent('folder', this.currentInfo.id, 'id-path-name-parent-description-size-time_duration-uuid-device-channels-parameter_set-created_at')
file.updateFileList(folders)
file.updateFileList(files)
@@ -684,25 +851,67 @@ export default {
// this.$refs.datatable_ref.refresh()
// this.$refs.datatable_ref.currentPage = 1
},
downloadSelected: function () {
for (let i = 0; i < this.selected.length; i++) {
const meta = this.selected[i]
this.downloadExcel(meta)
getAllChildrenByParent: async function (collection) {
const childrenCollection = await api.collection.getByParent('folder', collection)
const childrenMeta = await api.meta.getByParent('folder', collection)
for (const collection of childrenCollection.data) {
await this.getAllChildrenByParent(collection.id)
}
for (const meta of childrenMeta.data) {
this.downloadIDList.push(meta.id)
}
},
async deleteSelected () {
downloadSelected: async function () {
this.downloadIDList.length = 0
const meta = this.selected
if (Array.isArray(meta) === true) {
for (const ele of meta) {
if (ele.type === 'folder') {
await this.getAllChildrenByParent(ele.id)
} else {
this.downloadIDList.push(ele.id)
}
}
}
const connectCheck = await api.connection.check()
if (connectCheck.status === 200) {
this.$refs.download_ref.count = 0
this.$refs.download_ref.fileNums = this.downloadIDList.length
this.$refs.download_ref.metaListNew.push(...this.downloadIDList)
} else {
this.$refs.download_offline_ref.count = 0
this.$refs.download_offline_ref.fileNums = this.downloadIDList.length
this.$refs.download_offline_ref.metaListNew.push(...this.downloadIDList)
}
},
newDownload: async function (data) {
const connectCheck = await api.connection.check()
if (connectCheck.status === 200) {
this.$refs.download_ref.fileNums = 1
this.$refs.download_ref.metaListNew.push(data.id)
} else {
this.$refs.download_offline_ref.fileNums = 1
this.$refs.download_offline_ref.metaListNew.push(data.id)
}
},
deleteSelected: async function () {
for (let i = 0; i < this.selected.length; i++) {
const meta = this.selected[i]
this.fillDeleteInfo(meta)
await this.deleteSingleFileByDeleteInfo()
if (this.deleteInfo.metaID === undefined) {
await this.deleteFolder(this.deleteInfo.folderID)
} else {
await this.deleteSingleFileByDeleteInfo()
}
this.showToast(`deleted ${this.deleteInfo.name}`, {
position: 'bottom-right',
})
}
const tmpCurrentPage = this.$refs.datatable_ref.currentPage
await this.refreshPage()
this.$refs.datatable_ref.currentPage = tmpCurrentPage
this.$refs.datatable_ref.inputPage(tmpCurrentPage)
// filter the checked files
this.fileLists = this.fileLists.filter((file) => { return file.checked === false })
await this.$refs.datatable_ref.inputPage(1)
await this.$refs.datatable_ref.inputPage(tmpCurrentPage)
},
downloadCsv: async function (meta) {
const href = location.href.split('/')[2]
@@ -714,20 +923,26 @@ export default {
}
},
downloadExcel: async function (meta) {
this.downloadIDList.length = 0
const href = location.href.split('/')[2]
const connectCheck = await api.connection.check()
if (meta.device.library_name.indexOf('Elite') >= 0) {
if (connectCheck.status === 200) {
window.open('http://' + href + '/#/download/online/excel/' + meta.id)
} else {
window.open('http://' + href + '/#/download/offline/excel/' + meta.id)
}
} else if (meta.device.library_name.indexOf('Neulive') >= 0) {
if (connectCheck.status === 200) {
window.open('http://' + href + '/#/download/online/csv-edf/' + meta.id)
} else {
window.open('http://' + href + '/#/download/offline/csv-edf/' + meta.id)
let metaID = ''
if (Array.isArray(meta) === true) {
for (const ele of meta) {
if (ele.type === 'folder') {
await this.getAllChildrenByParent(ele.id)
} else {
this.downloadIDList.push(ele.id)
}
}
} else {
this.downloadIDList.push(meta.id)
}
metaID = this.downloadIDList.join('-')
if (connectCheck.status === 200) {
window.open('http://' + href + '/#/download/online/excel/' + metaID)
} else {
window.open('http://' + href + '/#/download/offline/excel/' + metaID)
}
},
downloadSdCard: async function (meta) {
@@ -752,16 +967,17 @@ export default {
}
},
replay: function (meta) {
const href = location.href.split('/')[2]
if (meta.device.library_name.includes('Neulive') === true) {
// window.open('http://' + location.href.split('/')[2].split(':')[0] + '/#/admin/data-replay/' + meta.id)
this.$router.push({
path: '/admin/data-replay/' + meta.id,
})
} else if (meta.device.library_name.includes('Elite') === true) {
// window.open('http://' + location.href.split('/')[2].split(':')[0] + '/#/admin/data-replay/elite/' + meta.id)
this.$router.push({
path: '/admin/data-replay/elite/' + meta.id,
})
window.open('http://' + href + '/#/admin/data-replay/elite/' + meta.id)
// this.$router.push({
// path: '/admin/data-replay/elite/' + meta.id,
// })
}
},
spike: function (meta) {
@@ -771,10 +987,14 @@ export default {
})
}
},
getWorkingMode: function (library, mode) {
getWorkingMode: function (device, parameterSet) {
try {
return configTable.getModeConfig(library, mode).name
} catch {
if (parameterSet) {
return configTable.getModeConfig(device.library_name, parameterSet.MODE).name
}
return ''
} catch (e) {
console.log('e', e)
return ''
}
},
@@ -783,8 +1003,16 @@ export default {
const controllerList = await api.controller.getAll()
this.controllerList = controllerList.data
this.getSDuuidList()
window.addEventListener('keypress', (e) => {
this.keyboardEvent = e
})
},
destroyed () {
},
}
</script>
<style>
.text-not-select {
user-select: none;
}
</style>
@@ -0,0 +1,101 @@
<template>
<va-modal
class="flex sm12 xl12 md12 xs12"
v-model="showModal"
size="small"
:title="'MOVE'"
:okText=" $t('modal.confirm') "
@ok="moveFolder()"
@cancel="cancel()"
>
<div class="row flex sm12 xl12 md12 xs12">
<va-select
v-model="destination"
:options="option"
class="va-select-without-margin"
searchable
/>
</div>
</va-modal>
</template>
<script>
import api from '@/data/api/index'
export default {
name: 'aaa',
data: () => {
return {
showModal: false,
option: [],
destination: '',
selected: [],
}
},
methods: {
cancel: function () {
this.destination = ''
this.selected = []
},
refreshCollection: async function () {
await this.getAllCollection()
},
moveFolder: async function () {
for (const e of this.selected) {
if (e.type === 'folder') {
await api.collection.update(e.id, {
parent: {
folder: [this.destination.id],
},
})
}
if (e.type === undefined) {
await api.meta.update(e.id, {
parent: {
folder: [this.destination.id],
},
})
}
}
this.cancel()
this.$emit('refreshPage')
},
getAllCollection: async function () {
// get all collections by api
const collectionResponse = await api.collection.getAll()
// filter the root folder & select folder itself
const allCollection = collectionResponse.data.filter((ele) => {
return ele.name !== 'root' && this.selected.findIndex(v => v.id === ele.id && v.type === 'folder') === -1
})
// create a new list of collection contain text for display
const newCollection = allCollection.map((ele) => {
let parentName = ''
// if has parent
if (Object.keys(ele.parent).length > 0) {
// get parent name
for (const id of ele.parent.folder) {
const parent = allCollection.find((v) => {
return v.id === id
})
if (parent) {
parentName = parent.name
}
}
}
// if parent name is admin then the name is remain origin
if (ele.name === 'admin' || parentName === 'admin') {
ele.text = ele.name
} else {
// if not the name contain it's parent
ele.text = parentName + ' / ' + ele.name
}
return ele
})
this.option = newCollection
},
},
mounted () {
},
}
</script>
<style></style>
+58 -25
View File
@@ -4,17 +4,22 @@
<project-manager/>
</div>
<div
:class="(taskViewPanel.show || projectManagerPanel.show)
? (taskViewPanel.show && projectManagerPanel.show)
? cardStyle.small
: cardStyle.medium
:class="(projectManagerPanel.show)
? cardStyle.medium
: cardStyle.large
">
<project-view @start_project="startProject($event)" @stop_project="stopProject($event)" @save_project="saveProject($event)"/>
<project-view @start_project="startProject($event)" @stop_project="stopProject($event)" @save_project="saveProject($event)" @detect="detect"/>
</div>
<div :class="cardStyle.small" v-show="taskViewPanel.show">
<slide-out
dock="right"
:mask-color="'rgba(0, 0, 0, 0)'"
:visible.sync="taskViewPanel.show"
:title="(taskViewPanel.type === 1) ? 'Device' : (taskViewPanel.type === 3) ? 'Condition' : (taskViewPanel.type === 4) ? 'Parameter' : ''"
@closed="onClosing"
resizable
>
<project-task/>
</div>
</slide-out>
</div>
</template>
@@ -22,7 +27,7 @@
import ProjectManager from '@/components/project/manager/ProjectManager'
import ProjectView from '@/components/project/view/ProjectView'
import ProjectTask from '@/components/project/task/ProjectTask'
import { mapActions } from 'vuex'
import { mapActions, mapGetters } from 'vuex'
import { mapFields } from 'vuex-map-fields'
import types from '@/store/modules/project/types'
import { taskInfo } from '@/data/task/TaskInfo'
@@ -35,6 +40,9 @@ export default {
ProjectTask,
},
computed: {
...mapGetters('project', [
types.project.getSelect,
]),
...mapFields('project', [
'projectConfigList',
'runningProjectList',
@@ -47,8 +55,8 @@ export default {
return {
controllerList: [],
cardStyle: {
small: 'flex xl4 md4 sm12 xs12',
medium: 'flex xl8 md8 sm12 xs12',
small: 'flex xl3 md3 sm12 xs12',
medium: 'flex xl9 md9 sm12 xs12',
large: 'flex xl12 md12 sm12 xs12',
},
}
@@ -74,7 +82,7 @@ export default {
},
async '+/get_running_project/+' (data, topic) {
this.runningProjectList.length = 0
const runningProjects = JSON.parse(String.fromCharCode.apply(null, data)).data
const runningProjects = JSON.parse(new TextDecoder().decode(data)).data
this.runningProjectList.push(...runningProjects)
},
async '+/broadcast' (data, topic) {
@@ -93,6 +101,9 @@ export default {
},
},
methods: {
onClosing: async function () {
await this.saveProject(this.getSelectProject)
},
pageToast: function (mes) {
this.showToast(
mes,
@@ -125,16 +136,28 @@ export default {
this.mqttUnSub(id + '/get_running_project/+')
},
initPage: async function () {
await this.initProject()
await taskInfo.updateTaskInfo()
this.pageMqttSub(taskInfo.getTaskInfo().controllerID)
},
startProject: function (project) {
console.log('start_project', project)
console.log('taskInfo.getTaskInfo().controllerID', taskInfo.getTaskInfo().controllerID)
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'run_project/0',
project: project,
}))
let deviceReady = true
for (const device of Object.values(this.getSelectProject.device)) {
if (device.pairStatus !== 1) {
if (device.pair === null) {
window.alert('Device ' + device.name + ' is not connected yet.')
} else {
window.alert('Device ' + device.pair + ' is not connected yet.')
}
deviceReady = false
}
}
if (deviceReady === true) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'run_project/0',
project: project,
}))
}
},
stopProject: function (project) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
@@ -144,18 +167,25 @@ export default {
},
saveProject: async function (project) {
this.updateProject({ project: project, api: this.API })
this.showToast(
'project update finish',
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 5000,
},
)
},
detect: async function (device) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: device,
instruction: 'VIS_DEVICE_DETECT',
}))
setTimeout(() => {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: device,
instruction: 'VIS_DEVICE_DONE',
}))
}, 5000)
},
...mapActions('project',
[
types.project.init,
types.project.update,
types.project.addDevice,
],
@@ -179,6 +209,9 @@ export default {
header: 'get_running_project/0',
}))
},
destroyed () {
this.projectManagerPanel.show = true
},
}
</script>
@@ -1,37 +1,28 @@
<template>
<div>
<va-card style="height: 90vh; overflow: auto; display: block;">
<va-card style="height: 88vh; overflow: auto; display: block;">
<template slot="header">
<div class="row">
<div class="flex d-flex xs5 sm5 lg5 xl5">
<va-icon name="fa fa-bluetooth-b" color="primary"/>
<h5 class="mb-0">PROJECTS</h5>
<p class="project-view-header">PROJECTS</p>
</div>
<div class="flex xs7 sm7 lg7 xl7" style="text-align: right;">
<!-- <va-button v-if="projectConfigList.length !== 0" class="ma-0 circle-button" @click="closePanel"> -->
<va-icon v-if="projectConfigList.length !== 0" @click.native="closePanel"
name="fa fa-times"
color="black"
/>
<!-- </va-button> -->
<img class="img-vertical-center" src="@/assets/img/project/menu_close.svg" @click="closePanel">
</div>
</div>
<!-- <div class="flex d-flex xl5 lg5 sm5 xs5 ma-0">
<va-icon name="fa fa-bluetooth-b mr-3" color="primary"/>
<h5 class="mb-0">PROJECTS</h5>
</div>
<div class="flex d-flex xl7 lg7 sm7 xs7 ma-0" style="text-align: right;">
<va-button v-if="projectConfigList.length !== 0" class="pa-0 ma-0 circle-button" small color="dark" @click="closePanel">
<va-icon
name="fa fa-times"
color="white"
/>
</va-button>
</div> -->
</template>
<div class="flex d-flex m12 xs12 md12 xl12">
<div>
<va-button @click="createProject({ api: API })" icon="fa fa-plus"></va-button>
<div class="input-icons input-style flex sm12 xs12 md7 xl7 pa-0">
<img class="icon" src="@/assets/img/project/search.svg">
<input class="input-field" type="text" v-model="filterText">
</div>
<div class="ml-1 pa-0" style="text-align: right;">
<button class="project-copy-btn" @click="copyProject({ project: getSelectProject, index: index, api: API })">
<img class="img-vertical-center" src="@/assets/img/project/copy-alt.svg">
</button>
<button class="project-copy-btn ml-1" @click="createProject({ api: API })">
<img class="img-vertical-center" src="@/assets/img/project/plus.svg">
</button>
</div>
</div>
<div>
@@ -42,15 +33,15 @@
</va-tabs>
</div>
<div class="mt-1">
<project-manager-list v-if='tabValue == 0'/>
<running-project-manager-list v-if='tabValue == 1'/>
<project-manager-list v-if='tabValue == 0' :filterText="filterText"/>
<running-project-manager-list v-if='tabValue == 1' :filterText="filterText"/>
</div>
</va-card>
</div>
</template>
<script>
import { mapActions } from 'vuex'
import { mapActions, mapGetters } from 'vuex'
import { mapFields } from 'vuex-map-fields'
import types from '@/store/modules/project/types'
import ProjectManagerList from '@/components/project/manager/ProjectManagerList'
@@ -63,6 +54,10 @@ export default {
RunningProjectManagerList,
},
computed: {
...mapGetters('project', [
'getSelectProject',
]),
...mapFields('project', [
'lockMode',
'projectList',
@@ -75,6 +70,7 @@ export default {
return {
tabValue: 0,
tabTitles: ['CONFIG', 'RUNNING'],
filterText: '',
}
},
methods: {
@@ -86,6 +82,9 @@ export default {
...mapActions('project',
[
types.project.create,
types.project.copy,
types.project.select,
types.project.delete,
],
),
closePanel: function () {
@@ -100,4 +99,39 @@ export default {
<style>
.input-icons img {
position: absolute;
}
.input-icons {
width: 67%;
/* margin-bottom: 10px; */
}
.icon {
color: grey;
min-width: 40px;
padding: 10px;
}
.input-field {
width: 100%;
padding: 9px;
text-align: right;
background: #f1f1f1;
border: none;
border-radius: 6px 6px 0 0;
border-bottom: 1.5px solid #758b9a;
}
.project-copy-btn {
width: 50px;
height: 38px;
background: #858dd6;
border: none;
border-radius: 5px;
cursor: pointer;
}
</style>
@@ -1,12 +1,13 @@
<template>
<div class="row">
<div class="flex xs12 lg12 md12">
<va-item class="mb-1" v-for="(project, index) in projectConfigList" :key="index" @click="selectProject({index: index})" clickable>
<va-item :class="(selectProjectIndex === index) ? 'project-list-text project-list-focus': 'project-list-text project-list'" v-for="(project, index) in configList" :key="index" @click="select(index)">
<va-item-section @dblclick.native="switchEdit('name', index)">
<div v-if="projectTable.name == index">
<va-input
:ref="'input_ref'"
v-model="project.name"
style="width: 100px;"
style="min-width: 100px;"
@blur="switchEdit('name', -1, project)"
@keyup.enter="switchEdit('name', -1, project)"
/>
@@ -14,12 +15,11 @@
<div v-else>
{{ project.name }}
</div>
<!-- <va-item-label>
{{ project.name }}
</va-item-label> -->
</va-item-section>
<va-item-section side>
<va-icon class="fa fa-close" color="danger" @click.native.stop="deleteProject({ project: project, index: index, api: API })"></va-icon>
<img class="mr-2" src="@/assets/img/project/copy-alt-grey.svg" @click="copyProject({ project: project, index: index, api: API })">
<img v-if="selectDeleteIndex !== index" class="mr-2" src="@/assets/img/project/cross.svg" @click.stop="confirmDelete($event, index)">
<img v-else class="mr-2" src="@/assets/img/project/delete14_14.svg" @click.stop="_deleteProject(project, index)">
</va-item-section>
</va-item>
</div>
@@ -32,9 +32,28 @@ import types from '@/store/modules/project/types'
export default {
name: 'project-manager-list',
props: {
filterText: {
type: String,
default: '',
},
},
computed: {
configList () {
const projectList = this.projectConfigList
projectList.sort((a, b) => {
const date1 = new Date(a.created_at).getTime()
const date2 = new Date(b.created_at).getTime()
return date2 - date1
})
if (this.filterText === '') return projectList
return projectList.filter(ele => ele.name.includes(this.filterText))
},
...mapFields('project', [
'projectConfigList',
'projectSelectIndex',
'projectTableSelectIndex',
]),
},
data () {
@@ -42,19 +61,53 @@ export default {
projectTable: {
name: -1,
},
selectProjectIndex: -1,
selectDeleteIndex: -1,
}
},
methods: {
reset: function () {
this.selectProjectIndex = -1
this.selectDeleteIndex = -1
},
resetDelete: function (e) {
if (e.target.classList.contains('clicked')) {
e.target.classList.remove('clicked')
return
}
this.selectDeleteIndex = -1
},
confirmDelete: function (e, index) {
e.target.classList.add('clicked')
this.selectProjectIndex = index
this.selectDeleteIndex = index
window.addEventListener('mousedown', this.resetDelete, { once: true })
},
_deleteProject: async function (project, index) {
this.reset()
await this.deleteProject({ project: project, index: index, api: this.API })
},
select: function (index) {
this.selectProjectIndex = index
this.selectDeleteIndex = -1
this.projectTableSelectIndex = -1
this.selectProject({ index: index })
},
switchEdit: function (tag, index, project) {
if (this.projectTable[tag] >= 0) {
this.projectTable[tag] = -1
project && this.API.project.update(project.id, { name: project.name })
} else {
this.projectTable[tag] = index
this.$nextTick(() => {
this.$refs.input_ref[0].$refs.input.focus()
})
}
},
...mapActions('project',
[
types.project.copy,
types.project.select,
types.project.delete,
],
@@ -64,3 +117,32 @@ export default {
},
}
</script>
<style lang="scss">
.project-list-text {
// font
font-family: 'Inter-Regular';
font-style: italic;
font-weight: 400;
font-size: 16px;
line-height: 24px;
color: #768b9b;
}
.project-list-focus {
/* Rectangle 5 */
background: #ebedff;
border: 1px solid #dbdcf0;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
border-radius: 5px;
}
.project-list-focus:hover {
opacity: 0.8;
background: #ebedff;
}
.project-list:hover {
opacity: 0.8;
}
</style>
+1 -1
View File
@@ -1,6 +1,6 @@
<template>
<div>
<va-card style="height: 90vh; overflow: auto;">
<va-card style="height: 88vh; overflow: auto;">
<project-task-config></project-task-config>
</va-card>
</div>
@@ -1,8 +1,9 @@
<template>
<div>
<project-task-config-device v-if="taskViewPanel.type===1"></project-task-config-device>
<project-task-config-condition v-if="taskViewPanel.type===3"></project-task-config-condition>
<project-task-config-parameter v-if="taskViewPanel.type===4"></project-task-config-parameter>
<project-task-config-condition v-if="taskViewPanel.type===2" :actionType="'start'"></project-task-config-condition>
<project-task-config-condition v-if="taskViewPanel.type===3" :actionType="'stop'"></project-task-config-condition>
<project-task-config-parameter v-show="taskViewPanel.type===4"></project-task-config-parameter>
</div>
</template>
<script>
@@ -1,52 +1,18 @@
<template>
<div class="flex sm12 xl12 md12 xs12">
<div class="task-config__header-separator mb-1">
<div class="task-config__header-text">
<span>Action &#38; Condition</span>
<va-button class="circle-button" small color="dark" @click="closePanel">
<va-icon
name="fa fa-times"
color="white"
/>
</va-button>
<!-- <span>Condition</span> -->
<div v-for="(condition, key) in conditionObj" :key="key">
<!-- <div v-if="key === 'cycle' || key === 'cycle_next'" class="flex d-flex align--center"> -->
<div class="flex d-flex align--center">
<va-checkbox v-model="condition.select"></va-checkbox>
<span class="mr-1">{{ condition.prefix }}</span>
<input style="width: 100px;" class="mr-1" :type="condition.type" v-model="condition.value"/>
<span>{{ condition.suffix }}</span>
</div>
</div>
<div>
<!-- <div v-for="(action, actionKey) in this.getSelectTask.action" :key="actionKey">
{{ getDeviceProject(action.target).name }} {{ action.type }} {{ getConditionTask(action.condition[0]).value }}
</div> -->
</div>
<span>Device</span>
<div class="flex d-flex" v-if="Object.keys(registeredDevice).length > 0">
<div v-for="(device, deviceKey) in registeredDevice" :key="deviceKey">
<va-button @click="selectDevice(deviceKey)" small>{{ device.name }}</va-button>
</div>
</div>
<div align="center" v-else>
No registered device found.
</div>
<div v-if="settingStep >= 1">
<span>Action</span>
<div class="flex d-flex">
<div v-for="action in actionTemplate" :key="action">
<va-button color="info" @click="selectAction(action)" small>{{ action }}</va-button>
</div>
</div>
</div>
<div v-if="settingStep >= 2">
<span>Condition</span>
<div v-for="(condition, key) in conditionObj" :key="key">
<div class="flex d-flex align--center">
<va-checkbox v-model="condition.select"></va-checkbox>
<span class="mr-1">{{ condition.prefix }}</span>
<input class="mr-1" :type="condition.type" v-model="condition.value"/>
<span>{{ condition.suffix }}</span>
</div>
</div>
<div align="right">
<va-button color="warning" @click="reset" small>Reset</va-button>
<va-button color="success" @click="save" small>Save</va-button>
</div>
<div align="right">
<va-button color="warning" @click="reset" small>Reset</va-button>
<va-button color="success" @click="save" small>Save</va-button>
</div>
</div>
</template>
@@ -61,9 +27,15 @@ export default {
name: 'project-task-config-condition',
components: {
},
props: {
actionType: {
type: String,
required: true,
},
},
computed: {
conditionObj () {
return this.conditionTemplate[this.actionSelect]
return this.conditionTemplate[this.actionType]
},
deviceSelectName () {
@@ -78,16 +50,18 @@ export default {
types.project.getSelect,
types.project.getDevice,
types.project.getAllDevice,
types.project.getDeviceShowName,
]),
...mapFields('project', [
'taskSelectKey',
'taskViewPanel',
'deviceSelectKey',
]),
},
data () {
return {
settingStep: 0,
settingStep: 1,
registeredDevice: {},
deviceSelect: '',
@@ -98,7 +72,11 @@ export default {
conditionTemplate: newConditionTemplate(),
conditionList: [],
taskOptions: {},
taskOptionsKeys: [],
project: {},
device: {},
task: {},
}
},
methods: {
@@ -137,7 +115,7 @@ export default {
},
save: function () {
const actionUUID = this.GLOBAL.getUUID()
const newAction = this.createAction(actionUUID, this.actionSelect, this.deviceSelect)
const newAction = this.createAction(actionUUID, this.actionType, this.deviceSelect)
// if device not add in task then add in
if (!this.getSelectTask.device.includes(this.deviceSelect)) {
@@ -156,21 +134,37 @@ export default {
this.setActionTask({ action: newAction })
this.reset()
},
updateTaskOptions: function () {
for (var idx = 0; idx < this.project.task.length; idx++) {
this.taskOptions[this.project.task[idx].name] = this.project.task[idx].uuid
}
this.taskOptionsKeys = Object.keys(this.taskOptions)
},
...mapActions('project', [
types.task.setCondition,
types.task.setAction,
types.task.setCycle,
]),
},
mounted () {
const project = this.getSelectProject
const device = this.getAllDeviceProject
const task = this.getSelectTask
console.log('project', project)
console.log('task', task)
this.registeredDevice = device
this.project = this.getSelectProject
this.device = this.getAllDeviceProject
this.deviceSelect = this.deviceSelectKey
this.task = this.getSelectTask
for (var idx = 0; idx < this.project.task.length; idx++) {
this.taskOptions[this.project.task[idx].name] = this.project.task[idx].uuid
}
this.taskOptionsKeys = Object.keys(this.taskOptions)
this.registeredDevice = this.device
},
watch: {
// refresh parameter when click different task's parameter
deviceSelectKey: {
handler: function () {
this.deviceSelect = this.deviceSelectKey
},
},
},
}
</script>
@@ -1,54 +1,54 @@
<template>
<div class="flex sm12 xl12 md12 xs12">
<div class="task-config__header-separator mb-1">
<div class="task-config__header-text">
<span> Device </span>
<va-button class="circle-button" small color="dark" @click="closePanel">
<va-icon
name="fa fa-times"
color="white"
/>
</va-button>
</div>
</div>
<div>
<va-list fit class="mb-2">
<va-item v-for="(device, index) in getSelectProject.device" :key="index" >
<va-item-section side>
<va-checkbox
:value="device.isSelect"
:arrayValue="(taskSelectKey != undefined)? String(taskSelectKey) : '-1'"
@input="selectDevice($event, device, index)"
ref="checkbox_ref"
/>
</va-item-section>
<va-list fit class="mb-2 pb-0">
<va-list-label>
Register
</va-list-label>
<va-item-section avatar class="ml-0">
<va-avatar style="border-radius: 0;">
<img
src='@/assets/img/elite_img.png' :alt="device.name">
</va-avatar>
</va-item-section>
<template v-for="(device, index) in deviceListInOrder">
<va-item :class="taskDevice.includes(device[0]) === true ? 'device-list-focus': ''" :key="'register' + String(index)" @click="selectDevice(device, index)" clickable>
<va-item-section avatar>
<va-avatar style="border-radius: 0;">
<img src='@/assets/img/elite_img.png' :alt="device[1].name">
</va-avatar>
</va-item-section>
<va-item-section>
<va-item-label>
{{ device.name }}
</va-item-label>
<va-item-section>
<va-item-label>
{{ getDeviceShowNameProject(device[0]) }}
</va-item-label>
</va-item-section>
</va-item>
</template>
</va-list>
<va-list fit class="mb-2 pb-0">
<va-list-label>
Connect
</va-list-label>
<va-item-label caption>
{{ device.connectDevice.device_address }}
</va-item-label>
</va-item-section>
</va-item>
<template v-for="(device, index) in getNotRegisterDeviceProject()">
<va-item :key="'connect' + index" clickable @click="registerConnectDevice(device)">
<va-item-section avatar>
<va-avatar style="border-radius: 0;">
<img src='@/assets/img/elite_img.png' :alt="device.macAddress">
</va-avatar>
</va-item-section>
<va-item-section>
<va-item-label>
{{ device.macAddress }}
</va-item-label>
</va-item-section>
</va-item>
</template>
</va-list>
</div>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
import { mapGetters } from 'vuex'
// import eliteImgUrl from '@/assets/img/elite_img.png'
// import neuliveImgUrl from '@/assets/img/neulive_img.png'
import { mapActions, mapGetters } from 'vuex'
import types from '@/store/modules/project/types'
export default {
@@ -56,9 +56,21 @@ export default {
components: {
},
computed: {
deviceListInOrder () {
return Object.entries(this.getSelectProject.device).sort((a, b) => a[1].order - b[1].order)
},
taskDevice () {
if (this.getSelectTask.device) {
return this.getSelectTask.device
}
return null
},
...mapGetters('project', [
types.project.getSelect,
types.task.getSelect,
types.project.getDeviceShowName,
types.project.getNotRegisterDevice,
]),
...mapFields('project', [
@@ -71,38 +83,70 @@ export default {
}
},
methods: {
selectDevice: function (event, device, key) {
// if select single task
if (this.taskSelectKey !== undefined) {
device.isSelect = event
// console.log('device.isSelect: ', device.isSelect)
device.isSelect.includes(String(this.taskSelectKey)) === true
? this.getSelectTask.device.push(key)
: this.getSelectTask.device = this.getSelectTask.device.filter(item => item !== key)
selectDevice: function (device, index) {
if (this.taskDevice.includes(device[0]) === false) {
this.appendToTask(device[0])
} else {
// if select all tasks
if (event.includes('-1')) {
// check all
device.isSelect = ['-1', ...Array(this.getSelectProject.task.length).fill().map((_, index) => String(index))]
for (const task of this.getSelectProject.task) {
if (!task.device.includes(key)) {
task.device.push(key)
}
}
} else {
// uncheck all
device.isSelect = []
for (const task of this.getSelectProject.task) {
task.device = task.device.filter(item => item !== key)
}
}
this.removeFromTask(device[0])
}
},
resetDevice: function () {
},
registerConnectDevice: async function (device) {
// register device
await this.createDeviceProject({
name: device.name,
library: device.library,
pair: device.macAddress,
pairStatus: 1,
order: this.getDeviceMaxOrderProject,
})
// select device
this.selectDevice(this.deviceListInOrder[this.deviceListInOrder.length - 1])
},
appendToTask: function (key) {
// if select single task
this.getSelectTask.device.push(key)
// create start action-condtion-pair when choose device
this.createActionConditionPairTask({
device: key,
task: this.getSelectTask,
action: 'start',
condition: {
type: 'previous_task_done',
comparsion: 'equal',
value: '',
},
})
},
removeFromTask: function (key) {
// if select single task
// this.getSelectTask.device = this.getSelectTask.device.filter(item => item !== key)
// remove device & relation action, condition, parameter
this.deleteDeviceTask({ deviceKey: key, onlySelectTask: true })
},
closePanel: function () {
this.taskViewPanel.show = !(this.taskViewPanel.show)
},
...mapActions('project',
[
types.project.createDevice,
types.task.deleteDevice,
types.task.createActionConditionPair,
],
),
},
mounted () {
},
}
</script>
<style lang="scss">
.device-list-focus {
background: #ebedff;
border: 1px solid #dbdcf0;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
border-radius: 5px;
}
</style>
@@ -1,21 +1,12 @@
<template>
<div class="flex sm12 xl12 md12 xs12">
<div class="task-config__header-separator mb-1">
<div class="task-config__header-text">
<span >Parameter Set</span>
<va-button class="circle-button" small color="dark" @click="closePanel">
<va-icon
name="fa fa-times"
color="white"
/>
</va-button>
</div>
</div>
<div>
<device-parameter-recording
:ref="'device_parameter_ref'"
:parameter="parameter"
:library="'Elite_EDC_1.5'"
:library="library"
:place="'scheduler'"
:resetParameterModeChange="true"
@setParameter="setParameter"
@setParameterWithDebounce="setParameterWithDebounce"
/>
@@ -37,6 +28,11 @@ export default {
DeviceParameterRecording,
},
computed: {
library () {
if (this.device === null || this.device === undefined) return null
return this.device.library
},
...mapGetters('project', [
types.task.getSelect,
types.task.getParameterSet,
@@ -47,6 +43,7 @@ export default {
'taskViewPanel',
'taskSelectKey',
'deviceSelectKey',
'projectSelectIndex',
]),
},
data () {
@@ -70,7 +67,8 @@ export default {
condition.select = !condition.select
},
setParameter: function (name, value) {
this.parameter = Object.assign({}, this.parameter)
// this.parameter = Object.assign({}, this.parameter)
this.parameter[name] = value
if (this.parameterUUID === '') {
this.parameterUUID = this.GLOBAL.getUUID()
@@ -89,6 +87,7 @@ export default {
resetParameter: function (mode) {
// get Device
this.device = this.getDeviceProject(this.deviceSelectKey)
if (this.device === undefined) return
// get Config
if (typeof this.device.library === 'string') { // string
this.config = configTable.getConfig(this.device.library)
@@ -108,8 +107,11 @@ export default {
this.parameterUUID = Object.keys(parameterSet)[0]
const param = Object.values(parameterSet)[0]
const modeOption = this.$refs.device_parameter_ref.workingModeOptions.find(ele => ele.id === param.MODE)
this.$refs.device_parameter_ref.workingModeSelectChange(modeOption)
this.$refs.device_parameter_ref.workingModeSelectChange(modeOption, false)
this.parameter = Object.assign(this.parameter, Object.values(parameterSet)[0])
} else {
const defaultMode = this.config.MODE_OPTIONS.find(ele => ele.description === 'Idle')
this.setParameter('MODE', defaultMode.id)
}
},
...mapActions('project',
@@ -119,8 +121,33 @@ export default {
),
},
mounted () {
// init parameter
this.resetParameter()
},
watch: {
// refresh parameter when click different task's parameter
taskSelectKey: {
handler: function () {
this.device = null
this.parameter = {}
this.parameterUUID = ''
this.resetParameter()
},
},
deviceSelectKey: {
handler: function () {
this.device = null
this.parameter = {}
this.parameterUUID = ''
this.resetParameter()
},
},
projectSelectIndex: {
handler: function () {
this.device = null
this.parameter = {}
this.parameterUUID = ''
this.resetParameter()
},
},
},
}
</script>
@@ -12,14 +12,14 @@
</div>
<!-- EIS -->
<div v-if="workingModeSelect != null && workingModeSelect.id == 0">
<d-c-volt :ref="'DCVolt'" :deviceID="deviceID" :parameterName="'DC_BIAS'" @parameterChange="deviceParameterChange($event)" />
<a-c-amplitude :ref="'ACAmplitude'" :deviceID="deviceID" :parameterName="'AC_AMP'" @parameterChange="deviceParameterChange($event)" />
<freq-range :ref="'FreqRange'" :deviceID="deviceID" :parameterName="'FREQ'" @parameterChange="deviceParameterChange($event)" />
<points-per-decades :ref="'PointsPerDecades'" :deviceID="deviceID" :parameterName="'PPD'" @parameterChange="deviceParameterChange($event)" />
<point-spacing :ref="'PointSpacing'" :deviceID="deviceID" :parameterName="'SCALE'" @parameterChange="deviceParameterChange($event)" />
<delay :ref="'Delay'" :deviceID="deviceID" :parameterName="'DELAY'" @parameterChange="deviceParameterChange($event)" />
<average :ref="'Average'" :deviceID="deviceID" :parameterName="'AVERAGE_NUM'" @parameterChange="deviceParameterChange($event)" />
<current-range :ref="'CurrentRange'" :deviceID="deviceID" :parameterName="'RTIA'" @parameterChange="deviceParameterChange($event)" />
<d-c-volt :ref="'DCVolt'" :deviceID="deviceID" :parameterName="'EIS_DC_BIAS'" @parameterChange="deviceParameterChange($event)" />
<a-c-amplitude :ref="'ACAmplitude'" :deviceID="deviceID" :parameterName="'EIS_AC_AMP'" @parameterChange="deviceParameterChange($event)" />
<freq-range :ref="'FreqRange'" :deviceID="deviceID" :parameterName="'EIS_FREQ'" @parameterChange="deviceParameterChange($event)" />
<points-per-decades :ref="'PointsPerDecades'" :deviceID="deviceID" :parameterName="'EIS_PPD'" @parameterChange="deviceParameterChange($event)" />
<point-spacing :ref="'PointSpacing'" :deviceID="deviceID" :parameterName="'EIS_SCALE'" @parameterChange="deviceParameterChange($event)" />
<delay :ref="'Delay'" :deviceID="deviceID" :parameterName="'EIS_DELAY'" @parameterChange="deviceParameterChange($event)" />
<average :ref="'Average'" :deviceID="deviceID" :parameterName="'EIS_AVERAGE_NUM'" @parameterChange="deviceParameterChange($event)" />
<current-range :ref="'CurrentRange'" :deviceID="deviceID" :parameterName="'GENERAL_HS_RTIA'" @parameterChange="deviceParameterChange($event)" />
</div>
<!-- CV -->
<div v-if="workingModeSelect != null && workingModeSelect.id == 1">
@@ -45,14 +45,6 @@
<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 sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">Voltage Range<p/>
</div>
<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 sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">High Z<p/>
@@ -66,7 +58,7 @@
<p class="display-6">E Initial<p/>
</div>
<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)" />
<volt-range :ref="'voltInitialNumber'" :deviceID="deviceID" :parameterName="'CV_E_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">
@@ -74,7 +66,7 @@
<p class="display-6">E1<p/>
</div>
<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)" />
<volt-range :ref="'voltMaxNumber'" :deviceID="deviceID" :parameterName="'CV_E1'" :minValue="-1.8" :maxValue="2" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
@@ -82,7 +74,7 @@
<p class="display-6">E2<p/>
</div>
<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)" />
<volt-range :ref="'voltMinNumber'" :deviceID="deviceID" :parameterName="'CV_E2'" :minValue="-1.8" :maxValue="2" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
@@ -90,7 +82,7 @@
<p class="display-6">Voltage Scan Rate<p/>
</div>
<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)" />
<scan-rate-range :ref="'voltScanRateNumber'" :deviceID="deviceID" :parameterName="'CV_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">
@@ -283,7 +275,7 @@ export default {
},
],
DCVolt: null,
AC_AMP: null,
EIS_AC_AMP: null,
FreqStart: null,
FreqStop: null,
PointsPerDecades: null,
@@ -395,44 +387,35 @@ 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)
}
this.ACAmplitude = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.AC_AMP) / 2047 * 800))
this.ACAmplitude = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_AC_AMP) / 2047 * 800))
if (this.$refs.ACAmplitude != null) {
this.$refs.ACAmplitude.itemChange(this.ACAmplitude)
}
this.Average = taskInfo.getDeviceInfo(this.deviceID).parameterSet.AVERAGE_NUM
this.Average = taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_AVERAGE_NUM
if (this.$refs.Average != null) {
this.$refs.Average.itemChange(this.Average)
}
this.CurrentRange = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RTIA
this.CurrentRange = taskInfo.getDeviceInfo(this.deviceID).parameterSet.GENERAL_HS_RTIA
if (this.$refs.CurrentRange != null) {
this.$refs.CurrentRange.itemChange(this.CurrentRange)
}
this.PointSpacing = taskInfo.getDeviceInfo(this.deviceID).parameterSet.SCALE
this.PointSpacing = taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_SCALE
if (this.$refs.PointSpacing != null) {
this.$refs.PointSpacing.itemChange(this.PointSpacing)
}
this.DCVolt = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.DC_BIAS) * 2200 / 4095))
this.DCVolt = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_DC_BIAS) * 2200 / 4095))
if (this.$refs.DCVolt != null) {
this.$refs.DCVolt.itemChange(this.DCVolt)
}
this.Delay = String(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.DELAY) / 10).toFixed(1))
this.Delay = String(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_DELAY) / 10).toFixed(1))
if (this.$refs.Delay != null) {
this.$refs.Delay.itemChange(this.Delay)
}
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.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.itemChangeMin(this.FreqStop)
}
this.PointsPerDecades = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.PPD)))
this.PointsPerDecades = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_PPD)))
if (this.$refs.PointsPerDecades != null) {
this.$refs.PointsPerDecades.itemChange(this.PointsPerDecades)
}
@@ -443,11 +426,6 @@ export default {
this.$refs.currentRangeSelect.updateLevelButton(this.currentRangeSelect)
}
this.voltageInRangeSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.ADC_LEVEL_V_IN_15
if (this.$refs.voltageInRangeSelect != null) {
this.$refs.voltageInRangeSelect.updateLevelButton(this.voltageInRangeSelect)
}
this.highzSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.CTRL_HIGH_Z_15
if (this.$refs.highzSelect != null) {
this.$refs.highzSelect.updateLevelButton(this.highzSelect)
@@ -463,12 +441,12 @@ export default {
this.$refs.stopVoltMinNumber.updateVoltNumber(this.stopVoltMinNumber)
}
this.voltInitialNumber = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.VOLT_INITIAL - 25000) / 5
this.voltInitialNumber = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.CV_E_INITIAL - 25000) / 5
if (this.$refs.voltInitialNumber != null) {
this.$refs.voltInitialNumber.updateVoltNumber(this.voltInitialNumber)
}
this.voltScanRateNumber = taskInfo.getDeviceInfo(this.deviceID).parameterSet.Scan_Rate
this.voltScanRateNumber = taskInfo.getDeviceInfo(this.deviceID).parameterSet.CV_SCAN_RATE
if (this.$refs.voltScanRateNumber != null) {
this.$refs.voltScanRateNumber.updateVoltScanRateNumber(this.voltScanRateNumber)
}
@@ -505,7 +505,7 @@ export default {
// },
// {
// id: 11,
// description: 'Cali ADC - test',
// description: 'Cali Mode - test',
// },
// {
// id: 12,
@@ -576,6 +576,10 @@ export default {
value: 1,
label: 'Vin',
},
{
value: 2,
label: 'Vout',
},
],
startVoltNumber: null,
stopVoltNumber: null,
@@ -1,6 +1,6 @@
<template>
<div>
<elite-parameter-recording-elitezm15 :ref="'rec_ref_2'" :deviceID="deviceID" @parameterChange="parameterChange"/>
<elite-parameter-recording-elitezm15 :ref="'rec_ref_2'" :deviceID="deviceID" @parameterChange="parameterChange" :place="'scheduler'"/>
<!-- <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"/>
+104 -32
View File
@@ -1,22 +1,30 @@
<template>
<div>
<va-card style="height: 90vh; overflow: auto; display: block;">
<!-- <pre>{{ getSelectProject }} </pre> -->
<va-card style="height: 88vh; overflow: auto; display: block;" @mousemove.native="mousemove">
<div id="project-view-show-btn" v-if="!projectManagerPanel.show" @click="showProjectManagerPanel">
<img id="project-view-show-btn-img" src="@/assets/img/project/arrow-right.svg">
</div>
<template slot="header">
<va-icon name="fa fa-bluetooth-b mr-3" color="primary"/>
<h5 class="mt-0 mb-0"> {{ getSelectProject ? getSelectProject.name : '' }}</h5>
<p class="project-view-header">{{ getSelectProject ? getSelectProject.name : '' }}</p>
</template>
<div v-if="getSelectProject === undefined">
<span>please select project</span>
</div>
<div v-else>
<project-menu/>
<project-table/>
<project-menu @detect="detect" @save_project="save"/>
<project-table @save="save"/>
<div align="right" v-if="lockMode === false">
<va-button @click="save">Save</va-button>
<va-button @click="start">Start</va-button>
<button class="project-start-btn" @click="start">
<div>
<img src='@/assets/img/project/play.svg' alt="start">
</div>
</button>
</div>
<div align="right" v-if="lockMode === true">
<va-button @click="stop">Stop</va-button>
<button class="project-stop-btn" @click="stop">
<img src='@/assets/img/project/stop.svg' alt="stop">
</button>
</div>
</div>
</va-card>
@@ -45,6 +53,7 @@ export default {
'deviceConnectList',
'projectSelectIndex',
'projectLibrary',
'projectManagerPanel',
]),
},
data () {
@@ -52,14 +61,48 @@ export default {
}
},
methods: {
showProjectManagerPanel: function () {
this.projectManagerPanel.show = true
},
mousemove: function (e) {
// define constant
const DETECT_X_MAX = 50
const DETECT_X_MIN = 0
// get element
const element = document.getElementById('project-view-show-btn')
if (!element) return
let x = e.offsetX
// console.log('e', e, e.srcElement.className, e.srcElement.id)
// if mouse on project
if (e.srcElement.id === 'project-view-show-btn' || e.srcElement.id === 'project-view-show-btn-img') {
element.style.opacity = 0.7
element.style.transform = 'rotate(90deg) translate(40vh, 25px)'
return
}
if (e.srcElement.className !== 'va-card__body' && e.srcElement.className !== 'va-card') {
element.style.transform = 'rotate(90deg) translate(40vh, 75px)'
return
}
if (x >= DETECT_X_MAX) x = DETECT_X_MAX
if (x < DETECT_X_MIN) x = DETECT_X_MIN
const offsetPercentage = Math.round(((DETECT_X_MAX - x) / DETECT_X_MAX) * 4) / 4
const newOffset = 75 - offsetPercentage * 50
element.style.opacity = offsetPercentage * 0.7
element.style.transform = 'rotate(90deg) translate(40vh, ' + String(newOffset) + 'px)'
},
start: function () {
this.$emit('start_project', this.getSelectProject)
},
stop: function () {
this.$emit('stop_project', this.getSelectProject)
},
save: function () {
this.$emit('save_project', this.getSelectProject)
save: function (project) {
this.$emit('save_project', project)
},
detect: function (device) {
this.$emit('detect', device)
},
...mapActions('project',
[
@@ -69,30 +112,59 @@ export default {
),
},
watch: {
projectSelectIndex: {
handler: async function () {
// console.log('device', this.deviceConnectList)
for (const device of this.deviceConnectList) {
var newDevice = {
uuid: this.GLOBAL.getUUID(),
name: device.mac_address,
product: device.device_name,
library: device.library_name,
connectDevice: device,
isSelect: [],
}
await this.addDeviceProject({ device: newDevice })
if (device.library_name !== undefined) {
this.projectLibrary = device.library_name
}
}
},
},
},
async mounted () {
// console.log('mounted')
// console.log(this.deviceConnectList)
// console.log(this.deviceConnectList.length)
},
}
</script>
<style lang="scss">
#project-view-show-btn {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 50px;
border-radius: 100px 100px 0 0;
background-color: #495057;
transform: rotate(90deg) translate(40vh, 75px);
transition: transform 0.1s linear;
}
#project-view-show-btn-img {
position: relative;
top: 5px;
left: 30px;
width: 40px;
height: 40px;
}
.project-view-header {
margin: 0.3rem 0 2rem 0;
font-family: 'Inter-ExtraBold';
// font-style: normal;
// font-weight: 800;
font-size: 24px;
line-height: 29px;
/* identical to box height */
color: #2c4053;
}
.project-start-btn {
width: 120px;
height: 50px;
background: #87d9d4;
border-radius: 8px;
border: white;
cursor: pointer;
}
.project-stop-btn {
width: 120px;
height: 50px;
background: #ff6c63;
border-radius: 8px;
border: white;
cursor: pointer;
}
</style>
+129 -31
View File
@@ -1,57 +1,155 @@
<template>
<div>
<div class="row">
<div class="flex d-flex">
<switch-project/>
<add-task/>
<add-device @showDeviceModal="showDeviceModal"/>
<!-- <clear-task/>
<save-project/>
<import-project/>
<export-project/>
<delete-project/> -->
<project-device @showDeviceModal="showDeviceModal" @save="saveProject"></project-device>
<div class="flex d-flex sm12 xs12 md6 xl4 px-0">
<add-task @save="saveProject"/>
<div>
<button class="add-cycle-btn" @click="showCycleModal">
<div class="add-cycle-text">
<p>Add Cycle</p>
</div>
</button>
</div>
<div>
<button class="copy-project-btn" @click="() => {
copyTask({ project: getSelectProject, index: projectTableSelectIndex})
saveProject()
}">
<img class="img-vertical-center" src="@/assets/img/project/copy.svg">
</button>
</div>
<div>
<button class="copy-project-btn" @click="saveProject(true)">
<img class="img-vertical-center" src="@/assets/img/project/save.svg">
</button>
</div>
<div>
<button class="copy-project-btn" @click="() => {
deleteTask({ project: getSelectProject, index: projectTableSelectIndex})
saveProject()
}">
<img class="img-vertical-center" src="@/assets/img/project/delete.svg">
</button>
</div>
</div>
<project-device @showDeviceModal="showDeviceModal($event)"></project-device>
<device-modal ref="device_modal_ref"></device-modal>
<new-device-modal ref="device_modal_ref" @detect="detect" @save="saveProject"></new-device-modal>
<cycle-modal ref="cycle_modal_ref" @createCycle="createCycle"></cycle-modal>
</div>
</template>
<script>
import SwitchProject from '@/components/project/view/menu/components/SwitchProject'
// import SwitchProject from '@/components/project/view/menu/components/SwitchProject'
import AddTask from '@/components/project/view/menu/components/AddTask'
// import ClearTask from '@/components/project/view/menu/components/ClearTask'
// import ExportProject from '@/components/project/view/menu/components/ExportProject'
// import ImportProject from '@/components/project/view/menu/components/ImportProject'
// import SaveProject from '@/components/project/view/menu/components/SaveProject'
// import DeleteProject from '@/components/project/view/menu/components/DeleteProject'
import AddDevice from '@/components/project/view/menu/components/AddDevice'
// import AddDevice from '@/components/project/view/menu/components/AddDevice'
import ProjectDevice from '@/components/project/view/menu/components/ProjectDevice'
import DeviceModal from '@/components/project/view/menu/components/DeviceModal'
import NewDeviceModal from '@/components/project/view/menu/components/NewDeviceModal'
import CycleModal from '@/components/project/view/menu/components/CycleModal'
import { mapFields } from 'vuex-map-fields'
import { mapActions, mapGetters } from 'vuex'
import types from '@/store/modules/project/types'
export default {
name: 'project-menu',
components: {
SwitchProject,
AddTask,
AddDevice,
// ClearTask,
// ExportProject,
// ImportProject,
// SaveProject,
// DeleteProject,
// AddDevice,
ProjectDevice,
DeviceModal,
NewDeviceModal,
CycleModal,
},
computed: {
...mapGetters('project', [
types.project.getSelect,
]),
...mapFields('project', [
'taskViewPanel',
'taskSelectKey',
'deviceSelectKey',
'lockMode',
'projectTableSelectIndex',
]),
},
data () {
return {
}
},
methods: {
showDeviceModal: function (device) {
this.$refs.device_modal_ref.show()
this.$refs.device_modal_ref.initSetting(device)
detect: function (device) {
this.$emit('detect', device)
},
showDeviceModal: function (key, device) {
this.$refs.device_modal_ref.show()
this.$refs.device_modal_ref.initSetting(key, device)
},
createCycle: function (cycleInfo) {
this.createCycleTask({ cycleInfo: cycleInfo })
},
showCycleModal: function () {
this.$refs.cycle_modal_ref.show()
this.$refs.cycle_modal_ref.reset()
},
saveProject: function (showMessage = false) {
if (showMessage === true) {
this.showToast(
'project update finish',
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 5000,
},
)
}
this.$emit('save_project', this.getSelectProject)
},
...mapActions('project',
[
types.task.copy,
types.task.delete,
types.task.rearrange,
types.task.createCycle,
],
),
},
}
</script>
<style lang="scss">
.add-cycle-btn {
margin-left: 0.5rem;
width: 120px;
height: 38px;
left: 0;
top: 0;
background: #87d9d4;
border: none;
border-radius: 8px;
cursor: pointer;
}
.add-cycle-text {
width: 110px;
height: 24px;
font-family: 'Inter-Bold';
font-style: normal;
font-weight: 700;
font-size: 16px;
line-height: 24px;
text-align: center;
color: #ffffff;
margin: 0 auto;
}
.copy-project-btn {
margin-left: 0.5rem;
width: 50px;
height: 38px;
background: #87d9d4;
border: none;
border-radius: 8px;
cursor: pointer;
}
.img-vertical-center {
vertical-align: middle;
}
</style>
@@ -1,6 +1,6 @@
<template>
<div>
<va-button @click="addDevice" small>ADD DEVICE</va-button>
<va-button @click="addDevice" small>+ DEVICE</va-button>
</div>
</template>
<script>
@@ -1,6 +1,13 @@
<template>
<div>
<va-button @click="createTask" small>ADD TASK</va-button>
<button class="add-task-btn" @click="() => {
createTask()
save()
}">
<div class="add-task-text">
<p>Add Task</p>
</div>
</button>
</div>
</template>
<script>
@@ -18,15 +25,39 @@ export default {
}
},
methods: {
save: function () {
this.$emit('save')
},
...mapActions('project',
[
types.task.init,
types.task.create,
types.task.save,
types.task.delete,
types.task.select,
],
),
},
}
</script>
<style lang="scss">
.add-task-btn {
width: 120px;
height: 38px;
left: 0;
top: 0;
background: #87d9d4;
border: none;
border-radius: 8px;
cursor: pointer;
}
.add-task-text {
width: 100px;
height: 24px;
font-family: 'Inter-Bold';
font-style: normal;
font-weight: 700;
font-size: 16px;
line-height: 24px;
text-align: center;
color: #ffffff;
margin: 0 auto;
}
</style>
@@ -0,0 +1,259 @@
<template>
<div>
<va-modal
class="flex sm12 xl12 md12 xs12"
v-model="showModal"
size="small"
:noOutsideDismiss="true"
hide-default-actions
>
<template slot="header">
<div class="d-flex mb-3">
<va-icon name="fa fa-bluetooth-b mr-3" color="primary"/>
<h5 v-if="Object.keys(cycleInfo).length == 0" class="mt-0 mb-0">Create Cycle</h5>
<h5 v-else class="mt-0 mb-0">{{ cycleInfo.name }}</h5>
</div>
</template>
<div class="row">
<div class="row flex sm6 xl6 md6 xs6">
<div class="flex sm2 xl2 md2 xs2 pt-2">
<span>Start</span>
</div>
<div class="flex sm8 xl8 md8 xs8">
<va-select
:label="''"
v-model="task.start"
textBy="name"
class="va-select-without-margin"
:options="taskOptions"
:noClear='true'
/>
</div>
</div>
<div class="row flex sm6 xl6 md6 xs6">
<div class="flex sm2 xl2 md2 xs2 pt-2">
<span>End</span>
</div>
<div class="flex sm8 xl8 md8 xs8">
<va-select
:label="''"
v-model="task.end"
textBy="name"
class="va-select-without-margin"
:options="taskOptions"
:noClear='true'
/>
</div>
</div>
<div class="row flex sm12 xl12 md12 xs12">
<div class="flex sm2 xl2 md2 xs2 pt-2">
<span> Cycle No. </span>
</div>
<div class="flex sm2 xl2 md2 xs2">
<va-input v-model="task.cycle"/>
</div>
</div>
<div class="row flex sm12 xl12 md12 xs12" style="height: 40px;">
<div class="flex sm1 xl1 md1 xs1">
<va-checkbox
v-model="task.useID"
/>
</div>
<div class="flex sm4 xl4 md4 xs4">
Use ID As Header
</div>
<div v-if="task.useID" class="flex sm4 xl4 md4 xs4">
<va-input v-model="task.id"></va-input>
</div>
</div>
<!-- <div class="row flex sm12 xl12 md12 xs12">
<div class="flex sm1 xl1 md1 xs1">
<va-checkbox
v-model="task.buttonTrigger"
/>
</div>
<div class="flex sm6 xl6 md6 xs6">
Wait Until Button Press In Next Loop
</div>
</div> -->
</div>
<div class="flex-center sm12 xl12 md12 xs12">
<va-button v-if="Object.keys(cycleInfo).length > 0" @click="removeCycle" color="danger">Remove</va-button>
<va-button @click="hide">Cancel</va-button>
<va-button @click="createCycle" @keyup.native="keyFunction($event,item)">OK</va-button>
</div>
</va-modal>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
import { mapActions, mapGetters } from 'vuex'
import types from '@/store/modules/project/types'
export default {
name: 'cycle-modal',
components: {
},
computed: {
...mapGetters('project', [
types.project.getSelect,
]),
...mapFields('project', [
'deviceConnectList',
'projectLibrary',
]),
},
data () {
return {
showModal: false,
taskOptions: [],
task: {
id: '',
name: '',
start: -1,
end: -1,
cycle: '1',
useID: false,
buttonTrigger: false,
uuid: '',
},
cycleInfo: {},
}
},
methods: {
show: function () {
this.showModal = true
// window.addEventListener('keydown', (e) => {
// console.log('e', e)
// if (e.keyCode === 13) {
// this.createCycle()
// }
// }, { once: true })
},
hide: function () {
this.showModal = false
},
createCycle: async function () {
const project = this.getSelectProject
if (Object.keys(this.cycleInfo).length === 0) {
this.$emit('createCycle', this.task)
}
if (Object.keys(this.cycleInfo).length !== 0) {
this.cycleInfo.max = this.task.cycle
this.cycleInfo.name = this.task.name
this.cycleInfo.useID = this.task.useID
this.cycleInfo.id = this.task.id
const originStartIndex = await this.getIndexTask({ project: project, uuid: this.cycleInfo.range[0] })
const newStartIndex = await this.getIndexTask({ project: project, uuid: this.task.start.value })
if (this.task.useID === true) {
const condition = project.task[originStartIndex].condition
const action = project.task[originStartIndex].action
delete condition[(Object.keys(condition).find(key => condition[key].type === 'after_task_run'))]
const conditionUUID = this.GLOBAL.getUUID()
const newCond = await this.createConditionTask({ uuid: conditionUUID, condition: 'until_button_trigger', compOp: 'equal', value: '' })
project.task[originStartIndex].condition = Object.assign({}, condition, newCond)
action[Object.keys(action).find(key => action[key].type === 'cycle')].condition.push(conditionUUID)
project.task[originStartIndex].name = this.task.name
} else {
const condition = project.task[originStartIndex].condition
const action = project.task[originStartIndex].action
delete condition[(Object.keys(condition).find(key => condition[key].type === 'until_button_trigger'))]
const conditionUUID = this.GLOBAL.getUUID()
const newCond = await this.createConditionTask({ uuid: conditionUUID, condition: 'after_task_run', compOp: 'equal', value: '0' })
project.task[originStartIndex].condition = Object.assign({}, condition, newCond)
action[Object.keys(action).find(key => action[key].type === 'cycle')].condition.push(conditionUUID)
}
if (Number(originStartIndex) + 1 !== Number(newStartIndex)) {
await this.swapTask({ project: project, originIndex: originStartIndex, newIndex: newStartIndex })
}
const originEndIndex = await this.getIndexTask({ project: project, uuid: this.cycleInfo.range[1] })
const newEndIndex = await this.getIndexTask({ project: project, uuid: this.task.end.value })
project.task[originEndIndex].name = this.task.name
if (Number(originEndIndex) - 1 !== Number(newEndIndex)) {
await this.swapTask({ project: project, originIndex: originEndIndex, newIndex: newEndIndex + 1 })
}
}
this.$emit('save')
this.showModal = false
return true
},
removeCycle: async function () {
const project = this.getSelectProject
// remove project cycle
project.cycle.splice(project.cycle.findIndex(ele => ele.name === this.cycleInfo.name), 1)
// remove left cycle task
const originStartIndex = await this.getIndexTask({ project: project, uuid: this.cycleInfo.range[0] })
await this.deleteTask({ project: project, index: originStartIndex })
// remove right cycle task
const originEndIndex = await this.getIndexTask({ project: project, uuid: this.cycleInfo.range[1] })
await this.deleteTask({ project: project, index: originEndIndex })
this.$emit('save')
this.showModal = false
return true
},
updateTaskOptions: function () {
const taskOptions = []
const project = this.getSelectProject
for (var idx = 0; idx < project.task.length; idx++) {
if (Object.keys(this.cycleInfo).length !== 0) {
if (this.cycleInfo.range.findIndex(ele => ele === project.task[idx].uuid) !== -1) continue
}
taskOptions.push({
id: idx,
name: project.task[idx].name,
value: project.task[idx].uuid,
})
}
this.taskOptions = taskOptions
},
reset: function () {
this.updateTaskOptions()
this.task.start = this.taskOptions[0]
this.task.end = this.taskOptions[this.taskOptions.length - 1]
},
setCycleInfo: async function (project, uuid) {
this.cycleInfo = project.cycle.find(ele => ele.range.find(ele => ele === uuid))
const startIndex = await this.getIndexTask({ project: project, uuid: this.cycleInfo.range[0] }) + 1
const endIndex = await this.getIndexTask({ project: project, uuid: this.cycleInfo.range[1] }) - 1
this.updateTaskOptions()
this.task.start = this.taskOptions[this.taskOptions.findIndex(ele => ele.value === project.task[startIndex].uuid)]
this.task.end = this.taskOptions[this.taskOptions.findIndex(ele => ele.value === project.task[endIndex].uuid)]
this.task.name = this.cycleInfo.name
this.task.cycle = this.cycleInfo.max
this.task.useID = this.cycleInfo.useID
this.task.id = this.cycleInfo.id
},
...mapActions('project',
[
types.project.addDevice,
types.project.findDevice,
types.project.setDevice,
types.task.init,
types.task.create,
types.task.save,
types.task.delete,
types.task.select,
types.task.getIndex,
types.task.swap,
types.task.createCondition,
],
),
},
mounted () {
},
}
</script>
@@ -0,0 +1,155 @@
<template>
<div>
<va-modal
class="flex sm12 xl12 md12 xs12"
v-model="showModal"
size="small"
:noOutsideDismiss="true"
hide-default-actions
>
<template slot="header">
<div class="d-flex mb-3">
<va-icon name="fa fa-bluetooth-b mr-3" color="primary"/>
<h5 class="mt-0 mb-0">Choose Device</h5>
</div>
</template>
<va-list fit class="mb-2 pb-0">
<va-list-label>
Connect
</va-list-label>
<va-item v-if="deviceList.length === 0">
<va-item-section>
There is no connected device.
</va-item-section>
</va-item>
<template v-else v-for="(device, index) in deviceList">
<va-item :class="deviceSelect === index ? 'device-list-focus': ''" :key="'connect-' + index" @click="selectDevice(device, index)" clickable>
<va-item-section avatar>
<va-avatar style="border-radius: 0;">
<img src='@/assets/img/elite_img.png' :alt="device.macAddress">
</va-avatar>
</va-item-section>
<va-item-section>
{{ device.macAddress }}
</va-item-section>
<va-item-section side>
<va-icon name="fa fa-map-marker" color="gray" @click.native="detect(device.macAddress)"/>
</va-item-section>
</va-item>
<!-- <va-list-separator v-if="index < deviceList.length - 1" :key="'separator-' + index" /> -->
</template>
</va-list>
<div class="flex-center sm12 xl12 md12 xs12">
<va-button color='danger' @click="removeDevice">Remove</va-button>
<va-button @click="hide">Cancel</va-button>
<va-button @click="changeDevice">OK</va-button>
</div>
</va-modal>
</div>
</template>
<script>
// import { mapFields } from 'vuex-map-fields'
import { mapActions, mapGetters } from 'vuex'
import types from '@/store/modules/project/types'
export default {
name: 'add-device-modal',
components: {
},
computed: {
optionDeviceVersion () {
return (this.optionDeviceVersionObj[this.device.product.value] !== undefined)
? this.optionDeviceVersionObj[this.device.product.value]
: undefined
},
...mapGetters('project', [
types.project.getSelect,
types.project.getDeviceShowName,
]),
// ...mapFields('project', [
// 'deviceConnectList',
// ]),
},
data () {
return {
showModal: false,
showDisplayDevice: false,
key: '',
device: {},
deviceList: [],
deviceSelect: -1,
}
},
methods: {
show: function () {
this.showModal = true
},
hide: function () {
this.showModal = false
},
detect: function (device) {
if (device) this.$emit('detect', device)
},
selectDevice: function (device, index) {
this.deviceSelect = index
},
changeDevice: function () {
if (this.deviceList[this.deviceSelect]) {
this.device.pair = this.deviceList[this.deviceSelect].macAddress
}
this.$emit('save')
this.hide()
},
removeDevice: function () {
this.deleteDeviceProject({ deviceKey: this.key })
this.$emit('save')
this.hide()
},
getDeviceList: async function (device) {
const deviceList = await this.checkNotRegisterDeviceProject({ library: device.library })
const _device = { macAddress: device.pair, library: device.library }
if (device.pair !== null) {
this.deviceList = [_device, ...deviceList]
} else {
this.deviceList = [...deviceList]
}
},
initSetting: function (key, device) {
this.key = key
this.device = device
this.deviceList = []
this.deviceSelect = 0
this.getDeviceList(device)
},
...mapActions('project',
[
types.project.addDevice,
types.project.findDevice,
types.project.setDevice,
types.project.deleteDevice,
types.project.checkNotRegisterDevice,
types.task.init,
types.task.create,
types.task.save,
types.task.delete,
types.task.select,
],
),
},
mounted () {
},
}
</script>
<style lang="scss">
.device-list-focus {
background: #ebedff;
border: 1px solid #dbdcf0;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
border-radius: 5px;
}
</style>
@@ -1,13 +1,44 @@
<template>
<div class="row">
<div class="flex d-flex">
<div v-for="(device, index) in getSelectProject.device" :key="index">
<va-button color="info" @click="showDeviceModal(device)" small>
<va-icon name="fa fa-close" @click.native.stop="deleteDevice(index)"></va-icon>
{{ device.name }} {{ device.connectDevice && device.connectDevice.device_address }}
</va-button>
<div class="flex d-flex sm12 xs12 md12 xl12 pa-0" style="align-items: center; margin-left: 0.6rem; margin-top: -12px;">
<!-- header -->
<div class="flex sm3 xs3 md3 xl1 px-0 project-device-header-text">
<p>Device</p>
</div>
<!-- create persudo devcie -->
<div class="flex d-flex" v-if="showLibrary === true">
<div class="flex d-flex pa-0 sm12 xs12 md6 xl3">
<div>
<button class="pair-button" @click="clickShowDevice('EDC')">
<span class="pair-button-text">EDC</span>
</button>
</div>
<div class="ml-2">
<button class="pair-button" @click="clickShowDevice('EIS')">
<span class="pair-button-text">EIS</span>
</button>
</div>
<div class="ml-2">
<button class="pair-button" @click="cancelSelectDevice()">
<span class="pair-button-text">X</span>
</button>
</div>
</div>
</div>
<!-- device list -->
<div class="flex d-flex" v-if="showDevice === false && showLibrary === false">
<draggable class="d-flex" :list="deviceListInOrder" :move="handleMove" @end="handleDragEnd">
<!-- devices -->
<div class="mr-2" v-for="(device, index) in deviceListInOrder" :key="index">
<button :class="device[1].pairStatus === 1 ? 'pair-button mr-2' : 'not-pair-button mr-2'" @click="showDeviceModal(device[0], device[1])">
<span class="pair-button-text">{{ getDeviceShowNameProject(device[0]) }}</span>
</button>
</div>
<!-- append device -->
<div v-if="deviceListInOrder.length < 4">
<button class="add-button" icon="fa fa-plus" @click="clickShowLibrary"><span class="add-button-text">+</span></button>
</div>
</draggable>
</div>
</div>
</template>
@@ -15,46 +46,171 @@
import { mapFields } from 'vuex-map-fields'
import { mapActions, mapGetters } from 'vuex'
import types from '@/store/modules/project/types'
import draggable from 'vuedraggable'
export default {
name: 'project-device',
components: {
draggable,
},
computed: {
deviceListInOrder () {
return Object.entries(this.getSelectProject.device).sort((a, b) => a[1].order - b[1].order)
},
...mapGetters('project', [
types.project.getSelect,
types.project.getDeviceShowName,
types.project.getDeviceMaxOrder,
]),
...mapFields('project', [
'projectLibrary',
'projectSelectIndex',
]),
},
data () {
return {
showDevice: false,
showLibrary: false,
notRegisterDevice: [],
index: -1,
futureIndex: -1,
}
},
methods: {
showDeviceModal: function (device) {
this.$emit('showDeviceModal', device)
clickShowLibrary: async function () {
this.notRegisterDevice = await this.checkNotRegisterDeviceProject({})
if (this.notRegisterDevice.length === 0) {
this.showLibrary = true
return true
}
await this.createDeviceProject({
name: this.notRegisterDevice[0].name,
library: this.notRegisterDevice[0].library,
pair: this.notRegisterDevice[0].macAddress,
pairStatus: 1,
order: this.getDeviceMaxOrderProject,
})
this.$emit('save')
return true
},
clickShowDevice: async function (library) {
this.showLibrary = false
await this.createDeviceProject({
name: library + '-' + String(Object.keys(this.getSelectProject.device).length + 1),
library: library,
pair: null,
pairStatus: 0,
order: this.getDeviceMaxOrderProject,
})
this.$emit('save')
return false
},
cancelSelectDevice: function () {
this.showLibrary = false
},
showDeviceModal: function (key, device) {
this.$emit('showDeviceModal', key, device)
},
deleteDevice: function (deviceIndex) {
this.deleteDeviceProject({ index: deviceIndex })
this.$emit('save')
},
handleMove (e) {
const { index, futureIndex } = e.draggedContext
this.index = index
this.futureIndex = futureIndex
return false // disable sort
},
handleDragEnd () {
const changeList = ['name', 'library', 'pair', 'pairStatus']
const deviceListTemp = JSON.parse(JSON.stringify(this.deviceListInOrder))
const keyOld = deviceListTemp[this.index][0]
const keyNew = deviceListTemp[this.futureIndex][0]
const deviceList = this.getSelectProject.device
for (const key of changeList) {
deviceList[keyOld][key] = deviceListTemp[this.futureIndex][1][key]
deviceList[keyNew][key] = deviceListTemp[this.index][1][key]
}
this.$emit('save')
},
...mapActions('project',
[
types.project.createDevice,
types.project.deleteDevice,
types.project.checkNotRegisterDevice,
types.project.checkPairDeviceExist,
],
),
},
mounted () {
for (const device in this.getSelectProject.device) {
if (this.projectLibrary === null) {
this.projectLibrary = this.getSelectProject.device[device].library.value
}
}
},
watch: {
projectSelectIndex: {
immediate: true,
handler: async function (val) {
console.log('projectSelectIndex', val)
this.checkPairDeviceExistProject()
},
},
},
}
</script>
<style lang="scss">
.add-button {
width: 38px;
height: 36px;
background: #e0e0e0;
border: 2px dashed #b7b7b7;
border-radius: 20px;
}
.add-button-text {
color: white;
font-size: 20px;
font-weight: bold;
}
.pair-button {
width: 100%;
height: 36px;
background: #858dd6;
border: 0;
border-radius: 20px;
}
.not-pair-button {
width: 100%;
height: 36px;
background: #e0e0e0;
border: 0;
border-radius: 20px;
}
.pair-button-text {
font-family: 'Inter-Regular';
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 24px;
text-align: center;
color: #ffffff;
}
.project-device-header-text {
align-items: center;
// font-family: 'Inter-Regular';
// font-style: normal;
font-weight: 700;
font-size: 20px;
line-height: 29px;
/* identical to box height */
color: rgb(52, 73, 94);
// color: #768b9b;
}
</style>
+551 -143
View File
@@ -1,66 +1,124 @@
<template>
<div class="markup-tables project-table flex d-flex sm12 xl12 md12 xs12" id="scro" style="height: 66vh; overflow: auto;">
<div class="table-wrapper">
<table class="va-table">
<div class="markup-tables project-table flex d-flex sm12 xl12 md12 xs12 px-0 mx-0" id="scro" style="width: 100%; height: 55vh; overflow: auto; padding-top: 0;">
<div class="table-wrapper" style="width: 100%;">
<table class="va-table project-table-text">
<thead>
<tr>
<th v-if="lockMode === false">
<va-checkbox
v-model="tableColumn.checked"
:array-value="'-1'"
@input="selectAll($event)"
/>
</th>
<th align="center">order</th>
<th align="center">name</th>
<tr class="project-table-header">
<th align="center" style="min-width: 50px; padding: 0;">order</th>
<th align="center" style="min-width: 100px;">name</th>
<th align="center" @click="openConfig(1)">device</th>
<th align="center">action and condition</th>
<th align="center">parameter</th>
<th align="center"></th>
<th align="center" style="min-width: 100px;">start</th>
<th align="center" style="min-width: 100px;">stop</th>
<th align="center" style="min-width: 100px;">parameter</th>
<!-- <th v-if="lockMode" align="center">cycle</th> -->
<th align="center" style="min-width: 50px;"></th>
</tr>
</thead>
<!-- <tbody> -->
<vuedraggable class="draggable" v-model="getSelectProject.task" @start="() => {}" @end="() => {}" tag="tbody" animation="500">
<vuedraggable :disabled="lockMode === true || inputMode === true" class="draggable" :list="getSelectProject.task" @end="()=> {
rearrangeTask({ project: getSelectProject })
saveProject()
}" tag="tbody" animation="500">
<template class="item" v-for="(task, taskIndex) in getSelectProject.task">
<tr v-if="task.device && task.device.length === 0" :key="taskIndex" height="80px">
<td v-if="lockMode === false">
<va-checkbox
v-model="tableColumn.checked"
:array-value="String(taskIndex)"
/>
</td>
<tr
v-if="task.type === 'cycle'"
:key="'empty' + taskIndex"
height="50px"
@click="showCycleModal(task.uuid)"
>
<td align="center">
{{ taskIndex + 1 }}
</td>
<td align="center">
{{ task.name }}
<td align="center" @dblclick="switchInput('name', taskIndex)">
<div v-if="tableColumn.name == taskIndex && getCycleInfo(task.uuid, 'useID') === true && lockMode === true">
<va-input
v-model="inputSaved"
style="width: 100px;"
@blur="switchCycle('name', -1, getSelectProject, task)"
@keyup.enter="switchCycle('name', -1, getSelectProject, task)"
/>
</div>
<div v-else>
<div v-if="getCycleInfo(task.uuid, 'useID') === true">
{{ getCycleInfo(task.uuid, 'id') }}
</div>
<div v-if="getCycleInfo(task.uuid, 'useID') === false">
{{ getCycleInfo(task.uuid, 'name') }}
</div>
</div>
</td>
<td align="center">
<va-button :flat="true" @click="openConfig(1, taskIndex)" small>Add Device</va-button>
<td align="center" v-if="getCycleLocation(task.uuid) === 'start'">
{{ getCycleInfo(task.uuid, 'max') }} Rounds
</td>
<td align="center">
<va-button :flat="true" @click="openConfig(3, taskIndex)" small>+ New Action/Condition</va-button>
<td v-if="lockMode === true && getCycleLocation(task.uuid) === 'start'">
{{ getCycleInfo(task.uuid, 'count') }} / {{ getCycleInfo(task.uuid, 'max') }}
</td>
<td align="center">
<va-button :flat="true" @click="openConfig(4, taskIndex)" small>Add Parameter</va-button>
</td>
<td align="center">
<va-icon class="fa fa-close" @click.native="() => deleteTask({ index: taskIndex})"></va-icon>
<td v-if="lockMode === true && Object.values(task.condition).findIndex(ele => ele.type == 'until_button_trigger') != -1 && task.status === 1">
<va-button icon="fa fa-play" @click="trigger_button(getSelectProject)" flat></va-button>
<td/>
<td align="center" v-if="lockMode === true">
<fulfilling-bouncing-circle-spinner
v-if="task.status === 1"
:animation-duration="3000"
:color="'#6c7fee'"
:size="16"
></fulfilling-bouncing-circle-spinner>
<!-- <va-icon v-if="task.status === 2" class="fa fa-check"></va-icon> -->
</td>
</tr>
<tr v-else v-for="(deviceUUID) in task.device" :key="taskIndex + deviceUUID" height="80px">
<td v-if="lockMode === false">
<va-checkbox
v-model="tableColumn.checked"
:array-value="String(taskIndex)"
/>
</td>
<tr
v-else-if="task.device && task.device.length === 0"
:class="taskIndex === projectTableSelectIndex ? 'table-row-focus' : ''"
:key="'empty' + taskIndex" height="50px"
@click="() => { projectTableSelectIndex = taskIndex }"
>
<td align="center">
{{ taskIndex + 1 }}
{{ taskIndex + 1 }}
</td>
<!-- name -->
<td align="center" @dblclick="switchInput('name', taskIndex)">
<div v-if="tableColumn.name == taskIndex && lockMode === false">
<va-input
:ref="'input_ref'"
v-model="task.name"
style="width: 100px;"
@blur="switchInput('name', -1)"
@keyup.enter="switchInput('name', -1)"
/>
</div>
<div v-else align="center">
{{ task.name }}
</div>
</td>
<td align="center">
<va-button :flat="true" @click="openConfig(1, taskIndex)" small>+</va-button>
</td>
<td align="center">
<va-button :flat="true" @click="openConfig(2, taskIndex)" :disabled="true" small>-</va-button>
</td>
<td align="center">
<va-button :flat="true" @click="openConfig(3, taskIndex)" :disabled="true" small>-</va-button>
</td>
<td align="center">
<va-button :flat="true" @click="openConfig(4, taskIndex)" :disabled="true" small>-</va-button>
</td>
</tr>
<tr
v-else
height="50px"
:class="taskIndex === projectTableSelectIndex ? 'table-row-focus' : ''"
:key="String(taskIndex)"
@click="() => { projectTableSelectIndex = taskIndex }"
>
<!-- order -->
<td align="center">
{{ taskIndex + 1 }}
</td>
<!-- name -->
<td align="center" @dblclick="switchInput('name', taskIndex)">
<div v-if="tableColumn.name == taskIndex && lockMode === false">
<va-input
:ref="'input_ref'"
v-model="task.name"
style="width: 100px;"
@blur="switchInput('name', -1)"
@@ -68,9 +126,6 @@
/>
</div>
<div v-else>
<!-- <vuedraggable class="draggable">
{{ task.name }}
</vuedraggable> -->
{{ task.name }}
</div>
</td>
@@ -78,65 +133,110 @@
<td align="center">
<div v-if="task.device && task.device.length === 0">
<va-button :flat="true" @click="openConfig(1, taskIndex, deviceUUID)" small>
Add device
+ Device
</va-button>
</div>
<div v-else>
<va-button :flat="true" @click="openConfig(1, taskIndex, deviceUUID)" small>
<span>{{ getDeviceProject(deviceUUID) && getDeviceProject(deviceUUID).name }}</span>
</va-button>
<div class="flex project-table-cell" v-for="(deviceUUID) in task.device" :key="deviceUUID" @click="openConfig(1, taskIndex, deviceUUID)">
<p>{{ getDeviceShowNameProject(deviceUUID)}}</p>
</div>
</div>
</td>
<!-- device end -->
<!-- action -->
<!-- start -->
<td align="center">
<div v-if="Object.keys(task.action).length === 0">
<va-button :flat="true" @click="openConfig(3, taskIndex, deviceUUID)" small>
Add event
</va-button>
</div>
<div v-else class="flex">
<div class="flex project-table-cell" v-for="(deviceUUID) in task.device" :key="deviceUUID">
<div v-if="Object.values(task.action).filter(ele => ele.type === 'start' && ele.target === deviceUUID).length === 0">
+
</div>
<div v-for="(action, actionKey) in task.action" :key="actionKey">
<div v-if="action.target === deviceUUID">
<div v-for="conditionKey in action.condition" :key="conditionKey">
<div small>
{{ action.type }} {{ task.condition[conditionKey].type }} {{ task.condition[conditionKey].value }}
<div v-if="action.condition.length === 0">
+
</div>
<div v-else v-for="conditionKey in action.condition" :key="conditionKey">
<div v-if="action.type == 'start' && task.condition[conditionKey].type === 'previous_task_done'">
<div v-if=" taskIndex === 0"> - </div>
<div v-else> Follow {{ getSelectProject.task[taskIndex - 1].name }} </div>
</div>
</div>
</div>
</div>
</div>
</td>
<!-- start end -->
<!-- stop -->
<td align="center">
<div class="flex project-table-cell" v-for="(deviceUUID) in task.device" :key="deviceUUID" @click="openConfig(3, taskIndex, deviceUUID)">
<div v-if="Object.values(task.action).filter(ele => ele.type === 'stop' && ele.target === deviceUUID).length === 0">
+
</div>
<div v-for="(action, actionKey) in task.action" :key="actionKey">
<div v-if="action.target === deviceUUID">
<div v-if="action.condition.length === 0">
+
</div>
<div v-else v-for="conditionKey in action.condition" :key="conditionKey">
<div v-if="action.type == 'stop' && task.condition[conditionKey].type === 'after_task_run'" >
{{ transTime(task.condition[conditionKey].value) }}
<va-icon class="fa fa-close" @click.native="delAction(task, actionKey, conditionKey)"/>
</div>
</div>
</div>
</div>
<va-button :flat="true" @click="openConfig(3, taskIndex, deviceUUID)" small>
+ New Action/Condition
</va-button>
</div>
</td>
<!-- action end -->
<!-- stop end -->
<td align="center">
<div v-if="Object.keys(task.parameter_set).length === 0">
<va-button :flat="true" @click="openConfig(4, taskIndex, deviceUUID)" small>
Add Parameter
</va-button>
</div>
<va-button :flat="true" @click="openConfig(4, taskIndex, deviceUUID)" v-else class="flex d-flex">
<div class="flex" small>
<div v-for="(parameterSet, parameterSetKey) in getParameterSetTask(taskIndex, deviceUUID)" :key="parameterSetKey">
<div v-for="(parameter, parameterKey) in parameterSet" :key="parameterKey">
<span v-if="parameterKey !== 'target'">
<div small>
{{ parameterName(parameterKey) }} : {{ parameterValue(parameterKey, parameter) }}
</div>
</span>
</div>
</div>
<div class="flex project-table-cell" v-for="(deviceUUID) in task.device" :key="deviceUUID" @click="openConfig(4, taskIndex, deviceUUID)">
<div v-if="Object.values(task.parameter_set).filter(ele => ele.target === deviceUUID).length === 0" >
<p>
+
</p>
</div>
</va-button>
<div style="height: auto;" v-for="(parameterSet, parameterSetKey) in getParameterSetTask(taskIndex, deviceUUID)" :key="parameterSetKey">
<v-popover
placement="right"
trigger="hover"
popoverBaseClass="tooltip popover test"
:disabled="!Object.keys(parameterSet).filter(ele=>ele !== 'MODE' && ele !== 'target').length > 0"
>
<div class="tooltip-target">
{{ parameterName('MODE', deviceUUID) }} : {{ parameterValue('MODE', parameterSet.MODE, deviceUUID) }}
</div>
<template slot="popover">
<div>
<div v-for="(parameter) in parameterShow(parameterSet.MODE, deviceUUID)" :key="parameter + parameterSet.MODE">
<p v-if="getConfig(deviceUUID).includes('TRIG') === true">
{{ parameterPair(parameter, parameterSet, deviceUUID) }}
</p>
<p v-else>
{{ parameterName(parameter, deviceUUID) }} : {{ parameterValue(parameter, parameterSet[parameter], deviceUUID) }}
</p>
</div>
</div>
</template>
</v-popover>
</div>
</div>
</td>
<td align="center" v-if="lockMode === false">
<va-icon v-if="String(taskIndex) !== '0'" class="fa fa-toggle-up" @click.native="swapTask(taskIndex, 0)"/>
<!-- <va-icon v-if="String(taskIndex) !== '0'" class="fa fa-toggle-up" @click.native="swapTask(taskIndex, 0)"/>
<va-icon v-if="parseInt(taskIndex) !== getSelectProject.task.length - 1" class="fa fa-toggle-down" @click.native="swapTask(taskIndex, 1)"/>
<va-icon class="fa fa-close" @click.native="() => deleteTask({ index: taskIndex})"></va-icon>
<va-icon class="fa fa-copy ml-1" @click.native="() => copyTask({ project: getSelectProject, index: taskIndex})"></va-icon> -->
<va-icon class="fa fa-close" color="#B8C3CC" @click.native="() => deleteTask({ project: getSelectProject, index: taskIndex})"></va-icon>
</td>
<!-- <td align="center" v-if="lockMode === true">
<div v-if="task.cycle > 0 && task.status === 2 && task.cycle_count === 0">
{{ task.cycle }}/{{ task.cycle }}
</div>
<div v-else-if="task.cycle > 0">
{{ task.cycle_count }}/{{ task.cycle }}
</div>
</td> -->
<!-- <td v-if="lockMode === true && Object.values(task.condition).findIndex(ele => ele.type == 'until_button_trigger') != -1 && task.status === 1">
<va-button icon="fa fa-play" @click="trigger_button(getSelectProject)" flat></va-button>
<td/> -->
<td align="center" v-if="lockMode === true">
<!-- {{ task.status }} -->
<fulfilling-bouncing-circle-spinner
@@ -150,9 +250,15 @@
</tr>
</template>
</vuedraggable>
<!-- </tbody> -->
<!-- </tbody> -->
<tr class="table-row-add-task" v-if="lockMode === false">
<td align="center" colspan="7" class="table-row-add-task-text" @click="createTask">+ task</td>
</tr>
</table>
</div>
<div>
<cycle-modal ref="cycle_modal_ref" @save="saveProject"></cycle-modal>
</div>
</div>
</template>
<script>
@@ -162,12 +268,15 @@ import types from '@/store/modules/project/types'
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
import configTable from '@/data/config-table/index'
import vuedraggable from 'vuedraggable'
import { taskInfo } from '@/data/task/TaskInfo'
import CycleModal from '@/components/project/view/menu/components/CycleModal'
export default {
name: 'project-table',
components: {
FulfillingBouncingCircleSpinner,
vuedraggable,
CycleModal,
},
computed: {
config () {
@@ -177,6 +286,9 @@ export default {
...mapGetters('project', [
types.project.getSelect,
types.project.getDevice,
types.project.getCycle,
types.project.getDeviceLibrary,
types.project.getDeviceShowName,
types.task.get,
types.task.getCondition,
types.task.getParameterSet,
@@ -188,6 +300,7 @@ export default {
'deviceSelectKey',
'lockMode',
'projectLibrary',
'projectTableSelectIndex',
]),
},
data () {
@@ -196,29 +309,61 @@ export default {
name: -1,
checked: [],
},
inputSaved: '',
index: -1,
futureIndex: -1,
inputMode: false,
}
},
methods: {
transTime: function (sec) {
if (sec === undefined || sec === 'None') {
return '0 s'
}
let result = ''
if (sec < 1) {
result = '~ 1 s'
} else {
let seconds = parseInt(sec / 1)
if (seconds < 60) {
result = `${seconds} sec`
} else {
let minutes = parseInt(seconds / 60)
seconds %= 60
if (minutes < 60) {
if (seconds === 0) {
result = `${minutes} min`
} else {
result = `${minutes} m ${seconds} s`
}
} else {
const hours = parseInt(minutes / 60)
minutes %= 60
if (seconds === 0 && minutes === 0) {
result = `${hours} hour`
} else {
result = `${hours} h ${minutes} m ${seconds} s`
}
}
}
}
return result
},
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
dragEnd: function (event) {
console.log('event', event)
console.log('from', event.oldDraggableIndex)
console.log('to', event.newDraggableIndex)
const newTaskList = JSON.parse(JSON.stringify(this.getSelectProject.task))
console.log('this.getSelectProject.task', newTaskList, this.getSelectProject.task)
const b = newTaskList[event.oldDraggableIndex]
const a = newTaskList[event.newDraggableIndex]
console.log('a', a)
console.log('b', b)
console.log('b.device.length', b.device.length)
if (b && b.device.length === 0) return
console.log('1')
// newTaskList.splice(event.newDraggableIndex, 1, this.getSelectProject.task[event.oldDraggableIndex])
if (a === undefined) return
console.log('2')
// newTaskList.splice(event.oldDraggableIndex, 1, a)
newTaskList.filter(ele => ele != null)
console.log('newTaskList', newTaskList)
// this.getSelectProject.task = newTaskList
this.rearrangeTask({ project: this.getSelectProject })
this.saveProject()
},
swapTask: function (taskIndex, upDown) {
taskIndex = parseInt(taskIndex)
@@ -231,40 +376,67 @@ export default {
this.getSelectProject.task.splice(taskIndex, 1, this.getSelectProject.task[taskIndex + 1])
this.getSelectProject.task.splice(taskIndex + 1, 1, a)
}
this.rearrangeTask({ project: this.getSelectProject })
this.saveProject()
},
delSelected: function () {
for (const indexSelected of this.tableColumn.checked) {
this.deleteTask({ index: indexSelected })
this.deleteTask({ project: this.getSelectProject, index: indexSelected })
}
this.saveProject()
},
delAction: function (task, actionKey, conditionKey) {
// console.log(action)
// console.log(conditionKey)
// console.log(action.condition[0])
// console.log(action.condition.length)
// for (let i = 0; i < action.condition.length; i++) {
// if (String(action.condition[i]) === String(conditionKey)) {
// delete action.condition[i]
// break
// }
// }
const _action = JSON.parse(JSON.stringify(task.action))
const _condition = JSON.parse(JSON.stringify(task.condition))
// console.log(Object.keys(_task.action))
delete _action[actionKey]
delete _condition[conditionKey]
// delete _task.action[actionKey]
// delete _task.condition[conditionKey]
// console.log(Object.keys(_task.action))
task.action = _action
task.condition = _condition
console.log('task', task)
// delete action.condition[0]
this.saveProject()
},
saveProject: function () {
console.log('saveProject')
this.$emit('save', this.getSelectProject)
},
trigger_button: function (projectID) {
console.log('project', projectID)
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'set_project/0',
project: projectID.uuid,
content: 'test',
}))
},
switchInput: function (tag, index) {
this.tableColumn[tag] >= 0
? this.tableColumn[tag] = -1
: this.tableColumn[tag] = index
if (this.tableColumn[tag] === -1) {
if (index !== -1) {
this.inputMode = true
this.tableColumn[tag] = index
this.$nextTick(() => {
this.$refs.input_ref[0].$refs.input.focus()
})
}
} else {
this.inputMode = false
this.tableColumn[tag] = -1
}
this.saveProject()
},
switchCycle: function (tag, index, projectID, task) {
this.switchInput(tag, index)
const cycleInfo = this.getCycleProject(task.uuid) // 0: index, 1: location, 2: info
if (this.inputSaved === cycleInfo[2].id) return
cycleInfo[2].id = this.inputSaved
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'set_project_cycle/0',
project: projectID.uuid,
index: cycleInfo[0],
content: { id: this.inputSaved },
}))
this.$emit('save', this.getSelectProject)
},
selectAll: function (selectedArray) {
const totalRange = [...Array(this.getSelectProject.task.length).keys()].map(idx => String(idx))
@@ -291,34 +463,109 @@ export default {
}
}
},
parameterName (name) {
if (this.config !== undefined && Object.keys(this.config) !== 0) {
parameterShow (mode, deviceKey) {
const config = configTable.getConfig(this.getDeviceLibraryProject(deviceKey))
if (config !== undefined && Object.keys(config) !== 0) {
if (this.getDeviceLibraryProject(deviceKey).includes('TRIG')) return config.MODE[mode].showParameter
return config.MODE[mode].parameter
}
},
parameterPair (name, valueSet, deviceKey) {
let _name, _value
const config = configTable.getConfig(this.getDeviceLibraryProject(deviceKey))
if (config !== undefined && Object.keys(config) !== 0) {
if (this.getDeviceLibraryProject(deviceKey).includes('TRIG')) {
if (name.includes('ACC_a_out')) {
const accName = name + '_current'
if (Boolean(valueSet[name]) === true) {
_name = 'Channel' + String((parseInt(name.replace('ACC_a_out', '')) + 1))
const scale = config[accName].unit[config[accName].defaultUnit]
_value = `${config[accName].outputReadabilityData(valueSet[accName], scale)} ${config[accName].defaultUnit}`
} else return ''
} else if (name.includes('TRIG')) {
if (Boolean(valueSet[name]) === true) {
const optionTrigger = [
'RISING',
'FALLING',
'BOTH',
]
const trigName = name.replace('en', '') + 'edge_type'
_name = 'TRIG' + String((parseInt(name.replace('TRIG', '').replace('_en', '')) + 1))
_value = optionTrigger[valueSet[trigName]]
} else return ''
} else if (name.includes('TIME_DURATION')) {
if (valueSet.TIME_DURATION && parseInt(valueSet.TIME_DURATION) > 0) {
const scale = config[name].unit[config[name].defaultUnit]
_name = 'Timer'
_value = `${config[name].outputReadabilityData(valueSet[name], scale)} ${config[name].defaultUnit}`
} else return ''
}
}
}
return _name + ': ' + _value
},
parameterName (name, deviceKey) {
const config = configTable.getConfig(this.getDeviceLibraryProject(deviceKey))
if (config !== undefined && Object.keys(config) !== 0) {
if (name === 'MODE') {
return 'Mode'
}
if (typeof this.config[name].showName === 'function') {
return this.config[name].showName()
if (typeof config[name].showName === 'function') {
return config[name].showName()
}
return this.config[name].showName
return config[name].showName
}
},
parameterValue (name, value) {
if (this.config !== undefined && Object.keys(this.config) !== 0) {
parameterValue (name, value, deviceKey) {
const config = configTable.getConfig(this.getDeviceLibraryProject(deviceKey))
const _value = (value === undefined) ? config[name].defaultValue : value
if (config !== undefined && Object.keys(config) !== 0) {
if (name === 'MODE') {
return this.config.MODE[value].name
return config.MODE[_value].name
}
if (this.config[name].type === 'number') {
const scale = this.config[name].unit[this.config[name].defaultUnit]
return `${this.config[name].outputReadabilityData(value, scale)} ${this.config[name].defaultUnit}`
} else if (this.config[name].type === 'array') {
return `${this.config[name].outputReadabilityData(value)}`
} else if (this.config[name].type === 'none') {
if (config[name].type === 'number') {
const scale = config[name].unit[config[name].defaultUnit]
return `${config[name].outputReadabilityData(_value, scale)} ${config[name].defaultUnit}`
} else if (config[name].type === 'array') {
return `${config[name].outputReadabilityData(_value)}`
} else if (config[name].type === 'none') {
return ''
}
}
},
showCycleModal: function (uuid) {
if (!this.lockMode) {
this.$refs.cycle_modal_ref.show()
this.$refs.cycle_modal_ref.setCycleInfo(this.getSelectProject, uuid)
}
},
getCycleInfo: function (uuid, attribute) {
const cycleInfo = this.getCycleProject(uuid) // 0: index, 1: location, 2: info
if (cycleInfo.length === 0) return ''
return cycleInfo[2][attribute]
},
getCycleLocation: function (uuid) {
const cycleInfo = this.getCycleProject(uuid) // 0: index, 1: location, 2: info
return cycleInfo[1]
},
getConfig: function (deviceKey) {
return this.getDeviceLibraryProject(deviceKey)
},
handleMove (e) {
const { index, futureIndex } = e.draggedContext
this.index = index
this.futureIndex = futureIndex
return false // disable sort
},
...mapActions('project', [
types.task.create,
types.task.copy,
types.task.delete,
types.task.rearrange,
]),
},
mounted () {
@@ -332,15 +579,12 @@ export default {
margin: auto;
}
// .item {
// height: 40px;
// line-height: 40px;
// margin-bottom: 20px;
// background-color: skyblue;
// text-align: center;
// color: #ffffff;
// cursor: move;
// }
.table-row-focus {
background: #ebedff;
// border: 0.5px solid #dbdcf0;
// box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
border-radius: 5px;
}
.markup-tables {
width: 100%;
@@ -358,13 +602,17 @@ export default {
max-height: 100px;
overflow: auto;
white-space: nowrap;
font-size: 1.1rem;
}
td:hover {
cursor: pointer;
}
th {
padding: 0 0 0 0;
margin: 0;
// padding: 0 0 0;
// margin: 0;
font-size: 1rem;
border: none;
}
div {
@@ -373,4 +621,164 @@ export default {
}
}
.table-row-add-task {
height: 50px;
background: #f4f4f4;
border: 1px dashed #c7c7c7;
border-radius: 5px;
}
.table-row-add-task-text {
font-family: 'Inter-Regular';
font-style: italic;
font-weight: 600;
font-size: 16px;
line-height: 24px;
text-align: center;
color: #c7c7c7;
}
.project-table-header {
position: sticky;
top: 0;
background: white;
font-family: 'Inter-Bold';
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 24px;
text-align: center;
color: #2c4053;
}
.project-table-text {
font-family: 'Inter-Regular';
font-style: normal;
// font-weight: 400;
font-size: 16px;
line-height: 24px;
text-align: center;
color: #2c4053;
}
.project-table-cell:hover {
opacity: 0.6;
}
.tooltip {
display: block !important;
z-index: 10000;
.tooltip-inner {
// background: red !important;
color: white;
border-radius: 16px;
padding: 5px 10px 4px;
box-shadow: rgba(108, 127, 238, 0.6) 0 2px 3px 0;
background-color: #ebedff !important;
}
.tooltip-arrow {
width: 0;
height: 0;
border-style: solid;
position: absolute;
margin: 5px;
border-color: black;
z-index: 1;
}
&[x-placement^="top"] {
margin-bottom: 5px;
.tooltip-arrow {
border-width: 5px 5px 0 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
bottom: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0;
}
}
&[x-placement^="bottom"] {
margin-top: 5px;
.tooltip-arrow {
border-width: 0 5px 5px 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-top-color: transparent !important;
top: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0;
}
}
&[x-placement^="right"] {
margin-left: 5px;
.tooltip-arrow {
border-width: 5px 5px 5px 0;
border-left-color: transparent !important;
border-top-color: transparent !important;
border-bottom-color: transparent !important;
left: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0;
}
}
&[x-placement^="left"] {
margin-right: 5px;
.tooltip-arrow {
border-width: 5px 0 5px 5px;
border-top-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
right: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0;
}
}
&.popover {
$color: #ebedff;
.popover-inner {
background: $color;
color: black;
padding: 24px;
border-radius: 5px;
box-shadow: 0 5px 30px rgba(black, 0.1);
}
.popover-arrow {
border-color: $color;
}
}
&[aria-hidden='true'] {
visibility: hidden;
opacity: 0;
transition: opacity 0.15s, visibility 0.15s;
}
&[aria-hidden='false'] {
visibility: visible;
opacity: 1;
transition: opacity 0.15s;
}
}
.test {
left: -175px !important;
}
</style>
+48 -6
View File
@@ -143,13 +143,29 @@ export default {
showDeviceSetting: true,
chartAreaClass: ['flex', 'xs12', 'sm12', 'md12', 'xl8', 'pa-0'],
getParmDone: false,
batteryInterval: {},
}
},
mqtt: {
async '+/device_battery/+' (data, topic) {
const deviceBattery = JSON.parse(String.fromCharCode.apply(null, data)).data
const device = this.deviceListNew.find(ele => ele.memory_board === deviceBattery.device)
device.battery = deviceBattery.battery
},
async '+/get_device_info_all/+' (data, topic) {
// console.log('get_device_info_all', String.fromCharCode.apply(null, data))
this.deviceListNew = JSON.parse(String.fromCharCode.apply(null, data)).data
// console.log(this.deviceListNew)
for (let i = 0; i < this.deviceListNew.length; i++) {
const curDevice = this.deviceListNew[i]
if ((curDevice.memory_board in this.batteryInterval) === false) {
this.batteryInterval[curDevice.memory_board] = setInterval(() => { this.getBattery(curDevice) }, 60000)
}
}
// console.log(this.batteryInterval)
// console.log(this.deviceListNew)
// await taskInfo.deviceInfo(String.fromCharCode.apply(null, data), this.deviceList)
// console.log('this.deviceList 0', this.deviceList)
@@ -232,6 +248,11 @@ export default {
let device
// let content
switch (mes[0]) {
case 'device_refresh':
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'get_device_info_all/0',
}))
break
case 'state':
switch (mes[1]) {
case 'device_available':
@@ -296,7 +317,14 @@ export default {
device: parseInt(mes[1]),
instruction: 'interrupt',
}))
this.pageToast('The device [' + taskInfo.getDeviceIDByRaw(parseInt(mes[1])) + '] mission is done.')
this.pageToast('The device [' + taskInfo.getDeviceIDByRaw(parseInt(mes[1])) + '] mission done.')
break
case 'project':
// refresh real-time page when going to next task
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'get_device_info_all/0',
}))
this.pageToast(mes[1])
break
default:
break
@@ -304,6 +332,12 @@ export default {
},
},
methods: {
getBattery: function (device) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_battery/0',
device: device.memory_board,
}))
},
mqttSub: function (val) {
this.$mqtt.subscribe(val)
},
@@ -321,6 +355,7 @@ export default {
this.mqttSub(id + '/device_parameter/+')
this.mqttSub(id + '/device_parameter_value/+')
this.mqttSub(id + '/device_sd_card_status/+')
this.mqttSub('+/device_battery/+')
},
pageMqttUnSub: function (id) {
for (const device in taskInfo.getTaskInfo().deviceList) {
@@ -333,6 +368,7 @@ export default {
this.mqttUnSub(id + '/device_parameter/+')
this.mqttUnSub(id + '/device_parameter_value/+')
this.mqttUnSub(id + '/device_sd_card_status/+')
this.mqttUnSub('+/device_battery/+')
},
pageInit: async function () {
if (await this.$refs.devices_ref != null) {
@@ -405,7 +441,7 @@ export default {
if (!isDefault) {
await this.taskContentChartSaveToCache({ controllerID: taskInfo.getTaskInfo().controllerID })
}
this.pageToast('The chart has been added.')
// this.pageToast('The chart has been added.')
return newChart.chartID
},
@@ -423,7 +459,7 @@ export default {
mappingID: null,
cardName: null,
})
this.pageToast('The chart has been Initialized.')
// this.pageToast('The chart has been Initialized.')
},
removeChartCheck: function (chartID) {
this.selectChartID = chartID
@@ -459,7 +495,7 @@ export default {
if (saveCache === true) {
await this.taskContentChartSaveToCache({ controllerID: taskInfo.getTaskInfo().controllerID })
}
this.pageToast('The chart has been removed.')
// this.pageToast('The chart has been removed.')
},
showDeviceSettingClick: function () {
this.showDeviceSetting = true
@@ -500,8 +536,9 @@ export default {
_itemID: deviceID,
_chartID: null,
_type: 'device',
_reset: false,
})
this.pageToast('The device [' + deviceID + '] has been registered.')
// this.pageToast('The device [' + deviceID + '] has been registered.')
},
removeDevice: function (deviceID) {
this.mqttUnSub(taskInfo.getTaskInfo().controllerID + '/data_server/device_data_stream/' + deviceID + '/+')
@@ -511,7 +548,7 @@ export default {
this.removeChart(chart)
}
}
this.pageToast('The device [' + deviceID + '] has been removed.')
// this.pageToast('The device [' + deviceID + '] has been removed.')
},
addFormula: async function (formulaID) {
const chart = await this.addChart(true)
@@ -616,6 +653,7 @@ export default {
}
await taskInfo.updateTaskInfo(this.$route.params.taskID)
this.GLOBAL.refreshCache()
this.pageMqttSub(taskInfo.getTaskInfo().controllerID)
await this.pageInit()
@@ -640,6 +678,10 @@ export default {
}
clearInterval(this.dataRefreshTimer)
this.pageMqttUnSub(taskInfo.getTaskInfo().controllerID)
for (var interval in this.batteryInterval) {
clearInterval(this.batteryInterval[interval])
}
},
}
@@ -214,11 +214,14 @@ export default {
this.calClicked = clicked
},
captureChart: function () {
// count same ID in chartData
const captureTimes = String(Object.keys(this.chartData).filter(ele => ele.includes(String(this.data.chartID))).length)
const newData = Object.assign({}, this.data)
this.chartData[String(this.data.chartID) + '-1'] = newData
this.chartData[String(this.data.chartID) + '-1'].captured = true
this.chartData[String(this.data.chartID) + '-1'].cardName = this.chartData[String(this.data.chartID) + '-1'].cardName + ' - captured'
this.chartData[String(this.data.chartID) + '-1'].chartID = String(this.data.chartID) + '-1'
this.chartData[String(this.data.chartID) + '-' + captureTimes] = newData
this.chartData[String(this.data.chartID) + '-' + captureTimes].captured = true
this.chartData[String(this.data.chartID) + '-' + captureTimes].cardName += ' - captured -' + captureTimes
this.chartData[String(this.data.chartID) + '-' + captureTimes].createdBy = 'capture'
this.chartData[String(this.data.chartID) + '-' + captureTimes].chartID = String(this.data.chartID) + '-' + captureTimes
this.taskContentChartPanelKey++
},
updateZoom: function (e) {
@@ -60,7 +60,7 @@
import { mapFields } from 'vuex-map-fields'
import { mapActions } from 'vuex'
import taskTypes from '@/store/modules/task/content/types'
import paramTable from '@/data/config-table/index'
import configTable from '@/data/config-table/index'
// import newTooltip from '@/factories/chart/tooltipFactory'
import { getTimeFormatter } from '@/store/modules/task/content/actions/chartAct'
import sgFilter from '@/data/SGFilter'
@@ -88,7 +88,6 @@ export default {
data () {
return {
info: null,
paramTable: paramTable,
rawData: null,
mode_name: '',
xName: '',
@@ -241,19 +240,23 @@ export default {
const dataX = []
const dataY = []
const time = []
for (index = 0; index < dataLength; index++) {
const dsample = 1
const m = parseInt((this.sgFilterArgument.windowSize - 1) / 2)
for (index = 0; index < dataLength; index += dsample) {
dataX.push(seriesData[index][0])
dataY.push(seriesData[index][1])
dataY.push(seriesData[index][1] * 1e-9)
time.push(seriesData[index][2])
}
// console.log(time[time.length - 1], time[0])
// console.log(dataX.length, time[time.length - 1] - time[0], dataX.length * 1e6 / (time[time.length - 1] - time[0]))
// console.log('dataX', dataX)
// console.log('dataY', dataY)
// console.log('time', time)
const filteredData = sgFilter(dataY, this.sgFilterArgument.windowSize, this.sgFilterArgument.polynomial)
// console.log('filterdData', filteredData)
const filteredData = sgFilter(dataY, this.sgFilterArgument.windowSize, this.sgFilterArgument.polynomial, this.getSampleRate())
for (index = 0; index < dataLength; index++) {
_data.push([dataX[index], filteredData[index], time[index]])
for (index = 0; index < filteredData.length; index++) {
_data.push([dataX[index + m], filteredData[index], time[index + m]])
}
// for (index = 0; index < dataLength; index++) {
@@ -417,13 +420,27 @@ export default {
var value = this.data.series[0].data[(this.data.series[0].data).length - 1][1]
return this.yName + ': ' + value + ' ' + this.yUnit
},
getSampleRate: function () {
try {
const deviceMappingID = this.chartData[this.chartID].mappingID
const device = this.deviceListNew.find(ele => ele.memory_board === deviceMappingID)
const deviceConfig = configTable.getConfig(deviceMappingID)
const voltStep = deviceConfig.VOLT_STEP.outputReadabilityData(device.configuration.VOLT_STEP)
const sampleRate = deviceConfig.SAMPLE_RATE.outputReadabilityData(device.configuration.SAMPLE_RATE)
return (1 / (voltStep / 1000)) * sampleRate
} catch (e) {
console.log('getSampleRateERROR', e)
return 1
}
},
...mapActions('taskContent', [
taskTypes.chart.saveToCache,
]),
},
async mounted () {
this.rawData = this.chartData[this.chartID]
// const test = [3.0, 12.9, 22.6, 32.10000000000001, 41.4, 50.5, 59.400000000000006, 68.1, 76.6, 84.9, 93.0, 100.9, 108.60000000000001, 116.1, 123.39999999999999, 130.5, 137.4, 144.10000000000002, 150.6, 156.9, 163.0, 168.9, 174.60000000000002, 180.10000000000002, 185.4, 190.5, 195.39999999999998, 200.1, 204.59999999999997, 208.90000000000003, 213.0, 216.89999999999998, 220.59999999999997, 224.09999999999997, 227.40000000000003, 230.5, 233.39999999999998, 236.1, 238.6, 240.90000000000003, 243.0, 244.9, 246.6, 248.10000000000002, 249.40000000000003, 250.5, 251.40000000000003, 252.09999999999997, 252.6, 252.9, 253.0, 252.90000000000003, 252.59999999999997, 252.10000000000002, 251.39999999999998, 250.5, 249.39999999999992, 248.09999999999997, 246.60000000000002, 244.89999999999998, 243.0, 240.89999999999992, 238.59999999999997, 236.10000000000002, 233.39999999999992, 230.5, 227.39999999999992, 224.10000000000002, 220.60000000000002, 216.89999999999992, 213.0, 208.89999999999986, 204.5999999999999, 200.10000000000002, 195.39999999999998, 190.5, 185.39999999999998, 180.0999999999999, 174.60000000000002, 168.89999999999998, 163.0, 156.89999999999998, 150.5999999999999, 144.10000000000002, 137.39999999999998, 130.5, 123.40000000000009, 116.10000000000002, 108.60000000000002, 100.89999999999986, 93.0, 84.90000000000009, 76.60000000000002, 68.10000000000002, 59.399999999999864, 50.5, 41.399999999999864, 32.09999999999991, 22.59999999999991, 12.899999999999977]
// console.log('sgFilter', sgFilter(test, 5, 2, 10))
// console.log('x', this.rawData.xAxis.length)
// if (this.mode_name === 'I-V Curve') {
// this.rawData.xAxis[0].boundaryGap = [0, '5%']
@@ -1,84 +1,85 @@
<template>
<div>
<!-- Whole Real-time Display Tool here -->
<div v-for="(plot, plotIndex) in realTime" :key="plotIndex">
<div v-for="(line, lineIndex) in plot" :key="plotIndex + '_' + lineIndex" class="row ma-0 pa-0">
<div v-for="(curve, curveIndex) in plot" :key="plotIndex + '-' + curveIndex" class="row ma-0 pa-0">
<!-- cycle -->
<div class="mt-1" style="width: 75px;"
v-show="data !== null && data.cycle > 0"
>
<div class="mt-1" style="width: 75px;" v-show="data !== null && data.cycle > 0">
<va-input
label="cycle no."
v-model="data.cycle"
:options="line.xUnitOption"
noClear
disabled
/>
</div>
<!-- y-axis -->
<div class="d-flex flex-row mt-1 ml-1">
<!-- value (y-axis) -->
<div style="width: 75px;">
<va-input
label="y-axis"
v-model="line.yValue"
v-model="curve.yValue"
disabled
/>
</div>
<!-- unit (y-axis) -->
<div style="width: 75px;">
<va-select
v-model="line.yUnit"
:options="line.yUnitOption"
@input="changeUnit('y', plotIndex, lineIndex)"
v-model="curve.yUnit"
:options="curve.yUnitOption"
@input="changeUnit('y', plotIndex, curveIndex)"
noClear
/>
</div>
</div>
<!-- x-axis -->
<div class="d-flex flex-row mt-1 ml-1">
<!-- value (x-axis) -->
<div style="width: 75px;">
<va-input
label="x-axis"
v-model="line.xValue"
v-model="curve.xValue"
disabled
/>
</div>
<!-- unit (x-axis) -->
<div style="width: 75px;">
<va-select
v-model="line.xUnit"
:options="line.xUnitOption"
@input="changeUnit('x', plotIndex, lineIndex)"
v-model="curve.xUnit"
:options="curve.xUnitOption"
@input="changeUnit('x', plotIndex, curveIndex)"
noClear
/>
</div>
</div>
<!-- intervel -->
<div class="d-flex flex-row mt-1 ml-1">
<!-- interval (y-axis) -->
<div class="ml-1" style="width: 80px;">
<va-input
v-show="!lineIndex"
v-model="line.yInterval"
v-show="!curveIndex"
v-model="curve.yInterval"
label="y-grid"
@focus="$event.target.select()"
@keyup.enter="setInterval('y', plotIndex, lineIndex, line.yInterval)"
@blur="setInterval('y', plotIndex, lineIndex, line.yInterval)"
@keyup.enter="setInterval('y', plotIndex, curveIndex, curve.yInterval)"
@blur="setInterval('y', plotIndex, curveIndex, curve.yInterval)"
>
<p slot="append" style="margin-right: 0;" small>
{{ line.yUnit }}
{{ curve.yUnit }}
</p>
</va-input>
</div>
<!-- interval (x-axis) -->
<div class="ml-1" style="width: 80px;">
<va-input
v-show="!lineIndex"
v-model="line.xInterval"
v-show="!curveIndex"
v-model="curve.xInterval"
label="x-grid"
@focus="$event.target.select()"
@keyup.enter="setInterval('x', plotIndex, lineIndex, line.xInterval)"
@blur="setInterval('x', plotIndex, lineIndex, line.xInterval)"
@keyup.enter="setInterval('x', plotIndex, curveIndex, curve.xInterval)"
@blur="setInterval('x', plotIndex, curveIndex, curve.xInterval)"
>
<p slot="append" style="margin-right: 0;" small>
{{ line.xUnit }}
{{ curve.xUnit }}
</p>
</va-input>
</div>
@@ -124,58 +125,118 @@ export default {
...mapActions('taskContent', [
taskTypes.chart.saveToCache,
]),
// for user to choose wanted unit
setUnit: function (plotIndex, lineIndex) {
getDeviceMode: function () {
const device = this.deviceListNew.find(ele => String(ele.memory_board) === String(this.chartData[this.chartID].mappingID))
if (device === undefined) return
return device.configuration.MODE
},
getChannelConfiguration: function () {
const device = this.deviceListNew.find(ele => String(ele.memory_board) === String(this.chartData[this.chartID].mappingID))
if (device === undefined) return
return configTable.getChannelConfig(device.configuration._LIBRARY_, device.configuration.MODE)
},
// set a new display tool
setRealTime: function (plotIndex, curveIndex) {
// construct realTime object, i.e., record the coressponding value and unit
// the formate imitates the data.gridSource
const channelInfo = this.getChannelConfiguration()
if (this.data !== undefined && this.data.gridSource !== undefined) {
const _xPhysicsQuantity = this.data.gridSource[plotIndex][lineIndex].name.split('_')[0].split('-').at(-1)
const _yPhysicsQuantity = this.data.gridSource[plotIndex][lineIndex].name.split('_')[1].split('-').at(-1)
const [_xAxis, _yAxis] = this.chartRouter.getChartTable(_xPhysicsQuantity, _yPhysicsQuantity)
const x = this.data.gridSource[plotIndex][curveIndex].xSource
const y = this.data.gridSource[plotIndex][curveIndex].ySource
let _xAxis
let _yAxis
if (channelInfo) {
if (x.name === 'Time') {
_xAxis = { default: channelInfo.time }
} else {
let xInfo = channelInfo[x.channel - 1]
if (xInfo === undefined) {
xInfo = {
name: '',
defaultUnit: '',
unit: {},
}
}
_xAxis = { default: xInfo }
}
if (y.name === 'Time') {
_yAxis = { default: channelInfo.time }
} else {
let yInfo = channelInfo[y.channel - 1]
if (yInfo === undefined) {
yInfo = {
name: '',
defaultUnit: '',
unit: {},
}
}
_yAxis = { default: yInfo }
}
} else {
_xAxis = {
default: {
name: '',
defaultUnit: '',
unit: {},
},
}
_yAxis = {
default: {
name: '',
defaultUnit: '',
unit: {},
},
}
}
const _realTime = JSON.parse(JSON.stringify(this.realTime))
const _newChannel = {}
const _newCurve = {}
// set name, sourceIndex in data.series
_newChannel.name = this.data.gridSource[plotIndex][lineIndex].name
_newChannel.seriesSource = this.data.series.findIndex((ele) => ele.name === _newChannel.name)
_newCurve.name = this.data.gridSource[plotIndex][curveIndex].name
_newCurve.seriesSource = this.data.series.findIndex((ele) => ele.name === _newCurve.name)
// set x-axis
_newChannel.xValue = 0
_newChannel.xUnit = _xAxis.default.defaultUnit
_newChannel.xScale = _xAxis.default.unit
_newChannel.xUnitOption = Object.keys(_xAxis.default.unit)
_newChannel.xName = _xAxis.default.name
_newChannel.xInterval = 'auto'
_newCurve.xValue = 0
_newCurve.xUnit = (typeof _xAxis.default.defaultUnit === 'function') ? _xAxis.default.defaultUnit(this.getDeviceMode()) : _xAxis.default.defaultUnit
_newCurve.xScaleOption = _xAxis.default.unit
_newCurve.xUnitOption = Object.keys(_xAxis.default.unit)
_newCurve.xName = _xAxis.default.name
_newCurve.xInterval = 'auto'
// set y-axis
_newChannel.yValue = 0
_newChannel.yUnit = _yAxis.default.defaultUnit
_newChannel.yScale = _yAxis.default.unit
_newChannel.yUnitOption = Object.keys(_yAxis.default.unit)
_newChannel.yName = _yAxis.default.name
_newChannel.yInterval = 'auto'
_newCurve.yValue = 0
_newCurve.yUnit = (typeof _yAxis.default.defaultUnit === 'function') ? _yAxis.default.defaultUnit(this.getDeviceMode()) : _yAxis.default.defaultUnit
_newCurve.yScaleOption = _yAxis.default.unit
_newCurve.yUnitOption = Object.keys(_yAxis.default.unit)
_newCurve.yName = _yAxis.default.name
_newCurve.yInterval = 'auto'
// set functional
_newChannel.functional = 'default'
_newCurve.functional = 'default'
// padding
while (plotIndex >= _realTime.length) {
_realTime.push([])
}
while (lineIndex >= _realTime[plotIndex].length) {
while (curveIndex >= _realTime[plotIndex].length) {
_realTime[plotIndex].push({})
}
// merge the additional part into original part
_realTime[plotIndex][lineIndex] = _newChannel
_realTime[plotIndex][curveIndex] = _newCurve
this.realTime = _realTime
}
},
setInterval: async function (axis, plotIndex, lineIndex, val) {
// set the interval size keyed by user
setInterval: async function (axis, plotIndex, curveIndex, val) {
if (!isNaN(val)) {
const scaleOption = this.realTime[plotIndex][lineIndex][axis + 'Scale']
const unit = this.realTime[plotIndex][lineIndex][axis + 'Unit']
const scaleOption = this.realTime[plotIndex][curveIndex][axis + 'ScaleOption']
const unit = this.realTime[plotIndex][curveIndex][axis + 'Unit']
this.chartData[this.chartID][axis + 'Axis'][plotIndex].interval = val * scaleOption[unit]
} else {
this.chartData[this.chartID][axis + 'Axis'][plotIndex].interval = 'hi' // I know it looks stupid, but this one is nessesary
this.chartData[this.chartID][axis + 'Axis'][plotIndex].interval = 'hi' // I know it looks weird, but this one is necessesary
this.chartData[this.chartID][axis + 'Axis'][plotIndex].interval = null
this.realTime[plotIndex][lineIndex][axis + 'Interval'] = 'auto'
this.realTime[plotIndex][curveIndex][axis + 'Interval'] = 'auto'
}
await this.taskContentChartSaveToCache({ controllerID: taskInfo.getTaskInfo().controllerID })
},
@@ -185,16 +246,18 @@ export default {
return
}
for (let plotIndex = 0; plotIndex < this.realTime.length; plotIndex++) {
for (let lineIndex = 0; lineIndex < this.realTime[plotIndex].length; lineIndex++) {
for (let curveIndex = 0; curveIndex < this.realTime[plotIndex].length; curveIndex++) {
// miss the source of data -> try to find the source
if (this.realTime[plotIndex][lineIndex].seriesSource === -1) {
this.realTime[plotIndex][lineIndex].seriesSource = this.data.series.findIndex((ele) => ele.name === this.realTime[plotIndex][lineIndex].name)
if (this.realTime[plotIndex][curveIndex].seriesSource === -1) {
this.realTime[plotIndex][curveIndex].seriesSource = this.data.series.findIndex((ele) => ele.name === this.realTime[plotIndex][curveIndex].name)
}
// the device is active now --> update the real time value
if (this.data.series[this.realTime[plotIndex][lineIndex].seriesSource] !== undefined && this.data.series[this.realTime[plotIndex][lineIndex].seriesSource].data !== undefined && this.data.series[this.realTime[plotIndex][lineIndex].seriesSource].data.length > 0) {
this.realTime[plotIndex][lineIndex].xValue = (this.data.series[this.realTime[plotIndex][lineIndex].seriesSource].data.at(-1)[0] / this.realTime[plotIndex][lineIndex].xScale[this.realTime[plotIndex][lineIndex].xUnit]).toFixed(3)
this.realTime[plotIndex][lineIndex].yValue = (this.data.series[this.realTime[plotIndex][lineIndex].seriesSource].data.at(-1)[1] / this.realTime[plotIndex][lineIndex].yScale[this.realTime[plotIndex][lineIndex].yUnit]).toFixed(3)
if (this.data.series[this.realTime[plotIndex][curveIndex].seriesSource] !== undefined &&
this.data.series[this.realTime[plotIndex][curveIndex].seriesSource].data !== undefined &&
this.data.series[this.realTime[plotIndex][curveIndex].seriesSource].data.length > 0) {
this.realTime[plotIndex][curveIndex].xValue = (this.data.series[this.realTime[plotIndex][curveIndex].seriesSource].data.at(-1)[0] / this.realTime[plotIndex][curveIndex].xScaleOption[this.realTime[plotIndex][curveIndex].xUnit]).toFixed(3)
this.realTime[plotIndex][curveIndex].yValue = (this.data.series[this.realTime[plotIndex][curveIndex].seriesSource].data.at(-1)[1] / this.realTime[plotIndex][curveIndex].yScaleOption[this.realTime[plotIndex][curveIndex].yUnit]).toFixed(3)
}
}
}
@@ -202,15 +265,15 @@ export default {
// match the formatter to current unit and functional
updateFormatter: function () {
for (let plotIndex = 0; plotIndex < this.realTime.length; plotIndex++) {
for (let lineIndex = 0; lineIndex < this.realTime[plotIndex].length; lineIndex++) {
if (lineIndex === 0) {
const _xUnit = this.realTime[plotIndex][lineIndex].xUnit
const _yUnit = this.realTime[plotIndex][lineIndex].yUnit
const _xScale = this.realTime[plotIndex][lineIndex].xScale[this.realTime[plotIndex][lineIndex].xUnit]
const _yScale = this.realTime[plotIndex][lineIndex].yScale[this.realTime[plotIndex][lineIndex].yUnit]
for (let curveIndex = 0; curveIndex < this.realTime[plotIndex].length; curveIndex++) {
if (curveIndex === 0) {
const _xUnit = this.realTime[plotIndex][curveIndex].xUnit
const _yUnit = this.realTime[plotIndex][curveIndex].yUnit
const _xScale = this.realTime[plotIndex][curveIndex].xScaleOption[this.realTime[plotIndex][curveIndex].xUnit]
const _yScale = this.realTime[plotIndex][curveIndex].yScaleOption[this.realTime[plotIndex][curveIndex].yUnit]
// update xAxis.formatter
if (this.realTime[plotIndex][lineIndex].xName === 'Time') {
if (this.realTime[plotIndex][curveIndex].xName === 'Time') {
this.data.xAxis[plotIndex].axisLabel.formatter = this.timeFormatter
} else {
this.data.xAxis[plotIndex].axisLabel.formatter = function (val) {
@@ -218,7 +281,7 @@ export default {
}
}
// update yAxis.formatter
if (this.realTime[plotIndex][lineIndex].yName === 'Time') {
if (this.realTime[plotIndex][curveIndex].yName === 'Time') {
this.data.yAxis[plotIndex].axisLabel.formatter = this.timeFormatter
} else {
this.data.yAxis[plotIndex].axisLabel.formatter = function (val) {
@@ -231,20 +294,20 @@ export default {
}
}
},
changeUnit: function (axis, plotIndex, lineIndex) {
changeUnit: function (axis, plotIndex, curveIndex) {
this.updateValue()
this.updateFormatter()
this.setInterval(axis, plotIndex, lineIndex, 'auto')
this.setInterval(axis, plotIndex, curveIndex, 'auto')
},
// match the number of real time display bar to data.gridSource
matchChart: function () {
for (let plotIndex = 0; plotIndex < this.data.gridSource.length; plotIndex++) {
if (this.data.gridSource[plotIndex] !== undefined) {
for (let lineIndex = 0; lineIndex < this.data.gridSource[plotIndex].length; lineIndex++) {
for (let curveIndex = 0; curveIndex < this.data.gridSource[plotIndex].length; curveIndex++) {
if (plotIndex >= this.realTime.length) {
this.setUnit(plotIndex, lineIndex)
} else if (lineIndex >= this.realTime[plotIndex].length) {
this.setUnit(plotIndex, lineIndex)
this.setRealTime(plotIndex, curveIndex)
} else if (curveIndex >= this.realTime[plotIndex].length) {
this.setRealTime(plotIndex, curveIndex)
}
}
}
@@ -255,25 +318,38 @@ export default {
this.data = canvasChartData
},
// match the functional to operated data in CanvasChart.vue
matchFunctional: function (newFunctional, plotIndex, lineIndex) {
if (this.realTime[plotIndex][lineIndex] === undefined) return
if (this.realTime[plotIndex][lineIndex].functional === newFunctional) return
const _currChannel = this.realTime[plotIndex][lineIndex]
const _xPhysicsQuantity = this.data.gridSource[plotIndex][lineIndex].name.split('_')[0].split('-').at(-1)
const _yPhysicsQuantity = this.data.gridSource[plotIndex][lineIndex].name.split('_')[1].split('-').at(-1)
matchFunctional: function (newFunctional, plotIndex, curveIndex) {
if (this.realTime[plotIndex][curveIndex] === undefined) return
if (this.realTime[plotIndex][curveIndex].functional === newFunctional) return
const _currCurve = this.realTime[plotIndex][curveIndex]
let _xPhysicsQuantity = this.data.gridSource[plotIndex][curveIndex].name.split('_')[0].split('-').at(-1)
let _yPhysicsQuantity = this.data.gridSource[plotIndex][curveIndex].name.split('_')[1].split('-').at(-1)
// Potential
if (!_xPhysicsQuantity.includes('ZReal') && !_xPhysicsQuantity.includes('ZImag')) {
_xPhysicsQuantity = _xPhysicsQuantity.substring(0, 1)
} else {
_xPhysicsQuantity = _xPhysicsQuantity.substring(0, 5)
}
if (!_yPhysicsQuantity.includes('ZReal') && !_yPhysicsQuantity.includes('ZImag')) {
_yPhysicsQuantity = _yPhysicsQuantity.substring(0, 1)
} else {
_yPhysicsQuantity = _yPhysicsQuantity.substring(0, 5)
}
if (_xPhysicsQuantity === 'P') _xPhysicsQuantity = 'V'
if (_yPhysicsQuantity === 'P') _yPhysicsQuantity = 'V'
const [_xAxis, _yAxis] = this.chartRouter.getChartTable(_xPhysicsQuantity, _yPhysicsQuantity)
_currChannel.functional = newFunctional
_currCurve.functional = newFunctional
// set x-axis
_currChannel.xUnit = _xAxis.default.defaultUnit
_currChannel.xScale = _xAxis.default.unit
_currChannel.xUnitOption = Object.keys(_xAxis.default.unit)
_currChannel.xName = _xAxis.default.name
_currCurve.xUnit = (typeof _xAxis.default.defaultUnit === 'function') ? _xAxis.default.defaultUnit(this.getDeviceMode()) : _xAxis.default.defaultUnit
_currCurve.xScaleOption = _xAxis.default.unit
_currCurve.xUnitOption = Object.keys(_xAxis.default.unit)
_currCurve.xName = _xAxis.default.name
// set y-axis
_currChannel.yUnit = _yAxis[newFunctional].defaultUnit
_currChannel.yScale = _yAxis[newFunctional].unit
_currChannel.yUnitOption = Object.keys(_yAxis[newFunctional].unit)
_currChannel.yName = _yAxis[newFunctional].name
_currCurve.yUnit = (typeof _yAxis[newFunctional].defaultUnit === 'function') ? _yAxis[newFunctional].defaultUnit(this.getDeviceMode()) : _yAxis[newFunctional].defaultUnit
_currCurve.yScaleOption = _yAxis[newFunctional].unit
_currCurve.yUnitOption = Object.keys(_yAxis[newFunctional].unit)
_currCurve.yName = _yAxis[newFunctional].name
},
timeFormatter: function (val) {
let label = ''
@@ -186,10 +186,9 @@ export default {
} else if (deviceInfo.library_name.includes('Elite')) {
const sourceObj = configTable.getChannelConfig(String(deviceInfo.library_name), deviceInfo.configuration.MODE) // [{id:0 channel:'Current'}, {id:1, channel:'Voltage'}, ]
let channelSet
if (deviceInfo.library_name.includes('EIS') && deviceInfo.configuration.MODE === 0) {
if (deviceInfo.library_name.includes('EIS') && (deviceInfo.configuration.MODE === 0 || deviceInfo.configuration.MODE === 5)) {
channelSet = ['Zimag_Raw', 'Zreal_Raw', 'Frequency', 'Cycle', 'Zimag', 'Zreal', 'Impedance', 'Phase', 'Current', 'Level gain']
} else {
// channelSet = deviceInfo.configuration.CHANNEL_LABEL
channelSet = []
const keys = Object.keys(sourceObj)
for (let i = 0; i < keys.length; i++) {
@@ -263,10 +262,9 @@ export default {
} else if (deviceInfo.library_name.indexOf('Elite') >= 0) {
const sourceObj = configTable.getChannelConfig(String(deviceInfo.library_name), deviceInfo.configuration.MODE) // [{id:0 channel:'Current'}, {id:1, channel:'Voltage'}, ]
let channelSet
if (deviceInfo.library_name.includes('EIS') && deviceInfo.configuration.MODE === 0) {
if (deviceInfo.library_name.includes('EIS') && (deviceInfo.configuration.MODE === 0 || deviceInfo.configuration.MODE === 5)) {
channelSet = ['Zimag_Raw', 'Zreal_Raw', 'Frequency', 'Cycle', 'Zimag', 'Zreal', 'Impedance', 'Phase', 'Current', 'Level gain']
} else {
// channelSet = deviceInfo.configuration.CHANNEL_LABEL
channelSet = []
const keys = Object.keys(sourceObj)
for (let i = 0; i < keys.length; i++) {
@@ -1,36 +1,6 @@
const chartTable = {
// split 'A-B' by '-',
// then A-B[0] is about 'A' and A-B[1] is about 'B'
T_V: [
// 0
{
default: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
min: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 's',
downloadUnit: 'ms',
},
},
// 1
{
default: {
name: 'Voltage',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
],
T_I: [
// 0
{
@@ -57,7 +27,7 @@ const chartTable = {
mA: 1e6,
A: 1e9,
},
defaultUnit: 'mA',
defaultUnit: (Mode) => { return (Mode === 10 || Mode === 11) ? 'nA' : 'mA' },
downloadUnit: 'mA',
},
// Q = ∫ I dt
@@ -74,65 +44,6 @@ const chartTable = {
},
},
],
T_R: [
// 0
{
default: {
name: 'Time',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
min: 60 * 1e6,
hour: 60 * 60 * 1e6,
},
defaultUnit: 's',
downloadUnit: 'ms',
},
},
// 1
{
default: {
name: 'Resistance',
unit: {
: 1,
Ω: 1e3,
: 1e6,
: 1e9,
},
defaultUnit: 'Ω',
downloadUnit: 'Ω',
},
},
],
V_V: [
// 0
{
default: {
name: 'Voltage',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
// 1
{
default: {
name: 'Voltage',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
],
V_I: [
// 0
{
@@ -180,19 +91,18 @@ const chartTable = {
mA: 1e6,
A: 1e9,
},
defaultUnit: 'mA',
defaultUnit: (Mode) => { return (Mode === 10 || Mode === 11) ? 'nA' : 'mA' },
downloadUnit: 'mA',
},
// Gm = dI/dV
differential: {
name: 'Transconductance',
unit: {
'mA/V': 1,
'A/V': 1e3,
'kA/V': 1e6,
'mA/mV': 1e-3,
'A/mV': 1,
},
defaultUnit: 'A/V',
downloadUnit: 'A/V',
defaultUnit: 'mA/mV',
downloadUnit: 'A',
},
// Power = ∫ I dv
integral: {
@@ -207,94 +117,6 @@ const chartTable = {
},
},
],
V_R: [
// 0
{
default: {
name: 'Voltage',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
// 1
{
default: {
name: 'Resistance',
unit: {
: 1,
Ω: 1e3,
: 1e6,
: 1e9,
},
defaultUnit: 'Ω',
downloadUnit: 'Ω',
},
},
],
I_R: [
// 0
{
default: {
name: 'Voltage',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'mV',
},
},
// 1
{
default: {
name: 'Current',
unit: {
nA: 1,
uA: 1e3,
mA: 1e6,
A: 1e9,
},
defaultUnit: 'mA',
downloadUnit: 'mA',
},
},
],
Zreal_Zimag: [
// 0
{
default: {
name: 'Z_real',
unit: {
: 1e-3,
Ω: 1,
: 1e3,
: 1e6,
},
downloadUnit: 'Ω',
defaultUnit: 'Ω',
},
},
// 1
{
default: {
name: 'Z_imag',
unit: {
: 1e-3,
Ω: 1,
: 1e3,
: 1e6,
},
downloadUnit: 'Ω',
defaultUnit: 'Ω',
},
},
],
}
export const chartRouter = {
getChartTable: (xAxis, yAxis) => {
@@ -302,6 +124,6 @@ export const chartRouter = {
const name2 = yAxis + '_' + xAxis
if (chartTable[name1] !== undefined) return [chartTable[name1][0], chartTable[name1][1]]
else if (chartTable[name2] !== undefined) return [chartTable[name2][1], chartTable[name2][0]]
else return 'idiot'
else return []
},
}
@@ -140,7 +140,7 @@ export default {
// const status = checkParam.status
// const message = checkParam.message
// if (status === true) {
this.setArchiveSettings()
await this.setArchiveSettings()
// this.$emit('start', device)
setTimeout(() => {
this.$emit('start', device)
@@ -160,7 +160,7 @@ export default {
// const message = checkParam.message
// if (status === true) {
// device.stopping = false
this.setArchiveSettings()
await this.setArchiveSettings()
setTimeout(() => {
this.$emit('record', device)
}, 500)
@@ -176,9 +176,9 @@ export default {
generateChart: function (device) {
this.$emit('generate', device)
},
setArchiveSettings: function () {
this.$refs.fcwindow_ref.forEach(ref => {
ref.setArchiveSettings()
setArchiveSettings: async function () {
this.$refs.fcwindow_ref.forEach(async (ref) => {
await ref.setArchiveSettings()
})
},
refresh: function () {
@@ -19,11 +19,33 @@
<img :src="device.picture" :alt="device.name">
</va-avatar>
</va-item-section>
<va-item-section class="ml-3" caption>
<va-item-label>
{{ `[${device.memory_board}]` }} {{ device.name }}
<!-- <va-button @click="getBattery(device)"> get battery </va-button> -->
<!-- <pre> {{ device.battery }} </pre> -->
<va-item-label v-if="!device.library_name.includes('EDC')">
{{ `[${device.memory_board}]` }} {{ device.name === 'Elite-CPG' ? 'Current Pulse Generator' : device.name }}
</va-item-label>
<!-- <va-item-label v-if="device.status !== 0">
{{ `[${device.memory_board}]` }} {{ device.name }} <va-icon class="ml-3 fa fa-battery-full" color="rgb(178 180 178)"/>
</va-item-label> -->
<va-item-label v-else-if="parseInt((device.battery - 2900) / 10) >= 75">
{{ `[${device.memory_board}]` }} {{ device.name }} <va-icon class="ml-3 fa fa-battery-full" color="#5BC236"/> {{ (parseInt((device.battery - 2900) / 10) > 100 ? 100 : parseInt((device.battery - 2900) / 10)) + '%' }}
</va-item-label>
<va-item-label v-else-if="parseInt((device.battery - 2900) / 10) >= 50">
{{ `[${device.memory_board}]` }} {{ device.name }} <va-icon class="ml-3 fa fa-battery-three-quarters" color="#5BC236"/> {{ parseInt((device.battery - 2900) / 10) + '%' }}
</va-item-label>
<va-item-label v-else-if="parseInt((device.battery - 2900) / 10) >= 25">
{{ `[${device.memory_board}]` }} {{ device.name }} <va-icon class="ml-3 fa fa-battery-half" color="#F6B431"/> {{ parseInt((device.battery - 2900) / 10) + '%' }}
</va-item-label>
<va-item-label v-else-if="parseInt((device.battery - 2900) / 10) > 10">
{{ `[${device.memory_board}]` }} {{ device.name }} <va-icon class="ml-3 fa fa-battery-quarter" color="#DA244B"/> {{ parseInt((device.battery - 2900) / 10) + '%' }}
</va-item-label>
<va-item-label v-else>
{{ `[${device.memory_board}]` }} {{ device.name }} <va-icon class="ml-3 fa fa-battery-empty" color="#DA244B"/> <span style="color: red;"> low battery </span>
</va-item-label>
<!-- <va-item-label v-else>
{{ `[${device.memory_board}]` }} {{ device.name }} <va-icon class="ml-3 fa fa-battery-empty" color="#DA244B"/> {{ '0%' }}
</va-item-label> -->
<va-item-label caption>
{{ device.mac_address.toUpperCase() }}
</va-item-label>
@@ -33,6 +55,8 @@
<va-item class="pa-0 ma-0 mt-2">
<va-item-section class="ml-3">
<va-item-label>
<va-button @click.stop="quickstart(device)" v-if="device.library_name.includes('PEL')" class="px-2 py-0 mr-0" color="success" small>START</va-button>
<!-- <va-button @click.stop="quickstart(device)" v-if="device.library_name.includes('CPG')" class="px-2 py-0 mr-0" color="success" small>START</va-button> -->
<va-button @click.stop="start(device)" v-if="device.library_name.includes('Elite') && device.status !== 1" class="px-2 py-0 mr-0" color="success" small>START</va-button>
<va-button @click.stop="stop(device)" v-if="device.library_name.includes('Elite') && device.status === 1" class="px-2 py-0 mr-0" color="danger" small>STOP</va-button>
<va-button id="detectButton" @click.stop="detect(device)" v-if="device.library_name.includes('Elite')" color="primary" class="px-2 py-0 mr-0" small>DETECT</va-button>
@@ -42,8 +66,8 @@
</va-item>
</span>
<div slot="body">
<div class="mt-0 mb-0" style="height: 60vh; overflow-y: scroll; overflow-x: hidden;" :key="'detail' + device.id">
<div>
<div class="mt-0 mb-0" style="height: 60vh; overflow-y: scroll; overflow-x: hidden; scrollbar-width: none;" :key="'detail' + device.id">
<div v-if="device.library_name.includes('Elite')">
<file-control-window :ref="`fcwindow_ref_${device.memory_board}`" :device="device" class="pl-0 pr-0" />
</div>
<div>
@@ -133,6 +157,13 @@ export default {
// CanvasChart.methods.resetClicked()
}
},
quickstart: function (device) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: device.mac_address,
instruction: 'start',
}))
},
stop: function (device) {
this.$emit('stop', device)
this.pageToast('The device ' + device.name + ' has been stopped.')
@@ -178,4 +209,9 @@ export default {
filter: brightness(100%);
}
}
.va-collapse__body {
padding-left: 0;
padding-right: 0;
}
</style>
@@ -129,9 +129,9 @@ export default {
generateChart: function (device) {
this.$emit('add', device.id)
},
setArchiveSettings: function () {
setArchiveSettings: async function () {
if (this.$refs.pdlist_ref != null) {
this.$refs.pdlist_ref.setArchiveSettings()
await this.$refs.pdlist_ref.setArchiveSettings()
}
},
refresh: function () {
@@ -2,7 +2,7 @@
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12">
<div class="flex sm6 xl6 md6 xs6">
<va-select
:on-change="directorySelect(directory)"
@input="directorySelect(directory)"
:label="'DIRECTORY'"
v-model="directory"
textBy="name"
@@ -89,7 +89,7 @@ export default {
}
},
directorySelect: function (directoryInfo) {
if (typeof directoryInfo === 'object') {
if (directoryInfo.parent) {
if (this.device.parent.folder === undefined || this.device.parent.folder.indexOf(directoryInfo.id) === -1) {
if (this.device.status === 0) {
this.device.parent.folder = []
@@ -122,9 +122,9 @@ export default {
// directory init
const collection = await api.collection.getAll()
this.directoryOptions = collection.data.filter(el => el.name !== 'root')
if (Object.keys(this.device.parent).length === 0) {
this.directory = this.directoryOptions[0]
this.directory = this.directoryOptions.find(ele => ele.name === 'admin')
this.directorySelect(this.directory)
} else {
for (const directory of this.directoryOptions) {
if (this.device.parent.folder.includes(directory.id)) {
@@ -143,8 +143,8 @@ export default {
pageInit: async function () {
},
},
mounted () {
this.setArchiveSettings()
async mounted () {
await this.setArchiveSettings()
},
destroyed () {
},
@@ -16,7 +16,7 @@
/>
</div>
<div class="flex sm2 xl2 md2 xs2 px-0 mx-0 my-0 py-0 pl-2">
<va-button class="pa-0 ma-0 mt-2 circle-button" small color="dark" @click="showModal=true">
<va-button v-if="place != 'scheduler'" class="pa-0 ma-0 mt-2 circle-button" small color="dark" @click="showModal=true">
<va-icon
name="fa fa-info"
color="white"
@@ -26,8 +26,28 @@
</div>
</div>
<!-- split because of styling problem(treenode), combine together furture -->
<!-- Trigger -->
<div v-if="library && library.includes('TRIG')">
<Trigger v-if="parameter.MODE === 0" :parameter="parameter" :parameterTable="parameterTable" @parameterChange="parameterChange"></Trigger>
<div v-if="parameter.MODE === 2">
<component
v-for="name in parameterArrayInMode"
:key="name"
:is="parameterTable[name].componentType"
:templateType=1
:withHeader="true"
:parameterName="name"
:inputValue="parameter[name]"
v-bind="parameterTable[name]"
@parameterChange="parameterChange"
@getParameter="getParameter"
@sendInstruction="sendInstruction"
/>
</div>
<TriggerNew v-if="parameter.MODE === 3" :parameter="parameter" :parameterTable="parameterTable" @parameterChange="parameterChange"></TriggerNew>
</div>
<!-- EIS -->
<div v-if="library.includes('EIS')">
<div v-if="library && library.includes('EIS')">
<component
v-for="name in parameterArrayInMode"
:key="name"
@@ -44,7 +64,7 @@
/>
</div>
<!-- ZM15-PulseSensingMode -->
<div v-else-if="parameter.MODE === 14">
<div v-else-if="library && (library.includes('EDC') || library.includes('BAT')) && parameter.MODE === 14">
<EliteParameterRecordingElitePulseSensing
:parameter="parameter"
:device="device"
@@ -55,7 +75,7 @@
/>
</div>
<!-- ZM15-DPVMode -->
<div v-else-if="parameter.MODE === 15">
<div v-else-if="library && (library.includes('EDC') || library.includes('BAT')) && parameter.MODE === 15">
<EliteParameterRecordingEliteDPV
:parameter="parameter"
:device="device"
@@ -66,7 +86,7 @@
/>
</div>
<!-- ZM15-OtherModes -->
<div v-else>
<div v-else-if="library && (library.includes('EDC') || library.includes('BAT'))">
<va-tree-category
v-for="name in parameterArrayInMode"
:key="name"
@@ -81,6 +101,7 @@
:parameterName="name"
:inputValue="parameter[name]"
:disable="name === 'CTRL_HIGH_Z_15' && device && device.status === 0"
:syncParameter="parameterTable[name].syncParameter"
v-bind="parameterTable[name]"
@parameterChange="parameterChange"
@getParameter="getParameter"
@@ -89,11 +110,61 @@
</va-tree-node>
</va-tree-category>
</div>
<!-- PEL-->
<div v-if="library && library.includes('PEL')">
<div v-if="parameter.MODE === 0">
<PEL :device="device"></PEL>
</div>
<div v-else>
<component
v-for="name in parameterArrayInMode"
:key="name"
:is="parameterTable[name].componentType"
:templateType=1
:withHeader="true"
:parameterName="name"
:inputValue="parameter[name]"
:disable="name === 'CTRL_HIGH_Z_15' && device && device.status === 0"
v-bind="parameterTable[name]"
@parameterChange="parameterChange"
@getParameter="getParameter"
@sendInstruction="sendInstruction"
/>
</div>
</div>
<!-- CPG -->
<div v-if="library && library.includes('CPG')">
<div v-if="parameter.MODE === 0">
<ElectricalStimulation
:parameter="parameter"
:parameterTable="parameterTable"
@parameterChange="parameterChange"
@getParameter="getParameter"
@sendInstruction="sendInstruction"
></ElectricalStimulation>
</div>
<div v-else>
<component
v-for="name in parameterArrayInMode"
:key="name"
:is="parameterTable[name].componentType"
:templateType=1
:withHeader="true"
:parameterName="name"
:inputValue="parameter[name]"
:disable="name === 'CTRL_HIGH_Z_15' && device && device.status === 0"
v-bind="parameterTable[name]"
@parameterChange="parameterChange"
@getParameter="getParameter"
@sendInstruction="sendInstruction"
/>
</div>
</div>
</va-tree-root>
<!-- guide picture button -->
<div>
<vue-final-modal
v-if="library.includes('Elite_EDC')"
v-if="library"
v-model="showModal"
classes="modal-container"
content-class="modal-content"
@@ -107,7 +178,8 @@
<!-- <va-icon class='fa fa-close modal__close' @click="showModal=false"></va-icon>
<span class="modal__title"></span> -->
<div class="modal__content">
<img :src="require('@/assets/img/elite-wire/' + getImageUrl + '.svg')" class="modal_img" alt="No Pic" draggable="false" >
<img v-if="library.includes('EDC')" :src="require('@/assets/img/elite-wire/' + getImageUrl + '.svg')" class="modal_img" alt="No Pic" draggable="false" >
<img v-if="library.includes('CPG')" :src="require('@/assets/img/elite-wire/CPG_UI_infomation_figure.png')" class="modal_img" alt="No Pic" draggable="false" >
<!-- <img :src="`${pat}`" class="imgaa" alt="No Pic" draggable="false"> -->
</div>
</vue-final-modal>
@@ -123,10 +195,14 @@ import InputField from '../parameter/itemNew/InputField'
import MultiInputField from '../parameter/itemNew/MultiInputField'
import EliteParameterRecordingEliteDPV from '../parameter/itemNew/DPVNew/EliteParameterRecordingEliteDPV'
import DevMode from '../parameter/itemNew/DevMode'
import Trigger from '../parameter/itemNew/TriggerNew/Trigger'
import TriggerNew from '../parameter/itemNew/TriggerNew/TriggerNew'
import EliteParameterRecordingElitePulseSensing from '../parameter/itemNew/PulseSensingNew/EliteParameterRecordingElitePulseSensing'
import { VueFinalModal } from 'vue-final-modal'
import { mapFields } from 'vuex-map-fields'
import configTable from '@/data/config-table/index'
import ElectricalStimulation from '../parameter/itemNew/ElectricalStimulation/ElectricalStimulation'
import PEL from './itemNew/PEL'
export default {
name: 'EliteParameterRecordingElitezm15',
@@ -140,6 +216,10 @@ export default {
InputField,
MultiInputField,
DevMode,
Trigger,
TriggerNew,
ElectricalStimulation,
PEL,
},
props: {
parameter: {
@@ -147,7 +227,8 @@ export default {
required: true,
},
library: {
type: String,
type: [String, null],
default: null,
},
serialNumber: {
type: [String, Array],
@@ -156,6 +237,14 @@ export default {
type: Object,
default: null,
},
place: {
type: String,
default: '',
},
resetParameterModeChange: {
type: Boolean,
default: false,
},
},
computed: {
parameterTable () {
@@ -174,7 +263,7 @@ export default {
return null
},
parameterArrayInMode () {
return this.workingModeSelect && this.parameterTable.MODE[this.workingModeSelect.id].parameter
return this.workingModeSelect && this.parameterTable && this.parameterTable.MODE[this.workingModeSelect.id].parameter
},
modeSelection () {
if (this.parameter.MODE) {
@@ -183,7 +272,7 @@ export default {
return this.workingModeSelect.id
},
getImageUrl () {
if (this.workingModeSelect === null) {
if (!this.workingModeSelect) {
return 'IV-Wire'
} else {
return this.workingModeSelect.img_src
@@ -230,9 +319,9 @@ export default {
return ''
}
},
parameterChange: function (name, value, debounce = false) {
parameterChange: function (name, value, debounce = false, force = false) {
/** if parameter is equal to value, then don't change, JSON.stringify is for array & object compare */
if (JSON.stringify(value) !== JSON.stringify(this.parameter[name])) {
if (JSON.stringify(value) !== JSON.stringify(this.parameter[name]) || force === true) {
this.parameter[name] = value
debounce === false
? this.$emit('setParameter', name, value)
@@ -241,19 +330,34 @@ export default {
},
refresh () {
},
workingModeSelectChange (val) {
workingModeSelectChange (val, reset = true) {
if (val === undefined || this.parameter.MODE === undefined) return
this.workingModeSelect = val
console.log('workingModeSelectChange', this.workingModeSelect.id, this.parameter.MODE)
// console.log('workingModeSelectChange', this.workingModeSelect, this.parameter.MODE)
if (this.workingModeSelect.id !== this.parameter.MODE) {
this.parameterChange('MODE', this.workingModeSelect.id)
if (this.resetParameterModeChange === true) {
if (reset === true) {
for (const parameter of this.parameterTable.MODE[this.workingModeSelect.id].parameter) {
this.$emit('setParameter', parameter, this.parameterTable[parameter].defaultValue)
}
}
}
// if device is idle, then setting highz when mode switch
if (this.deviceStatus === true && this.workingModeSelect.highz !== undefined) {
this.parameterChange('CTRL_HIGH_Z_15', this.workingModeSelect.highz)
if (this.deviceStatus === true) {
if (this.workingModeSelect.highz !== undefined) {
this.parameterChange('CTRL_HIGH_Z_15', this.workingModeSelect.highz)
}
}
}
},
resetWorkingMode () {
this.workingModeOptions = this.parameterTable.MODE_OPTIONS
this.workingModeSelect = (this.parameter.MODE !== undefined) ? this.workingModeOptions.find(ele => ele.id === this.parameter.MODE) : this.workingModeOptions[0]
console.log(this.workingModeOptions, this.workingModeSelect)
},
getParameter: function (name) {
this.$emit('getParameter', name)
},
@@ -266,11 +370,27 @@ export default {
// this.developerMode === true
// ? this.workingModeOptions = this.workingModeDevOptions
// : this.workingModeOptions = this.workingModeNoDevOptions
this.workingModeOptions = this.parameterTable.MODE_OPTIONS
// init mode
this.workingModeSelect = (this.parameter.MODE !== undefined) ? this.workingModeOptions.find(ele => ele.id === this.parameter.MODE) : this.workingModeOptions[0]
if (this.parameterTable !== null) {
this.workingModeOptions = this.parameterTable.MODE_OPTIONS
// init mode
this.workingModeSelect = (this.parameter.MODE !== undefined) ? this.workingModeOptions.find(ele => ele.id === this.parameter.MODE) : this.workingModeOptions[0]
}
},
watch: {
parameter: {
deep: true,
handler: function () {
// refresh real time parameter
this.workingModeSelect = (this.parameter.MODE !== undefined) ? this.workingModeOptions.find(ele => ele.id === this.parameter.MODE) : this.workingModeOptions[0]
},
},
library: {
handler: function () {
if (!this.parameterTable) return
this.workingModeOptions = this.parameterTable.MODE_OPTIONS
this.workingModeSelect = (this.parameter.MODE !== undefined) ? this.workingModeOptions.find(ele => ele.id === this.parameter.MODE) : this.workingModeOptions[0]
},
},
},
destroyed () {
},
@@ -12,14 +12,14 @@
</div>
<!-- EIS -->
<div v-if="workingModeSelect != null && workingModeSelect.id == 0">
<d-c-volt :ref="'DCVolt'" :deviceID="deviceID" :parameterName="'DC_BIAS'" @parameterChange="deviceParameterChange($event)" />
<a-c-amplitude :ref="'ACAmplitude'" :deviceID="deviceID" :parameterName="'AC_AMP'" @parameterChange="deviceParameterChange($event)" />
<freq-range :ref="'FreqRange'" :deviceID="deviceID" :parameterName="'FREQ'" @parameterChange="deviceParameterChange($event)" />
<points-per-decades :ref="'PointsPerDecades'" :deviceID="deviceID" :parameterName="'PPD'" @parameterChange="deviceParameterChange($event)" />
<point-spacing :ref="'PointSpacing'" :deviceID="deviceID" :parameterName="'SCALE'" @parameterChange="deviceParameterChange($event)" />
<delay :ref="'Delay'" :deviceID="deviceID" :parameterName="'DELAY'" @parameterChange="deviceParameterChange($event)" />
<average :ref="'Average'" :deviceID="deviceID" :parameterName="'AVERAGE_NUM'" @parameterChange="deviceParameterChange($event)" />
<current-range :ref="'CurrentRange'" :deviceID="deviceID" :parameterName="'RTIA'" @parameterChange="deviceParameterChange($event)" />
<d-c-volt :ref="'DCVolt'" :deviceID="deviceID" :parameterName="'EIS_DC_BIAS'" @parameterChange="deviceParameterChange($event)" />
<a-c-amplitude :ref="'ACAmplitude'" :deviceID="deviceID" :parameterName="'EIS_AC_AMP'" @parameterChange="deviceParameterChange($event)" />
<freq-range :ref="'FreqRange'" :deviceID="deviceID" :parameterName="'EIS_FREQ'" @parameterChange="deviceParameterChange($event)" />
<points-per-decades :ref="'PointsPerDecades'" :deviceID="deviceID" :parameterName="'EIS_PPD'" @parameterChange="deviceParameterChange($event)" />
<point-spacing :ref="'PointSpacing'" :deviceID="deviceID" :parameterName="'EIS_SCALE'" @parameterChange="deviceParameterChange($event)" />
<delay :ref="'Delay'" :deviceID="deviceID" :parameterName="'EIS_DELAY'" @parameterChange="deviceParameterChange($event)" />
<average :ref="'Average'" :deviceID="deviceID" :parameterName="'EIS_AVERAGE_NUM'" @parameterChange="deviceParameterChange($event)" />
<current-range :ref="'CurrentRange'" :deviceID="deviceID" :parameterName="'GENERAL_HS_RTIA'" @parameterChange="deviceParameterChange($event)" />
</div>
<!-- CV -->
<div v-if="workingModeSelect != null && workingModeSelect.id == 1">
@@ -45,14 +45,6 @@
<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 sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">Voltage Range<p/>
</div>
<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 sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">High Z<p/>
@@ -66,7 +58,7 @@
<p class="display-6">E Initial<p/>
</div>
<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)" />
<volt-range :ref="'voltInitialNumber'" :deviceID="deviceID" :parameterName="'CV_E_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">
@@ -74,7 +66,7 @@
<p class="display-6">E1<p/>
</div>
<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)" />
<volt-range :ref="'voltMaxNumber'" :deviceID="deviceID" :parameterName="'CV_E1'" :minValue="-1.8" :maxValue="2" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
@@ -82,7 +74,7 @@
<p class="display-6">E2<p/>
</div>
<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)" />
<volt-range :ref="'voltMinNumber'" :deviceID="deviceID" :parameterName="'CV_E2'" :minValue="-1.8" :maxValue="2" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
@@ -90,7 +82,7 @@
<p class="display-6">Voltage Scan Rate<p/>
</div>
<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)" />
<scan-rate-range :ref="'voltScanRateNumber'" :deviceID="deviceID" :parameterName="'CV_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">
@@ -283,7 +275,7 @@ export default {
},
],
DCVolt: null,
AC_AMP: null,
EIS_AC_AMP: null,
FreqStart: null,
FreqStop: null,
PointsPerDecades: null,
@@ -395,45 +387,36 @@ 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)
}
this.ACAmplitude = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.AC_AMP) / 2047 * 800))
this.ACAmplitude = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_AC_AMP) / 2047 * 800))
if (this.$refs.ACAmplitude != null) {
this.$refs.ACAmplitude.itemChange(this.ACAmplitude)
}
this.Average = taskInfo.getDeviceInfo(this.deviceID).parameterSet.AVERAGE_NUM
this.Average = taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_AVERAGE_NUM
if (this.$refs.Average != null) {
this.$refs.Average.itemChange(this.Average)
}
this.CurrentRange = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RTIA
this.CurrentRange = taskInfo.getDeviceInfo(this.deviceID).parameterSet.GENERAL_HS_RTIA
if (this.$refs.CurrentRange != null) {
this.$refs.CurrentRange.itemChange(this.CurrentRange)
}
this.PointSpacing = taskInfo.getDeviceInfo(this.deviceID).parameterSet.SCALE
this.PointSpacing = taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_SCALE
if (this.$refs.PointSpacing != null) {
this.$refs.PointSpacing.itemChange(this.PointSpacing)
}
this.DCVolt = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.DC_BIAS - 15000) / 10
this.DCVolt = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_DC_BIAS - 15000) / 10
if (this.$refs.DCVolt != null) {
this.$refs.DCVolt.itemChange(this.DCVolt)
}
this.Delay = String(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.DELAY) / 10).toFixed(1))
this.Delay = String(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_DELAY) / 10).toFixed(1))
if (this.$refs.Delay != null) {
this.$refs.Delay.itemChange(this.Delay)
}
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.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.itemChangeMin(this.FreqStop)
}
this.PointsPerDecades = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.PPD)))
this.PointsPerDecades = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.EIS_PPD)))
if (this.$refs.PointsPerDecades != null) {
this.$refs.PointsPerDecades.itemChange(this.PointsPerDecades)
}
@@ -444,11 +427,6 @@ export default {
this.$refs.currentRangeSelect.updateLevelButton(this.currentRangeSelect)
}
this.voltageInRangeSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.ADC_LEVEL_V_IN_15
if (this.$refs.voltageInRangeSelect != null) {
this.$refs.voltageInRangeSelect.updateLevelButton(this.voltageInRangeSelect)
}
this.highzSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.CTRL_HIGH_Z_15
if (this.$refs.highzSelect != null) {
this.$refs.highzSelect.updateLevelButton(this.highzSelect)
@@ -464,12 +442,12 @@ export default {
this.$refs.stopVoltMinNumber.updateVoltNumber(this.stopVoltMinNumber)
}
this.voltInitialNumber = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.VOLT_INITIAL - 25000) / 5
this.voltInitialNumber = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.CV_E_INITIAL - 25000) / 5
if (this.$refs.voltInitialNumber != null) {
this.$refs.voltInitialNumber.updateVoltNumber(this.voltInitialNumber)
}
this.voltScanRateNumber = taskInfo.getDeviceInfo(this.deviceID).parameterSet.Scan_Rate
this.voltScanRateNumber = taskInfo.getDeviceInfo(this.deviceID).parameterSet.CV_SCAN_RATE
if (this.$refs.voltScanRateNumber != null) {
this.$refs.voltScanRateNumber.updateVoltScanRateNumber(this.voltScanRateNumber)
}
@@ -14,19 +14,18 @@
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-input
@keyup.enter="instruParameterChange(inputWrite)"
@blur="instruParameterChange(inputWrite)"
class="mb-0"
v-model="inputWrite"
label="Write value (0x3000FF ... )"
style="width: 100px;"
maxlength="34"
/>
<va-button slot="append" class="mr-2 pa-1 shrink" style="width: 2em; height: 2em; border-radius: 50%; font-size: 20px;" small @click="sendInstr('ble_instru_send')">
W
</va-button>
<div>
<h1>
Write
</h1>
</div>
<div class="flex row">
<div>
<textarea class="hexStringArea" v-model="hexInput" @input="formatHexInput" placeholder="Enter hex string..." ref="textarea" maxlength="731"></textarea>
</div>
<div>
<va-icon class="ml-3 fa fa-check-circle custom-icon" size="30px" @click.native="sendInstr('ble_instru_send')"></va-icon>
</div>
</div>
</div>
</div>
@@ -93,6 +92,7 @@ export default {
},
data () {
return {
hexInput: '',
inputWrite: '',
inputNotify: '',
}
@@ -100,6 +100,34 @@ export default {
mqtt: {
},
methods: {
formatHexInput () {
const textarea = this.$refs.textarea
let cursorPosition = textarea.selectionStart
// Remove any non-hex characters (if necessary)
const cleanInput = this.hexInput.replace(/[^A-Fa-f0-9]/g, '')
// Calculate spaces that will be added
const spacesBefore = (this.hexInput.slice(0, cursorPosition).match(/ /g) || []).length
// Add space after every two characters
const formattedInput = cleanInput.match(/.{1,2}/g)?.join(' ') || ''
// Set the formatted input
this.hexInput = formattedInput.toUpperCase()
// Calculate new cursor position
const spacesAfter = (formattedInput.slice(0, cursorPosition).match(/ /g) || []).length
cursorPosition = cursorPosition + (spacesAfter - spacesBefore)
// Set the new cursor position
this.$nextTick(() => {
textarea.setSelectionRange(cursorPosition, cursorPosition)
})
const instructionArray = this.hexInput.split(' ').map(hex => parseInt(hex, 16))
this.$emit('parameterChange', 'BLE_WRITE', instructionArray, true)
},
sendInstr (instr) {
this.$emit('sendInstruction', instr)
},
@@ -112,20 +140,6 @@ export default {
readCisData () {
this.$emit('getParameter', 'ADC_VALUE_I')
},
instruParameterChange (instruction) {
while (instruction.length <= 33) {
instruction += '0'
}
const sendIns = new Array(17).fill(0)
for (let i = 0; i <= 16; i++) {
const startIndex = i * 2
sendIns[i] = instruction.substring(startIndex, startIndex + 2)
sendIns[i] = parseInt(sendIns[i], 16)
}
this.$emit('parameterChange', 'BLE_WRITE', '0:16=' + String(sendIns))
},
},
async mounted () {
},
@@ -136,3 +150,27 @@ export default {
}
</script>
<style>
.hexStringArea {
width: 100%;
height: 100px;
font-size: 14px;
}
.va-tree-category__list-internal-container {
padding-left: 0;
}
.custom-icon {
color: #007bff; /* Default color */
transition: color 0.3s ease;
}
.custom-icon:hover {
color: #0056b3; /* Color when hovering */
}
.custom-icon:active {
color: #003580; /* Color when clicked */
}
</style>
@@ -0,0 +1,201 @@
<template>
<div>
<!-- Main container for the pulse output section -->
<div class="pulse-output" style="width: 95%; justify-content: space-between;">
<!-- PULSE OUTPUT label section -->
<div>
<p style="font-family: 'Inter-Bold';">Pulse Output</p>
</div>
<!-- Timer section, clicking on this triggers setTimer() -->
<div style="display: flex;">
<div class="timer" @click="setTimer" style="cursor: pointer;">
<img src="@/assets/icons/ES_Mode/button-timer.svg">
<p
v-if="parameter.CONTINUE_MODE === 0"
style="font-family: 'Inter'; font-size: 1rem;"
>{{ formattedTime }}</p>
<p v-if="parameter.CONTINUE_MODE === 1"
style="font-family: 'Inter'; font-size: 1.5rem; font-style: normal;"
></p>
</div>
<!-- Buttons for controlling electrode activation -->
<div style="min-width: 80px; text-align: end;">
<!-- Output button visible when electrode is not activated -->
<va-button
:class="isElectrodeActivated ? 'not-visible' : ''"
color="#5cd699"
style="padding: 0.125rem 0.5rem;"
@click="activateElectrode"
small
>output</va-button>
<!-- Stop button visible when electrode is activated -->
<va-button
:class="!isElectrodeActivated ? 'not-visible' : ''"
color="danger"
style="padding: 0.125rem 0.5rem;"
@click="deactiveElectrode"
small
>stop</va-button>
</div>
</div>
</div>
<!-- Test component to handle parameters -->
<PulseOutputSettings
:parameter="parameter"
:parameterTable="parameterTable"
@parameterChange="parameterChange"
@sendInstruction="sendInstruction"
></PulseOutputSettings>
<!-- Timer modal component to handle timer settings -->
<TimerModal :ref="'timer_modal_ref'" :parameter="parameter" :parameterTable="parameterTable" @parameterChange="parameterChange"></TimerModal>
</div>
</template>
<script>
import PulseOutputSettings from './PulseOutputSettings'
import TimerModal from './TimerModal'
export default {
name: 'ElectricalStimulation',
components: {
PulseOutputSettings,
TimerModal,
},
props: {
parameter: {
type: Object,
default: () => {},
},
parameterTable: {
type: Object,
default: () => {},
},
},
computed: {
isElectrodeActivated () {
return this.parameter.ACTIVATE_ELECTRODE === 1
},
formattedTime () {
let totalSeconds = this.parameter.STOP_TIME
const hh = Math.floor(totalSeconds / 3600)
totalSeconds %= 3600
const mm = Math.floor(totalSeconds / 60)
const ss = totalSeconds % 60
// Now conditionally format the output:
let formatted = ''
if (hh > 0) {
formatted += `${hh} h `
}
if (mm > 0) {
formatted += `${mm} m `
}
if (ss > 0 || formatted === '') {
formatted += `${ss} s`
}
return formatted.trim() // Ensure there are no trailing spaces
},
},
created () {
},
data () {
return {
selectedValue: null,
radioItems: [
{ value: 1 },
{ value: 2 },
],
}
},
methods: {
setTimer () {
this.$refs.timer_modal_ref.show()
},
activateElectrode () {
this.parameter.ACTIVATE_ELECTRODE = !this.parameter.ACTIVATE_ELECTRODE
this.parameter.WORKING_ELECTRODE.map((item, index) => {
this.parameter.WORKING_ELECTRODE[index] = 1
})
this.parameterChange('WORKING_ELECTRODE', this.parameter.WORKING_ELECTRODE)
this.parameterChange('ACTIVATE_ELECTRODE', this.parameter.ACTIVATE_ELECTRODE)
this.sendInstruction('output')
},
deactiveElectrode () {
this.parameter.ACTIVATE_ELECTRODE = !this.parameter.ACTIVATE_ELECTRODE
this.parameter.WORKING_ELECTRODE.map((item, index) => {
this.parameter.WORKING_ELECTRODE[index] = 0
})
this.parameterChange('WORKING_ELECTRODE', this.parameter.WORKING_ELECTRODE)
this.parameterChange('ACTIVATE_ELECTRODE', this.parameter.ACTIVATE_ELECTRODE)
this.sendInstruction('deactive_electrode')
},
parameterChange (key, value) {
this.$emit('parameterChange', key, value, false, true)
},
sendInstruction: function (instr) {
this.$emit('sendInstruction', instr)
},
},
}
</script>
<style>
.underline {
width: 100%;
height: 1px;
background-color: #2c3e50;
margin-top: 5px;
}
.pulse-output {
display: flex;
align-items: center;
font-size: 18px;
}
.timer {
display: flex;
align-items: center;
margin-left: 10px;
font-style: italic;
transition: opacity 0.3s ease; /* Smooth transition effect */
}
.timer:hover {
opacity: 0.6;
}
.timer-icon {
font-size: 16px;
margin-right: 5px;
}
.output-button {
background-color: #5cd699;
color: white;
border: none;
padding: 8px 16px;
font-size: 16px;
border-radius: 5px;
cursor: pointer;
}
.output-button:hover {
background-color: #45bf7d;
}
.not-visible {
display: none;
}
</style>
@@ -0,0 +1,423 @@
<template>
<!-- Main container div -->
<div class="container">
<!-- Row for electrode and pulse pattern controls -->
<div class="row flex xl12 lg12 my-3" style="padding: 0 0.25rem;">
<!-- Left side: Electrode section -->
<div class="flex xl6 lg6 py-0 px-0">
<div class="centered-item">
<span>Electrode</span>
<div class="underline"></div>
</div>
<!-- Looping over electrode options to render checkboxes -->
<div class="radio-item" style="padding: 0.25rem; line-height: 30px; justify-content: space-evenly;" v-for="(option, index) in channelOption" :key="'electrode-1-' + option">
<div style="display: flex; align-items: center;">
<!-- Checkbox input for electrode selection -->
<input
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
style="margin-right: 0.25rem; cursor: pointer;"
type="checkbox"
v-model="parameter.ELECTRODE_SELECTOR[index]"
@click="selectedElectrode(index)"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
/>
<span class="number">{{ option }}</span>
</div>
<!-- Play button (active or inactive depending on conditions) -->
<div style="min-width: 30px;">
<div
v-if="parameter.ACTIVATE_ELECTRODE === 1 && parameter.WORKING_ELECTRODE[index] === 1 && parameter.ELECTRODE_SELECTOR[index] === true"
style="display: flex;"
>
<img src="@/assets/icons/ES_Mode/button-play-active.svg">
</div>
<div
v-else
style="display: flex; cursor: pointer;"
@click="startElectrode(index)"
>
<img src="@/assets/icons/ES_Mode/button-play.svg">
</div>
</div>
<!-- Stop button (active or inactive depending on conditions) -->
<div style="min-width: 30px;">
<div
style="display: flex;"
v-if="parameter.ACTIVATE_ELECTRODE === 1 && parameter.WORKING_ELECTRODE[index] === 0 && parameter.ELECTRODE_SELECTOR[index] === true"
>
<img src="@/assets/icons/ES_Mode/button-stop-active.svg">
</div>
<div
v-else
style="display: flex; cursor: pointer;"
@click="stopElectrode(index)"
>
<img src="@/assets/icons/ES_Mode/button-stop.svg">
</div>
</div>
</div>
</div>
<!-- Right side: Pulse Pattern section -->
<div class="flex xl6 lg6 py-0" style="padding-right: 0;">
<div class="centered-item">
<span>Pulse Pattern</span>
<div class="underline"></div>
</div>
<!-- Looping over pulse pattern options to render radio buttons -->
<div class="radio-item" style="padding: 0.25rem; line-height: 30px; justify-content: space-evenly;" v-for="(option, index) in channelOption" :key="'electrode-2-' + option">
<div style="display: flex; align-items: center;">
<!-- Radio button for pattern 1 -->
<input
style="margin-right: 0.25rem; cursor: pointer;"
type="radio"
:name="'pulse-pattern-' + index"
:value="0"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
v-model="parameter.PATTERN_SELECTOR[index]"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@click="bindingPattern(index, 0)"
/>
<span class="number">1</span>
</div>
<div style="display: flex; align-items: center;">
<!-- Radio button for pattern 2 -->
<input
style="margin-right: 0.25rem; cursor: pointer;"
type="radio"
:name="'pulse-pattern-' + index"
:value="1"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
v-model="parameter.PATTERN_SELECTOR[index]"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@click="bindingPattern(index, 1)"
/>
<span class="number">2</span>
</div>
</div>
</div>
</div>
<!-- Section for Pulse Patterns 1 and 2 -->
<div v-for="(value, index) in [1,2]" class="controls" style="width: 100%; margin-bottom: 1rem;" :key="'pattern-' + index">
<p style="font-size: 18px; font-family: 'Inter-Bold';">Pulse Pattern {{ value }}</p>
<div class="row flex xl12 lg12" style="margin-top: 0.5rem; padding: 0 0.25rem; font-family: 'Inter';" >
<!-- Left column: Input fields for Amplitude and Pulse Width -->
<div class="flex xl6 lg6 py-0">
<div>
<p>Amplitude</p>
<!-- Amplitude input field -->
<va-input
v-model="parameter.AMPLITUDE[index]"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@blur="valueChecked('AMPLITUDE', index)"
@keyup.enter="valueChecked('AMPLITUDE', index)"
>
<p slot="append" style="margin-right: 0;" small>
mA
</p>
</va-input>
<p>Pulse Width</p>
<!-- Pulse Width input field -->
<va-input
v-model="parameter.PULSE_WIDTH[index]"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@blur="valueChecked('PULSE_WIDTH', index)"
@keyup.enter="valueChecked('PULSE_WIDTH', index)"
>
<p slot="append" style="margin-right: 0;" small>
µs
</p>
</va-input>
</div>
</div>
<!-- Right column: Radio buttons for Mode selection and Frequency input -->
<div class="flex xl6 lg6 py-0" style="align-content: flex-end;">
<!-- Radio button for Burst Mode -->
<div class="radio-item" style="margin-bottom: 2rem; gap: 8px;">
<input
type="radio"
style="cursor: pointer;"
:value="0"
v-model="parameter.PATTERN_MODE[index]"
:name="'pulse-mode-' + index"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@click="patternModeChange(index, 0)"
/>
<span class="number">Burst Mode</span>
</div>
<!-- Radio button for Frequency Mode -->
<div class="radio-item" style="gap: 8px;">
<input
type="radio"
style="cursor: pointer;"
:value="1"
v-model="parameter.PATTERN_MODE[index]"
:name="'pulse-mode-' + index"
:class="parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
:disabled="parameter.ACTIVATE_ELECTRODE === 1"
@click="patternModeChange(index, 1)"
/>
<span class="number">Frequency</span>
</div>
<!-- Frequency input field (enabled only in Frequency mode) -->
<div>
<va-input
v-model="parameter.FREQUENCY[index]"
@keyup.enter="valueChecked('FREQUENCY', index)"
@blur="valueChecked('FREQUENCY', index)"
:class="parameter.PATTERN_MODE[index] === 0 || parameter.ACTIVATE_ELECTRODE === 1 ? 'disable-input': ''"
:disabled="parameter.PATTERN_MODE[index] === 0 || parameter.ACTIVATE_ELECTRODE === 1"
>
<p slot="append" style="margin-right: 0;" small>
Hz
</p>
</va-input>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'PulseOutputSettings',
// Props passed from the parent component
props: {
parameter: {
type: Object,
default: () => {}, // Default to an empty object if no parameter is provided
},
parameterTable: {
type: Object,
default: () => {}, // Default to an empty object for parameterTable
},
order: Number, // Numerical order for the component (could be used to track different instances)
pulsePattern: Number, // Indicates the pulse pattern selected (1 or 2)
status: String, // Status indicator (could be used for component state, e.g., active/inactive)
},
computed: {
// No computed properties defined in this component
},
// Component's local data
data () {
return {
selectedValue: [], // Stores selected values for the UI components
selectedPattern: null, // Stores the currently selected pattern
channelOption: [1, 2, 3, 4], // Available channel options (4 channels for example)
pulsePatternItems: [ // List of pulse pattern items (1 and 2)
{ value: 1 },
{ value: 2 },
],
}
},
// Methods that define behavior
methods: {
// Toggles the electrode selector for a given index and emits the change
selectedElectrode (index) {
// Toggle the boolean value in ELECTRODE_SELECTOR
this.parameter.ELECTRODE_SELECTOR[index] = !this.parameter.ELECTRODE_SELECTOR[index]
// Emit the change to the parent component
this.parameterChange('ELECTRODE_SELECTOR', this.parameter.ELECTRODE_SELECTOR)
},
// Handles the change of pulse pattern mode (either Frequency or Burst mode)
patternModeChange (index, value) {
// Set the frequency based on the selected mode
if (value === 1) {
this.parameter.FREQUENCY[index] = 1 // Set frequency to 1 for Frequency mode
} else {
this.parameter.FREQUENCY[index] = 0 // Set frequency to 0 for Burst mode
}
// Update PATTERN_MODE and emit the change
this.parameter.PATTERN_MODE[index] = value
this.parameterChange('PATTERN_MODE', this.parameter.PATTERN_MODE)
this.parameterChange('FREQUENCY', this.parameter.FREQUENCY)
},
// Binds the selected pattern to the specified electrode groups
bindingPattern (index, value) {
const temp = value
// Set the pattern for the first two electrodes if index is 0 or 1
if (index === 0 || index === 1) {
this.parameter.PATTERN_SELECTOR[0] = temp
this.parameter.PATTERN_SELECTOR[1] = temp
// Set the pattern for the second group of electrodes if index is 2 or 3
} else if (index === 2 || index === 3) {
this.parameter.PATTERN_SELECTOR[2] = temp
this.parameter.PATTERN_SELECTOR[3] = temp
}
// Emit the updated PATTERN_SELECTOR
this.parameterChange('PATTERN_SELECTOR', this.parameter.PATTERN_SELECTOR)
},
// Starts the electrode for the specified index
startElectrode (index) {
// Check if the electrode can be activated
if (this.parameter.ACTIVATE_ELECTRODE === 0 || this.parameter.ELECTRODE_SELECTOR[index] === false) {
return // Do nothing if the electrode is not selected or activation is off
}
// Toggle the WORKING_ELECTRODE state and emit the change
this.parameter.WORKING_ELECTRODE[index] = !this.parameter.WORKING_ELECTRODE[index]
this.parameterChange('WORKING_ELECTRODE', this.parameter.WORKING_ELECTRODE)
// Send an instruction to start the electrode (external function call)
this.sendInstruction('resume_electrode_' + index)
},
// Stops the electrode for the specified index
stopElectrode (index) {
// Check if the electrode can be deactivated
if (this.parameter.ACTIVATE_ELECTRODE === 0 || this.parameter.ELECTRODE_SELECTOR[index] === false) {
return // Do nothing if the electrode is not selected or activation is off
}
// Toggle the WORKING_ELECTRODE state and emit the change
this.parameter.WORKING_ELECTRODE[index] = !this.parameter.WORKING_ELECTRODE[index]
this.parameterChange('WORKING_ELECTRODE', this.parameter.WORKING_ELECTRODE)
// Send an instruction to stop the electrode (external function call)
this.sendInstruction('suspend_electrode_' + index)
},
// Ensures the value is within the acceptable range, rounded to the grid
valueChecked (parameterName, index) {
// Get the grid, minimum, and maximum values from the parameter table
const grid = this.parameterTable[parameterName].grid
const min = this.parameterTable[parameterName].range[0]
const max = this.parameterTable[parameterName].range[1]
// Round the value to the nearest grid and ensure it is within bounds
let value = Number(this.parameter[parameterName][index])
value = Math.round(value / grid) * grid
if (value < min) {
value = min // Set to min if it's too small
} else if (value > max) {
value = max // Set to max if it's too large
}
// Update the parameter and emit the change
this.parameter[parameterName][index] = value
this.parameterChange(parameterName, this.parameter[parameterName])
},
// Emits the parameter change event to the parent component
parameterChange (parameterName, value) {
this.$emit('parameterChange', parameterName, value)
},
// Sends instructions (e.g., start/stop electrode) to the parent component or external system
sendInstruction: function (instr) {
this.$emit('sendInstruction', instr)
},
},
}
</script>
<style scoped>
.centered-container {
display: flex;
justify-content: space-around;
align-items: center;
width: 100%;
}
.centered-item {
text-align: center;
}
.centered-item span {
display: block;
font-family: 'Inter';
font-size: 16px;
font-weight: 500;
color: #2c3e50;
}
.container {
align-items: center;
gap: 20px;
width: 95%;
}
.radio-group {
display: flex;
align-items: center;
flex-direction: column;
gap: 20px;
}
.radio-item {
display: flex;
align-items: center;
}
.disable-input {
opacity: 0.5;
}
input[type="radio"] {
/* remove standard background appearance */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
/* create custom radiobutton appearance */
display: inline-block;
width: 21px;
height: 21px;
padding: 2px;
/* background-color only for content */
background-clip: content-box;
border: 2px solid #bbbbbb;
background-color: #ffffff;
border-radius: 50%;
}
/* appearance for checked radiobutton */
input[type="radio"]:checked {
background-color: #858dd5;
}
input[type="checkbox"] {
/* remove standard background appearance */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
/* create custom radiobutton appearance */
display: inline-block;
width: 21px;
height: 21px;
padding: 2px;
/* background-color only for content */
background-clip: content-box;
border: 2px solid #bbbbbb;
background-color: #ffffff;
border-radius: 50%;
}
/* appearance for checked radiobutton */
input[type="checkbox"]:checked {
background-color: #858dd5;
}
</style>
@@ -0,0 +1,238 @@
<template>
<div>
<va-modal
v-model="showModal"
hideDefaultActions
noOutsideDismiss
>
<div class="timer-container">
<h2 style="font-size: 20px;">Timer</h2>
<div class="timer-inputs">
<div>
<input
type="number"
v-model="hours"
min="0"
class="time-input"
@click="mode = null"
/><span style="padding-left: 10px;">h</span>
</div>
<div>
<input
type="number"
v-model="minutes"
min="0"
class="time-input"
@click="mode = null"
/><span style="padding-left: 10px;">m</span>
</div>
<div>
<input
type="number"
v-model="seconds"
min="0"
class="time-input"
@click="mode = null"
/><span style="padding-left: 10px;">s</span>
</div>
</div>
<div class="mode-selection">
<input
type="radio"
id="continueMode"
:value="'infinity'"
:checked="mode === 'infinity'"
@click="toggleMode"
/>
<label
for="continueMode"
class="radio-text"
>continuous mode, </label>
</div>
<div style="display: flex; flex-direction: row; align-items: center; justify-content: flex-end;">
<p class="time-text">{{ formattedTime }}</p>
<va-button @click="setTimer" small>SET</va-button>
</div>
</div>
</va-modal>
</div>
</template>
<script>
export default {
name: 'TimerModal',
props: {
parameter: {
type: Object,
default: () => {},
},
},
computed: {
formattedTime () {
let totalSeconds = 0
totalSeconds += (parseInt(this.seconds) || 0)
totalSeconds += (parseInt(this.minutes) || 0) * 60
totalSeconds += (parseInt(this.hours) || 0) * 3600
const hh = Math.floor(totalSeconds / 3600)
totalSeconds %= 3600
const mm = Math.floor(totalSeconds / 60)
const ss = totalSeconds % 60
// Now conditionally format the output:
let formatted = ''
if (hh > 0) {
formatted += `${hh} h `
}
if (mm > 0) {
formatted += `${mm} m `
}
if (ss > 0) {
formatted += `${ss} s`
}
return formatted.trim() // Ensure there are no trailing spaces
},
},
data () {
return {
hours: '',
minutes: '',
seconds: '',
mode: null,
showModal: false,
}
},
methods: {
toggleMode () {
// If the mode is already selected, uncheck it (set it to null)
if (this.mode === 'infinity') {
this.mode = null
} else {
this.mode = 'infinity' // Otherwise, select the 'infinity' mode
this.hours = ' '
this.minutes = ' '
this.seconds = ' '
}
},
setTimer () {
// Your logic to handle timer setting, like validation or starting the timer
console.log('Timer set with', this.hours, this.minutes, this.seconds, this.mode)
let totalSeconds = 0
if (this.seconds > 0) {
totalSeconds += parseInt(this.seconds)
}
if (this.minutes > 0) {
totalSeconds += parseInt(this.minutes) * 60
}
if (this.hours > 0) {
totalSeconds += parseInt(this.hours) * 3600
}
this.$emit('parameterChange', 'STOP_TIME', totalSeconds)
this.$emit('parameterChange', 'CONTINUE_MODE', this.mode === 'infinity' ? 1 : 0)
this.hide()
},
initParameter () {
this.mode = this.parameter.CONTINUE_MODE === 1 ? 'infinity' : null
if (this.parameter.CONTINUE_MODE === 1) return
let totalSeconds = this.parameter.STOP_TIME
const hh = Math.floor(totalSeconds / 3600)
totalSeconds %= 3600
const mm = Math.floor(totalSeconds / 60)
const ss = totalSeconds % 60
this.hours = hh > 0 ? hh : ''
this.minutes = mm > 0 ? mm : ''
this.seconds = ss > 0 ? ss : ''
},
show () {
this.initParameter()
this.showModal = true
},
hide () {
this.showModal = false
},
},
}
</script>
<style scoped>
.timer-container {
display: flex;
flex-direction: column;
/* align-items: center; */
gap: 15px;
}
.timer-inputs {
display: flex;
gap: 10px;
}
.time-input {
width: 80px;
height: 40px;
text-align: right;
font-size: 1.2em;
border: 1px solid #cccccc;
border-radius: 10px;
padding: 5px;
}
.mode-selection {
display: flex;
align-items: center;
gap: 10px;
}
input[type="radio"] {
/* remove standard background appearance */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
/* create custom radiobutton appearance */
display: inline-block;
width: 21px;
height: 21px;
padding: 2px;
/* background-color only for content */
background-clip: content-box;
border: 2px solid #bbbbbb;
background-color: #ffffff;
border-radius: 50%;
}
/* appearance for checked radiobutton */
input[type="radio"]:checked {
background-color: #858dd5;
}
.radio-text {
font-family: Inter;
font-size: 16px;
font-weight: 500;
text-align: left;
color: #2c3e50;
}
.time-text {
font-family: Inter;
font-size: 14px;
font-weight: 500;
line-height: 19.36px;
text-align: left;
}
.disable-infinite-input {
color: #bdbdbd;
}
</style>
@@ -75,6 +75,10 @@ export default {
type: Boolean,
default: false,
},
syncParameter: {
type: Object,
default: () => {},
},
},
created () {
},
@@ -87,6 +91,13 @@ export default {
methods: {
buttonSelectChange (value) {
this.$emit('parameterChange', this.parameterName, value)
this.syncParameter && Object.keys(this.syncParameter).forEach(element => {
if (String(element) === String(value)) {
this.syncParameter[value].forEach(element => {
this.$emit('parameterChange', element[0], element[1])
})
}
})
},
},
async mounted () {
@@ -0,0 +1,112 @@
<template>
<div>
<div style="height: 60vh; overflow-y: scroll; overflow-x: hidden; scrollbar-width: none;">
<va-toggle v-model="switchInput" @click.native="setSwitch" flat small></va-toggle>
<div class="px-2">
<div v-if="switchInput === true">
<div>
<h1 style="font-size: 20px;">Manual</h1>
</div>
<div style="display: flex; margin-top: 0.5rem; margin-bottom: 1rem; width: 90%; justify-content: flex-start;">
<input type="text" class="flex-item" v-model="input1" @blur="setPulse">
<input type="text" class="flex-item" v-model="input2" @blur="setPulse">
<input type="text" class="flex-item" v-model="input3" @blur="setPulse">
</div>
</div>
<div v-if="switchInput === false">
<div>
<h1 style="font-size: 20px;">Pattern</h1>
</div>
<div style="display: flex; margin-top: 0.5rem; margin-bottom: 1rem; width: 90%; justify-content: flex-start;">
<input type="text" class="flex-item" v-model="input5" @blur="setPattern">
<!-- <va-button class="pa-0 ma-0 mt-1 circle-button" small color="dark">S
</va-button> -->
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
import { mapFields } from 'vuex-map-fields'
export default {
name: 'PEL',
components: {
},
props: {
device: {
type: Object,
required: true,
},
},
data () {
return {
input1: '0',
input2: '0',
input3: '0',
input4: '0',
input5: '0',
switchInput: false,
}
},
computed: {
...mapFields('', [
'developerMode',
]),
},
methods: {
setPulse: function () {
this.setParameter('PULSE', [this.hexToInt(this.input1), this.hexToInt(this.input2), this.hexToInt(this.input3)])
},
setPattern: function () {
this.setParameter('PATTERN', this.input5)
},
setSwitch: function () {
this.setParameter('PATTERN_SWITCH', this.switchInput)
},
intToHex: function (int) {
return int.toString(2).padStart(4, '0')
},
hexToInt (hex) {
return parseInt(hex, 2)
},
mqttPublish: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
setParameter: function (parameterName, parameterValue) {
this.mqttPublish(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: this.device.mac_address,
parameter: parameterName,
content: parameterValue,
}))
},
},
mounted () {
this.input1 = this.intToHex(this.device.configuration.PULSE[0])
this.input2 = this.intToHex(this.device.configuration.PULSE[1])
this.input3 = this.intToHex(this.device.configuration.PULSE[2])
this.input5 = this.device.configuration.PATTERN
this.switchInput = Boolean(this.device.configuration.PATTERN_SWITCH)
},
destroyed () {
},
}
</script>
<style lang="scss">
.no-dark-style-va-button {
&:focus {
filter: brightness(100%);
}
}
.flex-item {
width: 55px; /* Max width of 75px */
padding: 5px;
margin-right: 1rem;
}
</style>
@@ -0,0 +1,152 @@
<template>
<div class="flex sm12 xl12 md12 xs12 mb-2 pb-1 align--center">
<div class="row">
<div class="flex sm12 xl5 md5 xs12 my-1 py-0">
<p class="display-6"> CHANNEL {{ Number(channel) + 1 }} <p/>
</div>
<div class="flex sm12 xl3 md3 xs12 px-0 mx-0 my-0 py-0">
<va-input
class="mb-0 small-va-input"
v-model="inputStringText"
:disabled="!channelToggle"
@keyup.enter="inputChange(inputString)"
@blur="inputChange(inputString)"
>
<p slot="append" style="margin-right: 0;" small>
mA
</p>
</va-input>
</div>
<div class="flex sm12 xl4 md4 xs12 px-0 mx-0 my-0 py-0">
<va-toggle class="mb-0" v-model="toggle" color="success" style="float: right;" flat small @click.native="switchToggle()"/>
</div>
</div>
<div class="sm11 xl12 md12 xs12 my-1 py-1">
<va-slider
pins
:min="outputReadabilityData(range.min)"
:max="outputReadabilityData(range.max)"
value-visible
:step="10"
:color="toggle === true ? 'primary' : 'gray'"
:disabled="!toggle"
v-model="inputSlider"
/>
</div>
</div>
</template>
<script>
export default {
name: 'ChannelBlock',
components: {
},
computed: {
toggle: {
get () {
return Boolean(this.inputValue[this.toggleName])
},
set (val) {
this.channelToggle = val
},
},
inputStringText: {
get () {
return String(this.outputReadabilityData(this.inputValue[this.parameterName]))
},
set (val) {
this.inputString = val
},
},
inputSlider: {
get () {
return this.outputReadabilityData(this.inputValue[this.parameterName])
},
set (val) {
this.inputChange(val)
},
},
},
props: {
inputValue: {
type: Object,
},
channel: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
toggleName: {
type: String,
required: true,
},
range: {
type: Object,
},
defaultUnit: {
type: String,
},
unit: {
type: Object,
},
outputReadabilityData: {
type: Function,
default: (val) => val,
},
outputRawData: {
type: Function,
default: (val) => val,
},
},
created () {
},
data () {
return {
inputString: '',
channelToggle: false,
}
},
mqtt: {
},
methods: {
inputChange (val) {
// if change from input field
if (typeof (val) === 'string') {
if (isNaN(val) || val === '') {
return false
}
val = this.outputRawData(val)
if (parseFloat(val) < this.range.min) {
val = this.range.min
} else if (parseFloat(val) > this.range.max) {
val = this.range.max
}
} else if (typeof (val) === 'number') {
val = this.outputRawData(val)
}
this.$emit('parameterChange', this.parameterName, val, true)
},
switchToggle () {
this.$emit('parameterChange', this.toggleName, this.channelToggle)
},
},
}
</script>
<style lang="scss">
.small-va-input {
.va-input {
&__container {
min-height: 1rem;
}
&__container__input {
margin-bottom: 0.001rem;
padding: 0.8rem 0.5rem;
}
}
}
</style>
@@ -0,0 +1,216 @@
<template>
<div :class="disabled === true ? 'flex d-flex py-1 disabled-text' : 'flex d-flex py-1'" style="align-items: center;">
<div style="flex-basis: 25%;">
<span>{{ showName }}</span>
</div>
<div v-if="onlyButton === true && disabled === true" style="flex-basis: 50%; display: flex; align-items: center; justify-content: center;">
<img class="button-flat" src="@/assets/icons/button-disable.svg"/>
</div>
<div v-else-if="onlyButton === true && inputValue === false" style="flex-basis: 50%; display: flex; align-items: center; justify-content: center;" @click="inputChange(true)">
<img class="button-flat" src="@/assets/icons/button-off.svg"/>
</div>
<div v-else-if="onlyButton === true && inputValue === true" style="flex-basis: 50%; display: flex; align-items: center; justify-content: center;" @click="inputChange(false)">
<img class="button-flat" src="@/assets/icons/button-on.svg"/>
</div>
<div v-else style="flex-basis: 50%; align-items: center; text-align: -webkit-right;">
<va-input class="mr-2" style="margin-bottom: 0; width: 100px; color: green;"
@keyup.enter="inputChange(inputString)"
@blur="inputChange(inputString)"
v-model="inputStringModel"
:disabled="disabled">
<p v-if="withToggleButton === true" slot="append" style="margin-right: 0;" small>
{{ unitSelect }}
</p>
</va-input>
</div>
<div v-if="withToggleButton === false" style="flex-basis: 25%; align-items: center;">
{{ unitSelect }}
</div>
<div v-if="withToggleButton === true && disabled === true" style="flex-basis: 25%; align-items: center; display: inline-flex;">
<img class="button-dot" src="@/assets/icons/button-dot-off.svg">
</div>
<div v-else-if="withToggleButton === true && toggleValue === false" style="flex-basis: 25%; align-items: center; display: inline-flex;" @click="toggleChange(true)">
<img class="button-dot" src="@/assets/icons/button-dot-off.svg">
</div>
<div v-else-if="withToggleButton === true && toggleValue === true" style="flex-basis: 25%; align-items: center; display: inline-flex;" @click="toggleChange(false)">
<img class="button-dot" src="@/assets/icons/button-dot-on.svg">
</div>
</div>
</template>
<script>
export default {
name: 'InputFieldWithHeader',
components: {
},
props: {
templateType: {
type: Number,
default: 0,
},
onlyButton: {
type: Boolean,
default: false,
},
withHeader: {
type: Boolean,
default: false,
},
withUnitButton: {
type: Boolean,
default: false,
},
withToggleButton: {
type: Boolean,
default: false,
},
parameterName: {
type: String,
required: true,
},
showName: {
type: String,
},
range: {
type: Object,
},
inputValue: {
type: [Number, String, Boolean],
required: true,
},
referenceValue: {
type: Object,
},
defaultUnit: {
type: String,
},
unit: {
type: Object,
},
outputReadabilityData: {
type: Function,
default: (val) => val,
},
outputRawData: {
type: Function,
default: (val) => val,
},
disabled: {
type: Boolean,
default: false,
},
index: {
type: Number,
default: -1,
},
toggleParameter: {
type: String,
},
toggleValue: {
type: [Number, Boolean],
},
},
created () {
},
computed: {
inputStringModel: {
get () {
return String(this.outputReadabilityData(this.inputValue))
},
set (val) {
this.inputString = val
},
},
unitLength () {
return Object.keys(this.unit).length
},
},
data () {
return {
unitSelect: this.defaultUnit,
unitButtonClicked: '',
inputString: '',
size: {
12: 'flex sm12 xl12 md12 xs12 px-0 mx-0',
6: 'flex sm6 xl6 md6 xs6 px-0 mx-0',
5: 'flex sm5 xl5 md5 xs5 px-0 mx-0 my-0 py-0',
4: 'flex sm4 xl4 md4 xs4 px-0 mx-0 my-0 py-0',
3: 'flex sm3 xl3 md3 xs3 px-0 mx-0 my-0 py-0',
},
style: {
header: '',
content: '',
unitButton: '',
},
}
},
mqtt: {
},
methods: {
inputChange: function (val) {
/** */
let scale = 1
if (this.unitSelect) {
scale = this.unit[this.unitSelect]
}
// if change from input field
if (typeof (val) === 'string') {
if (isNaN(val) || val === '') {
return false
}
val = this.outputRawData(val, scale)
if (parseFloat(val) < this.range.min) {
val = this.range.min
} else if (parseFloat(val) > this.range.max) {
val = this.range.max
}
}
/** if parameter is array with index needs to return */
if (this.index === -1) {
this.$emit('parameterChange', this.parameterName, val)
} else {
this.$emit('parameterChangeByIndex', this.parameterName, val, this.index)
}
},
unitChange: function () {
this.unitButtonClicked += 1
this.unitSelect = Object.keys(this.unit)[this.unitButtonClicked % this.unitLength]
},
toggleChange: function (val) {
this.$emit('parameterChangeByIndex', this.toggleParameter, val, this.index)
},
},
async mounted () {
if (this.withHeader === true && this.withUnitButton === true) {
this.style.header = this.size[5]
this.style.content = this.size[4]
this.style.unitButton = this.size[3]
} else if (this.withHeader === true) {
this.style.header = this.size[6]
this.style.content = this.size[6]
} else {
this.style.content = this.size[12]
}
},
destroyed () {
},
watch: {
},
}
</script>
<style>
.button-dot {
height: 16px;
width: 16px;
}
.button-flat {
height: 20px;
width: 64px;
}
.disabled-text {
color: #c2c2c2;
}
</style>
@@ -0,0 +1,149 @@
<template>
<div class="flex sm12 xl12 md12 xs12 mb-2 pb-1 align--center">
<div class="row">
<div class="flex sm12 xl5 md5 xs12 my-1 py-0">
<p class="display-6 my-2"> Timer <p/>
</div>
<div class="flex sm12 xl3 md3 xs12 px-0 mx-0 my-2 py-0">
<va-input
class="mb-0 small-va-input"
v-model="inputStringText"
:disabled="!toggle"
@keyup.enter="inputChange(inputString)"
@blur="inputChange(inputString)"
>
<p slot="append" style="margin-right: 0;" small>
s
</p>
</va-input>
</div>
<div class="flex sm12 xl4 md4 xs12 px-0 mx-0 my-2 py-0">
<va-toggle class="mb-0" v-model="toggle" color="success" style="float: right;" flat small @click.native="switchToggle()"/>
</div>
</div>
<!-- <div class="sm11 xl12 md12 xs12 my-1 py-1">
<va-slider
pins
:min="outputReadabilityData(range.min)"
:max="outputReadabilityData(range.max)"
value-visible
:step="10"
:color="timerToggle === true ? 'primary' : 'gray'"
:disabled="!timerToggle"
v-model="inputSlider"
/>
</div> -->
</div>
</template>
<script>
export default {
name: 'TimerBlock',
components: {
},
computed: {
inputStringText: {
get () {
return String(this.outputReadabilityData(this.inputValue[this.parameterName]))
},
set (val) {
this.inputString = val
},
},
inputSlider: {
get () {
return this.outputReadabilityData(this.inputValue[this.parameterName])
},
set (val) {
this.inputChange(val)
},
},
toggle: {
get () {
return !(this.inputValue[this.parameterName] === 0)
},
set (val) {
this.timerToggle = val
},
},
},
props: {
inputValue: {
type: Object,
},
parameterName: {
type: String,
required: true,
},
range: {
type: Object,
},
defaultUnit: {
type: String,
},
unit: {
type: Object,
},
outputReadabilityData: {
type: Function,
default: (val) => val,
},
outputRawData: {
type: Function,
default: (val) => val,
},
},
created () {
},
data () {
return {
inputString: '',
timerToggle: false,
}
},
mqtt: {
},
methods: {
inputChange (val) {
// if change from input field
if (typeof (val) === 'string') {
if (isNaN(val) || val === '') {
return false
}
val = this.outputRawData(val)
if (parseFloat(val) < this.range.min) {
val = this.range.min
} else if (parseFloat(val) > this.range.max) {
val = this.range.max
}
} else if (typeof (val) === 'number') {
val = this.outputRawData(val)
}
this.$emit('parameterChange', this.parameterName, val, true)
},
switchToggle () {
if (this.timerToggle === true) {
this.$emit('parameterChange', this.parameterName, 1)
}
if (this.timerToggle === false) {
this.$emit('parameterChange', this.parameterName, 0)
}
},
},
}
</script>
<style lang="scss">
.small-va-input {
.va-input {
&__container {
min-height: 1rem;
}
&__container__input {
margin-bottom: 0.001rem;
padding: 0.8rem 0.5rem;
}
}
}
</style>
@@ -0,0 +1,108 @@
<template>
<div>
<div v-if="parameter.MODE === 0">
<div v-for="channel in channelList" :key="channel">
<ChannelBlock
:channel="channel"
:inputValue="parameter"
:parameterName="channelBlockCurrent(channel)"
:toggleName="channelBlockToggle(channel)"
v-bind="parameterTable[channelBlockCurrent(channel)]"
@parameterChange="parameterChange"
></ChannelBlock>
</div>
<div class="row px-0 mx-0">
<p class="my-2 mr-2 display-5"> ADVANCED SETTING </p>
<!-- <va-toggle class="mb-0" flat small color="success" v-model="openAdvanced"/> -->
</div>
<div>
<TimerBlock
:inputValue="parameter"
:parameterName="'TIME_DURATION'"
v-bind="parameterTable.TIME_DURATION"
@parameterChange="parameterChange"
></TimerBlock>
</div>
<div>
<div v-for="triggerIndex in triggerList" :key="'trigger_' + triggerIndex">
<TriggerBlock
:triggerIndex="triggerIndex"
:inputValue="parameter"
:parameterName="triggerBlockType(triggerIndex)"
:toggleName="triggerBlockEnable(triggerIndex)"
v-bind="parameterTable[triggerBlockType()]"
@parameterChange="parameterChange"
></TriggerBlock>
</div>
</div>
</div>
</div>
</template>
<script>
import ChannelBlock from './ChannelBlock.vue'
import TriggerBlock from './TriggerBlock.vue'
import TimerBlock from './TimerBlock.vue'
export default {
name: 'Trigger',
components: {
ChannelBlock,
TriggerBlock,
TimerBlock,
},
computed: {
},
props: {
parameter: {
type: Object,
default: () => {},
},
parameterTable: {
type: Object,
default: () => {},
},
},
data () {
return {
channelList: [0, 1, 2, 3],
triggerList: [0, 1],
openAdvanced: Boolean(this.parameter.TRIG0_en || this.parameter.TRIG1_en),
}
},
methods: {
channelBlockToggle (channelIndex) {
let name = 'ACC_a_out'
if (channelIndex !== undefined) {
name += channelIndex
}
return name
},
channelBlockCurrent (channelIndex) {
let name = 'ACC_a_out'
if (channelIndex !== undefined) {
name += channelIndex
}
name += '_current'
return name
},
triggerBlockEnable (triggerIndex) {
let name = 'TRIG'
if (triggerIndex !== undefined) {
name += triggerIndex
}
name += '_en'
return name
},
triggerBlockType (triggerIndex) {
let name = 'TRIG'
if (triggerIndex !== undefined) {
name += triggerIndex
}
name += '_edge_type'
return name
},
parameterChange: function (name, value, debounce) {
this.$emit('parameterChange', name, value, debounce)
},
},
}
</script>
@@ -0,0 +1,101 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 ma-0 pa-0">
<div class="d-flex sm12 xl12 md12 xs12 my-0 py-0">
<div class="flex sm8 xl8 md8 xs8 my-1 py-0">
<p class="display-6 my-2"> TRIGGER IN {{ triggerIndex + 1 }} <p/>
</div>
<div class="flex sm4 xl4 md4 xs4 ma-0 pa-0 my-2">
<va-toggle class="mb-0" v-model="toggle" color="success" style="float: right;" flat small @click.native="switchToggle()"/>
</div>
</div>
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<va-radio-button
v-for="(option, index) in optionTrigger"
:key="index"
style="float: left;"
v-model="selectTrigger"
:option="optionTrigger[index]"
:label="optionTrigger[index]"
:disabled="!toggle"
@click.native.stop="inputChange(index)"
/>
</div>
</div>
</template>
<script>
export default {
name: 'TriggerBlock',
components: {
},
props: {
triggerIndex: {
type: Number,
required: true,
},
inputValue: {
type: Object,
},
parameterName: {
type: String,
required: true,
},
toggleName: {
type: String,
required: true,
},
range: {
type: Object,
},
defaultUnit: {
type: String,
},
unit: {
type: Object,
},
outputReadabilityData: {
type: Function,
default: (val) => val,
},
outputRawData: {
type: Function,
default: (val) => val,
},
},
computed: {
toggle: {
get () {
return Boolean(this.inputValue[this.toggleName])
},
set (val) {
this.triggerToggle = val
},
},
},
created () {
},
data () {
return {
selectTrigger: 'RISING',
optionTrigger: [
'RISING',
'FALLING',
'BOTH',
],
triggerToggle: false,
}
},
methods: {
inputChange (val) {
this.$emit('parameterChange', this.parameterName, val)
},
switchToggle () {
this.$emit('parameterChange', this.toggleName, this.triggerToggle)
},
},
mounted () {
this.selectTrigger = this.optionTrigger[this.inputValue[this.parameterName]]
this.triggerToggle = Boolean(this.inputValue[this.toggleName])
},
}
</script>
@@ -0,0 +1,270 @@
<template>
<div>
<div v-for="channel of [0,1,2,3,4,5,6,7]" :key="channel">
<button class="accordion">
<div style="display: flex; justify-content: space-between; align-items: center;">
<div class="d-flex align--center">
<i v-if="panelSpread.includes(channel) === false" class="va-icon fa fa-angle-right mr-1" style="width: 15px;"></i>
<i v-if="panelSpread.includes(channel) === true" class="va-icon fa fa-angle-down mr-1" style="width: 15px;"></i>
<span>{{ channelName[channel] }}</span>
</div>
<div class="d-flex align--center">
<va-toggle class="mb-0" color="#2CE9A4" :value="parameter.USED[channel]" style="float: right;" flat small @click.native.stop="parameterChangeByIndex('USED', !parameter.USED[channel], channel)"/>
</div>
</div>
</button>
<div class="panel">
<InputFieldWithToggle
v-if="[2,3].indexOf(channel) >= 0"
style="margin-bottom: 0.5rem;"
:index="channel"
:parameterName="'OUTPUT_5V'"
:inputValue="parameter.OUTPUT_5V[channel]"
:onlyButton="true"
:disabled="channel === 2 ? true: !parameter.USED[channel]"
v-bind="parameterTable.OUTPUT_5V"
@parameterChange="parameterChange"
@parameterChangeByIndex="parameterChangeByIndex"
></InputFieldWithToggle>
<InputFieldWithToggle
v-if="[4,5,6,7].indexOf(channel) >= 0"
:index="channel"
:parameterName="'CURRENT'"
:inputValue="parameter.CURRENT[channel]"
:disabled="!parameter.USED[channel]"
v-bind="parameterTable.CURRENT"
@parameterChange="parameterChange"
@parameterChangeByIndex="parameterChangeByIndex"
></InputFieldWithToggle>
<!-- pre-T -->
<InputFieldWithToggle
:index="channel"
:parameterName="'T_EARLY'"
:inputValue="parameter.T_EARLY[channel]"
:withToggleButton="true"
:toggleParameter="'V_EARLY'"
:toggleValue="parameter.V_EARLY[channel]"
:disabled="!parameter.USED[channel]"
v-bind="parameterTable.T_EARLY"
@parameterChange="parameterChange"
@parameterChangeByIndex="parameterChangeByIndex"
></InputFieldWithToggle>
<InputFieldWithToggle
:index="channel"
:parameterName="'CYCLE'"
:inputValue="parameter.CYCLE[channel]"
:disabled="!parameter.USED[channel]"
v-bind="parameterTable.CYCLE"
@parameterChange="parameterChange"
@parameterChangeByIndex="parameterChangeByIndex"
></InputFieldWithToggle>
<InputFieldWithToggle
:index="channel"
:parameterName="'T_MID0'"
:inputValue="parameter.T_MID0[channel]"
:withToggleButton="true"
:toggleParameter="'V_MID0'"
:toggleValue="parameter.V_MID0[channel]"
:disabled="!parameter.USED[channel]"
v-bind="parameterTable.T_MID0"
@parameterChange="parameterChange"
@parameterChangeByIndex="parameterChangeByIndex"
></InputFieldWithToggle>
<InputFieldWithToggle
:index="channel"
:parameterName="'T_MID1'"
:inputValue="parameter.T_MID1[channel]"
:withToggleButton="true"
:toggleParameter="'V_MID1'"
:toggleValue="parameter.V_MID1[channel]"
:disabled="!parameter.USED[channel]"
v-bind="parameterTable.T_MID1"
@parameterChange="parameterChange"
@parameterChangeByIndex="parameterChangeByIndex"
></InputFieldWithToggle>
<InputFieldWithToggle
:index="channel"
:parameterName="'T_MID2'"
:inputValue="parameter.T_MID2[channel]"
:withToggleButton="true"
:toggleParameter="'V_MID2'"
:toggleValue="parameter.V_MID2[channel]"
:disabled="!parameter.USED[channel]"
v-bind="parameterTable.T_MID2"
@parameterChange="parameterChange"
@parameterChangeByIndex="parameterChangeByIndex"
></InputFieldWithToggle>
<InputFieldWithToggle
:index="channel"
:parameterName="'T_MID3'"
:inputValue="parameter.T_MID3[channel]"
:withToggleButton="true"
:toggleParameter="'V_MID3'"
:toggleValue="parameter.V_MID3[channel]"
:disabled="!parameter.USED[channel]"
v-bind="parameterTable.T_MID3"
@parameterChange="parameterChange"
@parameterChangeByIndex="parameterChangeByIndex"
></InputFieldWithToggle>
<InputFieldWithToggle
:index="channel"
:parameterName="'T_LATE'"
:inputValue="parameter.T_LATE[channel]"
:withToggleButton="true"
:toggleParameter="'V_LATE'"
:toggleValue="parameter.V_LATE[channel]"
:disabled="!parameter.USED[channel]"
v-bind="parameterTable.T_LATE"
@parameterChange="parameterChange"
@parameterChangeByIndex="parameterChangeByIndex"
></InputFieldWithToggle>
</div>
</div>
</div>
</template>
<script>
import InputFieldWithToggle from './InputFieldWithToggle.vue'
export default {
name: 'Trigger',
components: {
InputFieldWithToggle,
},
computed: {
},
props: {
parameter: {
type: Object,
default: () => {},
},
parameterTable: {
type: Object,
default: () => {},
},
},
data () {
return {
panelSpread: [],
channelName: [
'Gas valve 1',
'Gas valve 2',
'Gas valve 3',
'5V TTL',
'LED 1',
'LED 2',
'LED 3',
'LED 4',
],
channelList: [0, 1, 2, 3],
triggerList: [0, 1],
openAdvanced: Boolean(this.parameter.TRIG0_en || this.parameter.TRIG1_en),
}
},
methods: {
channelBlockToggle (channelIndex) {
let name = 'ACC_a_out'
if (channelIndex !== undefined) {
name += channelIndex
}
return name
},
channelBlockCurrent (channelIndex) {
let name = 'ACC_a_out'
if (channelIndex !== undefined) {
name += channelIndex
}
name += '_current'
return name
},
triggerBlockEnable (triggerIndex) {
let name = 'TRIG'
if (triggerIndex !== undefined) {
name += triggerIndex
}
name += '_en'
return name
},
triggerBlockType (triggerIndex) {
let name = 'TRIG'
if (triggerIndex !== undefined) {
name += triggerIndex
}
name += '_edge_type'
return name
},
parameterChange: function (name, value, debounce) {
this.$emit('parameterChange', name, value, debounce)
},
parameterChangeByIndex: function (name, value, index) {
if (name.indexOf('V_MID') >= 0) {
console.log('sadsaasdadadad')
if (name === 'V_MID0' || name === 'V_MID2') {
this.parameter.V_MID0.splice(index, 1, value)
this.parameter.V_MID2.splice(index, 1, value)
this.parameter.V_MID1.splice(index, 1, !value)
this.parameter.V_MID3.splice(index, 1, !value)
}
if (name === 'V_MID1' || name === 'V_MID3') {
this.parameter.V_MID1.splice(index, 1, value)
this.parameter.V_MID3.splice(index, 1, value)
this.parameter.V_MID0.splice(index, 1, !value)
this.parameter.V_MID2.splice(index, 1, !value)
}
this.$emit('parameterChange', 'V_MID0', this.parameter.V_MID0, false, true)
this.$emit('parameterChange', 'V_MID1', this.parameter.V_MID1, false, true)
this.$emit('parameterChange', 'V_MID2', this.parameter.V_MID2, false, true)
this.$emit('parameterChange', 'V_MID3', this.parameter.V_MID3, false, true)
}
const _value = [...this.parameter[name]]
_value[index] = value
this.$emit('parameterChange', name, _value)
},
test: function (index) {
console.log('index', index)
// this.triggerUsed.splice(index, 1, !this.triggerUsed[index])
},
},
mounted () {
const acc = document.getElementsByClassName('accordion')
const panelSpread = this.panelSpread
for (let i = 0; i < acc.length; i++) {
acc[i].addEventListener('click', function () {
this.classList.toggle('active')
var panel = this.nextElementSibling
if (panel.style.display === 'block') {
panel.style.display = 'none'
panelSpread.splice(panelSpread.indexOf(i), 1)
} else {
panel.style.display = 'block'
panelSpread.push(i)
}
})
}
},
}
</script>
<style>
.accordion {
background-color: white;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.panel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
}
.button-dot {
height: 16px;
width: 16px;
}
</style>
+12 -11
View File
@@ -75,7 +75,7 @@ function sgFilter (data, windowSize, k) {
// return list
}
function sgFilterGetDifferential (data, windowSize, polynomial) {
function sgFilterGetDifferential (data, windowSize, polynomial, sampleRate = 1) {
// self
const arr = []
const m = parseInt((windowSize - 1) / 2)
@@ -96,23 +96,24 @@ function sgFilterGetDifferential (data, windowSize, polynomial) {
// use index 1 row in matrix
const rowOneInB = row(B, 1)._data[0]
const start = []
const end = []
// const start = []
// const end = []
const list = []
// eslint-disable-next-line no-unused-vars
for (const _ of range(0, m)) {
start.push(data[0])
end.push(data[data.length - 1])
}
const _data = [...start, ...data, ...end]
// for (const _ of range(0, m)) {
// start.push(data[0])
// end.push(data[data.length - 1])
// }
// const _data = [...start, ...data, ...end]
// const _data = [...data]
// m ... data_length - m - 1
for (const i of range(m, _data.length - m)) {
for (const i of range(m, data.length - m)) {
const arra = []
// -m ... 0 ... m
for (const j of range(-m, m + 1)) {
arra.push(_data[i.value + j.value])
arra.push(data[i.value + j.value])
}
let sum = 0
@@ -120,7 +121,7 @@ function sgFilterGetDifferential (data, windowSize, polynomial) {
sum += (arra[index] * rowOneInB[index])
}
list.push(sum)
list.push(sum * sampleRate)
}
return list
}
+98
View File
@@ -0,0 +1,98 @@
export default {
name: 'Dev Mode',
parameter: ['ADC_VALUE_I'],
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
time: {
name: 'Time',
physicalQuantity: 's',
unit: {
us: 1,
ms: 1e3,
s: 1e6,
m: 60 * 1e6,
h: 60 * 60 * 1e6,
auto: 1,
},
defaultUnit: 'auto',
},
0: {
name: '0',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
1: {
name: '1',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
2: {
name: '2',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
3: {
name: '3',
physicalQuantity: '',
unit: {
default: 1,
},
defaultUnit: 'default',
},
},
charts: {
default: [
{
name: 'Dev Mode',
description: '',
subplot: [
{
x1: {
type: 'time',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
y1: {
type: 'value',
valScale: 'linear',
min: 'dataMin',
max: 'dataMax',
},
data: [
{
legend: 'dev',
x1: {
channel: 'time',
},
y1: {
channel: 1,
},
},
],
},
],
},
],
},
}
@@ -0,0 +1,14 @@
export default {
name: 'Electrial Stimulation',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
},
channels: {
},
charts: {
default: [
],
},
}
+98
View File
@@ -0,0 +1,98 @@
import EletricalStimulation from './EletricalStimulation'
import DevMode from './DevMode'
/**
* Number-type-parameter
* PARAMETER_TITLE :{
* @param type value-type
* @param showName name
* @param componentType component-type
* @param range component-range
* @param defaultValue default-value
* @param defaultUnit default-unit
* @param downloadUnit download-unit
* @param unit unit-table
* @param outputRawData function return raw data
* @param outputReadabilityData function return user data
* }
*/
/**
* Array-type-parameter
* PARAMETER_TITLE :{
* @param type value-type
* @param showName name
* @param componentType component-type
* @param options select-options
* @param range select-range
* @param defaultValue default-value
* @param outputRawData function return raw data
* @param outputReadabilityData function return user data
* }
*/
const CPG = {
ADC_VALUE_I: {
type: 'none',
showName: 'Instruction',
componentType: 'dev-mode',
},
PULSE_WIDTH: {
type: 'number',
showName: 'Pulse Width',
componentType: 'input',
range: [50, 1000],
grid: 10,
defaultValue: 0,
defaultUnit: 'us',
downloadUnit: 'us',
},
AMPLITUDE: {
type: 'number',
showName: 'Amplititude',
componentType: 'input',
range: [0.5, 50],
grid: 0.5,
defaultValue: 0,
defaultUnit: 'mA',
downloadUnit: 'mA',
},
FREQUENCY: {
type: 'number',
showName: 'Frequency',
componentType: 'input',
range: [1, 500],
grid: 10,
defaultValue: 1,
defaultUnit: 'Hz',
downloadUnit: 'Hz',
},
BurstMode: {
type: 'bool',
showName: 'Burst Mode',
},
MODE_OPTIONS: [
{
id: 0,
description: 'Eletrical Stimulation',
img_src: 'CPG_UI_infomation_figure',
highz: 1,
},
{
id: 1,
description: 'Dev Mode',
img_src: 'DevM-Wire',
},
],
MODE: {
0: EletricalStimulation,
1: DevMode,
},
}
export default CPG
+22
View File
@@ -0,0 +1,22 @@
export default {
name: 'Idle',
parameter: [], // 這個mode用到的參數
showParameter: [], // 有要秀給user看的參數
headerParameter: () => [], // export header的參數
valScales: {
linear: {
func: (val) => {
return val
},
},
log: {
func: (val) => {
return Math.log10(Math.abs(val))
},
},
},
channels: {
},
charts: {
},
}
+9 -4
View File
@@ -1,7 +1,8 @@
export default {
name: 'Cali ADC - test',
parameter: ['DAC_VOLT', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'ADC_DAC_CHANNEL_15'], // 這個mode用到的參數
showParameter: ['DAC_VOLT', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'ADC_DAC_CHANNEL_15'], // 有要秀給user看的參數
name: 'Cali Mode - test',
parameter: ['ADC_DAC_CHANNEL_15', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'DAC_LEVEL_V_OUT_15', 'DAC_VOLT_BUTTON'], // 這個mode用到的參數
showParameter: ['ADC_DAC_CHANNEL_15', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'DAC_LEVEL_V_OUT_15', 'DAC_VOLT_BUTTON'], // 有要秀給user看的參數
headerParameter: () => ['ADC_DAC_CHANNEL_15', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'DAC_LEVEL_V_OUT_15', 'DAC_VOLT_BUTTON'], // export header的參數
valScales: {
linear: {
func: (val) => {
@@ -17,6 +18,7 @@ export default {
channels: {
time: {
name: 'Time',
physicalQuantity: 's',
unit: {
us: 1,
ms: 1e3,
@@ -29,6 +31,7 @@ export default {
},
0: {
name: 'I_in',
physicalQuantity: 'A',
unit: {
nA: 1,
},
@@ -36,6 +39,7 @@ export default {
},
1: {
name: 'V_in/V_out',
physicalQuantity: 'V',
unit: {
uV: 1,
},
@@ -43,6 +47,7 @@ export default {
},
2: {
name: 'Gain',
physicalQuantity: '',
unit: {
default: 1,
},
@@ -52,7 +57,7 @@ export default {
charts: {
default: [
{
name: 'Cali ADC - test',
name: 'Cali Mode - test',
description: '',
subplot: [
{
@@ -17,6 +17,7 @@ export default {
channels: {
time: {
name: 'Time',
physicalQuantity: 's',
unit: {
us: 1,
ms: 1e3,
@@ -29,6 +30,7 @@ export default {
},
0: {
name: 'I_in',
physicalQuantity: 'A',
unit: {
nA: 1,
},
@@ -36,6 +38,7 @@ export default {
},
1: {
name: 'V_in/V_out',
physicalQuantity: 'V',
unit: {
uV: 1,
},
@@ -1,8 +1,8 @@
export default {
name: 'Chronoamperometry',
parameter: ['VOLT_VSCAN', 'SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 這個mode用到的參數
showParameter: ['ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'VOLT_VSCAN', 'SAMPLE_RATE', 'TIME_DURATION'], // 有要秀給user看的參數
headerParameter: () => ['VOLT_VSCAN', 'SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'TIME_DURATION'], // 有要秀給user看的參數
parameter: ['CA_VOLT', 'SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'TIME_DURATION'], // 這個mode用到的參數
showParameter: ['ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'CTRL_HIGH_Z_15', 'CA_VOLT', 'SAMPLE_RATE', 'TIME_DURATION'], // 有要秀給user看的參數
headerParameter: () => ['CA_VOLT', 'SAMPLE_RATE', 'ADC_LEVEL_I_15', 'ADC_LEVEL_V_IN_15', 'TIME_DURATION'], // 有要秀給user看的參數
valScales: {
linear: {
func: (val) => {
@@ -18,6 +18,7 @@ export default {
channels: {
time: {
name: 'Time',
physicalQuantity: 's',
unit: {
us: 1,
ms: 1e3,
@@ -30,6 +31,7 @@ export default {
},
0: {
name: 'I_in',
physicalQuantity: 'A',
unit: {
nA: 1,
uA: 1e3,
@@ -40,6 +42,7 @@ export default {
},
1: {
name: 'Potential',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
@@ -50,6 +53,7 @@ export default {
},
2: {
name: 'V_out',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
@@ -18,6 +18,7 @@ export default {
channels: {
time: {
name: 'Time',
physicalQuantity: 's',
unit: {
us: 1,
ms: 1e3,
@@ -30,6 +31,7 @@ export default {
},
0: {
name: 'I_in',
physicalQuantity: 'A',
unit: {
nA: 1,
uA: 1e3,
@@ -40,6 +42,7 @@ export default {
},
1: {
name: 'Potential',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
@@ -50,6 +53,7 @@ export default {
},
2: {
name: 'V_out',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
@@ -58,6 +62,50 @@ export default {
defaultUnit: 'mV',
downloadUnit: 'mV',
},
3: {
name: 'sum_cnt',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'uV',
},
4: {
name: 'sum_adc_delta_Iin',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'uV',
},
5: {
name: 'sum_adc_delta_Voutin',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'uV',
},
6: {
name: 'resis',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
V: 1e6,
},
defaultUnit: 'mV',
downloadUnit: 'uV',
},
},
charts: {
default: [
@@ -18,6 +18,7 @@ export default {
channels: {
time: {
name: 'Time',
physicalQuantity: 's',
unit: {
us: 1,
ms: 1e3,
@@ -30,6 +31,7 @@ export default {
},
0: {
name: 'I_in',
physicalQuantity: 'A',
unit: {
nA: 1,
uA: 1e3,
@@ -40,6 +42,7 @@ export default {
},
1: {
name: 'V_in',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
@@ -50,6 +53,7 @@ export default {
},
2: {
name: 'V_out',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
@@ -18,6 +18,7 @@ export default {
channels: {
time: {
name: 'Time',
physicalQuantity: 's',
unit: {
us: 1,
ms: 1e3,
@@ -30,6 +31,7 @@ export default {
},
0: {
name: 'I_in',
physicalQuantity: 'A',
unit: {
nA: 1,
uA: 1e3,
@@ -40,6 +42,7 @@ export default {
},
1: {
name: 'V_out',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
@@ -50,6 +53,7 @@ export default {
},
2: {
name: 'V_in',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
@@ -60,6 +64,7 @@ export default {
},
3: {
name: 'Cycle number',
physicalQuantity: '',
unit: {
cycle: 1,
},
@@ -18,6 +18,7 @@ export default {
channels: {
time: {
name: 'Time',
physicalQuantity: 's',
unit: {
us: 1,
ms: 1e3,
@@ -30,6 +31,7 @@ export default {
},
0: {
name: 'I_in',
physicalQuantity: 'A',
unit: {
nA: 1,
uA: 1e3,
@@ -40,6 +42,7 @@ export default {
},
1: {
name: 'Potential',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
@@ -50,6 +53,7 @@ export default {
},
2: {
name: 'V_out',
physicalQuantity: 'V',
unit: {
uV: 1,
mV: 1e3,
@@ -60,6 +64,7 @@ export default {
},
3: {
name: 'Cycle number',
physicalQuantity: '',
unit: {
cycle: 1,
},

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