Commit 7cdf8ee02fb2f456f2c4ba9d52fe3e03965fe746

Authored by ww
1 parent 9b283601

feat: implement TextComponent && DigitalDashboardComponent echo real data

@@ -14,12 +14,14 @@ VITE_PUBLIC_PATH = / @@ -14,12 +14,14 @@ VITE_PUBLIC_PATH = /
14 # VITE_PROXY = [["/api","http://101.133.234.90:8080/api"]] 14 # VITE_PROXY = [["/api","http://101.133.234.90:8080/api"]]
15 # 线上测试环境 15 # 线上测试环境
16 # VITE_PROXY = [["/api","http://localhost:8080/api"],["/thingskit-drawio","http://localhost:3000/"]] 16 # VITE_PROXY = [["/api","http://localhost:8080/api"],["/thingskit-drawio","http://localhost:3000/"]]
17 -VITE_PROXY = [["/api","https://dev.thingskit.com/api"],["/thingskit-drawio","http://localhost:3000/"]] 17 +# VITE_PROXY = [["/api","https://dev.thingskit.com/api"],["/thingskit-drawio","http://localhost:3000/"]]
  18 +VITE_PROXY = [["/api","http://121.37.251.8:8080/api"],["/thingskit-drawio","http://localhost:3000/"]]
18 # VITE_PROXY = [["/api","http://192.168.10.106:8080/api"],["/thingskit-drawio","http://192.168.10.106:8080/api"]] 19 # VITE_PROXY = [["/api","http://192.168.10.106:8080/api"],["/thingskit-drawio","http://192.168.10.106:8080/api"]]
19 20
20 # 实时数据的ws地址 21 # 实时数据的ws地址
21 # VITE_WEB_SOCKET = ws://localhost:8080/api/ws/plugins/telemetry?token= 22 # VITE_WEB_SOCKET = ws://localhost:8080/api/ws/plugins/telemetry?token=
22 -VITE_WEB_SOCKET = ws://44.99.141.212:8080/api/ws/plugins/telemetry?token= 23 +# VITE_WEB_SOCKET = ws://44.99.141.212:8080/api/ws/plugins/telemetry?token=
  24 +VITE_WEB_SOCKET = ws://121.37.251.8:8080/api/ws/plugins/telemetry?token=
23 25
24 # Delete console 26 # Delete console
25 VITE_DROP_CONSOLE = true 27 VITE_DROP_CONSOLE = true
@@ -37,5 +39,5 @@ VITE_GLOB_API_URL_PREFIX=/yt @@ -37,5 +39,5 @@ VITE_GLOB_API_URL_PREFIX=/yt
37 VITE_GLOB_CONFIGURATION = /thingskit-drawio 39 VITE_GLOB_CONFIGURATION = /thingskit-drawio
38 40
39 # Content Security Policy 41 # Content Security Policy
40 -VITE_CONTENT_SECURITY_POLICY = true 42 +VITE_CONTENT_SECURITY_POLICY = false
41 43
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 ], 6 ],
7 "commentTranslate.targetLanguage": "en", 7 "commentTranslate.targetLanguage": "en",
8 "cSpell.words": [ 8 "cSpell.words": [
  9 + "Cmds",
9 "unref" 10 "unref"
10 ] 11 ]
11 } 12 }
@@ -62,6 +62,8 @@ export interface ComponentInfo { @@ -62,6 +62,8 @@ export interface ComponentInfo {
62 gradientInfo: GradientInfo[]; 62 gradientInfo: GradientInfo[];
63 iconColor: string; 63 iconColor: string;
64 icon: string; 64 icon: string;
  65 + value?: string | number;
  66 + updateTime?: number;
65 } 67 }
66 68
67 export interface DataSource { 69 export interface DataSource {
@@ -122,7 +122,7 @@ @@ -122,7 +122,7 @@
122 }>(); 122 }>();
123 const activeKey = ref('1'); 123 const activeKey = ref('1');
124 let entityId = null; 124 let entityId = null;
125 - // 图表tab切换选项卡 125 + // 图表tab切换选项卡 1965 1280 1861 836
126 const tabListTitle = [ 126 const tabListTitle = [
127 { 127 {
128 key: '1', 128 key: '1',
@@ -51,6 +51,7 @@ @@ -51,6 +51,7 @@
51 option && unref(chartRef)?.setOption(option); 51 option && unref(chartRef)?.setOption(option);
52 }); 52 });
53 } 53 }
  54 +
54 const getRadio = computed(() => { 55 const getRadio = computed(() => {
55 const { radio } = props.radio; 56 const { radio } = props.radio;
56 return radio; 57 return radio;
@@ -93,10 +94,12 @@ @@ -93,10 +94,12 @@
93 > 94 >
94 <Tooltip 95 <Tooltip
95 placement="topLeft" 96 placement="topLeft"
96 - :title="props.value.updateTime || dateUtil().format(DEFAULT_DATE_FORMAT)" 97 + :title="dateUtil(props?.value?.updateTime || new Date()).format(DEFAULT_DATE_FORMAT)"
97 > 98 >
98 <span class="mr-2">更新时间:</span> 99 <span class="mr-2">更新时间:</span>
99 - <span> {{ props.value.updateTime || dateUtil().format(DEFAULT_DATE_FORMAT) }}</span> 100 + <span>
  101 + {{ dateUtil(props?.value?.updateTime || new Date()).format(DEFAULT_DATE_FORMAT) }}
  102 + </span>
100 </Tooltip> 103 </Tooltip>
101 </div> 104 </div>
102 </div> 105 </div>
@@ -17,20 +17,21 @@ @@ -17,20 +17,21 @@
17 }>(); 17 }>();
18 18
19 const integerPart = computed(() => { 19 const integerPart = computed(() => {
20 - const { value = 0 } = props.value; 20 + let { value = 0 } = props.value;
21 const { max = 5 } = props.layout; 21 const { max = 5 } = props.layout;
22 - let _value = value?.toFixed(2).split('.')[0]; 22 + if (isNaN(value)) value = 0;
  23 + let _value = Number(value).toFixed(2).split('.')[0];
23 if (_value.length < max) _value = _value.padStart(5, '0'); 24 if (_value.length < max) _value = _value.padStart(5, '0');
24 -  
25 if (_value.length > max) _value = ''.padStart(5, '9'); 25 if (_value.length > max) _value = ''.padStart(5, '9');
26 26
27 return _value; 27 return _value;
28 }); 28 });
29 29
30 const decimalPart = computed(() => { 30 const decimalPart = computed(() => {
31 - const { value = 0 } = props.value; 31 + let { value = 0 } = props.value;
32 const { keepNumber = 2 } = props.layout; 32 const { keepNumber = 2 } = props.layout;
33 - let _value = value?.toFixed(2).split('.')[1]; 33 + if (isNaN(value)) value = 0;
  34 + let _value = Number(value)?.toFixed(2).split('.')[1];
34 if (_value.length < keepNumber) _value = _value.padStart(5, '0'); 35 if (_value.length < keepNumber) _value = _value.padStart(5, '0');
35 36
36 if (_value.length > keepNumber) _value = ''.padStart(5, '0'); 37 if (_value.length > keepNumber) _value = ''.padStart(5, '0');
@@ -91,10 +92,12 @@ @@ -91,10 +92,12 @@
91 > 92 >
92 <Tooltip 93 <Tooltip
93 placement="topLeft" 94 placement="topLeft"
94 - :title="props.value.updateTime || dateUtil().format(DEFAULT_DATE_FORMAT)" 95 + :title="dateUtil(props?.value?.updateTime || new Date()).format(DEFAULT_DATE_FORMAT)"
95 > 96 >
96 <span class="mr-1">更新时间:</span> 97 <span class="mr-1">更新时间:</span>
97 - <span>{{ props.value.updateTime || dateUtil().format(DEFAULT_DATE_FORMAT) }}</span> 98 + <span>
  99 + {{ dateUtil(props?.value?.updateTime || new Date()).format(DEFAULT_DATE_FORMAT) }}
  100 + </span>
98 </Tooltip> 101 </Tooltip>
99 </div> 102 </div>
100 </div> 103 </div>
@@ -288,9 +288,9 @@ export const transformDashboardComponentConfig = ( @@ -288,9 +288,9 @@ export const transformDashboardComponentConfig = (
288 value: { 288 value: {
289 id: buildUUID(), 289 id: buildUUID(),
290 name: dataSourceRecord.attributeRename || dataSourceRecord.attribute, 290 name: dataSourceRecord.attributeRename || dataSourceRecord.attribute,
291 - // value: record.va 291 + value: dataSourceRecord.componentInfo.value,
292 unit: dataSourceRecord.componentInfo.unit, 292 unit: dataSourceRecord.componentInfo.unit,
293 - updateTime: record.updateTime || record.createTime, 293 + updateTime: dataSourceRecord.componentInfo.updateTime,
294 fontColor: dataSourceRecord.componentInfo.fontColor, 294 fontColor: dataSourceRecord.componentInfo.fontColor,
295 gradientInfo: dataSourceRecord.componentInfo.gradientInfo, 295 gradientInfo: dataSourceRecord.componentInfo.gradientInfo,
296 }, 296 },
@@ -90,14 +90,14 @@ @@ -90,14 +90,14 @@
90 <div v-if="getShowUpdate" class="text-center text-xs text-gray-400 truncate"> 90 <div v-if="getShowUpdate" class="text-center text-xs text-gray-400 truncate">
91 <Tooltip 91 <Tooltip
92 placement="topLeft" 92 placement="topLeft"
93 - :title="props.value.updateTime || dateUtil().format(DEFAULT_DATE_FORMAT)" 93 + :title="dateUtil(props?.value?.updateTime || new Date()).format(DEFAULT_DATE_FORMAT)"
94 > 94 >
95 <span>更新时间:</span> 95 <span>更新时间:</span>
96 <span 96 <span
97 :style="{ fontSize: fontSize({ radio: getRadio, basic: 12, max: 16 }) }" 97 :style="{ fontSize: fontSize({ radio: getRadio, basic: 12, max: 16 }) }"
98 class="truncate" 98 class="truncate"
99 > 99 >
100 - {{ props.value.updateTime || dateUtil().format(DEFAULT_DATE_FORMAT) }} 100 + {{ dateUtil(props?.value?.updateTime || new Date()).format(DEFAULT_DATE_FORMAT) }}
101 </span> 101 </span>
102 </Tooltip> 102 </Tooltip>
103 </div> 103 </div>
@@ -88,10 +88,10 @@ export const transformTextComponentConfig = ( @@ -88,10 +88,10 @@ export const transformTextComponentConfig = (
88 } as TextComponentLayout, 88 } as TextComponentLayout,
89 value: { 89 value: {
90 name: dataSourceRecord.attributeRename || dataSourceRecord.attribute, 90 name: dataSourceRecord.attributeRename || dataSourceRecord.attribute,
91 - // value: record.va 91 + value: dataSourceRecord.componentInfo.value,
92 icon: dataSourceRecord.componentInfo.icon, 92 icon: dataSourceRecord.componentInfo.icon,
93 unit: dataSourceRecord.componentInfo.unit, 93 unit: dataSourceRecord.componentInfo.unit,
94 - updateTime: record.updateTime || record.createTime, 94 + updateTime: dataSourceRecord.componentInfo.updateTime,
95 fontColor: dataSourceRecord.componentInfo.fontColor, 95 fontColor: dataSourceRecord.componentInfo.fontColor,
96 iconColor: dataSourceRecord.componentInfo.iconColor, 96 iconColor: dataSourceRecord.componentInfo.iconColor,
97 } as TextComponentValue, 97 } as TextComponentValue,
@@ -23,6 +23,7 @@ @@ -23,6 +23,7 @@
23 import { DataBoardLayoutInfo } from '../types/type'; 23 import { DataBoardLayoutInfo } from '../types/type';
24 import { WidgetComponentType } from './config/visualOptions'; 24 import { WidgetComponentType } from './config/visualOptions';
25 import Authority from '/@/components/Authority/src/Authority.vue'; 25 import Authority from '/@/components/Authority/src/Authority.vue';
  26 + import { useSocketConnect } from '../hook/useSocketConnect';
26 27
27 const ROUTE = useRoute(); 28 const ROUTE = useRoute();
28 29
@@ -43,9 +44,6 @@ @@ -43,9 +44,6 @@
43 const GirdLayoutColNum = 24; 44 const GirdLayoutColNum = 24;
44 const GridLayoutMargin = 10; 45 const GridLayoutMargin = 10;
45 46
46 - const defaultWidth = 6;  
47 - const defaultHeight = 6;  
48 -  
49 const handleBack = () => { 47 const handleBack = () => {
50 ROUTER.go(-1); 48 ROUTER.go(-1);
51 }; 49 };
@@ -164,6 +162,8 @@ @@ -164,6 +162,8 @@
164 } catch (error) {} 162 } catch (error) {}
165 }; 163 };
166 164
  165 + const { beginSendMessage } = useSocketConnect(dataBoardList);
  166 +
167 const getDataBoardComponent = async () => { 167 const getDataBoardComponent = async () => {
168 try { 168 try {
169 // dataBoardList.value = []; 169 // dataBoardList.value = [];
@@ -178,8 +178,8 @@ @@ -178,8 +178,8 @@
178 } 178 }
179 return { 179 return {
180 i: item.id, 180 i: item.id,
181 - w: layout.w || defaultWidth,  
182 - h: layout.h || defaultHeight, 181 + w: layout.w || DEFAULT_WIDGET_WIDTH,
  182 + h: layout.h || DEFAULT_WIDGET_HEIGHT,
183 x: layout.x || 0, 183 x: layout.x || 0,
184 y: layout.y || 0, 184 y: layout.y || 0,
185 record: { 185 record: {
@@ -189,6 +189,7 @@ @@ -189,6 +189,7 @@
189 }, 189 },
190 }; 190 };
191 }); 191 });
  192 + beginSendMessage();
192 } catch (error) {} 193 } catch (error) {}
193 }; 194 };
194 195
  1 +import { useWebSocket } from '@vueuse/core';
  2 +import { Ref, unref } from 'vue';
  3 +import { DataBoardLayoutInfo } from '../types/type';
  4 +import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum';
  5 +import { getAuthCache } from '/@/utils/auth';
  6 +
  7 +interface SocketMessage {
  8 + tsSubCmds: SocketMessageItem[];
  9 +}
  10 +
  11 +interface SocketMessageItem {
  12 + entityType: string;
  13 + entityId: string;
  14 + scope: string;
  15 + cmdId: number;
  16 + keys: string;
  17 +}
  18 +
  19 +interface CmdMapping {
  20 + componentId: string;
  21 + deviceId: string;
  22 + recordIndex: number;
  23 + dataSourceIndex: number;
  24 + attribute: string;
  25 +}
  26 +
  27 +interface ResponseMessage {
  28 + subscriptionId: number;
  29 + errorCode: number;
  30 + errorMsg: Nullable<string>;
  31 + data: {
  32 + [key: string]: [[number, string]];
  33 + };
  34 + latestValues: {
  35 + [key: string]: number;
  36 + };
  37 +}
  38 +
  39 +const generateMessage = (deviceId: string, cmdId: number, attr: string): SocketMessageItem => {
  40 + return {
  41 + entityType: 'DEVICE',
  42 + entityId: deviceId,
  43 + scope: 'LATEST_TELEMETRY',
  44 + cmdId,
  45 + keys: attr,
  46 + };
  47 +};
  48 +
  49 +export function useSocketConnect(dataSourceRef: Ref<DataBoardLayoutInfo[]>) {
  50 + const token = getAuthCache(JWT_TOKEN_KEY);
  51 +
  52 + const cmdIdMapping = new Map<number, CmdMapping>();
  53 +
  54 + const waitSendQueue: string[] = [];
  55 +
  56 + const config = {
  57 + server: `${import.meta.env.VITE_WEB_SOCKET}${token}`,
  58 + };
  59 +
  60 + const getNeedUpdateValueById = (componentId: string, deviceId: string) => {};
  61 +
  62 + const getNeedUpdateValueByIndex = (recordIndex: number, dataSourceIndex: number) => {
  63 + return unref(dataSourceRef)[recordIndex].record.dataSource[dataSourceIndex];
  64 + };
  65 +
  66 + const { close, send, open, status } = useWebSocket(config.server, {
  67 + onConnected() {
  68 + if (waitSendQueue.length) {
  69 + waitSendQueue.forEach((string) => {
  70 + send(string);
  71 + });
  72 + waitSendQueue.length = 0;
  73 + }
  74 + },
  75 + onMessage(ws, message) {
  76 + try {
  77 + const res: ResponseMessage = JSON.parse(message.data);
  78 + const { subscriptionId, data = {} } = res;
  79 + const mappingRecord = cmdIdMapping.get(subscriptionId);
  80 + if (!mappingRecord) return;
  81 + const { attribute, recordIndex, dataSourceIndex } = mappingRecord;
  82 + const [[timespan, value]] = data[attribute];
  83 + const record = getNeedUpdateValueByIndex(recordIndex, dataSourceIndex);
  84 + record.componentInfo.value = value;
  85 + record.componentInfo.updateTime = timespan;
  86 + } catch (error) {
  87 + throw Error(error as string);
  88 + }
  89 + },
  90 + onDisconnected() {
  91 + close();
  92 + },
  93 + });
  94 +
  95 + const setCmdId = (cmdId: number, record: CmdMapping) => {
  96 + cmdIdMapping.set(cmdId, record);
  97 + };
  98 +
  99 + const transformSocketMessageItem = () => {
  100 + const messageList: SocketMessageItem[] = [];
  101 + console.log(dataSourceRef);
  102 + unref(dataSourceRef).forEach((record, recordIndex) => {
  103 + const componentId = record.record.id;
  104 + record.record.dataSource.forEach((dataSource, dataSourceIndex) => {
  105 + const { deviceId, attribute } = dataSource;
  106 + const cmdId = recordIndex * dataSourceIndex + recordIndex;
  107 + setCmdId(cmdId, {
  108 + componentId,
  109 + deviceId,
  110 + recordIndex,
  111 + dataSourceIndex,
  112 + attribute,
  113 + });
  114 +
  115 + messageList.push(generateMessage(deviceId, cmdId, attribute));
  116 + });
  117 + });
  118 + return {
  119 + tsSubCmds: messageList,
  120 + } as SocketMessage;
  121 + };
  122 +
  123 + const beginSendMessage = () => {
  124 + // close();
  125 + cmdIdMapping.clear();
  126 +
  127 + // open();
  128 + const messageList = transformSocketMessageItem();
  129 +
  130 + if (unref(status) !== 'OPEN') {
  131 + waitSendQueue.push(JSON.stringify(messageList));
  132 + return;
  133 + }
  134 + send(JSON.stringify(messageList));
  135 + };
  136 +
  137 + return {
  138 + close,
  139 + send,
  140 + open,
  141 + beginSendMessage,
  142 + };
  143 +}