首页 前端知识 ECharts根据本周, 本月, 本年, 自定义展示折线图

ECharts根据本周, 本月, 本年, 自定义展示折线图

2024-06-07 12:06:50 前端知识 前端哥 888 353 我要收藏

1. 父组件

<PublicEcharts
      :title="'短信/彩信发送量'"
      :eChartTitle="'短信/彩信发送量趋势图'"
      :type="'sms'"
      :seriesNameData="['短信', '彩信']"
      :color="['#507AFE', '#7ED3F4']"
      :unit="'笔'"
    />

2. 子组件

<template>
  <div class="report-page">
    <div class="pl-4 py14 text-base border-bottom">{{ title }}</div>
    <div class="report-card">
      <div class="flex">
        <div class="btn-group">
          <span v-for="(item, i) in timeData" :key="i" :class="{ active: activeIndex === i }" @click="payChangeHandle(i, item)">
            {{ item.name }}
          </span>
        </div>

        <el-date-picker
          v-if="activeIndex === 3"
          ref="dateRef"
          @change="dateChanged"
          v-model="dateRange"
          type="daterange"
          range-separator="至"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
          value-format="timestamp"
          :picker-options="pickerOptions"
          :clearable="false"
        ></el-date-picker>
      </div>
      <!-- <template v-show="!isEmpty"> -->
      <div class="mt-5 m-1" v-if="type === 'pay'">
        <span>交易金额合计:</span>
        <span class="text-lg text-primary">{{ totalData.payTotalAmount | formatPrice(0) }}</span>
        元,
        <span>交易数量合计:</span>
        <span class="text-lg text-primary">{{ totalData.payTotal | formatPrice(0) }}</span>
        笔
      </div>
      <div class="mt-5 m-1" v-else-if="type === 'sms'">
        <span>短信发送量合计:</span>
        <span class="text-lg text-primary">{{ totalData.smsTotal | formatPrice(0) }}</span>
        条,
        <span>彩信发送量合计:</span>
        <span class="text-lg text-primary">{{ totalData.mmsTotal | formatPrice(0) }}</span>
        条
      </div>
      <div class="mt-5 m-1" v-else-if="type === 'esign'">
        <span>签署份数合计:</span>
        <span class="text-lg text-primary">{{ totalData.total | formatPrice(0) }}</span>
        份
      </div>
      <div class="pay-charts" ref="payRef"></div>
      <!-- </template> -->
      <!-- <el-empty v-if="isEmpty" :image-size="120" :image="emptyImg" description="暂无数据" class="empty-con2"></el-empty> -->
      <div></div>
    </div>
  </div>
</template>

<script>
import * as echarts from 'echarts'
import moment from 'moment'
export default {
  name: 'TenantmngFrontendIndex',
  props: {
    title: String,
    eChartTitle: String,
    seriesNameData: {
      type: Array,
      default: () => []
    },
    type: {
      type: String,
      default: ''
    },
    color: {
      type: Array,
      default: () => ['#507AFE', 'transparent']
    },
    unit : {
      type: String,
    }
  },
  data() {
    this.timeData = [
      { name: '本周', id: 1 },
      { name: '本月', id: 2 },
      { name: '本年', id: 3 },
      { name: '自定义', id: 4 }
    ]
    return {
      emptyImg: require('../../assets/main_images/empty.png'),
      isEmpty: false,
      totalData: {},
      activeIndex: 0,
      reportEchart: null,
      isShowTooltip: true,
      week: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
      weekNum: [
        { week: '周一', num: 1 },
        { week: '周二', num: 2 },
        { week: '周三', num: 3 },
        { week: '周四', num: 4 },
        { week: '周五', num: 5 },
        { week: '周六', num: 6 },
        { week: '周日', num: 0 }
      ],
      month: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
      eChartOptions: {
        title: {
          text: this.eChartTitle
        },
        legend: {
          selectedMode: this.type === 'sms' ? true : false,
          itemWidth: 18,
          itemHeight: 12
        },
        xAxis: {},
        yAxis: {
          type: 'value'
        },
        tooltip: {
          show: true,
          trigger: 'axis',
          formatter: params => {
            if (params[0].value === undefined) return

            let timer = this.getCurrentDateByWeek(params[0].axisValueLabel)

            let htmlStr = timer + '<br />'

            let unit = this.unit
            params.forEach((item, i) => {
              htmlStr +=
                (this.type === 'pay' ? params[0].marker : item.marker) +
                (item.seriesName || '交易数量') +
                ':&nbsp;' +
                item.value +
                (!item.seriesName ? '笔' : unit)
              if (i < params.length) htmlStr += '<br />'
            })

            return htmlStr
          }
        },
        series: [],
        color: this.color
      },
      dataLength: 0,
      dateRange: [],
      // dateRange: [1646064000000, 1654099200000],
      selectDate: '',
      timeDiffer: 0,
      dateRangeSplitNumber: 0,
      pickerOptions: {
        disabledDate: time => {
          // 只能选择365天的范围且不能大于当前日期
          const choiceDateTime = new Date(this.selectDate).getTime() // 获取点击的最小时间戳
          const minTime = new Date(choiceDateTime).setMonth(new Date(choiceDateTime).getMonth() - 12) + 86400000 // 获取前一年
          const maxTime = new Date(choiceDateTime).setMonth(new Date(choiceDateTime).getMonth() + 12) - 86400000 // 获取后一年
          const min = minTime
          const newDate = new Date(new Date().toLocaleDateString()).getTime() + 24 * 60 * 60 * 1000 - 1 // 当天时间戳
          const max = newDate < maxTime ? newDate : maxTime
          // 如果已经选中一个日期 则 返回 该日期前后12个月时间可选,后12个月最大为当前日期
          if (this.selectDate) {
            return time.getTime() < min || time.getTime() > max
          }
          // 若一个日期也没选中 则 返回 当前日期以前日期可选
          return time.getTime() > newDate
        },
        // 设置不能选择的日期
        onPick: ({ maxDate, minDate }) => {
          this.selectDate = minDate.getTime()
          if (maxDate) {
            this.selectDate = ''
          }
        }
      }
    }
  },
  mounted() {
    this.reportEchart = echarts.init(this.$refs.payRef)
    this.payChangeHandle(0, { id: 1 })
    // this.dateChanged()
    window.addEventListener('resize', () => {
      this.resizeHandler()
    })

    // 跳转到详情
    this.reportEchart.on('click', params => {
      let time = this.getCurrentDateByWeek(params.name)

      const routeUrl = this.$router.resolve({
        path: '/operational/reportDetail',
        query: {
          serviceCode: this.type,
          dateType: this.activeIndex + 1,
          time: new Date(time + ' 00:00:00').getTime()
        }
      })
      window.open(routeUrl.href, '_blank')
    })
  },
  // 销毁
  destroyed() {
    // 销毁图表
    this.destroyedChart()
  },
  methods: {
    resizeHandler() {
      this.reportEchart && this.reportEchart.resize()
    },
    async payChangeHandle(i, item) {
      if (!this.dateRange.length && i === 3) {
        // this.$refs.dateRef.focus()
        this.activeIndex = i
        return
      }
      // 调接口
      let response = await this.$api.getReportData(
        null,
        `?dateType=${item.id}&scope=${2}&serviceCode=${this.type}&startTime=${this.dateRange[0] || ''}&endTime=${this.dateRange[1] || ''}`
      )

      // response.records = response.records.slice(2)

      if (!response) {
        response = {
          records: [],
          payTotal: 0,
          payTotalAmount: 0,
          smsTotal: 0,
          mmsTotal: 0
        }
        this.isShowTooltip = false
      }

      // this.isEmpty = !!!response.records.length
      if (!response.records.length) {
        return this.$message.warning('该时间区间暂无数据!')
      }

      this.activeIndex = i
      this.timeDiffer = 0

      this.dataLength = response.records.length
      this.totalData = response

      const result = this.filterDataFunc(i, response.records)
      this.formatterDateFunc(result)
    },

    formatterDateFunc(resultObj) {
      // console.log('resultObj', resultObj)

      const t = new Date()
      this.eChartOptions.xAxis = {}
      if (this.activeIndex === 0) {
        // 本周
        this.eChartOptions.xAxis = {
          type: 'category',
          boundaryGap: false,
          data: resultObj.xAxis,
        }
      } else if (this.activeIndex === 1) {
        this.eChartOptions.xAxis = {
          type: 'category',
          boundaryGap: false,
          data: resultObj.xAxis,
        }
      } else if (this.activeIndex === 2) {
        this.eChartOptions.xAxis = {
          type: 'category',
          boundaryGap: false,
          data: resultObj.xAxis,
        }
      } else if (this.activeIndex === 3) {
        this.conventsplitNumberByDate()
        // 自定义
        this.eChartOptions.xAxis = {
          type: 'category',
          boundaryGap: false,
          data: resultObj.xAxis,
          axisLabel: {
            showMinLabel: Boolean(this.dateRangeSplitNumber),
            showMaxLabel: true
          }
        }
      }

      this.eChartOptions.series = []
      resultObj.series.forEach((item, i) => {
        this.eChartOptions.series.push({
          data: item,
          type: 'line',
          smooth: true,
          name: this.seriesNameData[i],
        })
        // 交易数量这条折现隐藏,  为了浮窗中显示数据
        if (this.seriesNameData[i] === '交易数量') {
          this.eChartOptions.series[i].name = ''
          this.eChartOptions.series[i].symbol = null
        }
        if (this.timeDiffer > 30) {
          this.eChartOptions.series[i].showSymbol = false
          this.eChartOptions.series[i].symbolSize = 8
        } else {
          this.eChartOptions.series[i].showSymbol = true
          this.eChartOptions.series[i].symbolSize = 6
        }
      })

      // this.eChartOptions = this.$deepCopy(this.eChartOptions)
      this.reportEchart.setOption(this.eChartOptions)
    },
    dateChanged() {
      this.payChangeHandle(3, { id: 4 })
    },
    // 转换成eCharts需要的二维数组
    filterDataFunc(i, data) {
      let customData = {
        xAxis: [],
        series: [[], []]
      }
      data.forEach(item => {
        let dateTime = moment(item.time).format('YYYY-MM-DD')
        if (this.activeIndex === 0) {
          const w = moment(item.time).format('d')
          dateTime = this.weekNum.find(n => n.num == w).week
        } else if (this.activeIndex === 1) {
          dateTime = moment(item.time).format('D') + '日'
        } else if (this.activeIndex === 2) {
          dateTime = moment(item.time).format('M月')
        }
        customData.xAxis.push(dateTime)

        if (this.type === 'pay') {
          customData.series[0].push(item.payAmount)
          customData.series[1].push(item.payCount)
        } else if (this.type === 'sms') {
          customData.series[0].push(item.smsCount)
          customData.series[1].push(item.mmsCount)
        } else if (this.type === 'esign') {
          customData.series[0].push(item.count)
          customData.series = [customData.series[0]]
        }
      })
      return customData
    },
    // 自定义时间刻度的换算
    conventsplitNumberByDate() {
      this.timeDiffer = parseInt((this.dateRange[1] - this.dateRange[0]) / 1000 / 60 / 60 / 24)
      if (this.timeDiffer <= 15) {
        this.dateRangeSplitNumber = 1
      } else {
        this.dateRangeSplitNumber = parseInt(this.timeDiffer / 10)
      }
    },
    destroyedChart() {
      if (this.reportEchart) {
        // 销毁实例,销毁后实例无法再被使用。
        this.reportEchart.dispose()
        this.reportEchart = null
        // 取消事件绑定
        window.removeEventListener('resize', () => {
          this.resizeHandler()
        })
      }
    },
    // 获取本周, 本月, 本年的日期
    getCurrentDateByWeek(str) {
      let timer = str
      let now = new Date()
      if (this.activeIndex === 0) {
        // 本周
        let nowTime = now.getTime()
        let oneDayTime = 24 * 60 * 60 * 1000
        let w = this.weekNum.find(item => item.week === str)?.num // 选中的周
        if (w === 0) w = 7

        // 当前周
        let nowWeek = now.getDay()
        if (nowWeek === 0) nowWeek = 7
        timer = moment(nowTime - (nowWeek - w) * oneDayTime).format('YYYY-MM-DD') // 显示周一
      } else if (this.activeIndex === 1) {
        // 本月
        timer = moment(new Date()).format('YYYY-MM') + '-' + str.replace('日', '')
        // 格式化(补零)
        timer = moment(timer).format('YYYY-MM-DD')
      } else if (this.activeIndex === 2) {
        // 本年
        timer = now.getFullYear()  + '-' + str.replace('月', '')
        timer = moment(timer).format('YYYY-MM')
      }

      return timer
    }
  }
}
</script>

<style lang="scss" scoped>
.report-page {
  .report-card {
    padding: 20px 20px 0;
    .btn-group {
      width: 340px;
      height: 36px;
      display: flex;

      > span {
        cursor: pointer;
        flex: 1;
        text-align: center;
        line-height: 36px;
        border-radius: 2px;
        border-top: 1px solid $borderColor;
        border-bottom: 1px solid $borderColor;
        border-right: 1px solid $borderColor;
        &:first-child {
          border-left: 1px solid $borderColor;
        }
        &.active {
          border-color: $mainColor;
          background-color: $mainColor;
          color: #fff;
        }
      }
    }
    ::v-deep .el-date-editor {
      width: 240px;
      height: 36px;
      margin-left: 16px;
      border-color: $borderColor;
    }
  }
  .pay-charts {
    margin-top: 15px;
    width: 100%;
    height: 400px;
  }
}

.empty-con2 {
  height: 471px;
}
</style>

3. 大功告成 

4. 后端返回的数据结构

 

 

转载请注明出处或者链接地址:https://www.qianduange.cn//article/11271.html
标签
评论
发布的文章

1.10 Unity中的数据存储 JSON

2024-06-13 21:06:30

JSON 数据格式化方法

2024-06-13 21:06:26

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!