Commit cd0263e1511050325cb6f1d67777dc2752f95275
Merge branch 'feat/object-model' into 'main_dev'
feat:支持标准modbus_rtu解析及命令下发 See merge request yunteng/thingskit-scada!216
Showing
39 changed files
with
1305 additions
and
763 deletions
1 | import type { DeviceActiveType, DeviceAttributeItemType, DeviceItemType, DeviceProfileItemType, OrganizationItemType, ProductsDetailWithThingsModelType, RpcCommandType, SendValue, ThingsModel, ThingsModelItemType } from './model' | 1 | import type { DeviceActiveType, DeviceAttributeItemType, DeviceItemType, DeviceProfileItemType, OrganizationItemType, ProductsDetailWithThingsModelType, RpcCommandType, SendValue, ThingsModel, ThingsModelItemType } from './model' |
2 | import { CommandWayEnum } from '@/enums/commandEnum' | 2 | import { CommandWayEnum } from '@/enums/commandEnum' |
3 | -import type { DeviceTypeEnum } from '@/enums/datasource' | ||
4 | -import { FunctionTypeEnum } from '@/enums/datasource' | 3 | +import type { DeviceTypeEnum } from '@/enums/deviceEnum' |
4 | +import { FunctionTypeEnum } from '@/enums/objectModelEnum' | ||
5 | import { isShareMode } from '@/utils/env' | 5 | import { isShareMode } from '@/utils/env' |
6 | import { defHttp } from '@/utils/http' | 6 | import { defHttp } from '@/utils/http' |
7 | 7 | ||
@@ -24,6 +24,7 @@ enum Api { | @@ -24,6 +24,7 @@ enum Api { | ||
24 | GET_LIST_BY_CONFIGURATION_ID = '/configuration/center/getListByConfigurationId', | 24 | GET_LIST_BY_CONFIGURATION_ID = '/configuration/center/getListByConfigurationId', |
25 | 25 | ||
26 | GET_PRODUCTS_DETAIL_WITH_THINGS_MODEL = '/things_model/batch/get_tsl', | 26 | GET_PRODUCTS_DETAIL_WITH_THINGS_MODEL = '/things_model/batch/get_tsl', |
27 | + | ||
27 | } | 28 | } |
28 | 29 | ||
29 | export interface GenModbusCommandType { | 30 | export interface GenModbusCommandType { |
@@ -33,6 +34,7 @@ export interface GenModbusCommandType { | @@ -33,6 +34,7 @@ export interface GenModbusCommandType { | ||
33 | registerAddress: number | 34 | registerAddress: number |
34 | registerNumber?: number | 35 | registerNumber?: number |
35 | registerValues?: number[] | 36 | registerValues?: number[] |
37 | + hexByteOrderEnum?: string | ||
36 | } | 38 | } |
37 | 39 | ||
38 | export const getDeviceProfile = (deviceType?: DeviceTypeEnum) => { | 40 | export const getDeviceProfile = (deviceType?: DeviceTypeEnum) => { |
@@ -128,6 +130,17 @@ export const getDeviceActiveTime = (entityId: string) => { | @@ -128,6 +130,17 @@ export const getDeviceActiveTime = (entityId: string) => { | ||
128 | ) | 130 | ) |
129 | } | 131 | } |
130 | 132 | ||
133 | +export const getDeviceTelemetryValue = (params: { entityId: string; keys: string }) => { | ||
134 | + return defHttp.get({ | ||
135 | + url: `${Api.GET_DEVICE_ACTIVE}${params.entityId}/values/timeseries`, | ||
136 | + params: { | ||
137 | + keys: params.keys, | ||
138 | + }, | ||
139 | + }, { | ||
140 | + joinPrefix: false, | ||
141 | + }) | ||
142 | +} | ||
143 | + | ||
131 | // 获取设备详情 | 144 | // 获取设备详情 |
132 | export const getDeviceInfo = (deviceId: string) => { | 145 | export const getDeviceInfo = (deviceId: string) => { |
133 | return defHttp.get<DeviceItemType>( | 146 | return defHttp.get<DeviceItemType>( |
1 | -import type { DataTypeEnum, FunctionTypeEnum, TransportTypeEnum } from '@/enums/datasource' | 1 | +import type { CommandCallWayEnum } from '@/enums/commandEnum' |
2 | +import type { TCPProtocolTypeEnum, TransportTypeEnum } from '@/enums/deviceEnum' | ||
3 | +import type { DataTypeEnum, ExtendDescOperationTypeEnum, FunctionTypeEnum, OriginalDataTypeEnum } from '@/enums/objectModelEnum' | ||
2 | 4 | ||
3 | export interface DeviceProfileItemType { | 5 | export interface DeviceProfileItemType { |
4 | id: string | 6 | id: string |
@@ -41,6 +43,7 @@ export interface Configuration { | @@ -41,6 +43,7 @@ export interface Configuration { | ||
41 | 43 | ||
42 | export interface TransportConfiguration { | 44 | export interface TransportConfiguration { |
43 | type: string | 45 | type: string |
46 | + protocol: TCPProtocolTypeEnum | ||
44 | } | 47 | } |
45 | 48 | ||
46 | export interface ProvisionConfiguration { | 49 | export interface ProvisionConfiguration { |
@@ -116,6 +119,10 @@ export interface DeviceItemType { | @@ -116,6 +119,10 @@ export interface DeviceItemType { | ||
116 | deviceType: string | 119 | deviceType: string |
117 | alarmStatus: number | 120 | alarmStatus: number |
118 | enable: boolean | 121 | enable: boolean |
122 | + deviceProfile: { | ||
123 | + transportType: TransportTypeEnum | ||
124 | + profileData: ProfileData | ||
125 | + } | ||
119 | 126 | ||
120 | transportType: TransportTypeEnum | 127 | transportType: TransportTypeEnum |
121 | } | 128 | } |
@@ -135,10 +142,14 @@ export interface ThingsModelItemType { | @@ -135,10 +142,14 @@ export interface ThingsModelItemType { | ||
135 | } | 142 | } |
136 | 143 | ||
137 | export interface ExtensionDesc { | 144 | export interface ExtensionDesc { |
138 | - zoomFactor?: number | ||
139 | - actionType?: string | ||
140 | - dataType: string | ||
141 | - registerAddress: number | 145 | + writeOnly?: boolean |
146 | + bitMask?: number | ||
147 | + operationType: ExtendDescOperationTypeEnum | ||
148 | + originalDataType: OriginalDataTypeEnum | ||
149 | + registerAddress: string | ||
150 | + scaling?: number | ||
151 | + valueRange?: Record<'min' | 'max', number> | ||
152 | + registerCount?: number | ||
142 | } | 153 | } |
143 | 154 | ||
144 | export interface Detail { | 155 | export interface Detail { |
@@ -146,7 +157,7 @@ export interface Detail { | @@ -146,7 +157,7 @@ export interface Detail { | ||
146 | } | 157 | } |
147 | 158 | ||
148 | export interface DataType { | 159 | export interface DataType { |
149 | - type: string | 160 | + type: DataTypeEnum |
150 | specs: Specs | StructJSON[] | 161 | specs: Specs | StructJSON[] |
151 | specsList: Specs[] | 162 | specsList: Specs[] |
152 | } | 163 | } |
@@ -163,6 +174,7 @@ export interface Specs { | @@ -163,6 +174,7 @@ export interface Specs { | ||
163 | name?: string | 174 | name?: string |
164 | value?: any | 175 | value?: any |
165 | dataType?: DataTypeEnum | 176 | dataType?: DataTypeEnum |
177 | + step?: number | ||
166 | } | 178 | } |
167 | 179 | ||
168 | export interface ValueRange { | 180 | export interface ValueRange { |
@@ -207,6 +219,8 @@ export interface Tsl { | @@ -207,6 +219,8 @@ export interface Tsl { | ||
207 | functionName: string | 219 | functionName: string |
208 | identifier: string | 220 | identifier: string |
209 | accessMode: string | 221 | accessMode: string |
222 | + functionType: FunctionTypeEnum | ||
223 | + callType: CommandCallWayEnum | ||
210 | specs: { | 224 | specs: { |
211 | dataType: DataType | 225 | dataType: DataType |
212 | } | 226 | } |
1 | import type { ThingsModelItemType } from '@/api/device/model' | 1 | import type { ThingsModelItemType } from '@/api/device/model' |
2 | import type { ImageSelectorDataType } from '@/core/Library/components/ImageSelector' | 2 | import type { ImageSelectorDataType } from '@/core/Library/components/ImageSelector' |
3 | -import type { CommandWayEnum } from '@/enums/commandEnum' | ||
4 | -import type { ActRangListItemTypeEnum, ActTypeEnum, AggregateTypeEnum, CommandDeliveryWayEnum, DeviceTypeEnum, EventActionTypeEnum, EventTypeEnum, SocketSubscriberEnum } from '@/enums/datasource' | 3 | +import type { CommandDeliveryWayEnum, CommandWayEnum } from '@/enums/commandEnum' |
4 | +import type { ActRangListItemTypeEnum, ActTypeEnum, AggregateTypeEnum, EventActionTypeEnum, EventTypeEnum, SocketSubscriberEnum } from '@/enums/datasource' | ||
5 | +import type { DeviceTypeEnum } from '@/enums/deviceEnum' | ||
5 | 6 | ||
6 | export enum DeleteNodeDataTypeEnum { | 7 | export enum DeleteNodeDataTypeEnum { |
7 | DATASOURCE = 'DATASOURCE', | 8 | DATASOURCE = 'DATASOURCE', |
@@ -2,7 +2,9 @@ import type { FormSchema } from '@/components/Form' | @@ -2,7 +2,9 @@ import type { FormSchema } from '@/components/Form' | ||
2 | import { ComponentEnum } from '@/components/Form/src/enum' | 2 | import { ComponentEnum } from '@/components/Form/src/enum' |
3 | import type { BasicColumn } from '@/components/Table' | 3 | import type { BasicColumn } from '@/components/Table' |
4 | import type { CommandWayEnum } from '@/enums/commandEnum' | 4 | import type { CommandWayEnum } from '@/enums/commandEnum' |
5 | -import { ActTypeEnum, type CodeTypeEnum, type ContentDataFieldsEnum, type DeviceTypeEnum } from '@/enums/datasource' | 5 | +import { ActTypeEnum, type ContentDataFieldsEnum } from '@/enums/datasource' |
6 | +import type { DeviceTypeEnum, TCPProtocolTypeEnum } from '@/enums/deviceEnum' | ||
7 | + | ||
6 | export enum TableColumnFieldEnum { | 8 | export enum TableColumnFieldEnum { |
7 | DEVICE_ID = 'deviceId', | 9 | DEVICE_ID = 'deviceId', |
8 | WAY = 'way', | 10 | WAY = 'way', |
@@ -15,7 +17,7 @@ export interface TableRecordItemType { | @@ -15,7 +17,7 @@ export interface TableRecordItemType { | ||
15 | [TableColumnFieldEnum.WAY]?: Nullable<CommandWayEnum> | 17 | [TableColumnFieldEnum.WAY]?: Nullable<CommandWayEnum> |
16 | [TableColumnFieldEnum.COMMAND]?: Nullable<string | Recordable> | 18 | [TableColumnFieldEnum.COMMAND]?: Nullable<string | Recordable> |
17 | [ContentDataFieldsEnum.DEVICE_TYPE]?: Nullable<DeviceTypeEnum> | 19 | [ContentDataFieldsEnum.DEVICE_TYPE]?: Nullable<DeviceTypeEnum> |
18 | - [ContentDataFieldsEnum.CODE_TYPE]?: Nullable<CodeTypeEnum> | 20 | + [ContentDataFieldsEnum.CODE_TYPE]?: Nullable<TCPProtocolTypeEnum> |
19 | } | 21 | } |
20 | 22 | ||
21 | export const getFormSchemas = (): FormSchema[] => { | 23 | export const getFormSchemas = (): FormSchema[] => { |
@@ -2,10 +2,10 @@ import type { DeviceItemType, Specs, StructJSON, Tsl } from '@/api/device/model' | @@ -2,10 +2,10 @@ import type { DeviceItemType, Specs, StructJSON, Tsl } from '@/api/device/model' | ||
2 | import type { NodeDataDataSourceJsonType, OperationPasswordDataType, SingleClickEventDataType } from '@/api/node/model' | 2 | import type { NodeDataDataSourceJsonType, OperationPasswordDataType, SingleClickEventDataType } from '@/api/node/model' |
3 | import { type FormSchema, useComponentRegister } from '@/components/Form' | 3 | import { type FormSchema, useComponentRegister } from '@/components/Form' |
4 | import { ComponentEnum } from '@/components/Form/src/enum' | 4 | import { ComponentEnum } from '@/components/Form/src/enum' |
5 | -import { ThingsModelForm, validateTCPCustomCommand } from '@/core/Library/components/ThingsModelForm' | 5 | +import { ThingsModelForm } from '@/core/Library/components/ThingsModelForm' |
6 | import { getFormSchemas } from '@/core/Library/components/ThingsModelForm/config' | 6 | import { getFormSchemas } from '@/core/Library/components/ThingsModelForm/config' |
7 | -import { CodeTypeEnum, DataTypeEnum, TransportTypeEnum } from '@/enums/datasource' | ||
8 | -import { TCPObjectModelActionTypeEnum } from '@/enums/objectModelEnum' | 7 | +import { TCPProtocolTypeEnum, TransportTypeEnum } from '@/enums/deviceEnum' |
8 | +import { DataTypeEnum, OriginalDataTypeEnum } from '@/enums/objectModelEnum' | ||
9 | 9 | ||
10 | useComponentRegister(ComponentEnum.THINGS_MODEL_FORM, ThingsModelForm) | 10 | useComponentRegister(ComponentEnum.THINGS_MODEL_FORM, ThingsModelForm) |
11 | 11 | ||
@@ -35,59 +35,57 @@ function getStructJsonFromDataSourceJson(objectModelTsl: Tsl): StructJSON { | @@ -35,59 +35,57 @@ function getStructJsonFromDataSourceJson(objectModelTsl: Tsl): StructJSON { | ||
35 | } | 35 | } |
36 | } | 36 | } |
37 | 37 | ||
38 | -function getTCPModbusSchemas({ objectModelTsl, required }: { objectModelTsl: Tsl; required?: boolean }): FormSchema { | ||
39 | - const { specs: tslSpecs, extensionDesc } = objectModelTsl | ||
40 | - const { dataType } = tslSpecs | ||
41 | - const { specs, type } = dataType || {} | ||
42 | - const { valueRange, length = 10240 } = specs! as Specs | ||
43 | - const { max = Number.MAX_SAFE_INTEGER, min = Number.MIN_SAFE_INTEGER } = valueRange || {} | ||
44 | - const { actionType } = extensionDesc || {} | 38 | +const validateDouble = (value: number, min?: number | string, max?: number | string) => { |
39 | + min = Number(min) ?? Number.MIN_SAFE_INTEGER | ||
40 | + max = Number(max) ?? Number.MAX_SAFE_INTEGER | ||
45 | 41 | ||
46 | - function createInputNumber({ | ||
47 | - identifier, | ||
48 | - functionName, | ||
49 | - }: Tsl): FormSchema { | ||
50 | - return { | ||
51 | - field: identifier, | ||
52 | - label: functionName, | ||
53 | - component: ComponentEnum.INPUT_NUMBER, | ||
54 | - required, | ||
55 | - componentProps: { | ||
56 | - max: actionType === TCPObjectModelActionTypeEnum.BOOL ? 1 : max, | ||
57 | - min: actionType === TCPObjectModelActionTypeEnum.BOOL ? 0 : min, | ||
58 | - precision: actionType === TCPObjectModelActionTypeEnum.BOOL ? 0 : 2, | ||
59 | - }, | ||
60 | - } | 42 | + return { |
43 | + flag: value < min || value > max, | ||
44 | + message: `取值范围在${min}~${max}之间`, | ||
61 | } | 45 | } |
46 | +} | ||
62 | 47 | ||
63 | - const createInput = ({ identifier, functionName }: Tsl): FormSchema => { | ||
64 | - return { | ||
65 | - field: identifier, | ||
66 | - label: functionName, | ||
67 | - component: ComponentEnum.INPUT, | ||
68 | - rules: [ | ||
69 | - { | ||
70 | - required, | ||
71 | - message: `${functionName}是必填项`, | ||
72 | - }, | ||
73 | - { | ||
74 | - validator: validateTCPCustomCommand, | ||
75 | - }, | ||
76 | - ], | ||
77 | - componentProps: { | ||
78 | - maxLength: length, | ||
79 | - }, | ||
80 | - } as FormSchema | ||
81 | - } | 48 | +export const createModbusValueInput = (objectModel: Tsl): FormSchema => { |
49 | + const { identifier, functionName, extensionDesc } = objectModel | ||
50 | + | ||
51 | + const { dataType } = objectModel.specs || {} | ||
52 | + const { specs } = dataType || {} | ||
53 | + const { valueRange } = specs as Specs | ||
54 | + const { max, min } = valueRange || {} | ||
82 | 55 | ||
83 | - return type === DataTypeEnum.STRING ? createInput(objectModelTsl) : createInputNumber(objectModelTsl) | 56 | + const isStringType = extensionDesc?.originalDataType === OriginalDataTypeEnum.STRING |
57 | + return { | ||
58 | + field: identifier, | ||
59 | + label: functionName, | ||
60 | + component: isStringType ? ComponentEnum.INPUT : ComponentEnum.INPUT_NUMBER, | ||
61 | + rules: isStringType | ||
62 | + ? [] | ||
63 | + : [ | ||
64 | + { | ||
65 | + type: 'number', | ||
66 | + validator: (_rule, value) => { | ||
67 | + const { flag, message } = validateDouble(value, min, max) | ||
68 | + if (flag) | ||
69 | + return Promise.reject(Error(`${functionName}${message}`)) | ||
70 | + | ||
71 | + return Promise.resolve(value) | ||
72 | + }, | ||
73 | + }, | ||
74 | + ], | ||
75 | + componentProps: { | ||
76 | + // max: max ?? Number.MAX_SAFE_INTEGER, | ||
77 | + // min: min ?? Number.MIN_SAFE_INTEGER, | ||
78 | + placeholder: `请输入${functionName}`, | ||
79 | + precision: 0, | ||
80 | + }, | ||
81 | + } | ||
84 | } | 82 | } |
85 | 83 | ||
86 | export const createFormSchemas = ({ operationPasswordInfo, objectModelTsl, deviceInfo }: CreateFormSchemasParamsType): FormSchema[] => { | 84 | export const createFormSchemas = ({ operationPasswordInfo, objectModelTsl, deviceInfo }: CreateFormSchemasParamsType): FormSchema[] => { |
87 | const schemas: FormSchema[] = [] | 85 | const schemas: FormSchema[] = [] |
88 | 86 | ||
89 | - if (deviceInfo?.transportType === TransportTypeEnum.TCP && deviceInfo.codeType === CodeTypeEnum.MODBUS_RTU && deviceInfo.code) { | ||
90 | - schemas.push(getTCPModbusSchemas({ required: true, objectModelTsl })) | 87 | + if (deviceInfo?.transportType === TransportTypeEnum.TCP && deviceInfo.deviceProfile?.profileData?.transportConfiguration?.protocol === TCPProtocolTypeEnum.MODBUS_RTU) { |
88 | + schemas.push(createModbusValueInput(objectModelTsl)) | ||
91 | } | 89 | } |
92 | else { | 90 | else { |
93 | const isStructType = objectModelTsl.specs.dataType.type === DataTypeEnum.STRUCT | 91 | const isStructType = objectModelTsl.specs.dataType.type === DataTypeEnum.STRUCT |
1 | <script setup lang="ts"> | 1 | <script setup lang="ts"> |
2 | import { Modal } from 'ant-design-vue' | 2 | import { Modal } from 'ant-design-vue' |
3 | import { nextTick, ref, toRaw, unref } from 'vue' | 3 | import { nextTick, ref, toRaw, unref } from 'vue' |
4 | -import type { AttributeDeliverModalOpenParamsType } from './AttributeDeliverModal.config' | ||
5 | -import { createFormSchemas } from './AttributeDeliverModal.config' | ||
6 | -import { useCommandDeliver } from './useCommadDeliver' | 4 | +import { type AttributeDeliverModalOpenParamsType, createFormSchemas } from './AttributeDeliverModal.config' |
7 | import { BasicForm, useForm } from '@/components/Form' | 5 | import { BasicForm, useForm } from '@/components/Form' |
8 | import { FormLayoutEnum } from '@/components/Form/src/enum' | 6 | import { FormLayoutEnum } from '@/components/Form/src/enum' |
9 | -import { DataTypeEnum } from '@/enums/datasource' | 7 | +import type { DeviceItemType, Tsl } from '@/api/device/model' |
8 | +import { useProductsStore } from '@/store/modules/products' | ||
9 | +import { getDeviceInfo } from '@/api/device' | ||
10 | +import type { CommandWayEnum } from '@/enums/commandEnum' | ||
11 | +import { useCommandDelivery } from '@/hooks/business/useCommandDelivery' | ||
12 | +import { DataTypeEnum } from '@/enums/objectModelEnum' | ||
13 | +import { useMessage } from '@/hooks/web/useMessage' | ||
10 | 14 | ||
11 | const visible = ref(false) | 15 | const visible = ref(false) |
12 | 16 | ||
@@ -15,25 +19,41 @@ const [register, { getFieldsValue, resetFields, validate, setProps, clearValidat | @@ -15,25 +19,41 @@ const [register, { getFieldsValue, resetFields, validate, setProps, clearValidat | ||
15 | showActionButtonGroup: false, | 19 | showActionButtonGroup: false, |
16 | }) | 20 | }) |
17 | 21 | ||
18 | -const { setup, getDeviceInfo, getObjectModelTsl, doCommandDeliver } = useCommandDeliver() | 22 | +const deviceInfo = ref<DeviceItemType>() |
23 | +const objectModelTsl = ref<Tsl>() | ||
24 | +const productsStore = useProductsStore() | ||
25 | +const commandWay = ref<CommandWayEnum>() | ||
19 | 26 | ||
20 | const open = async ({ operationPasswordInfo, dataSourceJson, eventBindData }: AttributeDeliverModalOpenParamsType) => { | 27 | const open = async ({ operationPasswordInfo, dataSourceJson, eventBindData }: AttributeDeliverModalOpenParamsType) => { |
21 | visible.value = true | 28 | visible.value = true |
22 | const { deviceId, deviceProfileId, attr } = dataSourceJson | 29 | const { deviceId, deviceProfileId, attr } = dataSourceJson |
23 | const { way } = eventBindData | 30 | const { way } = eventBindData |
24 | - await setup({ deviceId, deviceProfileId, attr, callType: way }) | 31 | + commandWay.value = way |
32 | + objectModelTsl.value = productsStore.getObjectModelByIdWithIdentifier(deviceProfileId, attr as string)! | ||
33 | + deviceInfo.value = await getDeviceInfo(deviceId) | ||
25 | 34 | ||
26 | nextTick(() => { | 35 | nextTick(() => { |
27 | - const schemas = createFormSchemas({ operationPasswordInfo, deviceInfo: toRaw(unref(getDeviceInfo)!), objectModelTsl: toRaw(unref(getObjectModelTsl)!) }) | 36 | + const schemas = createFormSchemas({ operationPasswordInfo, deviceInfo: toRaw(unref(deviceInfo)!), objectModelTsl: toRaw(unref(objectModelTsl)!) }) |
28 | setProps({ schemas }) | 37 | setProps({ schemas }) |
29 | }) | 38 | }) |
30 | } | 39 | } |
31 | 40 | ||
32 | async function getResult() { | 41 | async function getResult() { |
33 | - const result = getFieldsValue() | ||
34 | - const isStructJSON = unref(getObjectModelTsl)?.specs.dataType.type === DataTypeEnum.STRUCT | ||
35 | - const identifier = unref(getObjectModelTsl)!.identifier | ||
36 | - await doCommandDeliver(isStructJSON ? result : result[identifier]) | 42 | + let value = getFieldsValue() |
43 | + const { doCommandDelivery } = useCommandDelivery() | ||
44 | + | ||
45 | + const isStructJSON = unref(objectModelTsl)?.specs.dataType.type === DataTypeEnum.STRUCT | ||
46 | + const identifier = unref(objectModelTsl)!.identifier | ||
47 | + value = isStructJSON ? value : value[identifier] | ||
48 | + | ||
49 | + await doCommandDelivery({ | ||
50 | + objectModel: unref(objectModelTsl), | ||
51 | + deviceDetail: unref(deviceInfo), | ||
52 | + value, | ||
53 | + }) | ||
54 | + | ||
55 | + const { createMessage } = useMessage() | ||
56 | + createMessage.success('命令下发成功') | ||
37 | } | 57 | } |
38 | 58 | ||
39 | const handleOk = async () => { | 59 | const handleOk = async () => { |
@@ -53,7 +73,7 @@ defineExpose({ open }) | @@ -53,7 +73,7 @@ defineExpose({ open }) | ||
53 | 73 | ||
54 | <template> | 74 | <template> |
55 | <Modal | 75 | <Modal |
56 | - v-model:open="visible" :title="`属性下发 / ${getDeviceInfo?.alias || getDeviceInfo?.name}`" ok-text="确认" :width="400" cancel-text="取消" @cancel="handleCancel" | 76 | + v-model:open="visible" :title="`属性下发 / ${deviceInfo?.alias || deviceInfo?.name}`" ok-text="确认" :width="400" cancel-text="取消" @cancel="handleCancel" |
57 | @ok="handleOk" | 77 | @ok="handleOk" |
58 | > | 78 | > |
59 | <BasicForm @register="register" /> | 79 | <BasicForm @register="register" /> |
@@ -2,10 +2,16 @@ | @@ -2,10 +2,16 @@ | ||
2 | import { Modal } from 'ant-design-vue' | 2 | import { Modal } from 'ant-design-vue' |
3 | import { computed, nextTick, ref, unref } from 'vue' | 3 | import { computed, nextTick, ref, unref } from 'vue' |
4 | import { Icon } from '@iconify/vue' | 4 | import { Icon } from '@iconify/vue' |
5 | -import { useCommandDeliver } from './useCommadDeliver' | ||
6 | import { BasicForm, type FormSchema, useForm } from '@/components/Form' | 5 | import { BasicForm, type FormSchema, useForm } from '@/components/Form' |
7 | import { ComponentEnum, FormLayoutEnum } from '@/components/Form/src/enum' | 6 | import { ComponentEnum, FormLayoutEnum } from '@/components/Form/src/enum' |
8 | import type { NodeDataDataSourceJsonType, OperationPasswordDataType, SingleClickEventDataType } from '@/api/node/model' | 7 | import type { NodeDataDataSourceJsonType, OperationPasswordDataType, SingleClickEventDataType } from '@/api/node/model' |
8 | +import type { DoCommandDeliverParamsType } from '@/hooks/business/useCommandDelivery' | ||
9 | +import { useCommandDelivery } from '@/hooks/business/useCommandDelivery' | ||
10 | +import { CommandDeliveryWayEnum } from '@/enums/commandEnum' | ||
11 | +import { useProductsStore } from '@/store/modules/products' | ||
12 | +import { getDeviceInfo } from '@/api/device' | ||
13 | +import { TransportTypeEnum } from '@/enums/deviceEnum' | ||
14 | +import { useMessage } from '@/hooks/web/useMessage' | ||
9 | 15 | ||
10 | interface SwitchCommandDeliveryModalParamsType { | 16 | interface SwitchCommandDeliveryModalParamsType { |
11 | operationPasswordInfo?: OperationPasswordDataType | 17 | operationPasswordInfo?: OperationPasswordDataType |
@@ -18,8 +24,6 @@ const visible = ref(false) | @@ -18,8 +24,6 @@ const visible = ref(false) | ||
18 | 24 | ||
19 | const currentOperationPasswordInfo = ref<OperationPasswordDataType>() | 25 | const currentOperationPasswordInfo = ref<OperationPasswordDataType>() |
20 | 26 | ||
21 | -const currendSendValue = ref() | ||
22 | - | ||
23 | const [register, { resetFields, validate, setProps }] = useForm({ | 27 | const [register, { resetFields, validate, setProps }] = useForm({ |
24 | showActionButtonGroup: false, | 28 | showActionButtonGroup: false, |
25 | layout: FormLayoutEnum.VERTICAL, | 29 | layout: FormLayoutEnum.VERTICAL, |
@@ -45,17 +49,17 @@ const createFormSchemas = (password: string): FormSchema[] => { | @@ -45,17 +49,17 @@ const createFormSchemas = (password: string): FormSchema[] => { | ||
45 | ] | 49 | ] |
46 | } | 50 | } |
47 | 51 | ||
48 | -const getHasEnableOperationPassword = computed(() => !!(unref(currentOperationPasswordInfo)?.checked && unref(currentOperationPasswordInfo)?.value)) | 52 | +const productsStore = useProductsStore() |
49 | 53 | ||
50 | -const { setup, doCommandDeliver, getDeviceInfo } = useCommandDeliver() | 54 | +const getHasEnableOperationPassword = computed(() => !!(unref(currentOperationPasswordInfo)?.checked && unref(currentOperationPasswordInfo)?.value)) |
51 | 55 | ||
52 | -const open = async ({ operationPasswordInfo, dataSourceJson, eventBindData, sendValue }: SwitchCommandDeliveryModalParamsType) => { | 56 | +const currentParams = ref<SwitchCommandDeliveryModalParamsType>() |
57 | +const open = async (params: SwitchCommandDeliveryModalParamsType) => { | ||
58 | + const { operationPasswordInfo } = params | ||
53 | visible.value = true | 59 | visible.value = true |
60 | + currentParams.value = params | ||
54 | currentOperationPasswordInfo.value = operationPasswordInfo | 61 | currentOperationPasswordInfo.value = operationPasswordInfo |
55 | - currendSendValue.value = sendValue | ||
56 | - const { deviceId, deviceProfileId, attr } = unref(dataSourceJson) | ||
57 | - const { way } = eventBindData | ||
58 | - await setup({ deviceId, deviceProfileId, attr, callType: way }) | 62 | + |
59 | nextTick(() => { | 63 | nextTick(() => { |
60 | unref(getHasEnableOperationPassword) && setProps({ schemas: createFormSchemas(operationPasswordInfo!.value!) }) | 64 | unref(getHasEnableOperationPassword) && setProps({ schemas: createFormSchemas(operationPasswordInfo!.value!) }) |
61 | }) | 65 | }) |
@@ -64,7 +68,36 @@ const open = async ({ operationPasswordInfo, dataSourceJson, eventBindData, send | @@ -64,7 +68,36 @@ const open = async ({ operationPasswordInfo, dataSourceJson, eventBindData, send | ||
64 | const handlerOk = async () => { | 68 | const handlerOk = async () => { |
65 | if (unref(getHasEnableOperationPassword)) | 69 | if (unref(getHasEnableOperationPassword)) |
66 | await validate() | 70 | await validate() |
67 | - await doCommandDeliver(unref(currendSendValue)) | 71 | + const { doCommandDelivery } = useCommandDelivery() |
72 | + | ||
73 | + const { sendValue, eventBindData, dataSourceJson } = unref(currentParams)! | ||
74 | + const { way, commandWay } = eventBindData | ||
75 | + const { deviceProfileId, attr, deviceId } = dataSourceJson | ||
76 | + | ||
77 | + const deviceDetail = await getDeviceInfo(deviceId) | ||
78 | + | ||
79 | + const doCommandParams: DoCommandDeliverParamsType = { | ||
80 | + value: sendValue, | ||
81 | + identifier: attr as string, | ||
82 | + deviceDetail, | ||
83 | + deviceProfileId, | ||
84 | + way, | ||
85 | + } | ||
86 | + | ||
87 | + if (commandWay === CommandDeliveryWayEnum.CUSTOM) { | ||
88 | + doCommandParams.penetration = true | ||
89 | + } | ||
90 | + else if (commandWay === CommandDeliveryWayEnum.SERVICE) { | ||
91 | + const { service } = eventBindData | ||
92 | + doCommandParams.objectModel = productsStore.getObjectModelByIdWithIdentifier(deviceProfileId, service!)! | ||
93 | + doCommandParams.value = deviceDetail?.transportType === TransportTypeEnum.TCP ? doCommandParams.value : { [doCommandParams.objectModel.identifier]: doCommandParams.value } | ||
94 | + } | ||
95 | + | ||
96 | + await doCommandDelivery(doCommandParams) | ||
97 | + | ||
98 | + const { createMessage } = useMessage() | ||
99 | + createMessage.success('命令下发成功') | ||
100 | + | ||
68 | if (unref(getHasEnableOperationPassword)) resetFields() | 101 | if (unref(getHasEnableOperationPassword)) resetFields() |
69 | visible.value = false | 102 | visible.value = false |
70 | } | 103 | } |
@@ -73,22 +106,7 @@ defineExpose({ open }) | @@ -73,22 +106,7 @@ defineExpose({ open }) | ||
73 | </script> | 106 | </script> |
74 | 107 | ||
75 | <template> | 108 | <template> |
76 | - <Modal | ||
77 | - v-model:open="visible" | ||
78 | - :title="`属性下发 / ${getDeviceInfo?.alias || getDeviceInfo?.name}`" | ||
79 | - :width="300" | ||
80 | - ok-text="确认" | ||
81 | - cancel-text="取消" | ||
82 | - destroy-on-close | ||
83 | - @ok="handlerOk" | ||
84 | - > | ||
85 | - <!-- <template #title> | ||
86 | - <div v-if="getHasEnableOperationPassword" /> | ||
87 | - <div v-else class="flex"> | ||
88 | - <span><Icon icon="ant-design:exclamation-circle-filled" class="text-yellow-300 text-xl" /></span> | ||
89 | - <span class="font-bold ml-2">属性下发 / 提示</span> | ||
90 | - </div> | ||
91 | - </template> --> | 109 | + <Modal v-model:open="visible" :width="300" ok-text="确认" cancel-text="取消" destroy-on-close @ok="handlerOk"> |
92 | <BasicForm v-if="getHasEnableOperationPassword" @register="register" /> | 110 | <BasicForm v-if="getHasEnableOperationPassword" @register="register" /> |
93 | <div v-else class="flex items-center"> | 111 | <div v-else class="flex items-center"> |
94 | <Icon icon="ant-design:exclamation-circle-filled" class="text-yellow-300 text-xl" /> | 112 | <Icon icon="ant-design:exclamation-circle-filled" class="text-yellow-300 text-xl" /> |
1 | import { ComponentEnum } from '@/components/Form/src/enum' | 1 | import { ComponentEnum } from '@/components/Form/src/enum' |
2 | import type { FormSchema } from '@/components/Form' | 2 | import type { FormSchema } from '@/components/Form' |
3 | -import type { Tsl } from '@/api/device/model' | ||
4 | import type { OperationPasswordDataType } from '@/api/node/model' | 3 | import type { OperationPasswordDataType } from '@/api/node/model' |
5 | import { validateTCPCustomCommand } from '@/core/Library/components/ThingsModelForm' | 4 | import { validateTCPCustomCommand } from '@/core/Library/components/ThingsModelForm' |
6 | import { JSONEditorValidator } from '@/components/CodeEditor/src/JSONEditor' | 5 | import { JSONEditorValidator } from '@/components/CodeEditor/src/JSONEditor' |
7 | -import { DataTypeEnum } from '@/enums/datasource' | ||
8 | 6 | ||
9 | export enum FormFieldsEnum { | 7 | export enum FormFieldsEnum { |
10 | CUSTOM_COMMAND = 'customCommand', | 8 | CUSTOM_COMMAND = 'customCommand', |
@@ -22,75 +20,6 @@ export const formSchemas: FormSchema[] = [ | @@ -22,75 +20,6 @@ export const formSchemas: FormSchema[] = [ | ||
22 | }, | 20 | }, |
23 | ] | 21 | ] |
24 | 22 | ||
25 | -export const getModbusSchemas = (objectModelTsl: Tsl): FormSchema[] => { | ||
26 | - const { functionName, identifier, specs } = objectModelTsl | ||
27 | - const { type } = specs.dataType! | ||
28 | - const HEX_MAX_VALUE = Number(0xffff) | ||
29 | - | ||
30 | - const _formSchema: FormSchema = { | ||
31 | - field: identifier, | ||
32 | - label: functionName, | ||
33 | - component: ComponentEnum.INPUT_NUMBER, | ||
34 | - } | ||
35 | - | ||
36 | - const getIntSchema = () => { | ||
37 | - return Object.assign(_formSchema, { | ||
38 | - required: true, | ||
39 | - componentProps: { | ||
40 | - min: 0, | ||
41 | - max: HEX_MAX_VALUE, | ||
42 | - precision: 2, | ||
43 | - placeholder: '请输入正数', | ||
44 | - }, | ||
45 | - } as Partial<FormSchema>) | ||
46 | - } | ||
47 | - | ||
48 | - const getBoolSchema = () => { | ||
49 | - return Object.assign(_formSchema, { | ||
50 | - required: true, | ||
51 | - componentProps: { | ||
52 | - min: 0, | ||
53 | - max: 1, | ||
54 | - precision: 0, | ||
55 | - placeholder: '请输入0或1', | ||
56 | - }, | ||
57 | - } as Partial<FormSchema>) | ||
58 | - } | ||
59 | - | ||
60 | - const getDoubleSchema = () => { | ||
61 | - return Object.assign(_formSchema, { | ||
62 | - required: true, | ||
63 | - componentProps: { | ||
64 | - placeholder: '请输入数字', | ||
65 | - precision: 2, | ||
66 | - max: HEX_MAX_VALUE, | ||
67 | - }, | ||
68 | - } as Partial<FormSchema>) | ||
69 | - } | ||
70 | - | ||
71 | - const getStringSchema = () => { | ||
72 | - return Object.assign(_formSchema, { | ||
73 | - component: ComponentEnum.INPUT, | ||
74 | - required: true, | ||
75 | - rules: [{ validator: validateTCPCustomCommand }], | ||
76 | - componentProps: { | ||
77 | - placeholder: '请输入自定义命令', | ||
78 | - }, | ||
79 | - } as Partial<FormSchema>) | ||
80 | - } | ||
81 | - | ||
82 | - const schemasMap: Partial<Record<DataTypeEnum, Fn<any, FormSchema>>> = { | ||
83 | - [DataTypeEnum.NUMBER_INT]: getIntSchema, | ||
84 | - [DataTypeEnum.BOOL]: getBoolSchema, | ||
85 | - [DataTypeEnum.NUMBER_DOUBLE]: getDoubleSchema, | ||
86 | - [DataTypeEnum.STRING]: getStringSchema, | ||
87 | - } | ||
88 | - | ||
89 | - const schemas = schemasMap[type as DataTypeEnum]?.() | ||
90 | - | ||
91 | - return [schemas!] | ||
92 | -} | ||
93 | - | ||
94 | export const getOperationPasswordSchemas = (operationPasswordInfo: OperationPasswordDataType): FormSchema[] => { | 23 | export const getOperationPasswordSchemas = (operationPasswordInfo: OperationPasswordDataType): FormSchema[] => { |
95 | return [ | 24 | return [ |
96 | { | 25 | { |
1 | <script setup lang="ts"> | 1 | <script setup lang="ts"> |
2 | import { nextTick, reactive, ref, toRaw, unref } from 'vue' | 2 | import { nextTick, reactive, ref, toRaw, unref } from 'vue' |
3 | import { Button } from 'ant-design-vue' | 3 | import { Button } from 'ant-design-vue' |
4 | -import { FormFieldsEnum, formSchemas, getJSONCommandSchemas, getModbusSchemas, getOperationPasswordSchemas, getTcpCustomCommandSchemas } from './config.ts' | ||
5 | -import { useCommandDeliver } from './useCommadDeliver' | 4 | +import { FormFieldsEnum, formSchemas, getJSONCommandSchemas, getOperationPasswordSchemas, getTcpCustomCommandSchemas } from './config.ts' |
5 | +import { createModbusValueInput } from './AttributeDeliverModal.config' | ||
6 | import { BasicModal, useModalInner } from '@/components/Modal' | 6 | import { BasicModal, useModalInner } from '@/components/Modal' |
7 | import type { NodeDataDataSourceJsonType, OperationPasswordDataType, SingleClickEventDataType } from '@/api/node/model' | 7 | import type { NodeDataDataSourceJsonType, OperationPasswordDataType, SingleClickEventDataType } from '@/api/node/model' |
8 | import { BasicForm, useForm } from '@/components/Form' | 8 | import { BasicForm, useForm } from '@/components/Form' |
9 | import { FormLayoutEnum } from '@/components/Form/src/enum' | 9 | import { FormLayoutEnum } from '@/components/Form/src/enum' |
10 | -import { CommandDeliveryWayEnum, TransportTypeEnum } from '@/enums/datasource' | ||
11 | import { ThingsModelForm } from '@/core/Library/components/ThingsModelForm' | 10 | import { ThingsModelForm } from '@/core/Library/components/ThingsModelForm' |
12 | import type { DeviceItemType, Tsl } from '@/api/device/model' | 11 | import type { DeviceItemType, Tsl } from '@/api/device/model' |
13 | -import { useProductsStoreWithOut } from '@/store/modules/products' | 12 | +import { useProductsStore, useProductsStoreWithOut } from '@/store/modules/products' |
14 | import { useJsonParse } from '@/hooks/business/useJSONParse' | 13 | import { useJsonParse } from '@/hooks/business/useJSONParse' |
15 | -import { CommandCallWayEnum, CommandWayEnum } from '@/enums/commandEnum' | 14 | +import { CommandDeliveryWayEnum } from '@/enums/commandEnum' |
15 | +import { TransportTypeEnum } from '@/enums/deviceEnum' | ||
16 | +import { getDeviceInfo } from '@/api/device' | ||
17 | +import type { DoCommandDeliverParamsType } from '@/hooks/business/useCommandDelivery' | ||
18 | +import { useCommandDelivery } from '@/hooks/business/useCommandDelivery' | ||
19 | +import { useMessage } from '@/hooks/web/useMessage' | ||
16 | 20 | ||
17 | interface OpenParamsType { | 21 | interface OpenParamsType { |
18 | dataSource: NodeDataDataSourceJsonType | 22 | dataSource: NodeDataDataSourceJsonType |
@@ -82,66 +86,60 @@ function handleOpenServiceCommandModal(deviceInfo: DeviceItemType, eventBindData | @@ -82,66 +86,60 @@ function handleOpenServiceCommandModal(deviceInfo: DeviceItemType, eventBindData | ||
82 | 86 | ||
83 | function handleOpenModbusCommandModal(objectModelTsl: Tsl) { | 87 | function handleOpenModbusCommandModal(objectModelTsl: Tsl) { |
84 | const { setProps } = customCommandFormAction | 88 | const { setProps } = customCommandFormAction |
85 | - setProps({ schemas: getModbusSchemas(objectModelTsl) }) | 89 | + setProps({ schemas: [createModbusValueInput(objectModelTsl)] }) |
86 | } | 90 | } |
87 | 91 | ||
88 | -const { setup, getDeviceInfo, getObjectModelTsl, doCommandDeliver } = useCommandDeliver() | 92 | +const deviceInfo = ref<DeviceItemType>() |
93 | +const objectModelTsl = ref<Tsl>() | ||
94 | +const currentParams = ref<OpenParamsType>() | ||
95 | +const productsStore = useProductsStore() | ||
89 | 96 | ||
90 | -const open = async ({ eventBindData, operationPasswordInfo, dataSource }: OpenParamsType) => { | 97 | +const open = async (params: OpenParamsType) => { |
98 | + const { eventBindData, operationPasswordInfo, dataSource } = params | ||
91 | const { deviceId, deviceProfileId, attr } = dataSource | 99 | const { deviceId, deviceProfileId, attr } = dataSource |
92 | - const { commandWay, callType, way, service } = eventBindData | 100 | + const { commandWay } = eventBindData |
93 | const { checked, value: operationPassword } = operationPasswordInfo || {} | 101 | const { checked, value: operationPassword } = operationPasswordInfo || {} |
94 | configuration.commandDeliveryWay = commandWay! | 102 | configuration.commandDeliveryWay = commandWay! |
95 | - | 103 | + currentParams.value = params |
104 | + deviceInfo.value = await getDeviceInfo(deviceId) | ||
105 | + objectModelTsl.value = productsStore.getObjectModelByIdWithIdentifier(deviceProfileId, attr as string)! | ||
96 | setModalProps({ | 106 | setModalProps({ |
97 | open: true, | 107 | open: true, |
98 | loading: true, | 108 | loading: true, |
99 | }) | 109 | }) |
100 | 110 | ||
101 | - await setup({ | ||
102 | - deviceId, | ||
103 | - deviceProfileId, | ||
104 | - attr, | ||
105 | - commandDeliverWay: commandWay, | ||
106 | - callType: configuration.commandDeliveryWay === CommandDeliveryWayEnum.SERVICE | ||
107 | - ? callType === CommandCallWayEnum.SYNC | ||
108 | - ? CommandWayEnum.TWO_WAY | ||
109 | - : CommandWayEnum.ONE_WAY | ||
110 | - : way, | ||
111 | - serviceIdentifier: service, | ||
112 | - }) | ||
113 | - | ||
114 | if (checked && operationPassword) | 111 | if (checked && operationPassword) |
115 | handleHasOperationPassword(operationPasswordInfo!) | 112 | handleHasOperationPassword(operationPasswordInfo!) |
116 | 113 | ||
114 | + await nextTick() | ||
115 | + | ||
117 | if (commandWay === CommandDeliveryWayEnum.CUSTOM) | 116 | if (commandWay === CommandDeliveryWayEnum.CUSTOM) |
118 | - handleOpenCustomCommandModal(toRaw(unref(getDeviceInfo)!), eventBindData) | 117 | + handleOpenCustomCommandModal(toRaw(unref(deviceInfo)!), eventBindData) |
119 | else if (commandWay === CommandDeliveryWayEnum.SERVICE) | 118 | else if (commandWay === CommandDeliveryWayEnum.SERVICE) |
120 | - handleOpenServiceCommandModal(toRaw(unref(getDeviceInfo)!), eventBindData) | 119 | + handleOpenServiceCommandModal(toRaw(unref(deviceInfo)!), eventBindData) |
121 | else if (commandWay === CommandDeliveryWayEnum.MODBUS) | 120 | else if (commandWay === CommandDeliveryWayEnum.MODBUS) |
122 | - handleOpenModbusCommandModal(toRaw(unref(getObjectModelTsl)!)) | 121 | + handleOpenModbusCommandModal(toRaw(unref(objectModelTsl)!)) |
123 | 122 | ||
124 | setModalProps({ | 123 | setModalProps({ |
125 | loading: false, | 124 | loading: false, |
126 | - title: `参数设置 / ${unref(getDeviceInfo)?.alias || unref(getDeviceInfo)?.name}`, | 125 | + title: `参数设置 / ${unref(deviceInfo)?.alias || unref(deviceInfo)?.name}`, |
127 | }) | 126 | }) |
128 | } | 127 | } |
129 | 128 | ||
130 | function handleGetCustomCommand() { | 129 | function handleGetCustomCommand() { |
131 | const res = customCommandFormAction.getFieldsValue() | 130 | const res = customCommandFormAction.getFieldsValue() |
132 | const command = res[FormFieldsEnum.CUSTOM_COMMAND] | 131 | const command = res[FormFieldsEnum.CUSTOM_COMMAND] |
133 | - return unref(getDeviceInfo)?.transportType === TransportTypeEnum.TCP ? command : useJsonParse(command).value | 132 | + return unref(deviceInfo)?.transportType === TransportTypeEnum.TCP ? command : useJsonParse(command).value |
134 | } | 133 | } |
135 | 134 | ||
136 | function handleGetServiceCommand() { | 135 | function handleGetServiceCommand() { |
137 | const res = unref(thingsModelElRef)!.getFieldsValue() | 136 | const res = unref(thingsModelElRef)!.getFieldsValue() |
138 | - | ||
139 | - return unref(getDeviceInfo)?.transportType === TransportTypeEnum.TCP ? res[FormFieldsEnum.SERVICE_COMMAND] : res | 137 | + return unref(deviceInfo)?.transportType === TransportTypeEnum.TCP ? res[FormFieldsEnum.SERVICE_COMMAND] : res |
140 | } | 138 | } |
141 | 139 | ||
142 | function handleGetModbusCommand() { | 140 | function handleGetModbusCommand() { |
143 | const res = customCommandFormAction.getFieldsValue() | 141 | const res = customCommandFormAction.getFieldsValue() |
144 | - const identifier = unref(getObjectModelTsl)!.identifier | 142 | + const identifier = unref(objectModelTsl)!.identifier |
145 | return res[identifier] | 143 | return res[identifier] |
146 | } | 144 | } |
147 | 145 | ||
@@ -156,7 +154,31 @@ const handleSubmit = async () => { | @@ -156,7 +154,31 @@ const handleSubmit = async () => { | ||
156 | ? handleGetModbusCommand() | 154 | ? handleGetModbusCommand() |
157 | : handleGetServiceCommand() | 155 | : handleGetServiceCommand() |
158 | 156 | ||
159 | - await doCommandDeliver(res) | 157 | + const { doCommandDelivery } = useCommandDelivery() |
158 | + | ||
159 | + const { eventBindData, dataSource } = unref(currentParams)! | ||
160 | + const { deviceProfileId } = dataSource | ||
161 | + const { commandWay, way } = eventBindData | ||
162 | + | ||
163 | + const params: DoCommandDeliverParamsType = { | ||
164 | + value: res, | ||
165 | + deviceDetail: unref(deviceInfo), | ||
166 | + objectModel: unref(objectModelTsl), | ||
167 | + way, | ||
168 | + } | ||
169 | + | ||
170 | + if (commandWay === CommandDeliveryWayEnum.CUSTOM) { | ||
171 | + params.penetration = true | ||
172 | + } | ||
173 | + else if (commandWay === CommandDeliveryWayEnum.SERVICE) { | ||
174 | + const { service } = eventBindData | ||
175 | + params.objectModel = productsStore.getObjectModelByIdWithIdentifier(deviceProfileId, service!)! | ||
176 | + params.value = unref(deviceInfo)?.transportType === TransportTypeEnum.TCP ? params.value : { [params.objectModel.identifier]: params.value } | ||
177 | + } | ||
178 | + | ||
179 | + await doCommandDelivery(params) | ||
180 | + const { createMessage } = useMessage() | ||
181 | + createMessage.success('命令下发成功') | ||
160 | closeModal() | 182 | closeModal() |
161 | } | 183 | } |
162 | 184 |
src/core/Library/components/PublicForm/components/DataEvents/CommandDeliveryModal/useCommadDeliver.ts
deleted
100644 → 0
1 | -import { computed, ref, unref } from 'vue' | ||
2 | -import { useGetModbusCommand } from './useGetModbusCommand' | ||
3 | -import { CodeTypeEnum, CommandDeliveryWayEnum, CommandTypeEnum, DataTypeEnum, TransportTypeEnum } from '@/enums/datasource' | ||
4 | -import type { DeviceItemType, RpcCommandType, Tsl } from '@/api/device/model' | ||
5 | -import { getDeviceActive, getDeviceInfo, sendRpcOneway } from '@/api/device' | ||
6 | -import { useProductsStoreWithOut } from '@/store/modules/products' | ||
7 | -import { CommandMethodEnum, CommandWayEnum } from '@/enums/commandEnum' | ||
8 | -import { useMessage } from '@/hooks/web/useMessage' | ||
9 | - | ||
10 | -interface UseCommandDeliverParamsType { | ||
11 | - deviceProfileId: string | ||
12 | - deviceId: string | ||
13 | - attr: string | ||
14 | - callType?: CommandWayEnum | ||
15 | - commandDeliverWay?: CommandDeliveryWayEnum | ||
16 | - serviceIdentifier?: string | ||
17 | -} | ||
18 | - | ||
19 | -/** | ||
20 | - * @description 命令下发流程 | ||
21 | - * - TCP设备(下发命令为String): | ||
22 | - * > - Modbus类型(INT,DOUBLE,BOOL,TEXT): | ||
23 | - * >> 1. 验证设备是否绑定地址码与物模型是否绑定寄存器地址 | ||
24 | - * >> 2. 物模型类型为INT,DOUBLE,BOOL: 调用接口生成Modbus命令 | ||
25 | - * >>> 1. 数据类型为INT,DOUBLE时需要进行乘以缩放因子后验证值是否为整型与浮点型 | ||
26 | - * >>> 2. 数据类型为INT,DOUBLE缩放处理后进行HEX转码 | ||
27 | - * >>> 3. DOUBLE类型寄存器个数为2 | ||
28 | - * >>> 4. BOOL类型值为0与1 | ||
29 | - * >> 3. 物模型类型为TEXT: 输入值为自定义Modbus命令 | ||
30 | - * >> 4. 物模型类型为服务: 服务命令为下发值 | ||
31 | - * > - 自定义类型: 输入值为Modubs命令 | ||
32 | - * - 非TCP设备(下发命令为(Object), {[identifier]: value}): | ||
33 | - * > - 自定义命令下发: JSON格式命令下发 | ||
34 | - * > - 属性下发与服务下发: | ||
35 | - * >> - | ||
36 | - * | ||
37 | - * @returns | ||
38 | - */ | ||
39 | -export function useCommandDeliver(params?: UseCommandDeliverParamsType) { | ||
40 | - const deviceInfo = ref<DeviceItemType>() | ||
41 | - const objectModelTsl = ref<Nullable<Tsl>>(null) | ||
42 | - const { createMessage } = useMessage() | ||
43 | - | ||
44 | - const configuration: Partial<UseCommandDeliverParamsType> = { | ||
45 | - deviceId: undefined, | ||
46 | - deviceProfileId: undefined, | ||
47 | - attr: undefined, | ||
48 | - } | ||
49 | - | ||
50 | - const getDeviceInfoById = async () => { | ||
51 | - const res = await getDeviceInfo(configuration.deviceId!) | ||
52 | - deviceInfo.value = res | ||
53 | - } | ||
54 | - | ||
55 | - const getObjectModelTslByIdWithIdentifier = () => { | ||
56 | - const productStore = useProductsStoreWithOut() | ||
57 | - const { deviceProfileId, attr } = configuration | ||
58 | - objectModelTsl.value = productStore.getObjectModelByIdWithIdentifier(deviceProfileId!, attr!) | ||
59 | - } | ||
60 | - | ||
61 | - const setup = async (params?: UseCommandDeliverParamsType) => { | ||
62 | - Object.assign(configuration, params || {}) | ||
63 | - const { deviceId, deviceProfileId, attr } = configuration | ||
64 | - if (!deviceId || !deviceProfileId || !attr) return | ||
65 | - getObjectModelTslByIdWithIdentifier() | ||
66 | - await getDeviceInfoById() | ||
67 | - } | ||
68 | - | ||
69 | - if (params && params.deviceId && params.deviceProfileId && params.attr) setup() | ||
70 | - | ||
71 | - const getCommand = async (command: any) => { | ||
72 | - const { commandDeliverWay, serviceIdentifier } = configuration | ||
73 | - | ||
74 | - const isTcpDevice = unref(deviceInfo)?.transportType === TransportTypeEnum.TCP | ||
75 | - | ||
76 | - // 指定下发命令方式 | ||
77 | - if (commandDeliverWay) { | ||
78 | - if (commandDeliverWay === CommandDeliveryWayEnum.CUSTOM) return command | ||
79 | - | ||
80 | - if (commandDeliverWay === CommandDeliveryWayEnum.SERVICE && serviceIdentifier) { | ||
81 | - return isTcpDevice | ||
82 | - ? command | ||
83 | - : { | ||
84 | - [serviceIdentifier]: command, | ||
85 | - } | ||
86 | - } | ||
87 | - } | ||
88 | - | ||
89 | - const isTCPModbusDevice = isTcpDevice && unref(deviceInfo)?.codeType === CodeTypeEnum.MODBUS_RTU | ||
90 | - const identifier = unref(objectModelTsl)!.identifier | ||
91 | - | ||
92 | - if (!isTCPModbusDevice) { | ||
93 | - return { | ||
94 | - [identifier]: command, | ||
95 | - } | ||
96 | - } | ||
97 | - else { | ||
98 | - const isString = objectModelTsl.value?.specs.dataType.type === DataTypeEnum.STRING | ||
99 | - | ||
100 | - if (isString) return command | ||
101 | - | ||
102 | - const { extensionDesc } = unref(objectModelTsl)! | ||
103 | - const { code } = unref(deviceInfo)! | ||
104 | - | ||
105 | - const { getModbusCommand, validateCanGetCommand } = useGetModbusCommand() | ||
106 | - if (!validateCanGetCommand(extensionDesc, code).flag) return | ||
107 | - | ||
108 | - const res = await getModbusCommand(command as number, extensionDesc!, code) | ||
109 | - return res | ||
110 | - } | ||
111 | - } | ||
112 | - | ||
113 | - async function doCommandDeliver(command: any) { | ||
114 | - const { callType = CommandWayEnum.ONE_WAY, commandDeliverWay } = configuration | ||
115 | - | ||
116 | - if (callType === CommandWayEnum.TWO_WAY) { | ||
117 | - const res = await getDeviceActive(unref(deviceInfo)!.tbDeviceId!) | ||
118 | - const [firstItem] = res | ||
119 | - const { value } = firstItem | ||
120 | - | ||
121 | - if (!value) { | ||
122 | - createMessage.warning('设备不在线') | ||
123 | - return Promise.reject(Error('设备不在线')) | ||
124 | - } | ||
125 | - } | ||
126 | - | ||
127 | - const res = await getCommand(command) | ||
128 | - | ||
129 | - const rpcCommandParams: RpcCommandType = { | ||
130 | - additionalInfo: { | ||
131 | - cmdType: | ||
132 | - unref(commandDeliverWay) === CommandDeliveryWayEnum.SERVICE | ||
133 | - ? CommandTypeEnum.SERVICE | ||
134 | - : CommandTypeEnum.API, | ||
135 | - }, | ||
136 | - persistent: true, | ||
137 | - method: CommandMethodEnum.THINGSKIT, | ||
138 | - params: res, | ||
139 | - } | ||
140 | - | ||
141 | - await sendRpcOneway(rpcCommandParams, unref(deviceInfo)?.tbDeviceId, callType) | ||
142 | - createMessage.success('命令下发成功') | ||
143 | - } | ||
144 | - | ||
145 | - return { | ||
146 | - getDeviceInfo: computed(() => unref(deviceInfo)), | ||
147 | - getObjectModelTsl: computed(() => unref(objectModelTsl)), | ||
148 | - setup, | ||
149 | - getCommand, | ||
150 | - doCommandDeliver, | ||
151 | - } | ||
152 | -} |
1 | +import { unref } from 'vue' | ||
2 | +import { DataTypeEnum, OriginalDataTypeEnum } from '@/enums/objectModelEnum' | ||
3 | +import type { FormSchema } from '@/components/Form' | ||
4 | +import type { DataType, DeviceItemType, Specs, StructJSON, Tsl } from '@/api/device/model' | ||
5 | +import { ComponentEnum } from '@/components/Form/src/enum' | ||
6 | +import { TCPProtocolTypeEnum } from '@/enums/deviceEnum' | ||
7 | + | ||
8 | +export interface BasicCreateFormParams { | ||
9 | + identifier: string | ||
10 | + functionName: string | ||
11 | + dataType: DataType | ||
12 | +} | ||
13 | + | ||
14 | +const validateDouble = (value: number, min?: number | string, max?: number | string) => { | ||
15 | + min = Number(min) ?? Number.MIN_SAFE_INTEGER | ||
16 | + max = Number(max) ?? Number.MAX_SAFE_INTEGER | ||
17 | + | ||
18 | + return { | ||
19 | + flag: value < min || value > max, | ||
20 | + message: `取值范围在${min}~${max}之间`, | ||
21 | + } | ||
22 | +} | ||
23 | + | ||
24 | +export const useGenerateFormSchemasByObjectModel = () => { | ||
25 | + const createInputNumber = ({ | ||
26 | + identifier, | ||
27 | + functionName, | ||
28 | + dataType, | ||
29 | + }: BasicCreateFormParams): FormSchema => { | ||
30 | + const { specs, type } = dataType | ||
31 | + const { valueRange, step } = specs! as Partial<Specs> | ||
32 | + const { max, min } = valueRange || {} | ||
33 | + return { | ||
34 | + field: identifier, | ||
35 | + label: functionName, | ||
36 | + component: 'InputNumber', | ||
37 | + rules: [ | ||
38 | + { | ||
39 | + type: 'number', | ||
40 | + trigger: 'change', | ||
41 | + validator: (_rule, value) => { | ||
42 | + const { flag, message } = validateDouble(value, min, max) | ||
43 | + if (flag) | ||
44 | + return Promise.reject(Error(`${functionName}${message}`)) | ||
45 | + | ||
46 | + return Promise.resolve(value) | ||
47 | + }, | ||
48 | + }, | ||
49 | + ], | ||
50 | + componentProps: { | ||
51 | + max: max ?? Number.MAX_SAFE_INTEGER, | ||
52 | + min: min ?? Number.MIN_SAFE_INTEGER, | ||
53 | + step, | ||
54 | + placeholder: `请输入${functionName}`, | ||
55 | + precision: type === DataTypeEnum.NUMBER_INT ? 0 : 2, | ||
56 | + }, | ||
57 | + } as FormSchema | ||
58 | + } | ||
59 | + | ||
60 | + const createInput = ({ | ||
61 | + identifier, | ||
62 | + functionName, | ||
63 | + dataType, | ||
64 | + }: BasicCreateFormParams): FormSchema => { | ||
65 | + const { specs } = dataType | ||
66 | + const { length = 10240 } = specs! as Partial<Specs> | ||
67 | + return { | ||
68 | + field: identifier, | ||
69 | + label: functionName, | ||
70 | + component: 'Input', | ||
71 | + rules: [ | ||
72 | + { | ||
73 | + type: 'string', | ||
74 | + trigger: 'change', | ||
75 | + validator: (_rule, value) => { | ||
76 | + if (value?.length > length) | ||
77 | + return Promise.reject(Error(`${functionName}数据长度应该小于${length}`)) | ||
78 | + | ||
79 | + return Promise.resolve(value) | ||
80 | + }, | ||
81 | + }, | ||
82 | + ], | ||
83 | + componentProps: { | ||
84 | + maxLength: length, | ||
85 | + placeholder: `请输入${functionName}`, | ||
86 | + }, | ||
87 | + } as FormSchema | ||
88 | + } | ||
89 | + | ||
90 | + const createSelect = ({ | ||
91 | + identifier, | ||
92 | + functionName, | ||
93 | + dataType, | ||
94 | + }: BasicCreateFormParams): FormSchema => { | ||
95 | + const { specs } = dataType | ||
96 | + const { boolClose, boolOpen } = specs! as Partial<Specs> | ||
97 | + return { | ||
98 | + field: identifier, | ||
99 | + label: functionName, | ||
100 | + component: ComponentEnum.SELECT, | ||
101 | + componentProps: { | ||
102 | + options: [ | ||
103 | + { label: `${boolClose}-0`, value: 0 }, | ||
104 | + { label: `${boolOpen}-1`, value: 1 }, | ||
105 | + ], | ||
106 | + placeholder: `请选择${functionName}`, | ||
107 | + getPopupContainer: () => document.body, | ||
108 | + }, | ||
109 | + } | ||
110 | + } | ||
111 | + | ||
112 | + const createEnumSelect = ({ | ||
113 | + identifier, | ||
114 | + functionName, | ||
115 | + dataType, | ||
116 | + }: BasicCreateFormParams): FormSchema => { | ||
117 | + const { specsList } = dataType | ||
118 | + return { | ||
119 | + field: identifier, | ||
120 | + label: functionName, | ||
121 | + component: ComponentEnum.SELECT, | ||
122 | + componentProps: { | ||
123 | + options: specsList?.map(item => ({ label: item.name, value: item.value })), | ||
124 | + placeholder: `请选择${functionName}`, | ||
125 | + getPopupContainer: () => document.body, | ||
126 | + }, | ||
127 | + } | ||
128 | + } | ||
129 | + | ||
130 | + const createModbusValueInput = (objectModel: Tsl): FormSchema => { | ||
131 | + const { identifier, functionName, extensionDesc } = objectModel | ||
132 | + | ||
133 | + const { dataType } = objectModel.specs || {} | ||
134 | + const { specs } = dataType || {} | ||
135 | + const { valueRange } = specs as Specs | ||
136 | + const { max, min } = valueRange || {} | ||
137 | + | ||
138 | + const isStringType = extensionDesc?.originalDataType === OriginalDataTypeEnum.STRING | ||
139 | + return { | ||
140 | + field: identifier, | ||
141 | + label: functionName, | ||
142 | + component: isStringType ? ComponentEnum.INPUT : ComponentEnum.INPUT_NUMBER, | ||
143 | + rules: isStringType | ||
144 | + ? [] | ||
145 | + : [ | ||
146 | + { | ||
147 | + type: 'number', | ||
148 | + validator: (_rule, value) => { | ||
149 | + const { flag, message } = validateDouble(value, min, max) | ||
150 | + if (flag) | ||
151 | + return Promise.reject(Error(`${functionName}${message}`)) | ||
152 | + | ||
153 | + return Promise.resolve(value) | ||
154 | + }, | ||
155 | + }, | ||
156 | + ], | ||
157 | + componentProps: { | ||
158 | + max: max ?? Number.MAX_SAFE_INTEGER, | ||
159 | + min: min ?? Number.MIN_SAFE_INTEGER, | ||
160 | + placeholder: `请输入${functionName}`, | ||
161 | + precision: 0, | ||
162 | + }, | ||
163 | + } | ||
164 | + } | ||
165 | + | ||
166 | + const schemaMethod: Partial<Record<DataTypeEnum, (...args: any[]) => FormSchema>> = { | ||
167 | + [DataTypeEnum.BOOL]: createSelect, | ||
168 | + [DataTypeEnum.NUMBER_DOUBLE]: createInputNumber, | ||
169 | + [DataTypeEnum.NUMBER_INT]: createInputNumber, | ||
170 | + [DataTypeEnum.STRING]: createInput, | ||
171 | + [DataTypeEnum.ENUM]: createEnumSelect, | ||
172 | + } | ||
173 | + | ||
174 | + const getFormByObjectModel = ( | ||
175 | + objectModel: Tsl, | ||
176 | + deviceDetail: DeviceItemType, | ||
177 | + ): FormSchema[] => { | ||
178 | + const { functionName, identifier, specs } = objectModel | ||
179 | + | ||
180 | + const isTCPModbusProduct | ||
181 | + = unref(deviceDetail).deviceProfile?.profileData?.transportConfiguration?.protocol | ||
182 | + === TCPProtocolTypeEnum.MODBUS_RTU | ||
183 | + | ||
184 | + const { dataType } = specs | ||
185 | + const { type } = dataType || {} | ||
186 | + | ||
187 | + if (isTCPModbusProduct) | ||
188 | + return [createModbusValueInput(objectModel)] | ||
189 | + | ||
190 | + if (type === DataTypeEnum.STRUCT) { | ||
191 | + return (dataType?.specs as StructJSON[]).map((item) => { | ||
192 | + const { functionName, identifier, dataType } = item | ||
193 | + const { type } = dataType || {} | ||
194 | + | ||
195 | + return schemaMethod[type!]?.({ identifier, functionName, dataType }) | ||
196 | + }) as FormSchema[] | ||
197 | + } | ||
198 | + | ||
199 | + const result = schemaMethod[type!]?.({ identifier, functionName, dataType: dataType! }) | ||
200 | + return result ? [result] : [] | ||
201 | + } | ||
202 | + | ||
203 | + return { getFormByObjectModel } | ||
204 | +} |
src/core/Library/components/PublicForm/components/DataEvents/CommandDeliveryModal/useGetModbusCommand.ts
deleted
100644 → 0
1 | -import { type GenModbusCommandType, genModbusCommand } from '@/api/device' | ||
2 | -import type { ExtensionDesc } from '@/api/device/model' | ||
3 | -import { ModbusCRCEnum } from '@/enums/commandEnum' | ||
4 | -import { TCPObjectModelActionTypeEnum } from '@/enums/objectModelEnum' | ||
5 | -import { useMessage } from '@/hooks/web/useMessage' | ||
6 | - | ||
7 | -export const InsertString = (t: any, c: any, n: any) => { | ||
8 | - const r: string | number[] = [] | ||
9 | - | ||
10 | - for (let i = 0; i * 2 < t.length; i++) | ||
11 | - r.push(t.substr(i * 2, n)) | ||
12 | - | ||
13 | - return r.join(c) | ||
14 | -} | ||
15 | - | ||
16 | -export const FillString = (t: any, c: any, n: any, b: any) => { | ||
17 | - if (t === '' || c.length !== 1 || n <= t.length) | ||
18 | - return t | ||
19 | - | ||
20 | - const l = t.length | ||
21 | - | ||
22 | - for (let i = 0; i < n - l; i++) { | ||
23 | - if (b === true) | ||
24 | - t = c + t | ||
25 | - | ||
26 | - else | ||
27 | - t += c | ||
28 | - } | ||
29 | - return t | ||
30 | -} | ||
31 | - | ||
32 | -export const SingleToHex = (t: any) => { | ||
33 | - if (t === '') | ||
34 | - return '' | ||
35 | - | ||
36 | - t = parseFloat(t) | ||
37 | - | ||
38 | - if (isNaN(t) === true) | ||
39 | - return 'Error' | ||
40 | - | ||
41 | - if (t === 0) | ||
42 | - return '00000000' | ||
43 | - | ||
44 | - let s, e, m | ||
45 | - | ||
46 | - if (t > 0) { | ||
47 | - s = 0 | ||
48 | - } | ||
49 | - else { | ||
50 | - s = 1 | ||
51 | - | ||
52 | - t = 0 - t | ||
53 | - } | ||
54 | - m = t.toString(2) | ||
55 | - | ||
56 | - if (m >= 1) { | ||
57 | - if (m.indexOf('.') === -1) | ||
58 | - m = `${m}.0` | ||
59 | - | ||
60 | - e = m.indexOf('.') - 1 | ||
61 | - } | ||
62 | - else { | ||
63 | - e = 1 - m.indexOf('1') | ||
64 | - } | ||
65 | - if (e >= 0) | ||
66 | - m = m.replace('.', '') | ||
67 | - | ||
68 | - else | ||
69 | - m = m.substring(m.indexOf('1')) | ||
70 | - | ||
71 | - if (m.length > 24) | ||
72 | - m = m.substr(0, 24) | ||
73 | - | ||
74 | - else | ||
75 | - m = FillString(m, '0', 24, false) | ||
76 | - | ||
77 | - m = m.substring(1) | ||
78 | - | ||
79 | - e = (e + 127).toString(2) | ||
80 | - | ||
81 | - e = FillString(e, '0', 8, true) | ||
82 | - | ||
83 | - let r = parseInt(s + e + m, 2).toString(16) | ||
84 | - | ||
85 | - r = FillString(r, '0', 8, true) | ||
86 | - | ||
87 | - return InsertString(r, ' ', 2).toUpperCase() | ||
88 | -} | ||
89 | - | ||
90 | -export const FormatHex = (t: any, n: any, ie: any) => { | ||
91 | - const r: string[] = [] | ||
92 | - | ||
93 | - let s = '' | ||
94 | - | ||
95 | - let c = 0 | ||
96 | - | ||
97 | - for (let i = 0; i < t.length; i++) { | ||
98 | - if (t.charAt(i) !== ' ') { | ||
99 | - s += t.charAt(i) | ||
100 | - | ||
101 | - c += 1 | ||
102 | - | ||
103 | - if (c === n) { | ||
104 | - r.push(s) | ||
105 | - | ||
106 | - s = '' | ||
107 | - | ||
108 | - c = 0 | ||
109 | - } | ||
110 | - } | ||
111 | - if (ie === false) { | ||
112 | - if (i === t.length - 1 && s !== '') | ||
113 | - r.push(s) | ||
114 | - } | ||
115 | - } | ||
116 | - return r.join('\n') | ||
117 | -} | ||
118 | - | ||
119 | -export const FormatHexBatch = (t: any, n: any, ie: any) => { | ||
120 | - const a = t.split('\n') | ||
121 | - | ||
122 | - const r: string[] = [] | ||
123 | - | ||
124 | - for (let i = 0; i < a.length; i++) | ||
125 | - r[i] = FormatHex(a[i], n, ie) | ||
126 | - | ||
127 | - return r.join('\n') | ||
128 | -} | ||
129 | - | ||
130 | -export const SingleToHexBatch = (t: any) => { | ||
131 | - const a = t.split('\n') | ||
132 | - | ||
133 | - const r: string[] = [] | ||
134 | - | ||
135 | - for (let i = 0; i < a.length; i++) | ||
136 | - r[i] = SingleToHex(a[i]) | ||
137 | - | ||
138 | - return r.join('\r\n') | ||
139 | -} | ||
140 | - | ||
141 | -const getArray = (values: any) => { | ||
142 | - const str = values.replace(/\s+/g, '') | ||
143 | - const array: any = [] | ||
144 | - | ||
145 | - for (let i = 0; i < str.length; i += 4) { | ||
146 | - const chunk = parseInt(str.substring(i, i + 4), 16) | ||
147 | - array.push(chunk) | ||
148 | - } | ||
149 | - return array | ||
150 | -} | ||
151 | - | ||
152 | -const getFloatPart = (number: string | number) => { | ||
153 | - const isLessZero = Number(number) < 0 | ||
154 | - number = number.toString() | ||
155 | - const floatPartStartIndex = number.indexOf('.') | ||
156 | - const value = ~floatPartStartIndex | ||
157 | - ? `${isLessZero ? '-' : ''}0.${number.substring(floatPartStartIndex + 1)}` | ||
158 | - : '0' | ||
159 | - return Number(value) | ||
160 | -} | ||
161 | - | ||
162 | -const REGISTER_MAX_VALUE = Number(0xffff) | ||
163 | - | ||
164 | -export function useGetModbusCommand() { | ||
165 | - const { createMessage } = useMessage() | ||
166 | - | ||
167 | - const getModbusCommand = async (value: number, extensionDesc: ExtensionDesc, deviceAddressCode: string) => { | ||
168 | - const { registerAddress, actionType, zoomFactor } = extensionDesc as Required<ExtensionDesc> | ||
169 | - | ||
170 | - const params: GenModbusCommandType = { | ||
171 | - crc: ModbusCRCEnum.CRC_16_LOWER, | ||
172 | - registerNumber: 1, | ||
173 | - deviceCode: deviceAddressCode, | ||
174 | - registerAddress, | ||
175 | - method: actionType, | ||
176 | - registerValues: [value], | ||
177 | - } | ||
178 | - | ||
179 | - if (actionType === TCPObjectModelActionTypeEnum.INT) { | ||
180 | - const newValue | ||
181 | - = Math.trunc(value) * zoomFactor | ||
182 | - + getFloatPart(value) * zoomFactor | ||
183 | - | ||
184 | - if (newValue % 1 !== 0) { | ||
185 | - createMessage.warning(`属性下发类型必须是整数,缩放因子为${zoomFactor}`) | ||
186 | - return | ||
187 | - } | ||
188 | - | ||
189 | - if (value * zoomFactor > REGISTER_MAX_VALUE) { | ||
190 | - createMessage.warning(`属性下发值不能超过${REGISTER_MAX_VALUE},缩放因子为${zoomFactor}`) | ||
191 | - return | ||
192 | - } | ||
193 | - | ||
194 | - params.registerValues = [newValue] | ||
195 | - } | ||
196 | - else if (actionType === TCPObjectModelActionTypeEnum.DOUBLE) { | ||
197 | - const regex = /^-?\d+(\.\d{0,2})?$/ | ||
198 | - const values | ||
199 | - = Math.trunc(value) * zoomFactor | ||
200 | - + getFloatPart(value) * zoomFactor | ||
201 | - | ||
202 | - if (!regex.test(values.toString())) { | ||
203 | - createMessage.warning(`属性下发值精确到两位小数,缩放因子为${zoomFactor}`) | ||
204 | - return | ||
205 | - } | ||
206 | - | ||
207 | - const newValue | ||
208 | - = values === 0 ? [0, 0] : getArray(SingleToHex(values)) | ||
209 | - params.registerValues = newValue | ||
210 | - params.registerNumber = 2 | ||
211 | - params.method = '10' | ||
212 | - } | ||
213 | - | ||
214 | - return await genModbusCommand(params) | ||
215 | - } | ||
216 | - | ||
217 | - /** | ||
218 | - * | ||
219 | - * @param extensionDesc 物模型拓展描述符 | ||
220 | - * @param deviceAddressCode 设备地址码 | ||
221 | - */ | ||
222 | - const validateCanGetCommand = (extensionDesc?: ExtensionDesc, deviceAddressCode?: string, createValidateMessage = true) => { | ||
223 | - const result = { flag: true, message: '' } | ||
224 | - if (!extensionDesc) { | ||
225 | - result.flag = false | ||
226 | - result.message = '当前物模型扩展描述没有填写' | ||
227 | - } | ||
228 | - | ||
229 | - if (!deviceAddressCode) { | ||
230 | - result.flag = false | ||
231 | - result.message = '当前设备未绑定设备地址码' | ||
232 | - } | ||
233 | - | ||
234 | - if (result.message && createValidateMessage) | ||
235 | - createMessage.warning(result.message) | ||
236 | - | ||
237 | - return result | ||
238 | - } | ||
239 | - | ||
240 | - return { | ||
241 | - getModbusCommand, | ||
242 | - validateCanGetCommand, | ||
243 | - } | ||
244 | -} |
@@ -6,7 +6,7 @@ import { JSONEditor } from '@/components/CodeEditor/src/JSONEditor' | @@ -6,7 +6,7 @@ import { JSONEditor } from '@/components/CodeEditor/src/JSONEditor' | ||
6 | import { BasicModal, useModalInner } from '@/components/Modal' | 6 | import { BasicModal, useModalInner } from '@/components/Modal' |
7 | import { useMessage } from '@/hooks/web/useMessage' | 7 | import { useMessage } from '@/hooks/web/useMessage' |
8 | import { useJsonParse } from '@/hooks/business/useJSONParse' | 8 | import { useJsonParse } from '@/hooks/business/useJSONParse' |
9 | -import { TransportTypeEnum } from '@/enums/datasource' | 9 | +import { TransportTypeEnum } from '@/enums/deviceEnum' |
10 | 10 | ||
11 | const emit = defineEmits(['register', 'editComplete']) | 11 | const emit = defineEmits(['register', 'editComplete']) |
12 | 12 |
@@ -2,8 +2,9 @@ import type { FormSchema } from '@/components/Form' | @@ -2,8 +2,9 @@ import type { FormSchema } from '@/components/Form' | ||
2 | import { ComponentEnum } from '@/components/Form/src/enum' | 2 | import { ComponentEnum } from '@/components/Form/src/enum' |
3 | import type { BasicColumn } from '@/components/Table' | 3 | import type { BasicColumn } from '@/components/Table' |
4 | import type { CommandWayEnum } from '@/enums/commandEnum' | 4 | import type { CommandWayEnum } from '@/enums/commandEnum' |
5 | -import type { CodeTypeEnum, ContentDataFieldsEnum, DeviceTypeEnum, TransportTypeEnum } from '@/enums/datasource' | 5 | +import type { ContentDataFieldsEnum } from '@/enums/datasource' |
6 | import { EventActionTypeEnum, EventActionTypeNameEnum, EventTypeEnum, EventTypeNameEnum } from '@/enums/datasource' | 6 | import { EventActionTypeEnum, EventActionTypeNameEnum, EventTypeEnum, EventTypeNameEnum } from '@/enums/datasource' |
7 | +import type { DeviceTypeEnum, TCPProtocolTypeEnum } from '@/enums/deviceEnum' | ||
7 | 8 | ||
8 | export enum TableColumnFieldEnum { | 9 | export enum TableColumnFieldEnum { |
9 | DEVICE_ID = 'deviceId', | 10 | DEVICE_ID = 'deviceId', |
@@ -18,9 +19,8 @@ export interface TableRecordItemType { | @@ -18,9 +19,8 @@ export interface TableRecordItemType { | ||
18 | [TableColumnFieldEnum.WAY]?: Nullable<CommandWayEnum> | 19 | [TableColumnFieldEnum.WAY]?: Nullable<CommandWayEnum> |
19 | [TableColumnFieldEnum.COMMAND]?: Nullable<string | Recordable> | 20 | [TableColumnFieldEnum.COMMAND]?: Nullable<string | Recordable> |
20 | [ContentDataFieldsEnum.DEVICE_TYPE]?: Nullable<DeviceTypeEnum> | 21 | [ContentDataFieldsEnum.DEVICE_TYPE]?: Nullable<DeviceTypeEnum> |
21 | - [ContentDataFieldsEnum.CODE_TYPE]?: Nullable<CodeTypeEnum> | 22 | + [ContentDataFieldsEnum.CODE_TYPE]?: Nullable<TCPProtocolTypeEnum> |
22 | [ContentDataFieldsEnum.DEVICE_PROFILE_ID]: Nullable<string> | 23 | [ContentDataFieldsEnum.DEVICE_PROFILE_ID]: Nullable<string> |
23 | - [ContentDataFieldsEnum.TRANSPORT_TYPE]?: Nullable<TransportTypeEnum> | ||
24 | } | 24 | } |
25 | 25 | ||
26 | export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { | 26 | export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { |
@@ -4,13 +4,13 @@ import { usePublicFormContext } from '../../../usePublicFormContext' | @@ -4,13 +4,13 @@ import { usePublicFormContext } from '../../../usePublicFormContext' | ||
4 | import { getThingsModelServices } from '@/api/device' | 4 | import { getThingsModelServices } from '@/api/device' |
5 | import { type FormSchema } from '@/components/Form' | 5 | import { type FormSchema } from '@/components/Form' |
6 | import { ComponentEnum } from '@/components/Form/src/enum' | 6 | import { ComponentEnum } from '@/components/Form/src/enum' |
7 | -import { CommandWayEnum, CommandWayNameEnum } from '@/enums/commandEnum' | ||
8 | -import { CommandDeliveryWayEnum, CommandDeliveryWayNameEnum, DeviceTypeEnum, EventActionTypeEnum, EventActionTypeNameEnum, EventTypeEnum, EventTypeNameEnum, TransportTypeEnum } from '@/enums/datasource' | 7 | +import { CommandDeliveryWayEnum, CommandDeliveryWayNameEnum, CommandWayEnum, CommandWayNameEnum } from '@/enums/commandEnum' |
8 | +import { EventActionTypeEnum, EventActionTypeNameEnum, EventTypeEnum, EventTypeNameEnum } from '@/enums/datasource' | ||
9 | import type { ThingsModel } from '@/api/device/model' | 9 | import type { ThingsModel } from '@/api/device/model' |
10 | import { PackageCategoryEnum } from '@/core/Library/enum' | 10 | import { PackageCategoryEnum } from '@/core/Library/enum' |
11 | -import { useContentDataStoreWithOut } from '@/store/modules/contentData' | ||
12 | import { validateTCPCustomCommand } from '@/core/Library/components/ThingsModelForm' | 11 | import { validateTCPCustomCommand } from '@/core/Library/components/ThingsModelForm' |
13 | import { JSONEditorValidator } from '@/components/CodeEditor/src/JSONEditor' | 12 | import { JSONEditorValidator } from '@/components/CodeEditor/src/JSONEditor' |
13 | +import { DeviceTypeEnum, TCPProtocolTypeEnum, TransportTypeEnum } from '@/enums/deviceEnum' | ||
14 | 14 | ||
15 | export enum FormFieldsEnum { | 15 | export enum FormFieldsEnum { |
16 | ACTION_TYPE = 'actionType', | 16 | ACTION_TYPE = 'actionType', |
@@ -35,16 +35,11 @@ export enum FormFieldsNameEnum { | @@ -35,16 +35,11 @@ export enum FormFieldsNameEnum { | ||
35 | SERVICE = '服务', | 35 | SERVICE = '服务', |
36 | } | 36 | } |
37 | 37 | ||
38 | -const contentDataStore = useContentDataStoreWithOut() | ||
39 | - | ||
40 | export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { | 38 | export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { |
41 | const { getNodeData, getCellInfo, getDeviceInfo } = usePublicFormContext() | 39 | const { getNodeData, getCellInfo, getDeviceInfo } = usePublicFormContext() |
42 | const { dataSourceJson } = unref(getNodeData) || {} | 40 | const { dataSourceJson } = unref(getNodeData) || {} |
43 | const { deviceProfileId } = dataSourceJson || {} | 41 | const { deviceProfileId } = dataSourceJson || {} |
44 | - // transportType:判断是什么类型的设备 code:设备地址码 deviceType:设备类型 | ||
45 | - const { transportType, deviceType, codeType } = unref(getDeviceInfo) || {} | ||
46 | - | ||
47 | - const isTemplate = contentDataStore.isTemplate // 判断是否是模板 | 42 | + const { transportType } = unref(getDeviceInfo) || {} |
48 | 43 | ||
49 | return [ | 44 | return [ |
50 | { | 45 | { |
@@ -115,39 +110,30 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { | @@ -115,39 +110,30 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { | ||
115 | component: ComponentEnum.SELECT, | 110 | component: ComponentEnum.SELECT, |
116 | required: true, | 111 | required: true, |
117 | ifShow: ({ model }) => model[FormFieldsEnum.ACTION_TYPE] === EventActionTypeEnum.PARAMS_SETTING, | 112 | ifShow: ({ model }) => model[FormFieldsEnum.ACTION_TYPE] === EventActionTypeEnum.PARAMS_SETTING, |
113 | + defaultValue: CommandDeliveryWayEnum.CUSTOM, | ||
118 | componentProps: ({ formActionType }) => { | 114 | componentProps: ({ formActionType }) => { |
119 | function getOptions() { | 115 | function getOptions() { |
120 | const options = [ | 116 | const options = [ |
121 | { label: CommandDeliveryWayNameEnum.CUSTOM, value: CommandDeliveryWayEnum.CUSTOM }, | 117 | { label: CommandDeliveryWayNameEnum.CUSTOM, value: CommandDeliveryWayEnum.CUSTOM }, |
122 | ] | 118 | ] |
123 | 119 | ||
124 | - const serviceOption = { label: CommandDeliveryWayNameEnum.SERVICE, value: CommandDeliveryWayEnum.SERVICE } | ||
125 | - const modbusOption = { label: CommandDeliveryWayNameEnum.MODBUS, value: CommandDeliveryWayEnum.MODBUS } | ||
126 | - | ||
127 | - function setOptions() { | ||
128 | - // 是模板的话选择不到设备标识符类型所以就判断为放开自定义命令 | ||
129 | - if (isTemplate) { | ||
130 | - if (transportType !== TransportTypeEnum.TCP) | ||
131 | - options.push(serviceOption) | ||
132 | - return | ||
133 | - } | ||
134 | - | ||
135 | - if (transportType !== TransportTypeEnum.TCP && deviceType === DeviceTypeEnum.SENSOR) { | ||
136 | - // 判断不是TCP但是是网关子 | ||
137 | - options.push(serviceOption) | ||
138 | - return | ||
139 | - } | ||
140 | - | ||
141 | - if (deviceType !== DeviceTypeEnum.SENSOR) | ||
142 | - options.push(serviceOption) | 120 | + const isTCPDevice = unref(getDeviceInfo)?.transportType === TransportTypeEnum.TCP |
121 | + const isTCPModbusDevice = isTCPDevice && unref(getDeviceInfo)?.deviceProfile?.profileData?.transportConfiguration?.protocol === TCPProtocolTypeEnum.MODBUS_RTU | ||
143 | 122 | ||
144 | - if (transportType !== TransportTypeEnum.TCP) return | 123 | + // TCP 自定义设备 自定义 |
124 | + if (isTCPDevice && !isTCPModbusDevice && unref(getDeviceInfo)?.deviceType === DeviceTypeEnum.SENSOR) | ||
125 | + return options | ||
145 | 126 | ||
146 | - if (codeType !== CommandDeliveryWayEnum.CUSTOM) | ||
147 | - options.push(modbusOption) | 127 | + // TCP Modbus设备 自定义&Modbus |
128 | + if (isTCPModbusDevice) { | ||
129 | + const modbusOption = { label: CommandDeliveryWayNameEnum.MODBUS, value: CommandDeliveryWayEnum.MODBUS } | ||
130 | + options.push(modbusOption) | ||
131 | + return options | ||
148 | } | 132 | } |
149 | 133 | ||
150 | - setOptions() | 134 | + // 其他 自定义&服务 |
135 | + options.push({ label: CommandDeliveryWayNameEnum.SERVICE, value: CommandDeliveryWayEnum.SERVICE }) | ||
136 | + | ||
151 | return options | 137 | return options |
152 | } | 138 | } |
153 | 139 |
@@ -3,11 +3,12 @@ import { getDeviceAttributes, getListByConfigurationId, getListByDeviceProfileId | @@ -3,11 +3,12 @@ import { getDeviceAttributes, getListByConfigurationId, getListByDeviceProfileId | ||
3 | import type { DeviceItemType, ThingsModelItemType } from '@/api/device/model' | 3 | import type { DeviceItemType, ThingsModelItemType } from '@/api/device/model' |
4 | import type { FormSchema } from '@/components/Form' | 4 | import type { FormSchema } from '@/components/Form' |
5 | import { ComponentEnum } from '@/components/Form/src/enum' | 5 | import { ComponentEnum } from '@/components/Form/src/enum' |
6 | -import { ContentDataFieldsEnum, ContentDataFieldsNameEnum, DataTypeEnum } from '@/enums/datasource' | 6 | +import { ContentDataFieldsEnum, ContentDataFieldsNameEnum } from '@/enums/datasource' |
7 | import { useContentDataStoreWithOut } from '@/store/modules/contentData' | 7 | import { useContentDataStoreWithOut } from '@/store/modules/contentData' |
8 | import type { ProductAndDevice } from '@/api/content/model' | 8 | import type { ProductAndDevice } from '@/api/content/model' |
9 | import { ControlComponentEnum } from '@/core/Library/packages/Control' | 9 | import { ControlComponentEnum } from '@/core/Library/packages/Control' |
10 | import { useParseParams } from '@/core/LoadData' | 10 | import { useParseParams } from '@/core/LoadData' |
11 | +import { DataTypeEnum } from '@/enums/objectModelEnum' | ||
11 | 12 | ||
12 | const contentDataStore = useContentDataStoreWithOut() | 13 | const contentDataStore = useContentDataStoreWithOut() |
13 | export const formSchemas = (componentKey?: string): FormSchema[] => { | 14 | export const formSchemas = (componentKey?: string): FormSchema[] => { |
@@ -88,12 +89,13 @@ export const formSchemas = (componentKey?: string): FormSchema[] => { | @@ -88,12 +89,13 @@ export const formSchemas = (componentKey?: string): FormSchema[] => { | ||
88 | showSearch: true, | 89 | showSearch: true, |
89 | api: async (params: string) => { | 90 | api: async (params: string) => { |
90 | if (!deviceProfileId) return [] | 91 | if (!deviceProfileId) return [] |
91 | - const options = await getDeviceAttributes(params) | 92 | + let options = await getDeviceAttributes(params) |
92 | if (componentKey === ControlComponentEnum.SWITCH) { // 开关只返回bool | 93 | if (componentKey === ControlComponentEnum.SWITCH) { // 开关只返回bool |
93 | - return options.filter((item) => { | 94 | + options = options.filter((item) => { |
94 | return item.detail.dataType.type === DataTypeEnum.BOOL | 95 | return item.detail.dataType.type === DataTypeEnum.BOOL |
95 | }) | 96 | }) |
96 | } | 97 | } |
98 | + | ||
97 | return options | 99 | return options |
98 | }, | 100 | }, |
99 | params: deviceProfileId, | 101 | params: deviceProfileId, |
@@ -2,7 +2,8 @@ import { validateTCPCustomCommand } from '.' | @@ -2,7 +2,8 @@ import { validateTCPCustomCommand } from '.' | ||
2 | import type { Specs, StructJSON } from '@/api/device/model' | 2 | import type { Specs, StructJSON } from '@/api/device/model' |
3 | import { type FormSchema } from '@/components/Form' | 3 | import { type FormSchema } from '@/components/Form' |
4 | import { ComponentEnum } from '@/components/Form/src/enum' | 4 | import { ComponentEnum } from '@/components/Form/src/enum' |
5 | -import { DataTypeEnum, TransportTypeEnum } from '@/enums/datasource' | 5 | +import { TransportTypeEnum } from '@/enums/deviceEnum' |
6 | +import { DataTypeEnum } from '@/enums/objectModelEnum' | ||
6 | 7 | ||
7 | export enum FormFieldsEnum { | 8 | export enum FormFieldsEnum { |
8 | SERVICE_COMMAND = 'serviceCommand', | 9 | SERVICE_COMMAND = 'serviceCommand', |
@@ -5,9 +5,9 @@ import { getFormSchemas } from './config' | @@ -5,9 +5,9 @@ import { getFormSchemas } from './config' | ||
5 | import { ThingsModelForm } from '.' | 5 | import { ThingsModelForm } from '.' |
6 | import type { StructJSON } from '@/api/device/model' | 6 | import type { StructJSON } from '@/api/device/model' |
7 | import { BasicForm, useForm } from '@/components/Form' | 7 | import { BasicForm, useForm } from '@/components/Form' |
8 | -import { DataTypeEnum } from '@/enums/datasource' | ||
9 | import { FormLabelAlignEnum, FormLayoutEnum } from '@/components/Form/src/enum' | 8 | import { FormLabelAlignEnum, FormLayoutEnum } from '@/components/Form/src/enum' |
10 | import { deepMerge } from '@/utils' | 9 | import { deepMerge } from '@/utils' |
10 | +import { DataTypeEnum } from '@/enums/objectModelEnum' | ||
11 | 11 | ||
12 | interface ThingsModelFormPropsType { | 12 | interface ThingsModelFormPropsType { |
13 | value?: Recordable | 13 | value?: Recordable |
@@ -67,7 +67,7 @@ export function useNodeData({ cell, immediate = true }: UseNodeDataParamsType) { | @@ -67,7 +67,7 @@ export function useNodeData({ cell, immediate = true }: UseNodeDataParamsType) { | ||
67 | }) | 67 | }) |
68 | 68 | ||
69 | const getDeviceDetail = async () => { | 69 | const getDeviceDetail = async () => { |
70 | - if (!unref(nodeData)?.dataSourceJson.deviceId) return | 70 | + if (!unref(nodeData)?.dataSourceJson?.deviceId) return |
71 | deviceInfo.value = await getDeviceInfo(unref(nodeData)!.dataSourceJson.deviceId) | 71 | deviceInfo.value = await getDeviceInfo(unref(nodeData)!.dataSourceJson.deviceId) |
72 | } | 72 | } |
73 | 73 |
@@ -2,8 +2,8 @@ import { h, render, toRaw, unref } from 'vue' | @@ -2,8 +2,8 @@ import { h, render, toRaw, unref } from 'vue' | ||
2 | import { ControlComponentEnum } from '../packages/Control' | 2 | import { ControlComponentEnum } from '../packages/Control' |
3 | import { doCommandDelivery, getDeviceActive } from '@/api/device' | 3 | import { doCommandDelivery, getDeviceActive } from '@/api/device' |
4 | import type { MouseUpEventDataType, NodeDataDataSourceJsonType, NodeDataEventJsonType, SingleClickEventDataType } from '@/api/node/model' | 4 | import type { MouseUpEventDataType, NodeDataDataSourceJsonType, NodeDataEventJsonType, SingleClickEventDataType } from '@/api/node/model' |
5 | -import { CommandMethodEnum, CommandWayEnum } from '@/enums/commandEnum' | ||
6 | -import { ActRangListItemTypeEnum, CommandTypeEnum, EventActionTypeEnum } from '@/enums/datasource' | 5 | +import { CommandMethodEnum, CommandTypeEnum, CommandWayEnum } from '@/enums/commandEnum' |
6 | +import { ActRangListItemTypeEnum, EventActionTypeEnum } from '@/enums/datasource' | ||
7 | import { useMessage } from '@/hooks/web/useMessage' | 7 | import { useMessage } from '@/hooks/web/useMessage' |
8 | import { AttributeDeliverModal, CommandDeliveryModal, SwitchCommandDeliveryModal } from '@/core/Library/components/PublicForm/components/DataEvents/CommandDeliveryModal' | 8 | import { AttributeDeliverModal, CommandDeliveryModal, SwitchCommandDeliveryModal } from '@/core/Library/components/PublicForm/components/DataEvents/CommandDeliveryModal' |
9 | import type { MxCell } from '@/fitCore/types' | 9 | import type { MxCell } from '@/fitCore/types' |
@@ -8,8 +8,10 @@ import { ComponentEnum } from '@/components/Form/src/enum' | @@ -8,8 +8,10 @@ import { ComponentEnum } from '@/components/Form/src/enum' | ||
8 | import { useContentDataStoreWithOut } from '@/store/modules/contentData' | 8 | import { useContentDataStoreWithOut } from '@/store/modules/contentData' |
9 | import { DateFormatEnum } from '@/enums/timeEnum' | 9 | import { DateFormatEnum } from '@/enums/timeEnum' |
10 | import type { BasicColumn } from '@/components/Table' | 10 | import type { BasicColumn } from '@/components/Table' |
11 | -import { AlarmStatusEnum, type CodeTypeEnum, type ContentDataFieldsEnum } from '@/enums/datasource' | 11 | +import { type ContentDataFieldsEnum } from '@/enums/datasource' |
12 | import { useParseParams } from '@/core/LoadData' | 12 | import { useParseParams } from '@/core/LoadData' |
13 | +import type { TCPProtocolTypeEnum } from '@/enums/deviceEnum' | ||
14 | +import { AlarmStatusEnum } from '@/enums/alarmEnum' | ||
13 | 15 | ||
14 | export const tableColumns: BasicColumn[] = [ | 16 | export const tableColumns: BasicColumn[] = [ |
15 | { | 17 | { |
@@ -27,7 +29,7 @@ export const tableColumns: BasicColumn[] = [ | @@ -27,7 +29,7 @@ export const tableColumns: BasicColumn[] = [ | ||
27 | export interface TableRecordItemType { | 29 | export interface TableRecordItemType { |
28 | uuid: string | 30 | uuid: string |
29 | [TableColumnFieldEnum.DEVICE_ID]?: Nullable<string> | 31 | [TableColumnFieldEnum.DEVICE_ID]?: Nullable<string> |
30 | - [ContentDataFieldsEnum.CODE_TYPE]?: Nullable<CodeTypeEnum> | 32 | + [ContentDataFieldsEnum.CODE_TYPE]?: Nullable<TCPProtocolTypeEnum> |
31 | } | 33 | } |
32 | 34 | ||
33 | export const AlarmColorMap = { | 35 | export const AlarmColorMap = { |
@@ -8,8 +8,8 @@ import type { AlarmListItemType } from '@/api/alarm/model' | @@ -8,8 +8,8 @@ import type { AlarmListItemType } from '@/api/alarm/model' | ||
8 | import type { CreateComponentType } from '@/core/Library/types' | 8 | import type { CreateComponentType } from '@/core/Library/types' |
9 | import { useContentDataStore } from '@/store/modules/contentData' | 9 | import { useContentDataStore } from '@/store/modules/contentData' |
10 | import { isLightboxMode, isShareMode } from '@/utils/env' | 10 | import { isLightboxMode, isShareMode } from '@/utils/env' |
11 | -import { AlarmStatusColorEnum, AlarmStatusEnum, AlarmStatusNameEnum } from '@/enums/datasource' | ||
12 | import { formatToDateTime } from '@/utils/dateUtil' | 11 | import { formatToDateTime } from '@/utils/dateUtil' |
12 | +import { AlarmStatusColorEnum, AlarmStatusNameEnum } from '@/enums/alarmEnum' | ||
13 | 13 | ||
14 | const props = defineProps<{ | 14 | const props = defineProps<{ |
15 | config: CreateComponentType | 15 | config: CreateComponentType |
@@ -67,7 +67,7 @@ onMounted(async () => { | @@ -67,7 +67,7 @@ onMounted(async () => { | ||
67 | useIntervalFn(initFetchAlarmList, (initOptions.polling || 30) * 1000) | 67 | useIntervalFn(initFetchAlarmList, (initOptions.polling || 30) * 1000) |
68 | } | 68 | } |
69 | else { | 69 | else { |
70 | - const statusList = Object.values(AlarmStatusEnum) | 70 | + const statusList = Object.values(AlarmStatusNameEnum) |
71 | Object.assign(initOptions, { | 71 | Object.assign(initOptions, { |
72 | scroll: false, | 72 | scroll: false, |
73 | interval: 0, | 73 | interval: 0, |
@@ -75,6 +75,15 @@ const init = () => { | @@ -75,6 +75,15 @@ const init = () => { | ||
75 | videoPlayInstance.value = videoJs(unref(videoPlayEl)!, unref(getOptions), () => { | 75 | videoPlayInstance.value = videoJs(unref(videoPlayEl)!, unref(getOptions), () => { |
76 | emit('ready', unref(videoPlayInstance)) | 76 | emit('ready', unref(videoPlayInstance)) |
77 | }) | 77 | }) |
78 | + | ||
79 | + unref(videoPlayInstance)?.on('timeupdate', () => { | ||
80 | + if (!unref(videoPlayInstance)) return | ||
81 | + | ||
82 | + const differTime = unref(videoPlayInstance)!.buffered().end(0) - unref(videoPlayInstance)!.currentTime() | ||
83 | + | ||
84 | + if (differTime > 10) | ||
85 | + init() | ||
86 | + }) | ||
78 | } | 87 | } |
79 | 88 | ||
80 | const customInit = (getOptionsFn: (optios: VideoJsPlayerOptions) => VideoJsPlayerOptions) => { | 89 | const customInit = (getOptionsFn: (optios: VideoJsPlayerOptions) => VideoJsPlayerOptions) => { |
@@ -3,11 +3,12 @@ import { getDeviceAttributes, getListByConfigurationId, getListByDeviceProfileId | @@ -3,11 +3,12 @@ import { getDeviceAttributes, getListByConfigurationId, getListByDeviceProfileId | ||
3 | import type { DeviceItemType, ThingsModelItemType } from '@/api/device/model' | 3 | import type { DeviceItemType, ThingsModelItemType } from '@/api/device/model' |
4 | import type { FormSchema } from '@/components/Form' | 4 | import type { FormSchema } from '@/components/Form' |
5 | import { ComponentEnum } from '@/components/Form/src/enum' | 5 | import { ComponentEnum } from '@/components/Form/src/enum' |
6 | -import { ContentDataFieldsEnum, ContentDataFieldsNameEnum, DataTypeEnum } from '@/enums/datasource' | 6 | +import { ContentDataFieldsEnum, ContentDataFieldsNameEnum } from '@/enums/datasource' |
7 | import { useContentDataStoreWithOut } from '@/store/modules/contentData' | 7 | import { useContentDataStoreWithOut } from '@/store/modules/contentData' |
8 | import type { ProductAndDevice } from '@/api/content/model' | 8 | import type { ProductAndDevice } from '@/api/content/model' |
9 | import { ControlComponentEnum } from '@/core/Library/packages/Control' | 9 | import { ControlComponentEnum } from '@/core/Library/packages/Control' |
10 | import { useParseParams } from '@/core/LoadData' | 10 | import { useParseParams } from '@/core/LoadData' |
11 | +import { DataTypeEnum } from '@/enums/objectModelEnum' | ||
11 | 12 | ||
12 | const contentDataStore = useContentDataStoreWithOut() | 13 | const contentDataStore = useContentDataStoreWithOut() |
13 | export const formSchemas = (componentKey?: string): FormSchema[] => { | 14 | export const formSchemas = (componentKey?: string): FormSchema[] => { |
@@ -84,11 +84,13 @@ export class DataDynamicEffectHandler { | @@ -84,11 +84,13 @@ export class DataDynamicEffectHandler { | ||
84 | if (flag) { | 84 | if (flag) { |
85 | const nodeEl = this.nodeUtils.getNodesForCells([cell]) | 85 | const nodeEl = this.nodeUtils.getNodesForCells([cell]) |
86 | const { type } = record! | 86 | const { type } = record! |
87 | + | ||
87 | if (type === ActRangListItemTypeEnum.SHOW) { | 88 | if (type === ActRangListItemTypeEnum.SHOW) { |
88 | nodeEl.forEach((node) => { | 89 | nodeEl.forEach((node) => { |
89 | node.classList.add(ActAnimationName.VISIBLE) | 90 | node.classList.add(ActAnimationName.VISIBLE) |
90 | node.classList.remove(ActAnimationName.HIDDEN) | 91 | node.classList.remove(ActAnimationName.HIDDEN) |
91 | }) | 92 | }) |
93 | + this.nodeUtils.updateCellValue(cell, record?.title ? record.title : latestValue) | ||
92 | } | 94 | } |
93 | else if (type === ActRangListItemTypeEnum.HIDDEN) { | 95 | else if (type === ActRangListItemTypeEnum.HIDDEN) { |
94 | nodeEl.forEach((node) => { | 96 | nodeEl.forEach((node) => { |
@@ -55,9 +55,9 @@ export class MessageHandler { | @@ -55,9 +55,9 @@ export class MessageHandler { | ||
55 | const { data, node } = commandSource | 55 | const { data, node } = commandSource |
56 | const { attr, deviceProfileId } = data as NodeDataDataSourceJsonType | 56 | const { attr, deviceProfileId } = data as NodeDataDataSourceJsonType |
57 | 57 | ||
58 | - let { latestValue } = useLatestMessageValue(message.data, attr) | 58 | + let { latestValue } = useLatestMessageValue(message.data, attr as string) |
59 | if (isNull(latestValue)) return | 59 | if (isNull(latestValue)) return |
60 | - latestValue = useObjectModelValue(deviceProfileId, attr, latestValue) | 60 | + latestValue = useObjectModelValue(deviceProfileId, attr as string, latestValue) |
61 | const cell = this.nodeUtils.getCellById(node) | 61 | const cell = this.nodeUtils.getCellById(node) |
62 | 62 | ||
63 | const cellValue = cell.getValue() as Element | 63 | const cellValue = cell.getValue() as Element |
1 | import type { DataType, Specs, StructJSON } from '@/api/device/model' | 1 | import type { DataType, Specs, StructJSON } from '@/api/device/model' |
2 | -import { DataTypeEnum } from '@/enums/datasource' | 2 | +import { TransportTypeEnum } from '@/enums/deviceEnum' |
3 | +import { DataTypeEnum } from '@/enums/objectModelEnum' | ||
3 | import { useJsonParse } from '@/hooks/business/useJSONParse' | 4 | import { useJsonParse } from '@/hooks/business/useJSONParse' |
4 | import { useProductsStoreWithOut } from '@/store/modules/products' | 5 | import { useProductsStoreWithOut } from '@/store/modules/products' |
5 | 6 | ||
@@ -45,6 +46,13 @@ function getValueByType(type: string, value: any, dataType: DataType) { | @@ -45,6 +46,13 @@ function getValueByType(type: string, value: any, dataType: DataType) { | ||
45 | } | 46 | } |
46 | } | 47 | } |
47 | 48 | ||
49 | +function getModbusDeviceValueByType(value: any, dataType: DataType) { | ||
50 | + if (dataType.type === DataTypeEnum.BOOL && dataType.specsList && dataType.specsList.length) | ||
51 | + return getEnumTypeValue(value, dataType.specsList as Specs[]) | ||
52 | + | ||
53 | + return value | ||
54 | +} | ||
55 | + | ||
48 | export function useObjectModelValue(deviceProfileId: string, attr: string, value: any) { | 56 | export function useObjectModelValue(deviceProfileId: string, attr: string, value: any) { |
49 | const productsStore = useProductsStoreWithOut() | 57 | const productsStore = useProductsStoreWithOut() |
50 | 58 | ||
@@ -52,5 +60,8 @@ export function useObjectModelValue(deviceProfileId: string, attr: string, value | @@ -52,5 +60,8 @@ export function useObjectModelValue(deviceProfileId: string, attr: string, value | ||
52 | if (!result) | 60 | if (!result) |
53 | return value | 61 | return value |
54 | 62 | ||
55 | - return getValueByType(result.specs.dataType.type as DataTypeEnum, value, result.specs.dataType) | 63 | + const products = productsStore.getProductDetailById(deviceProfileId) |
64 | + const isTCPModbus = products.transportType === TransportTypeEnum.TCP && result.extensionDesc?.originalDataType | ||
65 | + | ||
66 | + return isTCPModbus ? getModbusDeviceValueByType(value, result.specs.dataType) : getValueByType(result.specs.dataType.type as DataTypeEnum, value, result.specs.dataType) | ||
56 | } | 67 | } |
src/enums/alarmEnum.ts
0 → 100644
1 | +export enum AlarmStatusEnum { | ||
2 | + CLEARED_UN_ACK = 'CLEARED_UNACK', | ||
3 | + ACTIVE_UN_ACK = 'ACTIVE_UNACK', | ||
4 | + CLEARED_ACK = 'CLEARED_ACK', | ||
5 | + ACTIVE_ACK = 'ACTIVE_ACK', | ||
6 | +} | ||
7 | + | ||
8 | +export enum AlarmStatusColorEnum { | ||
9 | + CLEARED_UNACK = 'red', | ||
10 | + ACTIVE_UNACK = 'orange', | ||
11 | + CLEARED_ACK = 'cyan', | ||
12 | + ACTIVE_ACK = 'green', | ||
13 | +} | ||
14 | + | ||
15 | +export enum AlarmStatusNameEnum { | ||
16 | + CLEARED_UNACK = '清除未确认', | ||
17 | + ACTIVE_UNACK = '激活未确认', | ||
18 | + CLEARED_ACK = '清除已确认', | ||
19 | + ACTIVE_ACK = '激活已确认', | ||
20 | +} |
@@ -13,6 +13,31 @@ export enum CommandCallWayEnum { | @@ -13,6 +13,31 @@ export enum CommandCallWayEnum { | ||
13 | ASYNC = 'ASYNC', | 13 | ASYNC = 'ASYNC', |
14 | } | 14 | } |
15 | 15 | ||
16 | +export enum CommandTypeEnum { | ||
17 | + CUSTOM = 0, | ||
18 | + SERVICE = 1, | ||
19 | + ATTRIBUTE = 2, | ||
20 | + API = 'api', | ||
21 | +} | ||
22 | + | ||
23 | +export enum CommandTypeNameEnum { | ||
24 | + CUSTOM = '自定义', | ||
25 | + SERVICE = '服务', | ||
26 | + ATTRIBUTE = '属性', | ||
27 | +} | ||
28 | + | ||
29 | +export enum CommandDeliveryWayEnum { | ||
30 | + CUSTOM = 'CUSTOM', | ||
31 | + SERVICE = 'SERVICE', | ||
32 | + MODBUS = 'MODBUS', | ||
33 | +} | ||
34 | + | ||
35 | +export enum CommandDeliveryWayNameEnum { | ||
36 | + CUSTOM = '自定义命令', | ||
37 | + SERVICE = '服务调用', | ||
38 | + MODBUS = 'MODBUS', | ||
39 | +} | ||
40 | + | ||
16 | export enum CommandMethodEnum { | 41 | export enum CommandMethodEnum { |
17 | THINGSKIT = 'methodThingskit', | 42 | THINGSKIT = 'methodThingskit', |
18 | } | 43 | } |
@@ -64,50 +64,6 @@ export enum ActTypeNameEnum { | @@ -64,50 +64,6 @@ export enum ActTypeNameEnum { | ||
64 | VARIABLE_IMAGE = '变量图片', | 64 | VARIABLE_IMAGE = '变量图片', |
65 | } | 65 | } |
66 | 66 | ||
67 | -export enum DeviceTypeEnum { | ||
68 | - /** | ||
69 | - * @description 网关设备 | ||
70 | - */ | ||
71 | - GATEWAY = 'GATEWAY', | ||
72 | - | ||
73 | - /** | ||
74 | - * @description 直连设备 | ||
75 | - */ | ||
76 | - DIRECT_CONNECTION = 'DIRECT_CONNECTION', | ||
77 | - | ||
78 | - /** | ||
79 | - * @description 网关子设备 | ||
80 | - */ | ||
81 | - SENSOR = 'SENSOR', | ||
82 | -} | ||
83 | - | ||
84 | -export enum DeviceTypeNameEnum { | ||
85 | - /** | ||
86 | - * @description 网关设备 | ||
87 | - */ | ||
88 | - GATEWAY = '网关设备', | ||
89 | - | ||
90 | - /** | ||
91 | - * @description 直连设备 | ||
92 | - */ | ||
93 | - DIRECT_CONNECTION = '直连设备', | ||
94 | - | ||
95 | - /** | ||
96 | - * @description 网关子设备 | ||
97 | - */ | ||
98 | - SENSOR = '网关子设备', | ||
99 | -} | ||
100 | - | ||
101 | -export enum TransportTypeEnum { | ||
102 | - MQTT = 'MQTT', | ||
103 | - TCP = 'TCP', | ||
104 | -} | ||
105 | - | ||
106 | -export enum CodeTypeEnum { | ||
107 | - CUSTOM = 'CUSTOM', | ||
108 | - MODBUS_RTU = 'MODBUS_RTU', | ||
109 | -} | ||
110 | - | ||
111 | export enum EventTypeEnum { | 67 | export enum EventTypeEnum { |
112 | /** | 68 | /** |
113 | * @description 鼠标抬起 | 69 | * @description 鼠标抬起 |
@@ -271,46 +227,6 @@ export enum VariableImageSourceNameEnum { | @@ -271,46 +227,6 @@ export enum VariableImageSourceNameEnum { | ||
271 | GALLERY = '图库图形', | 227 | GALLERY = '图库图形', |
272 | } | 228 | } |
273 | 229 | ||
274 | -export enum CommandDeliveryWayEnum { | ||
275 | - CUSTOM = 'CUSTOM', | ||
276 | - SERVICE = 'SERVICE', | ||
277 | - MODBUS = 'MODBUS', | ||
278 | -} | ||
279 | - | ||
280 | -export enum CommandDeliveryWayNameEnum { | ||
281 | - CUSTOM = '自定义命令', | ||
282 | - SERVICE = '服务调用', | ||
283 | - MODBUS = 'MODBUS', | ||
284 | -} | ||
285 | - | ||
286 | -export enum FunctionTypeEnum { | ||
287 | - PROPERTIES = 'properties', | ||
288 | - EVENTS = 'events', | ||
289 | - SERVICE = 'services', | ||
290 | -} | ||
291 | - | ||
292 | -export enum AssessMode { | ||
293 | - READ = 'r', | ||
294 | - WRITE = 'w', | ||
295 | -} | ||
296 | - | ||
297 | -export enum CommandTypeEnum { | ||
298 | - SERVICE = 1, | ||
299 | - API = 'API', | ||
300 | -} | ||
301 | - | ||
302 | -/** | ||
303 | - * 新增参数 动态显示表单 | ||
304 | - */ | ||
305 | -export enum DataTypeEnum { | ||
306 | - NUMBER_INT = 'INT', | ||
307 | - NUMBER_DOUBLE = 'DOUBLE', | ||
308 | - STRING = 'TEXT', | ||
309 | - STRUCT = 'STRUCT', | ||
310 | - BOOL = 'BOOL', | ||
311 | - ENUM = 'ENUM', | ||
312 | -} | ||
313 | - | ||
314 | export enum AggregateTypeEnum { | 230 | export enum AggregateTypeEnum { |
315 | MIN = 'MIN', | 231 | MIN = 'MIN', |
316 | MAX = 'MAX', | 232 | MAX = 'MAX', |
@@ -333,24 +249,3 @@ export enum SocketSubscriberEnum { | @@ -333,24 +249,3 @@ export enum SocketSubscriberEnum { | ||
333 | HISTORY_CMDS = 'historyCmds', | 249 | HISTORY_CMDS = 'historyCmds', |
334 | } | 250 | } |
335 | 251 | ||
336 | -export enum AlarmStatusEnum { | ||
337 | - CLEARED_UN_ACK = 'CLEARED_UNACK', | ||
338 | - ACTIVE_UN_ACK = 'ACTIVE_UNACK', | ||
339 | - CLEARED_ACK = 'CLEARED_ACK', | ||
340 | - ACTIVE_ACK = 'ACTIVE_ACK', | ||
341 | -} | ||
342 | - | ||
343 | -export enum AlarmStatusColorEnum { | ||
344 | - CLEARED_UNACK = 'red', | ||
345 | - ACTIVE_UNACK = 'orange', | ||
346 | - CLEARED_ACK = 'cyan', | ||
347 | - ACTIVE_ACK = 'green', | ||
348 | -} | ||
349 | - | ||
350 | -export enum AlarmStatusNameEnum { | ||
351 | - CLEARED_UNACK = '清除未确认', | ||
352 | - ACTIVE_UNACK = '激活未确认', | ||
353 | - CLEARED_ACK = '清除已确认', | ||
354 | - ACTIVE_ACK = '激活已确认', | ||
355 | -} | ||
356 | - |
src/enums/deviceEnum.ts
0 → 100644
1 | +export enum DeviceTypeEnum { | ||
2 | + /** | ||
3 | + * @description 网关设备 | ||
4 | + */ | ||
5 | + GATEWAY = 'GATEWAY', | ||
6 | + | ||
7 | + /** | ||
8 | + * @description 直连设备 | ||
9 | + */ | ||
10 | + DIRECT_CONNECTION = 'DIRECT_CONNECTION', | ||
11 | + | ||
12 | + /** | ||
13 | + * @description 网关子设备 | ||
14 | + */ | ||
15 | + SENSOR = 'SENSOR', | ||
16 | +} | ||
17 | + | ||
18 | +export enum DeviceTypeNameEnum { | ||
19 | + /** | ||
20 | + * @description 网关设备 | ||
21 | + */ | ||
22 | + GATEWAY = '网关设备', | ||
23 | + | ||
24 | + /** | ||
25 | + * @description 直连设备 | ||
26 | + */ | ||
27 | + DIRECT_CONNECTION = '直连设备', | ||
28 | + | ||
29 | + /** | ||
30 | + * @description 网关子设备 | ||
31 | + */ | ||
32 | + SENSOR = '网关子设备', | ||
33 | +} | ||
34 | + | ||
35 | +export enum TransportTypeEnum { | ||
36 | + DEFAULT = 'DEFAULT', | ||
37 | + MQTT = 'MQTT', | ||
38 | + COAP = 'COAP', | ||
39 | + LWM2M = 'LWM2M', | ||
40 | + SNMP = 'SNMP', | ||
41 | + TCP = 'TCP', | ||
42 | +} | ||
43 | + | ||
44 | +export enum TCPProtocolTypeEnum { | ||
45 | + CUSTOM = 'CUSTOM', | ||
46 | + MODBUS_RTU = 'MODBUS_RTU', | ||
47 | +} | ||
48 | + | ||
49 | +export enum TCPProtocolTypeNameEnum { | ||
50 | + CUSTOM = '自定义', | ||
51 | + MODBUS_RTU = 'MODBUS_RTU', | ||
52 | +} |
1 | /** | 1 | /** |
2 | - * @description TCP物模型拓展描述符数据格式 | 2 | + * 新增参数 动态显示表单 |
3 | */ | 3 | */ |
4 | -export enum TCPObjectModelActionTypeEnum { | ||
5 | - BOOL = '05', | ||
6 | - INT = '06', | ||
7 | - DOUBLE = '16', | 4 | +export enum DataTypeEnum { |
5 | + NUMBER_INT = 'INT', | ||
6 | + NUMBER_DOUBLE = 'DOUBLE', | ||
7 | + STRING = 'TEXT', | ||
8 | + STRUCT = 'STRUCT', | ||
9 | + BOOL = 'BOOL', | ||
10 | + ENUM = 'ENUM', | ||
11 | +} | ||
12 | + | ||
13 | +export enum FunctionTypeEnum { | ||
14 | + PROPERTIES = 'properties', | ||
15 | + EVENTS = 'events', | ||
16 | + SERVICE = 'services', | ||
17 | +} | ||
18 | + | ||
19 | +export enum ObjectModelAccessModeEnum { | ||
20 | + READ = 'r', | ||
21 | + READ_AND_WRITE = 'rw', | ||
22 | +} | ||
23 | + | ||
24 | +export enum OriginalDataTypeEnum { | ||
25 | + INT16_AB = 'INT16_AB', | ||
26 | + INT16_BA = 'INT16_BA', | ||
27 | + UINT16_AB = 'UINT16_AB', | ||
28 | + UINT16_BA = 'UINT16_BA', | ||
29 | + INT32_AB_CD = 'INT32_AB_CD', | ||
30 | + INT32_CD_AB = 'INT32_CD_AB', | ||
31 | + INT32_BA_DC = 'INT32_BA_DC', | ||
32 | + INT32_DC_BA = 'INT32_DC_BA', | ||
33 | + UINT32_AB_CD = 'UINT32_AB_CD', | ||
34 | + UINT32_CD_AB = 'UINT32_CD_AB', | ||
35 | + UINT32_BA_DC = 'UINT32_BA_DC', | ||
36 | + UINT32_DC_BA = 'UINT32_DC_BA', | ||
37 | + FLOAT_AB_CD = 'FLOAT_AB_CD', | ||
38 | + FLOAT_CD_AB = 'FLOAT_CD_AB', | ||
39 | + FLOAT_BA_DC = 'FLOAT_BA_DC', | ||
40 | + FLOAT_DC_BA = 'FLOAT_DC_BA', | ||
41 | + DOUBLE = 'DOUBLE', | ||
42 | + STRING = 'STRING', | ||
43 | + BOOLEAN = 'BOOLEAN', | ||
44 | + BITS = 'BITS', | ||
45 | +} | ||
46 | + | ||
47 | +export enum OriginalDataTypeNameEnum { | ||
48 | + INT16_AB = '16位有符号整数AB', | ||
49 | + INT16_BA = '16位有符号整数BA', | ||
50 | + UINT16_AB = '16位无符号整数AB', | ||
51 | + UINT16_BA = '16位无符号整数BA', | ||
52 | + INT32_AB_CD = '32位有符号整数AB_CD', | ||
53 | + INT32_CD_AB = '32位有符号整数CD_AB', | ||
54 | + INT32_BA_DC = '32位有符号整数BA_DC', | ||
55 | + INT32_DC_BA = '32位有符号整数DC_BA', | ||
56 | + UINT32_AB_CD = '32位无符号整数AB_CD', | ||
57 | + UINT32_CD_AB = '32位无符号整数CD_AB', | ||
58 | + UINT32_BA_DC = '32位无符号整数BA_DC', | ||
59 | + UINT32_DC_BA = '32位无符号整数DC_BA', | ||
60 | + FLOAT_AB_CD = '单精度浮点型AB_CD', | ||
61 | + FLOAT_CD_AB = '单精度浮点型CD_AB', | ||
62 | + FLOAT_BA_DC = '单精度浮点型BA_DC', | ||
63 | + FLOAT_DC_BA = '单精度浮点型DC_BA', | ||
64 | + DOUBLE = '双精度浮点型', | ||
65 | + STRING = '字符串', | ||
66 | + BOOLEAN = '布尔型', | ||
67 | + BITS = '位', | ||
68 | +} | ||
69 | + | ||
70 | +export enum ExtendDescOperationTypeEnum { | ||
71 | + INPUT_STATUS_R_02 = 'inputStatus_r_02', | ||
72 | + COIL_STATUS_R_01 = 'coilStatus_r_01', | ||
73 | + COIL_STATUS_RW_01_05 = 'coilStatus_rw_01_05', | ||
74 | + COIL_STATUS_RW_01_0F = 'coilStatus_rw_01_0F', | ||
75 | + COIL_STATUS_W_05 = 'coilStatus_w_05', | ||
76 | + COIL_STATUS_W_0F = 'coilStatus_w_0F', | ||
77 | + HOLDING_REGISTER_R_03 = 'holdingRegister_r_03', | ||
78 | + HOLDING_REGISTER_RW_03_06 = 'holdingRegister_rw_03_06', | ||
79 | + HOLDING_REGISTER_RW_03_10 = 'holdingRegister_rw_03_10', | ||
80 | + HOLDING_REGISTER_W_06 = 'holdingRegister_w_06', | ||
81 | + HOLDING_REGISTER_W_10 = 'holdingRegister_w_10', | ||
82 | + INPUT_REGISTER_R_04 = 'inputRegister_r_04', | ||
83 | +} | ||
84 | + | ||
85 | +export enum ExtendDescOperationTypeNameEnum { | ||
86 | + INPUT_STATUS_R_02 = '离散量输入(只读,0x02)', | ||
87 | + COIL_STATUS_R_01 = '线圈状态(只读,0x01)', | ||
88 | + COIL_STATUS_RW_01_05 = '线圈状态(读写,读取使用0x01,写入使用0x05)', | ||
89 | + COIL_STATUS_RW_01_0F = '线圈状态(读写,读取使用0x01,写入使用0x0F)', | ||
90 | + COIL_STATUS_W_05 = '线圈状态(只写,0x05)', | ||
91 | + COIL_STATUS_W_0F = '线圈状态(只写,0x0F)', | ||
92 | + HOLDING_REGISTER_R_03 = '保持寄存器(只读,0x03)', | ||
93 | + HOLDING_REGISTER_RW_03_06 = '保持寄存器(读写,读取使用0x03,写入使用0x06)', | ||
94 | + HOLDING_REGISTER_RW_03_10 = '保持寄存器(读写,读取使用0x03,写入使用0x10)', | ||
95 | + HOLDING_REGISTER_W_06 = '保持寄存器(只写,0x06)', | ||
96 | + HOLDING_REGISTER_W_10 = '保持寄存器(只写,0x10)', | ||
97 | + INPUT_REGISTER_R_04 = '输入寄存器(只读,0x04)', | ||
8 | } | 98 | } |
src/hooks/business/useBaseConversion.ts
0 → 100644
1 | +import { OriginalDataTypeEnum } from '@/enums/objectModelEnum' | ||
2 | +import { useParseOriginalDataType } from '@/hooks/business/useParseOriginalDataType' | ||
3 | + | ||
4 | +export function useBaseConversion() { | ||
5 | + function DecTo32Float(number: number) { | ||
6 | + const arr = new Uint8Array(4) | ||
7 | + const view = new DataView(arr.buffer) | ||
8 | + view.setFloat32(0, +number) | ||
9 | + return arr | ||
10 | + } | ||
11 | + | ||
12 | + function DecTo64Double(number: number) { | ||
13 | + const arr = new Uint8Array(8) | ||
14 | + const view = new DataView(arr.buffer) | ||
15 | + view.setFloat64(0, +number) | ||
16 | + return arr | ||
17 | + } | ||
18 | + | ||
19 | + function arrToBase(toBase: number, arr: Uint8Array) { | ||
20 | + let result = '' | ||
21 | + for (let i = 0; i < arr.length; i++) | ||
22 | + result += (256 + arr[i]).toString(toBase).substring(1).toUpperCase() | ||
23 | + | ||
24 | + return result | ||
25 | + } | ||
26 | + | ||
27 | + function DecTo16Uint(number: number) { | ||
28 | + const arr = new Uint8Array(2) | ||
29 | + const view = new DataView(arr.buffer) | ||
30 | + view.setUint16(0, +number) | ||
31 | + return arr | ||
32 | + } | ||
33 | + | ||
34 | + function DecTo16Int(number: number) { | ||
35 | + const arr = new Uint8Array(2) | ||
36 | + const view = new DataView(arr.buffer) | ||
37 | + view.setInt16(0, +number) | ||
38 | + return arr | ||
39 | + } | ||
40 | + | ||
41 | + function DecTo32Uint(number: number) { | ||
42 | + const arr = new Uint8Array(4) | ||
43 | + const view = new DataView(arr.buffer) | ||
44 | + view.setUint32(0, +number) | ||
45 | + return arr | ||
46 | + } | ||
47 | + | ||
48 | + function DecTo32Int(number: number) { | ||
49 | + const arr = new Uint8Array(4) | ||
50 | + const view = new DataView(arr.buffer) | ||
51 | + view.setInt32(0, +number) | ||
52 | + return arr | ||
53 | + } | ||
54 | + | ||
55 | + function DecToBinaryByType(type: OriginalDataTypeEnum, number: number) { | ||
56 | + switch (type) { | ||
57 | + case OriginalDataTypeEnum.INT16_AB: | ||
58 | + case OriginalDataTypeEnum.INT16_BA: | ||
59 | + return arrToBase(2, DecTo16Int(number)) | ||
60 | + | ||
61 | + case OriginalDataTypeEnum.UINT16_AB: | ||
62 | + case OriginalDataTypeEnum.UINT16_BA: | ||
63 | + return arrToBase(2, DecTo16Uint(number)) | ||
64 | + | ||
65 | + case OriginalDataTypeEnum.INT32_AB_CD: | ||
66 | + case OriginalDataTypeEnum.INT32_CD_AB: | ||
67 | + case OriginalDataTypeEnum.INT32_BA_DC: | ||
68 | + case OriginalDataTypeEnum.INT32_DC_BA: | ||
69 | + return arrToBase(2, DecTo32Int(number)) | ||
70 | + | ||
71 | + case OriginalDataTypeEnum.UINT32_AB_CD: | ||
72 | + case OriginalDataTypeEnum.UINT32_CD_AB: | ||
73 | + case OriginalDataTypeEnum.UINT32_BA_DC: | ||
74 | + case OriginalDataTypeEnum.UINT32_DC_BA: | ||
75 | + return arrToBase(2, DecTo32Uint(number)) | ||
76 | + | ||
77 | + case OriginalDataTypeEnum.FLOAT_AB_CD: | ||
78 | + case OriginalDataTypeEnum.FLOAT_CD_AB: | ||
79 | + case OriginalDataTypeEnum.FLOAT_BA_DC: | ||
80 | + case OriginalDataTypeEnum.FLOAT_DC_BA: | ||
81 | + return arrToBase(2, DecTo32Float(number)) | ||
82 | + | ||
83 | + case OriginalDataTypeEnum.DOUBLE: | ||
84 | + return arrToBase(2, DecTo64Double(number)) | ||
85 | + } | ||
86 | + } | ||
87 | + | ||
88 | + function SplitStringToGroupByItemLength( | ||
89 | + value: string, | ||
90 | + itemLength = 8, | ||
91 | + ignoreLessThan = false, | ||
92 | + ): string[] { | ||
93 | + const reg = new RegExp(`.{${ignoreLessThan ? '' : '1,'}${itemLength}}`, 'g') | ||
94 | + return value.match(reg) || [] | ||
95 | + } | ||
96 | + | ||
97 | + function ExchangeByteOrder(binary: string, order: string) { | ||
98 | + const group = SplitStringToGroupByItemLength(binary) | ||
99 | + | ||
100 | + const BASE_ORDER = { | ||
101 | + A: 0, | ||
102 | + B: 1, | ||
103 | + C: 2, | ||
104 | + D: 3, | ||
105 | + } | ||
106 | + | ||
107 | + const array: string[] = Array.from({ length: binary.length / 8 }) | ||
108 | + | ||
109 | + order | ||
110 | + .split('') | ||
111 | + .forEach((bytePosition, index) => (array[index] = group[BASE_ORDER[bytePosition as keyof typeof BASE_ORDER] as number])) | ||
112 | + | ||
113 | + return array.join('') | ||
114 | + } | ||
115 | + | ||
116 | + function ByteToHex(binary: string) { | ||
117 | + const group = SplitStringToGroupByItemLength(binary, 16) | ||
118 | + return group.map(byte => parseInt(byte, 2).toString(16)) | ||
119 | + } | ||
120 | + | ||
121 | + function ByteToDec(binary: string) { | ||
122 | + const group = SplitStringToGroupByItemLength(binary, 16) | ||
123 | + return group.map(byte => parseInt(byte, 2)) | ||
124 | + } | ||
125 | + | ||
126 | + function StringToHEXBuffer(string: string | number) { | ||
127 | + return string | ||
128 | + .toString() | ||
129 | + .split('') | ||
130 | + .map(string => string.charCodeAt(0).toString(16)) | ||
131 | + .reverse() | ||
132 | + } | ||
133 | + | ||
134 | + function getRegisterValueByOriginalDataType( | ||
135 | + value: number, | ||
136 | + type: OriginalDataTypeEnum, | ||
137 | + additional?: { bitMask?: number; registerNumber?: number }, | ||
138 | + ) { | ||
139 | + const { exchangeSortFlag } = useParseOriginalDataType(type) | ||
140 | + // eslint-disable-next-line no-console | ||
141 | + console.groupCollapsed('Modbus Debug') | ||
142 | + | ||
143 | + let result: number[] | ||
144 | + | ||
145 | + if (type === OriginalDataTypeEnum.BOOLEAN) { | ||
146 | + result = [value] | ||
147 | + } | ||
148 | + else if (type === OriginalDataTypeEnum.BITS) { | ||
149 | + const { bitMask = 0 } = additional || {} | ||
150 | + const binaryArray = Array.from({ length: 16 }, () => 0) | ||
151 | + binaryArray[15 - bitMask] = value | ||
152 | + result = [parseInt(binaryArray.join(''), 2)] | ||
153 | + } | ||
154 | + else if (type === OriginalDataTypeEnum.STRING) { | ||
155 | + let buffer = StringToHEXBuffer(value) | ||
156 | + const { registerNumber = 0 } = additional || {} | ||
157 | + | ||
158 | + if (buffer.length < registerNumber * 2) { | ||
159 | + buffer = [ | ||
160 | + ...Array.from({ length: registerNumber * 2 - buffer.length }, () => '00'), | ||
161 | + ...buffer, | ||
162 | + ] | ||
163 | + } | ||
164 | + | ||
165 | + result = SplitStringToGroupByItemLength(buffer.join(''), 4).map(hex => parseInt(hex, 16)) | ||
166 | + } | ||
167 | + else { | ||
168 | + // eslint-disable-next-line no-console | ||
169 | + console.table({ input: value, sort: exchangeSortFlag, type }) | ||
170 | + | ||
171 | + let binary = DecToBinaryByType(type, value)! | ||
172 | + | ||
173 | + // eslint-disable-next-line no-console | ||
174 | + console.table({ beforeExchange: binary }) | ||
175 | + | ||
176 | + if (exchangeSortFlag) binary = ExchangeByteOrder(binary, exchangeSortFlag) | ||
177 | + result = ByteToDec(binary) | ||
178 | + | ||
179 | + // eslint-disable-next-line no-console | ||
180 | + console.table({ | ||
181 | + afterEchange: binary, | ||
182 | + dec: result.toString(), | ||
183 | + hex: ByteToHex(binary).toString(), | ||
184 | + }) | ||
185 | + } | ||
186 | + | ||
187 | + // eslint-disable-next-line no-console | ||
188 | + console.groupEnd() | ||
189 | + | ||
190 | + return result | ||
191 | + } | ||
192 | + | ||
193 | + return { | ||
194 | + DecToBinaryByType, | ||
195 | + ByteToDec, | ||
196 | + ByteToHex, | ||
197 | + ExchangeByteOrder, | ||
198 | + SplitStringToGroupByItemLength, | ||
199 | + getRegisterValueByOriginalDataType, | ||
200 | + StringToHEXBuffer, | ||
201 | + } | ||
202 | +} |
src/hooks/business/useCommandDelivery.ts
0 → 100644
1 | +import { ref } from 'vue' | ||
2 | +import { isFunction } from '@wry-smile/utils-is' | ||
3 | +import { useMessage } from '../web/useMessage' | ||
4 | +import { useCoverModbusCommand } from './useCoverModbusCommand' | ||
5 | +import { | ||
6 | + TCPProtocolTypeEnum, | ||
7 | + TransportTypeEnum, | ||
8 | +} from '@/enums/deviceEnum' | ||
9 | +import { FunctionTypeEnum } from '@/enums/objectModelEnum' | ||
10 | +import { CommandCallWayEnum, CommandMethodEnum, CommandTypeEnum, CommandWayEnum } from '@/enums/commandEnum' | ||
11 | +import type { DeviceItemType, DeviceProfileItemType, RpcCommandType, Tsl } from '@/api/device/model' | ||
12 | +import { getDeviceActive, getDeviceInfo, doCommandDelivery as rpcCommandApi } from '@/api/device' | ||
13 | +import { useProductsStoreWithOut } from '@/store/modules/products' | ||
14 | + | ||
15 | +interface SetupType { | ||
16 | + entityId: string | ||
17 | + transportType: TransportTypeEnum | ||
18 | + isTCPModbus: boolean | ||
19 | + deviceCode: string | undefined | ||
20 | + deviceDetail: DeviceItemType | ||
21 | + objectModel: Tsl | undefined | ||
22 | + identifier: string | ||
23 | +} | ||
24 | + | ||
25 | +export interface DoCommandDeliverParamsType { | ||
26 | + value: any | ||
27 | + deviceDetail?: DeviceItemType | ||
28 | + deviceId?: string | ||
29 | + identifier?: string | ||
30 | + objectModel?: Tsl | ||
31 | + deviceProfileId?: string | ||
32 | + deviceProfileDetail?: DeviceProfileItemType | ||
33 | + way?: CommandWayEnum | ||
34 | + cmdType?: CommandTypeEnum | ||
35 | + transportType?: TransportTypeEnum | ||
36 | + penetration?: boolean | ||
37 | + | ||
38 | + beforeFetch?: ( | ||
39 | + rpcCommand: RpcCommandType, | ||
40 | + setup: SetupType | ||
41 | + ) => RpcCommandType | Promise<RpcCommandType> | ||
42 | +} | ||
43 | + | ||
44 | +export function useCommandDelivery() { | ||
45 | + const loading = ref(false) | ||
46 | + async function doSetup(params: DoCommandDeliverParamsType) { | ||
47 | + let { deviceDetail, identifier, deviceProfileId, objectModel, transportType } = params | ||
48 | + const { deviceId, deviceProfileDetail } = params | ||
49 | + | ||
50 | + const entityId = deviceId || deviceDetail?.tbDeviceId | ||
51 | + if (!entityId) | ||
52 | + throw new Error('not found entityId') | ||
53 | + | ||
54 | + identifier = identifier || objectModel?.identifier | ||
55 | + | ||
56 | + if (!identifier) | ||
57 | + throw new Error('not found identifier') | ||
58 | + | ||
59 | + transportType = transportType || (deviceDetail?.transportType as TransportTypeEnum) | ||
60 | + | ||
61 | + if ( | ||
62 | + !transportType | ||
63 | + || (transportType === TransportTypeEnum.TCP && !deviceDetail) | ||
64 | + || !deviceDetail?.deviceProfile | ||
65 | + ) { | ||
66 | + deviceDetail = await getDeviceInfo(entityId) | ||
67 | + transportType = deviceDetail.transportType as TransportTypeEnum | ||
68 | + } | ||
69 | + | ||
70 | + const isTCPModbus | ||
71 | + = transportType === TransportTypeEnum.TCP | ||
72 | + && deviceDetail?.deviceProfile?.profileData?.transportConfiguration?.protocol | ||
73 | + === TCPProtocolTypeEnum.MODBUS_RTU | ||
74 | + | ||
75 | + if (isTCPModbus && !objectModel?.extensionDesc) { | ||
76 | + deviceProfileId = deviceDetail.deviceProfileId || deviceProfileId || deviceProfileDetail?.id | ||
77 | + if (!deviceProfileId) | ||
78 | + throw new Error('not found deviceProfile') | ||
79 | + | ||
80 | + const productStore = useProductsStoreWithOut() | ||
81 | + objectModel = productStore.getObjectModelByIdWithIdentifier(deviceProfileId!, identifier)! | ||
82 | + } | ||
83 | + | ||
84 | + const deviceCode = deviceDetail.code | ||
85 | + return { | ||
86 | + entityId, | ||
87 | + transportType, | ||
88 | + isTCPModbus, | ||
89 | + deviceCode, | ||
90 | + deviceDetail, | ||
91 | + objectModel, | ||
92 | + identifier, | ||
93 | + } | ||
94 | + } | ||
95 | + | ||
96 | + async function doCommandDelivery(params: DoCommandDeliverParamsType) { | ||
97 | + try { | ||
98 | + loading.value = true | ||
99 | + | ||
100 | + const setupResult = await doSetup(params) | ||
101 | + | ||
102 | + const { entityId, transportType, isTCPModbus, deviceCode, objectModel, identifier } | ||
103 | + = setupResult | ||
104 | + | ||
105 | + let command = params.value | ||
106 | + | ||
107 | + let rpcCommand: RpcCommandType = { | ||
108 | + persistent: true, | ||
109 | + method: CommandMethodEnum.THINGSKIT, | ||
110 | + additionalInfo: { | ||
111 | + cmdType: params.cmdType ?? CommandTypeEnum.API, | ||
112 | + }, | ||
113 | + params: command, | ||
114 | + } | ||
115 | + | ||
116 | + let way = params.way ?? CommandWayEnum.ONE_WAY | ||
117 | + | ||
118 | + if (!params.penetration) { | ||
119 | + if (transportType === TransportTypeEnum.TCP) { | ||
120 | + command = params.value | ||
121 | + if (isTCPModbus) { | ||
122 | + const { doCoverCommand } = useCoverModbusCommand() | ||
123 | + command = await doCoverCommand(params.value, objectModel!, deviceCode, entityId) | ||
124 | + } | ||
125 | + } | ||
126 | + else { | ||
127 | + command = { | ||
128 | + [identifier]: command, | ||
129 | + } | ||
130 | + } | ||
131 | + | ||
132 | + if (objectModel?.functionType === FunctionTypeEnum.SERVICE) { | ||
133 | + rpcCommand.additionalInfo.cmdType = CommandTypeEnum.SERVICE | ||
134 | + way | ||
135 | + = objectModel.callType === CommandCallWayEnum.ASYNC | ||
136 | + ? CommandWayEnum.ONE_WAY | ||
137 | + : CommandWayEnum.TWO_WAY | ||
138 | + } | ||
139 | + | ||
140 | + rpcCommand.params = command | ||
141 | + } | ||
142 | + | ||
143 | + const sendApi = rpcCommandApi | ||
144 | + | ||
145 | + if (params.beforeFetch && isFunction(params.beforeFetch)) | ||
146 | + rpcCommand = await params.beforeFetch(rpcCommand, setupResult) | ||
147 | + | ||
148 | + if (way === CommandWayEnum.TWO_WAY) { | ||
149 | + const result = await getDeviceActive(entityId) | ||
150 | + const [firsetItem] = result || [] | ||
151 | + | ||
152 | + if (!firsetItem.value) { | ||
153 | + const { createMessage } = useMessage() | ||
154 | + createMessage.warning('当前设备不在线') | ||
155 | + return | ||
156 | + } | ||
157 | + } | ||
158 | + await sendApi({ way, deviceId: entityId, command: rpcCommand }) | ||
159 | + } | ||
160 | + finally { | ||
161 | + loading.value = false | ||
162 | + } | ||
163 | + } | ||
164 | + | ||
165 | + return { | ||
166 | + loading, | ||
167 | + doCommandDelivery, | ||
168 | + } | ||
169 | +} |
src/hooks/business/useCoverModbusCommand.ts
0 → 100644
1 | +import { isNullOrUnDef } from '@wry-smile/utils-is' | ||
2 | +import { useParseOriginalDataType } from './useParseOriginalDataType' | ||
3 | + | ||
4 | +import { isFloatType, isNumberType, useParseOperationType } from './useParseOperationType' | ||
5 | +import { useBaseConversion } from '@/hooks/business/useBaseConversion' | ||
6 | +import { useMessage } from '@/hooks/web/useMessage' | ||
7 | +import type { ExtensionDesc, Specs, Tsl } from '@/api/device/model' | ||
8 | +import { type GenModbusCommandType, genModbusCommand, getDeviceInfo, getDeviceTelemetryValue } from '@/api/device' | ||
9 | +import { ModbusCRCEnum } from '@/enums/commandEnum' | ||
10 | +import { OriginalDataTypeEnum } from '@/enums/objectModelEnum' | ||
11 | + | ||
12 | +const getFloatPart = (number: string | number) => { | ||
13 | + const isLessZero = Number(number) < 0 | ||
14 | + number = number.toString() | ||
15 | + const floatPartStartIndex = number.indexOf('.') | ||
16 | + const value = ~floatPartStartIndex | ||
17 | + ? `${isLessZero ? '-' : ''}0.${number.substring(floatPartStartIndex + 1)}` | ||
18 | + : '0' | ||
19 | + return Number(value) | ||
20 | +} | ||
21 | + | ||
22 | +function getValueFromValueRange(value: number, valueRange: Record<'min' | 'max', number>) { | ||
23 | + const { min, max } = valueRange || {} | ||
24 | + if (!isNullOrUnDef(min) && value < min) return min | ||
25 | + if (!isNullOrUnDef(max) && value > max) return max | ||
26 | + return value | ||
27 | +} | ||
28 | + | ||
29 | +async function getCurrentBitCommand(entityId: string, objectModel: Tsl, value: number) { | ||
30 | + const deviceDetail = await getDeviceInfo(entityId) | ||
31 | + const thingsModels = deviceDetail.deviceProfile.profileData.thingsModel | ||
32 | + | ||
33 | + const { registerAddress } = objectModel.extensionDesc || {} | ||
34 | + | ||
35 | + const bitsModel = thingsModels?.filter( | ||
36 | + item => | ||
37 | + item.extensionDesc?.originalDataType === OriginalDataTypeEnum.BITS | ||
38 | + && item.extensionDesc.registerAddress === registerAddress, | ||
39 | + ) | ||
40 | + | ||
41 | + const valuePositionMap | ||
42 | + = bitsModel?.reduce((prev, next) => { | ||
43 | + return { ...prev, [next.identifier]: next.extensionDesc?.bitMask } | ||
44 | + }, {} as Record<string, number>) || {} | ||
45 | + | ||
46 | + const attrKeys = Object.keys(valuePositionMap) | ||
47 | + | ||
48 | + const latestBitsValues = await getDeviceTelemetryValue({ entityId, keys: attrKeys.join(',') }) | ||
49 | + | ||
50 | + const binaryArr = Array.from({ length: 16 }, () => 0) | ||
51 | + | ||
52 | + for (const key of attrKeys) { | ||
53 | + const index = valuePositionMap[key] | ||
54 | + | ||
55 | + if (!isNullOrUnDef(index)) { | ||
56 | + const [latest] = latestBitsValues[key] | ||
57 | + const { value } = latest | ||
58 | + binaryArr[index] = Number(value) | ||
59 | + } | ||
60 | + } | ||
61 | + | ||
62 | + if (!isNullOrUnDef(objectModel.extensionDesc?.bitMask)) | ||
63 | + binaryArr[objectModel.extensionDesc.bitMask] = value | ||
64 | + | ||
65 | + return [parseInt(binaryArr.reverse().join(''), 2)] | ||
66 | +} | ||
67 | + | ||
68 | +export function useCoverModbusCommand() { | ||
69 | + const { createMessage } = useMessage() | ||
70 | + | ||
71 | + const doCoverCommand = async (value: number, objectModel: Tsl, deviceAddressCode?: string, entityId?: string) => { | ||
72 | + if (!deviceAddressCode) { | ||
73 | + const message = '当前设备未绑定设备地址码' | ||
74 | + createMessage.warning(message) | ||
75 | + throw new Error(message) | ||
76 | + } | ||
77 | + | ||
78 | + const { | ||
79 | + registerAddress, | ||
80 | + operationType, | ||
81 | + scaling, | ||
82 | + originalDataType, | ||
83 | + bitMask, | ||
84 | + registerCount: registerNumber, | ||
85 | + } = objectModel.extensionDesc as Required<ExtensionDesc> | ||
86 | + | ||
87 | + const { writeRegisterAddress } = useParseOperationType(operationType) | ||
88 | + | ||
89 | + const { unsigned, exchangeSortFlag, registerCount } | ||
90 | + = useParseOriginalDataType(originalDataType) | ||
91 | + | ||
92 | + const params: GenModbusCommandType = { | ||
93 | + crc: ModbusCRCEnum.CRC_16_LOWER, | ||
94 | + registerNumber: registerCount || registerNumber, | ||
95 | + deviceCode: deviceAddressCode, | ||
96 | + registerAddress: parseInt(registerAddress, 16), | ||
97 | + method: writeRegisterAddress!, | ||
98 | + registerValues: [value], | ||
99 | + } | ||
100 | + | ||
101 | + if (exchangeSortFlag) params.hexByteOrderEnum = exchangeSortFlag | ||
102 | + | ||
103 | + const { getRegisterValueByOriginalDataType } = useBaseConversion() | ||
104 | + | ||
105 | + if (isNumberType(originalDataType)) { | ||
106 | + let newValue = Math.trunc(value) * scaling + getFloatPart(value) * scaling | ||
107 | + | ||
108 | + newValue = unsigned ? newValue : Math.abs(newValue) | ||
109 | + | ||
110 | + newValue = getValueFromValueRange( | ||
111 | + newValue, | ||
112 | + (objectModel.specs?.dataType.specs as Specs).valueRange!, | ||
113 | + ) | ||
114 | + | ||
115 | + if (!isFloatType(originalDataType) && newValue % 1 !== 0) { | ||
116 | + const message = `属性下发类型必须是整数,缩放因子为${scaling}` | ||
117 | + createMessage.warning(message) | ||
118 | + throw Error(message) | ||
119 | + } | ||
120 | + | ||
121 | + value = newValue | ||
122 | + } | ||
123 | + | ||
124 | + params.registerValues = originalDataType === OriginalDataTypeEnum.BITS | ||
125 | + ? await getCurrentBitCommand(entityId!, objectModel, value) | ||
126 | + : getRegisterValueByOriginalDataType(value, originalDataType, { | ||
127 | + bitMask, | ||
128 | + registerNumber, | ||
129 | + }) | ||
130 | + | ||
131 | + if (!params.method) { | ||
132 | + const message = '物模型操作类型无法进行写入' | ||
133 | + createMessage.warning(message) | ||
134 | + throw Error(message) | ||
135 | + } | ||
136 | + | ||
137 | + return await genModbusCommand(params) | ||
138 | + } | ||
139 | + | ||
140 | + return { | ||
141 | + doCoverCommand, | ||
142 | + } | ||
143 | +} |
src/hooks/business/useParseOperationType.ts
0 → 100644
1 | +import type { ExtendDescOperationTypeEnum } from '@/enums/objectModelEnum' | ||
2 | +import { | ||
3 | + DataTypeEnum, | ||
4 | + ObjectModelAccessModeEnum, | ||
5 | + OriginalDataTypeEnum, | ||
6 | +} from '@/enums/objectModelEnum' | ||
7 | + | ||
8 | +export function isNumberType(originalDataType: OriginalDataTypeEnum) { | ||
9 | + return ![ | ||
10 | + OriginalDataTypeEnum.BITS, | ||
11 | + OriginalDataTypeEnum.BOOLEAN, | ||
12 | + OriginalDataTypeEnum.STRING, | ||
13 | + ].includes(originalDataType) | ||
14 | +} | ||
15 | + | ||
16 | +export function isFloatType(originalDataType: OriginalDataTypeEnum) { | ||
17 | + return [ | ||
18 | + OriginalDataTypeEnum.FLOAT_AB_CD, | ||
19 | + OriginalDataTypeEnum.FLOAT_BA_DC, | ||
20 | + OriginalDataTypeEnum.FLOAT_CD_AB, | ||
21 | + OriginalDataTypeEnum.FLOAT_DC_BA, | ||
22 | + OriginalDataTypeEnum.DOUBLE, | ||
23 | + ].includes(originalDataType) | ||
24 | +} | ||
25 | + | ||
26 | +export function getDataTypeByOriginalDataType(originalDataType: OriginalDataTypeEnum) { | ||
27 | + if (originalDataType === OriginalDataTypeEnum.STRING) return DataTypeEnum.STRING | ||
28 | + else if (originalDataType === OriginalDataTypeEnum.BOOLEAN) return DataTypeEnum.BOOL | ||
29 | + else if (isFloatType(originalDataType)) return DataTypeEnum.NUMBER_DOUBLE | ||
30 | + else return DataTypeEnum.NUMBER_INT | ||
31 | +} | ||
32 | + | ||
33 | +export function useParseOperationType(actionType: ExtendDescOperationTypeEnum) { | ||
34 | + const [, accessMode, inputOrOutput, output = undefined] = actionType.split('_') | ||
35 | + | ||
36 | + const _accessMode | ||
37 | + = accessMode === ObjectModelAccessModeEnum.READ | ||
38 | + ? ObjectModelAccessModeEnum.READ | ||
39 | + : ObjectModelAccessModeEnum.READ_AND_WRITE | ||
40 | + | ||
41 | + const writeOnly | ||
42 | + = _accessMode === ObjectModelAccessModeEnum.READ_AND_WRITE | ||
43 | + && accessMode !== ObjectModelAccessModeEnum.READ_AND_WRITE | ||
44 | + | ||
45 | + return { | ||
46 | + accessMode: _accessMode, | ||
47 | + originAccessMode: accessMode, | ||
48 | + writeOnly, | ||
49 | + readRegisterAddress: writeOnly ? undefined : inputOrOutput, | ||
50 | + writeRegisterAddress: writeOnly ? inputOrOutput : output, | ||
51 | + } | ||
52 | +} |
1 | +import { OriginalDataTypeEnum } from '@/enums/objectModelEnum' | ||
2 | + | ||
3 | +export type OriginalDataTypePrefixType<S = `${OriginalDataTypeEnum}`> = S extends string | ||
4 | + ? S extends `${infer D}_${string}` | ||
5 | + ? D | ||
6 | + : S | ||
7 | + : '' | ||
8 | + | ||
9 | +function getRegisterCount(originalDataType: OriginalDataTypeEnum) { | ||
10 | + switch (originalDataType) { | ||
11 | + case OriginalDataTypeEnum.INT16_AB: | ||
12 | + case OriginalDataTypeEnum.INT16_BA: | ||
13 | + case OriginalDataTypeEnum.UINT16_AB: | ||
14 | + case OriginalDataTypeEnum.UINT16_BA: | ||
15 | + case OriginalDataTypeEnum.BITS: | ||
16 | + case OriginalDataTypeEnum.BOOLEAN: | ||
17 | + return 1 | ||
18 | + | ||
19 | + case OriginalDataTypeEnum.INT32_AB_CD: | ||
20 | + case OriginalDataTypeEnum.INT32_BA_DC: | ||
21 | + case OriginalDataTypeEnum.INT32_CD_AB: | ||
22 | + case OriginalDataTypeEnum.INT32_DC_BA: | ||
23 | + case OriginalDataTypeEnum.UINT32_AB_CD: | ||
24 | + case OriginalDataTypeEnum.UINT32_BA_DC: | ||
25 | + case OriginalDataTypeEnum.UINT32_CD_AB: | ||
26 | + case OriginalDataTypeEnum.UINT32_DC_BA: | ||
27 | + return 2 | ||
28 | + | ||
29 | + case OriginalDataTypeEnum.FLOAT_AB_CD: | ||
30 | + case OriginalDataTypeEnum.FLOAT_BA_DC: | ||
31 | + case OriginalDataTypeEnum.FLOAT_CD_AB: | ||
32 | + case OriginalDataTypeEnum.FLOAT_DC_BA: | ||
33 | + return 2 | ||
34 | + | ||
35 | + case OriginalDataTypeEnum.DOUBLE: | ||
36 | + return 4 | ||
37 | + } | ||
38 | +} | ||
39 | + | ||
40 | +export function useParseOriginalDataType(originalDataType: OriginalDataTypeEnum) { | ||
41 | + const signedMatchRef = /^UN/ | ||
42 | + | ||
43 | + const splitArray = originalDataType.split('_') as [OriginalDataTypePrefixType] | ||
44 | + | ||
45 | + const [dataType] = splitArray | ||
46 | + | ||
47 | + const exchangeSortFlag = splitArray.slice(1).join('_') | ||
48 | + | ||
49 | + return { | ||
50 | + registerCount: getRegisterCount(originalDataType), | ||
51 | + unsigned: !signedMatchRef.test(originalDataType), | ||
52 | + dataType, | ||
53 | + exchangeSortFlag: exchangeSortFlag || null, | ||
54 | + } | ||
55 | +} |
@@ -43,11 +43,11 @@ foreignObject[thingskit-component] > div > div > div { | @@ -43,11 +43,11 @@ foreignObject[thingskit-component] > div > div > div { | ||
43 | } | 43 | } |
44 | 44 | ||
45 | .act-visible { | 45 | .act-visible { |
46 | - visibility: visible; | 46 | + display: block; |
47 | } | 47 | } |
48 | 48 | ||
49 | .act-hidden { | 49 | .act-hidden { |
50 | - visibility: hidden; | 50 | + display: none; |
51 | } | 51 | } |
52 | 52 | ||
53 | .act-spin-animation { | 53 | .act-spin-animation { |