Commit 95403b74f74061acfee77997164af33afc9dfb7a

Authored by loveumiko
2 parents 0203a98c a4341e8d

Merge branch 'main_dev' of http://git.yunteng.com/yunteng/thingskit-front into f…

…ix/board-style-issues
... ... @@ -28,6 +28,8 @@ enum DeviceManagerApi {
28 28
29 29 DEVICE_ALARM_URL = '/alarm',
30 30
  31 + ALARM_BATCH_ACK = '/alarm/batch/ack',
  32 +
31 33 DEVICE_CREDENTIALS = '/device/credentials',
32 34
33 35 COMMAND_ISSUANCE = '/rpc',
... ... @@ -346,3 +348,13 @@ export const getDevicesByDeviceIds = (ids: string[]) => {
346 348 data: ids,
347 349 });
348 350 };
  351 +
  352 +export const doBatchAckAlarm = (ids: string[]) => {
  353 + return defHttp.post(
  354 + {
  355 + url: DeviceManagerApi.ALARM_BATCH_ACK,
  356 + data: { alarmIds: ids },
  357 + },
  358 + { joinPrefix: false }
  359 + );
  360 +};
... ...
... ... @@ -18,6 +18,9 @@
18 18 查看告警详情
19 19 </a-button>
20 20 </template>
  21 + <template #toolbar>
  22 + <Button @click="handleBatchAck" type="primary">批量处理</Button>
  23 + </template>
21 24 </BasicTable>
22 25 <AlarmDetailDrawer @register="registerDetailDrawer" @success="handleSuccess" />
23 26 </div>
... ... @@ -26,10 +29,10 @@
26 29 import { defineComponent, nextTick, h } from 'vue';
27 30 import { BasicTable, useTable, TableAction } from '/@/components/Table';
28 31 import { alarmColumns, alarmSearchSchemas } from './config/detail.config';
29   - import { getDeviceAlarm } from '/@/api/device/deviceManager';
  32 + import { doBatchAckAlarm, getDeviceAlarm } from '/@/api/device/deviceManager';
30 33 import { useDrawer } from '/@/components/Drawer';
31 34 import AlarmDetailDrawer from './cpns/AlarmDetailDrawer.vue';
32   - import { Modal } from 'ant-design-vue';
  35 + import { Modal, Button } from 'ant-design-vue';
33 36 import { JsonPreview } from '/@/components/CodeEditor';
34 37 import { getDeviceDetail } from '/@/api/device/deviceManager';
35 38 import { getAttribute } from '/@/api/ruleengine/ruleengineApi';
... ... @@ -38,17 +41,21 @@
38 41 operationString,
39 42 operationBoolean,
40 43 } from '/@/views/rule/linkedge/config/formatData';
  44 + import { AlarmLogItem } from '/@/api/device/model/deviceConfigModel';
  45 + import { AlarmStatus } from '/@/enums/alarmEnum';
  46 + import { useMessage } from '/@/hooks/web/useMessage';
41 47
42 48 export default defineComponent({
43 49 name: 'AlarmCenter',
44 50 components: {
  51 + Button,
45 52 BasicTable,
46 53 TableAction,
47 54 AlarmDetailDrawer,
48 55 },
49 56
50 57 setup() {
51   - const [registerTable, { reload }] = useTable({
  58 + const [registerTable, { reload, getSelectRows, clearSelectedRowKeys }] = useTable({
52 59 title: '告警记录列表',
53 60 api: getDeviceAlarm,
54 61 columns: alarmColumns,
... ... @@ -61,6 +68,14 @@
61 68 bordered: true,
62 69 showIndexColumn: false,
63 70 showTableSetting: true,
  71 + rowSelection: {
  72 + type: 'checkbox',
  73 + getCheckboxProps: (record: AlarmLogItem) => {
  74 + return {
  75 + disabled: record.status === AlarmStatus.CLEARED_ACK,
  76 + };
  77 + },
  78 + },
64 79 actionColumn: {
65 80 width: 200,
66 81 title: '操作',
... ... @@ -148,12 +163,24 @@
148 163 attribute,
149 164 };
150 165 };
  166 +
  167 + const { createMessage } = useMessage();
  168 + const handleBatchAck = async () => {
  169 + const ids = getSelectRows<AlarmLogItem>().map((item) => item.id);
  170 +
  171 + await doBatchAckAlarm(ids);
  172 + createMessage.success('操作成功');
  173 + clearSelectedRowKeys();
  174 + reload();
  175 + };
  176 +
151 177 return {
152 178 registerTable,
153 179 registerDetailDrawer,
154 180 handleDetail,
155 181 handleSuccess,
156 182 handleViewAlarmDetails,
  183 + handleBatchAck,
157 184 };
158 185 },
159 186 });
... ...
... ... @@ -91,7 +91,7 @@ export const formSchema: FormSchema[] = [
91 91 valueField: 'fileList',
92 92 componentProps: () => {
93 93 return {
94   - // listType: 'picture-card',
  94 + listType: 'picture-card',
95 95 maxFileLimit: 1,
96 96 api: async (file: File) => {
97 97 try {
... ... @@ -110,10 +110,10 @@ export const formSchema: FormSchema[] = [
110 110 onPreview: (fileList: FileItem) => {
111 111 createImgPreview({ imageList: [fileList.url!] });
112 112 },
113   - showUploadList: {
114   - showDownloadIcon: true,
115   - showRemoveIcon: true,
116   - },
  113 + // showUploadList: {
  114 + // showDownloadIcon: true,
  115 + // showRemoveIcon: true,
  116 + // },
117 117 };
118 118 },
119 119 },
... ...
... ... @@ -22,7 +22,7 @@
22 22 watch(
23 23 () => props.customerList,
24 24 (newValue) => {
25   - const transferResult = newValue.map((item) => [item.ts, item.value]);
  25 + const transferResult = newValue.map((item) => [item.date, item.value]);
26 26
27 27 setOptions({
28 28 tooltip: {
... ... @@ -35,7 +35,7 @@
35 35 },
36 36 },
37 37 xAxis: {
38   - type: 'time',
  38 + type: 'category',
39 39 splitLine: {
40 40 show: true,
41 41 lineStyle: {
... ... @@ -90,7 +90,7 @@
90 90 trend: props.type,
91 91 });
92 92
93   - const transferResult = res.map((item) => [item.ts, item.value]);
  93 + const transferResult = res.map((item) => [item.date, item.value]);
94 94 setOptions({
95 95 tooltip: {
96 96 trigger: 'axis',
... ...
... ... @@ -31,7 +31,7 @@
31 31 },
32 32 },
33 33 xAxis: {
34   - type: 'time',
  34 + type: 'category',
35 35 splitLine: {
36 36 show: true,
37 37 lineStyle: {
... ... @@ -79,11 +79,11 @@
79 79 const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
80 80 onMounted(async () => {
81 81 const res = await getTrendData({
82   - ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_30_DAY),
  82 + ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_1_MONTH),
83 83 trend: 'CUSTOMER_TREND',
84 84 });
85 85
86   - const transferResult = res.map((item) => [item.ts, item.value]);
  86 + const transferResult = res.map((item) => [item.date, item.value]);
87 87 setOptions({
88 88 tooltip: {
89 89 trigger: 'axis',
... ... @@ -95,7 +95,7 @@
95 95 },
96 96 },
97 97 xAxis: {
98   - type: 'time',
  98 + type: 'category',
99 99 splitLine: {
100 100 show: true,
101 101 lineStyle: {
... ...
... ... @@ -37,7 +37,15 @@
37 37 <DatePicker
38 38 @change="(_, DateString) => onDateChange(_, DateString, role === RoleEnum.CUSTOMER_USER)"
39 39 v-model:value="dateValue"
40   - />
  40 + >
  41 + <Button
  42 + type="link"
  43 + class="!px-0"
  44 + :style="dateValue ? { color: '#0960bd', fontWeight: 500 } : { color: '#000000d9' }"
  45 + >
  46 + {{ dateValue ? (dateValue as moment.Moment).format('YYYY-MM-DD') : '自定义' }}
  47 + </Button>
  48 + </DatePicker>
41 49 </div>
42 50 </template>
43 51 <div v-if="activeKey === '1'">
... ... @@ -99,13 +107,13 @@
99 107 <Tooltip :overlayStyle="{ maxWidth: '340px' }">
100 108 <template #title>
101 109 <section>
102   - <div>30天: 查询最近30天的数据,间隔时间为1天.</div>
  110 + <div>最近一个月: 查询最近一个月的数据,间隔时间为1天.</div>
103 111 <div>最近三个月: 查询最近三个月的数据,间隔时间为1天.</div>
104   - <div>最近一年: 查询最近一年的数据,间隔时间为30天.</div>
  112 + <div>最近一年: 查询最近一年的数据,间隔时间为1月.</div>
105 113 <div>
106 114 间隔时间:
107 115 <span class="font-bold underline"> 以当天的(最后时间)作为结束时间 </span>
108   - ,往前推移对应天数或小时的时间作为开始时间,然后在此时间区间内进行分组聚合查询.
  116 + ,往前推移对应天数或的时间作为开始时间,然后在此时间区间内进行分组聚合查询.
109 117 </div>
110 118 </section>
111 119 </template>
... ... @@ -120,9 +128,28 @@
120 128 </template>
121 129 <DatePicker.RangePicker
122 130 @change="onDateCustomerChange"
  131 + :disabledDate="handleDisableDate"
  132 + @calendarChange="handleCalendarChange"
123 133 size="small"
124 134 v-model:value="customerDateValue"
125   - />
  135 + >
  136 + <Button
  137 + type="link"
  138 + class="!px-0"
  139 + :style="
  140 + customerDateValue && customerDateValue.length
  141 + ? { color: '#0960bd', fontWeight: 500 }
  142 + : { color: '#000000d9' }
  143 + "
  144 + >{{
  145 + customerDateValue && customerDateValue.length
  146 + ? `${(customerDateValue?.[0] as moment.Moment)?.format('YYYY-MM-DD')}
  147 + ~
  148 + ${(customerDateValue?.[1] as moment.Moment)?.format('YYYY-MM-DD')}`
  149 + : '自定义'
  150 + }}</Button
  151 + >
  152 + </DatePicker.RangePicker>
126 153 </div>
127 154 </template>
128 155 <CustomerTrend :customerTrendList="customerTrendList" />
... ... @@ -130,8 +157,8 @@
130 157 </div>
131 158 </template>
132 159 <script lang="ts" setup>
133   - import { ref, reactive } from 'vue';
134   - import { Card, DatePicker, Tooltip } from 'ant-design-vue';
  160 + import { ref, reactive, unref } from 'vue';
  161 + import { Card, DatePicker, Tooltip, Button } from 'ant-design-vue';
135 162 import VisitAnalysis from './VisitAnalysis.vue';
136 163 import VisitAnalysisBar from './VisitAnalysisBar.vue';
137 164 import { RoleEnum, isAdmin } from '/@/enums/roleEnum';
... ... @@ -146,6 +173,7 @@
146 173 import { getTrendData } from '/@/api/dashboard';
147 174 import { useGlobSetting } from '/@/hooks/setting';
148 175 import { QuestionCircleOutlined } from '@ant-design/icons-vue';
  176 + import { RangePickerValue } from 'ant-design-vue/lib/date-picker/interface';
149 177
150 178 defineExpose({
151 179 isAdmin,
... ... @@ -496,6 +524,18 @@
496 524 // onDateTenantChange,
497 525 onDateCustomerChange,
498 526 } = useDate();
  527 +
  528 + const handleCalendarChange = (val: RangePickerValue) => {
  529 + customerDateValue.value = val as any;
  530 + };
  531 +
  532 + const handleDisableDate = (current: moment.Moment) => {
  533 + if (!unref(customerDateValue) || unref(customerDateValue).length === 0) {
  534 + return false;
  535 + }
  536 + const diffDate = current.diff(unref(customerDateValue)[0], 'days');
  537 + return Math.abs(diffDate) > 30;
  538 + };
499 539 </script>
500 540
501 541 <style lang="less">
... ...
... ... @@ -47,7 +47,15 @@
47 47 <DatePicker
48 48 @change="(_, DateString) => onDateChange(_, DateString, role === RoleEnum.CUSTOMER_USER)"
49 49 v-model:value="dateValue"
50   - />
  50 + >
  51 + <Button
  52 + type="link"
  53 + class="!px-0"
  54 + :style="dateValue ? { color: '#0960bd', fontWeight: 500 } : { color: '#000000d9' }"
  55 + >
  56 + {{ dateValue ? (dateValue as moment.Moment).format('YYYY-MM-DD') : '自定义' }}
  57 + </Button>
  58 + </DatePicker>
51 59 </div>
52 60 </template>
53 61 <!-- <div v-if="activeKey === '1'">
... ... @@ -84,13 +92,13 @@
84 92 <Tooltip :overlayStyle="{ maxWidth: '340px' }">
85 93 <template #title>
86 94 <section>
87   - <div>30天: 查询最近30天的数据,间隔时间为1天.</div>
  95 + <div>最近一个月: 查询最近一个月的数据,间隔时间为1天.</div>
88 96 <div>最近三个月: 查询最近三个月的数据,间隔时间为1天.</div>
89   - <div>最近一年: 查询最近一年的数据,间隔时间为30天.</div>
  97 + <div>最近一年: 查询最近一年的数据,间隔时间为1月.</div>
90 98 <div>
91 99 间隔时间:
92 100 <span class="font-bold underline"> 以当天的(最后时间)作为结束时间 </span>
93   - ,往前推移对应天数或小时的时间作为开始时间,然后在此时间区间内进行分组聚合查询.
  101 + ,往前推移对应天数或的时间作为开始时间,然后在此时间区间内进行分组聚合查询.
94 102 </div>
95 103 </section>
96 104 </template>
... ... @@ -106,8 +114,27 @@
106 114 <DatePicker.RangePicker
107 115 @change="onDateTenantChange"
108 116 size="small"
  117 + @calendarChange="handleCalendarChange"
  118 + :disabledDate="handleDisableDate"
109 119 v-model:value="tenantDateValue"
110   - />
  120 + >
  121 + <Button
  122 + type="link"
  123 + class="!px-0"
  124 + :style="
  125 + tenantDateValue && tenantDateValue.length
  126 + ? { color: '#0960bd', fontWeight: 500 }
  127 + : { color: '#000000d9' }
  128 + "
  129 + >{{
  130 + tenantDateValue && tenantDateValue.length
  131 + ? `${(tenantDateValue?.[0] as moment.Moment)?.format('YYYY-MM-DD')}
  132 + ~
  133 + ${(tenantDateValue?.[1] as moment.Moment)?.format('YYYY-MM-DD')}`
  134 + : '自定义'
  135 + }}</Button
  136 + >
  137 + </DatePicker.RangePicker>
111 138 </div>
112 139 </template>
113 140 <TenantTrend :tenantTrendList="tenantTrendList" />
... ... @@ -139,8 +166,8 @@
139 166 </div>
140 167 </template>
141 168 <script lang="ts" setup>
142   - import { ref, reactive } from 'vue';
143   - import { Card, DatePicker, Tooltip } from 'ant-design-vue';
  169 + import { ref, reactive, unref } from 'vue';
  170 + import { Card, DatePicker, Tooltip, Button } from 'ant-design-vue';
144 171 import { QuestionCircleOutlined } from '@ant-design/icons-vue';
145 172 // import VisitAnalysis from './VisitAnalysis.vue';
146 173 import VisitAnalysisBar from './VisitAnalysisBar.vue';
... ... @@ -155,6 +182,7 @@
155 182 import { useDate } from '../hooks/useDate';
156 183 import { getTrendData } from '/@/api/dashboard';
157 184 import { useGlobSetting } from '/@/hooks/setting';
  185 + import { RangePickerValue } from 'ant-design-vue/lib/date-picker/interface';
158 186
159 187 defineExpose({
160 188 isAdmin,
... ... @@ -514,6 +542,18 @@
514 542 onDateTenantChange,
515 543 // onDateCustomerChange,
516 544 } = useDate();
  545 +
  546 + const handleCalendarChange = (val: RangePickerValue) => {
  547 + tenantDateValue.value = val as any;
  548 + };
  549 +
  550 + const handleDisableDate = (current: moment.Moment) => {
  551 + if (!unref(tenantDateValue) || unref(tenantDateValue).length === 0) {
  552 + return false;
  553 + }
  554 + const diffDate = current.diff(unref(tenantDateValue)[0], 'days');
  555 + return Math.abs(diffDate) > 30;
  556 + };
517 557 </script>
518 558
519 559 <style lang="less">
... ...
... ... @@ -31,7 +31,7 @@
31 31 },
32 32 },
33 33 xAxis: {
34   - type: 'time',
  34 + type: 'category',
35 35 splitLine: {
36 36 show: true,
37 37 lineStyle: {
... ... @@ -79,10 +79,10 @@
79 79 const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
80 80 onMounted(async () => {
81 81 const res = await getTrendData({
82   - ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_30_DAY),
  82 + ...getDateByShortcutQueryKey(ShortcutQueryKeyEnum.LATEST_1_MONTH),
83 83 trend: 'TENANT_TREND',
84 84 });
85   - const transferResult = res.map((item) => [item.ts, item.value]);
  85 + const transferResult = res.map((item) => [item.date, item.value]);
86 86 setOptions({
87 87 tooltip: {
88 88 trigger: 'axis',
... ... @@ -94,7 +94,7 @@
94 94 },
95 95 },
96 96 xAxis: {
97   - type: 'time',
  97 + type: 'category',
98 98 splitLine: {
99 99 show: true,
100 100 lineStyle: {
... ...
1 1 import { dateUtil, formatToDateTime } from '/@/utils/dateUtil';
2 2 import { ref } from 'vue';
3 3 import { getTrendData } from '/@/api/dashboard';
  4 +import { RangePickerValue } from 'ant-design-vue/lib/date-picker/interface';
4 5
5 6 export enum ShortcutQueryKeyEnum {
6   - LATEST_30_DAY = 'LATEST_30_DAY',
  7 + LATEST_1_MONTH = 'LATEST_1_MONTH',
7 8 LATEST_3_MONTH = 'LATEST_3_MONTH',
8 9 LATEST_1_YEAR = 'LATEST_1_YEAR',
9 10 }
10 11
11 12 export function getDateByShortcutQueryKey(value: ShortcutQueryKeyEnum) {
12 13 const mapping = {
13   - [ShortcutQueryKeyEnum.LATEST_30_DAY]: () => {
  14 + [ShortcutQueryKeyEnum.LATEST_1_MONTH]: () => {
14 15 return {
15   - startTs: dateUtil().subtract(30, 'day').startOf('day').valueOf(),
  16 + startTs: dateUtil().subtract(1, 'month').startOf('day').valueOf(),
16 17 interval: 24 * 60 * 60 * 1000,
17 18 };
18 19 },
... ... @@ -40,13 +41,13 @@ export function getDateByShortcutQueryKey(value: ShortcutQueryKeyEnum) {
40 41
41 42 export function useDate() {
42 43 const tenantDateValue = ref([]);
43   - const customerDateValue = ref([]);
  44 + const customerDateValue = ref<RangePickerValue>([]);
44 45 const tenantTrendList = ref([]);
45 46 const customerTrendList = ref([]);
46 47 const activeTenantIndex = ref(0);
47 48 const activeCustomerIndex = ref(0);
48 49 const TenantOrCustomerDateList = ref([
49   - { label: '30天', value: ShortcutQueryKeyEnum.LATEST_30_DAY },
  50 + { label: '最近一个月', value: ShortcutQueryKeyEnum.LATEST_1_MONTH },
50 51 { label: '最近三个月', value: ShortcutQueryKeyEnum.LATEST_3_MONTH },
51 52 { label: '最近一年', value: ShortcutQueryKeyEnum.LATEST_1_YEAR },
52 53 ]);
... ... @@ -65,7 +66,7 @@ export function useDate() {
65 66 ...getDateByShortcutQueryKey(value),
66 67 trend: 'TENANT_TREND',
67 68 });
68   - tenantTrendList.value = res.map((item) => [item.ts, item.value]);
  69 + tenantTrendList.value = res.map((item) => [item.date, item.value]);
69 70 } else {
70 71 if (activeCustomerIndex.value === index) return;
71 72 activeCustomerIndex.value = index;
... ... @@ -74,7 +75,7 @@ export function useDate() {
74 75 ...getDateByShortcutQueryKey(value),
75 76 trend: 'CUSTOMER_TREND',
76 77 });
77   - customerTrendList.value = res.map((item) => [item.ts, item.value]);
  78 + customerTrendList.value = res.map((item) => [item.date, item.value]);
78 79 }
79 80 }
80 81
... ...
... ... @@ -103,7 +103,9 @@
103 103 const value = {
104 104 ['触发属性']: findName,
105 105 ['触发条件']: `${findLogin}${curr.value.logicValue}`,
106   - ['触发值']: `${curr.value.realValue}${findAttribute.detail?.dataType?.specs?.unit?.key}`,
  106 + ['触发值']: `${curr.value.realValue}${
  107 + findAttribute.detail?.dataType?.specs?.unit?.key ?? ''
  108 + }`,
107 109 };
108 110 const data = {
109 111 [item.name]: value,
... ...
... ... @@ -60,7 +60,7 @@
60 60 span: 12,
61 61 },
62 62 componentProps: {
63   - maxLength: 255,
  63 + maxLength: 64,
64 64 placeholder: '请输入邮件主题',
65 65 },
66 66 },
... ... @@ -72,7 +72,7 @@
72 72 colProps: {
73 73 span: 12,
74 74 },
75   - rules: [...emailRule, { required: true ,message:'主送人不能为空'}],
  75 + rules: [...emailRule, { required: true, message: '主送人不能为空' }],
76 76 componentProps: {
77 77 maxLength: 255,
78 78 placeholder: '请输入主送',
... ...
... ... @@ -43,7 +43,7 @@
43 43 <div
44 44 v-show="!item.notFoundData"
45 45 :id="`chart-${item.device}`"
46   - style="width: 100%; height: 400px"
  46 + class="w-full h-96"
47 47 ></div>
48 48 </div>
49 49 </div>
... ... @@ -273,6 +273,9 @@
273 273 series,
274 274 xAxis: { data: xAxisData },
275 275 } as echarts.EChartsOption);
  276 +
  277 + await nextTick();
  278 + resize();
276 279 } catch (error) {
277 280 } finally {
278 281 loading.value = false;
... ...
... ... @@ -67,7 +67,7 @@
67 67 if (credentials) {
68 68 for (let i in credentials) Reflect.set(credentialsFile, i, credentials[i]);
69 69 }
70   - setFieldsValue(value);
  70 + setFieldsValue({ ...value, type: credentials.type });
71 71 };
72 72
73 73 const resetValue = () => resetFields();
... ...
... ... @@ -576,7 +576,17 @@ export const actionSchema: FormSchema[] = [
576 576 const { setFieldsValue } = formActionType;
577 577 return {
578 578 placeholder: '请选择类型',
579   - api: findDictItemByCode,
  579 + api: async (parmas: Recordable) => {
  580 + try {
  581 + const record = await findDictItemByCode(parmas);
  582 + return record.filter(
  583 + (item) =>
  584 + item.itemValue !== CommandTypeEnum.ATTRIBUTE.toString() || item.itemText != '属性'
  585 + );
  586 + } catch (error) {
  587 + return [];
  588 + }
  589 + },
580 590 labelField: 'itemText',
581 591 valueField: 'itemValue',
582 592 params: {
... ...
... ... @@ -267,8 +267,10 @@
267 267 const validate = getFieldsValue();
268 268 //ft-add-2022-11-22
269 269 const type = validate?.outTarget;
270   - if (type === 'DEVICE_OUT' && validate.device == 'PART') {
271   - if (validate.deviceId == undefined) return createMessage.error('请选择设备');
  270 + if (type === 'DEVICE_OUT') {
  271 + if (!validate.deviceProfileId) return createMessage.error('请选择产品');
  272 + if (validate.device == 'PART' && validate.deviceId == undefined)
  273 + return createMessage.error('请选择设备');
272 274 }
273 275 //ft-add-2022-11-22
274 276 //TODO-fengtao-设备验证
... ...
... ... @@ -191,7 +191,8 @@
191 191 const updateFn: DataFetchUpdateFn = (message, attribute) => {
192 192 const { data = {} } = message;
193 193 const [latest] = data[attribute] || [];
194   - const [_, value] = latest;
  194 + const [name, value] = latest;
  195 + if (!name && !value) return;
195 196 noSendValue.value = getNumberValue(value);
196 197 sliderValue.value = getNumberValue(value);
197 198 };
... ...