Commit f65c43197421df9a1880d8925905d215515b2bf1

Authored by fengtao
1 parent b5a37c58

fix:修改设备配置相关

@@ -60,7 +60,7 @@ @@ -60,7 +60,7 @@
60 }); 60 });
61 const emit = defineEmits(['expand']); 61 const emit = defineEmits(['expand']);
62 62
63 - const show = ref(true); 63 + const show = ref(false);
64 64
65 const { prefixCls } = useDesign('collapse-container'); 65 const { prefixCls } = useDesign('collapse-container');
66 66
@@ -214,45 +214,49 @@ @@ -214,45 +214,49 @@
214 if (isUpdate.value == 1) { 214 if (isUpdate.value == 1) {
215 delete postDeviceConfogData.id; 215 delete postDeviceConfogData.id;
216 } 216 }
217 - //1 TODO 待解决OID对象唯一标识不能重复问题验证  
218 - let isMappings = false;  
219 - // let isQuerying = false; 217 + let isMappingsKey = ref(false);
  218 + let isMappingValue = ref(false);
  219 + let isQueryings = ref(false);
  220 + let isOIDRepet = ref(false);
220 postDeviceConfogData?.profileData?.transportConfiguration?.communicationConfigs?.forEach( 221 postDeviceConfogData?.profileData?.transportConfiguration?.communicationConfigs?.forEach(
221 - (f) => {  
222 - // if (f.spec == 'TELEMETRY_QUERYING' && f.queryingFrequencyMs == null) {  
223 - // isQuerying = true;  
224 - // } else {  
225 - // isQuerying = false;  
226 - // }  
227 - // if (f.spec == 'CLIENT_ATTRIBUTES_QUERYING' && f.queryingFrequencyMs == null) {  
228 - // isQuerying = true;  
229 - // } else {  
230 - // isQuerying = false;  
231 - // } 222 + (f: any) => {
  223 + if (f.spec == 'TELEMETRY_QUERYING' || f.spec == 'CLIENT_ATTRIBUTES_QUERYING') {
  224 + if (f.queryingFrequencyMs == null) {
  225 + isQueryings.value = true;
  226 + return createMessage.error('请填写查询频率');
  227 + } else {
  228 + isQueryings.value = false;
  229 + }
  230 + }
232 if (f.mappings.length == 0) { 231 if (f.mappings.length == 0) {
233 - isMappings = true; 232 + isMappingsKey.value = true;
  233 + isMappingValue.value = true;
234 } else { 234 } else {
235 f.mappings.forEach((f1) => { 235 f.mappings.forEach((f1) => {
236 const findNoneKey = Object.keys(f1).includes(''); 236 const findNoneKey = Object.keys(f1).includes('');
237 if (findNoneKey) { 237 if (findNoneKey) {
238 - isMappings = findNoneKey;  
239 - } else {  
240 - isMappings = false; 238 + isMappingsKey.value = true;
241 } 239 }
242 }); 240 });
243 f.mappings.forEach((f2) => { 241 f.mappings.forEach((f2) => {
244 const findNoneVal = Object.values(f2).includes(''); 242 const findNoneVal = Object.values(f2).includes('');
245 if (findNoneVal) { 243 if (findNoneVal) {
246 - isMappings = findNoneVal;  
247 - } else {  
248 - isMappings = false; 244 + isMappingValue.value = true;
  245 + }
  246 + });
  247 + //新增OID不能重复=====同一层级的OID不能重复
  248 + f.mappings.forEach((item, _) => {
  249 + if (f.mappings.some((citem) => citem !== item && citem.oid === item.oid)) {
  250 + isOIDRepet.value = true;
249 } 251 }
250 }); 252 });
251 } 253 }
252 } 254 }
253 ); 255 );
254 - // if (isQuerying) return createMessage.error('请填写Querying frequency,ms');  
255 - if (isMappings) return createMessage.error('请填写Date key和OID'); 256 + if (isQueryings.value) return createMessage.error('请填写查询频率');
  257 + if (isMappingsKey.value) return createMessage.error('请填写Date key和OID');
  258 + if (isMappingValue.value) return createMessage.error('请填写Date key和OID');
  259 + if (isOIDRepet.value) return createMessage.error('OID不能重复');
256 deviceConfigAddOrEdit(isEdit.value ? noEditObj : postDeviceConfogData) 260 deviceConfigAddOrEdit(isEdit.value ? noEditObj : postDeviceConfogData)
257 .then((res) => { 261 .then((res) => {
258 if (!res) return; 262 if (!res) return;
@@ -32,7 +32,7 @@ export const CoapSchemas: FormSchema[] = [ @@ -32,7 +32,7 @@ export const CoapSchemas: FormSchema[] = [
32 { 32 {
33 field: 'coapDeviceType', 33 field: 'coapDeviceType',
34 component: 'Select', 34 component: 'Select',
35 - label: 'CoAP 设备类型', 35 + label: 'CoAP设备类型',
36 defaultValue: 'DEFAULT', 36 defaultValue: 'DEFAULT',
37 componentProps: { 37 componentProps: {
38 options: [ 38 options: [
@@ -45,7 +45,7 @@ export const CoapSchemas: FormSchema[] = [ @@ -45,7 +45,7 @@ export const CoapSchemas: FormSchema[] = [
45 { 45 {
46 field: 'transportPayloadType', 46 field: 'transportPayloadType',
47 component: 'Select', 47 component: 'Select',
48 - label: 'CoAP 设备消息 Payload', 48 + label: 'CoAP设备消息Payload',
49 defaultValue: 'JSON', 49 defaultValue: 'JSON',
50 componentProps: { 50 componentProps: {
51 options: [ 51 options: [
@@ -59,7 +59,7 @@ export const CoapSchemas: FormSchema[] = [ @@ -59,7 +59,7 @@ export const CoapSchemas: FormSchema[] = [
59 { 59 {
60 field: 'powerMode', 60 field: 'powerMode',
61 component: 'Select', 61 component: 'Select',
62 - label: 'Power Saving Mode', 62 + label: '节能模式',
63 defaultValue: 'DRX', 63 defaultValue: 'DRX',
64 componentProps: { 64 componentProps: {
65 options: [ 65 options: [
@@ -76,11 +76,11 @@ export const CoapSchemas: FormSchema[] = [ @@ -76,11 +76,11 @@ export const CoapSchemas: FormSchema[] = [
76 { 76 {
77 field: 'psmActivityTimer', 77 field: 'psmActivityTimer',
78 component: 'InputNumber', 78 component: 'InputNumber',
79 - label: 'PSM Activity Timer', 79 + label: 'PSM活动计时器',
80 required: true, 80 required: true,
81 - defaultValue: '10', 81 + defaultValue: 10,
82 componentProps: { 82 componentProps: {
83 - placeholder: '请输入PSM Activity Timer', 83 + placeholder: '请输入PSM活动计时器',
84 }, 84 },
85 colProps: { span: 11 }, 85 colProps: { span: 11 },
86 ifShow: ({ values }) => isPsm(values.powerMode), 86 ifShow: ({ values }) => isPsm(values.powerMode),
@@ -104,11 +104,11 @@ export const CoapSchemas: FormSchema[] = [ @@ -104,11 +104,11 @@ export const CoapSchemas: FormSchema[] = [
104 { 104 {
105 field: 'edrxCycle', 105 field: 'edrxCycle',
106 component: 'InputNumber', 106 component: 'InputNumber',
107 - label: 'eDRX cycle', 107 + label: 'eDRX循环',
108 required: true, 108 required: true,
109 - defaultValue: '81', 109 + defaultValue: 81,
110 componentProps: { 110 componentProps: {
111 - placeholder: '请输入PSM Activity Timer', 111 + placeholder: '请输入eDRX循环',
112 }, 112 },
113 colProps: { span: 11 }, 113 colProps: { span: 11 },
114 ifShow: ({ values }) => isDrx(values.powerMode), 114 ifShow: ({ values }) => isDrx(values.powerMode),
@@ -132,11 +132,11 @@ export const CoapSchemas: FormSchema[] = [ @@ -132,11 +132,11 @@ export const CoapSchemas: FormSchema[] = [
132 { 132 {
133 field: 'pagingTransmissionWindow', 133 field: 'pagingTransmissionWindow',
134 component: 'InputNumber', 134 component: 'InputNumber',
135 - label: 'Paging Transmission Window', 135 + label: '寻呼传输窗口',
136 required: true, 136 required: true,
137 - defaultValue: '10', 137 + defaultValue: 10,
138 componentProps: { 138 componentProps: {
139 - placeholder: '请输入Paging Transmission Window', 139 + placeholder: '请输入寻呼传输窗口',
140 }, 140 },
141 colProps: { span: 11 }, 141 colProps: { span: 11 },
142 ifShow: ({ values }) => isDrx(values.powerMode), 142 ifShow: ({ values }) => isDrx(values.powerMode),
  1 +<template>
  2 + <div>
  3 + <BasicModal
  4 + v-bind="$attrs"
  5 + width="30rem"
  6 + :height="heightNum"
  7 + @register="register"
  8 + title="Add new server config"
  9 + @cancel="handleCancel"
  10 + :showOkBtn="true"
  11 + @ok="handleSubmit"
  12 + v-model:visible="visible"
  13 + >
  14 + <div style="display: flex; align-items: center; justify-content: center">
  15 + <h2>Server type:</h2>
  16 + <Select
  17 + v-model:value="selectValue"
  18 + style="width: 340px"
  19 + :options="selectOptions"
  20 + @change="emitChange"
  21 + />
  22 + </div>
  23 + </BasicModal>
  24 + </div>
  25 +</template>
  26 +<script setup lang="ts">
  27 + import { ref } from 'vue';
  28 + import { BasicModal, useModalInner } from '/@/components/Modal';
  29 + import { Select } from 'ant-design-vue';
  30 + import { SelectTypes } from 'ant-design-vue/es/select';
  31 +
  32 + const emit = defineEmits(['register', 'emitSelect']);
  33 + const [register] = useModalInner((data) => {
  34 + console.log(data);
  35 + });
  36 + const heightNum = ref(80);
  37 + const visible = ref(false);
  38 + const selectValue = ref('LwM2M');
  39 + const selectOptions = ref<SelectTypes['options']>([
  40 + {
  41 + label: 'LwM2M Server',
  42 + value: 'LwM2M',
  43 + },
  44 + {
  45 + label: 'Bootstrap Server',
  46 + value: 'Bootstrap',
  47 + },
  48 + ]);
  49 + const emitChange = (e) => {
  50 + selectValue.value = e;
  51 + };
  52 + const handleSubmit = () => {
  53 + emit('emitSelect', selectValue.value);
  54 + handleCancel();
  55 + };
  56 +
  57 + const handleCancel = () => {
  58 + visible.value = false;
  59 + };
  60 +</script>
  61 +<style lang="less" scoped></style>
@@ -236,7 +236,6 @@ export const deviceSchemas: FormSchema[] = [ @@ -236,7 +236,6 @@ export const deviceSchemas: FormSchema[] = [
236 colProps: { span: 22 }, 236 colProps: { span: 22 },
237 component: 'InputTextArea', 237 component: 'InputTextArea',
238 componentProps: { 238 componentProps: {
239 - disabled: true,  
240 autoSize: { 239 autoSize: {
241 maxRows: 50, 240 maxRows: 50,
242 }, 241 },
@@ -250,45 +249,31 @@ export const deviceSchemas: FormSchema[] = [ @@ -250,45 +249,31 @@ export const deviceSchemas: FormSchema[] = [
250 "keyName": {}, 249 "keyName": {},
251 "attributeLwm2m": {} 250 "attributeLwm2m": {}
252 }, 251 },
253 - "bootstrap": {  
254 - "servers": {  
255 - "binding": "UQ",  
256 - "shortId": 123,  
257 - "lifetime": 300,  
258 - "notifIfDisabled": true,  
259 - "defaultMinPeriod": 1  
260 - },  
261 - "bootstrapServer": {  
262 - "bootstrapServerIs": true,  
263 - "host": "0.0.0.0",  
264 - "port": 5687,  
265 - "securityHost": "0.0.0.0",  
266 - "securityPort": 5688,  
267 - "serverId": 111,  
268 - "clientHoldOffTime": 1,  
269 - "serverPublicKey": "",  
270 - "bootstrapServerAccountTimeout": 0  
271 - },  
272 - "lwm2mServer": { 252 + "bootstrap": [
  253 + {
  254 + "shortServerId": 123,
273 "bootstrapServerIs": false, 255 "bootstrapServerIs": false,
274 "host": "0.0.0.0", 256 "host": "0.0.0.0",
275 "port": 5685, 257 "port": 5685,
276 - "securityHost": "0.0.0.0",  
277 - "securityPort": 5686,  
278 - "serverId": 123,  
279 "clientHoldOffTime": 1, 258 "clientHoldOffTime": 1,
280 "serverPublicKey": "", 259 "serverPublicKey": "",
281 - "bootstrapServerAccountTimeout": 0 260 + "serverCertificate": "",
  261 + "bootstrapServerAccountTimeout": 0,
  262 + "lifetime": 300,
  263 + "defaultMinPeriod": 1,
  264 + "notifIfDisabled": true,
  265 + "binding": "U",
  266 + "securityMode": "NO_SEC"
282 } 267 }
283 - }, 268 + ],
284 "clientLwM2mSettings": { 269 "clientLwM2mSettings": {
285 "clientOnlyObserveAfterConnect": 1, 270 "clientOnlyObserveAfterConnect": 1,
286 "fwUpdateStrategy": 1, 271 "fwUpdateStrategy": 1,
287 - "swUpdateStrategy": 2,  
288 - "swUpdateResource": "coap://localhost:5685", 272 + "swUpdateStrategy": 1,
289 "powerMode": "DRX", 273 "powerMode": "DRX",
290 "compositeOperationsSupport": false 274 "compositeOperationsSupport": false
291 }, 275 },
  276 + "bootstrapServerUpdateEnable": false,
292 "type": "LWM2M" 277 "type": "LWM2M"
293 } 278 }
294 `, 279 `,
@@ -11,29 +11,44 @@ @@ -11,29 +11,44 @@
11 </TabPane> 11 </TabPane>
12 <TabPane forceRender key="2" tab="Bootstrap"> 12 <TabPane forceRender key="2" tab="Bootstrap">
13 <div> 13 <div>
14 - <Checkbox v-model:checked="bootstrapServerUpdateEnable">包括引导服务器更新</Checkbox>  
15 - <Card 14 + <Checkbox
  15 + @change="handleCheckChange($event)"
  16 + v-model:checked="bootstrapServerUpdateEnable"
  17 + >包括引导服务器更新</Checkbox
  18 + >
  19 + <CollapseContainer
16 v-for="(item, index) in dynamicBOOTSTRAP.bootstrap" 20 v-for="(item, index) in dynamicBOOTSTRAP.bootstrap"
17 :key="item" 21 :key="item"
18 - title="LwM2M Server"  
19 - style="width: 99%; margin-top: 2vh" 22 + :title="collapseTitle(item)"
  23 + class="mt-4"
20 > 24 >
21 - <template #extra>  
22 - <Button size="small" type="dashed" @click="handleRemove(index)">  
23 - <template #icon>  
24 - <MinusCircleOutlined />  
25 - </template> 25 + <template #action>
  26 + <Button
  27 + style="margin-right: 1vw"
  28 + size="small"
  29 + type="text"
  30 + @click="handleRemove(index)"
  31 + >
  32 + <template #icon> <DeleteOutlined /> </template>
26 </Button> 33 </Button>
27 </template> 34 </template>
28 - <!-- BootStrapForm表单项 -->  
29 - <BootStrapForm :ref="dynamicBindRef.BootStrapFormItemRef" :index="index" :item="item" />  
30 - </Card> 35 + <div style="border: 1px solid #d9d9d9; width: 100%">
  36 + <div style="margin: 10px 15px">
  37 + <BootStrapForm
  38 + :ref="dynamicBindRef.BootStrapFormItemRef"
  39 + :index="index"
  40 + :item="item"
  41 + />
  42 + </div>
  43 + </div>
  44 + </CollapseContainer>
31 <div style="margin-top: 2vh"> 45 <div style="margin-top: 2vh">
32 - <Button size="middle" type="dashed" @click="handleAdd"> 46 + <Button size="middle" type="text" @click="handleAdd">
33 <template #icon> 47 <template #icon>
34 <PlusCircleOutlined /> 48 <PlusCircleOutlined />
35 </template> 49 </template>
36 - Add LwM2M Server 50 + <span v-if="selectCheckStatus">Add server config</span>
  51 + <span v-else>Add LwM2M Server</span>
37 </Button> 52 </Button>
38 </div> 53 </div>
39 </div> 54 </div>
@@ -61,6 +76,7 @@ @@ -61,6 +76,7 @@
61 <BasicForm :showResetButton="false" :showSubmitButton="false" @register="registerDevice" /> 76 <BasicForm :showResetButton="false" :showSubmitButton="false" @register="registerDevice" />
62 </TabPane> 77 </TabPane>
63 </Tabs> 78 </Tabs>
  79 + <ServerConfigModal @register="registerModal" @emitSelect="acceptEmitFunc" />
64 </div> 80 </div>
65 </template> 81 </template>
66 82
@@ -70,8 +86,11 @@ @@ -70,8 +86,11 @@
70 import { BasicForm, useForm } from '/@/components/Form'; 86 import { BasicForm, useForm } from '/@/components/Form';
71 import { modelSchemas, settingsSchemas, deviceSchemas } from './index'; 87 import { modelSchemas, settingsSchemas, deviceSchemas } from './index';
72 import BootStrapForm from './cpns/BootStrapForm.vue'; 88 import BootStrapForm from './cpns/BootStrapForm.vue';
73 - import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons-vue'; 89 + import { DeleteOutlined, PlusCircleOutlined } from '@ant-design/icons-vue';
74 import { Button, Checkbox } from 'ant-design-vue'; 90 import { Button, Checkbox } from 'ant-design-vue';
  91 + import { CollapseContainer } from '/@/components/Container';
  92 + import { useModal } from '/@/components/Modal';
  93 + import ServerConfigModal from './cpns/ServerConfigModal.vue';
75 94
76 export default defineComponent({ 95 export default defineComponent({
77 name: 'index', 96 name: 'index',
@@ -80,16 +99,21 @@ @@ -80,16 +99,21 @@
80 TabPane: Tabs.TabPane, 99 TabPane: Tabs.TabPane,
81 BasicForm, 100 BasicForm,
82 BootStrapForm, 101 BootStrapForm,
83 - MinusCircleOutlined, 102 + DeleteOutlined,
84 Card, 103 Card,
85 PlusCircleOutlined, 104 PlusCircleOutlined,
86 Button, 105 Button,
87 Checkbox, 106 Checkbox,
  107 + CollapseContainer,
  108 + ServerConfigModal,
88 }, 109 },
89 setup() { 110 setup() {
  111 + const collapseTitle = (item) => {
  112 + return `LwM2M Server Short server ID: ${item.shortServerId} Security config mode: ${item.securityMode}`;
  113 + };
90 const bootstrapServerUpdateEnable = ref(false); 114 const bootstrapServerUpdateEnable = ref(false);
91 const dynamicBOOTSTRAP: any = reactive({ 115 const dynamicBOOTSTRAP: any = reactive({
92 - bootstrap: [{}], 116 + bootstrap: [{ securityMode: 'NO_SEC', shortServerId: 1234 }],
93 }); 117 });
94 const dynamicBindRef: any = { 118 const dynamicBindRef: any = {
95 BootStrapFormItemRef: ref([]), 119 BootStrapFormItemRef: ref([]),
@@ -140,9 +164,20 @@ @@ -140,9 +164,20 @@
140 span: 14, 164 span: 14,
141 }, 165 },
142 }); 166 });
  167 + const [registerModal, { openModal }] = useModal();
143 168
144 const handleAdd = () => { 169 const handleAdd = () => {
145 - dynamicBOOTSTRAP.bootstrap.push({}); 170 + //TODO 如果是server config 则只弹窗一次
  171 + if (selectCheckStatus.value) {
  172 + openModal(true, {
  173 + isUpdate: true,
  174 + });
  175 + } else {
  176 + dynamicBOOTSTRAP.bootstrap.push({
  177 + securityMode: 'NO_SEC',
  178 + shortServerId: 1234,
  179 + });
  180 + }
146 }; 181 };
147 const handleRemove = (index) => { 182 const handleRemove = (index) => {
148 dynamicBOOTSTRAP.bootstrap.splice(index, 1); 183 dynamicBOOTSTRAP.bootstrap.splice(index, 1);
@@ -240,7 +275,32 @@ @@ -240,7 +275,32 @@
240 resetDeviceValue(); 275 resetDeviceValue();
241 }); 276 });
242 }; 277 };
243 - 278 + const selectCheckStatus = ref(false);
  279 + const handleCheckChange = (e) => {
  280 + selectCheckStatus.value = e.target.checked;
  281 + if (!selectCheckStatus.value) {
  282 + const findIndex = dynamicBOOTSTRAP.bootstrap.findIndex((o) => o.type == 'Bootstrap');
  283 + if (findIndex !== -1) {
  284 + dynamicBOOTSTRAP.bootstrap.splice(findIndex, 1);
  285 + }
  286 + }
  287 + };
  288 + const acceptEmitFunc = (e) => {
  289 + switch (e) {
  290 + case 'LwM2M':
  291 + dynamicBOOTSTRAP.bootstrap.push({
  292 + securityMode: 'NO_SEC',
  293 + shortServerId: 1234,
  294 + });
  295 + break;
  296 + case 'Bootstrap':
  297 + dynamicBOOTSTRAP.bootstrap.push({
  298 + securityMode: 'NO_SEC',
  299 + shortServerId: 1234,
  300 + });
  301 + break;
  302 + }
  303 + };
244 return { 304 return {
245 currentKey, 305 currentKey,
246 currentSize, 306 currentSize,
@@ -256,6 +316,11 @@ @@ -256,6 +316,11 @@
256 handleAdd, 316 handleAdd,
257 handleRemove, 317 handleRemove,
258 bootstrapServerUpdateEnable, 318 bootstrapServerUpdateEnable,
  319 + collapseTitle,
  320 + handleCheckChange,
  321 + registerModal,
  322 + acceptEmitFunc,
  323 + selectCheckStatus,
259 }; 324 };
260 }, 325 },
261 }); 326 });
@@ -20,7 +20,7 @@ export const MqttSchemas: FormSchema[] = [ @@ -20,7 +20,7 @@ export const MqttSchemas: FormSchema[] = [
20 { 20 {
21 field: 'deviceTelemetryTopic', 21 field: 'deviceTelemetryTopic',
22 component: 'Input', 22 component: 'Input',
23 - label: '遥测数据 topic 筛选器', 23 + label: '遥测数据主题筛选器',
24 required: true, 24 required: true,
25 defaultValue: 'v1/devices/me/telemetry', 25 defaultValue: 'v1/devices/me/telemetry',
26 componentProps: { 26 componentProps: {
@@ -32,7 +32,7 @@ export const MqttSchemas: FormSchema[] = [ @@ -32,7 +32,7 @@ export const MqttSchemas: FormSchema[] = [
32 field: 'deviceAttributesTopic', 32 field: 'deviceAttributesTopic',
33 component: 'Input', 33 component: 'Input',
34 required: true, 34 required: true,
35 - label: 'Attributes topic filter', 35 + label: '属性主题过滤器',
36 defaultValue: 'v1/devices/me/attributes', 36 defaultValue: 'v1/devices/me/attributes',
37 componentProps: { 37 componentProps: {
38 placeholder: '请输入Attributes topic 筛选器', 38 placeholder: '请输入Attributes topic 筛选器',
@@ -64,7 +64,14 @@ export const MqttSchemas: FormSchema[] = [ @@ -64,7 +64,14 @@ export const MqttSchemas: FormSchema[] = [
64 colProps: { span: 23 }, 64 colProps: { span: 23 },
65 defaultValue: false, 65 defaultValue: false,
66 component: 'Checkbox', 66 component: 'Checkbox',
67 - renderComponentContent: `启用后,平台将默认使用Protobuf有效载荷格式。如果解析失败,平台将尝试使用JSON有效负载格式。用于固件更新期间的向后兼容性。例如,固件的初始版本使用Json,而新版本使用Protobuf。在设备组的固件更新过程中,需要同时支持Protobuf和JSON。兼容性模式会导致性能轻微下降,因此建议在所有设备更新后禁用此模式。`, 67 + ifShow: ({ values }) => isProtobuf(values.transportPayloadType),
  68 + renderComponentContent: '启用与其他有效负载格式的兼容性',
  69 + },
  70 + {
  71 + field: 'desc1',
  72 + component: 'InputTextArea',
  73 + label: '',
  74 + slot: 'desc1',
68 ifShow: ({ values }) => isProtobuf(values.transportPayloadType), 75 ifShow: ({ values }) => isProtobuf(values.transportPayloadType),
69 }, 76 },
70 { 77 {
@@ -73,7 +80,16 @@ export const MqttSchemas: FormSchema[] = [ @@ -73,7 +80,16 @@ export const MqttSchemas: FormSchema[] = [
73 colProps: { span: 23 }, 80 colProps: { span: 23 },
74 defaultValue: false, 81 defaultValue: false,
75 component: 'Checkbox', 82 component: 'Checkbox',
76 - renderComponentContent: `启用后,平台将使用Json有效负载格式通过以下主题推送属性和RPC:v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id,v1/devices/me/rpc/response/$request_id.此设置不会影响使用新(v2)主题发送的属性和rpc订阅:v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. Where $request_id是一个整数请求标识符。`, 83 + renderComponentContent: '默认下行主题使用Json格式',
  84 + ifShow: ({ values }) =>
  85 + isProtobuf(values.transportPayloadType) &&
  86 + !!values.useJsonPayloadFormatForDefaultDownlinkTopics,
  87 + },
  88 + {
  89 + field: 'desc2',
  90 + component: 'InputTextArea',
  91 + label: '',
  92 + slot: 'desc2',
77 ifShow: ({ values }) => 93 ifShow: ({ values }) =>
78 isProtobuf(values.transportPayloadType) && 94 isProtobuf(values.transportPayloadType) &&
79 !!values.useJsonPayloadFormatForDefaultDownlinkTopics, 95 !!values.useJsonPayloadFormatForDefaultDownlinkTopics,
@@ -19,6 +19,28 @@ @@ -19,6 +19,28 @@
19 </p> 19 </p>
20 </div> 20 </div>
21 </template> 21 </template>
  22 + <template #desc1>
  23 + <div style="width: 47rem; margin-left: 2rem">
  24 + <p>
  25 + 启用时,默认情况下,平台将使用Protobuf有效载荷格式。如果解析失败,平台将尝试使用JSON负载格式。
  26 + 有助于固件更新期间的向后兼容性。例如,固件的初始版本使用Json,而新版本使用Protobuf。
  27 + 在设备组的固件更新过程中,需要同时支持Protobuf和JSON。兼容性模式会导致性能略有下降,
  28 + 因此建议在更新所有设备后禁用此模式。
  29 + </p>
  30 + </div>
  31 + </template>
  32 + <template #desc2>
  33 + <div style="width: 47rem; margin-left: 2rem">
  34 + <p>
  35 + 启用后,平台将使用Json负载格式通过以下主题推送属性
  36 + 和RPC:v1/devices/me/attributes/response/$request\u id、v1/devices/me/attributes、
  37 + v1/devices/me/RPC/request/$request\u id、v1/devices/me/RPC/response/$request\u id。
  38 + 此设置不会影响使用新(v2)主题发送的属性和rpc订阅:
  39 + v2/a/res/$request\u id、v2/a、v2/r/req/$request\u id、v2/r/res/$request\u id。
  40 + 其中,$request\u id是整数请求标识符。
  41 + </p>
  42 + </div>
  43 + </template>
22 </BasicForm> 44 </BasicForm>
23 </div> 45 </div>
24 </div> 46 </div>
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 <div 2 <div
3 v-for="(param, index) in dynamicInput.params" 3 v-for="(param, index) in dynamicInput.params"
4 :key="index" 4 :key="index"
5 - style="display: flex; margin-top: 0.2vh" 5 + style="display: flex; margin-top: 0.25vh"
6 > 6 >
7 <Select 7 <Select
8 v-model:value="param.dataType" 8 v-model:value="param.dataType"
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 @change="emitChange" 17 @change="emitChange"
18 /> 18 />
19 <a-input 19 <a-input
20 - placeholder="请输入OID" 20 + placeholder="请输入OID(不能重复)"
21 v-model:value="param.oid" 21 v-model:value="param.oid"
22 style="width: 38%; margin: 0 0 5px 8px" 22 style="width: 38%; margin: 0 0 5px 8px"
23 @change="emitChange" 23 @change="emitChange"
@@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
30 /> 30 />
31 </div> 31 </div>
32 <div> 32 <div>
33 - <a-button type="dashed" style="width: 38%" @click="add"> 33 + <a-button type="text" style="width: 28%; margin-top: 0.25vh" @click="add">
34 <PlusCircleOutlined /> 34 <PlusCircleOutlined />
35 Add mapping 35 Add mapping
36 </a-button> 36 </a-button>
@@ -16,10 +16,12 @@ @@ -16,10 +16,12 @@
16 > 16 >
17 <InputNumber 17 <InputNumber
18 v-if="item.spec == 'TELEMETRY_QUERYING' || item.spec == 'CLIENT_ATTRIBUTES_QUERYING'" 18 v-if="item.spec == 'TELEMETRY_QUERYING' || item.spec == 'CLIENT_ATTRIBUTES_QUERYING'"
19 - v-model:value="item.queryingFrequencyMs"  
20 - :min="5000"  
21 - :max="1000000000" 19 + v-model:value="queryingFrequencyMs"
  20 + :min="0"
  21 + :max="99999999999999999999"
  22 + style="margin-top: 0.25vh"
22 /> 23 />
  24 + <div style="margin-top: 0.65vh"></div>
23 <MappingsForm 25 <MappingsForm
24 :value="item.mappings" 26 :value="item.mappings"
25 @change="handleMappingsChange" 27 @change="handleMappingsChange"
@@ -33,7 +35,7 @@ @@ -33,7 +35,7 @@
33 style="text-align: center; line-height: 20vh" 35 style="text-align: center; line-height: 20vh"
34 :style="{ lineHeight: dynamicHeight + 'vh' }" 36 :style="{ lineHeight: dynamicHeight + 'vh' }"
35 > 37 >
36 - <Button size="small" type="dashed" @click="handleRemove(item, index)"> 38 + <Button size="small" type="default" @click="handleRemove(item, index)">
37 <template #icon> 39 <template #icon>
38 <MinusCircleOutlined /> 40 <MinusCircleOutlined />
39 </template> 41 </template>
@@ -47,6 +49,7 @@ @@ -47,6 +49,7 @@
47 import { Button, InputNumber } from 'ant-design-vue'; 49 import { Button, InputNumber } from 'ant-design-vue';
48 import { MinusCircleOutlined } from '@ant-design/icons-vue'; 50 import { MinusCircleOutlined } from '@ant-design/icons-vue';
49 import MappingsForm from './MappingsForm.vue'; 51 import MappingsForm from './MappingsForm.vue';
  52 + import { useMessage } from '/@/hooks/web/useMessage';
50 53
51 const props = defineProps({ 54 const props = defineProps({
52 item: { 55 item: {
@@ -59,7 +62,8 @@ @@ -59,7 +62,8 @@
59 }); 62 });
60 const emit = defineEmits(['removeItem']); 63 const emit = defineEmits(['removeItem']);
61 const dynamicHeight = ref(25); 64 const dynamicHeight = ref(25);
62 - 65 + const queryingFrequencyMs = ref(5000);
  66 + const { createMessage } = useMessage();
63 const handleMappingsChange = (e) => { 67 const handleMappingsChange = (e) => {
64 // eslint-disable-next-line vue/no-mutating-props 68 // eslint-disable-next-line vue/no-mutating-props
65 props.item.mappings = e; 69 props.item.mappings = e;
@@ -70,9 +74,18 @@ @@ -70,9 +74,18 @@
70 //设置回显的高度 74 //设置回显的高度
71 const setFieldsValueFunc = () => { 75 const setFieldsValueFunc = () => {
72 dynamicHeight.value = props.item.mappings.length * 3 + props.item.mappings.length + 15; 76 dynamicHeight.value = props.item.mappings.length * 3 + props.item.mappings.length + 15;
  77 + queryingFrequencyMs.value = props.item.queryingFrequencyMs;
73 }; 78 };
74 //获取表单的值 79 //获取表单的值
75 const getSnmpFormFunc = () => { 80 const getSnmpFormFunc = () => {
  81 + if (
  82 + props.item.spec == 'TELEMETRY_QUERYING' ||
  83 + props.item.spec == 'CLIENT_ATTRIBUTES_QUERYING'
  84 + ) {
  85 + if (queryingFrequencyMs.value == null) {
  86 + return createMessage.error('请填写查询频率');
  87 + }
  88 + }
76 let obj: any = {}; 89 let obj: any = {};
77 obj = { 90 obj = {
78 ...{ spec: props.item.spec }, 91 ...{ spec: props.item.spec },
@@ -80,7 +93,7 @@ @@ -80,7 +93,7 @@
80 ...{ 93 ...{
81 queryingFrequencyMs: 94 queryingFrequencyMs:
82 props.item.spec == 'TELEMETRY_QUERYING' || props.item.spec == 'CLIENT_ATTRIBUTES_QUERYING' 95 props.item.spec == 'TELEMETRY_QUERYING' || props.item.spec == 'CLIENT_ATTRIBUTES_QUERYING'
83 - ? props.item.queryingFrequencyMs 96 + ? queryingFrequencyMs.value
84 : null, 97 : null,
85 }, 98 },
86 }; 99 };
@@ -27,22 +27,14 @@ @@ -27,22 +27,14 @@
27 :options="selectOptions" 27 :options="selectOptions"
28 @change="handleChange(item.spec)" 28 @change="handleChange(item.spec)"
29 allowClear 29 allowClear
30 - >  
31 - <SelectOption  
32 - v-for="it in selectOptions"  
33 - :value="it.value"  
34 - :key="it.value"  
35 - :label="it.label"  
36 - :disabled="it.disabled"  
37 - />  
38 - </Select> 30 + />
39 </SnmpForm> 31 </SnmpForm>
40 </template> 32 </template>
41 <div 33 <div
42 v-if="dynamicSNMP.communicationConfigs.length < 4" 34 v-if="dynamicSNMP.communicationConfigs.length < 4"
43 style="margin-left: 0vw; margin-top: 2vh" 35 style="margin-left: 0vw; margin-top: 2vh"
44 > 36 >
45 - <Button size="middle" type="dashed" @click="handleAdd"> 37 + <Button size="middle" type="text" @click="handleAdd">
46 <template #icon> 38 <template #icon>
47 <PlusCircleOutlined /> 39 <PlusCircleOutlined />
48 </template> 40 </template>
@@ -60,7 +52,7 @@ @@ -60,7 +52,7 @@
60 import { BasicForm, useForm } from '/@/components/Form'; 52 import { BasicForm, useForm } from '/@/components/Form';
61 import { snmpSchemas } from './config'; 53 import { snmpSchemas } from './config';
62 import { PlusCircleOutlined } from '@ant-design/icons-vue'; 54 import { PlusCircleOutlined } from '@ant-design/icons-vue';
63 - import { Button, Select, SelectOption } from 'ant-design-vue'; 55 + import { Button, Select } from 'ant-design-vue';
64 import SnmpForm from './cpns/SnmpForm.vue'; 56 import SnmpForm from './cpns/SnmpForm.vue';
65 57
66 interface mappingsI { 58 interface mappingsI {
@@ -77,26 +69,22 @@ @@ -77,26 +69,22 @@
77 { 69 {
78 label: 'Telemetry', 70 label: 'Telemetry',
79 value: 'TELEMETRY_QUERYING', 71 value: 'TELEMETRY_QUERYING',
80 - disabled: false,  
81 }, 72 },
82 { 73 {
83 label: 'Client attributes', 74 label: 'Client attributes',
84 value: 'CLIENT_ATTRIBUTES_QUERYING', 75 value: 'CLIENT_ATTRIBUTES_QUERYING',
85 - disabled: false,  
86 }, 76 },
87 { 77 {
88 label: 'Shared attributes', 78 label: 'Shared attributes',
89 value: 'SHARED_ATTRIBUTES_SETTING', 79 value: 'SHARED_ATTRIBUTES_SETTING',
90 - disabled: false,  
91 }, 80 },
92 { 81 {
93 label: 'RPC request', 82 label: 'RPC request',
94 value: 'TO_DEVICE_RPC_REQUEST', 83 value: 'TO_DEVICE_RPC_REQUEST',
95 - disabled: false,  
96 }, 84 },
97 ]); 85 ]);
98 const selectValue = ref(''); 86 const selectValue = ref('');
99 - //解决新增选择框互斥问题和编辑回显互斥问题 87 + //Select互斥
100 const handleChange = (value: string) => { 88 const handleChange = (value: string) => {
101 selectValue.value = value; 89 selectValue.value = value;
102 selectOptions.value.forEach((ele: any) => { 90 selectOptions.value.forEach((ele: any) => {
@@ -154,12 +142,15 @@ @@ -154,12 +142,15 @@
154 }); 142 });
155 }; 143 };
156 const handleRemoveItem = (item, index) => { 144 const handleRemoveItem = (item, index) => {
157 - console.log(item.spec);  
158 - //2 TODO待解决删除时清空互斥问题 145 + selectOptions.value.forEach((ele: any) => {
  146 + if (ele.value == item.spec) {
  147 + ele.disabled = false;
  148 + }
  149 + });
159 dynamicSNMP.communicationConfigs.splice(index, 1); 150 dynamicSNMP.communicationConfigs.splice(index, 1);
160 }; 151 };
  152 +
161 //回显表单值 153 //回显表单值
162 - //TODO 采用这种方式动态绑定ref 都会造成回显数据顺序是随机的但不影响回显数据的正确性  
163 const setStepFieldsValueFunc = (v) => { 154 const setStepFieldsValueFunc = (v) => {
164 setFieldsValue({ 155 setFieldsValue({
165 timeoutMs: v.timeoutMs, 156 timeoutMs: v.timeoutMs,
@@ -168,14 +159,13 @@ @@ -168,14 +159,13 @@
168 dynamicSNMP.communicationConfigs = v.communicationConfigs; 159 dynamicSNMP.communicationConfigs = v.communicationConfigs;
169 dynamicSNMP.communicationConfigs.forEach((snmp, index: number) => { 160 dynamicSNMP.communicationConfigs.forEach((snmp, index: number) => {
170 nextTick(() => { 161 nextTick(() => {
171 - //编辑回显互斥赋值  
172 handleChange(snmp.spec); 162 handleChange(snmp.spec);
173 unref(dynamicBindRef.SnmpFormItemRef)[index]?.setFieldsValueFunc(); 163 unref(dynamicBindRef.SnmpFormItemRef)[index]?.setFieldsValueFunc();
174 }); 164 });
175 }); 165 });
176 }; 166 };
177 167
178 - //获取最终的 168 + //获取表单
179 const getSnmpForm = async () => { 169 const getSnmpForm = async () => {
180 let value = await validate(); 170 let value = await validate();
181 if (!value) return; 171 if (!value) return;