正文
一些echarts的基本图形
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
先拿一个图形渲染过程举例
引用处<bar ref="ARPUChart" v-if="ARPUChart" style="width:500px;height:300px;"></bar>import bar from '../base/ChartBar.vue'获取数据//ARPU达成情况async ARPUChar () { const url = `${this.api.IncomeCause.ARPUCharBarUrl}?${this.requestParam}` try { const res = await this.$http(url) this.authVerify(res.data) if (!this.$store.state.authVerify) { return false } this.ARPUChart = false this.getARPUCharBarData(res.data.data) } catch (e) { this.common.handleError(e, this) }},//渲染图形//ARPU柱状图getARPUCharBarData (barData) { let zoom = false let zoomEnd = 100 if (barData.xAxisData.length > 3) { zoom = true zoomEnd = 2 / barData.xAxisData.length * 100 } this.$nextTick(() => { this.ARPUChart = true setTimeout(() => { let thatChart = this.$refs.ARPUChart.$refs.chartArea thatChart.mergeOptions({ legend: { data: barData.seriesData.map(item => item.name), textStyle: { color: "#999", fontSize: 10 } }, xAxis: [ { data: barData.xAxisData, axisLabel: { textStyle: { color: '#666', fontSize: 12, } }, triggerEvent: true } ], grid: { top: 100, bottom: 40 }, dataZoom: { show: zoom, y: 'bottom', start: 0, end: zoomEnd, height: 14, backgroundColor: '#F0F0F0', dataBackground: { areaStyle: { color: 'rgba(0,0,0,0)' }, lineStyle: { color: 'rgba(0,0,0,0)' } }, handleIcon: 'M0,0 v15h1 v-15h-1 Z M0,4 h3v6h-3v-6 Z M0,4 h-2v6h3v-6 Z', handleStyle: { color: 'rgba(54,147,255,0.8)' }, fillerColor: 'rgba(54,147,255,0.25)', zoomLock: true }, yAxis: [ { type: 'value', name: '', axisTick: { show: false }, splitLine: { show: false }, axisLabel: { formatter: '{value}', textStyle: { color: '#999', fontSize: 12, } }, axisLine: { lineStyle: { color: '#ddd' } } } ], title: { text: barData.title, textStyle: { color: "#333", fontSize: 14 }, top: 30 }, series: (() => { let data = [] barData.seriesData.forEach((item, index) => { const color = this.color[index] data.push({ name: item.name, data: item.data, type: "bar", barWidth: 14, itemStyle: { normal: { color }, emphasis: { color } } }) }) return data })() }) const clickEvent = (params) => { if (params.name === '分公司' || params.value === '分公司' || this.deptId) return if (params.componentType === 'xAxis') { this.setDeptId(params.value) } if (params.componentType === 'series') { this.setDeptId(params.name) } thatChart.chart.off("click", clickEvent) } thatChart.chart.on("click", clickEvent) }, 0) })},
下面是各种基本图形的渲染:
ArpuChar.vue
<template> <chart :options="option" ref="chartArea" auto-resize> </chart></template><script>import ECharts from "vue-echarts/components/ECharts.vue"import "echarts/lib/chart/bar"import "echarts/lib/component/tooltip"import "echarts/lib/component/title"import "echarts/lib/component/legend"export default { components: { chart: ECharts }, data () { return { option: { title: { text: "ARPU", x: "center", textStyle: { fontSize: 14, color: "#333", fontWeight: "normal" } }, tooltip: { trigger: "axis", axisPointer: { // 坐标轴指示器,坐标轴触发有效 type: "shadow", // 默认为直线,可选为:'line' | 'shadow' shadowStyle: { color: 'rgba(0,0,0,0)' } }, formatter (data) { // console.log(data) let str = "" let symbol = { "新客户": -1, "老客户": 1 } if (data.length === 2) { str += `现状(${data[0].seriesName}):${symbol[data[0].seriesName] * (data[0].data)}</br>` str += `同期(${data[1].seriesName}):${symbol[data[1].seriesName] * (data[1].data)}</br>` return str } if (data.length === 3) { str += `现状(${data[0].seriesName}):${symbol[data[0].seriesName] * (data[0].data)}</br>` str += `同期(${data[1].seriesName}):${symbol[data[1].seriesName] * (data[1].data)}</br>` str += `体量(${data[2].seriesName}):${symbol[data[2].seriesName] * (data[2].data)}</br>` return str } str += `现状 (${data[0].seriesName}) : ${symbol[data[0].seriesName] * (data[0].data)}</br>` str += `现状 (${data[1].seriesName}) : ${symbol[data[1].seriesName] * (data[1].data)}</br></br>` str += `同期 (${data[2].seriesName}) : ${symbol[data[2].seriesName] * (data[2].data)}</br>` str += `同期 (${data[3].seriesName}) : ${symbol[data[3].seriesName] * (data[3].data)}</br>` if (data.length > 4) { str += `</br>体量 (${data[4].seriesName}) : ${symbol[data[4].seriesName] * (data[4].data)}</br>` str += `体量 (${data[5].seriesName}) : ${symbol[data[5].seriesName] * (data[5].data)}</br>` } return str } }, color: ["#A6A2F5", "#5AD7FE"], legend: { top: 30, icon: "circle", itemWidth: 6, data: ["新客户", "老客户"] }, grid: { left: "5%", top: "13%", right: "4%", bottom: "3%", containLabel: true }, xAxis: { show: false, type: "value" }, yAxis: [ { type: "category", axisTick: { show: false }, data: ["分公司", "打新", "续约", "直销一部", "KA"], inverse: true }, { type: "category", axisTick: { show: false }, data: (() => { let arr = ['现状', '同期', '体量'] let dataArr = [] for (let i = 0; i < 5; i++) { dataArr = [...dataArr, ...arr] } return dataArr })(), inverse: true } ], series: [ { name: "新客户", type: "bar", stack: "现状", data: [] }, { name: "老客户", type: "bar", stack: "现状", data: [] }, { name: "新客户", type: "bar", stack: "同期", data: [] }, { name: "老客户", type: "bar", stack: "同期", data: [] }, { name: "新客户", type: "bar", stack: "体量", data: [] }, { name: "老客户", type: "bar", stack: "体量", data: [] } ] } } }}</script>
CharPie.vue
<template> <chart :options="option" ref="chartArea" auto-resize> </chart></template><script>import ECharts from "vue-echarts/components/ECharts.vue"import "echarts/lib/chart/pie"import "echarts/lib/component/tooltip"import "echarts/lib/component/title"import "echarts/lib/component/legend"/*const data = [ { value: 40, name: "打新" }, { value: 20, name: "直销" }, { value: 30, name: "续约" }, { value: 10, name: " KA" } ]*/export default { props: ["chartOption"], components: { chart: ECharts }, data () { return { option: { title: { x: "center", top: 10, text: "" }, tooltip: { }, color: [], legend: [], series: [] } } }}</script><style lang="stylus"></style>
ChartBar.vue
<template> <chart :options="option" ref="chartArea" auto-resize> </chart></template><script type="text/ecmascript-6">import ECharts from "vue-echarts/components/ECharts.vue"import 'echarts/lib/chart/bar'import 'echarts/lib/chart/line'import 'echarts/lib/component/legend'import 'echarts/lib/component/title'import 'echarts/lib/component/tooltip'import 'echarts/lib/component/dataZoom'export default { components: { chart: ECharts }, props: ['chartOption'], data () { return { option: { title: { show: true, text: '', top: 10, left: 'center' }, tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, legend: { icon: 'circle', itemWidth: 6, data: [], top: 50 }, grid: { top: 100, left: '3%', right: '4%', bottom: '3%', containLabel: true }, xAxis: [ { type: 'category', axisTick: { show: false }, axisLabel: { textStyle: { color: '#666', fontSize: 12, } }, axisLine: { lineStyle: { color: '#ddd' } }, data: [] } ], yAxis: [ { type: 'value', name: '', axisTick: { show: false }, splitLine: { show: false }, axisLabel: { textStyle: { color: '#666', fontSize: 12, } }, axisLine: { lineStyle: { color: '#ddd' } } }, ], series: [] } } }}</script><style lang="stylus" rel="stylesheet/stylus" scoped>.charts height 100%</style>
ChartStack.vue
<template> <chart :options="option" ref="chartArea" auto-resize> </chart></template><script>import ECharts from "vue-echarts/components/ECharts.vue"import 'echarts/lib/chart/bar'import 'echarts/lib/chart/line'import 'echarts/lib/component/legend'import 'echarts/lib/component/title'import 'echarts/lib/component/tooltip'import 'echarts/lib/component/dataZoom'export default { props: ["chartOption"], components: { chart: ECharts }, data () { return { option: { title: { x: "center", top: 10, text: "" }, tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, legend: { icon: 'circle', itemWidth: 6, data: [], top: 50 }, grid: { top: 100, left: '3%', right: '4%', bottom: '3%', containLabel: true }, yAxis: [ { type: 'value', show: false } ], xAxis: [ { type: 'category', axisTick: { show: false }, axisLabel: { textStyle: { color: '#666', fontSize: 12, } }, axisLine: { lineStyle: { color: '#ddd' } }, data: [] } ], series: [] } } }}</script><style lang="stylus"></style>
ClientForm.vue
<template> <chart :options="option" ref="chartArea" auto-resize></chart></template><script>import ECharts from "vue-echarts/components/ECharts.vue"import "echarts/lib/chart/pie"import "echarts/lib/component/tooltip"import "echarts/lib/component/title"import "echarts/lib/component/legend"export default { components: { chart: ECharts }, data () { return { option: { title: { text: '' }, tooltip: { trigger: 'item', formatter: "{a} <br/>{b} : {c} ({d}%)" }, legend: { data: [] }, color: [], calculable: true, series: [] } } }}</script>
Funnel.vue
<template> <chart :options="option" ref="chartArea" auto-resize> </chart></template><script>import ECharts from "vue-echarts/components/ECharts.vue"import "echarts/lib/chart/funnel"import "echarts/lib/component/tooltip"import "echarts/lib/component/legend"import "echarts/lib/component/markPoint"export default { props: ["chartOption"], components: { chart: ECharts }, data () { return { option: { title: { text: '' }, tooltip: { trigger: 'item', textStyle: { fontSize: 10 }, }, legend: { data: [] }, series: [] } } }}</script><style lang="stylus" scoped>.echarts width 100% !important height 320px !important</style>
IncreaseChar.vue
<template> <chart :options="option" ref="chartArea" auto-resize> </chart></template><script>import ECharts from "vue-echarts/components/ECharts.vue"import "echarts/lib/chart/bar"import "echarts/lib/chart/line"import "echarts/lib/component/tooltip"import "echarts/lib/component/title"import "echarts/lib/component/legend"export default { components: { chart: ECharts }, props: ['chartOption'], data () { return { option: { title: { text: "ARPU", x: "center", textStyle: { fontSize: 14, color: "#333", fontWeight: "normal" } }, color: ["#5B6494", "#EF7CFF", "#FCBE65"], legend: { top: 30, icon: "circle", itemWidth: 6, data: ["现状", "同期", "体量"] }, tooltip: { trigger: "axis", axisPointer: { // 坐标轴指示器,坐标轴触发有效 type: "shadow", // 默认为直线,可选为:'line' | 'shadow' shadowStyle: { color: 'rgba(0,0,0,0)' } }, formatter: (data) => { let tipData = data.filter(item => item.value) // console.log(tipData) let str = '' for (let value of tipData) { str += `${value.marker}${value.seriesName}: ${value.value}%</br>` } return str } // formatter: (a) => { // // // console.log(this.option.legend) // function initArr(arr) { // return arr // .map((item, index) => ({ value: item, index })) // .filter(item => item.value) // } // let dataArr = [] // let series = (() => { // let optionArr = Array.from({length: 6}, () => { // return {} // }) // optionArr.forEach((item, index) => { // if (index === 0 || index === 1) { // item.name = '现状' // item.stack = '现状' // } else if (index === 2 || index === 3) { // item.name = '同期' // item.stack = '同期' // } else { // item.name = '体量' // item.stack = '体量' // } // let dataArr = [] // if (index === 0) { // item.data = this.chartOption.newCustomer.data.now.data // } else if (index === 1) { // item.data = this.chartOption.oldCustomer.data.now.data // } else if (index === 2) { // item.data = this.chartOption.newCustomer.data.lastYear.data.join(' ').split(' ') // } else if (index === 3) { // item.data = this.chartOption.oldCustomer.data.lastYear.data.join(' ').split(' ') // item.data.unshift(null) // } else if (index === 4) { // if (this.chartOption.newCustomer.data.sameLeavl) { // item.data = this.chartOption.newCustomer.data.sameLeavl.data.join(' ').split(' ') // } else { // item.name = '' // item.stack = '' // } // } else if (index === 5) { // if (this.chartOption.oldCustomer.data.sameLeavl) { // item.data = this.chartOption.oldCustomer.data.sameLeavl.data.join(' ').split(' ') // item.data.unshift(null) // } else { // item.name = '' // item.stack = '' // } // } // }) // // // console.log(optionArr) // // // console.log(optionArr) // optionArr = optionArr.filter(item => item.data) // return optionArr // })() // // // console.log(series) // for (let v of series) { // dataArr.push(initArr(v.data)) // } // function mark(color) { // return `<span style="display:inline-blockmargin-right:5pxmargin-bottom:4pxborder-radius:10pxwidth:6pxheight:6pxbackground-color:${color}"></span>` // } // let marks = this.option.color.map(item => mark(item)) // let str = "" // let idx = a.dataIndex // let seriesIndex = a.seriesIndex // // // console.log(idx) // // // console.log(dataArr) // // if (idx % 2 === 0) { // if (seriesIndex === 0 || seriesIndex === 2 || seriesIndex === 4) { // str += '新客户</br>' // let i = 0 // if (a.seriesIndex === 0) { // i = dataArr[0].findIndex(item => item.index === idx) // } else { // i = dataArr[2].findIndex(item => item.index === idx) // } // // // console.log('------------') // // // console.log(i) // // // console.log('-----------') // // // console.log(dataArr) // let data1 = dataArr[0][i]["value"] // let data2 = dataArr[2][i]["value"] // str += `${marks[0]}现状:${data1}%</br>` // str += `${marks[1]}同期:${data2}%</br>` // if (dataArr.length > 4) { // let data3 = dataArr[4][i]["value"] // str += `${marks[2]}体量:${data3}%</br>` // } // // // console.log(1) // // // console.log(a) // } else { // str += '老客户</br>' // // // console.log(2) // let i = 0 // if (a.seriesIndex === 1) { // i = dataArr[1].findIndex(item => item.index === idx) // } else { // i = dataArr[3].findIndex(item => item.index === idx) // } // // // console.log('=====') // // // console.log(i) // // // console.log('=====') // let data1 = dataArr[1][i]["value"] // let data2 = dataArr[3][i]["value"] // str += `${marks[0]}现状:${data1}%</br>` // str += `${marks[1]}同期:${data2}%</br>` // if (dataArr.length > 4) { // let data3 = dataArr[5][i]["value"] // str += `${marks[2]}体量:${data3}%</br>` // } // } // return str // } }, grid: { top: 80, bottom: 30, left: '25%', right: 60 }, xAxis: { type: "value", position: "top", splitNumber: 3, axisTick: { show: false }, splitLine: { show: false }, axisLabel: { formatter: "{value}%" } }, yAxis: [ { type: "category", axisLine: { show: false }, // axisLabel: {show: false}, axisTick: { show: false }, splitLine: { show: false }, data: ["分公司", "打新", "续约", "直销一部", "KA"], inverse: true }, { inverse: true, axisTick: { show: false }, data: (() => { let arr = ['新客户', '老客户'] let dataArr = [] for (let i = 0; i < 5; i++) { dataArr = [...dataArr, ...arr] } return dataArr })() } ], series: [ { name: "现状", stack: '总量', yAxisIndex: 1, type: "bar", data: [] }, { name: "现状", stack: '总量', yAxisIndex: 1, type: "bar", data: [] }, { name: "同期", yAxisIndex: 1, lineStyle: { width: 0 }, symbol: "pin", symbolSize: 20, type: "line", data: [] }, { name: "同期", yAxisIndex: 1, lineStyle: { width: 0 }, symbol: "pin", symbolSize: 20, type: "line", data: [] }, { name: "体量", yAxisIndex: 1, lineStyle: { width: 0 }, symbol: "pin", symbolSize: 20, type: "line", data: [] }, { name: "体量", yAxisIndex: 1, lineStyle: { width: 0 }, symbol: "pin", symbolSize: 20, type: "line", data: [] } ] } } }}</script>
LeftHightlight.vue
<template> <div class="leftHight"> <div class="leftContent"> <div class="conLeft"> <div class="number"> <span>{{thisData.customNum.total | currency}}</span> <span>签单客户数</span> </div> <div class="compar"> <div> <span>同比</span> <span>{{thisData.customNum.lastYearCompare}}%</span> <span class="icon-upp" v-if="thisData.customNum.lastYearCompare > 0"></span> <span class="icon-down" v-if="thisData.customNum.lastYearCompare < 0"></span> </div> <div> <span>同期</span> <span>{{thisData.customNum.yearOverYearCompare}}%</span> <span class="icon-upp" v-if="thisData.customNum.yearOverYearCompare > 0"></span> <span class="icon-down" v-if="thisData.customNum.yearOverYearCompare < 0"></span> </div> <div> <span>体量</span> <span>{{thisData.customNum.sameLevelCompare}}%</span> <span class="icon-upp" v-if="thisData.customNum.sameLevelCompare > 0"></span> <span class="icon-down" v-if="thisData.customNum.sameLevelCompare < 0"></span> </div> </div> <div class="reach"> <el-progress :percentage="parseInt(thisData.customNum.reachRate)>100?100:parseInt(thisData.customNum.reachRate)" :show-text="false" class="speed"></el-progress> <span>达成率:{{thisData.customNum.reachRate}}%</span> </div> </div> <div class="conMid"> <div class="number">{{thisData.ARPU.number | money | currency }}</div> <div class="name">ARPU</div> <div class="compar"> <span>同期</span> <span>{{thisData.ARPU.yearOverYearCompare | money | currency}}</span> <span class="icon-upp" v-if="thisData.ARPU.yearOverYearCompare > 0"></span> <span class="icon-down" v-if="thisData.ARPU.yearOverYearCompare < 0"></span> </div> <div class="compar"> <span>体量</span> <span>{{thisData.ARPU.sameLevelCompare | money | currency}}</span> <span class="icon-upp" v-if="thisData.ARPU.sameLevelCompare > 0"></span> <span class="icon-down" v-if="thisData.ARPU.sameLevelCompare < 0"></span> </div> </div> <div class="conRight"> <div class="number"> <span>{{parseInt(thisData.income.number) | money | currency}}</span> <span>签单金额</span> </div> <div class="compar"> <div> <span>同比</span> <span>{{thisData.income.lastYearCompare}}%</span> <span class="icon-upp" v-if="thisData.income.lastYearCompare > 0"></span> <span class="icon-down" v-if="thisData.income.lastYearCompare < 0"></span> </div> <div> <span>同期</span> <span>{{thisData.income.yearOverYearCompare}}%</span> <span class="icon-upp" v-if="thisData.income.yearOverYearCompare > 0"></span> <span class="icon-down" v-if="thisData.income.yearOverYearCompare < 0"></span> </div> <div> <span>体量</span> <span>{{thisData.income.sameLevelCompare}}%</span> <span class="icon-upp" v-if="thisData.income.sameLevelCompare > 0"></span> <span class="icon-down" v-if="thisData.income.sameLevelCompare < 0"></span> </div> </div> <div class="reach"> <el-progress :percentage="parseInt(thisData.income.reachRate)>100 ?100:parseInt(thisData.income.reachRate)" :show-text="false" class="speed"></el-progress> <span>达成率:{{thisData.income.reachRate}}%</span> </div> </div> </div> <div class="rightContent" @click="toPeople" ref="rightContent"> <div class="rightLeft"> <div class="number">{{thisData.peopleYield.number | money | currency}}</div> <div class="name">人均单产</div> <div class="compar"> <span>同期</span> <span>{{thisData.peopleYield.yearOverYearCompare | money | currency}}</span> <span class="icon-upp" v-if="thisData.peopleYield.yearOverYearCompare > 0"></span> <span class="icon-down" v-if="thisData.peopleYield.yearOverYearCompare < 0"></span> </div> <div class="compar"> <span>体量</span> <span>{{thisData.peopleYield.sameLevelCompare | money | currency}}</span> <span class="icon-upp" v-if="thisData.peopleYield.sameLevelCompare > 0"></span> <span class="icon-down" v-if="thisData.peopleYield.sameLevelCompare < 0"></span> </div> </div> <div class="rightRight"> <div class="number">{{thisData.postPeople.postNum | currency}}</div> <div class="name">在岗人数</div> <div class="compar"> <span>预算人数 {{thisData.postPeople.budgetNum}}</span> <span>满编率 {{thisData.postPeople.full}}%</span> </div> <div class="compar"> <span>流失率 {{thisData.postPeople.loss}}%</span> <span>底线 {{thisData.postPeople.baseline}}%</span> </div> </div> </div> </div></template><script type="text/ecmascript-6">import { mapGetters, mapActions } from 'vuex'import getParam from '../mixins/getParam'//import incomeCauseHeader from '../../json/incomeCauseHeader.json'export default { mixins: [getParam], data () { return { thisData: { customNum: { total: 0, lastYearCompare: 0, yearOverYearCompare: 0, sameLevelCompare: 0, reachRate: 0 }, ARPU: { number: 0, yearOverYearCompare: 0, sameLevelCompare: 0 }, income: { number: 0, lastYearCompare: 0, yearOverYearCompare: 0, sameLevelCompare: 0, reachRate: 0 }, peopleYield: { number: 0, yearOverYearCompare: 0, sameLevelCompare: 0 }, postPeople: { postNum: 0, budgetNum: 0, full: 0, loss: 0, baseline: 0 } } } }, watch: { }, computed: { ...mapGetters(['scope', 'deptId', 'compId']) }, mounted () { }, methods: { ...mapActions(['authVerify']), toPeople () { let router = this.$route.path if (router === '/incomeCause') { this.$router.push('/incomePeople') } }, async getHeaderData () { const url = `${this.api.head.incomeHeader}?${this.requestParam}` //this.thisData = null try { const res = await this.$http(url) this.authVerify(res.data) if (!this.$store.state.authVerify) { return false } this.thisData = res.data } catch (e) { this.common.handleError(e, this) } } }}</script><style lang="stylus" ref="stylesheet/stylus" scoped>.leftHight display flex width 1050px height 150px font-family PingFang-SC-Medium .leftContent display flex width 658px height 150px padding 20px padding-right 0px border-radius 4px box-shadow 0 0 20px 0 rgba(152, 141, 194, 0.23) background-color #fff cursor pointer box-sizing border-box margin-right 10px &:hover transition 0.1s all linear width 678px height 170px margin-left -10px margin-top -10px background #F8F8F8 box-shadow 0 1px 6px 0 rgba(0, 0, 0, 0.38) .conLeft, .conRight width 220px display flex flex-wrap wrap border-right 1px solid #DDDDDD box-sizing border-box .number display flex width 120px height 60px flex-direction column span &:nth-of-type(1) height 40px line-height 40px font-size 28px color #333333 &:nth-of-type(2) height 20px font-size 14px color #666666 .compar height 75px div display flex height 20px margin-bottom 5px span padding-right 2px height 20px line-height 20px font-size 12px color #999999 white-space nowrap .reach width 215px display flex align-items flex-end .speed width 77px height 14px margin-right 43px span height 20px line-height 20px font-size 12px color #999 .conMid width 135px display flex flex-direction column border-right 1px solid #DDDDDD box-sizing border-box .number height 40px font-size 28px color #333333 margin-bottom 4px padding-left 20px .name padding-left 20px font-size 14px color #666666 margin-bottom 10px .compar font-size 12px color #999999 display flex padding-left 20px span padding-right 5px height 20px line-height 20px white-space nowrap .conRight width 283px padding-left 10px border none .number width 178px margin-right 10px .rightContent width 370px height 150px padding 20px padding-right 0px cursor pointer display flex box-sizing border-box background-color #fff border-radius 4px &:hover transition 0.1s all linear width 380px height 170px margin-left -10px margin-top -10px background #F8F8F8 box-shadow 0 1px 6px 0 rgba(0, 0, 0, 0.38) .rightLeft, .rightRight display flex flex-direction column .number height 40px line-height 40px font-size 28px color #333333 margin-bottom 4px .name font-size 14px color #666666 margin-bottom 10px .compar font-size 12px color #999999 display flex span padding-right 5px height 20px line-height 20px .rightLeft // width: 222px .rightRight // width:160px margin-left 5px .compar span padding-right 2px</style>
OldClient.vue
<template> <chart :options="option" ref="chartArea" auto-resize></chart></template><script>import ECharts from "vue-echarts/components/ECharts.vue"import "echarts/lib/chart/bar"import "echarts/lib/component/tooltip"import "echarts/lib/component/title"import "echarts/lib/component/legend"export default { components: { chart: ECharts }, data () { return { option: { title: { text: '' }, tooltip: { trigger: "axis", axisPointer: { type: 'none' } }, color: [], legend: { data: [] }, xAxis: { type: 'category', data: [] }, yAxis: { type: 'value' }, series: [] } } }}</script>
ProportionChar.vue
<template> <chart :options="option" ref="chartArea" auto-resize> </chart></template><script>import ECharts from "vue-echarts/components/ECharts.vue"import "echarts/lib/chart/bar"import "echarts/lib/component/tooltip"import "echarts/lib/component/title"import "echarts/lib/component/legend"import "echarts/lib/component/dataZoom"export default { components: { chart: ECharts }, data () { return { option: { title: { text: "签单占比情况", x: "center", textStyle: { fontSize: 14, color: "#333", fontWeight: "normal" } }, color: ["#5AD7FE", "#A6A2F5"], tooltip: { trigger: "axis", axisPointer: { // 坐标轴指示器,坐标轴触发有效 type: "shadow", // 默认为直线,可选为:'line' | 'shadow' shadowStyle: { color: 'rgba(0,0,0,0)' } }, textStyle: { fontSize: 12 }, formatter (data) { // console.log(data) let str = "" if (data.length === 2) { str += `现状(${data[0].seriesName}):${data[0].data}%</br>` str += `同期(${data[1].seriesName}):${data[1].data}%</br>` return str } if (data.length === 3) { str += `现状(${data[0].seriesName}):${data[0].data}%</br>` str += `同期(${data[1].seriesName}):${data[1].data}%</br>` str += `体量(${data[2].seriesName}):${data[2].data}%</br>` return str } if (data.length === 4) { str += `现状(新客户) : ${data[2].data}%</br>` str += `现状(老客户) : ${data[0].data}%</br></br>` // str += `同期(新客户) : ${data[4].data}%</br>` str += `同期(新客户) : ${data[3].data}%</br>` // str += `体量(新客户) : ${data[5].data}%</br>` str += `同期(老客户) : ${data[1].data}%</br>` return str } str += `现状(新客户) : ${data[3].data}%</br>` str += `现状(老客户) : ${data[0].data}%</br></br>` str += `同期(新客户) : ${data[4].data}%</br>` str += `同期(老客户) : ${data[1].data}%</br></br>` str += `体量(新客户) : ${data[5].data}%</br>` str += `体量(老客户) : ${data[2].data}%</br>` return str } }, legend: { top: 30, icon: "circle", itemWidth: 6, data: ["新客户", "老客户"] }, grid: { left: "4%", right: "4%", bottom: '20%', containLabel: true }, xAxis: { type: "category", data: ["分公司", "打新", "续约", "直销", "KA"], axisTick: { show: false }, offset: 40 }, yAxis: { splitNumber: 2, type: "value", axisTick: { show: false }, splitLine: { show: false }, axisLabel: { textStyle: { color: "#666" }, show: true, interval: "auto", formatter: "{value} %" } }, dataZoom: { showDetail: false, height: 20, start: 0, show: false, // end: 50, zoomLock: true, backgroundColor: "#F0F0F0", fillerColor: "rgba(54,147,255,0.25)", bottom: "10", handleIcon: "M0,0 v5h1 v-5h-1 Z M0,15 v-5h1 v5h-1 Z M0,5 h3v5h-3v-5 Z M-3,5 h3v5h-3v-5 Z", handleStyle: { color: "rgba(54,147,255,0.8)" }, dataBackground: { areaStyle: { color: "rgba(0,0,0,0)" }, lineStyle: { color: "rgba(0,0,0,0)" } } }, series: [ { name: "老客户", z: 3, type: "bar", stack: "现状", label: { normal: { color: "#999", formatter: "现\n状", show: true, position: "bottom", backgroundColor: '#fff', distance: 1, padding: [5, 0] } }, data: [] }, { name: "老客户", z: 3, type: "bar", stack: "同期", label: { normal: { color: "#999", formatter: "同\n期", show: true, position: "bottom", backgroundColor: '#fff', distance: 1, padding: [5, 0] } }, data: [] }, { name: "老客户", z: 3, type: "bar", stack: "体量", label: { normal: { color: "#999", formatter: "体\n量", show: true, position: "bottom", backgroundColor: '#fff', distance: 1, padding: [5, 0] } }, data: [] }, { name: "新客户", type: "bar", stack: "现状", label: { normal: { color: "#999", formatter: "现\n状", show: true, position: "bottom" } }, data: [] }, { name: "新客户", type: "bar", stack: "同期", label: { normal: { color: "#999", formatter: "同\n期", show: true, position: "bottom" } }, data: [] }, { name: "新客户", type: "bar", stack: "体量", label: { normal: { color: "#999", formatter: "体\n量", show: true, position: "bottom" } }, data: [] } ] } } }}</script>
RightHightlight.vue
<template> <div class="leftHight" v-if="thisData"> <div class="leftContent" @click="toCause"> <div class="conLeft"> <div class="number"> <span>{{thisData.customNum.total | currency}}</span> <span>签单客户数</span> </div> <div class="compar"> <div> <span>同比</span> <span>{{thisData.customNum.lastYearCompare}}%</span> <span class="icon-upp" v-if="thisData.customNum.lastYearCompare > 0"></span> <span class="icon-down" v-if="thisData.customNum.lastYearCompare < 0"></span> </div> <div> <span>同期</span> <span>{{thisData.customNum.yearOverYearCompare}}%</span> <span class="icon-upp" v-if="thisData.customNum.yearOverYearCompare > 0"></span> <span class="icon-down" v-if="thisData.customNum.yearOverYearCompare < 0"></span> </div> <div> <span>体量</span> <span>{{thisData.customNum.sameLevelCompare}}%</span> <span class="icon-upp" v-if="thisData.customNum.sameLevelCompare > 0"></span> <span class="icon-down" v-if="thisData.customNum.sameLevelCompare < 0"></span> </div> </div> <div class="reach"> <el-progress :percentage="parseInt(thisData.customNum.reachRate)>100?100:parseInt(thisData.customNum.reachRate)" :show-text="false" class="speed"></el-progress> <span>达成率:{{thisData.customNum.reachRate}}%</span> </div> </div> <div class="conMid"> <div class="number">{{thisData.ARPU.number | money | currency}}</div> <div class="name">ARPU</div> <div class="compar"> <span>同期</span> <span>{{thisData.ARPU.yearOverYearCompare | money | currency}}</span> <span class="icon-upp" v-if="thisData.ARPU.yearOverYearCompare > 0"></span> <span class="icon-down" v-if="thisData.ARPU.yearOverYearCompare < 0"></span> </div> <div class="compar"> <span>体量</span> <span>{{thisData.ARPU.sameLevelCompare | money | currency}}</span> <span class="icon-upp" v-if="thisData.ARPU.sameLevelCompare > 0"></span> <span class="icon-down" v-if="thisData.ARPU.sameLevelCompare < 0"></span> </div> </div> </div> <div class="rightContent"> <div class="conRight"> <div class="number"> <span>{{parseInt(thisData.income.number) | money | currency}}</span> <span>签单金额</span> </div> <div class="compar"> <div> <span>同比</span> <span>{{thisData.income.lastYearCompare}}%</span> <span class="icon-upp" v-if="thisData.income.lastYearCompare > 0"></span> <span class="icon-down" v-if="thisData.income.lastYearCompare < 0"></span> </div> <div> <span>同期</span> <span>{{thisData.income.yearOverYearCompare}}%</span> <span class="icon-upp" v-if="thisData.income.yearOverYearCompare > 0"></span> <span class="icon-down" v-if="thisData.income.yearOverYearCompare < 0"></span> </div> <div> <span>体量</span> <span>{{thisData.income.sameLevelCompare}}%</span> <span class="icon-upp" v-if="thisData.income.sameLevelCompare > 0"></span> <span class="icon-down" v-if="thisData.income.sameLevelCompare < 0"></span> </div> </div> <div class="reach"> <el-progress :percentage="parseInt(thisData.income.reachRate)>100?100:parseInt(thisData.income.reachRate)" :show-text="false" class="speed"></el-progress> <span>达成率:{{thisData.income.reachRate}}%</span> </div> </div> <div class="rightLeft"> <div class="number">{{parseInt(thisData.peopleYield.number) | money | currency}}</div> <div class="name">人均单产</div> <div class="compar"> <span>同期</span> <span>{{parseInt(thisData.peopleYield.yearOverYearCompare) | money | currency }}</span> <span class="icon-upp" v-if="thisData.income.yearOverYearCompare > 0"></span> <span class="icon-down" v-if="thisData.income.yearOverYearCompare < 0"></span> </div> <div class="compar"> <span>体量</span> <span>{{parseInt(thisData.peopleYield.sameLevelCompare) | money | currency }}</span> <span class="icon-upp" v-if="thisData.income.sameLevelCompare > 0"></span> <span class="icon-down" v-if="thisData.income.sameLevelCompare < 0"></span> </div> </div> <div class="rightRight"> <div class="number">{{thisData.postPeople.postNum | currency}}</div> <div class="name">在岗人数</div> <div class="compar"> <span>预算人数 {{thisData.postPeople.budgetNum}}</span> <span>满编率 {{thisData.postPeople.full}}%</span> </div> <div class="compar"> <span>流失率 {{thisData.postPeople.loss}}%</span> <span>底线 {{thisData.postPeople.baseline}}%</span> </div> </div> </div> </div></template><script type="text/ecmascript-6">import { mapGetters, mapActions } from 'vuex'import getParam from '../mixins/getParam'//import incomeCauseHeader from '../../json/incomeCauseHeader.json'export default { mixins: [getParam], data () { return { thisData: { customNum: { total: 0, lastYearCompare: 0, yearOverYearCompare: 0, sameLevelCompare: 0, reachRate: 0 }, ARPU: { number: 0, yearOverYearCompare: 0, sameLevelCompare: 0 }, income: { number: 0, lastYearCompare: 0, yearOverYearCompare: 0, sameLevelCompare: 0, reachRate: 0 }, peopleYield: { number: 0, yearOverYearCompare: 0, sameLevelCompare: 0 }, postPeople: { postNum: 0, budgetNum: 0, full: 0, loss: 0, baseline: 0 } } } }, watch: { }, computed: mapGetters(['scope', 'deptId', 'compId']), mounted () { }, methods: { ...mapActions(['authVerify']), toCause () { let router = this.$route.path if (router === '/incomePeople') { this.$router.push('/incomeCause') } }, async getHeaderData () { const url = `${this.api.head.incomeHeader}?${this.requestParam}` //this.thisData = null try { const res = await this.$http(url) this.authVerify(res.data) if (!this.$store.state.authVerify) { return false } this.thisData = res.data } catch (e) { this.common.handleError(e, this) } } }}</script><style lang="stylus" ref="stylesheet/stylus" scoped>.leftHight display flex width 1050px height 150px font-family PingFang-SC-Medium .leftContent display flex width 360px height 150px padding 20px padding-right 10px cursor pointer box-sizing border-box background-color #fff border-radius 4px margin-right 20px &:hover transition 0.1s all linear width 380px height 170px margin-left -10px margin-top -10px background #F8F8F8 box-shadow 0 1px 6px 0 rgba(0, 0, 0, 0.38) .conLeft width 200px display flex flex-wrap wrap .number display flex width 110px height 60px flex-direction column span &:nth-of-type(1) height 40px line-height 40px font-size 28px color #333333 &:nth-of-type(2) height 20px font-size 14px color #666666 .compar width 90px height 60px div display flex height 20px margin-bottom 5px span padding-right 5px height 20px line-height 20px font-size 12px color #999999 white-space nowrap .reach width 200px align-items center display flex .speed width 100px height 7px margin-right 9px span height 20px line-height 20px font-size 12px color #999 .conMid width 130px display flex flex-direction column .number height 40px font-size 28px color #333333 margin-bottom 4px padding-left 20px .name padding-left 20px font-size 14px color #666666 margin-bottom 10px .compar font-size 12px color #999999 display flex padding-left 20px span padding-right 5px height 16px line-height 16px white-space nowrap .rightContent width 660px height 150px padding 20px 10px display flex background-color #fff border-radius 4px box-shadow 0 0 20px 0 rgba(152, 141, 194, 0.23) cursor pointer box-sizing border-box &:hover transition 0.1s all linear width 680px height 170px margin-left -10px margin-top -10px background #F8F8F8 box-shadow 0 1px 6px 0 rgba(0, 0, 0, 0.38) .conRight width 300px display flex flex-wrap wrap padding-left 8px border-right 1px solid #DDDDDD .number display flex width 183px height 60px flex-direction column span &:nth-of-type(1) height 40px line-height 40px font-size 28px color #333333 &:nth-of-type(2) height 20px font-size 14px color #666666 .compar width 100px height 60px div display flex height 20px margin-bottom 5px span height 20px padding-right 5px line-height 20px font-size 12px color #999999 white-space nowrap .reach width 283px display flex .speed width 157px height 20px padding-top 6px margin-right 26px span height 20px line-height 20px font-size 12px color #999 .rightLeft, .rightRight display flex flex-direction column .number height 40px line-height 40px font-size 28px color #333333 margin-bottom 4px padding-left 5px padding-right 5px .name padding-left 10px font-size 14px color #666666 margin-bottom 10px .compar font-size 12px color #999999 display flex padding-left 10px span padding-right 5px height 16px line-height 16px white-space nowrap .rightLeft border-right 1px solid #DDDDDD .rightRight width 180px .compar span width 75px height 16px line-height 16px &:nth-of-type(1) margin-right 5px</style>
Scatter.vue
<template> <chart :options="option" ref="chartArea" auto-resize class="scatter" /></template><script>import ECharts from "vue-echarts/components/ECharts.vue"import "echarts/lib/chart/scatter"import "echarts/lib/component/tooltip"import "echarts/lib/component/legend"import "echarts/lib/component/title"export default { components: { chart: ECharts }, data () { return { option: { title: { text: '人员满编率', x: 'center', top: 10, textStyle: { color: "#333", fontSize: 14 } }, tooltip: { trigger: 'item', // showDelay: 0, // axisPointer: { // show: true, // type: 'cross', // lineStyle: { // // type: 'dashed', // width: 0, // opacity: 0 // }, // label: { // show: false // } // }, formatter ({ ...args }) { const val = args.data let institution = '满编' if (val[0] > 100) { institution = `超编人数:${Math.abs(val[1])}` } else if (val[0] < 100) { institution = `缺编人数:${Math.abs(val[1])}` } let res = `在岗人数:${val[2]}<br />满编率:${val[0]}%<br />${institution}` return res } }, legend: [], grid: { y: 100, y2: 30 }, xAxis: [{ type: 'value', name: '满编率', min: 0, scale: true, axisTick: { show: false }, axisLine: { lineStyle: { color: '#ddd', width: 2 } }, nameTextStyle: { color: '#999', fontSize: 12, padding: -10 }, axisLabel: { textStyle: { color: '#999', fontSize: 12 }, formatter (val) { return `${val}%` } }, splitLine: { show: false }, textStyle: { color: '#999', fontSize: 12, } }], yAxis: [{ type: 'value', scale: true, nameTextStyle: { color: '#999', fontSize: 12 }, axisTick: { show: false }, axisLine: { lineStyle: { color: '#ddd', width: 2 } }, axisLabel: { textStyle: { color: '#999', fontSize: 12 } }, splitLine: { show: false } }], series: [] } } }}</script>
SingleCharBar.vue
<template> <chart :options="option" ref="chartArea" auto-resize> </chart></template><script>import ECharts from "vue-echarts/components/ECharts.vue"import "echarts/lib/chart/bar"import "echarts/lib/component/tooltip"import "echarts/lib/component/title"import "echarts/lib/component/legend"export default { components: { chart: ECharts }, data () { return { option: { tooltip: { }, color: [], title: { text: "", x: "center", top: 10 }, legend: { bottom: 40, itemGap: 21, icon: "circle", itemWidth: 6, data: [] }, barWidth: "30px", calculable: true, xAxis: [ { show: false, type: "value" } ], yAxis: [ { show: false, type: "category", data: [""] } ], series: [] } } }}</script><style lang="stylus"></style>
TLSecondHeaderMoudle.vue
<template> <div class="moudleWrapper"> <h1 v-if="(baseData.name === '签单金额') || (baseData.name === '回款金额')">{{baseData.value | money | currency }}</h1> <h1 v-else>{{baseData.value | currency }}</h1> <div class="name">{{baseData.name}}</div> <div class="content"> <div class="reachRate"> <span>达成率:</span> <span>{{baseData.rate | currency(2)}}%</span> </div> <div class="time"> <span>{{baseData.advanceRate > 0 ? '超前时间进度' : '落后时间进度'}}</span> <span :class="baseData.advanceRate > 0 ? 'advance' : 'backward'">{{ Math.abs(baseData.advanceRate) | currency(2) }}%</span> </div> <!-- <div class="businessDepart"> <span>事业部达成率:</span> <span>{{baseData.businessDepart}}%</span> </div> --> </div> </div></template><script>export default { props: ['baseData']}</script><style lang="stylus" scoped>.moudleWrapper width 250px min-height 100px padding-left 19px !important box-sizing border-box h1 margin-bottom 5px font-size 26px color #333 letter-spacing 0.05px .name margin-bottom 12px font-size 14px color #666666 letter-spacing -0.12px .content display flex flex-wrap wrap .reachRate width 100px margin-bottom 10px .time width 130px margin-bottom 10px .reachRate, .time, .businessDepart span &:nth-of-type(1) font-size 12px color #999 letter-spacing -0.03px &:nth-of-type(2) font-size 13px color #54A5FF line-height 17px letter-spacing -0.03px .advance color #03B04C !important .backward color #FF5656 !important</style>
checkArea.vue
<template> <div> <div class="checkArea" v-if="cityData"> <div class="areas" v-for="(item,index) in cityData" v-if="cityData[0]['appDeptLevel'] == 1"> <h3>{{item.appDeptName}}:</h3> <div class="children"> <div class="child" :class="itemChild.sysDeptId == compId ? 'Select' : ''" v-for="(itemChild,indexChild) in item.childList" @click="checkCity($event,itemChild.sysDeptId,itemChild.appDeptName)">{{itemChild.appDeptName}}</div> </div> </div> </div> <div class="checkAreaTwo" v-if="cityData"> <div class="childrenTwo" v-for="(item,index) in cityData" v-if="cityData[0]['appDeptLevel'] == 2"> <div class="childTwo" :class="item.sysDeptId == compId ? 'SelectTwo' : ''" @click="checkCity($event,item.sysDeptId,item.appDeptName)" style="margin-bottom:0px">{{item.appDeptName}}</div> </div> </div> </div></template><script>import { mapGetters, mapActions } from "vuex"//import city from '../../json/city.json'export default { data () { return { cityData: [] } }, mounted () { this.getData() }, computed: mapGetters(['compId']), methods: { ...mapActions(["authVerify", 'setCompId', 'setCityName']), async getData () { let empId = this.common.getCookie('ZPSSO_USER_EMPID') const FirstUrl = `${this.api.judgeRole}${empId}` try { const resFirst = await this.$http(FirstUrl) if (resFirst.data.data && resFirst.data.data.roleIdList) { let roleIdList = resFirst.data.data.roleIdList let url = `${this.api.cityUrl}&empId=${empId}` let ret1 = roleIdList.find(function (elem, index) { return elem == 314 }) let ret2 = roleIdList.find(function (elem, index) { return elem == 5 }) let ret3 = roleIdList.find(function (elem, index) { return elem == 9 }) if (ret1 || ret2 || ret3) { url += `&business=all` } try { const res = await this.$http(url) this.cityData = res.data.data } catch (e) { this.common.handleError(e, this) } } } catch (e) { this.common.handleError(e, this) } }, checkCity (event, compId, curCity) { if (compId == this.compId) { this.setCompId('') this.setCityName('') this.$emit("storageCityName") } else { this.setCompId(compId) this.setCityName(curCity) this.$emit("storageCityName") } } }}</script><style lang="stylus" scoped>.checkArea display flex flex-direction column .areas display flex flex-direction column &:last-child margin-bottom 0px h3 font-size 14px color #666 margin-bottom 10px .children display flex flex-direction row flex-wrap wrap .child display flex padding 6px 13px height 26px margin-right 20px margin-bottom 20px justify-content center align-items center background #FFFFFF border 1px solid #DDDDDD border-radius 2px box-sizing border-box font-size 14px color #999999 cursor pointer &:last-child margin-right 0px .Select color #fff background-color #3693FF.checkAreaTwo display flex flex-direction row .childrenTwo display flex flex-direction row flex-wrap wrap margin-right 20px .childTwo display flex flex-direction row padding 6px 13px height 26px margin-bottom 20px justify-content center align-items center background #FFFFFF border 1px solid #DDDDDD border-radius 2px box-sizing border-box font-size 14px color #999999 cursor pointer &:last-child margin-right 0px .SelectTwo color #fff background-color #3693FF</style>
punchcardScatter.vue
<template> <chart :options="option" ref="chartArea" auto-resize class="scatter" /></template><script>import ECharts from "vue-echarts/components/ECharts.vue"import "echarts/lib/chart/scatter"import "echarts/lib/component/tooltip"import "echarts/lib/component/legend"import "echarts/lib/component/title"import "echarts/lib/component/markLine"// var Ydata = ['S0', 'S1', 'S2', 'S3', 'S4', 'S5', 'S6','S7', 'S8', 'S9'];// var Xdata = ["TL_打新1部","TL_打新2部","TL_打新3部","TL_打新4部","TL_打新5部"]// var data = [// [0,0,5],[1,0,1],[2,0,0],[3,0,0],[4,0,0],// [0,1,0],[1,1,0],[2,1,0],[3,1,0],[4,1,0],// [0,2,0],[1,2,2],[2,2,4],[3,2,2],[4,2,1],// [0,3,3],[1,3,4],[2,3,6],[3,3,4],[4,3,4],// [0,4,3],[1,4,3],[2,4,2],[3,4,5],[4,4,7],// [0,5,0],[1,5,0],[2,5,0],[3,5,0],[4,5,0],// [0,6,0],[1,6,0],[2,6,0],[3,6,0],[4,6,5],// [0,7,2],[1,7,2],[2,7,6],[3,7,9],[4,7,11],// [0,8,6],[1,8,7],[2,8,8],[3,8,4],[4,8,5],// [0,9,5],[1,9,7],[2,9,2],[3,9,4],[4,9,1]// ];// var data1 = data.map(function (item) {// return [item[0], item[1], item[2]]// })// var data2 = data.map(function (item) {// return [item[0], item[1], item[2]+2]// })export default { components: { chart: ECharts }, data () { return { option: { title: { textStyle: { color: "#333", fontSize: 14 } }, legend: {}, grid: { left: 40, bottom: 10, right: 30, containLabel: true }, xAxis: { type: 'category', boundaryGap: false, axisTick: { show: false }, splitLine: { show: true, lineStyle: { color: '#ddd', type: 'solid' } }, axisLine: { show: true, lineStyle: { color: '#ddd', } }, axisLabel: { rotate: 40, textStyle: { color: '#666', fontSize: 12, } } }, yAxis: { type: 'category', axisLine: { show: true, lineStyle: { color: '#ddd', } }, axisTick: { show: false }, splitLine: { show: false, lineStyle: { color: '#999', type: 'dashed' } }, axisLabel: { textStyle: { color: '#666', fontSize: 12, } }, }, series: [] } } }}</script>