Selaa lähdekoodia

业务监控前后端联调

吴朋磊 2 viikkoa sitten
vanhempi
commit
46d023a53a

+ 16 - 0
src/api/performanceMonitor.ts

@@ -0,0 +1,16 @@
+import { http } from '../utils/request'
+
+// 获取性能监控--头部数据
+export const getHeadData = () => {
+  return http.get('/adminApi/v1/business_monitor/headData')
+}
+
+// 获取性能监控--模块列表
+export const getModuleList = () => {
+  return http.get('/adminApi/v1/business_monitor/module_list')
+}
+
+// 获取性能监控--图表数据
+export const getChartData = (params: any) => {
+  return http.post('/adminApi/v1/business_monitor/statistics_data',params)
+}

+ 223 - 254
src/baseComponents/LineChart.vue

@@ -1,11 +1,11 @@
 <template>
     <div class="echart_content">
         <div class="is_show_all" v-if="showCheckBox">
-            <el-checkbox v-model="checkAll" :indeterminate="isIndeterminate"  @change="ToggleChangeAll" >
+            <el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="ToggleChangeAll">
                 显示全部
             </el-checkbox>
         </div>
-        <div ref="line_chart" class="chart_box" :style="{height:reportHeight || '400px'}"></div>
+        <div ref="line_chart" class="chart_box" :style="{ height: reportHeight || '400px' }"></div>
     </div>
 </template>
 <script>
@@ -22,7 +22,7 @@ export default {
             isIndeterminate: false,
             legendSelected: {},//图例选中状态
             legenSelectList: [],//选择的图例
-            legenAllList:this.title,//所有的图例数据
+            legenAllList: this.title,//所有的图例数据
 
         }
     },
@@ -33,11 +33,11 @@ export default {
             default: 0,
         },//grid右间距
         gridTop: {
-            type: [Number,String],
+            type: [Number, String],
             default: '',
         },
         legendWidth: {
-            type: [Number,String],
+            type: [Number, String],
             default: 'auto',
         },
         showCheckBox: {
@@ -52,25 +52,23 @@ export default {
         datax: {
             type: Array,
             default: function () {
-                return [
-                    'G10', 'G9', 'G8', 'G7', 'G6', 'G5', 'G4', 'G3', 'G2', 'G1'
-                ];
+                return [];
             }
         },//x轴数据
         datay: {
             type: Array,
             default: function () {
                 return [
-                   
+
 
                 ];
             }
         },//y轴数据
 
-        tooltipData:{
+        tooltipData: {
             type: Array,
             default: function () {
-                return [];
+                return [];  
             }
         },//悬浮弹窗的数据
         colors: {
@@ -85,7 +83,7 @@ export default {
         },//单位
         title: {
             type: Array,
-            default: ()=>[]
+            default: () => []
         },//图例标题
         // isSetMarkNumber:{
         //     type: Boolean,
@@ -93,7 +91,7 @@ export default {
         // },//是否设置辅助线label值
         markNumber: {
             type: Array,
-            default: ()=>[]
+            default: () => []
         },//辅助线位置值 
 
         isSmooth: {
@@ -106,65 +104,63 @@ export default {
         //     default: false
         // },//是否显示辅助线平均值
 
-        showBackground:{
-            type:Boolean,
-            default:true,
+        showBackground: {
+            type: Boolean,
+            default: true,
         },//是否显示背景阴影  默认显示
 
-        isShowLabel:{
-            type:Boolean,
-            default:false,
+        isShowLabel: {
+            type: Boolean,
+            default: false,
         },//是否显示柱状图label  默认显示
-        labelColor:{
+        labelColor: {
             type: String,
-            default:'',
+            default: '',
         },//柱状图label 颜色
-        showMarkPoint:{
+        showMarkPoint: {
             type: Boolean,
-            default:false,
+            default: false,
         },//是否显示气泡图  默认不显示
 
-        legendList:{
+        legendList: {
             type: Array,
             default: () => [],
         },//默认显示的图例数据  
 
-        yInverse:{
-            type:Boolean,
-            default:false,
+        yInverse: {
+            type: Boolean,
+            default: false,
         },//y轴是否反序
 
-        updateKey:{
-            type:Number,
-            default:0
+        updateKey: {
+            type: Number,
+            default: 0
         },
-        gridLeft:{
-            type:Number,
-            default:20
+        gridLeft: {
+            type: Number,
+            default: 20
         },
-        fontSize:{//字体大小
-            type:[Number,String],
-            default:''
+        fontSize: {//字体大小
+            type: [Number, String],
+            default: ''
         },
-        fontColor:{
-            type:String,
-            default:''
+        fontColor: {
+            type: String,
+            default: ''
         },
-        reportHeight:{//报告高度
-            type:String,
-            default:''
+        reportHeight: {//报告高度
+            type: String,
+            default: ''
         }
 
     },
     watch: {
 
 
-        legendList()
-        {
+        legendList() {
             this.LoadEchart();
         },//重新加载图表
-        updateKey()
-        {
+        updateKey() {
             this.LoadEchart();
         },//重新加载图表
 
@@ -181,27 +177,26 @@ export default {
         window.removeEventListener('resize', this.HandleResize);
         this.echart.dispose(); // 销毁之前的实例
     },
-    mounted() 
-    {
-     
+    mounted() {
+
         this.LoadEchart();//初始化图表
         this.HandleResize()
     },
     methods: {
-        markLine(index){
+        markLine(index) {
             return this.markNumber.length ? {
                 data: [{
                     type: 'average',
                     name: '平均值',
-                    yAxis: this.markNumber.length?this.markNumber[index]:null//Y 值为给定值的标记线
+                    yAxis: this.markNumber.length ? this.markNumber[index] : null//Y 值为给定值的标记线
                 }],
                 label: {
-                    position:"end",
-                    formatter: (params)=>{
-                        if(this.markNumber.length){
+                    position: "end",
+                    formatter: (params) => {
+                        if (this.markNumber.length) {
                             return this.markNumber[index]
-                        }else{
-  
+                        } else {
+
                             return params.value//' {c}'
                         }
                     }// 显示平均值数值
@@ -213,39 +208,36 @@ export default {
             } : {}
         },
         //加载echarts
-        LoadEchart() 
-        {
-            
+        LoadEchart() {
+
             // 简化图例选中列表的初始化
-            this.legenSelectList = this.legendList.length > 0 
-                ? [...this.legendList] 
+            this.legenSelectList = this.legendList.length > 0
+                ? [...this.legendList]
                 : []; //
-            
+
             this.legenAllList = [...this.title];
-           
+
             if (this.echart) {
                 this.echart.dispose(); // 销毁之前的实例
             }
             //devicePixelRatio: 2   2表示每个逻辑像素对应 2 个物理像素。这会进一步提高图表的清晰度,适用于更高分辨率的屏幕  解决高分辨率显示器文字模糊的问题
             this.echart = echarts.init(this.$refs.line_chart, { devicePixelRatio: 2 });//获取echarts容器  如果组件同一个页面多处使用 这里不能用id获取实例
-            
+
             // 图例选中状态初始化
             this.legendSelected = {};
             this.title.forEach((name, index) => {
                 this.legendSelected[name] = this.legenSelectList.includes(name);
             });
-            
+
             // 更新全选状态
             this.checkAll = this.legenSelectList.length === this.legenAllList.length;
-            this.isIndeterminate = this.legenSelectList.length > 0 && 
-                                this.legenSelectList.length < this.legenAllList.length;
-           
+            this.isIndeterminate = this.legenSelectList.length > 0 &&
+                this.legenSelectList.length < this.legenAllList.length;
+
 
-            console.log("打印this.isIndeterminate",this.isIndeterminate);
             const maxValue = Math.max(...this.datay.flat());
-            const minValue=Math.min(...this.datay.flat());
+            const minValue = Math.min(...this.datay.flat());
             const hideTick = minValue < 0 || this.yInverse;//是否隐藏刻度线 最小值小于0  或者反序y轴的时候隐藏刻度线
-            // console.log("打印最小值",minValue);
             // 获取当前显示图例对应数据中的最大值
             const visibleSeriesIndices = this.legenSelectList.map(name => this.title.indexOf(name));
             const visibleData = visibleSeriesIndices
@@ -256,24 +248,23 @@ export default {
             //     const seriesMax = Math.max(...series);
             //     return seriesMax > max ? seriesMax : max;
             // }, -Infinity);
-            
+
             // const yAxisMax =  Math.ceil((maxValue+2) / 5) * 5;//向上取整到5的倍数
             // console.log("打印最大值",maxValue);
-            const extraText=this.extraText?"占比":""
-            const dataCount=this.datax.length;
+            const extraText = this.extraText ? "占比" : ""
+            const dataCount = this.datax.length;
             // if(maxValue<10)
             // {
             //     maxValue=9
             // }
             //计算每个x轴的宽度 
             let totalWidth = this.$refs.line_chart.clientWidth;
-            let singleSeriesWidth = (totalWidth - 100)/dataCount;
+            let singleSeriesWidth = (totalWidth - 100) / dataCount;
             // console.log("打印x轴宽度",singleSeriesWidth);
-            let gridTop= this.showMarkPoint ? 45 : 20;
+            let gridTop = this.showMarkPoint ? 45 : 20;
             // 无图例 默认20  有图例 70
-            if(this.title.length>0)
-            {
-                gridTop=70;
+            if (this.title.length > 0) {
+                gridTop = 70;
             }
             let option = {
 
@@ -300,55 +291,54 @@ export default {
                     enterable: true,
                     formatter: (params) => {
                         // console.log(params);
-                        
+
                         // console.log("打印this.tooltipData",this.tooltipData);
-                       
-                            let tooltip = `<div class='tooltip_content'>`;
-                            let title = params[0].name;
-                            tooltip += `<div class='tooltip_title'>${title}</div>`;
-                            params.forEach((item, index) => {
-                                // console.log("打印item",item);
-                                let name = item.seriesName;
-                                let rate = item.value+this.unit;//占比
-                                if(this.tooltipData.length>0)
-                                {
-                                    let tooltipItem=this.tooltipData?.[item.seriesIndex]?.[item.dataIndex] || '';
-                                    tooltip += `<div class='tooltip_student'>
+
+                        let tooltip = `<div class='tooltip_content'>`;
+                        let title = params[0].name;
+                        tooltip += `<div class='tooltip_title'>${title}</div>`;
+                        params.forEach((item, index) => {
+                            // console.log("打印item",item);
+                            let name = item.seriesName;
+                            let rate = item.value + this.unit;//占比
+                            if (this.tooltipData.length > 0) {
+                                let tooltipItem = this.tooltipData?.[item.seriesIndex]?.[item.dataIndex] || '';
+                                tooltip += `<div class='tooltip_student'>
                                         <div class='tooltip_line_icon' style='background:${item.color}'></div>
                                         <div class='tooltip_student_name'>
                                              ${tooltipItem.name}:${tooltipItem.value}
                                         </div></div>`;
-                                }
-                                else{
-                                    tooltip += `<div class='tooltip_student'><div class='tooltip_line_icon' style='background:${item.color}'></div><div class='tooltip_student_name'>${name}${extraText}:${rate || '-'}</div></div>`;
-                                }
-                                
-                            })
-                            tooltip += `</div>`;
-                            return tooltip;
-                        
-                        
-                        
+                            }
+                            else {
+                                tooltip += `<div class='tooltip_student'><div class='tooltip_line_icon' style='background:${item.color}'></div><div class='tooltip_student_name'>${name}${extraText}:${rate || '-'}</div></div>`;
+                            }
+
+                        })
+                        tooltip += `</div>`;
+                        return tooltip;
+
+
+
                     },
                 },
                 legend: {
                     show: this.title.length ? true : false,//是否显示图例
                     left: this.showCheckBox ? "110px" : "0px",//图例距左边距离  有显示全部的 默认110px
-                    width:this.legendWidth,
+                    width: this.legendWidth,
                     itemGap: 20,//图例间距
                     itemHeight: 10,//图例的高度
                     itemWidth: 25,//图例的宽度
 
-                    
+
                     data: this.title,
                     textStyle: {
-                        fontSize: 12, 
+                        fontSize: 12,
                         color: "#333",
                         lineHeight: 30,
                     },
                     selectedMode: true,//允许图例切换显示
                     selected: this.legendSelected, // 绑定图例选中状态
-                    type:'scroll',//启用图例滚动  翻页功能
+                    type: 'scroll',//启用图例滚动  翻页功能
                     pageIconColor: '#999', // 翻页按钮默认颜色
                     pageIconInactiveColor: '#ccc', // 翻页按钮禁用状态颜色
                     pageButtonItemGap: 5, // 分页按钮与图例的间距
@@ -361,7 +351,7 @@ export default {
                     left: this.gridLeft,
                     right: this.gridRight,
                     top: this.gridTop || gridTop,
-                    bottom:0,
+                    bottom: 0,
                     containLabel: true, //用于控制网格区域是否包含坐标轴的标签  true 可以确保所有标签都能完整显示,不会被裁剪。
                 },
                 xAxis: {
@@ -373,7 +363,7 @@ export default {
                     axisTick: {
                         alignWithLabel: true,//不然刻度线跟随标签对齐
                         // show: !this.yInverse,            // 显示刻度线
-                        show:!hideTick,
+                        show: !hideTick,
                         inside: false,         // 刻度线朝外(默认是朝内)
                         length: 8,             // 刻度线长度
                         // lineStyle: {
@@ -382,42 +372,38 @@ export default {
                         // },
                         // color:'#E4E7ED'
                     },
-                    axisLine:{
-                        show:!this.yInverse,
+                    axisLine: {
+                        show: !this.yInverse,
                     },
                     axisLabel: {
                         interval: 0,//0 显示所有刻度
                         rotate: singleSeriesWidth < 60 ? 45 : 0,
-                        fontSize: this.fontSize?this.fontSize:14,
+                        fontSize: this.fontSize ? this.fontSize : 14,
                         color: this.fontColor || "#666",
                         fontWeight: 400,
-                        formatter:function(value) {
-                            
+                        formatter: function (value) {
+
                             //一个文字的长度大概约16.6  按16算
-              
-                            const valueWidth = value.length*14;
+
+                            const valueWidth = value.length * 14;
                             // console.log("lineChart打印字的大概宽度",valueWidth);
                             // console.log("打印singleSeriesWidth",singleSeriesWidth);
-                            if(valueWidth>singleSeriesWidth)
-                            {
-                               
-                                    //单系列宽度小于50 倾斜显示
-                                    if(singleSeriesWidth<80)
-                                    {
-                                        return value;
-                                    }
-                                    else
-                                    {
-                                        let maxLength=Math.floor(singleSeriesWidth/14);
-                
-                                        return value.slice(0, maxLength) + '...';
-                                    }
-                                
-                                
-                                
+                            if (valueWidth > singleSeriesWidth) {
+
+                                //单系列宽度小于50 倾斜显示
+                                if (singleSeriesWidth < 80) {
+                                    return value;
+                                }
+                                else {
+                                    let maxLength = Math.floor(singleSeriesWidth / 14);
+
+                                    return value.slice(0, maxLength) + '...';
+                                }
+
+
+
                             }
-                            else
-                            {
+                            else {
                                 return value;
                             }
                         },
@@ -429,17 +415,17 @@ export default {
                         margin: 20,
                         formatter: '{value}' + this.unit,
                         interval: 0, // 显示所有 label
-                        fontSize: this.fontSize?this.fontSize:14,
+                        fontSize: this.fontSize ? this.fontSize : 14,
                         color: this.fontColor || "#666",
                         fontWeight: 400
                     },
                     splitNumber: 5,//固定显示5个刻度  非强制 不一定生效
-                 
+
                     axisTick: {
                         interval: 0 // 显示所有刻度线
                     },
                     // splitNumber:4,//固定将y轴划分为5段
-                    
+
                     splitLine: {
                         show: true, //显示横向网格线
                         lineStyle:
@@ -455,10 +441,10 @@ export default {
                             color: ["#fafafa", "#ffffff"]
                         },// 网格线设置隔行背景色
                     },
-                    inverse:this.yInverse,
+                    inverse: this.yInverse,
                     // min:this.showBackground?0: (val) => {
 
-                        
+
                     //     if(val.min > 0 || val.min < -10) {
                     //         // return Math.floor(val.min / 10) * 10
                     //         return Math.floor(val.min)
@@ -494,16 +480,16 @@ export default {
                     // symbol: 'none',//设置无折线点
                     symbol: "emptyCircle",//设置折线点为圆形
                     showSymbol: true,//显示小圆点
-                    symbolSize:8,//折线点大小
-                    label: { 
+                    symbolSize: 8,//折线点大小
+                    label: {
                         show: this.isShowLabel, //是否显示数值
-                        color: this.labelColor || this.colors[index], 
-                        formatter: "{c}" + this.unit 
+                        color: this.labelColor || this.colors[index],
+                        formatter: "{c}" + this.unit
                     },
                     smooth: this.isSmooth,//设置折线平滑
                     markLine: this.markLine(index), //平均线
-                    
-                    markPoint: this.showMarkPoint?{
+
+                    markPoint: this.showMarkPoint ? {
                         // symbolSize:25,//气泡大小
                         // label: {
                         //     show: true,
@@ -523,12 +509,12 @@ export default {
                             {
                                 type: "min",
                                 name: "最小值",
-                                label: { color: "#fff",},
+                                label: { color: "#fff", },
                                 // z:index+1,
                                 // symbolOffset: [0, index * 8 - 10], // 每一个点依次向下偏移
                             },
                         ],
-                    }:undefined,//是否显示气泡      
+                    } : undefined,//是否显示气泡      
                     itemStyle: {
                         color: this.colors[index],
                         borderColor: this.colors[index],
@@ -536,10 +522,10 @@ export default {
                         shadowColor: 'rgba(0, 0, 0, .1)',
                         shadowBlur: 0,
                     },
-                    lineStyle:{
-                        width:3,//设置折线的粗细 
+                    lineStyle: {
+                        width: 3,//设置折线的粗细 
                     },
-                    areaStyle:this.showBackground? {
+                    areaStyle: this.showBackground ? {
                         color: {
                             type: 'linear',
                             x: 0,//渐变起点x
@@ -555,12 +541,12 @@ export default {
                                 }
                             ],
                         },
-                    }:undefined,//折线背景阴影设置
+                    } : undefined,//折线背景阴影设置
                     emphasis: {
                         focus: 'series',
                         blurScope: 'coordinateSystem'
                     },
-                    data:data,
+                    data: data,
                 })),
             };
 
@@ -571,38 +557,35 @@ export default {
         },
 
         // X轴文字过程显示省略号,鼠标hover上去时,弹出一个tooltip显示全称
-        LabelMouseOver() 
-        {
+        LabelMouseOver() {
             // 注意这里,是以X轴显示内容过长为例,如果是y轴的话,需要把params.componentType == 'xAxis'改为yAxis
             // 判断是否创建过div框,如果创建过就不再创建了
             // 该div用来盛放文本显示内容的,方便对其悬浮位置进行处理
             let elementDiv = document.getElementById("tooltipContent");
             // console.log("elementDiv",elementDiv)
-            
-            if (!elementDiv) 
-            {
+
+            if (!elementDiv) {
                 let div = document.createElement("div");
                 div.setAttribute("id", "tooltipContent");
                 div.style.display = "block";
                 document.querySelector("html").appendChild(div);//放入body下
             }
-            this.echart.on("mouseover", (params) => 
-            {
-                
+            this.echart.on("mouseover", (params) => {
+
                 if (params.componentType == "xAxis") {
-                let elementDiv = document.querySelector("#tooltipContent");
-                //设置悬浮文本的位置以及样式
-                let elementStyle =
-                    "position: absolute;z-index: 99999;color: #fff;font-size: 12px;padding: 5px;display: inline;border-radius: 4px;background-color: #303133;box-shadow: rgba(0, 0, 0, 0.3) 2px 2px 8px";
-                elementDiv.style.cssText = elementStyle;
-                elementDiv.innerHTML = params.value;
-                document.querySelector("html").onmousemove = function (event) {
                     let elementDiv = document.querySelector("#tooltipContent");
-                    let xx = event.pageX - 10;
-                    let yy = event.pageY - 25;
-                    elementDiv.style.top = yy + "px";
-                    elementDiv.style.left = xx + "px";
-                };
+                    //设置悬浮文本的位置以及样式
+                    let elementStyle =
+                        "position: absolute;z-index: 99999;color: #fff;font-size: 12px;padding: 5px;display: inline;border-radius: 4px;background-color: #303133;box-shadow: rgba(0, 0, 0, 0.3) 2px 2px 8px";
+                    elementDiv.style.cssText = elementStyle;
+                    elementDiv.innerHTML = params.value;
+                    document.querySelector("html").onmousemove = function (event) {
+                        let elementDiv = document.querySelector("#tooltipContent");
+                        let xx = event.pageX - 10;
+                        let yy = event.pageY - 25;
+                        elementDiv.style.top = yy + "px";
+                        elementDiv.style.left = xx + "px";
+                    };
                 }
             });
             this.echart.on("mouseout", function (params) {
@@ -614,34 +597,28 @@ export default {
             });
         },
         // 图例与显示全部按钮联动 事件
-        HandleLegendSelectChangeds(params) 
-        {
-           
+        HandleLegendSelectChangeds(params) {
+
             const selected = params.selected;
-            this.legenSelectList=[];
-            for(var i=0;i<this.legenAllList.length;i++)
-            {
-                if(selected[this.legenAllList[i]]==true)
-                {
+            this.legenSelectList = [];
+            for (var i = 0; i < this.legenAllList.length; i++) {
+                if (selected[this.legenAllList[i]] == true) {
                     this.legenSelectList.push(this.legenAllList[i]);
-                }                                                         
+                }
             }
             this.LoadEchart();
         },
         //全选
-        ChangeCheckAll(value)
-        {
+        ChangeCheckAll(value) {
             // console.log("打印value",this.checkAll);
-            if(value)
-            {
+            if (value) {
                 //选中全选
-                this.legenSelectList=this.legenAllList;
-                
+                this.legenSelectList = this.legenAllList;
+
                 this.isIndeterminate = false;
             }
-            else
-            {
-                this.legenSelectList=[];
+            else {
+                this.legenSelectList = [];
                 this.isIndeterminate = false;
             }
             this.LoadEchart();
@@ -653,7 +630,7 @@ export default {
             const legendData = this.echart.getOption().legend[0].data;
             const selected = params.selected;
             // 检查是否有任何图例项被隐藏
-            this.legendSelected=selected;
+            this.legendSelected = selected;
             const allSelected = legendData.every(
                 (seriesName) => selected[seriesName]
             );
@@ -670,8 +647,8 @@ export default {
             }
             this.isIndeterminate = someSelected;
             let legendSelectedList = [];
-            for(let key in this.legendSelected) {
-                if(this.legendSelected[key]) {
+            for (let key in this.legendSelected) {
+                if (this.legendSelected[key]) {
                     legendSelectedList.push(key)
                 }
             }
@@ -681,39 +658,32 @@ export default {
         },
 
         // 显示全部按钮
-        ToggleChangeAll() 
-        {
+        ToggleChangeAll() {
             if (!this.showCheckBox) return false
-            console.log(this.checkAll)
-           
-                
             const legendData = this.echart.getOption().legend[0].data;
             legendData.forEach((seriesName) => {
-                    this.echart.dispatchAction({
-                        type: this.checkAll ? "legendSelect" : "legendUnSelect",
-                        name: seriesName,
-                    });
+                this.echart.dispatchAction({
+                    type: this.checkAll ? "legendSelect" : "legendUnSelect",
+                    name: seriesName,
+                });
             });
-           
-           
+
+
             this.isIndeterminate = false;
 
             let legendSelectedList = [];
-            if(this.checkAll)
-            {
+            if (this.checkAll) {
                 legendSelectedList = this.title;
             }
-            else
-            {
+            else {
                 legendSelectedList = [];
             }
 
-            this.$emit('SelectLegend',legendSelectedList)
+            this.$emit('SelectLegend', legendSelectedList)
         },
 
         //显示X轴标签悬浮框
-        ShowXAxisTooltip()
-        {
+        ShowXAxisTooltip() {
             const chart = this.echart; // 获取 echarts 实例
             const container = chart.getDom(); // 获取容器 DOM
 
@@ -738,17 +708,17 @@ export default {
 
             chart.on('mouseover', (params) => {
                 if (params.componentType === 'xAxis') {
-                const value = params.value;
-                if (value && value.length > 5) { // 设置长度判断是否需要显示 tooltip
-                    tooltipDiv.style.display = 'block';
-                    tooltipDiv.innerText = value;
-                }
+                    const value = params.value;
+                    if (value && value.length > 5) { // 设置长度判断是否需要显示 tooltip
+                        tooltipDiv.style.display = 'block';
+                        tooltipDiv.innerText = value;
+                    }
                 }
             });
 
             chart.on('mouseout', (params) => {
                 if (params.componentType === 'xAxis') {
-                tooltipDiv.style.display = 'none';
+                    tooltipDiv.style.display = 'none';
                 }
             });
 
@@ -761,40 +731,40 @@ export default {
 
         // X轴文字过程显示省略号,鼠标hover上去时,弹出一个tooltip显示全称
         extension() {
-        // 注意这里,是以X轴显示内容过长为例,如果是y轴的话,需要把params.componentType == 'xAxis'改为yAxis
-        // 判断是否创建过div框,如果创建过就不再创建了
-        // 该div用来盛放文本显示内容的,方便对其悬浮位置进行处理
-        let elementDiv = document.getElementById("extension");
-        if (!elementDiv) {
-            let div = document.createElement("div");
-            div.setAttribute("id", "extension");
-            div.style.display = "block";
-            document.querySelector("html").appendChild(div);
-        }
-        this.myChart.on("mouseover", (params) => {
-            if (params.componentType == "xAxis") {
-            let elementDiv = document.querySelector("#extension");
-            //设置悬浮文本的位置以及样式
-            let elementStyle =
-                "position: absolute;z-index: 99999;color: #fff;font-size: 12px;padding: 5px;display: inline;border-radius: 4px;background-color: #303133;box-shadow: rgba(0, 0, 0, 0.3) 2px 2px 8px";
-            elementDiv.style.cssText = elementStyle;
-            elementDiv.innerHTML = params.value;
-            document.querySelector("html").onmousemove = function (event) {
-                let elementDiv = document.querySelector("#extension");
-                let xx = event.pageX - 10;
-                let yy = event.pageY + 15;
-                elementDiv.style.top = yy + "px";
-                elementDiv.style.left = xx + "px";
-            };
-            }
-        });
-        this.myChart.on("mouseout", function (params) {
-            //注意这里,我是以X轴显示内容过长为例,如果是y轴的话,需要改为yAxis
-            if (params.componentType == "xAxis") {
-            let elementDiv = document.querySelector("#extension");
-            elementDiv.style.cssText = "display:none";
+            // 注意这里,是以X轴显示内容过长为例,如果是y轴的话,需要把params.componentType == 'xAxis'改为yAxis
+            // 判断是否创建过div框,如果创建过就不再创建了
+            // 该div用来盛放文本显示内容的,方便对其悬浮位置进行处理
+            let elementDiv = document.getElementById("extension");
+            if (!elementDiv) {
+                let div = document.createElement("div");
+                div.setAttribute("id", "extension");
+                div.style.display = "block";
+                document.querySelector("html").appendChild(div);
             }
-        });
+            this.myChart.on("mouseover", (params) => {
+                if (params.componentType == "xAxis") {
+                    let elementDiv = document.querySelector("#extension");
+                    //设置悬浮文本的位置以及样式
+                    let elementStyle =
+                        "position: absolute;z-index: 99999;color: #fff;font-size: 12px;padding: 5px;display: inline;border-radius: 4px;background-color: #303133;box-shadow: rgba(0, 0, 0, 0.3) 2px 2px 8px";
+                    elementDiv.style.cssText = elementStyle;
+                    elementDiv.innerHTML = params.value;
+                    document.querySelector("html").onmousemove = function (event) {
+                        let elementDiv = document.querySelector("#extension");
+                        let xx = event.pageX - 10;
+                        let yy = event.pageY + 15;
+                        elementDiv.style.top = yy + "px";
+                        elementDiv.style.left = xx + "px";
+                    };
+                }
+            });
+            this.myChart.on("mouseout", function (params) {
+                //注意这里,我是以X轴显示内容过长为例,如果是y轴的话,需要改为yAxis
+                if (params.componentType == "xAxis") {
+                    let elementDiv = document.querySelector("#extension");
+                    elementDiv.style.cssText = "display:none";
+                }
+            });
         },
 
         // 监听窗口大小变化,重新计算表格高度 使用节流防止频繁改变窗口大小导致计算量过大而页面卡顿
@@ -808,8 +778,7 @@ export default {
 }
 </script>
 <style lang="scss" scoped>
-.is_show_all
-{
-    top:10px;
+.is_show_all {
+    top: 10px;
 }
 </style>

+ 16 - 16
src/baseComponents/TabSearch.vue

@@ -22,26 +22,26 @@
 import { ref, watch} from 'vue';
 
 interface TabItem {
-    label:String,
-    key:String,
-    prefix?:String,
-    prefixLight?:String,
-    suffix?:String,
+    label: string,
+    key: string,
+    prefix?: string,
+    prefixLight?: string,
+    suffix?: string | number,
 }
 
-type TabType = 'box'|'line'
+type TabType = 'box' | 'line'
 const props = defineProps({
-    tabList:{
-        required:true,
-        type:Array<TabItem>
+    tabList: {
+        required: true,
+        type: Array<TabItem>
     },
-    tabType:{
-        required:true,
-        type:String
+    tabType: {
+        required: true,
+        type: String as () => TabType
     },
-    defaultTabKey:{
-        required:true,
-        type:String
+    defaultTabKey: {
+        required: true,
+        type: String
     }
 })
 const emit = defineEmits(['tabChange'])
@@ -51,7 +51,7 @@ watch([()=>props.defaultTabKey,()=>props.tabList],([newVal,newValList])=>{
     activedId.value = newVal
 },{immediate:true,deep:true})
 
-const HandleTabChange = async (params) =>{
+const HandleTabChange = async (params: string) =>{
     activedId.value = params
     emit('tabChange',activedId.value)
 }

+ 136 - 73
src/views/performanceMonitor/index.vue

@@ -1,6 +1,7 @@
 <template>
     <div class="main_container custom_container">
         <div class="page_item end_item">
+            <!-- 当前在线人数 -->
             <div class="page_search">
                 <div class="search_content">
                     <div class="content_left">
@@ -8,9 +9,7 @@
                     </div>
                 </div>
             </div>
-
             <div class="page_jg_20"></div>
-
             <ul class="cardBoard">
                 <li v-for="card in cardBoardList" :key="card.label">
                     <div class="label">{{ card.label }}</div>
@@ -18,34 +17,30 @@
                 </li>
             </ul>
             
+            <!-- 模块列表  -->
             <div class="page_jg_20"></div>
-
-
-            <TabSearch tabType="line" :tabList="onlineTypeTablist" 
-                :defaultTabKey="defaultOnlineTypeTab">
+            <TabSearch tabType="line" :tabList="onlineTypeTablist" :defaultTabKey="defaultOnlineTypeTab">
             </TabSearch>
 
+            <!-- 时间范围 -->
             <div class="page_jg_20"></div>
-            
-             <TabSearch tabType="box" :tabList="dateRangeTablist" 
-                :defaultTabKey="defaultDateRangeTab">
+            <TabSearch tabType="box" :tabList="dateRangeTablist" :defaultTabKey="defaultDateRangeTab">
             </TabSearch>
 
+            <!-- 图表 -->
             <div class="page_jg_20"></div>
-
             <div class="chart_box">
                 <!--  某段时间的 某类型 在线人数统计 -->
                 <div class="chart">
                     <div class="page_search">
                         <div class="search_content">
                             <div class="content_left">
-                                <div class="grade_title">{{ onLineType  }}在线人数统计</div>
+                                <div class="grade_title">{{ onLineType }}在线人数统计</div>
                             </div>
                         </div>
                     </div>
-                    <LineChart reportHeight="244px" :datax="somePeriodTimeLineData.datax"  
-                        :datay="somePeriodTimeLineData.datay" 
-                        :showCheckBox="false" >
+                    <LineChart reportHeight="244px" :datax="somePeriodTimeLineData.datax"
+                        :datay="somePeriodTimeLineData.datay" :showCheckBox="false">
                     </LineChart>
                 </div>
 
@@ -54,12 +49,12 @@
                     <div class="page_search">
                         <div class="search_content">
                             <div class="content_left">
-                                <div class="grade_title">{{onLineTime}}时 / {{ onLineType  }} 在线人数统计</div>
+                                <div class="grade_title">{{ onLineTime }}时 / {{ onLineType }} 在线人数统计</div>
                             </div>
                         </div>
                     </div>
-                    <MultipleBarCharts :datax="someoneTimeBarData.datax" 
-                        :datay="someoneTimeBarData.datay" :height="244">
+                    <MultipleBarCharts :datax="someoneTimeBarData.datax" :datay="someoneTimeBarData.datay"
+                        :height="244">
                     </MultipleBarCharts>
                 </div>
 
@@ -68,20 +63,20 @@
                     <div class="page_search">
                         <div class="search_content">
                             <div class="content_left">
-                                <div class="grade_title">{{schoolName}} / 当天在线人数统计</div>
+                                <div class="grade_title">{{ schoolName }} / 当天在线人数统计</div>
                             </div>
                         </div>
                     </div>
 
-                    <TabSearch :tabList="visualizationTypeTablist" 
-                        tabType="box" :defaultTabKey="defaultVisualizationTypeTab" 
-                        @tabChange="(val)=>HandleTabChange('visualizationType',val)">
+                    <TabSearch :tabList="visualizationTypeTablist" tabType="box"
+                        :defaultTabKey="defaultVisualizationTypeTab"
+                        @tabChange="(val) => HandleTabChange('visualizationType', val)">
                     </TabSearch>
 
 
-                    <LineChart v-if="defaultVisualizationTypeTab == 'chart'" reportHeight="208px" :datax="someSchoolOneDayBarData.datax"  
-                        :datay="someSchoolOneDayBarData.datay" 
-                        :showCheckBox="false" >
+                    <LineChart v-if="defaultVisualizationTypeTab == 'chart'" reportHeight="208px"
+                        :datax="someSchoolOneDayBarData.datax" :datay="someSchoolOneDayBarData.datay"
+                        :showCheckBox="false">
                     </LineChart>
 
                     <template v-if="defaultVisualizationTypeTab == 'table'">
@@ -95,60 +90,62 @@
                             </div>
                         </div>
                         <div class="page_jg_20"></div>
-                        <Table :tableColumns="tableColumns" 
-                            :tableData="someSchoolOneDayTableData" >
+                        <Table :tableColumns="tableColumns" :tableData="someSchoolOneDayTableData">
                         </Table>
                     </template>
 
-                    
+
 
                 </div>
             </div>
         </div>
     </div>
-</template>  
+</template>
 
 <script setup lang="ts">
 import TabSearch from '@/baseComponents/TabSearch.vue';
 import Table from '@/baseComponents/Table.vue';
-import { computed, reactive, ref } from 'vue';
+import { computed, reactive, ref, onMounted } from 'vue';
 
 import { onlineTypeTablist, dateRangeTablist, visualizationTypeTablist } from './tabSearch';
-import {tableColumns} from './table'
+import { tableColumns } from './table'
+import { getHeadData, getModuleList, getChartData } from '@/api/performanceMonitor'
 
 
 import MultipleBarCharts from '@/baseComponents/MultipleBarCharts.vue';
 import LineChart from '@/baseComponents/LineChart.vue';
 
+
+
 // 看板数据
 const boardMsg = reactive({
-    teacherOnline:1330,
-    studentOnline:1330,
-    scaneOnline:78,
-    examinationPaperOnline:78,
-    analysisOnline:78
-}) 
+    teacherOnline: 0,
+    studentOnline: 0,
+    scaneOnline: 0,
+    examinationPaperOnline: 0,
+    analysisOnline: 0
+})
 // 看板列表
-const cardBoardList = computed(()=>[
+const cardBoardList = computed(() => [
     {
-        label:'教师在线',
-        value:boardMsg.teacherOnline
+        label: '教师在线',
+        value: boardMsg.teacherOnline
     },
     {
-        label:'学生在线',
-        value:boardMsg.studentOnline
+        label: '学生在线',
+        value: boardMsg.studentOnline
     },
     {
-        label:'使用扫描人数',
-        value:boardMsg.scaneOnline
+        label: '使用扫描人数',
+        value: boardMsg.scaneOnline
     },
     {
-        label:'使用阅卷人数',
-        value:boardMsg.examinationPaperOnline
+        label: '使用阅卷人数',
+        value: boardMsg.examinationPaperOnline
     },
     {
-        label:'使用分析人数',
-        value:boardMsg.analysisOnline
+        label: '使用分析人数',
+        value: boardMsg.analysisOnline
     },
 ])
 
@@ -158,24 +155,24 @@ const schoolName = ref('北京师范大学附属中学')  //学校名称
 
 // 某段时间的 某类型 在线人数统计
 const somePeriodTimeLineData = reactive({
-    datax:['0时','1时','2时','3时','4时','5时','6时','7时','8时','9时','10时'],
-    datay:[
-        [233,43,56,43,44,34,5,65,76,87,853],
+    datax: ['0时', '1时', '2时', '3时', '4时', '5时', '6时', '7时', '8时', '9时', '10时'],
+    datay: [
+        [233, 43, 56, 43, 44, 34, 5, 65, 76, 87, 853],
     ]
 })
 
 // 某一时刻的 某类型 在线人数统计
 const onLineTime = ref(0)
 const someoneTimeBarData = reactive({
-    datax:['北京师范大学附属中学','师达','交大分校','本部高中','本部初中'],
-    datay:[233,43,56,43,44]
+    datax: ['北京师范大学附属中学', '师达', '交大分校', '本部高中', '本部初中'],
+    datay: [233, 43, 56, 43, 44]
 })
 
 // 某个学校的当天在线人数统计 折线图数据
 const someSchoolOneDayBarData = reactive({
-    datax:['0时','1时','2时','3时','4时','5时','6时','7时','8时','9时','10时'],
-    datay:[
-        [233,43,56,43,44,34,5,65,76,87,853],
+    datax: ['0时', '1时', '2时', '3时', '4时', '5时', '6时', '7时', '8时', '9时', '10时'],
+    datay: [
+        [233, 43, 56, 43, 44, 34, 5, 65, 76, 87, 853],
     ]
 })
 
@@ -205,48 +202,114 @@ const someSchoolOneDayTableData = ref([
 const defaultOnlineTypeTab = ref('teacherOnline')  //  默认的在线类型
 const defaultDateRangeTab = ref('today')  // 默认的 时间范围
 const defaultVisualizationTypeTab = ref('chart')  //   默认的 某个学校的当天在线人数 的可视化展示类型
-const HandleTabChange = (type,val)=>{
-    switch(type){
+const HandleTabChange = (type: string, val: string) => {
+    switch (type) {
         case 'visualizationType':
             defaultVisualizationTypeTab.value = val
             break
     }
 }
 
-</script>
 
+// 获取头部数据
+const fetchHeadData = async () => {
+    try {
+        const res = await getHeadData()
+        const data = res.data || res
+        boardMsg.teacherOnline = data.teacherLoginNum ?? 0
+        boardMsg.studentOnline = data.studentLoginNum ?? 0
+        boardMsg.scaneOnline = data.scannedNum ?? 0
+        boardMsg.examinationPaperOnline = data.markingNum ?? 0
+        boardMsg.analysisOnline = data.reportNum ?? 0
+    } catch (err) {
+        console.error('getHeadData 请求失败:', err)
+    }
+}
 
+// 获取模块列表
+const fetchModuleList = async () => {
+    try {
+        const res = await getModuleList()
+        // console.log('getModuleList 响应数据:', res)
+        const data = res.data || res
+        // 筛选"在线"相关的模块,映射为 tabList 格式
+        const onlineList = (data || []).map((item: any) => ({
+                key: String(item.code),
+                label: item.name
+            }))
+        if (onlineList.length) {
+            onlineTypeTablist.value = onlineList
+            defaultOnlineTypeTab.value = onlineList[0].key
+        }
+    } catch (err) {
+        console.error('getModuleList 请求失败:', err)
+    }
+}
 
+// 获取图表数据
+const fetchChartData = async () => {
+    try {
+        const res = await getChartData({
+           schoolId: 0,
+           timeType: 0,
+           moduleCode: 0,
+           startTime: '',
+           endTime: '',
+        })
+        // console.log('getChartData 响应数据:', res)
+        const data = res.data || res
+        if (data) {
+            
+            // somePeriodTimeLineData.datax = data.map((item: any) => item.xname)
+            // somePeriodTimeLineData.datay = data.map((item: any) => item.count)
 
-<style lang="scss" scoped>
+            // somePeriodTimeLineData.datax = data.xname
+            // somePeriodTimeLineData.datay = data.count
+        }
+    } catch (err) {
+        console.error('getChartData 请求失败:', err)
+    }
+}
+
+onMounted(() => {
+    fetchHeadData()
+    fetchModuleList()
+    fetchChartData()
+})
 
-.cardBoard{
+</script>
+
+<style lang="scss" scoped>
+.cardBoard {
     display: grid;
-    grid-template-columns: repeat(5,1fr);
-    gap:20px;
-    li{
+    grid-template-columns: repeat(5, 1fr);
+    gap: 20px;
+
+    li {
         background-color: #f2f2f2;
-        padding:20px;
+        padding: 20px;
         border-radius: 8px;
-        .label{
+
+        .label {
             font-size: 16px;
         }
-        .num{
+
+        .num {
             font-size: 34px;
             font-weight: 600;
         }
     }
 }
 
-.chart_box{
+.chart_box {
     display: flex;
     flex-direction: column;
-    gap:10px;
-    .chart{
-        border:1px solid #dcdfe6;
-        min-height:320px;
-        padding:20px;
+    gap: 10px;
+
+    .chart {
+        border: 1px solid #dcdfe6;
+        min-height: 320px;
+        padding: 20px;
     }
 }
-
 </style>

+ 1 - 22
src/views/performanceMonitor/tabSearch.ts

@@ -2,28 +2,7 @@ import { ref } from "vue";
 
 
 // 在线类型列表
-export const onlineTypeTablist = ref([
-    {
-        label:'教师在线',
-        key:'teacherOnline',
-    },
-    {
-        label:'学生在线',
-        key:'studentOnline',
-    },
-    {
-        label:'阅卷在线',
-        key:'examinationPaperOnline',
-    },
-    {
-        label:'扫描在线',
-        key:'scaneOnline',
-    },
-    {
-        label:'分析在线',
-        key:'analysisOnline',
-    },
-])
+export const onlineTypeTablist = ref([])
 
 
 // 时间范围列表