map-view.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. "use client"
  2. import {MapContainer, Marker, Popup, TileLayer} from "react-leaflet"
  3. import {Icon} from "leaflet"
  4. import "leaflet/dist/leaflet.css"
  5. // 修复 Leaflet 默认图标问题
  6. const createCustomIcon = (status: string) => {
  7. const colors = {
  8. normal: "#52c41a",
  9. warning: "#faad14",
  10. error: "#f5222d",
  11. maintenance: "#722ed1",
  12. }
  13. return new Icon({
  14. iconUrl: `data:image/svg+xml;base64,${btoa(`
  15. <svg width="25" height="25" viewBox="0 0 25 25" xmlns="http://www.w3.org/2000/svg">
  16. <circle cx="12.5" cy="12.5" r="10" fill="${colors[status as keyof typeof colors]}" stroke="white" strokeWidth="2"/>
  17. <circle cx="12.5" cy="12.5" r="4" fill="white"/>
  18. </svg>
  19. `)}`,
  20. iconSize: [25, 25],
  21. iconAnchor: [12.5, 12.5],
  22. popupAnchor: [0, -12.5],
  23. })
  24. }
  25. interface Device {
  26. id: number
  27. name: string
  28. type: string
  29. status: string
  30. location: string
  31. lat: number
  32. lng: number
  33. battery: number
  34. signal: number
  35. }
  36. interface MapViewProps {
  37. devices: Device[]
  38. showRealTimeData?: boolean
  39. }
  40. export default function MapView({ devices, showRealTimeData = false }: MapViewProps) {
  41. const center: [number, number] = [39.9042, 116.4074] // 北京中心
  42. return (
  43. <MapContainer center={center} zoom={11} style={{ height: "100%", width: "100%" }} className="rounded-lg">
  44. <TileLayer
  45. attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
  46. url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
  47. />
  48. {devices.map((device) => (
  49. <Marker key={device.id} position={[device.lat, device.lng]} icon={createCustomIcon(device.status)}>
  50. <Popup>
  51. <div className="space-y-2">
  52. <h3 className="font-bold">{device.name}</h3>
  53. <p>
  54. <strong>位置:</strong> {device.location}
  55. </p>
  56. <p>
  57. <strong>状态:</strong>
  58. <span
  59. className={`ml-1 ${
  60. device.status === "normal"
  61. ? "text-green-600"
  62. : device.status === "warning"
  63. ? "text-yellow-600"
  64. : device.status === "error"
  65. ? "text-red-600"
  66. : "text-purple-600"
  67. }`}
  68. >
  69. {device.status === "normal"
  70. ? "正常"
  71. : device.status === "warning"
  72. ? "告警"
  73. : device.status === "error"
  74. ? "故障"
  75. : "维修中"}
  76. </span>
  77. </p>
  78. <p>
  79. <strong>电池:</strong> {device.battery}%
  80. </p>
  81. <p>
  82. <strong>信号:</strong> {device.signal}%
  83. </p>
  84. {showRealTimeData && (
  85. <div className="mt-2 p-2 bg-gray-100 rounded">
  86. <p className="text-sm">
  87. <strong>实时数据:</strong>
  88. </p>
  89. <p className="text-xs">倾斜角度: 2.3°</p>
  90. <p className="text-xs">位移距离: 0.8mm</p>
  91. <p className="text-xs">震动强度: 18dB</p>
  92. </div>
  93. )}
  94. </div>
  95. </Popup>
  96. </Marker>
  97. ))}
  98. </MapContainer>
  99. )
  100. }