Commit 1281e6e8d9f370174387405d02ef35d0c5fe93e7

Authored by ww
1 parent 283688d5

fix: DEFECT-1118 看板管理指令下发修复tcp设备下发指令逻辑

@@ -86,6 +86,12 @@ export interface DataSource { @@ -86,6 +86,12 @@ export interface DataSource {
86 deviceName: string; 86 deviceName: string;
87 deviceProfileId: string; 87 deviceProfileId: string;
88 tbDeviceId: string; 88 tbDeviceId: string;
  89 + customCommand: {
  90 + transportType?: string;
  91 + commandType?: string;
  92 + command?: string;
  93 + service?: string;
  94 + };
89 95
90 // front usage 96 // front usage
91 uuid?: string; 97 uuid?: string;
@@ -93,6 +99,7 @@ export interface DataSource { @@ -93,6 +99,7 @@ export interface DataSource {
93 height?: number; 99 height?: number;
94 radio?: RadioRecord; 100 radio?: RadioRecord;
95 deviceType?: DeviceTypeEnum; 101 deviceType?: DeviceTypeEnum;
  102 + [key: string]: any;
96 } 103 }
97 104
98 export interface DataComponentRecord { 105 export interface DataComponentRecord {
@@ -127,4 +127,5 @@ export type ComponentType = @@ -127,4 +127,5 @@ export type ComponentType =
127 | 'ProductPicker' 127 | 'ProductPicker'
128 | 'PollCommandInput' 128 | 'PollCommandInput'
129 | 'RegisterAddressInput' 129 | 'RegisterAddressInput'
130 - | 'ControlGroup'; 130 + | 'ControlGroup'
  131 + | 'JSONEditor';
@@ -17,6 +17,9 @@ export interface ControlComponentValue { @@ -17,6 +17,9 @@ export interface ControlComponentValue {
17 deviceProfileId?: string; 17 deviceProfileId?: string;
18 deviceType?: DeviceTypeEnum; 18 deviceType?: DeviceTypeEnum;
19 organizationId?: string; 19 organizationId?: string;
  20 +
  21 + dataSource?: DataSource;
  22 + [key: string]: any;
20 } 23 }
21 24
22 export const ControlComponentDefaultConfig: ControlComponentValue = { 25 export const ControlComponentDefaultConfig: ControlComponentValue = {
@@ -40,6 +43,7 @@ export const transformControlConfig = ( @@ -40,6 +43,7 @@ export const transformControlConfig = (
40 deviceType: dataSourceRecord.deviceType, 43 deviceType: dataSourceRecord.deviceType,
41 slaveDeviceId: dataSourceRecord.slaveDeviceId, 44 slaveDeviceId: dataSourceRecord.slaveDeviceId,
42 organizationId: dataSourceRecord.organizationId, 45 organizationId: dataSourceRecord.organizationId,
  46 + dataSource: dataSourceRecord,
43 } as ControlComponentValue, 47 } as ControlComponentValue,
44 }; 48 };
45 }; 49 };
1 import { ControlComponentValue } from './control.config'; 1 import { ControlComponentValue } from './control.config';
2 -import { getDeviceProfile } from '/@/api/alarm/position';  
3 -import { getDeviceRelation, sendCommandOneway } from '/@/api/dataBoard';  
4 -import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';  
5 -import { getModelServices } from '/@/api/device/modelOfMatter'; 2 +import { sendCommandOneway } from '/@/api/dataBoard';
6 import { useMessage } from '/@/hooks/web/useMessage'; 3 import { useMessage } from '/@/hooks/web/useMessage';
7 -import { isString } from '/@/utils/is';  
8 import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; 4 import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const';
9 5
10 const { createMessage } = useMessage(); 6 const { createMessage } = useMessage();
@@ -15,31 +11,20 @@ export function useSendCommand() { @@ -15,31 +11,20 @@ export function useSendCommand() {
15 }; 11 };
16 const sendCommand = async (record: ControlComponentValue, value: any) => { 12 const sendCommand = async (record: ControlComponentValue, value: any) => {
17 if (!record) return error(); 13 if (!record) return error();
18 - const { deviceProfileId, attribute, deviceType } = record;  
19 - let { deviceId } = record; 14 + const { attribute } = record;
  15 + const { dataSource } = record;
  16 + const { customCommand } = dataSource || {};
  17 +
  18 + const { deviceId } = record;
20 if (!deviceId) return error(); 19 if (!deviceId) return error();
21 try { 20 try {
22 - const list = await getDeviceProfile();  
23 - const deviceProfile = list.find((item) => item.id === deviceProfileId);  
24 - if (!deviceProfile) return error();  
25 -  
26 let params: string | Recordable = { 21 let params: string | Recordable = {
27 [attribute!]: Number(value), 22 [attribute!]: Number(value),
28 }; 23 };
29 24
30 // 如果是TCP设备从物模型中获取下发命令(TCP网关子设备无物模型服务与事件) 25 // 如果是TCP设备从物模型中获取下发命令(TCP网关子设备无物模型服务与事件)
31 - if (deviceProfile!.transportType === TransportTypeEnum.TCP) {  
32 - const serviceList = (await getModelServices({ deviceProfileId: deviceProfileId! })) || [];  
33 - const record = serviceList.find((item) => item.identifier === attribute);  
34 - const sendCommand = record?.functionJson.inputData?.at(0)?.serviceCommand || '';  
35 - params = isString(sendCommand) ? sendCommand : JSON.stringify(sendCommand);  
36 - }  
37 -  
38 - if (deviceType === DeviceTypeEnum.SENSOR) {  
39 - deviceId = await getDeviceRelation({  
40 - deviceId,  
41 - isSlave: deviceType === DeviceTypeEnum.SENSOR,  
42 - }); 26 + if (customCommand?.transportType === TransportTypeEnum.TCP) {
  27 + params = customCommand.command!;
43 } 28 }
44 29
45 // 控制按钮下发命令为0 或 1 30 // 控制按钮下发命令为0 或 1
@@ -57,7 +42,6 @@ export function useSendCommand() { @@ -57,7 +42,6 @@ export function useSendCommand() {
57 createMessage.success('命令下发成功'); 42 createMessage.success('命令下发成功');
58 return true; 43 return true;
59 } catch (msg) { 44 } catch (msg) {
60 - console.log('enter');  
61 return error(); 45 return error();
62 } 46 }
63 }; 47 };
@@ -61,7 +61,13 @@ @@ -61,7 +61,13 @@
61 const hasExistEl = Object.keys(dataSourceEl).filter((key) => dataSourceEl[key]); 61 const hasExistEl = Object.keys(dataSourceEl).filter((key) => dataSourceEl[key]);
62 for (const id of hasExistEl) { 62 for (const id of hasExistEl) {
63 const oldValues = dataSourceEl[id]?.getFieldsValue(); 63 const oldValues = dataSourceEl[id]?.getFieldsValue();
64 - dataSourceEl[id]?.setFieldsValue({ ...oldValues, [DataSourceField.ATTRIBUTE]: null }); 64 + dataSourceEl[id]?.setFieldsValue({
  65 + ...oldValues,
  66 + [DataSourceField.ATTRIBUTE]: null,
  67 + [DataSourceField.COMMAND_TYPE]: null,
  68 + [DataSourceField.SERVICE]: null,
  69 + });
  70 + dataSourceEl[id]?.clearValidate();
65 } 71 }
66 }; 72 };
67 73
@@ -125,6 +131,12 @@ @@ -125,6 +131,12 @@
125 _dataSource[index] = { 131 _dataSource[index] = {
126 ...value, 132 ...value,
127 componentInfo: { ...(props.defaultConfig || {}), ...componentInfo }, 133 componentInfo: { ...(props.defaultConfig || {}), ...componentInfo },
  134 + customCommand: {
  135 + transportType: value.transportType,
  136 + service: value.service,
  137 + command: value.command,
  138 + commandType: value.commandType,
  139 + },
128 }; 140 };
129 } 141 }
130 142
@@ -197,13 +209,26 @@ @@ -197,13 +209,26 @@
197 dataSource.value = props.record.record.dataSource.map((item) => { 209 dataSource.value = props.record.record.dataSource.map((item) => {
198 const id = buildUUID(); 210 const id = buildUUID();
199 211
  212 + const customCommand = item.customCommand || {};
  213 +
200 nextTick(() => { 214 nextTick(() => {
201 - (dataSourceEl[id] as FormActionType).setFieldsValue(item); 215 + (dataSourceEl[id] as FormActionType).setFieldsValue({
  216 + ...item,
  217 + transportType: customCommand.transportType,
  218 + command: customCommand?.command,
  219 + commandType: customCommand.commandType,
  220 + service: customCommand.service,
  221 + });
202 (dataSourceEl[id] as FormActionType).clearValidate(); 222 (dataSourceEl[id] as FormActionType).clearValidate();
203 }); 223 });
  224 +
204 return { 225 return {
205 id, 226 id,
206 ...item, 227 ...item,
  228 + transportType: customCommand.transportType,
  229 + command: customCommand?.command,
  230 + commandType: customCommand.commandType,
  231 + service: customCommand.service,
207 }; 232 };
208 }); 233 });
209 }; 234 };
@@ -72,7 +72,6 @@ @@ -72,7 +72,6 @@
72 const { getAllDataSourceFieldValue, validate } = unref(basicConfigurationEl)!; 72 const { getAllDataSourceFieldValue, validate } = unref(basicConfigurationEl)!;
73 await validate(); 73 await validate();
74 const value = getAllDataSourceFieldValue(); 74 const value = getAllDataSourceFieldValue();
75 -  
76 unref(isEdit) ? handleUpdateComponent(value) : handleAddComponent(value); 75 unref(isEdit) ? handleUpdateComponent(value) : handleAddComponent(value);
77 resetForm(); 76 resetForm();
78 } catch (error: unknown) { 77 } catch (error: unknown) {
@@ -4,11 +4,11 @@ @@ -4,11 +4,11 @@
4 const props = defineProps({ 4 const props = defineProps({
5 controlId: { 5 controlId: {
6 type: String, 6 type: String,
7 - required: true, 7 + // required: true,
8 }, 8 },
9 checkedId: { 9 checkedId: {
10 type: String, 10 type: String,
11 - required: true, 11 + // required: true,
12 }, 12 },
13 }); 13 });
14 const emit = defineEmits(['change']); 14 const emit = defineEmits(['change']);
1 import { getDeviceAttributes, getMeetTheConditionsDevice } from '/@/api/dataBoard'; 1 import { getDeviceAttributes, getMeetTheConditionsDevice } from '/@/api/dataBoard';
2 import { getOrganizationList } from '/@/api/system/system'; 2 import { getOrganizationList } from '/@/api/system/system';
3 -import { FormSchema } from '/@/components/Form'; 3 +import { FormSchema, useComponentRegister } from '/@/components/Form';
4 import { copyTransFun } from '/@/utils/fnUtils'; 4 import { copyTransFun } from '/@/utils/fnUtils';
5 import { DeviceAttributeParams, MasterDeviceList } from '/@/api/dataBoard/model'; 5 import { DeviceAttributeParams, MasterDeviceList } from '/@/api/dataBoard/model';
6 import { FrontComponent } from '../../const/const'; 6 import { FrontComponent } from '../../const/const';
@@ -10,6 +10,11 @@ import { findDictItemByCode } from '/@/api/system/dict'; @@ -10,6 +10,11 @@ import { findDictItemByCode } from '/@/api/system/dict';
10 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; 10 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
11 import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config'; 11 import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config';
12 import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const'; 12 import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const';
  13 +import { JSONEditor } from '/@/components/CodeEditor';
  14 +import { CommandTypeEnum } from '/@/views/rule/linkedge/config/config.data';
  15 +import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  16 +
  17 +useComponentRegister('JSONEditor', JSONEditor);
13 18
14 export enum BasicConfigField { 19 export enum BasicConfigField {
15 NAME = 'name', 20 NAME = 'name',
@@ -47,6 +52,10 @@ export enum DataSourceField { @@ -47,6 +52,10 @@ export enum DataSourceField {
47 DEVICE_RENAME = 'deviceRename', 52 DEVICE_RENAME = 'deviceRename',
48 LONGITUDE_ATTRIBUTE = 'longitudeAttribute', 53 LONGITUDE_ATTRIBUTE = 'longitudeAttribute',
49 LATITUDE_ATTRIBUTE = 'latitudeAttribute', 54 LATITUDE_ATTRIBUTE = 'latitudeAttribute',
  55 +
  56 + COMMAND = 'command',
  57 + COMMAND_TYPE = 'commandType',
  58 + SERVICE = 'service',
50 } 59 }
51 60
52 export const isControlComponent = (frontId: FrontComponent) => { 61 export const isControlComponent = (frontId: FrontComponent) => {
@@ -139,6 +148,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For @@ -139,6 +148,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For
139 [DataSourceField.TRANSPORT_TYPE]: null, 148 [DataSourceField.TRANSPORT_TYPE]: null,
140 }); 149 });
141 }, 150 },
  151 + getPopupContainer: () => document.body,
142 }; 152 };
143 }, 153 },
144 }, 154 },
@@ -172,6 +182,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For @@ -172,6 +182,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For
172 [DataSourceField.TRANSPORT_TYPE]: option[DataSourceField.TRANSPORT_TYPE], 182 [DataSourceField.TRANSPORT_TYPE]: option[DataSourceField.TRANSPORT_TYPE],
173 }); 183 });
174 }, 184 },
  185 + getPopupContainer: () => document.body,
175 }; 186 };
176 }, 187 },
177 }, 188 },
@@ -252,31 +263,14 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For @@ -252,31 +263,14 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For
252 component: 'ApiSelect', 263 component: 'ApiSelect',
253 label: '属性', 264 label: '属性',
254 colProps: { span: 8 }, 265 colProps: { span: 8 },
255 - dynamicRules: ({ model }) => {  
256 - const transportType = model[DataSourceField.TRANSPORT_TYPE];  
257 - return [  
258 - {  
259 - required: true,  
260 - message: `${  
261 - isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType)  
262 - ? '服务'  
263 - : '属性'  
264 - }为必填项`,  
265 - },  
266 - ];  
267 - }, 266 + rules: [{ required: true, message: '请选择属性' }],
  267 + ifShow: ({ model }) =>
  268 + !(isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]) && isControlComponent(frontId!)),
268 componentProps({ formModel }) { 269 componentProps({ formModel }) {
269 const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; 270 const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID];
270 - const transportType = formModel[DataSourceField.TRANSPORT_TYPE];  
271 - if (isEdit && ![deviceProfileId, transportType].every(Boolean))  
272 - return { placeholder: '请选择属性', getPopupContainer: () => document.body };  
273 return { 271 return {
274 api: async () => { 272 api: async () => {
275 try { 273 try {
276 - if (isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType)) {  
277 - return await getDeviceService(deviceProfileId);  
278 - }  
279 -  
280 if (deviceProfileId) { 274 if (deviceProfileId) {
281 return await getDeviceAttribute({ 275 return await getDeviceAttribute({
282 deviceProfileId, 276 deviceProfileId,
@@ -284,18 +278,87 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For @@ -284,18 +278,87 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For
284 }); 278 });
285 } 279 }
286 } catch (error) {} 280 } catch (error) {}
287 -  
288 return []; 281 return [];
289 }, 282 },
290 - placeholder:  
291 - isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType)  
292 - ? '请选择服务'  
293 - : '请选择属性', 283 + placeholder: '请选择属性',
  284 + getPopupContainer: () => document.body,
  285 + };
  286 + },
  287 + },
  288 + {
  289 + field: DataSourceField.COMMAND_TYPE,
  290 + component: 'ApiSelect',
  291 + label: '命令类型',
  292 + defaultValue: CommandTypeEnum.CUSTOM.toString(),
  293 + colProps: { span: 8 },
  294 + ifShow: ({ model }) =>
  295 + isControlComponent(frontId!) && isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]),
  296 + componentProps: ({ formActionType }) => {
  297 + const { setFieldsValue } = formActionType;
  298 + return {
  299 + api: findDictItemByCode,
  300 + params: {
  301 + dictCode: 'custom_define',
  302 + },
  303 + labelField: 'itemText',
  304 + valueField: 'itemValue',
  305 + placeholder: '请选择命令类型',
  306 + onChange() {
  307 + setFieldsValue({ [DataSourceField.COMMAND]: null, [DataSourceField.SERVICE]: null });
  308 + },
  309 + };
  310 + },
  311 + },
  312 + {
  313 + field: DataSourceField.SERVICE,
  314 + component: 'ApiSelect',
  315 + label: '服务',
  316 + colProps: { span: 8 },
  317 + rules: [{ required: true, message: '请选择服务' }],
  318 + ifShow: ({ model }) =>
  319 + isControlComponent(frontId as FrontComponent) &&
  320 + model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.SERVICE.toString() &&
  321 + isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]),
  322 + componentProps({ formModel, formActionType }) {
  323 + const { setFieldsValue } = formActionType;
  324 + const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID];
  325 + const transportType = formModel[DataSourceField.TRANSPORT_TYPE];
  326 + if (isEdit && ![deviceProfileId, transportType].every(Boolean))
  327 + return { placeholder: '请选择服务', getPopupContainer: () => document.body };
  328 + return {
  329 + api: async () => {
  330 + try {
  331 + if (deviceProfileId) {
  332 + return await getDeviceService(deviceProfileId);
  333 + }
  334 + } catch (error) {}
  335 + return [];
  336 + },
  337 + placeholder: '请选择服务',
294 getPopupContainer: () => document.body, 338 getPopupContainer: () => document.body,
  339 + onChange(value: string, options: ModelOfMatterParams) {
  340 + const command = value ? (options.functionJson.inputData || [])[0].serviceCommand : null;
  341 + setFieldsValue({ [DataSourceField.COMMAND]: command });
  342 + },
295 }; 343 };
296 }, 344 },
297 }, 345 },
298 { 346 {
  347 + field: DataSourceField.COMMAND,
  348 + component: 'Input',
  349 + label: '命令',
  350 + colProps: { span: 8 },
  351 + // 是控制组件 && 自定义命令 && 传输协议为TCP
  352 + ifShow: ({ model }) =>
  353 + isControlComponent(frontId!) &&
  354 + model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.CUSTOM.toString() &&
  355 + model[DataSourceField.TRANSPORT_TYPE] &&
  356 + isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]),
  357 + componentProps: {
  358 + placeholder: '请输入下发命令',
  359 + },
  360 + },
  361 + {
299 field: DataSourceField.DEVICE_RENAME, 362 field: DataSourceField.DEVICE_RENAME,
300 component: 'Input', 363 component: 'Input',
301 label: '设备名', 364 label: '设备名',
@@ -127,13 +127,15 @@ export function useSocketConnect(dataSourceRef: Ref<DataBoardLayoutInfo[]>) { @@ -127,13 +127,15 @@ export function useSocketConnect(dataSourceRef: Ref<DataBoardLayoutInfo[]>) {
127 if (isNullAndUnDef(subscriptionId)) return; 127 if (isNullAndUnDef(subscriptionId)) return;
128 const mappingRecord = cmdIdMapping.get(subscriptionId); 128 const mappingRecord = cmdIdMapping.get(subscriptionId);
129 if (!mappingRecord || !data) return; 129 if (!mappingRecord || !data) return;
130 - mappingRecord.forEach((item) => { 130 +
  131 + for (const item of mappingRecord) {
131 const { attribute, recordIndex, dataSourceIndex } = item; 132 const { attribute, recordIndex, dataSourceIndex } = item;
  133 + if (!attribute) continue;
132 const [[timespan, value]] = data[attribute]; 134 const [[timespan, value]] = data[attribute];
133 const record = getNeedUpdateValueByIndex(recordIndex, dataSourceIndex); 135 const record = getNeedUpdateValueByIndex(recordIndex, dataSourceIndex);
134 record.componentInfo.value = value; 136 record.componentInfo.value = value;
135 record.componentInfo.updateTime = timespan; 137 record.componentInfo.updateTime = timespan;
136 - }); 138 + }
137 return; 139 return;
138 } catch (error) { 140 } catch (error) {
139 throw Error(error as string); 141 throw Error(error as string);