代码更新
This commit is contained in:
parent
93e6267530
commit
a3b5a33c16
@ -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)),
|
||||||
|
|||||||
@ -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');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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芯片数据,单位:P(PetaFLOPS) -->
|
||||||
<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>
|
||||||
|
<!-- 昇腾芯片数据,单位:P(PetaFLOPS) -->
|
||||||
<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>
|
||||||
|
<!-- 传统超算芯片数据,单位:P(PetaFLOPS) -->
|
||||||
<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">
|
||||||
|
<!-- 集群总规模,单位:P(PetaFLOPS) -->
|
||||||
<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, // NVIDIA芯片规模,单位:P
|
||||||
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 || [];
|
||||||
|
// 日期数据(12月1日-12月7日)
|
||||||
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间隔
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保Y轴最小值从0开始
|
||||||
|
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数量}, ...],value单位:M(百万)
|
||||||
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);
|
||||||
|
// Y轴:token数量(百万)
|
||||||
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 {
|
||||||
|
|||||||
@ -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 || [];
|
||||||
|
// 日期数据(12月1日-12月7日)
|
||||||
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间隔
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保Y轴最小值从0开始
|
||||||
|
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 |
@ -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>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user