阅读视图

发现新文章,点击刷新页面。

使用AI从零打造炫酷医疗数据可视化大屏,源码免费拿!

在智慧医疗时代,数据可视化大屏已成为医院指挥中心、急诊监控室的核心工具。今天分享一套完整的医疗数据可视化大屏解决方案,带你深入了解从架构设计到动效实现的全流程。


🎯 项目概览

这是一个面向医疗场景的数据可视化大屏,涵盖患者就诊统计、科室床位管理、医生接诊分析、设备使用监控、全国患者流向等核心业务模块。

截屏2026-02-25 20.24.55.png

技术栈:

  • React 19.2.3 + TypeScript 5.9.3
  • Vite 7.2.4 极速构建
  • Tailwind CSS 4.1.17 原子化样式
  • ECharts 中国地图可视化
  • Recharts React 原生图表库
  • date-fns 日期处理
  • lucide-react 图标库

📊 功能模块详解

🔷 头部区域(Header)

typescript
const [time, setTime] = useState(new Date());

useEffect(() => {
  const timer = setInterval(() => setTime(new Date()), 1000);
  return () => clearInterval(timer);
}, []);
  • 实时时钟:秒级刷新,date-fns 格式化,支持中文星期显示
  • 渐变标题bg-clip-text + drop-shadow 实现发光效果
  • 滚动公告:CSS marquee 动画,无限循环

🔷 左侧面板(LeftPanel)

1. 疾病关键词搜索

typescript
const activeKeywordIndex = useHighlightCarousel(diseaseKeywords.length, 2500);
  • 6 个关键词按钮,自动轮播高亮
  • 高亮时放大 + 橙色边框 + 发光阴影

2. 患者年龄分布(柱状图)

typescript
const animatedAgeData = useChartDataRefresh(ageData, 4000, 0.12);
  • Recharts BarChart,4 个年龄段分组对比
  • 数据每 4 秒自动波动,模拟实时更新

3. 每周人流量分布(面积图)

typescript
<linearGradient id="colorFlow" x1="0" y1="0" x2="0" y2="1">
  <stop offset="5%" stopColor="#4fc3f7" stopOpacity={0.3}/>
  <stop offset="95%" stopColor="#4fc3f7" stopOpacity={0}/>
</linearGradient>
  • Recharts AreaChart,渐变填充
  • 双曲线对比展示两种类型数据

4. 就诊人数统计(翻牌器)

typescript
function useCountUp(targetValue: number, duration = 2000) {
  // easeOutQuart 缓动函数
  const easeProgress = 1 - Math.pow(1 - progress, 4);
  // ...
}
  • 自定义 FlipClock 组件
  • 数字从 0 递增到目标值,缓动动画更自然
  • 上月/本月分组展示婴幼儿、青少年、中壮年、老年人数据

🔷 中间面板(CenterPanel)

1. 全国患者流向图

typescript
useEffect(() => {
  fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json')
    .then(response => response.json())
    .then(geoJson => {
      echarts.registerMap('china', geoJson);
      setMapLoaded(true);
    });
}, []);

核心配置:

typescript
series: [
  // 飞线动画
  { type: 'lines', effect: { show: true, trailLength: 0.7, color: '#ffb74d' } },
  // 涟漪散点
  { type: 'effectScatter', rippleEffect: { brushType: 'stroke' } }
]
  • 动态加载阿里云 GeoJSON 地图数据
  • 飞线展示北京、上海、广州、深圳、成都、西安患者流向
  • 涟漪散点标注城市,支持缩放拖拽

2. 学历占比(SVG 圆环)

typescript
<circle
  cx="60" cy="60" r="54"
  stroke="#4fc3f7"
  strokeDasharray="339"
  strokeDashoffset={339 - (339 * educationStats.bachelor / 100)}
/>
  • 纯 SVG 实现进度圆环
  • strokeDashoffset 控制进度

3. 设备使用情况统计

typescript
const activeEquipmentIndex = useHighlightCarousel(equipmentStats.length, 1500);
  • 7 个设备卡片,轮播高亮
  • 显示设备数量、涨跌百分比、趋势迷你折线图
  • 提示语:"设备一、设备四应考虑进货"

🔷 右侧面板(RightPanel)

1. 患者就诊登记(表格轮播)

typescript
const { visibleItems: visibleRecords } = useListCarousel(patientRecords, 4, 2500);
  • 10 条记录,每次显示 4 条
  • 每 2.5 秒自动滚动,循环展示
  • 状态高亮:已治愈(绿色)/ 治疗中(橙色)

2. 科室床位使用情况(面积图)

  • Recharts AreaChart,5 个科室对比
  • 双色渐变填充

3. 医生接诊情况分析(组合图)

typescript
<ComposedChart data={animatedDoctorData}>
  <Bar dataKey="接诊数" barSize={4} fill="#29b6f6" />
  <Line dataKey="目标" stroke="#ff9800" strokeDasharray="5 5" />
</ComposedChart>
  • 柱状图展示实际接诊数
  • 虚线折线展示目标值
  • 直观对比 5 位医生的 KPI 完成情况

4. 每日医疗使用情况

typescript
const statCards = [
  { icon: Activity, label: '急诊人数', value: dailyStats.emergency },
  { icon: Users, label: '门诊人数', value: dailyStats.outpatient },
  { icon: PlusCircle, label: '住院人数', value: dailyStats.inpatient },
  { icon: ArrowUpRight, label: '出院人数', value: dailyStats.discharged },
];
  • 预约总人数翻牌器
  • 4 个统计卡片,轮播高亮
  • lucide-react 图标 + 数字递增动画

🎨 UI 设计亮点

1. 科技感卡片组件

typescript
<div className="relative bg-[#06142a]/60 border border-[#135c9d]/60 
  backdrop-blur-sm shadow-[inset_0_0_30px_rgba(19,92,157,0.2)]">
  {/* 四角装饰 */}
  <div className="absolute -top-px -left-px w-3 h-3 
    border-t-2 border-l-2 border-[#4fc3f7]" />
  {/* 顶部发光线 */}
  <div className="absolute top-0 left-10 right-10 h-px 
    bg-gradient-to-r from-transparent via-[#4fc3f7]/50 to-transparent" />
</div>

2. autofit.js 大屏适配

typescript
autofit.init({
  el: 'body',
  dw: 1920,  // 设计稿宽度
  dh: 1080,  // 设计稿高度
  resize: true
});
  • 一行代码适配任意分辨率
  • 自动监听窗口变化

3. 配色方案

元素 颜色值 用途
主背景 #020b18 深蓝科技感
边框 #135c9d 卡片边框
高亮 #4fc3f7 装饰、图表
强调 #ffb74d 高亮、警告
文字 #e0f7fa 主文字

🔧 自定义 Hooks 封装

Hook 功能 参数
useApiData<T> 泛型数据获取 fetcher, initialValue
useCountUp 数字递增动画 targetValue, duration
useListCarousel 列表轮播 items, visibleCount, interval
useHighlightCarousel 高亮轮播 itemCount, interval
useChartDataRefresh 图表数据波动 initialData, interval, range

📁 项目结构

src/
├── api/
│   ├── index.ts          # API 层(模拟延迟、响应包装)
│   └── mock/data.ts      # Mock 数据
├── components/
│   ├── Card.tsx          # 科技感卡片
│   ├── Header.tsx        # 头部(时钟 + 公告)
│   ├── LeftPanel.tsx     # 左侧(关键词 + 图表 + 翻牌器)
│   ├── CenterPanel.tsx   # 中间(地图 + 设备)
│   └── RightPanel.tsx    # 右侧(表格 + 图表 + 统计)
├── hooks/
│   ├── useData.ts        # 数据获取 Hooks
│   └── useCarousel.ts    # 动画效果 Hooks
└── utils/cn.ts           # 样式工具

🏥 适用场景

  • 医院运营指挥中心
  • 急诊科实时监控大屏
  • 卫健委数据展示平台
  • 智慧医疗解决方案演示

🌟 总结

这套方案的核心价值:

  1. 业务完整:覆盖医疗场景核心指标
  2. 动效丰富:翻牌器、轮播、飞线、涟漪
  3. 架构清晰:Hooks 封装,组件化设计
  4. 适配灵活:autofit.js 一键适配
  5. 开箱即用:Mock 数据层,快速切换生产环境

欢迎 Star ⭐,一起探索智慧医疗可视化的无限可能!


我放在公众号(柳杉前端) 回复 医疗数据可视化大屏 获取源码

#前端开发 #数据可视化 #React #智慧城市 #大屏设计

使用AI从零打造炫酷的智慧城市大屏(开源):React + Recharts 实战分享

一、起因:为什么要做这个项目?

最近在做数据可视化需求时,看了太多千篇一律的后台管理界面,总想着能不能做点更酷的东西。正好看到很多政府和企业的智慧城市指挥中心大屏,那些闪烁的数据、3D 地图、实时图表,科技感爆棚!

于是决定自己撸一个,顺便探索一下现代前端可视化技术的边界。


二、效果展示:先看看成品

截屏2026-02-22 16.19.52.png

🎨 整体布局

  • 左侧面板:经济指标 + 4 种图表(饼图、柱状图、折线图、面积图)
  • 中间地图:3D 网格地图 + 5 个区域标记(西南/中心/西北/东北/东南)
  • 右侧面板:人口民生 + 雷达图 + 指标卡片
  • 底部导航:城市交通、城市安全、人口民生三大模块切换

✨ 核心亮点

  1. 炫酷的 3D 地图效果:透视网格 + 发光区域圆圈 + 浮动标记
  2. 丰富的图表交互:悬停显示详细数据,Tooltip 自定义样式
  3. 流畅的动画效果:Framer Motion 驱动的进场动画 + 数据轮播
  4. 完整的数据流:Mock API + 自动刷新 Hook + 数据轮播组件
  5. 响应式布局:左右面板自适应宽度,图表自动撑满

三、技术栈:用了哪些工具?

技术栈 用途 为什么选它?
React 19 前端框架 最新版本,Hooks 更强大
TypeScript 类型系统 代码提示 + 类型安全
Vite 构建工具 启动快,HMR 秒级更新
Tailwind CSS 样式方案 原子化 CSS,开发效率高
Recharts 图表库 API 简洁,支持 React 组件化
Framer Motion 动画库 声明式动画,效果丝滑
Lucide React 图标库 轻量级,图标漂亮

四、核心功能拆解

📊 1. 自定义 Tooltip(图表交互增强)

痛点:Recharts 默认 Tooltip 样式太朴素,不符合科技大屏的气质。

解决方案:自定义 Tooltip 组件

const CustomTooltip = ({ active, payload, label }: any) => {
  if (active && payload && payload.length) {
    return (
      <div className="bg-[#0a1628]/95 backdrop-blur-md border border-cyan-500/30 rounded-lg p-3 shadow-[0_0_20px_rgba(0,229,255,0.3)]">
        <p className="text-cyan-400 text-xs font-bold mb-2">{label}</p>
        {payload.map((entry: any, index: number) => (
          <div key={index} className="flex items-center gap-2">
            <div className="w-2 h-2 rounded-full" style={{ backgroundColor: entry.color }} />
            <span className="text-white">{entry.name}: {entry.value}</span>
          </div>
        ))}
      </div>
    );
  }
  return null;
};

效果

  • 深色半透明背景 + 发光边框
  • 彩色指示点与图表颜色对应
  • 平滑的淡入淡出动画

🗺️ 2. 3D 地图效果(视觉核心)

实现思路

  1. 透视网格:使用 CSS transform: perspective() rotateX() 创建 3D 感
  2. 发光圆圈:每个区域用渐变圆圈 + blur 阴影 + animate-pulse
  3. 浮动标记:自定义 3D 金字塔 SVG + 上下浮动动画
// 透视网格
<div style={{
  background: `
    linear-gradient(rgba(0, 229, 255, 0.1) 1px, transparent 1px), 
    linear-gradient(90deg, rgba(0, 229, 255, 0.1) 1px, transparent 1px)
  `,
  backgroundSize: '60px 60px',
  transform: 'perspective(1000px) rotateX(70deg) translateY(-200px) scale(1.5)',
  maskImage: 'radial-gradient(circle at center, black 0%, transparent 70%)',
}} />

技巧

  • maskImage 实现边缘渐隐效果
  • 5 个区域圆圈位置精确对应地图标记
  • 标记自带信息卡片,悬停放大

🔄 3. 数据自动刷新(实战 Hooks)

需求:模拟实时数据更新,每 5 秒刷新一次。

自定义 Hook

export function useDataRefresh<T>(
  fetchFunction: () => Promise<T>,
  interval: number = 5000,
  initialData: T
) {
  const [data, setData] = useState<T>(initialData);
  const [loading, setLoading] = useState(false);

  const fetchData = useCallback(async () => {
    try {
      setLoading(true);
      const result = await fetchFunction();
      setData(result);
    } catch (err) {
      console.error('Data fetch error:', err);
    } finally {
      setLoading(false);
    }
  }, [fetchFunction]);

  useEffect(() => {
    fetchData(); // 初始加载
    const timer = setInterval(fetchData, interval); // 定时刷新
    return () => clearInterval(timer);
  }, [fetchData, interval]);

  return { data, loading, refresh: fetchData };
}

使用方式

const { data, loading, refresh } = useDataRefresh(
  fetchMetrics, // Mock API 函数
  5000,         // 刷新间隔
  []            // 初始数据
);

🎠 4. 数据轮播组件(动态展示)

场景:首页需要轮播展示多个重点指标。

实现要点

  1. useDataCarousel Hook:管理轮播逻辑
  2. AnimatePresence:切换时的淡入淡出动画
  3. 控制按钮:上一个/下一个/播放/暂停
const { currentData, next, prev, pause, play, isPlaying } = 
  useDataCarousel(dataList, 3000);

<AnimatePresence mode="wait">
  <motion.div
    key={currentIndex}
    initial={{ opacity: 0, x: 50 }}
    animate={{ opacity: 1, x: 0 }}
    exit={{ opacity: 0, x: -50 }}
    transition={{ duration: 0.5 }}
  >
    {/* 数据内容 */}
  </motion.div>
</AnimatePresence>

亮点

  • 支持手动控制和自动播放
  • 轮播指示器实时同步
  • 数据切换动画流畅自然

📡 5. Mock API 数据服务

为什么需要 Mock

  • 前端开发阶段后端接口未就绪
  • 方便演示和测试
  • 模拟随机数据,更真实

API 设计

// Mock API: 获取指标数据
export const fetchMetrics = async (): Promise<MetricData[]> => {
  await delay(500); // 模拟网络延迟
  return [
    { 
      title: '公共预算收入', 
      value: random(500, 600).toString(), 
      unit: '亿', 
      trend: 'up', 
      percentage: random(20, 30) 
    },
    // ... 更多数据
  ];
};

完整 API 列表

  • fetchMetrics() - 顶部指标卡片
  • fetchLineChartData() - 折线图
  • fetchPieData() - 饼图
  • fetchBarChartData() - 柱状图
  • fetchAreaChartData() - 面积图
  • fetchRadarData() - 雷达图
  • fetchMapMarkers() - 地图标记

🎨 6. 响应式布局方案

挑战:大屏通常是固定分辨率,但需要适配不同屏幕。

方案对比

方案 优点 缺点 适用场景
autofit.js 等比缩放,保持比例 小屏幕可能有黑边 固定比例大屏
Flexbox + 百分比 充分利用空间 需要精细调整 自适应布局
CSS Grid 布局灵活 学习成本高 复杂网格

我的选择:Flexbox + 百分比宽度

// 左右面板自适应
<div className="w-[22%] min-w-[320px] max-w-[400px]">
  {/* 面板内容 */}
</div>

// 图表区域撑满
<div className="flex-1 min-h-0 overflow-y-auto">
  {/* 图表列表 */}
</div>

技巧

  • flex-1 + min-h-0 解决 flex 子元素溢出
  • overflow-y-auto 让图表区域可滚动
  • ResponsiveContainer 让图表自动适应容器

五、踩坑实录

🐛 坑 1:Recharts 图表不撑满容器

现象:图表固定高度,无法充满 flex 容器。

原因ResponsiveContainer 需要明确的高度。

解决

// ❌ 错误写法
<div className="flex-1">
  <ResponsiveContainer width="100%" height="100%">
    <LineChart data={data} />
  </ResponsiveContainer>
</div>

// ✅ 正确写法
<div className="flex-1 min-h-0"> {/* 关键:min-h-0 */}
  <ResponsiveContainer width="100%" height="100%">
    <LineChart data={data} />
  </ResponsiveContainer>
</div>

🐛 坑 2:Framer Motion 动画闪烁

现象:列表项动画时会闪烁或重复。

原因:没有设置唯一的 key

解决

<AnimatePresence mode="wait"> {/* mode="wait" 很重要 */}
  <motion.div key={currentIndex}> {/* key 必须唯一 */}
    {/* 内容 */}
  </motion.div>
</AnimatePresence>

🐛 坑 3:地图标记位置不准

现象:标记偏离预期位置。

原因:绝对定位的基准点是左上角,而不是标记中心。

解决

<div style={{ left: x, top: y }}> {/* 左上角定位 */}
  <div className="transform -translate-x-1/2 -translate-y-1/2"> {/* 居中偏移 */}
    {/* 标记内容 */}
  </div>
</div>

六、性能优化建议

⚡ 1. 图表按需加载

import { LineChart } from 'recharts'; // ✅ 具名导入
// 而不是 import * as Recharts from 'recharts'; // ❌

⚡ 2. 动画节流

// 使用 Framer Motion 的 layout 模式
<motion.div layout layoutId="card">

⚡ 3. 数据缓存

const [cachedData, setCachedData] = useState({});
// 相同请求返回缓存结果

七、未来计划

  • WebSocket 实时数据推送:替换定时轮询
  • 可配置主题:支持多种颜色方案
  • 其他界面:增加其他tab大屏

八、总结

这个项目最大的收获是:

  1. Recharts 不只是画图:结合 TypeScript + 自定义组件,可以实现高度定制化
  2. Hooks 真香useDataRefreshuseDataCarousel 可以复用到任何项目
  3. CSS 动画比想象中强大perspective + blur + animate-pulse 就能做出酷炫效果
  4. Mock 数据是好习惯:前后端分离开发效率翻倍

如果你也在做数据可视化项目,希望这篇文章能给你一些启发!


九、快速上手

📦 安装依赖

npm install react recharts framer-motion lucide-react
npm install -D tailwindcss @tailwindcss/vite

🚀 启动项目

npm run dev

📂 项目结构

src/
├── api/
│   └── mockData.ts          # Mock API 服务
├── hooks/
│   └── useDataRefresh.ts    # 数据刷新 Hook
├── components/
│   └── DataCarouselDemo.tsx # 轮播组件
└── App.tsx                  # 主应用

本文所有代码均可商用,欢迎参考和学习!

我放在公众号(柳杉前端) 回复 智慧城市大屏 获取源码

#前端开发 #数据可视化 #React #智慧城市 #大屏设计

❌