Commit d2a6ff3f76f4bf268ec0cb94ea003807d29dbf8e

Authored by ww
1 parent 2e80187a

fix: 修复设备详情命令下发枚举类型无法下发&&优化命令下发逻辑

1 1 import { DeviceProfileModel } from '../../device/model/deviceModel';
2   -import { HistoryData } from './model';
  2 +import { DeviceAttributeItemType, HistoryData } from './model';
3 3 import { defHttp } from '/@/utils/http/axios';
4 4 import { isString } from '/@/utils/is';
5 5 import { OrderByEnum } from '/@/views/device/localtion/cpns/TimePeriodForm/config';
... ... @@ -38,7 +38,7 @@ export const getDeviceDataKeys = (id: string) => {
38 38 };
39 39 // 获取设备状态,在线 or 离线时间
40 40 export const getDeviceActiveTime = (entityId: string) => {
41   - return defHttp.get(
  41 + return defHttp.get<DeviceAttributeItemType[]>(
42 42 {
43 43 url: `/plugins/telemetry/DEVICE/${entityId}/values/attributes?keys=active`,
44 44 },
... ...
1 1 export interface HistoryData {
2 2 [key: string]: { ts: number; value: string }[];
3 3 }
  4 +
  5 +export interface DeviceAttributeItemType {
  6 + key: string;
  7 + value: boolean;
  8 + lastUpdateTs: number;
  9 +}
... ...
... ... @@ -13,7 +13,7 @@ import { ChildDeviceParams } from './model/deviceModel';
13 13 import { PaginationResult } from '/#/axios';
14 14 import { AlarmLogItem } from './model/deviceConfigModel';
15 15 import { omit } from 'lodash-es';
16   -import { CommandDeliveryWayEnum } from '/@/enums/toolEnum';
  16 +import { CommandDeliveryWayEnum } from '/@/enums/deviceEnum';
17 17 enum DeviceManagerApi {
18 18 /**
19 19 * 设备URL
... ...
1 1 import { BasicPageParams } from '/@/api/model/baseModel';
  2 +import { CommandTypeEnum, RPCCommandMethodEnum } from '/@/enums/deviceEnum';
2 3
3 4 export type TDeviceConfigPageQueryParam = BasicPageParams & TDeviceConfigParams;
4 5
... ... @@ -184,3 +185,10 @@ export interface Configuration {
184 185 export interface TransportConfiguration {
185 186 type: string;
186 187 }
  188 +
  189 +export interface RpcCommandType {
  190 + additionalInfo: { cmdType: CommandTypeEnum };
  191 + method: RPCCommandMethodEnum;
  192 + params: Recordable | string | number;
  193 + persistent: boolean;
  194 +}
... ...
... ... @@ -2,7 +2,7 @@ import { withInstall } from '/@/utils';
2 2 // @ts-ignore
3 3 import codeEditor from './src/CodeEditor.vue';
4 4 import jsonPreview from './src/json-preview/JsonPreview.vue';
5   -export { JSONEditor } from './src/JSONEditor';
  5 +export { JSONEditor, JSONEditorValidator, parseStringToJSON } from './src/JSONEditor';
6 6
7 7 export const CodeEditor = withInstall(codeEditor);
8 8 export const JsonPreview = withInstall(jsonPreview);
... ...
1   -import { FormSchema } from '../../../types/form';
  1 +import { FormSchema } from '/@/components/Form';
2 2 import { Specs, StructJSON } from '/@/api/device/model/modelOfMatterModel';
3 3 import { TransportTypeEnum } from '/@/enums/deviceEnum';
4 4 import { DataTypeEnum } from '/@/enums/objectModelEnum';
  5 +import { validateTCPCustomCommand } from '.';
5 6
6 7 export const getFormSchemas = ({
7 8 structJSON: structJson,
... ... @@ -143,6 +144,7 @@ export const getFormSchemas = ({
143 144 component: 'Input',
144 145 required,
145 146 defaultValue: serviceCommand,
  147 + rules: [{ validator: validateTCPCustomCommand }],
146 148 componentProps: {
147 149 placeholder: `请输入服务命令`,
148 150 },
... ...
... ... @@ -6,3 +6,45 @@ export enum TransportTypeEnum {
6 6 SNMP = 'SNMP',
7 7 TCP = 'TCP',
8 8 }
  9 +
  10 +export enum ReadAndWriteEnum {
  11 + READ = 'r',
  12 + READ_AND_WRITE = 'rw',
  13 +}
  14 +
  15 +export enum ServiceCallTypeEnum {
  16 + ASYNC = 'ASYNC',
  17 + SYNC = 'SYNC',
  18 +}
  19 +
  20 +export enum ServiceCallTypeNameEnum {
  21 + ASYNC = '异步',
  22 + SYNC = '同步',
  23 +}
  24 +
  25 +export enum CommandDeliveryWayEnum {
  26 + ONE_WAY = 'oneway',
  27 + TWO_WAY = 'twoway',
  28 +}
  29 +
  30 +export enum CommandDeliveryWayNameEnum {
  31 + ONE_WAY = '单向',
  32 + TWO_WAY = '双向',
  33 +}
  34 +
  35 +export enum CommandTypeEnum {
  36 + CUSTOM = 0,
  37 + SERVICE = 1,
  38 + ATTRIBUTE = 2,
  39 + API = 'api',
  40 +}
  41 +
  42 +export enum CommandTypeNameEnum {
  43 + CUSTOM = '自定义',
  44 + SERVICE = '服务',
  45 + ATTRIBUTE = '属性',
  46 +}
  47 +
  48 +export enum RPCCommandMethodEnum {
  49 + THINGSKIT = 'methodThingskit',
  50 +}
... ...
... ... @@ -154,16 +154,3 @@ export enum ExecutionActionNameEnum {
154 154 DEVICE_OUT = '设备输出',
155 155 MSG_NOTIFY = '告警输出',
156 156 }
157   -
158   -export enum CommandTypeEnum {
159   - CUSTOM = 0,
160   - SERVICE = 1,
161   - ATTRIBUTE = 2,
162   - API = 'api',
163   -}
164   -
165   -export enum CommandTypeNameEnum {
166   - CUSTOM = '自定义',
167   - SERVICE = '服务',
168   - ATTRIBUTE = '属性',
169   -}
... ...
... ... @@ -29,23 +29,3 @@ export enum BooleanStringEnum {
29 29 TRUE = 'true',
30 30 FALSE = 'false',
31 31 }
32   -
33   -export enum ReadAndWriteEnum {
34   - READ = 'r',
35   - READ_AND_WRITE = 'rw',
36   -}
37   -
38   -export enum ServiceCallTypeEnum {
39   - ASYNC = 'ASYNC',
40   - SYNC = 'SYNC',
41   -}
42   -
43   -export enum ServiceCallTypeNameEnum {
44   - ASYNC = '异步',
45   - SYNC = '同步',
46   -}
47   -
48   -export enum CommandDeliveryWayEnum {
49   - ONE_WAY = 'oneway',
50   - TWO_WAY = 'twoway',
51   -}
... ...
1   -import { FormProps, FormSchema, useComponentRegister } from '/@/components/Form';
  1 +import { FormSchema, useComponentRegister } from '/@/components/Form';
2 2 import { findDictItemByCode } from '/@/api/system/dict';
3 3 import { getGatewayDevice, queryDeviceProfileBy } from '/@/api/device/deviceManager';
4   -import { JSONEditorValidator } from '/@/components/CodeEditor/src/JSONEditor';
5 4 import { JSONEditor } from '/@/components/CodeEditor';
6 5 import { DeviceRecord, DeviceTypeEnum } from '/@/api/device/model/deviceModel';
7   -import { getModelServices } from '/@/api/device/modelOfMatter';
8   -import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
9   -import { h, toRaw, unref } from 'vue';
10   -import { CommandDeliveryWayEnum, ServiceCallTypeEnum } from '/@/enums/toolEnum';
  6 +import { h } from 'vue';
11 7 import { TaskTypeEnum } from '/@/views/task/center/config';
12 8 import { AddressTypeEnum } from '/@/views/task/center/components/PollCommandInput';
13 9 import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
... ... @@ -908,214 +904,3 @@ export const TokenSchemas: FormSchema[] = [
908 904 },
909 905 },
910 906 ];
911   -
912   -export enum ValueType {
913   - JSON = 'json',
914   - STRING = 'string',
915   -}
916   -
917   -export enum CommandFieldsEnum {
918   - COMMAND_TYPE = 'commandType',
919   - VALUE_TYPE = 'valueType',
920   - COMMAND_TEXT = 'commandText',
921   - COMAND_VALUE = 'commandValue',
922   - SERVICE = 'service',
923   - SERVICE_TYPE = 'service_type',
924   - TCP_SERVICE = 'tcpService',
925   - MODEL_INPUT = 'modelInput',
926   - CUSTOM_TYPE = 'customType',
927   -}
928   -
929   -export enum CommandType {
930   - CUSTOM = 'custom',
931   - SERVICE = 'service',
932   -}
933   -
934   -export const CommandSchemas = (
935   - transportType: TransportTypeEnum,
936   - deviceProfileId: string
937   -): FormSchema[] => {
938   - return [
939   - {
940   - field: CommandFieldsEnum.COMMAND_TYPE,
941   - component: 'RadioGroup',
942   - label: '下发类型',
943   - defaultValue: CommandType.CUSTOM,
944   - componentProps: ({ formActionType }) => {
945   - const { setFieldsValue } = formActionType;
946   - return {
947   - options: [
948   - { label: '自定义', value: CommandType.CUSTOM },
949   - { label: '服务', value: CommandType.SERVICE },
950   - ],
951   - onChange() {
952   - setFieldsValue({
953   - [CommandFieldsEnum.SERVICE]: null,
954   - [CommandFieldsEnum.MODEL_INPUT]: null,
955   - [CommandFieldsEnum.COMAND_VALUE]: null,
956   - [CommandFieldsEnum.COMMAND_TEXT]: null,
957   - });
958   - },
959   - };
960   - },
961   - },
962   - {
963   - field: CommandFieldsEnum.CUSTOM_TYPE,
964   - component: 'RadioGroup',
965   - label: '单向/双向',
966   - defaultValue: CommandDeliveryWayEnum.ONE_WAY,
967   - ifShow: ({ model }) => model[CommandFieldsEnum.COMMAND_TYPE] === CommandType.CUSTOM,
968   - componentProps: {
969   - options: [
970   - {
971   - label: '单向',
972   - value: CommandDeliveryWayEnum.ONE_WAY,
973   - },
974   - {
975   - label: '双向',
976   - value: CommandDeliveryWayEnum.TWO_WAY,
977   - },
978   - ],
979   - },
980   - },
981   - {
982   - field: CommandFieldsEnum.VALUE_TYPE,
983   - label: '命令类型',
984   - component: 'RadioGroup',
985   - ifShow: ({ model }) => model[CommandFieldsEnum.COMMAND_TYPE] === CommandType.CUSTOM,
986   - defaultValue: transportType === TransportTypeEnum.TCP ? ValueType.STRING : ValueType.JSON,
987   - componentProps: () => {
988   - const options: Record<'label' | 'value', string>[] = [];
989   - if (transportType === TransportTypeEnum.TCP) {
990   - options.push({ label: '字符串', value: ValueType.STRING });
991   - } else {
992   - options.push({ label: 'JSON', value: ValueType.JSON });
993   - }
994   - return {
995   - options,
996   - };
997   - },
998   - },
999   - {
1000   - field: CommandFieldsEnum.COMMAND_TEXT,
1001   - label: '命令',
1002   - ifShow: ({ model }) =>
1003   - model[CommandFieldsEnum.VALUE_TYPE] === ValueType.STRING &&
1004   - model[CommandFieldsEnum.COMMAND_TYPE] === CommandType.CUSTOM,
1005   - component: 'InputTextArea',
1006   - componentProps: {
1007   - autoSize: {
1008   - minRows: 3,
1009   - },
1010   - placeholder: '请输入命令内容',
1011   - },
1012   - dynamicRules: () => {
1013   - return [
1014   - {
1015   - required: false,
1016   - validator: (_, value) => {
1017   - const zg = /^[0-9a-zA-Z]*$/;
1018   - if (!zg.test(value)) {
1019   - return Promise.reject('输入的内容只能是字母和数字的组合');
1020   - } else {
1021   - return Promise.resolve();
1022   - }
1023   - },
1024   - },
1025   - ];
1026   - },
1027   - },
1028   - {
1029   - field: CommandFieldsEnum.COMAND_VALUE,
1030   - label: '命令',
1031   - component: 'JSONEditor',
1032   - colProps: { span: 20 },
1033   - changeEvent: 'update:value',
1034   - valueField: 'value',
1035   - rules: [...JSONEditorValidator()],
1036   - ifShow: ({ model }) =>
1037   - model[CommandFieldsEnum.VALUE_TYPE] === ValueType.JSON &&
1038   - model[CommandFieldsEnum.COMMAND_TYPE] === CommandType.CUSTOM,
1039   -
1040   - componentProps: {
1041   - height: 250,
1042   - },
1043   - },
1044   - {
1045   - field: CommandFieldsEnum.SERVICE,
1046   - label: '服务',
1047   - component: 'ApiSelect',
1048   - ifShow: ({ model }) => model[CommandFieldsEnum.COMMAND_TYPE] !== CommandType.CUSTOM,
1049   - rules: [{ required: true, message: '请选择服务' }],
1050   - componentProps: ({ formActionType }) => {
1051   - const { setFieldsValue, updateSchema } = formActionType;
1052   - return {
1053   - api: async () => {
1054   - try {
1055   - const result = await getModelServices({ deviceProfileId });
1056   - return result || [];
1057   - } catch (error) {
1058   - return [];
1059   - }
1060   - },
1061   - valueField: 'identifier',
1062   - labelField: 'functionName',
1063   - getPopupContainer: () => document.body,
1064   - onChange(value: string, options: ModelOfMatterParams) {
1065   - if (!value) return;
1066   -
1067   - const setValues = {
1068   - [CommandFieldsEnum.CUSTOM_TYPE]:
1069   - options.callType === ServiceCallTypeEnum.ASYNC
1070   - ? CommandDeliveryWayEnum.ONE_WAY
1071   - : CommandDeliveryWayEnum.TWO_WAY,
1072   - [CommandFieldsEnum.MODEL_INPUT]: null,
1073   - };
1074   -
1075   - if (transportType !== TransportTypeEnum.TCP) {
1076   - updateSchema({
1077   - field: CommandFieldsEnum.MODEL_INPUT,
1078   - componentProps: {
1079   - inputData: toRaw(unref(options.functionJson.inputData)),
1080   - },
1081   - });
1082   - } else {
1083   - Object.assign(setValues, {
1084   - [CommandFieldsEnum.TCP_SERVICE]:
1085   - options.functionJson?.inputData?.[0]?.serviceCommand,
1086   - });
1087   - }
1088   -
1089   - setFieldsValue(setValues);
1090   - },
1091   - };
1092   - },
1093   - },
1094   - {
1095   - field: CommandFieldsEnum.TCP_SERVICE,
1096   - component: 'Input',
1097   - label: '命令',
1098   - dynamicDisabled: true,
1099   - ifShow: ({ model }) =>
1100   - model[CommandFieldsEnum.SERVICE] &&
1101   - transportType === TransportTypeEnum.TCP &&
1102   - model[CommandFieldsEnum.COMMAND_TYPE] !== CommandType.CUSTOM,
1103   - },
1104   - {
1105   - field: CommandFieldsEnum.MODEL_INPUT,
1106   - component: 'ThingsModelForm',
1107   - label: '输入参数',
1108   - changeEvent: 'update:value',
1109   - valueField: 'value',
1110   - ifShow: ({ model }) =>
1111   - model[CommandFieldsEnum.SERVICE] &&
1112   - transportType !== TransportTypeEnum.TCP &&
1113   - model[CommandFieldsEnum.COMMAND_TYPE] !== CommandType.CUSTOM,
1114   - componentProps: {
1115   - formProps: {
1116   - wrapperCol: { span: 24 },
1117   - } as FormProps,
1118   - },
1119   - },
1120   - ];
1121   -};
... ...
  1 +import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  2 +import { getModelServices } from '/@/api/device/modelOfMatter';
  3 +import { FormProps, FormSchema, useComponentRegister } from '/@/components/Form';
  4 +import { validateTCPCustomCommand } from '/@/components/Form/src/components/ThingsModelForm';
  5 +import { JSONEditor, JSONEditorValidator } from '/@/components/CodeEditor';
  6 +import {
  7 + TransportTypeEnum,
  8 + CommandTypeNameEnum,
  9 + CommandTypeEnum,
  10 + ServiceCallTypeEnum,
  11 + CommandDeliveryWayEnum,
  12 + CommandDeliveryWayNameEnum,
  13 +} from '/@/enums/deviceEnum';
  14 +
  15 +export interface CommandDeliveryFormFieldType {
  16 + [CommandFieldsEnum.COMMAND_TYPE]: CommandTypeEnum;
  17 + [CommandFieldsEnum.TCP_COMMAND_VALUE]?: string;
  18 + [CommandFieldsEnum.COMAND_VALUE]?: string;
  19 + [CommandFieldsEnum.SERVICE]?: string;
  20 + [CommandFieldsEnum.MODEL_INPUT]?: ModelOfMatterParams;
  21 + [CommandFieldsEnum.CALL_TYPE]: CommandDeliveryWayEnum;
  22 +}
  23 +
  24 +export enum CommandFieldsEnum {
  25 + COMMAND_TYPE = 'commandType',
  26 + TCP_COMMAND_VALUE = 'tcpCommandValue',
  27 + COMAND_VALUE = 'commandValue',
  28 + SERVICE = 'service',
  29 + MODEL_INPUT = 'modelInput',
  30 + CALL_TYPE = 'callType',
  31 +
  32 + SERVICE_COMMAND = 'serviceCommand',
  33 +
  34 + SERVICE_OBJECT_MODEL = 'serviceObjectModel',
  35 +}
  36 +
  37 +useComponentRegister('JSONEditor', JSONEditor);
  38 +
  39 +export const CommandSchemas = (
  40 + transportType: TransportTypeEnum,
  41 + deviceProfileId: string
  42 +): FormSchema[] => {
  43 + return [
  44 + {
  45 + field: CommandFieldsEnum.COMMAND_TYPE,
  46 + component: 'RadioGroup',
  47 + label: '下发类型',
  48 + defaultValue: CommandTypeEnum.CUSTOM,
  49 + required: true,
  50 + componentProps: ({ formActionType }) => {
  51 + const { setFieldsValue } = formActionType;
  52 + return {
  53 + options: [
  54 + { label: CommandTypeNameEnum.CUSTOM, value: CommandTypeEnum.CUSTOM },
  55 + { label: CommandTypeNameEnum.SERVICE, value: CommandTypeEnum.SERVICE },
  56 + ],
  57 + onChange() {
  58 + setFieldsValue({
  59 + [CommandFieldsEnum.SERVICE]: null,
  60 + [CommandFieldsEnum.MODEL_INPUT]: null,
  61 + [CommandFieldsEnum.COMAND_VALUE]: null,
  62 + [CommandFieldsEnum.TCP_COMMAND_VALUE]: null,
  63 + });
  64 + },
  65 + };
  66 + },
  67 + },
  68 + {
  69 + field: CommandFieldsEnum.CALL_TYPE,
  70 + component: 'RadioGroup',
  71 + label: '单向/双向',
  72 + required: true,
  73 + defaultValue: CommandDeliveryWayEnum.ONE_WAY,
  74 + ifShow: ({ model }) => model[CommandFieldsEnum.COMMAND_TYPE] === CommandTypeEnum.CUSTOM,
  75 + componentProps: {
  76 + options: Object.keys(CommandDeliveryWayEnum).map((key) => ({
  77 + label: CommandDeliveryWayNameEnum[key],
  78 + value: CommandDeliveryWayEnum[key],
  79 + })),
  80 + },
  81 + },
  82 + {
  83 + field: CommandFieldsEnum.TCP_COMMAND_VALUE,
  84 + label: '命令',
  85 + required: true,
  86 + ifShow: ({ model }) =>
  87 + transportType === TransportTypeEnum.TCP &&
  88 + model[CommandFieldsEnum.COMMAND_TYPE] === CommandTypeEnum.CUSTOM,
  89 + component: 'Input',
  90 + rules: [{ validator: validateTCPCustomCommand }],
  91 + componentProps: {
  92 + placeholder: '请输入命令',
  93 + },
  94 + },
  95 + {
  96 + field: CommandFieldsEnum.COMAND_VALUE,
  97 + label: '命令',
  98 + component: 'JSONEditor',
  99 + colProps: { span: 20 },
  100 + changeEvent: 'update:value',
  101 + valueField: 'value',
  102 + required: true,
  103 + rules: JSONEditorValidator(),
  104 + ifShow: ({ model }) =>
  105 + transportType !== TransportTypeEnum.TCP &&
  106 + model[CommandFieldsEnum.COMMAND_TYPE] === CommandTypeEnum.CUSTOM,
  107 + componentProps: {
  108 + height: 250,
  109 + },
  110 + },
  111 + {
  112 + field: CommandFieldsEnum.SERVICE,
  113 + label: '服务',
  114 + component: 'ApiSelect',
  115 + required: true,
  116 + ifShow: ({ model }) => model[CommandFieldsEnum.COMMAND_TYPE] !== CommandTypeEnum.CUSTOM,
  117 + rules: [{ required: true, message: '请选择服务' }],
  118 + componentProps: ({ formActionType }) => {
  119 + const { setFieldsValue } = formActionType;
  120 + return {
  121 + api: getModelServices,
  122 + params: {
  123 + deviceProfileId,
  124 + },
  125 + valueField: 'identifier',
  126 + labelField: 'functionName',
  127 + getPopupContainer: () => document.body,
  128 + placeholder: '请选择服务',
  129 + onChange(
  130 + value: string,
  131 + options: ModelOfMatterParams & Record<'label' | 'value', string>
  132 + ) {
  133 + if (!value) return;
  134 + setFieldsValue({
  135 + [CommandFieldsEnum.CALL_TYPE]:
  136 + options.callType === ServiceCallTypeEnum.ASYNC
  137 + ? CommandDeliveryWayEnum.ONE_WAY
  138 + : CommandDeliveryWayEnum.TWO_WAY,
  139 + [CommandFieldsEnum.MODEL_INPUT]: null,
  140 + [CommandFieldsEnum.SERVICE_OBJECT_MODEL]: Object.assign(options, {
  141 + functionName: options.label,
  142 + identifier: options.value,
  143 + }),
  144 + });
  145 + },
  146 + };
  147 + },
  148 + },
  149 + {
  150 + field: CommandFieldsEnum.SERVICE_OBJECT_MODEL,
  151 + label: '服务物模型',
  152 + component: 'Input',
  153 + ifShow: false,
  154 + },
  155 + {
  156 + field: CommandFieldsEnum.MODEL_INPUT,
  157 + component: 'Input',
  158 + label: '输入参数',
  159 + changeEvent: 'update:value',
  160 + valueField: 'value',
  161 + ifShow: ({ model }) =>
  162 + model[CommandFieldsEnum.SERVICE] &&
  163 + model[CommandFieldsEnum.SERVICE_OBJECT_MODEL] &&
  164 + model[CommandFieldsEnum.COMMAND_TYPE] !== CommandTypeEnum.CUSTOM,
  165 + componentProps: {
  166 + formProps: {
  167 + wrapperCol: { span: 24 },
  168 + } as FormProps,
  169 + },
  170 + slot: 'serviceCommand',
  171 + },
  172 + ];
  173 +};
... ...
  1 +export { default as CommandDeliveryModal } from './index.vue';
... ...
  1 +<template>
  2 + <BasicModal
  3 + title="命令下发"
  4 + :width="650"
  5 + @register="registerModal"
  6 + @ok="handleOk"
  7 + @cancel="handleCancel"
  8 + >
  9 + <BasicForm @register="registerForm">
  10 + <template #serviceCommand="{ field, model }">
  11 + <ThingsModelForm
  12 + :disabled="deviceDetail?.transportType === TransportTypeEnum.TCP"
  13 + ref="thingsModelFormRef"
  14 + v-model:value="model[field]"
  15 + :key="model[CommandFieldsEnum.SERVICE_OBJECT_MODEL]?.identifier"
  16 + :inputData="model[CommandFieldsEnum.SERVICE_OBJECT_MODEL]?.functionJson?.inputData"
  17 + :transportType="deviceDetail?.transportType"
  18 + />
  19 + </template>
  20 + </BasicForm>
  21 + </BasicModal>
  22 +</template>
  23 +<script lang="ts" setup>
  24 + import { nextTick, ref, unref } from 'vue';
  25 + import { BasicForm, ThingsModelForm, useForm } from '/@/components/Form';
  26 + import { CommandDeliveryFormFieldType, CommandFieldsEnum, CommandSchemas } from './config';
  27 + import { useMessage } from '/@/hooks/web/useMessage';
  28 + import { DeviceRecord } from '/@/api/device/model/deviceModel';
  29 + import { CommandDeliveryWayEnum } from '/@/enums/deviceEnum';
  30 + import { CommandTypeEnum, RPCCommandMethodEnum, TransportTypeEnum } from '/@/enums/deviceEnum';
  31 + import { BasicModal, useModalInner } from '/@/components/Modal';
  32 + import { getDeviceActiveTime } from '/@/api/alarm/position';
  33 + import { RpcCommandType } from '/@/api/device/model/deviceConfigModel';
  34 + import { parseStringToJSON } from '/@/components/CodeEditor';
  35 + import { commandIssuanceApi } from '/@/api/device/deviceManager';
  36 +
  37 + defineEmits(['register']);
  38 +
  39 + const thingsModelFormRef = ref<InstanceType<typeof ThingsModelForm>>();
  40 + const deviceDetail = ref<DeviceRecord>();
  41 +
  42 + const [registerModal, { setModalProps }] = useModalInner(
  43 + (params: ModalParamsType<DeviceRecord>) => {
  44 + const { record } = params;
  45 + deviceDetail.value = record;
  46 + setProps({
  47 + schemas: CommandSchemas(record.transportType as TransportTypeEnum, record.deviceProfileId),
  48 + });
  49 + }
  50 + );
  51 +
  52 + const { createMessage } = useMessage();
  53 +
  54 + const [registerForm, { setProps, getFieldsValue, validate, resetFields, clearValidate }] =
  55 + useForm({
  56 + labelWidth: 120,
  57 + baseColProps: { span: 20 },
  58 + labelAlign: 'right',
  59 + showSubmitButton: false,
  60 + showResetButton: false,
  61 + });
  62 +
  63 + const handleCancel = async () => {
  64 + await resetFields();
  65 + await nextTick();
  66 + await clearValidate();
  67 + };
  68 +
  69 + const handleValidate = async () => {
  70 + await validate();
  71 + await unref(thingsModelFormRef)?.validate?.();
  72 + };
  73 +
  74 + const handleValidateDeviceActive = async (): Promise<boolean> => {
  75 + const result = await getDeviceActiveTime(unref(deviceDetail)!.tbDeviceId);
  76 + const [firstItem] = result;
  77 + return !!firstItem.value;
  78 + };
  79 +
  80 + const handleCommandParams = (
  81 + values: CommandDeliveryFormFieldType,
  82 + serviceCommand: Recordable
  83 + ) => {
  84 + const { commandType } = values;
  85 +
  86 + const isTcpDevice = unref(deviceDetail)?.transportType === TransportTypeEnum.TCP;
  87 + if (commandType === CommandTypeEnum.CUSTOM) {
  88 + if (isTcpDevice) {
  89 + return values.tcpCommandValue;
  90 + }
  91 + return parseStringToJSON(values.commandValue!).json;
  92 + } else {
  93 + if (isTcpDevice) return Reflect.get(serviceCommand, CommandFieldsEnum.SERVICE_COMMAND);
  94 + return serviceCommand;
  95 + }
  96 + };
  97 +
  98 + const handleOk = async () => {
  99 + await handleValidate();
  100 +
  101 + try {
  102 + setModalProps({ loading: true, confirmLoading: true });
  103 +
  104 + const values = getFieldsValue() as CommandDeliveryFormFieldType;
  105 + const { callType, commandType } = values;
  106 + const serviceCommand = unref(thingsModelFormRef)?.getFieldsValue() || {};
  107 +
  108 + if (callType === CommandDeliveryWayEnum.TWO_WAY && !(await handleValidateDeviceActive())) {
  109 + createMessage.warn('当前设备不在线');
  110 + return;
  111 + }
  112 +
  113 + const rpcCommands: RpcCommandType = {
  114 + additionalInfo: {
  115 + cmdType:
  116 + commandType === CommandTypeEnum.CUSTOM
  117 + ? CommandTypeEnum.CUSTOM
  118 + : CommandTypeEnum.SERVICE,
  119 + },
  120 + method: RPCCommandMethodEnum.THINGSKIT,
  121 + persistent: true,
  122 + params: handleCommandParams(values, serviceCommand),
  123 + };
  124 +
  125 + await commandIssuanceApi(callType, unref(deviceDetail)!.tbDeviceId, rpcCommands);
  126 +
  127 + createMessage.success('命令下发成功');
  128 + } finally {
  129 + setModalProps({ loading: false, confirmLoading: false });
  130 + }
  131 + };
  132 +</script>
  133 +<style scoped lang="less"></style>
... ...
1   -<template>
2   - <div class="tabs-detail">
3   - <div>
4   - <BasicForm @register="registerForm" />
5   - <Space class="w-full justify-end py-2" justify="end">
6   - <Button :loading="loading" type="primary" @click="handleOk" class="mr-2">确定</Button>
7   - <Button type="default" @click="handleCancel" class="mr-2">重置</Button>
8   - </Space>
9   - </div>
10   - </div>
11   -</template>
12   -<script lang="ts" setup>
13   - import { nextTick, ref } from 'vue';
14   - import { BasicForm, useForm } from '/@/components/Form';
15   - import { CommandFieldsEnum, CommandSchemas, CommandType, ValueType } from '../../config/data';
16   - import { commandIssuanceApi } from '/@/api/device/deviceManager';
17   - import { useMessage } from '/@/hooks/web/useMessage';
18   - import { Button } from '/@/components/Button';
19   - import { Space } from 'ant-design-vue';
20   - import { DeviceRecord } from '/@/api/device/model/deviceModel';
21   - import { parseStringToJSON } from '/@/components/CodeEditor/src/JSONEditor';
22   - import { CommandDeliveryWayEnum } from '/@/enums/toolEnum';
23   - import { TransportTypeEnum } from '/@/enums/deviceEnum';
24   -
25   - defineEmits(['register']);
26   -
27   - const props = defineProps<{
28   - deviceDetail: DeviceRecord;
29   - }>();
30   -
31   - const { createMessage } = useMessage();
32   - const loading = ref(false);
33   -
34   - const [registerForm, { getFieldsValue, validate, resetFields, clearValidate }] = useForm({
35   - labelWidth: 120,
36   - schemas: CommandSchemas(
37   - props.deviceDetail.deviceProfile.transportType as TransportTypeEnum,
38   - props.deviceDetail.deviceProfileId
39   - ),
40   - baseColProps: { span: 20 },
41   - labelAlign: 'right',
42   - showSubmitButton: false,
43   - showResetButton: false,
44   - });
45   -
46   - const handleCancel = async () => {
47   - await resetFields();
48   - await nextTick();
49   - await clearValidate();
50   - };
51   -
52   - const handleOk = async () => {
53   - loading.value = true;
54   - try {
55   - // 验证
56   - const valid = await validate();
57   - if (!valid) return;
58   - // 收集表单数据
59   - const field = getFieldsValue();
60   - let command: Recordable = {
61   - persistent: true,
62   - method: 'methodThingskit',
63   - params: field[CommandFieldsEnum.COMMAND_TEXT],
64   - };
65   -
66   - if (field[CommandFieldsEnum.COMMAND_TYPE] === CommandType.CUSTOM) {
67   - if (field[CommandFieldsEnum.VALUE_TYPE] === ValueType.JSON) {
68   - const { json } = parseStringToJSON(field.commandValue);
69   - command.params = json;
70   - }
71   - } else {
72   - const { transportType } = props.deviceDetail.deviceProfile;
73   - command.params =
74   - transportType === TransportTypeEnum.TCP
75   - ? field[CommandFieldsEnum.TCP_SERVICE]
76   - : {
77   - [field[CommandFieldsEnum.SERVICE]]: field[CommandFieldsEnum.MODEL_INPUT],
78   - };
79   - command.additionalInfo = { cmdType: 1 };
80   - }
81   - commandIssuanceApi(
82   - field[CommandFieldsEnum.CUSTOM_TYPE] as CommandDeliveryWayEnum,
83   - props.deviceDetail.tbDeviceId,
84   - command
85   - )
86   - .then((res) => {
87   - if (!res) return;
88   - createMessage.success('命令下发成功');
89   - loading.value = true;
90   - // 请求
91   - handleCancel();
92   - })
93   - .catch((e) => {
94   - if (e?.message) {
95   - createMessage.error(e?.message);
96   - }
97   - handleCancel();
98   - })
99   - .finally(() => {
100   - setTimeout(() => {
101   - loading.value = false;
102   - }, 300);
103   - });
104   - } catch (e) {
105   - throw e;
106   - } finally {
107   - loading.value = false;
108   - }
109   - };
110   -</script>
111   -<style scoped lang="less">
112   - .jsoneditor-transform {
113   - background-position: -144px -96px;
114   - display: none !important;
115   - }
116   -
117   - .tabs-detail:deep(.object-model-validate-form) {
118   - > .ant-row {
119   - @apply w-full;
120   - }
121   - }
122   -</style>
... ... @@ -18,7 +18,8 @@
18 18 import { useGlobSetting } from '/@/hooks/setting';
19 19 import { ModeSwitchButton, EnumTableCardMode } from '/@/components/Widget';
20 20 import { toRaw } from 'vue';
21   - import { DataActionModeEnum, ReadAndWriteEnum } from '/@/enums/toolEnum';
  21 + import { DataActionModeEnum } from '/@/enums/toolEnum';
  22 + import { ReadAndWriteEnum } from '/@/enums/deviceEnum';
22 23 import { ObjectModelCommandDeliveryModal } from './ObjectModelCommandDeliveryModal';
23 24 import { ModalParamsType } from '/#/utils';
24 25 import { AreaChartOutlined } from '@ant-design/icons-vue';
... ...
... ... @@ -6,7 +6,7 @@
6 6 <template #toolbar>
7 7 <Space>
8 8 <Authority value="api:yt:device:rpc">
9   - <Button type="primary" @click="openModal(true)">命令下发</Button>
  9 + <Button type="primary" @click="handleOpenModal">命令下发</Button>
10 10 </Authority>
11 11 </Space>
12 12 </template>
... ... @@ -24,16 +24,7 @@
24 24 </template>
25 25 </BasicTable>
26 26
27   - <BasicModal
28   - @register="registerCommandIssuanceModal"
29   - width="700px"
30   - title="命令下发"
31   - :showOkBtn="false"
32   - cancelText="关闭"
33   - :footer="null"
34   - >
35   - <CommandIssuance :deviceDetail="deviceDetail" />
36   - </BasicModal>
  27 + <CommandDeliveryModal @register="registerCommandDeliverModal" :deviceDetail="deviceDetail" />
37 28 </template>
38 29 <script lang="ts" setup>
39 30 import { h } from 'vue';
... ... @@ -43,9 +34,10 @@
43 34 import { Button, Modal, Space } from 'ant-design-vue';
44 35 import { JsonPreview } from '/@/components/CodeEditor';
45 36 import { DeviceRecord } from '/@/api/device/model/deviceModel';
46   - import { BasicModal, useModal } from '/@/components/Modal';
47   - import CommandIssuance from '../CommandIssuance.vue';
  37 + import { useModal } from '/@/components/Modal';
  38 + import { CommandDeliveryModal } from '../CommandDeliveryModal';
48 39 import { Authority } from '/@/components/Authority';
  40 + import { DataActionModeEnum } from '/@/enums/toolEnum';
49 41
50 42 const props = defineProps({
51 43 fromId: {
... ... @@ -58,7 +50,7 @@
58 50 },
59 51 });
60 52
61   - const [registerCommandIssuanceModal, { openModal }] = useModal();
  53 + const [registerCommandDeliverModal, { openModal }] = useModal();
62 54
63 55 const [registerTable] = useTable({
64 56 api: deviceCommandRecordGetQuery,
... ... @@ -79,6 +71,7 @@
79 71 },
80 72 useSearchForm: true,
81 73 });
  74 +
82 75 const commonModalInfo = (title, value) => {
83 76 Modal.info({
84 77 title,
... ... @@ -86,14 +79,23 @@
86 79 content: h(JsonPreview, { data: value }),
87 80 });
88 81 };
  82 +
89 83 const handleRecordContent = (record) => {
90 84 if (!record?.request?.body) return;
91 85 if (Object.prototype.toString.call(record?.request?.body) !== '[object Object]') return;
92 86 const jsonParams = record?.request?.body?.params;
93 87 commonModalInfo('命令下发内容', jsonParams);
94 88 };
  89 +
95 90 const handleRecordResponseContent = (record) => {
96 91 const jsonParams = record?.response;
97 92 commonModalInfo('响应内容', jsonParams);
98 93 };
  94 +
  95 + function handleOpenModal() {
  96 + openModal(true, {
  97 + mode: DataActionModeEnum.READ,
  98 + record: props.deviceDetail,
  99 + } as ModalParamsType<DeviceRecord>);
  100 + }
99 101 </script>
... ...
1 1 import { FormSchema, useComponentRegister } from '/@/components/Form';
2 2 import {
3   - CommandTypeEnum,
4   - CommandTypeNameEnum,
5 3 ExecutionActionEnum,
6 4 ExecutionActionNameEnum,
7 5 TriggerEntityTypeEnum,
8 6 TriggerEntityTypeNameEnum,
9 7 } from '/@/enums/linkedgeEnum';
  8 +import { CommandTypeEnum, CommandTypeNameEnum } from '/@/enums/deviceEnum';
10 9 import AlarmProfileSelect from './AlarmProfileSelect.vue';
11 10 import {
12 11 byOrganizationIdGetMasterDevice,
... ... @@ -21,7 +20,7 @@ import { findDictItemByCode } from '/@/api/system/dict';
21 20 import { DictEnum } from '/@/enums/dictEnum';
22 21 import { getDeviceProfile } from '/@/api/alarm/position';
23 22 import { createPickerSearch } from '/@/utils/pickerSearch';
24   -import { ServiceCallTypeEnum, ServiceCallTypeNameEnum } from '/@/enums/toolEnum';
  23 +import { ServiceCallTypeEnum, ServiceCallTypeNameEnum } from '/@/enums/deviceEnum';
25 24 import { DeviceTypeEnum } from '../../../dataFlow/cpns/config';
26 25 import { getModelServices } from '/@/api/device/modelOfMatter';
27 26 import { ModelOfMatterParams, StructJSON } from '/@/api/device/model/modelOfMatterModel';
... ...
... ... @@ -5,8 +5,8 @@ import { FlipFlopConditionType } from '../FlipFlop/types';
5 5 import { DeviceModelOfMatterAttrs, DeviceTypeEnum } from '/@/api/device/model/deviceModel';
6 6 import { FormActionType, ThingsModelForm } from '/@/components/Form';
7 7 import { AlarmLevelEnum } from '/@/enums/alarmEnum';
8   -import { CommandTypeEnum, ExecutionActionEnum, TriggerEntityTypeEnum } from '/@/enums/linkedgeEnum';
9   -import { ServiceCallTypeEnum } from '/@/enums/toolEnum';
  8 +import { ExecutionActionEnum, TriggerEntityTypeEnum } from '/@/enums/linkedgeEnum';
  9 +import { CommandTypeEnum, ServiceCallTypeEnum } from '/@/enums/deviceEnum';
10 10 import { TransportTypeEnum } from '/@/enums/deviceEnum';
11 11
12 12 export interface ExecutionActionListRefItemType {
... ...
... ... @@ -7,7 +7,8 @@ import {
7 7 ExecutionActionFormItemRecordType,
8 8 ExecutionActionListRefItemType,
9 9 } from './type';
10   -import { CommandTypeEnum, ExecutionActionEnum } from '/@/enums/linkedgeEnum';
  10 +import { ExecutionActionEnum } from '/@/enums/linkedgeEnum';
  11 +import { CommandTypeEnum } from '/@/enums/deviceEnum';
11 12 import { useJsonParse } from '/@/hooks/business/useJsonParse';
12 13 import { createNewExecutionActionItem } from '.';
13 14 import { FormFieldsEnum } from './config';
... ...
... ... @@ -3,7 +3,7 @@ import { TaskTypeEnum } from '/@/views/task/center/config';
3 3 import { genModbusCommand } from '/@/api/task';
4 4 import { useMessage } from '/@/hooks/web/useMessage';
5 5 import { SingleToHex } from '/@/views/device/list/cpns/tabs/ObjectModelCommandDeliveryModal/config';
6   -import { CommandTypeEnum } from '/@/enums/linkedgeEnum';
  6 +import { CommandTypeEnum } from '/@/enums/deviceEnum';
7 7 import { TransportTypeEnum } from '/@/enums/deviceEnum';
8 8
9 9 const getArray = (values) => {
... ...
... ... @@ -14,7 +14,7 @@ import { DataActionModeEnum } from '/@/enums/toolEnum';
14 14 import { TaskTypeEnum } from '/@/views/task/center/config';
15 15 import { createPickerSearch } from '/@/utils/pickerSearch';
16 16 import { DataTypeEnum } from '/@/enums/objectModelEnum';
17   -import { CommandTypeEnum } from '/@/enums/linkedgeEnum';
  17 +import { CommandTypeEnum } from '/@/enums/deviceEnum';
18 18 import { TransportTypeEnum } from '/@/enums/deviceEnum';
19 19
20 20 useComponentRegister('OrgTreeSelect', OrgTreeSelect);
... ...
... ... @@ -2,8 +2,7 @@ import { ref } from 'vue';
2 2 import { DataSource } from '../../palette/types';
3 3 import { sendCommandOneway, sendCommandTwoway } from '/@/api/dataBoard';
4 4 import { useMessage } from '/@/hooks/web/useMessage';
5   -import { ServiceCallTypeEnum } from '/@/enums/toolEnum';
6   -import { TransportTypeEnum } from '/@/enums/deviceEnum';
  5 +import { TransportTypeEnum, ServiceCallTypeEnum } from '/@/enums/deviceEnum';
7 6
8 7 const { createMessage } = useMessage();
9 8 export function useSendCommand() {
... ...