73 lines
2.5 KiB
TypeScript
73 lines
2.5 KiB
TypeScript
"use client"
|
||
|
||
import { useEffect, useState } from "react"
|
||
import { MapContainer, TileLayer, CircleMarker, Popup } from "react-leaflet"
|
||
import type { EsportsStar } from "../_lib/config-types"
|
||
import { defaultStars } from "../_lib/config-types"
|
||
import "leaflet/dist/leaflet.css"
|
||
|
||
const gameColors: Record<string, string> = {
|
||
王者荣耀: "#f59e0b",
|
||
英雄联盟: "#3b82f6",
|
||
魔兽世界: "#10b981",
|
||
}
|
||
|
||
/**
|
||
* 真实中国/世界地图(Leaflet + OSM),替代方块型 SVG 地图
|
||
* 由 dashboard-content 通过 dynamic(..., { ssr: false }) 引入
|
||
*/
|
||
export default function RealMap() {
|
||
const [stars, setStars] = useState<EsportsStar[]>(defaultStars)
|
||
|
||
useEffect(() => {
|
||
fetch("/api/screen/streamers")
|
||
.then((res) => res.json())
|
||
.then((body: { success?: boolean; data?: EsportsStar[] }) => {
|
||
if (body.success && Array.isArray(body.data) && body.data.length > 0) {
|
||
setStars(body.data)
|
||
}
|
||
})
|
||
.catch(() => {})
|
||
}, [])
|
||
|
||
return (
|
||
<div className="w-full h-full min-h-[480px] rounded-lg overflow-hidden [&_.leaflet-container]:bg-[#0c0c0e]">
|
||
<MapContainer
|
||
center={[35.5, 105]}
|
||
zoom={4}
|
||
className="w-full h-full rounded-lg"
|
||
style={{ minHeight: 480 }}
|
||
scrollWheelZoom
|
||
>
|
||
<TileLayer
|
||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||
/>
|
||
{stars.map((star) => (
|
||
<CircleMarker
|
||
key={star.id}
|
||
center={[star.location.lat, star.location.lng]}
|
||
radius={10}
|
||
pathOptions={{
|
||
fillColor: gameColors[star.game] || "#06b6d4",
|
||
color: gameColors[star.game] || "#06b6d4",
|
||
weight: 2,
|
||
fillOpacity: 0.8,
|
||
}}
|
||
>
|
||
<Popup>
|
||
<div className="text-sm text-left min-w-[140px]">
|
||
<div className="font-semibold text-slate-900">{star.name}</div>
|
||
<div className="text-slate-600">{star.game}</div>
|
||
<div className="text-slate-500">粉丝: {(star.fans / 10000).toFixed(1)}万</div>
|
||
<div className="text-slate-500">日收益: ¥{star.dailyRevenue?.toLocaleString?.() ?? star.dailyRevenue}</div>
|
||
<div className="text-slate-500">转化率: {star.conversionRate}%</div>
|
||
</div>
|
||
</Popup>
|
||
</CircleMarker>
|
||
))}
|
||
</MapContainer>
|
||
</div>
|
||
)
|
||
}
|