13 changed files with 1391 additions and 15 deletions
Binary file not shown.
After Width: | Height: | Size: 461 KiB |
After Width: | Height: | Size: 270 KiB |
After Width: | Height: | Size: 110 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 307 B |
@ -0,0 +1,579 @@ |
|||||
|
<template> |
||||
|
<div |
||||
|
ref="charts" |
||||
|
style="min-width: 12vw;max-height:220px;height:220px;" |
||||
|
/> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import * as echarts from 'echarts' |
||||
|
import { debounce } from '@/utils' |
||||
|
|
||||
|
export default { |
||||
|
props: { |
||||
|
config: Object |
||||
|
}, |
||||
|
watch: { |
||||
|
config: { |
||||
|
handler: function(val) { |
||||
|
this.$nextTick(() => { |
||||
|
this.init() |
||||
|
}) |
||||
|
}, |
||||
|
immediate: true, |
||||
|
deep: true, |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
chart: null |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
option() { |
||||
|
let percent = 0; |
||||
|
if (this.config.total === 0) { |
||||
|
percent = 0 |
||||
|
} else { |
||||
|
percent = ((this.config.value / this.config.total) * 100).toFixed(2) |
||||
|
} |
||||
|
const center = ['50%', '55%'] |
||||
|
const self = this |
||||
|
return { |
||||
|
grid: { |
||||
|
left: '0', |
||||
|
top: '0', |
||||
|
right: '0', |
||||
|
bottom: '0', |
||||
|
containLabel: false |
||||
|
}, |
||||
|
// backgroundColor: '#0E1327', |
||||
|
backgroundColor: 'transparent', |
||||
|
tooltip: { |
||||
|
show: false |
||||
|
}, |
||||
|
|
||||
|
angleAxis: { |
||||
|
show: false, |
||||
|
max: 100 * 360 / 270, //-45度到225度,二者偏移值是270度除360度 |
||||
|
type: 'value', |
||||
|
startAngle: 225, //极坐标初始角度 |
||||
|
splitLine: { |
||||
|
show: false |
||||
|
} |
||||
|
}, |
||||
|
barMaxWidth: '11%', //圆环宽度 |
||||
|
radiusAxis: { |
||||
|
show: false, |
||||
|
type: 'category' |
||||
|
}, |
||||
|
//圆环位置和大小 |
||||
|
polar: { |
||||
|
center: center, |
||||
|
radius: '100%' |
||||
|
}, |
||||
|
|
||||
|
series: [ |
||||
|
|
||||
|
// 最外圈的边框(左右) |
||||
|
{ |
||||
|
name: '内部透明起始结束的圆边', |
||||
|
type: 'gauge', |
||||
|
center: center, |
||||
|
radius: '80%', |
||||
|
splitNumber: 10, |
||||
|
axisLine: { |
||||
|
lineStyle: { |
||||
|
color: [ |
||||
|
// 右/下/左/上 |
||||
|
[0.3, new echarts.graphic.LinearGradient( |
||||
|
1, 0, 0, 0, |
||||
|
[{ |
||||
|
offset: 0.4, |
||||
|
color: this.config.opacityBorder[0] |
||||
|
}, { |
||||
|
offset: 1, |
||||
|
color: this.config.opacityBorder[1] |
||||
|
}] |
||||
|
)], |
||||
|
[0.7, new echarts.graphic.LinearGradient( |
||||
|
0, 0, 1, 0, |
||||
|
[{ |
||||
|
offset: 0, |
||||
|
color: this.config.opacityBorder[0] |
||||
|
}, { |
||||
|
offset: 1, |
||||
|
color: this.config.opacityBorder[0] |
||||
|
}] |
||||
|
)], |
||||
|
[1, new echarts.graphic.LinearGradient( |
||||
|
0, 0, 1, 0, |
||||
|
[{ |
||||
|
offset: 0.4, |
||||
|
color: this.config.opacityBorder[0] |
||||
|
}, { |
||||
|
offset: 1, |
||||
|
color: this.config.opacityBorder[1] |
||||
|
}] |
||||
|
)] |
||||
|
], |
||||
|
width: 2 |
||||
|
} |
||||
|
}, |
||||
|
z: 4, |
||||
|
axisLabel: { |
||||
|
show: false |
||||
|
}, |
||||
|
axisTick: { |
||||
|
show: false |
||||
|
}, |
||||
|
splitLine: { |
||||
|
show: false |
||||
|
}, |
||||
|
//仪表盘详情,用于显示数据。 |
||||
|
detail: { |
||||
|
show: true, |
||||
|
offsetCenter: [0, '95%'], |
||||
|
color: '#fff', |
||||
|
formatter(params) { |
||||
|
return `{t1|${self.config.valueLabel}}\n{t2|${self.config.totalLabel}}` |
||||
|
}, |
||||
|
rich: { |
||||
|
t1: { |
||||
|
fontFamily: 'PingFang TC', |
||||
|
fontSize: '5%', |
||||
|
color: '#C6CEEC', |
||||
|
lineHeight: 18 |
||||
|
}, |
||||
|
t2: { |
||||
|
fontFamily: 'PingFang TC', |
||||
|
fontSize: '10%', |
||||
|
color: '#FFFFFF', |
||||
|
lineHeight: 18 |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
label: { |
||||
|
show: false |
||||
|
}, |
||||
|
pointer: { |
||||
|
show: false |
||||
|
}, |
||||
|
title: { |
||||
|
//标题 |
||||
|
show: false |
||||
|
}, |
||||
|
data: [ |
||||
|
{ |
||||
|
name: percent + '%', |
||||
|
value: percent |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
|
||||
|
// 带有阴影的边框 |
||||
|
{ |
||||
|
name: 'border', |
||||
|
type: 'pie', |
||||
|
clockWise: false, |
||||
|
radius: '70%', |
||||
|
center: center, |
||||
|
animation: false, |
||||
|
z: 0, |
||||
|
data: [{ |
||||
|
value: 0, |
||||
|
color: 'transparent', |
||||
|
label: { |
||||
|
show: false |
||||
|
}, |
||||
|
labelLine: { |
||||
|
show: false |
||||
|
}, |
||||
|
emphasis: { |
||||
|
disabled: true |
||||
|
}, |
||||
|
select: { |
||||
|
disabled: true |
||||
|
}, |
||||
|
tooltip: { |
||||
|
show: false |
||||
|
}, |
||||
|
itemStyle: { |
||||
|
color: '#071422', |
||||
|
shadowColor: this.config.shadowColor, |
||||
|
shadowBlur: 25, |
||||
|
shadowOffsetX: 0, |
||||
|
shadowOffsetY: -25 |
||||
|
} |
||||
|
}] |
||||
|
}, |
||||
|
// 阴影的边框(中间) |
||||
|
{ |
||||
|
name: '内部透明起始结束的圆边', |
||||
|
type: 'gauge', |
||||
|
center: center, |
||||
|
radius: '70%', |
||||
|
axisLine: { |
||||
|
lineStyle: { |
||||
|
color: [ |
||||
|
// 右/下/左/上 |
||||
|
[0.4, new echarts.graphic.LinearGradient( |
||||
|
1, 0, 0, 0, |
||||
|
[{ |
||||
|
offset: 0, |
||||
|
color: this.config.opacityBorder[0] |
||||
|
}, { |
||||
|
offset: 1, |
||||
|
color: this.config.opacityBorder[1] |
||||
|
}] |
||||
|
)], |
||||
|
[0.6, new echarts.graphic.LinearGradient( |
||||
|
1, 0, 0, 0, |
||||
|
[{ |
||||
|
offset: 0, |
||||
|
color: this.config.opacityBorder[0] |
||||
|
}, { |
||||
|
offset: 1, |
||||
|
color: this.config.opacityBorder[0] |
||||
|
}] |
||||
|
)] |
||||
|
], |
||||
|
width: 2 |
||||
|
} |
||||
|
}, |
||||
|
z: 4, |
||||
|
axisLabel: { |
||||
|
show: false |
||||
|
}, |
||||
|
axisTick: { |
||||
|
show: false |
||||
|
}, |
||||
|
splitLine: { |
||||
|
show: false |
||||
|
}, |
||||
|
detail: { |
||||
|
show: false |
||||
|
}, |
||||
|
label: { |
||||
|
show: false |
||||
|
}, |
||||
|
pointer: { |
||||
|
show: false |
||||
|
}, |
||||
|
title: { |
||||
|
//标题 |
||||
|
show: false |
||||
|
}, |
||||
|
data: [ |
||||
|
{ |
||||
|
name: percent + '%', |
||||
|
value: percent |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
|
||||
|
// 刻度 |
||||
|
{ |
||||
|
name: '外部刻度', |
||||
|
type: 'gauge', |
||||
|
center: center, |
||||
|
radius: '75%', |
||||
|
min: 0, //最小刻度 |
||||
|
max: 100, //最大刻度 |
||||
|
splitNumber: 10, //刻度数量 |
||||
|
startAngle: 225, |
||||
|
endAngle: -45, |
||||
|
axisLine: { |
||||
|
show: false, |
||||
|
lineStyle: { |
||||
|
width: 1, |
||||
|
color: [ |
||||
|
[1, 'rgba(0,0,0,0)'] |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
//仪表盘轴线 |
||||
|
axisLabel: { |
||||
|
show: false |
||||
|
}, //刻度标签。 |
||||
|
axisTick: { |
||||
|
show: true, |
||||
|
splitNumber: 4, |
||||
|
lineStyle: { |
||||
|
//用颜色渐变函数不起作用 |
||||
|
color: '#6DCBFF', |
||||
|
width: 1 |
||||
|
}, |
||||
|
length: 1 |
||||
|
}, |
||||
|
//刻度样式 |
||||
|
splitLine: { |
||||
|
show: true, |
||||
|
length: 2, |
||||
|
lineStyle: { |
||||
|
//用颜色渐变函数不起作用 |
||||
|
color: '#6DCBFF' |
||||
|
} |
||||
|
}, //分隔线样式 |
||||
|
detail: { |
||||
|
show: false |
||||
|
}, |
||||
|
pointer: { |
||||
|
show: false |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 最宽的圆环,上层, 显示彩色的进度条 |
||||
|
{ |
||||
|
type: 'bar', |
||||
|
data: [ |
||||
|
{ |
||||
|
value: percent, |
||||
|
itemStyle: { |
||||
|
//图形渐变颜色方法,四个数字分别代表,右,下,左,上,offset表示0%到100% |
||||
|
color: { |
||||
|
type: 'linear', |
||||
|
x: 0, |
||||
|
y: 1, |
||||
|
x2: 0, |
||||
|
y2: 0, |
||||
|
colorStops: [ |
||||
|
{ |
||||
|
offset: 0, |
||||
|
color: this.config.progressBar[0] |
||||
|
}, { |
||||
|
offset: 1, |
||||
|
color: this.config.progressBar[1] |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
barGap: '-100%', //柱间距离,上下两层圆环重合 |
||||
|
coordinateSystem: 'polar', |
||||
|
roundCap: true, //顶端圆角从 v4.5.0 开始支持 |
||||
|
//圆环层级,同zindex |
||||
|
z: 2 |
||||
|
}, |
||||
|
// 最宽的圆环,下层, 显示底色的进度条 |
||||
|
{ |
||||
|
type: 'bar', |
||||
|
data: [ |
||||
|
{ |
||||
|
value: 100, |
||||
|
itemStyle: { |
||||
|
color: this.config.progressBarBG |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
barGap: '-100%', |
||||
|
coordinateSystem: 'polar', |
||||
|
roundCap: true, |
||||
|
z: 1 |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
name: '内部透明起始结束的圆边', |
||||
|
type: 'gauge', |
||||
|
center: center, |
||||
|
radius: '40%', |
||||
|
splitNumber: 10, |
||||
|
axisLine: { |
||||
|
lineStyle: { |
||||
|
color: [ |
||||
|
[0, new echarts.graphic.LinearGradient( |
||||
|
0, 1, 0, 0, |
||||
|
[{ |
||||
|
offset: 0, |
||||
|
color: this.config.circle2Color[0] |
||||
|
}, { |
||||
|
offset: 1, |
||||
|
color: this.config.circle2Color[1] |
||||
|
}] |
||||
|
)], |
||||
|
[0.2, new echarts.graphic.LinearGradient( |
||||
|
0, 1, 0, 0, |
||||
|
[{ |
||||
|
offset: 0, |
||||
|
color: this.config.circle2Color[0] |
||||
|
}, { |
||||
|
offset: 1, |
||||
|
color: this.config.circle2Color[1] |
||||
|
}] |
||||
|
)], |
||||
|
[0.8, new echarts.graphic.LinearGradient( |
||||
|
0, 0, 1, 0, |
||||
|
[{ |
||||
|
offset: 0, |
||||
|
color: this.config.circle2Color[1] |
||||
|
}, { |
||||
|
offset: 1, |
||||
|
color: this.config.circle2Color[1] |
||||
|
}] |
||||
|
)], |
||||
|
[1, new echarts.graphic.LinearGradient( |
||||
|
0, 0, 0, 1, |
||||
|
[{ |
||||
|
offset: 0, |
||||
|
color: this.config.circle2Color[1] |
||||
|
}, { |
||||
|
offset: 1, |
||||
|
color: this.config.circle2Color[0] |
||||
|
}] |
||||
|
)] |
||||
|
], |
||||
|
width: 1 |
||||
|
} |
||||
|
}, |
||||
|
z: 4, |
||||
|
axisLabel: { |
||||
|
show: false |
||||
|
}, |
||||
|
axisTick: { |
||||
|
show: false |
||||
|
}, |
||||
|
splitLine: { |
||||
|
show: false |
||||
|
}, |
||||
|
detail: { |
||||
|
show: false |
||||
|
}, |
||||
|
label: { |
||||
|
show: false |
||||
|
}, |
||||
|
pointer: { |
||||
|
show: false |
||||
|
}, |
||||
|
title: { |
||||
|
//标题 |
||||
|
show: false |
||||
|
}, |
||||
|
data: [ |
||||
|
{ |
||||
|
name: percent + '%', |
||||
|
value: percent |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
|
||||
|
// 内圆的边框 |
||||
|
{ |
||||
|
name: '外边框', |
||||
|
type: 'pie', |
||||
|
clockWise: false, |
||||
|
hoverAnimation: false, |
||||
|
radius: ['35%', '35%'],//边框大小 |
||||
|
center: center,//边框位置 |
||||
|
tooltip: { |
||||
|
show: false |
||||
|
}, |
||||
|
label: { |
||||
|
show: false |
||||
|
}, |
||||
|
data: [ |
||||
|
{ |
||||
|
value: 10, |
||||
|
itemStyle: { |
||||
|
normal: { |
||||
|
borderWidth: 1,//设置边框粗细 |
||||
|
borderColor: this.config.circle2Color[1]//边框颜色 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
|
||||
|
// 内圆 |
||||
|
{ |
||||
|
type: 'pie', |
||||
|
radius: '35%', |
||||
|
center: center, |
||||
|
z: 1, |
||||
|
itemStyle: { |
||||
|
normal: { |
||||
|
color: new echarts.graphic.RadialGradient(.5, .5, .8, [ |
||||
|
{ |
||||
|
offset: 0, |
||||
|
color: this.config.innerCircle[0] |
||||
|
}, |
||||
|
{ |
||||
|
offset: .5, |
||||
|
color: this.config.innerCircle[1] |
||||
|
}, |
||||
|
{ |
||||
|
offset: 1, |
||||
|
color: this.config.innerCircle[2] |
||||
|
} |
||||
|
], |
||||
|
false |
||||
|
), |
||||
|
label: { |
||||
|
show: false |
||||
|
}, |
||||
|
labelLine: { |
||||
|
show: false |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
hoverAnimation: false, |
||||
|
label: { |
||||
|
normal: { |
||||
|
show: true, |
||||
|
position: 'center', |
||||
|
color: '#4c4a4a', |
||||
|
formatter: `{t1|${percent}%}\n{t2|${this.config.value}}\n{t3|${this.config.unit}}`, |
||||
|
rich: { |
||||
|
t1: { |
||||
|
fontFamily: 'PingFang TC', |
||||
|
fontSize: '5%', |
||||
|
color: '#C6CEEC', |
||||
|
lineHeight: 14 |
||||
|
}, |
||||
|
t2: { |
||||
|
fontFamily: 'PingFang TC', |
||||
|
fontSize: '10%', |
||||
|
color: '#FFFFFF', |
||||
|
lineHeight: 14, |
||||
|
fontWeight: 600 |
||||
|
}, |
||||
|
t3: { |
||||
|
fontFamily: 'PingFang TC', |
||||
|
fontSize: '5%', |
||||
|
color: '#C6CEEC', |
||||
|
lineHeight: 14 |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
emphasis: {//中间文字显示 |
||||
|
show: true |
||||
|
} |
||||
|
}, |
||||
|
tooltip: { |
||||
|
show: false |
||||
|
}, |
||||
|
data: [100] |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
window.addEventListener('resize', debounce(() => { |
||||
|
this.chart?.resize() |
||||
|
}, 200)) |
||||
|
|
||||
|
}, |
||||
|
methods: { |
||||
|
init() { |
||||
|
if (!this.chart) { |
||||
|
this.chart = echarts.init(this.$refs.charts) |
||||
|
} |
||||
|
this.chart.setOption(this.option) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
<style scoped> |
||||
|
|
||||
|
</style> |
@ -0,0 +1,173 @@ |
|||||
|
<template> |
||||
|
<div |
||||
|
class="data-view" |
||||
|
:style="{backgroundImage: `url(${DataViewBG})`}" |
||||
|
> |
||||
|
<!-- 头部部分 --> |
||||
|
<div |
||||
|
class="data-view-header" |
||||
|
:style="{backgroundImage: `url(${DataViewHeaderBg})`}" |
||||
|
> |
||||
|
<div class="identifier"> |
||||
|
<img style="width: 23px; height: 23px;" :src="icon" alt=""> |
||||
|
<span style="padding-left: 10px;">{{identifier}}</span> |
||||
|
</div> |
||||
|
<h1 class="YouSheBiaoTiHei data-view-header-title">{{ title }}</h1> |
||||
|
<div class="data-view-header-time"> |
||||
|
<img @click="$emit('leave')" style="width: 26px; height: 26px; cursor: pointer;" :src="ICUNFullscreen" alt=""> |
||||
|
<div style="width: 26px;"/> |
||||
|
<span>{{date}}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 内容 --> |
||||
|
<div class="data-view-body"> |
||||
|
<!-- 左边的表格 --> |
||||
|
<div class="left-table"> |
||||
|
<slot name="left-table"/> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 中间的内容 --> |
||||
|
<div class="middle"> |
||||
|
<!-- 中间的图表 --> |
||||
|
<div class="middle-charts"> |
||||
|
<slot name="middle-charts"></slot> |
||||
|
</div> |
||||
|
<!-- 中间的表格 --> |
||||
|
<div class="middle-table"> |
||||
|
<slot name="middle-table"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 右边的表格 --> |
||||
|
<div class="right-table"> |
||||
|
<slot name="right-table"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import DataViewBG from '@/assets/images/data-view-bg.png' |
||||
|
import DataViewHeaderBg from '@/assets/images/data-view-header-bg.png' |
||||
|
import ICUNFullscreen from '@/assets/images/ic_unfullscreen.png' |
||||
|
import { getWeek, parseTime } from '@/utils/ruoyi' |
||||
|
|
||||
|
|
||||
|
export default { |
||||
|
components: { }, |
||||
|
props: { |
||||
|
// 左上角的标识 |
||||
|
identifier: { |
||||
|
type: String |
||||
|
}, |
||||
|
// 左上角的图标 |
||||
|
icon: { |
||||
|
type: String |
||||
|
}, |
||||
|
// 大标题 |
||||
|
title: { |
||||
|
type: String |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
ICUNFullscreen, |
||||
|
DataViewBG, |
||||
|
DataViewHeaderBg, |
||||
|
date: parseTime(new Date(), `{y}-{m}-{d} {h}:{i}:{s}`) + " " + getWeek() |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
// 每秒更新一次时间 |
||||
|
setInterval(() => { |
||||
|
this.date = parseTime(new Date(), `{y}-{m}-{d} {h}:{i}:{s}`) + " " + getWeek() |
||||
|
}, 1000) |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
<style scoped> |
||||
|
.data-view { |
||||
|
height: 100vh; |
||||
|
width: 100vw; |
||||
|
background-size: cover; |
||||
|
background-repeat: no-repeat; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
|
||||
|
.data-view-header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
background-size: contain; |
||||
|
background-repeat: no-repeat; |
||||
|
height: 6vw; |
||||
|
padding: 0 20px 0 20px; |
||||
|
|
||||
|
.identifier { |
||||
|
font-family: 'PingFang SC'; |
||||
|
font-style: normal; |
||||
|
font-weight: 500; |
||||
|
font-size: 24px; |
||||
|
line-height: 25px; |
||||
|
color: #FFFFFF; |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
margin-top: 14px; |
||||
|
} |
||||
|
|
||||
|
.data-view-header-time { |
||||
|
font-family: 'PingFang SC'; |
||||
|
font-style: normal; |
||||
|
font-weight: 500; |
||||
|
font-size: 18px; |
||||
|
line-height: 25px; |
||||
|
color: #FFFFFF; |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
margin-top: 14px; |
||||
|
} |
||||
|
|
||||
|
.data-view-header-title { |
||||
|
color: #D4DCFF; |
||||
|
font-size: 2.5vw; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.data-view-body { |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
justify-content: space-between; |
||||
|
margin-top: 40px; |
||||
|
padding: 0 20px 0 20px; |
||||
|
} |
||||
|
|
||||
|
.left-table { |
||||
|
width: 23.5%; |
||||
|
} |
||||
|
|
||||
|
.middle { |
||||
|
width: 50%; |
||||
|
|
||||
|
.middle-charts { |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
|
||||
|
.middle-table { |
||||
|
margin-top: 0.5vh; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
.right-table { |
||||
|
width: 23.5%; |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
</style> |
@ -0,0 +1,255 @@ |
|||||
|
<template> |
||||
|
<div |
||||
|
class="data-view-table" |
||||
|
:class="['data-view-table' + '--' + size]" |
||||
|
> |
||||
|
<div |
||||
|
class="data-view-table-header" |
||||
|
:style="{ backgroundImage: `url(${DataViewTableHeaderBG})` }" |
||||
|
> |
||||
|
<span class="YouSheBiaoTiHei header-title">{{ title }}</span> |
||||
|
</div> |
||||
|
<table class="data-view-table-body"> |
||||
|
<thead> |
||||
|
<tr class="data-view-table-body-header"> |
||||
|
<th |
||||
|
class="data-view-table-body-header-item" |
||||
|
v-for="(column, index) of columns" |
||||
|
:key="column.key" |
||||
|
:style="{width: columnSizes[index] + '%'}" |
||||
|
> |
||||
|
{{ column.label }} |
||||
|
</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody ref="tbody" @mouseout="mouseleave" @mouseover="mouseenter"> |
||||
|
<tr |
||||
|
v-for="(item, index) in data" |
||||
|
:key="index" |
||||
|
class="data-view-table-body-item" |
||||
|
:class="[ |
||||
|
index % 2 === 0 ? 'data-view-table-body-item--odd' : 'data-view-table-body-item--even', |
||||
|
item.balanceWarning === 1 && 'data-view-table-body-item--warning' |
||||
|
]" |
||||
|
> |
||||
|
<td |
||||
|
v-for="(column, index) in columns" |
||||
|
:key="column.key" |
||||
|
:style="{width: columnSizes[index] + '%'}" |
||||
|
> |
||||
|
{{ item[column.key] }} |
||||
|
</td> |
||||
|
</tr> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import DataViewTableHeaderBGLarge from '@/assets/images/data-view-table-header-bg-large.png' |
||||
|
import DataViewTableHeaderBGMiddle from '@/assets/images/data-view-table-header-bg-middle.png' |
||||
|
|
||||
|
export default { |
||||
|
components: {}, |
||||
|
props: { |
||||
|
title: { |
||||
|
type: String |
||||
|
}, |
||||
|
data: { |
||||
|
type: Array |
||||
|
}, |
||||
|
columns: { |
||||
|
type: Array |
||||
|
}, |
||||
|
columnSizes: { |
||||
|
type: Array |
||||
|
}, |
||||
|
size: String |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
DataViewTableHeaderBGLarge, |
||||
|
DataViewTableHeaderBGMiddle, |
||||
|
timer: null, |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
DataViewTableHeaderBG() { |
||||
|
if (this.size === 'large') { |
||||
|
return DataViewTableHeaderBGLarge |
||||
|
} else if (this.size === 'middle') { |
||||
|
return DataViewTableHeaderBGMiddle |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
watch: { |
||||
|
data: { |
||||
|
handler(newValue, oldValue) { |
||||
|
this.$nextTick(() => { |
||||
|
this.scroll() |
||||
|
}) |
||||
|
}, |
||||
|
immediate: true |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
scrollReset() { |
||||
|
this.$refs.tbody.scroll({top: 0, behavior: "smooth"}) |
||||
|
}, |
||||
|
mouseleave() { |
||||
|
this.scroll() |
||||
|
}, |
||||
|
mouseenter() { |
||||
|
clearTimeout(this.timer) |
||||
|
}, |
||||
|
scroll() { |
||||
|
const tbody = this.$refs.tbody |
||||
|
if ((tbody.clientHeight + tbody.scrollTop) < tbody.scrollHeight) { |
||||
|
clearInterval(this.timer) |
||||
|
this.timer = setInterval(() => { |
||||
|
const remainScrollTop = tbody.scrollHeight - (tbody.clientHeight + tbody.scrollTop) |
||||
|
tbody.scrollTop += 1 |
||||
|
if (tbody.scrollTop >= remainScrollTop) { |
||||
|
clearInterval(this.timer) |
||||
|
} |
||||
|
}, 100) |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
<style scoped lang="scss"> |
||||
|
|
||||
|
.data-view-table { |
||||
|
|
||||
|
.data-view-table-header { |
||||
|
background-size: cover; |
||||
|
background-repeat: no-repeat; |
||||
|
height: 51px; |
||||
|
align-items: center; |
||||
|
padding-left: 28px; |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
|
||||
|
.header-title { |
||||
|
font-size: 22px; |
||||
|
/* identical to box height */ |
||||
|
text-transform: uppercase; |
||||
|
color: #FFFFFF; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
table { |
||||
|
/*设置相邻单元格的边框间的距离*/ |
||||
|
border-spacing: 0; |
||||
|
/*表格设置合并边框模型*/ |
||||
|
border-collapse: collapse; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
table tbody { |
||||
|
display: block; |
||||
|
overflow-y: scroll; |
||||
|
} |
||||
|
|
||||
|
table tbody::-webkit-scrollbar { |
||||
|
display: none; /* Chrome Safari */ |
||||
|
} |
||||
|
|
||||
|
table tbody { |
||||
|
scrollbar-width: none; /* firefox */ |
||||
|
-ms-overflow-style: none; /* IE 10+ */ |
||||
|
overflow-x: hidden; |
||||
|
overflow-y: auto; |
||||
|
} |
||||
|
|
||||
|
.data-view-table-body { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
|
||||
|
tr, td { |
||||
|
padding: 8px 0px 8px 0px; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
.data-view-table-body-header { |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
background: rgba(14, 75, 255, 0.14); |
||||
|
|
||||
|
th { |
||||
|
font-family: 'PingFang SC'; |
||||
|
font-style: normal; |
||||
|
font-weight: 500; |
||||
|
font-size: 14px; |
||||
|
line-height: 20px; |
||||
|
/* identical to box height */ |
||||
|
|
||||
|
text-align: center; |
||||
|
|
||||
|
color: #5887FF; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
tbody { |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
.data-view-table-body-item { |
||||
|
width: 100%; |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
} |
||||
|
|
||||
|
.data-view-table-body-item--odd { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.data-view-table-body-item--even { |
||||
|
background: rgba(14, 75, 255, 0.14); |
||||
|
} |
||||
|
|
||||
|
.data-view-table-body-item--warning { |
||||
|
background: rgba(255, 14, 14, 0.14) !important; |
||||
|
td { |
||||
|
color: #FF3939; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.data-view-table--large { |
||||
|
|
||||
|
table tbody { |
||||
|
height: 40vh; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.data-view-table--middle { |
||||
|
|
||||
|
table tbody { |
||||
|
height: 65vh; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.data-view-table-body-header { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.data-view-table-body-item td { |
||||
|
font-family: 'PingFang SC'; |
||||
|
font-style: normal; |
||||
|
font-weight: 500; |
||||
|
font-size: 14px; |
||||
|
line-height: 20px; |
||||
|
/* identical to box height */ |
||||
|
text-align: center; |
||||
|
color: #C6CEEC; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
</style> |
@ -0,0 +1,291 @@ |
|||||
|
<template> |
||||
|
<data-view-layout |
||||
|
title="卡卡数据可视化" |
||||
|
identifier="KK- MANAGE" |
||||
|
:icon="icon" |
||||
|
@leave="handleLeave" |
||||
|
ref="layout" |
||||
|
> |
||||
|
<template #left-table> |
||||
|
<data-view-table |
||||
|
title="商户数据" |
||||
|
:columnSizes="[20, 20, 20, 20, 20]" |
||||
|
:columns="[ |
||||
|
{label: '商户名称', key: 'username'}, |
||||
|
{label: '余额', key: 'balance'}, |
||||
|
{label: '剩余押金额度', key: 'residueBalance'}, |
||||
|
{label: '成功总金额', key: 'collectionSuccessPrice'}, |
||||
|
{label: '成功率', key: 'percentage'}, |
||||
|
]" |
||||
|
:data="data1" |
||||
|
size="middle" |
||||
|
ref="table1" |
||||
|
/> |
||||
|
</template> |
||||
|
|
||||
|
<template #middle-charts> |
||||
|
<data-view-echart :config="chart1"/> |
||||
|
<data-view-echart :config="chart2"/> |
||||
|
<data-view-echart :config="chart3"/> |
||||
|
<data-view-echart :config="chart4"/> |
||||
|
</template> |
||||
|
|
||||
|
<template #middle-table> |
||||
|
<data-view-table |
||||
|
title="在线卡数据" |
||||
|
:columnSizes="[12, 12, 12, 12, 20, 20, 12]" |
||||
|
:columns="[ |
||||
|
{label: '银行名称/卡号', key: 'bankName'}, |
||||
|
{label: '收款人名称', key: 'cardHolder'}, |
||||
|
{label: '卡商名称', key: 'username'}, |
||||
|
{label: '已收款', key: 'todayIncomeReceived'}, |
||||
|
{label: '剩余收款额度', key: 'todayRemainingAmount'}, |
||||
|
{label: '出款笔数/金额', key: 'todayOutNumber'}, |
||||
|
{label: '剩余卡余额', key: 'remainingAmount'}, |
||||
|
]" |
||||
|
:data="data2" |
||||
|
size="large" |
||||
|
ref="table2" |
||||
|
/> |
||||
|
</template> |
||||
|
|
||||
|
<template #right-table> |
||||
|
<data-view-table |
||||
|
title="在线卡商数据" |
||||
|
:columnSizes="[25, 25, 25, 25]" |
||||
|
:columns="[ |
||||
|
{label: '卡商名称', key: 'username'}, |
||||
|
{label: '押金/剩余额度', key: 'dayMargin'}, |
||||
|
{label: '日总跑量', key: 'toDayTotal'}, |
||||
|
{label: '押金周转率', key: 'turnoverRate'}, |
||||
|
]" |
||||
|
:data="data3" |
||||
|
size="middle" |
||||
|
ref="table3" |
||||
|
/> |
||||
|
</template> |
||||
|
</data-view-layout> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import DataViewBG from '@/assets/images/data-view-bg.png' |
||||
|
import DataViewEchart from './components/data-view-echart.vue' |
||||
|
import DataViewLayout from './components/data-view-layout.vue' |
||||
|
import icon from '@/assets/logo/plain.png' |
||||
|
import DataViewTable from './components/data-view-table.vue' |
||||
|
import { amountFormat, sortBy } from '@/utils/ruoyi' |
||||
|
import screenfull from 'screenfull'; |
||||
|
|
||||
|
export default { |
||||
|
components: { DataViewTable, DataViewLayout, DataViewEchart }, |
||||
|
data() { |
||||
|
return { |
||||
|
DataViewBG, |
||||
|
icon, |
||||
|
// 商户数据 |
||||
|
data1: [], |
||||
|
// 在线卡数据 |
||||
|
data2: [], |
||||
|
// 在线卡商数据 |
||||
|
data3: [], |
||||
|
// 图表-代收成功单数/代收总单数 |
||||
|
chart1: { |
||||
|
value: 0, |
||||
|
total: 0, |
||||
|
unit: "单", |
||||
|
// 进度条主色(渐变色), 由左到右 |
||||
|
progressBar: ["#4494FF", '#B04BFF'], |
||||
|
// 进度条背景色 |
||||
|
progressBarBG: '#091560', |
||||
|
// 两边透明的圆边颜色, 第一个浅色, 第二个深色 |
||||
|
circle2Color: ['#168FFF00', '#168FFF'], |
||||
|
// 内圆的渐变, 由内到外 |
||||
|
innerCircle: ['#082863', '#082863', '#8000FF68'], |
||||
|
// 透明边框的颜色, 数组第一个为浅色, 第二个为深色 |
||||
|
opacityBorder: ['rgba(0, 0, 0, 0)', 'rgba(45, 103, 252, 1)'], |
||||
|
// 投影颜色 |
||||
|
shadowColor: '#2D68FF', |
||||
|
// 刻度颜色 |
||||
|
scaleColor: '#6DCBFF', |
||||
|
// 数值文字 |
||||
|
valueLabel: '代收成功单数', |
||||
|
// 总数值文字 |
||||
|
totalLabel: '总订单:0', |
||||
|
}, |
||||
|
chart2: { |
||||
|
value: 0, |
||||
|
total: 0, |
||||
|
unit: "元", |
||||
|
progressBar: ["#4494FF", '#B04BFF'], |
||||
|
progressBarBG: '#091560', |
||||
|
circle2Color: ['#168FFF00', '#168FFF'], |
||||
|
innerCircle: ['#082863', '#082863', '#8000FF68'], |
||||
|
opacityBorder: ['rgba(0, 0, 0, 0)', 'rgba(45, 103, 252, 1)'], |
||||
|
shadowColor: '#2D68FF', |
||||
|
scaleColor: '#6DCBFF', |
||||
|
valueLabel: '代收成功金额', |
||||
|
totalLabel: '总金额:0', |
||||
|
}, |
||||
|
chart3: { |
||||
|
value: 0, |
||||
|
total: 0, |
||||
|
unit: "单", |
||||
|
progressBar: ["#4494FF", '#EFA83E'], |
||||
|
progressBarBG: '#0A2F28', |
||||
|
circle2Color: ['#30BE7900', '#30BE79'], |
||||
|
innerCircle: ['#2EB87642', '#2EB87642', '#2AA56C'], |
||||
|
opacityBorder: ['rgba(0, 0, 0, 0)', '#30C17B'], |
||||
|
shadowColor: '#30C17B', |
||||
|
scaleColor: '#6DCBFF', |
||||
|
valueLabel: '代付成功单数', |
||||
|
totalLabel: '总金额:0', |
||||
|
}, |
||||
|
chart4: { |
||||
|
value: 0, |
||||
|
total: 0, |
||||
|
unit: "元", |
||||
|
progressBar: ["#4494FF", '#EFA83E'], |
||||
|
progressBarBG: '#0A2F28', |
||||
|
circle2Color: ['#30BE7900', '#30BE79'], |
||||
|
innerCircle: ['#2EB87642', '#2EB87642', '#2AA56C'], |
||||
|
opacityBorder: ['rgba(0, 0, 0, 0)', '#30C17B'], |
||||
|
shadowColor: '#30C17B', |
||||
|
scaleColor: '#6DCBFF', |
||||
|
valueLabel: '代付成功金额', |
||||
|
totalLabel: '总金额:0', |
||||
|
}, |
||||
|
ws: null, |
||||
|
isScreenFull: false, |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
this.connectWS() |
||||
|
}, |
||||
|
methods: { |
||||
|
connectWS() { |
||||
|
this.ws = new WebSocket(`ws://192.168.31.129:18997/websocket`) |
||||
|
this.ws.onopen = () => { |
||||
|
this.ws.send(JSON.stringify({ 'type': 'add_push' })) |
||||
|
} |
||||
|
this.ws.onmessage = (event) => { |
||||
|
if (!event.data) { |
||||
|
return |
||||
|
} |
||||
|
let data |
||||
|
try { |
||||
|
data = JSON.parse(event.data) |
||||
|
} catch (e) { |
||||
|
return |
||||
|
} |
||||
|
if (!data || data.type !== 'push') { |
||||
|
return |
||||
|
} |
||||
|
const card = JSON.parse(data.value.card) |
||||
|
const carddealer = JSON.parse(data.value.carddealer) |
||||
|
const statisticsPush = JSON.parse(data.value.statisticsPush) |
||||
|
|
||||
|
// payTotalQty 代收总订单数 |
||||
|
// paySuccessQty 代收成功订单数 |
||||
|
// paySuccessAmount 代收成功金额 |
||||
|
// payTotalAmount 代收总金额 |
||||
|
// transferTotalQty 代付总订单数 |
||||
|
// transferSuccessQty 代付成功订单数 |
||||
|
// transferSuccessAmount 代付成功金额 |
||||
|
// transferTotalAmount 代付总金额 |
||||
|
console.log("statisticsPush", statisticsPush) |
||||
|
|
||||
|
this.chart1.value = statisticsPush.paySuccessQty |
||||
|
this.chart1.total = statisticsPush.payTotalQty |
||||
|
this.chart1.totalLabel = '总订单:' + statisticsPush.payTotalQty |
||||
|
|
||||
|
this.chart2.value = this.NumberDiv(statisticsPush.paySuccessAmount, 100) |
||||
|
this.chart2.total = this.NumberDiv(statisticsPush.payTotalAmount, 100) |
||||
|
this.chart2.totalLabel = '总金额:' + this.NumberDiv(statisticsPush.payTotalAmount, 100) |
||||
|
|
||||
|
this.chart3.value = statisticsPush.transferSuccessQty |
||||
|
this.chart3.total = statisticsPush.transferTotalQty |
||||
|
this.chart3.totalLabel = '总订单:' + statisticsPush.transferTotalQty |
||||
|
|
||||
|
this.chart4.value = this.NumberDiv(statisticsPush.transferSuccessAmount, 100) |
||||
|
this.chart4.total = this.NumberDiv(statisticsPush.transferTotalAmount, 100) |
||||
|
this.chart4.totalLabel = '总金额:' + this.NumberDiv(statisticsPush.transferTotalAmount, 100) |
||||
|
|
||||
|
const pushMerchant = JSON.parse(data.value.pushMerchant) |
||||
|
// 商户数据 |
||||
|
this.data1 = pushMerchant.map(i => { |
||||
|
return { |
||||
|
username: i.username, |
||||
|
balance: amountFormat({ amount: i.balance }) || "0", |
||||
|
residueBalance: amountFormat({ amount: i.residueBalance }) || "0", |
||||
|
collectionSuccessPrice: amountFormat({ amount: i.collectionSuccessPrice }) || "0", |
||||
|
percentage: (i.percentage * 100).toFixed(2) + "%", |
||||
|
balanceWarning: i.balanceWarning, |
||||
|
} |
||||
|
}) |
||||
|
this.data1 = sortBy(this.data1, 'balanceWarning') |
||||
|
// 在线卡数据 |
||||
|
this.data2 = card.map(i => { |
||||
|
return { |
||||
|
bankName: i.bankName + '/' + "**** " + i.cardNumber.slice(-4), |
||||
|
cardHolder: i.cardHolder, |
||||
|
username: i.username, |
||||
|
todayIncomeReceived: amountFormat({ amount: i.todayIncomeReceived }) || "0", |
||||
|
todayRemainingAmount: amountFormat({ amount: i.todayRemainingAmount }) || "0", |
||||
|
todayOutNumber: i.todayOutNumber + '/' + amountFormat({ amount: i.todayOutReceived }) || "0", |
||||
|
remainingAmount: amountFormat({ amount: i.remainingAmount }) || "0", |
||||
|
balanceWarning: i.balanceWarning, |
||||
|
} |
||||
|
}) |
||||
|
this.data2 = sortBy(this.data2, 'balanceWarning') |
||||
|
// 在线卡商数据 |
||||
|
this.data3 = carddealer.map(i => { |
||||
|
return { |
||||
|
username: i.username, |
||||
|
dayMargin: (amountFormat({ amount: i.dayMargin }) || "0") + (amountFormat({ amount: i.margin }) || "0"), |
||||
|
toDayTotal: amountFormat({ amount: i.toDayTotal }) || "0", |
||||
|
turnoverRate: (i.turnoverRate * 100).toFixed(2) + "%", |
||||
|
balanceWarning: i.balanceWarning, |
||||
|
} |
||||
|
}) |
||||
|
this.data3 = sortBy(this.data3, 'balanceWarning') |
||||
|
|
||||
|
this.$refs.table1.scrollReset(); |
||||
|
this.$refs.table2.scrollReset(); |
||||
|
this.$refs.table3.scrollReset(); |
||||
|
} |
||||
|
}, |
||||
|
/** |
||||
|
* 退出全屏 |
||||
|
*/ |
||||
|
handleLeave() { |
||||
|
if (this.isScreenFull) { |
||||
|
screenfull.exit() |
||||
|
} else { |
||||
|
screenfull.request(this.$refs.layout.$el) |
||||
|
} |
||||
|
this.isScreenFull = !this.isScreenFull; |
||||
|
}, |
||||
|
disconnect() { |
||||
|
this.ws?.send({ 'type': 'del_push' }) |
||||
|
} |
||||
|
}, |
||||
|
beforeDestroy() { |
||||
|
this.disconnect() |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
<style> |
||||
|
@font-face { |
||||
|
font-family: "YouSheBiaoTiHei"; |
||||
|
src: url('../../assets/fonts/YouSheBiaoTiHei.ttf'); |
||||
|
font-weight: normal; |
||||
|
font-style: normal; |
||||
|
} |
||||
|
|
||||
|
.YouSheBiaoTiHei { |
||||
|
font-family: "YouSheBiaoTiHei", serif; |
||||
|
font-style: normal; |
||||
|
font-weight: 400; |
||||
|
} |
||||
|
|
||||
|
</style> |
Loading…
Reference in new issue