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