21 changed files with 1361 additions and 31 deletions
@ -0,0 +1,193 @@ |
|||
<template> |
|||
<span> |
|||
{{ displayValue }} |
|||
</span> |
|||
</template> |
|||
<script> |
|||
import {requestAnimationFrame, cancelAnimationFrame} from './requestAnimationFrame.js' |
|||
|
|||
export default { |
|||
name: 'CountTo', |
|||
props: { |
|||
startVal: { |
|||
type: Number, |
|||
required: false, |
|||
default: 0 |
|||
}, |
|||
endVal: { |
|||
type: Number, |
|||
required: false, |
|||
default: 2017 |
|||
}, |
|||
duration: { |
|||
type: Number, |
|||
required: false, |
|||
default: 3000 |
|||
}, |
|||
autoplay: { |
|||
type: Boolean, |
|||
required: false, |
|||
default: true |
|||
}, |
|||
decimals: { |
|||
type: Number, |
|||
required: false, |
|||
default: 0, |
|||
validator(value) { |
|||
return value >= 0 |
|||
} |
|||
}, |
|||
decimal: { |
|||
type: String, |
|||
required: false, |
|||
default: '.' |
|||
}, |
|||
separator: { |
|||
type: String, |
|||
required: false, |
|||
default: ',' |
|||
}, |
|||
prefix: { |
|||
type: String, |
|||
required: false, |
|||
default: '' |
|||
}, |
|||
suffix: { |
|||
type: String, |
|||
required: false, |
|||
default: '' |
|||
}, |
|||
useEasing: { |
|||
type: Boolean, |
|||
required: false, |
|||
default: true |
|||
}, |
|||
easingFn: { |
|||
type: Function, |
|||
default(t, b, c, d) { |
|||
return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b |
|||
} |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
localStartVal: this.startVal, |
|||
displayValue: this.formatNumber(this.startVal), |
|||
printVal: null, |
|||
paused: false, |
|||
localDuration: this.duration, |
|||
startTime: null, |
|||
timestamp: null, |
|||
remaining: null, |
|||
rAF: null |
|||
} |
|||
}, |
|||
computed: { |
|||
countDown() { |
|||
return this.startVal > this.endVal |
|||
} |
|||
}, |
|||
watch: { |
|||
startVal() { |
|||
if (this.autoplay) { |
|||
this.start() |
|||
} |
|||
}, |
|||
endVal() { |
|||
if (this.autoplay) { |
|||
this.start() |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
if (this.autoplay) { |
|||
this.start() |
|||
} |
|||
this.$emit('mountedCallback') |
|||
}, |
|||
methods: { |
|||
start() { |
|||
this.localStartVal = this.startVal |
|||
this.startTime = null |
|||
this.localDuration = this.duration |
|||
this.paused = false |
|||
this.rAF = requestAnimationFrame(this.count) |
|||
}, |
|||
pauseResume() { |
|||
if (this.paused) { |
|||
this.resume() |
|||
this.paused = false |
|||
} else { |
|||
this.pause() |
|||
this.paused = true |
|||
} |
|||
}, |
|||
pause() { |
|||
cancelAnimationFrame(this.rAF) |
|||
}, |
|||
resume() { |
|||
this.startTime = null |
|||
this.localDuration = +this.remaining |
|||
this.localStartVal = +this.printVal |
|||
requestAnimationFrame(this.count) |
|||
}, |
|||
reset() { |
|||
this.startTime = null |
|||
cancelAnimationFrame(this.rAF) |
|||
this.displayValue = this.formatNumber(this.startVal) |
|||
}, |
|||
count(timestamp) { |
|||
if (!this.startTime) this.startTime = timestamp |
|||
this.timestamp = timestamp |
|||
const progress = timestamp - this.startTime |
|||
this.remaining = this.localDuration - progress |
|||
|
|||
if (this.useEasing) { |
|||
if (this.countDown) { |
|||
this.printVal = this.localStartVal - this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration) |
|||
} else { |
|||
this.printVal = this.easingFn(progress, this.localStartVal, this.endVal - this.localStartVal, this.localDuration) |
|||
} |
|||
} else { |
|||
if (this.countDown) { |
|||
this.printVal = this.localStartVal - ((this.localStartVal - this.endVal) * (progress / this.localDuration)) |
|||
} else { |
|||
this.printVal = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration) |
|||
} |
|||
} |
|||
if (this.countDown) { |
|||
this.printVal = this.printVal < this.endVal ? this.endVal : this.printVal |
|||
} else { |
|||
this.printVal = this.printVal > this.endVal ? this.endVal : this.printVal |
|||
} |
|||
|
|||
this.displayValue = this.formatNumber(this.printVal) |
|||
if (progress < this.localDuration) { |
|||
this.rAF = requestAnimationFrame(this.count) |
|||
} else { |
|||
this.$emit('callback') |
|||
} |
|||
}, |
|||
isNumber(val) { |
|||
return !isNaN(parseFloat(val)) |
|||
}, |
|||
formatNumber(num) { |
|||
num = num.toFixed(this.decimals) |
|||
num += '' |
|||
const x = num.split('.') |
|||
let x1 = x[0] |
|||
const x2 = x.length > 1 ? this.decimal + x[1] : '' |
|||
const rgx = /(\d+)(\d{3})/ |
|||
if (this.separator && !this.isNumber(this.separator)) { |
|||
while (rgx.test(x1)) { |
|||
x1 = x1.replace(rgx, '$1' + this.separator + '$2') |
|||
} |
|||
} |
|||
return this.prefix + x1 + x2 + this.suffix |
|||
} |
|||
}, |
|||
destroyed() { |
|||
cancelAnimationFrame(this.rAF) |
|||
} |
|||
} |
|||
</script> |
@ -0,0 +1,46 @@ |
|||
let lastTime = 0 |
|||
const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀
|
|||
|
|||
let requestAnimationFrame |
|||
let cancelAnimationFrame |
|||
|
|||
const isServer = typeof window === 'undefined' |
|||
if (isServer) { |
|||
requestAnimationFrame = function() { |
|||
return |
|||
} |
|||
cancelAnimationFrame = function() { |
|||
return |
|||
} |
|||
} else { |
|||
requestAnimationFrame = window.requestAnimationFrame |
|||
cancelAnimationFrame = window.cancelAnimationFrame |
|||
let prefix |
|||
// 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
|
|||
for (let i = 0; i < prefixes.length; i++) { |
|||
if (requestAnimationFrame && cancelAnimationFrame) { break } |
|||
prefix = prefixes[i] |
|||
requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame'] |
|||
cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame'] |
|||
} |
|||
|
|||
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
|
|||
if (!requestAnimationFrame || !cancelAnimationFrame) { |
|||
requestAnimationFrame = function(callback) { |
|||
const currTime = new Date().getTime() |
|||
// 为了使setTimteout的尽可能的接近每秒60帧的效果
|
|||
const timeToCall = Math.max(0, 16 - (currTime - lastTime)) |
|||
const id = window.setTimeout(() => { |
|||
callback(currTime + timeToCall) |
|||
}, timeToCall) |
|||
lastTime = currTime + timeToCall |
|||
return id |
|||
} |
|||
|
|||
cancelAnimationFrame = function(id) { |
|||
window.clearTimeout(id) |
|||
} |
|||
} |
|||
} |
|||
|
|||
export { requestAnimationFrame, cancelAnimationFrame } |
@ -0,0 +1,102 @@ |
|||
<template> |
|||
<div :class="className" :style="{height:height,width:width}" /> |
|||
</template> |
|||
|
|||
<script> |
|||
const echarts = require('echarts') |
|||
require('echarts/theme/macarons') // echarts theme |
|||
import resize from './mixins/resize' |
|||
|
|||
const animationDuration = 6000 |
|||
|
|||
export default { |
|||
mixins: [resize], |
|||
props: { |
|||
className: { |
|||
type: String, |
|||
default: 'chart' |
|||
}, |
|||
width: { |
|||
type: String, |
|||
default: '100%' |
|||
}, |
|||
height: { |
|||
type: String, |
|||
default: '300px' |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
chart: null |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => { |
|||
this.initChart() |
|||
}) |
|||
}, |
|||
beforeDestroy() { |
|||
if (!this.chart) { |
|||
return |
|||
} |
|||
this.chart.dispose() |
|||
this.chart = null |
|||
}, |
|||
methods: { |
|||
initChart() { |
|||
this.chart = echarts.init(this.$el, 'macarons') |
|||
|
|||
this.chart.setOption({ |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
axisPointer: { // 坐标轴指示器,坐标轴触发有效 |
|||
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow' |
|||
} |
|||
}, |
|||
grid: { |
|||
top: 10, |
|||
left: '2%', |
|||
right: '2%', |
|||
bottom: '3%', |
|||
containLabel: true |
|||
}, |
|||
xAxis: [{ |
|||
type: 'category', |
|||
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], |
|||
axisTick: { |
|||
alignWithLabel: true |
|||
} |
|||
}], |
|||
yAxis: [{ |
|||
type: 'value', |
|||
axisTick: { |
|||
show: false |
|||
} |
|||
}], |
|||
series: [{ |
|||
name: 'pageA', |
|||
type: 'bar', |
|||
stack: 'vistors', |
|||
barWidth: '60%', |
|||
data: [79, 52, 200, 334, 390, 330, 220], |
|||
animationDuration |
|||
}, { |
|||
name: 'pageB', |
|||
type: 'bar', |
|||
stack: 'vistors', |
|||
barWidth: '60%', |
|||
data: [80, 52, 200, 334, 390, 330, 220], |
|||
animationDuration |
|||
}, { |
|||
name: 'pageC', |
|||
type: 'bar', |
|||
stack: 'vistors', |
|||
barWidth: '60%', |
|||
data: [30, 52, 200, 334, 390, 330, 220], |
|||
animationDuration |
|||
}] |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
@ -0,0 +1,118 @@ |
|||
<template> |
|||
<el-card class="box-card-component" style="margin-left:8px;"> |
|||
<div slot="header" class="box-card-header"> |
|||
<img src="https://wpimg.wallstcn.com/e7d23d71-cf19-4b90-a1cc-f56af8c0903d.png"> |
|||
</div> |
|||
<div style="position:relative;"> |
|||
<pan-thumb :image="avatar" class="panThumb" /> |
|||
<mallki class-name="mallki-text" text="vue-element-admin" /> |
|||
<div style="padding-top:35px;" class="progress-item"> |
|||
<span>Vue</span> |
|||
<el-progress :percentage="70" /> |
|||
</div> |
|||
<div class="progress-item"> |
|||
<span>JavaScript</span> |
|||
<el-progress :percentage="18" /> |
|||
</div> |
|||
<div class="progress-item"> |
|||
<span>CSS</span> |
|||
<el-progress :percentage="12" /> |
|||
</div> |
|||
<div class="progress-item"> |
|||
<span>ESLint</span> |
|||
<el-progress :percentage="100" status="success" /> |
|||
</div> |
|||
</div> |
|||
</el-card> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex' |
|||
import PanThumb from '@/components/PanThumb' |
|||
import Mallki from '@/components/TextHoverEffect/Mallki' |
|||
|
|||
export default { |
|||
components: { PanThumb, Mallki }, |
|||
|
|||
filters: { |
|||
statusFilter(status) { |
|||
const statusMap = { |
|||
success: 'success', |
|||
pending: 'danger' |
|||
} |
|||
return statusMap[status] |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
statisticsData: { |
|||
article_count: 1024, |
|||
pageviews_count: 1024 |
|||
} |
|||
} |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'name', |
|||
'avatar', |
|||
'roles' |
|||
]) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" > |
|||
.box-card-component{ |
|||
.el-card__header { |
|||
padding: 0px!important; |
|||
} |
|||
} |
|||
</style> |
|||
<style lang="scss" scoped> |
|||
.box-card-component { |
|||
.box-card-header { |
|||
position: relative; |
|||
height: 220px; |
|||
img { |
|||
width: 100%; |
|||
height: 100%; |
|||
transition: all 0.2s linear; |
|||
&:hover { |
|||
transform: scale(1.1, 1.1); |
|||
filter: contrast(130%); |
|||
} |
|||
} |
|||
} |
|||
.mallki-text { |
|||
position: absolute; |
|||
top: 0px; |
|||
right: 0px; |
|||
font-size: 20px; |
|||
font-weight: bold; |
|||
} |
|||
.panThumb { |
|||
z-index: 100; |
|||
height: 70px!important; |
|||
width: 70px!important; |
|||
position: absolute!important; |
|||
top: -45px; |
|||
left: 0px; |
|||
border: 5px solid #ffffff; |
|||
background-color: #fff; |
|||
margin: auto; |
|||
box-shadow: none!important; |
|||
::v-deep .pan-info { |
|||
box-shadow: none!important; |
|||
} |
|||
} |
|||
.progress-item { |
|||
margin-bottom: 10px; |
|||
font-size: 14px; |
|||
} |
|||
@media only screen and (max-width: 1510px){ |
|||
.mallki-text{ |
|||
display: none; |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,135 @@ |
|||
<template> |
|||
<div :class="className" :style="{height:height,width:width}" /> |
|||
</template> |
|||
|
|||
<script> |
|||
const echarts = require('echarts') |
|||
require('echarts/theme/macarons') // echarts theme |
|||
import resize from './mixins/resize' |
|||
|
|||
export default { |
|||
mixins: [resize], |
|||
props: { |
|||
className: { |
|||
type: String, |
|||
default: 'chart' |
|||
}, |
|||
width: { |
|||
type: String, |
|||
default: '100%' |
|||
}, |
|||
height: { |
|||
type: String, |
|||
default: '350px' |
|||
}, |
|||
autoResize: { |
|||
type: Boolean, |
|||
default: true |
|||
}, |
|||
chartData: { |
|||
type: Object, |
|||
required: true |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
chart: null |
|||
} |
|||
}, |
|||
watch: { |
|||
chartData: { |
|||
deep: true, |
|||
handler(val) { |
|||
this.setOptions(val) |
|||
} |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => { |
|||
this.initChart() |
|||
}) |
|||
}, |
|||
beforeDestroy() { |
|||
if (!this.chart) { |
|||
return |
|||
} |
|||
this.chart.dispose() |
|||
this.chart = null |
|||
}, |
|||
methods: { |
|||
initChart() { |
|||
this.chart = echarts.init(this.$el, 'macarons') |
|||
this.setOptions(this.chartData) |
|||
}, |
|||
setOptions({ expectedData, actualData } = {}) { |
|||
this.chart.setOption({ |
|||
xAxis: { |
|||
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], |
|||
boundaryGap: false, |
|||
axisTick: { |
|||
show: false |
|||
} |
|||
}, |
|||
grid: { |
|||
left: 10, |
|||
right: 10, |
|||
bottom: 20, |
|||
top: 30, |
|||
containLabel: true |
|||
}, |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
axisPointer: { |
|||
type: 'cross' |
|||
}, |
|||
padding: [5, 10] |
|||
}, |
|||
yAxis: { |
|||
axisTick: { |
|||
show: false |
|||
} |
|||
}, |
|||
legend: { |
|||
data: ['expected', 'actual'] |
|||
}, |
|||
series: [{ |
|||
name: 'expected', itemStyle: { |
|||
normal: { |
|||
color: '#FF005A', |
|||
lineStyle: { |
|||
color: '#FF005A', |
|||
width: 2 |
|||
} |
|||
} |
|||
}, |
|||
smooth: true, |
|||
type: 'line', |
|||
data: expectedData, |
|||
animationDuration: 2800, |
|||
animationEasing: 'cubicInOut' |
|||
}, |
|||
{ |
|||
name: 'actual', |
|||
smooth: true, |
|||
type: 'line', |
|||
itemStyle: { |
|||
normal: { |
|||
color: '#3888fa', |
|||
lineStyle: { |
|||
color: '#3888fa', |
|||
width: 2 |
|||
}, |
|||
areaStyle: { |
|||
color: '#f3f8ff' |
|||
} |
|||
} |
|||
}, |
|||
data: actualData, |
|||
animationDuration: 2800, |
|||
animationEasing: 'quadraticOut' |
|||
}] |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
@ -0,0 +1,148 @@ |
|||
<template> |
|||
<div :class="className" :style="{height:height,width:width}"/> |
|||
</template> |
|||
|
|||
<script> |
|||
const echarts = require('echarts') |
|||
require('./china.js') |
|||
require('echarts/theme/macarons') // echarts theme |
|||
import resize from './mixins/resize' |
|||
|
|||
export default { |
|||
mixins: [resize], |
|||
props: { |
|||
className: { |
|||
type: String, |
|||
default: 'chart' |
|||
}, |
|||
width: { |
|||
type: String, |
|||
default: '100%' |
|||
}, |
|||
height: { |
|||
type: String, |
|||
default: '300px' |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
chart: null |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => { |
|||
this.initChart() |
|||
}) |
|||
}, |
|||
beforeDestroy() { |
|||
if (!this.chart) { |
|||
return |
|||
} |
|||
this.chart.dispose() |
|||
this.chart = null |
|||
}, |
|||
methods: { |
|||
initChart() { |
|||
this.chart = echarts.init(this.$el, 'macarons') |
|||
|
|||
this.chart.setOption({ |
|||
title: { |
|||
text: '订单量', |
|||
subtext: '纯属虚构', |
|||
left: 'center' |
|||
}, |
|||
tooltip: { |
|||
trigger: 'item' |
|||
}, |
|||
legend: { |
|||
orient: 'vertical', |
|||
left: 'left', |
|||
data: ['订单量'] |
|||
}, |
|||
visualMap: { |
|||
type: 'piecewise', |
|||
pieces: [ |
|||
|
|||
{min: 1500}, |
|||
{min: 900, max: 1500}, |
|||
{min: 310, max: 1000}, |
|||
{min: 200, max: 300}, |
|||
{min: 10, max: 200, label: '10 到 200(自定义label)'}, |
|||
{value: 123, label: '123(自定义特殊颜色)', color: 'grey'}, |
|||
{min: 5, max: 5, label: '5(自定义特殊颜色)', color: 'black'}, |
|||
{max: 5} |
|||
], |
|||
color: ['#E0022B', '#E09107', '#A3E00B'] |
|||
}, |
|||
toolbox: { |
|||
show: true, |
|||
orient: 'vertical', |
|||
left: 'right', |
|||
top: 'center', |
|||
feature: { |
|||
mark: {show: true}, |
|||
dataView: {show: true, readOnly: false}, |
|||
restore: {show: true}, |
|||
saveAsImage: {show: true} |
|||
} |
|||
}, |
|||
roamController: { |
|||
show: true, |
|||
left: 'right', |
|||
mapTypeControl: { |
|||
'china': true |
|||
} |
|||
}, |
|||
series: [ |
|||
{ |
|||
name: '订单量', |
|||
type: 'map', |
|||
mapType: 'china', |
|||
roam: false, |
|||
label: { |
|||
show: true, |
|||
color: 'rgb(249, 249, 249)' |
|||
}, |
|||
data: [ |
|||
{name: '北京', value: 5}, |
|||
{name: '天津', value: Math.round(Math.random() * 2000)}, |
|||
{name: '上海', value: Math.round(Math.random() * 2000)}, |
|||
{name: '重庆', value: Math.round(Math.random() * 2000)}, |
|||
{name: '河北', value: 0}, |
|||
{name: '河南', value: Math.round(Math.random() * 2000)}, |
|||
{name: '云南', value: 123}, |
|||
{name: '辽宁', value: 305}, |
|||
{name: '黑龙江', value: Math.round(Math.random() * 2000)}, |
|||
{name: '湖南', value: 200}, |
|||
{name: '安徽', value: Math.round(Math.random() * 2000)}, |
|||
{name: '山东', value: Math.round(Math.random() * 2000)}, |
|||
{name: '新疆', value: Math.round(Math.random() * 2000)}, |
|||
{name: '江苏', value: Math.round(Math.random() * 2000)}, |
|||
{name: '浙江', value: Math.round(Math.random() * 2000)}, |
|||
{name: '江西', value: Math.round(Math.random() * 2000)}, |
|||
{name: '湖北', value: Math.round(Math.random() * 2000)}, |
|||
{name: '广西', value: Math.round(Math.random() * 2000)}, |
|||
{name: '甘肃', value: Math.round(Math.random() * 2000)}, |
|||
{name: '山西', value: Math.round(Math.random() * 2000)}, |
|||
{name: '内蒙古', value: Math.round(Math.random() * 2000)}, |
|||
{name: '陕西', value: Math.round(Math.random() * 2000)}, |
|||
{name: '吉林', value: Math.round(Math.random() * 2000)}, |
|||
{name: '福建', value: Math.round(Math.random() * 2000)}, |
|||
{name: '贵州', value: Math.round(Math.random() * 2000)}, |
|||
{name: '广东', value: Math.round(Math.random() * 2000)}, |
|||
{name: '青海', value: Math.round(Math.random() * 2000)}, |
|||
{name: '西藏', value: Math.round(Math.random() * 2000)}, |
|||
{name: '四川', value: Math.round(Math.random() * 2000)}, |
|||
{name: '宁夏', value: Math.round(Math.random() * 2000)}, |
|||
{name: '海南', value: Math.round(Math.random() * 2000)}, |
|||
{name: '台湾', value: Math.round(Math.random() * 2000)}, |
|||
{name: '香港', value: Math.round(Math.random() * 2000)}, |
|||
{name: '澳门', value: Math.round(Math.random() * 2000)} |
|||
] |
|||
} |
|||
] |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
@ -0,0 +1,181 @@ |
|||
<template> |
|||
<el-row :gutter="40" class="panel-group"> |
|||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> |
|||
<div class="card-panel" @click="handleSetLineChartData('newVisitis')"> |
|||
<div class="card-panel-icon-wrapper icon-people"> |
|||
<svg-icon icon-class="peoples" class-name="card-panel-icon" /> |
|||
</div> |
|||
<div class="card-panel-description"> |
|||
<div class="card-panel-text"> |
|||
New Visits |
|||
</div> |
|||
<count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" /> |
|||
</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> |
|||
<div class="card-panel" @click="handleSetLineChartData('messages')"> |
|||
<div class="card-panel-icon-wrapper icon-message"> |
|||
<svg-icon icon-class="message" class-name="card-panel-icon" /> |
|||
</div> |
|||
<div class="card-panel-description"> |
|||
<div class="card-panel-text"> |
|||
Messages |
|||
</div> |
|||
<count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num" /> |
|||
</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> |
|||
<div class="card-panel" @click="handleSetLineChartData('purchases')"> |
|||
<div class="card-panel-icon-wrapper icon-money"> |
|||
<svg-icon icon-class="money" class-name="card-panel-icon" /> |
|||
</div> |
|||
<div class="card-panel-description"> |
|||
<div class="card-panel-text"> |
|||
Purchases |
|||
</div> |
|||
<count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num" /> |
|||
</div> |
|||
</div> |
|||
</el-col> |
|||
<el-col :xs="12" :sm="12" :lg="6" class="card-panel-col"> |
|||
<div class="card-panel" @click="handleSetLineChartData('shoppings')"> |
|||
<div class="card-panel-icon-wrapper icon-shopping"> |
|||
<svg-icon icon-class="shopping" class-name="card-panel-icon" /> |
|||
</div> |
|||
<div class="card-panel-description"> |
|||
<div class="card-panel-text"> |
|||
Shoppings |
|||
</div> |
|||
<count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num" /> |
|||
</div> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
</template> |
|||
|
|||
<script> |
|||
import CountTo from 'CountTo' |
|||
|
|||
export default { |
|||
components: { |
|||
CountTo |
|||
}, |
|||
methods: { |
|||
handleSetLineChartData(type) { |
|||
this.$emit('handleSetLineChartData', type) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.panel-group { |
|||
margin-top: 18px; |
|||
|
|||
.card-panel-col { |
|||
margin-bottom: 32px; |
|||
} |
|||
|
|||
.card-panel { |
|||
height: 108px; |
|||
cursor: pointer; |
|||
font-size: 12px; |
|||
position: relative; |
|||
overflow: hidden; |
|||
color: #666; |
|||
background: #fff; |
|||
box-shadow: 4px 4px 40px rgba(0, 0, 0, .05); |
|||
border-color: rgba(0, 0, 0, .05); |
|||
|
|||
&:hover { |
|||
.card-panel-icon-wrapper { |
|||
color: #fff; |
|||
} |
|||
|
|||
.icon-people { |
|||
background: #40c9c6; |
|||
} |
|||
|
|||
.icon-message { |
|||
background: #36a3f7; |
|||
} |
|||
|
|||
.icon-money { |
|||
background: #f4516c; |
|||
} |
|||
|
|||
.icon-shopping { |
|||
background: #34bfa3 |
|||
} |
|||
} |
|||
|
|||
.icon-people { |
|||
color: #40c9c6; |
|||
} |
|||
|
|||
.icon-message { |
|||
color: #36a3f7; |
|||
} |
|||
|
|||
.icon-money { |
|||
color: #f4516c; |
|||
} |
|||
|
|||
.icon-shopping { |
|||
color: #34bfa3 |
|||
} |
|||
|
|||
.card-panel-icon-wrapper { |
|||
float: left; |
|||
margin: 14px 0 0 14px; |
|||
padding: 16px; |
|||
transition: all 0.38s ease-out; |
|||
border-radius: 6px; |
|||
} |
|||
|
|||
.card-panel-icon { |
|||
float: left; |
|||
font-size: 48px; |
|||
} |
|||
|
|||
.card-panel-description { |
|||
float: right; |
|||
font-weight: bold; |
|||
margin: 26px; |
|||
margin-left: 0px; |
|||
|
|||
.card-panel-text { |
|||
line-height: 18px; |
|||
color: rgba(0, 0, 0, 0.45); |
|||
font-size: 16px; |
|||
margin-bottom: 12px; |
|||
} |
|||
|
|||
.card-panel-num { |
|||
font-size: 20px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@media (max-width:550px) { |
|||
.card-panel-description { |
|||
display: none; |
|||
} |
|||
|
|||
.card-panel-icon-wrapper { |
|||
float: none !important; |
|||
width: 100%; |
|||
height: 100%; |
|||
margin: 0 !important; |
|||
|
|||
.svg-icon { |
|||
display: block; |
|||
margin: 14px auto !important; |
|||
float: none !important; |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,81 @@ |
|||
<template> |
|||
<div :class="className" :style="{height:height,width:width}" /> |
|||
</template> |
|||
|
|||
<script> |
|||
const echarts = require('echarts') |
|||
require('echarts/theme/macarons') // echarts theme |
|||
import resize from './mixins/resize' |
|||
|
|||
|
|||
|
|||
export default { |
|||
mixins: [resize], |
|||
props: { |
|||
className: { |
|||
type: String, |
|||
default: 'chart' |
|||
}, |
|||
width: { |
|||
type: String, |
|||
default: '100%' |
|||
}, |
|||
height: { |
|||
type: String, |
|||
default: '300px' |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
chart: null |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => { |
|||
this.initChart() |
|||
}) |
|||
}, |
|||
beforeDestroy() { |
|||
if (!this.chart) { |
|||
return |
|||
} |
|||
this.chart.dispose() |
|||
this.chart = null |
|||
}, |
|||
methods: { |
|||
initChart() { |
|||
this.chart = echarts.init(this.$el, 'macarons') |
|||
|
|||
this.chart.setOption({ |
|||
tooltip: { |
|||
trigger: 'item', |
|||
formatter: '{a} <br/>{b} : {c} ({d}%)' |
|||
}, |
|||
legend: { |
|||
left: 'center', |
|||
bottom: '10', |
|||
data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts'] |
|||
}, |
|||
series: [ |
|||
{ |
|||
name: 'WEEKLY WRITE ARTICLES', |
|||
type: 'pie', |
|||
roseType: 'radius', |
|||
radius: [15, 95], |
|||
center: ['50%', '38%'], |
|||
data: [ |
|||
{ value: 320, name: 'Industries' }, |
|||
{ value: 240, name: 'Technology' }, |
|||
{ value: 149, name: 'Forex' }, |
|||
{ value: 100, name: 'Gold' }, |
|||
{ value: 59, name: 'Forecasts' } |
|||
], |
|||
animationEasing: 'cubicInOut', |
|||
animationDuration: 2600 |
|||
} |
|||
] |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
@ -0,0 +1,116 @@ |
|||
<template> |
|||
<div :class="className" :style="{height:height,width:width}" /> |
|||
</template> |
|||
|
|||
<script> |
|||
import echarts from 'echarts' |
|||
require('echarts/theme/macarons') // echarts theme |
|||
import resize from './mixins/resize' |
|||
|
|||
const animationDuration = 3000 |
|||
|
|||
export default { |
|||
mixins: [resize], |
|||
props: { |
|||
className: { |
|||
type: String, |
|||
default: 'chart' |
|||
}, |
|||
width: { |
|||
type: String, |
|||
default: '100%' |
|||
}, |
|||
height: { |
|||
type: String, |
|||
default: '300px' |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
chart: null |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$nextTick(() => { |
|||
this.initChart() |
|||
}) |
|||
}, |
|||
beforeDestroy() { |
|||
if (!this.chart) { |
|||
return |
|||
} |
|||
this.chart.dispose() |
|||
this.chart = null |
|||
}, |
|||
methods: { |
|||
initChart() { |
|||
this.chart = echarts.init(this.$el, 'macarons') |
|||
|
|||
this.chart.setOption({ |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
axisPointer: { // 坐标轴指示器,坐标轴触发有效 |
|||
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow' |
|||
} |
|||
}, |
|||
radar: { |
|||
radius: '66%', |
|||
center: ['50%', '42%'], |
|||
splitNumber: 8, |
|||
splitArea: { |
|||
areaStyle: { |
|||
color: 'rgba(127,95,132,.3)', |
|||
opacity: 1, |
|||
shadowBlur: 45, |
|||
shadowColor: 'rgba(0,0,0,.5)', |
|||
shadowOffsetX: 0, |
|||
shadowOffsetY: 15 |
|||
} |
|||
}, |
|||
indicator: [ |
|||
{ name: 'Sales', max: 10000 }, |
|||
{ name: 'Administration', max: 20000 }, |
|||
{ name: 'Information Technology', max: 20000 }, |
|||
{ name: 'Customer Support', max: 20000 }, |
|||
{ name: 'Development', max: 20000 }, |
|||
{ name: 'Marketing', max: 20000 } |
|||
] |
|||
}, |
|||
legend: { |
|||
left: 'center', |
|||
bottom: '10', |
|||
data: ['Allocated Budget', 'Expected Spending', 'Actual Spending'] |
|||
}, |
|||
series: [{ |
|||
type: 'radar', |
|||
symbolSize: 0, |
|||
areaStyle: { |
|||
normal: { |
|||
shadowBlur: 13, |
|||
shadowColor: 'rgba(0,0,0,.2)', |
|||
shadowOffsetX: 0, |
|||
shadowOffsetY: 10, |
|||
opacity: 1 |
|||
} |
|||
}, |
|||
data: [ |
|||
{ |
|||
value: [5000, 7000, 12000, 11000, 15000, 14000], |
|||
name: 'Allocated Budget' |
|||
}, |
|||
{ |
|||
value: [4000, 9000, 15000, 15000, 13000, 11000], |
|||
name: 'Expected Spending' |
|||
}, |
|||
{ |
|||
value: [5500, 11000, 12000, 15000, 12000, 12000], |
|||
name: 'Actual Spending' |
|||
} |
|||
], |
|||
animationDuration: animationDuration |
|||
}] |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
@ -0,0 +1,55 @@ |
|||
<template> |
|||
<el-table :data="list" style="width: 100%;padding-top: 15px;"> |
|||
<el-table-column label="Order_No" min-width="200"> |
|||
<template slot-scope="scope"> |
|||
{{ scope.row.order_no | orderNoFilter }} |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="Price" width="195" align="center"> |
|||
<template slot-scope="scope"> |
|||
¥{{ scope.row.price | toThousandFilter }} |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="Status" width="100" align="center"> |
|||
<template slot-scope="{row}"> |
|||
<el-tag :type="row.status | statusFilter"> |
|||
{{ row.status }} |
|||
</el-tag> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
</template> |
|||
|
|||
<script> |
|||
import { transactionList } from '@/api/remote-search' |
|||
|
|||
export default { |
|||
filters: { |
|||
statusFilter(status) { |
|||
const statusMap = { |
|||
success: 'success', |
|||
pending: 'danger' |
|||
} |
|||
return statusMap[status] |
|||
}, |
|||
orderNoFilter(str) { |
|||
return str.substring(0, 30) |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
list: null |
|||
} |
|||
}, |
|||
created() { |
|||
this.fetchData() |
|||
}, |
|||
methods: { |
|||
fetchData() { |
|||
transactionList().then(response => { |
|||
this.list = response.data.items.slice(0, 8) |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
File diff suppressed because one or more lines are too long
@ -0,0 +1,55 @@ |
|||
import {debounce} from '@/utils' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
$_sidebarElm: null, |
|||
$_resizeHandler: null |
|||
} |
|||
}, |
|||
mounted() { |
|||
this.$_resizeHandler = debounce(() => { |
|||
if (this.chart) { |
|||
this.chart.resize() |
|||
} |
|||
}, 100) |
|||
this.$_initResizeEvent() |
|||
this.$_initSidebarResizeEvent() |
|||
}, |
|||
beforeDestroy() { |
|||
this.$_destroyResizeEvent() |
|||
this.$_destroySidebarResizeEvent() |
|||
}, |
|||
// to fixed bug when cached by keep-alive
|
|||
// https://github.com/PanJiaChen/vue-element-admin/issues/2116
|
|||
activated() { |
|||
this.$_initResizeEvent() |
|||
this.$_initSidebarResizeEvent() |
|||
}, |
|||
deactivated() { |
|||
this.$_destroyResizeEvent() |
|||
this.$_destroySidebarResizeEvent() |
|||
}, |
|||
methods: { |
|||
// use $_ for mixins properties
|
|||
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
|
|||
$_initResizeEvent() { |
|||
window.addEventListener('resize', this.$_resizeHandler) |
|||
}, |
|||
$_destroyResizeEvent() { |
|||
window.removeEventListener('resize', this.$_resizeHandler) |
|||
}, |
|||
$_sidebarResizeHandler(e) { |
|||
if (e.propertyName === 'width') { |
|||
this.$_resizeHandler() |
|||
} |
|||
}, |
|||
$_initSidebarResizeEvent() { |
|||
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0] |
|||
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler) |
|||
}, |
|||
$_destroySidebarResizeEvent() { |
|||
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler) |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue