import { useRef, useMemo } from 'react'; import * as THREE from 'three'; import { useFrame } from '@react-three/fiber'; import { DEVICE_POSITIONS, PV_ARRAY, COLORS } from '../constants'; interface PVPanelsProps { devices: Array<{ id: number; code: string; status: string; power?: number; rated_power?: number }>; hoveredId: number | null; onHover: (id: number | null) => void; onClick: (device: { id: number; code: string; status: string; power?: number; rated_power?: number }) => void; detailMode?: boolean; } const PV_ZONES = [ { code: 'PV-INV-01', center: DEVICE_POSITIONS['PV-INV-01'].position }, { code: 'PV-INV-02', center: DEVICE_POSITIONS['PV-INV-02'].position }, { code: 'PV-INV-03', center: DEVICE_POSITIONS['PV-INV-03'].position }, ] as const; function PVZone({ center, device, isHovered, onHover, onClick, }: { center: readonly [number, number, number]; device: { id: number; code: string; status: string; power?: number; rated_power?: number } | undefined; isHovered: boolean; onHover: (id: number | null) => void; onClick: (device: { id: number; code: string; status: string; power?: number; rated_power?: number }) => void; }) { const groupRef = useRef(null); const panels = useMemo(() => { const items: { pos: [number, number, number] }[] = []; const { cols, rows, panelWidth, panelHeight, gap } = PV_ARRAY; const totalW = cols * panelWidth + (cols - 1) * gap; const totalD = rows * panelHeight + (rows - 1) * gap; for (let r = 0; r < rows; r++) { for (let c = 0; c < cols; c++) { const x = -totalW / 2 + panelWidth / 2 + c * (panelWidth + gap); const z = -totalD / 2 + panelHeight / 2 + r * (panelHeight + gap); items.push({ pos: [x, 0, z] }); } } return items; }, []); const ratio = device && device.rated_power ? (device.power ?? 0) / device.rated_power : 0; const emissiveIntensity = Math.min(ratio * 0.5, 0.5); return ( { e.stopPropagation(); if (device) onHover(device.id); }} onPointerOut={(e) => { e.stopPropagation(); onHover(null); }} onClick={(e) => { e.stopPropagation(); if (device) onClick(device); }} > {panels.map((p, i) => ( ))} ); } export default function PVPanels({ devices, hoveredId, onHover, onClick }: PVPanelsProps) { const deviceMap = useMemo(() => { const map = new Map(); devices.forEach((d) => map.set(d.code, d)); return map; }, [devices]); return ( {PV_ZONES.map((zone) => { const device = deviceMap.get(zone.code); return ( ); })} ); }