springboot集成echarts显示图表

核心实体类设计

1.统一返回结果类 (Result.java)
import lombok.Data;

@Data
public class Result<T> {
    private boolean success;
    private String message;
    private T data;

    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setSuccess(true);
        result.setData(data);
        return result;
    }

    public static <T> Result<T> error(String message) {
        Result<T> result = new Result<>();
        result.setSuccess(false);
        result.setMessage(message);
        return result;
    }
}

2.图表数据实体 (ChartData.java)
import lombok.Data;

import java.io.Serializable;
import java.util.List;

@Data
public class ChartData implements Serializable {
    /**
     * 图表标题
     */
    private String title;

    /**
     * X轴分类数据
     */
    private List<String> categories;

    /**
     * 系列数据
     */
    private List<SeriesConfig> series;
}

3.系列配置实体 (SeriesConfig.java)

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
public class SeriesConfig {
    /**
     * 系列名称
     */
    private String name;

    /**
     * 图表类型:line, bar, pie, scatter等
     */
    private String type;

    /**
     * 普通数据值 - 用于line, bar, pie等图表
     */
    private List<Object> data;

    /**
     * 散点图专用数据 - 用于scatter图表
     * 格式:List<Object[]> 其中每个Object[]包含[x, y]坐标
     */
    private List<Object[]> scatterData;

    /**
     * 颜色
     */
    private String color;

    /**
     * 是否为面积图
     */
    private boolean areaStyle = false;

    /**
     * 堆叠标识
     */
    private String stack;

    /**
     * 获取实际数据 - 根据图表类型返回对应的数据
     */
    public List<Object> getActualData() {
        if ("scatter".equals(type) && scatterData != null) {
            // 散点图数据需要转换为ECharts格式
            List<Object> result = new ArrayList<>();
            for (Object[] point : scatterData) {
                if (point.length >= 2) {
                    result.add(new Object[]{point[0], point[1]});
                }
            }
            return result;
        }
        return data;
    }

}
4.图表数据构建工具 (ChartUtil.java)
import org.example.flowable.entity.ChartData;
import org.example.flowable.entity.SeriesConfig;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 图表数据构建工具类
 * 提供各种图表类型的数据构建方法
 */
public class ChartUtil {

    /**
     * 构建通用图表数据
     * @param title 图表标题
     * @param categories X轴分类数据
     * @param seriesConfigs 系列配置列表
     * @return ChartData
     */
    public static ChartData buildChartData(String title, List<String> categories, List<SeriesConfig> seriesConfigs) {
        ChartData chartData = new ChartData();
        chartData.setTitle(title);
        chartData.setCategories(categories);
        chartData.setSeries(seriesConfigs);
        return chartData;
    }

    /**
     * 构建趋势图数据(折线图)
     * @param title 图表标题
     * @param categories X轴分类数据
     * @param seriesDataMap 系列数据映射 (系列名 -> 数据列表)
     * @return ChartData
     */
    public static ChartData buildTrendChart(String title, List<String> categories,
                                            Map<String, List<Object>> seriesDataMap) {
        List<SeriesConfig> configs = new ArrayList<>();

        seriesDataMap.forEach((name, data) -> {
            SeriesConfig config = new SeriesConfig();
            config.setName(name);
            config.setType("line");
            config.setData(data);
            configs.add(config);
        });

        return buildChartData(title, categories, configs);
    }

    /**
     * 构建柱状图数据
     * @param title 图表标题
     * @param categories X轴分类数据
     * @param seriesDataMap 系列数据映射 (系列名 -> 数据列表)
     * @return ChartData
     */
    public static ChartData buildBarChart(String title, List<String> categories,
                                          Map<String, List<Object>> seriesDataMap) {
        List<SeriesConfig> configs = new ArrayList<>();

        seriesDataMap.forEach((name, data) -> {
            SeriesConfig config = new SeriesConfig();
            config.setName(name);
            config.setType("bar");
            config.setData(data);
            configs.add(config);
        });

        return buildChartData(title, categories, configs);
    }

    /**
     * 构建饼图数据
     * @param title 图表标题
     * @param categories 分类名称列表
     * @param data 对应的数据值列表
     * @return ChartData
     */
    public static ChartData buildPieChart(String title, List<String> categories, List<Object> data) {
        List<SeriesConfig> configs = new ArrayList<>();

        SeriesConfig config = new SeriesConfig();
        config.setName(title);
        config.setType("pie");
        config.setData(data);
        configs.add(config);

        return buildChartData(title, categories, configs);
    }

    /**
     * 构建面积图数据
     * @param title 图表标题
     * @param categories X轴分类数据
     * @param seriesDataMap 系列数据映射
     * @return ChartData
     */
    public static ChartData buildAreaChart(String title, List<String> categories,
                                           Map<String, List<Object>> seriesDataMap) {
        List<SeriesConfig> configs = new ArrayList<>();

        seriesDataMap.forEach((name, data) -> {
            SeriesConfig config = new SeriesConfig();
            config.setName(name);
            config.setType("line");
            config.setData(data);
            config.setAreaStyle(true); // 标记为面积图
            configs.add(config);
        });

        return buildChartData(title, categories, configs);
    }

    /**
     * 构建散点图数据
     * @param title 图表标题
     * @param seriesDataMap 系列数据映射 (系列名 -> 散点数据列表)
     * @return ChartData
     */
    public static ChartData buildScatterChart(String title, Map<String, List<Object[]>> seriesDataMap) {
        List<SeriesConfig> configs = new ArrayList<>();

        seriesDataMap.forEach((name, data) -> {
            SeriesConfig config = new SeriesConfig();
            config.setName(name);
            config.setType("scatter");
            config.setScatterData(data);
            configs.add(config);
        });

        return buildChartData(title, new ArrayList<>(), configs);
    }

    /**
     * 快速构建单系列图表
     * @param title 图表标题
     * @param categories X轴分类数据
     * @param seriesName 系列名称
     * @param seriesType 系列类型 (line, bar, pie等)
     * @param data 数据列表
     * @return ChartData
     */
    public static ChartData buildSingleSeriesChart(String title, List<String> categories,
                                                   String seriesName, String seriesType, List<Object> data) {
        SeriesConfig config = new SeriesConfig();
        config.setName(seriesName);
        config.setType(seriesType);
        config.setData(data);

        return buildChartData(title, categories, Arrays.asList(config));
    }

    /**
     * 构建堆叠柱状图
     * @param title 图表标题
     * @param categories X轴分类数据
     * @param seriesDataMap 系列数据映射
     * @param stackName 堆叠名称
     * @return ChartData
     */
    public static ChartData buildStackedBarChart(String title, List<String> categories,
                                                 Map<String, List<Object>> seriesDataMap, String stackName) {
        List<SeriesConfig> configs = new ArrayList<>();

        seriesDataMap.forEach((name, data) -> {
            SeriesConfig config = new SeriesConfig();
            config.setName(name);
            config.setType("bar");
            config.setData(data);
            config.setStack(stackName);
            configs.add(config);
        });

        return buildChartData(title, categories, configs);
    }

    /**
     * 构建堆叠面积图
     * @param title 图表标题
     * @param categories X轴分类数据
     * @param seriesDataMap 系列数据映射
     * @param stackName 堆叠名称
     * @return ChartData
     */
    public static ChartData buildStackedAreaChart(String title, List<String> categories,
                                                  Map<String, List<Object>> seriesDataMap, String stackName) {
        List<SeriesConfig> configs = new ArrayList<>();

        seriesDataMap.forEach((name, data) -> {
            SeriesConfig config = new SeriesConfig();
            config.setName(name);
            config.setType("line");
            config.setData(data);
            config.setAreaStyle(true);
            config.setStack(stackName);
            configs.add(config);
        });

        return buildChartData(title, categories, configs);
    }

    /**
     * 构建雷达图数据
     * @param title 图表标题
     * @param indicators 雷达图指标
     * @param seriesDataMap 系列数据映射
     * @return ChartData
     */
    public static ChartData buildRadarChart(String title, List<String> indicators,
                                            Map<String, List<Object>> seriesDataMap) {
        List<SeriesConfig> configs = new ArrayList<>();

        seriesDataMap.forEach((name, data) -> {
            SeriesConfig config = new SeriesConfig();
            config.setName(name);
            config.setType("radar");
            config.setData(data);
            configs.add(config);
        });

        return buildChartData(title, indicators, configs);
    }

    /**
     * 构建仪表盘数据
     * @param title 图表标题
     * @param seriesName 系列名称
     * @param value 数值
     * @param max 最大值
     * @return ChartData
     */
    public static ChartData buildGaugeChart(String title, String seriesName, Object value, Object max) {
        List<SeriesConfig> configs = new ArrayList<>();

        SeriesConfig config = new SeriesConfig();
        config.setName(seriesName);
        config.setType("gauge");
        config.setData(Arrays.asList(value));
        configs.add(config);

        return buildChartData(title, new ArrayList<>(), configs);
    }
}

图表数据控制器

import lombok.extern.slf4j.Slf4j;
import org.example.flowable.common.Result;
import org.example.flowable.entity.ChartData;
import org.example.flowable.entity.SeriesConfig;
import org.example.flowable.utils.ChartUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

@RestController
@RequestMapping("/api/chart")
@Slf4j
public class ChartController {

    @GetMapping("/trend")
    public Result<ChartData> getTrendData() {
        try {
            String title = "流程处理效率趋势图";
            List<String> categories = Arrays.asList(
                    "2024-01-01", "2024-01-02", "2024-01-03", "2024-01-04",
                    "2024-01-05", "2024-01-06", "2024-01-07", "2024-01-08"
            );

            Map<String, List<Object>> seriesDataMap = new HashMap<>();
            seriesDataMap.put("处理效率", Arrays.asList(65, 68, 72, 70, 75, 78, 80, 82));
            seriesDataMap.put("处理数量", Arrays.asList(120, 135, 150, 140, 160, 170, 180, 185));

            ChartData chartData = ChartUtil.buildTrendChart(title, categories, seriesDataMap);

            return Result.success(chartData);
        } catch (Exception e) {
            return Result.error("获取趋势图数据失败");
        }
    }

    @GetMapping("/stats")
    public Result<ChartData> getStatsData() {
        try {
            String title = "流程实例统计";
            List<String> categories = Arrays.asList("进行中", "已完成", "已暂停", "已取消");
            Map<String, List<Object>> seriesDataMap = new HashMap<>();
            seriesDataMap.put("流程数量", Arrays.asList(45, 120, 30, 15));
            ChartData chartData = ChartUtil.buildBarChart(title, categories, seriesDataMap);
            return Result.success(chartData);
        } catch (Exception e) {
            return Result.error("获取统计图数据失败");
        }
    }


    @GetMapping("/user-activity")
    public Result<ChartData> getUserActivityData() {
        try {
            String title = "用户活跃度统计";
            List<String> categories = Arrays.asList("周一", "周二", "周三", "周四", "周五", "周六", "周日");
            Map<String, List<Object>> seriesDataMap = new HashMap<>();
            seriesDataMap.put("活跃用户", Arrays.asList(120, 132, 101, 134, 90, 230, 210));
            seriesDataMap.put("新增用户", Arrays.asList(20, 25, 18, 30, 15, 45, 35));
            ChartData chartData = ChartUtil.buildTrendChart(title, categories, seriesDataMap);
            return Result.success(chartData);
        } catch (Exception e) {
            return Result.error("获取用户活跃度数据失败");
        }
    }


    @GetMapping("/task-completion")
    public Result<ChartData> getTaskCompletionData() {
        try {
            String title = "任务完成率";
            List<String> categories = Arrays.asList("已完成", "进行中", "待处理", "已取消");
            List<Object> data = Arrays.asList(65, 20, 10, 5);
            ChartData chartData = ChartUtil.buildPieChart(title, categories, data);
            return Result.success(chartData);
        } catch (Exception e) {
            return Result.error("获取任务完成率数据失败");
        }
    }

    @GetMapping("/sales-trend")
    public Result<ChartData> getSalesTrendData() {
        try {
            String title = "销售趋势分析";
            List<String> categories = Arrays.asList("Q1", "Q2", "Q3", "Q4");
            Map<String, List<Object>> seriesDataMap = new HashMap<>();
            seriesDataMap.put("产品A", Arrays.asList(100, 120, 150, 180));
            seriesDataMap.put("产品B", Arrays.asList(80, 90, 110, 130));
            ChartData chartData = ChartUtil.buildBarChart(title, categories, seriesDataMap);
            return Result.success(chartData);
        } catch (Exception e) {
            return Result.error("获取销售趋势数据失败");
        }
    }

    @GetMapping("/area-chart")
    public Result<ChartData> getAreaChartData() {
        try {
            String title = "销售面积图";
            List<String> categories = Arrays.asList("1月", "2月", "3月", "4月", "5月", "6月");
            Map<String, List<Object>> seriesDataMap = new HashMap<>();
            seriesDataMap.put("销售额", Arrays.asList(120, 150, 180, 200, 220, 250));
            seriesDataMap.put("利润", Arrays.asList(30, 40, 50, 60, 70, 80));
            ChartData chartData = ChartUtil.buildAreaChart(title, categories, seriesDataMap);
            return Result.success(chartData);
        } catch (Exception e) {
            return Result.error("获取面积图数据失败");
        }
    }

    @GetMapping("/scatter")
    public Result<ChartData> getScatterData() {
        try {
            String title = "用户行为分析";
            Map<String, List<Object[]>> seriesDataMap = new HashMap<>();

            // 用户A的行为数据 [x, y] 坐标
            List<Object[]> userAData = Arrays.asList(
                    new Object[]{10, 20},
                    new Object[]{15, 25},
                    new Object[]{20, 30},
                    new Object[]{25, 35}
            );
            seriesDataMap.put("用户A", userAData);

            // 用户B的行为数据
            List<Object[]> userBData = Arrays.asList(
                    new Object[]{12, 18},
                    new Object[]{18, 28},
                    new Object[]{22, 32},
                    new Object[]{28, 38}
            );
            seriesDataMap.put("用户B", userBData);

            ChartData chartData = ChartUtil.buildScatterChart(title, seriesDataMap);
            return Result.success(chartData);
        } catch (Exception e) {
            return Result.error("获取散点图数据失败");
        }
    }

    @GetMapping("/stacked-bar")
    public Result<ChartData> getStackedBarData() {
        try {
            String title = "部门业绩统计";
            List<String> categories = Arrays.asList("Q1", "Q2", "Q3", "Q4");

            Map<String, List<Object>> seriesDataMap = new HashMap<>();
            seriesDataMap.put("销售部", Arrays.asList(100, 120, 150, 180));
            seriesDataMap.put("技术部", Arrays.asList(80, 90, 110, 130));
            seriesDataMap.put("市场部", Arrays.asList(60, 70, 80, 90));

            ChartData chartData = ChartUtil.buildStackedBarChart(title, categories, seriesDataMap, "部门业绩");

            log.info("堆叠柱状图数据构建完成");
            return Result.success(chartData);
        } catch (Exception e) {
            log.error("获取堆叠柱状图数据失败", e);
            return Result.error("获取堆叠柱状图数据失败");
        }
    }

    @GetMapping("/radar")
    public Result<ChartData> getRadarData() {
        try {
            String title = "员工能力评估";
            List<String> indicators = Arrays.asList("技术能力", "沟通能力", "学习能力", "创新能力", "团队协作", "执行力");

            Map<String, List<Object>> seriesDataMap = new HashMap<>();
            seriesDataMap.put("张三", Arrays.asList(85, 90, 80, 75, 88, 82));
            seriesDataMap.put("李四", Arrays.asList(78, 85, 90, 88, 80, 85));
            seriesDataMap.put("王五", Arrays.asList(92, 75, 85, 90, 85, 88));

            ChartData chartData = ChartUtil.buildRadarChart(title, indicators, seriesDataMap);

            return Result.success(chartData);
        } catch (Exception e) {
            return Result.error("获取雷达图数据失败");
        }
    }

    @GetMapping("/gauge")
    public Result<ChartData> getGaugeData() {
        try {
            String title = "系统性能监控";
            String seriesName = "CPU使用率";
            Object value = 75; // 当前值
            Object max = 100;  // 最大值

            ChartData chartData = ChartUtil.buildGaugeChart(title, seriesName, value, max);

            return Result.success(chartData);
        } catch (Exception e) {
            return Result.error("获取仪表盘数据失败");
        }
    }

    @GetMapping("/multi-gauge")
    public Result<ChartData> getMultiGaugeData() {
        try {
            String title = "系统监控面板";

            // 构建多个仪表盘数据
            List<SeriesConfig> configs = new ArrayList<>();

            // CPU使用率
            SeriesConfig cpuConfig = new SeriesConfig();
            cpuConfig.setName("CPU使用率");
            cpuConfig.setType("gauge");
            cpuConfig.setData(Arrays.asList(75));
            configs.add(cpuConfig);

            // 内存使用率
            SeriesConfig memoryConfig = new SeriesConfig();
            memoryConfig.setName("内存使用率");
            memoryConfig.setType("gauge");
            memoryConfig.setData(Arrays.asList(60));
            configs.add(memoryConfig);

            // 磁盘使用率
            SeriesConfig diskConfig = new SeriesConfig();
            diskConfig.setName("磁盘使用率");
            diskConfig.setType("gauge");
            diskConfig.setData(Arrays.asList(45));
            configs.add(diskConfig);

            ChartData chartData = ChartUtil.buildChartData(title, new ArrayList<>(), configs);

            return Result.success(chartData);
        } catch (Exception e) {
            return Result.error("获取多仪表盘数据失败");
        }
    }
}

前端图表组件

1.ChartComponent.vue
<template>
  <div class="chart-container">
    <div class="chart-header">
      <h3>{{ chartTitle }}</h3>
      <div class="chart-controls">
        <button @click="refreshChart" class="btn-refresh">刷新数据</button>
        <select v-model="selectedChartType" @change="switchChartType">
          <option value="trend">折线图</option>
          <option value="stats">单柱状图</option>
<!--          <option value="user-activity">用户活跃度</option>-->
          <option value="task-completion">饼图</option>
          <option value="sales-trend">双柱状图</option>
          <option value="area-chart">面积图</option>
          <option value="scatter">散点图</option>
          <option value="stacked-bar">堆叠柱状图</option>
          <option value="radar">雷达图</option>
          <option value="gauge">仪表盘</option>
          <option value="multi-gauge">多仪表盘</option>
        </select>
      </div>
    </div>

    <div ref="chartContainer" class="chart-content"></div>

    <div class="data-explanation">
      <h4>数据说明:</h4>
      <ul>
        <li><strong>数据来源:</strong>后端ChartController接口</li>
        <li><strong>连接方式:</strong>前端通过axios调用/api/chart接口</li>
        <li><strong>数据处理:</strong>获取JSON数据后转换为ECharts配置</li>
        <li><strong>渲染方式:</strong>使用ECharts库渲染图表</li>
        <li><strong>数据更新:</strong>支持实时刷新和图表类型切换</li>
        <li><strong>交互功能:</strong>点击图例可切换线条显示/隐藏</li>
      </ul>
    </div>
  </div>
</template>

<script>
import axios from 'axios'
import * as echarts from 'echarts'

export default {
  name: 'ChartComponent',
  data() {
    return {
      selectedChartType: 'trend',
      chartTitle: '流程处理效率趋势图',
      apiEndpoints: {
        trend: '/api/chart/trend',
        stats: '/api/chart/stats',
        'user-activity': '/api/chart/user-activity',
        'task-completion': '/api/chart/task-completion',
        'sales-trend': '/api/chart/sales-trend',
        'area-chart': '/api/chart/area-chart',
        scatter: '/api/chart/scatter',
        'stacked-bar': '/api/chart/stacked-bar',
        radar: '/api/chart/radar',
        gauge: '/api/chart/gauge',
        'multi-gauge': '/api/chart/multi-gauge'
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart()
      // 改为调用真实接口
      this.loadChartData()
    })
  },
  beforeUnmount() {
    if (this.chartInstance) {
      this.chartInstance.dispose()
    }
  },
  methods: {
    initChart() {
      if (this.$refs.chartContainer) {
        this.chartInstance = echarts.init(this.$refs.chartContainer)

        // 添加窗口大小变化监听
        window.addEventListener('resize', () => {
          if (this.chartInstance) {
            this.chartInstance.resize()
          }
        })
      }
    },

    // 调用真实接口获取数据
    async loadChartData() {
      try {
        console.log(`正在请求接口: ${this.apiEndpoints[this.selectedChartType]}`)

        const response = await axios.get(this.apiEndpoints[this.selectedChartType])

        // console.log('接口响应:', response.data)

        if (response.data.success) {
          const chartData = response.data.data
          this.chartTitle = chartData.title || '图表'

          console.log('接收到的图表数据:', chartData)

          // 验证数据完整性
          if (this.validateChartData(chartData)) {
            // 构建ECharts配置
            const option = this.buildEChartsOption(chartData)
            console.log('ECharts配置:', option)

            if (this.chartInstance) {
              this.chartInstance.clear()
              this.chartInstance.setOption(option, true)
              console.log('图表渲染成功')
            }
          } else {
            console.error('数据验证失败,使用默认数据')
            this.loadDefaultData()
          }

        } else {
          console.error('获取图表数据失败:', response.data.message)
          this.loadDefaultData()
        }
      } catch (error) {
        console.error('请求图表数据出错:', error)
        console.log('使用默认数据作为备用')
        this.loadDefaultData()
      }
    },

    // 验证图表数据的完整性
    validateChartData(chartData) {
      if (!chartData) {
        console.error('chartData为空')
        return false
      }

      if (!chartData.series || !Array.isArray(chartData.series)) {
        console.error('series数据无效')
        return false
      }

      // 检查每个series是否有效
      for (let i = 0; i < chartData.series.length; i++) {
        const series = chartData.series[i]
        if (!series || typeof series !== 'object') {
          console.error(`series[${i}]为空或不是对象`)
          return false
        }

        if (!series.name || !series.type) {
          console.error(`series[${i}]缺少必需字段:`, series)
          return false
        }
      }

      return true
    },

    // 构建ECharts配置
    buildEChartsOption(chartData) {
      // console.log('原始数据字段:', Object.keys(chartData))
      // console.log('series数据:', chartData.series)

      const option = {
        title: {
          text: chartData.title || '图表',
          left: 'center'
        },
        tooltip: {
          trigger: 'axis'
        },
        legend: {
          data: [],
          top: 30
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        xAxis: {
          type: 'category',
          data: chartData.categories || []
        },
        yAxis: {
          type: 'value'
        },
        series: []
      }

      // 处理series数据
      if (chartData.series && Array.isArray(chartData.series)) {
        option.series = chartData.series.map(series=> {
              const seriesConfig = {
                name: series.name,
                type: series.type,
                data: this.getSeriesData(series),
                color: series.color || ''
              }

          // 面积图特殊处理
          if (series.areaStyle) {
            seriesConfig.areaStyle = {}
          }

          // 堆叠图特殊处理
          if (series.stack) {
            seriesConfig.stack = series.stack
          }

          return seriesConfig
        })

        // 设置图例数据
        option.legend.data = option.series.map(s => s.name)
      }

      // 特殊处理饼图
      if (chartData.series && chartData.series.length > 0 && chartData.series[0].type === 'pie') {
        const pieData = chartData.categories.map((name, index) => ({
          name: name,
          value: this.getSeriesData(chartData.series[0])[index]
        }))

        option.series[0] = {
          name: chartData.series[0].name,
          type: 'pie',
          radius: ['40%', '70%'], // 环形饼图
          center: ['50%', '60%'], // 饼图位置
          data: pieData,
          emphasis: {
            itemStyle: {
              shadowBlur: 10,
              shadowOffsetX: 0,
              shadowColor: 'rgba(0, 0, 0, 0.5)'
            },
            label: {
              show: true,
              fontSize: '16',
              fontWeight: 'bold'
            }
          },
          label: {
            show: true,
            formatter: '{b}: {c} ({d}%)', // 显示名称、数值和百分比
            fontSize: 12
          },
          labelLine: {
            show: true
          },
          itemStyle: {
            borderRadius: 8, // 圆角
            borderColor: '#fff',
            borderWidth: 2
          }
        }

        // 饼图专用tooltip配置
        option.tooltip = {
          trigger: 'item',
          formatter: '{a} <br/>{b}: {c} ({d}%)',
          backgroundColor: 'rgba(0,0,0,0.8)',
          borderColor: '#ccc',
          borderWidth: 1,
          textStyle: {
            color: '#fff'
          }
        }

        // 饼图专用legend配置
        option.legend = {
          orient: 'vertical',
          left: 'left',
          top: 'center',
          data: chartData.categories,
          textStyle: {
            fontSize: 12
          }
        }

        // 饼图不需要x轴和y轴
        delete option.xAxis
        delete option.yAxis
        delete option.grid
      }

      // 特殊处理雷达图
      if (chartData.series && chartData.series.length > 0 && chartData.series[0].type === 'radar') {
        const indicators = (chartData.categories || []).map(name => ({ name, max: 100 }))

        option.radar = {
          indicator: indicators,
          center: ['50%', '58%'],   
          radius: '56%',            
          splitNumber: 5,
          shape: 'polygon',
          axisName: { color: '#666', fontSize: 11, padding: [1, 3] },
          axisLine: { lineStyle: { color: 'rgba(0,0,0,0.14)' } },
          splitLine: { lineStyle: { color: 'rgba(0,0,0,0.10)' } },
          splitArea: { areaStyle: { color: ['rgba(24,144,255,0.03)','rgba(24,144,255,0.05)'] } }
        }

        const colors = ['#5470C6','#91CC75','#FAC858','#EE6666','#73C0DE']
        option.series = chartData.series.map((s, i) => {
          const color = s.color || colors[i % colors.length]
          return {
            name: s.name,
            type: 'radar',
            symbol: 'circle',
            symbolSize: 4,         
            lineStyle: { width: 2, color },
            itemStyle: { color },
            areaStyle: { color, opacity: 0.15 }, 
            emphasis: { focus: 'series', lineStyle: { width: 3 } },
            data: [{ value: this.getSeriesData(s), name: s.name }]
          }
        })

        option.legend = {
          top: 34,
          left: 'center',
          icon: 'circle',
          itemWidth: 8,
          itemHeight: 8,
          itemGap: 14,
          textStyle: { fontSize: 12 },
          data: chartData.series.map(s => s.name)
        }

        option.tooltip = {
          trigger: 'item',
          confine: true,
          formatter: (p) => {
            const vals = p.value || []
            return `${p.seriesName}<br/>` + (chartData.categories || [])
                .map((n, i) => `${n}:${vals[i] ?? '-'}`).join('<br/>')
          }
        }

        delete option.xAxis
        delete option.yAxis
        delete option.grid
      }
      // 特殊处理仪表盘
      if (chartData.series && chartData.series.length > 0 && chartData.series[0].type === 'gauge') {
        if (chartData.series.length === 1) {
          // 单仪表盘
          const value = this.getSeriesData(chartData.series[0])[0]
          option.series = [{
            name: chartData.series[0].name,
            type: 'gauge',
            center: ['50%', '60%'],
            radius: '80%',
            min: 0,
            max: 100,
            splitNumber: 10,
            axisLine: {
              lineStyle: {
                width: 8,
                color: [
                  [0.3, '#67e0e3'],
                  [0.7, '#37a2da'],
                  [1, '#fd666d']
                ]
              }
            },
            pointer: {
              itemStyle: {
                color: 'auto'
              }
            },
            axisTick: {
              distance: -30,
              splitNumber: 5,
              lineStyle: {
                width: 2,
                color: '#999'
              }
            },
            splitLine: {
              distance: -30,
              length: 30,
              lineStyle: {
                width: 4,
                color: '#999'
              }
            },
            axisLabel: {
              color: 'auto',
              distance: 40,
              fontSize: 12
            },
            detail: {
              valueAnimation: true,
              formatter: '{value}%',
              color: 'auto',
              fontSize: 20,
              offsetCenter: [0, '70%']
            },
            data: [{
              value: value,
              name: chartData.series[0].name
            }]
          }]
        } else {
          // 多仪表盘
          option.series = chartData.series.map((series, index) => {
            const value = this.getSeriesData(series)[0]
            const centerX = 25 + (index % 2) * 50
            const centerY = 30 + Math.floor(index / 2) * 60

            return {
              name: series.name,
              type: 'gauge',
              center: [centerX + '%', centerY + '%'],
              radius: '30%',
              min: 0,
              max: 100,
              splitNumber: 5,
              axisLine: {
                lineStyle: {
                  width: 4,
                  color: [
                    [0.3, '#67e0e3'],
                    [0.7, '#37a2da'],
                    [1, '#fd666d']
                  ]
                }
              },
              pointer: {
                itemStyle: {
                  color: 'auto'
                }
              },
              axisTick: {
                distance: -15,
                splitNumber: 5,
                lineStyle: {
                  width: 1,
                  color: '#999'
                }
              },
              splitLine: {
                distance: -15,
                length: 15,
                lineStyle: {
                  width: 2,
                  color: '#999'
                }
              },
              axisLabel: {
                color: 'auto',
                distance: 20,
                fontSize: 10
              },
              detail: {
                valueAnimation: true,
                formatter: '{value}%',
                color: 'auto',
                fontSize: 14,
                offsetCenter: [0, '60%']
              },
              data: [{
                value: value,
                name: series.name
              }]
            }
          })
        }
        option.tooltip = {
          trigger: 'item',
          formatter: '{a} <br/>{b}: {c}%'
        }

        delete option.xAxis
        delete option.yAxis
        delete option.grid
        delete option.legend
      }



    // 特殊处理散点图
      if (chartData.series && chartData.series.length > 0 && chartData.series[0].type === 'scatter') {
        // 散点图不需要x轴分类
        option.xAxis.type = 'value'
        delete option.xAxis.data
      }
      return option
    },
    // 获取系列数据
    getSeriesData(series) {
      if(series.type==='scatter' && series.scatterData){
        // 散点图数据格式转化
        return series.scatterData.map(point => [point[0], point[1]])
      }
      return series.data || []
    },

    // 保留默认数据作为备用
    loadDefaultData() {
      const option = {
        title: {
          text: '暂无数据',
          left: 'center'
        },
        series: [
          {
            type: 'line',
            data: []
          }
        ]
      }

      if (this.chartInstance) {
        this.chartInstance.clear()
        this.chartInstance.setOption(option, true)
      }
    },

    // 刷新图表数据
    refreshChart() {
      console.log('刷新图表数据')
      this.loadChartData()
    },

    // 切换图表类型
    switchChartType() {
      console.log(`切换图表类型为: ${this.selectedChartType}`)
      this.loadChartData()
    }
  }
}
</script>

<style scoped>
.chart-container {
  padding: 20px;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.chart-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding-bottom: 15px;
  border-bottom: 1px solid #eee;
}

.chart-header h3 {
  margin: 0;
  color: #333;
}

.chart-controls {
  display: flex;
  gap: 10px;
  align-items: center;
}

.btn-refresh {
  padding: 8px 16px;
  background: #1890ff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.3s;
}

.btn-refresh:hover {
  background: #40a9ff;
}

select {
  padding: 8px 12px;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  background: white;
}

.chart-content {
  width: 100%;
  height: 400px;
  margin-bottom: 20px;
}

.data-explanation {
  background: #f5f5f5;
  padding: 15px;
  border-radius: 4px;
  border-left: 4px solid #1890ff;
}

.data-explanation h4 {
  margin: 0 0 10px 0;
  color: #333;
}

.data-explanation ul {
  margin: 0;
  padding-left: 20px;
}

.data-explanation li {
  margin-bottom: 5px;
  color: #666;
  line-height: 1.5;
}
</style>

2.页面引入组件
<!-- Dashboard.vue -->
<template>
  <div class="dashboard">
    <h1>流程管理仪表板</h1>

    <!-- 图表组件 -->
    <ChartComponent />

    <!-- 其他仪表板内容 -->
    <div class="dashboard-grid">
      <div class="card">
        <h3>流程概览</h3>
        <p>当前运行中的流程实例数量</p>
      </div>
      <div class="card">
        <h3>任务统计</h3>
        <p>待处理任务数量</p>
      </div>
    </div>
  </div>
</template>

<script>
import ChartComponent from '@/components/ChartComponent.vue'

export default {
  name: 'Dashboard',
  components: {
    ChartComponent
  }
}
</script>

<style scoped>
.dashboard {
  padding: 20px;
}

.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
  margin-top: 20px;
}

.card {
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
</style>

页面效果图

image
image
image
image
image
image
image
image
image
image

posted @ 2025-10-20 17:15  愚昧小生  阅读(8)  评论(0)    收藏  举报