Commit 7cdf8ee02fb2f456f2c4ba9d52fe3e03965fe746
1 parent
9b283601
feat: implement TextComponent && DigitalDashboardComponent echo real data
Showing
11 changed files
with
179 additions
and
24 deletions
... | ... | @@ -14,12 +14,14 @@ VITE_PUBLIC_PATH = / |
14 | 14 | # VITE_PROXY = [["/api","http://101.133.234.90:8080/api"]] |
15 | 15 | # 线上测试环境 |
16 | 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 | 19 | # VITE_PROXY = [["/api","http://192.168.10.106:8080/api"],["/thingskit-drawio","http://192.168.10.106:8080/api"]] |
19 | 20 | |
20 | 21 | # 实时数据的ws地址 |
21 | 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 | 26 | # Delete console |
25 | 27 | VITE_DROP_CONSOLE = true |
... | ... | @@ -37,5 +39,5 @@ VITE_GLOB_API_URL_PREFIX=/yt |
37 | 39 | VITE_GLOB_CONFIGURATION = /thingskit-drawio |
38 | 40 | |
39 | 41 | # Content Security Policy |
40 | -VITE_CONTENT_SECURITY_POLICY = true | |
42 | +VITE_CONTENT_SECURITY_POLICY = false | |
41 | 43 | ... | ... |
... | ... | @@ -51,6 +51,7 @@ |
51 | 51 | option && unref(chartRef)?.setOption(option); |
52 | 52 | }); |
53 | 53 | } |
54 | + | |
54 | 55 | const getRadio = computed(() => { |
55 | 56 | const { radio } = props.radio; |
56 | 57 | return radio; |
... | ... | @@ -93,10 +94,12 @@ |
93 | 94 | > |
94 | 95 | <Tooltip |
95 | 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 | 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 | 103 | </Tooltip> |
101 | 104 | </div> |
102 | 105 | </div> | ... | ... |
... | ... | @@ -17,20 +17,21 @@ |
17 | 17 | }>(); |
18 | 18 | |
19 | 19 | const integerPart = computed(() => { |
20 | - const { value = 0 } = props.value; | |
20 | + let { value = 0 } = props.value; | |
21 | 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 | 24 | if (_value.length < max) _value = _value.padStart(5, '0'); |
24 | - | |
25 | 25 | if (_value.length > max) _value = ''.padStart(5, '9'); |
26 | 26 | |
27 | 27 | return _value; |
28 | 28 | }); |
29 | 29 | |
30 | 30 | const decimalPart = computed(() => { |
31 | - const { value = 0 } = props.value; | |
31 | + let { value = 0 } = props.value; | |
32 | 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 | 35 | if (_value.length < keepNumber) _value = _value.padStart(5, '0'); |
35 | 36 | |
36 | 37 | if (_value.length > keepNumber) _value = ''.padStart(5, '0'); |
... | ... | @@ -91,10 +92,12 @@ |
91 | 92 | > |
92 | 93 | <Tooltip |
93 | 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 | 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 | 101 | </Tooltip> |
99 | 102 | </div> |
100 | 103 | </div> | ... | ... |
... | ... | @@ -288,9 +288,9 @@ export const transformDashboardComponentConfig = ( |
288 | 288 | value: { |
289 | 289 | id: buildUUID(), |
290 | 290 | name: dataSourceRecord.attributeRename || dataSourceRecord.attribute, |
291 | - // value: record.va | |
291 | + value: dataSourceRecord.componentInfo.value, | |
292 | 292 | unit: dataSourceRecord.componentInfo.unit, |
293 | - updateTime: record.updateTime || record.createTime, | |
293 | + updateTime: dataSourceRecord.componentInfo.updateTime, | |
294 | 294 | fontColor: dataSourceRecord.componentInfo.fontColor, |
295 | 295 | gradientInfo: dataSourceRecord.componentInfo.gradientInfo, |
296 | 296 | }, | ... | ... |
... | ... | @@ -90,14 +90,14 @@ |
90 | 90 | <div v-if="getShowUpdate" class="text-center text-xs text-gray-400 truncate"> |
91 | 91 | <Tooltip |
92 | 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 | 95 | <span>更新时间:</span> |
96 | 96 | <span |
97 | 97 | :style="{ fontSize: fontSize({ radio: getRadio, basic: 12, max: 16 }) }" |
98 | 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 | 101 | </span> |
102 | 102 | </Tooltip> |
103 | 103 | </div> | ... | ... |
... | ... | @@ -88,10 +88,10 @@ export const transformTextComponentConfig = ( |
88 | 88 | } as TextComponentLayout, |
89 | 89 | value: { |
90 | 90 | name: dataSourceRecord.attributeRename || dataSourceRecord.attribute, |
91 | - // value: record.va | |
91 | + value: dataSourceRecord.componentInfo.value, | |
92 | 92 | icon: dataSourceRecord.componentInfo.icon, |
93 | 93 | unit: dataSourceRecord.componentInfo.unit, |
94 | - updateTime: record.updateTime || record.createTime, | |
94 | + updateTime: dataSourceRecord.componentInfo.updateTime, | |
95 | 95 | fontColor: dataSourceRecord.componentInfo.fontColor, |
96 | 96 | iconColor: dataSourceRecord.componentInfo.iconColor, |
97 | 97 | } as TextComponentValue, | ... | ... |
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 | import { DataBoardLayoutInfo } from '../types/type'; |
24 | 24 | import { WidgetComponentType } from './config/visualOptions'; |
25 | 25 | import Authority from '/@/components/Authority/src/Authority.vue'; |
26 | + import { useSocketConnect } from '../hook/useSocketConnect'; | |
26 | 27 | |
27 | 28 | const ROUTE = useRoute(); |
28 | 29 | |
... | ... | @@ -43,9 +44,6 @@ |
43 | 44 | const GirdLayoutColNum = 24; |
44 | 45 | const GridLayoutMargin = 10; |
45 | 46 | |
46 | - const defaultWidth = 6; | |
47 | - const defaultHeight = 6; | |
48 | - | |
49 | 47 | const handleBack = () => { |
50 | 48 | ROUTER.go(-1); |
51 | 49 | }; |
... | ... | @@ -164,6 +162,8 @@ |
164 | 162 | } catch (error) {} |
165 | 163 | }; |
166 | 164 | |
165 | + const { beginSendMessage } = useSocketConnect(dataBoardList); | |
166 | + | |
167 | 167 | const getDataBoardComponent = async () => { |
168 | 168 | try { |
169 | 169 | // dataBoardList.value = []; |
... | ... | @@ -178,8 +178,8 @@ |
178 | 178 | } |
179 | 179 | return { |
180 | 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 | 183 | x: layout.x || 0, |
184 | 184 | y: layout.y || 0, |
185 | 185 | record: { |
... | ... | @@ -189,6 +189,7 @@ |
189 | 189 | }, |
190 | 190 | }; |
191 | 191 | }); |
192 | + beginSendMessage(); | |
192 | 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 | +} | ... | ... |