|
|
@@ -0,0 +1,375 @@
|
|
|
+<template>
|
|
|
+ <div class="data_page">
|
|
|
+ <div class="page_header">
|
|
|
+ <div class="header_left">
|
|
|
+ <div class="header_label">外呼数据</div>
|
|
|
+ </div>
|
|
|
+ <div class="header_right">
|
|
|
+ <userBox />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="filter_box">
|
|
|
+ <div class="filter_left">
|
|
|
+ <div class="filter_item">
|
|
|
+ <div class="filter_time_list">
|
|
|
+ <div class="filter_time_item" :class="{'current_date':curDateRange==='yesterday'}" @click="handleChangeRadio('yesterday')">昨日</div>
|
|
|
+ <div class="filter_time_item" :class="{'current_date':curDateRange==='sevenDays'}" @click="handleChangeRadio('sevenDays')">近7日</div>
|
|
|
+ <div class="filter_time_item" :class="{'current_date':curDateRange==='thirtyDays'}" @click="handleChangeRadio('thirtyDays')">近30日</div>
|
|
|
+ <div class="filter_time_item" :class="{'current_date':curDateRange==='custom'}" @click="handleChangeRadio('custom')">自定义</div>
|
|
|
+ </div>
|
|
|
+ <DatePicker class="date_picker" v-show="curDateRange==='custom'" :transfer="true" type="daterange"
|
|
|
+ placeholder="选择日期" clearable @on-change="handleChangeDate" :options="dateOption" v-model="curDate" format="yyyy-MM-dd">
|
|
|
+ </DatePicker>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="filter_right">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="page_content">
|
|
|
+ <div class="info_list">
|
|
|
+ <div class="info_item">
|
|
|
+ <div class="label">五菱数据量</div>
|
|
|
+ <div class="val">{{countData.callClientCount}}</div>
|
|
|
+ </div>
|
|
|
+ <div class="info_item">
|
|
|
+ <div class="label">外呼任务量</div>
|
|
|
+ <div class="val">{{countData.yiWiseCount+countData.pengYueCount}}</div>
|
|
|
+ <div class="group_val">
|
|
|
+ <div class="total_val">
|
|
|
+ <div class="val_label">SA1:</div>
|
|
|
+ <div class="item_val">{{countData.yiWiseCount}}</div>
|
|
|
+ </div>
|
|
|
+ <div class="total_val">
|
|
|
+ <div class="val_label">SA2:</div>
|
|
|
+ <div class="item_val">{{countData.pengYueCount}}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="chart_box">
|
|
|
+ <!-- 折线图 -->
|
|
|
+ <div class="line_chart" id="lineChart"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import { mapState } from 'vuex'
|
|
|
+import { getDateTime, digitalUnit } from '@/utils'
|
|
|
+import userBox from '@/pages/platform/components/userBox'
|
|
|
+export default {
|
|
|
+ components: {
|
|
|
+ userBox
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ dateOption: {
|
|
|
+ disabledDate (date) {
|
|
|
+ return date.valueOf() >= new Date()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yesterday: [getDateTime(-1), getDateTime(-1)],
|
|
|
+ sevenDays: [getDateTime(-7), getDateTime(-1)],
|
|
|
+ thirtyDays: [getDateTime(-30), getDateTime(-1)],
|
|
|
+ curDate: [getDateTime(-7), getDateTime(-1)],
|
|
|
+ curDateRange: 'sevenDays',
|
|
|
+ countData: {
|
|
|
+ callClientCount: 0,
|
|
|
+ pengYueCount: 0,
|
|
|
+ yiWiseCount: 0,
|
|
|
+ },
|
|
|
+ positionsData: {
|
|
|
+ clientPositions: [],
|
|
|
+ taskPositions: []
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapState({
|
|
|
+ user: (state) => state.user, //
|
|
|
+ }),
|
|
|
+ },
|
|
|
+ created () {
|
|
|
+ this.handleSearch()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleChangeDate (val) {
|
|
|
+ this.curDate = [val[0], val[1]]
|
|
|
+ this.handleSearch()
|
|
|
+ },
|
|
|
+ handleChangeRadio(val) {
|
|
|
+ this.curDateRange = val
|
|
|
+ if (this[val]) {
|
|
|
+ this.curDate = this[val]
|
|
|
+ this.handleSearch()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleSearch() {
|
|
|
+ this.currentPage = 1
|
|
|
+ this.initData()
|
|
|
+ this.getPositions()
|
|
|
+ },
|
|
|
+ initData() {
|
|
|
+ this.$http.get(`/call/api/stats/total-count`, {
|
|
|
+ params: {
|
|
|
+ startDate: (this.curDate && this.curDate[0]) || getDateTime(-7),
|
|
|
+ endDate: (this.curDate && this.curDate[7]) || getDateTime(-1),
|
|
|
+ }
|
|
|
+ }).then((response) => {
|
|
|
+ let { data, code, msg } = response
|
|
|
+ if (code === 1) {
|
|
|
+ this.countData = data || {
|
|
|
+ callClientCount: 0,
|
|
|
+ pengYueCount: 0,
|
|
|
+ yiWiseCount: 0,
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.$Notice.warning({
|
|
|
+ desc: msg
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ getPositions () {
|
|
|
+ this.$http.get(`/call/api/stats/positions`, {
|
|
|
+ params: {
|
|
|
+ startDate: (this.curDate && this.curDate[0]) || getDateTime(-7),
|
|
|
+ endDate: (this.curDate && this.curDate[7]) || getDateTime(-1),
|
|
|
+ }
|
|
|
+ }).then((response) => {
|
|
|
+ let { data, code, msg } = response
|
|
|
+ if (code === 1) {
|
|
|
+ this.positionsData = data || {
|
|
|
+ clientPositions: [],
|
|
|
+ taskPositions: []
|
|
|
+ }
|
|
|
+ this.lineChartDraw()
|
|
|
+ } else {
|
|
|
+ this.$Notice.warning({
|
|
|
+ desc: msg
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ lineChartDraw () {
|
|
|
+ let chartDiv = document.getElementById('lineChart')
|
|
|
+ let clientChart = echarts.init(chartDiv)
|
|
|
+ window.addEventListener('resize', function() {
|
|
|
+ clientChart.resize()
|
|
|
+ })
|
|
|
+ clientChart.setOption({
|
|
|
+ legend: {
|
|
|
+ data: ['五菱数据量', '外呼任务量'],
|
|
|
+ icon: 'roundRect',
|
|
|
+ align: 'right',
|
|
|
+ itemWidth: 24,
|
|
|
+ itemHeight: 1,
|
|
|
+ itemGap: 24,
|
|
|
+ top: 14,
|
|
|
+ left: 20,
|
|
|
+ // 图标样式
|
|
|
+ itemStyle: {
|
|
|
+ borderWidth: 0,
|
|
|
+ borderRadius: 3,
|
|
|
+ opacity: 1
|
|
|
+ },
|
|
|
+ textStyle: {//图例文字的样式
|
|
|
+ fontWeight: 400,
|
|
|
+ fontSize: '12px',
|
|
|
+ color: '#999999',
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: '24px',
|
|
|
+ right: '24px',
|
|
|
+ top: '58px',
|
|
|
+ bottom: '24px',
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ data: (this.positionsData.clientPositions || []).map(item => {
|
|
|
+ return item.x
|
|
|
+ }),
|
|
|
+ axisLine: { show: false },
|
|
|
+ axisTick: { show: false },
|
|
|
+ axisLabel: {
|
|
|
+ margin: 20
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ splitLine: { //网格线
|
|
|
+ lineStyle: {
|
|
|
+ type: 'dashed'//设置网格线类型 dotted:虚线 solid:实线
|
|
|
+ },
|
|
|
+ show: true //隐藏或显示
|
|
|
+ },
|
|
|
+ axisLine: { show: false },
|
|
|
+ axisTick: { show: false },
|
|
|
+ min: 0,
|
|
|
+ minInterval: 1,
|
|
|
+ splitNumbe: 8,
|
|
|
+ axisLabel: {
|
|
|
+ formatter: function(value, index) {
|
|
|
+ return digitalUnit(value)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '五菱数据量',
|
|
|
+ type: 'line',
|
|
|
+ data: (this.positionsData.clientPositions || []).map(item => {
|
|
|
+ return item.y
|
|
|
+ }),
|
|
|
+ symbol: 'circle', // 可选值: 'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow', 'none'
|
|
|
+ symbolSize: 12, //拐点大小
|
|
|
+ itemStyle: {
|
|
|
+ color: '#1677FF', // 拐点填充色
|
|
|
+ borderColor: '#ffffff', // 拐点边框颜色
|
|
|
+ borderWidth: 2, // 拐点边框宽度
|
|
|
+ opacity: 1 // 完全不透明
|
|
|
+ },
|
|
|
+ smooth: true,
|
|
|
+ showSymbol: false,
|
|
|
+ color: '#1677FF',
|
|
|
+ lineStyle: {
|
|
|
+ width: 2,
|
|
|
+ color: '#1677FF',
|
|
|
+ }, //线条的样式
|
|
|
+ areaStyle: {
|
|
|
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
+ {
|
|
|
+ offset: 0,
|
|
|
+ color: 'rgba(22, 119, 255, 0.5)'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ offset: 1,
|
|
|
+ color: 'rgba(22, 119, 255, 0)'
|
|
|
+ }
|
|
|
+ ])
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: '外呼任务量',
|
|
|
+ type: 'line', //形状为柱状图
|
|
|
+ data: (this.positionsData.taskPositions || []).map(item => {
|
|
|
+ return item.y
|
|
|
+ }),
|
|
|
+ symbol: 'circle', // 可选值: 'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow', 'none'
|
|
|
+ symbolSize: 12, //拐点大小
|
|
|
+ itemStyle: {
|
|
|
+ color: '#FFCF88', // 拐点填充色
|
|
|
+ borderColor: '#ffffff', // 拐点边框颜色
|
|
|
+ borderWidth: 2, // 拐点边框宽度
|
|
|
+ opacity: 1 // 完全不透明
|
|
|
+ },
|
|
|
+ smooth: true,
|
|
|
+ showSymbol: false,
|
|
|
+ color: '#FFCF88',
|
|
|
+ lineStyle: {
|
|
|
+ width: 2,
|
|
|
+ color: '#FFCF88',
|
|
|
+ }, //线条的样式
|
|
|
+ areaStyle: {
|
|
|
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
+ {
|
|
|
+ offset: 0,
|
|
|
+ color: 'rgba(255, 207, 136, 0.5)'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ offset: 1,
|
|
|
+ color: 'rgba(255, 207, 136, 0)'
|
|
|
+ }
|
|
|
+ ])
|
|
|
+ },
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ }, true)
|
|
|
+ },
|
|
|
+ },
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style lang="less" scoped>
|
|
|
+.data_page {
|
|
|
+ .page_content {
|
|
|
+ .info_list {
|
|
|
+ display: flex;
|
|
|
+ gap: 24px;
|
|
|
+ margin-bottom: 24px;
|
|
|
+ .info_item {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 189px;
|
|
|
+ max-width: 289px;
|
|
|
+ height: 138px;
|
|
|
+ background: linear-gradient(91deg, #FFFFFF 0%, rgba(255, 255, 255, 0.5) 100%);
|
|
|
+ border-radius: 20px;
|
|
|
+ border: 1px solid #FFFFFF;
|
|
|
+ cursor: pointer;
|
|
|
+ padding: 16px 100px 12px 24px;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .label {
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #222222;
|
|
|
+ line-height: 20px;
|
|
|
+ display: flex;
|
|
|
+ width: max-content;
|
|
|
+ white-space: nowrap;
|
|
|
+ .ivu-tooltip{
|
|
|
+ height: 20px;
|
|
|
+ }
|
|
|
+ .tooltip_icon {
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ margin-left: 4px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .val {
|
|
|
+ font-family: DINOT;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 30px;
|
|
|
+ color: #222222;
|
|
|
+ height: 30px;
|
|
|
+ line-height: 30px;
|
|
|
+ margin: 24px 0 16px;
|
|
|
+ }
|
|
|
+ .group_val{
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 24px;
|
|
|
+ .total_val{
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-weight: 400;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 20px;
|
|
|
+ .val_label {
|
|
|
+ color: #999999;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+ .item_val {
|
|
|
+ color: #136DFB;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ .chart_box{
|
|
|
+ .line_chart{
|
|
|
+ flex:1;
|
|
|
+ min-width: 1120px;
|
|
|
+ height: 400px;
|
|
|
+ background: #FFFFFF;
|
|
|
+ border-radius: 10px
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|