Commit 9e0402d8043d2499aaef567fc85bd6c22b296961

Authored by xp.Huang
2 parents d4a291e0 7004bf55

Merge branch 'sqy_dev' into 'main'

feat地理位置---:历史记录

See merge request huang/yun-teng-iot-front!63
... ... @@ -6,3 +6,27 @@ export const getDeviceProfile = () => {
6 6 url: '/deviceProfile/me/list',
7 7 });
8 8 };
  9 +
  10 +export const getDeviceHistoryInfo = (params) => {
  11 + return defHttp.get(
  12 + {
  13 + url: `/plugins/telemetry/DEVICE/${params.entityId}/values/timeseries`,
  14 + params: { ...params, entityId: null, orderBy: 'ASC' },
  15 + },
  16 + {
  17 + joinPrefix: false,
  18 + }
  19 + );
  20 +};
  21 +
  22 +// 获取设备数据的keys
  23 +export const getDeviceDataKeys = (id: string) => {
  24 + return defHttp.get(
  25 + {
  26 + url: `/plugins/telemetry/DEVICE/${id}/keys/timeseries`,
  27 + },
  28 + {
  29 + joinPrefix: false,
  30 + }
  31 + );
  32 +};
... ...
... ... @@ -14,7 +14,6 @@ import { setupStore } from '/@/store';
14 14 import { setupGlobDirectives } from '/@/directives';
15 15 import { setupI18n } from '/@/locales/setupI18n';
16 16 import { registerGlobComp } from '/@/components/registerGlobComp';
17   -
18 17 // Do not introduce on-demand in local development?
19 18 // In the local development for introduce on-demand, the number of browser requests will increase by about 20%.
20 19 // Which may slow down the browser refresh.
... ...
... ... @@ -21,10 +21,10 @@
21 21 import { BasicTable, useTable, TableAction } from '/@/components/Table';
22 22 import { alarmColumns, alarmSearchSchemas } from './config/detail.config';
23 23 import { getDeviceAlarm } from '/@/api/device/deviceManager';
24   - import AlarmDetailDrawer from './cpns/AlarmDetailDrawer.vue';
25 24 import { useDrawer } from '/@/components/Drawer';
  25 + import AlarmDetailDrawer from './cpns/AlarmDetailDrawer.vue';
26 26 export default defineComponent({
27   - name: 'DeviceManagement',
  27 + name: 'AlarmCenter',
28 28 components: {
29 29 BasicTable,
30 30 TableAction,
... ...
... ... @@ -92,89 +92,328 @@ export const columns: BasicColumn[] = [
92 92 },
93 93 ];
94 94
  95 +// 动态生成options
  96 +function generateOptions(value: number) {
  97 + if (value === 3600000) {
  98 + return [
  99 + {
  100 + label: '10秒',
  101 + value: 10000,
  102 + },
  103 + {
  104 + label: '15秒',
  105 + value: 15000,
  106 + },
  107 + {
  108 + label: '30秒',
  109 + value: 30000,
  110 + },
  111 + {
  112 + label: '1分钟',
  113 + value: 60000,
  114 + },
  115 + {
  116 + label: '2分钟',
  117 + value: 120000,
  118 + },
  119 + {
  120 + label: '5分钟',
  121 + value: 300000,
  122 + },
  123 + ];
  124 + } else if (value === 7200000) {
  125 + return [
  126 + {
  127 + label: '15秒',
  128 + value: 15000,
  129 + },
  130 + {
  131 + label: '30秒',
  132 + value: 30000,
  133 + },
  134 + {
  135 + label: '1分钟',
  136 + value: 60000,
  137 + },
  138 + {
  139 + label: '2分钟',
  140 + value: 120000,
  141 + },
  142 + {
  143 + label: '5分钟',
  144 + value: 300000,
  145 + },
  146 + {
  147 + label: '10分钟',
  148 + value: 600000,
  149 + },
  150 + {
  151 + label: '15分钟',
  152 + value: 900000,
  153 + },
  154 + ];
  155 + } else if (value === 18000000) {
  156 + return [
  157 + {
  158 + label: '1分钟',
  159 + value: 60000,
  160 + },
  161 + {
  162 + label: '2分钟',
  163 + value: 120000,
  164 + },
  165 + {
  166 + label: '5分钟',
  167 + value: 300000,
  168 + },
  169 + {
  170 + label: '10分钟',
  171 + value: 600000,
  172 + },
  173 + {
  174 + label: '15分钟',
  175 + value: 900000,
  176 + },
  177 + {
  178 + label: '30分钟',
  179 + value: 1800000,
  180 + },
  181 + ];
  182 + } else if (value === 36000000) {
  183 + return [
  184 + {
  185 + label: '2分钟',
  186 + value: 120000,
  187 + },
  188 + {
  189 + label: '5分钟',
  190 + value: 300000,
  191 + },
  192 + {
  193 + label: '10分钟',
  194 + value: 600000,
  195 + },
  196 + {
  197 + label: '15分钟',
  198 + value: 900000,
  199 + },
  200 + {
  201 + label: '30分钟',
  202 + value: 1800000,
  203 + },
  204 + {
  205 + label: '1小时',
  206 + value: 3600000,
  207 + },
  208 + ];
  209 + } else if (value === 43200000) {
  210 + return [
  211 + {
  212 + label: '2分钟',
  213 + value: 120000,
  214 + },
  215 + {
  216 + label: '5分钟',
  217 + value: 300000,
  218 + },
  219 + {
  220 + label: '10分钟',
  221 + value: 600000,
  222 + },
  223 + {
  224 + label: '15分钟',
  225 + value: 900000,
  226 + },
  227 + {
  228 + label: '30分钟',
  229 + value: 1800000,
  230 + },
  231 + {
  232 + label: '1小时',
  233 + value: 3600000,
  234 + },
  235 + ];
  236 + } else if (value === 86400000) {
  237 + return [
  238 + {
  239 + label: '5分钟',
  240 + value: 300000,
  241 + },
  242 + {
  243 + label: '10分钟',
  244 + value: 600000,
  245 + },
  246 + {
  247 + label: '15分钟',
  248 + value: 900000,
  249 + },
  250 + {
  251 + label: '30分钟',
  252 + value: 1800000,
  253 + },
  254 + {
  255 + label: '1小时',
  256 + value: 3600000,
  257 + },
  258 + {
  259 + label: '2小时',
  260 + value: 7200000,
  261 + },
  262 + ];
  263 + } else if (value === 604800000) {
  264 + return [
  265 + {
  266 + label: '30分钟',
  267 + value: 1800000,
  268 + },
  269 + {
  270 + label: '1小时',
  271 + value: 3600000,
  272 + },
  273 + {
  274 + label: '2小时',
  275 + value: 7200000,
  276 + },
  277 + {
  278 + label: '5小时',
  279 + value: 18000000,
  280 + },
  281 + {
  282 + label: '10小时',
  283 + value: 36000000,
  284 + },
  285 + {
  286 + label: '12小时',
  287 + value: 43200000,
  288 + },
  289 + {
  290 + label: '1天',
  291 + value: 86400000,
  292 + },
  293 + ];
  294 + } else {
  295 + return [
  296 + {
  297 + label: '2小时',
  298 + value: 7200000,
  299 + },
  300 + {
  301 + label: '5小时',
  302 + value: 18000000,
  303 + },
  304 + {
  305 + label: '10小时',
  306 + value: 36000000,
  307 + },
  308 + {
  309 + label: '12小时',
  310 + value: 43200000,
  311 + },
  312 + {
  313 + label: '1天',
  314 + value: 86400000,
  315 + },
  316 + ];
  317 + }
  318 +}
95 319 export const schemas: FormSchema[] = [
96 320 {
97   - field: 'name',
  321 + field: 'endTs',
98 322 label: '最后数据',
99 323 component: 'Select',
100   - componentProps: {
101   - options: [
102   - {
103   - label: '最近1小时',
104   - value: '1',
105   - },
106   - {
107   - label: '最近2小时',
108   - value: '2',
109   - },
110   - {
111   - label: '最近5小时',
112   - value: '5',
  324 + required: true,
  325 + componentProps({ formModel, formActionType }) {
  326 + return {
  327 + onChange(value) {
  328 + const { updateSchema } = formActionType;
  329 + formModel.interval = '';
  330 + updateSchema({
  331 + field: 'interval',
  332 + componentProps: {
  333 + placeholder: '请选择分组间隔',
  334 + options: generateOptions(value),
  335 + },
  336 + });
113 337 },
114   - {
115   - label: '最近12小时',
116   - value: '12',
117   - },
118   - {
119   - label: '最近1天',
120   - value: '1天',
121   - },
122   - {
123   - label: '最近7天',
124   - value: '7天',
125   - },
126   - {
127   - label: '最近30天',
128   - value: '30天',
129   - },
130   - ],
  338 + options: [
  339 + {
  340 + label: '最近1小时',
  341 + value: 3600000,
  342 + },
  343 + {
  344 + label: '最近2小时',
  345 + value: 7200000,
  346 + },
  347 + {
  348 + label: '最近5小时',
  349 + value: 18000000,
  350 + },
  351 + {
  352 + label: '最近10小时',
  353 + value: 36000000,
  354 + },
  355 + {
  356 + label: '最近12小时',
  357 + value: 43200000,
  358 + },
  359 + {
  360 + label: '最近1天',
  361 + value: 86400000,
  362 + },
  363 + {
  364 + label: '最近7天',
  365 + value: 604800000,
  366 + },
  367 + {
  368 + label: '最近30天',
  369 + value: 2592000000,
  370 + },
  371 + ],
  372 + };
131 373 },
132 374 colProps: {
133 375 span: 6,
134 376 },
135 377 },
136 378 {
137   - field: 'name',
  379 + field: 'interval',
138 380 label: '分组间隔',
139 381 component: 'Select',
  382 + colProps: {
  383 + span: 6,
  384 + },
140 385 componentProps: {
  386 + placeholder: '请选择分组间隔',
141 387 options: [
142 388 {
143   - label: '15秒',
144   - value: '15',
145   - },
146   - {
147   - label: '30秒',
148   - value: '30',
  389 + label: '5分钟',
  390 + value: 300000,
149 391 },
150 392 {
151   - label: '1分钟',
152   - value: '60',
  393 + label: '10分钟',
  394 + value: 600000,
153 395 },
154 396 {
155   - label: '2分钟',
156   - value: '120',
  397 + label: '15分钟',
  398 + value: 900000,
157 399 },
158 400 {
159   - label: '5分钟',
160   - value: '360',
  401 + label: '30分钟',
  402 + value: 1800000,
161 403 },
162 404 {
163   - label: '10分钟',
164   - value: '600',
  405 + label: '1小时',
  406 + value: 3600000,
165 407 },
166 408 {
167   - label: '15分钟',
168   - value: '900',
  409 + label: '2小时',
  410 + value: 7200000,
169 411 },
170 412 ],
171 413 },
172   - colProps: {
173   - span: 6,
174   - },
175 414 },
176 415 {
177   - field: 'name',
  416 + field: 'agg',
178 417 label: '数据聚合功能',
179 418 component: 'Select',
180 419 componentProps: {
... ...
1 1 <template>
2   - <div class="wrapper">
  2 + <div class="wrapper123">
3 3 <div ref="wrapRef" :style="{ height, width }"> </div>
4 4 <div class="right-wrap">
5 5 <BasicTable @register="registerTable" @rowClick="deviceRowClick">
... ... @@ -25,14 +25,21 @@
25 25 </template>
26 26 </BasicTable>
27 27 </div>
28   - <a-button type="primary" @click="handleClick">打开弹窗</a-button>
29   - <BasicModal @register="registerModal" title="历史数据" width="70%">
  28 + <BasicModal
  29 + @register="registerModal"
  30 + title="历史数据"
  31 + width="70%"
  32 + :footer="null"
  33 + @cancel="cancelHistoryModal"
  34 + :canFullscreen="false"
  35 + >
30 36 <BasicForm @register="registerForm" />
  37 + <div ref="chartRef" :style="{ height: '600px', width }"></div>
31 38 </BasicModal>
32 39 </div>
33 40 </template>
34 41 <script lang="ts">
35   - import { defineComponent, ref, nextTick, unref, onMounted } from 'vue';
  42 + import { defineComponent, ref, nextTick, unref, onMounted, Ref } from 'vue';
36 43 import { useScript } from '/@/hooks/web/useScript';
37 44 import { formSchema, columns } from './config.data';
38 45 import { BasicTable, useTable } from '/@/components/Table';
... ... @@ -43,6 +50,9 @@
43 50 import { useModal, BasicModal } from '/@/components/Modal';
44 51 import { BasicForm, useForm } from '/@/components/Form';
45 52 import { schemas } from './config.data';
  53 + import { useECharts } from '/@/hooks/web/useECharts';
  54 + import { getDeviceHistoryInfo, getDeviceDataKeys } from '/@/api/alarm/position';
  55 + import moment from 'moment';
46 56 export default defineComponent({
47 57 name: 'BaiduMap',
48 58 components: {
... ... @@ -64,7 +74,7 @@
64 74 setup() {
65 75 const wrapRef = ref<HTMLDivElement | null>(null);
66 76 const { toPromise } = useScript({ src: BAI_DU_MAP_URL });
67   -
  77 + const entityId = ref('');
68 78 async function initMap() {
69 79 await toPromise();
70 80 await nextTick();
... ... @@ -73,13 +83,9 @@
73 83 if (!wrapEl) return;
74 84 const map = new BMap.Map(wrapEl);
75 85 const point = new BMap.Point(104.04666605565338, 30.543516387560476);
76   -
77 86 map.centerAndZoom(point, 15);
78 87 map.enableScrollWheelZoom(true);
79 88 }
80   - onMounted(() => {
81   - initMap();
82   - });
83 89
84 90 const [registerTable] = useTable({
85 91 api: devicePage,
... ... @@ -90,9 +96,13 @@
90 96 },
91 97 showIndexColumn: false,
92 98 useSearchForm: true,
  99 + pagination: {
  100 + showSizeChanger: false,
  101 + },
93 102 });
94 103 // 点击表格某一行触发
95 104 const deviceRowClick = (record) => {
  105 + entityId.value = record.tbDeviceId;
96 106 const BMap = (window as any).BMap;
97 107 const wrapEl = unref(wrapRef);
98 108 const map = new BMap.Map(wrapEl);
... ... @@ -106,30 +116,32 @@
106 116 };
107 117 map.centerAndZoom(point, 15);
108 118 map.enableScrollWheelZoom(true);
  119 + // 创建信息窗口对象
109 120 let infoWindow = new BMap.InfoWindow(
110 121 `
111   - <div style="display:flex;justify-content:space-between; margin:20px 0px;">
112   - <div style="font-size:16px;font-weight:bold">${name}</div>
113   - ${
114   - deviceState === 'INACTIVE'
115   - ? '<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="/src/assets/images/djh.png">待激活</div>'
116   - : deviceState === 'ONLINE'
117   - ? '<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="/src/assets/images/online1.png">在线</div>'
118   - : '<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="/src/assets/images/lx1.png">离线</div>'
119   - }
120   - </div>
121   - <div>所属组织:${organizationDTO.name}</div>
122   - <div style="margin-top:6px;">接入协议:${deviceProfile.transportType}</div>
123   - <div style="margin-top:6px;">设备位置:${address}</div>
124   - <div style="margin-top:6px;">下线时间:${updateTime}</div>
125   - <div style="display:flex;justify-content:space-between; margin-top:10px">
126   - <button style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">设备信息</button>
127   - <button style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">报警记录</button>
128   - <button onclick="historyClick()"style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">历史数据</button>
129   - </div>
130   - `,
  122 + <div style="display:flex;justify-content:space-between; margin:20px 0px;">
  123 + <div style="font-size:16px;font-weight:bold">${name}</div>
  124 + ${
  125 + deviceState === 'INACTIVE'
  126 + ? '<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="/src/assets/images/djh.png">待激活</div>'
  127 + : deviceState === 'ONLINE'
  128 + ? '<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="/src/assets/images/online1.png">在线</div>'
  129 + : '<div style="display:flex;align-items:center"><img style="width:15px;height:15px" src="/src/assets/images/lx1.png">离线</div>'
  130 + }
  131 + </div>
  132 + <div>所属组织:${organizationDTO.name}</div>
  133 + <div style="margin-top:6px;">接入协议:${deviceProfile.transportType}</div>
  134 + <div style="margin-top:6px;">设备位置:${address}</div>
  135 + <div style="margin-top:6px;">下线时间:${updateTime}</div>
  136 + <div style="display:flex;justify-content:space-between; margin-top:10px">
  137 + <button style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">设备信息</button>
  138 + <button style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">报警记录</button>
  139 + <button onclick="openHistoryModal()" style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">历史数据</button>
  140 + </div>
  141 + `,
131 142 options
132   - ); // 创建信息窗口对象
  143 + );
  144 +
133 145 map.openInfoWindow(infoWindow, map.getCenter());
134 146 let preMarker = null;
135 147 const rivet =
... ... @@ -156,39 +168,190 @@
156 168 let infoWindow = new BMap.InfoWindow('该设备暂无地理位置', options); // 创建信息窗口对象
157 169 map.openInfoWindow(infoWindow, map.getCenter());
158 170 }
159   -
160   - console.log(record);
161 171 };
162   -
  172 + let keys = [];
163 173 const [registerModal, { openModal }] = useModal();
164   - const [registerForm] = useForm({
  174 + const [registerForm, { resetFields, getFieldsValue, setFieldsValue, validate }] = useForm({
165 175 labelWidth: 120,
166 176 schemas,
  177 + async submitFunc() {
  178 + // 表单验证
  179 + await validate();
  180 + let { endTs, interval, agg } = getFieldsValue();
  181 + if (!endTs) return;
  182 + // 数据收集
  183 + const dataArray: any[] = [];
  184 + const startTs = Date.now() - endTs;
  185 + endTs = Date.now();
  186 + // 发送请求
  187 + const res = await getDeviceHistoryInfo({
  188 + entityId: entityId.value,
  189 + keys: keys.join(),
  190 + startTs,
  191 + endTs,
  192 + interval,
  193 + agg,
  194 + });
  195 + // 处理数据
  196 + for (const key in res) {
  197 + for (const item1 of res[key]) {
  198 + let { ts, value } = item1;
  199 + const time = moment(ts).format('YYYY-MM-DD HH:mm:ss');
  200 + value = Number(value).toFixed(2);
  201 + dataArray.push([time, value, key]);
  202 + }
  203 + }
  204 +
  205 + const series: any = keys.map((item) => {
  206 + return {
  207 + name: item,
  208 + type: 'line',
  209 + stack: 'Total',
  210 + data: dataArray.filter((item1) => item1[2] === item),
  211 + };
  212 + });
  213 + // 设置数据
  214 + setOptions({
  215 + tooltip: {
  216 + trigger: 'axis',
  217 + },
  218 + legend: {
  219 + data: keys,
  220 + },
  221 + grid: {
  222 + left: '3%',
  223 + right: '4%',
  224 + bottom: '3%',
  225 + containLabel: true,
  226 + },
  227 + dataZoom: [
  228 + {
  229 + type: 'inside',
  230 + start: 0,
  231 + end: 50,
  232 + },
  233 + {
  234 + start: 20,
  235 + end: 40,
  236 + },
  237 + ],
  238 + xAxis: {
  239 + type: 'time',
  240 + boundaryGap: false,
  241 + },
  242 + yAxis: {
  243 + type: 'value',
  244 + boundaryGap: [0, '100%'],
  245 + },
  246 + series,
  247 + });
  248 + },
167 249 });
168   - const handleClick = () => {
  250 +
  251 + const chartRef = ref<HTMLDivElement | null>(null);
  252 + const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
  253 +
  254 + const openHistoryModal = async () => {
169 255 openModal(true);
170   - };
171 256
  257 + // 收集参数
  258 + const dataArray: any[] = [];
  259 + const startTs = Date.now() - 86400000; //最近一天
  260 + const endTs = Date.now();
  261 + // 发送请求
  262 + keys = await getDeviceDataKeys(entityId.value);
  263 + const res = await getDeviceHistoryInfo({
  264 + entityId: entityId.value,
  265 + keys: keys.join(),
  266 + startTs,
  267 + endTs,
  268 + interval: 7200000, //间隔两小时
  269 + agg: 'AVG',
  270 + });
  271 + // 处理数据
  272 + for (const key in res) {
  273 + for (const item1 of res[key]) {
  274 + let { ts, value } = item1;
  275 + const time = moment(ts).format('YYYY-MM-DD HH:mm:ss');
  276 + value = Number(value).toFixed(2);
  277 + dataArray.push([time, value, key]);
  278 + }
  279 + }
  280 + const series: any = keys.map((item) => {
  281 + return {
  282 + name: item,
  283 + type: 'line',
  284 + stack: 'Total',
  285 + data: dataArray.filter((item1) => item1[2] === item),
  286 + };
  287 + });
  288 + // 设置数据;
  289 + setOptions({
  290 + tooltip: {
  291 + trigger: 'axis',
  292 + },
  293 + legend: {
  294 + data: keys,
  295 + },
  296 + grid: {
  297 + left: '3%',
  298 + right: '4%',
  299 + bottom: '3%',
  300 + containLabel: true,
  301 + },
  302 + dataZoom: [
  303 + {
  304 + type: 'inside',
  305 + start: 0,
  306 + end: 50,
  307 + },
  308 + {
  309 + start: 0,
  310 + end: 20,
  311 + },
  312 + ],
  313 + xAxis: {
  314 + type: 'time',
  315 + boundaryGap: false,
  316 + },
  317 + yAxis: {
  318 + type: 'value',
  319 + boundaryGap: [0, '100%'],
  320 + },
  321 + series,
  322 + });
  323 +
  324 + setFieldsValue({
  325 + endTs: 86400000,
  326 + interval: 7200000,
  327 + agg: 'AVG',
  328 + });
  329 + };
  330 + const cancelHistoryModal = () => {
  331 + resetFields();
  332 + setOptions({});
  333 + };
  334 + onMounted(() => {
  335 + initMap();
  336 + (window as any).openHistoryModal = openHistoryModal;
  337 + });
172 338 return {
173 339 wrapRef,
174 340 registerTable,
175 341 deviceRowClick,
176 342 DeviceState,
177   - handleClick,
178 343 registerModal,
179 344 registerForm,
  345 + chartRef,
  346 + cancelHistoryModal,
180 347 };
181 348 },
182 349 });
183 350 </script>
184   -
185 351 <style scoped>
186 352 .wrapper {
187 353 position: relative;
188 354 }
189   - .active {
190   - background-color: #fff;
191   - }
192 355 .right-wrap {
193 356 padding-top: 10px;
194 357 width: 22%;
... ...
... ... @@ -13,32 +13,35 @@
13 13 light:border-#F2F2F5
14 14 "
15 15 >
16   - <img :src="item.imgUrl" style="width: 90px; height: 90px" />
  16 + <img :src="item.imgUrl" style="width: 5rem; height: 5rem" />
17 17 <div class="growCardItem-right">
18 18 <div class="flex justify-between ml-3">
19   - <div style="font-size: 26px; color: #333">{{ item.value }}</div>
20   - <img src="../../../../assets/images/tip.png" style="width: 20px; height: 20px" />
  19 + <div style="font-size: 1.625rem; color: #333">{{ item.value }}</div>
  20 + <img src="../../../../assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" />
21 21 </div>
22 22 <div class="ml-3">{{ item.title }}</div>
23   - <div class="ml-1.5 mt-3 flex flex-nowrap" style="width: 240px" v-if="item.offLine">
  23 + <div class="ml-1.5 mt-3 flex flex-nowrap" style="width: 15rem" v-if="item.offLine">
24 24 <div class="count">
25 25 <img
26 26 src="../../../../assets/images/online.png"
27   - style="width: 10px; height: 10px; margin-right: 4px"
  27 + style="width: 0.6rem; height: 0.6rem"
  28 + class="mr-1"
28 29 />
29 30 在线 {{ item.onLine }}
30 31 </div>
31 32 <div class="count">
32 33 <img
33 34 src="../../../../assets/images/offline.png"
34   - style="width: 10px; height: 10px; margin-right: 4px"
  35 + style="width: 0.6rem; height: 0.6rem"
  36 + class="mr-1"
35 37 />
36 38 离线 {{ item.offLine }}
37 39 </div>
38 40 <div class="count">
39 41 <img
40 42 src="../../../../assets/images/inactive.png"
41   - style="width: 10px; height: 10px; margin-right: 4px"
  43 + style="width: 0.6rem; height: 0.6rem"
  44 + class="mr-1"
42 45 />
43 46 未激活 {{ item.inactive }}
44 47 </div>
... ... @@ -56,24 +59,24 @@
56 59
57 60 <style scoped lang="less">
58 61 .growCardItem {
59   - height: 179px;
  62 + height: 11.187rem;
60 63 color: #666;
61 64 .growCardItem-top {
62 65 display: flex;
63   - margin: 20px;
64   - padding-bottom: 10px;
  66 + margin: 1.25rem;
  67 + padding-bottom: 0.625rem;
65 68 .growCardItem-right {
66   - width: 300px;
  69 + width: 18.75rem;
67 70 .count {
68 71 display: flex;
69   - font-size: 12px;
  72 + font-size: 0.75rem;
70 73 align-items: center;
71   - margin-left: 8px;
  74 + margin-left: 0.5rem;
72 75 }
73 76 }
74 77 }
75 78 .growCardItem-bottom {
76   - margin-left: 20px;
  79 + margin-left: 1.25rem;
77 80 }
78 81 }
79 82 </style>
... ...
... ... @@ -8,8 +8,8 @@
8 8 import { useWebSocket } from '@vueuse/core';
9 9 import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum';
10 10 import { getAuthCache } from '/@/utils/auth';
11   - import type { socketDataType } from '../../types';
12 11 import { useMessage } from '/@/hooks/web/useMessage';
  12 + import type { socketDataType } from '../../types';
13 13 export default defineComponent({
14 14 name: 'RealTimeData',
15 15 components: {
... ... @@ -22,7 +22,7 @@
22 22 },
23 23 },
24 24 setup(props) {
25   - const token = getAuthCache(JWT_TOKEN_KEY);
  25 + const token: string = getAuthCache(JWT_TOKEN_KEY);
26 26 const state = reactive({
27 27 server: `ws://101.133.234.90:8080/api/ws/plugins/telemetry?token=${token}`,
28 28 sendValue: JSON.stringify({
... ... @@ -54,25 +54,24 @@
54 54 dataSource: state.recordList,
55 55 });
56 56
57   - const { send } = useWebSocket(state.server, {
  57 + const { send, close } = useWebSocket(state.server, {
58 58 onConnected() {
59 59 send(state.sendValue);
60 60 console.log('建立连接了');
61   - console.log(props.deviceDetail.tbDeviceId);
62 61 },
63 62 onMessage(_, e) {
64 63 const { data } = JSON.parse(e.data);
65   - console.log('来新消息了', 'data---', data);
66   - const newArray: any = [];
  64 + console.log('来新消息了', '---data---', data);
  65 + const newArray: socketDataType[] = [];
67 66 for (const key in data) {
68   - const newData = data[key].flat(1);
  67 + const [time, value] = data[key].flat(1);
69 68 let obj = {
70 69 key,
71   - time: newData[0],
72   - value: newData[1],
  70 + time,
  71 + value,
73 72 };
74 73 if (state.recordList.length === 0) {
75   - state.recordList.push(obj);
  74 + state.recordList.unshift(obj);
76 75 } else {
77 76 newArray.push(obj);
78 77 }
... ... @@ -80,9 +79,9 @@
80 79 newArray.forEach((item) => {
81 80 let flag = false;
82 81 state.recordList.forEach((item1) => {
83   - if (item.key === item1.key) {
84   - item1.time = item.time;
  82 + if (item1.key === item.key) {
85 83 item1.value = item.value;
  84 + item1.time = item.time;
86 85 flag = true;
87 86 }
88 87 });
... ... @@ -91,7 +90,10 @@
91 90 }
92 91 });
93 92 },
94   - onDisconnected() {},
  93 + onDisconnected() {
  94 + console.log('断开连接了');
  95 + close();
  96 + },
95 97 onError() {
96 98 createMessage.error('webSocket连接超时,请联系管理员');
97 99 },
... ...