Echarts 折线图表日期分段代码逻辑实现

180 阅读4分钟

将数据统计成按单周,双周,还有按月统计数据代码逻辑,主要看日期。具体功能如下图展示。

单周

图片.png

双周

图片.png

按月

图片.png

后端获取到的数据是一个start Time:2024-05-21 10:30:00的列表,具体数据需要自己修改操作。修改getlist接口中的数据。

具体实现如下

<template>
  <div class='line-chart'>
    <div class="title-search">
      <div class="title">次数</div>
    </div>
    <div class="tooltip">
      <div class="item">
        <div class="finished-total-line"></div>
        <div class="text">累计数</div>
      </div>
      <div class="item">
        <div class="finished-line"></div>
        <div class="text">当期数</div>
      </div>
      <div class="box" style="width:55%"></div>
      <!-- <div class="timeSelect" style="width:10%">

        <el-select v-model="value" placeholder="请选择时间" @change="changeSelect">
          <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
          </el-option>
        </el-select>
      </div > -->
      <div>
        <el-radio-group v-model="value" style="margin-bottom: 30px; " @change="changeSelect" >
          <el-radio-button label="1">单周</el-radio-button>
          <el-radio-button label="2">双周</el-radio-button>
          <el-radio-button label="3"></el-radio-button>
        </el-radio-group>
      </div>
    </div>
    <div class="chart">
      <div id="myLineChart"></div>
    </div>
  </div>
</template>
<script>
import *as echarts from 'echarts'
import moment from 'moment'
import {getProjectAppointmentList, getCompanyAppointmentList} from '@/api/'

export default {
  name: "LineChart",
  props: {

    userId: String,
    projectId: String,
    companyId: String,
  },

  data() {
    return {
      value: '2',
      sortList: [],
      listEcharts: [],
      object: [],
      option: {
        color: ['#5383FF', '#E8B957'],
        tooltip: {
          trigger: 'axis',
        },
        grid: {
          left: '5%',
          right: '5%',
          bottom: '10%',
          top: '10%',
        },
        xAxis: {
          type: 'category',
          boundaryGap: false,
          axisTick: {
            interval: 'auto',
          },
          axisLabel: {
            interval: 'auto',
            rotate: 0,
          },
          data: []
        },
        yAxis: [
          {
            type: 'value',
            name: '当期约谈次数',
            min: 0,
            max: 10,
            position: 'left',
            show: false,
          },
          {
            type: 'value',
            name: '累计约谈次数',
            min: 0,
            max: 100,
            position: 'right',
            show: false,
          }
        ],
        series: [
          {
            label: {
              show: true,
              position: 'top',
              color: '#5383FF',
              fontSize: 12,
              fontWeight: 700,
              formatter: '{c}',
            },
            name: '当期会谈数',
            type: 'line',
            data: [],
            smooth: true,
            symbol: 'circle',
            showSymbol: true,
            yAxisIndex: 0,
          },
          {
            label: {
              show: true,
              position: 'top',
              color: '#E8B957',
              fontSize: 12,
              fontWeight: 700,
              distance: 10,
              formatter: '{c}',
            },
            name: '累计会谈数',
            type: 'line',
            data: [],
            smooth: false,
            symbol: 'circle',
            showSymbol: true,
            yAxisIndex: 1,
          },
        ]
      }
    }
  },
  mounted() {
    this.getList()
  this.myChat = echarts.init(document.getElementById('myLineChart'))
  console.log(document.getElementById('myLineChart').clientWidth)
  window.addEventListener('resize', this.resizeChart)

  },
  beforeDestroy() {
    if (!this.myChat) {
      return
    }
    window.removeEventListener('resize', this.resizeChart)
    this.myChat.dispose()
    this.myChat = null
  },
  watch: {
    sortList() {
      this.changeSelect()
    }
  },
  methods: {
    resizeChart: _.debounce(function () {
      console.log('chart resize!')
      if (this.myChat != null) {
        this.myChat.resize()
      }
    }, 100),
    getList() {
      //调用接口
        getProjectAppointmentList().then(res => {
          this.object = res
          const list = this.object
          //获取时间排序列表
          this.sortList = list.sort(function (a, b) {
            return moment(a.appointmentInfo.startTime).isBefore(moment(b.appointmentInfo.startTime)) ? -1 : 1
          })
        })
    },
   
    renderChart() {
      console.log('renderChart')
      this.$nextTick(() => { //使用nextTick为了保证dom元素都已经渲染完毕
        this.myChat.setOption(this.option)
      });

      this.myChat.resize()
    },

    /**
     * @description: 计算两个日期相差多少个月
     * @param {String} startTime 开始时间
     * @param {String} endTime 结束时间
     * @return: 相差的月数
     */
    getDistanceMonth(startTime, endTime) {
      startTime = new Date(startTime)
      endTime = new Date(endTime)
      var dateToMonth = 0
      var startDate = startTime.getDate() + startTime.getHours() / 24 + startTime.getMinutes() / 24 / 60;
      var endDate = endTime.getDate() + endTime.getHours() / 24 + endTime.getMinutes() / 24 / 60;
      if (endDate >= startDate) {
        dateToMonth = 0
      } else {
        dateToMonth = -1
      }
      let yearToMonth = (endTime.getYear() - startTime.getYear()) * 12
      let monthToMonth = endTime.getMonth() - startTime.getMonth()
      return yearToMonth + monthToMonth + dateToMonth
    },

    getMonthList() {

      // 获取最早时间日期
      var minDate = this.sortList[0].appointmentInfo.startTime
      // 月份间隔列表
      var TimeList = []
      //最小月份
      minDate = minDate.slice(0, 10)

      let Nowdate = new Date()
      let nowMonth = Nowdate.getMonth() // 当前月
      let nowYear = Nowdate.getFullYear() // 当前年
      let monthEndDate = new Date(nowYear, nowMonth + 1, 0)// 当前月的结束时间
      // 当前月前一个月的结束时间
      this.monthEnd = this.$dayjs(monthEndDate).format('YYYY-MM-DD')
      //月份数
      let monthes = this.getDistanceMonth(minDate, this.monthEnd)
      TimeList.push({ time: this.monthEnd, count: 0, Cumulative: 0 })
      for (let i = 0; i < monthes; i++) {
        monthEndDate = new Date(nowYear, nowMonth - i, 0)
        this.monthEndDate = this.$dayjs(monthEndDate).format('YYYY-MM-DD')
        TimeList.push({ time: this.monthEndDate, count: 0, Cumulative: 0 })
      }
      TimeList = TimeList.reverse()
      for (let i = 0, j = 0; i < TimeList.length, j < this.sortList.length; j++) {
        //如果日期超过当前结点   控制时间节点到下一坐标
        while (moment(this.sortList[j].appointmentInfo.startTime).isAfter(moment(TimeList[i].time + " 24:00:00"))) {
          i++
          if (i >= TimeList.length) {
            break
          }
        }
        if( i >= TimeList.length){
          break
        }
        if (moment(this.sortList[j].appointmentInfo.startTime).isBefore(moment(TimeList[i].time + " 24:00:00"))) {
          TimeList[i].count = parseInt(TimeList[i].count) + 1
        }
      }
      TimeList = this.CountList(TimeList)
      return TimeList
    },
    //日期转字符串格式
    DateToStr(date) {
      var year = date.getFullYear();//年
      var month = date.getMonth();//月
      var day = date.getDate();//日
      var hours = date.getHours();//时
      var min = date.getMinutes();//分
      var second = date.getSeconds();//秒
      return year + "-" +
        ((month + 1) > 9 ? (month + 1) : "0" + (month + 1)) + "-" +
        (day > 9 ? day : ("0" + day)) + " " +
        (hours > 9 ? hours : ("0" + hours)) + ":" +
        (min > 9 ? min : ("0" + min)) + ":" +
        (second > 9 ? second : ("0" + second));
    },
    //计算两个日期所差周数
    diffInWeeks(date1, date2) {
      // 计算日期之间的毫秒数差值
      const diffMilliseconds = Math.abs(date2 - date1);
      // 毫秒数转换为周数
      const millisecondsInWeek = 1000 * 60 * 60 * 24 * 7;
      const weeks = diffMilliseconds / millisecondsInWeek;
      // 返回结果
      return Math.floor(weeks);
    },
    //根据日期找到该日期所在周周日
    getNextSunday(dateString) {
      const date = new Date(dateString);
      const dayOfWeek = date.getDay();
      // 如果当前日期是星期日(0),则返回当前日期
      if (dayOfWeek === 0) {
        return date;
      } else {
        // 找到下一个周日
        const nextSunday = new Date(date);
        nextSunday.setDate(date.getDate() + (7 - dayOfWeek));
        return nextSunday;
      }
    },
    getWeekList(week) {
      var TimeList = []
      var minDate = this.sortList[0].appointmentInfo.startTime
      var minDateWeek = this.getNextSunday(minDate)
      minDateWeek = this.DateToStr(minDateWeek).slice(0, 10)
      var now = new Date();
      var nowTime = now.getTime();
      var day = now.getDay();
      var oneDayTime = 24 * 60 * 60 * 1000;
      //显示周日
      var lastSundayTime = nowTime + (7 - day) * oneDayTime;
      var lastTime = new Date(lastSundayTime)
      var strLastTime = this.DateToStr(lastTime).slice(0, 10)
      TimeList.push({ time: strLastTime, count: 0, Cumulative: 0 })

      //计算相差周数
      var diffWeeks = this.diffInWeeks(new Date(minDateWeek), new Date(strLastTime))

      if (week == 1) {
        for (let i = 1; i <= diffWeeks; i++) {
          var tmp = moment(strLastTime).add(-7 * i, 'd').format("YYYY-MM-DD")
          TimeList.push({ time: tmp, count: 0, Cumulative: 0 })
        }
      } else if (week == 2) {
        for (let i = 1; i <= diffWeeks / 2; i++) {
          var tmp = moment(strLastTime).add(-14 * i, 'd').format("YYYY-MM-DD")
          TimeList.push({ time: tmp, count: 0, Cumulative: 0 })

        }
      }
      TimeList = TimeList.reverse()

      //TimeList时间节点列表    sortList排序后列表
      for (let i = 0, j = 0; j < this.sortList.length; j++) {

        //如果日期超过当前结点   控制时间节点到下一坐标
        while (moment(this.sortList[j].appointmentInfo.startTime).isAfter(moment(TimeList[i].time + " 24:00:00"))) {
          i++
          if (i >= TimeList.length) {
            break
          }
        }
        if( i >= TimeList.length){
          break
        }
        if (moment(this.sortList[j].appointmentInfo.startTime).isBefore(moment(TimeList[i].time + " 24:00:00"))) {
          TimeList[i].count = parseInt(TimeList[i].count) + 1
        }

      }
      TimeList = this.CountList(TimeList)

      return TimeList

    },
    //计算每日数量及累计
    CountList(echlist) {

      var cumulativeCount = 0
      for (let i = 0; i < echlist.length; i++) {
        cumulativeCount += parseInt(echlist[i].count)
        echlist[i].Cumulative += cumulativeCount

      }
      return echlist;
    },
    changeSelect() {

      this.option.xAxis.data = []
      this.option.series[0].data = []
      this.option.series[1].data = []

      var echartsList = []

      //一周
      if (this.value == 1) {
        echartsList = this.getWeekList(1)
        for (let i = 0; i < echartsList.length; i++) {
          this.option.xAxis.data.push(echartsList[i].time)
          this.option.series[0].data.push(parseInt(echartsList[i].count))
          this.option.series[1].data.push(parseInt(echartsList[i].Cumulative))
        }
        //两周
      } else if (this.value == 2) {
        echartsList = this.getWeekList(2)
        for (let i = 0; i < echartsList.length; i++) {
          this.option.xAxis.data.push(echartsList[i].time)
          this.option.series[0].data.push(parseInt(echartsList[i].count))
          this.option.series[1].data.push(parseInt(echartsList[i].Cumulative))
        }
      } else if (this.value == 3) {
        echartsList = this.getMonthList()
        for (let i = 0; i < echartsList.length; i++) {
          this.option.xAxis.data.push(echartsList[i].time)
          this.option.series[0].data.push(parseInt(echartsList[i].count))
          this.option.series[1].data.push(parseInt(echartsList[i].Cumulative))
        }
      }
      this.option.yAxis[1].max = Math.floor(Math.max(...this.option.series[1].data) * 2.2)
      this.option.yAxis[0].max = Math.floor(Math.max(...this.option.series[0].data) * 1)
      this.renderChart()
    }
  },
}
</script>
<style lang='scss' scoped>
::v-deep.el-radio-button{
  .el-radio-button__inner {
    width: 80px;
    line-height: 1.5;
    padding: 12px 15px;
    font-size: 13px;
    // border-radius: 7px;
}

.el-radio-button__inner:hover {
    color: #E8B957;
}
  .el-radio-button__orig-radio:checked+.el-radio-button__inner {
    color: #E8B957;
    background-color: white;
    border-color: #E8B957;
    box-shadow: 0px 0px 2px 2px #E8B957 !important;
    z-index:1;
  }
}


.line-chart {
  box-sizing: border-box;
  width: 100%;
  padding: 32px;
  border-radius: 16px;
  background: #FFF;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);

  .frequency {
    display: flex;
    align-items: center;
    justify-content: start;
    margin-top: 32px;

    .item {
      margin-right: 48px;
      text-align: center;
    }

    .num {
      color: rgb(0 0 0 / 90%);
      font-family: DIN Alternate;
      font-size: 32px;
      font-weight: 700;
    }

    .label {
      margin-top: 8px;
      color: rgb(0 0 0 / 50%);
      font-size: 12px;
    }
  }

  .tooltip {
    display: flex;
    align-items: center;
    justify-content: start;
    padding: 16px 0;
    gap: 16px;

    .timeSelect {
      position: relative;
      display: flex;
      margin-right: 8%;
    }

    .item {
      display: flex;
      align-items: center;

      .finished-total-line {
        width: 15px;
        height: 2px;
        border-radius: 2px;
        background-color: #E8B957;
      }

      .finished-line {
        width: 15px;
        height: 2px;
        border-radius: 2px;
        background-color: #5383FF;
      }

      .healthy-line {
        width: 15px;
        height: 2px;
        border-radius: 2px;
        background-color: #0E7319;
      }

      .text {
        margin-left: 4px;
        color: rgb(0 0 0 / 50%);
        font-size: 12px;
      }
    }
  }

  .chart {
    height: 400px;
    width: 100%;

    #myLineChart {
      width: 100%;
      height: 400px;
    }
  }
}
</style>
<style lang="scss">
.line-chart {
  .title-search .search {
    .el-date-editor {
      width: 256px;
    }
  }
}
</style>
```
```