Commit fc25d5e8ba05b1e66ab36b6646d288732701239d

Authored by fengwotao
1 parent 1e80cb7f

fix(src/api/external): 修改设备分布新增设备最新属性表格

@@ -16,7 +16,8 @@ enum Api { @@ -16,7 +16,8 @@ enum Api {
16 VIDEOURL = '/video/url/', 16 VIDEOURL = '/video/url/',
17 GEOJSONURL = '/map/geo_json/', 17 GEOJSONURL = '/map/geo_json/',
18 DEVICE_URL = '/device', 18 DEVICE_URL = '/device',
19 - GET_ATTRBUTELIST = '/device/attributes/' 19 + GET_ATTRBUTELIST = '/device/attributes/',
  20 + GET_DEVICE_LATEST = '/plugins/telemetry/DEVICE/'
20 } 21 }
21 22
22 export const getDictItemByCode = (value: string) => { 23 export const getDictItemByCode = (value: string) => {
@@ -127,3 +128,11 @@ export const getAttribute = (deviceProfileId: string) => @@ -127,3 +128,11 @@ export const getAttribute = (deviceProfileId: string) =>
127 defHttp.get({ 128 defHttp.get({
128 url: `${Api.GET_ATTRBUTELIST}${deviceProfileId}` 129 url: `${Api.GET_ATTRBUTELIST}${deviceProfileId}`
129 }) 130 })
  131 +
  132 +// 获取设备最新数据
  133 +export const getDeviceLatest = (tbDeviceId: string) =>
  134 +defHttp.get({
  135 + url: `${Api.GET_DEVICE_LATEST}${tbDeviceId}/values/timeseries`
  136 +}, {
  137 + joinPrefix: false
  138 +})
  1 +<template>
  2 + <n-drawer display-directive="if" v-model:show="modelShow" :width="502" :placement="placement">
  3 + <n-drawer-content title="设备最新属性数据" closable>
  4 + <n-space vertical>
  5 + <n-data-table size="small" :columns="dimensions" :data="source" :pagination="pagination" />
  6 + </n-space>
  7 + </n-drawer-content>
  8 + </n-drawer>
  9 +</template>
  10 +
  11 +<script lang="ts" setup>
  12 +import { ref } from 'vue'
  13 +import { NDataTable,NDrawer, NDrawerContent, NSpace } from 'naive-ui'
  14 +import { dimensions, pagination } from '../config'
  15 +import type { sourceInterface } from '../config'
  16 +import dayjs from 'dayjs'
  17 +
  18 +// defineProps({
  19 +// modelShow: Boolean
  20 +// })
  21 +
  22 +const placement = ref('right')
  23 +
  24 +const modelShow =ref(false)
  25 +
  26 +const source =ref<sourceInterface[]>([])
  27 +
  28 +const setValue = (value: Recordable) => {
  29 + if (!value) return
  30 + source.value = Object.keys(value).map((item:string) => {
  31 + return {
  32 + key: item,
  33 + value: value[item][0].value,
  34 + lastUpdateTime: dayjs( value[item][0].ts).format('YYYY-MM-DD HH:mm:ss')
  35 + }
  36 + })
  37 +}
  38 +
  39 +const openDrawer = () => modelShow.value = true
  40 +
  41 +defineExpose({
  42 + setValue,
  43 + openDrawer
  44 +})
  45 +</script>
  46 +
  47 +<style lang="scss" scoped></style>
@@ -36,6 +36,32 @@ export const filterDevice = (items: any) => { @@ -36,6 +36,32 @@ export const filterDevice = (items: any) => {
36 } 36 }
37 } 37 }
38 38
  39 +export const dimensions= [
  40 + {
  41 + "title": "键",
  42 + "key": "key"
  43 + },
  44 + {
  45 + "title": "值",
  46 + "key": "value"
  47 + },
  48 + {
  49 + "title": "最后更新时间",
  50 + "key": "lastUpdateTime"
  51 + }
  52 +]
  53 +
  54 +export interface sourceInterface {
  55 + key: string
  56 + value: string
  57 + lastUpdateTime: string
  58 +}
  59 +
  60 +export const pagination = {
  61 + page: 1,
  62 + pageSize: 10
  63 +}
  64 +
39 export enum ThemeEnum { 65 export enum ThemeEnum {
40 NORMAL = 'normal', 66 NORMAL = 'normal',
41 DARK = 'dark', 67 DARK = 'dark',
1 <template> 1 <template>
2 - <div @mouseenter="handleMouseenter" @mouseleave="handleMouseleave" class="chart-amap" ref="vChartRef">  
3 - <!-- <div v-show="showSearchBox" @click.stop="handleOpenSearchBox" class="search-box"></div>  
4 - <search-box :modelShow="modelShow" @searchParams="handleSearchParams" @closeDrawer="handleCloseDrawer"></search-box> --> 2 + <div class="chart-amap" ref="vChartRef">
  3 + <device-latest-table ref="deviceLatestTableRef" :tbDeviceId="tbDeviceIdStr"></device-latest-table>
5 </div> 4 </div>
6 </template> 5 </template>
7 6
8 <script setup lang="ts"> 7 <script setup lang="ts">
9 -import { ref, PropType, toRefs, watch, render, h } from 'vue' 8 +import { ref, PropType, toRefs, watch, render, h, onMounted, onUnmounted} from 'vue'
10 import AMapLoader from '@amap/amap-jsapi-loader' 9 import AMapLoader from '@amap/amap-jsapi-loader'
11 import { CreateComponentType } from '@/packages/index.d' 10 import { CreateComponentType } from '@/packages/index.d'
12 import { useChartDataFetch } from '@/hooks' 11 import { useChartDataFetch } from '@/hooks'
@@ -17,9 +16,11 @@ import djh from './images/djh.png' @@ -17,9 +16,11 @@ import djh from './images/djh.png'
17 import online from './images/online.png' 16 import online from './images/online.png'
18 import lx1 from './images/lx1.png' 17 import lx1 from './images/lx1.png'
19 import onLineImg from './images/marker/3.png' 18 import onLineImg from './images/marker/3.png'
  19 +import listImg from './images/list.png'
20 import { getDeviceActiveTime } from '@/api/external/common/index' 20 import { getDeviceActiveTime } from '@/api/external/common/index'
21 import dayjs from 'dayjs' 21 import dayjs from 'dayjs'
22 -// import SearchBox from './components/SearchBox.vue' 22 +import DeviceLatestTable from './components/DeviceLatestTable.vue'
  23 +import { getDeviceLatest } from '@/api/external/common'
23 24
24 const props = defineProps({ 25 const props = defineProps({
25 chartConfig: { 26 chartConfig: {
@@ -28,9 +29,7 @@ const props = defineProps({ @@ -28,9 +29,7 @@ const props = defineProps({
28 } 29 }
29 }) 30 })
30 31
31 -// const modelShow = ref(false)  
32 -  
33 -const showSearchBox = ref(false) 32 +const deviceLatestTableRef = ref<Nullable<InstanceType<typeof DeviceLatestTable>>>(null);
34 33
35 const { 34 const {
36 amapKey, 35 amapKey,
@@ -88,7 +87,7 @@ const initMap = (newData: any) => { @@ -88,7 +87,7 @@ const initMap = (newData: any) => {
88 `amap://styles/${amapStyleKeyCustom.value !== '' ? amapStyleKeyCustom.value : amapStyleKey.value}` 87 `amap://styles/${amapStyleKeyCustom.value !== '' ? amapStyleKeyCustom.value : amapStyleKey.value}`
89 ) 88 )
90 } 89 }
91 - mapIns.on('mouseout', () => { 90 + mapIns.on('click', () => {
92 mapIns.clearInfoWindow() 91 mapIns.clearInfoWindow()
93 }) 92 })
94 }) 93 })
@@ -97,10 +96,14 @@ const initMap = (newData: any) => { @@ -97,10 +96,14 @@ const initMap = (newData: any) => {
97 }) 96 })
98 } 97 }
99 98
  99 +
  100 +const tbDeviceIdStr = ref('')
  101 +
100 //创建信息弹窗 102 //创建信息弹窗
101 const createInfoWindow = async (extraInfo: dataExtraInfoType) => { 103 const createInfoWindow = async (extraInfo: dataExtraInfoType) => {
102 try { 104 try {
103 const { name, alias, organizationDTO, deviceState, deviceProfile, deviceInfo, tbDeviceId } = extraInfo 105 const { name, alias, organizationDTO, deviceState, deviceProfile, deviceInfo, tbDeviceId } = extraInfo
  106 + tbDeviceIdStr.value = tbDeviceId
104 if (tbDeviceId.startsWith('@')) return //假的模拟数据则终止 107 if (tbDeviceId.startsWith('@')) return //假的模拟数据则终止
105 const res = await getDeviceActiveTime(tbDeviceId) //查询设备最后离线时间 108 const res = await getDeviceActiveTime(tbDeviceId) //查询设备最后离线时间
106 let { lastUpdateTs } = res[0] 109 let { lastUpdateTs } = res[0]
@@ -142,7 +145,10 @@ const createInfoWindow = async (extraInfo: dataExtraInfoType) => { @@ -142,7 +145,10 @@ const createInfoWindow = async (extraInfo: dataExtraInfoType) => {
142 </div>` 145 </div>`
143 } 146 }
144 </div> 147 </div>
145 - <div style="display:flex;flex-direction:column;justify-content:space-between;color:white;margin-top:2rem;gap:0.8rem;"> 148 + <div style="display:flex;justify-content:flex-end;cursor:pointer;" onclick="handleOpenDrawer()">
  149 + <img style="${deviceStateImg};position:relative;top:0.7rem" src="${listImg}"/>
  150 + </div>
  151 + <div style="display:flex;flex-direction:column;justify-content:space-between;color:white;margin-top:1rem;gap:0.8rem;">
146 <div style="${textOverflow}">所属组织:${organizationDTO.name}</div> 152 <div style="${textOverflow}">所属组织:${organizationDTO.name}</div>
147 <div style="${textOverflow}">接入协议:${deviceProfile.transportType}</div> 153 <div style="${textOverflow}">接入协议:${deviceProfile.transportType}</div>
148 <div style="${textOverflow}">设备位置:${!deviceInfo.address ? '该设备暂无地理位置' : deviceInfo.address}</div> 154 <div style="${textOverflow}">设备位置:${!deviceInfo.address ? '该设备暂无地理位置' : deviceInfo.address}</div>
@@ -156,37 +162,28 @@ const createInfoWindow = async (extraInfo: dataExtraInfoType) => { @@ -156,37 +162,28 @@ const createInfoWindow = async (extraInfo: dataExtraInfoType) => {
156 } 162 }
157 } 163 }
158 164
159 -const handleMouseenter = () => (showSearchBox.value = true)  
160 -  
161 -const handleMouseleave = () => (showSearchBox.value = false)  
162 -  
163 -// const handleOpenSearchBox = () => (modelShow.value = true) 165 +const handleOpenDrawer = async () => {
  166 + deviceLatestTableRef.value?.openDrawer()
  167 + if (!tbDeviceIdStr.value) return
  168 + const resp = await getDeviceLatest(tbDeviceIdStr.value)
  169 + deviceLatestTableRef.value?.setValue(resp)
  170 +}
164 171
165 -// const handleCloseDrawer = () => (modelShow.value = false) 172 +onMounted(() => {
  173 + (window as any).handleOpenDrawer = handleOpenDrawer;
  174 +});
166 175
167 -// const handleSearchParams = async (searchPage: any, params: any) => {  
168 -// try {  
169 -// Object.keys(params).forEach(item => {  
170 -// if (!params[item]) Reflect.deleteProperty(params, item)  
171 -// })  
172 -// const { items } = await getDeviceList(searchPage, params)  
173 -// const values = filterDevice(items)  
174 -// if (!values) return  
175 -// setTimeout(() => {  
176 -// dataHandle(values)  
177 -// }, 1000)  
178 -// } finally {  
179 -// handleCloseDrawer()  
180 -// }  
181 -// } 176 +onUnmounted(() => {
  177 + (window as any).handleOpenDrawer = null;
  178 +});
182 179
183 //地图鼠标hover 180 //地图鼠标hover
184 const mapClick = (markerInstance: any, markerItem: dataJsonMarkersType) => { 181 const mapClick = (markerInstance: any, markerItem: dataJsonMarkersType) => {
185 markerInstance.setExtData({ 182 markerInstance.setExtData({
186 extraInfo: markerItem.extraInfo 183 extraInfo: markerItem.extraInfo
187 }) 184 })
188 - // click  
189 - markerInstance.on('mouseover', async (e: any) => { 185 + // mouseover
  186 + markerInstance.on('click', async (e: any) => {
190 const { extraInfo } = e.target.getExtData() 187 const { extraInfo } = e.target.getExtData()
191 if (extraInfo.tbDeviceId.startsWith('@')) return //假的模拟数据则终止弹窗 188 if (extraInfo.tbDeviceId.startsWith('@')) return //假的模拟数据则终止弹窗
192 let infoWindow = new AMapIns.InfoWindow({ 189 let infoWindow = new AMapIns.InfoWindow({
@@ -195,9 +192,9 @@ const mapClick = (markerInstance: any, markerItem: dataJsonMarkersType) => { @@ -195,9 +192,9 @@ const mapClick = (markerInstance: any, markerItem: dataJsonMarkersType) => {
195 }) 192 })
196 infoWindow.open(mapIns, e.target.getPosition()) 193 infoWindow.open(mapIns, e.target.getPosition())
197 }) 194 })
198 - markerInstance.on('mouseout', () => {  
199 - mapIns.clearInfoWindow()  
200 - }) 195 + // markerInstance.on('click', () => {
  196 + // mapIns.clearInfoWindow()
  197 + // })
201 } 198 }
202 199
203 const dataHandle = (newData: dataJsonType) => { 200 const dataHandle = (newData: dataJsonType) => {