|
|
|
|
/**
|
|
|
|
|
* 地图工具函数
|
|
|
|
|
*/
|
|
|
|
|
import { Style, Text, Circle, Fill, Stroke, Icon } from 'ol/style'
|
|
|
|
|
import { Feature } from 'ol'
|
|
|
|
|
import type { MarkerData, DetectorInfo } from '../types/map.types'
|
|
|
|
|
import { STATUS_DICT, STATUS_PRIORITY, STATUS_ORDER } from '../constants/map.constants'
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 从字典中查找状态信息
|
|
|
|
|
*/
|
|
|
|
|
export const findStatusInfo = (
|
|
|
|
|
dict: (typeof STATUS_DICT)[keyof typeof STATUS_DICT],
|
|
|
|
|
value: string
|
|
|
|
|
) => {
|
|
|
|
|
return dict?.find((item) => item.value === value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取状态映射
|
|
|
|
|
*/
|
|
|
|
|
export const getStatusMapping = (type: keyof typeof STATUS_DICT, value: string): string => {
|
|
|
|
|
const info = findStatusInfo(STATUS_DICT[type], value)
|
|
|
|
|
return info ? `${type}_${value}` : ''
|
|
|
|
|
}
|
|
|
|
|
// 获取状态优先级,越小优先级越高
|
|
|
|
|
export const getStatusPriority = (statusStr: string | keyof typeof STATUS_PRIORITY): number => {
|
|
|
|
|
return STATUS_PRIORITY[statusStr] || 0
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 根据字典数据获取设备最高优先级状态
|
|
|
|
|
*/
|
|
|
|
|
export const getHighestPriorityStatus = (markerData: {
|
|
|
|
|
gasStatus?: number
|
|
|
|
|
batteryStatus?: number
|
|
|
|
|
fenceStatus?: number
|
|
|
|
|
onlineStatus?: number
|
|
|
|
|
}): keyof typeof STATUS_PRIORITY => {
|
|
|
|
|
const statuses: string[] = []
|
|
|
|
|
|
|
|
|
|
// 收集非正常状态
|
|
|
|
|
if (markerData.gasStatus === 1) {
|
|
|
|
|
const gasStatusStr = getStatusMapping('gasStatus', String(markerData.gasStatus))
|
|
|
|
|
gasStatusStr && statuses.push(gasStatusStr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (markerData.batteryStatus === 1) {
|
|
|
|
|
const batteryStatusStr = getStatusMapping('batteryStatus', String(markerData.batteryStatus))
|
|
|
|
|
statuses.push(batteryStatusStr)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (markerData.fenceStatus === 1) {
|
|
|
|
|
const fenceStatusStr = getStatusMapping('fenceStatus', String(markerData.fenceStatus))
|
|
|
|
|
fenceStatusStr && statuses.push(fenceStatusStr)
|
|
|
|
|
}
|
|
|
|
|
// 检查各种状态
|
|
|
|
|
const onlineStatus = String(markerData.onlineStatus) !== '1' ? 'offline' : null
|
|
|
|
|
if (onlineStatus) {
|
|
|
|
|
statuses.push(onlineStatus)
|
|
|
|
|
}
|
|
|
|
|
// console.log('statuses', statuses)
|
|
|
|
|
|
|
|
|
|
// 如果没有报警状态,则为正常
|
|
|
|
|
if (statuses.length === 0) return 'normal'
|
|
|
|
|
|
|
|
|
|
// 返回优先级最高的状态
|
|
|
|
|
return statuses.reduce((prev, current) =>
|
|
|
|
|
STATUS_PRIORITY[prev] < STATUS_PRIORITY[current] ? prev : current
|
|
|
|
|
) as keyof typeof STATUS_PRIORITY
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据字典数据获取状态颜色
|
|
|
|
|
*/
|
|
|
|
|
export const getStatusColor = (status: string | keyof typeof STATUS_PRIORITY): string => {
|
|
|
|
|
if (status === 'normal') return '#67c23a'
|
|
|
|
|
if (status === 'offline') return STATUS_DICT.onlineStatus[0].cssClass
|
|
|
|
|
// 安全校验,确保状态字符串格式正确
|
|
|
|
|
if (!status.includes('_')) return ''
|
|
|
|
|
|
|
|
|
|
const [type, value] = status.split('_') as [keyof typeof STATUS_DICT, string]
|
|
|
|
|
const info = findStatusInfo(STATUS_DICT[type], value)
|
|
|
|
|
return info?.cssClass || '#67c23a'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据字典数据获取状态标签
|
|
|
|
|
*/
|
|
|
|
|
export const getStatusLabel = (status: string | keyof typeof STATUS_PRIORITY): string => {
|
|
|
|
|
if (status === 'normal') return '正常'
|
|
|
|
|
if (status === 'offline') return STATUS_DICT.onlineStatus[0].label
|
|
|
|
|
// 安全校验,确保状态字符串格式正确
|
|
|
|
|
if (!status.includes('_')) return ''
|
|
|
|
|
|
|
|
|
|
const [type, value] = status.split('_') as [keyof typeof STATUS_DICT, string]
|
|
|
|
|
const info = findStatusInfo(STATUS_DICT[type], value)
|
|
|
|
|
return info?.label || '正常'
|
|
|
|
|
}
|
|
|
|
|
export const getLabelWithTypeValue = (type: string, value: number | undefined): string => {
|
|
|
|
|
if (value === undefined) return '-'
|
|
|
|
|
const info = findStatusInfo(STATUS_DICT[type], String(value))
|
|
|
|
|
return info?.label || '-'
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 创建开始位置图标SVG
|
|
|
|
|
*/
|
|
|
|
|
export const createStartIconSVG = (size: number = 24, color: string = '#1296db') => {
|
|
|
|
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(`
|
|
|
|
|
<svg width="${size}" height="${size}" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
|
|
<path d="M998.4 968.533333c-132.266667 0-209.066667-8.533333-256-21.333333v-64h51.2c12.8 0 25.6-12.8 25.6-25.6s-12.8-25.6-25.6-25.6h-51.2v-42.666667h51.2c12.8 0 25.6-12.8 25.6-25.6s-12.8-25.6-25.6-25.6h-51.2v-42.666666h51.2c12.8 0 25.6-12.8 25.6-25.6s-12.8-25.6-25.6-25.6h-51.2v-34.133334c0-12.8-12.8-25.6-25.6-25.6s-25.6 12.8-25.6 25.6v34.133334H640c-12.8 0-25.6 12.8-25.6 25.6s12.8 25.6 25.6 25.6h51.2v42.666666H640c-12.8 0-25.6 12.8-25.6 25.6s12.8 25.6 25.6 25.6h51.2v128c-8.533333-8.533333-17.066667-21.333333-25.6-29.866666v-46.933334c0-12.8-12.8-25.6-25.6-25.6s-25.6 12.8-25.6 25.6c0 38.4 0 110.933333-21.333333 136.533334-8.533333 12.8-4.266667 25.6 4.266666 34.133333 4.266667 4.266667 8.533333 4.266667 12.8 4.266667 8.533333 0 17.066667-4.266667 21.333334-12.8 8.533333-12.8 17.066667-34.133333 21.333333-51.2 51.2 46.933333 136.533333 64 341.333333 64 12.8 0 25.6-12.8 25.6-25.6s-8.533333-21.333333-21.333333-21.333334z" p-id="13416" fill="${color}"></path>
|
|
|
|
|
<path d="M998.4 840.533333c-12.8 0-25.6 12.8-25.6 25.6v17.066667c0 4.266667 0 4.266667-4.266667 4.266667h-68.266666l-4.266667-4.266667v-93.866667h93.866667c12.8 0 25.6-12.8 25.6-25.6v-93.866666c0-12.8-12.8-25.6-25.6-25.6h-119.466667c-12.8 0-25.6 12.8-25.6 25.6s12.8 25.6 25.6 25.6h93.866667v42.666666h-93.866667c-12.8 0-25.6 12.8-25.6 25.6v119.466667c0 17.066667 4.266667 29.866667 17.066667 38.4 8.533333 8.533333 25.6 17.066667 38.4 17.066667h68.266666c29.866667 0 55.466667-25.6 55.466667-55.466667v-17.066667c0-12.8-12.8-25.6-25.6-25.6zM516.266667 819.2c-21.333333-12.8-46.933333-8.533333-59.733334 12.8-12.8 17.066667-21.333333 34.133333-25.6 55.466667-4.266667 8.533333-8.533333 21.333333-12.8 29.866666-4.266667-8.533333-8.533333-21.333333-12.8-34.133333-25.6-72.533333-81.066667-128-179.2-200.533333C136.533333 622.933333 85.333333 524.8 85.333333 418.133333 85.333333 234.666667 234.666667 85.333333 418.133333 85.333333s332.8 149.333333 332.8 332.8c0 21.333333 0 42.666667-4.266666 64s8.533333 46.933333 34.133333 51.2c21.333333 4.266667 46.933333-8.533333 51.2-34.133333 4.266667-25.6 8.533333-55.466667 8.533333-81.066667 0-230.4-187.733333-418.133333-418.133333-418.133333S0 187.733333 0 418.133333c0 136.533333 64 260.266667 174.933333 337.066667 93.866667 72.533333 132.266667 115.2 149.333334 162.133333 17.066667 46.933333 34.133333 98.133333 85.333333 102.4h8.533333c55.466667 0 72.533333-55.466667 89.6-110.933333 4.266667-12.8 8.533333-25.6 17.066667-34.133333 17.066667-17.066667 8.533333-42.666667-8.533333-55.466667z" fill="${color}"></path>
|
|
|
|
|
<path d="M418.133333 200.533333c-119.466667 0-213.333333 93.866667-213.333333 213.333334s93.866667 213.333333 213.333333 213.333333 213.333333-93.866667 213.333334-213.333333c0-115.2-98.133333-213.333333-213.333334-213.333334z m0 341.333334c-72.533333 0-128-55.466667-128-128s55.466667-128 128-128 128 55.466667 128 128-59.733333 128-128 128z" p-id="13418" fill="${color}"></path>
|
|
|
|
|
</svg>
|
|
|
|
|
`)}`
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 创建结束位置图标SVG
|
|
|
|
|
*/
|
|
|
|
|
export const createEndIconSVG = (size: number = 24, color: string = '#dd4e3b') => {
|
|
|
|
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(`
|
|
|
|
|
<svg width="${size}" height="${size}" viewBox="0 0 1025 1024" xmlns="http://www.w3.org/2000/svg">
|
|
|
|
|
<path d="M820.049793 497.128631c4.248963-25.493776 8.497925-55.236515 8.497925-80.730291 0-229.443983-186.954357-416.39834-416.39834-416.39834S0 191.20332 0 420.647303c0 135.966805 63.73444 259.186722 174.207469 335.66805 93.477178 72.232365 131.717842 114.721992 148.713693 161.460581 16.995851 46.738589 33.991701 97.726141 84.979253 101.975103h8.497925c55.236515 0 72.232365-55.236515 89.228216-110.473029 4.248963-12.746888 8.497925-25.493776 16.995851-33.991701 12.746888-21.244813 8.497925-46.738589-12.746888-59.485477-21.244813-12.746888-46.738589-8.497925-59.485478 12.746888-12.746888 16.995851-21.244813 33.991701-25.493775 55.236514-4.248963 8.497925-8.497925 21.244813-12.746888 29.742739-4.248963-8.497925-8.497925-21.244813-12.746888-33.991701-25.493776-72.232365-80.73029-127.46888-178.456432-199.701245-84.979253-55.236515-135.966805-152.962656-135.966805-259.186722C84.979253 237.941909 233.692946 89.228216 416.39834 89.228216s331.419087 148.713693 331.419087 331.419087c0 21.244813 0 42.489627-4.248962 63.73444s8.497925 46.738589 33.991701 50.987552c16.995851 0 38.240664-12.746888 42.489627-38.240664z" fill="${color}"></path>
|
|
|
|
|
<path d="M416.39834 203.950207c-118.970954 0-212.448133 93.477178-212.448133 212.448133s93.477178 212.448133 212.448133 212.448133 212.448133-93.477178 212.448133-212.448133c0-114.721992-97.726141-212.448133-212.448133-212.448133z m0 339.917013c-72.232365 0-127.46888-55.236515-127.468879-127.46888s55.236515-127.46888 127.468879-127.468879 127.46888 55.236515 127.46888 127.468879-59.485477 127.46888-127.46888 127.46888zM590.605809 900.780083c4.248963 8.497925 12.746888 12.746888 21.244813 12.746888h4.248963l110.473029-29.742739c12.746888-4.248963 21.244813-16.995851 16.995851-29.742738-4.248963-12.746888-16.995851-21.244813-29.742739-16.995851l-42.489626 12.746888 59.485477-80.73029c4.248963-8.497925 8.497925-16.995851 0-29.742739s-12.746888-12.746888-21.244814-12.746888l-46.738589 4.248963 67.983403-106.224067c8.497925-12.746888 4.248963-25.493776-8.497926-33.991701-12.746888-8.497925-25.493776-4.248963-33.991701 8.497925l-101.975104 148.713693c-4.248963 8.497925-4.248963 16.995851 0 25.493776 4.248963 8.497925 12.746888 12.746888 25.493776 12.746888l42.489627-4.248962-67.983403 89.228215c0 8.497925 0 21.244813 4.248963 29.742739zM726.572614 917.775934l-118.970954 29.742738c-12.746888 4.248963-21.244813 16.995851-16.995851 29.742739 4.248963 12.746888 12.746888 21.244813 25.493776 21.244813h4.248963l118.970954-29.742739c12.746888-4.248963 21.244813-16.995851 16.995851-29.742738-4.248963-16.995851-16.995851-25.493776-29.742739-21.244813zM1002.755187 820.049793c-29.742739-8.497925-55.236515-25.493776-76.481328-42.489627 46.738589-50.987552 63.73444-101.975104 63.73444-106.224066 4.248963-8.497925 0-16.995851-4.248963-21.244814s-8.497925-8.497925-16.995851-8.497925h-80.73029c4.248963-12.746888 8.497925-21.244813 8.497925-21.244813 4.248963-12.746888-4.248963-29.742739-16.99585-33.991702-12.746888-4.248963-29.742739 4.248963-33.991702 16.995851 0 0-25.493776 67.983402-72.232365 114.721992-8.497925 8.497925-12.746888 25.493776 0 33.991701 4.248963 4.248963 12.746888 8.497925 16.995851 8.497925 4.248963 0 12.746888-4.248963 16.995851-8.497925l16.99585-16.995851c8.497925 12.746888 16.995851 25.493776 29.742739 38.240664-21.244813 12.746888-42.489627 29.742739-72.232365 38.240664-12.746888 4.248963-21.244813 21.244813-16.995851 33.991701 4.248963 8.497925 12.746888 16.995851 25.493776 16.995851h8.497925c33.991701-12.746888 63.73444-29.742739 89.228216-46.738589 25.493776 21.244813 59.485477 42.489627 97.726141 55.236514h8.497925c12.746888 0 21.244813-8.497925 25.493776-16.99585 4.248963-16.995851-4.248963-29.742739-16.99585-33.991701zM892.282158 743.568465c-16.995851-21.244813-25.493776-38.240664-33.991702-50.987552h67.983403c-8.497925 12.746888-16.995851 29.742739-33.991701 50.987552z" fill="${color}"></path>
|
|
|
|
|
<path d="M926.273859 926.273859h8.497925c8.497925 0 21.244813-4.248963 25.493776-16.995851 4.248963-12.746888 0-29.742739-12.746888-33.991701l-72.232365-21.244813c-12.746888-4.248963-29.742739 0-33.991701 12.746888-4.248963 12.746888 0 29.742739 12.746888 33.991701l72.232365 25.493776zM960.26556 973.012448l-101.975104-46.738589c-12.746888-4.248963-29.742739 0-33.991701 12.746888-4.248963 12.746888 0 29.742739 12.746888 33.991701l101.975104 46.738589c4.248963 0 8.497925 4.248963 8.497925 4.248963 8.497925 0 16.995851-4.248963 21.244813-16.995851 12.746888-16.995851 4.248963-29.742739-8.497925-33.991701z" fill="${color}"></path>
|
|
|
|
|
</svg>
|
|
|
|
|
`)}`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 创建位置图标SVG
|
|
|
|
|
*/
|
|
|
|
|
export const createLocationIconSVG = (size: number = 24,color: string='#1296db') => {
|
|
|
|
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(`
|
|
|
|
|
<svg width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
|
|
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z" fill="${color}"/>
|
|
|
|
|
<circle cx="12" cy="9" r="2" fill="white"/>
|
|
|
|
|
</svg>
|
|
|
|
|
`)}`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 创建标记样式
|
|
|
|
|
*/
|
|
|
|
|
export const createMarkerStyle = (
|
|
|
|
|
color: string,
|
|
|
|
|
isCluster: boolean = false,
|
|
|
|
|
clusterSize?: number
|
|
|
|
|
) => {
|
|
|
|
|
if (isCluster && clusterSize) {
|
|
|
|
|
// 聚合标记样式
|
|
|
|
|
return new Style({
|
|
|
|
|
image: new Circle({
|
|
|
|
|
radius: Math.min(20 + clusterSize * 2, 40),
|
|
|
|
|
fill: new Fill({
|
|
|
|
|
color: color + '80' // 添加透明度
|
|
|
|
|
}),
|
|
|
|
|
stroke: new Stroke({
|
|
|
|
|
color: color,
|
|
|
|
|
width: 2
|
|
|
|
|
})
|
|
|
|
|
}),
|
|
|
|
|
text: new Text({
|
|
|
|
|
text: clusterSize.toString(),
|
|
|
|
|
fill: new Fill({
|
|
|
|
|
color: '#ffffff'
|
|
|
|
|
}),
|
|
|
|
|
font: 'bold 14px Arial'
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
// 单个标记样式 - 使用位置图标
|
|
|
|
|
return new Style({
|
|
|
|
|
image: new Icon({
|
|
|
|
|
src: createLocationIconSVG(24,color),
|
|
|
|
|
scale: 1,
|
|
|
|
|
anchor: [0.5, 0.8], // 锚点设置在底部中心
|
|
|
|
|
anchorXUnits: 'fraction',
|
|
|
|
|
anchorYUnits: 'fraction'
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成探测器列表项HTML
|
|
|
|
|
*/
|
|
|
|
|
export const createDetectorListItem = (detector: DetectorInfo) => `
|
|
|
|
|
<div style="display: flex; align-items: center; padding: 6px 0; border-bottom: 1px solid #f0f0f0;">
|
|
|
|
|
<div style="width: 10px; height: 10px; border-radius: 50%; background-color: ${detector.statusColor}; margin-right: 10px; flex-shrink: 0;"></div>
|
|
|
|
|
<div style="flex: 1; min-width: 0;">
|
|
|
|
|
<div style="font-weight: 500; font-size: 13px; color: #333; margin-bottom: 2px;">${detector.name}</div>
|
|
|
|
|
<div style="color: ${detector.statusColor}; font-size: 11px; font-weight: 400;">${detector.statusLabel}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
`
|
|
|
|
|
export const createDetectorListItem2 = (type: string, label: string, count: number) => {
|
|
|
|
|
if (count === 0) return ''
|
|
|
|
|
return `
|
|
|
|
|
<div style="display: flex; align-items: center; padding: 6px 0; border-bottom: 1px solid #f0f0f0;">
|
|
|
|
|
<div style="width: 50px; margin-right: 10px; flex-shrink: 0;">
|
|
|
|
|
${label}
|
|
|
|
|
</div>
|
|
|
|
|
<div style="flex: 1; min-width: 0;">
|
|
|
|
|
<div style="font-weight: 400;">${count}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成聚合标记弹窗HTML
|
|
|
|
|
*/
|
|
|
|
|
export const createClusterPopupHTML = (detectorList: DetectorInfo[]) => {
|
|
|
|
|
let detectorListHTML = ''
|
|
|
|
|
if (detectorList.length > 5) {
|
|
|
|
|
// 正常探测器数量
|
|
|
|
|
const normalCount = detectorList.filter((detector) => detector.status === 'normal').length
|
|
|
|
|
// if (normalCount === detectorList.length) return ''
|
|
|
|
|
|
|
|
|
|
// 气体报警数量
|
|
|
|
|
const gasAlarmCount = detectorList.filter(
|
|
|
|
|
(detector) => detector.status === 'gasStatus_1'
|
|
|
|
|
).length
|
|
|
|
|
// 围栏报警
|
|
|
|
|
const fenceAlarmCount = detectorList.filter(
|
|
|
|
|
(detector) => detector.status === 'fenceStatus_1'
|
|
|
|
|
).length
|
|
|
|
|
// 低电量数量
|
|
|
|
|
const lowBatteryCount = detectorList.filter(
|
|
|
|
|
(detector) => detector.status === 'batteryStatus_1'
|
|
|
|
|
).length
|
|
|
|
|
// 离线探测器数量
|
|
|
|
|
const offlineCount = detectorList.filter((detector) => detector.status === 'offline').length
|
|
|
|
|
|
|
|
|
|
detectorListHTML =
|
|
|
|
|
createDetectorListItem2('gasAlarm', '气体报警', gasAlarmCount) +
|
|
|
|
|
createDetectorListItem2('fenceAlarm', '围栏报警', fenceAlarmCount) +
|
|
|
|
|
createDetectorListItem2('lowBattery', '低电量', lowBatteryCount) +
|
|
|
|
|
createDetectorListItem2('offline', '离线', offlineCount) +
|
|
|
|
|
createDetectorListItem2('normal', '正常', normalCount)
|
|
|
|
|
// `
|
|
|
|
|
|
|
|
|
|
// <div style="font-size: 12px; color: #666; margin-bottom: 8px;">
|
|
|
|
|
// <div>气体报警${gasAlarmCount}个</div>
|
|
|
|
|
// <div>围栏报警${fenceAlarmCount}个</div>
|
|
|
|
|
// <div>离线${offlineCount}个</div>
|
|
|
|
|
// <div>低电量${lowBatteryCount}个</div>
|
|
|
|
|
// <div>正常${normalCount}个</div>
|
|
|
|
|
// </div>
|
|
|
|
|
|
|
|
|
|
// `
|
|
|
|
|
} else {
|
|
|
|
|
detectorListHTML = detectorList.map(createDetectorListItem).join('')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return `
|
|
|
|
|
<div style="max-height: 250px; overflow-y: auto; padding-right: 4px;">
|
|
|
|
|
${detectorListHTML}
|
|
|
|
|
</div>
|
|
|
|
|
`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取聚合标记数据
|
|
|
|
|
*/
|
|
|
|
|
export const getClusterMarkerData = (features: Feature[]): keyof typeof STATUS_PRIORITY => {
|
|
|
|
|
// 收集所有标记的状态
|
|
|
|
|
const allStatuses: string[] = []
|
|
|
|
|
|
|
|
|
|
features.forEach((feature) => {
|
|
|
|
|
const markerData = feature.get('markerData') as MarkerData
|
|
|
|
|
if (markerData) {
|
|
|
|
|
const status = markerData.statusStr || ''
|
|
|
|
|
allStatuses.push(status)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 返回优先级最高的状态
|
|
|
|
|
if (allStatuses.length === 0) return 'normal'
|
|
|
|
|
|
|
|
|
|
return allStatuses.reduce((prev, current) =>
|
|
|
|
|
STATUS_PRIORITY[prev] < STATUS_PRIORITY[current] ? prev : current
|
|
|
|
|
) as keyof typeof STATUS_PRIORITY
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 按优先级排序探测器列表
|
|
|
|
|
*/
|
|
|
|
|
export const sortDetectorsByPriority = (detectorList: DetectorInfo[]): DetectorInfo[] => {
|
|
|
|
|
return detectorList.sort((a, b) => {
|
|
|
|
|
const aPriority = STATUS_ORDER.indexOf(a.status as keyof typeof STATUS_PRIORITY)
|
|
|
|
|
const bPriority = STATUS_ORDER.indexOf(b.status as keyof typeof STATUS_PRIORITY)
|
|
|
|
|
return aPriority - bPriority
|
|
|
|
|
})
|
|
|
|
|
}
|