feat(aerial): CCTV 안전관리 감지 기능 추가 (선박 출입, 침입 감지)

This commit is contained in:
Nan Kyung Lee 2026-03-09 10:39:14 +09:00
부모 9574594151
커밋 5b734d3cf1
2개의 변경된 파일48개의 추가작업 그리고 0개의 파일을 삭제

파일 보기

@ -12,6 +12,8 @@ interface CCTVPlayerProps {
sourceNm?: string | null;
cellIndex?: number;
oilDetectionEnabled?: boolean;
vesselDetectionEnabled?: boolean;
intrusionDetectionEnabled?: boolean;
}
export interface CCTVPlayerHandle {
@ -36,6 +38,8 @@ export const CCTVPlayer = forwardRef<CCTVPlayerHandle, CCTVPlayerProps>(({
sourceNm,
cellIndex = 0,
oilDetectionEnabled = false,
vesselDetectionEnabled = false,
intrusionDetectionEnabled = false,
}, ref) => {
const videoRef = useRef<HTMLVideoElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
@ -309,6 +313,24 @@ export const CCTVPlayer = forwardRef<CCTVPlayerHandle, CCTVPlayerProps>(({
/>
)}
{/* 안전관리 감지 상태 배지 */}
{(vesselDetectionEnabled || intrusionDetectionEnabled) && (
<div className="absolute top-2 right-2 flex flex-col gap-1 z-20">
{vesselDetectionEnabled && (
<div className="flex items-center gap-1 px-1.5 py-0.5 rounded text-[8px] font-bold"
style={{ background: 'rgba(59,130,246,.3)', color: '#93c5fd' }}>
🚢
</div>
)}
{intrusionDetectionEnabled && (
<div className="flex items-center gap-1 px-1.5 py-0.5 rounded text-[8px] font-bold"
style={{ background: 'rgba(249,115,22,.3)', color: '#fdba74' }}>
🚨
</div>
)}
</div>
)}
{/* OSD 오버레이 */}
<div className="absolute top-2 left-2 flex items-center gap-1.5 z-20">
<span className="text-[9px] font-bold px-1.5 py-0.5 rounded bg-black/70 text-white">

파일 보기

@ -56,6 +56,8 @@ export function CctvView() {
const [gridMode, setGridMode] = useState(1)
const [activeCells, setActiveCells] = useState<CctvCameraItem[]>([])
const [oilDetectionEnabled, setOilDetectionEnabled] = useState(false)
const [vesselDetectionEnabled, setVesselDetectionEnabled] = useState(false)
const [intrusionDetectionEnabled, setIntrusionDetectionEnabled] = useState(false)
const playerRefs = useRef<(CCTVPlayerHandle | null)[]>([])
const loadData = useCallback(async () => {
@ -240,6 +242,28 @@ export function CctvView() {
>
{oilDetectionEnabled ? '🛢 감지 ON' : '🛢 오일 감지'}
</button>
<button
onClick={() => setVesselDetectionEnabled(v => !v)}
className="px-2.5 py-1 border rounded-[5px] text-[10px] font-semibold cursor-pointer font-korean transition-colors"
style={vesselDetectionEnabled
? { background: 'rgba(59,130,246,.15)', borderColor: 'rgba(59,130,246,.4)', color: 'var(--blue, #3b82f6)' }
: { background: 'var(--bg3)', borderColor: 'var(--bd)', color: 'var(--t2)' }
}
title={gridMode === 9 ? '9분할 모드에서는 비활성화됩니다' : '선박 출입 감지'}
>
{vesselDetectionEnabled ? '🚢 감지 ON' : '🚢 선박 출입'}
</button>
<button
onClick={() => setIntrusionDetectionEnabled(v => !v)}
className="px-2.5 py-1 border rounded-[5px] text-[10px] font-semibold cursor-pointer font-korean transition-colors"
style={intrusionDetectionEnabled
? { background: 'rgba(249,115,22,.15)', borderColor: 'rgba(249,115,22,.4)', color: 'var(--orange, #f97316)' }
: { background: 'var(--bg3)', borderColor: 'var(--bd)', color: 'var(--t2)' }
}
title={gridMode === 9 ? '9분할 모드에서는 비활성화됩니다' : '침입 감지'}
>
{intrusionDetectionEnabled ? '🚨 감지 ON' : '🚨 침입 감지'}
</button>
<button
onClick={() => {
playerRefs.current.forEach(r => r?.capture())
@ -269,6 +293,8 @@ export function CctvView() {
sourceNm={cam.sourceNm}
cellIndex={i}
oilDetectionEnabled={oilDetectionEnabled && gridMode !== 9}
vesselDetectionEnabled={vesselDetectionEnabled && gridMode !== 9}
intrusionDetectionEnabled={intrusionDetectionEnabled && gridMode !== 9}
/>
) : (
<div className="text-[10px] text-text-3 font-korean opacity-40"> </div>