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 | 10 | import { toRaw, unref } from 'vue'; |
11 | 11 | import ObjectModelValidateForm from '/@/components/Form/src/externalCompns/components/ObjectModelValidateForm/ObjectModelValidateForm.vue'; |
12 | 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 | 16 | useComponentRegister('JSONEditor', JSONEditor); |
14 | 17 | useComponentRegister('ObjectModelValidateForm', ObjectModelValidateForm); |
15 | 18 | |
... | ... | @@ -17,6 +20,7 @@ export enum TypeEnum { |
17 | 20 | IS_GATEWAY = 'GATEWAY', |
18 | 21 | SENSOR = 'SENSOR', |
19 | 22 | } |
23 | + | |
20 | 24 | export const isGateWay = (type: string) => { |
21 | 25 | return type === TypeEnum.IS_GATEWAY; |
22 | 26 | }; |
... | ... | @@ -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 | 171 | field: 'code', |
116 | - label: '设备标识/地址码', | |
172 | + label: '设备标识', | |
117 | 173 | dynamicRules({ values }) { |
118 | 174 | return [ |
119 | 175 | { |
... | ... | @@ -125,15 +181,17 @@ export const step1Schemas: FormSchema[] = [ |
125 | 181 | ]; |
126 | 182 | }, |
127 | 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 | 196 | field: 'brand', |
139 | 197 | component: 'ApiRadioGroup', | ... | ... |
... | ... | @@ -127,6 +127,7 @@ |
127 | 127 | import { copyTransFun } from '/@/utils/fnUtils'; |
128 | 128 | import { useDrawer } from '/@/components/Drawer'; |
129 | 129 | import DeptDrawer from '/@/views/system/organization/OrganizationDrawer.vue'; |
130 | + import { TaskTypeEnum } from '/@/views/task/center/config'; | |
130 | 131 | |
131 | 132 | export default defineComponent({ |
132 | 133 | components: { |
... | ... | @@ -385,11 +386,21 @@ |
385 | 386 | positionState.latitude = deviceInfo.latitude; |
386 | 387 | positionState.address = deviceInfo.address; |
387 | 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 | 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 | 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 | 188 | disabled: transportType ? transportType && transportType !== PushWayEnum.TCP : true, |
189 | 189 | }, |
190 | 190 | ], |
... | ... | @@ -240,7 +240,7 @@ export const formSchemas: FormSchema[] = [ |
240 | 240 | label: 'ModbusRTU轮询', |
241 | 241 | rules: [{ required: true, message: '请输入Modbus RTU 轮询指令' }], |
242 | 242 | ifShow: ({ model }) => |
243 | - model[FormFieldsEnum.EXECUTE_CONTENT_TYPE] === TaskTypeEnum.MODBUS_RTU && | |
243 | + model[FormFieldsEnum.EXECUTE_CONTENT_TYPE] === TaskTypeEnum.MODBUS && | |
244 | 244 | model[FormFieldsEnum.PUSH_WAY] === PushWayEnum.TCP, |
245 | 245 | valueField: 'value', |
246 | 246 | changeEvent: 'update:value', | ... | ... |
1 | 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 | 6 | enum AddressTypeEnum { |
8 | 7 | DEC = 'DEC', |
9 | 8 | HEX = 'HEX', |
10 | 9 | } |
11 | - | |
12 | 10 | const emit = defineEmits(['update:value']); |
13 | 11 | |
14 | - const DEC_MAX_VALUE = parseInt('0xffff', 16); | |
15 | - | |
16 | 12 | const props = withDefaults( |
17 | 13 | defineProps<{ |
18 | 14 | value?: number | string; |
19 | - inputProps?: Recordable; | |
20 | 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 | 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 | 79 | const addressTypeOptions = [ |
29 | 80 | { label: AddressTypeEnum.DEC, value: AddressTypeEnum.DEC }, |
30 | 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 | 139 | </script> |
74 | 140 | |
75 | 141 | <template> |
76 | 142 | <InputGroup compact class="!flex"> |
77 | 143 | <Select |
78 | - v-model:value="type" | |
144 | + v-model:value="inputType" | |
79 | 145 | :options="addressTypeOptions" |
80 | - @change="handleChange" | |
81 | 146 | :disabled="disabled" |
82 | 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 | 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 | 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 | 158 | </div> |
98 | 159 | </InputGroup> |
99 | 160 | </template> | ... | ... |
1 | 1 | import { findDictItemByCode } from '/@/api/system/dict'; |
2 | 2 | import { FormSchema, useComponentRegister } from '/@/components/Form'; |
3 | 3 | import { DictEnum } from '/@/enums/dictEnum'; |
4 | -import RegisterAddressInput from './RegisterAddressInput.vue'; | |
5 | 4 | import { createPickerSearch } from '/@/utils/pickerSearch'; |
6 | 5 | import { ControlGroup } from '../ControlGroup'; |
7 | 6 | |
7 | +useComponentRegister('ControlGroup', ControlGroup); | |
8 | + | |
8 | 9 | export enum FormFieldsEnum { |
9 | 10 | // 设备地址码 |
10 | 11 | DEVICE_CODE = 'deviceCode', |
... | ... | @@ -28,9 +29,6 @@ export enum FormFieldsEnum { |
28 | 29 | REGISTER_VALUES = 'registerValues', |
29 | 30 | } |
30 | 31 | |
31 | -useComponentRegister('RegisterAddressInput', RegisterAddressInput); | |
32 | -useComponentRegister('ControlGroup', ControlGroup); | |
33 | - | |
34 | 32 | export enum FunctionCodeEnum { |
35 | 33 | // 读取线圈状态01 |
36 | 34 | READ_COIL_STATE_01 = '01', | ... | ... |
... | ... | @@ -27,11 +27,11 @@ export enum TaskTargetNameEnum { |
27 | 27 | |
28 | 28 | export enum TaskTypeEnum { |
29 | 29 | CUSTOM = 'CUSTOM', |
30 | - MODBUS_RTU = 'MODBUS_RTU', | |
30 | + MODBUS = 'MODBUS', | |
31 | 31 | } |
32 | 32 | |
33 | 33 | export enum TaskTypeNameEnum { |
34 | - MODBUS_RTU = 'MODBUS_RTU轮询', | |
34 | + MODBUS = 'MODBUS_RTU轮询', | |
35 | 35 | CUSTOM = '自定义数据下发', |
36 | 36 | } |
37 | 37 | ... | ... |