Bonus-AI-LargeScreen/src/views/home.vue

431 lines
13 KiB
Vue

<template>
<div class="body-container">
<el-menu class="el-menu-demo" mode="horizontal"
style="position: absolute;top:50px;left: 50px; background-color: transparent;width: 50%;font-size: 20px;border-bottom:none">
<el-submenu index="1" style="background-color: transparent">
<template slot="title">样本库</template>
<el-menu-item index="2-1" @click="handleClick('/dataSetCategory');">样本类型管理</el-menu-item>
<el-menu-item index="2-2" @click="handleClick('/dataSetFile');">数据集管理</el-menu-item>
<!-- <el-menu-item index="2-2" @click="handleClick('/dataSetTask');">标注任务分配</el-menu-item>-->
<el-menu-item index="2-2" @click="handleClick('/dataSetLog');">标注日志</el-menu-item>
<el-menu-item index="2-3" @click="handleClick('/dataSetModel');">模型管理</el-menu-item>
<el-menu-item index="2-3" @click="handleClick('/dataSetAlgorithm');">算法评价</el-menu-item>
</el-submenu>
</el-menu>
<div class="container">
<div class="container-left">
<div class="left-top">
<box-header box-header-text="平台简介"></box-header>
<intro-video></intro-video>
</div>
<div class="left-bottom">
<box-header box-header-text="算法使用统计"></box-header>
<div class="pie" ref="pie"></div>
</div>
</div>
<div class="container-middle">
<div class="box-header">
<div class="box-header-text">算法应用概览</div>
</div>
<route-icon></route-icon>
</div>
<div class="container-right">
<div class="right-top">
<box-header box-header-text="月度访问统计"></box-header>
<div class="barChart" ref="barChart">
</div>
</div>
<div class="right-bottom">
<box-header box-header-text="算法使用统计"></box-header>
<online-count></online-count>
</div>
</div>
</div>
</div>
</template>
<script>
import BoxHeader from '@/views/components/boxHeader.vue'
import introVideo from "@/views/largeScreen/introVideo.vue";
import {graphic, init} from "echarts";
import onlineCount from "@/views/largeScreen/onlineCount.vue";
import routeIcon from "@/views/largeScreen/routeIcon.vue";
export default {
components: {
routeIcon,
onlineCount,
introVideo,
BoxHeader
},
mounted() {
// 图表初始化
this.pieInit();
this.echartsInit();
},
data() {
return {
myRectangleEchartLC: '',
rightXDataLC: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
rightYDataLC: [1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000],
// 配置数据,包含每个扇区的名称、值和颜色
optionData: [
{
name: '身份证识别',
value: 823,
itemStyle: {
color: 'RGBA(153, 242, 248, 1)'
}
},
{
name: '人脸识别',
value: 526,
itemStyle: {
color: 'RGBA(13, 104, 100, 1)',
}
},
{
name: '安全帽识别',
value: 418,
itemStyle: {
color: 'RGBA(84, 158, 230, 1)'
},
},
{
name: '大模型问答',
value: 578,
itemStyle: {
color: 'RGBA(134, 157, 233, 1)'
},
}
],
}
},
methods: {
handleClick(route) {
if (route === 'showPopup') {
this.showPopup();
} else {
this.$router.push(route);
}
},
pieInit() {
let myChart = this.$echarts.init(this.$refs.pie);
this.option = this.getPie3D(this.optionData, 0.85);
myChart.setOption(this.option);
},
// 生成3D饼图的配置项
getPie3D(pieData, internalDiameterRatio) {
let series = [];
let sumValue = pieData.reduce((acc, cur) => acc + cur.value, 0);
let startValue = 0;
const k = 1 - internalDiameterRatio;
// 按值从大到小排序并生成系列项
pieData.sort((a, b) => b.value - a.value).forEach((item, i) => {
const endValue = startValue + item.value;
const seriesItem = {
name: item.name || `series${i}`,
type: 'surface',
parametric: true,
wireframe: {show: false},
pieData: item,
pieStatus: {selected: false, hovered: false, k: k},
center: ['60%', '100%'],
radius: '60%',
itemStyle: item.itemStyle || {}
};
seriesItem.pieData.startRatio = startValue / sumValue;
seriesItem.pieData.endRatio = endValue / sumValue;
seriesItem.parametricEquation = this.getParametricEquation(
seriesItem.pieData.startRatio,
seriesItem.pieData.endRatio,
false,
false,
k,
item.value
);
startValue = endValue;
series.push(seriesItem);
});
return {
legend: this.getLegendConfig(pieData),
tooltip: this.getTooltipConfig(series),
xAxis3D: {min: -1, max: 1},
yAxis3D: {min: -1, max: 1},
zAxis3D: {min: -1, max: 1},
grid3D: this.getGrid3DConfig(series),
series: series
};
},
// 图例配置
getLegendConfig(pieData) {
return {
data: pieData.map(item => ({name: item.name, value: item.value})),
orient: 'vertical',
right: 0,
itemGap: 0,
inactiveColor: '#ccc',
textStyle: {
lineHeight: 20,
color: '#A1E2FF',
fontSize: '1rem',
padding: [30, 60, 10, 20]
},
itemHeight: 14,
itemWidth: 14,
show: true,
formatter: name => {
const target = pieData.find(item => item.name === name).value;
return `${name}:\n${target}`;
}
};
},
// 提示框配置
getTooltipConfig(series) {
return {
formatter: params => {
if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
let bfb = ((series[params.seriesIndex].pieData.endRatio - series[params.seriesIndex].pieData.startRatio) * 100).toFixed(2);
return `${params.seriesName}<br/>
<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>
${bfb}%`;
}
}
};
},
// 3D 网格配置
getGrid3DConfig(series) {
const boxHeight = this.getHeight3D(series, 1);
return {
show: false,
boxHeight: boxHeight,
top: '0%',
left: '-20%',
viewControl: {
alpha: 25,
distance: 200,
autoRotate: true, // 可以禁用或调整 autoRotate
autoRotateSpeed: 5 // 减缓旋转速度
},
postEffect: {
enable: true // 启用 GPU 加速渲染
},
light: {
main: {
intensity: 1.2 // 增强光照效果
}
}
};
},
// 计算3D饼图的高度
getHeight3D(series, height) {
const maxValue = Math.max(...series.map(item => item.pieData.value));
return height * 25 / maxValue;
},
// 生成扇形曲面的参数方程
getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
const midRatio = (startRatio + endRatio) / 2;
const startRadian = startRatio * Math.PI * 2;
const endRadian = endRatio * Math.PI * 2;
const midRadian = midRatio * Math.PI * 2;
const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
const hoverRate = isHovered ? 1.02 : 1; // 优化后的 hoverRate
return {
u: {min: -Math.PI, max: Math.PI * 3, step: Math.PI / 16}, // 优化后的步长
v: {min: 0, max: Math.PI * 2, step: Math.PI / 10}, // 优化后的步长
x: (u, v) => {
if (u < startRadian) return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
if (u > endRadian) return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
},
y: (u, v) => {
if (u < startRadian) return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
if (u > endRadian) return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
},
z: (u, v) => (Math.sin(v) > 0 ? 1 * h : -1)
};
},
// 格式化浮点数到两位小数
fomatFloat(num, n) {
let f = parseFloat(num);
if (isNaN(f)) return false;
f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n);
return f;
},
// 绑定鼠标事件
bindListen(myChart) {
// 绑定鼠标事件逻辑,可以根据需求实现
},
echartsInit() {
this.myRectangleEchartLC = init(this.$refs.barChart);
let rightYData = this.rightYDataLC;
let sum = rightYData.reduce((acc, curr) => acc + curr, 0);
let average = sum / rightYData.length;
this.myRectangleEchartLC.setOption({
tooltip: {
trigger: 'item',
axisPointer: {
type: 'cross'
}
},
xAxis: {
type: 'category',
data: this.rightXDataLC,
axisLabel: {
interval: 0, // 强制显示所有标签
// rotate: 45 // 旋转角度,可根据需要调整
},
axisPointer: {
type: 'shadow' // 在 x 轴每个单位下方显示阴影
}
},
yAxis: {
name: '单位',
type: 'value',
interval: 1000,
nameTextStyle: {
color: 'rgba(255, 255, 255, 0.5)',
fontSize: 20,
},
axisLabel: {
show: true,
color: 'rgba(255,255,255,0.5)', // 刻度标签颜色
fontSize: 12, // 刻度标签字号
fontFamily: 'Arial', // 刻度标签字体
fontWeight: 'bold', // 刻度标签字重
// formatter: function (value, index) {
// // 自定义刻度标签的显示格式,可以根据需要进行调整
// // return value + ' kg'; // 示例:在刻度值后面添加单位
// }
},
splitLine: {
show: true, // 是否显示 y 轴刻度线
lineStyle: {
color: 'rgba(255,255,255,0.2)', // 刻度线颜色
width: 1, // 刻度线宽度
type: 'solid' // 刻度线类型,可选值有:'solid', 'dashed', 'dotted'
}
}
},
series: [
{
name: '单位',
data: rightYData,
type: 'bar',
showBackground: true,
color: new graphic.LinearGradient(0, 0, 0, 1, [
{offset: 0, color: 'rgba(255, 255, 255, 1)'}, // 渐变起始颜色
{offset: 0.2, color: 'rgba(0, 150, 255, .85)'}, // 中间颜色
{offset: 1, color: 'rgba(59, 225, 255, 0.7)'} // 渐变结束颜色
]),
barWidth: '45%',
backgroundStyle: {
color: 'rgba(180, 180, 180, 0.2)'
},
itemStyle: {
barBorderRadius: [8, 8, 0, 0] // 设置柱子顶部左右两个角为圆角
},
markLine: {
data: [
{yAxis: average, name: '平均值'} // 添加平均值线
]
}
}
]
})
},
}
}
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 100%;
display: flex;
&-left,
&-middle,
&-right {
height: 100%;
padding: 0 1%;
}
&-left {
width: 30%;
display: flex;
flex-direction: column;
justify-content: space-between;
.left-top,
.left-bottom {
height: 49%;
border: 1px solid rgba(204, 252, 253, 0.3);
border-radius: 1%;
}
.left-bottom {
.pie {
width: 100%;
height: 90%;
}
}
}
&-middle {
width: 50%;
border: 1px solid rgba(204, 252, 253, 0.3);
.box-header {
width: 100%;
height: 5%;
background: url("../assets/images/boxLevelTwoHeader.svg") no-repeat center;
background-size: 100% 100%;
.box-header-text {
height: 100%;
padding-top: 0.8%;
margin-left: 6%;
color: #FFFFFF;
letter-spacing: 0.1rem;
}
}
}
&-right {
width: 30%;
display: flex;
flex-direction: column;
justify-content: space-between;
.right-top,
.right-bottom {
height: 49%;
border: 1px solid rgba(204, 252, 253, 0.3);
border-radius: 1%;
}
.right-top {
.barChart {
width: 100%;
height: 90%;
}
}
}
}
</style>