Compare commits

...

2 Commits

  1. 291
      web/src/components/VirtualCollapsePanel/index.vue
  2. 24
      web/src/views/HandDevice/Home/components/OpenLayerMap.vue
  3. 44
      web/src/views/HandDevice/Home/components/composables/useMapServices.ts
  4. 15
      web/src/views/HandDevice/Home/components/composables/useMapWatchers.ts
  5. 6
      web/src/views/HandDevice/Home/components/services/map.service.ts
  6. 149
      web/src/views/HandDevice/Home/components/services/marker.service.ts
  7. 2
      web/src/views/HandDevice/Home/components/utils/map.utils.ts
  8. 50
      web/src/views/HandDevice/Home/index.vue

291
web/src/components/VirtualCollapsePanel/index.vue

@ -1,229 +1,240 @@
<!-- 虚拟折叠面板 -->
<template>
<DynamicScroller
ref="scrollbarRef"
class="scroller"
:items="list"
:min-item-size="props.minItemSize"
:key-field="props.keyField"
v-slot="{ item, active }"
style="height: 100%"
@scroll="onScroll"
>
<DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.__expanded]">
<div class="collapse-header" @click="toggleExpand(item)">
<div class="collapse-header-left">
<slot name="header" :item="item">{{ item[props.nameField] }}</slot>
</div>
<DynamicScroller
ref="scrollbarRef"
class="scroller"
:items="list"
:min-item-size="props.minItemSize"
:key-field="props.keyField"
v-slot="{ item, active }"
style="height: 100%"
@scroll="onScroll"
>
<DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.__expanded]">
<div class="collapse-header" @click="toggleExpand(item)">
<div class="collapse-header-left">
<slot name="header" :item="item">{{ item[props.nameField] }}</slot>
</div>
<div class="collapse-header-right" v-if="props.showArrowRight">
<el-icon
class="arrow-right"
:class="{ 'rotate-icon': item.__expanded }"
:size="12"
:color="'#c1c1c1'"
>
<ArrowRight />
</el-icon>
</div>
</div>
<div class="collapse-header-right" v-if="props.showArrowRight">
<el-icon
class="arrow-right"
:class="{ 'rotate-icon': item.__expanded }"
:size="12"
:color="'#c1c1c1'"
>
<ArrowRight />
</el-icon>
</div>
</div>
<Transition name="fade" mode="out-in">
<div class="collapse-content" v-show="item.__expanded">
<slot name="content" :item="item"></slot>
</div>
</Transition>
</DynamicScrollerItem>
</DynamicScroller>
<Transition name="fade" mode="out-in">
<div class="collapse-content" v-show="item.__expanded">
<slot name="content" :item="item"></slot>
</div>
</Transition>
</DynamicScrollerItem>
</DynamicScroller>
</template>
<script setup lang="ts">
import { ref, computed, onBeforeUnmount, onDeactivated, useTemplateRef } from 'vue'
import { ref, computed, onBeforeUnmount, onDeactivated, useTemplateRef, nextTick } from 'vue'
import type { PropType } from 'vue'
import { ArrowRight } from '@element-plus/icons-vue'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'
const emit = defineEmits(['scroll'])
const props = defineProps({
data: {
type: Array as PropType<Record<string, any>[]>,
default: () => []
},
keyField: {
type: String,
default: 'id'
},
nameField: {
type: String,
default: 'name'
},
/** 每个项的最小高度 */
minItemSize: {
type: Number,
default: 48
},
showArrowRight: {
type: Boolean,
default: true
}
data: {
type: Array as PropType<Record<string, any>[]>,
default: () => []
},
keyField: {
type: String,
default: 'id'
},
nameField: {
type: String,
default: 'name'
},
/** 每个项的最小高度 */
minItemSize: {
type: Number,
default: 48
},
showArrowRight: {
type: Boolean,
default: true
}
})
const itemHeight = computed(() => props.minItemSize + 'px')
const activeItem = ref<Record<string, any> | null>(null)
const list = computed(() => {
console.time('list')
const activeItemId = activeItem.value ? activeItem.value[props.keyField] : null
const newList = props.data.map((listItem: Record<string, any>) => {
return {
...listItem,
__expanded: activeItemId && listItem[props.keyField] === activeItemId ? true : false
}
})
console.timeEnd('list')
return newList
console.time('list')
const activeItemId = activeItem.value ? activeItem.value[props.keyField] : null
const newList = props.data.map((listItem: Record<string, any>) => {
return {
...listItem,
__expanded: activeItemId && listItem[props.keyField] === activeItemId ? true : false
}
})
console.timeEnd('list')
return newList
})
const scrollbarRef = useTemplateRef('scrollbarRef')
const scrollbarScrollTop = ref(0)
function onScroll(e) {
scrollbarScrollTop.value = e.target.scrollTop
emit('scroll', e)
// console.log('scroll-end',e);
scrollbarScrollTop.value = e.target.scrollTop
// emit('scroll', e)
}
/**
* 切换折叠面板展开状态
* @param item 要切换展开状态的项
*/
function toggleExpand(item) {
activeItem.value = item.__expanded ? null : item
activeItem.value = item.__expanded ? null : item
}
/**
* 滚动到指定项
* @param item 要滚动到的项
*/
function scrollToItem(item) {
if (!item) return
activeItem.value = item
const findIndex = list.value.findIndex((i) => i[props.keyField] === item[props.keyField])
if (findIndex === -1) {
return
}
const top = props.minItemSize * findIndex
//
cancelAnimationFrame(AnimationId.value as number)
scrollTo(scrollbarScrollTop.value, top, scrollbarScrollTop.value)
if (!item) return
activeItem.value = item
const findIndex = list.value.findIndex((i) => i[props.keyField] === item[props.keyField])
if (findIndex === -1) {
return
}
const top = props.minItemSize * findIndex
//
cancelAnimationFrame(AnimationId.value as number)
scrollTo(scrollbarScrollTop.value, top, scrollbarScrollTop.value)
}
/**
* 滚动到指定索引项
* @param index 要滚动到的索引项
*/
function scrollToIndex(index) {
if (index < 0 || index >= list.value.length) return
if (index < 0 || index >= list.value.length) return
activeItem.value = list.value[index]
activeItem.value = list.value[index]
const top = props.minItemSize * index
// const top = props.minItemSize * index
// console.log('top', top)
const top = props.minItemSize * index
//
cancelAnimationFrame(AnimationId.value as number)
scrollTo(scrollbarScrollTop.value, top, scrollbarScrollTop.value)
// //
// cancelAnimationFrame(AnimationId.value as number)
// scrollTo(scrollbarScrollTop.value, top, scrollbarScrollTop.value)
// nextTick(() => {
// // scrollbarRef.value?.scrollToItem(index)
// scrollbarRef.value?.$refs?.scroller?.scrollToPosition(top)
// })
setTimeout(() => {
scrollbarRef.value?.$refs?.scroller?.scrollToPosition(top)
}, 200)
}
/**
* 滚动到指定位置
* @param position 要滚动到的位置
*/
function scrollToPosition(position: number) {
if (position < 0) return
//
cancelAnimationFrame(AnimationId.value as number)
scrollTo(scrollbarScrollTop.value, position, scrollbarScrollTop.value)
if (position < 0) return
//
cancelAnimationFrame(AnimationId.value as number)
scrollTo(scrollbarScrollTop.value, position, scrollbarScrollTop.value)
}
//
const AnimationId = ref<number>()
function scrollTo(from: number, to: number, current: number) {
if (scrollbarScrollTop.value === to) {
return
}
const speed = (to - from) / 30
if (scrollbarScrollTop.value === to) {
return
}
const speed = (to - from) / props.minItemSize
if (speed < 0) {
if (current <= to) {
return
}
} else if (speed > 0) {
if (current >= to) {
return
}
if (speed < 0) {
if (current <= to) {
return
}
} else if (speed > 0) {
if (current >= to) {
return
}
current = current + speed
}
current = current + speed
// DynamicScrollerRecycleScrollerRecycleScroller
scrollbarRef.value?.$refs?.scroller?.scrollToPosition(current)
AnimationId.value = requestAnimationFrame(() => {
scrollTo(from, to, current)
})
// DynamicScrollerRecycleScrollerRecycleScroller
scrollbarRef.value?.$refs?.scroller?.scrollToPosition(current)
AnimationId.value = requestAnimationFrame(() => {
scrollTo(from, to, current)
})
}
onDeactivated(() => {
//
cancelAnimationFrame(AnimationId.value as number)
//
cancelAnimationFrame(AnimationId.value as number)
})
onBeforeUnmount(() => {
//
cancelAnimationFrame(AnimationId.value as number)
//
cancelAnimationFrame(AnimationId.value as number)
})
defineExpose({
toggleExpand,
scrollToItem,
scrollToIndex,
scrollToPosition
toggleExpand,
scrollToItem,
scrollToIndex,
scrollToPosition
})
</script>
<style lang="scss" scoped>
.collapse-header {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
overflow: hidden;
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
overflow: hidden;
height: v-bind(itemHeight);
padding: 0 4px;
cursor: pointer;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
.collapse-header-left {
font-size: 12px;
color: #303133;
flex: 1;
}
height: v-bind(itemHeight);
padding: 0 4px;
cursor: pointer;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
.collapse-header-left {
font-size: 12px;
color: #303133;
flex: 1;
}
}
.collapse-content {
transform-origin: top;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
transform-origin: top;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
// collapse-content
.fade-enter-active,
.fade-leave-active {
transition: all 0.2s ease;
transition: all 0.1s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: scaleY(0);
opacity: 0;
transform: scaleY(0);
}
.arrow-right {
transition: all 0.2s ease;
transition: all 0.2s ease;
}
.rotate-icon {
transform: rotate(90deg);
transform: rotate(90deg);
}
::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.1) !important;
border-radius: 4px;
background: rgba(0, 0, 0, 0.1) !important;
border-radius: 4px;
}
::-webkit-scrollbar {
width: 8px;
background-color: #f5f5f5;
width: 8px;
background-color: #f5f5f5;
}
</style>

24
web/src/views/HandDevice/Home/components/OpenLayerMap.vue

@ -93,8 +93,7 @@ const {
setTrajectoriesVisible,
setFencesVisible,
toggleFenceDrawing,
clearFenceDrawLayer,
updateMarkers
clearFenceDrawLayer
} = useMapServices()
const {
@ -175,22 +174,21 @@ const init = () => {
{
isDrawing: () => !!services.fenceDrawService?.isCurrentlyDrawing?.(),
onMarkerClick: (marker: MarkerData) => {
console.log('marker clicked', marker)
// console.log('marker clicked', marker)
emit('on-click-marker', marker)
},
onClusterClick: (features: FeatureLike[]) => {
console.log('onClusterClick', features)
// console.log('onClusterClick', features)
const markerCoords = features.map((feature) => feature.get('markerData').coordinates)
services.mapService?.fitToMarkers(markerCoords)
},
onZoomEnd: (zoom: number) => {
console.log('onZoomEnd', zoom)
//
// services.markerService?.createMarkerLayerFromProps(props)
services.markerService?.setClusterDistance()
services.markerService?.getSinglePointsInView()
// console.log('marker', marker)
}
}
)
@ -252,6 +250,7 @@ const setCenter = (coords: [number, number]) => {
if (isMapInitialized) {
services.mapService?.setCenter(coords)
services.mapService?.setZoom(17)
}
}
/**
@ -290,25 +289,24 @@ const refreshFences = () => {
watch(
() => props.markers,
(newMarkers, oldMarkers) => {
updateMarkers(newMarkers, props)
if (newMarkers.length !== oldMarkers.length) {
console.log('markers changed', newMarkers, oldMarkers)
services.markerService?.updateData(newMarkers)
if (oldMarkers == undefined || newMarkers.length !== oldMarkers.length) {
fitToMarkers()
}
},
{ deep: true, immediate: false }
{ deep: false, immediate: true }
)
watch(
() => props.fences,
() => {
refreshFences()
},
{ deep: true, immediate: false }
{ deep: false, immediate: false }
)
onMounted(() => {
setTimeout(() => {
init()
}, 100)
init()
})
defineExpose({ refreshFences, fitToMarkers, setCenter, showTrajectory })

44
web/src/views/HandDevice/Home/components/composables/useMapServices.ts

@ -16,7 +16,7 @@ import { FenceDrawService } from '../services/fence-draw.service'
interface ServiceInstances {
mapService: MapService | null
markerService: MarkerService | null
popupService: PopupService | null
trajectoryService: TrajectoryService | null
fenceService: FenceService | null
@ -28,7 +28,7 @@ export const useMapServices = () => {
const services: ServiceInstances = {
mapService: null,
markerService: null,
popupService: null,
trajectoryService: null,
fenceService: null,
@ -48,14 +48,12 @@ export const useMapServices = () => {
// 重新初始化服务,确保markerService有地图实例
services.mapService = mapService
services.markerService = new MarkerService(mapService.map)
services.popupService = new PopupService()
services.trajectoryService = new TrajectoryService(mapService.map)
services.fenceService = new FenceService(mapService.map)
services.fenceDrawService = new FenceDrawService(mapService.map)
// 创建marker图层
services.markerService.createMarkerLayer(props)
// 创建轨迹图层
services.trajectoryService.createTrajectoryLayer()
// 创建围栏图层
@ -70,10 +68,8 @@ export const useMapServices = () => {
const setMarkersVisible = (visible: boolean) => {
if (visible) {
services.markerService?.show()
} else {
services.markerService?.hide()
}
}
@ -129,35 +125,7 @@ export const useMapServices = () => {
}
}
/**
*
*/
const updateMarkers = (markers: any[], currentProps?: MapProps) => {
if (services.markerService) {
const map = services.mapService?.getMap()
if (map) {
// console.log('updateMarkers', markers)
// 更新marker service(这可能会创建新的layer)
console.time('createMarkerLayer');
services.markerService.createMarkerLayer({
...currentProps,
markers
})
console.timeEnd('createMarkerLayer');
}
}
}
/**
*
*/
const refreshMarkerStyles = () => {
if (services.markerService) {
services.markerService.refreshStyles()
}
}
/**
*
*/
@ -204,8 +172,8 @@ export const useMapServices = () => {
setFencesVisible,
toggleFenceDrawing,
clearFenceDrawLayer,
updateMarkers,
refreshMarkerStyles,
destroyServices
}
}

15
web/src/views/HandDevice/Home/components/composables/useMapWatchers.ts

@ -86,21 +86,6 @@ export const useMapWatchers = (options: WatchOptions) => {
})
}
/**
*
*/
// const setupMarkersDataWatcher = () => {
// return watch(
// markers,
// (newMarkers = []) => {
// // if (newMarkers && newMarkers.length > 0) {
// console.log('Markers data changed, updating markers:', newMarkers.length)
// updateMarkers(newMarkers)
// // }
// },
// { deep: true, immediate: false }
// )
// }
/**
*

6
web/src/views/HandDevice/Home/components/services/map.service.ts

@ -108,7 +108,11 @@ export class MapService {
center = fromLonLat(center)
this.map.getView().setCenter(center)
}
// 设置缩放级别
setZoom(zoom: number): void {
if (!this.map) return
this.map.getView().setZoom(zoom)
}
/**
*
*/

149
web/src/views/HandDevice/Home/components/services/marker.service.ts

@ -13,14 +13,13 @@ import { AnimationService } from './animation.service'
import type { MarkerData, MapProps } from '../types/map.types'
import { createMarkerStyle, getClusterMarkerData, getStatusColor } from '../utils/map.utils'
import { ANIMATION_CONFIG } from '../constants/map.constants'
// 防抖
import { debounce } from 'lodash-es'
export class MarkerService {
private map: Map | null = null
markerLayer: VectorLayer<VectorSource | Cluster> | null = null
// 当前图层模式(single或cluster聚合):避免重复创建图层
private currentLayerMode: 'single' | 'cluster' | '' = ''
markerLayer: VectorLayer<Cluster> | null = null
private vectorSource: VectorSource
private animationService: AnimationService | null = null
@ -28,6 +27,7 @@ export class MarkerService {
this.map = map
this.vectorSource = new VectorSource()
this.animationService = new AnimationService(map)
this.createMarkerLayer()
}
show() {
this.markerLayer?.setVisible(true)
@ -37,27 +37,14 @@ export class MarkerService {
this.markerLayer?.setVisible(false)
this.animationService?.hide()
}
/**
*
*/
createMarkerLayer = debounce((props: MapProps) => {
console.time('updateData')
this.updateData(props)
console.timeEnd('updateData')
console.time('createMarkerLayerFromProps')
this.createMarkerLayerFromProps(props)
console.timeEnd('createMarkerLayerFromProps')
}, 1000)
/**
*
*/
updateData(props: MapProps): void {
updateData(markers: MarkerData[]): void {
this.animationService?.clear()
this.vectorSource.clear()
// 添加标记
const markers = props.markers || []
// debugger
const features: Feature<Point>[] = []
markers.forEach((marker) => {
const feature = new Feature({
@ -72,7 +59,7 @@ export class MarkerService {
this.vectorSource.addFeatures(features)
this.getSinglePointsInView()
}
setClusterDistance= debounce(()=> {
setClusterDistance = debounce(() => {
if (!this.map) return
const clusterLayer = this.markerLayer
if (!clusterLayer) return
@ -80,20 +67,20 @@ export class MarkerService {
if (!clusterSource) return
const zoom = this.map.getView().getZoom() || 0
let distance = 2
if (zoom <= 4) {
if (zoom <= 4) {
distance = 100
}else if (zoom <= 6) {
} else if (zoom <= 6) {
distance = 80
} else if (zoom <= 10) {
distance = 30
} else if (zoom <= 16) {
distance = 30
}else if (zoom <= 17) {
} else if (zoom <= 17) {
distance = 10
}
console.log('zoom',zoom,'distance',distance)
console.log('zoom', zoom, 'distance', distance)
clusterSource?.setDistance(distance)
},200)
}, 200)
/**
*
* @returns {Array}
@ -107,6 +94,7 @@ export class MarkerService {
// 获取聚合图层的源
const clusterSource = clusterLayer.getSource()
if (!clusterSource) return
// 获取当前视图范围
const view = map.getView()
@ -117,7 +105,7 @@ export class MarkerService {
// console.log('featuresInView',featuresInView)
featuresInView.forEach((clusterFeature) => {
// 关键:获取聚合要素中包含的所有原始要素
const originalFeatures = clusterFeature.get('features')
const originalFeatures = clusterFeature.get('features')
// console.log('originalFeatures',originalFeatures);
if (originalFeatures && originalFeatures.length === 1) {
@ -127,89 +115,51 @@ export class MarkerService {
}
})
this.animationService?.addAll(singlePoints || [])
return singlePoints
},300)
}, 300)
/**
* props创建markerLayer
*
*/
// : VectorLayer<VectorSource | Cluster>
createMarkerLayerFromProps(props: MapProps) {
// console.log('createMarkerLayerFromProps')
// this.updateData(props)
createMarkerLayer() {
let newLayer: VectorLayer<Cluster> | null = null
// 检查是否应该强制使用单个marker模式
const shouldForceSingleMark = () => {
if (!props.forceSingleMark || !this.map) return false
const currentZoom = this.map.getView().getZoom()
console.log('聚合图层')
return currentZoom && currentZoom >= ANIMATION_CONFIG.clusterThreshold
}
const clusterSource = new Cluster({
source: this.vectorSource,
distance: 20 // 单位是像素
})
let newLayer: VectorLayer<VectorSource | Cluster> | null = null
// 如果启用聚合且不强制使用单个marker模式
if (props.enableCluster && !shouldForceSingleMark()) {
if (this.currentLayerMode === 'cluster') return
this.currentLayerMode = 'cluster'
// this.animationService?.clear()
console.log('聚合图层')
const clusterSource = new Cluster({
source: this.vectorSource,
distance: 20 // 单位是像素
})
newLayer = new VectorLayer({
source: clusterSource,
zIndex: 1,
style: (feature) => {
// 视图变化新视口内所有要素的样式重计算​ (如平移、缩放),所以不能调用this.animationService?.add
const features = feature.get('features')
newLayer = new VectorLayer({
source: clusterSource,
zIndex: 1,
style: (feature) => {
// 视图变化新视口内所有要素的样式重计算​ (如平移、缩放),所以不能调用this.animationService?.add
const features = feature.get('features')
// 确保features存在且不为空
if (!features || features.length === 0) {
return new Style() // 返回空样式,隐藏无效的feature
}
// console.log('聚合元素', features)
if (features.length === 1) {
// 单个marker
const markerData: MarkerData = features[0].get('markerData')
return markerData ? createMarkerStyle(markerData.statusColor || '') : new Style()
} else {
// 聚合marker
const highestStatus = getClusterMarkerData(features)
const color = getStatusColor(highestStatus)
return createMarkerStyle(color, true, features.length)
}
// 确保features存在且不为空
if (!features || features.length === 0) {
return new Style() // 返回空样式,隐藏无效的feature
}
})
} else {
if (this.currentLayerMode === 'single') return
this.currentLayerMode = 'single'
console.log('基础marker图层')
newLayer = new VectorLayer({
source: this.vectorSource,
zIndex: 1,
renderOrder: (a, b) => {
// 按xxx属性排列
return b.get('markerData').statusPriority - a.get('markerData').statusPriority
}
})
}
// console.log('聚合元素', features)
if (this.markerLayer) {
const isVisible = this.markerLayer?.getVisible() || false
newLayer.setVisible(isVisible) // 新图层保持当前可见状态
this.map?.removeLayer(this.markerLayer)
}
if (features.length === 1) {
// 单个marker
const markerData: MarkerData = features[0].get('markerData')
return markerData ? createMarkerStyle(markerData.statusColor || '') : new Style()
} else {
// 聚合marker
const highestStatus = getClusterMarkerData(features)
const color = getStatusColor(highestStatus)
return createMarkerStyle(color, true, features.length)
}
}
})
this.markerLayer = newLayer
this.map?.addLayer(this.markerLayer)
@ -230,8 +180,7 @@ export class MarkerService {
destroy(): void {
this.markerLayer = null
this.animationService?.destroy()
// this.currentProps = null
this.createMarkerLayer.cancel()
this.map = null
}
}

2
web/src/views/HandDevice/Home/components/utils/map.utils.ts

@ -158,7 +158,7 @@ export const createMarkerStyle = (
styleCache[key]= new Style({
image: new Circle({
radius: Math.min(20 + clusterSize, 40),
radius: Math.min(20 + clusterSize/4, 40),
fill: new Fill({
color: color + '80' // 添加透明度
}),

50
web/src/views/HandDevice/Home/index.vue

@ -30,10 +30,7 @@
<template #header="{ item }">
<div class="marker-item">
<div class="flex-1 text-13px"> {{ item.name }}</div>
<div
class="text-12px pr-1"
:style="{ color: item.statusColor }"
>
<div class="text-12px pr-1" :style="{ color: item.statusColor }">
{{ item.statusLabel }}
</div>
</div>
@ -113,7 +110,7 @@ import { MarkerData, FenceData } from './components/types/map.types'
import { useHandDetectorStore } from '@/store/modules/handDetector'
import { ElMessage, ElScrollbar } from 'element-plus'
import dayjs, { Dayjs } from 'dayjs'
import dayjs from 'dayjs'
import { getDistance } from 'ol/sphere'
import { shallowRef } from 'vue'
const componentsIsActive = ref(false)
@ -126,7 +123,7 @@ const fences = ref<FenceData[]>([])
const mapRef = ref<InstanceType<typeof OpenLayerMap>>()
const search = ref('')
const selectStatus = ref(['normal', 'offline', 'fenceStatus_1', 'alarm','batteryStatus_1'])
const selectStatus = ref(['normal', 'offline', 'fenceStatus_1', 'alarm', 'batteryStatus_1'])
watch(
() => search.value,
(newSearch, oldSearch) => {
@ -152,33 +149,30 @@ const filterMarkers = computed(() => {
})
}
if (selectStatus.value.length !== 0) {
arr = arr.filter((item) => {
// console.log('selectStatus', selectStatus.value,item.statusStr);
// console.log('selectStatus', selectStatus.value,item.statusStr);
if (!item.statusStr) {
return true
}
if (item.statusStr == 'gasStatus_2' || item.statusStr == 'gasStatus_1') {
return selectStatus.value.includes('alarm')
}
// if (item.statusStr == 'fenceStatus_1') {
// return selectStatus.value.includes('fenceStatus_1')
// }
return selectStatus.value.includes(item.statusStr)
})
}
// console.log('markers.value', markers.value)
return arr
})
const filterMarkers2 = function getFilterMarkers2() {
var arr: MarkerData[] = []
var nowTime=dayjs().format('YYYY-MM-DD HH:mm:ss')
for (let i = 0; i < 10000; i++) {
const lon= 80+Math.random()*20
const lat= 30+Math.random()*20
var nowTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
for (let i = 0; i < 50000; i++) {
const lon = 100 + Math.random() * 2
const lat = 30 + Math.random() * 2
arr.push({
id: i + 1,
sn: '867989072728120',
@ -222,17 +216,14 @@ const filterMarkers2 = function getFilterMarkers2() {
expanded: false
})
}
markers.value=arr
markers.value = arr
}
const getMarkers = async () => {
console.log('getMarkers')
return await getLastDetectorData().then((res: HandDetectorData[]) => {
console.time('getLastDetectorData');
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, //
@ -252,13 +243,13 @@ const getMarkers = async () => {
}
})
.sort((a, b) => a.statusPriority - b.statusPriority)
console.timeEnd('getLastDetectorData');
markers.value = res2
})
}
const getFences = async () => {
return await handDetectorStore.getAllFences().then((res) => {
// console.log('getFences', res)
let fencesData = res
.map((i) => {
return {
@ -272,7 +263,6 @@ const getFences = async () => {
}
//
function setCenter(item: MarkerData) {
console.log('setCenter', item)
if (item.longitude && item.latitude) {
mapRef.value?.setCenter([item.longitude || 0, item.latitude || 0])
}
@ -396,13 +386,11 @@ async function showTrajectory(item: MarkerData) {
const historicalCurveRef = ref<InstanceType<typeof HistoricalCurve>>()
// 线
function onClickHistoricalCurve(item: MarkerData) {
// console.log('onClickHistoricalCurve', item)
historicalCurveRef.value?.openDrawer(toRaw(item))
}
//
function onClickTrajectory(item: MarkerData) {
console.log('onClickTrajectory', item)
trajectoryTimeRange.value = [dayjs().subtract(1, 'hour').valueOf(), dayjs().valueOf()]
showTrajectory(item)
}
@ -410,20 +398,18 @@ function onClickTrajectory(item: MarkerData) {
const scrollbarRef = useTemplateRef<InstanceType<typeof VirtualCollapsePanel>>('scrollbarRef')
//
function onClickMarker(markerItem: MarkerData) {
console.log('onClickMarker', markerItem)
var findIndex = filterMarkers.value.findIndex((item) => item.id === markerItem.id)
if (findIndex === -1) {
return
}
setTimeout(() => {
scrollbarRef.value?.scrollToIndex(findIndex)
}, 300)
// console.log('findIndex', findIndex, filterMarkers.value[findIndex])
scrollbarRef.value?.scrollToIndex(findIndex)
}
onMounted(() => {
getMarkers()
// filterMarkers2()
// filterMarkers2()
getFences()
@ -466,7 +452,7 @@ onUnmounted(() => {
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
padding: 5px 0 10px 10px;
margin-left: 10px;
.marker-item {
display: flex;
flex-direction: row;

Loading…
Cancel
Save