大屏优化

This commit is contained in:
hrx 2026-01-26 11:43:09 +08:00
parent a313470243
commit 793fc447bf
4 changed files with 214 additions and 42 deletions

View File

@ -1,30 +1,30 @@
<template> <template>
<div> <div :key="animationKey">
<div class="left"> <div class="left">
<!-- 第1行2个横向模块 --> <!-- 第1行2个横向模块 -->
<div class="row row-1"> <div class="row row-1">
<div class="cluster"> <div class="cluster data-section" :style="{ animationDelay: '0.2s' }">
<div class="title">异构芯片规模</div> <div class="title">异构芯片规模</div>
<div class="conter"> <div class="conter">
<div class="conter-top"> <div class="conter-top">
<div class="top-tit one">{{ chipData.NVIDIA }}<span>P</span></div> <div class="top-tit one data-item" :style="{ animationDelay: '0.3s' }">{{ chipData.NVIDIA }}<span>P</span></div>
<div class="top-tit two">{{ chipData.ascend }}<span>P</span></div> <div class="top-tit two data-item" :style="{ animationDelay: '0.4s' }">{{ chipData.ascend }}<span>P</span></div>
<div class="top-tit three">{{ chipData.supercomputer }}<span>P</span></div> <div class="top-tit three data-item" :style="{ animationDelay: '0.5s' }">{{ chipData.supercomputer }}<span>P</span></div>
</div> </div>
<div class="conter-center"> <div class="conter-center">
<img src="../images/3D.png" alt=""> <img src="../images/3D.png" alt="">
</div> </div>
<div class="conter-bottom"> <div class="conter-bottom">
<div class="bottom-tit">NVIDIA</div> <div class="bottom-tit data-item" :style="{ animationDelay: '0.6s' }">NVIDIA</div>
<div class="bottom-tit">晟腾</div> <div class="bottom-tit data-item" :style="{ animationDelay: '0.7s' }">晟腾</div>
<div class="bottom-tit">传统超算</div> <div class="bottom-tit data-item" :style="{ animationDelay: '0.8s' }">传统超算</div>
</div> </div>
</div> </div>
</div> </div>
<div class="heterogeneous"> <div class="heterogeneous data-section" :style="{ animationDelay: '0.9s' }">
<div class="title">集群规模</div> <div class="title">集群规模</div>
<div class="content"> <div class="content">
<dv-decoration-9 style="width:200px;height:200px;color: #fff;font-size: 20px; font-weight: 600;"> <dv-decoration-9 class="data-item" :style="{ animationDelay: '1s' }" style="width:200px;height:200px;color: #fff;font-size: 20px; font-weight: 600;">
{{ chipData.total }}P {{ chipData.total }}P
</dv-decoration-9> </dv-decoration-9>
</div> </div>
@ -32,18 +32,18 @@
</div> </div>
<!-- 第2行通栏模块运行中芯片数量 --> <!-- 第2行通栏模块运行中芯片数量 -->
<div class="row row-2"> <div class="row row-2">
<div class="running"> <div class="running data-section" :style="{ animationDelay: '0.9s' }">
<div class="title">运行中芯片数量</div> <div class="title">运行中芯片数量</div>
<div ref="runningChart" class="chart-container "></div> <div ref="runningChart" class="chart-container "></div>
</div> </div>
</div> </div>
<!-- 第3行2个横向模块 --> <!-- 第3行2个横向模块 -->
<div class="row row-3"> <div class="row row-3">
<div class="model"> <div class="model" >
<div class="title">模型调用量</div> <div class="title data-section" :style="{ animationDelay: '0.9s' }">模型调用量</div>
<div ref="modelChart" class="chart-container model-chart"></div> <div ref="modelChart" class="chart-container model-chart"></div>
</div> </div>
<div class="token"> <div class="token data-section" :style="{ animationDelay: '0.9s' }">
<div class="title">token调用量</div> <div class="title">token调用量</div>
<div ref="tokenChart" class="chart-container token-chart"></div> <div ref="tokenChart" class="chart-container token-chart"></div>
</div> </div>
@ -70,7 +70,8 @@ export default {
ascend: 0, ascend: 0,
supercomputer: 0, supercomputer: 0,
total: 0 total: 0
} },
animationKey: 0
}; };
}, },
created() { created() {
@ -96,7 +97,15 @@ export default {
handleClusterChanged(event) { handleClusterChanged(event) {
this.currentData = event.data; this.currentData = event.data;
this.updateChipData(); this.updateChipData();
this.updateCharts(); // key
this.animationKey += 1;
//
this.$nextTick(() => {
this.initRunningChart();
this.initModelChart();
this.initTokenChart();
});
}, },
updateChipData() { updateChipData() {
@ -508,6 +517,7 @@ export default {
gap: 15px; gap: 15px;
padding: 10px 0; padding: 10px 0;
box-sizing: border-box; box-sizing: border-box;
} }
.conter { .conter {
@ -662,6 +672,49 @@ export default {
} }
} }
/* 数据元素顺序渲染动画 */
.data-section {
animation: fadeInLeft 0.8s ease-out forwards;
opacity: 0;
transform: translateX(-20px);
}
.data-item {
animation: fadeInLeft 0.6s ease-out forwards;
opacity: 0;
transform: translateX(-10px);
}
.chart-container {
animation: fadeInLeft 1s ease-out forwards;
opacity: 0;
transform: translateX(-30px);
}
/* 为不同图表添加延迟动画 */
.running .chart-container {
animation-delay: 1.2s;
}
.model .chart-container {
animation-delay: 1.4s;
}
.token .chart-container {
animation-delay: 1.6s;
}
@keyframes fadeInLeft {
0% {
opacity: 0;
transform: translateX(-20px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
/* 响应式适配 */ /* 响应式适配 */
@media (min-width: 1920px) { @media (min-width: 1920px) {
.title { .title {

View File

@ -1,47 +1,47 @@
<template> <template>
<div> <div :key="animationKey">
<div class="right"> <div class="right">
<!-- 1 --> <!-- 1 -->
<div class="row row-1"> <div class="row row-1">
<!-- 应用类型 --> <!-- 应用类型 -->
<div class="app-class"> <div class="app-class data-section" :style="{ animationDelay: '0.2s' }">
<div class="title">应用类型</div> <div class="title">应用类型</div>
<div class="content"> <div class="content">
<!-- 中心TOP1 --> <!-- 中心TOP1 -->
<div class="circle-center"> <div class="circle-center data-item" :style="{ animationDelay: '0.3s' }">
<div class="rank">TOP1</div> <div class="rank">TOP1</div>
<div class="name">{{ appTypes[0] || '智能推理' }}</div> <div class="name">{{ appTypes[0] || '智能推理' }}</div>
</div> </div>
<!-- 周围TOP项 --> <!-- 周围TOP项 -->
<div class="circle-item item-top2"> <div class="circle-item item-top2 data-item" :style="{ animationDelay: '0.4s' }">
<div class="rank">TOP2</div> <div class="rank">TOP2</div>
<div class="name">{{ appTypes[1] || '智能训练' }}</div> <div class="name">{{ appTypes[1] || '智能训练' }}</div>
</div> </div>
<div class="circle-item item-top3"> <div class="circle-item item-top3 data-item" :style="{ animationDelay: '0.5s' }">
<div class="rank">TOP3</div> <div class="rank">TOP3</div>
<div class="name">{{ appTypes[2] || '图形渲染' }}</div> <div class="name">{{ appTypes[2] || '图形渲染' }}</div>
</div> </div>
<div class="circle-item item-top4"> <div class="circle-item item-top4 data-item" :style="{ animationDelay: '0.6s' }">
<div class="rank">TOP4</div> <div class="rank">TOP4</div>
<div class="name">{{ appTypes[3] || '蛋白质分析' }}</div> <div class="name">{{ appTypes[3] || '蛋白质分析' }}</div>
</div> </div>
<div class="circle-item item-top5"> <div class="circle-item item-top5 data-item" :style="{ animationDelay: '0.7s' }">
<div class="rank">TOP5</div> <div class="rank">TOP5</div>
<div class="name">{{ appTypes[4] || '其他' }}</div> <div class="name">{{ appTypes[4] || '其他' }}</div>
</div> </div>
</div> </div>
</div> </div>
<!-- 用户种类 --> <!-- 用户种类 -->
<div class="user-class"> <div class="user-class data-section" :style="{ animationDelay: '0.8s' }">
<div class="title">用户种类</div> <div class="title">用户种类</div>
<div class="content"> <div class="content">
<img src="../images/userClass.png" alt="用户种类示意图"> <img src="../images/userClass.png" alt="用户种类示意图">
<div class="user"> <div class="user">
<span class="finance">金融</span> <span class="finance data-item" :style="{ animationDelay: '0.9s' }">金融</span>
<span class="medical">医疗</span> <span class="medical data-item" :style="{ animationDelay: '1s' }">医疗</span>
<span class="creative">文创</span> <span class="creative data-item" :style="{ animationDelay: '1.1s' }">文创</span>
<span class="education">教育</span> <span class="education data-item" :style="{ animationDelay: '1.2s' }">教育</span>
<span class="intelligence">智能制造</span> <span class="intelligence data-item" :style="{ animationDelay: '1.3s' }">智能制造</span>
</div> </div>
</div> </div>
</div> </div>
@ -50,14 +50,14 @@
<!-- 2 --> <!-- 2 -->
<div class="row row-2"> <div class="row row-2">
<!-- 用户数量 --> <!-- 用户数量 -->
<div class="user-num"> <div class="user-num data-section" :style="{ animationDelay: '1.4s' }">
<div class="title">用户数量</div> <div class="title">用户数量</div>
<div class="content"> <div class="content">
<img src="../images/use-num.png" alt=""> <img src="../images/use-num.png" alt="">
</div> </div>
</div> </div>
<!-- 用户消费排行 --> <!-- 用户消费排行 -->
<div class="user-consume"> <div class="user-consume data-section" :style="{ animationDelay: '1.5s' }">
<div class="title">用户消费排行</div> <div class="title">用户消费排行</div>
<div class="content"> <div class="content">
<dv-scroll-board :config="scrollBoardConfig" :key="scrollBoardKey" ref="scrollBoardRef" style="width:95%;height:95%" /> <dv-scroll-board :config="scrollBoardConfig" :key="scrollBoardKey" ref="scrollBoardRef" style="width:95%;height:95%" />
@ -68,9 +68,9 @@
<!-- 3 --> <!-- 3 -->
<div class="row row-3"> <div class="row row-3">
<!-- 算力使用情况双折线图无背景色 --> <!-- 算力使用情况双折线图无背景色 -->
<div class="power-use"> <div class="power-use data-section" :style="{ animationDelay: '1.6s' }">
<div class="title">算力使用情况</div> <div class="title">算力使用情况</div>
<div ref="powerUseChart" class="power-use-chart"></div> <div ref="powerUseChart" class="power-use-chart data-item" :style="{ animationDelay: '1.7s' }"></div>
</div> </div>
</div> </div>
</div> </div>
@ -108,7 +108,8 @@ export default {
resizeTimer: null, resizeTimer: null,
powerChart: null, powerChart: null,
currentData: null, currentData: null,
appTypes: ['智能推理', '智能训练', '图形渲染', '蛋白质分析', '其他'] appTypes: ['智能推理', '智能训练', '图形渲染', '蛋白质分析', '其他'],
animationKey: 0
}; };
}, },
created() { created() {
@ -137,7 +138,14 @@ export default {
methods: { methods: {
handleClusterChanged(event) { handleClusterChanged(event) {
this.currentData = event.data; this.currentData = event.data;
this.updateDisplay(); // key
this.animationKey += 1;
//
this.$nextTick(() => {
this.initPowerUseChart();
this.updateDisplay();
});
}, },
updateDisplay() { updateDisplay() {
@ -245,7 +253,7 @@ export default {
show: true, show: true,
position: 'top', position: 'top',
formatter: function(params) { formatter: function(params) {
return (params.value / 10000).toFixed(1) + '万'; return (params.value / 10000).toFixed(1) + '万p';
}, },
color: '#fff', color: '#fff',
fontWeight: 'bold', fontWeight: 'bold',
@ -267,7 +275,7 @@ export default {
const value = params[0].value; const value = params[0].value;
return params[0].name + '<br/>' + return params[0].name + '<br/>' +
params[0].marker + params[0].seriesName + ': ' + params[0].marker + params[0].seriesName + ': ' +
value.toLocaleString() + '算力单位'; value.toLocaleString() + 'p';
} }
}, },
grid: { grid: {
@ -718,4 +726,34 @@ export default {
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
z-index: 0; z-index: 0;
} }
/* 数据元素顺序渲染动画 */
.data-section {
animation: fadeInLeft 0.8s ease-out forwards;
opacity: 0;
transform: translateX(-20px);
}
.data-item {
animation: fadeInLeft 0.6s ease-out forwards;
opacity: 0;
transform: translateX(-10px);
}
.power-use-chart {
animation: fadeInLeft 1s ease-out forwards;
opacity: 0;
transform: translateX(-30px);
}
@keyframes fadeInLeft {
0% {
opacity: 0;
transform: translateX(-20px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
</style> </style>

View File

@ -28,7 +28,7 @@ import ScreenHeader from './screenHeader/index.vue';
import ScreenLeft from './ScreenLeft/index.vue'; import ScreenLeft from './ScreenLeft/index.vue';
import ScreenCenter from './ScreenCenter/index.vue'; import ScreenCenter from './ScreenCenter/index.vue';
import ScreenRight from './ScreenRight/index.vue'; import ScreenRight from './ScreenRight/index.vue';
import './media'
export default { export default {
components: { components: {
ScreenHeader, ScreenHeader,
@ -41,6 +41,7 @@ export default {
} }
}, },
methods: { methods: {
} }
} }
</script> </script>
@ -55,17 +56,20 @@ export default {
#app { #app {
box-sizing: border-box; box-sizing: border-box;
height: 100vh; height: 100vh;
width: 100%; width: 100vw;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: url("../../../../assets/image/bg.jpg") no-repeat center ; background: url("../../../../assets/image/bg.jpg") no-repeat center ;
background-size: cover; // background-size: cover; //
overflow: hidden; overflow: hidden;
position: relative;
} }
.top { .top {
width: 100%; width: 100%;
height: 85px; min-height: 85px;
height: 8vh;
max-height: 120px;
} }
img { img {
@ -76,17 +80,84 @@ img {
} }
.center { .center {
display: flex; display: flex;
flex: 1;
min-height: 0;
.left{ .left{
width: 30%; width: 30%;
min-width: 300px;
max-width: 500px;
} }
.content{ .content{
width: 40%; width: 40%;
min-width: 400px;
max-width: 800px;
} }
.right{ .right{
width: 30%; width: 30%;
min-width: 300px;
max-width: 500px;
} }
} }
.center {
height: calc(100% - 80px); /* 响应式布局适配 */
@media (max-width: 1920px) {
.center {
.left,
.right {
width: 28%;
}
.content {
width: 44%;
}
}
}
@media (max-width: 1600px) {
.center {
.left,
.right {
width: 25%;
}
.content {
width: 50%;
}
}
}
@media (max-width: 1366px) {
.center {
.left,
.right {
width: 22%;
min-width: 250px;
}
.content {
width: 56%;
min-width: 350px;
}
}
.top {
min-height: 70px;
height: 7vh;
max-height: 100px;
}
}
@media (max-width: 1024px) {
.center {
flex-direction: column;
.left,
.content,
.right {
width: 100%;
min-width: unset;
max-width: unset;
height: 33.33%;
min-height: 300px;
}
}
} }
</style> </style>

View File

@ -0,0 +1,10 @@
function adapter(){
//获取布局视口宽度,因为开启了理想视口,布局视口=设备横向独立像素值
const dpWidth = document.documentElement.clientWidth
//计算根字体大小
const rootFonstSize = (dpWidth * 100)/1960
//设置根字体大小
document.documentElement.style.fontSize = rootFonstSize + 'px'
}
adapter()
window.onresize = adapter