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,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 |
@@ -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 | +} |