Commit fc25d5e8ba05b1e66ab36b6646d288732701239d

Authored by fengwotao
1 parent 1e80cb7f

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

... ... @@ -16,7 +16,8 @@ enum Api {
16 16 VIDEOURL = '/video/url/',
17 17 GEOJSONURL = '/map/geo_json/',
18 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 23 export const getDictItemByCode = (value: string) => {
... ... @@ -127,3 +128,11 @@ export const getAttribute = (deviceProfileId: string) =>
127 128 defHttp.get({
128 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 +})
\ No newline at end of file
... ...
  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 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 65 export enum ThemeEnum {
40 66 NORMAL = 'normal',
41 67 DARK = 'dark',
... ...
1 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 4 </div>
6 5 </template>
7 6
8 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 9 import AMapLoader from '@amap/amap-jsapi-loader'
11 10 import { CreateComponentType } from '@/packages/index.d'
12 11 import { useChartDataFetch } from '@/hooks'
... ... @@ -17,9 +16,11 @@ import djh from './images/djh.png'
17 16 import online from './images/online.png'
18 17 import lx1 from './images/lx1.png'
19 18 import onLineImg from './images/marker/3.png'
  19 +import listImg from './images/list.png'
20 20 import { getDeviceActiveTime } from '@/api/external/common/index'
21 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 25 const props = defineProps({
25 26 chartConfig: {
... ... @@ -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 34 const {
36 35 amapKey,
... ... @@ -88,7 +87,7 @@ const initMap = (newData: any) => {
88 87 `amap://styles/${amapStyleKeyCustom.value !== '' ? amapStyleKeyCustom.value : amapStyleKey.value}`
89 88 )
90 89 }
91   - mapIns.on('mouseout', () => {
  90 + mapIns.on('click', () => {
92 91 mapIns.clearInfoWindow()
93 92 })
94 93 })
... ... @@ -97,10 +96,14 @@ const initMap = (newData: any) => {
97 96 })
98 97 }
99 98
  99 +
  100 +const tbDeviceIdStr = ref('')
  101 +
100 102 //创建信息弹窗
101 103 const createInfoWindow = async (extraInfo: dataExtraInfoType) => {
102 104 try {
103 105 const { name, alias, organizationDTO, deviceState, deviceProfile, deviceInfo, tbDeviceId } = extraInfo
  106 + tbDeviceIdStr.value = tbDeviceId
104 107 if (tbDeviceId.startsWith('@')) return //假的模拟数据则终止
105 108 const res = await getDeviceActiveTime(tbDeviceId) //查询设备最后离线时间
106 109 let { lastUpdateTs } = res[0]
... ... @@ -142,7 +145,10 @@ const createInfoWindow = async (extraInfo: dataExtraInfoType) => {
142 145 </div>`
143 146 }
144 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 152 <div style="${textOverflow}">所属组织:${organizationDTO.name}</div>
147 153 <div style="${textOverflow}">接入协议:${deviceProfile.transportType}</div>
148 154 <div style="${textOverflow}">设备位置:${!deviceInfo.address ? '该设备暂无地理位置' : deviceInfo.address}</div>
... ... @@ -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 180 //地图鼠标hover
184 181 const mapClick = (markerInstance: any, markerItem: dataJsonMarkersType) => {
185 182 markerInstance.setExtData({
186 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 187 const { extraInfo } = e.target.getExtData()
191 188 if (extraInfo.tbDeviceId.startsWith('@')) return //假的模拟数据则终止弹窗
192 189 let infoWindow = new AMapIns.InfoWindow({
... ... @@ -195,9 +192,9 @@ const mapClick = (markerInstance: any, markerItem: dataJsonMarkersType) => {
195 192 })
196 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 200 const dataHandle = (newData: dataJsonType) => {
... ...