Compare commits

...

147 Commits

Author SHA1 Message Date
peterlu14 db0111d1db [update] amplitude rebuild & fix STI_T4 2021-09-01 10:57:35 +08:00
peterlu14 21cb382a1f [update] replace ADC_CLOCK to SAMPLE_RATE & 3.5 RECORDING_CH 2021-09-01 10:55:58 +08:00
peterlu14 1d8ef94ec6 Merge remote-tracking branch 'origin/feature/spike_UI' into release/0824_test 2021-08-27 19:08:52 +08:00
peterlu14 e49b6fb791 [update] export fix & subplot message & download 2021-08-27 19:07:57 +08:00
peterlu14 52e3d70dc8 [update] neulive ui switch & STI cycle amplitude T1-T4 fix 2021-08-26 16:59:39 +08:00
Roy a33bbd0581 fix current input value 2021-08-26 11:58:43 +08:00
Roy cd97260230 fix volt input value 2021-08-26 11:38:38 +08:00
Roy b9242764ab Merge branch 'e_0824_func_gen_bug' into release/0824_test 2021-08-26 10:46:36 +08:00
Jordan Hsu e8d75b9877 [init] spike ui 2021-08-26 02:03:30 +08:00
TommyXin 433e567e74 neulive 3.5 UI 2021-08-25 20:44:28 +08:00
TommyXin fbbebb3423 fix grid uV 2021-08-25 16:33:40 +08:00
Roy 6f2aab5276 OCP mode add current range button 2021-08-25 16:12:44 +08:00
TommyXin d82b1cb735 grid support input 'auto' 2021-08-25 01:17:07 +08:00
Roy 8aa87d587f update elite1.5 button 2021-08-24 17:40:32 +08:00
TommyXin 38503e198e EIS volt range 2021-08-24 04:35:02 +08:00
Jordan Hsu 8b78cdcdbd Merge remote-tracking branch 'origin/release/0812_test' into feature/spike_UI 2021-08-20 16:08:37 +08:00
peterlu14 94feff568a Merge remote-tracking branch 'origin/release/0812_test' into release/0812_test 2021-08-20 15:49:07 +08:00
peterlu14 06336bbd61 [update] add api spikeDetect 2021-08-20 15:48:18 +08:00
TommyXin 33b041a31b Merge remote-tracking branch 'origin/release/0812_test' into release/0812_test 2021-08-19 10:40:27 +08:00
TommyXin 14dda58fac neulive uV 2021-08-19 10:40:12 +08:00
Jordan Hsu f9bf41980b [modify] neulive replay function name 2021-08-18 14:55:45 +08:00
Jordan Hsu 6b20902c74 [fix] neulive stimulation phasic bug 2021-08-18 14:16:45 +08:00
peterlu14 ced0362910 Merge remote-tracking branch 'origin/release/0812_test' into release/0812_test 2021-08-17 16:59:13 +08:00
peterlu14 467016140f [update] real-time axis setting & edf format 2021-08-17 16:58:40 +08:00
Jordan Hsu f6e642cd5f Merge remote-tracking branch 'origin/release/0812_test' into release/0812_test 2021-08-13 16:00:48 +08:00
Jordan Hsu 7c5aed4dbc [fix] sti t range check bug 2021-08-13 15:54:55 +08:00
peterlu14 c069354415 [fix] EIS download 2021-08-13 13:14:10 +08:00
Jordan Hsu 738b58fded [modify] speed up neulive replay 2021-08-12 18:59:19 +08:00
Jordan Hsu f7c89585ac [modify] elite chart sampling method to lttb algo. and fix overview scale bug 2021-08-12 18:06:34 +08:00
peterlu14 36ed59816d Merge branch '0809_release_version' into release/0812_test 2021-08-12 17:01:34 +08:00
Jordan Hsu 516d20333c Merge remote-tracking branch 'origin/0809_release_version' into 0809_release_version 2021-08-12 17:00:56 +08:00
Jordan Hsu 74b8472c1d [modify] replay resampling method 2021-08-12 17:00:34 +08:00
peterlu14 ecb9e02610 [update] about to setting 2021-08-12 16:54:44 +08:00
peterlu14 74dea74476 Merge remote-tracking branch 'origin/0809_release_version' into release/0812_test 2021-08-12 14:40:47 +08:00
TommyXin 588a791bc1 Merge remote-tracking branch 'origin/0809_release_version' into 0809_release_version 2021-08-12 14:20:48 +08:00
TommyXin cd3e6f08f5 time 500ms&neulive uV&device panel height 2021-08-12 14:20:06 +08:00
peterlu14 1370e5659e [update] axis data divide 100 2021-08-12 13:42:48 +08:00
peterlu14 e18fa916b5 Merge branch 'download_rebuild' into 0809_release_version 2021-08-12 13:11:04 +08:00
peterlu14 b5a920338a [update] remove old download routes 2021-08-12 13:10:19 +08:00
peterlu14 6c4660966c [update] adjust tooltip formatter 2021-08-12 12:57:27 +08:00
peterlu14 0db13d3404 [update] remove old download pages 2021-08-12 12:55:45 +08:00
TommyXin 8b96a7308c fix stop button 2021-08-12 11:06:05 +08:00
peterlu14 d7e69e250e Merge remote-tracking branch 'origin/0809_release_version' into download_rebuild 2021-08-12 10:30:25 +08:00
TommyXin 14217aa1ea fix EIS freq max 2021-08-12 09:50:50 +08:00
peterlu14 506080c518 [update] replay download url fix 2021-08-12 04:23:53 +08:00
peterlu14 794b71cc9f [update] rebuild download structure 2021-08-12 04:16:40 +08:00
Jordan Hsu 7e355448e0 [fix] replay change scale bug 2021-08-10 19:53:37 +08:00
TommyXin 1bcf0d99e9 Merge remote-tracking branch 'origin/0809_release_version' into 0809_release_version 2021-08-10 19:28:48 +08:00
TommyXin af094ad93a fix subplot deviceOpions lose time 2021-08-10 19:28:37 +08:00
Jordan Hsu 062023bd95 [add] replay overview sampling function 2021-08-10 18:43:20 +08:00
Jordan Hsu fcef23b199 [fix] delete bug 2021-08-10 17:59:31 +08:00
Jordan Hsu 56051c881a [fix] replay layout bug 2021-08-10 17:29:19 +08:00
TommyXin 9bc027b445 fix subplot multi device selection 2021-08-10 16:27:57 +08:00
TommyXin 06528addc7 remove some style 2021-08-10 16:17:24 +08:00
peterlu14 279a1056f4 Merge branch '0809_release_version' into feature/edf_format 2021-08-10 13:31:09 +08:00
peterlu14 0ef305c434 Merge remote-tracking branch 'origin/file_page_rebuild' into 0809_release_version 2021-08-10 00:21:45 +08:00
TommyXin 2161b37932 subplot add error mes 2021-08-09 23:20:24 +08:00
TommyXin 6b63b2b406 multi-device register 2021-08-09 21:09:36 +08:00
TommyXin ccdc193067 fix mlit-page start plot error 2021-08-09 17:47:02 +08:00
TommyXin 2ba4644a78 [api] collection add /file 2021-08-09 13:28:58 +08:00
Jordan Hsu 72dbb2abf5 [fix] both replay download bug by adding sleep function 2021-08-06 11:06:48 +08:00
Jordan Hsu 7f498c01ed [modify] pulse sensing cycle is unified to CYCLE_NUMBER and wait for elite 2021-08-06 10:46:50 +08:00
Jordan Hsu d9f7813a3c [fix] download bug by adding sleep function 2021-08-06 10:18:19 +08:00
peterlu14 35c436ee67 [update] data timestamp align 2021-08-05 18:21:39 +08:00
Jordan Hsu 2f82138097 [remove] redundant code 2021-08-05 15:16:53 +08:00
Jordan Hsu e4d2186d86 [fix] replay change cycle bug 2021-08-05 15:07:03 +08:00
Jordan Hsu 749fd86c65 Merge branch 'feature/DPV_UI' into 0726_test_version 2021-08-05 14:35:04 +08:00
Jordan Hsu 95bb4afa49 [fix] replay cycle bug 2021-08-05 13:51:06 +08:00
Jordan Hsu 6c5c832fde [add] neulive sti T range check point 2021-08-05 12:25:52 +08:00
Jordan Hsu 256070ae76 [fix] typo 2021-08-04 18:44:07 +08:00
TommyXin 7edde3d7b2 vuex download 2021-08-04 18:25:08 +08:00
TommyXin 8ba6bcb8cb [api] get meta by limit&offset 2021-08-04 17:17:32 +08:00
Jordan Hsu 1398ffad4c [modify] EIS VoltRange component path 2021-08-04 16:55:13 +08:00
Jordan Hsu e82d17ab4f [add] pulse sensing mode segment hover effect, [remove] replay exp display 2021-08-04 16:43:53 +08:00
TommyXin d116c9951a CV formula 2021-08-02 17:04:53 +08:00
TommyXin d3e02ee4db ppd NaN error 2021-08-02 16:39:51 +08:00
TommyXin 2f9cd9fae0 Merge branch 'debug_0722' into 0726_test_version 2021-08-02 15:49:02 +08:00
TommyXin cfca599408 [EIS] add CV mode & formula changing 2021-08-02 15:46:23 +08:00
Jordan Hsu fecbd4e4da [modify] neulive sti time range rule 2021-07-31 22:22:09 +08:00
peterlu14 08fcba3f58 [update] axis value divide 100 2021-07-28 16:03:13 +08:00
Jordan Hsu e4da226a03 [init] DPV UI 2021-07-27 21:08:33 +08:00
peterlu14 b68471eff6 [update] elite download update 2021-07-27 17:32:27 +08:00
peterlu14 5cf83f18c4 [update] download file split raw and acc data 2021-07-27 12:23:01 +08:00
peterlu14 11f4793a7a Merge remote-tracking branch 'origin/feature/replay' into 0726_test_version 2021-07-26 15:51:47 +08:00
peterlu14 7d615e0e53 Merge remote-tracking branch 'origin/debug_0722' into 0726_test_version 2021-07-26 10:29:04 +08:00
peterlu14 589727142c Merge remote-tracking branch 'origin/feature/pulse_sensing_UI' into 0726_test_version 2021-07-26 10:26:30 +08:00
peterlu14 230fb4f8a4 [update] fix delete data & delete multi data 2021-07-26 10:24:00 +08:00
peterlu14 058057dca4 [update] add mem_rf_set 2021-07-26 04:41:06 +08:00
Jordan Hsu 9a13720f04 [fix] typo 2021-07-23 16:35:58 +08:00
Jordan Hsu d7fd0426bd [add] segment_ui_order param 2021-07-23 13:31:12 +08:00
Jordan Hsu 5addbef71c adjust UI 2021-07-23 11:08:33 +08:00
Jordan Hsu 9f988edd63 [modify] segment order param for roy 2021-07-22 23:55:08 +08:00
TommyXin e5ff49333d clear task info while leave page 2021-07-22 22:38:38 +08:00
TommyXin 2b70a54a07 dev tool for EIS&clear task info 2021-07-22 22:38:03 +08:00
TommyXin 9b64a5484e add subplot 2021-07-22 21:54:11 +08:00
TommyXin e6dcb0d389 new chart grid unit 2021-07-22 21:34:54 +08:00
TommyXin 8a2f001f28 fix add chart repeat 2021-07-22 21:20:17 +08:00
TommyXin 4fa122c754 fix page height error 2021-07-22 21:05:58 +08:00
TommyXin 1ebfa0b343 elite grid 2021-07-22 20:49:07 +08:00
Jordan Hsu 076f8111eb change meaning of segment_order 2021-07-22 17:48:49 +08:00
Jordan Hsu dd895bb177 [fix] if delete segment, reset t_pulse to 0 2021-07-22 16:40:57 +08:00
Jordan Hsu e3b9a00071 [modify] pulse sensing mode UI for roy testing 2021-07-22 16:13:01 +08:00
Jordan Hsu 8697e94aa7 [add] ui for pulse sensing mode 2021-07-21 22:57:48 +08:00
TommyXin e786ce437d rec_ref 2021-07-19 16:03:54 +08:00
TommyXin 8b841a8524 Merge remote-tracking branch 'origin/EIS_UI_rough' into EIS_UI_rough 2021-07-19 13:11:20 +08:00
TommyXin fabeca30b6 [fix] send "delay" parameter error 2021-07-19 13:10:32 +08:00
Roy 23a430d7e4 Merge commit '5a8147476c4e7dbf5a9c0419c3aeab2bba381f1a' into EIS_UI_rough 2021-07-16 14:34:57 +08:00
TommyXin 979918b31b change parameter formula 2021-07-14 17:21:12 +08:00
Jordan Hsu cee179b1f7 [modify] default showed unit 2021-07-14 16:49:21 +08:00
Jordan Hsu 758aac1909 [modify] both replay will re-download data, elite default only download first cycle
To be tested: elite if scale = 100 or 1000, will close chart averaging
2021-07-14 16:38:37 +08:00
TommyXin f7a487d316 EIS UI done 2021-07-14 12:48:08 +08:00
peterlu14 cf648fe862 Merge branch '0701_test_version' 2021-07-12 07:23:13 +08:00
peterlu14 d3610b3430 [fix] elite download 2021-07-12 07:22:16 +08:00
Roy 5a8147476c update elite1.5 UI 2021-07-09 16:23:25 +08:00
Roy 9ced5cfcc8 It Rt new Vout out UI 2021-07-08 11:44:11 +08:00
peterlu14 b1dd6d1750 Merge branch 'feature/download' into 0701_test_version 2021-07-05 19:47:03 +08:00
peterlu14 b27fb72401 [update] download feature 2021-07-05 19:44:50 +08:00
TommyXin 2fc79e9e27 init uint 2021-07-01 23:15:13 +08:00
TommyXin ac520b5451 add interval unit 2021-07-01 23:10:49 +08:00
TommyXin 6022d01c51 Merge branch 'opt_ui_1' into 0701_test_version 2021-07-01 21:53:43 +08:00
TommyXin 38395fb579 Merge remote-tracking branch 'origin/master_ocp' into 0701_test_version 2021-07-01 21:52:42 +08:00
TommyXin 2138e1eafc Merge remote-tracking branch 'origin/feature/replay' into 0701_test_version 2021-07-01 21:52:12 +08:00
TommyXin 120553f8c0 replay double markArea 2021-07-01 21:25:06 +08:00
Jordan Hsu 054a8a6382 [modify] no matter how both replay will re-download data 2021-07-01 21:02:59 +08:00
TommyXin e50f2b5efc realtime elite unit 2021-07-01 20:07:34 +08:00
TommyXin c780fd7a57 realtime unit 2021-07-01 19:59:43 +08:00
TommyXin bd298b73bc interval & task config stimulate 2021-07-01 19:40:43 +08:00
TommyXin c3e2f7f6e5 task config 2021-07-01 13:54:26 +08:00
peterlu14 311f89df15 Merge remote-tracking branch 'origin/master_ocp' 2021-06-30 17:36:37 +08:00
Roy b2465c70bc modify mode defulat chart 2021-06-28 18:29:20 +08:00
Jordan Hsu 9ec3ee46e6 fix fool-proof bug for elite 2021-06-28 17:19:34 +08:00
Jordan Hsu 1a5bd6da85 Merge remote-tracking branch 'origin/master_ocp' into feature/replay 2021-06-28 16:53:36 +08:00
Jordan Hsu 0915c28917 Merge branch 'master' into feature/replay 2021-06-28 16:22:34 +08:00
TommyXin c8c1abc2a5 [update] api opt 2021-06-27 23:42:17 +08:00
Jordan Hsu 37e07ec0ed [modify] both replay don't download existing data 2021-06-25 11:32:06 +08:00
Jordan Hsu 86440bfaba [fix] elite replay bug 2021-06-24 21:13:30 +08:00
Roy 4855ca30d9 OCP UI 2021-06-24 15:09:24 +08:00
Jordan Hsu dc4ae8fb1f [add] fool-proof for task content neulive param setting 2021-06-24 13:13:04 +08:00
Jordan Hsu 9a7d00645d [modify] elite replay append download data in dataInfo 2021-06-24 13:08:07 +08:00
Jordan Hsu ef77084297 clean redundant code 2021-06-23 11:27:18 +08:00
Jordan Hsu 5ee2d796cb [modify] echart sampling method and change neulive 3-axis legend name 2021-06-22 22:22:08 +08:00
Jordan Hsu 6689d64b0d [fix] neulive replay distribute bug 2021-06-19 21:55:41 +08:00
Jordan Hsu fe5f52472b [fix] neulive replay 3 axis bug, change scale bug 2021-06-19 20:53:28 +08:00
TommyXin dd5a8bfe27 Merge remote-tracking branch 'origin/master' into opt_ui_1 2021-06-19 11:50:39 +08:00
peterlu14 ac889e5410 Merge remote-tracking branch 'origin/feature/replay' 2021-06-16 02:24:31 +08:00
Jordan Hsu 9584d751fe [update] replay change log scale logic 2021-06-11 22:43:17 +08:00
Jordan Hsu fd31d41bdb [fix] elite cycle bug 2021-06-11 13:09:29 +08:00
241 changed files with 23621 additions and 17716 deletions
+5
View File
@@ -17206,6 +17206,11 @@
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.3.4.tgz",
"integrity": "sha512-SdKRBeoXUjaZ9R/8AyxsdTqkOfMcI5tWxPZOUX5Ie1BTL5rPSZ0O++pbiZCeYeythiZIdLEfkDiQPKIaWk5hDg=="
},
"vue-slicksort": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/vue-slicksort/-/vue-slicksort-1.2.0.tgz",
"integrity": "sha512-k1324l+AnYy6MrpySN7PYL165z2EkvZmMe+BS7H/EugzS8IrZYRtoqa3QxSSWB34C7cplV1hj3c+7peKpxpYxg=="
},
"vue-style-loader": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",
+1
View File
@@ -53,6 +53,7 @@
"vue-gtm": "^2.2.0",
"vue-mqtt": "^2.0.3",
"vue-router": "^3.1.3",
"vue-slicksort": "^1.2.0",
"vue-worker": "^1.2.1",
"vue-yandex-maps": "^0.9.0",
"vuedraggable": "^2.24.3",
+6 -2
View File
@@ -18,6 +18,9 @@ import 'echarts/lib/chart/line'
import 'echarts/lib/component/dataZoom'
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/legend/ScrollableLegendModel.js'
import 'echarts/lib/component/legend/ScrollableLegendView.js'
import 'echarts/lib/component/legend/scrollableLegendAction.js'
import 'echarts/lib/component/axisPointer'
import 'echarts/lib/component/grid'
import 'echarts/lib/component/markArea'
@@ -49,9 +52,10 @@ Vue.component('chart', ECharts)
Vue.use(VueWorker)
Vue.use(VueAxios, axios)
Vue.use(VueMqtt, 'ws://52.194.17.114:8083')
// Vue.use(VueMqtt, 'ws://52.194.17.114:8083')
// Vue.use(VueMqtt, 'ws://' + location.href.split('/')[2] + ':8083')
// Vue.use(VueMqtt, 'ws://' + '192.168.0.120' + ':8083')
// Vue.use(VueMqtt, 'ws://' + '192.168.151.125' + ':8083')
Vue.use(VueMqtt, 'ws://' + '192.168.151.125' + ':8083')
Vue.prototype.GLOBAL = global_
+4 -4
View File
@@ -60,7 +60,7 @@ export default {
data () {
return {
isTopBar: false,
minimized: false,
minimized: true,
mobileWidth: 767,
}
},
@@ -136,7 +136,7 @@ export default {
</style>
<style lang='scss'>
.layout.gutter--xl {
padding: 0.75rem;
}
// .layout.gutter--xl {
// padding: 0.5rem;
// }
</style>
+1 -1
View File
@@ -29,7 +29,7 @@ export default {
},
updateSidebarState () {
if (this.checkIsDesktop()) {
this.$emit('update:minimized', false)
this.$emit('update:minimized', true)
} else {
this.$emit('update:minimized', true)
}
@@ -1,7 +1,7 @@
<template>
<div>
<div class="row row-equal">
<div class="flex md12 xl3 xs12 sm12 area-style">
<div class="flex md12 xl3 xs12 sm12">
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-accordion>
@@ -18,11 +18,11 @@
</div>
</div>
<div :class="chartAreaClass" class="area-style">
<div :class="chartAreaClass">
<div class="row" >
<div class="flex sm12 xl12 md12 xs12">
<elite-replay-overview-chart v-show="showOverviewChart" :ref="'chart_overview'" class="mb-1" :cardheight="'7vh'" :data="chartOverviewData" @dataZoomEvent="dataZoomEvent($event)"/>
<elite-replay-chart :ref="'chart_detail'" @dblclick.native="distribute()" :cardheight="'88vh'" :data="chartDetailData" />
<elite-replay-chart :ref="'chart_detail'" @dblclick.native="distribute()" :cardheight="'88vh'" :chartheight="detailchartheight" :data="chartDetailData" />
<change-channel-value-min-max :ref="'set_min_max'"/>
</div>
</div>
@@ -41,7 +41,6 @@ import api from '@/data/api/index'
import { download } from '@/data/download/Download'
import types from '@/store/modules/analysis/replay/types'
import { mapFields } from 'vuex-map-fields'
import { newChartMode } from '@/factories/chart/chartFactory'
export default {
name: 'elite-data-replay',
@@ -60,6 +59,9 @@ export default {
'currentScale',
'axisXDataType',
'axisYDataType',
'startTimeCurrent',
'endTimeCurrent',
'sampleMethod',
]),
},
props: {
@@ -85,10 +87,9 @@ export default {
data () {
return {
showOverviewChart: false,
detailchartheight: '88vh',
dataInfo: {},
maxTime: 0,
startTimeCurrent: 0,
endTimeCurrent: 0,
startTime: 0,
endTime: 0,
zoomTime: 0,
@@ -155,7 +156,7 @@ export default {
})
let _gridNumber = 0
const register = this.metaList.map(meta => {
const setting = newChartMode(meta.parameter_set.MODE)
const setting = this.GLOBAL.getDefaultChartTypeByMode(meta.parameter_set.MODE)
const xType = setting[0] // Elite or Time
const yType = setting[2] // Elite or Time
const xValue = setting[1] // 1: I, 2: V, 3: R
@@ -243,19 +244,23 @@ export default {
metaInfo = _meta
}
})
const sampleRate = (80000 / metaInfo.parameter_set.ADC_CLOCK)
let scale = (((metaInfo.time_duration / 100000) * sampleRate) / 4000)
if (scale > 500) {
scale = '1000'
} else if (scale > 200) {
scale = '100'
} else if (scale > 30) {
scale = '10'
let scale = '100'
if (this.axisXDataType.description === 'Time') {
const sampleRate = metaInfo.parameter_set.SAMPLE_RATE / 10
const dataPointNum = (parseInt(metaInfo.time_duration) / 1e6) * sampleRate // us -> s: /1e6
if (dataPointNum > 2e6) { // 2000 (points) * 1000 (resample) = 2e6
scale = '1000'
} else if (dataPointNum > 2e5) { // 2000 (points) * 100 (resample) = 2e5
scale = '100'
} else if (dataPointNum > 2e4) { // 2000 (points) * 10 (resample) = 2e4
scale = '10'
} else {
scale = '1'
}
} else {
scale = '1'
scale = '1' // [TODO] select by user
}
console.log('overview scale:', scale)
const sampleMethod = 'mean'
// download data
const getAllData = async function (_this) {
for (const ch in _this.dataInfo[meta]) {
@@ -267,7 +272,7 @@ export default {
metaID: meta,
channel: ch,
scale: scale,
data: await _this.getData(parseInt(scale), sampleMethod, dataList[i].id, ch, metaInfo),
data: await _this.getData(parseInt(scale), _this.sampleMethod, dataList[i].id, ch, metaInfo),
})
}
}
@@ -297,19 +302,31 @@ export default {
metaInfo = _meta
}
})
const sampleRate = (80000 / metaInfo.parameter_set.ADC_CLOCK)
let scale = (((timeDur / 100000) * sampleRate) / 4000)
if (scale > 500) {
scale = '1000'
} else if (scale > 200) {
scale = '100'
} else if (scale > 30) {
scale = '10'
let scale = '100'
if (this.axisXDataType.description === 'Time') {
const sampleRate = metaInfo.parameter_set.SAMPLE_RATE / 10
const dataPointNum = (parseInt(timeDur) / 1e6) * sampleRate // us -> s: /1e6
if (dataPointNum > 2e6) { // 2000 (points) * 1000 (resample) = 2e6
scale = '1000'
} else if (dataPointNum > 2e5) { // 2000 (points) * 100 (resample) = 2e5
scale = '100'
} else if (dataPointNum > 2e4) { // 2000 (points) * 10 (resample) = 2e4
scale = '10'
} else {
scale = '1'
}
} else {
scale = '1'
scale = '1' // [TODO] select by user
}
// elite的sample rate不像neulive這麼高,因此試試scale = 100 or 1000時不要再sampling一次了,不然有些形狀(e.g. peak)會不一樣
if (scale === '100' || scale === '1000') {
this.updateChartSamplingChart({ chartID: this.chartDetailData.chartID, seriesIndex: _gridNumber, method: null })
} else {
this.updateChartSamplingChart({ chartID: this.chartDetailData.chartID, seriesIndex: _gridNumber, method: 'lttb' })
}
this.currentScale = scale
const sampleMethod = 'mean'
this.chartDetailData.series[_gridNumber].data.length = 0
let dataListX
const channelX = parseInt(this.axisXDataType.id)
@@ -318,27 +335,51 @@ export default {
}
const channelY = parseInt(this.axisYDataType.id)
const dataListY = this.dataInfo[meta][channelY][scale]
const isThisModeHasCycle = this.GLOBAL.hasCycleMode(metaInfo.parameter_set.MODE)
let startTime
let endTime
if (isThisModeHasCycle === true && this.axisXDataType.description !== 'Time') { // if有cycle的mode且目前x軸不為時間,抓出第一圈所在的時間段,初始化時先畫第一圈就好,加快初始時間
const cycleDataID = 3 // recorded cycle 所在的channel index
const dataCycleList = this.dataInfo[meta][cycleDataID][this.currentScale]
const cycleDataList = []
for (let i = 0; i < dataCycleList.length; i++) {
if (dataCycleList[i].data.length === 0) {
const data = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataCycleList[i].id, cycleDataID, metaInfo)
cycleDataList.push({ data: data })
} else {
cycleDataList.push({ data: dataCycleList[i].data })
}
}
const cycleDict = this.getCycleDictRec()(cycleDataList)
startTime = cycleDict[1][0] // [1]: 第一圈
endTime = cycleDict[1][1] // [1]: 第一圈
} else {
startTime = this.startTimeCurrent
endTime = this.endTimeCurrent
}
let startIndex = 0
let endIndex = 0
// get the subfile index
for (let i = 0; i < dataListY.length; i++) {
if (this.startTimeCurrent >= parseInt(dataListY[i].start_time) && this.startTimeCurrent <= parseInt(dataListY[i].end_time)) {
if (startTime >= parseInt(dataListY[i].start_time) && startTime <= parseInt(dataListY[i].end_time)) {
startIndex = i
}
if (this.endTimeCurrent >= parseInt(dataListY[i].start_time) && this.endTimeCurrent <= parseInt(dataListY[i].end_time)) {
if (endTime >= parseInt(dataListY[i].start_time) && endTime <= parseInt(dataListY[i].end_time)) {
endIndex = i
}
}
// download and push into chart
for (let i = startIndex; i <= endIndex; i++) {
const data = await this.getData(parseInt(scale), sampleMethod, dataListY[i].id, channelY, metaInfo)
const data = await this.getData(parseInt(scale), this.sampleMethod, dataListY[i].id, channelY, metaInfo)
let dataX
if (this.axisXDataType.description !== 'Time') {
dataX = await this.getData(parseInt(scale), sampleMethod, dataListX[i].id, channelX, metaInfo)
dataX = await this.getData(parseInt(scale), this.sampleMethod, dataListX[i].id, channelX, metaInfo)
}
for (let j = 0, len = data.length; j < len; j++) {
// check which channel and push processed data (i.e. merge two channel data, now data is (time, value) format)
if (parseInt(data[j][0]) >= this.startTimeCurrent && parseInt(data[j][0]) <= this.endTimeCurrent) {
if (parseInt(data[j][0]) >= startTime && parseInt(data[j][0]) <= endTime) {
const processedData = JSON.parse(JSON.stringify(data[j]))
if (dataX !== undefined) {
processedData[0] = dataX[j][1]
@@ -348,12 +389,28 @@ export default {
}
}
}
// for (let i = 0, len = this.chartDetailData.xAxis.length; i < len; i++) {
// this.chartDetailData.xAxis[i].min = this.startTimeCurrent
// this.chartDetailData.xAxis[i].max = this.endTimeCurrent
// }]
if (this.axisXDataType.description === 'Time') {
this.chartDetailData.xAxis[_gridNumber].min = this.startTimeCurrent
this.chartDetailData.xAxis[_gridNumber].max = this.endTimeCurrent
} else {
this.chartDetailData.xAxis[_gridNumber].min = 'dataMin'
this.chartDetailData.xAxis[_gridNumber].max = 'dataMax'
}
_gridNumber += 1
}
if (this.axisXDataType.description !== 'Time') {
this.showOverviewChart = false
this.detailchartheight = '88vh'
// this.$refs.chart_detail.updateChartHeight()
this.turnOnAxisEventHandler('click', 'xAxis.axisLabel', this.showMinMaxPanel, { axis: 'x' })
} else {
this.showOverviewChart = true
this.detailchartheight = '80vh'
this.turnOffAxisEventHandler('click', this.showMinMaxPanel, { axis: 'x' })
this.turnOnAxisEventHandler('click', 'yAxis.axisLabel', this.showMinMaxPanel, { axis: 'y' })
}
this.hideChartLoading()
},
checkDataZoom: function () {
@@ -363,6 +420,7 @@ export default {
this.startTimeCurrent = this.startTime
this.endTimeCurrent = this.endTime
this.drawDetailData()
this.$refs.top_control_panel.resetScale()
}
}
},
@@ -389,14 +447,6 @@ export default {
})
}
this.drawDetailData() // reDraw
if (this.axisXDataType.description !== 'Time') {
this.showOverviewChart = false
this.turnOnAxisEventHandler('click', 'xAxis.axisLabel', this.showMinMaxPanel, { axis: 'x' })
} else {
this.showOverviewChart = true
this.turnOffAxisEventHandler('click', this.showMinMaxPanel, { axis: 'x' })
this.turnOnAxisEventHandler('click', 'yAxis.axisLabel', this.showMinMaxPanel, { axis: 'y' })
}
},
distribute: function () {
// if (this.chartDetailData.grid.length === 1) {
@@ -428,11 +478,11 @@ export default {
...mapActions('replay', [types.meta.init]),
...mapActions('replay', [types.rec.init, types.rec.intoData, types.rec.initDisplaySetting, types.rec.updateDisplaySetting]),
...mapMutations('replay', [types.chart.updateRegistered]),
...mapMutations('replay', [types.chart.updateRegistered, types.chart.updateAxisSplitNumber, types.chart.updateChartSampling]),
...mapMutations('replay', [types.meta.updateByIndex]),
...mapGetters('replay', [types.meta.getAll]),
...mapGetters('replay', [types.rec.getAll, types.rec.getAllDisplaySetting, types.rec.getDisplaySettingByKey]),
...mapGetters('replay', [types.rec.getAll, types.rec.getCycleDict]),
},
// use watch because va-select with @change will have bug
watch: {
@@ -447,13 +497,16 @@ export default {
console.log(this.metaList)
console.log(this.dataInfo)
await this.register()
this.$refs.top_control_panel.init() // will can changeAxis() here
this.$refs.top_control_panel.init() // will call changeAxis() here
this.$refs.set_min_max.init()
this.turnOnAxisEventHandler('click', 'yAxis.axisLabel', this.showMinMaxPanel, { axis: 'y' })
this.drawOverviewData()
this.turnOnAxisEventHandler('click', 'yAxis.axisLabel', this.showMinMaxPanel, { axis: 'y' })
this.updateAxisSplitNumberChart({ chartID: this.chartDetailData.chartID, axis: 'x' })
this.updateAxisSplitNumberChart({ chartID: this.chartDetailData.chartID, axis: 'y' })
this.dataZoomTimer = setInterval(this.checkDataZoom, 1000)
this.initDone = true
// console.log(this.chartDetailData)
console.log(this.chartOverviewData)
console.log(this.chartDetailData)
},
beforeDestroy () {
this.$refs.chart_overview.clear()
@@ -471,21 +524,3 @@ export default {
},
}
</script>
<style lang="scss">
.area-style {
height: auto;
overflow-y: hidden;
overflow-x: hidden;
@include media-breakpoint-only(xl) {
height: 88vh;
overflow-y: scroll;
overflow-x: hidden;
}
}
.layout.gutter--xl .row .flex {
padding: 0.4rem 0.5rem 0.1rem 0.5rem;
}
</style>
@@ -1,7 +1,7 @@
<template>
<div class="flex" :class="cardclass">
<va-card :style="'height: ' + cardheight + ';'">
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="data" @dataZoom="updateZoom" :auto-resize="true"></chart>
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + chartheight + ';'" :options="data" @dataZoom="updateZoom" :auto-resize="true"></chart>
</va-card>
</div>
</template>
@@ -30,12 +30,16 @@ export default {
},
cardheight: {
type: String,
default: '82vh',
default: '88vh',
},
cardwidth: {
type: String,
default: 'auto',
},
chartheight: {
type: String,
default: '88vh',
},
},
created () {
},
@@ -1,18 +1,22 @@
<template>
<div>
<va-card>
<edit-file-name style="display: inline;" :ref="'edit_file_name'"/>
<download-file style="display: inline;"/>
<delete-file style="display: inline;"/>
<br/>
<change-axis class="box_inline-block" :ref="'change_axis_x'" deviceName="elite" axis="x" @changeAxis="changeAxis" @changeUnit="changeUnit" @clearCycle="clearCycle"/>
<change-unit class="box_inline-block" :ref="'change_unit_x'" deviceName="elite" axis="x" @refreshChart="refreshChart"/>
<change-scale class="box_inline-block" :ref="'change_scale_x'" deviceName="elite" axis="x" @refreshChart="refreshChart"/>
<br/>
<change-axis class="box_inline-block" :ref="'change_axis_y'" deviceName="elite" axis="y" @changeAxis="changeAxis" @changeUnit="changeUnit" @clearCycle="clearCycle"/>
<change-unit class="box_inline-block" :ref="'change_unit_y'" deviceName="elite" axis="y" @refreshChart="refreshChart"/>
<change-scale class="box_inline-block" :ref="'change_scale_y'" deviceName="elite" axis="y" @refreshChart="refreshChart"/>
<change-cycle style="margin: 3px;" :ref="'change_cycle'" @refreshChart="refreshChart"/>
<div class="flex-container">
<edit-file-name class="flex-child" :ref="'edit_file_name'"/>
<download-file class="flex-child2"/>
<delete-file class="flex-child2"/>
</div>
<div class="flex-container">
<change-axis class="flex-child" :ref="'change_axis_x'" deviceName="elite" axis="x" @changeAxis="changeAxis" @changeUnit="changeUnit" @clearCycle="clearCycle" @resetScale="resetScale"/>
<change-unit class="flex-child2" :ref="'change_unit_x'" deviceName="elite" axis="x" @refreshChart="refreshChart"/>
<change-scale class="flex-child1" :ref="'change_scale_x'" deviceName="elite" axis="x" @refreshChart="refreshChart" @clearCycle="clearCycle"/>
</div>
<div class="flex-container">
<change-axis class="flex-child" :ref="'change_axis_y'" deviceName="elite" axis="y" @changeAxis="changeAxis" @changeUnit="changeUnit" @clearCycle="clearCycle" @resetScale="resetScale"/>
<change-unit class="flex-child2" :ref="'change_unit_y'" deviceName="elite" axis="y" @refreshChart="refreshChart"/>
<change-scale class="flex-child1" :ref="'change_scale_y'" deviceName="elite" axis="y" @refreshChart="refreshChart" @clearCycle="clearCycle"/>
</div>
<change-cycle v-show="showCyclePanel" style="margin: 3px;" :ref="'change_cycle'" @refreshChart="refreshChart"/>
<show-resample-rate style="margin: 3px;"/>
<show-parameter style="margin: 3px;" :ref="'show_param'" deviceName="elite"/>
</va-card>
@@ -29,6 +33,7 @@ import DownloadFile from '@/components/analysis/replay/toolbox/DownloadFile.vue'
import DeleteFile from '@/components/analysis/replay/toolbox/DeleteFile.vue'
import EditFileName from '@/components/analysis/replay/toolbox/EditFileName.vue'
import ShowParameter from '@/components/analysis/replay/toolbox/ShowParameter.vue'
import { mapFields } from 'vuex-map-fields'
export default {
name: 'top-control-panel',
@@ -44,6 +49,9 @@ export default {
ShowParameter,
},
computed: {
...mapFields('replay', [
'showCyclePanel',
]),
},
props: {
},
@@ -51,6 +59,7 @@ export default {
},
data () {
return {
showCycle: false,
}
},
mqtt: {
@@ -83,6 +92,10 @@ export default {
clearCycle () {
this.$refs.change_cycle.clear()
},
resetScale () {
this.$refs.change_scale_x.reset()
this.$refs.change_scale_y.reset()
},
},
// use watch because va-select with @change will have bug
watch: {
@@ -98,4 +111,24 @@ export default {
margin: 2px;
display: inline-block;
}
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -1,7 +1,7 @@
<template>
<div>
<div class="row row-equal">
<div class="flex md12 xl3 xs12 sm12 area-style">
<div class="flex md12 xl3 xs12 sm12">
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-accordion>
@@ -18,11 +18,11 @@
</div>
</div>
<div :class="chartAreaClass" class="area-style">
<div :class="chartAreaClass">
<div class="row" >
<div class="flex sm12 xl12 md12 xs12">
<neulive-replay-overview-chart :ref="'chart_overview'" class="mb-1" :cardheight="'7vh'" :data="chartOverviewData" @dataZoomEvent="dataZoomEvent($event)"/>
<neulive-replay-chart :ref="'chart_detail'" @dblclick.native="distribute()" :cardheight="'88vh'" :data="chartDetailData" />
<neulive-replay-chart :ref="'chart_detail'" @dblclick.native="distribute()" :cardheight="'80vh'" :data="chartDetailData" @dataZoomEvent="updateMarkArea($event)" />
<change-channel-value-min-max :ref="'set_min_max'"/>
</div>
</div>
@@ -56,6 +56,9 @@ export default {
'chartOverviewData',
'chartDetailData',
'currentScale',
'startTimeCurrent',
'endTimeCurrent',
'sampleMethod',
]),
},
props: {
@@ -83,12 +86,13 @@ export default {
metaList: null,
dataInfo: {},
maxTime: 0,
startTimeCurrent: 0,
endTimeCurrent: 0,
startTime: 0,
endTime: 0,
zoomTime: 0,
chartAreaClass: ['flex', 'xs12', 'sm12', 'md12', 'xl9', 'pa-0'],
dataZoomStart: 0,
dataZoomEnd: 100,
inDistributeMode: false,
}
},
mqtt: {
@@ -199,6 +203,35 @@ export default {
chartID: 1,
})
},
updateMarkArea: function (e) {
console.log(e)
if (e.batch != null) {
// console.log(e.batch)
e.batch.forEach(dataZoom => {
const id = parseInt(dataZoom.dataZoomId.substr(dataZoom.dataZoomId.length - 3, dataZoom.dataZoomId.length - 1))
if (id === 1) {
this.dataZoomStart = dataZoom.start
this.dataZoomEnd = dataZoom.end
const startTime = (this.endTime - this.startTime) * dataZoom.start / 100
const endTime = (this.endTime - this.startTime) * dataZoom.end / 100
this.chartOverviewData.series[0].markArea.data[0][0].xAxis = this.startTime + startTime
this.chartOverviewData.series[0].markArea.data[0][1].xAxis = this.startTime + endTime
// console.log(this.startTime, this.endTime)
}
})
} else {
const id = parseInt(e.dataZoomId.substr(e.dataZoomId.length - 3, e.dataZoomId.length - 1))
if (id === 0) {
this.dataZoomStart = e.start
this.dataZoomEnd = e.end
const startTime = (this.endTime - this.startTime) * e.start / 100
const endTime = (this.endTime - this.startTime) * e.end / 100
this.chartOverviewData.series[0].markArea.data[0][0].xAxis = this.startTime + startTime
this.chartOverviewData.series[0].markArea.data[0][1].xAxis = this.startTime + endTime
// console.log(this.startTime, this.endTime)
}
}
},
dataZoomEvent: function (e) {
// console.log(e)
if (e.batch != null) {
@@ -219,9 +252,11 @@ export default {
// console.log(this.startTime, this.endTime)
}
}
this.chartOverviewData.series[0].markArea.data[0][0].xAxis = this.startTime + ((this.endTime - this.startTime) * (this.dataZoomStart / 100))
this.chartOverviewData.series[0].markArea.data[0][1].xAxis = this.startTime + ((this.endTime - this.startTime) * (this.dataZoomEnd / 100))
this.zoomTime = 0
},
drawOverviewData: async function () {
drawInitData: async function () {
this.showChartLoading('overview')
for (const meta in this.dataInfo) {
let metaInfo
@@ -230,44 +265,39 @@ export default {
metaInfo = _meta
}
})
const sampleRate = (80000 / metaInfo.parameter_set.ADC_CLOCK)
let scale = (((metaInfo.time_duration / 100000) * sampleRate) / 4000)
if (scale > 500) {
let scale = '1000'
const sampleRate = metaInfo.parameter_set.SAMPLE_RATE // Hz
const dataPointNum = (parseInt(metaInfo.time_duration) / 1e6) * sampleRate // us -> s: /1e6
if (dataPointNum > 2e6) { // 2000 (points) * 1000 (resample) = 2e6
scale = '1000'
} else if (scale > 200) {
} else if (dataPointNum > 2e5) { // 2000 (points) * 100 (resample) = 2e5
scale = '100'
} else if (scale > 30) {
} else if (dataPointNum > 2e4) { // 2000 (points) * 10 (resample) = 2e4
scale = '10'
} else {
scale = '1'
}
this.currentScale = scale
console.log('overview scale:', scale)
const sampleMethod = 'mean'
const getAllData = async function (_this) {
let seriesIndex = 0
for (const ch in _this.dataInfo[meta]) {
const dataList = _this.dataInfo[meta][ch][scale]
for (let i = 0; i < dataList.length; i++) {
if (dataList[i].data.length === 0) {
_this.intoDataRec({
index: i,
metaID: meta,
channel: ch,
scale: scale,
data: await _this.getData(parseInt(scale), sampleMethod, dataList[i].id, ch, metaInfo),
})
}
_this.intoDataRec({
index: i,
metaID: meta,
channel: ch,
scale: scale,
data: await _this.getData(parseInt(scale), _this.sampleMethod, dataList[i].id, ch, metaInfo),
})
_this.chartOverviewData.series[seriesIndex].data.push(...dataList[i].data)
_this.chartDetailData.series[seriesIndex].data.push(...dataList[i].data)
}
seriesIndex++
}
}
await getAllData(this)
let seriesIndex = 0
for (const ch in this.dataInfo[meta]) {
const dataList = this.dataInfo[meta][ch][scale]
for (let i = 0; i < dataList.length; i++) {
this.chartOverviewData.series[seriesIndex].data.push(...dataList[i].data)
}
seriesIndex++
}
}
this.hideChartLoading()
},
@@ -281,20 +311,21 @@ export default {
metaInfo = _meta
}
})
const sampleRate = (80000 / metaInfo.parameter_set.ADC_CLOCK)
let scale = (((timeDur / 100000) * sampleRate) / 4000)
if (scale > 500) {
let scale = '1000'
const sampleRate = metaInfo.parameter_set.SAMPLE_RATE // Hz
const dataPointNum = (timeDur / 1e6) * sampleRate // us -> s: /1e6
if (dataPointNum > 2e6) { // 2000 (points) * 1000 (resample) = 2e6
scale = '1000'
} else if (scale > 200) {
} else if (dataPointNum > 2e5) { // 2000 (points) * 100 (resample) = 2e5
scale = '100'
} else if (scale > 30) {
} else if (dataPointNum > 2e4) { // 2000 (points) * 10 (resample) = 2e4
scale = '10'
} else {
scale = '1'
}
this.currentScale = scale
const sampleMethod = 'mean'
let seriesIndex = 0
this.updateChartSamplingChart({ chartID: this.chartDetailData.chartID, seriesIndex: seriesIndex, method: function (frame) { return frame[0] } })
for (const ch in this.dataInfo[meta]) {
this.chartDetailData.series[seriesIndex].data.length = 0
const dataList = this.dataInfo[meta][ch][scale]
@@ -310,12 +341,22 @@ export default {
}
}
// download and push into chart
let endFlag = false // because data is sorted by time, so if current processed data piece exceeds endTimeCurrent, can early stop
for (let i = startIndex; i <= endIndex; i++) {
const data = await this.getData(parseInt(scale), sampleMethod, dataList[i].id, ch, metaInfo)
const data = await this.getData(parseInt(scale), this.sampleMethod, dataList[i].id, ch, metaInfo)
for (let j = 0, len = data.length; j < len; j++) {
if (parseInt(data[j][0]) >= this.startTimeCurrent && parseInt(data[j][0]) <= this.endTimeCurrent) {
this.chartDetailData.series[seriesIndex].data.push(data[j])
}
// early stop
if (parseInt(data[j][0]) > this.endTimeCurrent) {
endFlag = true
break
}
}
// early stop
if (endFlag === true) {
break
}
}
for (let i = 0, len = this.chartDetailData.xAxis.length; i < len; i++) {
@@ -334,43 +375,84 @@ export default {
this.startTimeCurrent = this.startTime
this.endTimeCurrent = this.endTime
this.drawDetailData()
this.$refs.top_control_panel.resetScale()
}
}
},
distribute: function () {
if (this.chartDetailData.grid.length === 1) {
this.chartDetailData.xAxis[0].axisLabel.show = false
if (this.inDistributeMode) {
let seriesIndex = 0
for (const meta in this.dataInfo) {
for (const ch in this.dataInfo[meta]) {
this.chartDetailData.series[seriesIndex].xAxisIndex = seriesIndex
this.chartDetailData.series[seriesIndex].yAxisIndex = seriesIndex
this.updateAxisLabelChart({
chartID: this.chartDetailData.chartID,
axis: 'y',
axisIndex: seriesIndex,
channel: ch,
})
seriesIndex++
}
}
this.updateGridListChart({
chartAllData: this.chartData,
chartID: this.chartDetailData.chartID,
gridLength: this.chartDetailData.series.length,
})
this.chartDetailData.series.forEach((series, index) => {
series.xAxisIndex = index
series.yAxisIndex = index
gridLength: seriesIndex,
})
for (let i = 0; i < this.chartDetailData.xAxis.length; i++) {
this.chartDetailData.xAxis[i].axisLabel.show = false
}
this.chartDetailData.xAxis[this.chartDetailData.xAxis.length - 1].axisLabel.show = true
this.inDistributeMode = false
} else {
this.updateGridListChart({
chartAllData: this.chartData,
chartID: this.chartDetailData.chartID,
gridLength: 1,
})
this.chartDetailData.series.forEach(series => {
series.xAxisIndex = 0
series.yAxisIndex = 0
})
let gridLength = 1
this.chartDetailData.xAxis[0].axisLabel.show = true
for (const meta in this.dataInfo) {
for (const ch in this.dataInfo[meta]) {
if (parseInt(ch) >= 256) { // x, y, z, mag
gridLength = 2
this.chartDetailData.xAxis[0].axisLabel.show = false
this.chartDetailData.xAxis[1].axisLabel.show = true
break
}
}
this.updateGridListChart({
chartAllData: this.chartData,
chartID: this.chartDetailData.chartID,
gridLength: gridLength,
})
let seriesIndex = 0
for (const ch in this.dataInfo[meta]) {
if (parseInt(ch) < 256) {
this.chartDetailData.series[seriesIndex].xAxisIndex = 0
this.chartDetailData.series[seriesIndex].yAxisIndex = 0
} else { // x, y, z, mag
this.chartDetailData.series[seriesIndex].xAxisIndex = 1
this.chartDetailData.series[seriesIndex].yAxisIndex = 1
this.updateAxisLabelChart({
chartID: this.chartDetailData.chartID,
axis: 'y',
axisIndex: 1,
channel: ch,
})
}
seriesIndex++
}
}
this.inDistributeMode = true
}
},
...mapActions('replay', [types.chart.init, types.chart.register, types.chart.clear, types.chart.updateGridList, types.chart.updateDataZoom]),
...mapActions('replay', [types.meta.init]),
...mapActions('replay', [types.rec.init, types.rec.intoData, types.rec.initDisplaySetting, types.rec.updateDisplaySetting]),
...mapMutations('replay', [types.chart.updateAxisLabel, types.chart.updateChartSampling]),
...mapMutations('replay', [types.meta.updateByIndex]),
...mapGetters('replay', [types.meta.getAll]),
...mapGetters('replay', [types.rec.getAll, types.rec.getAllDisplaySetting, types.rec.getDisplaySettingByKey]),
...mapGetters('replay', [types.rec.getAll]),
},
// use watch because va-select with @change will have bug
watch: {
@@ -382,14 +464,16 @@ export default {
this.metaList = this.getAllMeta()
await this.initRec({ api: api })
this.dataInfo = this.getAllRec()
console.log(this.metaList)
console.log(this.dataInfo)
await this.register()
this.drawOverviewData()
this.drawDetailData()
await this.drawInitData()
this.dataZoomTimer = setInterval(this.checkDataZoom, 1000)
this.$refs.top_control_panel.init()
this.$refs.set_min_max.init()
this.turnOnAxisEventHandler('click', 'yAxis.axisLabel', this.showMinMaxPanel, { axis: 'y' })
console.log(this.chartOverviewData)
console.log(this.chartDetailData)
},
beforeDestroy () {
this.$refs.chart_overview.clear()
@@ -407,21 +491,3 @@ export default {
},
}
</script>
<style lang="scss">
.area-style {
height: auto;
overflow-y: hidden;
overflow-x: hidden;
@include media-breakpoint-only(xl) {
height: 88vh;
overflow-y: scroll;
overflow-x: hidden;
}
}
.layout.gutter--xl .row .flex {
padding: 0.75rem 0.5rem 0.1rem 0.5rem;
}
</style>
@@ -5,9 +5,11 @@
<download-file style="display: inline;"/>
<delete-file style="display: inline;"/>
<show-resample-rate/>
<change-axis v-show="showXAxis" :ref="'change_axis_x'" deviceName="neulive" axis="x"/>
<change-axis v-show="showYAxis" :ref="'change_axis_y'" deviceName="neulive" axis="y"/>
<change-unit v-show="showXUnit" :ref="'change_unit_x'" deviceName="neulive" axis="x" @refreshChart="refreshChart"/>
<change-unit :ref="'change_unit_y'" deviceName="neulive" axis="y" @refreshChart="refreshChart"/>
<change-scale :ref="'change_scale_y'" deviceName="neulive" axis="y" @refreshChart="refreshChart"/>
<change-scale :ref="'change_scale_y'" deviceName="neulive" axis="y"/>
<show-parameter :ref="'show_param'" deviceName="neulive"/>
</va-card>
</div>
@@ -15,6 +17,7 @@
<script>
import ShowResampleRate from '@/components/analysis/replay/toolbox/ShowResampleRate.vue'
import ChangeAxis from '@/components/analysis/replay/toolbox/ChangeAxis.vue'
import ChangeUnit from '@/components/analysis/replay/toolbox/ChangeUnit.vue'
import ChangeScale from '@/components/analysis/replay/toolbox/ChangeScale.vue'
import DownloadFile from '@/components/analysis/replay/toolbox/DownloadFile.vue'
@@ -26,6 +29,7 @@ export default {
name: 'top-control-panel',
components: {
ShowResampleRate,
ChangeAxis,
ChangeUnit,
ChangeScale,
DownloadFile,
@@ -41,6 +45,8 @@ export default {
},
data () {
return {
showXAxis: false,
showYAxis: false,
showXUnit: false,
}
},
@@ -48,6 +54,8 @@ export default {
},
methods: {
init () {
this.$refs.change_axis_x.init()
this.$refs.change_axis_y.init()
this.$refs.change_unit_x.init()
this.$refs.change_unit_y.init()
this.$refs.change_scale_y.init()
@@ -57,6 +65,9 @@ export default {
refreshChart (options) {
this.$emit('refreshChart', options)
},
resetScale () {
this.$refs.change_scale_y.reset()
},
},
// use watch because va-select with @change will have bug
watch: {
@@ -20,7 +20,6 @@
<script>
import { mapFields } from 'vuex-map-fields'
import { newChartMode } from '@/factories/chart/chartFactory'
export default {
name: 'change-axis',
@@ -46,6 +45,7 @@ export default {
'metaList',
'axisXDataType',
'axisYDataType',
'showCyclePanel',
]),
},
methods: {
@@ -59,7 +59,7 @@ export default {
}
} else if (this.deviceName === 'elite') {
// use state meta to decide which default unit need to be used (like check I-V mode...)
const setting = newChartMode(this.metaList[this.metaIndex].parameter_set.MODE)
const setting = this.GLOBAL.getDefaultChartTypeByMode(this.metaList[this.metaIndex].parameter_set.MODE)
const xType = setting[0]
const xValue = setting[1]
const yType = setting[2]
@@ -105,16 +105,23 @@ export default {
}
},
changeAxis () {
if (this.axis === 'x') {
this.axisXDataType = this.channelFormat
} else if (this.axis === 'y') {
this.axisYDataType = this.channelFormat
}
if (this.deviceName === 'neulive') {
console.log('(Last updated: 2021/06/07) [TODO] for elite now, cuz neulive now only have v-t graph, for future neulive replay need to adjust')
// for elite now, cuz neulive now only have v-t graph, for future neulive replay need to adjust'
// console.log('(Last updated: 2021/06/19)')
} else if (this.deviceName === 'elite') {
if (this.axis === 'x') {
this.axisXDataType = this.channelFormat
} else if (this.axis === 'y') {
this.axisYDataType = this.channelFormat
}
if (this.axisXDataType.description !== 'Time' && this.metaList[this.metaIndex].parameter_set.CYCLE_NUMBER > 0) {
this.showCyclePanel = true
} else {
this.showCyclePanel = false
}
this.$emit('changeAxis', this.metaIndex) // temporarily use metaIndex for gridIndex
this.$emit('changeUnit', this.axis)
this.$emit('resetScale')
this.$emit('clearCycle')
}
},
@@ -1,5 +1,5 @@
<template>
<div v-show="showPanel">
<div v-if="showPanel">
<va-input
v-model="showWhichCycles"
@change="setCycle"
@@ -9,9 +9,10 @@
</template>
<script>
import { mapMutations } from 'vuex'
import { mapMutations, mapGetters } from 'vuex'
import { mapFields } from 'vuex-map-fields'
import types from '@/store/modules/analysis/replay/types'
import { download } from '@/data/download/Download'
export default {
name: 'change-cycle',
@@ -31,11 +32,11 @@ export default {
},
data () {
return {
showPanel: true,
showPanel: false,
metaID: 0,
showWhichCycles: '',
showWhichCycles: '1',
cycleNum: 0,
eachSliceNum: 0, // 每一等分data數量
cycleDataID: 3, // [TODO] manage by data type factory
}
},
computed: {
@@ -55,69 +56,133 @@ export default {
}
}
}
// console.log(cycleList)
return cycleList
const cycleSet = new Set(cycleList)
const sortedCycleList = [...cycleSet].sort() // ref: https://stackoverflow.com/questions/33089695/how-can-i-sort-an-es6-set
// console.log(sortedCycleList)
return sortedCycleList
},
...mapFields('replay', [
'chartData',
'recInfo',
'metaList',
'currentScale',
'sampleMethod',
'axisXDataType',
'axisYDataType',
'axisXLabelScale',
'axisYLabelScale',
]),
},
watch: {
},
methods: {
init () {
this.isThisModeHasCycle = this.GLOBAL.hasCycleMode(this.metaList[this.metaIndex].parameter_set.MODE)
this.cycleNum = this.metaList[this.metaIndex].parameter_set.CYCLE_NUMBER
this.metaID = this.metaList[this.metaIndex].id
if (this.cycleNum === 0) {
if (this.isThisModeHasCycle === true) {
this.showPanel = true
} else {
this.showPanel = false
}
},
clear () {
this.showWhichCycles = ''
this.showWhichCycles = '1'
},
setCycle () {
async setCycle () {
console.log('setCycle')
if (this.cycleNum !== 0) {
let allXData
if (this.axisXDataType.description !== 'Time') {
allXData = this.recInfo[this.metaID][this.axisXDataType.id][this.currentScale][this.metaIndex].data
if (this.isThisModeHasCycle === true) {
const dataCycleList = this.recInfo[this.metaID][this.cycleDataID][this.currentScale]
const cycleDataList = []
for (let i = 0; i < dataCycleList.length; i++) {
if (dataCycleList[i].data.length === 0) {
const data = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataCycleList[i].id, this.cycleDataID, this.metaList[this.metaIndex])
cycleDataList.push({ data: data })
} else {
cycleDataList.push({ data: dataCycleList[i].data })
}
}
const allYData = this.recInfo[this.metaID][this.axisYDataType.id][this.currentScale][this.metaIndex].data
const len = allYData.length
const eachSliceNum = parseInt(len / this.cycleNum)
const data = []
const cycleDict = this.getCycleDictRec()(cycleDataList)
const dataXList = this.recInfo[this.metaID][this.axisXDataType.id][this.currentScale]
const dataYList = this.recInfo[this.metaID][this.axisYDataType.id][this.currentScale]
const filteredData = []
for (let sliceIndex = 0; sliceIndex < this.cycleNum; sliceIndex++) {
// console.log(this.slices)
if (this.slices === '' || this.slices.includes((sliceIndex + 1).toString())) {
const sliceYData = allYData.slice(sliceIndex * eachSliceNum, (sliceIndex + 1) * eachSliceNum)
const sliceLen = sliceYData.length
if (allXData !== undefined) {
const sliceXData = allXData.slice(sliceIndex * eachSliceNum, (sliceIndex + 1) * eachSliceNum)
for (let j = 0; j < sliceLen; j++) {
data.push([sliceXData[j][1], sliceYData[j][1]])
// slice data
const value = cycleDict[sliceIndex + 1]
const startTime = value[0]
const endTime = value[1]
let startIndex = 0
let endIndex = 0
for (let i = 0; i < dataYList.length; i++) {
if (startTime >= parseInt(dataYList[i].start_time) && startTime <= parseInt(dataYList[i].end_time)) {
startIndex = i
}
} else {
const sliceYData = allYData.slice(sliceIndex * eachSliceNum, (sliceIndex + 1) * eachSliceNum)
for (let j = 0; j < sliceLen; j++) {
data.push(sliceYData[j])
if (endTime >= parseInt(dataYList[i].start_time) && endTime <= parseInt(dataYList[i].end_time)) {
endIndex = i
}
}
for (let i = startIndex; i <= endIndex; i++) {
const dataY = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataYList[i].id, this.axisYDataType.id, this.metaList[this.metaIndex])
if (this.axisXDataType.description !== 'Time') {
const dataX = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataXList[i].id, this.axisXDataType.id, this.metaList[this.metaIndex])
for (let j = 0, len = dataY.length; j < len; j++) {
if (parseInt(dataY[j][0]) >= startTime && parseInt(dataY[j][0]) <= endTime) {
let x
let y
if (this.axisXLabelScale.description === 'Log') {
x = Math.log10(Math.abs(dataX[j][1]))
} else if (this.axisXLabelScale.description === 'Linear') {
x = dataX[j][1]
}
if (this.axisYLabelScale.description === 'Log') {
y = Math.log10(Math.abs(dataY[j][1]))
} else if (this.axisYLabelScale.description === 'Linear') {
y = dataY[j][1]
}
filteredData.push([x, y])
}
}
} else {
for (let j = 0, len = dataY.length; j < len; j++) {
if (parseInt(dataY[j][0]) >= startTime && parseInt(dataY[j][0]) <= endTime) {
if (this.axisYLabelScale.description === 'Log') {
dataY[j][1] = Math.log10(Math.abs(dataY[j][1]))
} else if (this.axisYLabelScale.description === 'Linear') {
// do nothing
}
filteredData.push(dataY[j])
}
}
}
}
this.updateSeriesChart({
chartID: this.chartID,
seriesIndex: this.metaIndex,
data: filteredData,
})
// this.$emit('refreshChart', this.chartData[this.chartID])
}
}
this.updateSeriesChart({
chartID: this.chartID,
seriesIndex: this.metaIndex,
data: data,
})
}
this.$emit('refreshChart', this.chartData[this.chartID])
},
getData: async function (scale, sampleMethod, id, channel, meta) {
if (scale === 1) {
return await download.rawByIDChannels(id, channel, meta)
} else {
if (sampleMethod === 'mean') {
return await download.miniMeanByIDChannel(id, channel, meta)
} else if (sampleMethod === 'random') {
return await download.miniRandomByIDChannel(id, channel, meta)
}
}
},
...mapMutations('replay', [types.chart.updateSeries]),
...mapGetters('replay', [types.rec.getCycleDict]),
},
mounted () {
@@ -9,9 +9,10 @@
</template>
<script>
import { mapMutations } from 'vuex'
import { mapMutations, mapGetters } from 'vuex'
import { mapFields } from 'vuex-map-fields'
import types from '@/store/modules/analysis/replay/types'
import { download } from '@/data/download/Download'
export default {
name: 'change-scale',
@@ -21,6 +22,10 @@ export default {
deviceName: {
type: String, // elite or neulive
},
chartID: {
type: Number, // detail data
default: 1,
},
axis: {
type: String, // x or y
},
@@ -34,13 +39,22 @@ export default {
computed: {
...mapFields('replay', [
'chartData',
'recInfo',
'metaList',
'axisXLabelScale',
'axisYLabelScale',
'axisXDataType',
'axisYDataType',
'startTimeCurrent',
'endTimeCurrent',
'currentScale',
'sampleMethod',
]),
},
methods: {
init () {
this.metaInfo = this.metaList[this.metaIndex]
this.metaID = this.metaInfo.id
if (this.axis === 'x') {
this.axisXLabelScale = this.scaleOptions[0] // 0 mean use default unit
this.scaleFormat = this.axisXLabelScale
@@ -48,7 +62,6 @@ export default {
this.axisYLabelScale = this.scaleOptions[0] // 0 mean use default unit
this.scaleFormat = this.axisYLabelScale
}
this.changeScale()
},
changeScale () {
if (this.axis === 'x') {
@@ -56,36 +69,161 @@ export default {
} else if (this.axis === 'y') {
this.axisYLabelScale = this.scaleFormat
}
const chartID = 1 // detail data
if (this.deviceName === 'neulive') {
const keys = Object.keys(this.metaList[this.metaIndex].mini_data)
for (let axisIndex = 0; axisIndex < keys.length; axisIndex++) {
const key = keys[axisIndex]
if (parseInt(key) < 255) { // 256: x, 257: y, 258: z, 259: mag
this.updateAxisLabelChart({
chartID: chartID,
axis: this.axis,
axisIndex: axisIndex,
})
const keys = Object.keys(this.metaInfo.mini_data)
for (let gridIndex = 0; gridIndex < keys.length; gridIndex++) {
const ch = keys[gridIndex]
if (parseInt(ch) < 256) { // 256: x, 257: y, 258: z, 259: mag
this.calculateScaleHelper(gridIndex, ch)
}
}
} else if (this.deviceName === 'elite') {
this.updateAxisLabelChart({
chartID: chartID,
axis: this.axis,
axisIndex: this.metaIndex,
})
this.calculateScaleHelper(this.metaIndex, -1) // [TODO] elite tmp use metaIndex for grid index
}
this.$emit('refreshChart', this.chartData[chartID])
},
// call vuex to mutate chart label formatter by unit and axis
...mapMutations('replay', [types.chart.updateAxisLabel]),
async calculateScaleHelper (gridIndex, ch) {
let seriesData
if (this.scaleFormat.description === 'Log') {
seriesData = JSON.parse(JSON.stringify(this.chartData[this.chartID].series[gridIndex].data))
for (let i = 0; i < seriesData.length; i++) {
if (this.axis === 'x') {
seriesData[i][0] = Math.log10(Math.abs(seriesData[i][0]))
} else if (this.axis === 'y') {
seriesData[i][1] = Math.log10(Math.abs(seriesData[i][1]))
}
}
} else if (this.scaleFormat.description === 'Linear') {
// console.log(this.recInfo)
if (this.deviceName === 'neulive') {
// [Region] get the subfile index
seriesData = []
const dataYList = this.recInfo[this.metaID][ch][this.currentScale]
let startIndex = 0
let endIndex = 0
for (let i = 0; i < dataYList.length; i++) {
if (this.startTimeCurrent >= parseInt(dataYList[i].start_time) && this.startTimeCurrent <= parseInt(dataYList[i].end_time)) {
startIndex = i
}
if (this.endTimeCurrent >= parseInt(dataYList[i].start_time) && this.endTimeCurrent <= parseInt(dataYList[i].end_time)) {
endIndex = i
}
}
// [EndRegion]
for (let i = startIndex; i <= endIndex; i++) {
const data = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataYList[i].id, ch, this.metaInfo)
for (let j = 0, len = data.length; j < len; j++) {
if (parseInt(data[j][0]) >= this.startTimeCurrent && parseInt(data[j][0]) <= this.endTimeCurrent) {
const processedData = data[j]
if (this.axisXLabelScale.description === 'Log') {
processedData[0] = Math.log10(Math.abs(processedData[0]))
}
if (this.axisYLabelScale.description === 'Log') {
processedData[1] = Math.log10(Math.abs(processedData[1]))
}
seriesData.push(processedData)
}
}
}
} else if (this.deviceName === 'elite') {
seriesData = []
const isThisModeHasCycle = this.GLOBAL.hasCycleMode(this.metaInfo.parameter_set.MODE)
let startTime
let endTime
if (isThisModeHasCycle === true && this.axisXDataType.description !== 'Time') { // if有cycle的mode且目前x軸不為時間,抓出第一圈所在的時間段,初始化時先畫第一圈就好,加快初始時間
const cycleDataID = 3 // recorded cycle 所在的channel index
const dataCycleList = this.recInfo[this.metaID][cycleDataID][this.currentScale]
const cycleDataList = []
for (let i = 0; i < dataCycleList.length; i++) {
if (dataCycleList[i].data.length === 0) {
const data = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataCycleList[i].id, cycleDataID, this.metaInfo)
cycleDataList.push({ data: data })
} else {
cycleDataList.push({ data: dataCycleList[i].data })
}
}
const cycleDict = this.getCycleDictRec()(cycleDataList)
startTime = cycleDict[1][0] // [1]: 第一圈
endTime = cycleDict[1][1] // [1]: 第一圈
this.$emit('clearCycle')
} else {
startTime = this.startTimeCurrent
endTime = this.endTimeCurrent
}
const dataYList = this.recInfo[this.metaID][this.axisYDataType.id][this.currentScale]
let startIndex = 0
let endIndex = 0
for (let i = 0; i < dataYList.length; i++) {
if (startTime >= parseInt(dataYList[i].start_time) && startTime <= parseInt(dataYList[i].end_time)) {
startIndex = i
}
if (endTime >= parseInt(dataYList[i].start_time) && endTime <= parseInt(dataYList[i].end_time)) {
endIndex = i
}
}
// [EndRegion]
for (let i = startIndex; i <= endIndex; i++) {
const dataY = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataYList[i].id, this.axisYDataType.id, this.metaInfo)
let dataX
if (this.axisXDataType.description !== 'Time') {
const dataXList = this.recInfo[this.metaID][this.axisXDataType.id][this.currentScale]
dataX = await this.getData(parseInt(this.currentScale), this.sampleMethod, dataXList[i].id, this.axisXDataType.id, this.metaInfo)
}
for (let j = 0, len = dataY.length; j < len; j++) {
if (parseInt(dataY[j][0]) >= startTime && parseInt(dataY[j][0]) <= endTime) {
const processedData = dataY[j]
if (this.axisXDataType.description !== 'Time') {
processedData[0] = dataX[j][1]
}
if (this.axisXLabelScale.description === 'Log') {
processedData[0] = Math.log10(Math.abs(processedData[0]))
}
if (this.axisYLabelScale.description === 'Log') {
processedData[1] = Math.log10(Math.abs(processedData[1]))
}
seriesData.push(processedData)
}
}
}
}
}
this.updateSeriesChart({
chartID: this.chartID,
seriesIndex: gridIndex,
data: seriesData,
})
},
reset () {
if (this.axis === 'x') {
this.axisXLabelScale = this.scaleOptions[0] // 0 mean use default unit
this.scaleFormat = this.axisXLabelScale
} else if (this.axis === 'y') {
this.axisYLabelScale = this.scaleOptions[0] // 0 mean use default unit
this.scaleFormat = this.axisYLabelScale
}
},
getData: async function (scale, sampleMethod, id, channel, meta) {
if (scale === 1) {
return await download.rawByIDChannels(id, channel, meta)
} else {
if (sampleMethod === 'mean') {
return await download.miniMeanByIDChannel(id, channel, meta)
} else if (sampleMethod === 'random') {
return await download.miniRandomByIDChannel(id, channel, meta)
}
}
},
...mapMutations('replay', [types.chart.updateSeries]),
...mapGetters('replay', [types.rec.getCycleDict]),
},
mounted () {
},
data () {
return {
scaleFormat: {},
metaID: 0,
metaInfo: null,
scaleFormat: { id: 0, description: 'Linear' },
scaleOptions: [
{
id: 0,
@@ -12,7 +12,6 @@
import { mapMutations } from 'vuex'
import { mapFields } from 'vuex-map-fields'
import types from '@/store/modules/analysis/replay/types'
import { newChartMode } from '@/factories/chart/chartFactory'
export default {
name: 'change-unit',
@@ -53,7 +52,7 @@ export default {
}
} else if (this.deviceName === 'elite') {
// use state meta to decide which default unit need to be used (like check I-V mode...)
const setting = newChartMode(this.metaList[this.metaIndex].parameter_set.MODE)
const setting = this.GLOBAL.getDefaultChartTypeByMode(this.metaList[this.metaIndex].parameter_set.MODE)
const xType = setting[0]
const xValue = setting[1]
const yType = setting[2]
@@ -85,7 +84,7 @@ export default {
this.valueFormatX = this.valueFormatOptions[this.dataType][0]
this.valueFormat = this.valueFormatX
} else if (this.axis === 'y') {
this.valueFormatY = this.valueFormatOptions[this.dataType][0] // 0 mean use default unit (i.e. unitScale = 1)
this.valueFormatY = this.valueFormatOptions[this.dataType][0] // 0 mean use default unit
this.valueFormat = this.valueFormatY
}
this.changeUnit()
@@ -101,19 +100,19 @@ export default {
const keys = Object.keys(this.metaList[this.metaIndex].mini_data)
for (let axisIndex = 0; axisIndex < keys.length; axisIndex++) {
const key = keys[axisIndex]
if (parseInt(key) < 255) { // 256: x, 257: y, 258: z, 259: mag
this.updateAxisLabelChart({
chartID: chartID,
axis: this.axis,
axisIndex: axisIndex,
})
}
this.updateAxisLabelChart({
chartID: chartID,
axis: this.axis,
axisIndex: axisIndex,
channel: parseInt(key),
})
}
} else if (this.deviceName === 'elite') {
this.updateAxisLabelChart({
chartID: chartID,
axis: this.axis,
axisIndex: this.metaIndex,
channel: -1, // any num < 256, cuz channel only use for determining whether add unit text
})
}
this.$emit('refreshChart', this.chartData[chartID])
@@ -152,16 +151,16 @@ export default {
valueFormat: {},
valueFormatOptions: { // below id: 0 mean default
current: [
{
id: 0,
unit: 'nA',
unitScale: 1,
},
{
id: 1,
unit: 'uA',
unitScale: 1000,
},
{
id: 0,
unit: 'nA',
unitScale: 1,
},
{
id: 2,
unit: 'mA',
@@ -169,16 +168,16 @@ export default {
},
],
voltage: [ // Voltage
{
id: 0,
unit: 'uV',
unitScale: 1,
},
{
id: 1,
unit: 'mV',
unitScale: 1000,
},
{
id: 0,
unit: 'uV',
unitScale: 1,
},
{
id: 2,
unit: 'V',
@@ -186,16 +185,16 @@ export default {
},
],
resistance: [ // Resistance
{
id: 0,
unit: 'mΩ',
unitScale: 1,
},
{
id: 1,
unit: 'Ω',
unitScale: 1000,
},
{
id: 0,
unit: 'mΩ',
unitScale: 1,
},
{
id: 2,
unit: 'kΩ',
@@ -71,20 +71,8 @@ export default {
deleteFile: async function () {
for (let i = 0; i < this.deleteInfoList.length; i++) {
const deleteInfo = this.deleteInfoList[i]
for (const item of deleteInfo.rawChannelAndIDArrays) {
const channel = item[0]
const id = item[1]
await api.updateRawFile(channel, id, { deleted: true })
await api.clearDeleteRawFile(channel, id)
}
for (const item of deleteInfo.miniChannelAndIDArrays) {
const channel = item[0]
const id = item[1]
await api.updateMiniFile(channel, id, { deleted: true })
await api.clearDeleteMiniFile(channel, id)
}
await api.updateMetaFile(deleteInfo.metaID, { deleted: true })
await api.clearDeleteMetaFile(deleteInfo.metaID)
await api.meta.update(deleteInfo.metaID, { deleted: true })
await api.meta.clearDel()
}
await this.deleteFileDone()
},
@@ -32,7 +32,11 @@ export default {
downloadCSV: async function () {
for (let i = 0; i < this.metaList.length; i++) {
const meta = this.metaList[i]
window.open('http://' + location.href.split('/')[2].split(':')[0] + '/#/admin/download/neulive/csv/' + meta.id, '_blank', 'width=500,height=100,left=200,top=200')
if (meta.device.library_name.indexOf('Elite') >= 0) {
window.open('http://' + location.href.split('/')[2].split(':')[0] + '/#/download/excel/' + meta.id)
} else if (meta.device.library_name.indexOf('Neulive') >= 0) {
window.open('http://' + location.href.split('/')[2].split(':')[0] + '/#/download/csv/' + meta.id)
}
}
},
},
@@ -80,7 +80,7 @@ export default {
// [TODO] 0: not sure future UX design
const meta = this.metaList[0]
file.clearFileList()
const files = await api.getFolderMetaFileByParent('folder', meta.parent.folder[0])
const files = await api.meta.getByParent('folder', meta.parent.folder[0])
file.updateFileList(files)
const tmpFiles = file.getFileList()
for (let i = 0; i < tmpFiles.length; i++) {
@@ -90,7 +90,7 @@ export default {
},
editFile: async function () {
if (this.editInfo.success === true) {
await api.updateMetaFile(this.editInfo.info.id, { name: this.editInfo.changedName })
await api.meta.update(this.editInfo.info.id, { name: this.editInfo.changedName })
this.editInfo.name = this.editInfo.changedName
this.filename = this.editInfo.changedName
}
@@ -49,34 +49,54 @@ export default {
neuliveSampleRateOptions: [
{
id: 0,
value: 800,
value: 1000,
description: '1k',
},
{
id: 1,
value: 400,
value: 2000,
description: '2k',
},
{
id: 2,
value: 200,
value: 4000,
description: '4k',
},
{
id: 3,
value: 160,
value: 5000,
description: '5k',
},
{
id: 4,
value: 100,
value: 8000,
description: '8k',
},
{
id: 5,
value: 80,
value: 10000,
description: '10k',
},
{
id: 6,
value: 20000,
description: '20k',
},
{
id: 7,
value: 40000,
description: '40k',
},
{
id: 8,
value: 80000,
description: '80k',
},
{
id: 9,
value: 100000,
description: '100k',
},
],
stimulateElectrodeOptions: [
{
@@ -283,7 +303,7 @@ export default {
if (!(key.includes('sti') || key.includes('STI'))) {
let showKey = ''
let showValue = value
if (key === 'RECORDING_CH' || key === 'AXIS_CH' || key === 'AMP_GAIN' || key === 'ADC_CLOCK') {
if (key === 'RECORDING_CH' || key === 'AXIS_CH' || key === 'AMP_GAIN' || key === 'SAMPLE_RATE') {
if (key === 'RECORDING_CH') {
showKey = 'Channels'
// convert decimal to binary
@@ -328,7 +348,7 @@ export default {
showValue = this.ampGainOptions[i].description
}
}
} else if (key === 'ADC_CLOCK') {
} else if (key === 'SAMPLE_RATE') {
showKey = 'Sample Rate'
for (let i = 0; i < this.neuliveSampleRateOptions.length; i++) {
if (this.neuliveSampleRateOptions[i].value === value) {
@@ -0,0 +1,96 @@
<template>
<div>
<va-card>
<p style="font-size: 125%; text-decoration: underline;"> Channel </p>
<channels/>
<p style="font-size: 125%; text-decoration: underline;"> Detect </p>
<p :style="{color: this.$themes.primary}" class="display-6"> High pass filter </p>
<cutoff-freq/>
<filter-order/>
<p :style="{color: this.$themes.danger}" class="display-6"> Threshold </p>
<threshold/>
<br/>
<p class="display-6"> Waveform </p>
<wave-length/>
<prethreshold/>
<refractory-period/>
<detect-button @loadChartData="loadChartData"/>
</va-card>
</div>
</template>
<script>
import Channels from '@/components/analysis/spike/item/Channels.vue'
import CutoffFreq from '@/components/analysis/spike/item/CutoffFreq.vue'
import FilterOrder from '@/components/analysis/spike/item/FilterOrder.vue'
import Prethreshold from '@/components/analysis/spike/item/Prethreshold.vue'
import RefractoryPeriod from '@/components/analysis/spike/item/RefractoryPeriod.vue'
import Threshold from '@/components/analysis/spike/item/Threshold.vue'
import WaveLength from '@/components/analysis/spike/item/WaveLength.vue'
import DetectButton from '@/components/analysis/spike/item/DetectButton.vue'
export default {
name: 'control-panel',
components: {
Channels,
CutoffFreq,
FilterOrder,
Prethreshold,
RefractoryPeriod,
Threshold,
WaveLength,
DetectButton,
},
props: {
},
async created () {
},
data () {
return {
}
},
mqtt: {
},
methods: {
init () {
},
refreshChart (options) {
this.$emit('refreshChart', options)
},
loadChartData () {
this.$emit('loadChartData')
},
},
// use watch because va-select with @change will have bug
watch: {
},
mounted () {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
.right {
float: right;
}
</style>
+354
View File
@@ -0,0 +1,354 @@
<template>
<div>
<div class="row row-equal">
<div class="flex md12 xl3 xs12 sm12">
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-accordion>
<va-collapse class="mb-2" :isOpenDefault="true">
<span slot="header">Control Panel</span>
<div slot="body">
<div>
<control-panel :ref="'control_panel'" @loadChartData="drawSpikeData"/>
</div>
</div>
</va-collapse>
</va-accordion>
</div>
</div>
</div>
<div :class="chartAreaClass">
<div class="row" >
<div class="flex sm12 xl12 md12 xs12">
<spike-overview-chart :ref="'chart_overview'" :cardheight="'30vh'" :data="chartOverviewData"/>
<spike-chart :ref="'chart_detail'" :cardheight="'60vh'" :data="chartDetailData"/>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters, mapMutations } from 'vuex'
import SpikeOverviewChart from './SpikeOverviewChart.vue'
import SpikeChart from './SpikeChart.vue'
import ControlPanel from './ControlPanel.vue'
import api from '@/data/api/index'
import types from '@/store/modules/analysis/spike/types'
import { mapFields } from 'vuex-map-fields'
import newSeries from '@/factories/chart/seriesFactory'
export default {
name: 'spike-data-replay',
components: {
SpikeOverviewChart,
SpikeChart,
ControlPanel,
},
computed: {
...mapFields('spike', [
'chartData',
'chartOverviewData',
'chartDetailData',
'metaList',
'selectedChannel',
'cutoffFreq',
'selectedThreshold',
'upperThreshold',
'lowerThreshold',
'waveLength',
'preThreshold',
'refractoryPeriod',
]),
},
props: {
},
async created () {
this.chartOverviewData = await this.initChart({
chartAllData: this.chartData,
chartID: 0,
gridLength: 1,
type: 'overview',
device: 'neulive',
mode: 0,
})
this.chartDetailData = await this.initChart({
chartAllData: this.chartData,
chartID: 1,
gridLength: 1,
type: 'detail',
device: 'neulive',
mode: 0,
})
},
data () {
return {
dataInfo: {},
maxTime: 0,
chartAreaClass: ['flex', 'xs12', 'sm12', 'md12', 'xl9', 'pa-0'],
}
},
mqtt: {
},
methods: {
showChartLoading: function (chart) {
const loadStyle = {
text: '',
color: '#cccccc',
maskColor: 'rgba(255, 255, 255, 0.8)',
zlevel: 0,
}
switch (chart) {
case 'overview':
this.$refs.chart_overview.showLoading(loadStyle)
break
case 'detail':
this.$refs.chart_detail.showLoading(loadStyle)
break
default:
this.$refs.chart_overview.showLoading(loadStyle)
this.$refs.chart_detail.showLoading(loadStyle)
break
}
},
hideChartLoading: function (chart) {
switch (chart) {
case 'overview':
this.$refs.chart_overview.hideLoading()
break
case 'detail':
this.$refs.chart_detail.hideLoading()
break
default:
this.$refs.chart_overview.hideLoading()
this.$refs.chart_detail.hideLoading()
break
}
},
register: async function () {
const gridLength = 1
this.updateGridListChart({
chartAllData: this.chartData,
chartID: this.chartDetailData.chartID,
gridLength: gridLength,
})
const register = this.metaList.map(meta => {
this.registerChart({
chartAllData: this.chartData,
chartID: this.chartOverviewData.chartID,
gridIndex: 0,
deviceNameX: 'Time',
deviceNameY: 'Neulive',
deviceIDY: meta.name,
channelY: this.selectedChannel,
})
this.registerChart({
chartAllData: this.chartData,
chartID: this.chartDetailData.chartID,
gridIndex: 0,
deviceNameX: 'Time',
deviceNameY: 'Neulive',
deviceIDY: meta.name,
channelY: this.selectedChannel,
})
if (this.maxTime < parseInt(meta.time_duration)) {
this.maxTime = parseInt(meta.time_duration)
}
})
await Promise.all(register)
for (let i = 0; i < 2; i++) {
// ID 0 = overview, ID 1 = detail
this.updateAxisLabelChart({
chartID: i,
axis: 'x',
axisIndex: 0,
channel: this.selectedChannel,
})
this.updateAxisLabelChart({
chartID: i,
axis: 'y',
axisIndex: 0,
channel: this.selectedChannel,
})
this.updateDataZoomChart({
chartAllData: this.chartData,
chartID: i,
})
}
this.updateChartSamplingChart({ chartID: this.chartOverviewData.chartID, seriesIndex: 0, method: function (frame) { return frame[0] } })
this.chartOverviewData.xAxis[0].min = 0
this.chartOverviewData.xAxis[0].max = this.maxTime
},
drawSpikeData: async function () {
this.showChartLoading('overview')
this.showChartLoading('detail')
for (const meta in this.dataInfo) {
let metaInfo
this.metaList.forEach(_meta => {
if (parseInt(_meta.id) === parseInt(meta)) {
metaInfo = _meta
}
})
const sampleRate = metaInfo.parameter_set.SAMPLE_RATE / JSON.parse(metaInfo.channels).length // Hz
const period = 1e6 / sampleRate
let thresholdValue
if (this.selectedThreshold === 'over') {
thresholdValue = this.upperThreshold
} else if (this.selectedThreshold === 'bellow') {
thresholdValue = this.lowerThreshold
}
const randomColorArray = []
// [Region] whole processed signal
const allSpikeData = await api.analysis.spikeDetect({
id: meta,
channel: this.selectedChannel,
cut_off_freq: this.cutoffFreq,
threshold: [
`'${this.selectedThreshold}'`,
thresholdValue,
],
waveForm: [this.waveLength, this.preThreshold, this.refractoryPeriod],
ret_data_type: 'all',
})
this.chartOverviewData.series[0].data.length = 0
this.chartOverviewData.color = ['#000000'] // black
const splitData = allSpikeData.data.split('\n')
const allTimeArray = splitData[0].split(' ')
const allTimeArrayLength = allTimeArray.length
const allSignalArray = splitData[1].split(' ')
const allTimeMarkIndexArray = splitData[2].split(' ')
for (let i = 0; i < allTimeArrayLength; i++) {
this.chartOverviewData.series[0].data.push([parseInt(allTimeArray[i]), allSignalArray[i]])
}
this.chartOverviewData.xAxis[0].min = parseInt(allTimeArray[0])
this.chartOverviewData.xAxis[0].max = parseInt(allTimeArray[allTimeArrayLength - 1])
this.chartOverviewData.xAxis[0].axisLabel.show = true
this.chartOverviewData.series[0].markArea.data.length = 0
for (let i = 0; i < allTimeMarkIndexArray.length; i++) {
// generate color array for overview markArea and detail chart series
const randomColor = '#' + Math.floor(Math.random() * 16777215).toString(16) // ref: https://css-tricks.com/snippets/javascript/random-hex-color/
randomColorArray.push(randomColor)
if (Number.isInteger(parseInt(allTimeMarkIndexArray[i]))) { // cuz maybe is '' if no any match after filtering
const timeMarkIndex = parseInt(allTimeMarkIndexArray[i])
const start = parseInt(this.chartOverviewData.series[0].data[timeMarkIndex - parseInt(this.preThreshold / period)][0])
const end = parseInt(this.chartOverviewData.series[0].data[timeMarkIndex + parseInt(this.refractoryPeriod / period)][0])
this.chartOverviewData.series[0].markArea.data.push([
{
itemStyle: {
color: randomColor,
},
name: String(i + 1),
xAxis: start,
},
{
xAxis: end,
},
])
}
}
// [EndRegion]
// [Region] each detailed signal piece
const spikeData = await api.analysis.spikeDetect({
id: meta,
channel: this.selectedChannel,
cut_off_freq: this.cutoffFreq,
threshold: [
`'${this.selectedThreshold}'`,
thresholdValue,
],
waveForm: [this.waveLength, this.preThreshold, this.refractoryPeriod],
ret_data_type: 'partial',
})
for (let i = 0; i < this.chartDetailData.series.length; i++) {
this.chartDetailData.series[i].name = ''
this.chartDetailData.series[i].data.length = 0
}
const detailSignalArray = Object.values(spikeData.data)
if (detailSignalArray.length <= 8) {
this.chartDetailData.tooltip.show = true
} else {
this.chartDetailData.tooltip.show = false
}
this.chartDetailData.legend.data.length = 0
this.chartDetailData.legend.type = 'scroll'
this.chartDetailData.legend.top = '0.25%'
// this.chartDetailData.legendpageButtonPosition = 'start'
this.chartDetailData.animation = false
this.chartDetailData.color = []
for (let i = 0; i < detailSignalArray.length; i++) {
const detailSignal = detailSignalArray[i].split(' ')
const arrayLength = detailSignal.length
const step = parseInt(this.waveLength) / (arrayLength - 1)
const xAxisIndex = 0
const yAxisIndex = 0
const legendName = 'T_' + String(i + 1)
if (this.chartDetailData.series.length <= i) {
const _series = newSeries('line', legendName, xAxisIndex, yAxisIndex, [-1, -1], [metaInfo.name, this.selectedChannel], null, null)
this.chartDetailData.series.push(_series)
}
for (let j = 0; j < arrayLength; j++) {
this.chartDetailData.series[i].data.push([j * step, detailSignal[j]])
}
// push legendName
this.chartDetailData.legend.data.push(legendName)
this.chartDetailData.series[i].name = legendName
// set legend and series color
this.chartDetailData.color.push(randomColorArray[i])
}
this.chartDetailData.xAxis[0].min = 0
this.chartDetailData.xAxis[0].max = parseInt(this.waveLength)
this.chartDetailData.xAxis[0].axisLabel.show = true
// [EndRegion]
}
this.hideChartLoading()
console.log(this.chartOverviewData)
console.log(this.chartDetailData)
},
...mapActions('spike', [types.chart.init, types.chart.initSelectedChannel, types.chart.register, types.chart.clear, types.chart.updateGridList, types.chart.updateDataZoom]),
...mapActions('spike', [types.meta.init]),
...mapActions('spike', [types.rec.init, types.rec.intoData, types.rec.initDisplaySetting, types.rec.updateDisplaySetting]),
...mapMutations('spike', [types.chart.updateAxisLabel, types.chart.updateChartSampling]),
...mapMutations('spike', [types.meta.updateByIndex]),
...mapGetters('spike', [types.meta.getAll]),
...mapGetters('spike', [types.rec.getAll]),
},
// use watch because va-select with @change will have bug
watch: {
},
async mounted () {
const metaIDList = this.$route.params.metaList.split('-')
await this.initMeta({ metaIDList: metaIDList, api: api })
this.metaList = this.getAllMeta()
this.initSelectedChannelChart({ metaIndex: 0 })
await this.initRec({ api: api })
this.dataInfo = this.getAllRec()
console.log(this.metaList)
console.log(this.dataInfo)
await this.register()
this.$refs.control_panel.init()
},
beforeDestroy () {
this.$refs.chart_detail.clear()
for (const id in this.chartData) {
for (const _series of this.chartData[id].series) {
_series.length = 0
}
delete this.chartData[id]
}
this.clearChart({ chartAllData: this.chartData })
},
}
</script>
@@ -0,0 +1,110 @@
<template>
<div class="flex" :class="cardclass">
<va-card :style="'height: ' + cardheight + ';'">
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="data" @dataZoom="updateZoom" :auto-resize="true"></chart>
</va-card>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
import types from '@/store/modules/analysis/spike/types'
// import { chartData } from '../../../../data/task/ChartsManagement'
export default {
name: 'spike-replay-chart',
components: {
},
props: {
data: {
type: Object,
default: function () {
return {}
},
},
cardclass: {
type: Array,
default: function () {
return ['xs12', 'md12', 'xl12', 'sm12']
},
},
cardheight: {
type: String,
default: '82vh',
},
cardwidth: {
type: String,
default: 'auto',
},
},
created () {
},
data () {
return {
}
},
computed: {
},
watch: {
},
methods: {
resize: function () {
if (this.$refs.chart_ref != null) {
this.$refs.chart_ref.resize()
}
},
updateZoom: function (e) {
this.$emit('dataZoomEvent', e)
},
mergeOptions (options) {
this.$refs.chart_ref.mergeOptions(options)
},
turnOnAxisEventHandler (eventName, query, handler, attr) {
const chartID = 1
this.updateAxisEventHandlerChart({
chartID: chartID,
axis: attr.axis,
status: 'on',
})
// doc: https://echarts.apache.org/zh/api.html#echartsInstance.on
this.$refs.chart_ref.chart._zr.on(eventName, query, handler)
},
turnOffAxisEventHandler (eventName, handler, attr) {
const chartID = 1
this.updateAxisEventHandlerChart({
chartID: chartID,
axis: attr.axis,
status: 'off',
})
// doc: https://echarts.apache.org/zh/api.html#echartsInstance.off
this.$refs.chart_ref.chart._zr.off(eventName, handler)
},
showLoading (options) {
this.$refs.chart_ref.showLoading(options)
},
hideLoading () {
this.$refs.chart_ref.hideLoading()
},
clear () {
this.$refs.chart_ref.clear()
},
...mapMutations('spike', [types.chart.updateAxisEventHandler]),
},
async mounted () {
this.resizeTimer = setInterval(this.resize, 1000)
},
destroyed () {
clearInterval(this.resizeTimer)
},
}
</script>
<style lang='scss'>
.va-card {
&__body {
padding-top: 0.25rem;
}
}
</style>
@@ -0,0 +1,86 @@
<template>
<div class="flex" :class="cardclass">
<va-card :style="'height: ' + cardheight + ';'">
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="data" @dataZoom="updateZoom" :auto-resize="true"></chart>
</va-card>
</div>
</template>
<script>
// import { chartData } from '../../../../data/task/ChartsManagement'
export default {
name: 'spike-overview-chart',
components: {
},
props: {
data: {
type: Object,
default: function () {
return {}
},
},
cardclass: {
type: Array,
default: function () {
return ['xs12', 'md12', 'xl12', 'sm12']
},
},
cardheight: {
type: String,
default: '82vh',
},
cardwidth: {
type: String,
default: 'auto',
},
},
created () {
},
data () {
return {
}
},
computed: {
},
watch: {
},
methods: {
resize: function () {
if (this.$refs.chart_ref != null) {
this.$refs.chart_ref.resize()
}
},
mergeOptions (options) {
this.$refs.chart_ref.mergeOptions(options)
},
updateZoom: function (e) {
this.$emit('dataZoomEvent', e)
},
showLoading (options) {
this.$refs.chart_ref.showLoading(options)
},
hideLoading () {
this.$refs.chart_ref.hideLoading()
},
clear () {
this.$refs.chart_ref.clear()
},
},
async mounted () {
this.resizeTimer = setInterval(this.resize, 1000)
},
destroyed () {
clearInterval(this.resizeTimer)
},
}
</script>
<style lang='scss'>
.va-card {
&__body {
padding-top: 0.25rem;
}
}
</style>
@@ -0,0 +1,43 @@
<template>
<div>
<va-button-toggle small flat v-model="selectedChannel" :options="selectedChannelOptions" @click.native="reloadData(selectedChannel)"/>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'Channels',
components: {
},
computed: {
...mapFields('spike', [
'selectedChannel',
'selectedChannelOptions',
]),
},
props: {
},
created () {
},
data () {
return {
}
},
mqtt: {
},
methods: {
reloadData (val) {
this.selectedChannel = val
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,57 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
<p>Cut-off Freq<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
<va-input
@mouseleave.native="itemChange(cutoffFreq)"
@keyup.enter="itemChange(cutoffFreq)"
@blur="itemChange(cutoffFreq)"
v-model="cutoffFreq"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
Hz
</p>
</va-input>
</div>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'CutoffFreq',
components: {
},
computed: {
...mapFields('spike', [
'cutoffFreq',
]),
},
props: {
},
created () {
},
data () {
return {
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.cutoffFreq = val
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,49 @@
<template>
<div>
<va-button class="right" small @click="startDetect">
Start Detect
</va-button>
</div>
</template>
<script>
import types from '@/store/modules/analysis/spike/types'
import { mapFields } from 'vuex-map-fields'
import { mapMutations } from 'vuex'
export default {
name: 'Channels',
components: {
},
computed: {
...mapFields('spike', [
'chartDetailData',
'selectedChannel',
'waveLength',
]),
},
props: {
},
created () {
},
data () {
return {
}
},
mqtt: {
},
methods: {
startDetect () {
this.$emit('loadChartData')
},
...mapMutations('spike', [types.chart.updateAxisLabel]),
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,54 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
<p>Filter order<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
<va-input
@mouseleave.native="itemChange(filterOrder)"
@keyup.enter="itemChange(filterOrder)"
@blur="itemChange(filterOrder)"
v-model="filterOrder"
class="mb-0"
>
</va-input>
</div>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'FilterOrder',
components: {
},
computed: {
...mapFields('spike', [
'filterOrder',
]),
},
props: {
},
created () {
},
data () {
return {
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.filterOrder = val
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,57 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
<p>Prethreshold<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
<va-input
@mouseleave.native="itemChange(preThreshold)"
@keyup.enter="itemChange(preThreshold)"
@blur="itemChange(preThreshold)"
v-model="preThreshold"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
µs
</p>
</va-input>
</div>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'Prethreshold',
components: {
},
computed: {
...mapFields('spike', [
'preThreshold',
]),
},
props: {
},
created () {
},
data () {
return {
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.preThreshold = val
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,57 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm7 xl7 md7 xs7 px-0 mx-0">
<p>Refractory period<p/>
</div>
<div class="flex sm5 xl5 md5 xs5 px-0 mx-0">
<va-input
@mouseleave.native="itemChange(refractoryPeriod)"
@keyup.enter="itemChange(refractoryPeriod)"
@blur="itemChange(refractoryPeriod)"
v-model="refractoryPeriod"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
µs
</p>
</va-input>
</div>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'RefractoryPeriod',
components: {
},
computed: {
...mapFields('spike', [
'refractoryPeriod',
]),
},
props: {
},
created () {
},
data () {
return {
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.refractoryPeriod = val
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,83 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<va-radio-button
v-for="(option, index) in options"
:key="index"
v-model="selectedThreshold"
:option="option"
:label="`${option}`"
/>
<va-input
v-if="selectedThreshold === 'over'"
@mouseleave.native="itemChange(upperThreshold, 'upper')"
@keyup.enter="itemChange(upperThreshold, 'upper')"
@blur="itemChange(upperThreshold, 'upper')"
v-model="upperThreshold"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
µV
</p>
</va-input>
<va-input
v-if="selectedThreshold === 'bellow'"
@mouseleave.native="itemChange(lowerThreshold, 'lower')"
@keyup.enter="itemChange(lowerThreshold, 'lower')"
@blur="itemChange(lowerThreshold, 'lower')"
v-model="lowerThreshold"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
µV
</p>
</va-input>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'Threshold',
components: {
},
computed: {
...mapFields('spike', [
'selectedThreshold',
'upperThreshold',
'lowerThreshold',
]),
},
props: {
},
created () {
},
data () {
return {
options: [
// 'Auto',
'over',
'bellow',
],
}
},
mqtt: {
},
methods: {
itemChange (val, type) {
if (type === 'upper') {
this.upperThreshold = val
} else if (type === 'lower') {
this.lowerThreshold = val
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,57 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm7 xl7 md7 xs7 px-0 mx-0">
<p>Waveform length<p/>
</div>
<div class="flex sm5 xl5 md5 xs5 px-0 mx-0">
<va-input
@mouseleave.native="itemChange(waveLength)"
@keyup.enter="itemChange(waveLength)"
@blur="itemChange(waveLength)"
v-model="waveLength"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
µs
</p>
</va-input>
</div>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'WaveLength',
components: {
},
computed: {
...mapFields('spike', [
'waveLength',
]),
},
props: {
},
created () {
},
data () {
return {
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.waveLength = val
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,37 @@
<template>
<div>
<span> Resample: {{ currentScale }} to 1 </span>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'show-resample-rate',
components: {
},
props: {
},
created () {
},
data () {
return {
}
},
computed: {
...mapFields('spike', [
'currentScale',
]),
},
watch: {
},
methods: {
},
mounted () {
},
destroyed () {
},
}
</script>
+19 -8
View File
@@ -208,16 +208,27 @@ export default {
})
// console.log(this.controllerList)
},
'+/hardware_info/+' (data, topic) {
async '+/hardware_info/+' (data, topic) {
const topicSplit = topic.split('/')
const rawDevices = JSON.parse(String.fromCharCode.apply(null, data)).data
this.controllerList.forEach(controller => {
for (let i = 0; i < this.controllerList.length; i++) {
const controller = this.controllerList[i]
if (controller.id === topicSplit[0]) {
if (rawDevices.device_mac !== null) {
controller.mac = rawDevices.device_mac.toUpperCase()
// const info = await api.controller.getByMac(controller.mac)
// if (info.data.length === 0) {
// const req = {
// mac_address: controller.mac,
// mqtt_id: controller.id,
// status: controller.status,
// }
// api.controller.create(req)
// }
// console.log(info)
}
}
})
}
// console.log(this.controllerList)
},
'+/hardware_device_connect/+' (data, topic) {
@@ -471,9 +482,9 @@ export default {
}
},
createInitialCollection: async function (user) {
const root = await api.getCollectionsByParentName('folder', 0, 'root')
const root = await api.collection.getByParentName('folder', 0, 'root')
if (root.data.length === 0) {
await api.createCollection({
await api.collection.create({
name: 'root',
type: 'folder',
parent: { folder: [0] },
@@ -482,10 +493,10 @@ export default {
}
// init check and create collection
const _root = await api.getCollectionsByName('root')
const USER = await api.getCollectionsByName(user)
const _root = await api.collection.getByName('root')
const USER = await api.collection.getByName(user)
if (USER.data.length === 0) {
api.createCollection({
api.collection.create({
name: user,
parent: { folder: [_root.data[0].id] },
type: 'folder',
+140 -539
View File
@@ -1,143 +1,26 @@
<template>
<div>
<va-modal
class="flex sm12 xl12 md12 xs12 pa-0 ma-0"
v-model="showDownload"
size="small"
:hideDefaultActions="true"
:mobileFullscreen="false"
>
<template slot="header">
<div class="row mb-2">
<va-icon name="fa fa-download mr-3 " color="primary"/>
<h5 class="mt-0 mb-0">{{'Download'}}</h5>
</div>
</template>
<div class="downloadOptionsList">
<template v-for="(downloadOptions, i) in downloadOptionsList">
<va-accordion :key="downloadOptions.filename">
<va-collapse>
<va-item :key="downloadOptions.filename" slot="header" clickable>
<va-item-section avatar>
<va-item-label>
{{ downloadOptions.filename }}
</va-item-label>
</va-item-section>
<va-item-section>
<!-- <va-item-label>
{{ downloadInfo.minTime }}
</va-item-label>
<va-item-label caption>
{{ downloadInfo.maxTime }}
</va-item-label> -->
</va-item-section>
<va-item-section v-if="downloadOptions.download.status == 'idle'" side>
<va-icon name="fa fa-play" color="gray" @click.native.stop="confirmDownload(downloadOptions.metaPath)"/>
</va-item-section>
<va-item-section v-else side class="md4 offset--md8">
<div class="row flex sm12 xl12 md12 xs12">
<div class="flex-center spinner-box">
<fulfilling-bouncing-circle-spinner
:animation-duration="3000"
:color="'#6c7fee'"
:size="20"
>
</fulfilling-bouncing-circle-spinner>
<span class="ml-3">{{loaded}}</span>
</div>
</div>
</va-item-section>
</va-item>
<div slot="body">
<div v-if="downloadOptions.download.status == 'downloading'" class="row flex sm12 xl12 md12 xs12">
<div class="row flex sm12 xl12 md12 xs12">
<div class="flex-center spinner-box mt-4 mb-5">
<fulfilling-bouncing-circle-spinner
:animation-duration="3000"
:color="'#6c7fee'"
:size="60"
>
</fulfilling-bouncing-circle-spinner>
</div>
</div>
</div>
<div v-else>
<div class="mb-5">
<va-item class="flex sm12 xl12 md12 xs12 mr-1 pa-0">
<va-icon
class="flex sm1 xl1 md1 xs1 start "
name="glyphicon glyphicon-filter"
size="1.0rem"
:fixedWidth = "Boolean('true')"
/>
<div class="flex sm11 xl11 md11 xs11 row">
<div v-for="(item,index) in downloadOptions.channel" :key="item.channel" class="filter-button">
<va-button
class="mx-1 px-1"
v-if="item.checked"
@click="channelUnchecked(index,downloadOptions.metaPath)"
small
>
{{item.alias}}
</va-button>
<va-button
class="mx-1 px-1"
v-else
@click="channelChecked(index,downloadOptions.metaPath)"
small outline
>
{{item.alias}}
</va-button>
</div>
</div>
</va-item>
</div>
<div class="mb-5">
<va-item class="flex sm12 xl12 md12 xs12 pa-0">
<va-icon
class="flex sm1 xl1 md1 xs1 mr-4"
:fixedWidth="true"
name="va-icon glyphicon glyphicon-time"
size="1.0rem"
/>
<div class="flex">
<va-slider
class="flex sm11 xl11 md11 xs11 filter-button"
value-visible
range
v-model="downloadOptions.timeRange"
@click.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
@mouseup.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
@mouseleave.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
@touchend.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
:min="downloadOptions.minTime"
:max="downloadOptions.maxTime"
/>
<span> {{ transTime(downloadOptions.timeRange) }} </span>
</div>
</va-item>
</div>
</div>
</div>
</va-collapse>
</va-accordion>
<va-list-separator v-if="i < downloadOptionsList.length - 1" :key="'separator' + downloadOptions.filename" />
</template>
<div class="row flex sm12 xl12 md12 xs12" style="height: 100vh;">
<div class="flex-center spinner-box mt-4 mb-5">
<fulfilling-bouncing-circle-spinner
:animation-duration="3000"
:color="'#6c7fee'"
:size="60"
>
</fulfilling-bouncing-circle-spinner>
</div>
</va-modal>
</div>
</div>
</template>
<script>
import { file } from '../../data/file/File'
import { download } from '../../data/download/Download'
import { exportData } from '../../data/export/export'
import api from '@/data/api/index'
import types from '@/store/modules/download/types'
import { mapActions, mapMutations } from 'vuex'
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
import { mapFields } from 'vuex-map-fields'
import newDownload from '@/factories/file/downloadFactory'
import newChannel from '@/factories/file/channelFactory'
export default {
name: 'Download',
@@ -146,387 +29,17 @@ export default {
},
data: () => {
return {
showDownload: false,
controllerList: [],
downloadList: [],
downloadListRecord: [],
downloadOptionsList: [],
// downloadInfo: {
// metaPath: '',
// previousPath: '',
// filenameWithType: '',
// filename: '',
// channel: [],
// timeRange: [0, 0],
// minTime: 0,
// maxTime: 0,
// status: 'idle',
// device: '',
// },
currentlyDownloadInfo: {
metaPath: '',
previousPath: '',
filenameWithType: '',
filename: '',
channel: [],
timeRange: [0, 0],
minTime: 0,
maxTime: 0,
download: {
status: 'idle',
rate: 0,
},
device: '',
},
estimatedTime: 0,
fileSegmentIndex: 0,
fileSegmentMax: 0,
totoalFileSize: 0,
loadingPercent: 0,
loadTime: 0,
interval: null,
data: '',
}
},
computed: {
// transTime (min,max) {
// return this.getTimeInFormat(min) + ' - ' + this.getTimeInFormat(max)
// },
loaded () {
return this.loadingPercent + '%'
},
...mapFields('download', [
'metaList',
'downloadInfo',
'metaInfo',
]),
},
// mqtt: {
// async '+/file_segment/+' (data, topic) {
// console.log('file_segment')
// console.log(String.fromCharCode.apply(null, data))
// // console.log(navigator.connection.downlink)
// // console.log(this.fileNum)
// // console.log(this.downloadOptionsList.length)
// // console.log(JSON.parse(String.fromCharCode.apply(null, data)).data.file_size)
// if (this.downloadOptionsList.length > 0) {
// await download.updateFileSegmentInfo(String.fromCharCode.apply(null, data))
// this.fileSegmentMax = download.getFileSegmentMaxIndex()
// this.checkFileSegmentGetOrNot()
// }
// },
// async '+/file_segment_get/+' (data, topic) {
// console.log('file_segment_get')
// console.log(JSON.parse(new TextDecoder('utf-8').decode(data)))
// if (this.downloadOptionsList.length > 0) {
// const segmentData = atob(JSON.parse(new TextDecoder('utf-8').decode(data)).data.segment)
// this.data += segmentData
// this.fileSegmentIndex += 1
// this.checkFileSegmentGetOrNot()
// }
// },
// },
methods: {
transTime (timeRange) {
return this.getTimeInFormat(timeRange[0]) + ' - ' + this.getTimeInFormat(timeRange[1])
},
notify (name) {
this.showToast(`done ${name}`, {
position: 'bottom-right',
})
},
showDownloadModal: function () {
this.showDownload = true
},
channelChecked: function (channelIndex, path) {
download.getDownloadOptions(path).channel[channelIndex].checked = true
this.refresh()
},
channelUnchecked: function (channelIndex, path) {
download.getDownloadOptions(path).channel[channelIndex].checked = false
this.refresh()
},
getTimeInFormat: function (time) {
if (time < 60) {
const second = time
return `${second}s`
} else if (time < 3600) {
const second = time % 60
const minute = parseInt(time / 60)
return `${minute}m${second}s`
} else {
const hour = parseInt(time / 3600)
const hourRemain = time % 3600
const minute = parseInt(hourRemain / 60)
const second = hourRemain % 60
return `${hour}h${minute}m${second}s`
}
},
getCurrentFullPathName: function () {
return this.currentlyDownloadInfo.previousPath + '/' + this.currentlyDownloadInfo.filenameWithType
},
downloading: async function (info) {
this.$emit('download')
},
addDownloadTask: async function (info) {
this.downloading()
/*
** download all
*/
if (parseInt(info.time_duration) < 18e8) {
const rawData = await download.getAllRawDatas(info)
exportData.exportCSV(info, rawData)
} else {
for (const channelID in info.raw_data) {
const rawDataIDList = info.raw_data[channelID]
while (rawDataIDList.length > 1000) {
const _list = rawDataIDList.splice(0, 1000)
const rawData = await download.getIndexRawDatas(info, channelID, _list)
exportData.exportCSV(info, rawData)
}
const rawData = await download.getIndexRawDatas(info, channelID, rawDataIDList)
exportData.exportCSV(info, rawData, channelID)
rawData[channelID].length = 0
// const rawData = await download.getAllRawDatas(info)
// console.timeEnd('download')
}
}
// console.time('download')
// const rawData = await download.getAllRawDatas(info)
// console.timeEnd('download')
// exportData.exportCSV(info, rawData)
/*
** download split
*/
this.downloading()
},
_addDownloadTask: function (downloadPath) {
if (Array.isArray(downloadPath)) {
downloadPath.forEach(path => {
this.downloadList.push(path.path)
this.updateDownloadInfo(path.path)
})
} else {
this.downloadList.push(downloadPath)
this.updateDownloadInfo(downloadPath)
}
this.confirmDownload()
},
refresh: function () {
this.downloadOptionsList = download.getDownloadOptionsList()
console.log(this.downloadOptionsList)
},
confirmDownload: function (path) {
console.log('confirmDownload')
console.log(download.getDownloadOptionsList())
console.log(download.isFileDownloading())
console.log(download.downloadTaskRemain())
if (!download.isFileDownloading() && download.downloadTaskRemain()) {
const downloadOptionsIndex = download.getDownloadOptionsList().findIndex(downloadInfo => downloadInfo.metaPath === path)
// this.downloadBlockList[downloadInfoIndex].status = 'downloading'
this.currentlyDownloadInfo = download.getDownloadOptionsList()[downloadOptionsIndex]
this.currentlyDownloadInfo.download.status = 'downloading'
console.log(this.currentlyDownloadInfo)
console.log(download.getDownloadOptionsList())
download.updateDownloadSubFileList(
this.currentlyDownloadInfo.metaPath,
this.currentlyDownloadInfo.channel,
this.currentlyDownloadInfo.timeRange,
)
this.calculateFileSize(this.currentlyDownloadInfo.metaPath)
console.log('getactualsize')
this.subfileListRemain()
}
// if (this.downloadList.length > 0 && this.currentlyDownloadInfo.status === 'idle') {
// this.showDownload()
// this.updateDownloadSubFileList(this.downloadList[0])
// } else {
// /* TODO If file downloading then waiting */
// console.log('no download task or file downloading')
// }
},
_confirmDownload: function () {
console.log('confirmDownload')
console.log(download.getDownloadOptionsList())
// if (this.downloadList.length > 0 && this.currentlyDownloadInfo.status === 'idle') {
// this.showDownload()
// this.updateDownloadSubFileList(this.downloadList[0])
// } else {
// /* TODO If file downloading then waiting */
// console.log('no download task or file downloading')
// }
},
downloadAllSubFileList: async function (path) {
this.currentlyDownloadInfo = this.downloadInfo
download.downloadAllSubFileList(path)
this.subfileListRemain()
},
// updateDownloadInfo: function (path) {
// console.log(path)
// const metaInfo = file.getMetaInfo(path)
// const downloadInfoIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === path)
// if (downloadInfoIndex === -1) {
// this.downloadInfo.library = metaInfo.configuration._LIBRARY_
// this.downloadInfo.channel = metaInfo.channel.map(ch => {
// let channel = ''
// if (this.downloadInfo.library.includes('Elite')) {
// channel = (ch === 0) ? 'current' : (ch === 1) ? 'voltage' : (ch === 2) ? 'resistance' : ''
// } else {
// channel = 'channel' + ch
// }
// return {
// alias: channel,
// channel: ch,
// checked: true,
// }
// })
// this.downloadInfo.metaPath = path
// this.downloadInfo.previousPath = path.split('/').slice(0, -1).join('/')
// this.downloadInfo.filename = path.split(/[\/.]+/).slice(0, -1).pop()
// this.downloadInfo.minTime = parseInt([...new Set(metaInfo['start-time'])][0] / 1000)
// this.downloadInfo.maxTime = parseInt(metaInfo.time_duration / 1000)
// this.downloadInfo.timeRange = [this.downloadInfo.minTime, this.downloadInfo.maxTime]
// this.downloadInfo.status = 'idle'
// this.downloadBlockList.push(JSON.parse(JSON.stringify(this.downloadInfo)))
// } else {
// for (var item in this.downloadInfo) {
// this.downloadInfo[item] = this.downloadBlockList[downloadInfoIndex][item]
// }
// }
// },
updatecurrentlyDownloadInfo: function () {
const downloadInfoIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === this.currentlyDownloadInfo.metaPath)
if (downloadInfoIndex !== -1) {
for (var item in this.downloadBlockList[downloadInfoIndex]) {
this.downloadBlockList[downloadInfoIndex][item] = this.currentlyDownloadInfo[item]
}
}
},
updateMetaDownloadInfo: function () {
download.updateDownloadSubFileList(
this.currentlyDownloadInfo.metaPath,
this.currentlyDownloadInfo.channel,
this.currentlyDownloadInfo.timeRange,
)
},
updateDownloadSubFileList: function (path) {
console.log('updateDownloadSubFileList')
const downloadOptionsIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === path)
this.downloadBlockList[downloadOptionsIndex].status = 'downloading'
this.currentlyDownloadInfo = this.downloadBlockList[downloadOptionsIndex]
this.updatecurrentlyDownloadInfo()
download.updateDownloadSubFileList(
this.currentlyDownloadInfo.metaPath,
this.currentlyDownloadInfo.channel,
this.currentlyDownloadInfo.timeRange,
)
this.subfileListRemain()
},
_updateDownloadSubFileList: function (path) {
console.log(path)
console.log(this.downloadInfo)
const downloadOptionsIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === path)
this.downloadBlockList[downloadOptionsIndex].status = 'downloading'
this.currentlyDownloadInfo = this.downloadBlockList[downloadOptionsIndex]
// this.updatecurrentlyDownloadInfo()
download.updateDownloadSubFileList(
this.currentlyDownloadInfo.metaPath,
this.currentlyDownloadInfo.channel,
this.currentlyDownloadInfo.timeRange,
)
this.subfileListRemain()
},
subfileListRemain: function () {
console.log('subfileListRemain')
if (download.checkDownloadSubFileList(this.currentlyDownloadInfo.metaPath)) {
this.currentlyDownloadInfo.filenameWithType = download.getFirstSubfile(this.currentlyDownloadInfo.metaPath)
} else {
this.loadingPercent = 100
console.log(this.currentlyDownloadInfo.filenameWithType + ' download complete')
console.log(performance.now())
this.exportCSV()
this.test(this.downloadDone)
// this.currentlyDownloadInfo.status = this.currentlyDownloadInfo.status = 'idle'
// this.updatecurrentlyDownloadInfo()
// this.loadingPercent = 0
}
},
checkFileSegmentGetOrNot: function () {
console.log('checkFileSegmentGetOrNot')
if (this.fileSegmentIndex >= this.fileSegmentMax) {
const subfile = file.shiftDownloadSubFileList(this.currentlyDownloadInfo.metaPath)
file.pushDownloadData(this.currentlyDownloadInfo.metaPath, subfile, this.data)
this.data = ''
this.fileSegmentIndex = 0
this.subfileListRemain()
} else {
}
},
exportCSV: function () {
exportData.exportCSV(this.currentlyDownloadInfo)
},
exportTXT: function () {
},
timeRangeChange: function (timeRange, path) {
download.getDownloadOptions(path).timeRange = timeRange
this.refresh()
},
calculateFileSize: function () {
this.totoalFileSize = file.getFileSize(this.currentlyDownloadInfo.metaPath)
// const allSubfile = download.getAllSubfile(this.currentlyDownloadInfo.metaPath)
// this.fileNum = allSubfile.length
const downlinkSpeed = this.getNetSpeed('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAABTVBMVEX////qQzU0qFNChfT7vAU/g/RZlPU5gPT7uQCxyPqXufn/vQDpNCLqQTMwp1D7uADpOCfqPS4fo0bpMiD8wADpLxwopUv0paD1q6b86ObpOiv4/Pn+9/b4xcH2ubX1r6rsXVIre/NwvoOf0qvO6NQzqUm/4cf5zMn739zrSz398O/sVEjvdWz2t7PvenP4ycb7wir96Lf+8tb8zFH93pj+9eH//PD92Yvw9v7+7cP80Xb95q6pxPnq9u1PsmigvvlunvaJyZiGrvjD1vvyl5HtamHoJgzwhH3zmpTtXlLvenHuYSzygCL2mxjsUzDwcSf0jx34phH8z2DxfVHX5P38x0KHvnDOtiGjsjJ0rkLhuRW4tCnS4PyMsDtZq0it2bhmmvbO5OE1noBft3U1pWA/jNc8lLk5nJNBieSSy58+j8t5wIo6mKY2o25FrmBHQXgmAAAIJUlEQVR4nO2b2V/bRhCAhbADxJLQYQvwgcE2PsAhEHK0SUxigoGkTdMj6ZXDTdw2JbT+/x9r+QDZllYra8da85vvKU/yfszszO5IEQQEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRDWpLfXSplbqysWq9n1Unk7HfaSmJFey6ycNipGwpDUAZKRSMxt7B6vl7fDXl5QyqvVHdVQk5o8N4osa0nJqDSOSzNrmc7sVlRVk8fl7J4dTbmRXQt7sf5JZ6onkkPknC3VxE52tiJZPtUMjcru0lI1dkthL5uaTMNI0kVvOJLGRnYmCmx2R/IXPpukVFnh3nG9IvkPn81R1bJhKxC5vWME8evHMRO2hitr1URQv65jospp81jRkgz8LJLaStgyDpSfqywC2ENWN7gL48rJpAXUGe3kVthKQ2w3DKZ+c9ZuPOWocZQqrHagHY4yNRuoBbqjaZyc444D90A35AQPmzFdlYD8uorht410Q4UTnJON0A3TOxA15pLE6nUXvOYRlI3wI9gAFZRCFxReQBaZufAjKBwDtgkeioyQZX4UtcFDIyz5PqrJsqYlk2oymdQ8hqhc7MHtih9Ba+4rVTaqp6fHZ2fHp7sNaxDuPk3lQVCo+iijmmQ0zjJr9ncx6e3Syq6WcBk6crAHhVXqTSirJ7sZ53l2unQsGQ6R5GAPCuUT2vCpz28RL7K3q+pIIDlo9B026EYWmlT1vuGVT1X707jYg8IKVauXjQbdDbZctd0wuYjgGtU7peTcOvUTM/KgcPFQZDqnNYo6Khu7fh6ZftENo8yHYCnhLajN+R3NZzsFh489KAg73jk6yZisXNE4EVz3boXG7iSjzrUKH4KC93EtcTzZkzmZAD9a/obsJ0tnYa8xEKm9SPxboqHEwZkrCPuLkUj8JSFRpdOwlxiQg0iH+PJ3boJqNewVBuTOYqSrGH/lLKjtcFIuJuZhz7Dj+L1jldHKYa8wIKnIJfEfHDJVoj+Kcsr+sk1xvG0kZ30T9uvMleNI25DV2fo2zYH7y5FhxZdDhgbfH/vQsL8YGVG0tw15J+z1BefHUcNIPPLqsvsbt8NeX2BSo35DbUPbCHt9wbkzFsJe2+iHkN/P0ai562gYiS9abUPeCHt5DDhwFOy3DZWT62sQ7u+5GVq3DY2bz3sm555zkvYUl38Ke3kM2F92N4wsPqJ8ytKNwLyGMnxAiGFk+T6t4WY0IJtLUIYPSYZ7tE9ZWpgPyMJNKMM3pCR9MD3D6FMgwftxUpLuT89wfh7KkMk2ZGG4CWR4j1RK49SPYWH4FYzh1yTDN1M1BGoXjwhZuvhwqobvYAxdzt09Q+pSysJw4VkIhnevvSHtmY2NIdChhnRom7Lh42tv+AQNJ4OjfRiG4XRraRiG0+2HQJWGnzMNVLcgnksPpmoI1PH5uVtAGXJ0PwQ6efNzx4e6PXEzpwG7AXMzawObYrCalwaftUWhDIkz72XqmffmAg0kwxtQhqT3FrH4z5RPeXeThiOC4cIRlCHh3VPsF0Wpsfyt14QgQh3aBPf3h7HYr6Jo5ln+FGm3QjV8wfXsHYv8Joqicsjyp46i7oZgzcLtPX7sd0W00IsMf4qwDcGG+oLLtxixt2IPpcXul95tuvuBvZixGP+eJhZ5Lw5gGMQj0jYEuv92GfsmKrb34VJQVNrMfmiBtA2Bzt1dRr9r6zQJ0YbeZPQ7pEoanYcrNMJIv+g2iSF0Rj2RVGZAt+Hwwa3XJIZQckx+hXh0Bd2GQ9V00CSGg8gkT28QduH8AtiXGD0ub1Cxtw6CIpOz2xPi7QPs2N2n3/RjsfcOft16mgr6E69JhRTwQ4wBB70M/eAs2DmeBu77xBwFT9JeSxxpEiNbsR7sB0jN3oKNBom98SYxohjokrFEOK/Ng1fSLo/GmwRDxWceEQS8V1whElI0aKI+I1aZTrsHu97bKepehqKem6yiegnCnkmvOPQMYqeiTtIXH296CEb/YO3iTME7iJ1M9n+V8qqinRDCzS+GyZkUivqFv0z9OO8pCDdGHKXmnaZWpio+wpi60D/d8FIEHEGNkqfIUyuMrQLd81J50RS3/vyLrDitXdiFotjQO9bybd16nmL+TVQEe+XkuCiqIHYdD5vk/Vi4UMzB32vrc9S9mi48nY5bH7o87TnquaKLZKpwruj2dNj67x/XMEancZyx0aKopzbJ1nmxVrN5pmq14nnL1EefoihfXBShPk9wpdam24qDlZu6Lh7mLur183r9Itc6FHXddLxDb/3rmKnA4xknaPr+WIDMHopC+PNsfXLqjNPOUYumf0U6ttrjbWNqp5kh6lCKytZo24B7ZUiG5vQ2GVuf5+2bcXrHtRFSfgqqT0V72wAecxMVD8EUTeXL5TwDfvpEUvTVM3wxaBvRKR64HRXBothpG91MhfvPeJSKcHuxd9sIW7CjmINqGt22Eb6gANgXLcWPYdt1aepA9UZRKK/Q4BREkM1otpl+hRSIWgsgUyedugKRZ52pSrD3HwDU2HZGU+RlC9rIk259/lDMOlcZOqCWY5Sq+iGHAexROGTgaJqsvssBoSgGdDTNcy4T1EYzQBwVU6nz0wPdKbbGpoR0fno7Pwt+FoW64jeQiuk+OeaSVDHnMhF10Zud8F3RkRSt2aiHXMdObDVnT69PoZlrm7qzpzUg1s12Ll+YpeR0IFUr5i9abd2iP/M2u/9ut+r5Ym3G7a5IpWqFYrOZt2g2i4VCLXVt3BAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAE4Yf/AZmODCZml4YgAAAAAElFTkSuQmCC', 3)
// this.totoalFileSize = (allSubfile.length) * 1000000
console.log(downlinkSpeed)
console.log(this.totoalFileSize)
this.estimatedTime = this.totoalFileSize / (downlinkSpeed * 1024)
if (this.totoalFileSize >= 1 * 1024 * 1024) {
console.log('size big')
this.estimatedTime = this.estimatedTime * 10
}
console.log(this.estimatedTime)
this.loadTime = parseInt((this.estimatedTime / 1000) % 60) * 100
console.log(this.loadTime)
this.doProgress()
// allSubfile.forEach(subfile => {
// console.log(subfile)
// this.currentlyDownloadInfo.filenameWithType = subfile
// })
},
doProgress () {
const step = this.estimatedTime / 100 * 1000
this.interval = setInterval(() => {
if (this.loadingPercent >= 99) {
console.log('complete')
clearInterval(this.interval)
this.estimatedTime = 0
} else {
this.loadingPercent++
}
}, step)
},
getNetSpeed (url, times) {
const connection = window.navigator.connection
if (connection && connection.downlink) {
return connection.downlink * 1024 / 8
}
},
test: async function (fn) {
return await setTimeout(async function () {
await fn()
}, 1000)
},
downloadDone: function () {
download.getDownloadOptionsList().shift()
this.loadingPercent = 0
this.refresh()
this.confirmDownload()
},
getControllerList: async function () {
const update = async () => {
this.controllerList.push({
@@ -539,43 +52,131 @@ export default {
}
await update()
},
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
mqttSub: function (val) {
this.$mqtt.subscribe(val)
},
mqttUnSub: function (val) {
this.$mqtt.unsubscribe(val)
},
pageMqttSub: function () {
this.controllerList.forEach(controller => {
// this.mqttSub(controller.id + '/broadcast')
this.mqttSub(controller.id + '/file_meta_info/+')
this.mqttSub(controller.id + '/file_segment/+')
this.mqttSub(controller.id + '/file_segment_get/+')
})
},
pageMqttUnSub: function () {
this.controllerList.forEach(controller => {
// this.mqttUnSub(controller.id + '/broadcast')
this.mqttUnSub(controller.id + '/file_meta_info/+')
this.mqttUnSub(controller.id + '/file_segment/+')
this.mqttUnSub(controller.id + '/file_segment_get/+')
notify (name) {
this.showToast(`done ${name}`, {
position: 'bottom-right',
})
},
...mapActions('download',
[
types.raw.rawDataByID,
types.export.setHeader,
types.export.setTitle,
types.export.setData,
types.downloadStream.writerClose,
types.downloadStream.setDownloadStream,
],
),
...mapMutations('download',
[
types.download.setSampleRate,
types.download.setdownloadIdList,
],
),
},
watch: {
},
// watch: {
// loadingPercent(val) {
// if (val >= 100) {
// console.log('complete');
// clearInterval(this.interval)
// }
// }
// },
async mounted () {
await this.getControllerList()
this.pageMqttSub()
// TODO authorization
const format = this.$route.params.format
this.metaList = this.$route.params.metaList.split('-')
while (this.metaList.length !== 0) {
let meta
const metaID = this.metaList.pop()
const ret = await api.meta.getByID(metaID)
if (ret.status === 200) {
meta = ret.data[0]
}
if (meta !== undefined) {
this.metaInfo = meta
const channelArray = JSON.parse(this.metaInfo.channels)
const channelList = []
if (meta.device.library_name.indexOf('Neulive') >= 0) {
if (channelArray.some(el => el >= 256)) {
channelList.push(channelArray.filter(el => el < 256))
channelList.push(channelArray.filter(el => (el >= 256 && el <= 259)))
} else {
channelList.push(channelArray)
}
} else if (meta.device.library_name.indexOf('Elite') >= 0) {
channelList.push(channelArray)
}
while (channelList.length > 0) {
this.downloadInfo = newDownload()
this.downloadInfo.channel = channelList.pop()
// 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.size = parseInt(parseInt(meta.size) / 78)
} else {
this.downloadInfo.filename = meta.name + '-' + 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 + '-' + format
this.downloadInfo.size = parseInt(meta.size)
}
// init
// get sampleRate && downloadList
for (const channel of this.downloadInfo.channel) {
this.downloadInfo.channelInfo[channel] = newChannel()
this.setSampleRateDownload({ channel: channel })
this.setdownloadIdListDownload({ channel: channel })
}
// create writer
this.setDownloadStream()
console.log(this.downloadInfo)
console.log(this.metaInfo)
// set Header
if (this.downloadInfo.format !== 'csv-edf') {
this.setHeaderExport()
}
this.setTitleExport()
// start download data
let rowIndex = 0
while (rowIndex < this.downloadInfo.maxRows) {
for (const channel of this.downloadInfo.channel) {
for (const idx in this.downloadInfo.channelInfo[channel].downloadIDList) {
const _idx = parseInt(idx)
const rawID = this.downloadInfo.channelInfo[channel].downloadIDList[_idx][rowIndex]
// console.log(rowIndex, _idx, rawID)
if (rawID !== undefined) {
await this.rawDataByIDRaw({
channel: channel,
rawID: rawID,
idx: _idx,
api: api,
})
}
}
}
this.setDataExport({ last: (rowIndex === this.downloadInfo.maxRows - 1) })
rowIndex += 1
}
this.writerCloseDownloadStream()
}
}
}
await new Promise(resolve => setTimeout(resolve, 2000)) // sleep
window.close()
},
destroyed () {
this.pageMqttUnSub()
+589
View File
@@ -0,0 +1,589 @@
<template>
<div>
<va-modal
class="flex sm12 xl12 md12 xs12 pa-0 ma-0"
v-model="showDownload"
size="small"
:hideDefaultActions="true"
:mobileFullscreen="false"
>
<template slot="header">
<div class="row mb-2">
<va-icon name="fa fa-download mr-3 " color="primary"/>
<h5 class="mt-0 mb-0">{{'Download'}}</h5>
</div>
</template>
<div class="downloadOptionsList">
<template v-for="(downloadOptions, i) in downloadOptionsList">
<va-accordion :key="downloadOptions.filename">
<va-collapse>
<va-item :key="downloadOptions.filename" slot="header" clickable>
<va-item-section avatar>
<va-item-label>
{{ downloadOptions.filename }}
</va-item-label>
</va-item-section>
<va-item-section>
<!-- <va-item-label>
{{ downloadInfo.minTime }}
</va-item-label>
<va-item-label caption>
{{ downloadInfo.maxTime }}
</va-item-label> -->
</va-item-section>
<va-item-section v-if="downloadOptions.download.status == 'idle'" side>
<va-icon name="fa fa-play" color="gray" @click.native.stop="confirmDownload(downloadOptions.metaPath)"/>
</va-item-section>
<va-item-section v-else side class="md4 offset--md8">
<div class="row flex sm12 xl12 md12 xs12">
<div class="flex-center spinner-box">
<fulfilling-bouncing-circle-spinner
:animation-duration="3000"
:color="'#6c7fee'"
:size="20"
>
</fulfilling-bouncing-circle-spinner>
<span class="ml-3">{{loaded}}</span>
</div>
</div>
</va-item-section>
</va-item>
<div slot="body">
<div v-if="downloadOptions.download.status == 'downloading'" class="row flex sm12 xl12 md12 xs12">
<div class="row flex sm12 xl12 md12 xs12">
<div class="flex-center spinner-box mt-4 mb-5">
<fulfilling-bouncing-circle-spinner
:animation-duration="3000"
:color="'#6c7fee'"
:size="60"
>
</fulfilling-bouncing-circle-spinner>
</div>
</div>
</div>
<div v-else>
<div class="mb-5">
<va-item class="flex sm12 xl12 md12 xs12 mr-1 pa-0">
<va-icon
class="flex sm1 xl1 md1 xs1 start "
name="glyphicon glyphicon-filter"
size="1.0rem"
:fixedWidth = "Boolean('true')"
/>
<div class="flex sm11 xl11 md11 xs11 row">
<div v-for="(item,index) in downloadOptions.channel" :key="item.channel" class="filter-button">
<va-button
class="mx-1 px-1"
v-if="item.checked"
@click="channelUnchecked(index,downloadOptions.metaPath)"
small
>
{{item.alias}}
</va-button>
<va-button
class="mx-1 px-1"
v-else
@click="channelChecked(index,downloadOptions.metaPath)"
small outline
>
{{item.alias}}
</va-button>
</div>
</div>
</va-item>
</div>
<div class="mb-5">
<va-item class="flex sm12 xl12 md12 xs12 pa-0">
<va-icon
class="flex sm1 xl1 md1 xs1 mr-4"
:fixedWidth="true"
name="va-icon glyphicon glyphicon-time"
size="1.0rem"
/>
<div class="flex">
<va-slider
class="flex sm11 xl11 md11 xs11 filter-button"
value-visible
range
v-model="downloadOptions.timeRange"
@click.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
@mouseup.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
@mouseleave.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
@touchend.native="timeRangeChange(downloadOptions.timeRange,downloadOptions.metaPath)"
:min="downloadOptions.minTime"
:max="downloadOptions.maxTime"
/>
<span> {{ transTime(downloadOptions.timeRange) }} </span>
</div>
</va-item>
</div>
</div>
</div>
</va-collapse>
</va-accordion>
<va-list-separator v-if="i < downloadOptionsList.length - 1" :key="'separator' + downloadOptions.filename" />
</template>
</div>
</va-modal>
</div>
</template>
<script>
import { file } from '../../data/file/File'
import { download } from '../../data/download/Download'
import { exportData } from '../../data/export/export'
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
export default {
name: 'Download',
components: {
FulfillingBouncingCircleSpinner,
},
data: () => {
return {
showDownload: false,
controllerList: [],
downloadList: [],
downloadListRecord: [],
downloadOptionsList: [],
// downloadInfo: {
// metaPath: '',
// previousPath: '',
// filenameWithType: '',
// filename: '',
// channel: [],
// timeRange: [0, 0],
// minTime: 0,
// maxTime: 0,
// status: 'idle',
// device: '',
// },
currentlyDownloadInfo: {
metaPath: '',
previousPath: '',
filenameWithType: '',
filename: '',
channel: [],
timeRange: [0, 0],
minTime: 0,
maxTime: 0,
download: {
status: 'idle',
rate: 0,
},
device: '',
},
estimatedTime: 0,
fileSegmentIndex: 0,
fileSegmentMax: 0,
totoalFileSize: 0,
loadingPercent: 0,
loadTime: 0,
interval: null,
data: '',
}
},
computed: {
// transTime (min,max) {
// return this.getTimeInFormat(min) + ' - ' + this.getTimeInFormat(max)
// },
loaded () {
return this.loadingPercent + '%'
},
},
// mqtt: {
// async '+/file_segment/+' (data, topic) {
// console.log('file_segment')
// console.log(String.fromCharCode.apply(null, data))
// // console.log(navigator.connection.downlink)
// // console.log(this.fileNum)
// // console.log(this.downloadOptionsList.length)
// // console.log(JSON.parse(String.fromCharCode.apply(null, data)).data.file_size)
// if (this.downloadOptionsList.length > 0) {
// await download.updateFileSegmentInfo(String.fromCharCode.apply(null, data))
// this.fileSegmentMax = download.getFileSegmentMaxIndex()
// this.checkFileSegmentGetOrNot()
// }
// },
// async '+/file_segment_get/+' (data, topic) {
// console.log('file_segment_get')
// console.log(JSON.parse(new TextDecoder('utf-8').decode(data)))
// if (this.downloadOptionsList.length > 0) {
// const segmentData = atob(JSON.parse(new TextDecoder('utf-8').decode(data)).data.segment)
// this.data += segmentData
// this.fileSegmentIndex += 1
// this.checkFileSegmentGetOrNot()
// }
// },
// },
methods: {
transTime (timeRange) {
return this.getTimeInFormat(timeRange[0]) + ' - ' + this.getTimeInFormat(timeRange[1])
},
notify (name) {
this.showToast(`done ${name}`, {
position: 'bottom-right',
})
},
showDownloadModal: function () {
this.showDownload = true
},
channelChecked: function (channelIndex, path) {
download.getDownloadOptions(path).channel[channelIndex].checked = true
this.refresh()
},
channelUnchecked: function (channelIndex, path) {
download.getDownloadOptions(path).channel[channelIndex].checked = false
this.refresh()
},
getTimeInFormat: function (time) {
if (time < 60) {
const second = time
return `${second}s`
} else if (time < 3600) {
const second = time % 60
const minute = parseInt(time / 60)
return `${minute}m${second}s`
} else {
const hour = parseInt(time / 3600)
const hourRemain = time % 3600
const minute = parseInt(hourRemain / 60)
const second = hourRemain % 60
return `${hour}h${minute}m${second}s`
}
},
getCurrentFullPathName: function () {
return this.currentlyDownloadInfo.previousPath + '/' + this.currentlyDownloadInfo.filenameWithType
},
downloading: async function (info) {
this.$emit('download')
},
addDownloadTask: async function (info) {
this.downloading()
/*
** download all
*/
if (parseInt(info.time_duration) < 18e8) {
const rawData = await download.getAllRawDatas(info)
exportData.exportCSV(info, rawData)
} else {
for (const channelID in info.raw_data) {
const rawDataIDList = info.raw_data[channelID]
while (rawDataIDList.length > 1000) {
const _list = rawDataIDList.splice(0, 1000)
const rawData = await download.getIndexRawDatas(info, channelID, _list)
exportData.exportCSV(info, rawData)
}
const rawData = await download.getIndexRawDatas(info, channelID, rawDataIDList)
exportData.exportCSV(info, rawData, channelID)
rawData[channelID].length = 0
// const rawData = await download.getAllRawDatas(info)
// console.timeEnd('download')
}
}
// console.time('download')
// const rawData = await download.getAllRawDatas(info)
// console.timeEnd('download')
// exportData.exportCSV(info, rawData)
/*
** download split
*/
this.downloading()
},
_addDownloadTask: function (downloadPath) {
if (Array.isArray(downloadPath)) {
downloadPath.forEach(path => {
this.downloadList.push(path.path)
this.updateDownloadInfo(path.path)
})
} else {
this.downloadList.push(downloadPath)
this.updateDownloadInfo(downloadPath)
}
this.confirmDownload()
},
refresh: function () {
this.downloadOptionsList = download.getDownloadOptionsList()
console.log(this.downloadOptionsList)
},
confirmDownload: function (path) {
console.log('confirmDownload')
console.log(download.getDownloadOptionsList())
console.log(download.isFileDownloading())
console.log(download.downloadTaskRemain())
if (!download.isFileDownloading() && download.downloadTaskRemain()) {
const downloadOptionsIndex = download.getDownloadOptionsList().findIndex(downloadInfo => downloadInfo.metaPath === path)
// this.downloadBlockList[downloadInfoIndex].status = 'downloading'
this.currentlyDownloadInfo = download.getDownloadOptionsList()[downloadOptionsIndex]
this.currentlyDownloadInfo.download.status = 'downloading'
console.log(this.currentlyDownloadInfo)
console.log(download.getDownloadOptionsList())
download.updateDownloadSubFileList(
this.currentlyDownloadInfo.metaPath,
this.currentlyDownloadInfo.channel,
this.currentlyDownloadInfo.timeRange,
)
this.calculateFileSize(this.currentlyDownloadInfo.metaPath)
console.log('getactualsize')
this.subfileListRemain()
}
// if (this.downloadList.length > 0 && this.currentlyDownloadInfo.status === 'idle') {
// this.showDownload()
// this.updateDownloadSubFileList(this.downloadList[0])
// } else {
// /* TODO If file downloading then waiting */
// console.log('no download task or file downloading')
// }
},
_confirmDownload: function () {
console.log('confirmDownload')
console.log(download.getDownloadOptionsList())
// if (this.downloadList.length > 0 && this.currentlyDownloadInfo.status === 'idle') {
// this.showDownload()
// this.updateDownloadSubFileList(this.downloadList[0])
// } else {
// /* TODO If file downloading then waiting */
// console.log('no download task or file downloading')
// }
},
downloadAllSubFileList: async function (path) {
this.currentlyDownloadInfo = this.downloadInfo
download.downloadAllSubFileList(path)
this.subfileListRemain()
},
// updateDownloadInfo: function (path) {
// console.log(path)
// const metaInfo = file.getMetaInfo(path)
// const downloadInfoIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === path)
// if (downloadInfoIndex === -1) {
// this.downloadInfo.library = metaInfo.configuration._LIBRARY_
// this.downloadInfo.channel = metaInfo.channel.map(ch => {
// let channel = ''
// if (this.downloadInfo.library.includes('Elite')) {
// channel = (ch === 0) ? 'current' : (ch === 1) ? 'voltage' : (ch === 2) ? 'resistance' : ''
// } else {
// channel = 'channel' + ch
// }
// return {
// alias: channel,
// channel: ch,
// checked: true,
// }
// })
// this.downloadInfo.metaPath = path
// this.downloadInfo.previousPath = path.split('/').slice(0, -1).join('/')
// this.downloadInfo.filename = path.split(/[\/.]+/).slice(0, -1).pop()
// this.downloadInfo.minTime = parseInt([...new Set(metaInfo['start-time'])][0] / 1000)
// this.downloadInfo.maxTime = parseInt(metaInfo.time_duration / 1000)
// this.downloadInfo.timeRange = [this.downloadInfo.minTime, this.downloadInfo.maxTime]
// this.downloadInfo.status = 'idle'
// this.downloadBlockList.push(JSON.parse(JSON.stringify(this.downloadInfo)))
// } else {
// for (var item in this.downloadInfo) {
// this.downloadInfo[item] = this.downloadBlockList[downloadInfoIndex][item]
// }
// }
// },
updatecurrentlyDownloadInfo: function () {
const downloadInfoIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === this.currentlyDownloadInfo.metaPath)
if (downloadInfoIndex !== -1) {
for (var item in this.downloadBlockList[downloadInfoIndex]) {
this.downloadBlockList[downloadInfoIndex][item] = this.currentlyDownloadInfo[item]
}
}
},
updateMetaDownloadInfo: function () {
download.updateDownloadSubFileList(
this.currentlyDownloadInfo.metaPath,
this.currentlyDownloadInfo.channel,
this.currentlyDownloadInfo.timeRange,
)
},
updateDownloadSubFileList: function (path) {
console.log('updateDownloadSubFileList')
const downloadOptionsIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === path)
this.downloadBlockList[downloadOptionsIndex].status = 'downloading'
this.currentlyDownloadInfo = this.downloadBlockList[downloadOptionsIndex]
this.updatecurrentlyDownloadInfo()
download.updateDownloadSubFileList(
this.currentlyDownloadInfo.metaPath,
this.currentlyDownloadInfo.channel,
this.currentlyDownloadInfo.timeRange,
)
this.subfileListRemain()
},
_updateDownloadSubFileList: function (path) {
console.log(path)
console.log(this.downloadInfo)
const downloadOptionsIndex = this.downloadBlockList.findIndex(downloadInfo => downloadInfo.metaPath === path)
this.downloadBlockList[downloadOptionsIndex].status = 'downloading'
this.currentlyDownloadInfo = this.downloadBlockList[downloadOptionsIndex]
// this.updatecurrentlyDownloadInfo()
download.updateDownloadSubFileList(
this.currentlyDownloadInfo.metaPath,
this.currentlyDownloadInfo.channel,
this.currentlyDownloadInfo.timeRange,
)
this.subfileListRemain()
},
subfileListRemain: function () {
console.log('subfileListRemain')
if (download.checkDownloadSubFileList(this.currentlyDownloadInfo.metaPath)) {
this.currentlyDownloadInfo.filenameWithType = download.getFirstSubfile(this.currentlyDownloadInfo.metaPath)
} else {
this.loadingPercent = 100
console.log(this.currentlyDownloadInfo.filenameWithType + ' download complete')
console.log(performance.now())
this.exportCSV()
this.test(this.downloadDone)
// this.currentlyDownloadInfo.status = this.currentlyDownloadInfo.status = 'idle'
// this.updatecurrentlyDownloadInfo()
// this.loadingPercent = 0
}
},
checkFileSegmentGetOrNot: function () {
console.log('checkFileSegmentGetOrNot')
if (this.fileSegmentIndex >= this.fileSegmentMax) {
const subfile = file.shiftDownloadSubFileList(this.currentlyDownloadInfo.metaPath)
file.pushDownloadData(this.currentlyDownloadInfo.metaPath, subfile, this.data)
this.data = ''
this.fileSegmentIndex = 0
this.subfileListRemain()
} else {
}
},
exportCSV: function () {
exportData.exportCSV(this.currentlyDownloadInfo)
},
exportTXT: function () {
},
timeRangeChange: function (timeRange, path) {
download.getDownloadOptions(path).timeRange = timeRange
this.refresh()
},
calculateFileSize: function () {
this.totoalFileSize = file.getFileSize(this.currentlyDownloadInfo.metaPath)
// const allSubfile = download.getAllSubfile(this.currentlyDownloadInfo.metaPath)
// this.fileNum = allSubfile.length
const downlinkSpeed = this.getNetSpeed('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAABTVBMVEX////qQzU0qFNChfT7vAU/g/RZlPU5gPT7uQCxyPqXufn/vQDpNCLqQTMwp1D7uADpOCfqPS4fo0bpMiD8wADpLxwopUv0paD1q6b86ObpOiv4/Pn+9/b4xcH2ubX1r6rsXVIre/NwvoOf0qvO6NQzqUm/4cf5zMn739zrSz398O/sVEjvdWz2t7PvenP4ycb7wir96Lf+8tb8zFH93pj+9eH//PD92Yvw9v7+7cP80Xb95q6pxPnq9u1PsmigvvlunvaJyZiGrvjD1vvyl5HtamHoJgzwhH3zmpTtXlLvenHuYSzygCL2mxjsUzDwcSf0jx34phH8z2DxfVHX5P38x0KHvnDOtiGjsjJ0rkLhuRW4tCnS4PyMsDtZq0it2bhmmvbO5OE1noBft3U1pWA/jNc8lLk5nJNBieSSy58+j8t5wIo6mKY2o25FrmBHQXgmAAAIJUlEQVR4nO2b2V/bRhCAhbADxJLQYQvwgcE2PsAhEHK0SUxigoGkTdMj6ZXDTdw2JbT+/x9r+QDZllYra8da85vvKU/yfszszO5IEQQEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRDWpLfXSplbqysWq9n1Unk7HfaSmJFey6ycNipGwpDUAZKRSMxt7B6vl7fDXl5QyqvVHdVQk5o8N4osa0nJqDSOSzNrmc7sVlRVk8fl7J4dTbmRXQt7sf5JZ6onkkPknC3VxE52tiJZPtUMjcru0lI1dkthL5uaTMNI0kVvOJLGRnYmCmx2R/IXPpukVFnh3nG9IvkPn81R1bJhKxC5vWME8evHMRO2hitr1URQv65jospp81jRkgz8LJLaStgyDpSfqywC2ENWN7gL48rJpAXUGe3kVthKQ2w3DKZ+c9ZuPOWocZQqrHagHY4yNRuoBbqjaZyc444D90A35AQPmzFdlYD8uorht410Q4UTnJON0A3TOxA15pLE6nUXvOYRlI3wI9gAFZRCFxReQBaZufAjKBwDtgkeioyQZX4UtcFDIyz5PqrJsqYlk2oymdQ8hqhc7MHtih9Ba+4rVTaqp6fHZ2fHp7sNaxDuPk3lQVCo+iijmmQ0zjJr9ncx6e3Syq6WcBk6crAHhVXqTSirJ7sZ53l2unQsGQ6R5GAPCuUT2vCpz28RL7K3q+pIIDlo9B026EYWmlT1vuGVT1X707jYg8IKVauXjQbdDbZctd0wuYjgGtU7peTcOvUTM/KgcPFQZDqnNYo6Khu7fh6ZftENo8yHYCnhLajN+R3NZzsFh489KAg73jk6yZisXNE4EVz3boXG7iSjzrUKH4KC93EtcTzZkzmZAD9a/obsJ0tnYa8xEKm9SPxboqHEwZkrCPuLkUj8JSFRpdOwlxiQg0iH+PJ3boJqNewVBuTOYqSrGH/lLKjtcFIuJuZhz7Dj+L1jldHKYa8wIKnIJfEfHDJVoj+Kcsr+sk1xvG0kZ30T9uvMleNI25DV2fo2zYH7y5FhxZdDhgbfH/vQsL8YGVG0tw15J+z1BefHUcNIPPLqsvsbt8NeX2BSo35DbUPbCHt9wbkzFsJe2+iHkN/P0ai562gYiS9abUPeCHt5DDhwFOy3DZWT62sQ7u+5GVq3DY2bz3sm555zkvYUl38Ke3kM2F92N4wsPqJ8ytKNwLyGMnxAiGFk+T6t4WY0IJtLUIYPSYZ7tE9ZWpgPyMJNKMM3pCR9MD3D6FMgwftxUpLuT89wfh7KkMk2ZGG4CWR4j1RK49SPYWH4FYzh1yTDN1M1BGoXjwhZuvhwqobvYAxdzt09Q+pSysJw4VkIhnevvSHtmY2NIdChhnRom7Lh42tv+AQNJ4OjfRiG4XRraRiG0+2HQJWGnzMNVLcgnksPpmoI1PH5uVtAGXJ0PwQ6efNzx4e6PXEzpwG7AXMzawObYrCalwaftUWhDIkz72XqmffmAg0kwxtQhqT3FrH4z5RPeXeThiOC4cIRlCHh3VPsF0Wpsfyt14QgQh3aBPf3h7HYr6Jo5ln+FGm3QjV8wfXsHYv8Joqicsjyp46i7oZgzcLtPX7sd0W00IsMf4qwDcGG+oLLtxixt2IPpcXul95tuvuBvZixGP+eJhZ5Lw5gGMQj0jYEuv92GfsmKrb34VJQVNrMfmiBtA2Bzt1dRr9r6zQJ0YbeZPQ7pEoanYcrNMJIv+g2iSF0Rj2RVGZAt+Hwwa3XJIZQckx+hXh0Bd2GQ9V00CSGg8gkT28QduH8AtiXGD0ub1Cxtw6CIpOz2xPi7QPs2N2n3/RjsfcOft16mgr6E69JhRTwQ4wBB70M/eAs2DmeBu77xBwFT9JeSxxpEiNbsR7sB0jN3oKNBom98SYxohjokrFEOK/Ng1fSLo/GmwRDxWceEQS8V1whElI0aKI+I1aZTrsHu97bKepehqKem6yiegnCnkmvOPQMYqeiTtIXH296CEb/YO3iTME7iJ1M9n+V8qqinRDCzS+GyZkUivqFv0z9OO8pCDdGHKXmnaZWpio+wpi60D/d8FIEHEGNkqfIUyuMrQLd81J50RS3/vyLrDitXdiFotjQO9bybd16nmL+TVQEe+XkuCiqIHYdD5vk/Vi4UMzB32vrc9S9mi48nY5bH7o87TnquaKLZKpwruj2dNj67x/XMEancZyx0aKopzbJ1nmxVrN5pmq14nnL1EefoihfXBShPk9wpdam24qDlZu6Lh7mLur183r9Itc6FHXddLxDb/3rmKnA4xknaPr+WIDMHopC+PNsfXLqjNPOUYumf0U6ttrjbWNqp5kh6lCKytZo24B7ZUiG5vQ2GVuf5+2bcXrHtRFSfgqqT0V72wAecxMVD8EUTeXL5TwDfvpEUvTVM3wxaBvRKR64HRXBothpG91MhfvPeJSKcHuxd9sIW7CjmINqGt22Eb6gANgXLcWPYdt1aepA9UZRKK/Q4BREkM1otpl+hRSIWgsgUyedugKRZ52pSrD3HwDU2HZGU+RlC9rIk259/lDMOlcZOqCWY5Sq+iGHAexROGTgaJqsvssBoSgGdDTNcy4T1EYzQBwVU6nz0wPdKbbGpoR0fno7Pwt+FoW64jeQiuk+OeaSVDHnMhF10Zud8F3RkRSt2aiHXMdObDVnT69PoZlrm7qzpzUg1s12Ll+YpeR0IFUr5i9abd2iP/M2u/9ut+r5Ym3G7a5IpWqFYrOZt2g2i4VCLXVt3BAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAE4Yf/AZmODCZml4YgAAAAAElFTkSuQmCC', 3)
// this.totoalFileSize = (allSubfile.length) * 1000000
console.log(downlinkSpeed)
console.log(this.totoalFileSize)
this.estimatedTime = this.totoalFileSize / (downlinkSpeed * 1024)
if (this.totoalFileSize >= 1 * 1024 * 1024) {
console.log('size big')
this.estimatedTime = this.estimatedTime * 10
}
console.log(this.estimatedTime)
this.loadTime = parseInt((this.estimatedTime / 1000) % 60) * 100
console.log(this.loadTime)
this.doProgress()
// allSubfile.forEach(subfile => {
// console.log(subfile)
// this.currentlyDownloadInfo.filenameWithType = subfile
// })
},
doProgress () {
const step = this.estimatedTime / 100 * 1000
this.interval = setInterval(() => {
if (this.loadingPercent >= 99) {
console.log('complete')
clearInterval(this.interval)
this.estimatedTime = 0
} else {
this.loadingPercent++
}
}, step)
},
getNetSpeed (url, times) {
const connection = window.navigator.connection
if (connection && connection.downlink) {
return connection.downlink * 1024 / 8
}
},
test: async function (fn) {
return await setTimeout(async function () {
await fn()
}, 1000)
},
downloadDone: function () {
download.getDownloadOptionsList().shift()
this.loadingPercent = 0
this.refresh()
this.confirmDownload()
},
getControllerList: async function () {
const update = async () => {
this.controllerList.push({
id: 'tommy_test',
mac: '',
status: 'loading',
isScan: true,
files: [],
})
}
await update()
},
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
mqttSub: function (val) {
this.$mqtt.subscribe(val)
},
mqttUnSub: function (val) {
this.$mqtt.unsubscribe(val)
},
pageMqttSub: function () {
this.controllerList.forEach(controller => {
// this.mqttSub(controller.id + '/broadcast')
this.mqttSub(controller.id + '/file_meta_info/+')
this.mqttSub(controller.id + '/file_segment/+')
this.mqttSub(controller.id + '/file_segment_get/+')
})
},
pageMqttUnSub: function () {
this.controllerList.forEach(controller => {
// this.mqttUnSub(controller.id + '/broadcast')
this.mqttUnSub(controller.id + '/file_meta_info/+')
this.mqttUnSub(controller.id + '/file_segment/+')
this.mqttUnSub(controller.id + '/file_segment_get/+')
})
},
},
// watch: {
// loadingPercent(val) {
// if (val >= 100) {
// console.log('complete');
// clearInterval(this.interval)
// }
// }
// },
async mounted () {
await this.getControllerList()
this.pageMqttSub()
},
destroyed () {
this.pageMqttUnSub()
},
}
</script>
<style>
.filter-button {
text-align: center;
}
</style>
@@ -1,159 +0,0 @@
<template>
<div>
</div>
</template>
<script>
import api from '@/data/api/index'
import types from '@/store/modules/file/elite/csv/types'
import { mapActions, mapGetters, mapMutations } from 'vuex'
// import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
export default {
name: 'Download',
components: {
// FulfillingBouncingCircleSpinner,
},
data: () => {
return {
controllerList: [],
spliceDataNumsLimit: 20,
}
},
computed: {
getByIndex (index) {
return this.getByIndexDownload(index)
},
getDownloading () {
return this.getDownloadingDownload()
},
getRemainIDLength (index) {
return this.getRemainIDLengthDownload(index)
},
},
methods: {
getControllerList: async function () {
const update = async () => {
this.controllerList.push({
id: 'tommy_test',
mac: '',
status: 'loading',
isScan: true,
files: [],
})
}
await update()
},
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
mqttSub: function (val) {
this.$mqtt.subscribe(val)
},
mqttUnSub: function (val) {
this.$mqtt.unsubscribe(val)
},
pageMqttSub: function () {
this.controllerList.forEach(controller => {
// this.mqttSub(controller.id + '/broadcast')
this.mqttSub(controller.id + '/file_meta_info/+')
this.mqttSub(controller.id + '/file_segment/+')
this.mqttSub(controller.id + '/file_segment_get/+')
})
},
pageMqttUnSub: function () {
this.controllerList.forEach(controller => {
// this.mqttUnSub(controller.id + '/broadcast')
this.mqttUnSub(controller.id + '/file_meta_info/+')
this.mqttUnSub(controller.id + '/file_segment/+')
this.mqttUnSub(controller.id + '/file_segment_get/+')
})
},
notify (name) {
this.showToast(`done ${name}`, {
position: 'bottom-right',
})
},
...mapActions('eliteCsv',
[
types.download.init,
types.download.rawDataByIDs,
types.export.createHeadersString,
types.export.createTitlesString,
types.export.createDataString,
types.export.closeFileStream,
],
),
...mapMutations('eliteCsv',
[
types.download.setDownloading,
types.download.removeDownloadBuffer,
],
),
...mapGetters('eliteCsv',
[
types.download.getByIndex,
types.download.getDownloading,
types.download.getAll,
types.download.getRemainIDLength,
],
),
},
watch: {
},
async mounted () {
await this.getControllerList()
// TODO authorization
this.pageMqttSub()
const metaIDList = this.$route.params.metaList.split('-')
const recoverData = this.$route.params.recover
await this.initDownload({ metaIDList: metaIDList, api: api })
// let first file download in download List
this.setDownloadingDownload()
const downloadingFile = this.getDownloading
downloadingFile.recoverData = recoverData
let spliceDataNums = 0
// console.log('downloadingFile', downloadingFile)
// console.log(this.getRemainIDLength(0))
// create headers and title
this.createHeadersStringExport()
this.createTitlesStringExport()
// loop until each channel's rawID List empty
while (this.getRemainIDLength(0)) {
// forEach channel in raw_data
for (const channel in downloadingFile.raw_data) {
// get spliceDataNumsLimit numbers of ID to download once time
if (downloadingFile.raw_data[channel].length >= this.spliceDataNumsLimit) {
spliceDataNums = this.spliceDataNumsLimit
} else {
spliceDataNums = downloadingFile.raw_data[channel].length
}
const rawID = downloadingFile.raw_data[channel].splice(0, spliceDataNums)
// console.log('rawID', channel, rawID)
// download data and save into dataBuffer by rawDataIDList
await this.rawDataByIDsDownload({
channel: channel,
rawDataIDList: rawID,
api: api,
})
}
// export data
this.createDataStringExport()
// this.removeDownloadBufferDownload()
}
this.closeFileStreamExport()
},
destroyed () {
this.pageMqttUnSub()
},
}
</script>
<style>
.filter-button {
text-align: center;
}
</style>
@@ -1,207 +0,0 @@
<template>
<div>
</div>
</template>
<script>
import api from '@/data/api/index'
import types from '@/store/modules/file/elite/excel/types'
import { mapActions, mapGetters, mapMutations } from 'vuex'
// import { file } from '../../data/file/File'
// import { download } from '../../data/download/Download'
// import { exportData } from '../../data/export/export'
// import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
export default {
name: 'Download',
components: {
// FulfillingBouncingCircleSpinner,
},
data: () => {
return {
controllerList: [],
}
},
computed: {
getByIndex (index) {
return this.getByIndexDownload(index)
},
getDownloading () {
return this.getDownloadingDownload()
},
getRemainIDLength (index) {
return this.getRemainIDLengthDownload(index)
},
// transTime (min,max) {
// return this.getTimeInFormat(min) + ' - ' + this.getTimeInFormat(max)
// },
loaded () {
return this.loadingPercent + '%'
},
},
methods: {
transTime (timeRange) {
return this.getTimeInFormat(timeRange[0]) + ' - ' + this.getTimeInFormat(timeRange[1])
},
notify (name) {
this.showToast(`done ${name}`, {
position: 'bottom-right',
})
},
getControllerList: async function () {
const update = async () => {
this.controllerList.push({
id: 'tommy_test',
mac: '',
status: 'loading',
isScan: true,
files: [],
})
}
await update()
},
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
mqttSub: function (val) {
this.$mqtt.subscribe(val)
},
mqttUnSub: function (val) {
this.$mqtt.unsubscribe(val)
},
pageMqttSub: function () {
this.controllerList.forEach(controller => {
// this.mqttSub(controller.id + '/broadcast')
this.mqttSub(controller.id + '/file_meta_info/+')
this.mqttSub(controller.id + '/file_segment/+')
this.mqttSub(controller.id + '/file_segment_get/+')
})
},
pageMqttUnSub: function () {
this.controllerList.forEach(controller => {
// this.mqttUnSub(controller.id + '/broadcast')
this.mqttUnSub(controller.id + '/file_meta_info/+')
this.mqttUnSub(controller.id + '/file_segment/+')
this.mqttUnSub(controller.id + '/file_segment_get/+')
})
},
...mapActions('eliteExcel',
[
types.download.init,
types.download.rawDataByIDs,
types.export.createHeadersString,
types.export.createTitlesString,
types.export.createDataString,
types.export.closeFileStream,
],
),
...mapMutations('eliteExcel',
[
types.download.setDownloading,
types.download.removeDownloadBuffer,
],
),
...mapGetters('eliteExcel',
[
types.download.getByIndex,
types.download.getDownloading,
types.download.getAll,
types.download.getRemainIDLength,
],
),
},
openPortal () {
this.windowRef = window.open('', '', 'width=600,height=400,left=200,top=200')
this.windowRef.document.body.appendChild(this.$el)
// copyStyles(window.document, this.windowRef.document)
this.windowRef.addEventListener('beforeunload', this.closePortal)
},
closePortal () {
if (this.windowRef) {
this.windowRef.close()
this.windowRef = null
this.$emit('close')
}
},
// watch: {
// loadingPercent(val) {
// if (val >= 100) {
// console.log('complete');
// clearInterval(this.interval)
// }
// }
// },
async mounted () {
await this.getControllerList()
// TODO authorization
this.pageMqttSub()
const metaIDList = this.$route.params.metaList.split('-')
await this.initDownload({ metaIDList: metaIDList, api: api })
this.setDownloadingDownload()
const downloadingFile = this.getDownloading
console.log('downloadingFile', downloadingFile)
console.log(this.getRemainIDLength(0))
// create headers and title
this.createHeadersStringExport()
this.createTitlesStringExport()
// let spliceDataNums = 0
let rowIndex = 0
// let columnIndex = 0
// // while (this.getRemainIDLength(0)) {
while (rowIndex < downloadingFile.needRows) {
for (const channel in downloadingFile.downloadIDList) {
const rawID = downloadingFile.downloadIDList[channel][rowIndex]
// console.log('rawID', channel, rawID)
if (rawID !== undefined) {
await this.rawDataByIDsDownload({
channel: channel,
rawDataIDList: rawID,
api: api,
})
}
}
this.createDataStringExport()
this.removeDownloadBufferDownload()
// console.log('end', downloadingFile)
rowIndex += 1
}
this.closeFileStreamExport()
// }
// if (downloadingFile.raw_data[channel].length >= 10) {
// spliceDataNums = 10
// } else {
// spliceDataNums = downloadingFile.raw_data[channel].length
// }
// const rawID = downloadingFile.raw_data[channel].splice(0, spliceDataNums)
// console.log('rawID', channel, rawID)
// await this.rawDataByIDsDownload({
// channel: channel,
// rawDataIDList: rawID,
// api: api,
// })
// }
// // console.log('end', downloadingFile)
// // export data
// this.createDataStringExport({})
// this.removeDownloadBufferDownload()
// }
// const rawData = await download.getAllRawDatas(meta.data[0])
// exportData.exportCSV(meta.data[0], rawData)
// await this.initMeta({ metaIDList: metaIDList, api: api })
},
destroyed () {
this.pageMqttUnSub()
},
}
</script>
<style>
.filter-button {
text-align: center;
}
</style>
@@ -1,159 +0,0 @@
<template>
<div>
</div>
</template>
<script>
import api from '@/data/api/index'
import types from '@/store/modules/file/neulive/csv/types'
import { mapActions, mapGetters, mapMutations } from 'vuex'
// import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
export default {
name: 'Download',
components: {
// FulfillingBouncingCircleSpinner,
},
data: () => {
return {
controllerList: [],
spliceDataNumsLimit: 20,
}
},
computed: {
getByIndex (index) {
return this.getByIndexDownload(index)
},
getDownloading () {
return this.getDownloadingDownload()
},
getRemainIDLength (index) {
return this.getRemainIDLengthDownload(index)
},
},
methods: {
getControllerList: async function () {
const update = async () => {
this.controllerList.push({
id: 'tommy_test',
mac: '',
status: 'loading',
isScan: true,
files: [],
})
}
await update()
},
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
mqttSub: function (val) {
this.$mqtt.subscribe(val)
},
mqttUnSub: function (val) {
this.$mqtt.unsubscribe(val)
},
pageMqttSub: function () {
this.controllerList.forEach(controller => {
// this.mqttSub(controller.id + '/broadcast')
this.mqttSub(controller.id + '/file_meta_info/+')
this.mqttSub(controller.id + '/file_segment/+')
this.mqttSub(controller.id + '/file_segment_get/+')
})
},
pageMqttUnSub: function () {
this.controllerList.forEach(controller => {
// this.mqttUnSub(controller.id + '/broadcast')
this.mqttUnSub(controller.id + '/file_meta_info/+')
this.mqttUnSub(controller.id + '/file_segment/+')
this.mqttUnSub(controller.id + '/file_segment_get/+')
})
},
notify (name) {
this.showToast(`done ${name}`, {
position: 'bottom-right',
})
},
...mapActions('neuliveCsv',
[
types.download.init,
types.download.rawDataByIDs,
types.export.createHeadersString,
types.export.createTitlesString,
types.export.createDataString,
types.export.closeFileStream,
],
),
...mapMutations('neuliveCsv',
[
types.download.setDownloading,
types.download.removeDownloadBuffer,
],
),
...mapGetters('neuliveCsv',
[
types.download.getByIndex,
types.download.getDownloading,
types.download.getAll,
types.download.getRemainIDLength,
],
),
},
watch: {
},
async mounted () {
await this.getControllerList()
// TODO authorization
this.pageMqttSub()
const metaIDList = this.$route.params.metaList.split('-')
const recoverData = this.$route.params.recover
await this.initDownload({ metaIDList: metaIDList, api: api })
// let first file download in download List
this.setDownloadingDownload()
const downloadingFile = this.getDownloading
downloadingFile.recoverData = recoverData
let spliceDataNums = 0
// console.log('downloadingFile', downloadingFile)
// console.log(this.getRemainIDLength(0))
// create headers and title
this.createHeadersStringExport()
this.createTitlesStringExport()
// loop until each channel's rawID List empty
while (this.getRemainIDLength(0)) {
// forEach channel in raw_data
for (const channel in downloadingFile.raw_data) {
// get spliceDataNumsLimit numbers of ID to download once time
if (downloadingFile.raw_data[channel].length >= this.spliceDataNumsLimit) {
spliceDataNums = this.spliceDataNumsLimit
} else {
spliceDataNums = downloadingFile.raw_data[channel].length
}
const rawID = downloadingFile.raw_data[channel].splice(0, spliceDataNums)
// console.log('rawID', channel, rawID)
// download data and save into dataBuffer by rawDataIDList
await this.rawDataByIDsDownload({
channel: channel,
rawDataIDList: rawID,
api: api,
})
}
// export data
this.createDataStringExport()
// this.removeDownloadBufferDownload()
}
this.closeFileStreamExport()
},
destroyed () {
this.pageMqttUnSub()
},
}
</script>
<style>
.filter-button {
text-align: center;
}
</style>
@@ -1,207 +0,0 @@
<template>
<div>
</div>
</template>
<script>
import api from '@/data/api/index'
import types from '@/store/modules/file/neulive/excel/types'
import { mapActions, mapGetters, mapMutations } from 'vuex'
// import { file } from '../../data/file/File'
// import { download } from '../../data/download/Download'
// import { exportData } from '../../data/export/export'
// import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
export default {
name: 'Download',
components: {
// FulfillingBouncingCircleSpinner,
},
data: () => {
return {
controllerList: [],
}
},
computed: {
getByIndex (index) {
return this.getByIndexDownload(index)
},
getDownloading () {
return this.getDownloadingDownload()
},
getRemainIDLength (index) {
return this.getRemainIDLengthDownload(index)
},
// transTime (min,max) {
// return this.getTimeInFormat(min) + ' - ' + this.getTimeInFormat(max)
// },
loaded () {
return this.loadingPercent + '%'
},
},
methods: {
transTime (timeRange) {
return this.getTimeInFormat(timeRange[0]) + ' - ' + this.getTimeInFormat(timeRange[1])
},
notify (name) {
this.showToast(`done ${name}`, {
position: 'bottom-right',
})
},
getControllerList: async function () {
const update = async () => {
this.controllerList.push({
id: 'tommy_test',
mac: '',
status: 'loading',
isScan: true,
files: [],
})
}
await update()
},
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
mqttSub: function (val) {
this.$mqtt.subscribe(val)
},
mqttUnSub: function (val) {
this.$mqtt.unsubscribe(val)
},
pageMqttSub: function () {
this.controllerList.forEach(controller => {
// this.mqttSub(controller.id + '/broadcast')
this.mqttSub(controller.id + '/file_meta_info/+')
this.mqttSub(controller.id + '/file_segment/+')
this.mqttSub(controller.id + '/file_segment_get/+')
})
},
pageMqttUnSub: function () {
this.controllerList.forEach(controller => {
// this.mqttUnSub(controller.id + '/broadcast')
this.mqttUnSub(controller.id + '/file_meta_info/+')
this.mqttUnSub(controller.id + '/file_segment/+')
this.mqttUnSub(controller.id + '/file_segment_get/+')
})
},
...mapActions('neuliveExcel',
[
types.download.init,
types.download.rawDataByIDs,
types.export.createHeadersString,
types.export.createTitlesString,
types.export.createDataString,
types.export.closeFileStream,
],
),
...mapMutations('neuliveExcel',
[
types.download.setDownloading,
types.download.removeDownloadBuffer,
],
),
...mapGetters('neuliveExcel',
[
types.download.getByIndex,
types.download.getDownloading,
types.download.getAll,
types.download.getRemainIDLength,
],
),
},
openPortal () {
this.windowRef = window.open('', '', 'width=600,height=400,left=200,top=200')
this.windowRef.document.body.appendChild(this.$el)
// copyStyles(window.document, this.windowRef.document)
this.windowRef.addEventListener('beforeunload', this.closePortal)
},
closePortal () {
if (this.windowRef) {
this.windowRef.close()
this.windowRef = null
this.$emit('close')
}
},
// watch: {
// loadingPercent(val) {
// if (val >= 100) {
// console.log('complete');
// clearInterval(this.interval)
// }
// }
// },
async mounted () {
await this.getControllerList()
// TODO authorization
this.pageMqttSub()
const metaIDList = this.$route.params.metaList.split('-')
await this.initDownload({ metaIDList: metaIDList, api: api })
this.setDownloadingDownload()
const downloadingFile = this.getDownloading
console.log('downloadingFile', downloadingFile)
console.log(this.getRemainIDLength(0))
// create headers and title
this.createHeadersStringExport()
this.createTitlesStringExport()
// let spliceDataNums = 0
let rowIndex = 0
// let columnIndex = 0
// // while (this.getRemainIDLength(0)) {
while (rowIndex < downloadingFile.needRows) {
for (const channel in downloadingFile.downloadIDList) {
const rawID = downloadingFile.downloadIDList[channel][rowIndex]
// console.log('rawID', channel, rawID)
if (rawID !== undefined) {
await this.rawDataByIDsDownload({
channel: channel,
rawDataIDList: rawID,
api: api,
})
}
}
this.createDataStringExport()
this.removeDownloadBufferDownload()
// console.log('end', downloadingFile)
rowIndex += 1
}
this.closeFileStreamExport()
// }
// if (downloadingFile.raw_data[channel].length >= 10) {
// spliceDataNums = 10
// } else {
// spliceDataNums = downloadingFile.raw_data[channel].length
// }
// const rawID = downloadingFile.raw_data[channel].splice(0, spliceDataNums)
// console.log('rawID', channel, rawID)
// await this.rawDataByIDsDownload({
// channel: channel,
// rawDataIDList: rawID,
// api: api,
// })
// }
// // console.log('end', downloadingFile)
// // export data
// this.createDataStringExport({})
// this.removeDownloadBufferDownload()
// }
// const rawData = await download.getAllRawDatas(meta.data[0])
// exportData.exportCSV(meta.data[0], rawData)
// await this.initMeta({ metaIDList: metaIDList, api: api })
},
destroyed () {
this.pageMqttUnSub()
},
}
</script>
<style>
.filter-button {
text-align: center;
}
</style>
+6 -19
View File
@@ -1,13 +1,6 @@
<template>
<div>
<div class="row">
<div class="flex md12 xl12 xs12 sm12" :style="AreaStyle">
<file-table :ref="'file_ref'" @download="addDownloadTask"/>
</div>
<div class="flex md12 xl12 xs12 sm12" :style="AreaStyle">
<!-- <download :ref="'download_ref'" @download="downloadingFile"></download> -->
</div>
</div>
<file-table :ref="'file_ref'"/>
</div>
</template>
@@ -24,11 +17,6 @@ export default {
data () {
return {
controllerList: [],
AreaStyle: {
height: 'auto',
'overflow-y': 'hidden',
'overflow-x': 'hidden',
},
}
},
methods: {
@@ -70,15 +58,15 @@ export default {
this.$refs.file_ref.currentPathIndex = file.getPathMaxIndex()
file.clearFileList()
const initCollection = await api.getCollectionsByName('admin')
const initCollection = await api.collection.getByName('admin')
if (initCollection.data !== 0) {
file.addPath(initCollection.data[0])
this.$refs.file_ref.currentPathIndex = file.getPathMaxIndex()
this.$refs.file_ref.currentInfo = initCollection.data[0]
const folders = await api.getCollectionsByParent('folder', initCollection.data[0].id)
const files = await api.getFolderMetaFileByParent('folder', initCollection.data[0].id)
const folders = await api.collection.getByParent('folder', initCollection.data[0].id)
const files = await api.meta.getByParent('folder', initCollection.data[0].id)
file.updateFileList(folders)
file.updateFileList(files)
@@ -91,7 +79,8 @@ export default {
},
async mounted () {
await this.getControllerList()
await api.getJwtData()
await api.auth.getJwtData()
console.log(await api.meta.getByParentWithLimit('folder', 2, 5, 0, 'DESC'))
this.pageMqttSub()
this.pageInitPub()
},
@@ -102,5 +91,3 @@ export default {
},
}
</script>
<style lang="scss">
</style>
+51 -35
View File
@@ -45,19 +45,29 @@
v-model="showModal.deleteFile"
size="small"
:title="'DELETE'"
:message="`Delete File ${deleteInfo.name}.`"
:message="`Delete File ${deleteInfo.name}?`"
:okText=" $t('modal.confirm') "
@ok="deleteFile()"
>
</va-modal>
<va-modal
v-model="showModal.deleteMultiFiles"
size="small"
:title="'DELETE'"
:message="'Delete select files?'"
:okText=" $t('modal.confirm') "
@ok="deleteMultiFiles()"
>
</va-modal>
<va-card class="flex sm12 xl12 md12 xs12">
<template slot="header">
<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="deleteSelected" target="_blank" small>
<va-button class="" color="danger" v-if="selected.length" @click="deleteMultiFilesConfirm" target="_blank" small>
DELETE
</va-button>
</div>
@@ -164,14 +174,20 @@
</template>
<template slot="actions" slot-scope="props" >
<va-popover :message="`download ${props.rowData.name} in csv format`" placement="top">
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder'" @click.stop="downloadCsv(props.rowData)"/>
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Neulive') >= 0" @click.stop="downloadCsv(props.rowData)"/>
</va-popover>
<va-popover :message="`download ${props.rowData.name} in excel format`" placement="top">
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder'" @click.stop="downloadExcel(props.rowData)"/>
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Elite') >= 0" @click.stop="downloadExcel(props.rowData)"/>
</va-popover>
<va-popover :message="`download ${props.rowData.name} in csv-edf format`" placement="top">
<va-button flat small color="gray" icon="fa fa-download" v-if="props.rowData.type !== 'folder' && props.rowData.device.library_name.indexOf('Neulive') >= 0" @click.stop="downloadExcel(props.rowData)"/>
</va-popover>
<va-popover :message="`replay ${props.rowData.name}`" placement="top">
<va-button flat small color="gray" icon="fa fa-eye" v-if="props.rowData.type !== 'folder'" @click.stop="replay(props.rowData)"/>
</va-popover>
<va-popover :message="`spike ${props.rowData.name}`" placement="top">
<va-button flat small color="gray" icon="fa fa-filter" v-if="props.rowData.type !== 'folder'" @click.stop="spike(props.rowData)"/>
</va-popover>
<va-popover :message="`edit ${props.rowData.name}`" placement="top">
<va-button flat small color="gray" icon="fa fa-pencil" @click.stop="editFileConfirm(props.rowData)"/>
</va-popover>
@@ -211,6 +227,7 @@ export default {
showModal: {
createFolder: false,
deleteFile: false,
deleteMultiFiles: false,
editFile: false,
},
@@ -327,7 +344,7 @@ export default {
// },
select: function (file) {
event.stopPropagation()
const idx = this.fileLists.findIndex(f => f.name === file.name)
const idx = this.fileLists.findIndex(f => f.id === file.id)
this.fileLists[idx].checked = !this.fileLists[idx].checked
},
search: debounce(function (term) {
@@ -368,8 +385,8 @@ export default {
this.currentPathIndex = file.getPathMaxIndex()
// call getfolder api and update
const folders = await api.getCollectionsByParent('folder', info.id)
const files = await api.getFolderMetaFileByParent('folder', info.id)
const folders = await api.collection.getByParent('folder', info.id)
const files = await api.meta.getByParent('folder', info.id)
file.updateFileList(folders)
file.updateFileList(files)
@@ -388,8 +405,8 @@ export default {
this.currentPathIndex = file.getPathMaxIndex()
this.currentInfo = item
// call getfolder api and update
const folders = await api.getCollectionsByParent('folder', item.id)
const files = await api.getFolderMetaFileByParent('folder', item.id)
const folders = await api.collection.getByParent('folder', item.id)
const files = await api.meta.getByParent('folder', item.id)
file.updateFileList(folders)
file.updateFileList(files)
@@ -405,12 +422,12 @@ export default {
this.currentPathIndex = -1
// call getfolder api and update
const initCollection = await api.getCollectionsByParentName('folder', 0, 'root')
const initCollection = await api.collection.getByParentName('folder', 0, 'root')
if (initCollection.data.length === 1) {
this.currentInfo = initCollection.data[0]
const folders = await api.getCollectionsByParent('folder', initCollection.data[0].id)
const files = await api.getFolderMetaFileByParent('folder', initCollection.data[0].id)
const folders = await api.collection.getByParent('folder', initCollection.data[0].id)
const files = await api.meta.getByParent('folder', initCollection.data[0].id)
file.updateFileList(folders)
file.updateFileList(files)
this.fileLists = file.getFileList()
@@ -428,7 +445,7 @@ export default {
this.setInputFieldError(this.createInfo.errorMessagesAll[0] + ' ' + illegalChar[0], this.createInfo)
} else {
// folder name existed
const existedFolder = await api.getCollectionsByParentName(this.currentInfo.type, this.currentInfo.id, term)
const existedFolder = await api.collection.getByParentName(this.currentInfo.type, this.currentInfo.id, term)
if (existedFolder.data.length === 0) {
this.setInputFieldSuccess(this.createInfo)
} else {
@@ -444,7 +461,7 @@ export default {
createFolder: async function () {
const parent = [].concat((this.pathLists.length === 0) ? this.currentInfo.id : this.pathLists[this.pathLists.length - 1].id)
const type = 'folder'
await api.createCollection({
await api.collection.create({
name: this.createInfo.changedName,
parent: { [type]: parent },
type: type,
@@ -469,7 +486,7 @@ export default {
editFile: async function () {
// TODO editFile
if (this.editInfo.type !== 'folder') {
await api.updateMetaFile(this.editInfo.info.id, { name: this.editInfo.changedName })
await api.meta.update(this.editInfo.info.id, { name: this.editInfo.changedName })
} else {
}
await this.editFileDone()
@@ -543,20 +560,8 @@ export default {
}
},
async deleteSingleFileByDeleteInfo () {
for (const item of this.deleteInfo.rawChannelAndIDArrays) {
const channel = item[0]
const id = item[1]
await api.updateRawFile(channel, id, { deleted: true })
await api.clearDeleteRawFile(channel, id)
}
for (const item of this.deleteInfo.miniChannelAndIDArrays) {
const channel = item[0]
const id = item[1]
await api.updateMiniFile(channel, id, { deleted: true })
await api.clearDeleteMiniFile(channel, id)
}
await api.updateMetaFile(this.deleteInfo.metaID, { deleted: true })
await api.clearDeleteMetaFile(this.deleteInfo.metaID)
await api.meta.update(this.deleteInfo.metaID, { deleted: true })
await api.meta.clearDel()
},
deleteFileConfirm: function (info) {
this.fillDeleteInfo(info)
@@ -578,6 +583,12 @@ export default {
position: 'bottom-right',
})
},
deleteMultiFilesConfirm: function () {
this.showModal.deleteMultiFiles = true
},
deleteMultiFiles: async function () {
this.deleteSelected()
},
inputFieldReset: function (info) {
info.name = ''
info.changedName = ''
@@ -603,8 +614,8 @@ export default {
file.clearFileList()
// call getfolder api and update
const folders = await api.getCollectionsByParent('folder', this.currentInfo.id)
const files = await api.getFolderMetaFileByParent('folder', this.currentInfo.id)
const folders = await api.collection.getByParent('folder', this.currentInfo.id)
const files = await api.meta.getByParent('folder', this.currentInfo.id)
file.updateFileList(folders)
file.updateFileList(files)
@@ -637,17 +648,17 @@ export default {
downloadCsv: async function (meta) {
const href = location.href.split('/')[2]
if (meta.device.library_name.indexOf('Elite') >= 0) {
window.open('http://' + href + '/#/admin/download/elite/csv/' + meta.id, '_blank', 'width=500,height=100,left=200,top=200')
window.open('http://' + href + '/#/download/csv/' + meta.id)
} else if (meta.device.library_name.indexOf('Neulive') >= 0) {
window.open('http://' + href + '/#/admin/download/neulive/csv/' + meta.id, '_blank', 'width=500,height=100,left=200,top=200')
window.open('http://' + href + '/#/download/csv/' + meta.id)
}
},
downloadExcel: async function (meta) {
const href = location.href.split('/')[2]
if (meta.device.library_name.indexOf('Elite') >= 0) {
window.open('http://' + href + '/#/admin/download/elite/excel/' + meta.id, '_blank', 'width=500,height=100,left=200,top=200')
window.open('http://' + href + '/#/download/excel/' + meta.id)
} else if (meta.device.library_name.indexOf('Neulive') >= 0) {
window.open('http://' + href + '/#/admin/download/neulive/csv/' + meta.id + '/true', '_blank', 'width=500,height=100,left=200,top=200')
window.open('http://' + href + '/#/download/csv-edf/' + meta.id)
}
},
replay: function (meta) {
@@ -663,6 +674,11 @@ export default {
})
}
},
spike: function (meta) {
this.$router.push({
path: '/admin/data-spike/' + meta.id,
})
},
},
mounted () {
},
@@ -1,146 +0,0 @@
<template>
<div class="modal">
<va-modal
v-model="showModal"
size="small"
:title=" $t('Set condition')"
:okText=" $t('modal.confirm') "
:cancelText=" $t('modal.cancel') "
@ok="sendCondition"
@cancel="cancel"
>
<va-input
v-if="isTmp"
v-model="conditionAlias"
:label="$t('Condition name')"
required
/>
<p v-if="!isTmp"> {{ 'Condition name: '.concat(conditionAlias) }} </p>
<div
v-for="condition in conditions"
:key="condition.id"
>
<div class="flex row align--center">
<va-input
v-model="condition.startTime"
:label="$t('StartTime')"
/>
<va-input
v-model="condition.duration"
:label="$t('Duration')"
/>
<va-icon
name="ion ion-md-close"
color="info"
class="ml-2 pa-1 shrink"
style="cursor: pointer;"
@click.native="removeConditionButton(condition)"
/>
<select class="param-selection" v-model="condition.paramID">
<option v-for="(option, key) in allParams" :key="key" :value="key" >{{ option.paramsSet.alias }}</option>
</select>
</div>
</div>
<va-button class="mb-2" @click="addConditionButton()">
Add new condition
</va-button>
</va-modal>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import types from '@/store/modules/project/content/types'
import { getUniqueID } from '@/data/tool'
export default {
name: 'ConditionWindow',
components: {
},
computed: {
...mapGetters('projectContent', {
allParams: types.params.getAll,
}),
},
props: {
conditionID: {
type: String,
},
conditionName: {
type: String,
default: '',
},
},
data () {
return {
conditionAlias: this.conditionName,
conditions: [],
backupConditions: [],
showModal: false,
isTmp: false,
}
},
mqtt: {
},
methods: {
...mapActions('projectContent', [types.devices.updateSetting]),
...mapActions('projectContent', [types.params.updateTmp]),
backupCondition () {
this.backupConditions = JSON.parse(JSON.stringify(this.conditions)) // deep copy
},
restoreToBackupCondition () {
this.conditions = JSON.parse(JSON.stringify(this.backupConditions)) // deep copy
},
addConditionButton () {
const firstKey = Object.keys(this.allParams)[0]
const id = getUniqueID()
const condition = {
id: id,
startTime: 0,
duration: 0,
paramID: firstKey,
}
this.conditions.push(condition)
},
removeConditionButton (condition) {
this.conditions = this.conditions.filter(conditionToFilter => conditionToFilter.id !== condition.id)
},
async sendCondition () {
await this.updateSettingDevice({ conditionID: this.conditionID, alias: this.conditionAlias, conditions: this.conditions })
this.showModal = false
if (this.isTmp) {
this.conditions = []
this.conditionAlias = ''
this.isTmp = false
}
this.backupCondition()
this.$emit('updateParentView')
},
cancel () {
this.showModal = false
if (this.isTmp) {
this.conditionAlias = ''
this.isTmp = false
}
this.restoreToBackupCondition()
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -1,181 +0,0 @@
<template>
<div class="modal">
<va-modal
v-model="showModal"
size="small"
:title=" $t('Set timer and parameters')"
:okText=" $t('modal.confirm') "
:cancelText=" $t('modal.cancel') "
@ok="sendMapping"
@cancel="cancel"
>
Use condition template
<select class="condition-selection" v-model="selectedTemplateID" @change="onChangeTemplate($event)">
<option v-for="(condition, key) in allConditions" :key="key" :value="key" >{{ condition.alias }}</option>
</select>
<br/>
<div
v-for="mapping in mappings"
:key="mapping.id"
>
<div class="flex row align--center">
<va-input
v-model="mapping.startTime"
:label="$t('StartTime')"
/>
<va-input
v-model="mapping.duration"
:label="$t('Duration')"
/>
<va-icon
name="ion ion-md-close"
color="info"
class="ml-2 pa-1 shrink"
style="cursor: pointer;"
@click.native="removeMappingButton(mapping)"
/>
<select class="param-selection" v-model="mapping.paramID">
<option v-for="(option, key) in allParams" :key="key" :value="key" >{{ option.paramsSet.alias }}</option>
</select>
</div>
</div>
<va-button class="mb-2" @click="addMappingButton()">
Add new mapping
</va-button>
</va-modal>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import types from '@/store/modules/project/content/types'
import { getUniqueID } from '@/data/tool'
export default {
name: 'DeviceAndConditionMapping',
components: {
},
computed: {
...mapGetters('projectContent', {
allConditions: types.devices.getAllConditions,
}),
...mapGetters('projectContent', {
allParams: types.params.getAll,
}),
},
props: {
taskID: {
type: String,
required: true,
},
deviceID: {
type: String,
required: true,
},
deviceName: {
type: String,
default: 'Neulive',
},
},
data () {
return {
mappings: [],
backupMappings: [],
showModal: false,
selectedTemplateID: '',
lastSelectedID: '',
}
},
mqtt: {
},
methods: {
...mapActions('projectContent', [types.tasks.updateMapping, types.tasks.deleteMapping]),
...mapActions('projectContent', [types.params.updateTmp]),
getDefaultMapping () {
const firstKey = Object.keys(this.allParams)[0]
const id = getUniqueID()
const startConditionID = getUniqueID()
const durationConditionID = getUniqueID()
const startRecordingID = getUniqueID()
const endRecordingID = getUniqueID()
const startStimulationID = getUniqueID()
const endStimulationID = getUniqueID()
const mapping = {
id: id,
deviceID: this.deviceID,
startTime: 0,
duration: 0,
paramID: firstKey,
startConditionID: startConditionID,
durationConditionID: durationConditionID,
startRecordingID: startRecordingID,
endRecordingID: endRecordingID,
startStimulationID: startStimulationID,
endStimulationID: endStimulationID,
}
return mapping
},
backupMapping () {
this.backupMappings = JSON.parse(JSON.stringify(this.mappings)) // deep copy
},
restoreToBackupMapping () {
this.mappings = JSON.parse(JSON.stringify(this.backupMappings)) // deep copy
},
resetMapping () {
this.mappings = []
},
addMappingButton () {
const mapping = this.getDefaultMapping()
this.mappings.push(mapping)
},
async removeMappingButton (mapping) {
await this.deleteMappingTask({ taskID: this.taskID, mapping: mapping })
this.mappings = this.mappings.filter(mappingToFilter => mappingToFilter.id !== mapping.id)
},
async sendMapping () {
await this.updateMappingTask({ taskID: this.taskID, mappingList: this.mappings })
this.showModal = false
this.backupMapping()
this.lastSelectedID = this.selectedTemplateID
},
cancel () {
this.showModal = false
this.selectedTemplateID = this.lastSelectedID
this.restoreToBackupMapping()
},
onChangeTemplate (event) {
this.resetMapping()
const conditions = this.allConditions[this.selectedTemplateID]
for (const [_key, _value] of Object.entries(conditions)) {
var mapping = this.getDefaultMapping()
if (_key !== 'alias') {
mapping.id = _key
for (const [_k, _v] of Object.entries(_value)) {
mapping[_k] = _v
}
this.mappings.push(mapping)
}
}
this.backupMapping()
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -1,205 +0,0 @@
<template>
<div class="flex" >
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
Record
<div
style='display: inline-block;'
v-for="channel in [1, 2, 3, 4, 5, 6, 7, 8]"
:key="channel"
>
<va-button
class="mx-1 px-1"
v-if="channelList != null && channelList.indexOf(channel) >= 0"
@click="channelClickRemove(channel)"
small
>
{{channel}}
</va-button>
<va-button
class="mx-1 px-1"
v-if="channelList == null || channelList.indexOf(channel) < 0"
@click="channelClickAdd(channel)"
small outline
>
{{channel}}
</va-button>
</div>
</div>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
:on-change="ampGainSelectChange()"
:label="''"
v-model="ampGainSelect"
textBy="description"
:options="ampGainOptions"
/>
</div>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="sampleRateChange(4)">
4
</va-button>
<va-input
@keyup.enter="sampleRateChange(sampleRateInput)"
v-model="sampleRateInput"
class="mb-0"
style="width: 100px;"
>
<p slot="append" style="margin-right: 0;" small>
Hz
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="sampleRateChange(1000)">
1000
</va-button>
</div>
<va-slider
@mouseup.native="sampleRateChange(sampleRate)"
@mouseleave.native="sampleRateChange(sampleRate)"
@touchend.native="sampleRateChange(sampleRate)"
class="flex sm12 xl12 md12 xs12"
value-visible
v-model="sampleRate"
:min="4"
:max="1000"
/>
</div>
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
import types from '@/store/modules/project/content/types'
export default {
name: 'NeuliveParameterRecording',
components: {
},
data () {
return {
channelList: [],
ampGainOptions: [
{
id: 0,
description: '25',
},
{
id: 1,
description: '100',
},
{
id: 2,
description: '400',
},
{
id: 3,
description: '800',
},
],
ampGainSelect: { id: 2, description: '400' },
sampleRateInput: '1000',
sampleRate: 1000,
tmpParam: {},
}
},
mqtt: {
},
methods: {
...mapActions('projectContent', [types.params.updateTmp]),
init () {
this.tmpParam = { paramsSet: { recording: { RECORDING_CH: 0, AMP_GAIN: 1, ADC_CLOCK: parseInt(parseFloat(1 / parseFloat(this.sampleRate / 200)) * 1000) } } }
},
reset () {
this.tmpParam = { paramsSet: { recording: {} } }
},
async channelClickAdd (val) {
if (this.channelList.indexOf(val) < 0) {
this.channelList.push(val)
let channelSet = ''
for (let i = 8; i >= 1; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
this.updateTmp('RECORDING_CH', channelValue)
await this.updateTmpParam(this.tmpParam)
}
},
async channelClickRemove (val) {
if (this.channelList.indexOf(val) >= 0) {
this.channelList.splice(this.channelList.indexOf(val), 1)
let channelSet = ''
for (let i = 8; i >= 1; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
this.updateTmp('RECORDING_CH', channelValue)
await this.updateTmpParam(this.tmpParam)
}
},
async ampGainSelectChange () {
if (this.ampGainSelect != null) {
this.updateTmp('AMP_GAIN', (this.ampGainSelect.id + 3) % 4)
await this.updateTmpParam(this.tmpParam)
}
},
async sampleRateChange (val) {
if (this.sampleRate == null) {
return false
}
if (isNaN(val) || parseInt(val) > 1000 || parseInt(val) < 4) {
this.sampleRateInput = '1000'
this.sampleRate = 1000
return false
}
if (parseInt(this.sampleRateInput) !== this.sampleRate || this.sampleRate !== parseInt(val)) {
this.sampleRateInput = String(val)
this.sampleRate = parseInt(val)
}
this.updateTmp('ADC_CLOCK', parseInt(parseFloat(1 / parseFloat(this.sampleRate / 200)) * 1000))
await this.updateTmpParam(this.tmpParam)
},
updateTmp (key, value) {
this.tmpParam.paramsSet.recording[key] = value
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
async created () {
this.init()
await this.updateTmpParam(this.tmpParam)
},
async destroyed () {
this.reset()
},
watch: {
},
}
</script>
@@ -1,678 +0,0 @@
<template>
<div class="flex">
<div>
Stimulate
<div class="mt-4">
<div class="row sm12 xl12 md12 xs12">
<p class="display-6">ELECTRODE</p>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-button-toggle
:on-change="stimulateElectrodeSelectChange()"
small
outline
v-model="stimulateElectrodeSelect"
:options="stimulateElectrodeOptions"
/>
</div>
</div>
</div>
<div class="mt-4">
<div class="row sm12 xl12 md12 xs12">
<p class="display-6">CHANNELS</p>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div
style='display: inline-block;'
v-for="channel in [1, 2, 3, 4, 5, 6, 7, 8]"
:key="channel"
>
<va-button
class="mx-1 px-2"
color="success"
v-if="posChannelList.indexOf(channel) >= 0 && negChannelList.indexOf(channel) < 0"
@click="channelClick(channel)"
small
>
{{channel}}
</va-button>
<va-button
class="mx-1 px-2"
color="danger"
v-if="posChannelList.indexOf(channel) < 0 && negChannelList.indexOf(channel) >= 0"
@click="channelClick(channel)"
small
>
{{channel}}
</va-button>
<va-button
class="mx-1 px-2"
v-if="posChannelList.indexOf(channel) < 0 && negChannelList.indexOf(channel) < 0"
@click="channelClick(channel)"
small outline
>
{{channel}}
</va-button>
</div>
</div>
</div>
</div>
<div class="mt-4">
<div class="row sm12 xl12 md12 xs12">
<p class="display-6">CYCLE NUMBER</p>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-button-toggle
:on-change="cycleNumberSelectChange()"
small
outline
v-model="cycleNumberSelect"
:options="cycleNumberOptions"
/>
</div>
</div>
<div class="row" v-if="cycleNumberSelect==0">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="cycleNumberChange(1)">
1
</va-button>
<va-input
@keyup.enter="cycleNumberChange(cycleNumberInput)"
v-model="cycleNumberInput"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
Rounds
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="cycleNumberChange(256)">
256
</va-button>
</div>
<va-slider
class="flex sm12 xl12 md12 xs12"
@mouseup.native="cycleNumberChange(cycleNumber)"
@mouseleave.native="cycleNumberChange(cycleNumber)"
@touchend.native="cycleNumberChange(cycleNumber)"
value-visible
v-model="cycleNumber"
:min="1"
:max="256"
/>
</div>
</div>
</div>
<div class="mt-4">
<div class="row sm12 xl12 md12 xs12">
<p class="display-6">AMPLITUDE (uA)</p>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="amplitudeNumberChange(5)">
5
</va-button>
<va-input
@keyup.enter="amplitudeNumberChange(amplitudeNumberInput)"
v-model="amplitudeNumberInput"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
uA
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="amplitudeNumberChange(4000)">
4000
</va-button>
</div>
<va-slider
class="flex sm12 xl12 md12 xs12"
@mouseup.native="amplitudeNumberChange(amplitudeNumber)"
@mouseleave.native="amplitudeNumberChange(amplitudeNumber)"
@touchend.native="amplitudeNumberChange(amplitudeNumber)"
value-visible
v-model="amplitudeNumber"
:min="5"
:max="4000"
/>
</div>
</div>
</div>
<div class="mt-4">
<div class="row sm12 xl12 md12 xs12">
<p class="display-6">PATTERN</p>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-button-toggle
:on-change="patternModeSelectChange()"
small
outline
v-model="patternModeSelect"
:options="patternModeOptions"
/>
</div>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-button-toggle
small
outline
v-model="unitSelect"
:options="unitOptions"
@click.native="transUnit()"
/>
</div>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-input
v-model="frequencyNumberInput"
class="mb-0"
:label="'Frequency'"
@keyup.enter="frequencyNumberChange(frequencyNumberInput)"
>
<p slot="append" style="margin-right: 0;" small>
Hz
</p>
</va-input>
</div>
</div>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-input
v-model="periodNumberInput"
class="mb-0"
:label="'Period'"
@keyup.enter="periodNumberChange(periodNumberInput)"
>
<p slot="append" style="margin-right: 0;" small>
{{unitOptions[unitSelect].label}}
</p>
</va-input>
</div>
</div>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="patternModeSelect?timeRangeChange(1, 0):timeRangeChange(1, 0)">
0
</va-button>
<va-input
@keyup.enter="timeRangeChange(1, t1RangeInput)"
v-model="t1RangeInput"
class="mb-0"
:label="'T1 RANGE'"
>
<p slot="append" style="margin-right: 0;" small>
{{unitOptions[unitSelect].label}}
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(1, 10.23)">
10.23
</va-button>
</div>
</div>
</div>
<div class="row" v-if="patternModeSelect==1">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="timeRangeChange(2, 0)">
0
</va-button>
<va-input
@keyup.enter="timeRangeChange(2, t2RangeInput)"
v-model="t2RangeInput"
class="mb-0"
:label="'T2 RANGE'"
>
<p slot="append" style="margin-right: 0;" small>
{{unitOptions[unitSelect].label}}
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(2, 10.23)">
10.23
</va-button>
</div>
</div>
</div>
<div class="row" v-if="patternModeSelect==1">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="timeRangeChange(3, 0)">
0
</va-button>
<va-input
@keyup.enter="timeRangeChange(3, t3RangeInput)"
v-model="t3RangeInput"
class="mb-0"
:label="'T3 RANGE'"
>
<p slot="append" style="margin-right: 0;" small>
{{unitOptions[unitSelect].label}}
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(3, 10.23)">
10.23
</va-button>
</div>
</div>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="timeRangeChange(4, 0)">
0
</va-button>
<va-input
@keyup.enter="timeRangeChange(4, t4RangeInput)"
v-model="t4RangeInput"
class="mb-0"
:label="'T4 RANGE'"
>
<p slot="append" style="margin-right: 0;" small>
{{unitOptions[unitSelect].label}}
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(4, 1310.71)">
1310.71
</va-button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
import types from '@/store/modules/project/content/types'
export default {
name: 'NeuliveParameterStimulation',
components: {
},
data () {
return {
posChannelList: [2],
negChannelList: [1],
stimulateElectrodeSelect: null,
stimulateElectrodeOptions: [
{
label: 'Monopolar',
value: 0,
},
{
label: 'Bipolar',
value: 1,
},
],
cycleNumberSelect: null,
cycleNumberOptions: [
{
label: 'limite',
value: 0,
},
{
label: 'Unlimite',
value: 1,
},
],
cycleNumberInput: '1',
cycleNumber: 1,
cycleNumberArray: Array(9).fill(1),
amplitudeNumberInput: '50',
amplitudeNumber: 50,
patternModeSelect: null,
patternModeOptions: [
{
label: 'Monophasic',
value: 0,
},
{
label: 'Biphasic',
value: 1,
},
],
unitSelect: 1,
unitOptions: [
{
label: 's',
value: 0,
},
{
label: 'ms',
value: 1,
},
{
label: 'us',
value: 2,
},
],
unitMultiply: 1000,
// period = (t1 + t2 + t3 + t4) * 10
frequencyNumberInput: '0',
frequencyNumber: 0,
periodNumberInput: '0',
periodNumber: 0,
t1RangeInput: '0',
t1Range: 0,
t1RangeArray: Array(9).fill(0),
t2RangeInput: '0',
t2Range: 0,
t2RangeArray: Array(9).fill(0),
t3RangeInput: '0',
t3Range: 0,
t3RangeArray: Array(9).fill(0),
t4RangeInput: '0',
t4Range: 0,
t4RangeArray: Array(9).fill(0),
tmpParam: {},
}
},
computed: {
},
mqtt: {
},
methods: {
...mapActions('projectContent', [types.params.updateTmp]),
refresh () {
console.log('[TODO] stimulation refresh')
},
init () {
this.tmpParam = { paramsSet: { stimulation: { STI_H_BRIDGE: 1, CONTINUOUS_STI: 1, STI_CYCLE_LIST: '0:9=' + this.cycleNumberArray.toString(), STI_AMPLITUDE: 0, STI_PATTERN: 1, STI_CHANNEL: 0, STI_POLARITY: 0, STI_T1: '0:9=' + String(this.t1RangeArray), STI_T2: '0:9=' + String(this.t2RangeArray), STI_T3: '0:9=' + String(this.t3RangeArray), STI_T4: '0:9=' + String(this.t4RangeArray) } } }
},
reset () {
this.tmpParam = { paramsSet: { stimulation: {} } }
},
transUnit () {
if (this.unitSelect === 0) {
this.unitMultiply = 1000000
} else if (this.unitSelect === 1) {
this.unitMultiply = 1000
} else {
this.unitMultiply = 1
}
this.refresh()
},
async stimulateElectrodeSelectChange () {
if (this.stimulateElectrodeSelect == null) {
return false
}
this.updateTmp('STI_H_BRIDGE', this.stimulateElectrodeSelect)
await this.updateTmpParam(this.tmpParam)
},
channelClick (val) {
if (this.posChannelList.indexOf(val) >= 0) {
this.posChannelList.splice(this.posChannelList.indexOf(val), 1)
this.negChannelList.push(val)
} else if (this.negChannelList.indexOf(val) >= 0) {
this.negChannelList.splice(this.negChannelList.indexOf(val), 1)
} else {
this.posChannelList.push(val)
}
this.updateStiChannel()
},
async cycleNumberSelectChange () {
if (this.cycleNumberSelect == null) {
return false
}
this.updateTmp('CONTINUOUS_STI', this.cycleNumberSelect)
await this.updateTmpParam(this.tmpParam)
},
async cycleNumberChange (val) {
if (isNaN(val) || parseInt(val) > 256 || parseInt(val) < 1) {
this.cycleNumberInput = '1'
this.cycleNumber = 1
}
this.cycleNumberInput = String(val)
this.cycleNumber = parseInt(val)
if (this.cycleNumberArray[0] !== this.cycleNumber) {
this.cycleNumberArray.fill(this.cycleNumber, 0)
this.updateTmp('STI_CYCLE_LIST', '0:9=' + this.cycleNumberArray.toString())
await this.updateTmpParam(this.tmpParam)
}
},
async amplitudeNumberChange (val) {
if (this.amplitudeNumber == null) {
return false
}
if (typeof (val) === 'string') {
if (isNaN(val) || parseInt(val) > 4000 || parseInt(val) < 5) {
this.amplitudeNumberInput = '50'
this.amplitudeNumber = 50
}
if (parseInt(this.amplitudeNumberInput) !== parseInt(this.amplitudeNumber)) {
this.amplitudeNumber = parseInt(val)
}
} else {
if (isNaN(val) || parseInt(val) > 4000 || parseInt(val) < 5) {
this.amplitudeNumberInput = '50'
this.samplitudeNumber = 50
}
if (parseInt(this.amplitudeNumberInput) !== parseInt(this.amplitudeNumber) || this.amplitudeNumber !== val) {
this.amplitudeNumberInput = String(val)
this.amplitudeNumber = val
}
}
this.updateTmp('STI_AMPLITUDE', parseInt(this.amplitudeNumber / 5))
await this.updateTmpParam(this.tmpParam)
},
async patternModeSelectChange () {
if (this.patternModeSelect == null) {
return false
}
if (this.patternModeSelect === 0) {
this.t2Range = 0
this.t2RangeInput = '0'
this.t3Range = 0
this.t3RangeInput = '0'
this.t4Range = (this.periodNumber / 10) - this.t1Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
} else {
this.t3Range = this.t1Range
this.t3RangeInput = this.t1RangeInput
this.t4Range = (this.periodNumber / 10) - this.t1Range - this.t2Range - this.t3Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
}
this.updateTmp('STI_PATTERN', this.patternModeSelect)
await this.updateTmpParam(this.tmpParam)
},
frequencyNumberChange (val) {
if (this.frequencyNumberInput == null) {
return false
}
if (typeof (val) === 'string') {
if (isNaN(val) || parseInt(val) < 1 || parseInt(val) > 10000) {
this.frequencyNumberInput = '100'
this.frequencyNumber = 100
}
if (parseInt(this.frequencyNumberInput) !== parseInt(this.frequencyNumber)) {
this.frequencyNumber = parseInt(val)
}
}
this.periodNumber = (1 / this.frequencyNumber * 1e6).toFixed(3)
this.periodNumberInput = String(this.periodNumber / this.unitMultiply)
if (this.t1Range === 0 || this.t3Range === 0) {
this.t1Range = 10
this.t1RangeInput = String((this.t1Range * 10) / this.unitMultiply)
this.t3Range = 10
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
this.t4Range = (this.periodNumber / 10) - (this.t1Range + this.t2Range + this.t3Range)
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
} else {
this.t4Range = (this.periodNumber / 10) - (this.t1Range + this.t2Range + this.t3Range)
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
}
this.updateTimeRange()
},
periodNumberChange (val) {
if (this.periodNumberInput === null) {
return false
}
if (typeof (val) === 'string') {
if (isNaN(val) || parseFloat(val) < 0 || parseFloat(val / this.unitMultiply) > 1) {
this.periodNumber = 1000
this.periodNumberInput = String(this.periodNumber / this.unitMultiply)
}
if (parseInt(this.periodNumberInput) !== parseInt(this.periodNumber)) {
this.periodNumber = parseFloat(val * this.unitMultiply)
this.periodNumberInput = val
}
}
this.frequencyNumber = parseInt(1 / (this.periodNumber * 1e-6))
this.frequencyNumberInput = String(this.frequencyNumber)
if (this.t1Range === 0 || this.t3Range === 0) {
this.t1Range = 10
this.t1RangeInput = String((this.t1Range * 10) / this.unitMultiply)
this.t3Range = 10
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
this.t4Range = (this.periodNumber / 10) - (this.t1Range + this.t2Range + this.t3Range)
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
} else {
this.t4Range = (this.periodNumber / 10) - (this.t1Range + this.t2Range + this.t3Range)
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
}
this.updateTimeRange()
},
timeRangeChange (stiIimeSelect, val) {
switch (stiIimeSelect) {
case 1:
this.t1Range = parseInt((val * this.unitMultiply) / 10)
this.t1RangeInput = val
this.t3Range = parseInt((val * this.unitMultiply) / 10)
this.t3RangeInput = val
break
case 2:
this.t2Range = parseInt((val * this.unitMultiply) / 10)
this.t2RangeInput = val
break
case 3:
this.t1Range = parseInt((val * this.unitMultiply) / 10)
this.t1RangeInput = val
this.t3Range = parseInt((val * this.unitMultiply) / 10)
this.t3RangeInput = val
break
case 4:
this.t4Range = parseInt((val * this.unitMultiply) / 10)
this.t4RangeInput = val
if (this.frequencyNumber > 0) {
this.t2Range = (this.periodNumber / 10) - this.t1Range - this.t3Range - this.t4Range
this.t2RangeInput = String((this.t2Range * 10) / this.unitMultiply)
}
break
}
if (this.frequencyNumber > 0 && stiIimeSelect !== 4) {
this.t4Range = (this.periodNumber / 10) - this.t1Range - this.t2Range - this.t3Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
}
this.updateTimeRange()
},
async updateStiChannel () {
// stiChannelSet (+,-), stiPolaritySet (+)
let stiChannelSet = ''
let stiPolaritySet = ''
for (let i = 8; i >= 1; i--) {
if (this.posChannelList.indexOf(i) >= 0) {
stiChannelSet += '1'
stiPolaritySet += '1'
} else if (this.negChannelList.indexOf(i) >= 0) {
stiChannelSet += '1'
stiPolaritySet += '0'
} else {
stiChannelSet += '0'
stiPolaritySet += '0'
}
}
const stiChannelValue = parseInt(stiChannelSet, 2)
const stiPolarityValue = parseInt(stiPolaritySet, 2)
this.updateTmp('STI_CHANNEL', stiChannelValue)
this.updateTmp('STI_POLARITY', stiPolarityValue)
await this.updateTmpParam(this.tmpParam)
},
async updateTimeRange () {
if (this.t1RangeArray[0] !== this.t1Range) {
this.t1RangeArray.fill(this.t1Range, 0)
this.updateTmp('STI_T1', '0:9=' + String(this.t1RangeArray))
await this.updateTmpParam(this.tmpParam)
}
if (this.t2RangeArray[0] !== this.t2Range) {
this.t2RangeArray.fill(this.t2Range, 0)
this.updateTmp('STI_T2', '0:9=' + String(this.t2RangeArray))
await this.updateTmpParam(this.tmpParam)
}
if (this.t3RangeArray[0] !== this.t3Range) {
this.t3RangeArray.fill(this.t3Range, 0)
this.updateTmp('STI_T3', '0:9=' + String(this.t3RangeArray))
await this.updateTmpParam(this.tmpParam)
}
if (this.t4RangeArray[0] !== this.t4Range) {
this.t4RangeArray.fill(this.t4Range, 0)
this.updateTmp('STI_T4', '0:9=' + String(this.t4RangeArray))
await this.updateTmpParam(this.tmpParam)
}
},
updateTmp (key, value) {
this.tmpParam.paramsSet.stimulation[key] = value
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
async created () {
this.init()
await this.updateTmpParam(this.tmpParam)
},
async destroyed () {
this.reset()
},
watch: {
},
}
</script>
@@ -1,119 +0,0 @@
<template>
<div class="flex">
<va-modal
v-model="showModal"
size="small"
:title=" $t('Set parameters')"
:okText=" $t('modal.confirm') "
:cancelText=" $t('modal.cancel') "
@ok="AddParams"
@cancel="Cancel"
>
<va-input
@input="paramAliasChange(paramAlias)"
v-model="paramAlias"
:label="$t('Parameter set name')"
required
/>
<va-item>
<va-item-section side>
<va-checkbox v-model="recordingCheck" />
</va-item-section>
<va-item-section>
<va-item-label>
Recording
</va-item-label>
</va-item-section>
</va-item>
<va-item>
<va-item-section side>
<va-checkbox v-model="stimulationCheck" />
</va-item-section>
<va-item-section>
<va-item-label>
Stimulation
</va-item-label>
</va-item-section>
</va-item>
<neulive-parameter-recording v-if="recordingCheck"/>
<br/>
<neulive-parameter-stimulation v-if="stimulationCheck"/>
</va-modal>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import types from '@/store/modules/project/content/types'
import NeuliveParameterRecording from './NeuliveParameterRecording'
import NeuliveParameterStimulation from './NeuliveParameterStimulation'
import { getUniqueID } from '@/data/tool'
export default {
name: 'NeuliveParameterWindow',
components: {
NeuliveParameterRecording,
NeuliveParameterStimulation,
},
computed: {
...mapGetters('projectContent', {
tmpParam: types.params.getTmp,
}),
},
data () {
return {
paramAlias: '',
showModal: false,
recordingCheck: false,
stimulationCheck: false,
}
},
mqtt: {
},
methods: {
...mapActions('projectContent', [types.params.add, types.params.delete, types.params.resetTmp, types.params.deleteTmp, types.params.updateTmp]),
async paramAliasChange () {
await this.updateTmpParam({ paramsSet: { alias: this.paramAlias, desc: '' } })
},
async AddParams () {
if (typeof this.tmpParam !== 'undefined') {
if (typeof this.tmpParam.recording !== 'undefined' || typeof this.tmpParam.stimulation !== 'undefined') {
if (typeof this.tmpParam.alias === 'undefined') {
await this.updateTmpParam({ paramsSet: { alias: getUniqueID() } })
}
await this.updateTmpParam({ paramsSet: { id: getUniqueID() } })
if (!this.recordingCheck) {
await this.deleteTmpParam({ key: 'recording' })
}
if (!this.stimulationCheck) {
await this.deleteTmpParam({ key: 'stimulation' })
}
await this.addParam({ id: getUniqueID(), paramsSet: this.tmpParam })
await this.resetTmpParam()
this.reset()
}
}
this.$emit('updateParentView')
},
async Cancel () {
await this.resetTmpParam()
this.reset()
},
reset () {
this.paramAlias = ''
this.recordingCheck = false
this.stimulationCheck = false
},
printTmpParam: function () {
console.log(this.tmpParam)
},
},
mounted () {
},
destroyed () {
},
}
</script>
-215
View File
@@ -1,215 +0,0 @@
<template>
<div id="Task">
<h3> {{ 'Task: '.concat(String(taskNum)) }} </h3>
<br/>
<p> {{ 'Time settings' }} </p>
<div slot="body">
<va-input
v-model="maxCycle"
:label="$t('Max cycle')"
:readonly="TimeSettingDone"
/>
Start time
<va-checkbox v-model="startImmediatelyCheck" :label="'Right Now'"/>
<VueCtkDateTimePicker v-model="startTimeStringFormat" v-show="!startImmediatelyCheck" :no-button-now=true label='Pick date and time' :disabled="TimeSettingDone" :format="'YYYY-MM-DDTHH:mm:ss'"/>
<br/>
<va-input
v-model="duration"
:label="$t('Duration')"
:readonly="TimeSettingDone"
/>
<va-button @click="SetTaskInit"> Next </va-button>
</div>
<div v-if="TimeSettingDone">
Connected Devices
<va-button v-for="(deviceID, index) in availableDeviceIDs" :key="index" @click="toggleMappingModal(index)">
<!-- {{ getDeviceByID(deviceID).device_name }} -->
{{ 'Neulive' }}
<device-and-condition-mapping :ref="'condition_mapping'" :taskID="taskID" :deviceID="deviceID" :deviceName="getDeviceByID(deviceID).device_name"/>
</va-button>
</div>
<div v-if="TimeSettingDone">
Condition settings
<va-button id='conditionSetting' @click="toggleConditionModal(tmpConditionID, -1)">
+
<condition-window :ref="'new_condition'" :conditionID="tmpConditionID" @updateParentView="updateView"/>
</va-button>
<br/>
<va-button v-for="(value, key, index) in allConditions" :key="key" @click="toggleConditionModal(key, index)">
{{ value.alias }}
<condition-window :ref="'exist_condition'" :conditionID="key" :conditionName="value.alias"/>
</va-button>
</div>
<div v-if="TimeSettingDone">
Parameters settings
<va-button id='paramSetting' @click="toggleParamModal()">
+
<neulive-parameter-window :ref="'parameter_window'" @updateParentView="updateView"/>
</va-button>
</div>
<div
v-for="(param, key) in allParams"
:key="key"
>
<va-list-label :key="key"> {{ processed_param(param) }} </va-list-label>
<!-- <va-icon
name="ion ion-md-close"
color="info"
class="ml-2 pa-1 shrink"
style="cursor: pointer;"
@click.native="removeParamButton(key)"
/> -->
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import types from '@/store/modules/project/content/types'
import NeuliveParameterWindow from './NeuliveParameterWindow'
import ConditionWindow from './ConditionWindow'
import DeviceAndConditionMapping from './DeviceAndConditionMapping'
import { getUniqueID } from '@/data/tool'
import VueCtkDateTimePicker from 'vue-ctk-date-time-picker'
import 'vue-ctk-date-time-picker/dist/vue-ctk-date-time-picker.css'
export default {
name: 'Task',
components: {
NeuliveParameterWindow,
DeviceAndConditionMapping,
ConditionWindow,
VueCtkDateTimePicker,
},
computed: {
...mapGetters('projectContent', {
allTasks: types.tasks.getAll,
}),
...mapGetters('projectContent', {
availableDeviceIDs: types.devices.getAllAvaliable,
getDeviceByID: types.devices.getByID,
allConditions: types.devices.getAllConditions,
}),
...mapGetters('projectContent', {
allParams: types.params.getAll,
tmpParam: types.params.getTmp,
}),
},
props: {
taskID: {
type: String,
required: true,
},
taskNum: {
type: Number,
},
},
async created () {
},
data () {
return {
maxCycle: 1,
startTimeStringFormat: '',
startTime: 0,
startImmediatelyCheck: false,
duration: '',
TimeSettingDone: false,
showParamModal: false,
tmpConditionID: null,
}
},
methods: {
...mapActions('projectContent', [types.tasks.update, types.tasks.setInfo]),
...mapActions('projectContent', [types.devices.add]),
...mapActions('projectContent', [types.params.add, types.params.delete, types.params.resetTmp, types.params.deleteTmp, types.params.updateTmp]),
toggleMappingModal (index) {
this.$refs.condition_mapping[index].showModal = true
},
toggleConditionModal (key, index) {
if (index === -1) {
this.tmpConditionID = getUniqueID()
this.$refs.new_condition.showModal = true
this.$refs.new_condition.isTmp = true
} else {
var oldConditions = []
for (const [_key, _value] of Object.entries(this.allConditions[key])) {
if (_key !== 'alias') {
var condition = Object.assign({}, _value)
condition.id = _key
oldConditions.push(condition)
}
}
this.$refs.exist_condition[index].conditions = oldConditions
this.$refs.exist_condition[index].showModal = true
}
},
toggleParamModal () {
this.$refs.parameter_window.showModal = true
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
async SetDuration () {
const dateTime = new Date(this.startTimeStringFormat).getTime()
this.startTime = Math.floor(dateTime / 1000)
if (this.isNumeric(this.startTime) && this.isNumeric(this.duration) && (this.duration > 0)) {
this.TimeSettingDone = true
var conditionID = getUniqueID()
var randomID = getUniqueID()
if (this.startImmediatelyCheck) {
this.startTime = 0
}
await this.setInfoTask({ taskID: this.taskID, infos: { conditions: { [conditionID]: { time: { absolute: { equal: this.startTime } } } }, actions: { [randomID]: { desc: 'task status running', condition: [conditionID], content: { '-1': 'start' } } } } })
conditionID = getUniqueID()
randomID = getUniqueID()
await this.setInfoTask({ taskID: this.taskID, infos: { conditions: { [conditionID]: { time: { relative: { equal: this.duration } } } }, actions: { [randomID]: { desc: 'task status done add cycle', condition: [conditionID], content: { '-1': 'done' } } } } })
} else {
this.pageToast('Please set start and end time correctly')
}
},
async SetTaskInit () {
await this.setInfoTask({ taskID: this.taskID, infos: { max_cycle: this.maxCycle } })
await this.SetDuration()
console.log(this.allTasks)
},
async removeParamButton (key) {
if (Object.keys(this.allParams).length > 1) {
await this.deleteParam({ id: key })
// this.$forceUpdate()
} else {
this.pageToast('[Notice] need to have at least one param setting')
}
},
updateView () {
this.$forceUpdate()
},
processed_param (param) {
const _param = param.paramsSet.alias.concat(': ', JSON.stringify(param.paramsSet))
return _param
},
isNumeric: function (n) {
return !isNaN(parseFloat(n)) && isFinite(n)
},
},
async mounted () {
},
destroyed () {
},
}
</script>
<style lang="scss">
</style>
-101
View File
@@ -1,101 +0,0 @@
<template>
<div id="ProjectContent">
<div class="tasks">
<va-button class="" color="primary" target="_blank" @click="AddTask()" small>
ADD TASK
</va-button>
<va-card stripe='info' :title="$t('AllTasks')" class='flex md12 xl4 xs12 sm12'>
<task v-for="(task, key, index) in allTasks" :key="key" :taskID="key" :taskNum="index+1"/>
</va-card>
</div>
<va-button @click="generateJson"> Generate Json </va-button>
</div>
</template>
<script>
import Task from './items/Task.vue'
import { mapActions, mapGetters } from 'vuex'
import types from '@/store/modules/project/content/types'
import { getUniqueID, getDefaultInstruction } from '@/data/tool'
export default {
name: 'ProjectContent',
components: {
Task,
},
computed: {
...mapGetters('projectContent', {
allTasks: types.tasks.getAll,
}),
...mapGetters('projectContent', {
allDevices: types.devices.getAll,
availableDeviceIDs: types.devices.getAllAvaliable,
}),
...mapGetters('projectContent', {
allParams: types.params.getAll,
}),
},
async created () {
await this.initAll()
},
data () {
return {
devices: [],
}
},
methods: {
...mapActions('projectContent', [types.tasks.init, types.tasks.add]),
...mapActions('projectContent', [types.devices.init]),
...mapActions('projectContent', [types.params.init]),
async initAll () {
await this.initTask({ id: getUniqueID(), desc: 'task description', instructions: getDefaultInstruction() })
await this.initDevice({ availableDevice: ['4'], deviceInfo: { 4: { battery: 0, device_name: '', device_address: [], device_version: '', library_name: '', library_version: '', serial_number: [], status: '', isSync: false, isStimulate: false, parent: '' } } })
await this.initParam({ id: getUniqueID(), paramsSet: { alias: 'default', desc: '', recording: { ADC_CLOCK: 200, AMP_GAIN: 0, RECORDING_CH: 0 } } })
},
async AddTask () {
await this.initAll()
this.$forceUpdate()
},
generateJson () {
var _json = { project: { desc: 'project description', available_device: this.availableDeviceIDs, tasks: {} } }
for (const [taskID, task] of Object.entries(this.allTasks)) {
_json.project.tasks[taskID] = { desc: task.desc, devices: {}, events: {}, triggers: {}, parameter_sets: {}, instructions: {}, actions: {}, conditions: {} }
_json.project.tasks[taskID].start = 'timestamp'
_json.project.tasks[taskID].status = 'prepare'
_json.project.tasks[taskID].max_cycle = 1
_json.project.tasks[taskID].cycle = 0
_json.project.tasks[taskID].devices = this.allDevices
for (const [paramID, param] of Object.entries(this.allParams)) {
_json.project.tasks[taskID].parameter_sets[paramID] = param.paramsSet
}
_json.project.tasks[taskID].instructions = task.instructions
_json.project.tasks[taskID].actions = task.actions
_json.project.tasks[taskID].conditions = task.conditions
}
console.log(_json)
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
watch: {
},
async mounted () {
},
destroyed () {
},
}
</script>
<style lang="scss">
</style>
@@ -11,16 +11,16 @@
<!-- {{ controller }} -->
<va-item :key="controller.device_mac" class="pa-0 ma-0"
>
<va-item-section avatar class="ml-2 mr-2">
<va-item-section avatar class="ml-4 mr-4">
<img
:src="getImageUrl()"
:alt="'BPS-CONTROLLER'"
width="300px"
height="300px"
width="200px"
height="200px"
contain
/>
</va-item-section>
<va-item-section class="ml-4" >
<va-item-section class="ml-5 mr-4" >
<va-item-label style="font-size: 2rem;">
{{ controller.wifi_name }}
</va-item-label>
@@ -46,7 +46,7 @@
<script>
import { mapActions, mapGetters, mapMutations } from 'vuex'
import api from '@/data/api/index'
import types from '@/store/modules/about/types'
import types from '@/store/modules/setting/types'
import eliteImgUrl from '@/assets/img/elite_img.png'
export default {
@@ -92,12 +92,13 @@ export default {
getImageUrl () {
return eliteImgUrl
},
...mapActions('about', [types.controller.init]),
...mapMutations('about', [types.controller.set, types.controller.updateByIndex]),
...mapGetters('about', [types.controller.getAll]),
...mapActions('setting', [types.controller.init]),
...mapMutations('setting', [types.controller.set, types.controller.updateByIndex]),
...mapGetters('setting', [types.controller.getAll]),
},
async mounted () {
this.initController({ api: api })
console.log(this.getAllController())
},
destroyed () {
},
@@ -105,13 +106,12 @@ export default {
</script>
<style lang="scss">
.area-style {
.area-style-setting-controller {
height: auto;
overflow-y: hidden;
overflow-x: hidden;
@include media-breakpoint-only(xl) {
height: 48vh;
overflow-y: scroll;
overflow-x: hidden;
}
@@ -1,10 +1,10 @@
<template>
<div class="device-info">
<div class="row flex">
<draggable class="flex d-flex sm12 xl12 md12 xs12" v-model="devices" @start="drag=true" @end="drag=false" >
<draggable class="flex d-flex sm12 xl12 md12 xs12" v-model="devicesList" @start="drag=true" @end="drag=false" >
<div
class="flex d-flex sm12 xl3 md4 xs12 ma-0 area-style "
v-for="(device, index) in devices" :key="device.id"
class="flex d-flex sm12 xl3 md4 xs12 ma-0 area-style-setting-device "
v-for="(device, index) in devicesList" :key="device.id"
>
<va-card
:noPadding="true"
@@ -21,7 +21,7 @@
class="mr-1"
color="#babfc2"
style="cursor: pointer;"
@click.native.stop="removeCheck(index, device)"
@click.native.stop="remove(index, device)"
/>
</div>
</div>
@@ -30,7 +30,7 @@
<p> {{ device.name }} </p>
</div>
<div class="center-medium">
<p> {{ macArrayToString(device.mac_address) }} </p>
<p> {{ device.mac_address }} </p>
</div>
<div class="mt-4 mb-4" style="text-align: center;">
<img
@@ -58,8 +58,9 @@
</template>
<script>
import { mapActions, mapGetters, mapMutations } from 'vuex'
import { mapFields } from 'vuex-map-fields'
import api from '@/data/api/index'
import types from '@/store/modules/about/types'
import types from '@/store/modules/setting/types'
import neuliveImgUrl from '@/assets/img/neulive_img.png'
import eliteImgUrl from '@/assets/img/elite_img.png'
import draggable from 'vuedraggable'
@@ -76,6 +77,9 @@ export default {
}
},
computed: {
...mapFields('setting', [
'devicesList',
]),
devices: {
get () {
return this.getAllDevice()
@@ -94,7 +98,7 @@ export default {
timeStampToLocaleTime: function (time) {
return this.GLOBAL.dateToStr(time)
},
getImageUrl (libraryName) {
getImageUrl: function (libraryName) {
if (libraryName !== null) {
if (libraryName.indexOf('Neulive') >= 0) {
return neuliveImgUrl
@@ -104,40 +108,36 @@ export default {
}
return null
},
autoConnect (index, device) {
autoConnect: async function (index, device) {
device.auto_connect = !device.auto_connect
this.updateDatabaseByIDDevice({
id: device.id,
request: { auto_connect: device.auto_connect },
api: api,
})
this.updateByIndexDevice({ index: index, item: { auto_connect: device.auto_connect } })
await api.device.updateByID(device.id, { auto_connect: device.auto_connect })
},
removeCheck (index, device) {
/**
* TODO remove modal
*/
this.removeDevice({ id: device.id, index: index, device, deviceList: this.devices, api: api })
remove (index, device) {
console.log('removeDevcie', index, device)
this.removeDevice({ id: device.id, index: index, api: api })
},
...mapActions('about', [types.device.init, types.device.remove, types.device.reorder, types.device.updateDatabaseByID]),
...mapMutations('about', [types.device.set, types.device.updateByIndex]),
...mapGetters('about', [types.device.getAll]),
...mapActions('setting', [types.device.init, types.device.remove, types.device.reorder]),
...mapMutations('setting', [types.device.set, types.device.updateByIndex]),
...mapGetters('setting', [types.device.getAll]),
},
async mounted () {
this.initDevice({ api: api })
const devices = await api.device.getAll()
if (devices.status === 200) {
this.devicesList = devices.data
}
},
destroyed () {
},
}
</script>
<style lang="scss">
.area-style {
.area-style-setting-device {
height: auto;
overflow-y: hidden;
overflow-x: hidden;
@include media-breakpoint-only(xl) {
height: 48vh;
height: auto;
overflow-y: scroll;
overflow-x: hidden;
}
+110 -27
View File
@@ -21,7 +21,7 @@
/>
<div class="row row-equal">
<div v-if="showDeviceSetting" class="flex md12 xl4 xs12 sm12 area-style">
<div v-if="showDeviceSetting" class="flex md12 xl4 xs12 sm12">
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<task-devices :ref="'devices_ref'" @add="addDevice($event)" @remove="removeDevice($event)" @refreshSetting="refreshChartSetting($event)" class="pa-0" />
@@ -33,7 +33,7 @@
</div>
<div :class="chartAreaClass" class="area-style">
<div :class="chartAreaClass">
<div class="row" >
<div class="flex sm12 xl12 md12 xs12">
<div class="flex sm12 xl12 md12 xs12" style="text-align: center;">
@@ -99,6 +99,7 @@ import { chartData } from '../../../data/task/ChartsManagement'
import { taskInfo } from '../../../data/task/TaskInfo'
import CanvasChart from './chart/CanvasChart'
import TaskDevices from './controller/TaskDevices'
// import api from '../../../data/api'
// import TaskFormula from './formula/TaskFormula'
// TODO change chart data tag format
@@ -110,9 +111,9 @@ export default {
TaskDevices,
// TaskFormula,
},
async created () {
await taskInfo.updateTaskInfo(this.$route.params.taskID)
},
// async created () {
// await taskInfo.updateTaskInfo(this.$route.params.taskID)
// },
data () {
return {
// modal
@@ -128,6 +129,10 @@ export default {
selectChartID: null,
showDeviceSetting: true,
chartAreaClass: ['flex', 'xs12', 'sm12', 'md12', 'xl8', 'pa-0'],
getParmDone: false,
deviceList: {},
}
},
mqtt: {
@@ -138,6 +143,7 @@ export default {
async '+/get_device_info/+' (data, topic) {
await taskInfo.deviceInfo(String.fromCharCode.apply(null, data))
this.refreshDevicesWindow()
this.getParmDone = true
},
async '+/device_parameter/+' (data, topic) {
await taskInfo.deviceParameter(String.fromCharCode.apply(null, data))
@@ -149,6 +155,47 @@ export default {
},
async '+/hardware_device/+' (data, topic) {
await taskInfo.deviceInfo(String.fromCharCode.apply(null, data))
// console.log(this.deviceList)
// for (const d1 in taskInfo.getTaskInfo().deviceList) {
// if (taskInfo.getTaskInfo().deviceList[d1].info.device_address.length > 0) {
// const addr1 = taskInfo.getTaskInfo().deviceList[d1].info.device_address.join()
// let parameter, content
// for (const d2 in this.deviceList) {
// const addr2 = this.deviceList[d2].info.device_address.join()
// if (addr1 === addr2) {
// console.log(this.deviceList[d2].parameterSet)
// for (const p in this.deviceList[d2].parameterSet) {
// if (p !== 'STIMULATING') {
// if (parameter == null) {
// parameter = p
// } else {
// parameter = parameter + '|' + p
// }
// let c
// if (Array.isArray(this.deviceList[d2].parameterSet[p])) {
// c = '0:' + this.deviceList[d2].parameterSet[p].length + '=' + this.deviceList[d2].parameterSet[p]
// } else {
// c = this.deviceList[d2].parameterSet[p]
// }
// if (content == null) {
// content = c
// } else {
// content = content + '|' + c
// }
// }
// }
// console.log('****', parameter, content)
// // this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
// // header: 'device_parameter/0',
// // device: parseInt(d1),
// // parameter: parameter,
// // content: content,
// // }))
// }
// }
// }
// }
if (this.$refs.devices_ref != null) {
await this.$refs.devices_ref.loadingDone()
}
@@ -156,9 +203,10 @@ export default {
// listen datastream [ topic: controllerID/data_server/device_data_stream/deviceID/channel ]
async '+/data_server/device_data_stream/+/+' (data, topic) {
const topicSplit = topic.split('/')
if (!taskInfo.getDeviceInfoByRawID(parseInt(topicSplit[3])).info.isSync) {
taskInfo.deviceStart(parseInt(topicSplit[3]))
chartData.defaultChartGenerator(taskInfo.getDeviceIDByRaw(parseInt(topicSplit[3])), null, 'device')
if (this.getParmDone & !taskInfo.getDeviceInfoByRawID(parseInt(topicSplit[3])).info.isSync) {
if (chartData.defaultChartGenerator(taskInfo.getDeviceIDByRaw(parseInt(topicSplit[3])), null, 'device')) {
taskInfo.deviceStart(parseInt(topicSplit[3]))
}
}
dataStreamBuffer.into(String.fromCharCode.apply(null, data), parseInt(topicSplit[3]), (parseInt(topicSplit[4]) + 1))
},
@@ -185,6 +233,10 @@ export default {
break
case 'disconnected':
taskInfo.deviceDisconnected(mes[1])
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'get_device_info/0',
device: parseInt(mes[1]),
}))
break
case 'connected':
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
@@ -198,7 +250,12 @@ export default {
this.showShutdownModal = true
break
case 'start':
taskInfo.deviceStart(parseInt(mes[1]))
if (!taskInfo.getDeviceInfoByRawID(parseInt(parseInt(mes[1]))).info.isSync) {
taskInfo.deviceStart(parseInt(mes[1]))
if (chartData.defaultChartGenerator(taskInfo.getDeviceIDByRaw(parseInt(parseInt(mes[1]))), null, 'device')) {
taskInfo.deviceStart(parseInt(parseInt(mes[1])))
}
}
break
case 'stop':
if (mes[1] === 'all') {
@@ -256,6 +313,14 @@ export default {
if (await this.$refs.devices_ref != null) {
await this.$refs.devices_ref.loadingStart()
}
// let _parameter, _content
// this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
// header: 'device_parameter/0',
// device: 7,
// parameter: 'RECORDING_CH|AXIS_CH',
// content: '7|1',
// }))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'hardware_device/0',
}))
@@ -279,9 +344,13 @@ export default {
}
},
refreshDevicesWindow: function () {
// console.log(taskInfo.getTaskInfo())
if (this.$refs.devices_ref != null) {
this.$refs.devices_ref.refresh()
}
// api.task.update({
// device_config: taskInfo.getTaskInfo().deviceList,
// })
},
addChart: async function () {
const defaultID = {}
@@ -377,8 +446,13 @@ export default {
this.chartAreaClass[3] = 'md12'
this.chartAreaClass[4] = 'xl12'
},
addDevice: async function (deviceID) {
this.mqttSub(taskInfo.getTaskInfo().controllerID + '/data_server/device_data_stream/' + taskInfo.getRawDeviceID(deviceID) + '/+')
addMappingChart: async function (deviceID) {
// if have chart with device ID
for (const chart in chartData.getAllChartsData()) {
if (chartData.getAllChartsData()[chart].mappingID === deviceID) {
return false
}
}
const chart = await this.addChart()
await this.$nextTick(async () => {
chartData.getAllChartsData()[chart].mappingID = deviceID
@@ -388,9 +462,19 @@ export default {
})
}
})
if (taskInfo.getDeviceInfo(deviceID).info.isSync) {
chartData.defaultChartGenerator(deviceID, chart, 'device')
}
return chart
},
addDevice: async function (deviceID) {
this.mqttSub(taskInfo.getTaskInfo().controllerID + '/data_server/device_data_stream/' + taskInfo.getRawDeviceID(deviceID) + '/+')
this.addMappingChart(deviceID)
// if (taskInfo.getDeviceInfo(deviceID).info.isSync) {
// chartData.defaultChartGenerator(deviceID, chart, 'device')
// }
// console.log(chartData.getAllChartsData())
// console.log(taskInfo.getTaskInfo())
// await api.task.update({
// device_config: taskInfo.getTaskInfo().deviceList,
// })
this.pageToast('The device [' + deviceID + '] has been registered.')
},
removeDevice: function (deviceID) {
@@ -497,13 +581,12 @@ export default {
watch: {
},
async mounted () {
// await taskInfo.updateTaskInfo(this.$route.params.taskID)
this.deviceList = await taskInfo.updateTaskInfo(this.$route.params.taskID)
console.log(taskInfo.getTaskInfo())
// this.screenHeight = document.documentElement.clientHeight
this.pageMqttSub(taskInfo.getTaskInfo().controllerID)
console.log(taskInfo.getTaskInfo().controllerID)
await this.pageInit()
// this.chartNumber = taskInfo.getTaskInfo().chartNumber
this.dataRefreshTimer = setInterval(this.refreshData, 100)
@@ -527,17 +610,17 @@ export default {
</script>
<style lang="scss">
.area-style {
height: auto;
overflow-y: hidden;
overflow-x: hidden;
// .area-style {
// height: 100%;
// overflow-y: hidden;
// overflow-x: hidden;
@include media-breakpoint-only(xl) {
height: 88vh;
overflow-y: scroll;
overflow-x: hidden;
}
}
// @include media-breakpoint-only(xl) {
// height: 94vh;
// overflow-y: scroll;
// overflow-x: hidden;
// }
// }
.no-dark-style-va-button {
&:focus {
+132 -32
View File
@@ -21,7 +21,7 @@
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="data" :auto-resize="true"></chart>
</div>
<div v-else>
Please add the source or choose a item to mapping.
Please add the source from device.
</div>
</div>
<div v-else-if="tabValue == 1" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" >
@@ -30,44 +30,71 @@
<div v-else :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" >
<canvas-chart-setting></canvas-chart-setting>
</div>
<div class="flex row xs12 md12 xl12 sm12" style="text-align: center;" >
<div>
<va-select
class="xs4 md4 xl4 sm4"
<div class="flex row">
<div class="flex row xs12 md12 xl12 sm12" style="text-align: center;" >
<!-- <va-select
class="ma-1"
:on-change="mappingSelectChange()"
small
:label="'MAPPING'"
v-model="mappingSelect"
textBy="name"
:options="mappingOptions"
/>
</div>
<div class="mx-1">
/> -->
<va-input
@keyup.enter="xIntervalChange(xIntervalInput)"
@blur="xIntervalChange(xIntervalInput)"
v-model="xIntervalInput"
:label="'x-interval'"
v-if="data.chartXMode === 'time'"
class="ma-1"
@keyup.enter="timeIntervalChange(timeIntervalInput)"
@blur="timeIntervalChange(timeIntervalInput)"
v-model="timeIntervalInput"
:label="'time-interval'"
>
<p slot="append" style="margin-right: 0;" small>
ms
</p>
</va-input>
</div>
<div class="mx-1">
<va-input
v-if="data.chartXMode === 'value'"
class="ma-1"
@keyup.enter="xIntervalChange(xIntervalInput)"
@blur="xIntervalChange(xIntervalInput)"
v-model="xIntervalInput"
:label="'x-grid'"
>
<p slot="append" style="margin-right: 0;" small>
{{data.chartXUnit}}
</p>
</va-input>
<va-input
class="ma-1"
@keyup.enter="yIntervalChange(yIntervalInput)"
@blur="yIntervalChange(yIntervalInput)"
v-model="yIntervalInput"
:label="'y-interval'"
:label="'y-grid'"
>
<p slot="append" style="margin-right: 0;" small>
{{data.chartYUnit}}
</p>
</va-input>
</div>
<div>
<va-button class="no-dark-style-va-button" small @click="init()">INIT</va-button>
<va-input
v-if="data.chartDevice === 'neulive'"
class="ma-1"
@keyup.enter="threeAxisIntervalChange(threeAxisIntervalInput)"
@blur="threeAxisIntervalChange(threeAxisIntervalInput)"
v-model="threeAxisIntervalInput"
:label="'3axis-interval'"
>
<p slot="append" style="margin-right: 0;" small>
g
</p>
</va-input>
<!-- <va-button class="no-dark-style-va-button" small @click="init()">INIT</va-button> -->
<va-button small color="dark" @click="remove()">REMOVE</va-button>
</div>
<!-- <div class="xs2 md2 xl2 sm2" style="text-align: center;" >
<va-button class="no-dark-style-va-button" small @click="init()">INIT</va-button>
<va-button small color="dark" @click="remove()">REMOVE</va-button>
</div> -->
</div>
</va-card>
</div>
@@ -119,8 +146,10 @@ export default {
mappingOptions: taskInfo.getMappingList(),
nameCard: chartData.getAllChartsData()[this.chartID].cardName,
initDone: false,
xIntervalInput: 500,
yIntervalInput: 1000,
timeIntervalInput: 'auto',
threeAxisIntervalInput: 'auto',
xIntervalInput: 'auto',
yIntervalInput: 'auto',
}
},
computed: {
@@ -128,20 +157,89 @@ export default {
watch: {
},
methods: {
timeIntervalChange: function (val) {
if (!isNaN(parseInt(val))) {
chartData.getAllChartsData()[this.chartID].xAxis.forEach(x => {
if (x.type === 'time') {
x.interval = val * 1000
}
})
} else {
this.timeIntervalInput = 'auto'
chartData.getAllChartsData()[this.chartID].xAxis.forEach(x => {
if (x.type === 'time') {
x.interval = 500 * 1000
}
})
}
},
xIntervalChange: function (val) {
chartData.getAllChartsData()[this.chartID].xAxis.forEach(x => {
x.interval = val * 1000
if (val < 500) {
x.axisLabel.show = false
} else {
x.axisLabel.show = true
}
})
if (!isNaN(parseInt(val))) {
chartData.getAllChartsData()[this.chartID].xAxis.forEach(x => {
if (x.type === 'value') {
x.interval = val * 1000
}
})
} else {
this.timeIntervalInput = 'auto'
chartData.getAllChartsData()[this.chartID].xAxis.forEach(x => {
if (x.type === 'value') {
x.interval = null
}
})
}
},
yIntervalChange: function (val) {
chartData.getAllChartsData()[this.chartID].yAxis.forEach(y => {
y.interval = val * 1
})
if (!isNaN(parseInt(val))) {
chartData.getAllChartsData()[this.chartID].yAxis.forEach(y => {
if (parseInt(y.channel) <= 255) {
if (chartData.getAllChartsData()[this.chartID].chartYUnit === 'uV') {
y.interval = parseInt(val)
console.log(y.interval)
} else {
y.interval = val * 1000
}
const maxList = []
const minList = []
y.seriesIndex.forEach(i => {
maxList.push(Math.max(...chartData.getAllChartsData()[this.chartID].series[i].data.map(p => p[1])))
minList.push(Math.min(...chartData.getAllChartsData()[this.chartID].series[i].data.map(p => p[1])))
})
const max = Math.max(maxList)
const min = Math.min(minList)
const center = (max + min) / 2
y.max = center + (max - min)
y.min = center - (max - min)
y.max = (parseInt(y.max / y.interval) + 1) * y.interval
y.min = (parseInt(y.min / y.interval) - 1) * y.interval
}
})
} else {
this.timeIntervalInput = 'auto'
chartData.getAllChartsData()[this.chartID].yAxis.forEach(y => {
if (parseInt(y.channel) <= 255) {
y.interval = null
y.max = 'dataMax'
y.min = 'dataMin'
}
})
}
},
threeAxisIntervalChange: function (val) {
if (!isNaN(parseInt(val))) {
chartData.getAllChartsData()[this.chartID].yAxis.forEach(y => {
if (parseInt(y.channel) >= 255) {
y.interval = val * 1
}
})
} else {
this.timeIntervalInput = 'auto'
chartData.getAllChartsData()[this.chartID].yAxis.forEach(y => {
if (parseInt(y.channel) >= 255) {
y.interval = null
}
})
}
},
init: function () {
this.mappingSelect = ''
@@ -200,6 +298,8 @@ export default {
this.nameCard = chartData.getAllChartsData()[this.chartID].cardName
await this.refreshMappingSelect()
this.initDone = true
// this.timeIntervalInput = '500'
// this.timeIntervalChange('500')
},
destroyed () {
clearInterval(this.resizeTimer)
@@ -1,75 +1,87 @@
<template>
<div style="height: 350px; overflow-y: scroll; overflow-x: hidden;">
<div>
<div class="flex row align--center">
<div class="flex md3 xl3 xs3 sm3">
<va-select
small
:label="'X SOURCE'"
v-model="deviceSelectX"
textBy="name"
:options="deviceOptions"
/>
</div>
<div class="flex md3 xl3 xs3 sm3">
<va-select
:on-change="channelSelectXChange()"
:label="'X CHANNEL'"
v-model="channelSelectX"
textBy="channel"
:options="channelOptionsX"
:disabled="channelSelectDisableX"
/>
</div>
<div class="flex md3 xl3 xs3 sm3">
<va-select
:label="'Y SOURCE'"
v-model="deviceSelectY"
textBy="name"
:options="deviceOptions"
/>
</div>
<div class="flex md3 xl3 xs3 sm3">
<va-select
:on-change="channelSelectYChange()"
:label="'Y CHANNEL'"
v-model="channelSelectY"
textBy="channel"
:options="channelOptionsY"
:disabled="channelSelectDisableY"
/>
</div>
<div class="flex md3 xl3 xs3 sm3">
<va-select
:label="'SubPlot'"
v-model="gridSelection"
textBy="value"
:options="gridOptions"
@click.enter="updateGridOptions()"
/>
</div>
<va-button :disabled="sourceAddStatus" class="flex md3 xl3 xs3 sm3 pa-1" @click="addRegisterDeviceChannel(gridSelection.id)" >
Add
</va-button><span class="ml-2" style="color: red;">{{error}}</span>
</div>
</div>
<va-tree-root>
<va-tree-category
style="font-size: 20px;"
v-for="grid in grids"
:key="grid.index"
:label="'GRID ' + grid.index">
:label="'Subplot ' + grid.index">
<va-tree-node
v-for="series in grid.series"
v-for="series in gridSource[grid.index]"
:key="series.name"
>
<div class="flex row align--center">
<va-badge class="mb-0" style="font-size: 14px;" color="primary">{{series.name}}</va-badge>
<va-badge class="mb-0" style="font-size: 14px;" color="primary" outline>{{series.xAxis}}</va-badge>
<va-badge class="mb-0" style="font-size: 14px;" color="primary" outline>{{series.yAxis}}</va-badge>
<va-icon
<!-- <va-icon
name="ion ion-md-close"
color="info"
class="ml-2 pa-1 shrink"
style="cursor: pointer;"
@click.native="removeProduct(product)"
/>
</div>
</va-tree-node>
<va-tree-node>
<div class="flex row align--center">
<div class="flex md6 xl6 xs6 sm6">
<va-select
small
:label="'X DEVICE'"
v-model="deviceSelectX"
textBy="name"
:options="deviceOptions"
/>
</div>
<div class="flex md6 xl6 xs6 sm6">
<va-select
:on-change="channelSelectXChange()"
:label="'X CHANNEL'"
v-model="channelSelectX"
textBy="channel"
:options="channelOptionsX"
:disabled="channelSelectDisableX"
/>
</div>
<div class="flex md6 xl6 xs6 sm6">
<va-select
:label="'Y DEVICE'"
v-model="deviceSelectY"
textBy="name"
:options="deviceOptions"
/>
</div>
<div class="flex md6 xl6 xs6 sm6">
<va-select
:on-change="channelSelectYChange()"
:label="'Y CHANNEL'"
v-model="channelSelectY"
textBy="channel"
:options="channelOptionsY"
:disabled="channelSelectDisableY"
/>
</div>
<va-button :disabled="sourceAddStatus" class="flex md6 xl6 xs6 sm6 pa-1" @click="addRegisterDeviceChannel(grid.index)" >
Add
</va-button>
/> -->
</div>
</va-tree-node>
</va-tree-category>
</va-tree-root>
<va-button @click="addGrid()">
Add Subplot
</va-button>
</div>
</template>
@@ -93,17 +105,16 @@ export default {
},
data () {
return {
error: '',
gridSelection: '',
gridOptions: [
{
id: 0,
value: 0,
},
],
grids: this.gridInfo,
electronics: [
{ id: 1, name: 'Cellphones' },
{ id: 2, name: 'Camera Body Kits' },
{ id: 3, name: 'External HDDs' },
],
products: [
{ id: 4, name: 'Cables' },
{ id: 5, name: 'Monitors' },
{ id: 6, name: 'Keyboards' },
],
gridSource: chartData.getAllChartsData()[this.chartID].gridSource,
channelSelectX: '',
channelOptionsX: [],
channelSelectY: '',
@@ -114,6 +125,7 @@ export default {
deviceSelectY: '',
deviceOptions: taskInfo.getDeviceList(),
sourceAddStatus: true,
sourceList: [],
}
},
watch: {
@@ -245,6 +257,15 @@ export default {
},
},
methods: {
updateGridOptions () {
this.gridOptions = []
for (let i = 0; i < this.grids.length; i++) {
this.gridOptions.push({
id: i,
value: String(i),
})
}
},
channelSelectYChange: function () {
this.checkSourceAddStatus()
},
@@ -258,6 +279,7 @@ export default {
this.channelOptionsY = []
this.deviceSelectX = ''
this.deviceSelectY = ''
this.gridSelection = ''
},
addRegisterDeviceChannel: function (gridIndex) {
let deviceNameX
@@ -281,11 +303,46 @@ export default {
deviceNameY = 'Time'
}
chartData.register(this.chartID, gridIndex, deviceNameX, deviceIDX, channelX, deviceNameY, deviceIDY, channelY, null)
console.log(this.chartID, gridIndex, deviceNameX, deviceIDX, channelX, deviceNameY, deviceIDY, channelY, null)
console.log(this.deviceSelectX, this.channelSelectX, this.deviceSelectY, this.channelSelectY)
if (deviceNameX !== 'Time') {
this.sourceList.push([this.deviceSelectX.name, deviceIDX, channelX].toString())
}
if (deviceNameY !== 'Time') {
this.sourceList.push([this.deviceSelectY.name, deviceIDY, channelY].toString())
}
this.sourceAddStatus = true
this.clearSelectOptions()
},
addGrid () {
chartData.updateGridList(this.chartID, chartData.getAllChartsData()[this.chartID].grid.length + 1)
this.grids = chartData.getAllChartsData()[this.chartID].grid
this.treeKey++
this.gridOptions = []
for (let i = 0; i < this.grids.length; i++) {
this.gridOptions.push({
id: i,
value: String(i),
})
}
console.log(chartData.getAllChartsData()[this.chartID])
},
checkSourceAddStatus () {
if (this.sourceList.indexOf([this.deviceSelectX.name, this.deviceSelectX.id, this.channelSelectX.id].toString()) >= 0) {
this.error = 'The same source has been selected in a subplot.'
this.sourceAddStatus = true
return
}
if (this.sourceList.indexOf([this.deviceSelectY.name, this.deviceSelectY.id, this.channelSelectY.id].toString()) >= 0) {
this.sourceAddStatus = true
this.error = 'The same source has been selected in a subplot.'
return
}
this.error = ''
if (this.gridSelection.id == null) {
this.sourceAddStatus = true
return
}
if (this.channelSelectX.id != null && this.channelSelectY.id != null) {
this.sourceAddStatus = false
} else if (this.channelSelectX.id != null && this.deviceSelectY.id < 0) {
@@ -305,6 +362,8 @@ export default {
removeProduct (product) {
this.products = this.products.filter(productToFilter => productToFilter !== product)
},
mounted () {
},
},
}
</script>
@@ -14,13 +14,13 @@
<span slot="header" >
<va-item :key="device.id" class="pa-0 ma-0"
>
<va-icon
<!-- <va-icon
name="ion ion-md-close"
color="danger"
class="ml-0 mr-3 pa-0 shrink"
style="cursor: pointer;"
@click.native.stop="removeCheck(device)"
/>
/> -->
<va-item-section avatar class="ml-0">
<va-avatar style="border-radius: 0;">
@@ -45,7 +45,7 @@
<va-item-section class="ml-3">
<va-item-label>
<va-button @click.stop="start(device)" v-if="(device.type == 'Neulive' && !device.isSync && !device.isStimulate) || (device.type == 'Elite' && !device.isSync)" class="px-2 py-0 mr-0" color="success" small>START</va-button>
<va-button @click.stop="stop(device)" v-if="(device.type == 'Neulive' && (device.isSync || device.isStimulate)) || (device.type == 'Elite' && device.isSync)" :disabled="device.stopping" class="px-2 py-0 mr-0" color="danger" small>STOP</va-button>
<va-button @click.stop="stop(device)" v-if="(device.type == 'Neulive' && (device.isSync || device.isStimulate)) || (device.type == 'Elite' && device.isSync)" class="px-2 py-0 mr-0" color="danger" small>STOP</va-button>
<va-button id="detectButton" @click.stop="detect(device)" v-if="device.type == 'Elite'" color="primary" class="px-2 py-0 mr-0" small>DETECT</va-button>
<va-button @click.stop="record(device)" v-if="device.type == 'Neulive' && !device.isSync" color="primary" class="px-2 py-0 mr-0 no-dark-style-va-button" small>RECORD</va-button>
<va-button @click.stop="stopRecord(device)" v-if="device.type == 'Neulive' && device.isSync" color="danger" class="px-2 py-0 mr-0 no-dark-style-va-button" small>STOP REC</va-button>
@@ -58,9 +58,9 @@
</span>
<div slot="body">
<div class="mt-0 mb-0" style="height: 350px; overflow-y: scroll; overflow-x: hidden;" :key="'detail' + device.id">
<div style="text-align: center;">
<!-- <div style="text-align: center;">
<va-button @click.stop="generateChart(device)" class="pl-2 pr-2 mr-0 no-dark-style-va-button" small>GENERATE MAPPING CHART</va-button>
</div>
</div> -->
<div>
<file-control-window :ref="'fcwindow_ref'" :deviceID="device.id" class="pl-0 pr-0" />
</div>
@@ -82,6 +82,8 @@
import EliteParameterWindow from '../parameter/EliteParameterWindow'
import NeuliveParameterWindow from '../parameter/NeuliveParameterWindow'
import FileControlWindow from '../meta/FileControlWindow'
import { mapActions } from 'vuex'
import types from '@/store/modules/task/content/types'
export default {
name: 'TaskDeviceList',
@@ -113,31 +115,47 @@ export default {
remove: function () {
this.$emit('remove', this.selectDevice)
},
start: function (device) {
this.setArchiveSettings()
// this.$emit('start', device)
setTimeout(() => {
this.$emit('start', device)
}, 500)
this.pageToast('The device ' + device.name + ' has been started.')
start: async function (device) {
const checkParam = await this.checkIfDeviceSetDoneParam({ device: device })
const status = checkParam.status
const message = checkParam.message
if (status === true) {
this.setArchiveSettings()
// this.$emit('start', device)
setTimeout(() => {
this.$emit('start', device)
}, 500)
this.pageToast('The device ' + device.name + ' has been started.')
} else {
this.pageToast('The device cannot be started because:' + message)
}
},
stop: function (device) {
this.$emit('stop', device)
this.pageToast('The device ' + device.name + ' has been stopped.')
if (!device.stopping) {
this.$emit('stop', device)
this.pageToast('The device ' + device.name + ' has been stopped.')
}
},
record: function (device) {
device.stopping = false
this.setArchiveSettings()
setTimeout(() => {
this.$emit('record', device)
}, 500)
this.pageToast('The device ' + device.name + ' has been started.')
record: async function (device) {
const checkParam = await this.checkIfRecordingSetDoneParam({ device: device })
const status = checkParam.status
const message = checkParam.message
if (status === true) {
device.stopping = false
this.setArchiveSettings()
setTimeout(() => {
this.$emit('record', device)
}, 500)
this.pageToast('The device ' + device.name + ' has been started.')
} else {
this.pageToast('Recording cannot be started because:' + message)
}
},
stopRecord: function (device) {
device.stopping = true
this.$emit('stopRecord', device)
this.pageToast('The device ' + device.name + ' has been stopped.')
if (!device.stopping) {
this.$emit('stopRecord', device)
this.pageToast('The device ' + device.name + ' has been stopped.')
}
},
generateChart: function (device) {
this.$emit('generate', device)
@@ -180,9 +198,16 @@ export default {
this.$emit('detect', device)
this.pageToast('The device ' + device.name + ' has been detect.')
},
stimulate: function (device) {
this.$emit('sti', device)
this.pageToast('The device ' + device.name + ' start stimulate.')
stimulate: async function (device) {
const checkParam = await this.checkIfStimulationSetDoneParam({ device: device })
const status = checkParam.status
const message = checkParam.message
if (status === true) {
this.$emit('sti', device)
this.pageToast('The device ' + device.name + ' start stimulate.')
} else {
this.pageToast('Stimulation cannot be started because:' + message)
}
},
stopStimulate: function (device) {
this.$emit('sti_stop', device)
@@ -195,6 +220,10 @@ export default {
recoverDetectButton () {
document.getElementById('detectButton').className += ' no-dark-style-va-button'
},
...mapActions('taskContent', [types.param.checkIfRecordingSetDone, types.param.checkIfStimulationSetDone, types.param.checkIfDeviceSetDone]),
},
destroyed () {
this.deviceList.length = 0
},
}
</script>
@@ -1,6 +1,6 @@
<template>
<div class="flex" :class="cardclass">
<va-card>
<va-card style="height: 88vh; overflow: auto;">
<template slot="header">
<va-icon name="fa fa-bluetooth-b mr-3" color="primary"/>
<h5 class="mt-0 mb-0">DEVICES</h5>
@@ -18,7 +18,6 @@
<task-device-list
:ref="'pdlist_ref'"
:deviceList="deviceList"
@remove="removeDevice($event)"
@start="startDevice($event)"
@stop="stopDevice($event)"
@record="record($event)"
@@ -29,7 +28,7 @@
@detect="detectDevice($event)"
/>
<div class="row flex xs12 md12 xl12 sm12 mt-2" style="text-align: center;">
<!-- <div class="row flex xs12 md12 xl12 sm12 mt-2" style="text-align: center;">
<div class="xs10 md10 xl10 sm10">
<va-select
small
@@ -43,7 +42,7 @@
REGISTER
</va-button>
</div>
</div>
</div> -->
</div>
</va-card>
@@ -56,6 +55,7 @@ import TaskDeviceList from './TaskDeviceList'
import { taskInfo } from '../../../../data/task/TaskInfo'
import { chartData } from '../../../../data/task/ChartsManagement'
import { dataStreamBuffer } from '../../../../data/task/DataStreamBuffer'
import api from '@/data/api'
export default {
name: 'TaskDevices',
@@ -97,14 +97,45 @@ export default {
},
loadingDone: async function () {
this.state.LOADING = false
// const ret = await api.task.getAll()
// if (ret.data.length > 0) {
// for (const device in ret.data[0].device_config) {
// if (ret.data[0].device_config[device].device_address) {
// }
// }
// }
console.log(this.deviceOptions)
for (let i = this.deviceOptions.length - 1; i >= 0; i--) {
this.deviceSelect = this.deviceOptions[i]
await this.addDevice(this.deviceOptions[i].id)
// this.sleep(500).then(() => {
// this.addDevice(this.deviceOptions[i].id)
// })
for (let i = 4; i <= 7; i++) {
if (taskInfo.getDeviceInfoByRawID(i).info.status === 'connected') {
const index = this.deviceList.findIndex(d => taskInfo.getRawDeviceID(d.id) === i)
if (index < 0) {
await this.addDevice(i)
}
} else {
console.log(this.deviceList)
const index = this.deviceList.findIndex(d => taskInfo.getRawDeviceID(d.id) === i)
console.log(index)
if (index > 0) {
await this.removeDevice(this.deviceList[index])
}
}
}
taskInfo.getDeviceList().length = 0
taskInfo.getDeviceList().push({
id: -1,
name: 'Time',
})
taskInfo.getDeviceList().push(...this.deviceList)
console.log(taskInfo.getDeviceList())
// for (let i = this.deviceOptions.length - 1; i >= 0; i--) {
// this.deviceSelect = this.deviceOptions[i]
// await this.addDevice(this.deviceOptions[i].id)
// // this.sleep(500).then(() => {
// // this.addDevice(this.deviceOptions[i].id)
// // })
// }
},
startDevice: async function (device) {
await chartData.defaultChartGenerator(device.id, null, 'device')
@@ -126,6 +157,8 @@ export default {
parameter: 'STIMULATING',
content: 1,
}))
taskInfo.getTaskInfo().deviceList[(taskInfo.getRawDeviceID(device.id)).toString()].parameterSet.STIMULATING = 1
device.isStimulate = true
} else if (taskInfo.getDeviceInfo(device.id).info.library_name.startsWith('Elite')) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
@@ -138,6 +171,9 @@ export default {
device.isSync = true
this.$emit('refreshSetting')
// ### show device info
api.task.update({
device_config: taskInfo.getTaskInfo().deviceList,
})
console.log(taskInfo.getDeviceInfo(device.id))
}
},
@@ -198,22 +234,27 @@ export default {
device.isSync = true
device.stopping = false
this.$emit('refreshSetting')
api.task.update({
device_config: taskInfo.getTaskInfo().deviceList,
})
// ### show device info
console.log(taskInfo.getDeviceInfo(device.id))
}
},
stopRecord: function (device) {
dataStreamBuffer.removeByDevice(taskInfo.getRawDeviceID(device.id))
if (taskInfo.getDeviceInfo(device.id).info.isSync) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(device.id),
instruction: 'stop_record',
}))
if (!device.stopping) {
dataStreamBuffer.removeByDevice(taskInfo.getRawDeviceID(device.id))
if (taskInfo.getDeviceInfo(device.id).info.isSync) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(device.id),
instruction: 'stop_record',
}))
}
device.isSync = false
device.stopping = true
}
device.isSync = false
device.stopping = true
},
sti: function (device) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
@@ -227,6 +268,11 @@ export default {
parameter: 'STIMULATING',
content: 1,
}))
taskInfo.getTaskInfo().deviceList[(taskInfo.getRawDeviceID(device.id)).toString()].parameterSet.STIMULATING = 1
api.task.update({
device_config: taskInfo.getTaskInfo().deviceList,
})
device.isStimulate = true
},
stiStop: function (device) {
@@ -285,7 +331,13 @@ export default {
if (selectID == null) {
return false
}
const addr = taskInfo.getDeviceInfoByRawID(selectID).info.device_address
if (addr.length === 0) {
return false
}
if (taskInfo.getTaskInfo().taskDeviceID.indexOf(selectID) > 0) {
return false
}
await taskInfo.getTaskInfo().deviceAddrList.push(taskInfo.getDeviceInfoByRawID(selectID).info.device_address)
await taskInfo.getTaskInfo().taskDeviceID.push(selectID)
const _address = this.GLOBAL.transMac(taskInfo.getDeviceInfoByRawID(selectID).info.device_address)
@@ -303,6 +355,8 @@ export default {
name: '[' + taskInfo.getTaskInfo().taskDeviceID.indexOf(selectID) + '] ' + taskInfo.getDeviceInfoByRawID(selectID).info.device_name,
addr: taskInfo.getDeviceInfoByRawID(selectID).info.device_address,
address: _address,
library_name: taskInfo.getDeviceInfoByRawID(selectID).info.library_name,
library_version: taskInfo.getDeviceInfoByRawID(selectID).info.library_version,
picture: pic,
type: type,
isSync: taskInfo.getDeviceInfoByRawID(selectID).info.isSync,
@@ -330,6 +384,12 @@ export default {
taskInfo.updateAllList()
this.$emit('remove', device.id)
},
clearDevice: async function () {
taskInfo.getTaskInfo().deviceAddrList.length = 0
taskInfo.getTaskInfo().taskDeviceID.length = 0
this.deviceList.length = 0
taskInfo.updateAllList()
},
generateChart: function (device) {
this.$emit('add', device.id)
},
@@ -1,37 +1,25 @@
<template>
<div class="flex mt-0 pt-0">
<div>
<div class="row flex sm12 xl12 md12 xs12">
<div>
<div class="flex">
<va-tree-root>
<div class="row pt-0 pb-0">
<div class="flex sm12 xl12 md12 xs12">
<va-input
@mouseup.native="fileNameChange(fileNameInput)"
@mouseleave.native="fileNameChange(fileNameInput)"
@touchend.native="fileNameChange(fileNameInput)"
@keyup.enter="fileNameChange(fileNameInput)"
v-model="fileNameInput"
:label="'FILE NAME'"
style="width: 200px;"
>
</va-input>
<va-select
:on-change="directorySelect(directory)"
:label="'DIRECTORY'"
v-model="directory"
textBy="name"
:options="directoryOptions"
noClear
style="width: 200px;"
/>
</div>
</div>
</va-tree-root>
</div>
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12">
<div class="flex sm6 xl6 md6 xs6">
<va-select
:on-change="directorySelect(directory)"
:label="'DIRECTORY'"
v-model="directory"
textBy="name"
:options="directoryOptions"
noClear
/>
</div>
<div class="flex sm6 xl6 md6 xs6">
<va-input
@mouseup.native="fileNameChange(fileNameInput)"
@mouseleave.native="fileNameChange(fileNameInput)"
@touchend.native="fileNameChange(fileNameInput)"
@keyup.enter="fileNameChange(fileNameInput)"
v-model="fileNameInput"
:label="'FILE NAME'"
>
</va-input>
</div>
</div>
@@ -76,14 +64,14 @@ export default {
fileNameChange: async function (name) {
if (this.enableSetting) {
if (this.deviceInfo.info.isSync === false) {
let fileNameCount = await api.getMetaFilesByName(name)
let fileNameCount = await api.meta.getByName(name)
if (fileNameCount.data != null) {
let duplicateCount = 1
let fileName = name
while (fileNameCount.data.length !== 0) {
const res = name.split('(')[0]
fileName = `${res}(${duplicateCount})`
fileNameCount = await api.getMetaFilesByName(fileName)
fileNameCount = await api.meta.getByName(fileName)
duplicateCount += 1
}
this.fileNameInput = fileName
@@ -143,7 +131,7 @@ export default {
this.fileNameChange(this.fileNameInput)
// directory init
const collection = await api.getCollectionsAll()
const collection = await api.collection.getAll()
this.directoryOptions = collection.data.filter(el => el.name !== 'root')
if (Object.keys(this.deviceInfo.info.parent).length === 0) {
@@ -0,0 +1,83 @@
<template>
<div>
<fieldset>
<va-radio-button
option="Auto"
v-model="optionValue"
label="Auto"
/>
<br v-if="optionValue === 'Auto'"/>
<auto-block v-if="optionValue === 'Auto'" :ref="'AutoBlock'" :deviceID="deviceID"/>
<va-radio-button
option="Advanced"
v-model="optionValue"
label="Advanced"
/>
<br v-if="optionValue === 'Advanced'"/>
<advanced-block v-if="optionValue === 'Advanced'" :ref="'AdvancedBlock'" :deviceID="deviceID"/>
</fieldset>
</div>
</template>
<script>
import { taskInfo } from '../../../../data/task/TaskInfo'
import AutoBlock from '../parameter/item/DPV/AutoBlock'
import AdvancedBlock from '../parameter/item/DPV/AdvancedBlock'
export default {
name: 'EliteParameterRecordingEliteDPV',
components: {
AutoBlock,
AdvancedBlock,
},
props: {
deviceID: {
type: Number,
required: true,
},
deviceName: {
type: String,
default: 'Elite',
},
},
created () {
},
data () {
return {
optionValue: 'Auto',
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
// Array[String of Parameter Nmae, Value]
deviceParameterChange: function (e) {
console.log('e[0],e[1]', e[0], ',', e[1])
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: e[0],
content: e[1],
}))
},
refresh () {
if (this.$refs.AutoBlock != null) {
this.$refs.AutoBlock.refresh()
}
if (this.$refs.AdvancedBlock != null) {
this.$refs.AdvancedBlock.refresh()
}
},
},
mounted () {
},
watch: {
},
destroyed () {
},
}
</script>
@@ -0,0 +1,564 @@
<template>
<div>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<va-select
@input="workingModeSelectChange(workingModeSelect)"
:label="'WORKING MODE'"
v-model="workingModeSelect"
textBy="description"
:options="workingModeOptions"
noClear
/>
</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)" />
</div>
<!-- CV -->
<div v-if="workingModeSelect != null && workingModeSelect.id == 1">
<va-button
color="primary"
target="_blank"
@click="measureEoc()"
small>
{{measureEocButton.start}}
</va-button>
<va-button
color="danger"
target="_blank"
@click="measureEocStop()"
small>
{{measureEocButton.stop}}
</va-button>
<div class="flex row mt-3 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">Current Range<p/>
</div>
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<level-button :ref="'currentRangeSelect'" :deviceID="deviceID" :options="currentRangeOptions" :parameterName="'ADC_LEVEL_I_15'" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex 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/>
</div>
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<level-button :ref="'highzSelect'" :deviceID="deviceID" :options="highzOptions" :parameterName="'CTRL_HIGH_Z_15'" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<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)" />
</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">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)" />
</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">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)" />
</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 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)" />
</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">Resolution<p/>
</div>
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<resolution-range :ref="'sampleRateNumber'" :deviceID="deviceID" :parameterName="'SAMPLE_RATE'" :minValue="0.1" :maxValue="100" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-0">
<p class="display-6">Cycle<p/>
</div>
<div class="flex sm12 xl12 md12 xs12 pa-0 ma-1" >
<cycle-range :ref="'cycleNoNumber'" :deviceID="deviceID" :parameterName="'CYCLE_NUMBER'" :minValue="1" :maxValue="50000" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
</div>
<!-- DEV -->
<va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 2"
style="font-size: 20px;"
:label="'RIS instruction (HEX)'">
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-input
@keyup.enter="instruParameterChange([instru.parameterName, instru.write])"
@blur="instruParameterChange([instru.parameterName, instru.write])"
class="mb-0"
v-model="instru.write"
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()">
W
</va-button>
</div>
</div>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-input
disabled="disabled"
class="mb-0"
v-model="instru.read"
label="Read value"
style="width: 100px; font-size: 30px;"
/>
<va-button slot="append" class="mr-2 pa-1 shrink" style="width: 2em; height: 2em; border-radius: 50%; font-size: 20px;" small @click="readCisData()">
R
</va-button>
</div>
</div>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-input
disabled="disabled"
class="mb-0"
v-model="instru.notify"
label="Notify value"
style="width: 100px;"
/>
<va-button slot="append" class="mr-2 pa-1 shrink" style="width: 2em; height: 2em; border-radius: 50%; font-size: 20px;" small @click="detect()">
N
</va-button>
</div>
</div>
</div>
</va-tree-category>
<va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 2"
style="font-size: 20px;"
:label="'VIS & CIS instruction'">
<va-card>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-input
disabled="disabled"
class="mb-0"
v-model="instru.read"
label="Read value"
style="width: 100px; font-size: 30px;"
/>
<va-button slot="append" class="mr-2 pa-1 shrink" style="width: 2em; height: 2em; border-radius: 50%; font-size: 20px;" small @click="readCisData()">
R
</va-button>
</div>
</div>
</div>
<div>
<va-button class="mr-2 pa-1" style="width: 4em; height: 2em; font-size: 15px;" small @click="detect()">
Detect
</va-button>
</div>
<div>
<va-button class="mr-2 pa-1" style="width: 4em; height: 2em; font-size: 15px;" small @click="version()">
Version
</va-button>
</div>
<div>
<va-button class="mr-2 pa-1" style="width: 4em; height: 2em; font-size: 15px;" small @click="battery()">
Battery
</va-button>
</div>
</va-card>
</va-tree-category>
</div>
</template>
<script>
import { taskInfo } from '../../../../data/task/TaskInfo.js'
import DCVolt from '../parameter/item/EIS/DCVolt.vue'
import ACAmplitude from '../parameter/item/EIS/ACAmplitude.vue'
import FreqRange from '../parameter/item/EIS/FreqRange.vue'
import PointsPerDecades from '../parameter/item/EIS/PointsPerDecades.vue'
import PointSpacing from '../parameter/item/EIS/PointSpacing.vue'
import Delay from '../parameter/item/EIS/Delay.vue'
import Average from '../parameter/item/EIS/Average.vue'
import CurrentRange from '../parameter/item/EIS/CurrentRange.vue'
// import SingalMode from '../parameter/item/EIS/SingalMode'
// CV
import LevelButton from '../parameter/item/LevelButton.vue'
import VoltRange from '../parameter/item/EIS/VoltRange.vue'
import ScanRateRange from '../parameter/item/ScanRateRange.vue'
import ResolutionRange from '../parameter/item/ResolutionRange.vue'
import CycleRange from '../parameter/item/CycleRange.vue'
export default {
name: 'EliteParameterRecordingEliteEIS',
components: {
DCVolt,
ACAmplitude,
FreqRange,
PointsPerDecades,
PointSpacing,
Delay,
Average,
CurrentRange,
LevelButton,
VoltRange,
ScanRateRange,
ResolutionRange,
CycleRange,
},
props: {
deviceID: {
type: Number,
required: true,
},
deviceName: {
type: String,
default: 'Elite',
},
},
created () {
},
data () {
return {
workingModeSelect: {
id: -1,
description: 'Init',
},
workingModeOptions: [
{
id: 0,
description: 'Potentiostatic Electrochemical Impedance Spectroscopy',
},
{
id: 1,
description: 'CV',
},
{
id: 2,
description: 'Dev Tools',
},
],
DCVolt: null,
AC_AMP: null,
FreqStart: null,
FreqStop: null,
PointsPerDecades: null,
PointSpacing: null,
Delay: null,
Average: null,
CurrentRange: null,
instru: {
write: '',
read: '',
notify: '',
},
measureEocButton: {
start: 'OCP',
stop: 'Stop',
status: false,
},
// CV
currentRangeSelect: null,
currentRangeOptions: [
{
value: 0,
label: '<1.5 μA',
},
{
value: 1,
label: '1-60 μA',
},
{
value: 2,
label: '40-175 μA',
},
{
value: 3,
label: '>120 uA',
},
{
value: 4,
label: 'Auto',
},
],
voltageInRangeSelect: null,
voltageInRangeOptions: [
{
value: 0,
label: '1',
},
{
value: 1,
label: '2',
},
{
value: 2,
label: '3',
},
{
value: 3,
label: 'Auto',
},
],
highzSelect: null,
highzOptions: [
{
value: 0,
label: 'On',
},
{
value: 1,
label: 'Off',
},
],
voltInitialNumber: null,
stopVoltMaxNumber: null,
stopVoltMinNumber: null,
voltScanRateNumber: null,
sampleRateNumber: null,
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
// Array[String of Parameter Nmae, Value]
deviceParameterChange: function (e) {
console.log('e[0],e[1]', e[0], ',', e[1])
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: e[0],
content: e[1],
}))
},
measureEoc () {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'VIS_CC_ZERO',
}))
this.measureEocButton.status = true
},
measureEocStop () {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'interrupt',
}))
this.measureEocButton.status = false
},
refresh () {
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))
if (this.$refs.ACAmplitude != null) {
this.$refs.ACAmplitude.itemChange(this.ACAmplitude)
}
this.Average = taskInfo.getDeviceInfo(this.deviceID).parameterSet.AVERAGE_NUM
if (this.$refs.Average != null) {
this.$refs.Average.itemChange(this.Average)
}
this.CurrentRange = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RTIA
if (this.$refs.CurrentRange != null) {
this.$refs.CurrentRange.itemChange(this.CurrentRange)
}
this.PointSpacing = taskInfo.getDeviceInfo(this.deviceID).parameterSet.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))
if (this.$refs.DCVolt != null) {
this.$refs.DCVolt.itemChange(this.DCVolt)
}
this.Delay = String(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.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.itemChangeMin(this.FreqStart)
}
this.FreqStop = String(parseFloat(Math.round(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.FREQ_STOP * 0.0149) * 100)) / 100).toFixed(1)) === '0.0' ? '0.015' : String(parseFloat(Math.round(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.FREQ_STOP * 0.0149) * 100)) / 100).toFixed(1))
if (this.$refs.FreqRange != null) {
this.$refs.FreqRange.itemChangeMax(this.FreqStop)
}
this.PointsPerDecades = String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet.PPD)))
if (this.$refs.PointsPerDecades != null) {
this.$refs.PointsPerDecades.itemChange(this.PointsPerDecades)
}
// CV
this.currentRangeSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.ADC_LEVEL_I_15
if (this.$refs.currentRangeSelect != null) {
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)
}
this.stopVoltMaxNumber = this.voltInitialNumber = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.VOLTSTOP_MAX - 25000) / 5
if (this.$refs.stopVoltMaxNumber != null) {
this.$refs.stopVoltMaxNumber.updateVoltNumber(this.stopVoltMaxNumber)
}
this.stopVoltMinNumber = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.VOLTSTOP_MIN - 25000) / 5
if (this.$refs.stopVoltMinNumber != null) {
this.$refs.stopVoltMinNumber.updateVoltNumber(this.stopVoltMinNumber)
}
this.voltInitialNumber = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.VOLT_INITIAL - 25000) / 5
if (this.$refs.voltInitialNumber != null) {
this.$refs.voltInitialNumber.updateVoltNumber(this.voltInitialNumber)
}
this.voltScanRateNumber = taskInfo.getDeviceInfo(this.deviceID).parameterSet.Scan_Rate
if (this.$refs.voltScanRateNumber != null) {
this.$refs.voltScanRateNumber.updateVoltScanRateNumber(this.voltScanRateNumber)
}
this.sampleRateNumber = taskInfo.getDeviceInfo(this.deviceID).parameterSet.SAMPLE_RATE
if (this.$refs.sampleRateNumber != null) {
this.$refs.sampleRateNumber.updateResolutionNumber(this.sampleRateNumber)
}
this.instru.read = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.ADC_VALUE_I).toString(16).toUpperCase()
},
workingModeSelectChange (val) {
if (this.workingModeSelect.id === -1) {
return false
}
this.workingModeSelect = val
if (this.workingModeSelect.id !== taskInfo.getDeviceInfo(this.deviceID).parameterSet.MODE) {
this.deviceParameterChange(['MODE', this.workingModeSelect.id])
console.log(this.workingModeSelect.id, this.workingModeSelect.description)
}
},
instruParameterChange: function (e) {
while (e[1].length <= 33) {
e[1] = e[1] + '0'
}
const sendIns = new Array(17).fill(0)
for (let i = 0; i <= 16; i++) {
const startIndex = i * 2
sendIns[i] = e[1].substring(startIndex, startIndex + 2)
sendIns[i] = parseInt(sendIns[i], 16)
}
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'BLE_WRITE',
content: '0:16=' + String(sendIns),
}))
},
sendInstr () {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'ble_instru_send',
}))
},
readCisData () {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter_value/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'ADC_VALUE_I',
}))
},
detect () {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'VIS_DEVICE_DETECT',
}))
setTimeout(() => {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'VIS_DEVICE_DONE',
}))
}, 5000)
},
version () {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'dev_version',
}))
},
battery () {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'dev_battery',
}))
},
},
mounted () {
this.refresh()
},
watch: {
},
destroyed () {
},
}
</script>
@@ -0,0 +1,190 @@
<template>
<div>
<SlickList lockAxis="y" class="long-list" :pressDelay='300' v-model="blockList" @sort-end="dragEnd">
<SlickItem v-for="(block, i) in blockList" :key="block.id" :index="i">
<segment-block :ref="'SegmentBlock'" :deviceID="deviceID" :segmentIndex="i" :segmentID="block.id" @deleteBlock="deleteBlock"/>
</SlickItem>
</SlickList>
<div style="text-align: center;">
<va-button :disabled="this.blockList.length >= 4" @click="addSegmentBlock">
+
</va-button>
</div>
<va-tree-root>
<va-tree-category
style="font-size: 20px;"
:label="'Advanced Setting'">
<va-tree-node>
<!-- <data-number :ref="'DataNumber'" :deviceID="deviceID" :parameterName="'DataNumber'" @parameterChange="deviceParameterChange($event)" /> -->
<data-output :ref="'DataOutput'" :deviceID="deviceID" :parameterName="'DATA_OUTPUT'" @parameterChange="deviceParameterChange($event)" />
<cycle-number :ref="'CycleNumber'" :deviceID="deviceID" :parameterName="'CYCLE_NUMBER'" @parameterChange="deviceParameterChange($event)" />
</va-tree-node>
</va-tree-category>
</va-tree-root>
</div>
</template>
<script>
import { taskInfo } from '../../../../data/task/TaskInfo'
import SegmentBlock from '../parameter/item/PulseSensing/SegmentBlock'
// import DataNumber from '../parameter/item/PulseSensing/DataNumber'
import DataOutput from '../parameter/item/PulseSensing/DataOutput'
import CycleNumber from '../parameter/item/PulseSensing/CycleNumber'
import { SlickList, SlickItem } from 'vue-slicksort'
import _ from 'lodash'
export default {
name: 'EliteParameterRecordingElitePulseSensing',
components: {
SegmentBlock,
// DataNumber,
DataOutput,
CycleNumber,
SlickList,
SlickItem,
},
props: {
deviceID: {
type: Number,
required: true,
},
deviceName: {
type: String,
default: 'Elite',
},
},
created () {
},
data () {
return {
blockList: [],
maxSegment: 4,
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
// Array[String of Parameter Nmae, Value]
deviceParameterChange: function (e) {
console.log('e[0],e[1]', e[0], ',', e[1])
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: e[0],
content: e[1],
}))
},
updateSegmentOrderParam () {
for (let i = 0; i < this.blockList.length; i++) {
const id = this.blockList[i].id
this.deviceParameterChange(['segment_ui_order_' + i, id + 1]) // 因為json那邊不能設負數(最小為0),所以有設segment的話傳過去的值要+1
this.deviceParameterChange(['segment_order_' + String(id), i + 1]) // 因為json那邊不能設負數(最小為0),所以有設segment的話傳過去的值要+1
}
},
clearSegmentOrderParam () {
const newIDArray = []
for (let i = 0; i < this.blockList.length; i++) {
const id = this.blockList[i].id
newIDArray.push(id)
}
for (let i = 0; i < newIDArray.length; i++) {
const id = newIDArray[i]
this.deviceParameterChange(['segment_ui_order_' + String(i), id + 1])
this.deviceParameterChange(['segment_order_' + String(id), i + 1])
}
for (let i = newIDArray.length; i < this.maxSegment; i++) {
this.deviceParameterChange(['segment_ui_order_' + String(i), 0]) // 因為json那邊不能設負數(最小為0),所以將沒有用到的segment ID設為0
}
const totalIDArray = []
for (let i = 0; i < this.maxSegment; i++) {
totalIDArray.push(i)
}
const diff = _.differenceWith(totalIDArray, newIDArray, _.isEqual) // 兩array的差集
for (let i = 0; i < diff.length; i++) {
const id = diff[i]
this.deviceParameterChange(['segment_order_' + String(id), 0]) // 因為json那邊不能設負數(最小為0),所以將沒有用到的segment ID設為0
}
},
addSegmentBlock () {
let availableID
for (let i = 0; i < this.maxSegment; i++) {
if (this.blockList.some(block => block.id === i) === false) { // ref: https://www.tutorialrepublic.com/faq/how-to-check-if-an-array-includes-an-object-in-javascript.php
availableID = i
break
}
}
this.blockList.push({ id: availableID })
this.updateSegmentOrderParam()
},
deleteBlock (segmentID) {
let deleteIndex = 0
for (let i = 0; i < this.blockList.length; i++) {
if (this.blockList[i].id === segmentID) {
deleteIndex = i
break
}
}
this.blockList.splice(deleteIndex, 1) // splice(starting index, how many values to remove);
this.clearSegmentOrderParam()
},
dragEnd (event) {
// console.log(this.blockList) // 尚未變換順序前的list
// console.log(event)
// console.log(event.newIndex)
// console.log(event.oldIndex)
// one-line swap two element of array, ref: https://stackoverflow.com/questions/872310/javascript-swap-array-elements
[this.blockList[event.oldIndex], this.blockList[event.newIndex]] = [this.blockList[event.newIndex], this.blockList[event.oldIndex]]
this.updateSegmentOrderParam()
},
refresh () {
const segmentOrderDict = {}
let order = 0
for (let i = 0; i < this.maxSegment; i++) {
const id = taskInfo.getDeviceInfo(this.deviceID).parameterSet['segment_ui_order_' + String(i)]
if (id > 0) {
segmentOrderDict[order] = id - 1 // 因為json那邊不能設負數,所以json上ID value = 0為沒設定此segment,有設的話實際ID要扣1回來
order += 1
}
}
const orderIDList = Object.values(segmentOrderDict)
this.blockList.length = 0
for (let i = 0; i < orderIDList.length; i++) {
if (this.blockList.some(block => block.id === orderIDList[i]) === false) {
this.blockList.push({ id: orderIDList[i] })
}
}
if (this.$refs.SegmentBlock != null) {
for (let i = 0; i < this.$refs.SegmentBlock.length; i++) {
this.$refs.SegmentBlock[i].refresh()
}
}
if (this.$refs.DataOutput != null) {
this.$refs.DataOutput.refresh()
}
if (this.$refs.CycleNumber != null) {
this.$refs.CycleNumber.refresh()
}
},
},
mounted () {
},
watch: {
},
destroyed () {
},
}
</script>
<style scoped>
.long-list {
max-height: 300px;
overflow: auto;
}
</style>
@@ -33,7 +33,7 @@
<!-- 1.5ui -->
<va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 0 || workingModeSelect.id == 1 || workingModeSelect.id == 5 || workingModeSelect.id == 6 || workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9 || workingModeSelect.id == 11"
v-if="workingModeSelect != null && workingModeSelect.id == 0 || workingModeSelect.id == 1 || workingModeSelect.id == 2 || workingModeSelect.id == 4 || workingModeSelect.id == 5 || workingModeSelect.id == 6 || workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9 || workingModeSelect.id == 11 || workingModeSelect.id == 13"
style="font-size: 20px;"
:label="'Range ( ' + currentRangeOptions[currentRangeSelect].label + ' )'">
<va-tree-node>
@@ -42,7 +42,7 @@
</va-tree-category>
<va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 0 || workingModeSelect.id == 1 || workingModeSelect.id == 4 ||workingModeSelect.id == 6 || workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9 || workingModeSelect.id == 11"
v-if="workingModeSelect != null && workingModeSelect.id == 0 || workingModeSelect.id == 1 || workingModeSelect.id == 2 || workingModeSelect.id == 4 || workingModeSelect.id == 5 || workingModeSelect.id == 6 || workingModeSelect.id == 7 || workingModeSelect.id == 8 || workingModeSelect.id == 9 || workingModeSelect.id == 11 || workingModeSelect.id == 13"
style="font-size: 20px;"
:label="'Range ( ' + voltageInRangeOptions[voltageInRangeSelect].label + ' )'">
<va-tree-node>
@@ -114,7 +114,7 @@
</va-tree-category>
<va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 2"
v-if="workingModeSelect != null && workingModeSelect.id == 2 || workingModeSelect.id == 3 || workingModeSelect.id == 5"
style="font-size: 20px;"
:label="'Volt out ( ' + outputVoltNumber/1000 + 'V )'">
<va-tree-node>
@@ -123,7 +123,7 @@
</va-tree-category>
<va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 2 || workingModeSelect.id == 3 || workingModeSelect.id == 4 || workingModeSelect.id == 5 || workingModeSelect.id == 6"
v-if="workingModeSelect != null && workingModeSelect.id == 0 || workingModeSelect.id == 1 || workingModeSelect.id == 2 || workingModeSelect.id == 3 || workingModeSelect.id == 4 || workingModeSelect.id == 5 || workingModeSelect.id == 6 || workingModeSelect.id == 13"
style="font-size: 20px;"
:label="'Sample rate ( ' + sampleRateNumber/10 + 'sps )'">
<va-tree-node>
@@ -239,6 +239,25 @@
</va-tree-node>
</va-tree-category>
<va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 13"
style="font-size: 20px;"
:label="'Duration ( ' + duration + timeOptions[timeUnit].label + ' )'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-input
class="mb-0"
v-model="duration"
/>
<level-button :ref="'timeUnit'" :deviceID="deviceID" :options="timeOptions" :parameterName="'TIME_UNIT'" @parameterChange="deviceParameterChange($event)" />
</div>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
v-if="workingModeSelect != null && workingModeSelect.id == 12"
style="font-size: 20px;"
@@ -340,6 +359,13 @@
</va-card>
</va-tree-category>
<div v-if="workingModeSelect != null && workingModeSelect.id == 14">
<elite-parameter-recording-elite-pulse-sensing :ref="'PulseSensingMode'" :deviceID="deviceID" :deviceName="deviceName"/>
</div>
<div v-if="workingModeSelect != null && workingModeSelect.id == 15">
<elite-parameter-recording-elite-d-p-v :ref="'DPVMode'" :deviceID="deviceID" :deviceName="deviceName"/>
</div>
</va-tree-root>
</div>
</template>
@@ -355,6 +381,8 @@ import OppLevelButton from '../parameter/item/OppLevelButton'
import MicroAmpereRange from '../parameter/item/MicroAmpereRange'
import ScanRateRange from '../parameter/item/ScanRateRange'
import ResolutionRange from '../parameter/item/ResolutionRange'
import EliteParameterRecordingElitePulseSensing from './EliteParameterRecordingElitePulseSensing'
import EliteParameterRecordingEliteDPV from './EliteParameterRecordingEliteDPV'
export default {
name: 'EliteParameterRecordingElitezm15',
@@ -367,6 +395,8 @@ export default {
MicroAmpereRange,
ScanRateRange,
ResolutionRange,
EliteParameterRecordingElitePulseSensing,
EliteParameterRecordingEliteDPV,
},
props: {
deviceID: {
@@ -439,6 +469,18 @@ export default {
id: 12,
description: 'Dev Mode',
},
{
id: 13,
description: 'Open Circuit Potential',
},
{
id: 14,
description: 'Pulse Sensing',
},
{
id: 15,
description: 'Differential Pulse Voltammetry (DPV)',
},
],
currentRangeSelect: null,
currentRangeOptions: [
@@ -545,7 +587,7 @@ export default {
voltScanRateNumber: null,
resolutionNumber: null,
measureEocButton: {
start: 'Measure Eoc',
start: 'OCP',
stop: 'Stop',
status: false,
},
@@ -557,6 +599,26 @@ export default {
read: '',
notify: '',
},
duration: 0,
timeUnit: null,
timeOptions: [
{
value: 0,
label: 'h',
},
{
value: 1,
label: 'm',
},
{
value: 2,
label: 's',
},
{
value: 3,
label: 'ms',
},
],
}
},
mqtt: {
@@ -631,6 +693,11 @@ export default {
this.$refs.cycleNoNumber.updateCycleNumber(this.cycleNoNumber)
}
this.timeUnit = taskInfo.getDeviceInfo(this.deviceID).parameterSet.TIME_UNIT
if (this.$refs.timeUnit != null) {
this.$refs.timeUnit.updateLevelButton(this.timeUnit)
}
this.outputVoltNumber = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.DAC_VOLT - 25000) / 5
if (this.$refs.outputVoltNumber != null) {
this.$refs.outputVoltNumber.updateVoltNumber(this.outputVoltNumber)
@@ -692,6 +759,14 @@ export default {
}
this.instru.read = (taskInfo.getDeviceInfo(this.deviceID).parameterSet.ADC_VALUE_I).toString(16).toUpperCase()
if (this.$refs.PulseSensingMode != null) {
this.$refs.PulseSensingMode.refresh()
}
if (this.$refs.DPVMode != null) {
this.$refs.DPVMode.refresh()
}
},
workingModeSelectChange (val) {
if (this.workingModeSelect.id === -1) {
@@ -782,6 +857,25 @@ export default {
instruction: 'dev_battery',
}))
},
setDuration () {
let totalTime = 0 // ms
if (this.timeOptions[this.timeUnit].label === 'h') {
totalTime = this.duration * 1000 * 60 * 60
} else if (this.timeOptions[this.timeUnit].label === 'm') {
totalTime = this.duration * 1000 * 60
} else if (this.timeOptions[this.timeUnit].label === 's') {
totalTime = this.duration * 1000
} else if (this.timeOptions[this.timeUnit].label === 'ms') {
totalTime = this.duration
}
setTimeout(() => {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'interrupt',
}))
}, totalTime)
},
},
mounted () {
this.refresh()
@@ -1,20 +1,12 @@
<template>
<div class="flex mt-0 pt-0">
<div>
<div class="row flex sm12 xl12 md12 xs12">
<div>
<div v-if="eliteVer=='1'">
<elite-parameter-recording :ref="'rec_ref'" :deviceID="deviceID"/>
</div>
<div v-else-if="eliteVer=='2'">
<elite-parameter-recording-elitezm15 :ref="'rec_ref'" :deviceID="deviceID"/>
<!--<elite-parameter-recording :ref="'rec_ref'" :deviceID="deviceID"/>-->
</div>
<div v-else-if="eliteVer=='3'">
<!--<elite-parameter-recording :ref="'rec_ref'" :deviceID="deviceID"/>-->
</div>
</div>
</div>
<elite-parameter-recording v-if="eliteVer=='1'" :ref="'rec_ref'" :deviceID="deviceID"/>
<!-- <elite-parameter-recording-elitezm15 :ref="'rec_ref'" :deviceID="deviceID"/> -->
<!--<elite-parameter-recording :ref="'rec_ref'" :deviceID="deviceID"/>-->
<elite-parameter-recording-elitezm15 v-else-if="eliteVer=='2'" :ref="'rec_ref'" :deviceID="deviceID"/>
<elite-parameter-recording-elite-e-i-s v-else :ref="'rec_ref'" :deviceID="deviceID"/>
<!--<elite-parameter-recording :ref="'rec_ref'" :deviceID="deviceID"/>-->
</div>
</template>
@@ -23,6 +15,7 @@
import EliteParameterRecording from './EliteParameterRecording'
import EliteParameterRecordingElitezm15 from './EliteParameterRecordingElitezm15'
import EliteParameterRecordingEliteEIS from './EliteParameterRecordingEliteEIS'
import { taskInfo } from '../../../../data/task/TaskInfo'
export default {
@@ -30,6 +23,7 @@ export default {
components: {
EliteParameterRecording,
EliteParameterRecordingElitezm15,
EliteParameterRecordingEliteEIS,
},
props: {
deviceID: {
@@ -102,6 +102,7 @@
v-model="ampGainSelect"
textBy="description"
:options="ampGainOptions"
:noClear='true'
/>
</div>
</div>
@@ -120,6 +121,7 @@
v-model="sampleRateSelect"
textBy="description"
:options="sampleRateOptions"
:noClear='true'
/>
</div>
</div>
@@ -138,6 +140,25 @@
v-model="radioFrequencySelect"
textBy="description"
:options="radioFrequencyOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Mem Radio Frequency'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="memRadioFrequencySelectChange()"
:label="''"
v-model="memRadioFrequencySelect"
textBy="description"
:options="memRadioFrequencyOptions"
/>
</div>
</div>
@@ -156,6 +177,7 @@
v-model="ledBrightnessSelect"
textBy="description"
:options="ledBrightnessOptions"
:noClear='true'
/>
</div>
</div>
@@ -174,6 +196,7 @@
v-model="acceleratorSensitivitySelect"
textBy="description"
:options="acceleratorSensitivityOptions"
:noClear='true'
/>
</div>
</div>
@@ -267,37 +290,37 @@ export default {
sampleRateOptions: [
{
id: 0,
value: 800,
value: 1000,
description: '1k',
},
{
id: 1,
value: 400,
value: 2000,
description: '2k',
},
{
id: 2,
value: 200,
value: 4000,
description: '4k',
},
{
id: 3,
value: 160,
value: 5000,
description: '5k',
},
{
id: 4,
value: 100,
value: 8000,
description: '8k',
},
{
id: 5,
value: 80,
value: 10000,
description: '10k',
},
{
id: 6,
value: 40,
value: 20000,
description: '20k',
},
],
@@ -344,6 +367,49 @@ export default {
description: '8',
},
],
memRadioFrequencySelect: null,
memRadioFrequencyOptions: [
{
id: 0,
value: -20,
description: '-20',
},
{
id: 1,
value: -16,
description: '-16',
},
{
id: 2,
value: -12,
description: '-12',
},
{
id: 3,
value: -8,
description: '-8',
},
{
id: 4,
value: -4,
description: '-4',
},
{
id: 5,
value: 0,
description: '0',
},
{
id: 6,
value: 4,
description: '4',
},
{
id: 7,
value: 8,
description: '8',
},
],
ledBrightnessSelect: null,
ledBrightnessOptions: [
{
@@ -406,7 +472,7 @@ export default {
}
})
this.ampGainSelect = this.ampGainOptions[(taskInfo.getDeviceInfo(this.deviceID).parameterSet.AMP_GAIN) % 4]
this.sampleRateSelect = this.sampleRateOptions[this.sampleRateOptions.findIndex(ele => ele.value === taskInfo.getDeviceInfo(this.deviceID).parameterSet.ADC_CLOCK)]
this.sampleRateSelect = this.sampleRateOptions[this.sampleRateOptions.findIndex(ele => ele.value === taskInfo.getDeviceInfo(this.deviceID).parameterSet.SAMPLE_RATE)]
this.recordOn = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RECORDING
this.axisChannelList.length = 0
const axisChannelSet = taskInfo.getDeviceInfo(this.deviceID).parameterSet.AXIS_CH.toString(2).split('').reverse()
@@ -425,6 +491,7 @@ export default {
})
this.radioFrequencySelect = this.radioFrequencyOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.RADIO_FREQUENCY]
this.memRadioFrequencySelect = this.memRadioFrequencyOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.MEM_RADIO_FREQUENCY]
this.ledBrightnessSelect = this.ledBrightnessOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.LED_BRIGHTNESS]
this.acceleratorSensitivitySelect = this.acceleratorSensitivityOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.ACCELERATOR_S]
},
@@ -487,12 +554,13 @@ export default {
}
},
sampleRateSelectChange () {
if (this.sampleRateSelect != null && this.sampleRateSelect.value !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.ADC_CLOCK))) {
if (this.sampleRateSelect != null && this.sampleRateSelect.value !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.SAMPLE_RATE))) {
const adcClock = 8e5 / this.sampleRateSelect.value
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'ADC_CLOCK',
content: this.sampleRateSelect.value,
parameter: 'SAMPLE_RATE|ADC_CLOCK',
content: `${this.sampleRateSelect.value}|${String(adcClock)}`,
}))
}
},
@@ -511,6 +579,21 @@ export default {
}))
}
},
memRadioFrequencySelectChange () {
if (this.memRadioFrequencySelect != null && this.memRadioFrequencySelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.MEM_RADIO_FREQUENCY))) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'MEM_RADIO_FREQUENCY',
content: this.memRadioFrequencySelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_set_central_rf/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.memRadioFrequencySelect.value,
}))
}
},
ledBrightnessSelectChange () {
if (this.ledBrightnessSelect != null && this.ledBrightnessSelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.LED_BRIGHTNESS))) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
@@ -562,8 +645,13 @@ export default {
for (const chartID in charts) {
for (const seriesIndex in charts[chartID].series) {
if (charts[chartID].series[seriesIndex].yAxisSource[1] >= 256 && charts[chartID].series[seriesIndex].yAxisSource[1] <= 260) {
charts[chartID].yAxis[seriesIndex].min = -scaleRange
charts[chartID].yAxis[seriesIndex].max = scaleRange
if (parseInt(charts[chartID].series[seriesIndex].yAxisSource[1]) === 260) {
charts[chartID].yAxis[seriesIndex].min = 0
charts[chartID].yAxis[seriesIndex].max = Math.ceil(Math.sqrt(Math.pow(scaleRange, 2) * 3))
} else {
charts[chartID].yAxis[seriesIndex].min = -scaleRange
charts[chartID].yAxis[seriesIndex].max = scaleRange
}
}
}
}
@@ -0,0 +1,856 @@
<template>
<div class="flex" >
<!-- <div>
<div class="row sm12 xl12 md12 xs12">
<va-button
class="mx-1 px-2 mb-3"
color="success"
v-if="!recordOn"
@click="recordClick"
small
>
Record
</va-button>
<va-button
class="mx-1 px-2 mb-3"
color="danger"
v-else
@click="recordClick"
small
>
Stop
</va-button>
</div>
</div> -->
<va-tree-root >
<va-tree-category
style="font-size: 20px;"
:label="'Channels'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div
style='display: inline-block;'
v-for="channel in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]"
:key="channel"
>
<va-button
class="mx-1 px-1"
v-if="channelList != null && channelList.indexOf(channel) >= 0"
@click="channelClickRemove(channel)"
small
>
{{channel}}
</va-button>
<va-button
class="mx-1 px-1"
v-if="channelList == null || channelList.indexOf(channel) < 0"
@click="channelClickAdd(channel)"
small outline
>
{{channel}}
</va-button>
</div>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'3-AXIS'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div
style='display: inline-block;'
v-for="axisChannel in ['x','y','z','m']"
:key="axisChannel"
>
<va-button
class="mx-1 px-1"
v-if="axisChannelList != null && axisChannelList.indexOf(axisChannel) >= 0"
@click="axisChannelClickRemove(axisChannel)"
small
>
{{axisChannel}}
</va-button>
<va-button
class="mx-1 px-1"
v-if="axisChannelList == null || axisChannelList.indexOf(axisChannel) < 0"
@click="axisChannelClickAdd(axisChannel)"
small outline
>
{{axisChannel}}
</va-button>
</div>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Amp gain'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="ampGainSelectChange()"
:label="''"
v-model="ampGainSelect"
textBy="description"
:options="ampGainOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Sample Rate'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="sampleRateSelectChange()"
:label="''"
v-model="sampleRateSelect"
textBy="description"
:options="sampleRateOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Radio Frequency'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="radioFrequencySelectChange()"
:label="''"
v-model="radioFrequencySelect"
textBy="description"
:options="radioFrequencyOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Mem Radio Frequency'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="memRadioFrequencySelectChange()"
:label="''"
v-model="memRadioFrequencySelect"
textBy="description"
:options="memRadioFrequencyOptions"
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Led Brightness'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="ledBrightnessSelectChange()"
:label="''"
v-model="ledBrightnessSelect"
textBy="description"
:options="ledBrightnessOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<va-tree-category
style="font-size: 20px;"
:label="'Accelerator Sensitivity'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<va-select
@input="acceleratorSensitivitySelectChange()"
:label="''"
v-model="acceleratorSensitivitySelect"
textBy="description"
:options="acceleratorSensitivityOptions"
:noClear='true'
/>
</div>
</div>
</va-tree-node>
</va-tree-category>
<!-- <va-tree-category
style="font-size: 20px;"
:label="'Sample rate'">
<va-tree-node>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="sampleRateChange(4)">
4
</va-button>
<va-input
@keyup.enter="sampleRateChange(sampleRateInput)"
v-model="sampleRateInput"
class="mb-0"
style="width: 100px;"
>
<p slot="append" style="margin-right: 0;" small>
Hz
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="sampleRateChange(1000)">
1000
</va-button>
</div>
<va-slider
@mouseup.native="sampleRateChange(sampleRate)"
@mouseleave.native="sampleRateChange(sampleRate)"
@touchend.native="sampleRateChange(sampleRate)"
class="flex sm12 xl12 md12 xs12"
value-visible
v-model="sampleRate"
:min="4"
:max="1000"
/>
</div>
</div>
</va-tree-node>
</va-tree-category> -->
</va-tree-root>
</div>
</template>
<script>
import { taskInfo } from '../../../../data/task/TaskInfo'
import { chartData } from '../../../../data/task/ChartsManagement'
export default {
name: 'NeuliveParameterRecording',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
deviceName: {
type: String,
default: 'Neulive',
},
},
data () {
return {
channelList: [],
ampGainSelect: null,
ampGainOptions: [
// {
// id: 0,
// description: '25',
// },
{
id: 0,
description: '100',
},
{
id: 1,
description: '400',
},
{
id: 2,
description: '800',
},
],
sampleRateSelect: null,
sampleRateOptions: [
{
id: 0,
value: 1000,
description: '1k',
},
{
id: 1,
value: 2000,
description: '2k',
},
{
id: 2,
value: 4000,
description: '4k',
},
{
id: 3,
value: 5000,
description: '5k',
},
{
id: 4,
value: 8000,
description: '8k',
},
{
id: 5,
value: 10000,
description: '10k',
},
{
id: 6,
value: 20000,
description: '20k',
},
{
id: 7,
value: 40000,
description: '40k',
},
{
id: 8,
value: 80000,
description: '80k',
},
{
id: 9,
value: 100000,
description: '100k',
},
],
radioFrequencySelect: null,
radioFrequencyOptions: [
{
id: 0,
value: -20,
description: '-20',
},
{
id: 1,
value: -16,
description: '-16',
},
{
id: 2,
value: -12,
description: '-12',
},
{
id: 3,
value: -8,
description: '-8',
},
{
id: 4,
value: -4,
description: '-4',
},
{
id: 5,
value: 0,
description: '0',
},
{
id: 6,
value: 4,
description: '4',
},
{
id: 7,
value: 8,
description: '8',
},
],
memRadioFrequencySelect: null,
memRadioFrequencyOptions: [
{
id: 0,
value: -20,
description: '-20',
},
{
id: 1,
value: -16,
description: '-16',
},
{
id: 2,
value: -12,
description: '-12',
},
{
id: 3,
value: -8,
description: '-8',
},
{
id: 4,
value: -4,
description: '-4',
},
{
id: 5,
value: 0,
description: '0',
},
{
id: 6,
value: 4,
description: '4',
},
{
id: 7,
value: 8,
description: '8',
},
],
ledBrightnessSelect: null,
ledBrightnessOptions: [
{
id: 0,
value: 0,
description: 'off',
},
{
id: 1,
value: 1,
description: 'bright',
},
{
id: 2,
value: 2,
description: 'normal',
},
],
acceleratorSensitivitySelect: null,
acceleratorSensitivityOptions: [
{
id: 0,
value: 3,
description: '2G',
},
{
id: 1,
value: 5,
description: '4G',
},
{
id: 2,
value: 8,
description: '8G',
},
{
id: 3,
value: 12,
description: '16G',
},
],
// sampleRateInput: '1000',
// sampleRate: null,
recordOn: false,
axisChannelList: [],
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
refresh () {
this.channelList.length = 0
// todo RECORDING_CH to RECORDING_CH_H & L
const channelSetLow = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RECORDING_CH_L.toString(2).split('').reverse()
channelSetLow.forEach((element, index) => {
if (parseInt(element) > 0) {
this.channelList.push(index + 1)
}
})
const channelSetHight = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RECORDING_CH_H.toString(2).split('').reverse()
channelSetHight.forEach((element, index) => {
if (parseInt(element) > 0) {
this.channelList.push(index + 17)
}
})
this.ampGainSelect = this.ampGainOptions[(taskInfo.getDeviceInfo(this.deviceID).parameterSet.AMP_GAIN) % 4]
this.sampleRateSelect = this.sampleRateOptions[this.sampleRateOptions.findIndex(ele => ele.value === taskInfo.getDeviceInfo(this.deviceID).parameterSet.SAMPLE_RATE)]
this.recordOn = taskInfo.getDeviceInfo(this.deviceID).parameterSet.RECORDING
this.axisChannelList.length = 0
const axisChannelSet = taskInfo.getDeviceInfo(this.deviceID).parameterSet.AXIS_CH.toString(2).split('').reverse()
axisChannelSet.forEach((element, index) => {
if (parseInt(element) === 1) {
if (index === 0) {
this.axisChannelList.push('x')
} else if (index === 1) {
this.axisChannelList.push('y')
} else if (index === 2) {
this.axisChannelList.push('z')
} else if (index === 3) {
this.axisChannelList.push('m')
}
}
})
this.radioFrequencySelect = this.radioFrequencyOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.RADIO_FREQUENCY]
this.memRadioFrequencySelect = this.memRadioFrequencyOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.MEM_RADIO_FREQUENCY]
this.ledBrightnessSelect = this.ledBrightnessOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.LED_BRIGHTNESS]
this.acceleratorSensitivitySelect = this.acceleratorSensitivityOptions[taskInfo.getDeviceInfo(this.deviceID).parameterSet.ACCELERATOR_S]
},
channelClickAdd (val) {
if (this.channelList.indexOf(val) < 0 && val <= 16 && val > 0) {
this.channelList.push(val)
let channelSet = ''
for (let i = 16; i >= 1; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_L) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING_CH_L',
content: channelValue,
}))
}
this.recordingChannelReset(this.channelList)
} else if (this.channelList.indexOf(val) < 0 && val <= 32 && val > 16) {
this.channelList.push(val)
let channelSet = ''
for (let i = 32; i >= 17; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_H) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING_CH_H',
content: channelValue,
}))
}
this.recordingChannelReset(this.channelList)
} else {
this.pageToast('Recording channels cannot choose more than 32.')
}
},
channelClickRemove (val) {
if (this.channelList.indexOf(val) >= 0 && val <= 16 && val > 0) {
this.channelList.splice(this.channelList.indexOf(val), 1)
let channelSet = ''
for (let i = 16; i >= 1; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_L) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING_CH_L',
content: channelValue,
}))
}
this.recordingChannelReset(this.channelList)
} else if (this.channelList.indexOf(val) >= 0 && val <= 32 && val > 16) {
this.channelList.splice(this.channelList.indexOf(val), 1)
let channelSet = ''
for (let i = 32; i >= 17; i--) {
if (this.channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH_H) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING_CH_H',
content: channelValue,
}))
}
this.recordingChannelReset(this.channelList)
}
},
recordingChannelReset (channelList) {
let channelSet = ''
for (let i = 32; i >= 1; i--) {
if (channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
const channelValue = parseInt(channelSet, 2)
if (channelValue !== taskInfo.getDeviceInfo(this.deviceID).RECORDING_CH) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING_CH',
content: channelValue,
}))
}
},
ampGainSelectChange () {
if (this.ampGainSelect != null && this.ampGainSelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.AMP_GAIN) % 4)) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'AMP_GAIN',
content: ((this.ampGainSelect.id) % 4),
}))
}
},
sampleRateSelectChange () {
if (this.sampleRateSelect != null && this.sampleRateSelect.value !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.SAMPLE_RATE))) {
const adcClock = 8e6 / this.sampleRateSelect.value
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'SAMPLE_RATE|ADC_CLOCK',
content: `${this.sampleRateSelect.value}|${String(adcClock)}`,
}))
}
},
radioFrequencySelectChange () {
if (this.radioFrequencySelect != null && this.radioFrequencySelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.RADIO_FREQUENCY))) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RADIO_FREQUENCY',
content: this.radioFrequencySelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_update_radio_frequency/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.radioFrequencySelect.value,
}))
}
},
memRadioFrequencySelectChange () {
if (this.memRadioFrequencySelect != null && this.memRadioFrequencySelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.MEM_RADIO_FREQUENCY))) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'MEM_RADIO_FREQUENCY',
content: this.memRadioFrequencySelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_set_central_rf/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.memRadioFrequencySelect.value,
}))
}
},
ledBrightnessSelectChange () {
if (this.ledBrightnessSelect != null && this.ledBrightnessSelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.LED_BRIGHTNESS))) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'LED_BRIGHTNESS',
content: this.ledBrightnessSelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_update_led_brightness/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.ledBrightnessSelect.value,
}))
}
},
acceleratorSensitivitySelectChange () {
if (this.acceleratorSensitivitySelect != null && this.acceleratorSensitivitySelect.id !== ((taskInfo.getDeviceInfo(this.deviceID).parameterSet.ACCELERATOR_S))) {
let scaleRange
switch (this.acceleratorSensitivitySelect.id) {
case 0:
scaleRange = 200
break
case 1:
scaleRange = 400
break
case 2:
scaleRange = 800
break
case 3:
scaleRange = 1600
break
default:
scaleRange = 0
break
}
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'ACCELERATOR_S',
content: this.acceleratorSensitivitySelect.id,
}))
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_update_accelerator_sensitivity/0',
device: taskInfo.getRawDeviceID(this.deviceID),
content: this.acceleratorSensitivitySelect.value,
}))
const charts = chartData.getAllChartsData()
for (const chartID in charts) {
for (const seriesIndex in charts[chartID].series) {
if (charts[chartID].series[seriesIndex].yAxisSource[1] >= 256 && charts[chartID].series[seriesIndex].yAxisSource[1] <= 260) {
if (parseInt(charts[chartID].series[seriesIndex].yAxisSource[1]) === 260) {
charts[chartID].yAxis[seriesIndex].min = 0
charts[chartID].yAxis[seriesIndex].max = Math.ceil(Math.sqrt(Math.pow(scaleRange, 2) * 3))
} else {
charts[chartID].yAxis[seriesIndex].min = -scaleRange
charts[chartID].yAxis[seriesIndex].max = scaleRange
}
}
}
}
}
},
// sampleRateChange (val) {
// if (this.sampleRate == null) {
// return false
// }
// if (isNaN(val) || parseInt(val) > 1000 || parseInt(val) < 4) {
// this.sampleRateInput = '1000'
// this.sampleRate = 1000
// return false
// }
// if (parseInt(this.sampleRateInput) !== this.sampleRate || this.sampleRate !== parseInt(val)) {
// this.sampleRateInput = String(val)
// this.sampleRate = parseInt(val)
// }
// if (this.sampleRate !== parseInt(200 / parseFloat(taskInfo.getDeviceInfo(this.deviceID).parameterSet.ADC_CLOCK / 1000))) {
// this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
// header: 'device_parameter/0',
// device: taskInfo.getRawDeviceID(this.deviceID),
// parameter: 'ADC_CLOCK',
// content: parseInt(parseFloat(1 / parseFloat(this.sampleRate / 200)) * 1000),
// }))
// }
// },
recordClick () {
this.recordOn = !this.recordOn
if (this.recordOn) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'record',
}))
this.$emit('record')
} else {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_instruction/0',
device: taskInfo.getRawDeviceID(this.deviceID),
instruction: 'stop_record',
}))
this.$emit('record_stop')
}
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'RECORDING',
content: this.recordOn,
}))
},
axisChannelClickAdd (val) {
if (this.axisChannelList.indexOf(val) < 0) {
const axisChannel = ['m', 'z', 'y', 'x']
this.axisChannelList.push(val)
let axisChannelSet = ''
for (const axis of axisChannel) {
if (this.axisChannelList.indexOf(axis) >= 0) {
axisChannelSet += '1'
} else {
axisChannelSet += '0'
}
}
const axisChannelValue = parseInt(axisChannelSet, 2)
if (axisChannelValue !== taskInfo.getDeviceInfo(this.deviceID).AXIS_CH) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'AXIS_CH',
content: axisChannelValue,
}))
}
}
},
axisChannelClickRemove (val) {
if (this.axisChannelList.indexOf(val) >= 0) {
const axisChannel = ['m', 'z', 'y', 'x']
this.axisChannelList.splice(this.axisChannelList.indexOf(val), 1)
let axisChannelSet = ''
for (const axis of axisChannel) {
if (this.axisChannelList.indexOf(axis) >= 0) {
axisChannelSet += '1'
} else {
axisChannelSet += '0'
}
}
const axisChannelValue = parseInt(axisChannelSet, 2)
if (axisChannelValue !== taskInfo.getDeviceInfo(this.deviceID).AXIS_CH) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'AXIS_CH',
content: axisChannelValue,
}))
}
}
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
mounted () {
this.refresh()
},
destroyed () {
},
watch: {
},
}
</script>
@@ -127,7 +127,7 @@
@touchend.native="cycleNumberChange(cycleNumber)"
value-visible
v-model="cycleNumber"
:min="1"
:min="0"
:max="255"
/>
</div>
@@ -205,7 +205,7 @@
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex sm12 xl6 md6 xs12">
<div class="flex row align--center">
<va-input
v-model="frequencyNumberInput"
@@ -219,10 +219,7 @@
</va-input>
</div>
</div>
</div>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex sm12 xl6 md6 xs12">
<div class="flex row align--center">
<va-input
v-model="periodNumberInput"
@@ -241,22 +238,24 @@
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="timeRangeChange(1, 0)">
0
</va-button>
<!-- <va-button slot="append" class="mr-2 pa-1 shrink" small @click="timeRangeChange(1, 0.1)">
0.1
</va-button> -->
<va-input
@keyup.enter="timeRangeChange(1, t1RangeInput)"
v-model="t1RangeInput"
class="mb-0"
:label="'T1 RANGE'"
:error="TRangeErrorMsgList[0].showError"
:error-messages="TRangeErrorMsgList[0].errorMsg"
>
<p slot="append" style="margin-right: 0;" small>
{{unitOptions[unitSelect].label}}
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(1, 10.23)">
<!-- <va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(1, 10.23)">
10.23
</va-button>
</va-button> -->
</div>
</div>
</div>
@@ -264,22 +263,24 @@
<div class="row" v-if="patternModeSelect==1">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="timeRangeChange(2, 0)">
<!-- <va-button slot="append" class="mr-2 pa-1 shrink" small @click="timeRangeChange(2, 0)">
0
</va-button>
</va-button> -->
<va-input
@keyup.enter="timeRangeChange(2, t2RangeInput)"
v-model="t2RangeInput"
class="mb-0"
:label="'T2 RANGE'"
:error="TRangeErrorMsgList[1].showError"
:error-messages="TRangeErrorMsgList[1].errorMsg"
>
<p slot="append" style="margin-right: 0;" small>
{{unitOptions[unitSelect].label}}
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(2, 10.23)">
<!-- <va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(2, 10.23)">
10.23
</va-button>
</va-button> -->
</div>
</div>
</div>
@@ -287,22 +288,24 @@
<div class="row" v-if="patternModeSelect==1">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="timeRangeChange(3, 0)">
0
</va-button>
<!-- <va-button slot="append" class="mr-2 pa-1 shrink" small @click="timeRangeChange(3, 0.1)">
0.1
</va-button> -->
<va-input
@keyup.enter="timeRangeChange(3, t3RangeInput)"
v-model="t3RangeInput"
class="mb-0"
:label="'T3 RANGE'"
:error="TRangeErrorMsgList[2].showError"
:error-messages="TRangeErrorMsgList[2].errorMsg"
>
<p slot="append" style="margin-right: 0;" small>
{{unitOptions[unitSelect].label}}
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(3, 10.23)">
<!-- <va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(3, 10.23)">
10.23
</va-button>
</va-button> -->
</div>
</div>
</div>
@@ -310,22 +313,25 @@
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="timeRangeChange(4, 0)">
<!-- <va-button slot="append" class="mr-2 pa-1 shrink" small @click="timeRangeChange(4, 0)">
0
</va-button>
</va-button> -->
<va-input
@keyup.enter="timeRangeChange(4, t4RangeInput)"
readonly
v-model="t4RangeInput"
class="mb-0"
:label="'T4 RANGE'"
:error="TRangeErrorMsgList[3].showError"
:error-messages="TRangeErrorMsgList[3].errorMsg"
>
<p slot="append" style="margin-right: 0;" small>
{{unitOptions[unitSelect].label}}
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(4, 1310.71)">
<!-- <va-button slot="append" class="ml-2 pa-1 shrink" small @click="timeRangeChange(4, 1310.71)">
1310.71
</va-button>
</va-button> -->
</div>
</div>
</div>
@@ -384,6 +390,7 @@ export default {
value: 1,
},
],
TRangeErrorMsgList: [{ id: 1, showError: false, errorMsg: [''] }, { id: 2, showError: false, errorMsg: [''] }, { id: 3, showError: false, errorMsg: [''] }, { id: 4, showError: false, errorMsg: [''] }],
cycleNumberSelect: null,
cycleNumberOptions: [
{
@@ -456,6 +463,20 @@ export default {
return true
}
},
TRangeStatusCheck () {
let flag = true
for (let i = 0; i < this.TRangeErrorMsgList.length; i++) {
if (this.TRangeErrorMsgList[i].showError === true) {
flag = false
break
}
}
if (flag === true) {
return true
} else {
return false
}
},
},
mqtt: {
},
@@ -470,6 +491,31 @@ export default {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
refreshPattern () {
this.patternModeSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_PATTERN ? 1 : 0
if (this.TRangeStatusCheck === true) { // if t1~t4 is not valid input, not need to refresh
this.t1Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T1[0]
this.t1RangeInput = String((this.t1Range * 10) / this.unitMultiply)
this.t1RangeArray.fill(this.t1Range, 0)
this.t2Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T2[0]
this.t2RangeInput = String((this.t2Range * 10) / this.unitMultiply)
this.t2RangeArray.fill(this.t2Range, 0)
this.t3Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T3[0]
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
this.t3RangeArray.fill(this.t3Range, 0)
this.t4Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T4[0]
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
this.t4RangeArray.fill(this.t4Range, 0)
}
this.periodNumber = (this.t1Range + this.t2Range + this.t3Range + this.t4Range) * 10
this.periodNumberInput = String((this.periodNumber) / this.unitMultiply)
if (this.periodNumber !== 0) {
this.frequencyNumber = parseInt(1 / (this.periodNumber * 1e-6))
this.frequencyNumberInput = String(this.frequencyNumber)
}
},
refresh () {
this.stimulationOn = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STIMULATING
@@ -489,11 +535,6 @@ export default {
}
}
})
// }
// console.log('cha',stiChannelSet)
// console.log('pol',stiPolaritySet)
// console.log('pos',this.posChannelList)
// console.log('neg',this.negChannelList)
this.stimulateElectrodeSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_H_BRIDGE ? 1 : 0
this.cycleNumberSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.CONTINUOUS_STI ? 1 : 0
this.cycleNumber = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_CYCLE_LIST[0]
@@ -502,49 +543,14 @@ export default {
this.amplitudeNumber = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_AMPLITUDE * 5
this.amplitudeNumberInput = String(this.amplitudeNumber)
this.patternModeSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_PATTERN ? 1 : 0
this.t1Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T1[0]
this.t1RangeInput = String((this.t1Range * 10) / this.unitMultiply)
this.t1RangeArray.fill(this.t1Range, 0)
this.t2Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T2[0]
this.t2RangeInput = String((this.t2Range * 10) / this.unitMultiply)
this.t2RangeArray.fill(this.t2Range, 0)
this.t3Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T3[0]
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
this.t3RangeArray.fill(this.t3Range, 0)
this.t4Range = taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T4[0]
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
this.t4RangeArray.fill(this.t4Range, 0)
if (this.pattternModeSelect === 0) {
this.periodNumber = (this.t1Range + this.t4Range) * 10
} else {
this.periodNumber = (this.t1Range + this.t2Range + this.t3Range + this.t4Range) * 10
}
this.periodNumberInput = String((this.periodNumber) / this.unitMultiply)
if (this.periodNumber !== 0) {
this.frequencyNumber = parseInt(1 / (this.periodNumber * 1e-6))
this.frequencyNumberInput = String(this.frequencyNumber)
}
// console.log('STI_CONTINUOUS', this.cycleNumberSelect)
// console.log('STI_H_BRIDGE', this.stimulateElectrodeSelect)
// console.log('STI_PATTERN', this.patternModeSelect)
// console.log('STI_T1', taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T1[0])
// console.log('STI_T2', taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T2[0])
// console.log('STI_T3', taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T3[0])
// console.log('STI_T4', taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_T4[0])
// console.log(this.periodNumber)
// console.log(this.periodNumberInput)
// console.log(this.frequencyNumber)
// console.log(this.frequencyNumberInput)
this.refreshPattern()
},
transUnit () {
if (this.unitSelect === 0) {
if (this.unitSelect === 0) { // s
this.unitMultiply = 1000000
} else if (this.unitSelect === 1) {
} else if (this.unitSelect === 1) { // ms
this.unitMultiply = 1000
} else {
} else { // us
this.unitMultiply = 1
}
this.refresh()
@@ -612,9 +618,10 @@ export default {
if (isNaN(val) || parseInt(val) > 255 || parseInt(val) < 1) {
this.cycleNumberInput = '1'
this.cycleNumber = 1
} else {
this.cycleNumberInput = String(val)
this.cycleNumber = parseInt(val)
}
this.cycleNumberInput = String(val)
this.cycleNumber = parseInt(val)
if (this.cycleNumberArray[0] !== this.cycleNumber) {
this.cycleNumberArray.fill(this.cycleNumber, 0)
@@ -658,130 +665,243 @@ export default {
}))
}
},
// [Region] Neulive sti pattern block
patternModeSelectChange () {
if (this.patternModeSelect == null) {
return false
}
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'STI_PATTERN',
content: this.patternModeSelect,
}))
if (this.patternModeSelect === 0) {
this.t2Range = 0
this.t2RangeInput = '0'
this.t3Range = 0
this.t3RangeInput = '0'
this.t4Range = (this.periodNumber / 10) - this.t1Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
} else {
this.t3Range = this.t1Range
this.t3RangeInput = this.t1RangeInput
this.t4Range = (this.periodNumber / 10) - this.t1Range - this.t2Range - this.t3Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
} else if (this.patternModeSelect === 1) {
this.t2Range = 0
this.t3Range = 10
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
}
if (this.patternModeSelect !== taskInfo.getDeviceInfo(this.deviceID).parameterSet.STI_PATTERN) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'STI_PATTERN',
content: this.patternModeSelect,
}))
this.autoComputeT4()
const check4 = this.checkIndividualTRange(4, this.t4Range)
if (check4) {
this.updateTimeRange()
}
this.updateTimeRange()
this.updateStiTRangeCheckParam()
},
frequencyNumberChange (val) {
if (this.frequencyNumberInput == null) {
if (this.frequencyNumberInput == null || isNaN(val)) {
return false
}
if (typeof (val) === 'string') {
if (isNaN(val) || parseInt(val) < 1 || parseInt(val) > 10000) {
this.frequencyNumberInput = '100'
this.frequencyNumber = 100
}
if (parseInt(this.frequencyNumberInput) !== parseInt(this.frequencyNumber)) {
this.frequencyNumber = parseInt(val)
}
val = parseInt(val)
if (val < 1) {
this.frequencyNumberInput = '1'
this.frequencyNumber = 1
this.pageToast('Reset to 1 Hz')
} else if (val > 20000) {
this.frequencyNumberInput = '20000'
this.frequencyNumber = 20000
this.pageToast('Reset to 20000 Hz')
} else {
this.frequencyNumberInput = val.toString()
this.frequencyNumber = val
}
this.periodNumber = (1 / this.frequencyNumber * 1e6).toFixed(3)
this.periodNumber = (1e6 / this.frequencyNumber).toFixed(3) // us
this.periodNumberInput = String(this.periodNumber / this.unitMultiply)
if (this.t1Range === 0 || this.t3Range === 0) {
this.t1Range = 10
this.t1RangeInput = String((this.t1Range * 10) / this.unitMultiply)
this.t3Range = 10
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
this.t4Range = (this.periodNumber / 10) - (this.t1Range + this.t2Range + this.t3Range)
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
} else {
this.t4Range = (this.periodNumber / 10) - (this.t1Range + this.t2Range + this.t3Range)
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
}
this.autoComputeT4()
this.updateTimeRange()
const check1 = this.checkIndividualTRange(1, this.t1Range)
const check2 = this.checkIndividualTRange(2, this.t2Range)
const check3 = this.checkIndividualTRange(3, this.t3Range)
const check4 = this.checkIndividualTRange(4, this.t4Range)
// if pass, call this.updateTimeRange(), if any fail, call updateErrorMsg in this.checkIndividualTRange()
if (check1 === true && check2 === true && check3 === true && check4 === true) {
this.updateTimeRange()
}
this.updateStiTRangeCheckParam()
},
periodNumberChange (val) {
if (this.periodNumberInput === null) {
const usVal = parseFloat(val * this.unitMultiply) // us
if (this.periodNumberInput == null || isNaN(usVal)) {
return false
}
if (typeof (val) === 'string') {
if (isNaN(val) || parseFloat(val) < 0 || parseFloat(val / this.unitMultiply) > 1) {
this.periodNumber = 1000
this.periodNumberInput = String(this.periodNumber / this.unitMultiply)
}
if (parseInt(this.periodNumberInput) !== parseInt(this.periodNumber)) {
this.periodNumber = parseFloat(val * this.unitMultiply)
this.periodNumberInput = val
}
if (usVal < 50) { // freq: 1 to 20000Hz, so period > 50us (1e6/50=20000)
this.periodNumber = 50
this.periodNumberInput = String(50 / this.unitMultiply)
this.pageToast('Reset to 50 us')
} else if (usVal > 1e6) { // freq: 1 to 20000Hz, so period < 1e6us (1e6/1e6=1)
this.periodNumber = 1e6
this.periodNumberInput = String(1e6 / this.unitMultiply)
this.pageToast('Reset to 1 s')
} else {
this.periodNumber = usVal
this.periodNumberInput = val
}
this.frequencyNumber = parseInt(1 / (this.periodNumber * 1e-6))
this.frequencyNumber = parseInt(1e6 / this.periodNumber)
this.frequencyNumberInput = String(this.frequencyNumber)
if (this.t1Range === 0 || this.t3Range === 0) {
this.t1Range = 10
this.t1RangeInput = String((this.t1Range * 10) / this.unitMultiply)
this.t3Range = 10
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
this.t4Range = (this.periodNumber / 10) - (this.t1Range + this.t2Range + this.t3Range)
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
} else {
this.t4Range = (this.periodNumber / 10) - (this.t1Range + this.t2Range + this.t3Range)
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
}
this.autoComputeT4()
this.updateTimeRange()
const check1 = this.checkIndividualTRange(1, this.t1Range)
const check2 = this.checkIndividualTRange(2, this.t2Range)
const check3 = this.checkIndividualTRange(3, this.t3Range)
const check4 = this.checkIndividualTRange(4, this.t4Range)
// if pass, call this.updateTimeRange(), if any fail, call updateErrorMsg in this.checkIndividualTRange()
if (check1 === true && check2 === true && check3 === true && check4 === true) {
this.updateTimeRange()
}
this.updateStiTRangeCheckParam()
},
timeRangeChange (stiIimeSelect, val) {
timeRangeChange (stiIimeSelect, inputVal) {
inputVal = parseFloat(inputVal)
switch (stiIimeSelect) {
case 1:
this.t1Range = parseInt((val * this.unitMultiply) / 10)
this.t1RangeInput = val
if (this.patternModeSelect === 1) {
this.t3Range = parseInt((val * this.unitMultiply) / 10)
this.t3RangeInput = val
}
this.t1RangeInput = inputVal
this.t1Range = parseFloat((inputVal * this.unitMultiply) / 10)
this.autoComputeT4()
break
case 2:
this.t2Range = parseInt((val * this.unitMultiply) / 10)
this.t2RangeInput = val
this.t2RangeInput = inputVal
this.t2Range = parseFloat((inputVal * this.unitMultiply) / 10)
this.autoComputeT4()
break
case 3:
this.t1Range = parseInt((val * this.unitMultiply) / 10)
this.t1RangeInput = val
this.t3Range = parseInt((val * this.unitMultiply) / 10)
this.t3RangeInput = val
this.t3RangeInput = inputVal
this.t3Range = parseFloat((inputVal * this.unitMultiply) / 10)
this.autoComputeT4()
break
case 4:
this.t4Range = parseInt((val * this.unitMultiply) / 10)
this.t4RangeInput = val
if (this.frequencyNumber > 0) {
this.t2Range = (this.periodNumber / 10) - this.t1Range - this.t3Range - this.t4Range
this.t2RangeInput = String((this.t2Range * 10) / this.unitMultiply)
}
this.t4RangeInput = inputVal
this.t4Range = parseFloat((inputVal * this.unitMultiply) / 10)
break
}
if (this.frequencyNumber > 0 && stiIimeSelect !== 4) {
this.t4Range = (this.periodNumber / 10) - this.t1Range - this.t2Range - this.t3Range
const status1 = this.checkIndividualTRange(1, this.t1Range)
const status2 = this.checkIndividualTRange(2, this.t2Range)
const status3 = this.checkIndividualTRange(3, this.t3Range)
const status4 = this.checkIndividualTRange(4, this.t4Range)
if (status1 && status2 && status3 && status4) {
this.resetAllTRangeErrorMsg({ totalT: 4 })
this.updateTimeRange()
}
this.updateStiTRangeCheckParam()
},
updateStiTRangeCheckParam () {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: 'sti_trange_set_done',
content: this.TRangeStatusCheck,
}))
},
autoResetAllTRange () {
if (this.patternModeSelect === 0) { // Monophasic
this.t1Range = 10
this.t1RangeInput = String((this.t1Range * 10) / this.unitMultiply)
this.t4Range = this.periodNumber / 10 - this.t1Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
} else if (this.patternModeSelect === 1) { // Biphasic
this.t1Range = 10
this.t1RangeInput = String((this.t1Range * 10) / this.unitMultiply)
this.t2Range = 10
this.t2RangeInput = String((this.t2Range * 10) / this.unitMultiply)
this.t3Range = 10
this.t3RangeInput = String((this.t3Range * 10) / this.unitMultiply)
this.t4Range = this.periodNumber / 10 - this.t1Range - this.t2Range - this.t3Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
}
this.updateTimeRange()
},
autoComputeT4 () {
this.t4Range = (this.periodNumber / 10) - this.t1Range - this.t2Range - this.t3Range
this.t4RangeInput = String((this.t4Range * 10) / this.unitMultiply)
if (this.t4Range >= 0) {
this.pageToast(`T4 = ${(this.t4Range / 100).toFixed(1)} ms`)
} else {
this.pageToast('T4 can not be negative. Please check T1~T3 setting.')
}
},
// [SubRegion] check sti T range setting helper function
// update individual t range error msg
updateTRangeErrorMsg (payload) {
const index = payload.stiIimeSelect - 1
this.TRangeErrorMsgList[index].showError = payload.status
this.TRangeErrorMsgList[index].errorMsg[0] = payload.msg
},
resetAllTRangeErrorMsg (payload) {
for (let i = 1; i <= payload.totalT; i++) {
this.updateTRangeErrorMsg({ stiIimeSelect: i, status: false, msg: '' })
}
},
checkIndividualTRange (stiIimeSelect, val) {
// val unit: us
val = parseFloat(val) * 10 // UI us
if (val < 0 || isNaN(val)) {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: `T${stiIimeSelect} can not be negative. Please check your setting.` })
return false
}
switch (stiIimeSelect) {
case 1:
if (val < 100 || val > 10230) { // us
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: '0.1ms <= T1 <= 10.23ms' })
return false
} else if (val > this.periodNumber) {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: 'T1 > PERIOD' })
return false
} else {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
return true
}
case 2:
if (val < 0 || val > 10230) { // us
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: '0ms <= T2 <= 10.23ms' })
return false
} else if (val > this.periodNumber) {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: 'T2 > PERIOD' })
return false
} else {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
return true
}
case 3:
if (val < 100 || val > 10230) { // us
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: '0.1ms <= T3 <= 10.23ms' })
return false
} else if (val > this.periodNumber) {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: 'T3 > PERIOD' })
return false
} else {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
return true
}
case 4:
if (val < 0 || val > 1310710) { // us
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: true, msg: '0ms <= T4 <= 1310.71ms' })
return false
} else {
this.updateTRangeErrorMsg({ stiIimeSelect: stiIimeSelect, status: false, msg: '' })
return true
}
}
},
// [EndSubRegion]
// [EndRegion]
updateStiChannel () {
// stiChannelSet (+,-), stiPolaritySet (+)
let stiChannelSet = ''
@@ -846,6 +966,16 @@ export default {
}))
}
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
mounted () {
this.refresh()
File diff suppressed because it is too large Load Diff
@@ -7,7 +7,27 @@
:label="'RECORDING'"
>
<va-tree-node>
<neulive-parameter-recording :ref="'rec_ref'" :deviceID="deviceID" @record="start()" @record_stop="stop()"/>
<neulive-parameter-recording
v-if="
(device)
? (device.info.library_name.indexOf('3.0') !== -1 || device.info.library_name.indexOf('3.1') !== -1)
: false
"
:ref="'rec_ref'" :deviceID="deviceID"
@record="start()"
@record_stop="stop()"
/>
<neulive-parameter-recording35
v-if="
(device)
? (device.info.library_name.indexOf('3.5') !== -1)
: false
"
:ref="'rec_ref'"
:deviceID="deviceID"
@record="start()"
@record_stop="stop()"
/>
</va-tree-node>
</va-tree-category>
<va-tree-category
@@ -15,7 +35,24 @@
:label="'STIMULATION'"
>
<va-tree-node>
<neulive-parameter-stimulation :ref="'sti_ref'" :deviceID="deviceID"/>
<neulive-parameter-stimulation
v-if="
(device)
? (device.info.library_name.indexOf('3.0') !== -1 || device.info.library_name.indexOf('3.1') !== -1)
: false
"
:ref="'sti_ref'"
:deviceID="deviceID"
/>
<neulive-parameter-stimulation35
v-if="
(device)
? (device.info.library_name.indexOf('3.5') !== -1)
: false
"
:ref="'sti_ref'"
:deviceID="deviceID"
/>
</va-tree-node>
</va-tree-category>
</va-tree-root>
@@ -26,12 +63,16 @@
import { taskInfo } from '../../../../data/task/TaskInfo'
import NeuliveParameterRecording from './NeuliveParameterRecording'
import NeuliveParameterStimulation from './NeuliveParameterStimulation'
import NeuliveParameterRecording35 from './NeuliveParameterRecording35'
import NeuliveParameterStimulation35 from './NeuliveParameterStimulation35'
export default {
name: 'NeuliveParameterWindow',
components: {
NeuliveParameterRecording,
NeuliveParameterStimulation,
NeuliveParameterRecording35,
NeuliveParameterStimulation35,
},
props: {
deviceID: {
@@ -45,6 +86,7 @@ export default {
},
data () {
return {
device: null,
}
},
mqtt: {
@@ -81,6 +123,8 @@ export default {
},
mounted () {
this.pageInit()
this.device = taskInfo.getDeviceInfo(this.deviceID)
console.log(taskInfo.getDeviceInfo(this.deviceID).info)
},
watch: {
deviceID: function (val) {
@@ -0,0 +1,98 @@
<template>
<div>
<e-initial :ref="'EInitial'" :deviceID="deviceID" :parameterName="'E_initial'" @parameterChange="deviceParameterChange($event)" />
<e-1 :ref="'E1'" :deviceID="deviceID" :parameterName="'E1'" @parameterChange="deviceParameterChange($event)" />
<e-2 :ref="'E2'" :deviceID="deviceID" :parameterName="'E1'" @parameterChange="deviceParameterChange($event)" />
<e-final :ref="'EFinal'" :deviceID="deviceID" :parameterName="'E_final'" @parameterChange="deviceParameterChange($event)" />
<pulse-amp :ref="'PulseAmp'" :deviceID="deviceID" :parameterName="'Pulse_Amp'" @parameterChange="deviceParameterChange($event)" />
<pulse-width :ref="'PulseWidth'" :deviceID="deviceID" :parameterName="'Pulse_Width'" @parameterChange="deviceParameterChange($event)" />
<increment :ref="'Increment'" :deviceID="deviceID" :parameterName="'Increment'" @parameterChange="deviceParameterChange($event)" />
<step-time :ref="'StepTime'" :deviceID="deviceID" :parameterName="'Step_time'" @parameterChange="deviceParameterChange($event)" />
<current-recording-period :ref="'CURR_REC'" :deviceID="deviceID" :parameterName="'CURR_REC_'" @parameterChange="deviceParameterChange($event)" />
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
import EInitial from './EInitial'
import E1 from './E1'
import E2 from './E2'
import EFinal from './EFinal'
import PulseAmp from './PulseAmp'
import PulseWidth from './PulseWidth'
import Increment from './Increment'
import StepTime from './StepTime'
import CurrentRecordingPeriod from './CurrentRecordingPeriod'
export default {
name: 'SegmentBlock',
components: {
EInitial,
E1,
E2,
EFinal,
PulseAmp,
PulseWidth,
Increment,
StepTime,
CurrentRecordingPeriod,
},
props: {
deviceID: {
type: Number,
required: true,
},
},
created () {
},
data () {
return {
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
// Array[String of Parameter Name, Value]
deviceParameterChange: function (e) {
console.log('e[0],e[1]', e[0], ',', e[1])
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: e[0],
content: e[1],
}))
},
refresh () {
if (this.$refs.EInitial != null) {
this.$refs.EInitial.refresh()
}
if (this.$refs.EFinal != null) {
this.$refs.EFinal.refresh()
}
if (this.$refs.PulseAmp != null) {
this.$refs.PulseAmp.refresh()
}
if (this.$refs.PulseWidth != null) {
this.$refs.PulseWidth.refresh()
}
if (this.$refs.Increment != null) {
this.$refs.Increment.refresh()
}
if (this.$refs.StepTime != null) {
this.$refs.StepTime.refresh()
}
},
},
mounted () {
this.refresh()
},
watch: {
},
destroyed () {
},
}
</script>
@@ -0,0 +1,89 @@
<template>
<div>
<e-initial :ref="'EInitial'" :deviceID="deviceID" :parameterName="'E_initial'" @parameterChange="deviceParameterChange($event)" />
<e-final :ref="'EFinal'" :deviceID="deviceID" :parameterName="'E_final'" @parameterChange="deviceParameterChange($event)" />
<pulse-amp :ref="'PulseAmp'" :deviceID="deviceID" :parameterName="'Pulse_Amp'" @parameterChange="deviceParameterChange($event)" />
<pulse-width :ref="'PulseWidth'" :deviceID="deviceID" :parameterName="'Pulse_Width'" @parameterChange="deviceParameterChange($event)" />
<increment :ref="'Increment'" :deviceID="deviceID" :parameterName="'Increment'" @parameterChange="deviceParameterChange($event)" />
<step-time :ref="'StepTime'" :deviceID="deviceID" :parameterName="'Step_time'" @parameterChange="deviceParameterChange($event)" />
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
import EInitial from './EInitial'
import EFinal from './EFinal'
import PulseAmp from './PulseAmp'
import PulseWidth from './PulseWidth'
import Increment from './Increment'
import StepTime from './StepTime'
export default {
name: 'SegmentBlock',
components: {
EInitial,
EFinal,
PulseAmp,
PulseWidth,
Increment,
StepTime,
},
props: {
deviceID: {
type: Number,
required: true,
},
},
created () {
},
data () {
return {
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
// Array[String of Parameter Name, Value]
deviceParameterChange: function (e) {
console.log('e[0],e[1]', e[0], ',', e[1])
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: e[0],
content: e[1],
}))
},
refresh () {
if (this.$refs.EInitial != null) {
this.$refs.EInitial.refresh()
}
if (this.$refs.EFinal != null) {
this.$refs.EFinal.refresh()
}
if (this.$refs.PulseAmp != null) {
this.$refs.PulseAmp.refresh()
}
if (this.$refs.PulseWidth != null) {
this.$refs.PulseWidth.refresh()
}
if (this.$refs.Increment != null) {
this.$refs.Increment.refresh()
}
if (this.$refs.StepTime != null) {
this.$refs.StepTime.refresh()
}
},
},
mounted () {
this.refresh()
},
watch: {
},
destroyed () {
},
}
</script>
@@ -0,0 +1,101 @@
<template>
<div>
<div class="row flex sm12 xl12 md12 xs12 align--center">
<div class="flex sm9 xl9 md9 xs9 px-0 mx-0">
<p class="display-6">Current Recording Period<p/>
</div>
<div class="flex sm3 xl3 md3 xs3 px-0 mx-0">
<p small> {{ itemInput }} ~ 100% </p>
<!-- <va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
%
</p>
</va-input> -->
</div>
</div>
<div class="flex sm12 xl12 md12 xs12" :key="inputeKey">
<va-slider
@mouseup.native="itemChange(itemInput)"
@mouseleave.native="itemChange(itemInput)"
@touchend.native="itemChange(itemInput)"
pins
:min="0"
:max="90"
value-visible
:step="10"
v-model="itemInput"
/>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'CurrentRecordingPeriod',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
disableSlider: false,
inputeKey: 0,
itemInput: Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName]),
// duration: Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet['t_pulse_' + String(this.segmentID)]) / 10,
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.$emit('parameterChange', [this.parameterName, val])
},
checkSliderRange (duration) {
if (duration <= 10) {
this.disableSlider = true
} else {
this.disableSlider = false
const percent = parseFloat((5 / duration) * 100)
if (percent > 5) {
this.itemChange([this.itemInputMin, this.itemInputMax])
} else if (percent >= 1.1 && percent <= 5) {
this.itemChange([this.itemInputMin, this.itemInputMax])
} else if (percent < 1.1) {
this.itemChange([this.itemInputMin, this.itemInputMax])
}
}
},
refresh () {
// this.itemInput
// this.duration = Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet['t_pulse_' + String(this.segmentID)]) / 10
},
},
async mounted () {
// this.checkSliderRange(this.duration)
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,121 @@
<template>
<div class="flex-container">
<p class="display-6 flex-child">E 1<p/>
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0 flex-child1"
:error="showError"
:error-messages="errorMsg"
>
</va-input>
<va-button
@click="unitChange()"
v-model="unitSelect"
class="px-2 py-0 mr-0 flex-child2"
>
{{ unitSelect }}
</va-button>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'E1',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)),
unitSelect: 'mV',
unitClickTime: 0,
showError: false,
errorMsg: [''],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
this.showError = false
this.errorMsg[0] = ''
if (this.unitSelect === 'V') {
val = parseFloat(val) * 1000
}
if (parseInt(val) < -5000 || parseInt(val) > 5000) {
this.showError = true
this.errorMsg[0] = '-5 ~ 5V'
return
}
if (parseFloat(val) !== Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)) {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), parseFloat(val) * 5 + 25000])
}
},
unitChange () {
this.unitClickTime += 1
if (this.unitClickTime % 2 === 0) {
this.unitSelect = 'mV'
this.itemInput = String(parseFloat(this.itemInput) * 1000)
} else {
this.unitSelect = 'V'
this.itemInput = String(parseFloat(this.itemInput) / 1000)
}
},
refresh () {
let volt = Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)
if (this.unitSelect === 'V') {
volt /= 1000
}
this.itemInput = String(volt)
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -0,0 +1,121 @@
<template>
<div class="flex-container">
<p class="display-6 flex-child">E 2<p/>
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0 flex-child1"
:error="showError"
:error-messages="errorMsg"
>
</va-input>
<va-button
@click="unitChange()"
v-model="unitSelect"
class="px-2 py-0 mr-0 flex-child2"
>
{{ unitSelect }}
</va-button>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'E2',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)),
unitSelect: 'mV',
unitClickTime: 0,
showError: false,
errorMsg: [''],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
this.showError = false
this.errorMsg[0] = ''
if (this.unitSelect === 'V') {
val = parseFloat(val) * 1000
}
if (parseInt(val) < -5000 || parseInt(val) > 5000) {
this.showError = true
this.errorMsg[0] = '-5 ~ 5V'
return
}
if (parseFloat(val) !== Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)) {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), parseFloat(val) * 5 + 25000])
}
},
unitChange () {
this.unitClickTime += 1
if (this.unitClickTime % 2 === 0) {
this.unitSelect = 'mV'
this.itemInput = String(parseFloat(this.itemInput) * 1000)
} else {
this.unitSelect = 'V'
this.itemInput = String(parseFloat(this.itemInput) / 1000)
}
},
refresh () {
let volt = Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)
if (this.unitSelect === 'V') {
volt /= 1000
}
this.itemInput = String(volt)
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -0,0 +1,121 @@
<template>
<div class="flex-container">
<p class="display-6 flex-child">E Final<p/>
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0 flex-child1"
:error="showError"
:error-messages="errorMsg"
>
</va-input>
<va-button
@click="unitChange()"
v-model="unitSelect"
class="px-2 py-0 mr-0 flex-child2"
>
{{ unitSelect }}
</va-button>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'EFinal',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)),
unitSelect: 'mV',
unitClickTime: 0,
showError: false,
errorMsg: [''],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
this.showError = false
this.errorMsg[0] = ''
if (this.unitSelect === 'V') {
val = parseFloat(val) * 1000
}
if (parseInt(val) < -5000 || parseInt(val) > 5000) {
this.showError = true
this.errorMsg[0] = '-5 ~ 5V'
return
}
if (parseFloat(val) !== Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)) {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), parseFloat(val) * 5 + 25000])
}
},
unitChange () {
this.unitClickTime += 1
if (this.unitClickTime % 2 === 0) {
this.unitSelect = 'mV'
this.itemInput = String(parseFloat(this.itemInput) * 1000)
} else {
this.unitSelect = 'V'
this.itemInput = String(parseFloat(this.itemInput) / 1000)
}
},
refresh () {
let volt = Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)
if (this.unitSelect === 'V') {
volt /= 1000
}
this.itemInput = String(volt)
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -0,0 +1,121 @@
<template>
<div class="flex-container">
<p class="display-6 flex-child">E Initial<p/>
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0 flex-child1"
:error="showError"
:error-messages="errorMsg"
>
</va-input>
<va-button
@click="unitChange()"
v-model="unitSelect"
class="px-2 py-0 mr-0 flex-child2"
>
{{ unitSelect }}
</va-button>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'EInitial',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)),
unitSelect: 'mV',
unitClickTime: 0,
showError: false,
errorMsg: [''],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
this.showError = false
this.errorMsg[0] = ''
if (this.unitSelect === 'V') {
val = parseFloat(val) * 1000
}
if (parseInt(val) < -5000 || parseInt(val) > 5000) {
this.showError = true
this.errorMsg[0] = '-5 ~ 5V'
return
}
if (parseFloat(val) !== Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)) {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), parseFloat(val) * 5 + 25000])
}
},
unitChange () {
this.unitClickTime += 1
if (this.unitClickTime % 2 === 0) {
this.unitSelect = 'mV'
this.itemInput = String(parseFloat(this.itemInput) * 1000)
} else {
this.unitSelect = 'V'
this.itemInput = String(parseFloat(this.itemInput) / 1000)
}
},
refresh () {
let volt = Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)
if (this.unitSelect === 'V') {
volt /= 1000
}
this.itemInput = String(volt)
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -0,0 +1,121 @@
<template>
<div class="flex-container">
<p class="display-6 flex-child">Increment<p/>
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0 flex-child1"
:error="showError"
:error-messages="errorMsg"
>
</va-input>
<va-button
@click="unitChange()"
v-model="unitSelect"
class="px-2 py-0 mr-0 flex-child2"
>
{{ unitSelect }}
</va-button>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'Increment',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)),
unitSelect: 'mV',
unitClickTime: 0,
showError: false,
errorMsg: [''],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
this.showError = false
this.errorMsg[0] = ''
if (this.unitSelect === 'V') {
val = parseFloat(val) * 1000
}
if (parseInt(val) < -5000 || parseInt(val) > 5000) {
this.showError = true
this.errorMsg[0] = '-5 ~ 5V'
return
}
if (parseFloat(val) !== Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)) {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), parseFloat(val) * 5 + 25000])
}
},
unitChange () {
this.unitClickTime += 1
if (this.unitClickTime % 2 === 0) {
this.unitSelect = 'mV'
this.itemInput = String(parseFloat(this.itemInput) * 1000)
} else {
this.unitSelect = 'V'
this.itemInput = String(parseFloat(this.itemInput) / 1000)
}
},
refresh () {
let volt = Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)
if (this.unitSelect === 'V') {
volt /= 1000
}
this.itemInput = String(volt)
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -0,0 +1,121 @@
<template>
<div class="flex-container">
<p class="display-6 flex-child">Pulse Amplitude<p/>
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0 flex-child1"
:error="showError"
:error-messages="errorMsg"
>
</va-input>
<va-button
@click="unitChange()"
v-model="unitSelect"
class="px-2 py-0 mr-0 flex-child2"
>
{{ unitSelect }}
</va-button>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'PulseAmp',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)),
unitSelect: 'mV',
unitClickTime: 0,
showError: false,
errorMsg: [''],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
this.showError = false
this.errorMsg[0] = ''
if (this.unitSelect === 'V') {
val = parseFloat(val) * 1000
}
if (parseInt(val) < -5000 || parseInt(val) > 5000) {
this.showError = true
this.errorMsg[0] = '-5 ~ 5V'
return
}
if (parseFloat(val) !== Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)) {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), parseFloat(val) * 5 + 25000])
}
},
unitChange () {
this.unitClickTime += 1
if (this.unitClickTime % 2 === 0) {
this.unitSelect = 'mV'
this.itemInput = String(parseFloat(this.itemInput) * 1000)
} else {
this.unitSelect = 'V'
this.itemInput = String(parseFloat(this.itemInput) / 1000)
}
},
refresh () {
let volt = Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)
if (this.unitSelect === 'V') {
volt /= 1000
}
this.itemInput = String(volt)
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -0,0 +1,130 @@
<template>
<div class="flex-container">
<p class="display-6 flex-child">Pulse Width<p/>
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0 flex-child1"
:error="showError"
:error-messages="errorMsg"
>
</va-input>
<va-button
@click="unitChange()"
v-model="unitSelect"
class="px-2 py-0 mr-0 flex-child2"
>
{{ unitSelect }}
</va-button>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'PulseWidth',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)]) / 10)),
unitSelect: 'msec',
unitClickTime: 0,
showError: false,
errorMsg: [''],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
this.showError = false
this.errorMsg[0] = ''
if (this.unitSelect === 'sec') {
val = parseInt(val) * 1000
}
// 5 ms a step
const remainder = parseInt(val) % 5
if (remainder !== 0) {
val = parseInt(val) + (5 - remainder)
}
if (parseInt(val) < 1 || parseInt(val) > 100000) {
this.showError = true
this.errorMsg[0] = '1ms ~ 100s'
return
}
if (parseFloat(val) !== Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] / 10)) {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), parseInt(val) * 10])
this.$emit('checkCurrentRecording', val)
}
},
unitChange () {
this.unitClickTime += 1
if (this.unitClickTime % 2 === 0) {
this.unitSelect = 'msec'
this.itemInput = String(parseFloat(this.itemInput) * 1000)
} else {
this.unitSelect = 'sec'
this.itemInput = String(parseFloat(this.itemInput) / 1000)
}
},
refresh () {
if (this.showError === false) {
let duration = Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)]) / 10)
if (this.unitSelect === 'sec') {
duration /= 1000
}
this.itemInput = String(duration)
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -0,0 +1,130 @@
<template>
<div class="flex-container">
<p class="display-6 flex-child">Step Time<p/>
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0 flex-child1"
:error="showError"
:error-messages="errorMsg"
>
</va-input>
<va-button
@click="unitChange()"
v-model="unitSelect"
class="px-2 py-0 mr-0 flex-child2"
>
{{ unitSelect }}
</va-button>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'StepTime',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)]) / 10)),
unitSelect: 'msec',
unitClickTime: 0,
showError: false,
errorMsg: [''],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
this.showError = false
this.errorMsg[0] = ''
if (this.unitSelect === 'sec') {
val = parseInt(val) * 1000
}
// 5 ms a step
const remainder = parseInt(val) % 5
if (remainder !== 0) {
val = parseInt(val) + (5 - remainder)
}
if (parseInt(val) < 1 || parseInt(val) > 100000) {
this.showError = true
this.errorMsg[0] = '1ms ~ 100s'
return
}
if (parseFloat(val) !== Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] / 10)) {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), parseInt(val) * 10])
this.$emit('checkCurrentRecording', val)
}
},
unitChange () {
this.unitClickTime += 1
if (this.unitClickTime % 2 === 0) {
this.unitSelect = 'msec'
this.itemInput = String(parseFloat(this.itemInput) * 1000)
} else {
this.unitSelect = 'sec'
this.itemInput = String(parseFloat(this.itemInput) / 1000)
}
},
refresh () {
if (this.showError === false) {
let duration = Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)]) / 10)
if (this.unitSelect === 'sec') {
duration /= 1000
}
this.itemInput = String(duration)
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -0,0 +1,66 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
<p class="display-6">AC Amplitude<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0" :key="inputeKey">
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
mV
</p>
</va-input>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'ACAmplitude',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName]) / 2047 * 800)),
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
if (parseInt(this.itemInput) !== Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName] / 2047 * 800)) {
this.$emit('parameterChange', [this.parameterName, Math.round(parseInt(this.itemInput) / 800 * 2047)])
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,80 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
<p class="display-6">Average<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0" :key="inputeKey">
<va-button-toggle
@click.native="itemChange(itemSelect)"
small
outline
v-model="itemSelect"
:options="options"
class="mb-0"
/>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'Average',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
options: [
{
value: 0,
label: '2',
},
{
value: 1,
label: '4',
},
{
value: 2,
label: '6',
},
{
value: 3,
label: '8',
},
],
itemSelect: taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemSelect = val
this.inputeKey++
if (this.itemSelect !== taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName]) {
this.$emit('parameterChange', [this.parameterName, this.itemSelect])
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,84 @@
<template>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm4 xl4 md4 xs4 pa-0 ma-0">
<p class="display-6">Current Range<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 pa-0 ma-0" :key="inputeKey">
<va-button-toggle
@click.native="itemChange(itemSelect)"
small
outline
v-model="itemSelect"
:options="options"
class="mb-0"
/>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'CurrentRange',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
options: [
{
value: 0,
label: '1',
},
{
value: 1,
label: '2',
},
{
value: 2,
label: '3',
},
{
value: 3,
label: '4',
},
{
value: 4,
label: 'Auto',
},
],
itemSelect: taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
if (this.itemSelect !== taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName]) {
this.$emit('parameterChange', [this.parameterName, this.itemSelect])
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,66 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
<p class="display-6">DC Voltage<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0" :key="inputeKey">
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
mV
</p>
</va-input>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'DCVolt',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName]) * 2200 / 4095)),
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
if (parseInt(this.itemInput) !== Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName]) * 2200 / 4095)) {
this.$emit('parameterChange', [this.parameterName, Math.round((parseInt(this.itemInput) * 4095) / 2200)])
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,66 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
<p class="display-6">Delay<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0" :key="inputeKey">
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
period
</p>
</va-input>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'Delay',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName] / 10)).toFixed(1)),
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
if (parseFloat(this.itemInput).toFixed(1) !== parseFloat(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName] / 10).toFixed(1)) {
this.$emit('parameterChange', [this.parameterName, parseInt((parseFloat(this.itemInput) * 10))])
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,95 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm4 xl4 md4 xs4 px-0 mx-0">
<p class="display-6">Frequency Range<p/>
</div>
<div class="row flex sm8 xl8 md8 xs8 px-0 mx-0" :key="inputeKey">
<va-input
@mouseleave.native="itemChangeMin(itemInputMin)"
@keyup.enter="itemChangeMin(itemInputMin)"
@blur="itemChangeMin(itemInputMin)"
v-model="itemInputMin"
class="my-0 py-0"
:label="'Min'"
>
<p slot="append" style="margin-right: 0;" small>
Hz
</p>
</va-input>
<va-input
@mouseleave.native="itemChangeMax(itemInputMax)"
@keyup.enter="itemChangeMax(itemInputMax)"
@blur="itemChangeMax(itemInputMax)"
v-model="itemInputMax"
class="my-0 py-0"
:label="'Max'"
>
<p slot="append" style="margin-right: 0;" small>
Hz
</p>
</va-input>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'FreqRange',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInputMin: 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)),
itemInputMax: 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)),
}
},
mqtt: {
},
methods: {
itemChangeMin (val) {
this.itemInputMin = val
this.inputeKey++
if (parseFloat(this.itemInputMin).toFixed(1) !== parseFloat(Math.round(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.FREQ_START * 0.0149) * 100)) / 100).toFixed(1)) {
if (parseFloat(this.itemInputMin) < 0.1) {
this.$emit('parameterChange', [this.parameterName + '_START', 1])
} else {
this.$emit('parameterChange', [this.parameterName + '_START', Math.round((parseFloat(this.itemInputMin)) / 0.0149)])
}
}
},
itemChangeMax (val) {
this.itemInputMax = val
this.inputeKey++
if (parseFloat(this.itemInputMax).toFixed(1) !== parseFloat(Math.round(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet.FREQ_STOP * 0.0149) * 100)) / 100).toFixed(1)) {
if (parseFloat(this.itemInputMax) < 0.1) {
this.$emit('parameterChange', [this.parameterName + '_START', 1])
} else {
this.$emit('parameterChange', [this.parameterName + '_STOP', Math.round((parseFloat(this.itemInputMax)) / 0.0149)])
}
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,71 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm5 xl5 md5 xs5 px-0 mx-0">
<p class="display-6">Point Spacing<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0" :key="inputeKey">
<va-button-toggle
@click.native="itemChange(itemSelect)"
small
outline
v-model="itemSelect"
:options="options"
/>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'PointSpacing',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
options: [
{
value: 0,
label: 'Logarithm',
},
{
value: 1,
label: 'Linear',
},
],
itemSelect: taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
if (this.itemSelect !== taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName]) {
this.$emit('parameterChange', [this.parameterName, this.itemSelect])
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,66 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0">
<p class="display-6">Points Per Decades<p/>
</div>
<div class="flex sm6 xl6 md6 xs6 px-0 mx-0" :key="inputeKey">
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
points
</p>
</va-input>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'PointsPerDecades',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(parseInt((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName]))),
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
if (String(this.itemInput) !== String(Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName]))) {
this.$emit('parameterChange', [this.parameterName, parseInt(this.itemInput)])
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,117 @@
<template>
<div class="row">
<div class="flex sm12 xl12 md12 xs12">
<div class="flex row align--center" :key="inputeKey">
<va-button slot="append" class="mr-2 pa-1 shrink" small @click="voltNumberChange(minValue*1000)">
{{ minValue }}
</va-button>
<va-input
@mouseleave.native="voltNumberChange(voltNumberInput)"
@keyup.enter="voltNumberChange(voltNumberInput)"
@blur="voltNumberChange(voltNumberInput)"
v-model="voltNumberInput"
class="mb-0"
style="width: 100px;"
>
<p slot="append" style="margin-right: 0;" small>
V
</p>
</va-input>
<va-button slot="append" class="ml-2 pa-1 shrink" small @click="voltNumberChange(maxValue*1000)">
{{ maxValue }}
</va-button>
</div>
<va-slider
@mouseup.native="voltNumberChange(voltNumber)"
@mouseleave.native="voltNumberChange(voltNumber)"
@touchend.native="voltNumberChange(voltNumber)"
@click.native="voltNumberChange(voltNumber)"
class="flex sm12 xl12 md12 xs12"
v-model="voltNumber"
:min="minValue*1000"
:max="maxValue*1000"
/>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'VoltRange',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
minValue: {
type: Number,
default: -5,
},
maxValue: {
type: Number,
default: 5,
},
},
created () {
},
data () {
return {
inputeKey: 0,
voltNumber: (taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName] - 25000) / 12.5,
voltNumberInput: String(parseFloat((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName] - 25000) / 12500).toFixed(3)),
}
},
mqtt: {
},
methods: {
voltNumberChange (val) {
this.inputeKey++
if (this.voltNumber == null) {
return false
}
if (typeof (val) === 'string') {
if (isNaN(val) || parseFloat(val) > 2 || parseFloat(val) < -1.8) {
this.voltNumberInput = '0.00'
this.voltNumber = 0
return false
}
if (parseFloat(this.voltNumberInput) !== parseFloat(this.voltNumber / 1000)) {
this.voltNumber = parseInt(parseFloat(val).toFixed(3) * 1000)
this.voltNumberInput = String(parseFloat(this.voltNumber / 1000).toFixed(3))
}
} else {
if (isNaN(val) || parseFloat(val) > 2000 || parseFloat(val) < -1800) {
this.voltNumberInput = '0.00'
this.voltNumber = 0
return false
}
if (parseFloat(this.voltNumberInput) !== parseFloat(this.voltNumber / 1000) || this.voltNumber !== val) {
this.voltNumberInput = String(parseFloat(val / 1000).toFixed(3))
this.voltNumber = val
}
}
if (this.voltNumber !== (taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName] - 25000) / 12.5) {
this.$emit('parameterChange', [this.parameterName, this.voltNumber * 12.5 + 25000])
}
},
updateVoltNumber (val) {
this.voltNumberChange(val)
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -85,7 +85,7 @@ export default {
return false
}
if (parseFloat(this.currentNumberInput) !== parseFloat(this.currentNumber / 100)) {
this.currentNumber = parseInt(parseFloat(val).toFixed(2) * 100)
this.currentNumber = parseInt((parseFloat(val) * 100).toFixed(2))
this.currentNumberInput = String(parseFloat(this.currentNumber / 100).toFixed(2))
}
} else {
@@ -0,0 +1,175 @@
<template>
<div>
<div class="row flex sm12 xl12 md12 xs12 align--center">
<div class="flex sm9 xl9 md9 xs9 px-0 mx-0">
<p class="display-6">Current Recording Period<p/>
</div>
<div class="flex sm3 xl3 md3 xs3 px-0 mx-0">
<p small> {{ this.sliderMin }} ~ {{ this.sliderMax }} % </p>
</div>
</div>
<div class="flex sm12 xl12 md12 xs12" :key="inputeKey">
<va-slider
@mouseup.native="itemChange(currentRange)"
@mouseleave.native="itemChange(currentRange)"
@touchend.native="itemChange(currentRange)"
:disabled="disableSlider"
range
pins
:min="sliderMin"
:max="sliderMax"
value-visible
:step="5"
v-model="currentRange"
/>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'CurrentRecordingPeriod',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
segmentID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
disableSlider: false,
sliderMin: 35,
sliderMax: 100,
currentRange: [],
inputeKey: 0,
itemInputMin: Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + 'START_' + String(this.segmentID)]),
itemInputMax: Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + 'END_' + String(this.segmentID)]),
duration: Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet['t_pulse_' + String(this.segmentID)]) / 10,
}
},
mqtt: {
},
methods: {
itemChange (val) {
let updateMin = val[0]
let updateMax = val[1]
this.inputeKey++
if (this.sliderMin > updateMin) {
updateMin = this.sliderMin
}
if (this.sliderMax < updateMax) {
updateMax = this.sliderMax
}
this.itemInputMin = updateMin
this.itemInputMax = updateMax
if (parseFloat(this.itemInputMin) !== Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + 'START_' + String(this.segmentID)])) {
if (this.itemInputMin === 0) {
updateMin = 1
}
this.$emit('parameterChange', [this.parameterName + 'START_' + String(this.segmentID), updateMin])
}
if (parseFloat(this.itemInputMax) !== Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + 'END_' + String(this.segmentID)])) {
if (this.itemInputMax === 100) {
updateMax = 99
}
this.$emit('parameterChange', [this.parameterName + 'END_' + String(this.segmentID), updateMax])
}
this.currentRange = [this.itemInputMin, this.itemInputMax]
// console.log(val)
// console.log(this.currentRange)
},
setSliderMinMax (min, max) {
this.sliderMin = min
this.sliderMax = max
},
checkSliderRange (duration) {
if (duration <= 10) {
this.disableSlider = true
} else {
this.disableSlider = false
const percent = parseFloat((5 / duration) * 100)
if (percent > 5) {
let tick
for (let i = 5; i < 50; i += 5) {
if (parseFloat(i) < percent && percent <= parseFloat(i + 5)) {
tick = i + 5
break
}
}
this.setSliderMinMax(tick, 100 - tick)
this.itemChange([this.itemInputMin, this.itemInputMax])
} else if (percent >= 1.1 && percent <= 5) {
this.setSliderMinMax(5, 95)
this.itemChange([this.itemInputMin, this.itemInputMax])
} else if (percent < 1.1) {
this.setSliderMinMax(0, 100)
this.itemChange([this.itemInputMin, this.itemInputMax])
}
}
},
reset () {
this.$emit('parameterChange', [this.parameterName + 'START_' + String(this.segmentID), 35])
this.$emit('parameterChange', [this.parameterName + 'END_' + String(this.segmentID), 95])
},
refresh () {
let start = Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + 'START_' + String(this.segmentID)])
let end = Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + 'END_' + String(this.segmentID)])
if (start === 1) {
start = 0
}
if (end === 99) {
end = 100
}
this.itemInputMin = start
this.itemInputMax = end
this.duration = Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet['t_pulse_' + String(this.segmentID)]) / 10
},
},
async mounted () {
if (this.itemInputMin === 1) {
this.itemInputMin = 0
}
if (this.itemInputMax === 99) {
this.itemInputMax = 100
}
this.checkSliderRange(this.duration)
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -0,0 +1,109 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm4 xl4 md4 xs4 px-0 mx-0">
<p class="display-6">Number of Cycles<p/>
</div>
<div class="flex sm8 xl8 md8 xs8 px-0 mx-0" :key="inputeKey">
<div class="flex-container">
<va-input
disabled
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0 flex-child"
>
<p slot="append" style="margin-right: 0;" small>
cycles
</p>
</va-input>
<va-button small disabled class="flex-child2" @click="setInfinite">
</va-button>
</div>
</div>
</div>
</template>
<script>
// import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'CycleNumber',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: '∞',
// itemInput: String(parseInt(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName])),
}
},
mqtt: {
},
methods: {
// [TODO, last modified: 2021/08/06]: pulse mode cycle can't exceed 255, and now cycle default = 0, but other mode cycle number setting will affect this mode
itemChange (val) {
// this.itemInput = val
// this.inputeKey++
// if (this.itemInput !== '') {
// if (parseInt(this.itemInput) !== Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName])) {
// this.$emit('parameterChange', [this.parameterName, parseInt(this.itemInput)])
// }
// } else { // infinite: send 0 to elite
// if (taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName] !== 0) {
// this.$emit('parameterChange', [this.parameterName, 0])
// }
// }
},
setInfinite () {
this.itemInput = '∞'
},
refresh () {
// let cycle = Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName])
let cycle = 0
if (cycle === 0) {
cycle = '∞'
}
this.itemInput = String(cycle)
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -0,0 +1,66 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 align--center my-0 py-0">
<div class="flex sm4 xl4 md4 xs4 px-0 mx-0">
<p class="display-6">Number of Data<p/>
</div>
<div class="flex sm8 xl8 md8 xs8 px-0 mx-0" :key="inputeKey">
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0"
>
<p slot="append" style="margin-right: 0;" small>
points
</p>
</va-input>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'DataNumber',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(parseInt(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName])),
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
if (parseInt(this.itemInput) !== Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName])) {
this.$emit('parameterChange', [this.parameterName, parseInt(this.itemInput)])
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,76 @@
<template>
<div class="flex row mt-0 pt-0 sm12 xl12 md12 xs12 align--center">
<div class="flex sm4 xl4 md4 xs4 pa-0 ma-0">
<p class="display-6">Data Output<p/>
</div>
<div class="flex sm8 xl8 md8 xs8 pa-0 ma-0" :key="inputeKey">
<va-button-toggle
@click.native="itemChange(itemSelect)"
disabled
small
outline
v-model="itemSelect"
:options="options"
class="mb-0"
/>
</div>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'DataOutput',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
options: [
{
value: 0,
label: 'Average',
},
{
value: 1,
label: 'Raw Data',
},
],
itemSelect: taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
if (this.itemSelect !== taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName]) {
this.$emit('parameterChange', [this.parameterName, this.itemSelect])
}
},
refresh () {
this.itemSelect = taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName]
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,114 @@
<template>
<div class="block">
<div class="row flex sm12 xl12 md12 xs12 align--center">
<div class="flex sm11 xl11 md11 xs11 px-0 mx-0">
<p class="display-6">- Segment {{ segmentIndex + 1 }} - <p/>
</div>
<div class="flex sm1 xl1 md1 xs1 px-0 mx-0">
<va-button @click="deleteBlock" color="danger" style="margin-right: 0;" small> - </va-button>
</div>
</div>
<segment-volt :ref="'V_initial'" :deviceID="deviceID" :segmentID="segmentID" :parameterName="'V_initial_'" @parameterChange="deviceParameterChange($event)" />
<segment-duration :ref="'t_pulse'" :deviceID="deviceID" :segmentID="segmentID" :parameterName="'t_pulse_'" @parameterChange="deviceParameterChange($event)" @checkCurrentRecording="checkCurrentRecording" />
<current-recording-period :ref="'CURR_REC'" :deviceID="deviceID" :segmentID="segmentID" :parameterName="'CURR_REC_'" @parameterChange="deviceParameterChange($event)" />
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
import SegmentVolt from './SegmentVolt'
import SegmentDuration from './SegmentDuration'
import CurrentRecordingPeriod from './CurrentRecordingPeriod'
export default {
name: 'SegmentBlock',
components: {
SegmentVolt,
SegmentDuration,
CurrentRecordingPeriod,
},
props: {
deviceID: {
type: Number,
required: true,
},
segmentIndex: {
type: Number,
required: true,
},
segmentID: {
type: Number,
required: true,
},
},
created () {
},
data () {
return {
CurrentPeriod: null,
VoltInput: null,
VoltButton: null,
DurationInput: null,
DurationButton: null,
}
},
mqtt: {
},
methods: {
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
// Array[String of Parameter Name, Value]
deviceParameterChange: function (e) {
console.log('e[0],e[1]', e[0], ',', e[1])
this.mqttPub(taskInfo.getTaskInfo().controllerID + '_user', JSON.stringify({
header: 'device_parameter/0',
device: taskInfo.getRawDeviceID(this.deviceID),
parameter: e[0],
content: e[1],
}))
},
checkCurrentRecording (duration) {
this.$refs.CURR_REC.checkSliderRange(duration)
},
resetBlock () {
this.$refs.V_initial.reset()
this.$refs.t_pulse.reset()
this.$refs.CURR_REC.reset()
},
deleteBlock () {
this.resetBlock()
this.$emit('deleteBlock', this.segmentID)
},
refresh () {
if (this.$refs.V_initial != null) {
this.$refs.V_initial.refresh()
}
if (this.$refs.t_pulse != null) {
this.$refs.t_pulse.refresh()
}
if (this.$refs.CURR_REC != null) {
this.$refs.CURR_REC.refresh()
}
},
},
mounted () {
this.refresh()
},
watch: {
},
destroyed () {
},
}
</script>
<style lang="scss">
.block {
opacity: 1;
}
.block:hover {
background-color: #d3d3d3;
}
</style>
@@ -0,0 +1,137 @@
<template>
<div class="flex-container">
<p class="display-6 flex-child">Segment Duration<p/>
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0 flex-child1"
:error="showError"
:error-messages="errorMsg"
>
</va-input>
<va-button
@click="unitChange()"
v-model="unitSelect"
class="px-2 py-0 mr-0 flex-child2"
>
{{ unitSelect }}
</va-button>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'SegmentDuration',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
segmentID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)]) / 10)),
unitSelect: 'ms',
unitClickTime: 0,
showError: false,
errorMsg: [''],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
this.showError = false
this.errorMsg[0] = ''
if (this.unitSelect === 's') {
val = parseInt(val) * 1000
}
// 5 ms a step
const remainder = parseInt(val) % 5
if (remainder !== 0) {
val = parseInt(val) + (5 - remainder)
}
if (parseInt(val) < 1 || parseInt(val) > 100000) {
this.showError = true
this.errorMsg[0] = '1ms ~ 100s'
return
}
if (parseFloat(val) !== Math.round(taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] / 10)) {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), parseInt(val) * 10])
this.$emit('checkCurrentRecording', val)
}
},
unitChange () {
this.unitClickTime += 1
if (this.unitClickTime % 2 === 0) {
this.unitSelect = 'ms'
this.itemInput = String(parseFloat(this.itemInput) * 1000)
} else {
this.unitSelect = 's'
this.itemInput = String(parseFloat(this.itemInput) / 1000)
}
},
reset () {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), 1000]) // 100ms
},
refresh () {
if (this.showError === false) {
let duration = Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)]) / 10)
if (this.unitSelect === 's') {
duration /= 1000
}
this.itemInput = String(duration)
}
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -0,0 +1,128 @@
<template>
<div class="flex-container">
<p class="display-6 flex-child">Segment Voltage<p/>
<va-input
@mouseleave.native="itemChange(itemInput)"
@keyup.enter="itemChange(itemInput)"
@blur="itemChange(itemInput)"
v-model="itemInput"
class="mb-0 flex-child1"
:error="showError"
:error-messages="errorMsg"
>
</va-input>
<va-button
@click="unitChange()"
v-model="unitSelect"
class="px-2 py-0 mr-0 flex-child2"
>
{{ unitSelect }}
</va-button>
</div>
</template>
<script>
import { taskInfo } from '@/data/task/TaskInfo'
export default {
name: 'SegmentVolt',
components: {
},
props: {
deviceID: {
type: Number,
required: true,
},
segmentID: {
type: Number,
required: true,
},
parameterName: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
itemInput: String(Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)),
unitSelect: 'V',
unitClickTime: 0,
showError: false,
errorMsg: [''],
}
},
mqtt: {
},
methods: {
itemChange (val) {
this.itemInput = val
this.inputeKey++
this.showError = false
this.errorMsg[0] = ''
if (this.unitSelect === 'V') {
val = parseFloat(val) * 1000
}
if (parseInt(val) < -5000 || parseInt(val) > 5000) {
this.showError = true
this.errorMsg[0] = '-5 ~ 5V'
return
}
if (parseFloat(val) !== Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)) {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), parseFloat(val) * 5 + 25000])
}
},
unitChange () {
this.unitClickTime += 1
if (this.unitClickTime % 2 === 0) {
this.unitSelect = 'V'
this.itemInput = String(parseFloat(this.itemInput) / 1000)
} else {
this.unitSelect = 'mV'
this.itemInput = String(parseFloat(this.itemInput) * 1000)
}
},
reset () {
this.$emit('parameterChange', [this.parameterName + String(this.segmentID), 25000])
},
refresh () {
let volt = Math.round((taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName + String(this.segmentID)] - 25000) / 5)
if (this.unitSelect === 'V') {
volt /= 1000
}
this.itemInput = String(volt)
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
<style lang="scss">
.flex-container {
display: flex;
}
.flex-child {
flex: 2;
}
.flex-child1 {
flex: 1;
}
.flex-child2 {
flex: 0;
}
.flex-child:first-child {
margin-right: 1px;
}
</style>
@@ -85,7 +85,7 @@ export default {
return false
}
if (parseFloat(this.voltNumberInput) !== parseFloat(this.voltNumber / 1000)) {
this.voltNumber = parseInt(parseFloat(val).toFixed(3) * 1000)
this.voltNumber = parseInt((parseFloat(val) * 1000).toFixed(3))
this.voltNumberInput = String(parseFloat(this.voltNumber / 1000).toFixed(3))
}
} else {
@@ -98,6 +98,7 @@ export default {
this.voltNumberInput = String(parseFloat(val / 1000).toFixed(3))
this.voltNumber = val
}
console.log('____val:', val, 'voltNumberInput:', this.voltNumberInput, 'voltNumber:', this.voltNumber)
}
if (this.voltNumber !== (taskInfo.getDeviceInfo(this.deviceID).parameterSet[this.parameterName] - 25000) / 5) {
this.$emit('parameterChange', [this.parameterName, this.voltNumber * 5 + 25000])
+18
View File
@@ -0,0 +1,18 @@
import api from './index'
import auth from './auth'
async function spikeDetect (attrs) {
const _header = auth.getHeader()
try {
return await api.axios.post('/api/analysis/spike_detect', attrs, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
const analysis = {
spikeDetect,
}
export default analysis
+27
View File
@@ -0,0 +1,27 @@
import api from './index'
const _header = {}
function setHeader (header) {
_header.Authorization = 'Bearer ' + header
}
function getHeader () {
if (Object.keys(_header).length === 0) {
getJwtData()
}
return _header
}
async function getJwtData () {
const _jwt = await api.axios.get('/public/auth/get_cookie')
setHeader(_jwt.data)
}
const auth = {
getHeader,
getJwtData,
}
export default auth
+81
View File
@@ -0,0 +1,81 @@
import api from './index'
import auth from './auth'
async function create (attrs) {
const _header = auth.getHeader()
const _data = {
name: attrs.name,
parent: attrs.parent,
type: attrs.type,
size: attrs.size,
}
try {
return await api.axios.post('/api/file/collection/create', _data, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function getByID (id) {
const _header = auth.getHeader()
try {
return await api.axios.get(`/api/file/collection/get_by_id/${id}`, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function getByName (name) {
const _header = auth.getHeader()
try {
return await api.axios.get(`/api/file/collection/get_by_name/${name}`, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function getByParent (type, parent) {
const _header = auth.getHeader()
try {
return await api.axios.get(`/api/file/collection/get_by_parent/${type}/${parent}`, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function getAll () {
const _header = auth.getHeader()
try {
return await api.axios.get('/api/file/collection/get/all', { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function getByParentName (collectionType, parent, name) {
console.log(collectionType, parent, name)
const _header = auth.getHeader()
try {
return await api.axios.get(`/api/file/collection/get_by_parent_name/${collectionType}/${parent}/${name}`, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
const collection = {
create,
getByID,
getByName,
getByParent,
getByParentName,
getAll,
}
export default collection
+52
View File
@@ -0,0 +1,52 @@
import api from './index'
import auth from './auth'
async function create (_data) {
const _header = auth.getHeader()
try {
return await api.axios.post('/api/controller/create/', _data, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function getAll () {
const _header = auth.getHeader()
console.log(_header)
try {
return await api.axios.get('/api/controller/get/all', { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function getByMac (mac) {
const _header = auth.getHeader()
try {
return await api.axios.get(`/api/controller/get_by_mac/${mac}`, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function update (attrs) {
const _header = auth.getHeader()
try {
return await api.axios.post('/api/controller/update', attrs, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
const controller = {
create,
getAll,
getByMac,
update,
}
export default controller
+73
View File
@@ -0,0 +1,73 @@
import api from './index'
import auth from './auth'
async function create (attrs) {
const _header = auth.getHeader()
try {
return await api.axios.post('/api/device/create', attrs, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function updateByID (id, attrs) {
const _header = auth.getHeader()
try {
return await api.axios.post(`/api/device/update_by_id/${id}`, attrs, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function del (id) {
const _header = auth.getHeader()
try {
return await api.axios.get(`/api/device/clear_deleted/${id}`, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function getByID (id) {
const _header = auth.getHeader()
try {
return await api.axios.get(`/api/device/get_by_id/${id}`, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function getByName (name) {
const _header = auth.getHeader()
try {
return await api.axios.get(`/api/device/get_by_name/${name}`, { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
async function getAll () {
const _header = auth.getHeader()
try {
return await api.axios.get('/api/device/get/all', { headers: _header })
} catch (e) {
console.error(e)
return false
}
}
const device = {
create,
updateByID,
del,
getByID,
getByName,
getAll,
}
export default device

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