From c68bc13dcd8e682f37828802b49035a4776bbbe4 Mon Sep 17 00:00:00 2001 From: orangegzx Date: Thu, 31 Aug 2023 18:40:13 +0800 Subject: [PATCH] feat(tag, monitoring): support BYTES type and wirte BYTES value --- src/composables/config/useAddTagCommon.ts | 17 ++----- src/composables/config/useTagForm.ts | 10 +++- src/composables/data/useDataMonitoring.ts | 2 +- .../data/useWriteDataCheckNParse.ts | 51 ++++++++++++++++--- src/composables/data/useWriteDataDialog.ts | 12 +++-- src/i18n/config.ts | 8 +++ src/i18n/data.ts | 4 ++ src/types/enums.ts | 2 +- src/utils/regexps.ts | 1 + src/utils/utils.ts | 2 +- .../southDriver/components/EditTagDialog.vue | 2 - .../config/southDriver/components/TagForm.vue | 24 +++++++++ .../southDriver/components/TagListForm.vue | 15 ++++++ .../monitoring/components/WriteDialog.vue | 9 +++- 14 files changed, 126 insertions(+), 33 deletions(-) diff --git a/src/composables/config/useAddTagCommon.ts b/src/composables/config/useAddTagCommon.ts index 0ca96a91..4307d4b4 100644 --- a/src/composables/config/useAddTagCommon.ts +++ b/src/composables/config/useAddTagCommon.ts @@ -4,7 +4,7 @@ import { useRoute } from 'vue-router' import { EmqxMessage } from '@emqx/emqx-ui' import type { TagFormItem, TagForm, TagData } from '@/types/config' import { TagType, TagAttributeType } from '@/types/enums' -import { getErrorMsg, popUpErrorMessage, dataType, createRandomString } from '@/utils/utils' +import { dataType, createRandomString } from '@/utils/utils' import useWriteDataCheckNParse from '@/composables/data/useWriteDataCheckNParse' export const useTagTypeSelect = () => { @@ -151,7 +151,7 @@ export const createTagForm = () => { type: null, // for the key when use v-for id: createRandomString(6), - decimal: null, + decimal: undefined, description: '', precision: undefined, value: undefined, @@ -181,10 +181,12 @@ export const useHandleTagValue = () => { handleTagValue, } } + export default () => { const route = useRoute() const { t } = useI18n() + const { handleTagValue } = useHandleTagValue() const groupName = computed(() => route.params.group as string) const sliceTagList = (list: TagFormItem[], errIndex: number) => { @@ -218,18 +220,9 @@ export default () => { } } - const { parseWriteData } = useWriteDataCheckNParse() const parseTagData = async (tagList: TagFormItem[]): Promise => { const tags: TagForm[] = tagList.map(({ id, ...tagData }) => { - const data = tagData - const { type, value } = data - if (value !== undefined && value !== null) { - /** let it go, when the tags value use hexadecimal, and sync EditTagDialog.vue - * const newValue = isUseHexadecimal.value ? await transToDecimal({ ...tagData, value } as TagDataInTable): value - */ - data.value = parseWriteData(Number(type), String(value)) - } - + const data = handleTagValue(tagData) return data }) return tags diff --git a/src/composables/config/useTagForm.ts b/src/composables/config/useTagForm.ts index 00990eb1..b1f894c1 100644 --- a/src/composables/config/useTagForm.ts +++ b/src/composables/config/useTagForm.ts @@ -71,7 +71,7 @@ export default (props: any) => { } // checkFloat, - const { checkWriteData } = useWriteDataCheckNParse() + const { checkWriteData } = useWriteDataCheckNParse(false) const createErrorMsg = (type: number, prefix: string, suffix: string) => { if (!type) return '' return prefix + TagType[type] + suffix @@ -99,7 +99,6 @@ export default (props: any) => { const { field } = rule const $index = field.split('.')[1] const tag: TagDataInTable = props?.data?.tagList ? props.data.tagList[$index] : props?.data - // const { type, attribute, decimal } = tag const { type, attribute } = tag try { @@ -127,6 +126,13 @@ export default (props: any) => { const errorMsg = errorMsgMap.value(type)[Number('1') as keyof typeof errorMsgMap.value] return callback(new Error(errorMsg)) } + + // validate bytes value length; when `static` support `bytes` support, let comment go + // const bytesValue = JSON.parse(trueValue) + // if (type === TagType.BYTES && bytesValue.length > 128) { + // // checkWriteData(bytes) has valid `value` is `Array` + // return callback(new Error(t('data.arrayLengthError', { length: 128 }))) + // } return callback() } diff --git a/src/composables/data/useDataMonitoring.ts b/src/composables/data/useDataMonitoring.ts index f273d3f5..be8db5fb 100644 --- a/src/composables/data/useDataMonitoring.ts +++ b/src/composables/data/useDataMonitoring.ts @@ -353,7 +353,7 @@ export default () => { } return value } - if (type === TagType.BYTE || type === TagType.BOOL || type === TagType.BIT || type === TagType.STRING) { + if (type === TagType.BYTES || type === TagType.BOOL || type === TagType.BIT || type === TagType.STRING) { return value } const data = await transToHexadecimal(tagData) diff --git a/src/composables/data/useWriteDataCheckNParse.ts b/src/composables/data/useWriteDataCheckNParse.ts index cd289ad5..ffd010e1 100644 --- a/src/composables/data/useWriteDataCheckNParse.ts +++ b/src/composables/data/useWriteDataCheckNParse.ts @@ -21,7 +21,7 @@ STRING 15 string import { TagType } from '@/types/enums' import { HEXADECIMAL_PREFIX } from '@/utils/constants' -import { HEXADECIMAL_REGEX, FLOAT_REGEX, BIT_REGEX, INT_REGEX } from '@/utils/regexps' +import { BYTES_REGEX, FLOAT_REGEX, BIT_REGEX, INT_REGEX } from '@/utils/regexps' import { transFloatNumberToHex, transNegativeNumberToHex, @@ -31,6 +31,7 @@ import { transIntHexToDecimalNum, } from './convert' import type { TagDataInTable } from './useDataMonitoring' +import { isJSONData } from '@/utils/utils' export enum WriteDataErrorCode { FormattingError = 1, @@ -38,6 +39,7 @@ export enum WriteDataErrorCode { GreaterThanMaximum, LessThanMinSafeInteger, GreaterThanMaxSafeInteger, + BYTESValueLengthError, } interface RangeObj { @@ -45,7 +47,7 @@ interface RangeObj { MAX: number } -export default () => { +export default (isWriteValue = true) => { const createIntTypeRange = (bitsNum: number): RangeObj => { return { MIN: -(2 ** (bitsNum - 1)), @@ -64,15 +66,43 @@ export default () => { const INT32_RANGE = createIntTypeRange(32) const INT64_RANGE = createIntTypeRange(64) + const BYTES_RANGE = createUIntTypeRange(8) const UINT8_RANGE = createUIntTypeRange(8) const UINT16_RANGE = createUIntTypeRange(16) const UINT32_RANGE = createUIntTypeRange(32) const UINT64_RANGE = createUIntTypeRange(64) - const checkByte = (value: string): Promise => - HEXADECIMAL_REGEX.test(value.replace(/\s/g, '')) - ? Promise.resolve(true) - : Promise.reject(new Error(WriteDataErrorCode.FormattingError.toString())) + const checkByte = async (value: string): Promise => { + // Static attribute do not currently support BYTES type, when creat a tag + if (!isWriteValue) return Promise.resolve(true) + + try { + await isJSONData(value) + const arrValue = JSON.parse(value) + console.log('arrValue', arrValue) + if (!Array.isArray(arrValue)) { + return Promise.reject(new Error(WriteDataErrorCode.FormattingError.toString())) + } + + const isElementAllInRange = arrValue.every((v: string | number) => { + const isIntNumber = BYTES_REGEX.test(String(v)) + const isInRange = Number(v) >= BYTES_RANGE.MIN && Number(v) <= BYTES_RANGE.MAX + + return isIntNumber && isInRange + }) + if (!isElementAllInRange) { + return Promise.reject(new Error(WriteDataErrorCode.FormattingError.toString())) + } + + if (arrValue.length > 128) { + return Promise.reject(new Error(WriteDataErrorCode.BYTESValueLengthError.toString())) + } + } catch (error) { + return Promise.reject(new Error(WriteDataErrorCode.FormattingError.toString())) + } + + return Promise.resolve(true) + } const checkBit = (value: string): Promise => BIT_REGEX.test(value) @@ -120,7 +150,7 @@ export default () => { const check = (type: TagType, value: string) => { const checkMap = { - [TagType.BYTE]: checkByte.bind(null, value), + [TagType.BYTES]: checkByte.bind(null, value), [TagType.INT8]: checkInt.bind(null, INT8_RANGE, value), [TagType.INT16]: checkInt.bind(null, INT16_RANGE, value), [TagType.INT32]: checkInt.bind(null, INT32_RANGE, value), @@ -142,9 +172,14 @@ export default () => { } const parseWriteData = (type: TagType, value: string) => { - if (type === TagType.BYTE || type === TagType.STRING || type === TagType.BOOL) { + if (type === TagType.STRING || type === TagType.BOOL) { return value } + + if (type === TagType.BYTES) { + return value ? JSON.parse(value) : value + } + return Number(value) } const checkWriteData = async (type: number, value: string): Promise => { diff --git a/src/composables/data/useWriteDataDialog.ts b/src/composables/data/useWriteDataDialog.ts index cf380aeb..3dfc33fb 100644 --- a/src/composables/data/useWriteDataDialog.ts +++ b/src/composables/data/useWriteDataDialog.ts @@ -51,6 +51,7 @@ export default (props: Props) => { ), [WriteDataErrorCode.LessThanMinSafeInteger]: t('data.writeDataSafeMinimumError'), [WriteDataErrorCode.GreaterThanMaxSafeInteger]: t('data.writeDataSafeMaximumError'), + [WriteDataErrorCode.BYTESValueLengthError]: t('data.arrayLengthError', { length: 128 }), })) const inputValue = ref('') @@ -63,7 +64,7 @@ export default (props: Props) => { const showToggleHexadecimalSwitch = computed(() => { return ( props.tag?.type && - props.tag.type !== TagType.BYTE && + props.tag.type !== TagType.BYTES && props.tag.type !== TagType.BOOL && props.tag.type !== TagType.BIT && props.tag.type !== TagType.STRING @@ -103,10 +104,11 @@ export default (props: Props) => { return Promise.resolve() } - const checkValueRes = await Promise.allSettled([ - checkFloat.bind(null, trueValue)(), - checkWriteData(type, trueValue), - ]) + const requests = [checkWriteData(type, trueValue)] + if (type !== TagType.BYTES) { + requests.push(checkFloat.bind(null, trueValue)()) + } + const checkValueRes = await Promise.allSettled(requests) const checkRes = checkValueRes.map((item: any) => item?.value || false) if (!checkRes.includes(true)) { inputErrorMsg.value = errorMsgMap.value[Number('1') as keyof typeof errorMsgMap.value] diff --git a/src/i18n/config.ts b/src/i18n/config.ts index a74a1618..1428639c 100644 --- a/src/i18n/config.ts +++ b/src/i18n/config.ts @@ -594,4 +594,12 @@ export default { zh: '请选择南向驱动数据', en: 'Please select the south drive data', }, + staticNotSupportBytes: { + zh: 'Static 属性暂不支持 BYTES 类型', + en: 'Static attribute do not currently support BYTES type', + }, + arrayFormatError: { + zh: '请输入数组', + en: 'Please enter an array', + }, } diff --git a/src/i18n/data.ts b/src/i18n/data.ts index 70063501..e7871d70 100644 --- a/src/i18n/data.ts +++ b/src/i18n/data.ts @@ -51,6 +51,10 @@ export default { zh: ' 内容格式错误', en: ' content format error', }, + arrayLengthError: { + zh: '请输入长度不大于 {length} 的数据', + en: 'Please enter data no longer than {length}', + }, writeDataMinimumErrorPrefix: { zh: '小于数据类型 ', en: 'Less than the minimum value of data type ', diff --git a/src/types/enums.ts b/src/types/enums.ts index 34ff3018..ebe77a81 100644 --- a/src/types/enums.ts +++ b/src/types/enums.ts @@ -51,7 +51,7 @@ export enum TagType { BIT, BOOL, STRING, - BYTE, + BYTES, WORD = 16, DWORD, LWORD, diff --git a/src/utils/regexps.ts b/src/utils/regexps.ts index 7035d588..fcd86d05 100644 --- a/src/utils/regexps.ts +++ b/src/utils/regexps.ts @@ -4,6 +4,7 @@ export const DECIMAL_POSITIVE_REGEX = /^[0-9]\d*$/ export const FLOAT_REGEX = /^-?\d*\.?\d+(e-?\d+)?$/ export const BIT_REGEX = /^[0-9a-f]+$/ export const INT_REGEX = /^-?\d+$/ +export const BYTES_REGEX = /^[0-9]+$/ export const BINARY_STRING_REGEX = /^(0|1)+$/ export const UPPER_LOWERCASE_REGEX = /^[A-Z][a-z]+$/ diff --git a/src/utils/utils.ts b/src/utils/utils.ts index ec6f3be4..646dbef6 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -212,7 +212,7 @@ export const isTheSameParentRoute = (from: any, to: any) => { export const isJSONData = (data: string) => { try { JSON.parse(data) - return Promise.resolve() + return Promise.resolve(true) } catch (error) { console.error(error) return Promise.reject(error) diff --git a/src/views/config/southDriver/components/EditTagDialog.vue b/src/views/config/southDriver/components/EditTagDialog.vue index 15367a2c..a572d21b 100644 --- a/src/views/config/southDriver/components/EditTagDialog.vue +++ b/src/views/config/southDriver/components/EditTagDialog.vue @@ -27,7 +27,6 @@ import TagFormCom from './TagForm.vue' import type { PluginInfo, TagData } from '@/types/config' import { updateTag } from '@/api/config' import { useI18n } from 'vue-i18n' -import useWriteDataCheckNParse from '@/composables/data/useWriteDataCheckNParse' import { useNodePluginInfo } from '@/composables/config/usePluginInfo' import { useHandleTagValue } from '@/composables/config/useAddTagCommon' @@ -52,7 +51,6 @@ const props = defineProps({ const emit = defineEmits(['update:modelValue', 'submitted']) const { t } = useI18n() -const { parseWriteData } = useWriteDataCheckNParse() const { getNodePluginInfo } = useNodePluginInfo() const pluginMsg: Ref = ref(undefined) diff --git a/src/views/config/southDriver/components/TagForm.vue b/src/views/config/southDriver/components/TagForm.vue index 52abe041..be533c39 100644 --- a/src/views/config/southDriver/components/TagForm.vue +++ b/src/views/config/southDriver/components/TagForm.vue @@ -8,6 +8,12 @@ + @@ -19,6 +25,7 @@ :key="item.value" :value="item.value" :label="item.label" + :disabled="item.value === TagType.BYTES && isAttrsIncludeStatic(form.attribute)" /> @@ -81,6 +88,8 @@ import { useTagPrecision } from '@/composables/config/useAddTagCommon' import TagAttributeSelect from './TagAttributeSelect.vue' import type { PluginInfo, TagForm } from '@/types/config' import useTagForm from '@/composables/config/useTagForm' +import { TagType } from '@/types/enums' +import AComWithDesc from '@/components/AComWithDesc.vue' const props = defineProps({ data: { @@ -109,6 +118,8 @@ const form: WritableComputedRef = computed({ }, }) +const isBYTESType = computed(() => form.value.type === TagType.BYTES) + const changeAttribute = () => { const isStaticAttr = isAttrsIncludeStatic.value(form.value.attribute) @@ -117,6 +128,9 @@ const changeAttribute = () => { } else { form.value.precision = undefined form.value.decimal = null + if (isBYTESType.value) { + form.value.type = null + } } // validate 'address' nextTick(() => { @@ -145,3 +159,13 @@ defineExpose({ resetFields, }) + + diff --git a/src/views/config/southDriver/components/TagListForm.vue b/src/views/config/southDriver/components/TagListForm.vue index 3ccd0812..6a3d70a3 100644 --- a/src/views/config/southDriver/components/TagListForm.vue +++ b/src/views/config/southDriver/components/TagListForm.vue @@ -15,6 +15,9 @@ - + True False @@ -66,6 +72,7 @@ const showDialog = computed({ emit('update:modelValue', val) }, }) +const isBYTESType = computed(() => props.tag?.type === TagType.BYTES) const dialogTitle = computed(() => props.tag?.tagName) const {