Commit f5633032ae96338a98b842a950727e2da0d93ded

Authored by ww
1 parent 9245f97a

perf: 优化数据看板控制组件&&数据源绑定

Showing 59 changed files with 1308 additions and 1266 deletions
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 ], 6 ],
7 "cSpell.words": [ 7 "cSpell.words": [
8 "ACKS", 8 "ACKS",
  9 + "Cascader",
9 "clazz", 10 "clazz",
10 "Cmds", 11 "Cmds",
11 "COAP", 12 "COAP",
@@ -137,7 +137,7 @@ export const createOrEditDevice = (data) => { @@ -137,7 +137,7 @@ export const createOrEditDevice = (data) => {
137 137
138 // 查询设备详情 138 // 查询设备详情
139 export const getDeviceDetail = (id: string) => { 139 export const getDeviceDetail = (id: string) => {
140 - return defHttp.get({ 140 + return defHttp.get<DeviceRecord>({
141 url: DeviceManagerApi.DEVICE_URL + `/${id}`, 141 url: DeviceManagerApi.DEVICE_URL + `/${id}`,
142 }); 142 });
143 }; 143 };
1 import { DataTypeEnum } from '/@/enums/objectModelEnum'; 1 import { DataTypeEnum } from '/@/enums/objectModelEnum';
2 -import { FunctionType } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; 2 +import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
3 3
4 export interface Specs { 4 export interface Specs {
5 min: string; 5 min: string;
@@ -9,7 +9,7 @@ export interface Specs { @@ -9,7 +9,7 @@ export interface Specs {
9 9
10 dataType?: string; 10 dataType?: string;
11 name?: string; 11 name?: string;
12 - value?: string; 12 + value?: string | number;
13 step: string; 13 step: string;
14 length: string; 14 length: string;
15 boolOpen: string; 15 boolOpen: string;
@@ -26,6 +26,13 @@ export interface DataType { @@ -26,6 +26,13 @@ export interface DataType {
26 specsList?: Specs[]; 26 specsList?: Specs[];
27 } 27 }
28 28
  29 +export interface ExtensionDesc {
  30 + zoomFactor?: number;
  31 + actionType?: string;
  32 + dataType: string;
  33 + registerAddress: number;
  34 +}
  35 +
29 export interface StructJSON { 36 export interface StructJSON {
30 functionName?: string; 37 functionName?: string;
31 identifier: string; 38 identifier: string;
@@ -46,7 +53,7 @@ export interface ModelOfMatterParams { @@ -46,7 +53,7 @@ export interface ModelOfMatterParams {
46 deviceProfileId?: string; 53 deviceProfileId?: string;
47 functionJson: FunctionJson; 54 functionJson: FunctionJson;
48 functionName: string; 55 functionName: string;
49 - functionType: FunctionType; 56 + functionType: FunctionTypeEnum;
50 identifier: string; 57 identifier: string;
51 remark: string; 58 remark: string;
52 id?: string; 59 id?: string;
@@ -54,11 +61,11 @@ export interface ModelOfMatterParams { @@ -54,11 +61,11 @@ export interface ModelOfMatterParams {
54 callType?: string; 61 callType?: string;
55 eventType?: string; 62 eventType?: string;
56 accessMode?: string; 63 accessMode?: string;
57 - extensionDesc?: Recordable; 64 + extensionDesc?: ExtensionDesc;
58 } 65 }
59 66
60 export interface GetModelTslParams { 67 export interface GetModelTslParams {
61 - functionType: FunctionType; 68 + functionType: FunctionTypeEnum;
62 deviceProfileId: string; 69 deviceProfileId: string;
63 ifShowClass?: string | Boolean; 70 ifShowClass?: string | Boolean;
64 } 71 }
@@ -85,3 +92,26 @@ export interface ModelOfMatterItemRecordType { @@ -85,3 +92,26 @@ export interface ModelOfMatterItemRecordType {
85 status: number; 92 status: number;
86 deviceProfileId: string; 93 deviceProfileId: string;
87 } 94 }
  95 +
  96 +export interface BatchGetObjectModelItemType {
  97 + id: string;
  98 + name: string;
  99 + transportType: string;
  100 + deviceType: string;
  101 + tsl: Tsl[];
  102 +}
  103 +
  104 +export interface Tsl {
  105 + functionName: string;
  106 + identifier: string;
  107 + functionType: string;
  108 + accessMode?: string;
  109 + specs?: {
  110 + dataType: DataType;
  111 + };
  112 + extensionDesc: ExtensionDesc;
  113 + eventType?: string;
  114 + outputData?: StructJSON[];
  115 + callType?: string;
  116 + inputData?: StructJSON[];
  117 +}
1 import { BasicPageParams } from '../model/baseModel'; 1 import { BasicPageParams } from '../model/baseModel';
2 import { 2 import {
  3 + BatchGetObjectModelItemType,
3 GetModelTslParams, 4 GetModelTslParams,
4 ImportModelOfMatterType, 5 ImportModelOfMatterType,
5 ModelOfMatterItemRecordType, 6 ModelOfMatterItemRecordType,
6 ModelOfMatterParams, 7 ModelOfMatterParams,
7 } from './model/modelOfMatterModel'; 8 } from './model/modelOfMatterModel';
  9 +import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
8 import { defHttp } from '/@/utils/http/axios'; 10 import { defHttp } from '/@/utils/http/axios';
9 -import { FunctionType } from '/@/views/device/profiles/step/cpns/physical/cpns/config';  
10 11
11 enum ModelOfMatter { 12 enum ModelOfMatter {
12 CREATE = '/things_model', 13 CREATE = '/things_model',
@@ -26,12 +27,14 @@ enum ModelOfMatter { @@ -26,12 +27,14 @@ enum ModelOfMatter {
26 27
27 IMPORT_CSV = '/things_model/csvImport', 28 IMPORT_CSV = '/things_model/csvImport',
28 EXCEL_EXPORT = '/things_model/downloadTemplate', 29 EXCEL_EXPORT = '/things_model/downloadTemplate',
  30 +
  31 + BATCH_GET_TSL_BY_DEVICE_PROFILES = '/things_model/batch/get_tsl',
29 } 32 }
30 33
31 export const getModelList = ( 34 export const getModelList = (
32 params: BasicPageParams & { 35 params: BasicPageParams & {
33 deviceProfileId?: string; 36 deviceProfileId?: string;
34 - functionTyp?: FunctionType; 37 + functionTyp?: FunctionTypeEnum;
35 nameOrIdentifier?: string; 38 nameOrIdentifier?: string;
36 selectType?: string | undefined; 39 selectType?: string | undefined;
37 id?: string; 40 id?: string;
@@ -181,3 +184,16 @@ export const excelExport = () => { @@ -181,3 +184,16 @@ export const excelExport = () => {
181 responseType: 'blob', 184 responseType: 'blob',
182 }); 185 });
183 }; 186 };
  187 +
  188 +export const batchGetObjectModel = ({
  189 + deviceProfileIds,
  190 + functionTypeEnum = 'all',
  191 +}: {
  192 + deviceProfileIds: string[];
  193 + functionTypeEnum?: FunctionTypeEnum | 'all';
  194 +}) => {
  195 + return defHttp.post<BatchGetObjectModelItemType[]>({
  196 + url: ModelOfMatter.BATCH_GET_TSL_BY_DEVICE_PROFILES,
  197 + data: { deviceProfileIds, functionTypeEnum },
  198 + });
  199 +};
@@ -59,7 +59,7 @@ export interface GenModbusCommandType { @@ -59,7 +59,7 @@ export interface GenModbusCommandType {
59 crc: string; 59 crc: string;
60 deviceCode: string; 60 deviceCode: string;
61 method: string; 61 method: string;
62 - registerAddress: string; 62 + registerAddress: number;
63 registerNumber?: number; 63 registerNumber?: number;
64 registerValues?: number[]; 64 registerValues?: number[];
65 } 65 }
@@ -11,6 +11,7 @@ export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.v @@ -11,6 +11,7 @@ export { default as RadioButtonGroup } from './src/components/RadioButtonGroup.v
11 export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue'; 11 export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue';
12 export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue'; 12 export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue';
13 export { default as ApiUpload } from './src/components/ApiUpload.vue'; 13 export { default as ApiUpload } from './src/components/ApiUpload.vue';
  14 +export { default as ApiCascader } from './src/components/ApiCascader.vue';
14 15
15 export { default as StructForm } from './src/components/StructForm/StructForm.vue'; 16 export { default as StructForm } from './src/components/StructForm/StructForm.vue';
16 export { default as JavaScriptFunctionEditor } from './src/components/JavaScriptFunctionEditor.vue'; 17 export { default as JavaScriptFunctionEditor } from './src/components/JavaScriptFunctionEditor.vue';
  1 +<script setup lang="ts">
  2 + import { Cascader } from 'ant-design-vue';
  3 + import { LoadingOutlined } from '@ant-design/icons-vue';
  4 + import { CascaderOptionType } from 'ant-design-vue/lib/cascader';
  5 + import { get } from 'lodash';
  6 + import { ref, unref, watch, watchEffect } from 'vue';
  7 + import { useRuleFormItem } from '/@/hooks/component/useFormItem';
  8 + import { useI18n } from '/@/hooks/web/useI18n';
  9 + import { isFunction } from '/@/utils/is';
  10 +
  11 + const { t } = useI18n();
  12 +
  13 + const props = withDefaults(
  14 + defineProps<{
  15 + value?: (string | number)[];
  16 + immediate?: boolean;
  17 + params?: any;
  18 + api?: Fn<any, Promise<any>>;
  19 + options?: CascaderOptionType[];
  20 + resultField?: string;
  21 + fieldNames?: Record<'label' | 'value' | 'children', string>;
  22 + }>(),
  23 + {
  24 + value: () => [],
  25 + immediate: true,
  26 + fieldNames: () => ({ label: 'label', value: 'value', children: 'children' }),
  27 + }
  28 + );
  29 +
  30 + const emit = defineEmits(['change', 'options-change', 'update:value']);
  31 +
  32 + const options = ref<CascaderOptionType[]>([]);
  33 + const loading = ref(false);
  34 + const isFirstLoad = ref(true);
  35 + const emitData = ref<any[]>([]);
  36 +
  37 + // Embedded in the form, just use the hook binding to perform form verification
  38 + const [state] = useRuleFormItem(props, 'value', 'update:value', emitData);
  39 +
  40 + watchEffect(() => {
  41 + props.immediate && fetch();
  42 + });
  43 +
  44 + watch(
  45 + () => props.params,
  46 + () => {
  47 + !unref(isFirstLoad) && fetch();
  48 + },
  49 + { deep: true }
  50 + );
  51 +
  52 + async function fetch() {
  53 + const api = props.api;
  54 + if (!api || !isFunction(api)) return;
  55 + options.value = [];
  56 + try {
  57 + loading.value = true;
  58 + const res = await api(props.params);
  59 + if (Array.isArray(res)) {
  60 + options.value = res;
  61 + emitChange();
  62 + return;
  63 + }
  64 + if (props.resultField) {
  65 + options.value = get(res, props.resultField) || [];
  66 + }
  67 + emitChange();
  68 + } catch (error) {
  69 + console.warn(error);
  70 + } finally {
  71 + loading.value = false;
  72 + }
  73 + }
  74 +
  75 + async function handleFetch(open) {
  76 + if (open) {
  77 + await fetch();
  78 + }
  79 + }
  80 +
  81 + function emitChange() {
  82 + emit('options-change', options);
  83 + }
  84 +
  85 + function handleChange(_, ...args) {
  86 + emitData.value = args;
  87 + }
  88 +</script>
  89 +
  90 +<template>
  91 + <Cascader
  92 + v-bind="$attrs"
  93 + @change="handleChange"
  94 + :fieldNames="fieldNames"
  95 + :options="options"
  96 + v-model:value="state"
  97 + @popupVisibleChange="handleFetch"
  98 + >
  99 + <template #notFoundContent v-if="loading">
  100 + <span>
  101 + <LoadingOutlined spin class="mr-1" />
  102 + {{ t('component.form.apiSelectNotFound') }}
  103 + </span>
  104 + </template>
  105 + </Cascader>
  106 +</template>
@@ -117,6 +117,7 @@ export type ComponentType = @@ -117,6 +117,7 @@ export type ComponentType =
117 | 'ColorPicker' 117 | 'ColorPicker'
118 | 'IconDrawer' 118 | 'IconDrawer'
119 | 'ApiUpload' 119 | 'ApiUpload'
  120 + | 'ApiCascader'
120 | 'ApiSearchSelect' 121 | 'ApiSearchSelect'
121 | 'StructForm' 122 | 'StructForm'
122 | 'ApiSelectScrollLoad' 123 | 'ApiSelectScrollLoad'
@@ -7,6 +7,12 @@ export enum DataTypeEnum { @@ -7,6 +7,12 @@ export enum DataTypeEnum {
7 ENUM = 'ENUM', 7 ENUM = 'ENUM',
8 } 8 }
9 9
  10 +export enum FunctionTypeEnum {
  11 + PROPERTIES = 'properties',
  12 + EVENTS = 'events',
  13 + SERVICE = 'services',
  14 +}
  15 +
10 export enum RegisterDataTypeEnum { 16 export enum RegisterDataTypeEnum {
11 UN_SHORT = 'unshort', 17 UN_SHORT = 'unshort',
12 } 18 }
@@ -26,3 +32,7 @@ export enum RegisterActionTypeNameEnum { @@ -26,3 +32,7 @@ export enum RegisterActionTypeNameEnum {
26 INT = '06写入单个保持寄存器', 32 INT = '06写入单个保持寄存器',
27 DOUBLE = '16写入多个保持寄存器', 33 DOUBLE = '16写入多个保持寄存器',
28 } 34 }
  35 +
  36 +export enum ModbusCRCEnum {
  37 + CRC_16_LOWER = 'CRC_16_LOWER',
  38 +}
@@ -2,8 +2,7 @@ import { BasicColumn, FormSchema } from '/@/components/Table'; @@ -2,8 +2,7 @@ import { BasicColumn, FormSchema } from '/@/components/Table';
2 import { findDictItemByCode } from '/@/api/system/dict'; 2 import { findDictItemByCode } from '/@/api/system/dict';
3 import { h, unref } from 'vue'; 3 import { h, unref } from 'vue';
4 import { Tooltip } from 'ant-design-vue'; 4 import { Tooltip } from 'ant-design-vue';
5 -  
6 -import { FunctionType } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; 5 +import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
7 import { useMessage } from '/@/hooks/web/useMessage'; 6 import { useMessage } from '/@/hooks/web/useMessage';
8 import { useClipboard } from '@vueuse/core'; 7 import { useClipboard } from '@vueuse/core';
9 import { DictEnum } from '/@/enums/dictEnum'; 8 import { DictEnum } from '/@/enums/dictEnum';
@@ -26,10 +25,10 @@ export const columns: BasicColumn[] = [ @@ -26,10 +25,10 @@ export const columns: BasicColumn[] = [
26 }, 25 },
27 ]; 26 ];
28 27
29 -export const formatFunctionType: Record<FunctionType, string> = {  
30 - [FunctionType.PROPERTIES]: '属性',  
31 - [FunctionType.EVENTS]: '事件',  
32 - [FunctionType.SERVICE]: '服务', 28 +export const formatFunctionType: Record<FunctionTypeEnum, string> = {
  29 + [FunctionTypeEnum.PROPERTIES]: '属性',
  30 + [FunctionTypeEnum.EVENTS]: '事件',
  31 + [FunctionTypeEnum.SERVICE]: '服务',
33 }; 32 };
34 33
35 const handleCopy = async (value: string) => { 34 const handleCopy = async (value: string) => {
@@ -45,7 +44,7 @@ export const columnsDrawer: BasicColumn[] = [ @@ -45,7 +44,7 @@ export const columnsDrawer: BasicColumn[] = [
45 title: '功能类型', 44 title: '功能类型',
46 dataIndex: 'functionType', 45 dataIndex: 'functionType',
47 width: 90, 46 width: 90,
48 - format: (text: FunctionType) => { 47 + format: (text: FunctionTypeEnum) => {
49 return formatFunctionType[text]; 48 return formatFunctionType[text];
50 }, 49 },
51 }, 50 },
@@ -5,7 +5,8 @@ import { MessageEnum } from '/@/enums/messageEnum'; @@ -5,7 +5,8 @@ import { MessageEnum } from '/@/enums/messageEnum';
5 import { numberRule } from '/@/utils/rules'; 5 import { numberRule } from '/@/utils/rules';
6 6
7 import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi'; 7 import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi';
8 -import { FormField, FunctionType } from './step/cpns/physical/cpns/config'; 8 +import { FormField } from './step/cpns/physical/cpns/config';
  9 +import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
9 import { h, unref } from 'vue'; 10 import { h, unref } from 'vue';
10 import { Tag, Tooltip } from 'ant-design-vue'; 11 import { Tag, Tooltip } from 'ant-design-vue';
11 import { EventType, EventTypeColor, EventTypeName } from '../list/cpns/tabs/EventManage/config'; 12 import { EventType, EventTypeColor, EventTypeName } from '../list/cpns/tabs/EventManage/config';
@@ -68,10 +69,10 @@ export const steps = [ @@ -68,10 +69,10 @@ export const steps = [
68 }, 69 },
69 ]; 70 ];
70 71
71 -export const formatFunctionType: Record<FunctionType, string> = {  
72 - [FunctionType.PROPERTIES]: '属性',  
73 - [FunctionType.EVENTS]: '事件',  
74 - [FunctionType.SERVICE]: '服务', 72 +export const formatFunctionType: Record<FunctionTypeEnum, string> = {
  73 + [FunctionTypeEnum.PROPERTIES]: '属性',
  74 + [FunctionTypeEnum.EVENTS]: '事件',
  75 + [FunctionTypeEnum.SERVICE]: '服务',
75 }; 76 };
76 77
77 export const physicalColumn: BasicColumn[] = [ 78 export const physicalColumn: BasicColumn[] = [
@@ -79,7 +80,7 @@ export const physicalColumn: BasicColumn[] = [ @@ -79,7 +80,7 @@ export const physicalColumn: BasicColumn[] = [
79 title: '功能类型', 80 title: '功能类型',
80 dataIndex: FormField.FUNCTION_TYPE, 81 dataIndex: FormField.FUNCTION_TYPE,
81 width: 90, 82 width: 90,
82 - format: (text: FunctionType) => { 83 + format: (text: FunctionTypeEnum) => {
83 return formatFunctionType[text]; 84 return formatFunctionType[text];
84 }, 85 },
85 }, 86 },
@@ -153,9 +154,12 @@ export const modelOfMatterForm: FormSchema[] = [ @@ -153,9 +154,12 @@ export const modelOfMatterForm: FormSchema[] = [
153 colProps: { span: 8 }, 154 colProps: { span: 8 },
154 componentProps: { 155 componentProps: {
155 options: [ 156 options: [
156 - { label: formatFunctionType[FunctionType.PROPERTIES], value: FunctionType.PROPERTIES },  
157 - { label: formatFunctionType[FunctionType.EVENTS], value: FunctionType.EVENTS },  
158 - { label: formatFunctionType[FunctionType.SERVICE], value: FunctionType.SERVICE }, 157 + {
  158 + label: formatFunctionType[FunctionTypeEnum.PROPERTIES],
  159 + value: FunctionTypeEnum.PROPERTIES,
  160 + },
  161 + { label: formatFunctionType[FunctionTypeEnum.EVENTS], value: FunctionTypeEnum.EVENTS },
  162 + { label: formatFunctionType[FunctionTypeEnum.SERVICE], value: FunctionTypeEnum.SERVICE },
159 ], 163 ],
160 }, 164 },
161 }, 165 },
@@ -156,7 +156,7 @@ @@ -156,7 +156,7 @@
156 import { isObject } from '/@/utils/is'; 156 import { isObject } from '/@/utils/is';
157 import { useRole } from '/@/hooks/business/useRole'; 157 import { useRole } from '/@/hooks/business/useRole';
158 import { ExportModelCategory } from '/@/api/device/modelOfMatter'; 158 import { ExportModelCategory } from '/@/api/device/modelOfMatter';
159 - import { FunctionType } from './cpns/physical/cpns/config'; 159 + import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
160 import SelectImport from '../components/SelectImport.vue'; 160 import SelectImport from '../components/SelectImport.vue';
161 161
162 const { isPlatformAdmin, isSysadmin } = useRole(); 162 const { isPlatformAdmin, isSysadmin } = useRole();
@@ -287,15 +287,15 @@ @@ -287,15 +287,15 @@
287 return Promise.all([ 287 return Promise.all([
288 ExportModelCategory({ 288 ExportModelCategory({
289 deviceProfileId, 289 deviceProfileId,
290 - functionType: FunctionType.EVENTS, 290 + functionType: FunctionTypeEnum.EVENTS,
291 }), 291 }),
292 ExportModelCategory({ 292 ExportModelCategory({
293 deviceProfileId, 293 deviceProfileId,
294 - functionType: FunctionType.PROPERTIES, 294 + functionType: FunctionTypeEnum.PROPERTIES,
295 }), 295 }),
296 ExportModelCategory({ 296 ExportModelCategory({
297 deviceProfileId, 297 deviceProfileId,
298 - functionType: FunctionType.SERVICE, 298 + functionType: FunctionTypeEnum.SERVICE,
299 }), 299 }),
300 ]); 300 ]);
301 }; 301 };
@@ -23,24 +23,24 @@ @@ -23,24 +23,24 @@
23 v-model:activeKey="activeKey" 23 v-model:activeKey="activeKey"
24 :size="size" 24 :size="size"
25 > 25 >
26 - <TabPane :key="FunctionType.PROPERTIES" tab="属性" />  
27 - <TabPane :key="FunctionType.SERVICE" :disabled="isTCPGatewaySubDevice" tab="服务" />  
28 - <TabPane :key="FunctionType.EVENTS" tab="事件" :disabled="isTCPGatewaySubDevice" /> 26 + <TabPane :key="FunctionTypeEnum.PROPERTIES" tab="属性" />
  27 + <TabPane :key="FunctionTypeEnum.SERVICE" :disabled="isTCPGatewaySubDevice" tab="服务" />
  28 + <TabPane :key="FunctionTypeEnum.EVENTS" tab="事件" :disabled="isTCPGatewaySubDevice" />
29 </Tabs> 29 </Tabs>
30 <Attribute 30 <Attribute
31 - v-if="activeKey === FunctionType.PROPERTIES" 31 + v-if="activeKey === FunctionTypeEnum.PROPERTIES"
32 :openModalMode="openModalMode" 32 :openModalMode="openModalMode"
33 :transportType="record?.transportType" 33 :transportType="record?.transportType"
34 ref="AttrRef" 34 ref="AttrRef"
35 /> 35 />
36 <Service 36 <Service
37 - v-if="activeKey === FunctionType.SERVICE" 37 + v-if="activeKey === FunctionTypeEnum.SERVICE"
38 :record="$props.record" 38 :record="$props.record"
39 :openModalMode="openModalMode" 39 :openModalMode="openModalMode"
40 ref="ServiceRef" 40 ref="ServiceRef"
41 /> 41 />
42 <Events 42 <Events
43 - v-if="activeKey === FunctionType.EVENTS" 43 + v-if="activeKey === FunctionTypeEnum.EVENTS"
44 :openModalMode="openModalMode" 44 :openModalMode="openModalMode"
45 ref="EventsRef" 45 ref="EventsRef"
46 /> 46 />
@@ -69,7 +69,7 @@ @@ -69,7 +69,7 @@
69 import { DeviceRecord, DeviceTypeEnum } from '/@/api/device/model/deviceModel'; 69 import { DeviceRecord, DeviceTypeEnum } from '/@/api/device/model/deviceModel';
70 import { useMessage } from '/@/hooks/web/useMessage'; 70 import { useMessage } from '/@/hooks/web/useMessage';
71 import { OpenModelMode, OpenModelOfMatterModelParams } from './types/index'; 71 import { OpenModelMode, OpenModelOfMatterModelParams } from './types/index';
72 - import { FunctionType } from './cpns/config'; 72 + import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
73 import { useRole } from '/@/hooks/business/useRole'; 73 import { useRole } from '/@/hooks/business/useRole';
74 74
75 const { isPlatformAdmin, isSysadmin } = useRole(); 75 const { isPlatformAdmin, isSysadmin } = useRole();
@@ -87,7 +87,7 @@ @@ -87,7 +87,7 @@
87 }); 87 });
88 88
89 const blockContent = `属性一般是指设备的运行状态,如当前温度等;服务是指设备可被调用的方法,支持定义参数,如执行某项任务;事件则是指设备上报的通知,如告警,需要被及时处理。`; 89 const blockContent = `属性一般是指设备的运行状态,如当前温度等;服务是指设备可被调用的方法,支持定义参数,如执行某项任务;事件则是指设备上报的通知,如告警,需要被及时处理。`;
90 - const activeKey = ref<FunctionType>(FunctionType.PROPERTIES); 90 + const activeKey = ref<FunctionTypeEnum>(FunctionTypeEnum.PROPERTIES);
91 const size = ref('small'); 91 const size = ref('small');
92 92
93 const AttrRef = ref<InstanceType<typeof Attribute>>(); 93 const AttrRef = ref<InstanceType<typeof Attribute>>();
@@ -98,7 +98,7 @@ @@ -98,7 +98,7 @@
98 const openModalMode = ref<OpenModelMode>(OpenModelMode.CREATE); 98 const openModalMode = ref<OpenModelMode>(OpenModelMode.CREATE);
99 const openModalParams = ref<OpenModelOfMatterModelParams>(); 99 const openModalParams = ref<OpenModelOfMatterModelParams>();
100 100
101 - const functionType = ref<FunctionType>(); 101 + const functionType = ref<FunctionTypeEnum>();
102 const { createMessage } = useMessage(); 102 const { createMessage } = useMessage();
103 103
104 const setAttrFormData = (data: ModelOfMatterParams) => AttrRef.value?.setFormData(data); 104 const setAttrFormData = (data: ModelOfMatterParams) => AttrRef.value?.setFormData(data);
@@ -106,12 +106,12 @@ @@ -106,12 +106,12 @@
106 const setEventsFormData = (data: ModelOfMatterParams) => EventsRef.value?.setFormData(data); 106 const setEventsFormData = (data: ModelOfMatterParams) => EventsRef.value?.setFormData(data);
107 107
108 const enums = { 108 const enums = {
109 - [FunctionType.PROPERTIES]: setAttrFormData,  
110 - [FunctionType.SERVICE]: setServiceFormData,  
111 - [FunctionType.EVENTS]: setEventsFormData, 109 + [FunctionTypeEnum.PROPERTIES]: setAttrFormData,
  110 + [FunctionTypeEnum.SERVICE]: setServiceFormData,
  111 + [FunctionTypeEnum.EVENTS]: setEventsFormData,
112 }; 112 };
113 113
114 - function setFormData(type: FunctionType, value: ModelOfMatterParams) { 114 + function setFormData(type: FunctionTypeEnum, value: ModelOfMatterParams) {
115 const setFn = enums[type]; 115 const setFn = enums[type];
116 setFn(value); 116 setFn(value);
117 } 117 }
@@ -147,7 +147,7 @@ @@ -147,7 +147,7 @@
147 AttrRef.value?.resetFormData(); 147 AttrRef.value?.resetFormData();
148 ServiceRef.value?.resetFormData(); 148 ServiceRef.value?.resetFormData();
149 EventsRef.value?.resetFormData(); 149 EventsRef.value?.resetFormData();
150 - activeKey.value = FunctionType.PROPERTIES; 150 + activeKey.value = FunctionTypeEnum.PROPERTIES;
151 if (flag) { 151 if (flag) {
152 closeModal(); 152 closeModal();
153 } 153 }
@@ -158,9 +158,9 @@ @@ -158,9 +158,9 @@
158 setModalProps({ loading: false, okButtonProps: { loading: true } }); 158 setModalProps({ loading: false, okButtonProps: { loading: true } });
159 159
160 let params: Partial<ModelOfMatterParams>; 160 let params: Partial<ModelOfMatterParams>;
161 - if (activeKey.value == FunctionType.PROPERTIES) { 161 + if (activeKey.value == FunctionTypeEnum.PROPERTIES) {
162 params = (await AttrRef.value?.getFormData()) || {}; 162 params = (await AttrRef.value?.getFormData()) || {};
163 - } else if (activeKey.value == FunctionType.SERVICE) { 163 + } else if (activeKey.value == FunctionTypeEnum.SERVICE) {
164 params = (await ServiceRef.value?.getFormData()) || {}; 164 params = (await ServiceRef.value?.getFormData()) || {};
165 } else { 165 } else {
166 params = (await EventsRef.value?.getFormData()) || {}; 166 params = (await EventsRef.value?.getFormData()) || {};
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 import { DeviceRecord } from '/@/api/device/model/deviceModel'; 24 import { DeviceRecord } from '/@/api/device/model/deviceModel';
25 import { Button } from 'ant-design-vue'; 25 import { Button } from 'ant-design-vue';
26 import { getModelTsl } from '/@/api/device/modelOfMatter'; 26 import { getModelTsl } from '/@/api/device/modelOfMatter';
27 - import { FunctionType } from './cpns/config'; 27 + import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
28 import { isObject } from '/@/utils/is'; 28 import { isObject } from '/@/utils/is';
29 29
30 defineEmits(['register']); 30 defineEmits(['register']);
@@ -75,15 +75,15 @@ @@ -75,15 +75,15 @@
75 return Promise.all([ 75 return Promise.all([
76 getModelTsl({ 76 getModelTsl({
77 deviceProfileId, 77 deviceProfileId,
78 - functionType: FunctionType.EVENTS, 78 + functionType: FunctionTypeEnum.EVENTS,
79 }), 79 }),
80 getModelTsl({ 80 getModelTsl({
81 deviceProfileId, 81 deviceProfileId,
82 - functionType: FunctionType.PROPERTIES, 82 + functionType: FunctionTypeEnum.PROPERTIES,
83 }), 83 }),
84 getModelTsl({ 84 getModelTsl({
85 deviceProfileId, 85 deviceProfileId,
86 - functionType: FunctionType.SERVICE, 86 + functionType: FunctionTypeEnum.SERVICE,
87 }), 87 }),
88 ]); 88 ]);
89 }; 89 };
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 transfromToStructJSON, 6 transfromToStructJSON,
7 excludeIdInStructJSON, 7 excludeIdInStructJSON,
8 } from '/@/components/Form/src/components/StructForm/util'; 8 } from '/@/components/Form/src/components/StructForm/util';
9 - import { FunctionType } from './config'; 9 + import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
10 import { isArray } from 'lodash'; 10 import { isArray } from 'lodash';
11 import { OpenModelMode } from '../types'; 11 import { OpenModelMode } from '../types';
12 import { formSchemas } from '/@/components/Form/src/components/StructForm/config'; 12 import { formSchemas } from '/@/components/Form/src/components/StructForm/config';
@@ -46,7 +46,7 @@ @@ -46,7 +46,7 @@
46 46
47 const value = { 47 const value = {
48 functionName, 48 functionName,
49 - functionType: FunctionType.PROPERTIES, 49 + functionType: FunctionTypeEnum.PROPERTIES,
50 remark, 50 remark,
51 identifier, 51 identifier,
52 accessMode, 52 accessMode,
@@ -3,7 +3,8 @@ @@ -3,7 +3,8 @@
3 </template> 3 </template>
4 <script lang="ts" setup> 4 <script lang="ts" setup>
5 import { BasicForm, useForm } from '/@/components/Form'; 5 import { BasicForm, useForm } from '/@/components/Form';
6 - import { eventSchemas, FunctionType } from './config'; 6 + import { eventSchemas } from './config';
  7 + import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
7 import { ModelOfMatterParams, StructJSON } from '/@/api/device/model/modelOfMatterModel'; 8 import { ModelOfMatterParams, StructJSON } from '/@/api/device/model/modelOfMatterModel';
8 import { StructFormValue } from '/@/components/Form/src/components/StructForm/type'; 9 import { StructFormValue } from '/@/components/Form/src/components/StructForm/type';
9 import { excludeIdInStructJSON } from '/@/components/Form/src/components/StructForm/util'; 10 import { excludeIdInStructJSON } from '/@/components/Form/src/components/StructForm/util';
@@ -57,7 +58,7 @@ @@ -57,7 +58,7 @@
57 functionName, 58 functionName,
58 identifier, 59 identifier,
59 remark, 60 remark,
60 - functionType: FunctionType.EVENTS, 61 + functionType: FunctionTypeEnum.EVENTS,
61 eventType, 62 eventType,
62 functionJson: { 63 functionJson: {
63 outputData, 64 outputData,
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 <script lang="ts" setup> 4 <script lang="ts" setup>
5 import { BasicForm, useForm } from '/@/components/Form'; 5 import { BasicForm, useForm } from '/@/components/Form';
6 import { FormField, serviceSchemas } from './config'; 6 import { FormField, serviceSchemas } from './config';
7 - import { FunctionType } from './config'; 7 + import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
8 import { StructFormValue } from '/@/components/Form/src/components/StructForm/type'; 8 import { StructFormValue } from '/@/components/Form/src/components/StructForm/type';
9 import { ModelOfMatterParams, StructJSON } from '/@/api/device/model/modelOfMatterModel'; 9 import { ModelOfMatterParams, StructJSON } from '/@/api/device/model/modelOfMatterModel';
10 import { DeviceRecord } from '/@/api/device/model/deviceModel'; 10 import { DeviceRecord } from '/@/api/device/model/deviceModel';
@@ -94,7 +94,7 @@ @@ -94,7 +94,7 @@
94 functionName, 94 functionName,
95 identifier, 95 identifier,
96 remark, 96 remark,
97 - functionType: FunctionType.SERVICE, 97 + functionType: FunctionTypeEnum.SERVICE,
98 callType, 98 callType,
99 functionJson: { 99 functionJson: {
100 inputData, 100 inputData,
@@ -9,9 +9,9 @@ @@ -9,9 +9,9 @@
9 </div> 9 </div>
10 <div> 10 <div>
11 <Tabs type="card" v-model:active-key="activeKey" @change="handleSwitchTsl"> 11 <Tabs type="card" v-model:active-key="activeKey" @change="handleSwitchTsl">
12 - <Tabs.TabPane :key="FunctionType.PROPERTIES" tab="属性" />  
13 - <Tabs.TabPane :key="FunctionType.SERVICE" tab="服务" />  
14 - <Tabs.TabPane :key="FunctionType.EVENTS" tab="事件" /> 12 + <Tabs.TabPane :key="FunctionTypeEnum.PROPERTIES" tab="属性" />
  13 + <Tabs.TabPane :key="FunctionTypeEnum.SERVICE" tab="服务" />
  14 + <Tabs.TabPane :key="FunctionTypeEnum.EVENTS" tab="事件" />
15 <template #tabBarExtraContent> 15 <template #tabBarExtraContent>
16 <Button class="ml-2" @click="handleCopy"> 16 <Button class="ml-2" @click="handleCopy">
17 <template #icon> 17 <template #icon>
@@ -38,7 +38,7 @@ @@ -38,7 +38,7 @@
38 import { CopyOutlined } from '@ant-design/icons-vue'; 38 import { CopyOutlined } from '@ant-design/icons-vue';
39 import { useMessage } from '/@/hooks/web/useMessage'; 39 import { useMessage } from '/@/hooks/web/useMessage';
40 import { Button, Typography, TypographyParagraph, Tabs, Spin, Input } from 'ant-design-vue'; 40 import { Button, Typography, TypographyParagraph, Tabs, Spin, Input } from 'ant-design-vue';
41 - import { FunctionType } from './config'; 41 + import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
42 import useCommon from '../hook/useCommon'; 42 import useCommon from '../hook/useCommon';
43 import { DeviceRecord } from '/@/api/device/model/deviceModel'; 43 import { DeviceRecord } from '/@/api/device/model/deviceModel';
44 import { getModelTsl } from '/@/api/device/modelOfMatter'; 44 import { getModelTsl } from '/@/api/device/modelOfMatter';
@@ -56,7 +56,7 @@ @@ -56,7 +56,7 @@
56 56
57 const jsonValue = ref(); 57 const jsonValue = ref();
58 58
59 - const activeKey = ref(FunctionType.PROPERTIES); 59 + const activeKey = ref(FunctionTypeEnum.PROPERTIES);
60 60
61 const { copied, copy } = useClipboard({ legacy: true }); 61 const { copied, copy } = useClipboard({ legacy: true });
62 const handleCopy = async () => { 62 const handleCopy = async () => {
@@ -81,7 +81,7 @@ @@ -81,7 +81,7 @@
81 jsonValue.value = null; 81 jsonValue.value = null;
82 }; 82 };
83 83
84 - const handleSwitchTsl = async (functionType: FunctionType) => { 84 + const handleSwitchTsl = async (functionType: FunctionTypeEnum) => {
85 try { 85 try {
86 loading.value = true; 86 loading.value = true;
87 const record = await getModelTsl({ 87 const record = await getModelTsl({
@@ -102,8 +102,8 @@ @@ -102,8 +102,8 @@
102 }; 102 };
103 103
104 onMounted(() => { 104 onMounted(() => {
105 - activeKey.value = FunctionType.PROPERTIES;  
106 - handleSwitchTsl(FunctionType.PROPERTIES); 105 + activeKey.value = FunctionTypeEnum.PROPERTIES;
  106 + handleSwitchTsl(FunctionTypeEnum.PROPERTIES);
107 }); 107 });
108 108
109 defineExpose({ 109 defineExpose({
@@ -33,17 +33,6 @@ export enum FormField { @@ -33,17 +33,6 @@ export enum FormField {
33 HAS_STRUCT_FROM = 'hasStructForm', 33 HAS_STRUCT_FROM = 'hasStructForm',
34 } 34 }
35 35
36 -export enum FunctionType {  
37 - PROPERTIES = 'properties',  
38 - EVENTS = 'events',  
39 - SERVICE = 'services',  
40 -}  
41 -  
42 -export enum AssessMode {  
43 - READ = 'r',  
44 - WRITE = 'w',  
45 -}  
46 -  
47 const isNumber = (type: string) => { 36 const isNumber = (type: string) => {
48 return type === DataTypeEnum.NUMBER_INT || type === DataTypeEnum.NUMBER_DOUBLE; 37 return type === DataTypeEnum.NUMBER_INT || type === DataTypeEnum.NUMBER_DOUBLE;
49 }; 38 };
@@ -27,7 +27,7 @@ import { DeviceModelOfMatterAttrs, DeviceProfileModel } from '/@/api/device/mode @@ -27,7 +27,7 @@ import { DeviceModelOfMatterAttrs, DeviceProfileModel } from '/@/api/device/mode
27 import TriggerDurationInput from './TriggerDurationInput.vue'; 27 import TriggerDurationInput from './TriggerDurationInput.vue';
28 import { DataTypeEnum } from '/@/enums/objectModelEnum'; 28 import { DataTypeEnum } from '/@/enums/objectModelEnum';
29 import { getModelTsl } from '/@/api/device/modelOfMatter'; 29 import { getModelTsl } from '/@/api/device/modelOfMatter';
30 -import { FunctionType } from '/@/views/device/profiles/step/cpns/physical/cpns/config'; 30 +import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
31 import { GetModelTslParams } from '/@/api/device/model/modelOfMatterModel'; 31 import { GetModelTslParams } from '/@/api/device/model/modelOfMatterModel';
32 import { FlipFlopComponentTypeEnum } from './types'; 32 import { FlipFlopComponentTypeEnum } from './types';
33 import { OptionsType } from 'ant-design-vue/es/vc-select/interface'; 33 import { OptionsType } from 'ant-design-vue/es/vc-select/interface';
@@ -405,7 +405,7 @@ export const getFormSchemas = ( @@ -405,7 +405,7 @@ export const getFormSchemas = (
405 labelField: 'functionName', 405 labelField: 'functionName',
406 valueField: 'identifier', 406 valueField: 'identifier',
407 params: { 407 params: {
408 - functionType: FunctionType.EVENTS, 408 + functionType: FunctionTypeEnum.EVENTS,
409 deviceProfileId: formModel[FormFieldEnum.DEVICE_PROFILE_ID], 409 deviceProfileId: formModel[FormFieldEnum.DEVICE_PROFILE_ID],
410 }, 410 },
411 placeholder: `请选择${FormFieldNameEnum.DEVICE_EVENT_TRIGGER_KEY}`, 411 placeholder: `请选择${FormFieldNameEnum.DEVICE_EVENT_TRIGGER_KEY}`,
@@ -37,5 +37,15 @@ @@ -37,5 +37,15 @@
37 </script> 37 </script>
38 38
39 <template> 39 <template>
40 - <BasicForm @register="register" /> 40 + <BasicForm @register="register" class="data-board-source-form" />
41 </template> 41 </template>
  42 +
  43 +<style lang="less" scoped>
  44 + .data-board-source-form {
  45 + :deep(.ant-form-item-control-input-content) {
  46 + > div > div {
  47 + width: 100%;
  48 + }
  49 + }
  50 + }
  51 +</style>
@@ -197,8 +197,7 @@ @@ -197,8 +197,7 @@
197 <label class="w-24 text-right pr-2">数据源{{ index + 1 }}</label> 197 <label class="w-24 text-right pr-2">数据源{{ index + 1 }}</label>
198 <component 198 <component
199 :ref="(event) => setDataSourceFormsEl(item.uuid, event, index)" 199 :ref="(event) => setDataSourceFormsEl(item.uuid, event, index)"
200 - class="flex-1 bg-light-50 dark:bg-dark-400"  
201 - style="max-width: calc(100% - 216px)" 200 + class="flex-1 bg-light-50 dark:bg-dark-400 data-board-source-form"
202 :is="getComponent" 201 :is="getComponent"
203 :component-config="componentConfig" 202 :component-config="componentConfig"
204 :values="item" 203 :values="item"
@@ -238,9 +237,11 @@ @@ -238,9 +237,11 @@
238 </template> 237 </template>
239 238
240 <style scoped lang="less"> 239 <style scoped lang="less">
241 - :deep(#deviceId) {  
242 - div {  
243 - width: 100%; 240 + .data-board-source-form {
  241 + :deep(.ant-form-item-control-input-content) {
  242 + > div > div {
  243 + width: 100%;
  244 + }
244 } 245 }
245 } 246 }
246 </style> 247 </style>
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 import { computed } from 'vue'; 2 import { computed } from 'vue';
3 - import { PackagesCategoryEnum } from '../../../packages/index.type';  
4 import { SelectedWidgetKeys } from '../../index.type'; 3 import { SelectedWidgetKeys } from '../../index.type';
5 import { Alert } from 'ant-design-vue'; 4 import { Alert } from 'ant-design-vue';
6 5
@@ -9,10 +8,10 @@ @@ -9,10 +8,10 @@
9 }>(); 8 }>();
10 9
11 const alert = { 10 const alert = {
12 - [PackagesCategoryEnum.MAP]: [  
13 - '1、绑定数据源为结构体时,可以自行选择结构体里的属性作为经纬度',  
14 - '2、绑定数据源为非结构体时,第一数据源为经度,第二数据源为纬度,且数据源为同一设备,并同时上报。否则地图组件不能正常显示。',  
15 - ], 11 + // [PackagesCategoryEnum.MAP]: [
  12 + // '1、绑定数据源为结构体时,可以自行选择结构体里的属性作为经纬度',
  13 + // '2、绑定数据源为非结构体时,第一数据源为经度,第二数据源为纬度,且数据源为同一设备,并同时上报。否则地图组件不能正常显示。',
  14 + // ],
16 }; 15 };
17 16
18 const getMessage = computed(() => { 17 const getMessage = computed(() => {
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 - import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type'; 2 + import { ComponentMode, ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
3 import { option } from './config'; 3 import { option } from './config';
4 import { Spin } from 'ant-design-vue'; 4 import { Spin } from 'ant-design-vue';
5 import { computed, ref, unref } from 'vue'; 5 import { computed, ref, unref } from 'vue';
6 import { useComponentScale } from '../../../hook/useComponentScale'; 6 import { useComponentScale } from '../../../hook/useComponentScale';
7 - import { useSendCommand } from '../../../hook/useSendCommand';  
8 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName'; 7 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
9 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 8 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
10 import { useDataFetch } from '../../../hook/socket/useSocket'; 9 import { useDataFetch } from '../../../hook/socket/useSocket';
11 - import { getSendValues } from '../config';  
12 import { useModal } from '/@/components/Modal'; 10 import { useModal } from '/@/components/Modal';
13 import PasswordModal from '../component/PasswordModal.vue'; 11 import PasswordModal from '../component/PasswordModal.vue';
  12 + import { useCommandDelivery } from '../../../hook/useCommandDelivery';
  13 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
14 14
15 const props = defineProps<{ 15 const props = defineProps<{
16 config: ComponentPropsConfigType<typeof option>; 16 config: ComponentPropsConfigType<typeof option>;
@@ -20,48 +20,31 @@ @@ -20,48 +20,31 @@
20 20
21 const currentValue = ref(false); 21 const currentValue = ref(false);
22 22
  23 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
  24 +
23 const getDesign = computed(() => { 25 const getDesign = computed(() => {
24 const { option, persetOption } = props.config; 26 const { option, persetOption } = props.config;
25 - const {  
26 - attribute,  
27 - attributeRename,  
28 - attributeName,  
29 - componentInfo,  
30 - commandType,  
31 - extensionDesc,  
32 - codeType,  
33 - deviceCode,  
34 - customCommand,  
35 - } = option; 27 + const { attribute, attributeRename, componentInfo, commandType, deviceProfileId } = option;
36 28
37 const { fontSize: persetFontSize, password: persetPassword } = persetOption || {}; 29 const { fontSize: persetFontSize, password: persetPassword } = persetOption || {};
38 const { fontSize, password } = componentInfo || {}; 30 const { fontSize, password } = componentInfo || {};
  31 +
  32 + const tsl = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
39 return { 33 return {
40 - attribute: attributeRename || attributeName || attribute, 34 + attribute: attributeRename || tsl?.functionName || attribute,
41 fontSize: fontSize || persetFontSize || 14, 35 fontSize: fontSize || persetFontSize || 14,
42 password: password || persetPassword, 36 password: password || persetPassword,
43 - extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {},  
44 commandType, 37 commandType,
45 - codeType,  
46 - deviceCode,  
47 - customCommand,  
48 }; 38 };
49 }); 39 });
50 40
51 - const { sendCommand, loading } = useSendCommand(); 41 + const { doCommandDeliver, loading } = useCommandDelivery();
52 42
53 - const handleSendCommand = async (data) => {  
54 - const { control: event } = data || {};  
55 - const target = event.target as HTMLInputElement;  
56 - const value = !target.checked; 43 + const handleSendCommand = async () => {
  44 + if (props.config.option.mode === ComponentMode.SELECT_PREVIEW) return;
57 const { option } = props.config || {}; 45 const { option } = props.config || {};
58 -  
59 - const { values, isModbusCommand, sendValue } =  
60 - (await getSendValues(option, unref(getDesign), value)) || {};  
61 -  
62 - const flag = await sendCommand(values, isModbusCommand ? sendValue : value, isModbusCommand);  
63 - if (flag) currentValue.value = value;  
64 - flag ? (currentValue.value = value) : (target.checked = !value); 46 + const result = await doCommandDeliver(option, Number(!unref(currentValue)));
  47 + currentValue.value = result ? !unref(currentValue) : unref(currentValue);
65 }; 48 };
66 49
67 const handleChange = async (event: Event) => { 50 const handleChange = async (event: Event) => {
@@ -74,16 +57,7 @@ @@ -74,16 +57,7 @@
74 return; 57 return;
75 } 58 }
76 59
77 - const target = event.target as HTMLInputElement;  
78 - const value = target.checked;  
79 - const { option } = props.config || {};  
80 -  
81 - const { values, isModbusCommand, sendValue } =  
82 - (await getSendValues(option, unref(getDesign), value)) || {};  
83 -  
84 - const flag = await sendCommand(values, isModbusCommand ? sendValue : value, isModbusCommand);  
85 - if (flag) currentValue.value = value;  
86 - flag ? (currentValue.value = value) : (target.checked = !value); 60 + handleSendCommand();
87 }; 61 };
88 62
89 const updateFn: DataFetchUpdateFn = (message, attribute) => { 63 const updateFn: DataFetchUpdateFn = (message, attribute) => {
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 - import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type'; 2 + import { ComponentMode, ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
3 import { option } from './config'; 3 import { option } from './config';
4 import { SvgIcon } from '/@/components/Icon'; 4 import { SvgIcon } from '/@/components/Icon';
5 import { Switch } from 'ant-design-vue'; 5 import { Switch } from 'ant-design-vue';
6 import { computed, ref } from 'vue'; 6 import { computed, ref } from 'vue';
7 import { useComponentScale } from '../../../hook/useComponentScale'; 7 import { useComponentScale } from '../../../hook/useComponentScale';
8 - import { useSendCommand } from '../../../hook/useSendCommand';  
9 import { unref } from 'vue'; 8 import { unref } from 'vue';
10 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName'; 9 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
11 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 10 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
12 import { useDataFetch } from '../../../hook/socket/useSocket'; 11 import { useDataFetch } from '../../../hook/socket/useSocket';
13 - import { getSendValues } from '../config';  
14 import { useModal } from '/@/components/Modal'; 12 import { useModal } from '/@/components/Modal';
15 import PasswordModal from '../component/PasswordModal.vue'; 13 import PasswordModal from '../component/PasswordModal.vue';
  14 + import { useCommandDelivery } from '../../../hook/useCommandDelivery';
  15 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
16 16
17 const props = defineProps<{ 17 const props = defineProps<{
18 config: ComponentPropsConfigType<typeof option>; 18 config: ComponentPropsConfigType<typeof option>;
@@ -20,19 +20,11 @@ @@ -20,19 +20,11 @@
20 20
21 const checked = ref(false); 21 const checked = ref(false);
22 22
  23 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
  24 +
23 const getDesign = computed(() => { 25 const getDesign = computed(() => {
24 const { option, persetOption } = props.config; 26 const { option, persetOption } = props.config;
25 - const {  
26 - componentInfo,  
27 - attribute,  
28 - attributeRename,  
29 - attributeName,  
30 - commandType,  
31 - extensionDesc,  
32 - codeType,  
33 - deviceCode,  
34 - customCommand,  
35 - } = option; 27 + const { componentInfo, attribute, deviceProfileId, attributeRename, commandType } = option;
36 const { 28 const {
37 icon: presetIcon, 29 icon: presetIcon,
38 iconColor: presetIconColor, 30 iconColor: presetIconColor,
@@ -41,21 +33,18 @@ @@ -41,21 +33,18 @@
41 } = persetOption || {}; 33 } = persetOption || {};
42 const { icon, iconColor, fontSize, password } = componentInfo || {}; 34 const { icon, iconColor, fontSize, password } = componentInfo || {};
43 35
  36 + const tsl = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
44 return { 37 return {
45 icon: icon ?? presetIcon, 38 icon: icon ?? presetIcon,
46 iconColor: iconColor || presetIconColor, 39 iconColor: iconColor || presetIconColor,
47 - attribute: attributeRename || attributeName || attribute,  
48 - extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {}, 40 + attribute: attributeRename || tsl?.functionName || attribute,
49 fontSize: fontSize || persetFontSize || 14, 41 fontSize: fontSize || persetFontSize || 14,
50 password: password || persetPassword, 42 password: password || persetPassword,
51 commandType, 43 commandType,
52 - codeType,  
53 - deviceCode,  
54 - customCommand,  
55 }; 44 };
56 }); 45 });
57 46
58 - const { sendCommand, loading } = useSendCommand(); 47 + const { loading, doCommandDeliver } = useCommandDelivery();
59 48
60 const handleChange = async () => { 49 const handleChange = async () => {
61 if (unref(getDesign).password) { 50 if (unref(getDesign).password) {
@@ -63,32 +52,14 @@ @@ -63,32 +52,14 @@
63 checked.value = !unref(checked); 52 checked.value = !unref(checked);
64 return; 53 return;
65 } 54 }
66 - const { option } = props.config || {};  
67 -  
68 - const { values, isModbusCommand, sendValue } =  
69 - (await getSendValues(option, unref(getDesign), unref(checked))) || {};  
70 -  
71 - const flag = await sendCommand(  
72 - values,  
73 - isModbusCommand ? sendValue : unref(checked),  
74 - isModbusCommand  
75 - );  
76 - if (!flag) checked.value = !unref(checked); 55 + handleSendCommand();
77 }; 56 };
78 57
79 const handleSendCommand = async () => { 58 const handleSendCommand = async () => {
  59 + if (props.config.option.mode === ComponentMode.SELECT_PREVIEW) return;
80 const { option } = props.config || {}; 60 const { option } = props.config || {};
81 - checked.value = !unref(checked);  
82 -  
83 - const { values, isModbusCommand, sendValue } =  
84 - (await getSendValues(option, unref(getDesign), unref(checked))) || {};  
85 -  
86 - const flag = await sendCommand(  
87 - values,  
88 - isModbusCommand ? sendValue : unref(checked),  
89 - isModbusCommand  
90 - );  
91 - if (!flag) checked.value = !unref(checked); 61 + const result = await doCommandDeliver(option, Number(unref(checked)));
  62 + if (!result) checked.value = !unref(checked);
92 }; 63 };
93 64
94 const updateFn: DataFetchUpdateFn = (message, attribute) => { 65 const updateFn: DataFetchUpdateFn = (message, attribute) => {
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 - import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type'; 2 + import { ComponentMode, ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
3 import { option } from './config'; 3 import { option } from './config';
4 import { Spin } from 'ant-design-vue'; 4 import { Spin } from 'ant-design-vue';
5 import { computed, ref, unref } from 'vue'; 5 import { computed, ref, unref } from 'vue';
6 import { useComponentScale } from '../../../hook/useComponentScale'; 6 import { useComponentScale } from '../../../hook/useComponentScale';
7 - import { useSendCommand } from '../../../hook/useSendCommand';  
8 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName'; 7 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
9 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 8 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
10 import { useDataFetch } from '../../../hook/socket/useSocket'; 9 import { useDataFetch } from '../../../hook/socket/useSocket';
11 - import { getSendValues } from '../config';  
12 import PasswordModal from '../component/PasswordModal.vue'; 10 import PasswordModal from '../component/PasswordModal.vue';
13 import { useModal } from '/@/components/Modal'; 11 import { useModal } from '/@/components/Modal';
  12 + import { useCommandDelivery } from '../../../hook/useCommandDelivery';
  13 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
14 14
15 const props = defineProps<{ 15 const props = defineProps<{
16 config: ComponentPropsConfigType<typeof option>; 16 config: ComponentPropsConfigType<typeof option>;
@@ -20,34 +20,31 @@ @@ -20,34 +20,31 @@
20 20
21 const currentValue = ref(false); 21 const currentValue = ref(false);
22 22
  23 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
  24 +
23 const getDesign = computed(() => { 25 const getDesign = computed(() => {
24 const { option, persetOption } = props.config; 26 const { option, persetOption } = props.config;
25 - const {  
26 - attribute,  
27 - attributeRename,  
28 - attributeName,  
29 - commandType,  
30 - extensionDesc,  
31 - codeType,  
32 - deviceCode,  
33 - customCommand,  
34 - componentInfo,  
35 - } = option; 27 + const { attribute, deviceProfileId, attributeRename, commandType, componentInfo } = option;
36 const { fontSize: persetFontSize, password: persetPassword } = persetOption || {}; 28 const { fontSize: persetFontSize, password: persetPassword } = persetOption || {};
37 const { fontSize, password } = componentInfo || {}; 29 const { fontSize, password } = componentInfo || {};
  30 +
  31 + const tsl = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
  32 +
38 return { 33 return {
39 - attribute: attributeRename || attributeName || attribute,  
40 - extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {}, 34 + attribute: attributeRename || tsl?.functionName || attribute,
41 password: password || persetPassword, 35 password: password || persetPassword,
42 commandType, 36 commandType,
43 - codeType,  
44 - deviceCode,  
45 - customCommand,  
46 fontSize: fontSize || persetFontSize || 14, 37 fontSize: fontSize || persetFontSize || 14,
47 }; 38 };
48 }); 39 });
  40 + const { doCommandDeliver, loading } = useCommandDelivery();
49 41
50 - const { loading, sendCommand } = useSendCommand(); 42 + const handleSendCommand = async () => {
  43 + if (props.config.option.mode === ComponentMode.SELECT_PREVIEW) return;
  44 + const { option } = props.config || {};
  45 + const result = await doCommandDeliver(option, Number(!unref(currentValue)));
  46 + currentValue.value = result ? !unref(currentValue) : unref(currentValue);
  47 + };
51 const handleChange = async (event: Event) => { 48 const handleChange = async (event: Event) => {
52 if (unref(getDesign).password) { 49 if (unref(getDesign).password) {
53 const target = event.target as HTMLInputElement; 50 const target = event.target as HTMLInputElement;
@@ -57,29 +54,7 @@ @@ -57,29 +54,7 @@
57 openModal(true, { password: unref(getDesign).password, control: event }); 54 openModal(true, { password: unref(getDesign).password, control: event });
58 return; 55 return;
59 } 56 }
60 -  
61 - const target = event.target as HTMLInputElement;  
62 - const value = target.checked;  
63 - const { option } = props.config || {};  
64 -  
65 - const { values, isModbusCommand, sendValue } =  
66 - (await getSendValues(option, unref(getDesign), value)) || {};  
67 -  
68 - const flag = await sendCommand(values, isModbusCommand ? sendValue : value, isModbusCommand);  
69 - flag ? (currentValue.value = value) : (target.checked = !value);  
70 - };  
71 -  
72 - const handleSendCommand = async (data) => {  
73 - const { control: event } = data || {};  
74 - const target = event.target as HTMLInputElement;  
75 - const value = !target.checked;  
76 - const { option } = props.config || {};  
77 -  
78 - const { values, isModbusCommand, sendValue } =  
79 - (await getSendValues(option, unref(getDesign), value)) || {};  
80 -  
81 - const flag = await sendCommand(values, isModbusCommand ? sendValue : value, isModbusCommand);  
82 - flag ? (currentValue.value = value) : (target.checked = !value); 57 + handleSendCommand();
83 }; 58 };
84 59
85 const updateFn: DataFetchUpdateFn = (message, attribute) => { 60 const updateFn: DataFetchUpdateFn = (message, attribute) => {
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 - import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type'; 2 + import { ComponentMode, ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
3 import { option } from './config'; 3 import { option } from './config';
4 import { Slider, Spin } from 'ant-design-vue'; 4 import { Slider, Spin } from 'ant-design-vue';
5 import { computed, ref, unref } from 'vue'; 5 import { computed, ref, unref } from 'vue';
6 import { useComponentScale } from '../../../hook/useComponentScale'; 6 import { useComponentScale } from '../../../hook/useComponentScale';
7 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName'; 7 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
8 - import { useSendCommand } from '../../../hook/useSendCommand';  
9 import { useReceiveValue } from '../../../hook/useReceiveValue'; 8 import { useReceiveValue } from '../../../hook/useReceiveValue';
10 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 9 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
11 import { useDataFetch } from '../../../hook/socket/useSocket'; 10 import { useDataFetch } from '../../../hook/socket/useSocket';
12 - import { TaskTypeEnum } from '/@/views/task/center/config';  
13 - import { useMessage } from '/@/hooks/web/useMessage';  
14 - import { SingleToHex } from '/@/views/device/list/cpns/tabs/ObjectModelCommandDeliveryModal/config';  
15 - import { genModbusCommand } from '/@/api/task';  
16 import PasswordModal from '../component/PasswordModal.vue'; 11 import PasswordModal from '../component/PasswordModal.vue';
17 import { useModal } from '/@/components/Modal'; 12 import { useModal } from '/@/components/Modal';
  13 + import { useCommandDelivery } from '../../../hook/useCommandDelivery';
  14 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
18 15
19 const props = defineProps<{ 16 const props = defineProps<{
20 config: ComponentPropsConfigType<typeof option>; 17 config: ComponentPropsConfigType<typeof option>;
21 }>(); 18 }>();
22 19
23 const sliderValue = ref<number>(33); 20 const sliderValue = ref<number>(33);
24 - const oldSliderValue = ref<number>(33);  
25 - const noSendValue = ref<number>(0);  
26 - const sliderEl = ref<Nullable<InstanceType<typeof Slider>>>(null); 21 + const sliderElRef = ref<InstanceType<typeof Slider>>();
27 22
28 - const { loading, sendCommand } = useSendCommand(); 23 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
29 24
30 const getDesign = computed(() => { 25 const getDesign = computed(() => {
31 const { option, persetOption } = props.config; 26 const { option, persetOption } = props.config;
32 - const {  
33 - componentInfo,  
34 - attribute,  
35 - attributeRename,  
36 - attributeName,  
37 - commandType,  
38 - extensionDesc,  
39 - codeType,  
40 - deviceCode,  
41 - customCommand,  
42 - } = option; 27 + const { componentInfo, attribute, deviceProfileId, attributeRename, commandType } = option;
  28 +
43 const { 29 const {
44 controlBarColor: persetControlBarColor, 30 controlBarColor: persetControlBarColor,
45 fonColor: persetFontColor, 31 fonColor: persetFontColor,
@@ -50,6 +36,8 @@ @@ -50,6 +36,8 @@
50 fontSize: persetFontSize, 36 fontSize: persetFontSize,
51 password: persetPassword, 37 password: persetPassword,
52 } = persetOption || {}; 38 } = persetOption || {};
  39 +
  40 + const tsl = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
53 const { 41 const {
54 controlBarColor, 42 controlBarColor,
55 password, 43 password,
@@ -61,16 +49,12 @@ @@ -61,16 +49,12 @@
61 fontSize, 49 fontSize,
62 } = componentInfo || {}; 50 } = componentInfo || {};
63 return { 51 return {
64 - attribute: attributeRename || attributeName || attribute, 52 + attribute: attributeRename || tsl?.functionName || attribute,
65 controlBarColor: controlBarColor ?? persetControlBarColor, 53 controlBarColor: controlBarColor ?? persetControlBarColor,
66 fontColor: fontColor ?? persetFontColor, 54 fontColor: fontColor ?? persetFontColor,
67 minNumber: minNumber ?? persetMinNumber, 55 minNumber: minNumber ?? persetMinNumber,
68 maxNumber: maxNumber ?? persetMaxNumber, 56 maxNumber: maxNumber ?? persetMaxNumber,
69 - extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {},  
70 commandType, 57 commandType,
71 - codeType,  
72 - deviceCode,  
73 - customCommand,  
74 textColor: textColor || persetTextColor, 58 textColor: textColor || persetTextColor,
75 valueSize: valueSize || persetValueSize || 20, 59 valueSize: valueSize || persetValueSize || 20,
76 fontSize: fontSize || persetFontSize || 14, 60 fontSize: fontSize || persetFontSize || 14,
@@ -78,153 +62,28 @@ @@ -78,153 +62,28 @@
78 }; 62 };
79 }); 63 });
80 64
81 - const index = ref<number>(0);  
82 - const afterValue = ref<number>(0); //点击Slider获取的值  
83 -  
84 - const handleChange = async (e) => {  
85 - index.value++;  
86 - afterValue.value = e;  
87 - if (index.value == 1) {  
88 - oldSliderValue.value = unref(sliderValue);  
89 - return; //这个是因为设置了最大值时,当sliderValue的值大于最大值时只会显示设置的最大值,会执行一次change  
90 - }  
91 - sliderValue.value = e;  
92 - };  
93 -  
94 - const handleAfterChange = async () => {  
95 - unref(sliderEl)?.blur();  
96 - if (unref(sliderValue) == unref(afterValue)) return;  
97 - if (unref(getDesign).password) return;  
98 - sliderValue.value = afterValue.value; //这一步是因为当我们是点击不是拖动时候,会让值更新不了,所以需要赋值一次  
99 - };  
100 -  
101 - const { createMessage } = useMessage();  
102 -  
103 - // 获取小数  
104 - const getFloatPart = (number: string | number) => {  
105 - const isLessZero = Number(number) < 0;  
106 - number = number.toString();  
107 - const floatPartStartIndex = number.indexOf('.');  
108 - const value = ~floatPartStartIndex  
109 - ? `${isLessZero ? '-' : ''}0.${number.substring(floatPartStartIndex + 1)}`  
110 - : '0';  
111 - return Number(value); 65 + const sendValue = ref(0);
  66 + const handleChange = async (value: number) => {
  67 + sendValue.value = value;
112 }; 68 };
113 69
114 - const getArray = (values) => {  
115 - const str = values.replace(/\s+/g, '');  
116 - const array: any = []; 70 + const { loading, doCommandDeliver } = useCommandDelivery();
117 71
118 - for (let i = 0; i < str.length; i += 4) {  
119 - const chunk = parseInt(str.substring(i, i + 4), 16);  
120 - array.push(chunk);  
121 - }  
122 - return array;  
123 - };  
124 -  
125 - const getSendValue = async (value: number) => {  
126 - const { extensionDesc, codeType, deviceCode, customCommand } = unref(getDesign) || {};  
127 - const { transportType } = customCommand || {};  
128 - const { registerAddress, actionType, zoomFactor } = extensionDesc || {};  
129 - const newZoomValue = zoomFactor ? Number(zoomFactor) : 1;  
130 - if (transportType == 'TCP' && codeType == TaskTypeEnum.MODBUS_RTU) {  
131 - if (!deviceCode) {  
132 - createMessage.warning('当前设备没有设置地址码');  
133 - return;  
134 - }  
135 - const modbusForm = ref({  
136 - crc: 'CRC_16_LOWER',  
137 - deviceCode: deviceCode,  
138 - method: actionType == '16' ? '10' : actionType,  
139 - registerAddress,  
140 - registerNumber: 1,  
141 - registerValues: [value],  
142 - }) as any;  
143 - if (!actionType) {  
144 - createMessage.warning('当前物模型扩展描述没有填写');  
145 - return;  
146 - }  
147 - if (actionType == '06') {  
148 - const newValue = Math.trunc(value) * newZoomValue + getFloatPart(value) * newZoomValue;  
149 - if (newValue % 1 != 0) {  
150 - createMessage.warning(`值必须是整数,缩放因子为${unref(newZoomValue)}`);  
151 - return;  
152 - }  
153 -  
154 - if (newValue > 65535) {  
155 - createMessage.warning(`值不能超过65535,缩放因子是${unref(newZoomValue)}`);  
156 - return;  
157 - }  
158 - modbusForm.value.registerValues = [newValue];  
159 - }  
160 - if (actionType == '05') {  
161 - if (Number(value) != 0 || Number(value) != 1) {  
162 - createMessage.warning(`当前物模型仅支持值为0和1`);  
163 - return;  
164 - }  
165 - }  
166 - if (actionType == '16' || actionType == '10') {  
167 - const regex = /^-?\d+(\.\d{0,2})?$/;  
168 - const values =  
169 - Math.trunc(value) * unref(newZoomValue) + getFloatPart(value) * unref(newZoomValue);  
170 - if (!regex.test(values as any)) {  
171 - createMessage.warning(`值精确到两位小数,缩放因子是${unref(newZoomValue)}`);  
172 - return;  
173 - }  
174 - const newValue = values == 0 ? [0, 0] : getArray(SingleToHex(values));  
175 - modbusForm.value.registerValues = newValue;  
176 - modbusForm.value.registerNumber = 2;  
177 - modbusForm.value.method = '10';  
178 - }  
179 - const sendValue = await genModbusCommand(unref(modbusForm));  
180 - return sendValue;  
181 - }  
182 - };  
183 -  
184 - const handleBlur = async () => { 72 + const handleAfterChange = () => {
185 if (unref(getDesign).password) { 73 if (unref(getDesign).password) {
186 - sliderValue.value = oldSliderValue.value;  
187 - openModal(true, { password: unref(getDesign).password, value: afterValue.value }); 74 + openModal(true, { password: unref(getDesign).password });
188 return; 75 return;
189 } 76 }
190 -  
191 - if (unref(oldSliderValue) !== unref(sliderValue)) {  
192 - const { codeType, customCommand } = unref(getDesign) || {};  
193 - const { transportType } = customCommand || {};  
194 - const sendValue = ref<any>(unref(sliderValue));  
195 - const isModbusCommand = ref<boolean>(false);  
196 - if (transportType == 'TCP' && codeType == TaskTypeEnum.MODBUS_RTU) {  
197 - sendValue.value = await getSendValue(unref(sliderValue));  
198 - isModbusCommand.value = true;  
199 - }  
200 - const flag = await sendCommand(props.config.option, unref(sendValue), unref(isModbusCommand));  
201 - flag  
202 - ? ((sliderValue.value = unref(sliderValue)),  
203 - (oldSliderValue.value = sliderValue.value),  
204 - (index.value = 0))  
205 - : (sliderValue.value = unref(oldSliderValue));  
206 - } 77 + handleSendCommand();
207 }; 78 };
208 79
209 - const handleSendCommand = async (data) => {  
210 - const { value } = data || {};  
211 - sliderValue.value = value;  
212 - if (unref(oldSliderValue) !== unref(sliderValue)) {  
213 - const { codeType, customCommand } = unref(getDesign) || {};  
214 - const { transportType } = customCommand || {};  
215 - const sendValue = ref<any>(unref(sliderValue));  
216 - const isModbusCommand = ref<boolean>(false);  
217 - if (transportType == 'TCP' && codeType == TaskTypeEnum.MODBUS_RTU) {  
218 - sendValue.value = await getSendValue(unref(sliderValue));  
219 - isModbusCommand.value = true;  
220 - }  
221 - const flag = await sendCommand(props.config.option, unref(sendValue), unref(isModbusCommand));  
222 - flag  
223 - ? ((sliderValue.value = unref(sliderValue)),  
224 - (oldSliderValue.value = sliderValue.value),  
225 - (index.value = 0))  
226 - : (sliderValue.value = unref(oldSliderValue));  
227 - } 80 + const handleSendCommand = async () => {
  81 + if (props.config.option.mode === ComponentMode.SELECT_PREVIEW) return;
  82 + const value = unref(sendValue);
  83 + const { option } = props.config || {};
  84 + const result = await doCommandDeliver(option, value);
  85 + unref(sliderElRef)?.blur();
  86 + sliderValue.value = result ? value : unref(sliderValue);
228 }; 87 };
229 88
230 const { getNumberValue } = useReceiveValue(); 89 const { getNumberValue } = useReceiveValue();
@@ -233,7 +92,6 @@ @@ -233,7 +92,6 @@
233 const [latest] = data[attribute] || []; 92 const [latest] = data[attribute] || [];
234 const [name, value] = latest; 93 const [name, value] = latest;
235 if (!name && !value) return; 94 if (!name && !value) return;
236 - noSendValue.value = getNumberValue(value);  
237 sliderValue.value = getNumberValue(value); 95 sliderValue.value = getNumberValue(value);
238 }; 96 };
239 97
@@ -254,10 +112,11 @@ @@ -254,10 +112,11 @@
254 fontSize: (getRatio ? getRatio * getDesign.valueSize : getDesign.valueSize) + 'px', 112 fontSize: (getRatio ? getRatio * getDesign.valueSize : getDesign.valueSize) + 'px',
255 }" 113 }"
256 class="font-bold text-xl mt-3 text-center" 114 class="font-bold text-xl mt-3 text-center"
257 - >{{ sliderValue }}</span  
258 > 115 >
  116 + {{ sliderValue }}
  117 + </span>
259 <Slider 118 <Slider
260 - ref="sliderEl" 119 + ref="sliderElRef"
261 :style="{ 120 :style="{
262 '--slider-color': getDesign.controlBarColor, 121 '--slider-color': getDesign.controlBarColor,
263 '--slider-handle': (getRatio ? getRatio * 14 : 14) + 'px', 122 '--slider-handle': (getRatio ? getRatio * 14 : 14) + 'px',
@@ -270,7 +129,6 @@ @@ -270,7 +129,6 @@
270 :max="getDesign.maxNumber" 129 :max="getDesign.maxNumber"
271 @change="handleChange" 130 @change="handleChange"
272 @afterChange="handleAfterChange" 131 @afterChange="handleAfterChange"
273 - @blur="handleBlur"  
274 /> 132 />
275 133
276 <span 134 <span
@@ -8,6 +8,47 @@ import { @@ -8,6 +8,47 @@ import {
8 } from '/@/views/visual/packages/index.type'; 8 } from '/@/views/visual/packages/index.type';
9 import { PublicConfigClass, componentInitConfig } from '/@/views/visual/packages/publicConfig'; 9 import { PublicConfigClass, componentInitConfig } from '/@/views/visual/packages/publicConfig';
10 import { ComponentConfigFieldEnum } from '../../../enum'; 10 import { ComponentConfigFieldEnum } from '../../../enum';
  11 +import { buildUUID } from '/@/utils/uuid';
  12 +
  13 +export interface SwitchItemType extends Recordable {
  14 + id: string;
  15 + checked: boolean;
  16 + deviceId?: string;
  17 + deviceProfileId?: string;
  18 + attribute?: string;
  19 + deviceName?: string;
  20 + attributeName?: string;
  21 + openCommand?: string;
  22 + closeCommand?: string;
  23 + openService?: string;
  24 + closeService?: string;
  25 +}
  26 +
  27 +export const DEFAULT_VALUE: SwitchItemType[] = [
  28 + {
  29 + deviceName: '光照设备',
  30 + attributeName: '光照',
  31 + icon: 'zongfushe',
  32 + unit: 'kw',
  33 + iconColor: '#367BFF',
  34 + fontColor: '#357CFB',
  35 + checked: false,
  36 + fontSize: 16,
  37 + id: buildUUID(),
  38 + },
  39 + {
  40 + value: 53.7,
  41 + deviceName: '风机设备',
  42 + attributeName: '风机',
  43 + icon: 'guangzhaoqiangdu',
  44 + unit: '℃',
  45 + iconColor: '#FFA000',
  46 + fontColor: '#FFA000',
  47 + checked: true,
  48 + fontSize: 16,
  49 + id: buildUUID(),
  50 + },
  51 +];
11 52
12 export const option: PublicPresetOptions = { 53 export const option: PublicPresetOptions = {
13 multipleDataSourceComponent: true, 54 multipleDataSourceComponent: true,
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 - import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type';  
3 - import { option } from './config'; 2 + import { ComponentMode, ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
  3 + import { DEFAULT_VALUE, option, SwitchItemType } from './config';
4 import { SvgIcon } from '/@/components/Icon'; 4 import { SvgIcon } from '/@/components/Icon';
5 import { Switch } from 'ant-design-vue'; 5 import { Switch } from 'ant-design-vue';
6 - import { computed, ref } from 'vue'; 6 + import { computed, ref, toRaw } from 'vue';
7 import { useComponentScale } from '../../../hook/useComponentScale'; 7 import { useComponentScale } from '../../../hook/useComponentScale';
8 - import { useSendCommand } from '../../../hook/useSendCommand';  
9 import { unref } from 'vue'; 8 import { unref } from 'vue';
10 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName'; 9 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
11 import { MultipleDataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 10 import { MultipleDataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
12 import { useMultipleDataFetch } from '../../../hook/socket/useSocket'; 11 import { useMultipleDataFetch } from '../../../hook/socket/useSocket';
13 import { useReceiveMessage } from '../../../hook/useReceiveMessage'; 12 import { useReceiveMessage } from '../../../hook/useReceiveMessage';
14 import { useReceiveValue } from '../../../hook/useReceiveValue'; 13 import { useReceiveValue } from '../../../hook/useReceiveValue';
15 - import { DataSource } from '/@/views/visual/palette/types';  
16 - import { getSendValues, CommandTypeEnumLIst } from '../config';  
17 import { useModal } from '/@/components/Modal'; 14 import { useModal } from '/@/components/Modal';
18 import PasswordModal from '../component/PasswordModal.vue'; 15 import PasswordModal from '../component/PasswordModal.vue';
  16 + import {
  17 + DoCommandDeliverDataSourceType,
  18 + useCommandDelivery,
  19 + } from '../../../hook/useCommandDelivery';
  20 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
19 21
20 const props = defineProps<{ 22 const props = defineProps<{
21 config: ComponentPropsConfigType<typeof option>; 23 config: ComponentPropsConfigType<typeof option>;
22 }>(); 24 }>();
23 25
24 - const svgList = ref<any>([  
25 - {  
26 - value: 26.2,  
27 - deviceName: '光照设备',  
28 - attributeName: '光照',  
29 - icon: 'zongfushe',  
30 - unit: 'kw',  
31 - iconColor: '#367BFF',  
32 - fontColor: '#357CFB',  
33 - checked: false,  
34 - id: 0,  
35 - },  
36 - {  
37 - value: 53.7,  
38 - deviceName: '风机设备',  
39 - attributeName: '风机',  
40 - icon: 'guangzhaoqiangdu',  
41 - unit: '℃',  
42 - iconColor: '#FFA000',  
43 - fontColor: '#FFA000',  
44 - checked: true,  
45 - id: 1,  
46 - },  
47 - ]); 26 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
48 27
49 const getDesign = computed(() => { 28 const getDesign = computed(() => {
50 const { persetOption = {}, option } = props.config; 29 const { persetOption = {}, option } = props.config;
@@ -64,90 +43,66 @@ @@ -64,90 +43,66 @@
64 const { 43 const {
65 attribute, 44 attribute,
66 attributeRename, 45 attributeRename,
67 - attributeName,  
68 deviceId, 46 deviceId,
69 deviceName, 47 deviceName,
70 deviceRename, 48 deviceRename,
71 commandType, 49 commandType,
72 - extensionDesc,  
73 - codeType,  
74 - deviceCode,  
75 - customCommand, 50 + deviceProfileId,
  51 + openCommand,
  52 + closeCommand,
  53 + openService,
  54 + closeService,
76 } = item; 55 } = item;
  56 +
  57 + const tsl = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
  58 +
77 return { 59 return {
78 unit: unit ?? persetUnit, 60 unit: unit ?? persetUnit,
  61 + deviceProfileId,
  62 + deviceId,
79 fontColor: fontColor ?? persetFontColor, 63 fontColor: fontColor ?? persetFontColor,
80 icon: icon ?? persetIcon, 64 icon: icon ?? persetIcon,
81 iconColor: iconColor ?? persetIconColor, 65 iconColor: iconColor ?? persetIconColor,
82 attribute: attribute, 66 attribute: attribute,
83 - attributeName: attributeRename || attributeName, 67 + attributeName: attributeRename || tsl?.functionName || attribute,
84 showDeviceName, 68 showDeviceName,
85 deviceName: deviceRename || deviceName, 69 deviceName: deviceRename || deviceName,
86 id: deviceId, 70 id: deviceId,
87 - extensionDesc: extensionDesc ? JSON.parse(extensionDesc) : {},  
88 commandType, 71 commandType,
89 - codeType,  
90 - deviceCode,  
91 - customCommand,  
92 fontSize: fontSize || persetFontSize || 14, 72 fontSize: fontSize || persetFontSize || 14,
93 password: password || persetPassword, 73 password: password || persetPassword,
94 - }; 74 + checked: false,
  75 + openCommand,
  76 + closeCommand,
  77 + openService,
  78 + closeService,
  79 + } as SwitchItemType;
95 }), 80 }),
96 }; 81 };
97 }); 82 });
98 83
99 - const { loading, sendCommand } = useSendCommand();  
100 - const handleChange = async (index: number, checked: Boolean, item: any) => { 84 + const handleChange = async (item) => {
101 if (item.password) { 85 if (item.password) {
102 - openModal(true, { password: item.password, index, checked });  
103 - controlList.value[index].checked = !checked; 86 + openModal(true, { password: item.password });
104 return; 87 return;
105 } 88 }
106 - const { heightPx, itemHeightRatio, itemWidthRatio, mode, widthPx, dataSource } =  
107 - props.config.option;  
108 - const data = {  
109 - ...dataSource?.[index],  
110 - heightPx,  
111 - itemHeightRatio,  
112 - itemWidthRatio,  
113 - mode,  
114 - widthPx,  
115 - } as DataSource;  
116 - const { values, isModbusCommand, sendValue } =  
117 - (await getSendValues(data, unref(getDesign).dataSource[index], checked)) || {};  
118 -  
119 - const flag = await sendCommand(values, isModbusCommand ? sendValue : checked, isModbusCommand);  
120 - if (!flag) controlList.value[index].checked = !checked; 89 + handleSendCommand(item);
121 }; 90 };
122 91
123 const { forEachGroupMessage } = useReceiveMessage(); 92 const { forEachGroupMessage } = useReceiveMessage();
124 const { getNumberValue } = useReceiveValue(); 93 const { getNumberValue } = useReceiveValue();
125 94
126 const controlList = ref( 95 const controlList = ref(
127 - props.config.option.dataSource  
128 - ? unref(getDesign).dataSource.map((item) => {  
129 - return { ...item, checked: false };  
130 - })  
131 - : svgList 96 + props.config.option.dataSource ? unref(getDesign).dataSource : DEFAULT_VALUE
132 ); 97 );
133 - const handleSendCommand = async (modalData) => {  
134 - const { index, checked } = modalData || {};  
135 - const { heightPx, itemHeightRatio, itemWidthRatio, mode, widthPx, dataSource } =  
136 - props.config.option;  
137 - const data = {  
138 - ...dataSource?.[index],  
139 - heightPx,  
140 - itemHeightRatio,  
141 - itemWidthRatio,  
142 - mode,  
143 - widthPx,  
144 - } as DataSource;  
145 - controlList.value[index].checked = checked;  
146 - const { values, isModbusCommand, sendValue } =  
147 - (await getSendValues(data, unref(getDesign).dataSource[index], checked)) || {};  
148 98
149 - const flag = await sendCommand(values, isModbusCommand ? sendValue : checked, isModbusCommand);  
150 - if (!flag) controlList.value[index].checked = !checked; 99 + const { loading, doCommandDeliver } = useCommandDelivery();
  100 + const handleSendCommand = async (modalData: SwitchItemType) => {
  101 + if (props.config.option.mode === ComponentMode.SELECT_PREVIEW) return;
  102 + await doCommandDeliver(
  103 + toRaw(unref(modalData)) as DoCommandDeliverDataSourceType,
  104 + Number(unref(modalData).checked)
  105 + );
151 }; 106 };
152 107
153 const updateFn: MultipleDataFetchUpdateFn = async (message, deviceId, attribute) => { 108 const updateFn: MultipleDataFetchUpdateFn = async (message, deviceId, attribute) => {
@@ -169,34 +124,26 @@ @@ -169,34 +124,26 @@
169 <main class="w-full h-full flex flex-col justify-evenly items-center"> 124 <main class="w-full h-full flex flex-col justify-evenly items-center">
170 <DeviceName :config="config" /> 125 <DeviceName :config="config" />
171 <div 126 <div
172 - style="width: 86%"  
173 - v-for="(item, index) in controlList" 127 + v-for="item in controlList"
174 :key="item.id" 128 :key="item.id"
175 - class="flex justify-between items-center" 129 + class="flex justify-between items-center w-full px-4"
176 > 130 >
177 - <div class="flex items-center">  
178 - <SvgIcon  
179 - :name="item.icon!"  
180 - prefix="iconfont"  
181 - :size="getRatio ? 30 * getRatio : 30"  
182 - :style="{ color: item.iconColor }"  
183 - />  
184 -  
185 - <div  
186 - class="text-gray-500 truncate ml-6"  
187 - :style="{ fontSize: (getRatio ? getRatio * item.fontSize : item.fontSize) + 'px' }"  
188 - >{{  
189 - `${item.deviceName} - ${  
190 - item.commandType ? CommandTypeEnumLIst[item.commandType].name : item.attributeName  
191 - }`  
192 - }}</div  
193 - > 131 + <SvgIcon
  132 + :name="item.icon!"
  133 + prefix="iconfont"
  134 + :size="getRatio ? 30 * getRatio : 30"
  135 + :style="{ color: item.iconColor }"
  136 + />
  137 + <div
  138 + class="text-gray-500 truncate mx-2"
  139 + :style="{ fontSize: (getRatio ? getRatio * item.fontSize : item.fontSize) + 'px' }"
  140 + >
  141 + {{ `${item.deviceName} - ${item.attributeName}` }}
194 </div> 142 </div>
195 -  
196 <Switch 143 <Switch
197 v-model:checked="item.checked" 144 v-model:checked="item.checked"
198 :loading="loading" 145 :loading="loading"
199 - @change="handleChange(index, item.checked, item)" 146 + @change="handleChange(item)"
200 :style="{ transform: `scale(${getRatio || 1})` }" 147 :style="{ transform: `scale(${getRatio || 1})` }"
201 /> 148 />
202 </div> 149 </div>
1 -import { ref, unref } from 'vue';  
2 -import { TaskTypeEnum } from '/@/views/task/center/config';  
3 -import { genModbusCommand } from '/@/api/task';  
4 -import { useMessage } from '/@/hooks/web/useMessage';  
5 -import { SingleToHex } from '/@/views/device/list/cpns/tabs/ObjectModelCommandDeliveryModal/config';  
6 -import { CommandTypeEnum } from '/@/enums/deviceEnum';  
7 -import { TransportTypeEnum } from '/@/enums/deviceEnum';  
8 -  
9 -const getArray = (values) => {  
10 - const str = values.replace(/\s+/g, '');  
11 - const array: any = [];  
12 -  
13 - for (let i = 0; i < str.length; i += 4) {  
14 - const chunk = parseInt(str.substring(i, i + 4), 16);  
15 - array.push(chunk);  
16 - }  
17 - return array;  
18 -};  
19 -  
20 -export const getSendValues = async (option, getDesign, checked) => {  
21 - const values: any = option;  
22 - const isModbusCommand = ref<boolean>(false); //判断是否是TCP设备-> 且设备标识符是modeBUs,切选择是下发命令类型是属性  
23 - const { extensionDesc, commandType, codeType, deviceCode, customCommand } = getDesign || {};  
24 - const { registerAddress, actionType } = extensionDesc || {};  
25 - const { openCommand, closeCommand, transportType } = customCommand || {};  
26 - const modBUS = ref<any>({});  
27 - const sendValue = ref();  
28 -  
29 - const { createMessage } = useMessage();  
30 - //判断是不是TCP类型设备  
31 - if (transportType === TransportTypeEnum.TCP) {  
32 - if (  
33 - //判断TCP下发类型是否是自定义还是服务  
34 - commandType === CommandTypeEnum.CUSTOM.toString() ||  
35 - commandType == CommandTypeEnum.SERVICE.toString()  
36 - ) {  
37 - values.customCommand.command = checked ? openCommand : closeCommand;  
38 - values.customCommand.command = values.customCommand.command  
39 - .replaceAll(/\s/g, '')  
40 - .toUpperCase();  
41 - }  
42 - if (  
43 - //判断命令下发类型是不是属性 且是modbus  
44 - commandType === CommandTypeEnum.ATTRIBUTE.toString() &&  
45 - codeType === TaskTypeEnum.MODBUS_RTU  
46 - ) {  
47 - if (!deviceCode) {  
48 - createMessage.warning('当前设备没有设置地址码');  
49 - return;  
50 - }  
51 - if (!actionType) {  
52 - createMessage.warning('当前物模型扩展描述没有填写');  
53 - return;  
54 - }  
55 - isModbusCommand.value = true;  
56 - modBUS.value = {  
57 - crc: 'CRC_16_LOWER',  
58 - deviceCode: deviceCode,  
59 - method: actionType == '16' ? '10' : actionType,  
60 - registerAddress,  
61 - registerNumber: 1,  
62 - registerValues: [Number(checked)],  
63 - };  
64 -  
65 - if (actionType == '16' || actionType == '10') {  
66 - const newValue = Number(checked) == 0 ? [0, 0] : getArray(SingleToHex(Number(checked)));  
67 - modBUS.value.registerValues = newValue;  
68 - modBUS.value.registerNumber = 2;  
69 - modBUS.value.method = '10';  
70 - }  
71 -  
72 - sendValue.value = await genModbusCommand(unref(modBUS));  
73 - }  
74 - }  
75 -  
76 - return { values, sendValue: unref(sendValue), isModbusCommand: unref(isModbusCommand) };  
77 -};  
78 -  
79 -export const CommandTypeEnumLIst = {  
80 - '0': { CUSTOM: 0, name: '自定义' },  
81 - '1': { CUSTOM: 1, name: '服务' },  
82 - '2': { CUSTOM: 2, name: '属性' },  
83 -};  
@@ -11,3 +11,7 @@ export const ControlList = [ @@ -11,3 +11,7 @@ export const ControlList = [
11 LateralNumericalControlConfig, 11 LateralNumericalControlConfig,
12 SwitchListConfig, 12 SwitchListConfig,
13 ]; 13 ];
  14 +
  15 +export enum ControlComponentEnum {
  16 + LATERAL_NUMERICAL_CONTROL = 'LateralNumericalControl',
  17 +}
@@ -3,11 +3,15 @@ @@ -3,11 +3,15 @@
3 import { BasicModal, useModalInner } from '/@/components/Modal'; 3 import { BasicModal, useModalInner } from '/@/components/Modal';
4 import { formSchema, getHistorySearchParams, SchemaFiled } from './history.config'; 4 import { formSchema, getHistorySearchParams, SchemaFiled } from './history.config';
5 import { HistoryModalOkEmitParams } from './type'; 5 import { HistoryModalOkEmitParams } from './type';
6 - import { ref, unref } from 'vue'; 6 + import { computed, ref, unref } from 'vue';
7 import { getAllDeviceByOrg } from '/@/api/dataBoard'; 7 import { getAllDeviceByOrg } from '/@/api/dataBoard';
8 import { getDeviceHistoryInfo } from '/@/api/alarm/position'; 8 import { getDeviceHistoryInfo } from '/@/api/alarm/position';
9 import { DataSource } from '/@/views/visual/palette/types'; 9 import { DataSource } from '/@/views/visual/palette/types';
10 - import { cloneDeep } from 'lodash-es'; 10 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
  11 + import { DataTypeEnum } from '/@/enums/objectModelEnum';
  12 + import { StructJSON } from '/@/api/device/model/modelOfMatterModel';
  13 + import { HistoryData } from '/@/api/alarm/position/model';
  14 + import { useJsonParse } from '/@/hooks/business/useJsonParse';
11 15
12 const emit = defineEmits(['register', 'ok']); 16 const emit = defineEmits(['register', 'ok']);
13 17
@@ -20,47 +24,44 @@ @@ -20,47 +24,44 @@
20 }); 24 });
21 25
22 const loading = ref(false); 26 const loading = ref(false);
23 - const getDesign = ref(); 27 + const dataSourceRef = ref<DataSource[]>([]);
24 28
25 - const getTwoMap = async (dataSource) => {  
26 - if (dataSource.length < 2) return;  
27 - dataSource = dataSource.splice(0, 2);  
28 - const deviceRecord = dataSource?.at(0) || ({} as DataSource); 29 + const getPositionRecord = computed<DataSource>(() => unref(dataSourceRef).at(0) as DataSource);
  30 +
  31 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
  32 +
  33 + const handleSetForm = async () => {
  34 + const deviceRecord = unref(getPositionRecord) || {};
29 35
30 if (!deviceRecord.organizationId) return; 36 if (!deviceRecord.organizationId) return;
31 const deviceList = await getAllDeviceByOrg( 37 const deviceList = await getAllDeviceByOrg(
32 deviceRecord.organizationId, 38 deviceRecord.organizationId,
33 deviceRecord.deviceProfileId 39 deviceRecord.deviceProfileId
34 ); 40 );
  41 +
35 const options = deviceList 42 const options = deviceList
36 .filter((item) => item.tbDeviceId === deviceRecord.deviceId) 43 .filter((item) => item.tbDeviceId === deviceRecord.deviceId)
37 .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId })); 44 .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId }));
38 45
39 - const attKey = dataSource.map((item) => ({  
40 - ...item,  
41 - label: item.attribute,  
42 - value: item.attribute,  
43 - })); 46 + const { latitudeIdentifier, longitudeIdentifier, deviceProfileId } = deviceRecord;
44 47
45 - updateSchemaMap(options, attKey, deviceRecord);  
46 - }; 48 + const attKey = [latitudeIdentifier, longitudeIdentifier].map((item) => {
  49 + const [identifier, structIdentifier] = item || [];
  50 + const detail = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, identifier);
47 51
48 - const getOneMap = async (dataSource) => {  
49 - const deviceRecord = dataSource?.[0];  
50 - if (!deviceRecord.organizationId) return;  
51 - const deviceList = await getAllDeviceByOrg(  
52 - deviceRecord.organizationId,  
53 - deviceRecord.deviceProfileId  
54 - );  
55 - const options = deviceList  
56 - .filter((item) => item.tbDeviceId === deviceRecord.deviceId)  
57 - .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId })); 52 + if (detail?.specs?.dataType.type === DataTypeEnum.STRUCT) {
  53 + const structIdentifierDetail = (detail.specs.dataType.specs as StructJSON[])?.find(
  54 + (temp) => temp.identifier === structIdentifier
  55 + );
  56 + return {
  57 + label: `${detail.functionName} / ${structIdentifierDetail?.functionName}`,
  58 + value: identifier,
  59 + };
  60 + }
  61 +
  62 + return { label: detail?.functionName, value: identifier };
  63 + });
58 64
59 - const attKey = dataSource?.map((item) => ({  
60 - ...item,  
61 - label: item.attributeName,  
62 - value: item.attribute,  
63 - }));  
64 updateSchemaMap(options, attKey, deviceRecord); 65 updateSchemaMap(options, attKey, deviceRecord);
65 }; 66 };
66 67
@@ -92,81 +93,73 @@ @@ -92,81 +93,73 @@
92 93
93 const [registerModal, { closeModal }] = useModalInner(async (dataSource: DataSource[]) => { 94 const [registerModal, { closeModal }] = useModalInner(async (dataSource: DataSource[]) => {
94 try { 95 try {
95 - getDesign.value = dataSource;  
96 - dataSource = cloneDeep(dataSource);  
97 - //判断选择是不是结构体  
98 - if (dataSource.length == 1 && dataSource?.[0]?.lal) {  
99 - getOneMap(dataSource);  
100 - return;  
101 - }  
102 - getTwoMap(dataSource); 96 + dataSourceRef.value = dataSource;
  97 + handleSetForm();
103 } catch (error) { 98 } catch (error) {
104 throw error; 99 throw error;
105 } 100 }
106 }); 101 });
107 102
108 - const getMultipleDataSource = async (res) => { 103 + const getPositionDataSource = async (res: HistoryData) => {
  104 + const keys = Object.keys(res);
  105 + const track: Record<'lng' | 'lat', number>[] = [];
  106 +
  107 + const {
  108 + latitudeIdentifier = [],
  109 + longitudeIdentifier = [],
  110 + deviceProfileId,
  111 + } = unref(getPositionRecord);
  112 +
  113 + const [latIdentifier] = latitudeIdentifier || [];
  114 + const [lngIdentifier] = longitudeIdentifier || [];
  115 +
  116 + if (!latIdentifier || !lngIdentifier) return track;
  117 +
  118 + const latDetail = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, latIdentifier);
  119 + const lngDetail = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, lngIdentifier);
  120 +
  121 + if (!latDetail || !lngDetail) return track;
  122 +
109 let timespanList = Object.keys(res).reduce((prev, next) => { 123 let timespanList = Object.keys(res).reduce((prev, next) => {
110 const ts = res[next].map((item) => item.ts); 124 const ts = res[next].map((item) => item.ts);
111 return [...prev, ...ts]; 125 return [...prev, ...ts];
112 }, [] as number[]); 126 }, [] as number[]);
113 timespanList = [...new Set(timespanList)]; 127 timespanList = [...new Set(timespanList)];
114 128
115 - const track: Record<'lng' | 'lat', number>[] = [];  
116 - const keys = Object.keys(res); 129 + for (const position of [longitudeIdentifier, latitudeIdentifier]) {
  130 + const [attribute] = position;
  131 + const detail = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
  132 + if (!detail) continue;
  133 + const { identifier } = detail || {};
  134 +
  135 + if (detail?.specs?.dataType.type === DataTypeEnum.STRUCT) {
  136 + const [, structIdentifier] = position;
  137 + res[identifier].forEach((temp) => {
  138 + const structJSON = useJsonParse(temp.value).value;
  139 + temp.value = structJSON?.[structIdentifier];
  140 + });
  141 + }
  142 + }
117 143
118 for (const ts of timespanList) { 144 for (const ts of timespanList) {
119 const list: { ts: number; value: number }[] = []; 145 const list: { ts: number; value: number }[] = [];
120 for (const key of keys) { 146 for (const key of keys) {
121 const record = res[key].find((item) => ts === item.ts); 147 const record = res[key].find((item) => ts === item.ts);
122 - if (!validEffective(record?.value)) {  
123 - continue;  
124 - }  
125 list.push(record as any); 148 list.push(record as any);
126 } 149 }
127 150
128 if (list.length === 2 && list.every(Boolean)) { 151 if (list.length === 2 && list.every(Boolean)) {
129 - const lng = list.at(0)?.value;  
130 - const lat = list.at(1)?.value;  
131 - if (lng && lat) track.push({ lng, lat }); 152 + let lng = list.at(0)?.value;
  153 + let lat = list.at(1)?.value;
  154 + if (lng && lat) {
  155 + track.push({ lng: Number(lng), lat: Number(lat) });
  156 + }
132 } 157 }
133 } 158 }
134 - return track;  
135 - };  
136 -  
137 - // 单数据源选择结构体  
138 - const getSingleDataSource = async (res) => {  
139 - const [keys] = Object.keys(res);  
140 - const track: Record<'lng' | 'lat', number>[] = [];  
141 - const dataSource = res[keys]?.map((item) => {  
142 - return {  
143 - value: item.value ? JSON.parse(item.value) : {},  
144 - };  
145 - });  
146 - const list: { value: number }[] = [];  
147 - dataSource?.forEach((item) => {  
148 - if (  
149 - //判断结构体得值是不是数字  
150 - Object.values(item.value).every((item1) => {  
151 - return validEffective(item1 as any);  
152 - })  
153 - ) {  
154 - list.push(item.value);  
155 - }  
156 - });  
157 - const { latitude, longitude } = unref(getDesign)?.[0]; //获取选择的经纬度选项  
158 159
159 - list.forEach((item) => {  
160 - const lng = item[longitude];  
161 - const lat = item[latitude];  
162 - if (lng && lat) track.push({ lng, lat });  
163 - });  
164 return track; 160 return track;
165 }; 161 };
166 162
167 - const validEffective = (value = '') => {  
168 - return !!(value && !isNaN(value as unknown as number));  
169 - };  
170 const handleOk = async () => { 163 const handleOk = async () => {
171 try { 164 try {
172 await validate(); 165 await validate();
@@ -180,9 +173,8 @@ @@ -180,9 +173,8 @@
180 ...value, 173 ...value,
181 [SchemaFiled.KEYS]: value[SchemaFiled.KEYS].join(','), 174 [SchemaFiled.KEYS]: value[SchemaFiled.KEYS].join(','),
182 }); 175 });
183 - const ifSingle = unref(getDesign)?.length === 1 && unref(getDesign)?.[0]?.lal;  
184 176
185 - const track = ifSingle ? await getSingleDataSource(res) : await getMultipleDataSource(res); 177 + const track = await getPositionDataSource(res);
186 emit('ok', { track, value } as HistoryModalOkEmitParams); 178 emit('ok', { track, value } as HistoryModalOkEmitParams);
187 closeModal(); 179 closeModal();
188 } catch (error) { 180 } catch (error) {
  1 +import { CategoryEnum } from '../..';
1 import { useComponentKeys } from '/@/views/visual/packages/hook/useComponentKeys'; 2 import { useComponentKeys } from '/@/views/visual/packages/hook/useComponentKeys';
2 import { ConfigType, PackagesCategoryEnum } from '/@/views/visual/packages/index.type'; 3 import { ConfigType, PackagesCategoryEnum } from '/@/views/visual/packages/index.type';
3 4
@@ -6,5 +7,6 @@ const componentKeys = useComponentKeys('MapComponentTrackHistory'); @@ -6,5 +7,6 @@ const componentKeys = useComponentKeys('MapComponentTrackHistory');
6 export const MapComponentTrackHistoryConfig: ConfigType = { 7 export const MapComponentTrackHistoryConfig: ConfigType = {
7 ...componentKeys, 8 ...componentKeys,
8 title: '历史轨迹', 9 title: '历史轨迹',
  10 + category: CategoryEnum.MAP,
9 package: PackagesCategoryEnum.MAP, 11 package: PackagesCategoryEnum.MAP,
10 }; 12 };
@@ -50,6 +50,7 @@ @@ -50,6 +50,7 @@
50 endTs, 50 endTs,
51 formatType 51 formatType
52 )}`; 52 )}`;
  53 +
53 genTrackPlaybackAnimation(track as any[]); 54 genTrackPlaybackAnimation(track as any[]);
54 }; 55 };
55 56
  1 +import { CategoryEnum } from '../..';
1 import { useComponentKeys } from '/@/views/visual/packages/hook/useComponentKeys'; 2 import { useComponentKeys } from '/@/views/visual/packages/hook/useComponentKeys';
2 import { ConfigType, PackagesCategoryEnum } from '/@/views/visual/packages/index.type'; 3 import { ConfigType, PackagesCategoryEnum } from '/@/views/visual/packages/index.type';
3 4
@@ -6,5 +7,6 @@ const componentKeys = useComponentKeys('MapComponentTrackReal'); @@ -6,5 +7,6 @@ const componentKeys = useComponentKeys('MapComponentTrackReal');
6 export const MapComponentTrackRealConfig: ConfigType = { 7 export const MapComponentTrackRealConfig: ConfigType = {
7 ...componentKeys, 8 ...componentKeys,
8 title: '实时轨迹', 9 title: '实时轨迹',
  10 + category: CategoryEnum.MAP,
9 package: PackagesCategoryEnum.MAP, 11 package: PackagesCategoryEnum.MAP,
10 }; 12 };
@@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
9 import { useMapTrackPlayBack } from './useMapTrackPlayback'; 9 import { useMapTrackPlayBack } from './useMapTrackPlayback';
10 import { useMultipleDataFetch } from '../../../hook/socket/useSocket'; 10 import { useMultipleDataFetch } from '../../../hook/socket/useSocket';
11 import { MultipleDataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 11 import { MultipleDataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
  12 + import get from 'lodash-es/get';
12 13
13 const props = defineProps<{ 14 const props = defineProps<{
14 config: ComponentPropsConfigType<typeof option>; 15 config: ComponentPropsConfigType<typeof option>;
@@ -24,44 +25,36 @@ @@ -24,44 +25,36 @@
24 return props.config.option.dataSource?.at(0)?.deviceId; 25 return props.config.option.dataSource?.at(0)?.deviceId;
25 }); 26 });
26 27
27 - const getDesign = computed(() => {  
28 - const { option } = props.config;  
29 - const { dataSource } = option || {};  
30 - return {  
31 - dataSource: dataSource,  
32 - };  
33 - });  
34 -  
35 /** 28 /**
36 * @description 经度key 29 * @description 经度key
37 */ 30 */
38 const getLngKey = computed(() => { 31 const getLngKey = computed(() => {
39 - return props.config.option.dataSource?.at(0)?.attribute || ''; 32 + return props.config.option.dataSource?.at(0)?.longitudeIdentifier || [];
40 }); 33 });
41 34
42 /** 35 /**
43 * @description 纬度key 36 * @description 纬度key
44 */ 37 */
45 const getLatKey = computed(() => { 38 const getLatKey = computed(() => {
46 - return props.config.option.dataSource?.at(1)?.attribute || ''; 39 + return props.config.option.dataSource?.at(0)?.latitudeIdentifier || [];
47 }); 40 });
48 41
49 const validEffective = (value = '') => { 42 const validEffective = (value = '') => {
50 return !!(value && !isNaN(value as unknown as number)); 43 return !!(value && !isNaN(value as unknown as number));
51 }; 44 };
52 45
53 - const getTwoMap = (message, deviceId) => { 46 + const handleMessage = (message, deviceId) => {
54 if (unref(getDeviceId) !== deviceId) return; 47 if (unref(getDeviceId) !== deviceId) return;
55 48
56 const { data = {} } = message; 49 const { data = {} } = message;
57 50
58 const bindMessage = data[deviceId]; 51 const bindMessage = data[deviceId];
59 52
60 - const lngData = bindMessage[unref(getLngKey)] || []; 53 + const lngData = get(bindMessage, unref(getLngKey)) || [];
61 const [lngLatest] = lngData; 54 const [lngLatest] = lngData;
62 const [, lng] = lngLatest || []; 55 const [, lng] = lngLatest || [];
63 56
64 - const latData = bindMessage[unref(getLatKey)] || []; 57 + const latData = get(bindMessage, unref(getLatKey)) || [];
65 const [latLatest] = latData; 58 const [latLatest] = latData;
66 const [, lat] = latLatest || []; 59 const [, lat] = latLatest || [];
67 60
@@ -70,32 +63,8 @@ @@ -70,32 +63,8 @@
70 } 63 }
71 }; 64 };
72 65
73 - const getOneMap = (message, deviceId) => {  
74 - if (unref(getDeviceId) !== deviceId) return;  
75 -  
76 - const { longitude, latitude, attribute } = unref(getDesign)?.dataSource?.[0] || {};  
77 - const { data } = message || {};  
78 - const bindMessage = data[deviceId];  
79 - const [, values] = attribute && bindMessage?.[attribute][0];  
80 -  
81 - const mapValues = values ? JSON.parse(values) : {};  
82 - const lng = longitude && mapValues[longitude];  
83 - const lat = latitude && mapValues[latitude];  
84 -  
85 - if (validEffective(lng) && validEffective(lat)) {  
86 - drawLine({ lng: Number(lng), lat: Number(lat) });  
87 - }  
88 - };  
89 -  
90 const updateFn: MultipleDataFetchUpdateFn = (message, deviceId) => { 66 const updateFn: MultipleDataFetchUpdateFn = (message, deviceId) => {
91 - const { lal } = unref(getDesign)?.dataSource?.[0] || {};  
92 - // 属性选择结构体类型时  
93 - if (lal && unref(getDesign)?.dataSource?.length == 1) {  
94 - getOneMap(message, deviceId);  
95 - return;  
96 - }  
97 - // 选择两个属性时  
98 - getTwoMap(message, deviceId); 67 + handleMessage(message, deviceId);
99 }; 68 };
100 69
101 useMultipleDataFetch(props, updateFn); 70 useMultipleDataFetch(props, updateFn);
1 -import cloneDeep from 'lodash-es/cloneDeep';  
2 -import { SwitchSignalLightConfig } from '.';  
3 -import {  
4 - ConfigType,  
5 - CreateComponentType,  
6 - PublicComponentOptions,  
7 - PublicPresetOptions,  
8 -} from '/@/views/visual/packages/index.type';  
9 -import { PublicConfigClass, componentInitConfig } from '/@/views/visual/packages/publicConfig';  
10 -import { ComponentConfigFieldEnum } from '/@/views/visual/packages/enum';  
11 -  
12 -export const option: PublicPresetOptions = {  
13 - [ComponentConfigFieldEnum.OPEN_COLOR]: '#30f230',  
14 - [ComponentConfigFieldEnum.CLOSE_COLOR]: '#eeeeee',  
15 - [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: true,  
16 -};  
17 -  
18 -export default class Config extends PublicConfigClass implements CreateComponentType {  
19 - public key: string = SwitchSignalLightConfig.key;  
20 -  
21 - public attr = { ...componentInitConfig };  
22 -  
23 - public componentConfig: ConfigType = cloneDeep(SwitchSignalLightConfig);  
24 -  
25 - public persetOption = cloneDeep(option);  
26 -  
27 - public option: PublicComponentOptions;  
28 -  
29 - constructor(option: PublicComponentOptions) {  
30 - super();  
31 - this.option = { ...option };  
32 - }  
33 -}  
1 -<script lang="ts" setup>  
2 - import { ComponentConfigFieldEnum } from '/@/views/visual/packages/enum';  
3 - import { useForm, BasicForm } from '/@/components/Form';  
4 - import { PublicFormInstaceType } from '/@/views/visual/dataSourceBindPanel/index.type';  
5 - import { option } from './config';  
6 -  
7 - const [register, { getFieldsValue, setFieldsValue, resetFields }] = useForm({  
8 - schemas: [  
9 - {  
10 - field: ComponentConfigFieldEnum.OPEN_COLOR,  
11 - label: 'ON颜色',  
12 - component: 'ColorPicker',  
13 - changeEvent: 'update:value',  
14 - componentProps: {  
15 - defaultValue: option.openColor,  
16 - },  
17 - },  
18 - {  
19 - field: ComponentConfigFieldEnum.CLOSE_COLOR,  
20 - label: 'OFF颜色',  
21 - component: 'ColorPicker',  
22 - changeEvent: 'update:value',  
23 - componentProps: {  
24 - defaultValue: option.closeColor,  
25 - },  
26 - },  
27 - {  
28 - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME,  
29 - label: '显示设备名称',  
30 - component: 'Checkbox',  
31 - defaultValue: option.showDeviceName,  
32 - },  
33 - ],  
34 - showActionButtonGroup: false,  
35 - labelWidth: 120,  
36 - baseColProps: {  
37 - span: 12,  
38 - },  
39 - });  
40 -  
41 - const getFormValues = () => {  
42 - return getFieldsValue();  
43 - };  
44 -  
45 - const setFormValues = (data: Recordable) => {  
46 - return setFieldsValue(data);  
47 - };  
48 -  
49 - defineExpose({  
50 - getFormValues,  
51 - setFormValues,  
52 - resetFormValues: resetFields,  
53 - } as PublicFormInstaceType);  
54 -</script>  
55 -  
56 -<template>  
57 - <BasicForm @register="register" />  
58 -</template>  
1 -<script lang="ts" setup>  
2 - import { commonDataSourceSchemas } from '../../../config/common.config';  
3 - import { BasicForm, useForm } from '/@/components/Form';  
4 - import { PublicFormInstaceType } from '/@/views/visual/dataSourceBindPanel/index.type';  
5 -  
6 - const [register, { getFieldsValue, setFieldsValue, validate, resetFields }] = useForm({  
7 - labelWidth: 0,  
8 - showActionButtonGroup: false,  
9 - layout: 'horizontal',  
10 - labelCol: { span: 0 },  
11 - schemas: commonDataSourceSchemas(),  
12 - });  
13 -  
14 - const getFormValues = () => {  
15 - return getFieldsValue();  
16 - };  
17 -  
18 - const setFormValues = (record: Recordable) => {  
19 - return setFieldsValue(record);  
20 - };  
21 -  
22 - defineExpose({  
23 - getFormValues,  
24 - setFormValues,  
25 - validate,  
26 - resetFormValues: resetFields,  
27 - } as PublicFormInstaceType);  
28 -</script>  
29 -  
30 -<template>  
31 - <BasicForm @register="register" />  
32 -</template>  
1 -// import { ComponentEnum, ComponentNameEnum } from '../index.type';  
2 -import { useComponentKeys } from '/@/views/visual/packages/hook/useComponentKeys';  
3 -import { ConfigType, PackagesCategoryEnum } from '/@/views/visual/packages/index.type';  
4 -  
5 -const componentKeys = useComponentKeys('SwitchSignalLight');  
6 -export const SwitchSignalLightConfig: ConfigType = {  
7 - ...componentKeys,  
8 - // title: ComponentNameEnum.TEXT_COMPONENT_1,  
9 - title: '开关量信号灯',  
10 - package: PackagesCategoryEnum.TEXT,  
11 -};  
1 -<script lang="ts" setup>  
2 - import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type';  
3 - import { option } from './config';  
4 - import { useComponentScale } from '/@/views/visual/packages/hook/useComponentScale';  
5 - import { ref, onMounted, unref } from 'vue';  
6 - import { useIntervalFn } from '@vueuse/core';  
7 - import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';  
8 - import { useReceiveValue } from '../../../hook/useReceiveValue';  
9 - import { useDataFetch } from '../../../hook/socket/useSocket';  
10 - import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';  
11 -  
12 - const props = defineProps<{  
13 - config: ComponentPropsConfigType<typeof option>;  
14 - }>();  
15 -  
16 - const isOpenClose = ref<boolean>(true);  
17 -  
18 - const randomFn = () => {  
19 - useIntervalFn(() => {  
20 - isOpenClose.value = !unref(isOpenClose);  
21 - }, 2000);  
22 - };  
23 - const { getNumberValue } = useReceiveValue();  
24 - const updateFn: DataFetchUpdateFn = (message, attribute) => {  
25 - const { data = {} } = message;  
26 - const [latest] = data[attribute] || [];  
27 - const [_, value] = latest;  
28 - isOpenClose.value = Boolean(getNumberValue(value));  
29 - };  
30 -  
31 - onMounted(() => {  
32 - !props.config.option.uuid && randomFn();  
33 - });  
34 -  
35 - useDataFetch(props, updateFn);  
36 -  
37 - const { getScale } = useComponentScale(props);  
38 -</script>  
39 -  
40 -<template>  
41 - <main :style="getScale" class="w-full h-full flex flex-col justify-center items-center">  
42 - <DeviceName :config="config" class="text-center" />  
43 - <div  
44 - style="--open-color: `${getDesign.openColor}`; --close-color: `${getDesign.closeColor}`"  
45 - :class="isOpenClose ? 'switch_open' : 'switch_close'"  
46 - >  
47 - </div>  
48 - </main>  
49 -</template>  
50 -<style lang="less" scoped>  
51 - .switch_open {  
52 - background: var(--open-color);  
53 - box-shadow: var(--open-color) 0 0 10px 3px;  
54 - width: 60px;  
55 - height: 60px;  
56 - border-radius: 50%;  
57 - margin: 10px 0;  
58 - }  
59 -  
60 - .switch_close {  
61 - background-color: var(--close-color);  
62 - box-shadow: none;  
63 - width: 42.023px;  
64 - height: 42.023px;  
65 - border-radius: 50%;  
66 - margin: 10px 0;  
67 - }  
68 -</style>  
@@ -2,11 +2,13 @@ @@ -2,11 +2,13 @@
2 import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type'; 2 import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
3 import { option } from './config'; 3 import { option } from './config';
4 import { useComponentScale } from '/@/views/visual/packages/hook/useComponentScale'; 4 import { useComponentScale } from '/@/views/visual/packages/hook/useComponentScale';
5 - import { computed } from 'vue'; 5 + import { computed, unref } from 'vue';
6 import { ref } from 'vue'; 6 import { ref } from 'vue';
7 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName'; 7 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
8 import { useDataFetch } from '../../../hook/socket/useSocket'; 8 import { useDataFetch } from '../../../hook/socket/useSocket';
9 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 9 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
  10 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
  11 + import { useThingsModelValueTransform } from '/@/views/visual/palette/hooks/useThingsModelValueTransform';
10 12
11 const props = defineProps<{ 13 const props = defineProps<{
12 config: ComponentPropsConfigType<typeof option>; 14 config: ComponentPropsConfigType<typeof option>;
@@ -14,6 +16,15 @@ @@ -14,6 +16,15 @@
14 16
15 const currentValue = ref<string | number>(123); 17 const currentValue = ref<string | number>(123);
16 18
  19 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
  20 +
  21 + const getThingModelTsl = computed(() => {
  22 + const { option } = props.config;
  23 +
  24 + const { deviceProfileId, attribute } = option;
  25 + return getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
  26 + });
  27 +
17 const getDesign = computed(() => { 28 const getDesign = computed(() => {
18 const { persetOption = {}, option } = props.config; 29 const { persetOption = {}, option } = props.config;
19 30
@@ -23,14 +34,14 @@ @@ -23,14 +34,14 @@
23 valueSize: persetValueSize, 34 valueSize: persetValueSize,
24 } = persetOption; 35 } = persetOption;
25 36
26 - const { componentInfo, attribute, attributeRename, attributeName } = option; 37 + const { componentInfo, attribute, attributeRename } = option;
27 38
28 const { fontColor, fontSize, valueSize } = componentInfo || {}; 39 const { fontColor, fontSize, valueSize } = componentInfo || {};
29 return { 40 return {
30 fontColor: fontColor || persetFontColor, 41 fontColor: fontColor || persetFontColor,
31 fontSize: fontSize || persetFontSize || 14, 42 fontSize: fontSize || persetFontSize || 14,
32 valueSize: valueSize || persetValueSize || 20, 43 valueSize: valueSize || persetValueSize || 20,
33 - attribute: attributeRename || attributeName || attribute, 44 + attribute: attributeRename || unref(getThingModelTsl)?.functionName || attribute,
34 }; 45 };
35 }); 46 });
36 47
@@ -39,7 +50,10 @@ @@ -39,7 +50,10 @@
39 const [latest] = data[attribute] || []; 50 const [latest] = data[attribute] || [];
40 if (!latest.length) return; 51 if (!latest.length) return;
41 const [_, value] = latest; 52 const [_, value] = latest;
42 - currentValue.value = value; 53 + currentValue.value = useThingsModelValueTransform(
  54 + value,
  55 + unref(getThingModelTsl)?.specs?.dataType
  56 + );
43 }; 57 };
44 58
45 useDataFetch(props, updateFn); 59 useDataFetch(props, updateFn);
@@ -52,7 +66,7 @@ @@ -52,7 +66,7 @@
52 <DeviceName :config="config" /> 66 <DeviceName :config="config" />
53 67
54 <h1 68 <h1
55 - class="my-4 font-bold !my-2 truncate" 69 + class="my-4 font-bold !my-2 truncate w-full text-center"
56 :style="{ 70 :style="{
57 color: getDesign.fontColor, 71 color: getDesign.fontColor,
58 fontSize: (getRatio ? getRatio * getDesign.valueSize : getDesign.valueSize) + 'px', 72 fontSize: (getRatio ? getRatio * getDesign.valueSize : getDesign.valueSize) + 'px',
@@ -63,10 +77,8 @@ @@ -63,10 +77,8 @@
63 <div 77 <div
64 class="text-gray-500 truncate" 78 class="text-gray-500 truncate"
65 :style="{ fontSize: (getRatio ? getRatio * getDesign.fontSize : getDesign.fontSize) + 'px' }" 79 :style="{ fontSize: (getRatio ? getRatio * getDesign.fontSize : getDesign.fontSize) + 'px' }"
66 - >{{ getDesign.attribute || '温度' }}</div  
67 > 80 >
68 - <!-- <div v-if="config.option.componentInfo.showDeviceName">  
69 - {{ config.option.deviceRename || config.option.deviceName }}  
70 - </div> --> 81 + {{ getDesign.attribute || '温度' }}
  82 + </div>
71 </main> 83 </main>
72 </template> 84 </template>
@@ -2,12 +2,14 @@ @@ -2,12 +2,14 @@
2 import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type'; 2 import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
3 import { option } from './config'; 3 import { option } from './config';
4 import { useComponentScale } from '/@/views/visual/packages/hook/useComponentScale'; 4 import { useComponentScale } from '/@/views/visual/packages/hook/useComponentScale';
5 - import { computed } from 'vue'; 5 + import { computed, unref } from 'vue';
6 import { ref } from 'vue'; 6 import { ref } from 'vue';
7 import { UpdateTime } from '/@/views/visual/commonComponents/UpdateTime'; 7 import { UpdateTime } from '/@/views/visual/commonComponents/UpdateTime';
8 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName'; 8 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
9 import { useDataFetch } from '../../../hook/socket/useSocket'; 9 import { useDataFetch } from '../../../hook/socket/useSocket';
10 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 10 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
  11 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
  12 + import { useThingsModelValueTransform } from '/@/views/visual/palette/hooks/useThingsModelValueTransform';
11 13
12 const props = defineProps<{ 14 const props = defineProps<{
13 config: ComponentPropsConfigType<typeof option>; 15 config: ComponentPropsConfigType<typeof option>;
@@ -16,6 +18,15 @@ @@ -16,6 +18,15 @@
16 const currentValue = ref<string | number>(123); 18 const currentValue = ref<string | number>(123);
17 const time = ref<Nullable<number>>(null); 19 const time = ref<Nullable<number>>(null);
18 20
  21 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
  22 +
  23 + const getThingModelTsl = computed(() => {
  24 + const { option } = props.config;
  25 +
  26 + const { deviceProfileId, attribute } = option;
  27 + return getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
  28 + });
  29 +
19 const getDesign = computed(() => { 30 const getDesign = computed(() => {
20 const { persetOption = {}, option } = props.config; 31 const { persetOption = {}, option } = props.config;
21 32
@@ -25,7 +36,7 @@ @@ -25,7 +36,7 @@
25 fontSize: persetFontSize, 36 fontSize: persetFontSize,
26 } = persetOption; 37 } = persetOption;
27 38
28 - const { componentInfo, attribute, attributeName, attributeRename } = option; 39 + const { componentInfo, attribute, attributeRename } = option;
29 40
30 const { fontColor, valueSize, fontSize } = componentInfo || {}; 41 const { fontColor, valueSize, fontSize } = componentInfo || {};
31 42
@@ -33,7 +44,7 @@ @@ -33,7 +44,7 @@
33 fontColor: fontColor || persetFontColor, 44 fontColor: fontColor || persetFontColor,
34 valueSize: valueSize || persetValueSize || 20, 45 valueSize: valueSize || persetValueSize || 20,
35 fontSize: fontSize || persetFontSize || 14, 46 fontSize: fontSize || persetFontSize || 14,
36 - attribute: attributeRename || attributeName || attribute, 47 + attribute: attributeRename || unref(getThingModelTsl)?.functionName || attribute,
37 }; 48 };
38 }); 49 });
39 50
@@ -42,7 +53,10 @@ @@ -42,7 +53,10 @@
42 const [info] = data[attribute] || []; 53 const [info] = data[attribute] || [];
43 if (!info.length) return; 54 if (!info.length) return;
44 const [timespan, value] = info; 55 const [timespan, value] = info;
45 - currentValue.value = value; 56 + currentValue.value = useThingsModelValueTransform(
  57 + value,
  58 + unref(getThingModelTsl)?.specs?.dataType
  59 + );
46 time.value = timespan; 60 time.value = timespan;
47 }; 61 };
48 62
@@ -54,9 +68,9 @@ @@ -54,9 +68,9 @@
54 <template> 68 <template>
55 <main class="w-full h-full flex flex-col justify-center items-center"> 69 <main class="w-full h-full flex flex-col justify-center items-center">
56 <DeviceName :config="config" /> 70 <DeviceName :config="config" />
57 - <div class="flex-1 flex justify-center items-center flex-col" :style="getScale"> 71 + <div class="flex-1 flex justify-center items-center flex-col w-full" :style="getScale">
58 <h1 72 <h1
59 - class="my-4 font-bold !my-2 truncate" 73 + class="my-4 font-bold !my-2 truncate w-full text-center"
60 :style="{ 74 :style="{
61 color: getDesign.fontColor, 75 color: getDesign.fontColor,
62 fontSize: (getRatio ? getRatio * getDesign.valueSize : getDesign.valueSize) + 'px', 76 fontSize: (getRatio ? getRatio * getDesign.valueSize : getDesign.valueSize) + 'px',
@@ -2,13 +2,15 @@ @@ -2,13 +2,15 @@
2 import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type'; 2 import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
3 import { option } from './config'; 3 import { option } from './config';
4 import { useComponentScale } from '/@/views/visual/packages/hook/useComponentScale'; 4 import { useComponentScale } from '/@/views/visual/packages/hook/useComponentScale';
5 - import { ref } from 'vue'; 5 + import { ref, unref } from 'vue';
6 import { UpdateTime } from '/@/views/visual/commonComponents/UpdateTime'; 6 import { UpdateTime } from '/@/views/visual/commonComponents/UpdateTime';
7 import { SvgIcon } from '/@/components/Icon'; 7 import { SvgIcon } from '/@/components/Icon';
8 import { computed } from 'vue'; 8 import { computed } from 'vue';
9 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName'; 9 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
10 import { useDataFetch } from '../../../hook/socket/useSocket'; 10 import { useDataFetch } from '../../../hook/socket/useSocket';
11 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 11 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
  12 + import { useThingsModelValueTransform } from '/@/views/visual/palette/hooks/useThingsModelValueTransform';
  13 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
12 14
13 const props = defineProps<{ 15 const props = defineProps<{
14 config: ComponentPropsConfigType<typeof option>; 16 config: ComponentPropsConfigType<typeof option>;
@@ -18,6 +20,15 @@ @@ -18,6 +20,15 @@
18 20
19 const time = ref<Nullable<number>>(null); 21 const time = ref<Nullable<number>>(null);
20 22
  23 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
  24 +
  25 + const getThingModelTsl = computed(() => {
  26 + const { option } = props.config;
  27 +
  28 + const { deviceProfileId, attribute } = option;
  29 + return getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
  30 + });
  31 +
21 const getDesign = computed(() => { 32 const getDesign = computed(() => {
22 const { persetOption = {}, option } = props.config; 33 const { persetOption = {}, option } = props.config;
23 34
@@ -49,7 +60,10 @@ @@ -49,7 +60,10 @@
49 const [latest] = data[attribute] || []; 60 const [latest] = data[attribute] || [];
50 if (!latest.length) return; 61 if (!latest.length) return;
51 const [timespan, value] = latest; 62 const [timespan, value] = latest;
52 - currentValue.value = value; 63 + currentValue.value = useThingsModelValueTransform(
  64 + value,
  65 + unref(getThingModelTsl)?.specs?.dataType
  66 + );
53 time.value = timespan; 67 time.value = timespan;
54 }; 68 };
55 69
@@ -61,7 +75,7 @@ @@ -61,7 +75,7 @@
61 <template> 75 <template>
62 <main :style="getScale" class="w-full h-full flex flex-col justify-center items-center"> 76 <main :style="getScale" class="w-full h-full flex flex-col justify-center items-center">
63 <DeviceName :config="config" /> 77 <DeviceName :config="config" />
64 - <div class="flex-1 flex justify-center items-center flex-col"> 78 + <div class="flex-1 flex justify-center items-center flex-col w-full">
65 <SvgIcon 79 <SvgIcon
66 :name="getDesign.icon!" 80 :name="getDesign.icon!"
67 prefix="iconfont" 81 prefix="iconfont"
@@ -69,7 +83,7 @@ @@ -69,7 +83,7 @@
69 :style="{ color: getDesign.iconColor }" 83 :style="{ color: getDesign.iconColor }"
70 /> 84 />
71 <h1 85 <h1
72 - class="font-bold m-2 truncate" 86 + class="font-bold m-2 truncate w-full text-center"
73 :style="{ 87 :style="{
74 color: getDesign.fontColor, 88 color: getDesign.fontColor,
75 fontSize: (getRatio ? getRatio * getDesign.valueSize : getDesign.valueSize) + 'px', 89 fontSize: (getRatio ? getRatio * getDesign.valueSize : getDesign.valueSize) + 'px',
@@ -2,12 +2,14 @@ @@ -2,12 +2,14 @@
2 import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type'; 2 import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type';
3 import { option } from './config'; 3 import { option } from './config';
4 import { useComponentScale } from '/@/views/visual/packages/hook/useComponentScale'; 4 import { useComponentScale } from '/@/views/visual/packages/hook/useComponentScale';
5 - import { computed } from 'vue'; 5 + import { computed, unref } from 'vue';
6 import { ref } from 'vue'; 6 import { ref } from 'vue';
7 import { SvgIcon } from '/@/components/Icon'; 7 import { SvgIcon } from '/@/components/Icon';
8 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName'; 8 import { DeviceName } from '/@/views/visual/commonComponents/DeviceName';
9 import { useDataFetch } from '../../../hook/socket/useSocket'; 9 import { useDataFetch } from '../../../hook/socket/useSocket';
10 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 10 import { DataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
  11 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
  12 + import { useThingsModelValueTransform } from '/@/views/visual/palette/hooks/useThingsModelValueTransform';
11 13
12 const props = defineProps<{ 14 const props = defineProps<{
13 config: ComponentPropsConfigType<typeof option>; 15 config: ComponentPropsConfigType<typeof option>;
@@ -15,6 +17,15 @@ @@ -15,6 +17,15 @@
15 17
16 const currentValue = ref<string | number>(123); 18 const currentValue = ref<string | number>(123);
17 19
  20 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
  21 +
  22 + const getThingModelTsl = computed(() => {
  23 + const { option } = props.config;
  24 +
  25 + const { deviceProfileId, attribute } = option;
  26 + return getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
  27 + });
  28 +
18 const getDesign = computed(() => { 29 const getDesign = computed(() => {
19 const { persetOption = {}, option } = props.config; 30 const { persetOption = {}, option } = props.config;
20 31
@@ -27,7 +38,7 @@ @@ -27,7 +38,7 @@
27 fontSize: persetFontSize, 38 fontSize: persetFontSize,
28 } = persetOption; 39 } = persetOption;
29 40
30 - const { componentInfo, attribute, attributeRename, attributeName } = option; 41 + const { componentInfo, attribute, attributeRename } = option;
31 42
32 const { icon, iconColor, fontColor, unit, valueSize, fontSize } = componentInfo || {}; 43 const { icon, iconColor, fontColor, unit, valueSize, fontSize } = componentInfo || {};
33 return { 44 return {
@@ -35,7 +46,7 @@ @@ -35,7 +46,7 @@
35 unit: unit ?? perseUnit, 46 unit: unit ?? perseUnit,
36 icon: icon || persetIcon, 47 icon: icon || persetIcon,
37 fontColor: fontColor || persetFontColor, 48 fontColor: fontColor || persetFontColor,
38 - attribute: attributeRename || attributeName || attribute, 49 + attribute: attributeRename || unref(getThingModelTsl)?.functionName || attribute,
39 valueSize: valueSize || persetValueSize || 20, 50 valueSize: valueSize || persetValueSize || 20,
40 fontSize: fontSize || persetFontSize || 14, 51 fontSize: fontSize || persetFontSize || 14,
41 }; 52 };
@@ -46,7 +57,10 @@ @@ -46,7 +57,10 @@
46 const [info] = data[attribute] || []; 57 const [info] = data[attribute] || [];
47 if (!info.length) return; 58 if (!info.length) return;
48 const [_, value] = info; 59 const [_, value] = info;
49 - currentValue.value = value; 60 + currentValue.value = useThingsModelValueTransform(
  61 + value,
  62 + unref(getThingModelTsl)?.specs?.dataType
  63 + );
50 }; 64 };
51 65
52 useDataFetch(props, updateFn); 66 useDataFetch(props, updateFn);
@@ -57,7 +71,7 @@ @@ -57,7 +71,7 @@
57 <template> 71 <template>
58 <main class="w-full h-full flex flex-col justify-center items-center"> 72 <main class="w-full h-full flex flex-col justify-center items-center">
59 <DeviceName :config="config" /> 73 <DeviceName :config="config" />
60 - <div :style="getScale" class="flex-1 flex justify-center items-center flex-col"> 74 + <div :style="getScale" class="flex-1 flex justify-center items-center flex-col w-full">
61 <SvgIcon 75 <SvgIcon
62 :name="getDesign.icon!" 76 :name="getDesign.icon!"
63 prefix="iconfont" 77 prefix="iconfont"
@@ -65,7 +79,7 @@ @@ -65,7 +79,7 @@
65 :style="{ color: getDesign.iconColor }" 79 :style="{ color: getDesign.iconColor }"
66 /> 80 />
67 <h1 81 <h1
68 - class="my-4 font-bold !my-2 truncate" 82 + class="my-4 font-bold !my-2 truncate w-full text-center"
69 :style="{ 83 :style="{
70 color: getDesign.fontColor, 84 color: getDesign.fontColor,
71 fontSize: (getRatio ? getRatio * getDesign.valueSize : getDesign.valueSize) + 'px', 85 fontSize: (getRatio ? getRatio * getDesign.valueSize : getDesign.valueSize) + 'px',
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 import { useMultipleDataFetch } from '../../../hook/socket/useSocket'; 10 import { useMultipleDataFetch } from '../../../hook/socket/useSocket';
11 import { MultipleDataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 11 import { MultipleDataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
12 import { useComponentScale } from '../../../hook/useComponentScale'; 12 import { useComponentScale } from '../../../hook/useComponentScale';
  13 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
13 14
14 const props = defineProps<{ 15 const props = defineProps<{
15 config: ComponentPropsConfigType<typeof option>; 16 config: ComponentPropsConfigType<typeof option>;
@@ -56,6 +57,8 @@ @@ -56,6 +57,8 @@
56 }, 57 },
57 ]; 58 ];
58 59
  60 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
  61 +
59 const getDesign = computed(() => { 62 const getDesign = computed(() => {
60 const { persetOption = {}, option } = props.config; 63 const { persetOption = {}, option } = props.config;
61 const { dataSource = [] } = option || {}; 64 const { dataSource = [] } = option || {};
@@ -71,15 +74,17 @@ @@ -71,15 +74,17 @@
71 dataSource: dataSource.map((item) => { 74 dataSource: dataSource.map((item) => {
72 const { unit, fontColor, backgroundColor, maxNumber, valueSize, fontSize } = 75 const { unit, fontColor, backgroundColor, maxNumber, valueSize, fontSize } =
73 item.componentInfo || {}; 76 item.componentInfo || {};
74 - const { attribute, attributeRename, deviceName, deviceRename, deviceId, attributeName } = 77 + const { attribute, attributeRename, deviceProfileId, deviceName, deviceRename, deviceId } =
75 item; 78 item;
  79 +
  80 + const tsl = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
76 return { 81 return {
77 unit: unit ?? presetUnit, 82 unit: unit ?? presetUnit,
78 fontColor: fontColor ?? presetFontColor, 83 fontColor: fontColor ?? presetFontColor,
79 backgroundColor: backgroundColor ?? persetBackgroundColor, 84 backgroundColor: backgroundColor ?? persetBackgroundColor,
80 deviceName: deviceRename || deviceName, 85 deviceName: deviceRename || deviceName,
81 attribute, 86 attribute,
82 - attributeName: attributeRename || attributeName, 87 + attributeName: attributeRename || tsl?.functionName,
83 maxNumber: maxNumber || persetMaxNumber, 88 maxNumber: maxNumber || persetMaxNumber,
84 id: deviceId, 89 id: deviceId,
85 valueSize: valueSize || persetValueSize || 20, 90 valueSize: valueSize || persetValueSize || 20,
@@ -10,6 +10,8 @@ @@ -10,6 +10,8 @@
10 import { useMultipleDataFetch } from '../../../hook/socket/useSocket'; 10 import { useMultipleDataFetch } from '../../../hook/socket/useSocket';
11 import { MultipleDataFetchUpdateFn } from '../../../hook/socket/useSocket.type'; 11 import { MultipleDataFetchUpdateFn } from '../../../hook/socket/useSocket.type';
12 import { useComponentScale } from '../../../hook/useComponentScale'; 12 import { useComponentScale } from '../../../hook/useComponentScale';
  13 + import { useDeviceProfileQueryContext } from '/@/views/visual/palette/hooks/useDeviceProfileQueryContext';
  14 + import { buildUUID } from '/@/utils/uuid';
13 15
14 const props = defineProps<{ 16 const props = defineProps<{
15 config: ComponentPropsConfigType<typeof option>; 17 config: ComponentPropsConfigType<typeof option>;
@@ -17,6 +19,8 @@ @@ -17,6 +19,8 @@
17 19
18 const time = ref<Nullable<number>>(null); 20 const time = ref<Nullable<number>>(null);
19 21
  22 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
  23 +
20 const getDesign = computed(() => { 24 const getDesign = computed(() => {
21 const { persetOption = {}, option } = props.config; 25 const { persetOption = {}, option } = props.config;
22 const { dataSource = [] } = option || {}; 26 const { dataSource = [] } = option || {};
@@ -28,12 +32,13 @@ @@ -28,12 +32,13 @@
28 valueSize: persetValueSize, 32 valueSize: persetValueSize,
29 fontSize: persetFontSize, 33 fontSize: persetFontSize,
30 } = persetOption || {}; 34 } = persetOption || {};
  35 +
31 return { 36 return {
32 dataSource: dataSource.map((item) => { 37 dataSource: dataSource.map((item) => {
33 const { fontColor, icon, iconColor, unit, valueSize, fontSize } = item.componentInfo; 38 const { fontColor, icon, iconColor, unit, valueSize, fontSize } = item.componentInfo;
34 - const { attribute, attributeRename, deviceName, deviceRename, deviceId, attributeName } = 39 + const { attribute, attributeRename, deviceName, deviceRename, deviceId, deviceProfileId } =
35 item; 40 item;
36 - 41 + const tsl = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
37 return { 42 return {
38 unit: unit ?? persetUnit, 43 unit: unit ?? persetUnit,
39 fontColor: fontColor ?? persetFontColor, 44 fontColor: fontColor ?? persetFontColor,
@@ -41,7 +46,7 @@ @@ -41,7 +46,7 @@
41 iconColor: iconColor ?? persetIconColor, 46 iconColor: iconColor ?? persetIconColor,
42 attribute, 47 attribute,
43 deviceName: deviceRename || deviceName, 48 deviceName: deviceRename || deviceName,
44 - attributeName: attributeRename || attributeName, 49 + attributeName: attributeRename || tsl?.functionName,
45 id: deviceId, 50 id: deviceId,
46 valueSize: valueSize || persetValueSize || 20, 51 valueSize: valueSize || persetValueSize || 20,
47 fontSize: fontSize || persetFontSize || 14, 52 fontSize: fontSize || persetFontSize || 14,
@@ -49,8 +54,10 @@ @@ -49,8 +54,10 @@
49 }), 54 }),
50 }; 55 };
51 }); 56 });
52 - const defaultSvgList = ref<any>([ 57 +
  58 + const defaultSvgList = ref([
53 { 59 {
  60 + id: buildUUID(),
54 value: 26.2, 61 value: 26.2,
55 deviceName: '温湿度', 62 deviceName: '温湿度',
56 attributeName: '温度', 63 attributeName: '温度',
@@ -58,8 +65,11 @@ @@ -58,8 +65,11 @@
58 unit: '℃', 65 unit: '℃',
59 iconColor: '#367BFF', 66 iconColor: '#367BFF',
60 fontColor: '#357CFB', 67 fontColor: '#357CFB',
  68 + fontSize: 16,
  69 + valueSize: 16,
61 }, 70 },
62 { 71 {
  72 + id: buildUUID(),
63 value: 53.7, 73 value: 53.7,
64 deviceName: '温湿度', 74 deviceName: '温湿度',
65 attributeName: '湿度', 75 attributeName: '湿度',
@@ -67,6 +77,8 @@ @@ -67,6 +77,8 @@
67 unit: '℃', 77 unit: '℃',
68 iconColor: '#FFA000', 78 iconColor: '#FFA000',
69 fontColor: '#FFA000', 79 fontColor: '#FFA000',
  80 + fontSize: 16,
  81 + valueSize: 16,
70 }, 82 },
71 ]); 83 ]);
72 84
@@ -108,7 +120,6 @@ @@ -108,7 +120,6 @@
108 :size="getRatio ? 30 * getRatio : 30" 120 :size="getRatio ? 30 * getRatio : 30"
109 :style="{ color: item.iconColor }" 121 :style="{ color: item.iconColor }"
110 /> 122 />
111 -  
112 <div 123 <div
113 class="text-gray-500 ml-6" 124 class="text-gray-500 ml-6"
114 :style="{ fontSize: (getRatio ? getRatio * item.fontSize : item.fontSize) + 'px' }" 125 :style="{ fontSize: (getRatio ? getRatio * item.fontSize : item.fontSize) + 'px' }"
@@ -122,10 +133,9 @@ @@ -122,10 +133,9 @@
122 fontSize: (getRatio ? getRatio * item.valueSize : item.valueSize) + 'px', 133 fontSize: (getRatio ? getRatio * item.valueSize : item.valueSize) + 'px',
123 }" 134 }"
124 > 135 >
125 - <span> {{ item.value || 0 }}</span> 136 + <span> {{ (item as any).value || 0 }}</span>
126 <span>{{ item.unit }} </span> 137 <span>{{ item.unit }} </span>
127 </span> 138 </span>
128 </div> 139 </div>
129 - <!-- <UpdateTime :time="time" /> -->  
130 </main> 140 </main>
131 </template> 141 </template>
  1 +export enum CategoryEnum {
  2 + MAP = 'MAP',
  3 +}
@@ -3,21 +3,25 @@ import { useSelectWidgetKeys, useSelectWidgetMode } from '../../dataSourceBindPa @@ -3,21 +3,25 @@ import { useSelectWidgetKeys, useSelectWidgetMode } from '../../dataSourceBindPa
3 import { PackagesCategoryEnum } from '../index.type'; 3 import { PackagesCategoryEnum } from '../index.type';
4 import { getDeviceProfile } from '/@/api/alarm/position'; 4 import { getDeviceProfile } from '/@/api/alarm/position';
5 import { getDeviceAttributes, getMeetTheConditionsDevice } from '/@/api/dataBoard'; 5 import { getDeviceAttributes, getMeetTheConditionsDevice } from '/@/api/dataBoard';
6 -import { DeviceAttributeParams, MasterDeviceList } from '/@/api/dataBoard/model';  
7 -import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';  
8 -import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; 6 +import { DeviceAttributeParams } from '/@/api/dataBoard/model';
9 import { getModelServices } from '/@/api/device/modelOfMatter'; 7 import { getModelServices } from '/@/api/device/modelOfMatter';
10 import { findDictItemByCode } from '/@/api/system/dict'; 8 import { findDictItemByCode } from '/@/api/system/dict';
11 -import { FormSchema, useComponentRegister } from '/@/components/Form'; 9 +import { ApiCascader, FormSchema, useComponentRegister } from '/@/components/Form';
12 import { OrgTreeSelect } from '/@/views/common/OrgTreeSelect'; 10 import { OrgTreeSelect } from '/@/views/common/OrgTreeSelect';
13 import { DataActionModeEnum } from '/@/enums/toolEnum'; 11 import { DataActionModeEnum } from '/@/enums/toolEnum';
14 import { TaskTypeEnum } from '/@/views/task/center/config'; 12 import { TaskTypeEnum } from '/@/views/task/center/config';
15 import { createPickerSearch } from '/@/utils/pickerSearch'; 13 import { createPickerSearch } from '/@/utils/pickerSearch';
16 import { DataTypeEnum } from '/@/enums/objectModelEnum'; 14 import { DataTypeEnum } from '/@/enums/objectModelEnum';
17 -import { CommandTypeEnum } from '/@/enums/deviceEnum'; 15 +import { CommandTypeEnum, CommandTypeNameEnum } from '/@/enums/deviceEnum';
18 import { TransportTypeEnum } from '/@/enums/deviceEnum'; 16 import { TransportTypeEnum } from '/@/enums/deviceEnum';
  17 +import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
  18 +import { ControlComponentEnum } from '../components/Control';
  19 +import { isNullOrUnDef } from '/@/utils/is';
  20 +import { validateTCPCustomCommand } from '/@/components/Form/src/components/ThingsModelForm';
  21 +import { CategoryEnum } from '../components';
19 22
20 useComponentRegister('OrgTreeSelect', OrgTreeSelect); 23 useComponentRegister('OrgTreeSelect', OrgTreeSelect);
  24 +useComponentRegister('ApiCascader', ApiCascader);
21 25
22 export interface CommonDataSourceBindValueType extends Record<DataSourceField, string> { 26 export interface CommonDataSourceBindValueType extends Record<DataSourceField, string> {
23 customCommand?: { 27 customCommand?: {
@@ -31,30 +35,51 @@ export interface CommonDataSourceBindValueType extends Record<DataSourceField, s @@ -31,30 +35,51 @@ export interface CommonDataSourceBindValueType extends Record<DataSourceField, s
31 } 35 }
32 36
33 export enum DataSourceField { 37 export enum DataSourceField {
34 - IS_GATEWAY_DEVICE = 'gatewayDevice', 38 + // IS_GATEWAY_DEVICE = 'gatewayDevice',
35 DEVICE_TYPE = 'deviceType', 39 DEVICE_TYPE = 'deviceType',
36 TRANSPORT_TYPE = 'transportType', 40 TRANSPORT_TYPE = 'transportType',
37 ORIGINATION_ID = 'organizationId', 41 ORIGINATION_ID = 'organizationId',
38 DEVICE_ID = 'deviceId', 42 DEVICE_ID = 'deviceId',
39 - DEVICE_CODE = 'deviceCode', //设备地址码 43 + // DEVICE_CODE = 'deviceCode', //设备地址码
40 DEVICE_PROFILE_ID = 'deviceProfileId', 44 DEVICE_PROFILE_ID = 'deviceProfileId',
41 ATTRIBUTE = 'attribute', 45 ATTRIBUTE = 'attribute',
42 - ATTRIBUTE_NAME = 'attributeName', 46 + // ATTRIBUTE_NAME = 'attributeName',
43 ATTRIBUTE_RENAME = 'attributeRename', 47 ATTRIBUTE_RENAME = 'attributeRename',
44 DEVICE_NAME = 'deviceName', 48 DEVICE_NAME = 'deviceName',
45 DEVICE_RENAME = 'deviceRename', 49 DEVICE_RENAME = 'deviceRename',
46 - LONGITUDE_ATTRIBUTE = 'longitudeAttribute',  
47 - LATITUDE_ATTRIBUTE = 'latitudeAttribute', 50 +
48 CODE_TYPE = 'codeType', 51 CODE_TYPE = 'codeType',
49 - COMMAND = 'command', 52 + // COMMAND = 'command',
  53 +
50 OPEN_COMMAND = 'openCommand', 54 OPEN_COMMAND = 'openCommand',
51 CLOSE_COMMAND = 'closeCommand', 55 CLOSE_COMMAND = 'closeCommand',
  56 +
52 COMMAND_TYPE = 'commandType', 57 COMMAND_TYPE = 'commandType',
53 - SERVICE = 'service', 58 +
  59 + // SERVICE = 'service',
  60 +
  61 + /**
  62 + * @description 关服务标识符
  63 + */
54 OPEN_SERVICE = 'openService', 64 OPEN_SERVICE = 'openService',
  65 +
  66 + /**
  67 + * @description 开服务标识符
  68 + */
55 CLOSE_SERVICE = 'closeService', 69 CLOSE_SERVICE = 'closeService',
56 - EXTENSION_DESC = 'extensionDesc',  
57 - CALL_TYPE = 'callType', 70 +
  71 + /**
  72 + * @description 经度标识符
  73 + */
  74 + LONGITUDE_IDENTIFIER = 'longitudeIdentifier',
  75 +
  76 + /**
  77 + * @description 纬度标识符号
  78 + */
  79 + LATITUDE_IDENTIFIER = 'latitudeIdentifier',
  80 +
  81 + // EXTENSION_DESC = 'extensionDesc',
  82 + // CALL_TYPE = 'callType',
58 } 83 }
59 84
60 const isTcpProfile = (transportType: string) => transportType === TransportTypeEnum.TCP; 85 const isTcpProfile = (transportType: string) => transportType === TransportTypeEnum.TCP;
@@ -69,15 +94,6 @@ const isBooleanComponent = (componentKeys: { categoryKey?: string; componentKey? @@ -69,15 +94,6 @@ const isBooleanComponent = (componentKeys: { categoryKey?: string; componentKey?
69 ); 94 );
70 }; 95 };
71 96
72 -const getDeviceService = async (deviceProfileId: string) => {  
73 - try {  
74 - const data = await getModelServices({ deviceProfileId });  
75 - if (data)  
76 - return data.map((item) => ({ ...item, label: item.functionName, value: item.identifier }));  
77 - } catch (error) {}  
78 - return [];  
79 -};  
80 -  
81 const getDeviceAttribute = async (params: DeviceAttributeParams) => { 97 const getDeviceAttribute = async (params: DeviceAttributeParams) => {
82 try { 98 try {
83 const data = await getDeviceAttributes(params); 99 const data = await getDeviceAttributes(params);
@@ -94,24 +110,6 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -94,24 +110,6 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
94 110
95 return [ 111 return [
96 { 112 {
97 - field: DataSourceField.IS_GATEWAY_DEVICE,  
98 - component: 'Switch',  
99 - label: '是否是网关设备',  
100 - show: false,  
101 - },  
102 - {  
103 - field: DataSourceField.DEVICE_NAME,  
104 - component: 'Input',  
105 - label: '设备名',  
106 - show: false,  
107 - },  
108 - {  
109 - field: DataSourceField.TRANSPORT_TYPE,  
110 - component: 'Input',  
111 - label: '设备配置类型',  
112 - show: false,  
113 - },  
114 - {  
115 field: DataSourceField.DEVICE_TYPE, 113 field: DataSourceField.DEVICE_TYPE,
116 component: 'ApiSelect', 114 component: 'ApiSelect',
117 label: '设备类型', 115 label: '设备类型',
@@ -127,13 +125,11 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -127,13 +125,11 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
127 valueField: 'itemValue', 125 valueField: 'itemValue',
128 labelField: 'itemText', 126 labelField: 'itemText',
129 placeholder: '请选择设备类型', 127 placeholder: '请选择设备类型',
130 - onChange: (value: DeviceTypeEnum) => { 128 + onChange: () => {
131 setFieldsValue({ 129 setFieldsValue({
132 - [DataSourceField.IS_GATEWAY_DEVICE]: value === DeviceTypeEnum.GATEWAY,  
133 [DataSourceField.DEVICE_PROFILE_ID]: null, 130 [DataSourceField.DEVICE_PROFILE_ID]: null,
134 [DataSourceField.DEVICE_ID]: null, 131 [DataSourceField.DEVICE_ID]: null,
135 [DataSourceField.ATTRIBUTE]: null, 132 [DataSourceField.ATTRIBUTE]: null,
136 - [DataSourceField.ATTRIBUTE_NAME]: null,  
137 [DataSourceField.TRANSPORT_TYPE]: null, 133 [DataSourceField.TRANSPORT_TYPE]: null,
138 }); 134 });
139 }, 135 },
@@ -142,6 +138,12 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -142,6 +138,12 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
142 }, 138 },
143 }, 139 },
144 { 140 {
  141 + field: DataSourceField.TRANSPORT_TYPE,
  142 + label: '传输协议',
  143 + component: 'Input',
  144 + ifShow: false,
  145 + },
  146 + {
145 field: DataSourceField.DEVICE_PROFILE_ID, 147 field: DataSourceField.DEVICE_PROFILE_ID,
146 component: 'ApiSelect', 148 component: 'ApiSelect',
147 label: '产品', 149 label: '产品',
@@ -164,12 +166,11 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -164,12 +166,11 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
164 labelField: 'name', 166 labelField: 'name',
165 valueField: 'id', 167 valueField: 'id',
166 placeholder: '请选择产品', 168 placeholder: '请选择产品',
167 - onChange: (_, option = {} as Record<'transportType', string>) => { 169 + onChange: (_, option: Record<'transportType', string>) => {
168 setFieldsValue({ 170 setFieldsValue({
169 [DataSourceField.DEVICE_ID]: null, 171 [DataSourceField.DEVICE_ID]: null,
170 [DataSourceField.ATTRIBUTE]: null, 172 [DataSourceField.ATTRIBUTE]: null,
171 - [DataSourceField.ATTRIBUTE_NAME]: null,  
172 - [DataSourceField.TRANSPORT_TYPE]: option[DataSourceField.TRANSPORT_TYPE], 173 + [DataSourceField.TRANSPORT_TYPE]: option?.[DataSourceField.TRANSPORT_TYPE],
173 [DataSourceField.COMMAND_TYPE]: null, 174 [DataSourceField.COMMAND_TYPE]: null,
174 }); 175 });
175 }, 176 },
@@ -201,10 +202,10 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -201,10 +202,10 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
201 }, 202 },
202 }, 203 },
203 { 204 {
204 - field: DataSourceField.DEVICE_PROFILE_ID, 205 + field: DataSourceField.DEVICE_NAME,
205 component: 'Input', 206 component: 'Input',
206 - label: '',  
207 - show: false, 207 + label: '设备名称',
  208 + ifShow: false,
208 }, 209 },
209 { 210 {
210 field: DataSourceField.DEVICE_ID, 211 field: DataSourceField.DEVICE_ID,
@@ -238,12 +239,11 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -238,12 +239,11 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
238 } 239 }
239 return []; 240 return [];
240 }, 241 },
241 - onChange(_value, record: MasterDeviceList) { 242 + onChange(_value, options: Record<'label' | 'codeType', string>) {
242 setFieldsValue({ 243 setFieldsValue({
243 - [DataSourceField.DEVICE_NAME]: record?.label,  
244 - [DataSourceField.CODE_TYPE]: record?.codeType,  
245 - [DataSourceField.DEVICE_CODE]: record?.code,  
246 [DataSourceField.COMMAND_TYPE]: null, 244 [DataSourceField.COMMAND_TYPE]: null,
  245 + [DataSourceField.DEVICE_NAME]: options?.label,
  246 + [DataSourceField.CODE_TYPE]: options?.codeType,
247 }); 247 });
248 }, 248 },
249 placeholder: '请选择设备', 249 placeholder: '请选择设备',
@@ -253,91 +253,9 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -253,91 +253,9 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
253 }, 253 },
254 { 254 {
255 field: DataSourceField.CODE_TYPE, 255 field: DataSourceField.CODE_TYPE,
  256 + label: '设备标识符类型',
256 component: 'Input', 257 component: 'Input',
257 - label: '设备标识符',  
258 - show: false,  
259 - },  
260 -  
261 - {  
262 - field: DataSourceField.DEVICE_CODE,  
263 - component: 'Input',  
264 - show: false,  
265 - label: '设备地址码',  
266 - },  
267 -  
268 - {  
269 - field: DataSourceField.ATTRIBUTE_NAME,  
270 - component: 'Input',  
271 - label: '属性名',  
272 - show: false,  
273 - },  
274 - {  
275 - field: DataSourceField.COMMAND_TYPE,  
276 - component: 'ApiSelect',  
277 - label: '命令类型',  
278 - defaultValue: CommandTypeEnum.CUSTOM.toString(),  
279 - rules: [{ required: true, message: '请选择命令类型' }],  
280 - colProps: { span: 8 },  
281 - ifShow: ({ model }) => {  
282 - return isControlComponent(category!) && isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]);  
283 - },  
284 - componentProps: ({ formActionType, formModel }) => {  
285 - const { setFieldsValue } = formActionType;  
286 - const { codeType, deviceType, transportType } = formModel || {};  
287 - return {  
288 - // api: findDictItemByCode,  
289 - api: async (params: Recordable) => {  
290 - try {  
291 - const record = await findDictItemByCode(params);  
292 - if (unref(selectWidgetKeys).componentKey == 'LateralNumericalControl') {  
293 - return record.filter(  
294 - (item) => item.itemValue == CommandTypeEnum.ATTRIBUTE.toString()  
295 - );  
296 - }  
297 - // TCP网关子 --> 不能要服务命令类型  
298 - if (deviceType == 'SENSOR' && transportType == 'TCP') {  
299 - return codeType == 'MODBUS_RTU'  
300 - ? record.filter((item) => item.itemValue == CommandTypeEnum.ATTRIBUTE.toString())  
301 - : codeType == 'CUSTOM'  
302 - ? record.filter((item) => item.itemValue == CommandTypeEnum.CUSTOM.toString())  
303 - : [];  
304 - }  
305 -  
306 - if (codeType == TaskTypeEnum.MODBUS_RTU) {  
307 - // setFieldsValue({ [DataSourceField.COMMAND_TYPE]: undefined });  
308 - return record.filter(  
309 - (item) => item.itemValue !== CommandTypeEnum.CUSTOM.toString()  
310 - );  
311 - } else {  
312 - return record.filter(  
313 - (item) => item.itemValue !== CommandTypeEnum.ATTRIBUTE.toString()  
314 - );  
315 - }  
316 - } catch (error) {  
317 - return [];  
318 - }  
319 - },  
320 - params: {  
321 - dictCode: 'custom_define',  
322 - },  
323 - labelField: 'itemText',  
324 - valueField: 'itemValue',  
325 - placeholder: '请选择命令类型',  
326 - getPopupContainer: () => document.body,  
327 - onChange() {  
328 - setFieldsValue({  
329 - [DataSourceField.COMMAND]: null,  
330 - [DataSourceField.SERVICE]: null,  
331 - [DataSourceField.OPEN_COMMAND]: null,  
332 - [DataSourceField.CLOSE_COMMAND]: null,  
333 - [DataSourceField.OPEN_SERVICE]: null,  
334 - [DataSourceField.CLOSE_SERVICE]: null,  
335 - [DataSourceField.CALL_TYPE]: null,  
336 - [DataSourceField.ATTRIBUTE]: null,  
337 - });  
338 - },  
339 - };  
340 - }, 258 + ifShow: false,
341 }, 259 },
342 { 260 {
343 field: DataSourceField.ATTRIBUTE, 261 field: DataSourceField.ATTRIBUTE,
@@ -345,9 +263,7 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -345,9 +263,7 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
345 label: '属性', 263 label: '属性',
346 colProps: { span: 8 }, 264 colProps: { span: 8 },
347 rules: [{ required: true, message: '请选择属性' }], 265 rules: [{ required: true, message: '请选择属性' }],
348 - ifShow: ({ model }) =>  
349 - !(isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]) && isControlComponent(category!)) ||  
350 - model[DataSourceField.COMMAND_TYPE] == 2, 266 + ifShow: () => category !== CategoryEnum.MAP,
351 componentProps({ formModel, formActionType }) { 267 componentProps({ formModel, formActionType }) {
352 const { setFieldsValue } = formActionType; 268 const { setFieldsValue } = formActionType;
353 const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; 269 const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID];
@@ -359,20 +275,25 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -359,20 +275,25 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
359 deviceProfileId, 275 deviceProfileId,
360 dataType: 276 dataType:
361 (isControlComponent(category!) && 277 (isControlComponent(category!) &&
362 - unref(selectWidgetKeys).componentKey !== 'LateralNumericalControl') || 278 + unref(selectWidgetKeys).componentKey !==
  279 + ControlComponentEnum.LATERAL_NUMERICAL_CONTROL) ||
363 isBooleanComponent(unref(selectWidgetKeys)) 280 isBooleanComponent(unref(selectWidgetKeys))
364 ? DataTypeEnum.BOOL 281 ? DataTypeEnum.BOOL
365 : undefined, 282 : undefined,
366 }); 283 });
367 284
368 // 选择控制组件4的时候只能选择属性且是(int double类型) 285 // 选择控制组件4的时候只能选择属性且是(int double类型)
369 - if (unref(selectWidgetKeys).componentKey == 'LateralNumericalControl') { 286 + if (
  287 + unref(selectWidgetKeys).componentKey ===
  288 + ControlComponentEnum.LATERAL_NUMERICAL_CONTROL
  289 + ) {
370 setFieldsValue({ 290 setFieldsValue({
371 [DataSourceField.COMMAND_TYPE]: CommandTypeEnum.ATTRIBUTE.toString(), 291 [DataSourceField.COMMAND_TYPE]: CommandTypeEnum.ATTRIBUTE.toString(),
372 }); 292 });
373 return option.filter( 293 return option.filter(
374 (item) => 294 (item) =>
375 - item.detail.dataType.type == 'INT' || item.detail.dataType.type == 'DOUBLE' 295 + item.detail.dataType.type === DataTypeEnum.NUMBER_INT ||
  296 + item.detail.dataType.type == DataTypeEnum.NUMBER_DOUBLE
376 ); 297 );
377 } 298 }
378 return option; 299 return option;
@@ -381,76 +302,133 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -381,76 +302,133 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
381 return []; 302 return [];
382 }, 303 },
383 placeholder: '请选择属性', 304 placeholder: '请选择属性',
384 - onChange(value: string, option: Record<'label' | 'value' | any, string>) {  
385 - const { detail }: any = option || {};  
386 - setFieldsValue({  
387 - [DataSourceField.ATTRIBUTE_NAME]: value ? option.label : null,  
388 - [DataSourceField.EXTENSION_DESC]: value ? JSON.stringify(option.extensionDesc) : '',  
389 - // 地图组件结构体  
390 - lal:  
391 - category === 'MAP' && value && detail?.dataType.type === 'STRUCT'  
392 - ? JSON.stringify(detail?.dataType.specs)  
393 - : null,  
394 - latitude: null,  
395 - longitude: null,  
396 - });  
397 - },  
398 ...createPickerSearch(), 305 ...createPickerSearch(),
399 }; 306 };
400 }, 307 },
401 }, 308 },
402 { 309 {
403 - field: 'lal',  
404 - label: '经纬度存储的值',  
405 - component: 'Input',  
406 - show: false,  
407 - },  
408 - {  
409 - field: 'longitude', 310 + field: DataSourceField.LONGITUDE_IDENTIFIER,
410 label: '经度', 311 label: '经度',
  312 + component: 'ApiCascader',
  313 + ifShow: ({}) => category === CategoryEnum.MAP,
411 colProps: { span: 8 }, 314 colProps: { span: 8 },
412 - component: 'Select',  
413 - required: true,  
414 - ifShow: ({ model }) => category === 'MAP' && model.lal,  
415 - componentProps({ formModel }) {  
416 - const { lal } = formModel || {}; 315 + changeEvent: 'update:value',
  316 + valueField: 'value',
  317 + componentProps: ({ formModel }) => {
  318 + const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID];
417 return { 319 return {
  320 + api: async () => {
  321 + try {
  322 + if (deviceProfileId) {
  323 + const options = await getDeviceAttributes({
  324 + deviceProfileId,
  325 + });
  326 +
  327 + const _options = options.map((item) => {
  328 + item = Object.assign(item, { functionName: item.name });
  329 + if (item.detail.dataType.type === DataTypeEnum.STRUCT) {
  330 + return Object.assign(item, { specs: item.detail.dataType.specs });
  331 + }
  332 + return item;
  333 + });
  334 + return _options;
  335 + }
  336 + } catch (error) {}
  337 + return [];
  338 + },
418 placeholder: '请选择经度', 339 placeholder: '请选择经度',
419 - options: lal  
420 - ? JSON.parse(lal)?.map((item) => ({ label: item.functionName, value: item.identifier }))  
421 - : [], 340 + getPopupContainer: () => document.body,
  341 + fieldNames: { label: 'functionName', value: 'identifier', children: 'specs' },
422 }; 342 };
423 }, 343 },
424 }, 344 },
425 { 345 {
426 - field: 'latitude', 346 + field: DataSourceField.LATITUDE_IDENTIFIER,
427 label: '纬度', 347 label: '纬度',
  348 + component: 'ApiCascader',
  349 + ifShow: ({}) => category === CategoryEnum.MAP,
428 colProps: { span: 8 }, 350 colProps: { span: 8 },
429 - required: true,  
430 - component: 'Select',  
431 - ifShow: ({ model }) => category === 'MAP' && model.lal,  
432 - componentProps({ formModel }) {  
433 - const { lal } = formModel || {}; 351 + changeEvent: 'update:value',
  352 + valueField: 'value',
  353 + componentProps: ({ formModel }) => {
  354 + const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID];
  355 +
434 return { 356 return {
  357 + api: async () => {
  358 + try {
  359 + if (deviceProfileId) {
  360 + const options = await getDeviceAttributes({
  361 + deviceProfileId,
  362 + });
  363 +
  364 + const _options = options.map((item) => {
  365 + item = Object.assign(item, { functionName: item.name });
  366 +
  367 + if (item.detail.dataType.type === DataTypeEnum.STRUCT) {
  368 + return Object.assign(item, { specs: item.detail.dataType.specs });
  369 + }
  370 + return item;
  371 + });
  372 +
  373 + return _options;
  374 + }
  375 + } catch (error) {}
  376 + return [];
  377 + },
435 placeholder: '请选择纬度', 378 placeholder: '请选择纬度',
436 - options: lal  
437 - ? JSON.parse(lal)?.map((item) => ({ label: item.functionName, value: item.identifier }))  
438 - : [], 379 + getPopupContainer: () => document.body,
  380 + fieldNames: { label: 'functionName', value: 'identifier', children: 'specs' },
439 }; 381 };
440 }, 382 },
441 }, 383 },
442 { 384 {
443 - field: DataSourceField.EXTENSION_DESC,  
444 - component: 'Input',  
445 - show: false,  
446 - label: '扩展描述符',  
447 - }, 385 + field: DataSourceField.COMMAND_TYPE,
  386 + component: 'Select',
  387 + label: '命令类型',
  388 + defaultValue: CommandTypeEnum.CUSTOM,
  389 + rules: [
  390 + {
  391 + required: true,
  392 + validator(_, value: number | string) {
  393 + if (isNullOrUnDef(value)) return Promise.reject('请选择命令类型');
  394 + return Promise.resolve();
  395 + },
  396 + },
  397 + ],
  398 + colProps: { span: 8 },
  399 + ifShow: ({ model }) => {
  400 + return (
  401 + isControlComponent(category!) &&
  402 + unref(selectWidgetKeys).componentKey !== ControlComponentEnum.LATERAL_NUMERICAL_CONTROL &&
  403 + isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]) &&
  404 + model[DataSourceField.CODE_TYPE] === TaskTypeEnum.CUSTOM
  405 + );
  406 + },
  407 + componentProps: ({ formActionType, formModel }) => {
  408 + const { setFieldsValue } = formActionType;
  409 + const deviceType = formModel[DataSourceField.DEVICE_TYPE];
  410 + const options: Record<'label' | 'value', string | number>[] = [
  411 + { label: CommandTypeNameEnum.CUSTOM, value: CommandTypeEnum.CUSTOM },
  412 + ];
448 413
449 - {  
450 - field: DataSourceField.CALL_TYPE,  
451 - component: 'Input',  
452 - ifShow: false,  
453 - label: 'callType', 414 + // 网关子设备无服务
  415 + if (deviceType !== DeviceTypeEnum.SENSOR)
  416 + options.push({ label: CommandTypeNameEnum.SERVICE, value: CommandTypeEnum.SERVICE });
  417 +
  418 + return {
  419 + options,
  420 + placeholder: '请选择命令类型',
  421 + getPopupContainer: () => document.body,
  422 + onChange() {
  423 + setFieldsValue({
  424 + [DataSourceField.OPEN_COMMAND]: null,
  425 + [DataSourceField.CLOSE_COMMAND]: null,
  426 + [DataSourceField.OPEN_SERVICE]: null,
  427 + [DataSourceField.CLOSE_SERVICE]: null,
  428 + });
  429 + },
  430 + };
  431 + },
454 }, 432 },
455 { 433 {
456 field: DataSourceField.OPEN_SERVICE, 434 field: DataSourceField.OPEN_SERVICE,
@@ -460,40 +438,19 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -460,40 +438,19 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
460 rules: [{ required: true, message: '请选择开服务' }], 438 rules: [{ required: true, message: '请选择开服务' }],
461 ifShow: ({ model }) => 439 ifShow: ({ model }) =>
462 isControlComponent(category!) && 440 isControlComponent(category!) &&
463 - model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.SERVICE.toString() && 441 + model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.SERVICE &&
464 isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]), 442 isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]),
465 - componentProps({ formModel, formActionType }) {  
466 - const { setFieldsValue } = formActionType; 443 + componentProps({ formModel }) {
467 const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; 444 const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID];
468 - const transportType = formModel[DataSourceField.TRANSPORT_TYPE];  
469 - if (isUpdate && ![deviceProfileId, transportType].every(Boolean))  
470 - return { placeholder: '请选择开服务', getPopupContainer: () => document.body };  
471 return { 445 return {
472 - api: async () => {  
473 - try {  
474 - if (deviceProfileId) {  
475 - const services = await getDeviceService(deviceProfileId);  
476 - const value = formModel[DataSourceField.SERVICE];  
477 - if (value) {  
478 - const selected = services.find((item) => item.value === value);  
479 - selected && setFieldsValue({ [DataSourceField.CALL_TYPE]: selected.callType });  
480 - }  
481 - return services;  
482 - }  
483 - } catch (error) {}  
484 - return []; 446 + api: getModelServices,
  447 + params: {
  448 + deviceProfileId,
485 }, 449 },
486 placeholder: '请选择开服务', 450 placeholder: '请选择开服务',
  451 + labelField: 'functionName',
  452 + valueField: 'identifier',
487 getPopupContainer: () => document.body, 453 getPopupContainer: () => document.body,
488 - onChange(value: string, options: ModelOfMatterParams) {  
489 - const command = value  
490 - ? (options.functionJson.inputData || [])[0]?.serviceCommand  
491 - : null;  
492 - setFieldsValue({  
493 - [DataSourceField.OPEN_COMMAND]: command,  
494 - [DataSourceField.CALL_TYPE]: value ? options.callType : null,  
495 - });  
496 - },  
497 }; 454 };
498 }, 455 },
499 }, 456 },
@@ -505,40 +462,19 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -505,40 +462,19 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
505 rules: [{ required: true, message: '请选择关服务' }], 462 rules: [{ required: true, message: '请选择关服务' }],
506 ifShow: ({ model }) => 463 ifShow: ({ model }) =>
507 isControlComponent(category!) && 464 isControlComponent(category!) &&
508 - model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.SERVICE.toString() && 465 + model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.SERVICE &&
509 isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]), 466 isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]),
510 - componentProps({ formModel, formActionType }) {  
511 - const { setFieldsValue } = formActionType; 467 + componentProps({ formModel }) {
512 const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID]; 468 const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID];
513 - const transportType = formModel[DataSourceField.TRANSPORT_TYPE];  
514 - if (isUpdate && ![deviceProfileId, transportType].every(Boolean))  
515 - return { placeholder: '请选择关服务', getPopupContainer: () => document.body };  
516 return { 469 return {
517 - api: async () => {  
518 - try {  
519 - if (deviceProfileId) {  
520 - const services = await getDeviceService(deviceProfileId);  
521 - const value = formModel[DataSourceField.SERVICE];  
522 - if (value) {  
523 - const selected = services.find((item) => item.value === value);  
524 - selected && setFieldsValue({ [DataSourceField.CALL_TYPE]: selected.callType });  
525 - }  
526 - return services;  
527 - }  
528 - } catch (error) {}  
529 - return []; 470 + api: getModelServices,
  471 + params: {
  472 + deviceProfileId,
530 }, 473 },
531 placeholder: '请选择关服务', 474 placeholder: '请选择关服务',
  475 + labelField: 'functionName',
  476 + valueField: 'identifier',
532 getPopupContainer: () => document.body, 477 getPopupContainer: () => document.body,
533 - onChange(value: string, options: ModelOfMatterParams) {  
534 - const command = value  
535 - ? (options.functionJson.inputData || [])[0]?.serviceCommand  
536 - : null;  
537 - setFieldsValue({  
538 - [DataSourceField.CLOSE_COMMAND]: command,  
539 - [DataSourceField.CALL_TYPE]: value ? options.callType : null,  
540 - });  
541 - },  
542 }; 478 };
543 }, 479 },
544 }, 480 },
@@ -547,11 +483,11 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -547,11 +483,11 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
547 component: 'Input', 483 component: 'Input',
548 label: '命令', 484 label: '命令',
549 colProps: { span: 8 }, 485 colProps: { span: 8 },
550 - rules: [{ required: true, message: '请输入开下发命令' }], 486 + rules: [{ validator: validateTCPCustomCommand }],
551 // 是控制组件 && 自定义命令 && 传输协议为TCP 487 // 是控制组件 && 自定义命令 && 传输协议为TCP
552 ifShow: ({ model }) => 488 ifShow: ({ model }) =>
553 isControlComponent(category!) && 489 isControlComponent(category!) &&
554 - model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.CUSTOM.toString() && 490 + model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.CUSTOM &&
555 model[DataSourceField.TRANSPORT_TYPE] && 491 model[DataSourceField.TRANSPORT_TYPE] &&
556 isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]), 492 isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]),
557 componentProps: { 493 componentProps: {
@@ -563,11 +499,11 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -563,11 +499,11 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
563 component: 'Input', 499 component: 'Input',
564 label: '命令', 500 label: '命令',
565 colProps: { span: 8 }, 501 colProps: { span: 8 },
566 - rules: [{ required: true, message: '请输入关下发命令' }], 502 + rules: [{ validator: validateTCPCustomCommand }],
567 // 是控制组件 && 自定义命令 && 传输协议为TCP 503 // 是控制组件 && 自定义命令 && 传输协议为TCP
568 ifShow: ({ model }) => 504 ifShow: ({ model }) =>
569 isControlComponent(category!) && 505 isControlComponent(category!) &&
570 - model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.CUSTOM.toString() && 506 + model[DataSourceField.COMMAND_TYPE] === CommandTypeEnum.CUSTOM &&
571 model[DataSourceField.TRANSPORT_TYPE] && 507 model[DataSourceField.TRANSPORT_TYPE] &&
572 isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]), 508 isTcpProfile(model[DataSourceField.TRANSPORT_TYPE]),
573 componentProps: { 509 componentProps: {
@@ -24,6 +24,7 @@ import { @@ -24,6 +24,7 @@ import {
24 } from './useSocket.type'; 24 } from './useSocket.type';
25 import { ComponentPropsConfigType } from '../../index.type'; 25 import { ComponentPropsConfigType } from '../../index.type';
26 import { isNullOrUnDef } from '/@/utils/is'; 26 import { isNullOrUnDef } from '/@/utils/is';
  27 +import { CategoryEnum } from '../../components';
27 28
28 interface DeviceGroupMapType { 29 interface DeviceGroupMapType {
29 subscriptionId: number; 30 subscriptionId: number;
@@ -410,8 +411,20 @@ export const useMultipleDataFetch = ( @@ -410,8 +411,20 @@ export const useMultipleDataFetch = (
410 Object.keys(unref(getDataSourceGroup)).forEach((key) => { 411 Object.keys(unref(getDataSourceGroup)).forEach((key) => {
411 const item = unref(getDataSourceGroup)[key]; 412 const item = unref(getDataSourceGroup)[key];
412 const attributes = [...new Set(item.map((item) => item.attribute))]; 413 const attributes = [...new Set(item.map((item) => item.attribute))];
  414 +
  415 + if (props.config.componentConfig.category === CategoryEnum.MAP) {
  416 + const positionIdentifier = item.reduce((prev, next) => {
  417 + const [lat] = next.latitudeIdentifier || [];
  418 + const [lng] = next.longitudeIdentifier || [];
  419 +
  420 + return [...prev, lat, lng];
  421 + }, []);
  422 +
  423 + attributes.push(...new Set(positionIdentifier));
  424 + }
  425 +
413 subscriber.trackUpdateGroup(key, { 426 subscriber.trackUpdateGroup(key, {
414 - attributes, 427 + attributes: attributes.filter(Boolean),
415 fn: updateFn, 428 fn: updateFn,
416 }); 429 });
417 }); 430 });
  1 +import { ref } from 'vue';
  2 +import { getDeviceDetail } from '/@/api/device/deviceManager';
  3 +import { useDeviceProfileQueryContext } from '../../palette/hooks/useDeviceProfileQueryContext';
  4 +import {
  5 + CommandTypeEnum,
  6 + RPCCommandMethodEnum,
  7 + ServiceCallTypeEnum,
  8 + TransportTypeEnum,
  9 +} from '/@/enums/deviceEnum';
  10 +import { RpcCommandType } from '/@/api/device/model/deviceConfigModel';
  11 +import { useMessage } from '/@/hooks/web/useMessage';
  12 +import { useGetModbusCommand } from './useGetModbusCommand';
  13 +import { TaskTypeEnum } from '/@/views/task/center/config';
  14 +import { DataTypeEnum } from '/@/enums/objectModelEnum';
  15 +import { sendCommandOneway, sendCommandTwoway } from '/@/api/dataBoard';
  16 +import { isNullOrUnDef } from '/@/utils/is';
  17 +
  18 +export interface DoCommandDeliverDataSourceType {
  19 + deviceId: string;
  20 + deviceProfileId: string;
  21 + attribute: string;
  22 + commandType?: CommandTypeEnum;
  23 + openCommand?: string;
  24 + closeCommand?: string;
  25 + openService?: string;
  26 + closeService?: string;
  27 +}
  28 +
  29 +export function useCommandDelivery() {
  30 + const loading = ref(false);
  31 +
  32 + const { createMessage } = useMessage();
  33 +
  34 + const { getDeviceProfileTslByIdWithIdentifier } = useDeviceProfileQueryContext();
  35 +
  36 + const doGetDeviceId = async (deviceId: string) => {
  37 + return await getDeviceDetail(deviceId);
  38 + };
  39 +
  40 + const { validateCanGetCommand, getModbusCommand } = useGetModbusCommand();
  41 +
  42 + const doCommandDeliver = async (
  43 + dataSource: DoCommandDeliverDataSourceType,
  44 + value: any
  45 + ): Promise<boolean> => {
  46 + try {
  47 + const { deviceId, deviceProfileId, attribute, commandType } = dataSource;
  48 +
  49 + loading.value = true;
  50 + const tsl = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute);
  51 + const deviceDetail = await doGetDeviceId(deviceId);
  52 +
  53 + let sendCommandFn = sendCommandOneway;
  54 +
  55 + let params: string | Recordable | undefined = {
  56 + [attribute]: value,
  57 + };
  58 +
  59 + if (deviceDetail.transportType === TransportTypeEnum.TCP) {
  60 + if (deviceDetail.codeType === TaskTypeEnum.MODBUS_RTU) {
  61 + if (!validateCanGetCommand(tsl?.extensionDesc, deviceDetail.code)) return false;
  62 + params = await getModbusCommand(value, tsl!.extensionDesc, deviceDetail.code!);
  63 + } else if (deviceDetail.codeType === TaskTypeEnum.CUSTOM) {
  64 + params = value;
  65 + if (commandType === CommandTypeEnum.CUSTOM) {
  66 + if (tsl?.specs?.dataType.type === DataTypeEnum.BOOL) {
  67 + const { openCommand, closeCommand } = dataSource;
  68 + params = !!Number(value) ? openCommand : closeCommand;
  69 + }
  70 + } else if (commandType === CommandTypeEnum.SERVICE) {
  71 + if (tsl?.specs?.dataType.type === DataTypeEnum.BOOL) {
  72 + const { openService, closeService } = dataSource;
  73 + const serviceIdentifier = !!Number(value) ? openService : closeService;
  74 + const serviceTsl = getDeviceProfileTslByIdWithIdentifier?.(
  75 + deviceProfileId,
  76 + serviceIdentifier!
  77 + );
  78 + params = serviceTsl?.inputData?.[0].serviceCommand;
  79 + sendCommandFn =
  80 + serviceTsl?.callType === ServiceCallTypeEnum.SYNC
  81 + ? sendCommandTwoway
  82 + : sendCommandOneway;
  83 + }
  84 + }
  85 + }
  86 + }
  87 +
  88 + if (isNullOrUnDef(params)) return false;
  89 +
  90 + const rpcCommand: RpcCommandType = {
  91 + additionalInfo: {
  92 + cmdType: CommandTypeEnum.API,
  93 + },
  94 + params,
  95 + method: RPCCommandMethodEnum.THINGSKIT,
  96 + persistent: true,
  97 + };
  98 +
  99 + await sendCommandFn({ deviceId: deviceId, value: rpcCommand });
  100 +
  101 + createMessage.success('命令下发成功');
  102 +
  103 + return true;
  104 + } catch (e) {
  105 + return false;
  106 + } finally {
  107 + loading.value = false;
  108 + }
  109 + };
  110 +
  111 + return {
  112 + loading,
  113 + doCommandDeliver,
  114 + };
  115 +}
  1 +import { ExtensionDesc } from '/@/api/device/model/modelOfMatterModel';
  2 +import { genModbusCommand } from '/@/api/task';
  3 +import { GenModbusCommandType } from '/@/api/task/model';
  4 +import { ModbusCRCEnum, RegisterActionTypeEnum } from '/@/enums/objectModelEnum';
  5 +import { useMessage } from '/@/hooks/web/useMessage';
  6 +
  7 +export const InsertString = (t: any, c: any, n: any) => {
  8 + const r: string | number[] = [];
  9 +
  10 + for (let i = 0; i * 2 < t.length; i++) r.push(t.substr(i * 2, n));
  11 +
  12 + return r.join(c);
  13 +};
  14 +
  15 +export const FillString = (t: any, c: any, n: any, b: any) => {
  16 + if (t === '' || c.length !== 1 || n <= t.length) return t;
  17 +
  18 + const l = t.length;
  19 +
  20 + for (let i = 0; i < n - l; i++) {
  21 + if (b === true) t = c + t;
  22 + else t += c;
  23 + }
  24 + return t;
  25 +};
  26 +
  27 +export const SingleToHex = (t: any) => {
  28 + if (t === '') return '';
  29 +
  30 + t = parseFloat(t);
  31 +
  32 + if (isNaN(t) === true) return 'Error';
  33 +
  34 + if (t === 0) return '00000000';
  35 +
  36 + let s, e, m;
  37 +
  38 + if (t > 0) {
  39 + s = 0;
  40 + } else {
  41 + s = 1;
  42 +
  43 + t = 0 - t;
  44 + }
  45 + m = t.toString(2);
  46 +
  47 + if (m >= 1) {
  48 + if (m.indexOf('.') === -1) m = `${m}.0`;
  49 +
  50 + e = m.indexOf('.') - 1;
  51 + } else {
  52 + e = 1 - m.indexOf('1');
  53 + }
  54 + if (e >= 0) m = m.replace('.', '');
  55 + else m = m.substring(m.indexOf('1'));
  56 +
  57 + if (m.length > 24) m = m.substr(0, 24);
  58 + else m = FillString(m, '0', 24, false);
  59 +
  60 + m = m.substring(1);
  61 +
  62 + e = (e + 127).toString(2);
  63 +
  64 + e = FillString(e, '0', 8, true);
  65 +
  66 + let r = parseInt(s + e + m, 2).toString(16);
  67 +
  68 + r = FillString(r, '0', 8, true);
  69 +
  70 + return InsertString(r, ' ', 2).toUpperCase();
  71 +};
  72 +
  73 +export const FormatHex = (t: any, n: any, ie: any) => {
  74 + const r: string[] = [];
  75 +
  76 + let s = '';
  77 +
  78 + let c = 0;
  79 +
  80 + for (let i = 0; i < t.length; i++) {
  81 + if (t.charAt(i) !== ' ') {
  82 + s += t.charAt(i);
  83 +
  84 + c += 1;
  85 +
  86 + if (c === n) {
  87 + r.push(s);
  88 +
  89 + s = '';
  90 +
  91 + c = 0;
  92 + }
  93 + }
  94 + if (ie === false) {
  95 + if (i === t.length - 1 && s !== '') r.push(s);
  96 + }
  97 + }
  98 + return r.join('\n');
  99 +};
  100 +
  101 +export const FormatHexBatch = (t: any, n: any, ie: any) => {
  102 + const a = t.split('\n');
  103 +
  104 + const r: string[] = [];
  105 +
  106 + for (let i = 0; i < a.length; i++) r[i] = FormatHex(a[i], n, ie);
  107 +
  108 + return r.join('\n');
  109 +};
  110 +
  111 +export const SingleToHexBatch = (t: any) => {
  112 + const a = t.split('\n');
  113 +
  114 + const r: string[] = [];
  115 +
  116 + for (let i = 0; i < a.length; i++) r[i] = SingleToHex(a[i]);
  117 +
  118 + return r.join('\r\n');
  119 +};
  120 +
  121 +const getArray = (values: any) => {
  122 + const str = values.replace(/\s+/g, '');
  123 + const array: any = [];
  124 +
  125 + for (let i = 0; i < str.length; i += 4) {
  126 + const chunk = parseInt(str.substring(i, i + 4), 16);
  127 + array.push(chunk);
  128 + }
  129 + return array;
  130 +};
  131 +
  132 +const getFloatPart = (number: string | number) => {
  133 + const isLessZero = Number(number) < 0;
  134 + number = number.toString();
  135 + const floatPartStartIndex = number.indexOf('.');
  136 + const value = ~floatPartStartIndex
  137 + ? `${isLessZero ? '-' : ''}0.${number.substring(floatPartStartIndex + 1)}`
  138 + : '0';
  139 + return Number(value);
  140 +};
  141 +
  142 +const REGISTER_MAX_VALUE = Number(0xffff);
  143 +
  144 +export function useGetModbusCommand() {
  145 + const { createMessage } = useMessage();
  146 +
  147 + const getModbusCommand = async (
  148 + value: number,
  149 + extensionDesc: ExtensionDesc,
  150 + deviceAddressCode: string
  151 + ) => {
  152 + const { registerAddress, actionType, zoomFactor } = extensionDesc as Required<ExtensionDesc>;
  153 +
  154 + const params: GenModbusCommandType = {
  155 + crc: ModbusCRCEnum.CRC_16_LOWER,
  156 + registerNumber: 1,
  157 + deviceCode: deviceAddressCode,
  158 + registerAddress,
  159 + method: actionType,
  160 + registerValues: [value],
  161 + };
  162 +
  163 + if (actionType === RegisterActionTypeEnum.INT) {
  164 + const newValue = Math.trunc(value) * zoomFactor + getFloatPart(value) * zoomFactor;
  165 +
  166 + if (newValue % 1 !== 0) {
  167 + createMessage.warning(`属性下发类型必须是整数,缩放因子为${zoomFactor}`);
  168 + return;
  169 + }
  170 +
  171 + if (value * zoomFactor > REGISTER_MAX_VALUE) {
  172 + createMessage.warning(`属性下发值不能超过${REGISTER_MAX_VALUE},缩放因子为${zoomFactor}`);
  173 + return;
  174 + }
  175 +
  176 + params.registerValues = [newValue];
  177 + } else if (actionType === RegisterActionTypeEnum.DOUBLE) {
  178 + const regex = /^-?\d+(\.\d{0,2})?$/;
  179 + const values = Math.trunc(value) * zoomFactor + getFloatPart(value) * zoomFactor;
  180 +
  181 + if (!regex.test(values.toString())) {
  182 + createMessage.warning(`属性下发值精确到两位小数,缩放因子为${zoomFactor}`);
  183 + return;
  184 + }
  185 +
  186 + const newValue = values === 0 ? [0, 0] : getArray(SingleToHex(values));
  187 + params.registerValues = newValue;
  188 + params.registerNumber = 2;
  189 + params.method = '10';
  190 + }
  191 +
  192 + return await genModbusCommand(params);
  193 + };
  194 +
  195 + /**
  196 + *
  197 + * @param extensionDesc 物模型拓展描述符
  198 + * @param deviceAddressCode 设备地址码
  199 + */
  200 + const validateCanGetCommand = (
  201 + extensionDesc?: ExtensionDesc,
  202 + deviceAddressCode?: string,
  203 + createValidateMessage = true
  204 + ) => {
  205 + const result = { flag: true, message: '' };
  206 + if (!extensionDesc) {
  207 + result.flag = false;
  208 + result.message = '当前物模型扩展描述没有填写';
  209 + }
  210 +
  211 + if (!deviceAddressCode) {
  212 + result.flag = false;
  213 + result.message = '当前设备未绑定设备地址码';
  214 + }
  215 +
  216 + if (result.message && createValidateMessage) createMessage.warning(result.message);
  217 +
  218 + return result;
  219 + };
  220 +
  221 + return {
  222 + getModbusCommand,
  223 + validateCanGetCommand,
  224 + };
  225 +}
1 -import { ref } from 'vue';  
2 -import { DataSource } from '../../palette/types';  
3 -import { sendCommandOneway, sendCommandTwoway } from '/@/api/dataBoard';  
4 -import { useMessage } from '/@/hooks/web/useMessage';  
5 -import { TransportTypeEnum, ServiceCallTypeEnum } from '/@/enums/deviceEnum';  
6 -  
7 -const { createMessage } = useMessage();  
8 -export function useSendCommand() {  
9 - const loading = ref(false);  
10 -  
11 - const error = () => {  
12 - // createMessage.error('下发指令失败');  
13 - return false;  
14 - };  
15 -  
16 - const sendCommand = async (record: DataSource, value: any, isModbusCommand = false) => {  
17 - if (!record) return false;  
18 - const { customCommand, attribute } = record || {};  
19 - const { deviceId } = record;  
20 - if (!deviceId) return false;  
21 -  
22 - try {  
23 - loading.value = true;  
24 - let params: string | Recordable = {  
25 - [attribute!]: Number(value),  
26 - };  
27 - if (isModbusCommand) {  
28 - params = value;  
29 - }  
30 -  
31 - let sendCommandFn = sendCommandOneway;  
32 - // 如果是TCP设备从物模型中获取下发命令(TCP网关子设备无物模型服务与事件)  
33 - if (customCommand?.transportType === TransportTypeEnum.TCP && !isModbusCommand) {  
34 - params = customCommand.command!;  
35 - if (customCommand.callType === ServiceCallTypeEnum.SYNC) {  
36 - sendCommandFn = sendCommandTwoway;  
37 - }  
38 - }  
39 - // 控制按钮下发命令为0 或 1  
40 - await sendCommandFn({  
41 - deviceId,  
42 - value: {  
43 - params: params || null,  
44 - persistent: true,  
45 - additionalInfo: {  
46 - cmdType: customCommand.commandType || 'API',  
47 - },  
48 - method: 'methodThingskit',  
49 - },  
50 - });  
51 - createMessage.success('命令下发成功');  
52 - return true;  
53 - } catch (msg) {  
54 - console.error(msg);  
55 - return error();  
56 - } finally {  
57 - loading.value = false;  
58 - }  
59 - };  
60 - return {  
61 - loading,  
62 - sendCommand,  
63 - };  
64 -}  
@@ -9,7 +9,7 @@ export const useApp = () => { @@ -9,7 +9,7 @@ export const useApp = () => {
9 9
10 const isPhone = () => { 10 const isPhone = () => {
11 const values = location?.pathname.split('/') || []; 11 const values = location?.pathname.split('/') || [];
12 - return values[values?.length - 2] === 'phone' ? true : false; 12 + return values[values?.length - 2] === 'phone';
13 }; 13 };
14 14
15 return { getIsAppPage, isPhone }; 15 return { getIsAppPage, isPhone };
@@ -11,6 +11,8 @@ import { @@ -11,6 +11,8 @@ import {
11 } from '../types'; 11 } from '../types';
12 import { buildUUID } from '/@/utils/uuid'; 12 import { buildUUID } from '/@/utils/uuid';
13 import { PublicComponentOptions } from '../../packages/index.type'; 13 import { PublicComponentOptions } from '../../packages/index.type';
  14 +import { batchGetObjectModel } from '/@/api/device/modelOfMatter';
  15 +import { BatchGetObjectModelItemType } from '/@/api/device/model/modelOfMatterModel';
14 16
15 export interface WidgetDataType extends Layout, ComponentDataType, PublicComponentOptions {} 17 export interface WidgetDataType extends Layout, ComponentDataType, PublicComponentOptions {}
16 18
@@ -23,6 +25,17 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => { @@ -23,6 +25,17 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => {
23 25
24 const dataSource = ref<WidgetDataType[]>([]); 26 const dataSource = ref<WidgetDataType[]>([]);
25 27
  28 + const deviceProfilesMapRef = ref<Map<string, BatchGetObjectModelItemType>>();
  29 +
  30 + const getAllDeviceProfileIdsByDataSource = computed(() => {
  31 + const result = unref(rawDataSource)?.componentData?.reduce((prev, next) => {
  32 + const ids = next.dataSource.map((temp) => temp.deviceProfileId);
  33 + return [...prev, ...ids];
  34 + }, []);
  35 +
  36 + return [...new Set(result)];
  37 + });
  38 +
26 const getSharePageData = computed(() => { 39 const getSharePageData = computed(() => {
27 return unref(propsRef).value!; 40 return unref(propsRef).value!;
28 }); 41 });
@@ -64,19 +77,8 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => { @@ -64,19 +77,8 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => {
64 loading.value = true; 77 loading.value = true;
65 const { data } = await getDataBoradDetail(); 78 const { data } = await getDataBoradDetail();
66 rawDataSource.value = data; 79 rawDataSource.value = data;
67 - // const result: WidgetDataType[] = (data.componentData || []).map((item) => {  
68 - // const { id } = item;  
69 -  
70 - // const layout =  
71 - // (data.componentLayout || []).find((item) => item.id === id) ||  
72 - // ({} as ComponentLayoutType);  
73 -  
74 - // return {  
75 - // i: buildUUID(),  
76 - // ...layout,  
77 - // ...item,  
78 - // } as WidgetDataType;  
79 - // }); 80 + await getAllDeviceProfiles();
  81 +
80 const result: WidgetDataType[] = data.componentLayout.map((item) => { 82 const result: WidgetDataType[] = data.componentLayout.map((item) => {
81 const { id } = item; 83 const { id } = item;
82 const dataSource = 84 const dataSource =
@@ -129,8 +131,35 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => { @@ -129,8 +131,35 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => {
129 } catch (error) {} 131 } catch (error) {}
130 }; 132 };
131 133
132 - onMounted(() => {  
133 - getDataSource(); 134 + const getAllDeviceProfiles = async () => {
  135 + if (!unref(getAllDeviceProfileIdsByDataSource).length) return;
  136 + const result = await batchGetObjectModel({
  137 + deviceProfileIds: unref(getAllDeviceProfileIdsByDataSource),
  138 + });
  139 +
  140 + const map = new Map();
  141 +
  142 + result.forEach((item) => {
  143 + map.set(item.id, item);
  144 + });
  145 +
  146 + deviceProfilesMapRef.value = map;
  147 + };
  148 +
  149 + function getDeviceProfileDetailById(id: string) {
  150 + return unref(deviceProfilesMapRef)?.get(id);
  151 + }
  152 +
  153 + function getDeviceProfileTslByIdWithIdentifier(id: string, identifier: string) {
  154 + const detail = getDeviceProfileDetailById(id);
  155 + if (!detail) return;
  156 + for (const item of detail.tsl) {
  157 + if (item.identifier === identifier) return item;
  158 + }
  159 + }
  160 +
  161 + onMounted(async () => {
  162 + await getDataSource();
134 }); 163 });
135 164
136 return { 165 return {
@@ -138,8 +167,11 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => { @@ -138,8 +167,11 @@ export const useDataSource = (propsRef: ComputedRef<Recordable>) => {
138 draggable: !unref(getIsSharePage) && !unref(getIsAppPage), 167 draggable: !unref(getIsSharePage) && !unref(getIsAppPage),
139 resizable: !unref(getIsSharePage) && !unref(getIsAppPage), 168 resizable: !unref(getIsSharePage) && !unref(getIsAppPage),
140 dataSource, 169 dataSource,
  170 + deviceProfilesMapRef,
141 rawDataSource, 171 rawDataSource,
142 getDataSource, 172 getDataSource,
143 setLayoutInfo, 173 setLayoutInfo,
  174 + getDeviceProfileDetailById,
  175 + getDeviceProfileTslByIdWithIdentifier,
144 }; 176 };
145 }; 177 };
  1 +import { inject, provide } from 'vue';
  2 +import { BatchGetObjectModelItemType, Tsl } from '/@/api/device/model/modelOfMatterModel';
  3 +
  4 +const SymbolKey = Symbol('data-board');
  5 +
  6 +export interface ContextOptionsType {
  7 + getDeviceProfileDetailById: (id: string) => BatchGetObjectModelItemType | undefined;
  8 + getDeviceProfileTslByIdWithIdentifier: (id: string, identifier?: string) => Tsl | undefined;
  9 +}
  10 +
  11 +export const createDeviceProfileQueryContext = (options: ContextOptionsType) => {
  12 + provide(SymbolKey, options);
  13 +};
  14 +
  15 +export const useDeviceProfileQueryContext = () => {
  16 + return inject<ContextOptionsType>(SymbolKey) || ({} as Partial<ContextOptionsType>);
  17 +};
  1 +import { DataType, Specs, StructJSON } from '/@/api/device/model/modelOfMatterModel';
  2 +import { DataTypeEnum } from '/@/enums/objectModelEnum';
  3 +import { useJsonParse } from '/@/hooks/business/useJsonParse';
  4 +function getBoolTypeValue(value: number, Specs: Specs) {
  5 + const { boolOpen, boolClose } = Specs;
  6 +
  7 + return Number(value) ? boolOpen : boolClose;
  8 +}
  9 +
  10 +function getEnumTypeValue(value: number, specsList: Specs[]) {
  11 + const res = specsList.find((item) => item.value === Number(value));
  12 +
  13 + return res?.name;
  14 +}
  15 +
  16 +function getStructTypeValue(value: string, specs: StructJSON[]): string {
  17 + const res = useJsonParse(value).value;
  18 +
  19 + function generateStruct(specs: StructJSON[], value: Recordable) {
  20 + if (!value) return {};
  21 +
  22 + return specs.reduce((prev, next) => {
  23 + return {
  24 + ...prev,
  25 + [next.functionName!]: getValueByType(
  26 + next.dataType!.type,
  27 + value[next.identifier],
  28 + next.dataType!
  29 + ),
  30 + };
  31 + }, {});
  32 + }
  33 +
  34 + return JSON.stringify(generateStruct(specs, res));
  35 +}
  36 +
  37 +function getValueByType(type: string, value: any, dataType: DataType) {
  38 + switch (type) {
  39 + case DataTypeEnum.BOOL:
  40 + return getBoolTypeValue(value, dataType.specs as Specs);
  41 + case DataTypeEnum.STRUCT:
  42 + return getStructTypeValue(value, dataType.specs as StructJSON[]);
  43 + case DataTypeEnum.ENUM:
  44 + return getEnumTypeValue(value, dataType.specsList as Specs[]);
  45 + default:
  46 + return value;
  47 + }
  48 +}
  49 +export function useThingsModelValueTransform(value: any, thingsModelDataType?: DataType) {
  50 + if (!thingsModelDataType) return value;
  51 +
  52 + const { type } = thingsModelDataType;
  53 + return getValueByType(type, value, thingsModelDataType);
  54 +}
@@ -40,6 +40,7 @@ @@ -40,6 +40,7 @@
40 import SIGNALSVG from '/@/assets/svg/signal.svg'; 40 import SIGNALSVG from '/@/assets/svg/signal.svg';
41 import BATTERYSVG from '/@/assets/svg/battery.svg'; 41 import BATTERYSVG from '/@/assets/svg/battery.svg';
42 import { useRoute } from 'vue-router'; 42 import { useRoute } from 'vue-router';
  43 + import { createDeviceProfileQueryContext } from './hooks/useDeviceProfileQueryContext';
43 44
44 const props = defineProps<{ 45 const props = defineProps<{
45 value?: Recordable; 46 value?: Recordable;
@@ -53,8 +54,17 @@ @@ -53,8 +54,17 @@
53 54
54 const ROUTE = useRoute(); 55 const ROUTE = useRoute();
55 56
56 - const { loading, draggable, resizable, dataSource, rawDataSource, setLayoutInfo, getDataSource } =  
57 - useDataSource(getProps); 57 + const {
  58 + loading,
  59 + draggable,
  60 + resizable,
  61 + dataSource,
  62 + rawDataSource,
  63 + setLayoutInfo,
  64 + getDataSource,
  65 + getDeviceProfileDetailById,
  66 + getDeviceProfileTslByIdWithIdentifier,
  67 + } = useDataSource(getProps);
58 68
59 const { resize, resized, moved, containerResized } = useDragGridLayout(dataSource, setLayoutInfo); 69 const { resize, resized, moved, containerResized } = useDragGridLayout(dataSource, setLayoutInfo);
60 70
@@ -157,6 +167,11 @@ @@ -157,6 +167,11 @@
157 167
158 createDataBoardContext({ send, close }); 168 createDataBoardContext({ send, close });
159 169
  170 + createDeviceProfileQueryContext({
  171 + getDeviceProfileDetailById,
  172 + getDeviceProfileTslByIdWithIdentifier,
  173 + });
  174 +
160 const { getDarkMode } = useRootSetting(); 175 const { getDarkMode } = useRootSetting();
161 watch( 176 watch(
162 getIsSharePage, 177 getIsSharePage,
1 import { PublicComponentOptions } from '../../packages/index.type'; 1 import { PublicComponentOptions } from '../../packages/index.type';
  2 +import { CommandTypeEnum } from '/@/enums/deviceEnum';
2 3
3 export interface ComponentDataType<T = ExtraDataSource> { 4 export interface ComponentDataType<T = ExtraDataSource> {
4 id: string; 5 id: string;
@@ -19,19 +20,26 @@ export interface DataSource { @@ -19,19 +20,26 @@ export interface DataSource {
19 deviceId: string; 20 deviceId: string;
20 deviceType: string; 21 deviceType: string;
21 attribute: string; 22 attribute: string;
22 - attributeName: string;  
23 - deviceName: string;  
24 - gatewayDevice: boolean;  
25 - slaveDeviceId: string; 23 + commandType?: CommandTypeEnum;
  24 + openCommand?: string;
  25 + closeCommand?: string;
  26 + openService?: string;
  27 + closeService?: string;
  28 + // attributeName: string;
  29 + // deviceName: string;
  30 + // gatewayDevice: boolean;
  31 + // slaveDeviceId: string;
26 deviceRename: string; 32 deviceRename: string;
27 attributeRename: string; 33 attributeRename: string;
28 componentInfo: ComponentInfo; 34 componentInfo: ComponentInfo;
29 - customCommand: CustomCommand;  
30 videoConfig?: VideoConfigType; 35 videoConfig?: VideoConfigType;
31 [key: string]: any; 36 [key: string]: any;
32 - lal?: string;  
33 - latitude?: string | number;  
34 - longitude?: string | number; 37 +
  38 + latitudeIdentifier?: string[];
  39 + longitudeIdentifier?: string[];
  40 + // lal?: string;
  41 + // latitude?: string | number;
  42 + // longitude?: string | number;
35 } 43 }
36 44
37 export interface ExtraDataSource extends DataSource, PublicComponentOptions { 45 export interface ExtraDataSource extends DataSource, PublicComponentOptions {