先看效果图:

代码实现

template 部分:

<div class="boxMain">
  <div class="queryBox">
    <div class="queryItem">
      <span>时间:</span>
      <el-date-picker
        style="width: 300px;"
        v-model="timeVal"
        type="daterange"
        @change="onTimeValChange"
        placeholder="选择日期"
        value-format="YYYY-MM-DD"
        format="YYYY-MM-DD"
        range-separator="至"
        :clearable="false"
      />
    </div>
  </div>
  <div class="visitBox" id="visitChart"></div>
  <!-- 自定义echarts图例 -->
  <div class="chartLegend">
    <div :class="{ legendItemActive: item.isSelected }" v-for="item in legendArr" :key="item.id" @click="onLegendClick(item)">
      <img :src="item.imgUrl" alt="" />
      <span>{{ item.name }}</span>
    </div>
  </div>
</div>

script 部分:

<script setup>
import { nextTick, onMounted, ref } from 'vue'
import * as echarts from 'echarts'
import $global from '@/utils/globalFun'

onMounted(() => {
  getVisitChartData()
})


const timeVal = ref([])
const onTimeValChange = () => {

}
const visitChartData = ref([])
const getVisitChartData = () => {
  if (timeVal.value.length === 0) {
    const now = new Date()
    const pre = new Date(now.getTime() - 1000 * 3600 * 24 * 7)
    timeVal.value = [
      $global.formatDate(pre, 'yyyy-MM-dd'), // formatDate为自定义的时间格式化方法
      $global.formatDate(now, 'yyyy-MM-dd')
    ]
  }
  const data = [
    { tm: '2025-06-01', num1: 33, num2: 17 },
    { tm: '2025-06-02', num1: 38, num2: 19 },
    { tm: '2025-06-03', num1: 32, num2: 22 },
    { tm: '2025-06-04', num1: 28, num2: 16 },
    { tm: '2025-06-05', num1: 25, num2: 17 },
    { tm: '2025-06-06', num1: 32, num2: 29 },
    { tm: '2025-06-07', num1: 24, num2: 15 }
  ]
  data.forEach(f => {
    f.num1 = f.num1 * 1000000
    f.num2 = f.num2 * 1000000
  })
  visitChartData.value = data
  nextTick(() => {
    drawVisitChart()
  })
}
const drawVisitChart = () => {
  const dom = document.getElementById('visitChart')
  let myChart = echarts.getInstanceByDom(dom)
  if (myChart) { // 如果存在,就清除
    myChart.dispose()
  }
  myChart = echarts.init(dom)
  const option = {
    grid: {
      left: '5%',
      right: '5%',
      bottom: '5%',
      top: '20%',
      containLabel: true
    },
    legend: {
      show: false,
      selected: {
        '系统访问量(次)': true,
        '服务调用量(次)': true
      }
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'shadow'
      }
    },
    yAxis: {
      name: '次',
      nameTextStyle: {
        color: 'rgba(85,85,85,0.5)',
        padding: [0, 20, 0, 0]
      },
      type: 'value',
      max: function (value) { // 取最大值向上取整为最大刻度
        return value.max < 100 ? 100 : Math.ceil(value.max) + 100
      },
      position: 'top',
      axisLabel: {
        color: '#999'
      },
      axisTick: {
        show: false
      },
      axisLine: {
        show: false
      },
      splitLine: {
        lineStyle: {
          type: 'dashed',
          color: 'rgba(85,85,85,0.3)'
        }
      }
    },
    xAxis: {
      type: 'category',
      data: visitChartData.value.map(m => m.tm),
      axisTick: {
        show: false
      },
      axisLine: {
        lineStyle: {
          type: 'solid',
          color: 'rgba(85,85,85,0.5)'
        }
      },
      axisLabel: {
        interval: 0,
        rotate: 40,
        fontSize: 13,
        color: 'rgba(85,85,85,0.5)'
      }
    },
    series: [
      {
        name: '系统访问量(次)',
        type: 'bar',
        barWidth: 20,
        data: visitChartData.value.map(m => m.num1),
        itemStyle: {
          color: function (params) {
            return new echarts.graphic.LinearGradient(0, 1, 0, 0, [{ offset: 0, color: '#00F7FC' }, { offset: 1, color: '#0089F8' }]) // 颜色渐变显示
          }
        }
      },
      {
        name: '服务调用量(次)',
        type: 'line',
        smooth: true,
        symbol: 'none',
        data: visitChartData.value.map(m => m.num2),
        itemStyle: {
          color: '#38E0AF'
        },
        lineStyle: {
          color: '#38E0AF',
          width: 1
        },
        areaStyle: {
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(72,199,156,0.42)' }, { offset: 1, color: 'rgba(0,137,248,0.1)' }]) // 颜色渐变显示
        }
      }
    ]
  }
  myChart.setOption(option)
}
const legendArr = ref([
  { id: 1, name: '系统访问量(次)', isSelected: true, imgUrl: $global.getAssetsImages('datahub/icon_visit.png') },
  { id: 2, name: '服务调用量(次)', isSelected: true, imgUrl: $global.getAssetsImages('datahub/icon_interface.png') }
])
const onLegendClick = (item) => {
  // 切换选中状态
  const obj = legendArr.value.find(f => f.id === item.id)
  obj.isSelected = !obj.isSelected
  // 更新图表配置
  const legendMap = {}
  legendArr.value.forEach(el => {
    legendMap[el.name] = el.isSelected
  })
  const myChart = echarts.getInstanceByDom(document.getElementById('visitChart'))
  if (myChart) {
    myChart.setOption({
      legend: {
        selected: legendMap
      }
    })
  }
}

</script>

css 部分:

<style lang="scss" scoped>
.boxMain {
  height: 320px;
  position: relative;
  .queryBox {
    height: 40px;
    display: flex;
    align-items: center;
    .queryItem {
      display: flex;
      align-items: center;
      span {
        padding: 0 10px;
        font-size: 14px;
        color: rgba(85, 85, 85, 0.8);
      }
    }
  }
  .visitBox {
    width: 100%;
    height: calc(100% - 50px);
    margin-top: 10px;
  }
  .chartLegend {
    height: 30px;
    position: absolute;
    top: 60px;
    right: 60px;
    display: flex;
    align-items: center;
    & > div {
      margin-right: 25px;
      cursor: pointer;
      display: flex;
      align-items: center;
      opacity: 0.5;
      img {
        height: 12px;
        margin-right: 6px;
      }
      span {
        font-size: 14px;
        color: #555;
      }
    }
    & > div:nth-last-of-type(1) {
      margin-right: 0;
    }
    .legendItemActive {
      opacity: 1;
    }
  }
}
</style>

其他:

图片素材 

/utils/globalFun.js 代码如下:

const $global = {
  /**
   * 引入本地静态图片
   */
  getAssetsImages (url, otherUrl) {
    if (otherUrl) {
      return new URL(`/src/${otherUrl}`, import.meta.url).href
    }
    return new URL(`/src/assets/imgs/${url}`, import.meta.url).href
  },
  /**
   * 把一个js日期类型参数转换成 'yyyy-mm-dd' 格式字符串
   * @param {string} format 日期格式或者Date对象, 如: yyyy-MM-dd HH:mm:ss
   */
  formatDate (date, format = 'yyyy-MM-dd') {
    if (!date || ['', '-'].includes(date)) return date

    // 如果 date 是字符串,转换为 Date 对象
    if (typeof date === 'string') date = new Date(date)

    const pad = (num, length = 2) => num.toString().padStart(length, '0')
    const { getDate: day, getMonth: month, getFullYear: year, getHours: hours, getMinutes: minutes, getSeconds: seconds } = date

    const replacements = {
      yyyy: year.call(date),
      yy: year.call(date).toString().slice(-2),
      MM: pad(month.call(date) + 1),
      dd: pad(day.call(date)),
      HH: pad(hours.call(date)),
      hh: pad(hours.call(date) % 12 || 12),
      mm: pad(minutes.call(date)),
      ss: pad(seconds.call(date)),
      t: hours.call(date) >= 12 ? 'pm' : 'am'
    }

    return format.replace(/yyyy|yy|MM|dd|HH|hh|mm|ss|t/g, (match) => replacements[match])
  }
}

export default $global

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐