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 || '交易数量') +
': ' +
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. 后端返回的数据结构