You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

335 lines
10 KiB

<template>
<div class="flex flex-row overflow-auto" style="height: calc(100vh - 160px)">
<div class="flex-1 h-full position-relative">
<OpenLayerMap
ref="mapRef"
class="map-container"
:showDrawFences="true"
:showTrajectories="true"
:markers="filterMarkers"
:fences="fences"
@time-range-change="timeRangeChange"
/>
<TopPanel
v-model="search"
:handDetectorCount="handDetectorCount"
:onlineCount="onlineCount"
/>
</div>
<div class="markerList">
<el-scrollbar height="100%">
<!--marker列表 -->
<el-collapse accordion>
<el-collapse-item :name="item.sn" v-for="item in filterMarkers" :key="item.id">
<template #title>
<div class="flex flex-row w-100%">
<div class="flex-1 text-left font-500">
{{ item.name }}
</div>
<div class="text-gray-500 font-400 text-12px" :style="{ color: item.statusColor }">
{{ item.statusLabel }}
</div>
</div>
</template>
<div class="markerList-content">
<div><span>SN:</span>{{ item.sn }}</div>
<div><span>类型:</span>{{ item.gasChemical }}</div>
<!-- <hr /> -->
<div
><span>气体状态:</span
>{{ getLabelWithTypeValue('gasStatus', item.gasStatus) }}</div
>
<div
><span>围栏状态:</span
>{{ getLabelWithTypeValue('fenceStatus', item.fenceStatus) }}</div
>
<div
><span>电池状态:</span
>{{ getLabelWithTypeValue('batteryStatus', item.batteryStatus) }}</div
>
<!-- <div><span>启用状态:</span>{{ item.enableStatus === 1 ? '启用' : '备用' }}</div> -->
<!-- <hr /> -->
<div><span>电量:</span>{{ item.battery }}</div>
<div><span>数值:</span>{{ item.value }} {{ item.unit }}</div>
<div><span>时间:</span>{{ item.timeStr }}</div>
<div style="margin-top: 10px">
<el-button
type="success"
size="small"
v-if="item.latitude && item.longitude"
@click="setCenter(item)"
>定位</el-button
>
<el-button type="success" size="small" @click="onClickTrajectory(item)"
>轨迹</el-button
>
</div>
<!-- {{ item }} -->
</div>
</el-collapse-item>
</el-collapse>
</el-scrollbar>
<!-- <div v-for="item in filterMarkers" :key="item.id" class="marker-item">
<div>{{ item.name }}:{{ item.onlineStatus === 1 ? '在线' : '离线' }}</div>
</div> -->
</div>
</div>
</template>
<script lang="ts" setup>
import OpenLayerMap from './components/OpenLayerMap.vue'
import TopPanel from './components/TopPanel.vue'
import { getLastDetectorData } from '@/api/gas'
import { HandDetectorData } from '@/api/gas/handdetector'
import { tdengineApi, tdStruct, tdQuery } from '@/api/gas/tdengine/index'
import { getLabelWithTypeValue, getHighestPriorityStatus,getStatusLabel,getStatusColor } from './components/utils/map.utils'
import { MarkerData, FenceData } from './components/types/map.types'
import { useHandDetectorStore } from '@/store/modules/handDetector'
import { ElMessage } from 'element-plus'
import dayjs from 'dayjs'
import { getDistance } from 'ol/sphere'
const handDetectorStore = useHandDetectorStore() // 手持探测器 store
const getDataTimer = ref<NodeJS.Timeout | null>(null)
const markers = ref<MarkerData[]>([])
const fences = ref<FenceData[]>([])
const mapRef = ref<typeof OpenLayerMap>()
const search = ref('')
watch(
() => search.value,
(newSearch, oldSearch) => {
if (newSearch !== oldSearch) {
mapRef.value?.fitToMarkers()
}
},
{ immediate: false }
)
// 手持设备数量
const handDetectorCount = computed(() => markers.value.length)
const onlineCount = computed(() => markers.value.filter((item) => item.onlineStatus === 1).length)
const filterMarkers = computed(() => {
if (search.value) {
return markers.value.filter((item) => {
var isName = item?.name?.includes(search.value)
var isSn = item.sn?.includes(search.value)
var isGasChemical = item.gasChemical?.includes(search.value)
return isName || isSn || isGasChemical
})
}
return markers.value
})
const getMarkers = async () => {
console.log('getMarkers')
return await getLastDetectorData().then((res: HandDetectorData[]) => {
res = res.filter((i) => i.enableStatus === 1)
var res2 = res.map((i) => {
// console.log([i.longitude, i.latitude])
let statusStr = getHighestPriorityStatus({
gasStatus: i.gasStatus, //气体报警状态
batteryStatus: i.batteryStatus, //电池报警状态
fenceStatus: i.fenceStatus, //电子围栏报警状态
onlineStatus: i.onlineStatus, //在线状态
}) //状态字符串
return {
...i,
coordinates: [i.longitude || 0, i.latitude || 0] as [number,number],
// data: [],
timeStr: i.time ? dayjs(i.time).format('YYYY-MM-DD HH:mm:ss') : '',
// value: i.value,
// unit: i.unit,
// gasStatus: i.gasStatus, //气体报警状态
// batteryStatus: i.batteryStatus, //电池报警状态
// fenceStatus: i.fenceStatus, //电子围栏报警状态
// onlineStatus: i.onlineStatus, //在线状态
// enableStatus: i.enableStatus, //启用状态
statusStr:statusStr, //状态字符串
statusColor: getStatusColor(statusStr), //状态颜色
statusLabel: getStatusLabel(statusStr), //状态标签
}
})
markers.value = res2
})
}
const getFences = async () => {
return await handDetectorStore.getAllFences().then((res) => {
// console.log('getFences', res)
let fencesData = res
.map((i) => {
return {
...i,
fenceRange: JSON.parse(i.fenceRange)
}
})
.filter((i) => i.status === 1)
fences.value = fencesData as unknown as FenceData[]
})
}
// 定位到手持设备
function setCenter(item: MarkerData) {
console.log('setCenter', item)
if (item.longitude && item.latitude) {
mapRef.value?.setCenter([item.longitude || 0, item.latitude || 0])
}
}
let currentMarker: MarkerData | null = null
var trajectoryTimeRange = ref([dayjs().subtract(1, 'hour').valueOf(), dayjs().valueOf()])
// 时间范围改变
function timeRangeChange(range: { startTime: number; endTime: number }) {
console.log('timeRangeChange', range)
trajectoryTimeRange.value = [range.startTime, range.endTime]
if (currentMarker) {
showTrajectory(currentMarker)
}
}
// 显示手持设备轨迹
async function showTrajectory(item: MarkerData) {
console.log('showTrajectory', item)
try {
if (!item.sn) {
ElMessage.error('手持设备无效')
return
}
currentMarker = item
const data = await tdengineApi.getHistoricalSn({
sn: item.sn,
startTime: dayjs(trajectoryTimeRange.value[0]).format('YYYY-MM-DD HH:mm:ss'),
endTime: dayjs(trajectoryTimeRange.value[1]).format('YYYY-MM-DD HH:mm:ss')
// sn: '867989072729904'
})
// 过滤前
console.log('过滤前', data.length)
// 过滤掉重复点位和无效点位
var newData = data.filter((item, index, arr) => {
if (!item.longitude || !item.latitude) {
return false
}
if (index === 0) {
return true
}
// 过滤掉前后点位一样的
return (
item.longitude !== arr[index - 1]?.longitude || item.latitude !== arr[index - 1]?.latitude
)
})
// 过滤后
console.log('过滤后', newData.length)
item.data = newData
.filter((item, index, arr) => {
if (index === 0) {
return true
}
if (index == arr.length - 2) {
return true
}
// 过滤掉前后点位相差超过100m的
let before = arr[index - 1]
let after = arr[index + 1]
let beforeDistance = getDistance(
[before.longitude, before.latitude],
[item.longitude, item.latitude]
)
console.log('beforeDistance', beforeDistance)
if (beforeDistance < 40) {
return true
}
let afterDistance = getDistance(
[after.longitude, after.latitude],
[item.longitude, item.latitude]
)
console.log('afterDistance', afterDistance)
if (afterDistance < 40) {
return true
}
let before_after_distance = getDistance(
[after.longitude, after.latitude],
[before.longitude, before.latitude]
)
console.log('before_after_distance', before_after_distance)
if (before_after_distance < 20) {
return true
}
return false
})
.map((j) => {
return {
...j,
lng: j.longitude,
lat: j.latitude,
time: dayjs(j.ts).format('YYYY-MM-DD HH:mm:ss'),
timeStr: dayjs(j.ts).format('YYYY-MM-DD HH:mm:ss')
}
})
console.log('item.data', item.data)
mapRef.value?.showTrajectory(trajectoryTimeRange.value[0], trajectoryTimeRange.value[1], [item])
} finally {
}
}
// 点击轨迹
function onClickTrajectory(item: MarkerData) {
console.log('onClickTrajectory', item)
trajectoryTimeRange.value = [dayjs().subtract(1, 'hour').valueOf(), dayjs().valueOf()]
showTrajectory(item)
}
onMounted(() => {
getMarkers()
getFences()
console.log('定时器,暂时关掉,太烦了')
getDataTimer.value = setInterval(() => {
getMarkers()
getFences()
}, 5000)
})
onUnmounted(() => {
clearInterval(getDataTimer.value as NodeJS.Timeout)
})
</script>
<style scoped lang="scss">
.map-container {
width: 100%;
height: 100%;
}
.markerList {
width: 240px;
height: 100%;
overflow: hidden;
background-color: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
padding: 0 10px;
margin-left: 10px;
.markerList-content {
padding: 10px;
font-size: 12px;
span {
display: inline-block;
min-width: 70px;
}
}
}
</style>