1. echarts介绍
首先我们先完成每个页面的路由,之前已经有home页面和user页面,缺少mail页面和其它选项下的page1和page2页面。在view文件夹下新建mail文件夹,新建index.vue,填充user页面的内容即可。在view下新建other文件夹,新建pageOne.vue和pageTwo.vue,页面内容简单填充即可。三个页面都要更改name属性,后面会用到,首字母大写。
cnpm i echarts@5.1.2安转指定版本依赖,在饼图的位置添加div,不需要在main.js中引入,只需要在home下的index.vue无版本引入。
(1)引入echarts
javascript
import * as echarts from 'echarts'
(2)展示echarts饼图
javascript
<el-card style="height:280px;">
<div style="height:280px" ref="echarts"></div>
</el-card>
(3)更改mounted(){},data下包含四个图的数据,注意orderData下的第一个数据是date!!报错一直找不到是这个原因。这里用Object.keys()返回数组的属性而不包含属性值。keyArray就是一个key的集合(图例集合、数组属性集合),所以此处进行遍历。legend表示图例,就是keyArray。
javascript
mounted() {
getData().then(res => {
const {code, data} = res.data
if (code === 20000) {
this.tableData = data.tableData
const order = data.orderData
const xData = order.date
const keyArray = Object.keys(order.data[0])
const series = []
keyArray.forEach(key => {
series.push({
name: key,
data: order.data.map(item => item[key]),
type: 'line'
})
})
const option = {
xAxis: {
data: xData
},
yAxis: {},
legend: {
data: keyArray
},
series:series
}
const myEcharts = echarts.init(this.$refs.echarts)
myEcharts.setOption(option)
}
})
}
1.1. 折线图实现
将type改为line
javascript
mounted() {
getData().then(res => {
const {code, data} = res.data
if (code === 20000) {
this.tableData = data.tableData
const order = data.orderData
const xData = order.date
const keyArray = Object.keys(order.data[0])
const series = []
keyArray.forEach(key => {
series.push({
name: key,
data: order.data.map(item => item[key]),
type: 'bar'
})
})
const option = {
xAxis: {
data: xData
},
yAxis: {},
legend: {
data: keyArray
},
series:series
}
const myEcharts = echarts.init(this.$refs.echarts)
myEcharts.setOption(option)
}
})
}
效果图
1.2. 柱状图实现
src/views/home下的index.js。
javascript
<el-card class="graph-item1" >
<div style="height:210px" ref='barEchartRef'></div>
</el-card>
mounted进行数据添加
javascript
//柱状图
const userOption = {
legend: {
// 图例文字颜色
textStyle: {
color: "#333",
},
},
grid: {
left: "20%",
},
// 提示框
tooltip: {
trigger: "axis",
},
xAxis: {
type: "category", // 类目轴
data: data.userData.map(item=>item.date),
axisLine: {
lineStyle: {
color: "#17b3a3",
},
},
axisLabel: {
interval: 0,
color: "#333",
},
},
yAxis: [
{
type: "value",
axisLine: {
lineStyle: {
color: "#17b3a3",
},
},
},
],
color: ["#2ec7c9", "#b6a2de"],
series: [
{
name:'新增用户',
data:data.userData.map(item=>item.new),
type:'bar'
},
{
name:'活跃用户',
data:data.userData.map(item=>item.active),
type:'bar'
}
],
}
const barEchart = echarts.init(this.$refs.barEchartRef)
barEchart.setOption(userOption)
效果图
1.3. 饼图实现
原理其实跟柱状图一样,知识柱状图条件会多一些。
javascript
const picOption = {
title: {//标题
subtext: "",
text: "饼图数据统计",
top: 'top',
left: 'center',
textStyle: {
fontSize: 11,
}
},
legend: {
itemHeight: 8,
itemWidth: 8,
// type: 'scroll',
orient: 'horizontal', // vertical
x: 'center',//可设定图例在左、右、居中
y: 'bottom',//可设定图例在上、下、居中
// padding:[0,50,0,0],//可设定图例[距上方距离,距右方距离,距下方距离,距左方距离]
data: data.videoData,
//circle:圆形 rect:矩形 roundRect:圆角矩形 triangle:角形
// diamond:菱形 pin:水滴 arrow:箭头
icon: 'rect',
},
tooltip: {//弹出框
//trigger:触发类型,'item'数据项图形触发,主要在散点图,
// 饼图等无类目轴的图表中使用。'axis'坐标轴触发,主要在柱状图,
// 折线图等会使用类目轴的图表中使用。
trigger: 'item',
//triggerOn:提示框触发的条件,'mousemove'鼠标移动时触发。
// 'click'鼠标点击时触发。'mousemove|click'同时鼠标移动和点击时触发。
// 'none'不在 'mousemove' 或 'click' 时触发
//triggerOn:"mousemove",
//是否显示提示框浮层
//showContent:true,
//是否永远显示提示框内容
//alwaysShowContent:false,
//浮层显示的延迟,单位为 ms
//showDelay:0,
//浮层隐藏的延迟,单位为 ms
//hideDelay:100,
//鼠标是否可进入提示框浮层中
//enterable:false,
//是否将 tooltip 框限制在图表的区域内
confine: true,
//提示框浮层的移动动画过渡时间,单位是 s,设置为 0 的时候会紧跟着鼠标移动
//transitionDuration:0.4,
//提示框浮层的位置,默认不设置时位置会跟随鼠标的位置,[10, 10],回掉函数,
// inside鼠标所在图形的内部中心位置,top、left、bottom、right
// 鼠标所在图形上侧,左侧,下侧,右侧,
//position:['50%', '50%'],
//提示框浮层内容格式器,支持字符串模板和回调函数两种形式,
// 模板变量有 {a}, {b},{c},{d},{e},分别表示系列名,数据名,数据值等
//formatter:"{b0}: {c0}<br />{b1}: {c1}",
// formatter: '{a} <br/>{b}: {c} ({d}%)'
formatter: '{b} <br/> {c}件({d}%)',
//标题背景色,
//backgroundColor:"white",
//边框颜色
//borderColor:"#ccc",
//边框线宽
//borderWidth:0,
//图例内边距,单位px 5 [5, 10] [5,10,5,10]
padding: 4,
//textStyle:文本样式
textStyle: {
fontSize: 10,
}
},
series: [
{
name: '统计分析',
type: 'pie',
clickable: true,//是否开启点击
minAngle: 2,//最小的扇区角度(0 ~ 360),防止某个值过小导致扇区太小影响交互
avoidLabelOverlap: true,//是否启用防止标签重叠策略
hoverAnimation: true,//是否开启 hover 在扇区上的放大动画效果。
silent: false,//图形是否不响应和触发鼠标事件
radius: ['30%', '50%'],//扇形环宽度
center: ['50%', '50%'],
labelLine: {
normal: {
length: 10, //第一条线
length2: 8, //第二条线
lineStyle: {
width: 1, // 线条的宽度
//线的颜色设置,如没有设置颜色则线条的颜色跟随饼状图的颜色
//color: "#000",
}
}
},
label: {
// formatter: '{b|{b}}\n \n {per|{d}%} ',
formatter: '{b|{b}}',
borderWidth: 20,
borderRadius: 4,
padding: [20, 40],
normal: {
//点击提示文字换行
formatter(params) {
let text = params.name
if (text.length <= 6) {
return text = text + '\n' + params.percent + '%';
} else if (text.length > 6 && text.length <= 12) {
return text = `${text.slice(0, 6)}\n${text.slice(6)}`
+ params.percent + '%'
} else if (text.length > 12 && text.length <= 18) {
return text = `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12)}`
+ params.percent + '%'
} else if (text.length > 24 && text.length <= 30) {
return text = `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12, 18)}\n${text.slice(24)}`
+ params.percent + '%'
} else if (text.length > 30) {
return text = `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12, 18)}\n${text.slice(24, 30)}\n${text.slice(30)}`
+ params.percent + '%'
}
},
textStyle: {
fontSize: 8
},
},
rich: {//点击提示文字样式
a: {
color: '#6E7079',
lineHeight: 22,
align: 'center'
},
b: {
color: '#4C5058',
fontSize: 12,
fontWeight: 'bold',
lineHeight: 18,
align: "bottom",
font: "Xingkai SC",
},
c: {
fontSize: 12,
lineHeight: 30,
color: '#63BF6A',
align: "center"
},
d: {
fontSize: 10,
lineHeight: 12,
color: '#4C5058',
align: "top"
}
}
},
//data: pieModel.pieArr,//饼状图数据
data: data.videoData.map((item, index) => {
var fontColor = colorArr[(index % colorArr.length)]
item.label = {
color: fontColor//饼状图文字颜色
}
return item;
}),
itemStyle: {
//扇形颜色
color: function (params) {
var index = params.dataIndex;
return colorArr[(index % colorArr.length)];
},
}
}
]
};
const pieEchart = echarts.init(this.$refs.pieEchartRef)
pieEchart.setOption(picOption)
效果图。
1.4. 折线图、柱状图、饼图图实现
效果图
完整代码
javascript
<template>
<el-row class="home-layout" :gutter="20">
<!--用户布局-->
<el-col :span="9" class="left-section">
<el-card shadow="hover">
<div class="user-layout">
<img class="user-header" :src="userImg"/>
<div class="user-info-layout">
<p class="user-name">Admin</p>
<p class="user-nickname">超级管理员</p>
</div>
</div>
<div class="login-layout">
<p class="login-time">上次登录时间:<span>2024-12-12</span></p>
<p class="login-loc">上次登录地点:<span>济南</span></p>
</div>
</el-card>
<!--列表展示-->
<el-card class="list-section">
<el-table :data="tableData">
<el-table-column
v-for="(val,key) in tableLabel"
:key="key"
:prop="key"
:label="val">
</el-table-column>
</el-table>
</el-card>
</el-col>
<!--右侧布局-->
<el-col class="right-section" :span="15">
<!--订单统计-->
<el-col :span="8" v-for="(item) in countData"
:key="item.name" :offset="0">
<el-card class="order-section"
:body-style="{display:'flex', padding:0}">
<div class="order-layout">
<i class="order-icon" :class="'el-icon-'+item.icon"
:style="{background:item.color}"></i>
<div class="order-detail">
<p class="order-num">¥{{item.value}}</p>
<p class="order-title">{{item.name}}</p>
</div>
</div>
</el-card>
</el-col>
<!--折线图-->
<el-card class="echars-line-layout">
<div class="echars-line-graph" ref="lineEchartRef"></div>
</el-card>
<div class="graph-layout">
<!--条形图-->
<el-card class="graph-item1">
<div style="height:210px" ref='barEchartRef'></div>
</el-card>
<!--饼图-->
<el-card class="graph-item2">
<div style="height:180px" ref='pieEchartRef'></div>
</el-card>
</div>
</el-col>
</el-row>
</template>
<script>
//import {getMenu} from '../../api/data.js'
import {getData} from '@/api/data'
//引入echarts
import * as echarts from 'echarts'
export default {
name: "home",
data() {
return {
userImg: require("../../assets/images/user.png"),
tableData: [
{
name: "华为",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "荣耀",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "oppo",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "vivo",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "苹果",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "小米",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "三星",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "魅族",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
}
],
tableLabel: {
name: '课程',
todayBuy: '今日购买',
monthBuy: '本月购买',
totalBuy: '总购买',
},
countData: [
{
name: "今日支付订单",
value: 1234,
icon: "success",
color: "#2ec7c9",
},
{
name: "今日收藏订单",
value: 210,
icon: "star-on",
color: "#ffb980",
},
{
name: "今日未支付订单",
value: 1234,
icon: "s-goods",
color: "#5ab1ef",
},
{
name: "本月支付订单",
value: 1234,
icon: "s-home",
color: "#fbcc00",
},
{
name: "本月收藏订单",
value: 210,
icon: "s-cooperation",
color: "#ff4444",
},
{
name: "本月未支付订单",
value: 1234,
icon: "s-shop",
color: "#33cc87",
},
]
}
},
mounted() {
//===============
// //接口请求一般在mounted下
// const axios = require('axios');
// // 上述请求也可以按以下方式完成(可选)
// axios.get('/user', {
// params: {
// ID: 12345
// }
// }).then(function (response) {
// console.log(response);
// })
// .catch(function (error) {
// console.log(error);
// })
// .finally(function () {
// // 总是会执行
// });
//===============
// getMenu().then(res => {
// console.log("post==",res)
// })
//===============
// getData().then(res => {
// console.log("getData",res)
// })
//===============将数据进行解构
// getData().then(res => {
// const { code,data } = res.data
// if (code === 20000){
// this.tableData = data.tableData
// }
// console.log(res)
// })
getData().then(res => {
const {code, data} = res.data
if (code === 20000) {
this.tableData = data.tableData
const order = data.orderData
const xData = order.date
const keyArray = Object.keys(order.data[0])
const series = []
keyArray.forEach(key => {
series.push({
name: key,
data: order.data.map(item => item[key]),
type: 'line'
})
})
const option = {
xAxis: {
data: xData
},
yAxis: {},
legend: {
data: keyArray
},
series: series
}
const lineEchart = echarts.init(this.$refs.lineEchartRef)
lineEchart.setOption(option)
//柱状图
const userOption = {
legend: {
// 图例文字颜色
textStyle: {
color: "#333",
},
},
grid: {
left: "20%",
},
// 提示框
tooltip: {
trigger: "axis",
},
xAxis: {
type: "category", // 类目轴
data: data.userData.map(item => item.date),
axisLine: {
lineStyle: {
color: "#17b3a3",
},
},
axisLabel: {
interval: 0,
color: "#333",
},
},
yAxis: [
{
type: "value",
axisLine: {
lineStyle: {
color: "#17b3a3",
},
},
},
],
color: ["#2ec7c9", "#b6a2de"],
series: [
{
name: '新增用户',
data: data.userData.map(item => item.new),
type: 'bar'
},
{
name: '活跃用户',
data: data.userData.map(item => item.active),
type: 'bar'
}
],
}
const barEchart = echarts.init(this.$refs.barEchartRef)
barEchart.setOption(userOption)
let colorArr = [
"#0f78f4",
"#dd536b",
"#9462e5",
"#a6a6a6",
"#e1bb22",
"#39c362",
"#3ed1cf",
]
const picOption = {
title: {//标题
subtext: "",
text: "饼图数据统计",
top: 'top',
left: 'center',
textStyle: {
fontSize: 11,
}
},
legend: {
itemHeight: 8,
itemWidth: 8,
// type: 'scroll',
orient: 'horizontal', // vertical
x: 'center',//可设定图例在左、右、居中
y: 'bottom',//可设定图例在上、下、居中
// padding:[0,50,0,0],//可设定图例[距上方距离,距右方距离,距下方距离,距左方距离]
data: data.videoData,
//circle:圆形 rect:矩形 roundRect:圆角矩形 triangle:角形
// diamond:菱形 pin:水滴 arrow:箭头
icon: 'rect',
},
tooltip: {//弹出框
//trigger:触发类型,'item'数据项图形触发,主要在散点图,
// 饼图等无类目轴的图表中使用。'axis'坐标轴触发,主要在柱状图,
// 折线图等会使用类目轴的图表中使用。
trigger: 'item',
//triggerOn:提示框触发的条件,'mousemove'鼠标移动时触发。
// 'click'鼠标点击时触发。'mousemove|click'同时鼠标移动和点击时触发。
// 'none'不在 'mousemove' 或 'click' 时触发
//triggerOn:"mousemove",
//是否显示提示框浮层
//showContent:true,
//是否永远显示提示框内容
//alwaysShowContent:false,
//浮层显示的延迟,单位为 ms
//showDelay:0,
//浮层隐藏的延迟,单位为 ms
//hideDelay:100,
//鼠标是否可进入提示框浮层中
//enterable:false,
//是否将 tooltip 框限制在图表的区域内
confine: true,
//提示框浮层的移动动画过渡时间,单位是 s,设置为 0 的时候会紧跟着鼠标移动
//transitionDuration:0.4,
//提示框浮层的位置,默认不设置时位置会跟随鼠标的位置,[10, 10],回掉函数,
// inside鼠标所在图形的内部中心位置,top、left、bottom、right
// 鼠标所在图形上侧,左侧,下侧,右侧,
//position:['50%', '50%'],
//提示框浮层内容格式器,支持字符串模板和回调函数两种形式,
// 模板变量有 {a}, {b},{c},{d},{e},分别表示系列名,数据名,数据值等
//formatter:"{b0}: {c0}<br />{b1}: {c1}",
// formatter: '{a} <br/>{b}: {c} ({d}%)'
formatter: '{b} <br/> {c}件({d}%)',
//标题背景色,
//backgroundColor:"white",
//边框颜色
//borderColor:"#ccc",
//边框线宽
//borderWidth:0,
//图例内边距,单位px 5 [5, 10] [5,10,5,10]
padding: 4,
//textStyle:文本样式
textStyle: {
fontSize: 10,
}
},
series: [
{
name: '统计分析',
type: 'pie',
clickable: true,//是否开启点击
minAngle: 2,//最小的扇区角度(0 ~ 360),防止某个值过小导致扇区太小影响交互
avoidLabelOverlap: true,//是否启用防止标签重叠策略
hoverAnimation: true,//是否开启 hover 在扇区上的放大动画效果。
silent: false,//图形是否不响应和触发鼠标事件
radius: ['30%', '50%'],//扇形环宽度
center: ['50%', '50%'],
labelLine: {
normal: {
length: 10, //第一条线
length2: 8, //第二条线
lineStyle: {
width: 1, // 线条的宽度
//线的颜色设置,如没有设置颜色则线条的颜色跟随饼状图的颜色
//color: "#000",
}
}
},
label: {
// formatter: '{b|{b}}\n \n {per|{d}%} ',
formatter: '{b|{b}}',
borderWidth: 20,
borderRadius: 4,
padding: [20, 40],
normal: {
//点击提示文字换行
formatter(params) {
let text = params.name
if (text.length <= 6) {
return text = text + '\n' + params.percent + '%';
} else if (text.length > 6 && text.length <= 12) {
return text = `${text.slice(0, 6)}\n${text.slice(6)}`
+ params.percent + '%'
} else if (text.length > 12 && text.length <= 18) {
return text = `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12)}`
+ params.percent + '%'
} else if (text.length > 24 && text.length <= 30) {
return text = `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12, 18)}\n${text.slice(24)}`
+ params.percent + '%'
} else if (text.length > 30) {
return text = `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12, 18)}\n${text.slice(24, 30)}\n${text.slice(30)}`
+ params.percent + '%'
}
},
textStyle: {
fontSize: 8
},
},
rich: {//点击提示文字样式
a: {
color: '#6E7079',
lineHeight: 22,
align: 'center'
},
b: {
color: '#4C5058',
fontSize: 12,
fontWeight: 'bold',
lineHeight: 18,
align: "bottom",
font: "Xingkai SC",
},
c: {
fontSize: 12,
lineHeight: 30,
color: '#63BF6A',
align: "center"
},
d: {
fontSize: 10,
lineHeight: 12,
color: '#4C5058',
align: "top"
}
}
},
//data: pieModel.pieArr,//饼状图数据
data: data.videoData.map((item, index) => {
var fontColor = colorArr[(index % colorArr.length)]
item.label = {
color: fontColor//饼状图文字颜色
}
return item;
}),
itemStyle: {
//扇形颜色
color: function (params) {
var index = params.dataIndex;
return colorArr[(index % colorArr.length)];
},
}
}
]
};
const pieEchart = echarts.init(this.$refs.pieEchartRef)
pieEchart.setOption(picOption)
}
})
}
}
</script>
<style lang="less">
.home-layout {
height: 100%;
padding: 10px 0;
}
/*用户模块*/
.left-section {
}
.user-layout {
display: flex;
flex-direction: row;
align-items: center;
border-bottom: #999 solid 1px;
padding: 0 0 10px;
}
.user-header {
width: 80px;
height: 80px;
border-radius: 50%;
}
.user-info-layout {
display: flex;
flex-direction: column;
margin-left: 20px;
}
.user-name {
font-size: 18px;
color: black;
font-weight: 700;
}
.user-nickname {
font-size: 18px;
color: black;
margin-top: 5px;
font-weight: 700;
}
.login-layout {
display: flex;
flex-direction: column;
margin-left: 20px;
}
.login-time {
font-size: 17px;
color: black;
margin-top: 5px;
}
.login-loc {
font-size: 17px;
color: black;
margin-top: 8px;
}
/*列表展示*/
.list-section {
margin: 15px 0;
height: 470px;
}
/*订单统计*/
.order-section {
padding: 0 0;
margin: 10px 0 10px;
background-color: white;
}
.order-layout {
display: flex;
flex-direction: row;
align-items: center;
}
.order-icon {
display: flex;
width: 65px;
height: 65px;
//border-radius: 50%;
align-items: center;
justify-content: center;
}
.order-detail {
display: flex;
flex-direction: column;
justify-content: center;
margin-left: 15px;
}
.order-num {
color: #333333;
font-size: 18px;
}
.order-title {
color: #333;
font-size: 18px;
font-weight: 700;
margin-top: 8px;
}
/*右侧布局*/
.right-section {
}
/*图标布局*/
.echars-line-layout {
margin: 10px 0;
}
.echars-line-graph {
height: 230px;
}
.graph-layout {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
margin: 10px 0;
}
.graph-item1 {
flex: 1;
height: 215px;
margin-right: 5px;
}
.graph-item2 {
flex: 1;
height: 215px;
margin-left: 5px;
}
</style>
1.5. Echars图表封装
(1)在src/components下新建MyEcharts.vue文件
javascript
//src/components/MyEcharts.vue
<template>
<div ref="echartRef"></div>
</template>
<script>
//引入echarts
import * as echarts from 'echarts'
export default {
props: {
//判断图表类型(true:柱状图、折线图 false:饼状图)
isAxisChart: {
type: Boolean,
default: true
},
//引入option
chartData: {
type: Object,
default () {
return {
xData: [],
series: []
}
},
},
},
//监听数据
watch: {
chartData: {
handler: function() {
this.initEchars()
},
deep: true //首次触发
}
},
methods: {
initEchars() {
this.initEcharsData()
if (this.echart) {
this.echart.setOption(this.options)
} else {
this.echart = echarts.init(this.$refs.echartRef)
this.echart.setOption(this.options)
}
},
initEcharsData() {
if (this.isAxisChart) {
this.axisOption.xAxis.data = this.chartData.xData
this.axisOption.series = this.chartData.series
} else {
this.normalOption.series = this.chartData.series
}
}
},
data() {
return {
axisOption: {
legend: {
// 图例文字颜色
textStyle: {
color: "#333",
},
},
grid: {
left: "20%",
},
// 提示框
tooltip: {
trigger: "axis",
},
xAxis: {
type: "category", // 类目轴
data: [],
axisLine: {
lineStyle: {
color: "#17b3a3",
},
},
axisLabel: {
interval: 0,
color: "#333",
},
},
yAxis: [{
type: "value",
axisLine: {
lineStyle: {
color: "#17b3a3",
},
},
}, ],
color: ["#0f78f4", "#dd536b", "#9462e5",
"#a6a6a6", "#e1bb22", "#39c362", "#3ed1cf",
],
series: [],
},
normalOption: {
tooltip: {
trigger: "item",
},
color: ["#0f78f4", "#dd536b", "#9462e5",
"#a6a6a6", "#e1bb22", "#39c362", "#3ed1cf",
],
series: [],
},
echart: null
}
},
//计算属性
computed: {
options() {
return this.isAxisChart ? this.axisOption : this.normalOption
}
}
}
</script>
<style>
</style>
(1)在src/views/home/index.vue
javascript
//src/views/home/index.vue
<template>
<el-row class="home-layout" :gutter="20">
<!--用户布局-->
<el-col :span="9" class="left-section">
<el-card shadow="hover">
<div class="user-layout">
<img class="user-header" :src="userImg"/>
<div class="user-info-layout">
<p class="user-name">Admin</p>
<p class="user-nickname">超级管理员</p>
</div>
</div>
<div class="login-layout">
<p class="login-time">上次登录时间:<span>2024-12-12</span></p>
<p class="login-loc">上次登录地点:<span>济南</span></p>
</div>
</el-card>
<!--列表展示-->
<el-card class="list-section">
<el-table :data="tableData">
<el-table-column v-for="(val,key) in tableLabel" :key="key" :prop="key" :label="val">
</el-table-column>
</el-table>
</el-card>
</el-col>
<!--右侧布局-->
<el-col class="right-section" :span="15">
<!--订单统计-->
<el-col :span="8" v-for="(item) in countData" :key="item.name" :offset="0">
<el-card class="order-section" :body-style="{display:'flex', padding:0}">
<div class="order-layout">
<i class="order-icon" :class="'el-icon-'+item.icon" :style="{background:item.color}"></i>
<div class="order-detail">
<p class="order-num">¥{{item.value}}</p>
<p class="order-title">{{item.name}}</p>
</div>
</div>
</el-card>
</el-col>
<!--折线图-->
<el-card class="echars-line-layout">
<!--普通-->
<!-- <div class="echars-line-graph" ref="lineEchartRef"></div> -->
<!--封装-->
<echart class="echars-line-graph" :chartData="echartData.line"></echart>
</el-card>
<div class="graph-layout">
<!--柱状图-->
<el-card class="graph-bar-layout">
<!--普通-->
<!-- <div class="graph-bar-item" ref='barEchartRef'></div> -->
<!--封装-->
<echart class="graph-bar-item" :chartData="echartData.bar"></echart>
</el-card>
<!--饼图-->
<el-card class="graph-pie-layout">
<!--普通-->
<!-- <div class="graph-pie-item" ref='barEchartRef'></div>-->
<!--封装-->
<echart class="graph-pie-item"
:chartData="echartData.pie" :isAxisChart="false"></echart>
</el-card>
</div>
</el-col>
</el-row>
</template>
<script>
//import {getMenu} from '../../api/data.js'
import {
getData
} from '@/api/data'
//引入echarts
import * as echarts from 'echarts'
import Echart from '../../components/MyEcharts.vue'
export default {
name: "home",
components: {
//加入组件
Echart
},
data() {
return {
userImg: require("../../assets/images/user.png"),
//图表
echartData: {
line: {
xData: [],
series: []
},
bar: {
xData: [],
series: []
},
pie: {
series: []
}
},
tableData: [{
name: "华为",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "荣耀",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "oppo",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "vivo",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "苹果",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "小米",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "三星",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
},
{
name: "魅族",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800,
}
],
tableLabel: {
name: '课程',
todayBuy: '今日购买',
monthBuy: '本月购买',
totalBuy: '总购买',
},
countData: [{
name: "今日支付订单",
value: 1234,
icon: "success",
color: "#2ec7c9",
},
{
name: "今日收藏订单",
value: 210,
icon: "star-on",
color: "#ffb980",
},
{
name: "今日未支付订单",
value: 1234,
icon: "s-goods",
color: "#5ab1ef",
},
{
name: "本月支付订单",
value: 1234,
icon: "s-home",
color: "#fbcc00",
},
{
name: "本月收藏订单",
value: 210,
icon: "s-cooperation",
color: "#ff4444",
},
{
name: "本月未支付订单",
value: 1234,
icon: "s-shop",
color: "#33cc87",
},
]
}
},
mounted() {
//===============
// //接口请求一般在mounted下
// const axios = require('axios');
// // 上述请求也可以按以下方式完成(可选)
// axios.get('/user', {
// params: {
// ID: 12345
// }
// }).then(function (response) {
// console.log(response);
// })
// .catch(function (error) {
// console.log(error);
// })
// .finally(function () {
// // 总是会执行
// });
//===============
// getMenu().then(res => {
// console.log("post==",res)
// })
//===============
// getData().then(res => {
// console.log("getData",res)
// })
//===============将数据进行解构
// getData().then(res => {
// const { code,data } = res.data
// if (code === 20000){
// this.tableData = data.tableData
// }
// console.log(res)
// })
getData().then(res => {
const {
code,
data
} = res.data
if (code === 20000) {
this.tableData = data.tableData
const order = data.orderData
const xData = order.date
const keyArray = Object.keys(order.data[0])
const series = []
keyArray.forEach(key => {
series.push({
name: key,
data: order.data.map(item => item[key]),
type: 'line'
})
})
//折线图
//=====普通=====
// const option = {
// xAxis: {
// data: xData
// },
// yAxis: {},
// legend: {
// data: keyArray
// },
// series: series
// }
// const lineEchart = echarts.init(this.$refs.lineEchartRef)
// lineEchart.setOption(option)
//=====封装=====
this.echartData.line.xData = xData
this.echartData.line.series = series
//柱状图
//=====普通=====
// const userOption = {
// legend: {
// // 图例文字颜色
// textStyle: {
// color: "#333",
// },
// },
// grid: {
// left: "20%",
// },
// // 提示框
// tooltip: {
// trigger: "axis",
// },
// xAxis: {
// type: "category", // 类目轴
// data: data.userData.map(item => item.date),
// axisLine: {
// lineStyle: {
// color: "#17b3a3",
// },
// },
// axisLabel: {
// interval: 0,
// color: "#333",
// },
// },
// yAxis: [{
// type: "value",
// axisLine: {
// lineStyle: {
// color: "#17b3a3",
// },
// },
// },],
// color: ["#2ec7c9", "#b6a2de"],
// series: [{
// name: '新增用户',
// data: data.userData.map(item => item.new),
// type: 'bar'
// },
// {
// name: '活跃用户',
// data: data.userData.map(item => item.active),
// type: 'bar'
// }
// ],
// }
// const barEchart = echarts.init(this.$refs.barEchartRef)
// barEchart.setOption(userOption)
//饼图图
//=====普通=====
this.echartData.bar.xData = data.userData.map(item => item.date)
this.echartData.bar.series = [{
name: '新增用户',
data: data.userData.map(item => item.new),
type: 'bar'
},
{
name: '活跃用户',
data: data.userData.map(item => item.active),
type: 'bar'
}
]
//=====封装=====
// let colorArr = [
// "#0f78f4",
// "#dd536b",
// "#9462e5",
// "#a6a6a6",
// "#e1bb22",
// "#39c362",
// "#3ed1cf",
// ]
// const pieOption = {
// title: { //标题
// subtext: "",
// text: "饼图数据统计",
// top: 'top',
// left: 'center',
// textStyle: {
// fontSize: 11,
// }
// },
// legend: {
// itemHeight: 8,
// itemWidth: 8,
// // type: 'scroll',
// orient: 'horizontal', // vertical
// x: 'center', //可设定图例在左、右、居中
// y: 'bottom', //可设定图例在上、下、居中
// // padding:[0,50,0,0],//可设定图例[距上方距离,距右方距离,距下方距离,距左方距离]
// data: data.videoData,
// //circle:圆形 rect:矩形 roundRect:圆角矩形 triangle:角形
// // diamond:菱形 pin:水滴 arrow:箭头
// icon: 'rect',
// },
// tooltip: { //弹出框
// //trigger:触发类型,'item'数据项图形触发,主要在散点图,
// // 饼图等无类目轴的图表中使用。'axis'坐标轴触发,主要在柱状图,
// // 折线图等会使用类目轴的图表中使用。
// trigger: 'item',
// //triggerOn:提示框触发的条件,'mousemove'鼠标移动时触发。
// // 'click'鼠标点击时触发。'mousemove|click'同时鼠标移动和点击时触发。
// // 'none'不在 'mousemove' 或 'click' 时触发
// //triggerOn:"mousemove",
// //是否显示提示框浮层
// //showContent:true,
// //是否永远显示提示框内容
// //alwaysShowContent:false,
// //浮层显示的延迟,单位为 ms
// //showDelay:0,
// //浮层隐藏的延迟,单位为 ms
// //hideDelay:100,
// //鼠标是否可进入提示框浮层中
// //enterable:false,
// //是否将 tooltip 框限制在图表的区域内
// confine: true,
// //提示框浮层的移动动画过渡时间,单位是 s,设置为 0 的时候会紧跟着鼠标移动
// //transitionDuration:0.4,
// //提示框浮层的位置,默认不设置时位置会跟随鼠标的位置,[10, 10],回掉函数,
// // inside鼠标所在图形的内部中心位置,top、left、bottom、right
// // 鼠标所在图形上侧,左侧,下侧,右侧,
// //position:['50%', '50%'],
// //提示框浮层内容格式器,支持字符串模板和回调函数两种形式,
// // 模板变量有 {a}, {b},{c},{d},{e},分别表示系列名,数据名,数据值等
// //formatter:"{b0}: {c0}<br />{b1}: {c1}",
// // formatter: '{a} <br/>{b}: {c} ({d}%)'
// formatter: '{b} <br/> {c}件({d}%)',
// //标题背景色,
// //backgroundColor:"white",
// //边框颜色
// //borderColor:"#ccc",
// //边框线宽
// //borderWidth:0,
// //图例内边距,单位px 5 [5, 10] [5,10,5,10]
// padding: 4,
// //textStyle:文本样式
// textStyle: {
// fontSize: 10,
// }
// },
// series: [{
// name: '统计分析',
// type: 'pie',
// clickable: true, //是否开启点击
// minAngle: 2, //最小的扇区角度(0 ~ 360),防止某个值过小导致扇区太小影响交互
// avoidLabelOverlap: true, //是否启用防止标签重叠策略
// hoverAnimation: true, //是否开启 hover 在扇区上的放大动画效果。
// silent: false, //图形是否不响应和触发鼠标事件
// radius: ['30%', '50%'], //扇形环宽度
// center: ['50%', '50%'],
// labelLine: {
// normal: {
// length: 10, //第一条线
// length2: 8, //第二条线
// lineStyle: {
// width: 1, // 线条的宽度
// //线的颜色设置,如没有设置颜色则线条的颜色跟随饼状图的颜色
// //color: "#000",
// }
// }
// },
// label: {
// // formatter: '{b|{b}}\n \n {per|{d}%} ',
// formatter: '{b|{b}}',
// borderWidth: 20,
// borderRadius: 4,
// padding: [20, 40],
// normal: {
// //点击提示文字换行
// formatter(params) {
// let text = params.name
// if (text.length <= 6) {
// return text = text + '\n' + params.percent + '%';
// } else if (text.length > 6 && text.length <= 12) {
// return text = `${text.slice(0, 6)}\n${text.slice(6)}` +
// params.percent + '%'
// } else if (text.length > 12 && text.length <= 18) {
// return text =
// `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12)}` +
// params.percent + '%'
// } else if (text.length > 24 && text.length <= 30) {
// return text =
// `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12, 18)}\n${text.slice(24)}` +
// params.percent + '%'
// } else if (text.length > 30) {
// return text =
// `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12, 18)}\n${text.slice(24, 30)}\n${text.slice(30)}` +
// params.percent + '%'
// }
// },
// textStyle: {
// fontSize: 8
// },
// },
// rich: { //点击提示文字样式
// a: {
// color: '#6E7079',
// lineHeight: 22,
// align: 'center'
// },
// b: {
// color: '#4C5058',
// fontSize: 12,
// fontWeight: 'bold',
// lineHeight: 18,
// align: "bottom",
// font: "Xingkai SC",
// },
// c: {
// fontSize: 12,
// lineHeight: 30,
// color: '#63BF6A',
// align: "center"
// },
// d: {
// fontSize: 10,
// lineHeight: 12,
// color: '#4C5058',
// align: "top"
// }
// }
// },
// //data: pieModel.pieArr,//饼状图数据
// data: data.videoData.map((item, index) => {
// var fontColor = colorArr[(index % colorArr.length)]
// item.label = {
// color: fontColor //饼状图文字颜色
// }
// return item;
// }),
// itemStyle: {
// //扇形颜色
// color: function (params) {
// var index = params.dataIndex;
// return colorArr[(index % colorArr.length)];
// },
// }
// }]
// };
// const pieOption = {
// tooltip: {
// trigger: "item",
// },
// color: [
// "#0f78f4",
// "#dd536b",
// "#9462e5",
// "#a6a6a6",
// "#e1bb22",
// "#39c362",
// "#3ed1cf",
// ],
// series: [
// {
// data:data.videoData,
// type:'pie'
// }
// ],
// }
// const pieEchart = echarts.init(this.$refs.pieEchartRef)
// pieEchart.setOption(pieOption)
//=====封装=====
this.echartData.pie.series= [
{
data:data.videoData,
type:'pie'
}
]
}
})
}
}
</script>
<style lang="less">
.home-layout {
height: 100%;
padding: 10px 0;
}
/*用户模块*/
.left-section {
}
.user-layout {
display: flex;
flex-direction: row;
align-items: center;
border-bottom: #999 solid 1px;
padding: 0 0 10px;
}
.user-header {
width: 80px;
height: 80px;
border-radius: 50%;
}
.user-info-layout {
display: flex;
flex-direction: column;
margin-left: 20px;
}
.user-name {
font-size: 18px;
color: black;
font-weight: 700;
}
.user-nickname {
font-size: 18px;
color: black;
margin-top: 5px;
font-weight: 700;
}
.login-layout {
display: flex;
flex-direction: column;
margin-left: 20px;
}
.login-time {
font-size: 17px;
color: black;
margin-top: 5px;
}
.login-loc {
font-size: 17px;
color: black;
margin-top: 8px;
}
/*列表展示*/
.list-section {
margin: 15px 0;
height: 470px;
}
/*订单统计*/
.order-section {
padding: 0 0;
margin: 10px 0 10px;
background-color: white;
}
.order-layout {
display: flex;
flex-direction: row;
align-items: center;
}
.order-icon {
display: flex;
width: 65px;
height: 65px;
//border-radius: 50%;
align-items: center;
justify-content: center;
}
.order-detail {
display: flex;
flex-direction: column;
justify-content: center;
margin-left: 15px;
}
.order-num {
color: #333333;
font-size: 18px;
}
.order-title {
color: #333;
font-size: 18px;
font-weight: 700;
margin-top: 8px;
}
/*右侧布局*/
.right-section {
}
/*图标布局*/
.echars-line-layout {
margin: 10px 0;
}
.echars-line-graph {
height: 230px;
}
.graph-layout {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
margin: 10px 0;
}
.graph-bar-layout {
flex: 1;
height: 215px;
margin-right: 5px;
}
.graph-bar-item {
height: 210px;
}
.graph-pie-layout {
flex: 1;
height: 215px;
margin-left: 5px;
}
.graph-pie-item {
height: 180px;
}
</style>
效果图