代码更新

This commit is contained in:
hrx 2026-02-11 16:12:51 +08:00
parent 93e6267530
commit a3b5a33c16
7 changed files with 557 additions and 149 deletions

View File

@ -19,7 +19,7 @@ const clusterData = {
NVIDIA: 33000, NVIDIA: 33000,
ascend: 5000, ascend: 5000,
supercomputer: 10, supercomputer: 10,
total: 5100 total: 51000
}, },
// 运行中芯片数量 // 运行中芯片数量
@ -107,7 +107,7 @@ const clusterData = {
NVIDIA: 4191, NVIDIA: 4191,
ascend: 635, ascend: 635,
supercomputer: 1, supercomputer: 1,
total: 647 total: Math.floor(51000 * 0.127)
}, },
runningChips: [2147, 1911.35, 2062, 2726, 2405, 2406, 2216], runningChips: [2147, 1911.35, 2062, 2726, 2405, 2406, 2216],
@ -186,7 +186,7 @@ const clusterData = {
NVIDIA: Math.floor(33000 * 0.294), NVIDIA: Math.floor(33000 * 0.294),
ascend: Math.floor(5000 * 0.294), ascend: Math.floor(5000 * 0.294),
supercomputer: 3, supercomputer: 3,
total: Math.floor(5100 * 0.294) total: Math.floor(51000 * 0.294)
}, },
runningChips: [16909, 15050, 16240, 21470, 18940, 18950, 17450].map(num => Math.floor(num * 0.294)), runningChips: [16909, 15050, 16240, 21470, 18940, 18950, 17450].map(num => Math.floor(num * 0.294)),
@ -265,7 +265,7 @@ const clusterData = {
NVIDIA: Math.floor(33000 * 0.156), NVIDIA: Math.floor(33000 * 0.156),
ascend: Math.floor(5000 * 0.156), ascend: Math.floor(5000 * 0.156),
supercomputer: 1, supercomputer: 1,
total: Math.floor(5100 * 0.156) total: Math.floor(51000 * 0.156)
}, },
runningChips: [16909, 15050, 16240, 21470, 18940, 18950, 17450].map(num => Math.floor(num * 0.156)), runningChips: [16909, 15050, 16240, 21470, 18940, 18950, 17450].map(num => Math.floor(num * 0.156)),
@ -345,7 +345,7 @@ const clusterData = {
NVIDIA: Math.floor(33000 * 0.098), NVIDIA: Math.floor(33000 * 0.098),
ascend: Math.floor(5000 * 0.098), ascend: Math.floor(5000 * 0.098),
supercomputer: 1, supercomputer: 1,
total: Math.floor(5100 * 0.098) total: Math.floor(51000 * 0.098)
}, },
runningChips: [16909, 15050, 16240, 21470, 18940, 18950, 17450].map(num => Math.floor(num * 0.098)), runningChips: [16909, 15050, 16240, 21470, 18940, 18950, 17450].map(num => Math.floor(num * 0.098)),
@ -425,7 +425,7 @@ const clusterData = {
NVIDIA: Math.floor(33000 * 0.117), NVIDIA: Math.floor(33000 * 0.117),
ascend: Math.floor(5000 * 0.117), ascend: Math.floor(5000 * 0.117),
supercomputer:1, supercomputer:1,
total: Math.floor(5100 * 0.117) total: Math.floor(51000 * 0.117)
}, },
runningChips: [16909, 15050, 16240, 21470, 18940, 18950, 17450].map(num => Math.floor(num * 0.117)), runningChips: [16909, 15050, 16240, 21470, 18940, 18950, 17450].map(num => Math.floor(num * 0.117)),
@ -505,7 +505,7 @@ const clusterData = {
NVIDIA: Math.floor(33000 * 0.156), NVIDIA: Math.floor(33000 * 0.156),
ascend: Math.floor(5000 * 0.156), ascend: Math.floor(5000 * 0.156),
supercomputer:1, supercomputer:1,
total: Math.floor(5100 * 0.156) total: Math.floor(51000 * 0.156)
}, },
runningChips: [16909, 15050, 16240, 21470, 18940, 18950, 17450].map(num => Math.floor(num * 0.156)), runningChips: [16909, 15050, 16240, 21470, 18940, 18950, 17450].map(num => Math.floor(num * 0.156)),

View File

@ -253,12 +253,12 @@ export default Vue.extend({
}, },
// ncmatch.cn // ncmatch.cn
isNcmatchDomain() { isNcmatchDomain() {
return window.location.hostname.includes('www.ncmatch.cn'); return window.location.hostname.includes('www. atch.cn');
}, },
// //
isActiveHome() { isActiveHome() {
if (this.isNcmatchDomain) { if (this.isNcmatchDomain) {
return this.$route.path.includes('/ncmatchHome/index'); return this.$route.path.includes('/ncmatchHo index');
} else { } else {
return this.$route.path.includes('/homePage/index'); return this.$route.path.includes('/homePage/index');
} }

View File

@ -3,48 +3,63 @@
<div class="left"> <div class="left">
<!-- 第1行2个横向模块 --> <!-- 第1行2个横向模块 -->
<div class="row row-1"> <div class="row row-1">
<!-- 异构芯片规模模块 -->
<div class="cluster data-section" :style="{ animationDelay: '0.2s' }"> <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">
<!-- NVIDIA芯片数据单位PPetaFLOPS -->
<div class="top-tit one data-item" :style="{ animationDelay: '0.3s' }">{{ chipData.NVIDIA }}<span>P</span></div> <div class="top-tit one data-item" :style="{ animationDelay: '0.3s' }">{{ chipData.NVIDIA }}<span>P</span></div>
<!-- 昇腾芯片数据单位PPetaFLOPS -->
<div class="top-tit two data-item" :style="{ animationDelay: '0.4s' }">{{ chipData.ascend }}<span>P</span></div> <div class="top-tit two data-item" :style="{ animationDelay: '0.4s' }">{{ chipData.ascend }}<span>P</span></div>
<!-- 传统超算芯片数据单位PPetaFLOPS -->
<div class="top-tit three data-item" :style="{ animationDelay: '0.5s' }">{{ 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="芯片3D示意图">
</div> </div>
<div class="conter-bottom"> <div class="conter-bottom">
<div class="bottom-tit data-item" :style="{ animationDelay: '0.6s' }">NVIDIA</div> <div class="bottom-tit data-item" :style="{ animationDelay: '0.6s' }">NVIDIA</div>
<div class="bottom-tit data-item" :style="{ animationDelay: '0.7s' }"></div> <div class="bottom-tit data-item" :style="{ animationDelay: '0.7s' }"></div>
<div class="bottom-tit data-item" :style="{ animationDelay: '0.8s' }">传统超算</div> <div class="bottom-tit data-item" :style="{ animationDelay: '0.8s' }">传统超算</div>
</div> </div>
</div> </div>
</div> </div>
<!-- 集群规模模块 -->
<div class="heterogeneous data-section" :style="{ animationDelay: '0.9s' }"> <div class="heterogeneous data-section" :style="{ animationDelay: '0.9s' }">
<div class="title">集群规模</div> <div class="title">集群规模</div>
<div class="content"> <div class="content">
<!-- 集群总规模单位PPetaFLOPS -->
<dv-decoration-9 class="data-item" :style="{ animationDelay: '1s' }" style="width:2rem;height:2rem;color: #fff;font-size: .2rem; font-weight: 600;"> <dv-decoration-9 class="data-item" :style="{ animationDelay: '1s' }" style="width:2rem;height:2rem;color: #fff;font-size: .2rem; font-weight: 600;">
{{ chipData.total }}P {{ chipData.total }}P
</dv-decoration-9> </dv-decoration-9>
</div> </div>
</div> </div>
</div> </div>
<!-- 第2行通栏模块运行中芯片数量 --> <!-- 第2行通栏模块运行中芯片数量 -->
<div class="row row-2"> <div class="row row-2">
<div class="running data-section" :style="{ animationDelay: '0.9s' }"> <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 data-section" :style="{ animationDelay: '0.9s' }">模型调用量</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>
<!-- token调用量模块 -->
<div class="token data-section" :style="{ animationDelay: '0.9s' }"> <div class="token data-section" :style="{ animationDelay: '0.9s' }">
<div class="title">token调用量</div> <div class="title">token调用量</div>
<!-- token调用量图表容器 -->
<div ref="tokenChart" class="chart-container token-chart"></div> <div ref="tokenChart" class="chart-container token-chart"></div>
</div> </div>
</div> </div>
@ -60,33 +75,39 @@ export default {
name: 'LeftPanel', name: 'LeftPanel',
data() { data() {
return { return {
runningChartInstance: null, runningChartInstance: null, //
modelChartInstance: null, modelChartInstance: null, //
tokenChartInstance: null, tokenChartInstance: null, // token
resizeTimer: null, resizeTimer: null, //
currentData: null, currentData: null, //
chipData: { chipData: { //
NVIDIA: 0, NVIDIA: 0, // NVIDIAP
ascend: 0, ascend: 0, // P
supercomputer: 0, supercomputer: 0,// P
total: 0 total: 0 // P
}, },
animationKey: 0 animationKey: 0 // key
}; };
}, },
created() { created() {
//
this.currentData = dataManager.getData(); this.currentData = dataManager.getData();
this.updateChipData(); this.updateChipData();
//
dataManager.eventBus.$on('cluster-changed', this.handleClusterChanged); dataManager.eventBus.$on('cluster-changed', this.handleClusterChanged);
}, },
mounted() { mounted() {
//
this.initRunningChart(); this.initRunningChart();
this.initModelChart(); this.initModelChart();
this.initTokenChart(); this.initTokenChart();
//
window.addEventListener('resize', this.handleResize); window.addEventListener('resize', this.handleResize);
}, },
beforeDestroy() { beforeDestroy() {
//
this.runningChartInstance?.dispose(); this.runningChartInstance?.dispose();
this.modelChartInstance?.dispose(); this.modelChartInstance?.dispose();
this.tokenChartInstance?.dispose(); this.tokenChartInstance?.dispose();
@ -94,13 +115,16 @@ export default {
dataManager.eventBus.$off('cluster-changed', this.handleClusterChanged); dataManager.eventBus.$off('cluster-changed', this.handleClusterChanged);
}, },
methods: { methods: {
//
handleClusterChanged(event) { handleClusterChanged(event) {
//
this.currentData = event.data; this.currentData = event.data;
this.updateChipData(); this.updateChipData();
// key
// key
this.animationKey += 1; this.animationKey += 1;
// //
this.$nextTick(() => { this.$nextTick(() => {
this.initRunningChart(); this.initRunningChart();
this.initModelChart(); this.initModelChart();
@ -108,17 +132,20 @@ export default {
}); });
}, },
//
updateChipData() { updateChipData() {
if (this.currentData?.left?.chipScale) { if (this.currentData?.left?.chipScale) {
//
this.chipData = { this.chipData = {
NVIDIA: this.currentData.left.chipScale.NVIDIA || 0, NVIDIA: this.currentData.left.chipScale.NVIDIA || 0, // NVIDIA
ascend: this.currentData.left.chipScale.ascend || 0, ascend: this.currentData.left.chipScale.ascend || 0, //
supercomputer: this.currentData.left.chipScale.supercomputer || 0, supercomputer: this.currentData.left.chipScale.supercomputer || 0, //
total: this.currentData.left.chipScale.total || 0 total: this.currentData.left.chipScale.total || 0 //
}; };
} }
}, },
//
initRunningChart() { initRunningChart() {
const chartDom = this.$refs.runningChart; const chartDom = this.$refs.runningChart;
if (!chartDom) return; if (!chartDom) return;
@ -126,17 +153,38 @@ export default {
this.updateRunningChart(); this.updateRunningChart();
}, },
//
updateRunningChart() { updateRunningChart() {
if (!this.runningChartInstance || !this.currentData?.left) return; if (!this.runningChartInstance || !this.currentData?.left) return;
//
const yData = this.currentData.left.runningChips || []; const yData = this.currentData.left.runningChips || [];
// 121-127
const xData = ['12/01', '12/02', '12/03', '12/04', '12/05', '12/06', '12/07']; const xData = ['12/01', '12/02', '12/03', '12/04', '12/05', '12/06', '12/07'];
// Y
const maxValue = Math.max(...yData); const maxValue = Math.max(...yData);
const minValue = Math.min(...yData); const minValue = Math.min(...yData);
const yMax = Math.ceil(maxValue / 1000) * 1000 + 1000;
const yMin = Math.floor(minValue / 1000) * 1000 - 1000;
// k
const maxValueInK = maxValue / 1000;
// Y
let yMax, interval;
if (maxValueInK >= 10) {
// 10k使10k
yMax = Math.ceil(maxValueInK / 10) * 10 * 1000; // 10
interval = 10 * 1000; // 10k
} else {
// 10k使1k
yMax = Math.ceil(maxValueInK) * 1000; //
interval = 1000; // 1k
}
// Y0
const yMin = 0;
//
const maxIndex = yData.indexOf(maxValue); const maxIndex = yData.indexOf(maxValue);
const markPointData = yData.map((value, index) => { const markPointData = yData.map((value, index) => {
if (index === maxIndex) { if (index === maxIndex) {
@ -152,7 +200,8 @@ export default {
show: true, show: true,
position: 'top', position: 'top',
formatter: function (params) { formatter: function (params) {
return (params.value / 10000).toFixed(1) + '万'; // 1
return (params.value / 1000).toFixed(1) + 'k(P)';
}, },
color: '#fff', color: '#fff',
fontWeight: 'bold', fontWeight: 'bold',
@ -171,9 +220,10 @@ export default {
textStyle: { color: '#fff' }, textStyle: { color: '#fff' },
formatter: function (params) { formatter: function (params) {
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 / 1000).toFixed(1) + 'k个';
} }
}, },
grid: { grid: {
@ -196,9 +246,9 @@ export default {
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
min: yMin, min: yMin, // 0
max: yMax, max: yMax,
splitNumber: 6, interval: interval, //
splitLine: { splitLine: {
lineStyle: { lineStyle: {
color: 'rgba(255,255,255,0.1)', color: 'rgba(255,255,255,0.1)',
@ -209,7 +259,8 @@ export default {
color: 'rgba(255,255,255,0.7)', color: 'rgba(255,255,255,0.7)',
fontSize: 12, fontSize: 12,
formatter: function (value) { formatter: function (value) {
return (value / 10000).toFixed(1) + '万'; // Y
return (value / 1000) + 'k';
} }
}, },
axisLine: { lineStyle: { color: 'rgba(255,255,255,0.3)' } }, axisLine: { lineStyle: { color: 'rgba(255,255,255,0.3)' } },
@ -250,6 +301,7 @@ export default {
this.runningChartInstance.setOption(option, true); this.runningChartInstance.setOption(option, true);
}, },
//
initModelChart() { initModelChart() {
const chartDom = this.$refs.modelChart; const chartDom = this.$refs.modelChart;
if (!chartDom) return; if (!chartDom) return;
@ -257,13 +309,18 @@ export default {
this.updateModelChart(); this.updateModelChart();
}, },
//
updateModelChart() { updateModelChart() {
if (!this.modelChartInstance || !this.currentData?.left) return; if (!this.modelChartInstance || !this.currentData?.left) return;
// [{name: '', value: }, ...]
const modelData = this.currentData.left.modelUsage || []; const modelData = this.currentData.left.modelUsage || [];
// Y
const yData = modelData.map(item => item.name); const yData = modelData.map(item => item.name);
// X
const xData = modelData.map(item => item.value); const xData = modelData.map(item => item.value);
// X
const maxValue = Math.max(...xData); const maxValue = Math.max(...xData);
const xMax = Math.ceil(maxValue / 50) * 50 + 10; const xMax = Math.ceil(maxValue / 50) * 50 + 10;
@ -273,6 +330,7 @@ export default {
backgroundColor: 'rgba(0,0,0,0.85)', backgroundColor: 'rgba(0,0,0,0.85)',
borderColor: '#50e3c2', borderColor: '#50e3c2',
formatter: function (params) { formatter: function (params) {
//
return params[0].name + ': ' + params[0].value; return params[0].name + ': ' + params[0].value;
} }
}, },
@ -362,6 +420,7 @@ export default {
this.modelChartInstance.setOption(option, true); this.modelChartInstance.setOption(option, true);
}, },
// token
initTokenChart() { initTokenChart() {
const chartDom = this.$refs.tokenChart; const chartDom = this.$refs.tokenChart;
if (!chartDom) return; if (!chartDom) return;
@ -369,13 +428,18 @@ export default {
this.updateTokenChart(); this.updateTokenChart();
}, },
// token
updateTokenChart() { updateTokenChart() {
if (!this.tokenChartInstance || !this.currentData?.left) return; if (!this.tokenChartInstance || !this.currentData?.left) return;
// token[{name: '', value: token}, ...]valueM
const tokenData = this.currentData.left.tokenUsage || []; const tokenData = this.currentData.left.tokenUsage || [];
// X
const xData = tokenData.map(item => item.name); const xData = tokenData.map(item => item.name);
// Ytoken
const yData = tokenData.map(item => item.value); const yData = tokenData.map(item => item.value);
// Y
const maxValue = Math.max(...yData); const maxValue = Math.max(...yData);
const yMax = Math.ceil(maxValue / 1000) * 1000 + 500; const yMax = Math.ceil(maxValue / 1000) * 1000 + 500;
@ -385,6 +449,7 @@ export default {
backgroundColor: 'rgba(0,0,0,0.85)', backgroundColor: 'rgba(0,0,0,0.85)',
borderColor: '#1890ff', borderColor: '#1890ff',
formatter: function (params) { formatter: function (params) {
// token
return params[0].name + '<br/>' + params[0].marker + params[0].seriesName + ': ' + params[0].value + 'M'; return params[0].name + '<br/>' + params[0].marker + params[0].seriesName + ': ' + params[0].value + 'M';
} }
}, },
@ -405,6 +470,7 @@ export default {
interval: 0, interval: 0,
margin: 10, margin: 10,
formatter: function (value) { formatter: function (value) {
//
if (value.length > 8) { if (value.length > 8) {
return value.substring(0, 8) + '...'; return value.substring(0, 8) + '...';
} }
@ -488,8 +554,10 @@ export default {
this.tokenChartInstance.setOption(option, true); this.tokenChartInstance.setOption(option, true);
}, },
//
handleResize() { handleResize() {
clearTimeout(this.resizeTimer); clearTimeout(this.resizeTimer);
// 200ms
this.resizeTimer = setTimeout(() => { this.resizeTimer = setTimeout(() => {
this.runningChartInstance?.resize(); this.runningChartInstance?.resize();
this.modelChartInstance?.resize(); this.modelChartInstance?.resize();
@ -497,7 +565,7 @@ export default {
}, 200); }, 200);
}, },
// updateCharts //
updateCharts() { updateCharts() {
console.log('updateCharts called in LeftPanel'); console.log('updateCharts called in LeftPanel');
this.updateRunningChart(); this.updateRunningChart();
@ -517,7 +585,6 @@ export default {
gap: .15rem; gap: .15rem;
padding: .1rem 0; padding: .1rem 0;
box-sizing: border-box; box-sizing: border-box;
} }
.conter { .conter {
@ -527,26 +594,27 @@ export default {
.conter-top { .conter-top {
width: 100%; width: 100%;
position: absolute; position: absolute;
display: flex; display: flex;
.one{ .one{
position: absolute; position: absolute;
left: .24rem; left: .24rem;
top: .24rem; top: .24rem;
} }
.two{ .two{
position: absolute; position: absolute;
left: 1.1rem; left: 1.1rem;
top: .24rem; top: .24rem;
} }
.three{ .three{
position: absolute; position: absolute;
left: 1.9rem; left: 1.9rem;
top: .24rem; top: .24rem;
} }
.top-tit {
.top-tit {
span { span {
margin-left: 2px; margin-left: 2px;
} }
@ -644,12 +712,13 @@ export default {
box-sizing: border-box; box-sizing: border-box;
} }
// //
.model-chart { .model-chart {
height: calc(100% - 46px); height: calc(100% - 46px);
width: 2.4rem; width: 2.4rem;
} }
// token
.token-chart { .token-chart {
width: 4.2rem; width: 4.2rem;
} }
@ -663,7 +732,6 @@ export default {
/* 调整第3行的高度比例 */ /* 调整第3行的高度比例 */
.row-3 { .row-3 {
.model, .model,
.token { .token {
.chart-container { .chart-container {

View File

@ -3,16 +3,16 @@
<div class="right"> <div class="right">
<!-- 1 --> <!-- 1 -->
<div class="row row-1"> <div class="row row-1">
<!-- 应用类型 --> <!-- 应用类型模块 -->
<div class="app-class data-section" :style="{ animationDelay: '0.2s' }"> <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 data-item" :style="{ animationDelay: '0.3s' }"> <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 --> <!-- 周围TOP2-TOP5应用 -->
<div class="circle-item item-top2 data-item" :style="{ animationDelay: '0.4s' }"> <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>
@ -31,7 +31,7 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 用户种类 --> <!-- 用户种类模块 -->
<div class="user-class data-section" :style="{ animationDelay: '0.8s' }"> <div class="user-class data-section" :style="{ animationDelay: '0.8s' }">
<div class="title">用户种类</div> <div class="title">用户种类</div>
<div class="content"> <div class="content">
@ -49,25 +49,37 @@
<!-- 2 --> <!-- 2 -->
<div class="row row-2"> <div class="row row-2">
<!-- 用户数量 --> <!-- 用户数量模块 -->
<div class="user-num data-section" :style="{ animationDelay: '1.4s' }"> <div class="user-num data-section" :style="{ animationDelay: '1.4s' }">
<div class="title">用户数量</div> <div class="title">用户数量</div>
<div class="content"> <div class="num-content">
<div class="num-left">
<!-- Y轴刻度 -->
<div class="y-axis">
<div class="y-tick" v-for="(tick, index) in yTicks" :key="index">{{ tick }}</div>
</div>
</div>
<div class="num-right">
<img src="../images/use-num.png" alt=""> <img src="../images/use-num.png" alt="">
<!-- X轴标签 -->
<div class="x-axis">
<div class="x-tick" v-for="(tick, index) in xTicks" :key="index">{{ tick }}</div>
</div> </div>
</div> </div>
<!-- 用户消费排行 --> </div>
</div>
<!-- 用户消费排行模块 -->
<div class="user-consume data-section" :style="{ animationDelay: '1.5s' }"> <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%" />
</div> </div>
</div> </div>
</div> </div>
<!-- 3 --> <!-- 3 算力使用情况模块 -->
<div class="row row-3"> <div class="row row-3">
<!-- 算力使用情况双折线图无背景色 -->
<div class="power-use data-section" :style="{ animationDelay: '1.6s' }"> <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 data-item" :style="{ animationDelay: '1.7s' }"></div> <div ref="powerUseChart" class="power-use-chart data-item" :style="{ animationDelay: '1.7s' }"></div>
@ -95,36 +107,47 @@ export default {
name: 'RightPanel', name: 'RightPanel',
data() { data() {
return { return {
// X
xTicks: ['7月','8月','9月','10月', '11月', '12月'],
// Y
yTicks: ['100', '80', '60', '40', '20', '0'],
scrollBoardConfig: { scrollBoardConfig: {
data: [], data: [], //
index: false, index: false, //
columnWidth: [50, 100, 90], columnWidth: [50, 100, 90], //
rowHeight: 28, rowHeight: 28, //
align: ['center', 'center', 'center'], align: ['center', 'center', 'center'], //
rowNum: 5, rowNum: 5, //
oddRowBGC: '#040c45', oddRowBGC: '#040c45', //
evenRowBGC: '#17264f', evenRowBGC: '#17264f', //
waitTime: 1500, // waitTime: 1500, //
carousel: 'single', carousel: 'single', //
hoverPause: false, // hoverPause: false, //
autoPlay: true // autoPlay: true //
}, },
scrollBoardKey: 0, scrollBoardKey: 0, // key
resizeTimer: null, resizeTimer: null, //
powerChart: null, powerChart: null, // 使
currentData: null, userNumChart: null, //
appTypes: ['智能推理', '智能训练', '图形渲染', '蛋白质分析', '其他'], currentData: null, //
animationKey: 0 appTypes: ['智能推理', '智能训练', '图形渲染', '蛋白质分析', '其他'], //
animationKey: 0 // key
}; };
}, },
created() { created() {
//
this.currentData = dataManager.getData(); this.currentData = dataManager.getData();
this.updateDisplay(); this.updateDisplay();
//
dataManager.eventBus.$on('cluster-changed', this.handleClusterChanged); dataManager.eventBus.$on('cluster-changed', this.handleClusterChanged);
}, },
mounted() { mounted() {
// 使
this.initPowerUseChart(); this.initPowerUseChart();
//
this.initUserNumChart();
//
window.addEventListener('resize', this.handleResize); window.addEventListener('resize', this.handleResize);
// //
@ -133,38 +156,55 @@ export default {
}); });
}, },
beforeDestroy() { beforeDestroy() {
//
if (this.$refs.powerUseChart) { if (this.$refs.powerUseChart) {
const chart = echarts.getInstanceByDom(this.$refs.powerUseChart); const chart = echarts.getInstanceByDom(this.$refs.powerUseChart);
if (chart) chart.dispose(); if (chart) chart.dispose();
} }
if (this.$refs.userNumChart) {
const chart = echarts.getInstanceByDom(this.$refs.userNumChart);
if (chart) chart.dispose();
}
window.removeEventListener('resize', this.handleResize); window.removeEventListener('resize', this.handleResize);
dataManager.eventBus.$off('cluster-changed', this.handleClusterChanged); dataManager.eventBus.$off('cluster-changed', this.handleClusterChanged);
}, },
methods: { methods: {
//
handleClusterChanged(event) { handleClusterChanged(event) {
//
this.currentData = event.data; this.currentData = event.data;
// key // key
this.animationKey += 1; this.animationKey += 1;
// //
this.$nextTick(() => { this.$nextTick(() => {
this.initPowerUseChart(); this.initPowerUseChart();
this.initUserNumChart();
this.updateDisplay(); this.updateDisplay();
}); });
}, },
//
updateDisplay() { updateDisplay() {
if (!this.currentData) return; if (!this.currentData) return;
//
this.appTypes = this.currentData.right?.appTypes || this.appTypes; this.appTypes = this.currentData.right?.appTypes || this.appTypes;
//
this.updateScrollBoard(); this.updateScrollBoard();
// 使
this.updatePowerChart(); this.updatePowerChart();
//
this.updateUserNumChart();
}, },
//
updateScrollBoard() { updateScrollBoard() {
if (!this.currentData?.right) return; if (!this.currentData?.right) return;
// [{name: '', amount: }, ...]
const userData = this.currentData.right.userConsumption || []; const userData = this.currentData.right.userConsumption || [];
//
const imgMap = { const imgMap = {
1: img1, 1: img1,
2: img2, 2: img2,
@ -176,19 +216,19 @@ export default {
8: img8, 8: img8,
9: img9, 9: img9,
10: img10 10: img10
}; };
// 5 // 5
const tableData = []; const tableData = [];
for (let i = 0; i < Math.max(5, userData.length); i++) { for (let i = 0; i < Math.max(5, userData.length); i++) {
if (userData[i]) { if (userData[i]) {
tableData.push([ tableData.push([
`<div class="rank-img"><img src="${imgMap[i + 1]}" /></div>`, `<div class="rank-img"><img src="${imgMap[i + 1]}" /></div>`, //
userData[i].name, userData[i].name, //
`¥${userData[i].amount.toLocaleString()}` `¥${userData[i].amount.toLocaleString()}` //
]); ]);
} else { } else {
//
tableData.push([ tableData.push([
`<div class="rank-img"><img src="${imgMap[i + 1]}" /></div>`, `<div class="rank-img"><img src="${imgMap[i + 1]}" /></div>`,
`用户${i + 1}`, `用户${i + 1}`,
@ -205,7 +245,6 @@ export default {
// //
this.scrollBoardConfig = newConfig; this.scrollBoardConfig = newConfig;
// //
this.scrollBoardKey += 1; this.scrollBoardKey += 1;
@ -215,10 +254,10 @@ export default {
}); });
}, },
// //
startScrollBoard() { startScrollBoard() {
if (this.$refs.scrollBoardRef && this.$refs.scrollBoardRef.startRoll) { if (this.$refs.scrollBoardRef && this.$refs.scrollBoardRef.startRoll) {
// startRoll // startRoll
this.$refs.scrollBoardRef.startRoll(); this.$refs.scrollBoardRef.startRoll();
} }
@ -231,6 +270,7 @@ export default {
} }
}, },
// 使
initPowerUseChart() { initPowerUseChart() {
const chartDom = this.$refs.powerUseChart; const chartDom = this.$refs.powerUseChart;
if (!chartDom) return; if (!chartDom) return;
@ -238,17 +278,35 @@ export default {
this.updatePowerChart(); this.updatePowerChart();
}, },
// 使
updatePowerChart() { updatePowerChart() {
if (!this.powerChart || !this.currentData?.right) return; if (!this.powerChart || !this.currentData?.right) return;
// 使p
const powerData = this.currentData.right.powerUsage || []; const powerData = this.currentData.right.powerUsage || [];
// 121-127
const dates = ['12/01', '12/02', '12/03', '12/04', '12/05', '12/06', '12/07']; const dates = ['12/01', '12/02', '12/03', '12/04', '12/05', '12/06', '12/07'];
//
const maxValue = Math.max(...powerData); const maxValue = Math.max(...powerData);
const minValue = Math.min(...powerData); const maxValueInK = maxValue / 1000;
const yMax = Math.ceil(maxValue / 1000) * 1000 + 1000;
const yMin = Math.floor(minValue / 1000) * 1000 - 1000;
// Y
let yMax, interval;
if (maxValueInK >= 10) {
// 10k使10k
yMax = Math.ceil(maxValueInK / 10) * 10 * 1000;
interval = 10 * 1000; // 10k
} else {
// 10k使1k
yMax = Math.ceil(maxValueInK) * 1000; //
interval = 1000; // 1k
}
// Y0
const yMin = 0;
//
const maxIndex = powerData.indexOf(maxValue); const maxIndex = powerData.indexOf(maxValue);
const markPointData = powerData.map((value, index) => { const markPointData = powerData.map((value, index) => {
if (index === maxIndex) { if (index === maxIndex) {
@ -264,7 +322,8 @@ export default {
show: true, show: true,
position: 'top', position: 'top',
formatter: function (params) { formatter: function (params) {
return (params.value / 10000).toFixed(1) + '万p'; // 1
return (params.value / 1000).toFixed(1) + 'k(P)';
}, },
color: '#fff', color: '#fff',
fontWeight: 'bold', fontWeight: 'bold',
@ -284,9 +343,10 @@ export default {
textStyle: { color: '#fff' }, textStyle: { color: '#fff' },
formatter: function (params) { formatter: function (params) {
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() + 'p'; (value / 1000).toFixed(1) + 'k';
} }
}, },
grid: { grid: {
@ -309,9 +369,9 @@ export default {
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
min: yMin, min: yMin, // 0
max: yMax, max: yMax,
splitNumber: 6, interval: interval, //
splitLine: { splitLine: {
lineStyle: { lineStyle: {
color: 'rgba(255,255,255,0.1)', color: 'rgba(255,255,255,0.1)',
@ -322,7 +382,8 @@ export default {
color: 'rgba(255,255,255,0.7)', color: 'rgba(255,255,255,0.7)',
fontSize: 12, fontSize: 12,
formatter: function (value) { formatter: function (value) {
return (value / 10000).toFixed(1) + '万'; // Y
return (value / 1000) + 'k';
} }
}, },
axisLine: { lineStyle: { color: 'rgba(255,255,255,0.3)' } }, axisLine: { lineStyle: { color: 'rgba(255,255,255,0.3)' } },
@ -362,13 +423,135 @@ export default {
this.powerChart.setOption(option, true); this.powerChart.setOption(option, true);
}, },
//
initUserNumChart() {
const chartDom = this.$refs.userNumChart;
if (!chartDom) return;
this.userNumChart = echarts.init(chartDom);
this.updateUserNumChart();
},
//
updateUserNumChart() {
if (!this.userNumChart) return;
// 使
const userNumData = this.currentData?.right?.userNum || [12, 38, 55, 72, 85, 63, 47, 29];
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
backgroundColor: 'rgba(0,0,0,0.85)',
borderColor: '#1890ff',
textStyle: { color: '#fff' },
formatter: function (params) {
const value = params[0].value;
return params[0].name + '<br/>' +
params[0].marker + '用户数量: ' + value;
}
},
grid: {
left: '0%',
right: '0%',
top: '10%',
bottom: '15%',
containLabel: true
},
xAxis: {
type: 'category',
data: this.xTicks,
axisLabel: {
color: 'rgba(255,255,255,0.7)',
fontSize: 12,
interval: 0
},
axisLine: {
lineStyle: {
color: 'rgba(255,255,255,0.3)',
width: 2
}
},
axisTick: {
show: true,
alignWithLabel: true,
lineStyle: {
color: 'rgba(255,255,255,0.5)'
}
}
},
yAxis: {
type: 'value',
min: 0,
max: 100,
interval: 20,
splitLine: {
lineStyle: {
color: 'rgba(255,255,255,0.1)',
type: 'dashed'
}
},
axisLabel: {
color: 'rgba(255,255,255,0.7)',
fontSize: 12
},
axisLine: {
lineStyle: {
color: 'rgba(255,255,255,0.3)',
width: 2
}
},
axisTick: {
show: true,
lineStyle: {
color: 'rgba(255,255,255,0.5)'
}
}
},
series: [
{
name: '用户数量',
type: 'bar',
barWidth: '40%',
data: userNumData,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#1890ff' },
{ offset: 1, color: '#005CCF' }
]),
borderRadius: [4, 4, 0, 0]
},
emphasis: {
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#40a9ff' },
{ offset: 1, color: '#096dd9' }
])
}
}
}
]
};
this.userNumChart.setOption(option, true);
},
//
handleResize() { handleResize() {
clearTimeout(this.resizeTimer); clearTimeout(this.resizeTimer);
// 200ms
this.resizeTimer = setTimeout(() => { this.resizeTimer = setTimeout(() => {
if (this.$refs.powerUseChart) { if (this.$refs.powerUseChart) {
const chart = echarts.getInstanceByDom(this.$refs.powerUseChart); const chart = echarts.getInstanceByDom(this.$refs.powerUseChart);
if (chart) chart.resize(); if (chart) chart.resize();
} }
if (this.$refs.userNumChart) {
const chart = echarts.getInstanceByDom(this.$refs.userNumChart);
if (chart) chart.resize();
}
}, 200); }, 200);
} }
} }
@ -376,6 +559,7 @@ export default {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
/* 用户消费排行表格中的排名图片样式 */
.user-consume { .user-consume {
/deep/ .rank-img { /deep/ .rank-img {
display: flex; display: flex;
@ -411,7 +595,11 @@ export default {
box-sizing: border-box; box-sizing: border-box;
} }
.app-class, .user-class, .user-num, .user-consume { /* 各模块宽度适配 */
.app-class,
.user-class,
.user-num,
.user-consume {
width: 46%; width: 46%;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
@ -423,30 +611,89 @@ export default {
} }
/* 用户数量模块样式调整 */ /* 用户数量模块样式调整 */
.user-num .content { .user-num .num-content {
width: 100%; width: 100%;
height: calc(100% - 50px); height: calc(100% - 50px);
display: flex; display: flex;
justify-content: center; color: #fff;
align-items: center; /* 垂直居中 */ font-size: .14rem;
overflow: hidden; padding: .1rem;
padding: .05rem; /* 添加内边距 */ box-sizing: border-box;
margin-top: -0.4rem; position: relative;
} }
.user-num .content img { .user-num-chart {
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: contain; /* 保持图片比例 */ min-height: 180px;
object-position: center center; /* 图片中心对齐 */
} }
.num-left {
width: 10%;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 20px 0;
box-sizing: border-box;
z-index: 1;
}
.y-axis {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
text-align: right;
padding-right: 10px;
}
.y-tick {
color: rgba(255,255,255,0.7);
font-size: .16rem;
line-height: 1;
}
.num-right {
width: 90%;
height: 100%;
display: flex;
flex-direction: column;
position: relative;
}
.num-right img {
position: absolute;
top: 4px;
left: 0;
width: 100%;
height: calc(100% - 30px);
// object-fit: fill;
}
.x-axis {
display: flex;
justify-content: space-between;
padding-top: 10px;
margin-top: auto;
height: 30px;
align-items: flex-start;
}
.x-tick {
color: rgba(255,255,255,0.7);
font-size: 12px;
flex: 1;
text-align: center;
}
/* 算力使用情况模块 */
.power-use { .power-use {
width: 95%; width: 95%;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
} }
/* 标题样式 */
.title { .title {
background: url(../images/titleBg.png) no-repeat; background: url(../images/titleBg.png) no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
@ -464,6 +711,7 @@ export default {
margin-bottom: .1rem; margin-bottom: .1rem;
} }
/* 用户种类模块内容区域 */
.user-class .content { .user-class .content {
width: 100%; width: 100%;
height: calc(100% - 50px); height: calc(100% - 50px);
@ -484,11 +732,16 @@ export default {
align-items: center; align-items: center;
} }
.finance, .medical, .creative, .education, .intelligence { .finance,
.medical,
.creative,
.education,
.intelligence {
padding-top: .12rem; padding-top: .12rem;
} }
} }
/* 用户消费排行模块内容区域 */
.user-consume .content { .user-consume .content {
width: 100%; width: 100%;
height: calc(100% - 50px); height: calc(100% - 50px);
@ -498,6 +751,7 @@ export default {
padding: 0 .05rem; padding: 0 .05rem;
} }
/* 算力使用情况图表容器 */
.power-use-chart { .power-use-chart {
width: 100%; width: 100%;
height: calc(100% - 50px); height: calc(100% - 50px);
@ -517,7 +771,7 @@ export default {
align-items: center; align-items: center;
} }
/* 中心TOP1样式 */ /* 中心TOP1应用样式 */
.circle-center { .circle-center {
width: 1.2rem; width: 1.2rem;
height: 1.2rem; height: 1.2rem;
@ -545,7 +799,7 @@ export default {
} }
} }
/* 周围TOP基础样式 */ /* 周围TOP2-TOP5应用基础样式 */
.circle-item { .circle-item {
width: .82rem; width: .82rem;
height: .82rem; height: .82rem;
@ -574,105 +828,131 @@ export default {
} }
} }
/* 各TOP定位 */ /* 各TOP应用定位 */
.item-top2 { .item-top2 {
width: .7rem; width: .7rem;
height: .7rem; height: .7rem;
top: .02rem; top: .02rem;
right: .02rem; right: .02rem;
} }
.item-top3 { .item-top3 {
bottom: .02rem; bottom: .02rem;
left: .02rem; left: .02rem;
} }
.item-top4 { .item-top4 {
top: .04rem; top: .04rem;
left: -0.04rem; left: -0.04rem;
} }
.item-top5 { .item-top5 {
bottom: .02rem; bottom: .02rem;
right: -0.02rem; right: -0.02rem;
} }
/* 增强动画效果 - 增加旋转速度 */ /* 动画效果定义 */
@keyframes rotate2 { @keyframes rotate2 {
0%, 100% {
0%,
100% {
transform: translate(0, 0) rotate(0deg); transform: translate(0, 0) rotate(0deg);
} }
25% { 25% {
transform: translate(-5px, -5px) rotate(15deg); transform: translate(-5px, -5px) rotate(15deg);
} }
50% { 50% {
transform: translate(0, 0) rotate(0deg); transform: translate(0, 0) rotate(0deg);
} }
75% { 75% {
transform: translate(5px, 5px) rotate(-15deg); transform: translate(5px, 5px) rotate(-15deg);
} }
} }
@keyframes rotate3 { @keyframes rotate3 {
0%, 100% {
0%,
100% {
transform: translate(0, 0) rotate(0deg); transform: translate(0, 0) rotate(0deg);
} }
25% { 25% {
transform: translate(5px, 5px) rotate(-15deg); transform: translate(5px, 5px) rotate(-15deg);
} }
50% { 50% {
transform: translate(0, 0) rotate(0deg); transform: translate(0, 0) rotate(0deg);
} }
75% { 75% {
transform: translate(-5px, -5px) rotate(15deg); transform: translate(-5px, -5px) rotate(15deg);
} }
} }
@keyframes rotate4 { @keyframes rotate4 {
0%, 100% {
0%,
100% {
transform: translate(0, 0) rotate(0deg); transform: translate(0, 0) rotate(0deg);
} }
25% { 25% {
transform: translate(5px, -5px) rotate(15deg); transform: translate(5px, -5px) rotate(15deg);
} }
50% { 50% {
transform: translate(0, 0) rotate(0deg); transform: translate(0, 0) rotate(0deg);
} }
75% { 75% {
transform: translate(-5px, 5px) rotate(-15deg); transform: translate(-5px, 5px) rotate(-15deg);
} }
} }
@keyframes rotate5 { @keyframes rotate5 {
0%, 100% {
0%,
100% {
transform: translate(0, 0) rotate(0deg); transform: translate(0, 0) rotate(0deg);
} }
25% { 25% {
transform: translate(-5px, 5px) rotate(-15deg); transform: translate(-5px, 5px) rotate(-15deg);
} }
50% { 50% {
transform: translate(0, 0) rotate(0deg); transform: translate(0, 0) rotate(0deg);
} }
75% { 75% {
transform: translate(5px, -5px) rotate(15deg); transform: translate(5px, -5px) rotate(15deg);
} }
} }
/* 为每个小圆添加明显的轨道运动 */ /* 为每个小圆添加轨道运动动画 */
.item-top2 { .item-top2 {
animation: fadeInLeft 0.6s ease-out forwards, rotate2 4s ease-in-out infinite; animation: fadeInLeft 0.6s ease-out forwards, rotate2 4s ease-in-out infinite;
box-shadow: 0 0 12px rgba(72, 176, 255, 0.6); box-shadow: 0 0 12px rgba(72, 176, 255, 0.6);
border: 2px solid rgba(72, 176, 255, 0.8); border: 2px solid rgba(72, 176, 255, 0.8);
} }
.item-top3 { .item-top3 {
animation: fadeInLeft 0.6s ease-out forwards, rotate3 5s ease-in-out infinite; animation: fadeInLeft 0.6s ease-out forwards, rotate3 5s ease-in-out infinite;
animation-delay: 0.5s, 0.5s; animation-delay: 0.5s, 0.5s;
box-shadow: 0 0 12px rgba(72, 176, 255, 0.6); box-shadow: 0 0 12px rgba(72, 176, 255, 0.6);
border: 2px solid rgba(72, 176, 255, 0.8); border: 2px solid rgba(72, 176, 255, 0.8);
} }
.item-top4 { .item-top4 {
animation: fadeInLeft 0.6s ease-out forwards, rotate4 6s ease-in-out infinite; animation: fadeInLeft 0.6s ease-out forwards, rotate4 6s ease-in-out infinite;
animation-delay: 1s, 1s; animation-delay: 1s, 1s;
box-shadow: 0 0 12px rgba(72, 176, 255, 0.6); box-shadow: 0 0 12px rgba(72, 176, 255, 0.6);
border: 2px solid rgba(72, 176, 255, 0.8); border: 2px solid rgba(72, 176, 255, 0.8);
} }
.item-top5 { .item-top5 {
animation: fadeInLeft 0.6s ease-out forwards, rotate5 7s ease-in-out infinite; animation: fadeInLeft 0.6s ease-out forwards, rotate5 7s ease-in-out infinite;
animation-delay: 1.5s, 1.5s; animation-delay: 1.5s, 1.5s;
@ -680,14 +960,17 @@ export default {
border: 2px solid rgba(72, 176, 255, 0.8); border: 2px solid rgba(72, 176, 255, 0.8);
} }
/* 增强中心圆的光效 */ /* 中心圆的光效动画 */
@keyframes centerGlow { @keyframes centerGlow {
0%, 100% {
0%,
100% {
box-shadow: box-shadow:
0 0 20px rgba(72, 176, 255, 0.8), 0 0 20px rgba(72, 176, 255, 0.8),
inset 0 0 25px rgba(72, 176, 255, 0.3); inset 0 0 25px rgba(72, 176, 255, 0.3);
transform: scale(1); transform: scale(1);
} }
50% { 50% {
box-shadow: box-shadow:
0 0 30px rgba(72, 176, 255, 1), 0 0 30px rgba(72, 176, 255, 1),
@ -722,7 +1005,7 @@ export default {
transition: all 0.3s ease; transition: all 0.3s ease;
} }
/* 为整个内容区域添加一个微妙的背景光晕(无脉动效果) */ /* 为整个内容区域添加微妙的背景光晕 */
.app-class .content::before { .app-class .content::before {
content: ''; content: '';
position: absolute; position: absolute;
@ -730,13 +1013,11 @@ export default {
left: 50%; left: 50%;
width: 2.8rem; width: 2.8rem;
height: 2.8rem; height: 2.8rem;
background: radial-gradient( background: radial-gradient(circle at center,
circle at center,
rgba(72, 176, 255, 0.12) 0%, rgba(72, 176, 255, 0.12) 0%,
rgba(0, 92, 207, 0.06) 40%, rgba(0, 92, 207, 0.06) 40%,
rgba(0, 92, 207, 0.02) 70%, rgba(0, 92, 207, 0.02) 70%,
transparent 90% transparent 90%);
);
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
z-index: 0; z-index: 0;
} }
@ -765,6 +1046,7 @@ export default {
opacity: 0; opacity: 0;
transform: translateX(-20px); transform: translateX(-20px);
} }
100% { 100% {
opacity: 1; opacity: 1;
transform: translateX(0); transform: translateX(0);

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -1,32 +1,90 @@
<template> <template>
<div id="zptime"> <div class="time-display">
{{setDate}} <span class="date-part">{{ dateStr }}</span>
<span class="time-part">{{ timeStr }}</span>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name:'zptime', name: 'ZpTime',
data() { data() {
return { return {
date: new Date(), date: new Date(),
timer: null // 便
} }
}, },
computed: { computed: {
setDate(){ //
return `当前时间: ${this.date.getFullYear()}${this.date.getMonth()+1}${this.date.getDate()}-${this.date.getHours()}${this.date.getMinutes()}${this.date.getSeconds()}` dateStr() {
return `当前日期:${this.date.getFullYear()}${this.padZero(this.date.getMonth() + 1)}${this.padZero(this.date.getDate())}`
},
//
timeStr() {
return `${this.padZero(this.date.getHours())}:${this.padZero(this.date.getMinutes())}:${this.padZero(this.date.getSeconds())}`
}
},
methods: {
// 9 09
padZero(num) {
return num.toString().padStart(2, '0')
},
//
updateTime() {
this.date = new Date()
} }
}, },
mounted() { mounted() {
setInterval(()=>{this.date = new Date()}, 1000); //
this.timer = setInterval(this.updateTime, 1000)
}, },
beforeUnmount() {
//
clearInterval(this.timer)
}
} }
</script> </script>
<style scoped> <style scoped>
#zptime{ .time-display {
/* 基础布局 */
display: flex;
align-items: center;
gap: 12px; /* 日期和时间之间的间距(替代硬编码空格) */
line-height: 75px; line-height: 75px;
color: rgba(255, 255, 255, 0.7); padding: 0 16px; /* 增加内边距,避免文字贴边 */
font-size: 20px;
/* 字体样式 */
font-size: 0.24rem; /* 增大字体,提升可读性 */
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
/* font-weight: 400; */
/* 颜色与背景(可选,根据你的页面调整) */
color: rgba(255, 255, 255, 0.9); /* 提高文字不透明度,更清晰 */
/*
background-color: rgba(0, 0, 0, 0.1);
border-radius: 8px;
*/
}
/* 日期部分样式 */
.date-part {
color: rgba(255, 255, 255, 0.9);
font-weight: 500; /* 轻微加粗,区分日期和时间 */
}
/* 时间部分样式 */
.time-part {
color: rgba(255, 255, 255, 0.8);
font-weight: 400;
letter-spacing: 1px; /* 时间数字间增加少量间距,更易读 */
}
/* 响应式适配(可选) */
@media (max-width: 768px) {
.time-display {
font-size: 0.24rem;
gap: 8px;
}
} }
</style> </style>