| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- <template>
- <view class="chart-panel bg-white radius" :class="{ 'chart-panel--fullscreen': fullscreen }">
- <l-echart ref="chartRef" class="chart-panel__echart" :class="{ 'chart-panel__echart--fullscreen': fullscreen }"></l-echart>
- </view>
- </template>
- <script setup>
- import * as echarts from "echarts";
- import { ref, watch, nextTick } from "vue";
- const CHART_COLORS = ["#4a90e2", "#40b883", "#f5a623", "#ef4444", "#9b59b6", "#1abc9c"];
- const props = defineProps({
- metricName: {
- type: String,
- default: "",
- },
- chartData: {
- type: Array,
- default: () => [],
- },
- seriesList: {
- type: Array,
- default: () => [],
- },
- fullscreen: {
- type: Boolean,
- default: false,
- },
- });
- const chartRef = ref(null);
- let chartInstance;
- function getSeriesList() {
- if (props.seriesList.length) return props.seriesList;
- if (props.chartData.length) {
- return [{ name: props.metricName || "暂无数据", data: props.chartData }];
- }
- return [];
- }
- function buildOption() {
- const seriesList = getSeriesList();
- if (!seriesList.length) {
- return {
- title: {
- text: "暂无数据",
- left: "center",
- top: "center",
- textStyle: { color: "#999", fontSize: 14, fontWeight: "normal" },
- },
- };
- }
- const labelOrder = [];
- const labelSeen = new Set();
- seriesList.forEach((series) => {
- (series.data || []).forEach((point) => {
- if (!labelSeen.has(point.label)) {
- labelSeen.add(point.label);
- labelOrder.push({
- label: point.label,
- timestamp: point.timestamp || 0,
- });
- }
- });
- });
- labelOrder.sort((a, b) => a.timestamp - b.timestamp);
- const xData = labelOrder.map((item) => item.label);
- const lineSeries = seriesList.map((series, index) => ({
- name: series.name,
- type: "line",
- smooth: true,
- symbol: "circle",
- symbolSize: 4,
- connectNulls: true,
- data: xData.map((label) => {
- const point = (series.data || []).find((item) => item.label === label);
- return point ? point.value : null;
- }),
- itemStyle: {
- color: CHART_COLORS[index % CHART_COLORS.length],
- },
- }));
- return {
- color: CHART_COLORS,
- tooltip: {
- trigger: "axis",
- backgroundColor: "rgba(255, 255, 255, 0.9)",
- borderColor: "rgba(0, 0, 0, 0.08)",
- },
- legend: {
- type: "scroll",
- top: 10,
- left: "center",
- data: seriesList.map((item) => item.name),
- icon: "circle",
- itemWidth: 8,
- itemHeight: 8,
- textStyle: {
- fontSize: 12,
- color: "#666",
- },
- },
- grid: {
- left: props.fullscreen ? "8%" : "12%",
- right: props.fullscreen ? "8%" : "12%",
- top: props.fullscreen ? 48 : 56,
- bottom: props.fullscreen ? 36 : 60,
- },
- dataZoom: [
- {
- type: "slider",
- show: xData.length > 4,
- xAxisIndex: 0,
- height: 18,
- bottom: 10,
- borderColor: "transparent",
- backgroundColor: "#f5f6f7",
- fillerColor: "rgba(74, 144, 226, 0.15)",
- handleSize: "80%",
- },
- ],
- xAxis: {
- type: "category",
- boundaryGap: false,
- data: xData,
- axisLine: {
- lineStyle: { color: "#e5e5e5" },
- },
- axisLabel: {
- color: "#999",
- fontSize: 11,
- },
- },
- yAxis: {
- type: "value",
- splitLine: {
- lineStyle: {
- type: "dashed",
- color: "#eee",
- },
- },
- axisLabel: {
- color: "#999",
- fontSize: 11,
- },
- },
- series: lineSeries,
- };
- }
- function resizeChart(instance) {
- if (!instance) return;
- setTimeout(() => instance.resize(), 80);
- setTimeout(() => instance.resize(), 300);
- }
- function renderChart() {
- nextTick(() => {
- if (!chartRef.value) return;
- chartRef.value.init(echarts, (instance) => {
- chartInstance = instance;
- instance.setOption(buildOption(), true);
- if (props.fullscreen) {
- resizeChart(instance);
- }
- });
- });
- }
- watch(
- () => [props.metricName, props.chartData, props.seriesList, props.fullscreen],
- () => {
- renderChart();
- },
- { deep: true, immediate: true }
- );
- </script>
- <style lang="scss" scoped>
- .chart-panel {
- padding: 10px 0 0;
- &--fullscreen {
- flex: 1;
- width: 100%;
- height: 100%;
- padding: 0;
- border-radius: 0;
- display: flex;
- flex-direction: column;
- box-sizing: border-box;
- :deep(.lime-echart),
- :deep(.lime-echart__canvas) {
- width: 100% !important;
- height: 100% !important;
- }
- }
- &__echart {
- width: 100%;
- height: 520rpx;
- &--fullscreen {
- flex: 1;
- width: 100%;
- height: 100% !important;
- min-height: 0;
- }
- }
- }
- </style>
|