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.

223 lines
7.0 KiB

2 weeks ago
/**
*
*/
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 => {
2 weeks ago
const info = findStatusInfo(STATUS_DICT[type], value)
return info ? `${type}_${value}` : ''
2 weeks ago
}
// 获取状态优先级,越小优先级越高
export const getStatusPriority = (statusStr: string | keyof typeof STATUS_PRIORITY): number => {
return STATUS_PRIORITY[statusStr] || 0
}
2 weeks ago
/**
*
*/
export const getHighestPriorityStatus = (markerData: {
gasStatus?: number
batteryStatus?: number
fenceStatus?: number
onlineStatus?: number
}): keyof typeof STATUS_PRIORITY => {
const statuses: string[] = []
2 weeks ago
// 收集非正常状态
if (markerData.gasStatus !== 0) {
const gasStatusStr = getStatusMapping('gasStatus', String(markerData.gasStatus))
gasStatusStr && statuses.push(gasStatusStr)
}
if (markerData.batteryStatus !== 0) {
const batteryStatusStr = getStatusMapping('batteryStatus', String(markerData.batteryStatus))
statuses.push(batteryStatusStr)
}
if (markerData.fenceStatus !== 0) {
const fenceStatusStr = getStatusMapping('fenceStatus', String(markerData.fenceStatus))
fenceStatusStr && statuses.push(fenceStatusStr)
}
// 检查各种状态
const onlineStatus = String(markerData.onlineStatus) === '0' ? 'offline' : null
if (onlineStatus) {
statuses.push(onlineStatus)
}
// console.log('statuses', statuses)
2 weeks ago
// 如果没有报警状态,则为正常
if (statuses.length === 0) return 'normal'
// 返回优先级最高的状态
return statuses.reduce((prev, current) =>
STATUS_PRIORITY[prev] < STATUS_PRIORITY[current] ? prev : current
) as keyof typeof STATUS_PRIORITY
2 weeks ago
}
/**
*
*/
export const getStatusColor = (status: string | keyof typeof STATUS_PRIORITY): string => {
2 weeks ago
if (status === 'normal') return '#67c23a'
if (status === 'offline') return STATUS_DICT.onlineStatus[0].cssClass
2 weeks ago
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 => {
2 weeks ago
if (status === 'normal') return '正常'
if (status === 'offline') return STATUS_DICT.onlineStatus[0].label
2 weeks ago
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 || '-'
}
2 weeks ago
/**
* SVG
*/
export const createLocationIconSVG = (color: string, size: number = 24) => {
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 = (
statusStr: keyof typeof STATUS_PRIORITY,
2 weeks ago
isCluster: boolean = false,
clusterSize?: number
) => {
// 如果是字符串,说明是状态值
// const statusStr:string =
// typeof markerData === 'string'
// ? (markerData as keyof typeof STATUS_PRIORITY)
// : getHighestPriorityStatus(markerData)
2 weeks ago
const color = getStatusColor(statusStr)
2 weeks ago
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(color, 24),
scale: 1,
1 week ago
anchor: [0.5, 0.8], // 锚点设置在底部中心
2 weeks ago
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>
`
/**
* HTML
*/
export const createClusterPopupHTML = (detectorList: DetectorInfo[]) => {
const 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[] = []
2 weeks ago
features.forEach((feature) => {
const markerData = feature.get('markerData') as MarkerData
if (markerData) {
const status = getHighestPriorityStatus(markerData)
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
2 weeks ago
}
/**
*
*/
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
})
}