| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- "use client"
- import {useMemo, useState} from "react"
- import Section from "@/components/shared/section"
- import MetricCard from "@/components/shared/metric-card"
- import {Activity, Cpu, Filter, Satellite, Wifi} from 'lucide-react'
- import {Button} from "@/components/ui/button"
- import {type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent,} from "@/components/ui/chart"
- import {Bar, BarChart, CartesianGrid, Line, LineChart, ResponsiveContainer, XAxis, YAxis,} from "recharts"
- import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card"
- import MapDistribution from "@/components/map/map-distribution"
- import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from "@/components/ui/select"
- function useMonitoringData() {
- const devices = 18860
- const types = [
- { name: "流量计", value: 5200 },
- { name: "压力传感", value: 4300 },
- { name: "液位传感", value: 3720 },
- { name: "阀门状态", value: 2640 },
- ]
- const onlineRate = 96.8
- const trend = Array.from({ length: 14 }).map((_, i) => ({
- t: `${i + 1}时`,
- online: 95 + Math.sin(i / 2) * 2 + (i % 3) * 0.2,
- alarms: Math.max(0, Math.round(60 + 8 * Math.sin(i / 1.5) + (i % 4) * 2)),
- }))
- return { devices, types, onlineRate, trend }
- }
- const onlineConfig = {
- online: { label: "在线率", color: "hsl(var(--chart-1))" },
- } satisfies ChartConfig
- const alarmConfig = {
- alarms: { label: "报警数", color: "hsl(var(--chart-5))" },
- } satisfies ChartConfig
- export default function MonitoringDashboard() {
- const { devices, types, onlineRate, trend } = useMonitoringData()
- const [industry, setIndustry] = useState<string>("all")
- const [risk, setRisk] = useState<string>("all")
- const [refreshing, setRefreshing] = useState(false)
- const typesBar = useMemo(
- () => types.map((t) => ({ name: t.name, value: t.value })),
- [types],
- )
- return (
- <div className="space-y-8">
- <Section
- title="监测概览"
- description="通过监测规模、类型、在线率等指标展示设备整体运行情况。"
- action={
- <Button
- variant="outline"
- onClick={() => {
- setRefreshing(true)
- setTimeout(() => setRefreshing(false), 800)
- }}
- >
- {refreshing ? "刷新中..." : "刷新数据"}
- </Button>
- }
- >
- <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
- <MetricCard title="监测设备数" value={devices} icon={<Satellite className="h-4 w-4 text-emerald-600" />} />
- <MetricCard
- title="设备类型数"
- value={types.length}
- icon={<Cpu className="h-4 w-4 text-emerald-600" />}
- />
- <MetricCard
- title="在线率"
- value={onlineRate}
- suffix="%"
- icon={<Wifi className="h-4 w-4 text-emerald-600" />}
- trend={{ delta: 0.4, label: "近24h" }}
- />
- <MetricCard
- title="今日报警"
- value={trend.reduce((acc, cur) => acc + cur.alarms, 0)}
- icon={<Activity className="h-4 w-4 text-emerald-600" />}
- />
- </div>
- </Section>
- <Section title="监测类型分布与在线率">
- <div className="grid gap-4 lg:grid-cols-3">
- <Card className="lg:col-span-2">
- <CardHeader>
- <CardTitle className="text-sm">在线率(近14小时)</CardTitle>
- </CardHeader>
- <CardContent>
- <ChartContainer config={onlineConfig} className="h-[240px]">
- <ResponsiveContainer width="100%" height="100%">
- <LineChart data={trend}>
- <CartesianGrid strokeDasharray="3 3" vertical={false} />
- <XAxis dataKey="t" tickLine={false} axisLine={false} />
- <YAxis domain={[92, 100]} tickLine={false} axisLine={false} unit="%" />
- <ChartTooltip content={<ChartTooltipContent />} />
- <Line type="monotone" dataKey="online" stroke="var(--color-online)" dot={false} strokeWidth={2} />
- </LineChart>
- </ResponsiveContainer>
- </ChartContainer>
- </CardContent>
- </Card>
- <Card>
- <CardHeader>
- <CardTitle className="text-sm">设备类型分布</CardTitle>
- </CardHeader>
- <CardContent>
- <ChartContainer
- config={{ value: { label: "数量", color: "hsl(var(--chart-2))" } }}
- className="h-[240px]"
- >
- <ResponsiveContainer width="100%" height="100%">
- <BarChart data={typesBar}>
- <CartesianGrid vertical={false} strokeDasharray="3 3" />
- <XAxis dataKey="name" tickLine={false} axisLine={false} />
- <YAxis tickLine={false} axisLine={false} />
- <ChartTooltip content={<ChartTooltipContent />} />
- <Bar dataKey="value" radius={6} fill="var(--color-value)" />
- </BarChart>
- </ResponsiveContainer>
- </ChartContainer>
- </CardContent>
- </Card>
- </div>
- </Section>
- <Section
- title="监测分布"
- description="基于设备地理位置信息,展示不同风险等级的覆盖情况。"
- action={
- <div className="flex items-center gap-2">
- <Filter className="h-4 w-4 text-muted-foreground" />
- <Select defaultValue="all" onValueChange={setIndustry}>
- <SelectTrigger className="w-[140px]">
- <SelectValue placeholder="行业" />
- </SelectTrigger>
- <SelectContent>
- <SelectItem value="all">全部行业</SelectItem>
- <SelectItem value="gas">燃气</SelectItem>
- <SelectItem value="water">供水</SelectItem>
- <SelectItem value="drain">排水</SelectItem>
- </SelectContent>
- </Select>
- <Select defaultValue="all" onValueChange={setRisk}>
- <SelectTrigger className="w-[140px]">
- <SelectValue placeholder="风险等级" />
- </SelectTrigger>
- <SelectContent>
- <SelectItem value="all">全部风险</SelectItem>
- <SelectItem value="low">低风险</SelectItem>
- <SelectItem value="mid">中风险</SelectItem>
- <SelectItem value="high">高风险</SelectItem>
- </SelectContent>
- </Select>
- </div>
- }
- >
- <MapDistribution industry={industry} risk={risk} />
- </Section>
- </div>
- )
- }
|