Commit 1b2f1b0047ffb71c27ae947b0fb5a953bba8dc0b
Merge branch 'perf/device-create-add-code-type-field' into 'main_dev'
fix: 修复设备创建新增codeType字段 See merge request yunteng/thingskit-front!757
Showing
7 changed files
with
203 additions
and
70 deletions
@@ -10,6 +10,9 @@ import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; | @@ -10,6 +10,9 @@ import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; | ||
10 | import { toRaw, unref } from 'vue'; | 10 | import { toRaw, unref } from 'vue'; |
11 | import ObjectModelValidateForm from '/@/components/Form/src/externalCompns/components/ObjectModelValidateForm/ObjectModelValidateForm.vue'; | 11 | import ObjectModelValidateForm from '/@/components/Form/src/externalCompns/components/ObjectModelValidateForm/ObjectModelValidateForm.vue'; |
12 | import { CommandDeliveryWayEnum, ServiceCallTypeEnum } from '/@/enums/toolEnum'; | 12 | import { CommandDeliveryWayEnum, ServiceCallTypeEnum } from '/@/enums/toolEnum'; |
13 | +import { TaskTypeEnum } from '/@/views/task/center/config'; | ||
14 | +import { AddressTypeEnum } from '/@/views/task/center/components/PollCommandInput'; | ||
15 | + | ||
13 | useComponentRegister('JSONEditor', JSONEditor); | 16 | useComponentRegister('JSONEditor', JSONEditor); |
14 | useComponentRegister('ObjectModelValidateForm', ObjectModelValidateForm); | 17 | useComponentRegister('ObjectModelValidateForm', ObjectModelValidateForm); |
15 | 18 | ||
@@ -17,6 +20,7 @@ export enum TypeEnum { | @@ -17,6 +20,7 @@ export enum TypeEnum { | ||
17 | IS_GATEWAY = 'GATEWAY', | 20 | IS_GATEWAY = 'GATEWAY', |
18 | SENSOR = 'SENSOR', | 21 | SENSOR = 'SENSOR', |
19 | } | 22 | } |
23 | + | ||
20 | export const isGateWay = (type: string) => { | 24 | export const isGateWay = (type: string) => { |
21 | return type === TypeEnum.IS_GATEWAY; | 25 | return type === TypeEnum.IS_GATEWAY; |
22 | }; | 26 | }; |
@@ -112,8 +116,60 @@ export const step1Schemas: FormSchema[] = [ | @@ -112,8 +116,60 @@ export const step1Schemas: FormSchema[] = [ | ||
112 | }, | 116 | }, |
113 | }, | 117 | }, |
114 | { | 118 | { |
119 | + field: 'codeType', | ||
120 | + label: '标识符类型', | ||
121 | + component: 'Select', | ||
122 | + dynamicRules({ values }) { | ||
123 | + return [ | ||
124 | + { | ||
125 | + required: | ||
126 | + (values?.transportType === TransportTypeEnum.TCP && | ||
127 | + values?.deviceType === DeviceTypeEnum.SENSOR) || | ||
128 | + values?.deviceType === DeviceTypeEnum.GATEWAY, | ||
129 | + message: '请输入设备标识符', | ||
130 | + }, | ||
131 | + ]; | ||
132 | + }, | ||
133 | + ifShow: ({ values }) => | ||
134 | + values?.transportType === TransportTypeEnum.TCP && | ||
135 | + (values.deviceType === DeviceTypeEnum.SENSOR || values.deviceType === DeviceTypeEnum.GATEWAY), | ||
136 | + componentProps: ({}) => { | ||
137 | + return { | ||
138 | + options: [ | ||
139 | + { label: '自定义', value: TaskTypeEnum.CUSTOM }, | ||
140 | + { label: 'ModBus', value: TaskTypeEnum.MODBUS }, | ||
141 | + ], | ||
142 | + }; | ||
143 | + }, | ||
144 | + }, | ||
145 | + { | ||
146 | + field: 'addressCode', | ||
147 | + label: '地址码', | ||
148 | + dynamicRules({ values }) { | ||
149 | + return [ | ||
150 | + { | ||
151 | + required: | ||
152 | + values?.transportType === TransportTypeEnum.TCP && | ||
153 | + values?.deviceType === DeviceTypeEnum.SENSOR, | ||
154 | + message: '请输入设备地址码', | ||
155 | + }, | ||
156 | + ]; | ||
157 | + }, | ||
158 | + component: 'RegisterAddressInput', | ||
159 | + changeEvent: 'update:value', | ||
160 | + valueField: 'value', | ||
161 | + componentProps: { | ||
162 | + type: AddressTypeEnum.HEX, | ||
163 | + maxValue: Number(247).toString(16), | ||
164 | + minValue: 0, | ||
165 | + }, | ||
166 | + ifShow: ({ values }) => { | ||
167 | + return values?.codeType === TaskTypeEnum.MODBUS; | ||
168 | + }, | ||
169 | + }, | ||
170 | + { | ||
115 | field: 'code', | 171 | field: 'code', |
116 | - label: '设备标识/地址码', | 172 | + label: '设备标识', |
117 | dynamicRules({ values }) { | 173 | dynamicRules({ values }) { |
118 | return [ | 174 | return [ |
119 | { | 175 | { |
@@ -125,15 +181,17 @@ export const step1Schemas: FormSchema[] = [ | @@ -125,15 +181,17 @@ export const step1Schemas: FormSchema[] = [ | ||
125 | ]; | 181 | ]; |
126 | }, | 182 | }, |
127 | component: 'Input', | 183 | component: 'Input', |
128 | - componentProps: { | ||
129 | - maxLength: 255, | ||
130 | - placeholder: '请输入设备标识或设备地址码', | 184 | + componentProps: () => { |
185 | + return { | ||
186 | + maxLength: 255, | ||
187 | + placeholder: '请输入设备标识或设备地址码', | ||
188 | + }; | ||
189 | + }, | ||
190 | + ifShow: ({ values }) => { | ||
191 | + return values?.codeType === TaskTypeEnum.CUSTOM; | ||
131 | }, | 192 | }, |
132 | - helpMessage: ['标准Modbus地址码值为16进制1-247值', '其他协议自定义'], | ||
133 | - ifShow: ({ values }) => | ||
134 | - values?.transportType === TransportTypeEnum.TCP && | ||
135 | - (values.deviceType === DeviceTypeEnum.SENSOR || values.deviceType === DeviceTypeEnum.GATEWAY), | ||
136 | }, | 193 | }, |
194 | + | ||
137 | { | 195 | { |
138 | field: 'brand', | 196 | field: 'brand', |
139 | component: 'ApiRadioGroup', | 197 | component: 'ApiRadioGroup', |
@@ -127,6 +127,7 @@ | @@ -127,6 +127,7 @@ | ||
127 | import { copyTransFun } from '/@/utils/fnUtils'; | 127 | import { copyTransFun } from '/@/utils/fnUtils'; |
128 | import { useDrawer } from '/@/components/Drawer'; | 128 | import { useDrawer } from '/@/components/Drawer'; |
129 | import DeptDrawer from '/@/views/system/organization/OrganizationDrawer.vue'; | 129 | import DeptDrawer from '/@/views/system/organization/OrganizationDrawer.vue'; |
130 | + import { TaskTypeEnum } from '/@/views/task/center/config'; | ||
130 | 131 | ||
131 | export default defineComponent({ | 132 | export default defineComponent({ |
132 | components: { | 133 | components: { |
@@ -385,11 +386,21 @@ | @@ -385,11 +386,21 @@ | ||
385 | positionState.latitude = deviceInfo.latitude; | 386 | positionState.latitude = deviceInfo.latitude; |
386 | positionState.address = deviceInfo.address; | 387 | positionState.address = deviceInfo.address; |
387 | devicePic.value = deviceInfo.avatar; | 388 | devicePic.value = deviceInfo.avatar; |
388 | - setFieldsValue(data); | 389 | + setFieldsValue({ |
390 | + ...data, | ||
391 | + code: data?.code, | ||
392 | + deviceCode: data?.code, | ||
393 | + }); | ||
389 | } | 394 | } |
390 | // 父组件调用获取字段值的方法 | 395 | // 父组件调用获取字段值的方法 |
391 | function parentGetFieldsValue() { | 396 | function parentGetFieldsValue() { |
392 | - return getFieldsValue(); | 397 | + const value = getFieldsValue(); |
398 | + return { | ||
399 | + ...value, | ||
400 | + ...(value?.code || value?.deviceCode | ||
401 | + ? { code: value?.codeType === TaskTypeEnum.CUSTOM ? value?.code : value?.deviceCode } | ||
402 | + : {}), | ||
403 | + }; | ||
393 | } | 404 | } |
394 | 405 | ||
395 | // 父组件调用表单验证 | 406 | // 父组件调用表单验证 |
@@ -183,8 +183,8 @@ export const formSchemas: FormSchema[] = [ | @@ -183,8 +183,8 @@ export const formSchemas: FormSchema[] = [ | ||
183 | value: TaskTypeEnum.CUSTOM, | 183 | value: TaskTypeEnum.CUSTOM, |
184 | }, | 184 | }, |
185 | { | 185 | { |
186 | - label: TaskTypeNameEnum.MODBUS_RTU, | ||
187 | - value: TaskTypeEnum.MODBUS_RTU, | 186 | + label: TaskTypeNameEnum.MODBUS, |
187 | + value: TaskTypeEnum.MODBUS, | ||
188 | disabled: transportType ? transportType && transportType !== PushWayEnum.TCP : true, | 188 | disabled: transportType ? transportType && transportType !== PushWayEnum.TCP : true, |
189 | }, | 189 | }, |
190 | ], | 190 | ], |
@@ -240,7 +240,7 @@ export const formSchemas: FormSchema[] = [ | @@ -240,7 +240,7 @@ export const formSchemas: FormSchema[] = [ | ||
240 | label: 'ModbusRTU轮询', | 240 | label: 'ModbusRTU轮询', |
241 | rules: [{ required: true, message: '请输入Modbus RTU 轮询指令' }], | 241 | rules: [{ required: true, message: '请输入Modbus RTU 轮询指令' }], |
242 | ifShow: ({ model }) => | 242 | ifShow: ({ model }) => |
243 | - model[FormFieldsEnum.EXECUTE_CONTENT_TYPE] === TaskTypeEnum.MODBUS_RTU && | 243 | + model[FormFieldsEnum.EXECUTE_CONTENT_TYPE] === TaskTypeEnum.MODBUS && |
244 | model[FormFieldsEnum.PUSH_WAY] === PushWayEnum.TCP, | 244 | model[FormFieldsEnum.PUSH_WAY] === PushWayEnum.TCP, |
245 | valueField: 'value', | 245 | valueField: 'value', |
246 | changeEvent: 'update:value', | 246 | changeEvent: 'update:value', |
1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
2 | - import { InputGroup, InputNumber, Select, Input } from 'ant-design-vue'; | ||
3 | - import { unref, watch } from 'vue'; | ||
4 | - import { computed } from 'vue'; | ||
5 | - import { ref } from 'vue'; | 2 | + import { Select, InputGroup, Input } from 'ant-design-vue'; |
3 | + import { ref, unref, computed } from 'vue'; | ||
4 | + import { isNullOrUnDef } from '/@/utils/is'; | ||
6 | 5 | ||
7 | enum AddressTypeEnum { | 6 | enum AddressTypeEnum { |
8 | DEC = 'DEC', | 7 | DEC = 'DEC', |
9 | HEX = 'HEX', | 8 | HEX = 'HEX', |
10 | } | 9 | } |
11 | - | ||
12 | const emit = defineEmits(['update:value']); | 10 | const emit = defineEmits(['update:value']); |
13 | 11 | ||
14 | - const DEC_MAX_VALUE = parseInt('0xffff', 16); | ||
15 | - | ||
16 | const props = withDefaults( | 12 | const props = withDefaults( |
17 | defineProps<{ | 13 | defineProps<{ |
18 | value?: number | string; | 14 | value?: number | string; |
19 | - inputProps?: Recordable; | ||
20 | disabled?: boolean; | 15 | disabled?: boolean; |
16 | + maxValue?: number | string; | ||
17 | + minValue?: number | string; | ||
18 | + type?: AddressTypeEnum; | ||
19 | + toUpperCase?: boolean; | ||
21 | }>(), | 20 | }>(), |
22 | { | 21 | { |
23 | - value: 0, | ||
24 | inputProps: () => ({}), | 22 | inputProps: () => ({}), |
23 | + type: AddressTypeEnum.DEC, | ||
24 | + maxValue: parseInt('FFFF', 16), | ||
25 | + minValue: 0, | ||
26 | + toUpperCase: true, | ||
25 | } | 27 | } |
26 | ); | 28 | ); |
27 | 29 | ||
30 | + const maxHexPadLength = computed(() => { | ||
31 | + const { maxValue, type } = props; | ||
32 | + if (type === AddressTypeEnum.DEC) { | ||
33 | + return Number(maxValue).toString(16).length; | ||
34 | + } else { | ||
35 | + return maxValue.toString().length; | ||
36 | + } | ||
37 | + }); | ||
38 | + | ||
39 | + const inputType = ref(props.type); | ||
40 | + | ||
41 | + const getInputValue = computed(() => { | ||
42 | + const { type, value, toUpperCase } = props; | ||
43 | + | ||
44 | + if (isNullOrUnDef(value)) return value; | ||
45 | + | ||
46 | + if (type === AddressTypeEnum.DEC) { | ||
47 | + if (unref(inputType) === AddressTypeEnum.DEC) { | ||
48 | + return Number(value); | ||
49 | + } else { | ||
50 | + const _value = Number(value).toString(16); | ||
51 | + return toUpperCase ? _value.toUpperCase() : _value; | ||
52 | + } | ||
53 | + } else { | ||
54 | + if (unref(inputType) === AddressTypeEnum.DEC) { | ||
55 | + return parseInt(value, 16); | ||
56 | + } else { | ||
57 | + return toUpperCase ? value.toString().toUpperCase() : value; | ||
58 | + } | ||
59 | + } | ||
60 | + }); | ||
61 | + | ||
62 | + const getValueOpposite = computed(() => { | ||
63 | + if (isNullOrUnDef(unref(getInputValue))) { | ||
64 | + if (unref(inputType) === AddressTypeEnum.DEC) { | ||
65 | + return `0x${decToHex(props.minValue).padStart(unref(maxHexPadLength), '0').toUpperCase()}`; | ||
66 | + } else { | ||
67 | + return hexToDec(props.minValue); | ||
68 | + } | ||
69 | + } | ||
70 | + | ||
71 | + if (unref(inputType) === AddressTypeEnum.DEC) | ||
72 | + return `0x${decToHex(unref(getInputValue)!) | ||
73 | + .toString() | ||
74 | + .padStart(unref(maxHexPadLength), '0') | ||
75 | + .toUpperCase()}`; | ||
76 | + else return hexToDec(unref(getInputValue)!); | ||
77 | + }); | ||
78 | + | ||
28 | const addressTypeOptions = [ | 79 | const addressTypeOptions = [ |
29 | { label: AddressTypeEnum.DEC, value: AddressTypeEnum.DEC }, | 80 | { label: AddressTypeEnum.DEC, value: AddressTypeEnum.DEC }, |
30 | { label: AddressTypeEnum.HEX, value: AddressTypeEnum.HEX }, | 81 | { label: AddressTypeEnum.HEX, value: AddressTypeEnum.HEX }, |
31 | ]; | 82 | ]; |
32 | 83 | ||
33 | - const type = ref(AddressTypeEnum.DEC); | 84 | + const getValueByInputType = (value: string | number) => { |
85 | + let { type, toUpperCase, maxValue, minValue } = props; | ||
34 | 86 | ||
35 | - const inputValue = ref<number | string>(props.value); | 87 | + if (type === AddressTypeEnum.DEC) { |
88 | + if (unref(inputType) === AddressTypeEnum.HEX) { | ||
89 | + value = hexToDec(value); | ||
90 | + } | ||
91 | + value = Number(value); | ||
92 | + maxValue = Number(maxValue); | ||
93 | + minValue = Number(minValue); | ||
94 | + value = value > maxValue ? maxValue : value; | ||
95 | + value = value < minValue ? minValue : value; | ||
96 | + } else { | ||
97 | + if (unref(inputType) === AddressTypeEnum.DEC) { | ||
98 | + value = decToHex(value); | ||
99 | + } | ||
36 | 100 | ||
37 | - const getHexValue = computed(() => { | ||
38 | - return parseInt(unref(inputValue) || 0, 16); | ||
39 | - }); | 101 | + const _maxValue = parseInt(maxValue, 16); |
102 | + const _minValue = parseInt(minValue, 16); | ||
40 | 103 | ||
41 | - const getDecValue = computed(() => { | ||
42 | - let formatValue = Number(unref(inputValue) || 0).toString(16); | ||
43 | - formatValue = `0x${formatValue.padStart(4, '0')}`; | ||
44 | - return (inputValue.value as number) > DEC_MAX_VALUE ? '0x0000' : formatValue; | ||
45 | - }); | 104 | + value = parseInt(value, 16) > _maxValue ? maxValue : value; |
105 | + value = parseInt(value, 16) < _minValue ? minValue : value; | ||
46 | 106 | ||
47 | - const toDEC = (value: number | string) => { | ||
48 | - return unref(type) === AddressTypeEnum.DEC | ||
49 | - ? isNaN(value as number) | ||
50 | - ? 0 | ||
51 | - : Number(value) | ||
52 | - : parseInt(value, 16); | ||
53 | - }; | 107 | + value = toUpperCase ? value.toString().toUpperCase() : value; |
108 | + } | ||
54 | 109 | ||
55 | - const handleEmit = () => { | ||
56 | - const syncValue = toDEC(unref(inputValue)); | ||
57 | - emit('update:value', syncValue); | 110 | + return value; |
58 | }; | 111 | }; |
59 | 112 | ||
60 | - const handleChange = (value: AddressTypeEnum) => { | ||
61 | - const syncValue = value === AddressTypeEnum.DEC ? unref(getHexValue) : unref(getDecValue); | ||
62 | - inputValue.value = syncValue; | ||
63 | - emit('update:value', toDEC(syncValue)); | 113 | + const validate = (value: string | number) => { |
114 | + if (unref(inputType) === AddressTypeEnum.DEC) { | ||
115 | + return /^[1-9]\d*$/.test(value.toString()); | ||
116 | + } else { | ||
117 | + return /(0x)?[0-9a-fA-F]+/.test(value.toString()); | ||
118 | + } | ||
64 | }; | 119 | }; |
65 | 120 | ||
66 | - const stop = watch( | ||
67 | - () => props.value, | ||
68 | - (value) => { | ||
69 | - inputValue.value = value; | ||
70 | - stop(); | 121 | + const handleSyncValue = (event: ChangeEvent) => { |
122 | + const value = (event.target as HTMLInputElement).value; | ||
123 | + if (isNullOrUnDef(value) || value === '') { | ||
124 | + emit('update:value', null); | ||
125 | + return; | ||
71 | } | 126 | } |
72 | - ); | 127 | + if (!validate(value)) return; |
128 | + const syncValue = getValueByInputType(value); | ||
129 | + emit('update:value', syncValue); | ||
130 | + }; | ||
131 | + | ||
132 | + function decToHex(value: number | string) { | ||
133 | + return Number(value).toString(16); | ||
134 | + } | ||
135 | + | ||
136 | + function hexToDec(value: number | string) { | ||
137 | + return parseInt(value, 16); | ||
138 | + } | ||
73 | </script> | 139 | </script> |
74 | 140 | ||
75 | <template> | 141 | <template> |
76 | <InputGroup compact class="!flex"> | 142 | <InputGroup compact class="!flex"> |
77 | <Select | 143 | <Select |
78 | - v-model:value="type" | 144 | + v-model:value="inputType" |
79 | :options="addressTypeOptions" | 145 | :options="addressTypeOptions" |
80 | - @change="handleChange" | ||
81 | :disabled="disabled" | 146 | :disabled="disabled" |
82 | class="bg-gray-200 max-w-20" | 147 | class="bg-gray-200 max-w-20" |
83 | /> | 148 | /> |
84 | - <InputNumber | ||
85 | - v-if="type === AddressTypeEnum.DEC" | ||
86 | - v-model:value="inputValue" | ||
87 | - :step="1" | ||
88 | - class="flex-1" | 149 | + |
150 | + <Input | ||
151 | + :value="getInputValue" | ||
152 | + @change="handleSyncValue" | ||
89 | :disabled="disabled" | 153 | :disabled="disabled" |
90 | - v-bind="inputProps" | ||
91 | - @change="handleEmit" | 154 | + :placeholder="`请输入${inputType === AddressTypeEnum.DEC ? '十进制' : '十六进制'}设备地址码`" |
92 | /> | 155 | /> |
93 | - <Input v-if="type === AddressTypeEnum.HEX" v-model:value="inputValue" @change="handleEmit" /> | ||
94 | <div class="text-center h-8 leading-8 px-2 bg-gray-200 cursor-pointer rounded-1 w-20"> | 156 | <div class="text-center h-8 leading-8 px-2 bg-gray-200 cursor-pointer rounded-1 w-20"> |
95 | - <div v-if="type === AddressTypeEnum.DEC">{{ getDecValue }}</div> | ||
96 | - <div v-if="type === AddressTypeEnum.HEX">{{ getHexValue }}</div> | 157 | + <div>{{ getValueOpposite }}</div> |
97 | </div> | 158 | </div> |
98 | </InputGroup> | 159 | </InputGroup> |
99 | </template> | 160 | </template> |
1 | import { findDictItemByCode } from '/@/api/system/dict'; | 1 | import { findDictItemByCode } from '/@/api/system/dict'; |
2 | import { FormSchema, useComponentRegister } from '/@/components/Form'; | 2 | import { FormSchema, useComponentRegister } from '/@/components/Form'; |
3 | import { DictEnum } from '/@/enums/dictEnum'; | 3 | import { DictEnum } from '/@/enums/dictEnum'; |
4 | -import RegisterAddressInput from './RegisterAddressInput.vue'; | ||
5 | import { createPickerSearch } from '/@/utils/pickerSearch'; | 4 | import { createPickerSearch } from '/@/utils/pickerSearch'; |
6 | import { ControlGroup } from '../ControlGroup'; | 5 | import { ControlGroup } from '../ControlGroup'; |
7 | 6 | ||
7 | +useComponentRegister('ControlGroup', ControlGroup); | ||
8 | + | ||
8 | export enum FormFieldsEnum { | 9 | export enum FormFieldsEnum { |
9 | // 设备地址码 | 10 | // 设备地址码 |
10 | DEVICE_CODE = 'deviceCode', | 11 | DEVICE_CODE = 'deviceCode', |
@@ -28,9 +29,6 @@ export enum FormFieldsEnum { | @@ -28,9 +29,6 @@ export enum FormFieldsEnum { | ||
28 | REGISTER_VALUES = 'registerValues', | 29 | REGISTER_VALUES = 'registerValues', |
29 | } | 30 | } |
30 | 31 | ||
31 | -useComponentRegister('RegisterAddressInput', RegisterAddressInput); | ||
32 | -useComponentRegister('ControlGroup', ControlGroup); | ||
33 | - | ||
34 | export enum FunctionCodeEnum { | 32 | export enum FunctionCodeEnum { |
35 | // 读取线圈状态01 | 33 | // 读取线圈状态01 |
36 | READ_COIL_STATE_01 = '01', | 34 | READ_COIL_STATE_01 = '01', |
@@ -27,11 +27,11 @@ export enum TaskTargetNameEnum { | @@ -27,11 +27,11 @@ export enum TaskTargetNameEnum { | ||
27 | 27 | ||
28 | export enum TaskTypeEnum { | 28 | export enum TaskTypeEnum { |
29 | CUSTOM = 'CUSTOM', | 29 | CUSTOM = 'CUSTOM', |
30 | - MODBUS_RTU = 'MODBUS_RTU', | 30 | + MODBUS = 'MODBUS', |
31 | } | 31 | } |
32 | 32 | ||
33 | export enum TaskTypeNameEnum { | 33 | export enum TaskTypeNameEnum { |
34 | - MODBUS_RTU = 'MODBUS_RTU轮询', | 34 | + MODBUS = 'MODBUS_RTU轮询', |
35 | CUSTOM = '自定义数据下发', | 35 | CUSTOM = '自定义数据下发', |
36 | } | 36 | } |
37 | 37 |