Commit 1281e6e8d9f370174387405d02ef35d0c5fe93e7

Authored by ww
1 parent 283688d5

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

... ... @@ -86,6 +86,12 @@ export interface DataSource {
86 86 deviceName: string;
87 87 deviceProfileId: string;
88 88 tbDeviceId: string;
  89 + customCommand: {
  90 + transportType?: string;
  91 + commandType?: string;
  92 + command?: string;
  93 + service?: string;
  94 + };
89 95
90 96 // front usage
91 97 uuid?: string;
... ... @@ -93,6 +99,7 @@ export interface DataSource {
93 99 height?: number;
94 100 radio?: RadioRecord;
95 101 deviceType?: DeviceTypeEnum;
  102 + [key: string]: any;
96 103 }
97 104
98 105 export interface DataComponentRecord {
... ...
... ... @@ -127,4 +127,5 @@ export type ComponentType =
127 127 | 'ProductPicker'
128 128 | 'PollCommandInput'
129 129 | 'RegisterAddressInput'
130   - | 'ControlGroup';
  130 + | 'ControlGroup'
  131 + | 'JSONEditor';
... ...
... ... @@ -17,6 +17,9 @@ export interface ControlComponentValue {
17 17 deviceProfileId?: string;
18 18 deviceType?: DeviceTypeEnum;
19 19 organizationId?: string;
  20 +
  21 + dataSource?: DataSource;
  22 + [key: string]: any;
20 23 }
21 24
22 25 export const ControlComponentDefaultConfig: ControlComponentValue = {
... ... @@ -40,6 +43,7 @@ export const transformControlConfig = (
40 43 deviceType: dataSourceRecord.deviceType,
41 44 slaveDeviceId: dataSourceRecord.slaveDeviceId,
42 45 organizationId: dataSourceRecord.organizationId,
  46 + dataSource: dataSourceRecord,
43 47 } as ControlComponentValue,
44 48 };
45 49 };
... ...
1 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 3 import { useMessage } from '/@/hooks/web/useMessage';
7   -import { isString } from '/@/utils/is';
8 4 import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const';
9 5
10 6 const { createMessage } = useMessage();
... ... @@ -15,31 +11,20 @@ export function useSendCommand() {
15 11 };
16 12 const sendCommand = async (record: ControlComponentValue, value: any) => {
17 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 19 if (!deviceId) return error();
21 20 try {
22   - const list = await getDeviceProfile();
23   - const deviceProfile = list.find((item) => item.id === deviceProfileId);
24   - if (!deviceProfile) return error();
25   -
26 21 let params: string | Recordable = {
27 22 [attribute!]: Number(value),
28 23 };
29 24
30 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 30 // 控制按钮下发命令为0 或 1
... ... @@ -57,7 +42,6 @@ export function useSendCommand() {
57 42 createMessage.success('命令下发成功');
58 43 return true;
59 44 } catch (msg) {
60   - console.log('enter');
61 45 return error();
62 46 }
63 47 };
... ...
... ... @@ -61,7 +61,13 @@
61 61 const hasExistEl = Object.keys(dataSourceEl).filter((key) => dataSourceEl[key]);
62 62 for (const id of hasExistEl) {
63 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 131 _dataSource[index] = {
126 132 ...value,
127 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 209 dataSource.value = props.record.record.dataSource.map((item) => {
198 210 const id = buildUUID();
199 211
  212 + const customCommand = item.customCommand || {};
  213 +
200 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 222 (dataSourceEl[id] as FormActionType).clearValidate();
203 223 });
  224 +
204 225 return {
205 226 id,
206 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 72 const { getAllDataSourceFieldValue, validate } = unref(basicConfigurationEl)!;
73 73 await validate();
74 74 const value = getAllDataSourceFieldValue();
75   -
76 75 unref(isEdit) ? handleUpdateComponent(value) : handleAddComponent(value);
77 76 resetForm();
78 77 } catch (error: unknown) {
... ...
... ... @@ -4,11 +4,11 @@
4 4 const props = defineProps({
5 5 controlId: {
6 6 type: String,
7   - required: true,
  7 + // required: true,
8 8 },
9 9 checkedId: {
10 10 type: String,
11   - required: true,
  11 + // required: true,
12 12 },
13 13 });
14 14 const emit = defineEmits(['change']);
... ...
1 1 import { getDeviceAttributes, getMeetTheConditionsDevice } from '/@/api/dataBoard';
2 2 import { getOrganizationList } from '/@/api/system/system';
3   -import { FormSchema } from '/@/components/Form';
  3 +import { FormSchema, useComponentRegister } from '/@/components/Form';
4 4 import { copyTransFun } from '/@/utils/fnUtils';
5 5 import { DeviceAttributeParams, MasterDeviceList } from '/@/api/dataBoard/model';
6 6 import { FrontComponent } from '../../const/const';
... ... @@ -10,6 +10,11 @@ import { findDictItemByCode } from '/@/api/system/dict';
10 10 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
11 11 import { DataTypeEnum } from '/@/components/Form/src/externalCompns/components/StructForm/config';
12 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 19 export enum BasicConfigField {
15 20 NAME = 'name',
... ... @@ -47,6 +52,10 @@ export enum DataSourceField {
47 52 DEVICE_RENAME = 'deviceRename',
48 53 LONGITUDE_ATTRIBUTE = 'longitudeAttribute',
49 54 LATITUDE_ATTRIBUTE = 'latitudeAttribute',
  55 +
  56 + COMMAND = 'command',
  57 + COMMAND_TYPE = 'commandType',
  58 + SERVICE = 'service',
50 59 }
51 60
52 61 export const isControlComponent = (frontId: FrontComponent) => {
... ... @@ -139,6 +148,7 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For
139 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 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 263 component: 'ApiSelect',
253 264 label: '属性',
254 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 269 componentProps({ formModel }) {
269 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 271 return {
274 272 api: async () => {
275 273 try {
276   - if (isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType)) {
277   - return await getDeviceService(deviceProfileId);
278   - }
279   -
280 274 if (deviceProfileId) {
281 275 return await getDeviceAttribute({
282 276 deviceProfileId,
... ... @@ -284,18 +278,87 @@ export const dataSourceSchema = (isEdit: boolean, frontId?: FrontComponent): For
284 278 });
285 279 }
286 280 } catch (error) {}
287   -
288 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 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 362 field: DataSourceField.DEVICE_RENAME,
300 363 component: 'Input',
301 364 label: '设备名',
... ...
... ... @@ -127,13 +127,15 @@ export function useSocketConnect(dataSourceRef: Ref<DataBoardLayoutInfo[]>) {
127 127 if (isNullAndUnDef(subscriptionId)) return;
128 128 const mappingRecord = cmdIdMapping.get(subscriptionId);
129 129 if (!mappingRecord || !data) return;
130   - mappingRecord.forEach((item) => {
  130 +
  131 + for (const item of mappingRecord) {
131 132 const { attribute, recordIndex, dataSourceIndex } = item;
  133 + if (!attribute) continue;
132 134 const [[timespan, value]] = data[attribute];
133 135 const record = getNeedUpdateValueByIndex(recordIndex, dataSourceIndex);
134 136 record.componentInfo.value = value;
135 137 record.componentInfo.updateTime = timespan;
136   - });
  138 + }
137 139 return;
138 140 } catch (error) {
139 141 throw Error(error as string);
... ...