第四十七节:驾驶舱大屏 ECharts 图表集成

第四十七节:驾驶舱大屏 ECharts 图表集成

🎯本节目标

  1. 安装 echarts 依赖
  2. 在驾驶舱页面封装图表容器,实现自适应(窗口缩放自动重绘)
  3. 对接 mock 大屏统计接口,渲染数字指标卡片 + 柱状图 + 饼图
  4. 处理页面销毁,释放 echarts 实例,防止内存泄漏

步骤 1:安装 echarts

复制代码
pnpm add echarts

步骤 2:修改 cockpit.vue 完整代码

复制代码
<template>
  <div class="cockpit-wrap">
    <!-- 返回后台按钮 -->
    <el-button class="back-btn" @click="backAdmin">返回管理后台</el-button>
    <h1 class="title">驾驶舱 · 数据大屏</h1>

    <!-- 顶部指标卡片 -->
    <div class="card-row">
      <div class="stat-card">
        <div class="label">用户总数</div>
        <div class="num">{{ statData.userTotal }}</div>
      </div>
      <div class="stat-card">
        <div class="label">资讯总数</div>
        <div class="num">{{ statData.newsTotal }}</div>
      </div>
      <div class="stat-card">
        <div class="label">部门数量</div>
        <div class="num">{{ statData.deptTotal }}</div>
      </div>
      <div class="stat-card">
        <div class="label">在线用户</div>
        <div class="num">{{ statData.onlineUser }}</div>
      </div>
    </div>

    <!-- 图表行 -->
    <div class="chart-row">
      <div class="chart-item">
        <div ref="barRef" class="chart"></div>
      </div>
      <div class="chart-item">
        <div ref="pieRef" class="chart"></div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue'
import { useRouter } from 'vue-router'
import * as echarts from 'echarts'
import axios from '@/api/request'

const router = useRouter()
const barRef = ref(null)
const pieRef = ref(null)
let barChart = null
let pieChart = null

// 统计数据
const statData = ref({
  userTotal: 0,
  newsTotal: 0,
  deptTotal: 0,
  onlineUser: 0
})

// 返回后台
const backAdmin = () => {
  router.push('/dashboard/dashboard')
}

// 获取大屏统计接口
const getCockpitStat = async () => {
  const res = await axios.get('/cockpit/getStat')
  if(res.code === 200) {
    statData.value = res.data
    renderChart()
  }
}

// 渲染图表
const renderChart = () => {
  // 柱状图
  barChart = echarts.init(barRef.value)
  barChart.setOption({
    title: { text: '月度用户增长', textStyle:{color:'#fff'} },
    tooltip: {},
    xAxis: {
      type: 'category',
      data: ['1月','2月','3月','4月','5月','6月'],
      axisLine:{lineStyle:{color:'#506688'}}
    },
    yAxis: {
      type: 'value',
      axisLine:{lineStyle:{color:'#506688'}},
      splitLine:{lineStyle:{color:'#273b60'}}
    },
    series: [{
      data: [80,120,95,160,210,240],
      type: 'bar',
      color: '#00bfff'
    }]
  })

  // 饼图
  pieChart = echarts.init(pieRef.value)
  pieChart.setOption({
    title: { text: '部门人员分布', textStyle:{color:'#fff'} },
    tooltip: {},
    series: [{
      type: 'pie',
      radius: '60%',
      data: [
        {value: 85, name:'研发部'},
        {value: 42, name:'运营部'},
        {value: 26, name:'市场部'},
        {value: 18, name:'行政部'}
      ]
    }]
  })
}

// 窗口大小变化自适应
const resizeHandler = () => {
  barChart?.resize()
  pieChart?.resize()
}

onMounted(() => {
  getCockpitStat()
  window.addEventListener('resize', resizeHandler)
})

// 销毁释放实例,防止内存泄漏
onUnmounted(() => {
  window.removeEventListener('resize', resizeHandler)
  barChart?.dispose()
  pieChart?.dispose()
})
</script>

<style scoped>
.cockpit-wrap {
  width: 100vw;
  height: 100vh;
  box-sizing: border-box;
  padding:20px;
  background-color: #091b39;
  color:#fff;
}
.back-btn {
  position: absolute;
  top:12px;
  right:20px;
  z-index:99;
}
.title {
  text-align:center;
  font-size:28px;
  margin:10px 0 30px;
}
.card-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap:16px;
  margin-bottom:20px;
}
.stat-card {
  background: rgba(30, 60, 110, 0.6);
  padding:20px;
  border-radius:8px;
  text-align:center;
}
.stat-card .label {
  font-size:16px;
  color:#a0b8e3;
}
.stat-card .num {
  font-size:32px;
  font-weight:bold;
  margin-top:8px;
}
.chart-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap:20px;
  height: calc(100% - 220px);
}
.chart-item {
  background: rgba(30, 60, 110, 0.6);
  border-radius:8px;
  padding:16px;
}
.chart {
  width:100%;
  height:100%;
}
</style>

步骤 3:确认 mock 接口(之前写的)

复制代码
'/cockpit/getStat' : () => {
  return {
    code:200,
    data:{
      userTotal: 1256,
      newsTotal: 89,
      deptTotal:12,
      onlineUser:36
    }
  }
}

✅测试清单

  1. 点击驾驶舱跳转,页面加载出 4 个统计卡片
  2. 柱状图、饼图正常渲染,深色大屏风格
  3. 浏览器窗口缩放,图表自动适配大小
  4. 点击返回管理后台,回到工作台,页面销毁 echarts 实例,无内存泄漏
相关推荐
Ai-_Man1 小时前
您您这可以把Grok的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。AI导出鸭
javascript·人工智能·ai·小程序·电脑
传人once1 小时前
多图片上传预览功能如何写
前端·css·html·jquery·html5
Eric.461 小时前
Wan‑Animate+MiniMax-H3 本地部署 AI 漫剧流水线:8G 显存动作迁移与动态分镜工程实战
前端·人工智能·comfyui·ai漫剧
liangshanbo12152 小时前
JavaScript 异步核心主线
javascript·事件循环·异步操作
传人once3 小时前
悬停旋转放大和位移效果如何写
javascript·css·动画
库拉镜像AI牛牛3 小时前
短剧内容自动化生产:知漫剧工作室落地教程
大数据·服务器·前端·人工智能·语音识别
律宏阔3 小时前
Flutter 列表图片内存优化:CachedNetworkImage 与 ClipRRect 的取舍
前端·flutter
行者全栈架构师3 小时前
【鸿蒙心迹】相册文搜图工程化落地:HarmonyOS 7.0 端侧 AI 检索全链路实战与 5 个踩坑解法
前端
律宏阔3 小时前
Dart 3 Record:解决 Future.wait 异构返回值的类型问题
前端·flutter
Seraphina363 小时前
DVWA(XSS Reflected/Stored High,CSRF Low)
前端·xss·csrf