Commit 85a9d018a6807886a00bc353863cdd4f83a3b71f

Authored by ww
1 parent e7195427

perf: 优化命令下发&&物模型枚举与结构体回显

Showing 32 changed files with 935 additions and 763 deletions
1 -import type { DeviceActiveType, DeviceAttributeItemType, DeviceItemType, DeviceProfileItemType, OrganizationItemType, 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' 3 import type { DeviceTypeEnum } from '@/enums/datasource'
  4 +import { FunctionTypeEnum } from '@/enums/datasource'
4 import { isShareMode } from '@/utils/env' 5 import { isShareMode } from '@/utils/env'
5 import { defHttp } from '@/utils/http' 6 import { defHttp } from '@/utils/http'
6 7
@@ -21,6 +22,8 @@ enum Api { @@ -21,6 +22,8 @@ enum Api {
21 GET_DEVICE_DETAIL = '/device/', // 获取设备详情 22 GET_DEVICE_DETAIL = '/device/', // 获取设备详情
22 23
23 GET_LIST_BY_CONFIGURATION_ID = '/configuration/center/getListByConfigurationId', 24 GET_LIST_BY_CONFIGURATION_ID = '/configuration/center/getListByConfigurationId',
  25 +
  26 + GET_PRODUCTS_DETAIL_WITH_THINGS_MODEL = '/things_model/batch/get_tsl',
24 } 27 }
25 28
26 export interface GenModbusCommandType { 29 export interface GenModbusCommandType {
@@ -139,3 +142,13 @@ export const getListByConfigurationId = (configurationId: string) => { @@ -139,3 +142,13 @@ export const getListByConfigurationId = (configurationId: string) => {
139 url: `${Api.GET_LIST_BY_CONFIGURATION_ID}?configurationId=${configurationId}`, 142 url: `${Api.GET_LIST_BY_CONFIGURATION_ID}?configurationId=${configurationId}`,
140 }) 143 })
141 } 144 }
  145 +
  146 +export const getProductsDetailWithThingsModel = ({ deviceProfileIds, functionTypeEnum }: { deviceProfileIds: string[]; functionTypeEnum?: FunctionTypeEnum | 'all' }) => {
  147 + return defHttp.post<ProductsDetailWithThingsModelType[]>({
  148 + url: Api.GET_PRODUCTS_DETAIL_WITH_THINGS_MODEL,
  149 + data: {
  150 + deviceProfileIds,
  151 + functionTypeEnum: functionTypeEnum || FunctionTypeEnum.PROPERTIES,
  152 + },
  153 + })
  154 +}
1 -import type { DataTypeEnum, FunctionType, TransportTypeEnum } from '@/enums/datasource' 1 +import type { DataTypeEnum, FunctionTypeEnum, TransportTypeEnum } from '@/enums/datasource'
2 2
3 export interface DeviceProfileItemType { 3 export interface DeviceProfileItemType {
4 id: string 4 id: string
@@ -27,6 +27,7 @@ export interface ProfileData { @@ -27,6 +27,7 @@ export interface ProfileData {
27 interface AdditionalInfo { 27 interface AdditionalInfo {
28 cmdType: string 28 cmdType: string
29 } 29 }
  30 +
30 export interface SendValue { 31 export interface SendValue {
31 additionalInfo: AdditionalInfo 32 additionalInfo: AdditionalInfo
32 method: string 33 method: string
@@ -57,7 +58,7 @@ export interface StructJSON { @@ -57,7 +58,7 @@ export interface StructJSON {
57 } 58 }
58 59
59 export interface ThingsModel { 60 export interface ThingsModel {
60 - functionType: FunctionType 61 + functionType: FunctionTypeEnum
61 functionName: string 62 functionName: string
62 identifier: string 63 identifier: string
63 callType: any 64 callType: any
@@ -71,7 +72,7 @@ export interface ThingsModel { @@ -71,7 +72,7 @@ export interface ThingsModel {
71 } 72 }
72 73
73 export interface FunctionJson { 74 export interface FunctionJson {
74 - dataType: DataType | DataType[] 75 + dataType: DataType
75 inputData?: StructJSON[] 76 inputData?: StructJSON[]
76 outputData?: StructJSON[] 77 outputData?: StructJSON[]
77 serviceCommand?: string 78 serviceCommand?: string
@@ -160,7 +161,7 @@ export interface Specs { @@ -160,7 +161,7 @@ export interface Specs {
160 min: string 161 min: string
161 max: string 162 max: string
162 name?: string 163 name?: string
163 - value?: string 164 + value?: any
164 dataType?: DataTypeEnum 165 dataType?: DataTypeEnum
165 } 166 }
166 167
@@ -193,3 +194,23 @@ export interface DeviceActiveType { @@ -193,3 +194,23 @@ export interface DeviceActiveType {
193 lastUpdateTs: number 194 lastUpdateTs: number
194 value: boolean 195 value: boolean
195 } 196 }
  197 +
  198 +export interface ProductsDetailWithThingsModelType {
  199 + id: string
  200 + name: string
  201 + transportType: string
  202 + deviceType: string
  203 + tsl: Tsl[]
  204 +}
  205 +
  206 +export interface Tsl {
  207 + functionName: string
  208 + identifier: string
  209 + accessMode: string
  210 + specs: {
  211 + dataType: DataType
  212 + }
  213 + extensionDesc?: ExtensionDesc
  214 + inputData?: StructJSON[]
  215 + outputData?: StructJSON[]
  216 +}
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' 3 import type { CommandWayEnum } from '@/enums/commandEnum'
4 -import type { ActRangListItemTypeEnum, ActTypeEnum, AggregateTypeEnum, CommandDeliveryWayEnum, DeviceTypeEnum, EventActionTypeEnum, EventTypeEnum, SocketSubscriberEnum, TransportTypeEnum } from '@/enums/datasource' 4 +import type { ActRangListItemTypeEnum, ActTypeEnum, AggregateTypeEnum, CommandDeliveryWayEnum, DeviceTypeEnum, EventActionTypeEnum, EventTypeEnum, SocketSubscriberEnum } from '@/enums/datasource'
5 5
6 export enum DeleteNodeDataTypeEnum { 6 export enum DeleteNodeDataTypeEnum {
7 DATASOURCE = 'DATASOURCE', 7 DATASOURCE = 'DATASOURCE',
@@ -93,18 +93,13 @@ export interface NodeDataDataSourceJsonType { @@ -93,18 +93,13 @@ export interface NodeDataDataSourceJsonType {
93 deviceProfileId: string 93 deviceProfileId: string
94 deviceProfileTemplateId?: string 94 deviceProfileTemplateId?: string
95 attr: string 95 attr: string
96 - attrInfo: ThingsModelItemType  
97 -  
98 - deviceType?: DeviceTypeEnum  
99 - transportType?: TransportTypeEnum  
100 96
101 enable: boolean 97 enable: boolean
102 chartOption?: ChartOptionType 98 chartOption?: ChartOptionType
103 videoOption?: VideoOptionType 99 videoOption?: VideoOptionType
104 alarmListOption?: AlarmListOptionType 100 alarmListOption?: AlarmListOptionType
105 - deviceInfo?: DeviceInfoType  
106 - circularFlowMeterOption?: FlowMeterColorItemType[] // 圆形水球图数据暂定any  
107 - rectFlowMeterOption?: FlowMeterColorItemType[] // 方形水球图颜色配置数据暂定any 101 + circularFlowMeterOption?: FlowMeterColorItemType[]
  102 + rectFlowMeterOption?: FlowMeterColorItemType[]
108 103
109 } 104 }
110 105
@@ -128,17 +123,12 @@ export interface DoubleClickEventDataType { @@ -128,17 +123,12 @@ export interface DoubleClickEventDataType {
128 openPage?: string 123 openPage?: string
129 enable: boolean 124 enable: boolean
130 service?: string 125 service?: string
  126 +
131 serviceCommand?: Recordable 127 serviceCommand?: Recordable
132 way?: CommandWayEnum 128 way?: CommandWayEnum
133 customCommand?: string 129 customCommand?: string
134 - deviceInfo?: DeviceInfoType  
135 commandWay?: CommandDeliveryWayEnum 130 commandWay?: CommandDeliveryWayEnum
136 callType?: string 131 callType?: string
137 - operationPassword?: {  
138 - label: string  
139 - value: string | number  
140 - checked: boolean  
141 - }  
142 } 132 }
143 133
144 export interface SingleClickEventDataType extends DoubleClickEventDataType { } 134 export interface SingleClickEventDataType extends DoubleClickEventDataType { }
@@ -155,7 +145,7 @@ export interface NodeDataEventJsonType { @@ -155,7 +145,7 @@ export interface NodeDataEventJsonType {
155 [EventTypeEnum.SINGLE]: SingleClickEventDataType 145 [EventTypeEnum.SINGLE]: SingleClickEventDataType
156 [EventTypeEnum.DOWN]: MouseDownEventDataType 146 [EventTypeEnum.DOWN]: MouseDownEventDataType
157 [EventTypeEnum.UP]: MouseUpEventDataType 147 [EventTypeEnum.UP]: MouseUpEventDataType
158 - [EventTypeEnum.OPERATION_PASSWORD]: OperationPasswordDataType 148 + [EventTypeEnum.OPERATION_PASSWORD]?: OperationPasswordDataType
159 } 149 }
160 150
161 export interface RangeItemType { 151 export interface RangeItemType {
1 -import type { Specs, StructJSON } from '@/api/device/model'  
2 -import type { NodeDataDataSourceJsonType } from '@/api/node/model' 1 +import type { DeviceItemType, Specs, StructJSON, Tsl } from '@/api/device/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, validateTCPCustomCommand } from '@/core/Library/components/ThingsModelForm'
@@ -15,32 +15,38 @@ export enum FormFieldsEnum { @@ -15,32 +15,38 @@ export enum FormFieldsEnum {
15 } 15 }
16 16
17 export interface AttributeDeliverModalOpenParamsType { 17 export interface AttributeDeliverModalOpenParamsType {
18 - title?: string  
19 - operationPassword?: string  
20 - operationPasswordEnable?: boolean 18 + operationPasswordInfo?: OperationPasswordDataType
21 dataSourceJson: NodeDataDataSourceJsonType 19 dataSourceJson: NodeDataDataSourceJsonType
  20 + eventBindData: SingleClickEventDataType
22 } 21 }
23 22
24 -function getStructJsonFromDataSourceJson(dataSourceJson: NodeDataDataSourceJsonType): StructJSON {  
25 - const { attrInfo } = dataSourceJson  
26 - const { identifier, name, detail } = attrInfo || {} 23 +export interface CreateFormSchemasParamsType {
  24 + deviceInfo: DeviceItemType
  25 + objectModelTsl: Tsl
  26 + operationPasswordInfo?: OperationPasswordDataType
  27 +}
  28 +
  29 +function getStructJsonFromDataSourceJson(objectModelTsl: Tsl): StructJSON {
  30 + const { identifier, functionName, specs } = objectModelTsl || {}
27 return { 31 return {
28 - functionName: name, 32 + functionName,
29 identifier, 33 identifier,
30 - dataType: detail.dataType, 34 + dataType: specs.dataType,
31 } 35 }
32 } 36 }
33 37
34 -function getTCPModbusSchemas({ structJson, required, actionType }: { structJson: StructJSON; required?: boolean; actionType: string }): FormSchema {  
35 - const { dataType } = structJson 38 +function getTCPModbusSchemas({ objectModelTsl, required }: { objectModelTsl: Tsl; required?: boolean }): FormSchema {
  39 + const { specs: tslSpecs, extensionDesc } = objectModelTsl
  40 + const { dataType } = tslSpecs
36 const { specs, type } = dataType || {} 41 const { specs, type } = dataType || {}
37 const { valueRange, length = 10240 } = specs! as Specs 42 const { valueRange, length = 10240 } = specs! as Specs
38 const { max = Number.MAX_SAFE_INTEGER, min = Number.MIN_SAFE_INTEGER } = valueRange || {} 43 const { max = Number.MAX_SAFE_INTEGER, min = Number.MIN_SAFE_INTEGER } = valueRange || {}
  44 + const { actionType } = extensionDesc || {}
39 45
40 function createInputNumber({ 46 function createInputNumber({
41 identifier, 47 identifier,
42 functionName, 48 functionName,
43 - }: StructJSON): FormSchema { 49 + }: Tsl): FormSchema {
44 return { 50 return {
45 field: identifier, 51 field: identifier,
46 label: functionName, 52 label: functionName,
@@ -54,7 +60,7 @@ function getTCPModbusSchemas({ structJson, required, actionType }: { structJson: @@ -54,7 +60,7 @@ function getTCPModbusSchemas({ structJson, required, actionType }: { structJson:
54 } 60 }
55 } 61 }
56 62
57 - const createInput = ({ identifier, functionName }: StructJSON): FormSchema => { 63 + const createInput = ({ identifier, functionName }: Tsl): FormSchema => {
58 return { 64 return {
59 field: identifier, 65 field: identifier,
60 label: functionName, 66 label: functionName,
@@ -74,24 +80,23 @@ function getTCPModbusSchemas({ structJson, required, actionType }: { structJson: @@ -74,24 +80,23 @@ function getTCPModbusSchemas({ structJson, required, actionType }: { structJson:
74 } as FormSchema 80 } as FormSchema
75 } 81 }
76 82
77 - return type === DataTypeEnum.STRING ? createInput(structJson) : createInputNumber(structJson) 83 + return type === DataTypeEnum.STRING ? createInput(objectModelTsl) : createInputNumber(objectModelTsl)
78 } 84 }
79 85
80 -export const createFormSchemas = ({ operationPassword, operationPasswordEnable, dataSourceJson }: AttributeDeliverModalOpenParamsType): FormSchema[] => { 86 +export const createFormSchemas = ({ operationPasswordInfo, objectModelTsl, deviceInfo }: CreateFormSchemasParamsType): FormSchema[] => {
81 const schemas: FormSchema[] = [] 87 const schemas: FormSchema[] = []
82 88
83 - const { deviceInfo } = dataSourceJson  
84 - if (deviceInfo?.transportType === TransportTypeEnum.TCP && deviceInfo.codeType === CodeTypeEnum.MODBUS_RTU && dataSourceJson.deviceInfo?.codeType) {  
85 - schemas.push(getTCPModbusSchemas({ required: true, structJson: getStructJsonFromDataSourceJson(dataSourceJson), actionType: dataSourceJson.deviceInfo?.codeType })) 89 + if (deviceInfo?.transportType === TransportTypeEnum.TCP && deviceInfo.codeType === CodeTypeEnum.MODBUS_RTU && deviceInfo.code) {
  90 + schemas.push(getTCPModbusSchemas({ required: true, objectModelTsl }))
86 } 91 }
87 else { 92 else {
88 - const isStructType = dataSourceJson.attrInfo?.detail?.dataType?.type === DataTypeEnum.STRUCT 93 + const isStructType = objectModelTsl.specs.dataType.type === DataTypeEnum.STRUCT
89 schemas.push( 94 schemas.push(
90 - ...getFormSchemas({ structJSON: isStructType ? dataSourceJson?.attrInfo?.detail?.dataType?.specs as StructJSON[] || [] : [getStructJsonFromDataSourceJson(dataSourceJson)], required: !isStructType }), 95 + ...getFormSchemas({ structJSON: isStructType ? objectModelTsl.specs.dataType.specs as StructJSON[] || [] : [getStructJsonFromDataSourceJson(objectModelTsl)], required: !isStructType }),
91 ) 96 )
92 } 97 }
93 98
94 - if (operationPassword && operationPasswordEnable) { 99 + if (operationPasswordInfo?.value && operationPasswordInfo.checked) {
95 schemas.unshift({ 100 schemas.unshift({
96 field: FormFieldsEnum.PASSWORD, 101 field: FormFieldsEnum.PASSWORD,
97 label: '操作密码', 102 label: '操作密码',
@@ -100,7 +105,7 @@ export const createFormSchemas = ({ operationPassword, operationPasswordEnable, @@ -100,7 +105,7 @@ export const createFormSchemas = ({ operationPassword, operationPasswordEnable,
100 rules: [ 105 rules: [
101 { 106 {
102 validator(_rule, value) { 107 validator(_rule, value) {
103 - if (value && value !== operationPassword) return Promise.reject(new Error('操作密码不正确')) 108 + if (value && value !== operationPasswordInfo.value) return Promise.reject(new Error('操作密码不正确'))
104 return Promise.resolve() 109 return Promise.resolve()
105 }, 110 },
106 }, 111 },
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, unref } from 'vue' 3 +import { nextTick, ref, toRaw, unref } from 'vue'
4 import type { AttributeDeliverModalOpenParamsType } from './AttributeDeliverModal.config' 4 import type { AttributeDeliverModalOpenParamsType } from './AttributeDeliverModal.config'
5 import { createFormSchemas } from './AttributeDeliverModal.config' 5 import { createFormSchemas } from './AttributeDeliverModal.config'
6 -import { useGetModbusCommand } from './useGetModbusCommand' 6 +import { useCommandDeliver } from './useCommadDeliver'
7 import { BasicForm, useForm } from '@/components/Form' 7 import { BasicForm, useForm } from '@/components/Form'
8 import { FormLayoutEnum } from '@/components/Form/src/enum' 8 import { FormLayoutEnum } from '@/components/Form/src/enum'
9 -import type { NodeDataDataSourceJsonType } from '@/api/node/model'  
10 -import { CodeTypeEnum, DataTypeEnum, TransportTypeEnum } from '@/enums/datasource'  
11 -  
12 -const resolveFn = ref<Fn>() 9 +import { DataTypeEnum } from '@/enums/datasource'
13 10
14 const visible = ref(false) 11 const visible = ref(false)
15 12
16 -const password = ref()  
17 -  
18 -const currentDataSourceJson = ref<NodeDataDataSourceJsonType>()  
19 -  
20 const [register, { getFieldsValue, resetFields, validate, setProps, clearValidate }] = useForm({ 13 const [register, { getFieldsValue, resetFields, validate, setProps, clearValidate }] = useForm({
21 layout: FormLayoutEnum.VERTICAL, 14 layout: FormLayoutEnum.VERTICAL,
22 showActionButtonGroup: false, 15 showActionButtonGroup: false,
23 }) 16 })
24 17
25 -const open = async ({ title, operationPassword, operationPasswordEnable, dataSourceJson }: AttributeDeliverModalOpenParamsType) => { 18 +const { setup, getDeviceInfo, getObjectModelTsl, doCommandDeliver } = useCommandDeliver()
  19 +
  20 +const open = async ({ operationPasswordInfo, dataSourceJson, eventBindData }: AttributeDeliverModalOpenParamsType) => {
26 visible.value = true 21 visible.value = true
27 - password.value = operationPassword  
28 - currentDataSourceJson.value = dataSourceJson  
29 - return new Promise((resolve) => {  
30 - resolveFn.value = resolve  
31 - nextTick(() => {  
32 - setProps({ schemas: createFormSchemas({ title, operationPassword, operationPasswordEnable, dataSourceJson }) })  
33 - }) 22 + const { deviceId, deviceProfileId, attr } = dataSourceJson
  23 + const { way } = eventBindData
  24 + await setup({ deviceId, deviceProfileId, attr, callType: way })
  25 +
  26 + nextTick(() => {
  27 + const schemas = createFormSchemas({ operationPasswordInfo, deviceInfo: toRaw(unref(getDeviceInfo)!), objectModelTsl: toRaw(unref(getObjectModelTsl)!) })
  28 + setProps({ schemas })
34 }) 29 })
35 } 30 }
36 31
37 async function getResult() { 32 async function getResult() {
38 const result = getFieldsValue() 33 const result = getFieldsValue()
39 - const isTCPModbusDevice = unref(currentDataSourceJson)?.deviceInfo?.transportType === TransportTypeEnum.TCP && unref(currentDataSourceJson)?.deviceInfo?.codeType === CodeTypeEnum.MODBUS_RTU  
40 - const isStructJSON = unref(currentDataSourceJson)?.attrInfo?.detail?.dataType?.type === DataTypeEnum.STRUCT  
41 - const attrKey = unref(currentDataSourceJson)!.attr  
42 - if (!isTCPModbusDevice) { return isStructJSON ? result : result[attrKey] }  
43 - else {  
44 - const value = result[attrKey]  
45 - const isString = unref(currentDataSourceJson)?.attrInfo?.detail?.dataType?.type === DataTypeEnum.STRING  
46 -  
47 - if (isString) return value  
48 -  
49 - const { getModbusCommand, validateCanGetCommand } = useGetModbusCommand()  
50 - if (!validateCanGetCommand(unref(currentDataSourceJson)!.attrInfo.extensionDesc, unref(currentDataSourceJson)!.deviceInfo?.code).flag) return  
51 -  
52 - const res = await getModbusCommand(value as unknown as number, unref(currentDataSourceJson)!.attrInfo.extensionDesc!, unref(currentDataSourceJson)!.deviceInfo!.code!)  
53 - return res  
54 - } 34 + const isStructJSON = unref(getObjectModelTsl)?.specs.dataType.type === DataTypeEnum.STRUCT
  35 + const identifier = unref(getObjectModelTsl)!.identifier
  36 + await doCommandDeliver(isStructJSON ? result : result[identifier])
55 } 37 }
56 38
57 const handleOk = async () => { 39 const handleOk = async () => {
58 await validate() 40 await validate()
59 - const result = await getResult()  
60 - if (!result) return  
61 - unref(resolveFn)?.(result) 41 + await getResult()
62 visible.value = false 42 visible.value = false
63 resetFields() 43 resetFields()
64 } 44 }
@@ -73,7 +53,7 @@ defineExpose({ open }) @@ -73,7 +53,7 @@ defineExpose({ open })
73 53
74 <template> 54 <template>
75 <Modal 55 <Modal
76 - v-model:open="visible" title="属性下发" ok-text="确认" :width="400" cancel-text="取消" @cancel="handleCancel" 56 + v-model:open="visible" :title="`属性下发 / ${getDeviceInfo?.alias || getDeviceInfo?.name}`" ok-text="确认" :width="400" cancel-text="取消" @cancel="handleCancel"
77 @ok="handleOk" 57 @ok="handleOk"
78 > 58 >
79 <BasicForm @register="register" /> 59 <BasicForm @register="register" />
1 -<script setup lang="ts">  
2 -import { Icon } from '@iconify/vue'  
3 -import { Modal } from 'ant-design-vue'  
4 -import { ref, unref } from 'vue'  
5 -  
6 -const visible = ref(false)  
7 -  
8 -const resolveFn = ref<Fn>()  
9 -  
10 -const rejectFn = ref<Fn>()  
11 -  
12 -const open = async () => {  
13 - visible.value = true  
14 - return new Promise((resolve, reject) => {  
15 - resolveFn.value = resolve  
16 - rejectFn.value = reject  
17 - })  
18 -}  
19 -  
20 -const handleOk = () => {  
21 - unref(resolveFn)?.()  
22 - visible.value = false  
23 -}  
24 -  
25 -const handleCancel = () => {  
26 - unref(rejectFn)?.()  
27 - visible.value = false  
28 -}  
29 -  
30 -defineExpose({ open })  
31 -</script>  
32 -  
33 -<template>  
34 - <Modal v-model:open="visible" :width="400" ok-text="确认" cancel-text="取消" @ok="handleOk" @cancel="handleCancel">  
35 - <template #title>  
36 - <div class="flex">  
37 - <span><Icon icon="ant-design:exclamation-circle-filled" class="text-yellow-300 text-xl" /></span>  
38 - <span class="font-bold ml-2">提示</span>  
39 - </div>  
40 - </template>  
41 - <div class="ml-5">  
42 - 是否确认此操作?  
43 - </div>  
44 - </Modal>  
45 -</template>  
src/core/Library/components/PublicForm/components/DataEvents/CommandDeliveryModal/SwitchCommandDeliveryModal.vue renamed from src/core/Library/components/PublicForm/components/DataEvents/CommandDeliveryModal/CommandDeliveryConfirmModal.vue
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, unref } from 'vue' 3 +import { computed, nextTick, ref, unref } from 'vue'
  4 +import { Icon } from '@iconify/vue'
  5 +import { useCommandDeliver } from './useCommadDeliver'
4 import { BasicForm, type FormSchema, useForm } from '@/components/Form' 6 import { BasicForm, type FormSchema, useForm } from '@/components/Form'
5 import { ComponentEnum, FormLayoutEnum } from '@/components/Form/src/enum' 7 import { ComponentEnum, FormLayoutEnum } from '@/components/Form/src/enum'
  8 +import type { NodeDataDataSourceJsonType, OperationPasswordDataType, SingleClickEventDataType } from '@/api/node/model'
6 9
7 -const resolveFn = ref<Fn>() 10 +interface SwitchCommandDeliveryModalParamsType {
  11 + operationPasswordInfo?: OperationPasswordDataType
  12 + dataSourceJson: NodeDataDataSourceJsonType
  13 + eventBindData: SingleClickEventDataType
  14 + sendValue: any
  15 +}
8 16
9 const visible = ref(false) 17 const visible = ref(false)
10 18
  19 +const currentOperationPasswordInfo = ref<OperationPasswordDataType>()
  20 +
  21 +const currendSendValue = ref()
  22 +
11 const [register, { resetFields, validate, setProps }] = useForm({ 23 const [register, { resetFields, validate, setProps }] = useForm({
12 showActionButtonGroup: false, 24 showActionButtonGroup: false,
13 layout: FormLayoutEnum.VERTICAL, 25 layout: FormLayoutEnum.VERTICAL,
@@ -18,7 +30,7 @@ const createFormSchemas = (password: string): FormSchema[] => { @@ -18,7 +30,7 @@ const createFormSchemas = (password: string): FormSchema[] => {
18 { 30 {
19 field: 'password', 31 field: 'password',
20 component: ComponentEnum.INPUT_PAWSSWORD, 32 component: ComponentEnum.INPUT_PAWSSWORD,
21 - label: '', 33 + label: '操作密码',
22 required: true, 34 required: true,
23 rules: [{ 35 rules: [{
24 validator(_rule, value) { 36 validator(_rule, value) {
@@ -33,21 +45,27 @@ const createFormSchemas = (password: string): FormSchema[] => { @@ -33,21 +45,27 @@ const createFormSchemas = (password: string): FormSchema[] => {
33 ] 45 ]
34 } 46 }
35 47
36 -const open = async (pwd: string) => {  
37 - visible.value = true  
38 - return new Promise((resolve) => {  
39 - resolveFn.value = resolve 48 +const getHasEnableOperationPassword = computed(() => !!(unref(currentOperationPasswordInfo)?.checked && unref(currentOperationPasswordInfo)?.value))
  49 +
  50 +const { setup, doCommandDeliver, getDeviceInfo } = useCommandDeliver()
40 51
41 - nextTick(() => {  
42 - setProps({ schemas: createFormSchemas(pwd) })  
43 - }) 52 +const open = async ({ operationPasswordInfo, dataSourceJson, eventBindData, sendValue }: SwitchCommandDeliveryModalParamsType) => {
  53 + visible.value = true
  54 + 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 })
  59 + nextTick(() => {
  60 + unref(getHasEnableOperationPassword) && setProps({ schemas: createFormSchemas(operationPasswordInfo!.value!) })
44 }) 61 })
45 } 62 }
46 63
47 const handlerOk = async () => { 64 const handlerOk = async () => {
48 - await validate()  
49 - unref(resolveFn)?.(true)  
50 - resetFields() 65 + if (unref(getHasEnableOperationPassword))
  66 + await validate()
  67 + await doCommandDeliver(unref(currendSendValue))
  68 + if (unref(getHasEnableOperationPassword)) resetFields()
51 visible.value = false 69 visible.value = false
52 } 70 }
53 71
@@ -56,10 +74,27 @@ defineExpose({ open }) @@ -56,10 +74,27 @@ defineExpose({ open })
56 74
57 <template> 75 <template>
58 <Modal 76 <Modal
59 - v-model:open="visible" :width="300" ok-text="确认" cancel-text="取消"  
60 - title="操作密码" 77 + v-model:open="visible"
  78 + :title="`属性下发 / ${getDeviceInfo?.alias || getDeviceInfo?.name}`"
  79 + :width="300"
  80 + ok-text="确认"
  81 + cancel-text="取消"
  82 + destroy-on-close
61 @ok="handlerOk" 83 @ok="handlerOk"
62 > 84 >
63 - <BasicForm @register="register" /> 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> -->
  92 + <BasicForm v-if="getHasEnableOperationPassword" @register="register" />
  93 + <div v-else class="flex items-center">
  94 + <Icon icon="ant-design:exclamation-circle-filled" class="text-yellow-300 text-xl" />
  95 + <span class="ml-2">
  96 + 是否确认此操作?
  97 + </span>
  98 + </div>
64 </Modal> 99 </Modal>
65 </template> 100 </template>
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 { StructJSON } from '@/api/device/model' 3 +import type { Tsl } from '@/api/device/model'
  4 +import type { OperationPasswordDataType } from '@/api/node/model'
  5 +import { validateTCPCustomCommand } from '@/core/Library/components/ThingsModelForm'
  6 +import { JSONEditorValidator } from '@/components/CodeEditor/src/JSONEditor'
  7 +import { DataTypeEnum } from '@/enums/datasource'
  8 +
  9 +export enum FormFieldsEnum {
  10 + CUSTOM_COMMAND = 'customCommand',
  11 + OPERATION_PASSWORD = 'password',
  12 +
  13 + SERVICE_COMMAND = 'serviceCommand',
  14 +}
  15 +
4 export const formSchemas: FormSchema[] = [ 16 export const formSchemas: FormSchema[] = [
5 { 17 {
6 field: 'sendValue', 18 field: 'sendValue',
@@ -10,219 +22,122 @@ export const formSchemas: FormSchema[] = [ @@ -10,219 +22,122 @@ export const formSchemas: FormSchema[] = [
10 }, 22 },
11 ] 23 ]
12 24
13 -const InsertString = (t: any, c: any, n: any) => {  
14 - const r: string | number[] = []  
15 -  
16 - for (let i = 0; i * 2 < t.length; i++)  
17 - r.push(t.substr(i * 2, n))  
18 -  
19 - return r.join(c)  
20 -}  
21 -const FillString = (t: any, c: any, n: any, b: any) => {  
22 - if (t === '' || c.length !== 1 || n <= t.length)  
23 - return t  
24 -  
25 - const l = t.length  
26 -  
27 - for (let i = 0; i < n - l; i++) {  
28 - if (b === true)  
29 - t = c + t 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)
30 29
31 - else  
32 - t += c 30 + const _formSchema: FormSchema = {
  31 + field: identifier,
  32 + label: functionName,
  33 + component: ComponentEnum.INPUT_NUMBER,
33 } 34 }
34 - return t  
35 -}  
36 -const SingleToHex = (t: any) => {  
37 - if (t === '')  
38 - return ''  
39 -  
40 - t = parseFloat(t)  
41 -  
42 - if (isNaN(t) === true)  
43 - return 'Error'  
44 -  
45 - if (t === 0)  
46 - return '00000000'  
47 -  
48 - let s, e, m  
49 35
50 - if (t > 0) {  
51 - s = 0 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>)
52 } 46 }
53 - else {  
54 - s = 1  
55 47
56 - t = 0 - t 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>)
57 } 58 }
58 - m = t.toString(2)  
59 59
60 - if (m >= 1) {  
61 - if (m.indexOf('.') === -1)  
62 - m = `${m}.0`  
63 -  
64 - e = m.indexOf('.') - 1  
65 - }  
66 - else {  
67 - e = 1 - m.indexOf('1') 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>)
68 } 69 }
69 - if (e >= 0)  
70 - m = m.replace('.', '')  
71 -  
72 - else  
73 - m = m.substring(m.indexOf('1'))  
74 -  
75 - if (m.length > 24)  
76 - m = m.substr(0, 24)  
77 -  
78 - else  
79 - m = FillString(m, '0', 24, false)  
80 -  
81 - m = m.substring(1)  
82 -  
83 - e = (e + 127).toString(2)  
84 -  
85 - e = FillString(e, '0', 8, true)  
86 -  
87 - let r = parseInt(s + e + m, 2).toString(16)  
88 -  
89 - r = FillString(r, '0', 8, true)  
90 70
91 - return InsertString(r, ' ', 2).toUpperCase()  
92 -}  
93 -  
94 -const FormatHex = (t: any, n: any, ie: any) => {  
95 - const r: string[] = []  
96 -  
97 - let s = ''  
98 -  
99 - let c = 0  
100 -  
101 - for (let i = 0; i < t.length; i++) {  
102 - if (t.charAt(i) !== ' ') {  
103 - s += t.charAt(i)  
104 -  
105 - c += 1  
106 -  
107 - if (c === n) {  
108 - r.push(s)  
109 -  
110 - s = ''  
111 -  
112 - c = 0  
113 - }  
114 - }  
115 - if (ie === false) {  
116 - if (i === t.length - 1 && s !== '')  
117 - r.push(s)  
118 - } 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>)
119 } 80 }
120 - return r.join('\n')  
121 -}  
122 -const FormatHexBatch = (t: any, n: any, ie: any) => {  
123 - const a = t.split('\n')  
124 -  
125 - const r: string[] = []  
126 -  
127 - for (let i = 0; i < a.length; i++)  
128 - r[i] = FormatHex(a[i], n, ie)  
129 81
130 - return r.join('\n')  
131 -}  
132 -const SingleToHexBatch = (t: any) => {  
133 - const a = t.split('\n')  
134 -  
135 - const r: string[] = [] 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 + }
136 88
137 - for (let i = 0; i < a.length; i++)  
138 - r[i] = SingleToHex(a[i]) 89 + const schemas = schemasMap[type as DataTypeEnum]?.()
139 90
140 - return r.join('\r\n') 91 + return [schemas!]
141 } 92 }
142 93
143 -const formSchemasConfig = (schemas: StructJSON, actionType: any): FormSchema[] => {  
144 - const { identifier, functionName } = schemas  
145 - if (actionType === '06') {  
146 - return [  
147 - {  
148 - field: identifier,  
149 - label: functionName,  
150 - component: ComponentEnum.INPUT_NUMBER,  
151 - rules: [{ required: true, message: '请输入正数' }],  
152 - componentProps: {  
153 - min: 0,  
154 - formatter: (e: any) => {  
155 - const value = `${e}`.replace('-', '').replace(/^(-)*(\d+)\.(\d\d).*$/, '$1$2.$3')  
156 - return value 94 +export const getOperationPasswordSchemas = (operationPasswordInfo: OperationPasswordDataType): FormSchema[] => {
  95 + return [
  96 + {
  97 + field: FormFieldsEnum.OPERATION_PASSWORD,
  98 + label: '操作密码',
  99 + component: ComponentEnum.INPUT_PAWSSWORD,
  100 + required: true,
  101 + rules: [
  102 + {
  103 + validator(_rule, value: string) {
  104 + if (value !== operationPasswordInfo.value)
  105 + return Promise.reject(Error('操作密码不正确'))
  106 + return Promise.resolve()
157 }, 107 },
158 - placeholder: '请输入正数',  
159 }, 108 },
  109 + ],
  110 + componentProps: {
  111 + placeholder: '请输入操作密码',
  112 + max: 120,
  113 + autocomplete: 'cc-number',
160 }, 114 },
161 - ]  
162 - }  
163 - else if (actionType === '05') {  
164 - return [  
165 - {  
166 - field: identifier,  
167 - label: functionName,  
168 - component: ComponentEnum.INPUT_NUMBER,  
169 - rules: [{ required: true, message: '请输入值' }],  
170 - componentProps: {  
171 - min: 0,  
172 - max: 1,  
173 - precision: 0,  
174 - placeholder: '请输入0或1',  
175 - },  
176 - },  
177 - ]  
178 - }  
179 - else {  
180 - return [  
181 - {  
182 - field: identifier,  
183 - label: functionName,  
184 - component: ComponentEnum.INPUT_NUMBER,  
185 - rules: [{ required: true, message: '请输入值' }],  
186 - componentProps: {  
187 - placeholder: '请输入数字',  
188 - formatter: (e: any) =>  
189 - `${e}`.replace(/\B(?=(\d{3})+(?!\d))/g, '').replace(/^(-)*(\d+)\.(\d\d).*$/, '$1$2.$3'),  
190 - },  
191 - },  
192 - ]  
193 - } 115 + },
  116 + ]
194 } 117 }
195 118
196 -const getArray = (values: any) => {  
197 - const str = values.replace(/\s+/g, '')  
198 - const array: any = []  
199 -  
200 - for (let i = 0; i < str.length; i += 4) {  
201 - const chunk = parseInt(str.substring(i, i + 4), 16)  
202 - array.push(chunk)  
203 - }  
204 - return array 119 +export const getTcpCustomCommandSchemas = (): FormSchema[] => {
  120 + return [
  121 + {
  122 + field: FormFieldsEnum.CUSTOM_COMMAND,
  123 + label: '自定义命令',
  124 + component: ComponentEnum.INPUT,
  125 + required: true,
  126 + rules: [{ validator: validateTCPCustomCommand }],
  127 + },
  128 + ]
205 } 129 }
206 130
207 -// 获取小数  
208 -const getFloatPart = (number: string | number) => {  
209 - const isLessZero = Number(number) < 0  
210 - number = number.toString()  
211 - const floatPartStartIndex = number.indexOf('.')  
212 - const value = ~floatPartStartIndex  
213 - ? `${isLessZero ? '-' : ''}0.${number.substring(floatPartStartIndex + 1)}`  
214 - : '0'  
215 - return Number(value) 131 +export const getJSONCommandSchemas = (): FormSchema[] => {
  132 + return [
  133 + {
  134 + field: FormFieldsEnum.CUSTOM_COMMAND,
  135 + label: '自定义命令',
  136 + component: ComponentEnum.JSON_EDITOR,
  137 + required: true,
  138 + changeEvent: 'update:value',
  139 + rules: JSONEditorValidator(),
  140 + },
  141 + ]
216 } 142 }
217 143
218 -export {  
219 - InsertString,  
220 - FillString,  
221 - SingleToHex,  
222 - FormatHex,  
223 - FormatHexBatch,  
224 - SingleToHexBatch,  
225 - formSchemasConfig,  
226 - getArray,  
227 - getFloatPart,  
228 -}  
1 export { default as CommandDeliveryModal } from './index.vue' 1 export { default as CommandDeliveryModal } from './index.vue'
2 -export { default as CommandDeliveryConfirmModal } from './CommandDeliveryConfirmModal.vue'  
3 -export { default as ConfirmModal } from './ConfirmModal.vue' 2 +export { default as SwitchCommandDeliveryModal } from './SwitchCommandDeliveryModal.vue'
4 export { default as AttributeDeliverModal } from './AttributeDeliverModal.vue' 3 export { default as AttributeDeliverModal } from './AttributeDeliverModal.vue'
1 <script setup lang="ts"> 1 <script setup lang="ts">
2 -import { nextTick, reactive, ref, 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 { SingleToHex, formSchemas, formSchemasConfig, getArray, getFloatPart } from './config.ts'  
5 -import { BasicModal } from '@/components/Modal'  
6 -import type { SingleClickEventDataType } from '@/api/node/model' 4 +import { FormFieldsEnum, formSchemas, getJSONCommandSchemas, getModbusSchemas, getOperationPasswordSchemas, getTcpCustomCommandSchemas } from './config.ts'
  5 +import { useCommandDeliver } from './useCommadDeliver'
  6 +import { BasicModal, useModalInner } from '@/components/Modal'
  7 +import type { NodeDataDataSourceJsonType, OperationPasswordDataType, SingleClickEventDataType } from '@/api/node/model'
7 import { BasicForm, useForm } from '@/components/Form' 8 import { BasicForm, useForm } from '@/components/Form'
8 -import { ComponentEnum, FormLayoutEnum } from '@/components/Form/src/enum'  
9 -import { CommandDeliveryWayEnum, CommandTypeEnum, TransportTypeEnum } from '@/enums/datasource'  
10 -import { genModbusCommand, getDeviceActiveTime, getDeviceInfo, getThingsModelServices, sendRpcOneway } from '@/api/device' 9 +import { FormLayoutEnum } from '@/components/Form/src/enum'
  10 +import { CommandDeliveryWayEnum, TransportTypeEnum } from '@/enums/datasource'
11 import { ThingsModelForm } from '@/core/Library/components/ThingsModelForm' 11 import { ThingsModelForm } from '@/core/Library/components/ThingsModelForm'
12 -import { useMessage } from '@/hooks/web/useMessage'  
13 -import type { StructJSON } from '@/api/device/model'  
14 -  
15 -interface ServiceInfo {  
16 - title?: string  
17 - serviceCommand?: Object  
18 - inputData?: []  
19 - transportType?: string  
20 - callType?: string  
21 - code?: string  
22 - way?: string 12 +import type { DeviceItemType, Tsl } from '@/api/device/model'
  13 +import { useProductsStoreWithOut } from '@/store/modules/products'
  14 +import { useJsonParse } from '@/hooks/business/useJSONParse'
  15 +import { CommandCallWayEnum, CommandWayEnum } from '@/enums/commandEnum'
  16 +
  17 +interface OpenParamsType {
  18 + dataSource: NodeDataDataSourceJsonType
  19 + eventBindData: SingleClickEventDataType
  20 + operationPasswordInfo?: OperationPasswordDataType
23 } 21 }
24 22
25 -const visible = ref<boolean>(false) 23 +const thingsModelElRef = ref<InstanceType<typeof ThingsModelForm>>()
26 24
27 -const { createMessage } = useMessage()  
28 -const loading = ref<boolean>(false)  
29 -  
30 -const dataSourceJson = ref<any>({})  
31 -const thingsModelElRef = ref()  
32 -  
33 -const isInputData = ref<boolean>(false)// 判断使用那个表单 true: 用封装的表单 false:用自己写的表单  
34 -  
35 -const zoomFactorValue = ref<number>(1) // 缩放因子  
36 -const isShowMultiply = ref<boolean>(false) // 只有tcp --> int和double类型才相乘缩放因子  
37 -const isShowActionType = ref<boolean>(true) // 判断设备属性标识符为modBus时没有填写扩展描述  
38 -const isShowModBUS = ref<boolean>(false) // 用于判断标识符类型是否时自定义还是modBUS  
39 -const modBUSForm = ref<any>({})  
40 -const formField = ref('') // 存一个表单取值的field  
41 -const isCommandWay = ref<undefined | string>('') // 存取命令下发方式的值  
42 -const deviceTitle = ref<string | undefined>()// 设备名称 25 +const getDefaultConfiguration = () => ({
  26 + modalVisible: false,
  27 + commandDeliveryWay: CommandDeliveryWayEnum.CUSTOM,
  28 + operationPasswordEnable: false,
  29 +})
43 30
44 -const isPasswordInfo = ref<{ checked?: boolean; value?: string | number; label?: string }>({})// 是否需要操作密码才进行命令下发 31 +const configuration = reactive(getDefaultConfiguration())
45 32
46 -const serviceInfo = reactive<ServiceInfo>({  
47 - title: '',  
48 - serviceCommand: {},  
49 - inputData: [],  
50 - transportType: '',  
51 - callType: '',  
52 - code: '',  
53 - way: '', // 单向还是双向  
54 -}) 33 +const [registerModal, { setModalProps, closeModal }] = useModalInner()
55 34
56 -const [register, { getFieldsValue, validate, setFieldsValue, updateSchema, setProps }] = useForm({ // 自定义下发值  
57 - schemas: formSchemas, 35 +// 操作密码
  36 +const [registerPassword, operationPasswordFormAction] = useForm({
58 showActionButtonGroup: false, 37 showActionButtonGroup: false,
59 layout: FormLayoutEnum.VERTICAL, 38 layout: FormLayoutEnum.VERTICAL,
60 labelWidth: 110, 39 labelWidth: 110,
61 }) 40 })
62 41
63 -const [registerPassword, { getFieldsValue: getPasswordValue, validate: validatePassword }] = useForm({ // 操作密码  
64 - schemas: [{  
65 - field: 'password',  
66 - label: '操作密码',  
67 - component: ComponentEnum.INPUT_PAWSSWORD,  
68 - required: true,  
69 - componentProps: {  
70 - placeholder: '请输入操作密码',  
71 - max: 120,  
72 - },  
73 - }], 42 +// 自定义下发值
  43 +const [register, customCommandFormAction] = useForm({
  44 + schemas: formSchemas,
74 showActionButtonGroup: false, 45 showActionButtonGroup: false,
75 layout: FormLayoutEnum.VERTICAL, 46 layout: FormLayoutEnum.VERTICAL,
76 - labelWidth: 110,  
77 }) 47 })
78 48
79 -const getServiceInfo = async (deviceProfileId: string, service?: string, serviceCommand?: Recordable) => {  
80 - isInputData.value = true  
81 - const functionJson: any = await getThingsModelServices(deviceProfileId)  
82 - serviceInfo.inputData = functionJson.filter((item: any) => item.identifier === service)?.[0].functionJson.inputData  
83 - serviceInfo.title = functionJson[0].functionName  
84 - serviceInfo.serviceCommand = serviceCommand 49 +function handleHasOperationPassword(operationPasswordInfo: OperationPasswordDataType) {
  50 + configuration.operationPasswordEnable = true
  51 + nextTick(() => {
  52 + operationPasswordFormAction.setProps({
  53 + schemas: getOperationPasswordSchemas(operationPasswordInfo),
  54 + })
  55 + })
  56 +}
  57 +
  58 +function handleOpenCustomCommandModal(deviceInfo: DeviceItemType, eventBindData: SingleClickEventDataType) {
  59 + const { transportType } = deviceInfo
  60 +
  61 + const { setProps, setFieldsValue } = customCommandFormAction
  62 + if (transportType === TransportTypeEnum.TCP)
  63 + setProps({ schemas: getTcpCustomCommandSchemas() })
  64 + else
  65 + setProps({ schemas: getJSONCommandSchemas() })
  66 +
  67 + setFieldsValue({ [FormFieldsEnum.CUSTOM_COMMAND]: eventBindData.customCommand })
  68 +}
  69 +
  70 +function handleOpenServiceCommandModal(deviceInfo: DeviceItemType, eventBindData: SingleClickEventDataType) {
  71 + const { service, serviceCommand = {} } = eventBindData
  72 +
  73 + const productsStore = useProductsStoreWithOut()
  74 +
  75 + const tsl = productsStore.getObjectModelByIdWithIdentifier(deviceInfo.deviceProfileId, service!)
  76 + unref(thingsModelElRef)?.setProps({ inputData: tsl?.inputData, transportType: deviceInfo.transportType, title: tsl?.functionName })
  77 +
  78 + nextTick(() => {
  79 + unref(thingsModelElRef)?.setFieldsValue(serviceCommand)
  80 + })
85 } 81 }
86 82
87 -// 获取设备信息  
88 -const getDeviceDetail = async (deviceId: string) => {  
89 - return await getDeviceInfo(deviceId) 83 +function handleOpenModbusCommandModal(objectModelTsl: Tsl) {
  84 + const { setProps } = customCommandFormAction
  85 + setProps({ schemas: getModbusSchemas(objectModelTsl) })
90 } 86 }
91 87
92 -const open = async (_data: SingleClickEventDataType) => {  
93 - const { operationPassword } = _data || {}  
94 - dataSourceJson.value = _data.deviceInfo  
95 - isPasswordInfo.value = operationPassword || {}  
96 - // commandWay-->命令下发方式  
97 - const { commandWay, customCommand, serviceCommand, service, callType, way } = _data || {}  
98 - isCommandWay.value = commandWay  
99 - const { attrInfo, deviceId } = unref(dataSourceJson)  
100 - const { identifier, extensionDesc, detail, name } = attrInfo || {}// 属性信息  
101 - const { dataType } = detail || {}  
102 - const { type } = dataType || {}  
103 -  
104 - const { code, transportType, deviceProfileId, alias, name: deviceName } = await getDeviceDetail(deviceId) || {}// 设备信息  
105 - deviceTitle.value = alias || deviceName// 产品名称  
106 - const { registerAddress, actionType, zoomFactor } = extensionDesc || {} // 获取扩展描述内容  
107 -  
108 - const schemas = [{ dataType, identifier, functionName: name } as StructJSON]  
109 -  
110 - zoomFactorValue.value = zoomFactor ? Number(zoomFactor) : 1  
111 - isShowMultiply.value = !!(type === 'INT' || type === 'DOUBLE')  
112 - formField.value = identifier  
113 - isShowActionType.value = !!actionType // 判断modBUS类型时 物模型是否填写扩展描述  
114 - serviceInfo.callType = callType // 服务命令调用方式 是同步还是异步  
115 - serviceInfo.way = way || 'oneway' // 命令下发是双向还是单向  
116 -  
117 - serviceInfo.transportType = transportType  
118 - serviceInfo.code = code  
119 -  
120 - visible.value = true  
121 -  
122 - if (transportType === TransportTypeEnum.TCP) {  
123 - if (commandWay === CommandDeliveryWayEnum.SERVICE) { // 判断命令下发方式是服务或者自定义调用 服务调用用封装的组件 自定义和modbus就用输入框  
124 - getServiceInfo(deviceProfileId, service, serviceCommand)  
125 - }  
126 - else if (commandWay === CommandDeliveryWayEnum.CUSTOM) { // 自定义  
127 - await nextTick()  
128 - updateSchema([  
129 - {  
130 - field: 'sendValue',  
131 - required: true,  
132 - label: '自定义下发值',  
133 - component: ComponentEnum.INPUT,  
134 - },  
135 - ])  
136 - setFieldsValue({ sendValue: customCommand })  
137 - }  
138 - else { // modBus调用  
139 - isShowModBUS.value = true  
140 - modBUSForm.value = {  
141 - crc: 'CRC_16_LOWER',  
142 - deviceCode: code,  
143 - method: actionType === '16' ? '10' : actionType,  
144 - registerAddress,  
145 - registerNumber: 1,  
146 - registerValues: [],  
147 - }  
148 - await nextTick()  
149 - setProps({ schemas: formSchemasConfig(schemas[0], actionType) })  
150 - }  
151 - }  
152 - else {  
153 - isShowModBUS.value = false  
154 -  
155 - // 命令下发方式是服务或则自定义调用  
156 - if (commandWay === CommandDeliveryWayEnum.SERVICE) { getServiceInfo(deviceProfileId, service, serviceCommand) }  
157 -  
158 - else if (commandWay === CommandDeliveryWayEnum.CUSTOM) {  
159 - await nextTick()  
160 - updateSchema([  
161 - {  
162 - field: 'sendValue',  
163 - component: ComponentEnum.JSON_EDITOR,  
164 - changeEvent: 'update:value',  
165 - label: '自定义下发值',  
166 - required: true,  
167 - },  
168 - ])  
169 - setFieldsValue({ sendValue: customCommand })  
170 - }  
171 - } 88 +const { setup, getDeviceInfo, getObjectModelTsl, doCommandDeliver } = useCommandDeliver()
  89 +
  90 +const open = async ({ eventBindData, operationPasswordInfo, dataSource }: OpenParamsType) => {
  91 + const { deviceId, deviceProfileId, attr } = dataSource
  92 + const { commandWay, callType, way, service } = eventBindData
  93 + const { checked, value: operationPassword } = operationPasswordInfo || {}
  94 + configuration.commandDeliveryWay = commandWay!
  95 +
  96 + setModalProps({
  97 + open: true,
  98 + loading: true,
  99 + })
  100 +
  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)
  115 + handleHasOperationPassword(operationPasswordInfo!)
  116 +
  117 + if (commandWay === CommandDeliveryWayEnum.CUSTOM)
  118 + handleOpenCustomCommandModal(toRaw(unref(getDeviceInfo)!), eventBindData)
  119 + else if (commandWay === CommandDeliveryWayEnum.SERVICE)
  120 + handleOpenServiceCommandModal(toRaw(unref(getDeviceInfo)!), eventBindData)
  121 + else if (commandWay === CommandDeliveryWayEnum.MODBUS)
  122 + handleOpenModbusCommandModal(toRaw(unref(getObjectModelTsl)!))
  123 +
  124 + setModalProps({
  125 + loading: false,
  126 + title: `参数设置 / ${unref(getDeviceInfo)?.alias || unref(getDeviceInfo)?.name}`,
  127 + })
  128 +}
  129 +
  130 +function handleGetCustomCommand() {
  131 + const res = customCommandFormAction.getFieldsValue()
  132 + const command = res[FormFieldsEnum.CUSTOM_COMMAND]
  133 + return unref(getDeviceInfo)?.transportType === TransportTypeEnum.TCP ? command : useJsonParse(command).value
  134 +}
  135 +
  136 +function handleGetServiceCommand() {
  137 + const res = unref(thingsModelElRef)!.getFieldsValue()
  138 +
  139 + return unref(getDeviceInfo)?.transportType === TransportTypeEnum.TCP ? res[FormFieldsEnum.SERVICE_COMMAND] : res
172 } 140 }
173 141
174 -const error = () => {  
175 - // createMessage.error('下发指令失败')  
176 - return false 142 +function handleGetModbusCommand() {
  143 + const res = customCommandFormAction.getFieldsValue()
  144 + const identifier = unref(getObjectModelTsl)!.identifier
  145 + return res[identifier]
177 } 146 }
178 147
179 const handleSubmit = async () => { 148 const handleSubmit = async () => {
180 - unref(isPasswordInfo)?.checked && await validatePassword()// 操作密码  
181 - !unref(isInputData) && await validate()  
182 - unref(isInputData) && await unref(thingsModelElRef).validate()  
183 -  
184 - if (unref(isPasswordInfo)?.checked) {  
185 - const { password } = getPasswordValue()  
186 - if (unref(isPasswordInfo)?.value !== password) {  
187 - createMessage.warning('操作密码不正确')  
188 - return  
189 - }  
190 - }  
191 - if (serviceInfo.callType === 'SYNC') { // 服务命令调用方式 是同步 需要调用设备是否在线才能下发  
192 - const res = await getDeviceActiveTime(dataSourceJson.value.deviceId)  
193 - const { value } = res?.[0] || {}  
194 - if (!value) {  
195 - createMessage.error('当前设备不在线')  
196 - return  
197 - }  
198 - }  
199 -  
200 - const sendValue = ref({})  
201 - try {  
202 - loading.value = true  
203 - if (unref(isShowModBUS)) {  
204 - if (!unref(isShowActionType)) {  
205 - createMessage.warning('当前物模型扩展描述没有填写')  
206 - return  
207 - }  
208 -  
209 - if (!serviceInfo.code) {  
210 - createMessage.error('当前缺少设备地址码')  
211 - return  
212 - }  
213 - const oldValue = getFieldsValue()[unref(formField)]  
214 - modBUSForm.value.registerNumber = 1  
215 - modBUSForm.value.registerValues = [oldValue]  
216 -  
217 - if (unref(isShowMultiply) && unref(modBUSForm).method === '06') {  
218 - const newValue  
219 - = Math.trunc(oldValue) * unref(zoomFactorValue)  
220 - + getFloatPart(oldValue) * unref(zoomFactorValue)  
221 - if (newValue % 1 !== 0) {  
222 - createMessage.warning(`属性下发类型必须是整数,缩放因子为${unref(zoomFactorValue)}`)  
223 - return  
224 - }  
225 -  
226 - if (oldValue * unref(zoomFactorValue) > 65535) {  
227 - createMessage.warning(`属性下发值不能超过65535,缩放因子是${unref(zoomFactorValue)}`)  
228 - return  
229 - }  
230 - // bool类型的就不用去乘缩放因子了  
231 - modBUSForm.value.registerValues = [newValue]  
232 - }  
233 -  
234 - if (unref(modBUSForm).method === '16' || unref(modBUSForm).method === '10') {  
235 - const regex = /^-?\d+(\.\d{0,2})?$/  
236 - const values  
237 - = Math.trunc(oldValue) * unref(zoomFactorValue)  
238 - + getFloatPart(oldValue) * unref(zoomFactorValue)  
239 -  
240 - if (!regex.test(values as any)) {  
241 - createMessage.warning(`属性下发值精确到两位小数,缩放因子是${unref(zoomFactorValue)}`)  
242 - return  
243 - }  
244 -  
245 - const newValue  
246 - = values === 0 ? [0, 0] : getArray(SingleToHex(unref(isShowMultiply) ? values : oldValue))  
247 - modBUSForm.value.registerValues = newValue  
248 - modBUSForm.value.registerNumber = 2  
249 - modBUSForm.value.method = '10'  
250 - }  
251 - sendValue.value = await genModbusCommand(unref(modBUSForm))  
252 - }  
253 - else {  
254 - if (unref(isInputData)) {  
255 - const values = serviceInfo.transportType === TransportTypeEnum.TCP ? Object.values(unref(thingsModelElRef)?.getFieldsValue()).join('').replace(/\s/g, '') : unref(thingsModelElRef)?.getFieldsValue()  
256 - sendValue.value = values  
257 - }  
258 - else {  
259 - const values = serviceInfo.transportType === TransportTypeEnum.TCP ? getFieldsValue().sendValue : JSON.parse(getFieldsValue().sendValue) || {}  
260 - sendValue.value = values  
261 - }  
262 - }  
263 - await sendRpcOneway({  
264 - additionalInfo: {  
265 - cmdType:  
266 - unref(isCommandWay) === CommandDeliveryWayEnum.SERVICE  
267 - ? CommandTypeEnum.SERVICE  
268 - : CommandTypeEnum.API,  
269 - },  
270 - persistent: true,  
271 - method: 'methodThingskit',  
272 - params: serviceInfo.transportType !== TransportTypeEnum.TCP && unref(isCommandWay) === CommandDeliveryWayEnum.SERVICE ? { service: unref(sendValue) } : unref(sendValue),  
273 - }, dataSourceJson.value.deviceId, serviceInfo.callType ? serviceInfo.callType === 'SYNC' ? 'twoway' : 'oneway' : serviceInfo.way)  
274 - createMessage.success('命令下发成功')  
275 - visible.value = false  
276 - isInputData.value = false  
277 - }  
278 - catch (msg) {  
279 - console.error(msg)  
280 - return error()  
281 - }  
282 - finally {  
283 - loading.value = false  
284 - } 149 + if (configuration.operationPasswordEnable) await operationPasswordFormAction.validate()
  150 + configuration.commandDeliveryWay === CommandDeliveryWayEnum.SERVICE ? await unref(thingsModelElRef)?.validate() : await customCommandFormAction.validate()
  151 +
  152 + const res
  153 + = configuration.commandDeliveryWay === CommandDeliveryWayEnum.CUSTOM
  154 + ? handleGetCustomCommand()
  155 + : configuration.commandDeliveryWay === CommandDeliveryWayEnum.MODBUS
  156 + ? handleGetModbusCommand()
  157 + : handleGetServiceCommand()
  158 +
  159 + await doCommandDeliver(res)
  160 + closeModal()
285 } 161 }
286 162
287 const handleCancel = () => { 163 const handleCancel = () => {
288 - visible.value = false  
289 - isInputData.value = false 164 + closeModal()
  165 + Object.assign(configuration, getDefaultConfiguration())
290 } 166 }
291 167
292 defineExpose({ 168 defineExpose({
@@ -295,28 +171,15 @@ defineExpose({ @@ -295,28 +171,15 @@ defineExpose({
295 </script> 171 </script>
296 172
297 <template> 173 <template>
298 - <BasicModal  
299 - v-model:open="visible" :title="`参数设置-${deviceTitle}`" :destroy-on-close="true" :confirm-loading="loading"  
300 - :ok-button-props="{ type: 'primary' }" @ok="handleSubmit" @cancel="handleCancel"  
301 - >  
302 - <BasicForm v-if="isPasswordInfo?.checked" @register="registerPassword" />  
303 - <BasicForm v-if="!isInputData" @register="register" />  
304 - <ThingsModelForm  
305 - v-else ref="thingsModelElRef" v-model:value="serviceInfo.serviceCommand" :title="serviceInfo.title"  
306 - :input-data="serviceInfo.inputData || []" :transport-type="serviceInfo.transportType"  
307 - /> 174 + <BasicModal :destroy-on-close="true" @register="registerModal" @ok="handleSubmit" @cancel="handleCancel">
  175 + <BasicForm v-if="configuration.operationPasswordEnable" @register="registerPassword" />
  176 + <BasicForm v-if="configuration.commandDeliveryWay !== CommandDeliveryWayEnum.SERVICE" @register="register" />
  177 + <ThingsModelForm v-if="configuration.commandDeliveryWay === CommandDeliveryWayEnum.SERVICE" ref="thingsModelElRef" />
308 <template #footer> 178 <template #footer>
309 - <Button  
310 - style="background-color: #ffffff;  
311 - border-color: #d9d9d9;  
312 - box-shadow: 0 2px 0 rgba(0, 0, 0, 0.02);" @click="handleCancel"  
313 - > 179 + <Button @click="handleCancel">
314 取消 180 取消
315 </Button> 181 </Button>
316 - <Button  
317 - type="primary" :loading="loading"  
318 - style="background: #1677ff !important; box-shadow: 0 2px 0 rgba(5, 145, 255, 0.1)" @click="handleSubmit"  
319 - > 182 + <Button type="primary" @click="handleSubmit">
320 确定 183 确定
321 </Button> 184 </Button>
322 </template> 185 </template>
  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 { SingleToHex, getArray } from './config'  
2 import { type GenModbusCommandType, genModbusCommand } from '@/api/device' 1 import { type GenModbusCommandType, genModbusCommand } from '@/api/device'
3 import type { ExtensionDesc } from '@/api/device/model' 2 import type { ExtensionDesc } from '@/api/device/model'
  3 +import { ModbusCRCEnum } from '@/enums/commandEnum'
4 import { TCPObjectModelActionTypeEnum } from '@/enums/objectModelEnum' 4 import { TCPObjectModelActionTypeEnum } from '@/enums/objectModelEnum'
5 import { useMessage } from '@/hooks/web/useMessage' 5 import { useMessage } from '@/hooks/web/useMessage'
6 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 +
7 const getFloatPart = (number: string | number) => { 152 const getFloatPart = (number: string | number) => {
8 const isLessZero = Number(number) < 0 153 const isLessZero = Number(number) < 0
9 number = number.toString() 154 number = number.toString()
@@ -21,8 +166,9 @@ export function useGetModbusCommand() { @@ -21,8 +166,9 @@ export function useGetModbusCommand() {
21 166
22 const getModbusCommand = async (value: number, extensionDesc: ExtensionDesc, deviceAddressCode: string) => { 167 const getModbusCommand = async (value: number, extensionDesc: ExtensionDesc, deviceAddressCode: string) => {
23 const { registerAddress, actionType, zoomFactor } = extensionDesc as Required<ExtensionDesc> 168 const { registerAddress, actionType, zoomFactor } = extensionDesc as Required<ExtensionDesc>
  169 +
24 const params: GenModbusCommandType = { 170 const params: GenModbusCommandType = {
25 - crc: 'CRC_16_LOWER', 171 + crc: ModbusCRCEnum.CRC_16_LOWER,
26 registerNumber: 1, 172 registerNumber: 1,
27 deviceCode: deviceAddressCode, 173 deviceCode: deviceAddressCode,
28 registerAddress, 174 registerAddress,
@@ -41,7 +187,7 @@ export function useGetModbusCommand() { @@ -41,7 +187,7 @@ export function useGetModbusCommand() {
41 } 187 }
42 188
43 if (value * zoomFactor > REGISTER_MAX_VALUE) { 189 if (value * zoomFactor > REGISTER_MAX_VALUE) {
44 - createMessage.warning(`属性下发值不能超过${REGISTER_MAX_VALUE},缩放因子${zoomFactor}`) 190 + createMessage.warning(`属性下发值不能超过${REGISTER_MAX_VALUE},缩放因子${zoomFactor}`)
45 return 191 return
46 } 192 }
47 193
@@ -54,7 +200,7 @@ export function useGetModbusCommand() { @@ -54,7 +200,7 @@ export function useGetModbusCommand() {
54 + getFloatPart(value) * zoomFactor 200 + getFloatPart(value) * zoomFactor
55 201
56 if (!regex.test(values.toString())) { 202 if (!regex.test(values.toString())) {
57 - createMessage.warning(`属性下发值精确到两位小数,缩放因子${zoomFactor}`) 203 + createMessage.warning(`属性下发值精确到两位小数,缩放因子${zoomFactor}`)
58 return 204 return
59 } 205 }
60 206
@@ -9,6 +9,8 @@ import { CommandDeliveryWayEnum, CommandDeliveryWayNameEnum, DeviceTypeEnum, Eve @@ -9,6 +9,8 @@ import { CommandDeliveryWayEnum, CommandDeliveryWayNameEnum, DeviceTypeEnum, Eve
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' 11 import { useContentDataStoreWithOut } from '@/store/modules/contentData'
  12 +import { validateTCPCustomCommand } from '@/core/Library/components/ThingsModelForm'
  13 +import { JSONEditorValidator } from '@/components/CodeEditor/src/JSONEditor'
12 14
13 export enum FormFieldsEnum { 15 export enum FormFieldsEnum {
14 ACTION_TYPE = 'actionType', 16 ACTION_TYPE = 'actionType',
@@ -36,14 +38,15 @@ export enum FormFieldsNameEnum { @@ -36,14 +38,15 @@ export enum FormFieldsNameEnum {
36 const contentDataStore = useContentDataStoreWithOut() 38 const contentDataStore = useContentDataStoreWithOut()
37 39
38 export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { 40 export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => {
39 - const { getNodeData, getCellInfo } = usePublicFormContext() 41 + const { getNodeData, getCellInfo, getDeviceInfo } = usePublicFormContext()
40 const { dataSourceJson } = unref(getNodeData) || {} 42 const { dataSourceJson } = unref(getNodeData) || {}
41 - const { deviceProfileId, deviceInfo, deviceId } = dataSourceJson || {} 43 + const { deviceProfileId, deviceId } = dataSourceJson || {}
42 // transportType:判断是什么类型的设备 code:设备地址码 deviceType:设备类型 44 // transportType:判断是什么类型的设备 code:设备地址码 deviceType:设备类型
43 let codeType: string | null = '' 45 let codeType: string | null = ''
44 - const { transportType, deviceType, codeType: deviceCodeType } = deviceInfo || {} 46 + const { transportType, deviceType, codeType: deviceCodeType } = unref(getDeviceInfo) || {}
45 codeType = deviceCodeType || (deviceId ? contentDataStore.diveceDetailMap?.[deviceId]?.codeType : null) 47 codeType = deviceCodeType || (deviceId ? contentDataStore.diveceDetailMap?.[deviceId]?.codeType : null)
46 const isTemplate = contentDataStore.isTemplate // 判断是否是模板 48 const isTemplate = contentDataStore.isTemplate // 判断是否是模板
  49 +
47 return [ 50 return [
48 { 51 {
49 field: 'eventName', 52 field: 'eventName',
@@ -68,7 +71,6 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { @@ -68,7 +71,6 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => {
68 const options: DefaultOptionType[] = [ 71 const options: DefaultOptionType[] = [
69 { label: EventActionTypeNameEnum.OPEN_LINK, value: EventActionTypeEnum.OPEN_LINK }, 72 { label: EventActionTypeNameEnum.OPEN_LINK, value: EventActionTypeEnum.OPEN_LINK },
70 { label: EventActionTypeNameEnum.OPEN_PAGE, value: EventActionTypeEnum.OPEN_PAGE }, 73 { label: EventActionTypeNameEnum.OPEN_PAGE, value: EventActionTypeEnum.OPEN_PAGE },
71 -  
72 ] 74 ]
73 75
74 if (unref(getCellInfo).category.toUpperCase() === PackageCategoryEnum.CONTROL) 76 if (unref(getCellInfo).category.toUpperCase() === PackageCategoryEnum.CONTROL)
@@ -93,7 +95,6 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { @@ -93,7 +95,6 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => {
93 field: FormFieldsEnum.OPEN_LINK, 95 field: FormFieldsEnum.OPEN_LINK,
94 label: '链接', 96 label: '链接',
95 component: ComponentEnum.INPUT, 97 component: ComponentEnum.INPUT,
96 - // dynamicDisabled: () => !deviceProfileId,  
97 required: true, 98 required: true,
98 ifShow: ({ model }) => model[FormFieldsEnum.ACTION_TYPE] === EventActionTypeEnum.OPEN_LINK, 99 ifShow: ({ model }) => model[FormFieldsEnum.ACTION_TYPE] === EventActionTypeEnum.OPEN_LINK,
99 }, 100 },
@@ -187,20 +188,16 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { @@ -187,20 +188,16 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => {
187 component: ComponentEnum.JSON_EDITOR, 188 component: ComponentEnum.JSON_EDITOR,
188 changeEvent: 'update:value', 189 changeEvent: 'update:value',
189 required: true, 190 required: true,
  191 + rules: JSONEditorValidator(),
190 ifShow: ({ model }) => transportType !== TransportTypeEnum.TCP && model[FormFieldsEnum.ACTION_TYPE] === EventActionTypeEnum.PARAMS_SETTING && model[FormFieldsEnum.COMMAND_WAY] === CommandDeliveryWayEnum.CUSTOM, 192 ifShow: ({ model }) => transportType !== TransportTypeEnum.TCP && model[FormFieldsEnum.ACTION_TYPE] === EventActionTypeEnum.PARAMS_SETTING && model[FormFieldsEnum.COMMAND_WAY] === CommandDeliveryWayEnum.CUSTOM,
191 - componentProps: () => {  
192 - return {}  
193 - },  
194 }, 193 },
195 { 194 {
196 field: FormFieldsEnum.CUSTOM_COMMAND, 195 field: FormFieldsEnum.CUSTOM_COMMAND,
197 label: FormFieldsNameEnum.COMMAND, 196 label: FormFieldsNameEnum.COMMAND,
198 component: ComponentEnum.INPUT, 197 component: ComponentEnum.INPUT,
199 required: true, 198 required: true,
  199 + rules: [{ validator: validateTCPCustomCommand }],
200 ifShow: ({ model }) => transportType === TransportTypeEnum.TCP && model[FormFieldsEnum.ACTION_TYPE] === EventActionTypeEnum.PARAMS_SETTING && model[FormFieldsEnum.COMMAND_WAY] === CommandDeliveryWayEnum.CUSTOM, 200 ifShow: ({ model }) => transportType === TransportTypeEnum.TCP && model[FormFieldsEnum.ACTION_TYPE] === EventActionTypeEnum.PARAMS_SETTING && model[FormFieldsEnum.COMMAND_WAY] === CommandDeliveryWayEnum.CUSTOM,
201 - componentProps: () => {  
202 - return {}  
203 - },  
204 }, 201 },
205 { 202 {
206 field: FormFieldsEnum.SERVICE, 203 field: FormFieldsEnum.SERVICE,
@@ -224,7 +221,6 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { @@ -224,7 +221,6 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => {
224 const service = formModel[FormFieldsEnum.SERVICE] 221 const service = formModel[FormFieldsEnum.SERVICE]
225 if (service) { 222 if (service) {
226 const thingsModel = unref(options).find(item => item.identifier === service) || null 223 const thingsModel = unref(options).find(item => item.identifier === service) || null
227 - // if (thingsModel)  
228 formModel[FormFieldsEnum.THINGS_MODEL] = thingsModel 224 formModel[FormFieldsEnum.THINGS_MODEL] = thingsModel
229 } 225 }
230 }, 226 },
@@ -243,15 +239,8 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => { @@ -243,15 +239,8 @@ export const getFormSchemas = (event: EventTypeEnum): FormSchema[] => {
243 component: ComponentEnum.THINGS_MODEL_FORM, 239 component: ComponentEnum.THINGS_MODEL_FORM,
244 ifShow: ({ model }) => model[FormFieldsEnum.THINGS_MODEL] && model[FormFieldsEnum.COMMAND_WAY] === CommandDeliveryWayEnum.SERVICE, 240 ifShow: ({ model }) => model[FormFieldsEnum.THINGS_MODEL] && model[FormFieldsEnum.COMMAND_WAY] === CommandDeliveryWayEnum.SERVICE,
245 changeEvent: 'update:value', 241 changeEvent: 'update:value',
246 - colSlot: 'serviceCommand', 242 + slot: 'serviceCommand',
247 }, 243 },
248 - // {  
249 - // field: 'deviceInfo',  
250 - // label: '设备属性数据',  
251 - // component: ComponentEnum.INPUT,  
252 - // defaultValue: dataSourceJson,  
253 - // ifShow: false,  
254 - // },  
255 { 244 {
256 field: 'transportType', 245 field: 'transportType',
257 label: '', 246 label: '',
1 -import { toRaw, unref } from 'vue' 1 +import { unref } from 'vue'
2 import { getDeviceAttributes, getListByConfigurationId, getListByDeviceProfileIds } from '@/api/device' 2 import { getDeviceAttributes, getListByConfigurationId, getListByDeviceProfileIds } from '@/api/device'
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'
@@ -32,9 +32,8 @@ export const formSchemas = (componentKey?: string): FormSchema[] => { @@ -32,9 +32,8 @@ export const formSchemas = (componentKey?: string): FormSchema[] => {
32 return { 32 return {
33 options: (unref(contentDataStore.getProductAndDevice) || []).map((item: ProductAndDevice) => ({ label: item.profileName || item.name, value: item.profileId, transportType: item?.transportType, deviceType: item?.deviceType })), 33 options: (unref(contentDataStore.getProductAndDevice) || []).map((item: ProductAndDevice) => ({ label: item.profileName || item.name, value: item.profileId, transportType: item?.transportType, deviceType: item?.deviceType })),
34 placeholder: '请选择产品', 34 placeholder: '请选择产品',
35 - onSelect(value: string, option: any) { 35 + onSelect(value: string) {
36 formModel[ContentDataFieldsEnum.DEVICE_PROFILE_ID] = value 36 formModel[ContentDataFieldsEnum.DEVICE_PROFILE_ID] = value
37 - formModel[ContentDataFieldsEnum.DEVICE_INFO] = value && option ? { transportType: option.transportType, deviceType: option.deviceType, codeType: option?.codeType, deviceName: null } : null  
38 }, 37 },
39 getPopupContainer: () => document.body, 38 getPopupContainer: () => document.body,
40 } 39 }
@@ -63,7 +62,6 @@ export const formSchemas = (componentKey?: string): FormSchema[] => { @@ -63,7 +62,6 @@ export const formSchemas = (componentKey?: string): FormSchema[] => {
63 fieldNames: { label: 'name', value: 'tbDeviceId' }, 62 fieldNames: { label: 'name', value: 'tbDeviceId' },
64 onSelect(value: string, option: DeviceItemType) { 63 onSelect(value: string, option: DeviceItemType) {
65 formModel[ContentDataFieldsEnum.DEVICE_PROFILE_ID] = value ? option.deviceProfileId : null 64 formModel[ContentDataFieldsEnum.DEVICE_PROFILE_ID] = value ? option.deviceProfileId : null
66 - formModel[ContentDataFieldsEnum.DEVICE_INFO] = value && option ? { code: option.code, transportType: option.transportType, deviceType: option.deviceType, deviceProfileId: option.deviceProfileId, deviceName: option.alias || option.name || null, codeType: option?.codeType } : null  
67 formModel[ContentDataFieldsEnum.ATTR] = null 65 formModel[ContentDataFieldsEnum.ATTR] = null
68 }, 66 },
69 filterOption: (inputValue: string, option: DeviceItemType) => { 67 filterOption: (inputValue: string, option: DeviceItemType) => {
@@ -93,26 +91,11 @@ export const formSchemas = (componentKey?: string): FormSchema[] => { @@ -93,26 +91,11 @@ export const formSchemas = (componentKey?: string): FormSchema[] => {
93 }, 91 },
94 params: deviceProfileId, 92 params: deviceProfileId,
95 fieldNames: { label: 'name', value: 'identifier' }, 93 fieldNames: { label: 'name', value: 'identifier' },
96 - onSelect(value: string, option: ThingsModelItemType) {  
97 - formModel[ContentDataFieldsEnum.ATTR_INFO] = value && option ? toRaw(unref(option)) : null  
98 - },  
99 filterOption: (inputValue: string, option: ThingsModelItemType) => { 94 filterOption: (inputValue: string, option: ThingsModelItemType) => {
100 return option.name.includes(inputValue) 95 return option.name.includes(inputValue)
101 }, 96 },
102 } 97 }
103 }, 98 },
104 }, 99 },
105 - {  
106 - field: ContentDataFieldsEnum.ATTR_INFO,  
107 - label: ContentDataFieldsNameEnum.ATTR_INFO,  
108 - component: ComponentEnum.INPUT,  
109 - ifShow: false,  
110 - },  
111 - {  
112 - field: ContentDataFieldsEnum.DEVICE_INFO,  
113 - label: ContentDataFieldsNameEnum.DEVICE_INFO,  
114 - component: ComponentEnum.INPUT,  
115 - ifShow: false,  
116 - },  
117 ] 100 ]
118 } 101 }
@@ -12,5 +12,4 @@ export interface ComponentExposeType { @@ -12,5 +12,4 @@ export interface ComponentExposeType {
12 getFieldsValue: () => any 12 getFieldsValue: () => any
13 setFieldsValue: (value: any) => void 13 setFieldsValue: (value: any) => void
14 validate: () => Promise<RuleError | any> 14 validate: () => Promise<RuleError | any>
15 - updateSchema?: any  
16 } 15 }
@@ -58,7 +58,7 @@ const getEventJson = (): NodeDataEventJsonType => { @@ -58,7 +58,7 @@ const getEventJson = (): NodeDataEventJsonType => {
58 58
59 Object.keys(status).forEach((key) => { 59 Object.keys(status).forEach((key) => {
60 if (eventJson[key as EventTypeEnum]) 60 if (eventJson[key as EventTypeEnum])
61 - eventJson[key as EventTypeEnum].enable = status[key as EventTypeEnum] 61 + eventJson[key as EventTypeEnum]!.enable = status[key as EventTypeEnum]
62 }) 62 })
63 63
64 return eventJson 64 return eventJson
@@ -190,7 +190,7 @@ createPublicFormContext(nodeDataActinType) @@ -190,7 +190,7 @@ createPublicFormContext(nodeDataActinType)
190 </div> 190 </div>
191 </Checkbox> 191 </Checkbox>
192 <Form> 192 <Form>
193 - <FormItem :validate-status="getValidateStatus(operationPassword.value)"> 193 + <FormItem :validate-status="getValidateStatus(operationPassword.value!)">
194 <InputPassword 194 <InputPassword
195 v-model:value="operationPassword.value" class="mt-1" :disabled="!operationPassword.checked" 195 v-model:value="operationPassword.value" class="mt-1" :disabled="!operationPassword.checked"
196 placeholder="请输入操作密码" 196 placeholder="请输入操作密码"
  1 +import { validateTCPCustomCommand } from '.'
1 import type { Specs, StructJSON } from '@/api/device/model' 2 import type { Specs, StructJSON } from '@/api/device/model'
2 import { type FormSchema } from '@/components/Form' 3 import { type FormSchema } from '@/components/Form'
3 import { ComponentEnum } from '@/components/Form/src/enum' 4 import { ComponentEnum } from '@/components/Form/src/enum'
4 -import { DataTypeEnum } from '@/enums/datasource' 5 +import { DataTypeEnum, TransportTypeEnum } from '@/enums/datasource'
  6 +
  7 +export enum FormFieldsEnum {
  8 + SERVICE_COMMAND = 'serviceCommand',
  9 +}
5 10
6 export const getFormSchemas = ({ structJSON: structJson, required, transportType }: { structJSON: StructJSON[]; required?: boolean; transportType?: string }): FormSchema[] => { 11 export const getFormSchemas = ({ structJSON: structJson, required, transportType }: { structJSON: StructJSON[]; required?: boolean; transportType?: string }): FormSchema[] => {
7 const createInputNumber = ({ 12 const createInputNumber = ({
@@ -120,10 +125,11 @@ export const getFormSchemas = ({ structJSON: structJson, required, transportType @@ -120,10 +125,11 @@ export const getFormSchemas = ({ structJSON: structJson, required, transportType
120 125
121 const createTCPServiceCommandInput = ({ serviceCommand }: StructJSON): FormSchema => { 126 const createTCPServiceCommandInput = ({ serviceCommand }: StructJSON): FormSchema => {
122 return { 127 return {
123 - field: 'serviceCommand', 128 + field: FormFieldsEnum.SERVICE_COMMAND,
124 label: '服务命令', 129 label: '服务命令',
125 component: ComponentEnum.INPUT, 130 component: ComponentEnum.INPUT,
126 required, 131 required,
  132 + rules: [{ validator: validateTCPCustomCommand }],
127 componentProps: { 133 componentProps: {
128 defaultValue: serviceCommand, 134 defaultValue: serviceCommand,
129 }, 135 },
@@ -134,8 +140,12 @@ export const getFormSchemas = ({ structJSON: structJson, required, transportType @@ -134,8 +140,12 @@ export const getFormSchemas = ({ structJSON: structJson, required, transportType
134 for (const item of structJson) { 140 for (const item of structJson) {
135 const { dataType } = item 141 const { dataType } = item
136 const { type } = dataType || {} 142 const { type } = dataType || {}
137 - if (transportType === 'TCP')  
138 - schemas.push(createTCPServiceCommandInput(item)) 143 +
  144 + if (transportType === TransportTypeEnum.TCP) {
  145 + item.serviceCommand && schemas.push(createTCPServiceCommandInput(item))
  146 + break
  147 + }
  148 +
139 if (type === DataTypeEnum.BOOL) 149 if (type === DataTypeEnum.BOOL)
140 schemas.push(createSelect(item)) 150 schemas.push(createSelect(item))
141 else if (type === DataTypeEnum.ENUM) 151 else if (type === DataTypeEnum.ENUM)
1 <script setup lang="ts"> 1 <script setup lang="ts">
2 import { Card } from 'ant-design-vue' 2 import { Card } from 'ant-design-vue'
3 -import { computed, nextTick, reactive, unref, watch } from 'vue'  
4 -import type { ComponentExposeType } from '../PublicForm' 3 +import { computed, nextTick, reactive, ref, unref, watch } from 'vue'
5 import { getFormSchemas } from './config' 4 import { getFormSchemas } from './config'
6 import { ThingsModelForm } from '.' 5 import { ThingsModelForm } from '.'
7 import type { StructJSON } from '@/api/device/model' 6 import type { StructJSON } from '@/api/device/model'
8 import { BasicForm, useForm } from '@/components/Form' 7 import { BasicForm, useForm } from '@/components/Form'
9 import { DataTypeEnum } from '@/enums/datasource' 8 import { DataTypeEnum } from '@/enums/datasource'
10 import { FormLabelAlignEnum, FormLayoutEnum } from '@/components/Form/src/enum' 9 import { FormLabelAlignEnum, FormLayoutEnum } from '@/components/Form/src/enum'
  10 +import { deepMerge } from '@/utils'
11 11
12 -const props = withDefaults(defineProps<{  
13 - value: Recordable 12 +interface ThingsModelFormPropsType {
  13 + value?: Recordable
14 inputData?: StructJSON[] 14 inputData?: StructJSON[]
15 required?: boolean 15 required?: boolean
16 title?: string 16 title?: string
17 transportType?: string 17 transportType?: string
18 -}>(), { 18 +}
  19 +
  20 +const props = withDefaults(defineProps<ThingsModelFormPropsType>(), {
19 inputData: () => [], 21 inputData: () => [],
20 required: true, 22 required: true,
21 }) 23 })
22 24
  25 +const propsRef = ref<Partial<ThingsModelFormPropsType>>({})
  26 +
  27 +const getProps = computed<ThingsModelFormPropsType>(() => ({ ...props, ...unref(propsRef) }))
  28 +
23 const thingsModelFormListElMap = reactive<Record<string, { el: InstanceType<typeof ThingsModelForm>; structJSON: StructJSON }>>({}) 29 const thingsModelFormListElMap = reactive<Record<string, { el: InstanceType<typeof ThingsModelForm>; structJSON: StructJSON }>>({})
24 30
25 const [register, formActionType] = useForm({ 31 const [register, formActionType] = useForm({
26 - schemas: getFormSchemas({ structJSON: props.inputData || [], required: props.required, transportType: props.transportType }), 32 + schemas: getFormSchemasByProps(),
27 showActionButtonGroup: false, 33 showActionButtonGroup: false,
  34 + name: Math.random().toString(16).substring(2),
28 labelWidth: 100, 35 labelWidth: 100,
29 labelAlign: FormLabelAlignEnum.RIGHT, 36 labelAlign: FormLabelAlignEnum.RIGHT,
30 layout: FormLayoutEnum.HORIZONTAL, 37 layout: FormLayoutEnum.HORIZONTAL,
31 }) 38 })
32 39
33 const getStructFormItem = computed(() => { 40 const getStructFormItem = computed(() => {
34 - const { inputData } = props  
35 - return inputData.filter(item => item.dataType?.type === DataTypeEnum.STRUCT) 41 + const { inputData } = unref(getProps)
  42 + return (inputData || []).filter(item => item.dataType?.type === DataTypeEnum.STRUCT)
36 }) 43 })
37 44
38 const setFormElRef = (el: InstanceType<typeof ThingsModelForm>, structJSON: StructJSON) => { 45 const setFormElRef = (el: InstanceType<typeof ThingsModelForm>, structJSON: StructJSON) => {
@@ -68,11 +75,7 @@ const validate = async () => { @@ -68,11 +75,7 @@ const validate = async () => {
68 await thingsModelFormListElMap[key].el.validate() 75 await thingsModelFormListElMap[key].el.validate()
69 } 76 }
70 77
71 -const updateSchema = (value: Recordable) => {  
72 - return formActionType.updateSchema(value)  
73 -}  
74 -  
75 -watch(() => props.value, 78 +watch(() => unref(getProps).value,
76 async (value) => { 79 async (value) => {
77 await nextTick() 80 await nextTick()
78 formActionType.setFieldsValue(value || {}) 81 formActionType.setFieldsValue(value || {})
@@ -80,25 +83,31 @@ watch(() => props.value, @@ -80,25 +83,31 @@ watch(() => props.value,
80 { immediate: true }, 83 { immediate: true },
81 ) 84 )
82 85
  86 +function getFormSchemasByProps() {
  87 + return getFormSchemas({ structJSON: unref(getProps).inputData || [], required: unref(getProps).required, transportType: unref(getProps).transportType })
  88 +}
  89 +
83 watch( 90 watch(
84 - () => props.inputData, 91 + () => unref(getProps).inputData,
85 (value) => { 92 (value) => {
86 - if (value && value.length) {  
87 - const schemas = getFormSchemas({ structJSON: props.inputData || [], required: props.required, transportType: props.transportType })  
88 - formActionType.setProps({ schemas })  
89 - } 93 + if (value && value.length)
  94 + formActionType.setProps({ schemas: getFormSchemasByProps() })
90 }) 95 })
91 96
92 -defineExpose<ComponentExposeType>({ 97 +function setProps(props: Partial<ThingsModelFormPropsType>) {
  98 + propsRef.value = deepMerge(unref(propsRef) || {}, props) as any
  99 +}
  100 +
  101 +defineExpose({
93 getFieldsValue, 102 getFieldsValue,
94 setFieldsValue, 103 setFieldsValue,
95 validate, 104 validate,
96 - updateSchema, 105 + setProps,
97 }) 106 })
98 </script> 107 </script>
99 108
100 <template> 109 <template>
101 - <Card class="!border-2 !border-dashed" :title="title"> 110 + <Card class="!border-2 !border-dashed" :title="getProps.title">
102 <BasicForm class="things-model-form" @register="register"> 111 <BasicForm class="things-model-form" @register="register">
103 <template v-for="item in getStructFormItem" #[item.identifier]="{ model, field }" :key="item.identifier"> 112 <template v-for="item in getStructFormItem" #[item.identifier]="{ model, field }" :key="item.identifier">
104 <ThingsModelForm 113 <ThingsModelForm
@@ -7,6 +7,8 @@ import { CellAttributeKeyEnum } from '@/enums/cellAttributeEnum' @@ -7,6 +7,8 @@ import { CellAttributeKeyEnum } from '@/enums/cellAttributeEnum'
7 import { useContentDataStoreWithOut } from '@/store/modules/contentData' 7 import { useContentDataStoreWithOut } from '@/store/modules/contentData'
8 import { useMessage } from '@/hooks/web/useMessage' 8 import { useMessage } from '@/hooks/web/useMessage'
9 import { MessageEnum } from '@/enums/messageEnum' 9 import { MessageEnum } from '@/enums/messageEnum'
  10 +import type { DeviceItemType } from '@/api/device/model'
  11 +import { getDeviceInfo } from '@/api/device'
10 12
11 interface UseNodeDataParamsType { 13 interface UseNodeDataParamsType {
12 cell: MxCell 14 cell: MxCell
@@ -35,9 +37,9 @@ export function useNodeData({ cell, immediate = true }: UseNodeDataParamsType) { @@ -35,9 +37,9 @@ export function useNodeData({ cell, immediate = true }: UseNodeDataParamsType) {
35 const { createMessage } = useMessage() 37 const { createMessage } = useMessage()
36 38
37 const nodeData = ref<NodeDataType>() 39 const nodeData = ref<NodeDataType>()
  40 + const deviceInfo = ref<DeviceItemType>()
38 41
39 const contentDataStore = useContentDataStoreWithOut() 42 const contentDataStore = useContentDataStoreWithOut()
40 - // const contentId = window.DrawApp.configurationContentId!  
41 const { configurationId } = useParseParams() 43 const { configurationId } = useParseParams()
42 44
43 const getCellID = () => { 45 const getCellID = () => {
@@ -64,9 +66,15 @@ export function useNodeData({ cell, immediate = true }: UseNodeDataParamsType) { @@ -64,9 +66,15 @@ export function useNodeData({ cell, immediate = true }: UseNodeDataParamsType) {
64 } 66 }
65 }) 67 })
66 68
  69 + const getDeviceDetail = async () => {
  70 + if (!unref(nodeData)?.dataSourceJson.deviceId) return
  71 + deviceInfo.value = await getDeviceInfo(unref(nodeData)!.dataSourceJson.deviceId)
  72 + }
  73 +
67 const getNodeAllData = async () => { 74 const getNodeAllData = async () => {
68 const result = await doGetNodeBindData(basicNodeBindData(ActionType.GET)) 75 const result = await doGetNodeBindData(basicNodeBindData(ActionType.GET))
69 nodeData.value = result || getDefaultNodeData() 76 nodeData.value = result || getDefaultNodeData()
  77 + await getDeviceDetail()
70 return result 78 return result
71 } 79 }
72 80
@@ -79,6 +87,8 @@ export function useNodeData({ cell, immediate = true }: UseNodeDataParamsType) { @@ -79,6 +87,8 @@ export function useNodeData({ cell, immediate = true }: UseNodeDataParamsType) {
79 const result = await doSaveNodeAllData(Object.assign(data, basicNodeBindData(ActionType.SAVE))) 87 const result = await doSaveNodeAllData(Object.assign(data, basicNodeBindData(ActionType.SAVE)))
80 removeCellSourceAttribute(cell) 88 removeCellSourceAttribute(cell)
81 nodeData.value = result || getDefaultNodeData() 89 nodeData.value = result || getDefaultNodeData()
  90 +
  91 + await getDeviceDetail()
82 return result 92 return result
83 } 93 }
84 94
@@ -123,6 +133,7 @@ export function useNodeData({ cell, immediate = true }: UseNodeDataParamsType) { @@ -123,6 +133,7 @@ export function useNodeData({ cell, immediate = true }: UseNodeDataParamsType) {
123 }) 133 })
124 134
125 return { 135 return {
  136 + getDeviceInfo: computed(() => unref(deviceInfo)),
126 getNodeData: computed(() => unref(nodeData)), 137 getNodeData: computed(() => unref(nodeData)),
127 getCellInfo, 138 getCellInfo,
128 getNodeAllData, 139 getNodeAllData,
1 -import { h, render, unref } from 'vue' 1 +import { h, render, toRaw, unref } from 'vue'
2 import { ControlComponentEnum } from '../packages/Control' 2 import { ControlComponentEnum } from '../packages/Control'
3 -import { useGetModbusCommand } from '../components/PublicForm/components/DataEvents/CommandDeliveryModal/useGetModbusCommand'  
4 -import { doCommandDelivery, getDeviceActive, getDeviceInfo } from '@/api/device' 3 +import { doCommandDelivery, getDeviceActive } from '@/api/device'
5 import type { MouseUpEventDataType, NodeDataDataSourceJsonType, NodeDataEventJsonType, SingleClickEventDataType } from '@/api/node/model' 4 import type { MouseUpEventDataType, NodeDataDataSourceJsonType, NodeDataEventJsonType, SingleClickEventDataType } from '@/api/node/model'
6 -import { CommandWayEnum } from '@/enums/commandEnum'  
7 -import { ActRangListItemTypeEnum, CodeTypeEnum, EventActionTypeEnum, TransportTypeEnum } from '@/enums/datasource' 5 +import { CommandMethodEnum, CommandWayEnum } from '@/enums/commandEnum'
  6 +import { ActRangListItemTypeEnum, CommandTypeEnum, EventActionTypeEnum } from '@/enums/datasource'
8 import { useMessage } from '@/hooks/web/useMessage' 7 import { useMessage } from '@/hooks/web/useMessage'
9 -import { AttributeDeliverModal, CommandDeliveryConfirmModal, CommandDeliveryModal, ConfirmModal } from '@/core/Library/components/PublicForm/components/DataEvents/CommandDeliveryModal' 8 +import { AttributeDeliverModal, CommandDeliveryModal, SwitchCommandDeliveryModal } from '@/core/Library/components/PublicForm/components/DataEvents/CommandDeliveryModal'
10 import type { MxCell } from '@/fitCore/types' 9 import type { MxCell } from '@/fitCore/types'
11 import { NodeUtils } from '@/hooks/business/useNodeUtils' 10 import { NodeUtils } from '@/hooks/business/useNodeUtils'
12 import { useContentDataStoreWithOut } from '@/store/modules/contentData' 11 import { useContentDataStoreWithOut } from '@/store/modules/contentData'
13 -import type { RpcCommandType } from '@/api/device/model'  
14 12
15 export function useNodeEvent(eventJson: NodeDataEventJsonType, dataSourceJson: NodeDataDataSourceJsonType, cell: MxCell) { 13 export function useNodeEvent(eventJson: NodeDataEventJsonType, dataSourceJson: NodeDataDataSourceJsonType, cell: MxCell) {
16 const { createMessage } = useMessage() 14 const { createMessage } = useMessage()
17 15
  16 + /**
  17 + * @description 多命令下发
  18 + * @param data
  19 + * @returns
  20 + */
18 const handlerCommandDelivery = async (data: MouseUpEventDataType) => { 21 const handlerCommandDelivery = async (data: MouseUpEventDataType) => {
19 try { 22 try {
20 const promiseList: (() => Promise<any>)[] = [] 23 const promiseList: (() => Promise<any>)[] = []
@@ -34,8 +37,8 @@ export function useNodeEvent(eventJson: NodeDataEventJsonType, dataSourceJson: N @@ -34,8 +37,8 @@ export function useNodeEvent(eventJson: NodeDataEventJsonType, dataSourceJson: N
34 way, 37 way,
35 deviceId, 38 deviceId,
36 command: { 39 command: {
37 - additionalInfo: { cmdType: 'API' },  
38 - method: 'methodThingskit', 40 + additionalInfo: { cmdType: CommandTypeEnum.API },
  41 + method: CommandMethodEnum.THINGSKIT,
39 params: command, 42 params: command,
40 persistent: true, 43 persistent: true,
41 }, 44 },
@@ -51,11 +54,19 @@ export function useNodeEvent(eventJson: NodeDataEventJsonType, dataSourceJson: N @@ -51,11 +54,19 @@ export function useNodeEvent(eventJson: NodeDataEventJsonType, dataSourceJson: N
51 } 54 }
52 } 55 }
53 56
  57 + /**
  58 + * @description 打开链接
  59 + * @param data
  60 + */
54 const handleOpenLink = (data: SingleClickEventDataType) => { 61 const handleOpenLink = (data: SingleClickEventDataType) => {
55 const { openLink } = data 62 const { openLink } = data
56 window.open(openLink) 63 window.open(openLink)
57 } 64 }
58 65
  66 + /**
  67 + * @description 跳转页面
  68 + * @param data
  69 + */
59 const handleSwitchPage = (data: SingleClickEventDataType) => { 70 const handleSwitchPage = (data: SingleClickEventDataType) => {
60 const { openPage } = data 71 const { openPage } = data
61 const pages = window.DrawApp.pages 72 const pages = window.DrawApp.pages
@@ -64,75 +75,36 @@ export function useNodeEvent(eventJson: NodeDataEventJsonType, dataSourceJson: N @@ -64,75 +75,36 @@ export function useNodeEvent(eventJson: NodeDataEventJsonType, dataSourceJson: N
64 window.DrawApp.selectPage(openPageFile) 75 window.DrawApp.selectPage(openPageFile)
65 } 76 }
66 77
67 - const handleParamsSetting = async (_data: SingleClickEventDataType) => {  
68 - const deviceInfo = dataSourceJson  
69 - 78 + const handleParamsSetting = async (data: SingleClickEventDataType) => {
70 const instance = h(CommandDeliveryModal) 79 const instance = h(CommandDeliveryModal)
71 render(instance, document.body); 80 render(instance, document.body);
72 - (instance.component?.exposed as InstanceType<typeof CommandDeliveryModal>)?.open({ ..._data, deviceInfo, operationPassword: eventJson?.OPERATION_PASSWORD }) 81 + (instance.component?.exposed as InstanceType<typeof CommandDeliveryModal>)?.open({ dataSource: toRaw(unref(dataSourceJson)), eventBindData: data, operationPasswordInfo: eventJson.OPERATION_PASSWORD })
73 } 82 }
74 83
75 const handleAttributeDelivery = async (data: SingleClickEventDataType) => { 84 const handleAttributeDelivery = async (data: SingleClickEventDataType) => {
76 try { 85 try {
77 const nodeUtils = new NodeUtils() 86 const nodeUtils = new NodeUtils()
78 - const { way = CommandWayEnum.ONE_WAY } = data  
79 - const { attr, deviceId, attrInfo } = dataSourceJson  
80 - const { transportType, alias, name: deviceName, code, codeType } = await getDeviceInfo(dataSourceJson.deviceId) || {}// 设备信息  
81 - const contentDataStore = useContentDataStoreWithOut()  
82 - const currentData = contentDataStore.contentData.find(item => item.id === cell.getId())  
83 - if (!currentData) return  
84 - const { actJson, eventJson } = currentData  
85 - const { value: operationPassword, checked: operationPasswordEnable } = eventJson.OPERATION_PASSWORD 87 + const operationPasswordInfo = toRaw(unref(eventJson.OPERATION_PASSWORD))
86 88
87 - const command: RpcCommandType = {  
88 - additionalInfo: { cmdType: 'API' },  
89 - method: 'methodThingskit',  
90 - params: {},  
91 - persistent: true,  
92 - }  
93 if (nodeUtils.getNodeComponentKey(cell) === ControlComponentEnum.SWITCH) { 89 if (nodeUtils.getNodeComponentKey(cell) === ControlComponentEnum.SWITCH) {
  90 + const contentDataStore = useContentDataStoreWithOut()
  91 + const currentData = contentDataStore.contentData.find(item => item.id === cell.getId())
  92 + if (!currentData) return
  93 + const { actJson } = currentData
94 const { rangeList } = actJson.STATUS_SETTING 94 const { rangeList } = actJson.STATUS_SETTING
95 const status = cell.getAttribute('SWITCH_STATUS') 95 const status = cell.getAttribute('SWITCH_STATUS')
96 const res = rangeList.find(item => item.type === (status === ActRangListItemTypeEnum.OPEN ? ActRangListItemTypeEnum.CLOSE : ActRangListItemTypeEnum.OPEN)) 96 const res = rangeList.find(item => item.type === (status === ActRangListItemTypeEnum.OPEN ? ActRangListItemTypeEnum.CLOSE : ActRangListItemTypeEnum.OPEN))
97 if (!res) return 97 if (!res) return
98 const { statusValue } = res 98 const { statusValue } = res
99 99
100 - command.params = transportType === TransportTypeEnum.TCP  
101 - ? statusValue!  
102 - : {  
103 - [attr]: statusValue,  
104 - }  
105 -  
106 - if (operationPasswordEnable) {  
107 - const instance = h(CommandDeliveryConfirmModal)  
108 - render(instance, document.body)  
109 - await (instance.component?.exposed as InstanceType<typeof CommandDeliveryConfirmModal>)?.open(operationPassword!)  
110 - }  
111 - else {  
112 - const instance = h(ConfirmModal)  
113 - render(instance, document.body)  
114 - await (instance.component?.exposed as InstanceType<typeof ConfirmModal>)?.open()  
115 - }  
116 -  
117 - if (transportType === TransportTypeEnum.TCP && codeType === CodeTypeEnum.MODBUS_RTU) {  
118 - const { validateCanGetCommand, getModbusCommand } = useGetModbusCommand()  
119 - if (!validateCanGetCommand(unref(dataSourceJson).attrInfo.extensionDesc, code).flag) return  
120 - const res = await getModbusCommand(statusValue!, unref(dataSourceJson).attrInfo.extensionDesc!, code)  
121 - if (!res) return  
122 - command.params = res  
123 - }  
124 -  
125 - await doCommandDelivery({ way, command, deviceId })  
126 - createMessage.success('命令下发成功') 100 + const instance = h(SwitchCommandDeliveryModal)
  101 + render(instance, document.body)
  102 + await (instance.component?.exposed as InstanceType<typeof SwitchCommandDeliveryModal>)?.open({ operationPasswordInfo, eventBindData: toRaw(unref(data)), dataSourceJson: toRaw(unref(dataSourceJson)), sendValue: statusValue }!)
127 } 103 }
128 else { 104 else {
129 const instance = h(AttributeDeliverModal) 105 const instance = h(AttributeDeliverModal)
130 - render(instance, document.body)  
131 - const value = await (instance.component?.exposed as InstanceType<typeof AttributeDeliverModal>)?.open({ title: `${alias || deviceName}-${attrInfo.name}`, operationPassword, operationPasswordEnable, dataSourceJson }) as string  
132 - command.params = transportType === TransportTypeEnum.TCP ? value : { [attr]: value }  
133 - if (!command.params) return  
134 - await doCommandDelivery({ way, command, deviceId })  
135 - createMessage.success('命令下发成功') 106 + render(instance, document.body);
  107 + (instance.component?.exposed as InstanceType<typeof AttributeDeliverModal>)?.open({ dataSourceJson, operationPasswordInfo, eventBindData: data })
136 } 108 }
137 } 109 }
138 catch (error) { 110 catch (error) {
  1 +import type { ConfigurationContentType } from '@/api/content/model'
  2 +import { getProductsDetailWithThingsModel } from '@/api/device'
  3 +import { useProductsStoreWithOut } from '@/store/modules/products'
  4 +
  5 +export function useProduct() {
  6 + const getAllDeviceProfileIds = async (contentData: ConfigurationContentType) => {
  7 + const deviceProfileIds = contentData.productAndDevice?.map(item => item.profileId) || []
  8 + const result = await getProductsDetailWithThingsModel({ deviceProfileIds, functionTypeEnum: 'all' })
  9 + const productsStore = useProductsStoreWithOut()
  10 + productsStore.setProducts(result.reduce((prev, next) => ({ ...prev, [next.id]: next }), {}))
  11 + }
  12 +
  13 + return {
  14 + getAllDeviceProfileIds,
  15 + }
  16 +}
@@ -57,9 +57,9 @@ const handleSubmit = async () => { @@ -57,9 +57,9 @@ const handleSubmit = async () => {
57 57
58 const handleSetFormValues = async () => { 58 const handleSetFormValues = async () => {
59 const { dataSourceJson } = unref(getNodeData) || {} 59 const { dataSourceJson } = unref(getNodeData) || {}
60 - const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId, attrInfo, deviceInfo } = dataSourceJson || {} 60 + const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId } = dataSourceJson || {}
61 await nextTick() 61 await nextTick()
62 - unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, attrInfo, deviceProfileTemplateId, deviceInfo }) 62 + unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, deviceProfileTemplateId })
63 setFieldsValue({ ...chartOption }) 63 setFieldsValue({ ...chartOption })
64 } 64 }
65 65
@@ -55,9 +55,9 @@ const handleSubmit = async () => { @@ -55,9 +55,9 @@ const handleSubmit = async () => {
55 55
56 const handleSetFormValues = async () => { 56 const handleSetFormValues = async () => {
57 const { dataSourceJson } = unref(getNodeData) || {} 57 const { dataSourceJson } = unref(getNodeData) || {}
58 - const { deviceId, attr, chartOption, deviceProfileId, attrInfo, deviceProfileTemplateId, deviceInfo } = dataSourceJson || {} 58 + const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId } = dataSourceJson || {}
59 await nextTick() 59 await nextTick()
60 - unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, attrInfo, deviceInfo, deviceProfileTemplateId }) 60 + unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, deviceProfileTemplateId })
61 setFieldsValue({ ...chartOption }) 61 setFieldsValue({ ...chartOption })
62 } 62 }
63 63
@@ -33,9 +33,9 @@ const dataSourceElRef = ref<Nullable<InstanceType<typeof DataSourceForm>>>() @@ -33,9 +33,9 @@ const dataSourceElRef = ref<Nullable<InstanceType<typeof DataSourceForm>>>()
33 33
34 const handleSetFormValues = async () => { 34 const handleSetFormValues = async () => {
35 const { dataSourceJson } = unref(getNodeData) || {} 35 const { dataSourceJson } = unref(getNodeData) || {}
36 - const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId, attrInfo, deviceInfo } = dataSourceJson || {} 36 + const { deviceId, attr, chartOption, deviceProfileId, deviceProfileTemplateId } = dataSourceJson || {}
37 await nextTick() 37 await nextTick()
38 - unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, deviceProfileTemplateId, attrInfo, deviceInfo }) 38 + unref(dataSourceElRef)?.setFieldsValue({ deviceId, attr, deviceProfileId, deviceProfileTemplateId })
39 setFieldsValue({ ...chartOption }) 39 setFieldsValue({ ...chartOption })
40 } 40 }
41 41
@@ -8,6 +8,7 @@ import { useContentDataStoreWithOut } from '@/store/modules/contentData' @@ -8,6 +8,7 @@ import { useContentDataStoreWithOut } from '@/store/modules/contentData'
8 import { useUserStoreWithOut } from '@/store/modules/user' 8 import { useUserStoreWithOut } from '@/store/modules/user'
9 import { useMessage } from '@/hooks/web/useMessage' 9 import { useMessage } from '@/hooks/web/useMessage'
10 import { MessageEnum } from '@/enums/messageEnum' 10 import { MessageEnum } from '@/enums/messageEnum'
  11 +import { useProduct } from '@/core/Library/hook/useProduct'
11 12
12 export function useContentData() { 13 export function useContentData() {
13 const contentDataStore = useContentDataStoreWithOut() 14 const contentDataStore = useContentDataStoreWithOut()
@@ -46,6 +47,9 @@ export function useContentData() { @@ -46,6 +47,9 @@ export function useContentData() {
46 const result = mode === PageModeEnum.SHARE ? await shareModeBootstrap() : await getContent() 47 const result = mode === PageModeEnum.SHARE ? await shareModeBootstrap() : await getContent()
47 48
48 if (result) { 49 if (result) {
  50 + const { getAllDeviceProfileIds } = useProduct()
  51 + await getAllDeviceProfileIds(result)
  52 +
49 const { productAndDevice, nodelist, isTemplate, templateId } = result 53 const { productAndDevice, nodelist, isTemplate, templateId } = result
50 if (nodelist) contentDataStore.saveContentData(nodelist) 54 if (nodelist) contentDataStore.saveContentData(nodelist)
51 if (isTemplate) contentDataStore.setIsTemplate(isTemplate) 55 if (isTemplate) contentDataStore.setIsTemplate(isTemplate)
@@ -2,6 +2,7 @@ import { isNull } from 'lodash-es' @@ -2,6 +2,7 @@ import { isNull } from 'lodash-es'
2 import type { App } from 'vue' 2 import type { App } from 'vue'
3 import type { SubscriptionUpdateMsg } from '../type/message' 3 import type { SubscriptionUpdateMsg } from '../type/message'
4 import { DataDynamicEffectHandler } from './dataDynamicEffectHandler' 4 import { DataDynamicEffectHandler } from './dataDynamicEffectHandler'
  5 +import { useObjectModelValue } from './useObjectModelValue'
5 import type { CommandSource, LightboxModeWebsocketService } from '.' 6 import type { CommandSource, LightboxModeWebsocketService } from '.'
6 import type { ActTypeEnum } from '@/enums/datasource' 7 import type { ActTypeEnum } from '@/enums/datasource'
7 import { DataSourceTypeEnum } from '@/enums/datasource' 8 import { DataSourceTypeEnum } from '@/enums/datasource'
@@ -52,10 +53,13 @@ export class MessageHandler { @@ -52,10 +53,13 @@ export class MessageHandler {
52 53
53 defaultHandler(commandSource: CommandSource, message: SubscriptionUpdateMsg) { 54 defaultHandler(commandSource: CommandSource, message: SubscriptionUpdateMsg) {
54 const { data, node } = commandSource 55 const { data, node } = commandSource
55 - const { attr } = data as NodeDataDataSourceJsonType  
56 - const { latestValue } = useLatestMessageValue(message.data, attr) 56 + const { attr, deviceProfileId } = data as NodeDataDataSourceJsonType
  57 +
  58 + let { latestValue } = useLatestMessageValue(message.data, attr)
57 if (isNull(latestValue)) return 59 if (isNull(latestValue)) return
  60 + latestValue = useObjectModelValue(deviceProfileId, attr, latestValue)
58 const cell = this.nodeUtils.getCellById(node) 61 const cell = this.nodeUtils.getCellById(node)
  62 +
59 const cellValue = cell.getValue() as Element 63 const cellValue = cell.getValue() as Element
60 cellValue.setAttribute('label', latestValue) 64 cellValue.setAttribute('label', latestValue)
61 this.nodeUtils.updateCellValue(cell, cellValue) 65 this.nodeUtils.updateCellValue(cell, cellValue)
  1 +import type { DataType, Specs, StructJSON } from '@/api/device/model'
  2 +import { DataTypeEnum } from '@/enums/datasource'
  3 +import { useJsonParse } from '@/hooks/business/useJSONParse'
  4 +import { useProductsStoreWithOut } from '@/store/modules/products'
  5 +
  6 +function getBoolTypeValue(value: number, Specs: Specs) {
  7 + const { boolOpen, boolClose } = Specs
  8 +
  9 + return Number(value) ? boolOpen : boolClose
  10 +}
  11 +
  12 +function getEnumTypeValue(value: number, specsList: Specs[]) {
  13 + const res = specsList.find(item => item.value === Number(value))
  14 +
  15 + return res?.name
  16 +}
  17 +
  18 +function getStructTypeValue(value: string, specs: StructJSON[]): string {
  19 + const res = useJsonParse(value).value
  20 +
  21 + function generateStruct(specs: StructJSON[], value: Recordable) {
  22 + if (!value) return {}
  23 +
  24 + return specs.reduce((prev, next) => {
  25 + return {
  26 + ...prev,
  27 + [next.functionName]: getValueByType(next.dataType!.type, value[next.identifier], next.dataType!),
  28 + }
  29 + }, {})
  30 + }
  31 +
  32 + return JSON.stringify(generateStruct(specs, res))
  33 +}
  34 +
  35 +function getValueByType(type: string, value: any, dataType: DataType) {
  36 + switch (type) {
  37 + case DataTypeEnum.BOOL:
  38 + return getBoolTypeValue(value, dataType.specs as Specs)
  39 + case DataTypeEnum.STRUCT:
  40 + return getStructTypeValue(value, dataType.specs as StructJSON[])
  41 + case DataTypeEnum.ENUM:
  42 + return getEnumTypeValue(value, dataType.specsList as Specs[])
  43 + default:
  44 + return value
  45 + }
  46 +}
  47 +
  48 +export function useObjectModelValue(deviceProfileId: string, attr: string, value: any) {
  49 + const productsStore = useProductsStoreWithOut()
  50 +
  51 + const result = productsStore.getObjectModelByIdWithIdentifier(deviceProfileId, attr)
  52 + if (!result)
  53 + return value
  54 +
  55 + return getValueByType(result.specs.dataType.type as DataTypeEnum, value, result.specs.dataType)
  56 +}
@@ -7,3 +7,16 @@ export enum CommandWayNameEnum { @@ -7,3 +7,16 @@ export enum CommandWayNameEnum {
7 ONE_WAY = '单向', 7 ONE_WAY = '单向',
8 TWO_WAY = '双向', 8 TWO_WAY = '双向',
9 } 9 }
  10 +
  11 +export enum CommandCallWayEnum {
  12 + SYNC = 'SYNC',
  13 + ASYNC = 'ASYNC',
  14 +}
  15 +
  16 +export enum CommandMethodEnum {
  17 + THINGSKIT = 'methodThingskit',
  18 +}
  19 +
  20 +export enum ModbusCRCEnum {
  21 + CRC_16_LOWER = 'CRC_16_LOWER',
  22 +}
@@ -244,11 +244,7 @@ export enum ContentDataFieldsEnum { @@ -244,11 +244,7 @@ export enum ContentDataFieldsEnum {
244 ACCESS_MODE = 'accessMode', 244 ACCESS_MODE = 'accessMode',
245 VIDEO_FLAG = 'videoComponentFlag', 245 VIDEO_FLAG = 'videoComponentFlag',
246 246
247 - ATTR_INFO = 'attrInfo',  
248 - DEVICE_INFO = 'deviceInfo',  
249 - TRANSPORT_TYPE = 'transportType',  
250 CODE_TYPE = 'codeType', 247 CODE_TYPE = 'codeType',
251 - DEVICE_ADDITIONAL_INFO = 'deviceAdditionalInfo',  
252 } 248 }
253 249
254 export enum ContentDataFieldsNameEnum { 250 export enum ContentDataFieldsNameEnum {
@@ -261,10 +257,6 @@ export enum ContentDataFieldsNameEnum { @@ -261,10 +257,6 @@ export enum ContentDataFieldsNameEnum {
261 ACCESS_MODE = 'ACCESS_MODE', 257 ACCESS_MODE = 'ACCESS_MODE',
262 VIDEO_URL = '视频地址', 258 VIDEO_URL = '视频地址',
263 259
264 - ATTR_INFO = '物模型属性详情',  
265 - DEVICE_INFO = '设备详情',  
266 - TRANSPORT_TYPE = '传输协议',  
267 - DEVICE_ADDITIONAL_INFO = '设备额外信息',  
268 } 260 }
269 261
270 export enum VariableImageSourceEnum { 262 export enum VariableImageSourceEnum {
@@ -289,7 +281,7 @@ export enum CommandDeliveryWayNameEnum { @@ -289,7 +281,7 @@ export enum CommandDeliveryWayNameEnum {
289 MODBUS = 'MODBUS', 281 MODBUS = 'MODBUS',
290 } 282 }
291 283
292 -export enum FunctionType { 284 +export enum FunctionTypeEnum {
293 PROPERTIES = 'properties', 285 PROPERTIES = 'properties',
294 EVENTS = 'events', 286 EVENTS = 'events',
295 SERVICE = 'services', 287 SERVICE = 'services',
  1 +import { defineStore } from 'pinia'
  2 +import { store } from '..'
  3 +import type { ProductsDetailWithThingsModelType, Tsl } from '@/api/device/model'
  4 +
  5 +interface ProductsStoreType {
  6 + products: Record<string, ProductsDetailWithThingsModelType>
  7 +}
  8 +
  9 +export const useProductsStore = defineStore('app-products', {
  10 + state: (): ProductsStoreType => {
  11 + return {
  12 + products: {},
  13 + }
  14 + },
  15 + actions: {
  16 + setProducts(products: Record<string, ProductsDetailWithThingsModelType>) {
  17 + this.products = products
  18 + },
  19 +
  20 + getProductDetailById(id: string) {
  21 + return this.products[id]
  22 + },
  23 +
  24 + getObjectModelsById(id: string) {
  25 + return this.products[id]
  26 + },
  27 +
  28 + getObjectModelByIdWithIdentifier(id: string, identifier: string): Nullable<Tsl> {
  29 + const product = this.getObjectModelsById(id)
  30 + if (!product) return null
  31 + return product.tsl.filter(item => item.identifier === identifier)[0]
  32 + },
  33 + },
  34 +})
  35 +
  36 +export function useProductsStoreWithOut() {
  37 + return useProductsStore(store)
  38 +}
@@ -61,6 +61,8 @@ declare global { @@ -61,6 +61,8 @@ declare global {
61 61
62 useLightboxModeService: Fn 62 useLightboxModeService: Fn
63 63
  64 + useProduct: Fn
  65 +
64 useAuth: Fn 66 useAuth: Fn
65 } 67 }
66 } 68 }