Authored by 鲁尚清

指标状态散点图从master迁移到500dev

@@ -4090,7 +4090,42 @@ layui.define(['laytpl', 'admin', 'form', 'table', 'echarts', 'sessions', 'xmSele @@ -4090,7 +4090,42 @@ layui.define(['laytpl', 'admin', 'form', 'table', 'echarts', 'sessions', 'xmSele
4090 } 4090 }
4091 }); 4091 });
4092 } 4092 }
  4093 + //start 连接状态 2022-05-19
  4094 + function connectStatus(param,title){
  4095 + var obj = {
  4096 + resId: param.resId,
  4097 + kpiId: param.kpiId,
  4098 + flag: param.flag,
  4099 + subFlag: param.subFlag
  4100 + }
4093 4101
  4102 +
  4103 + let urlParams='';
  4104 + for(let key in param){
  4105 + if(param[key]){
  4106 + urlParams+=key+'='+param[key]+'&'
  4107 + }
  4108 + }
  4109 + urlParams=urlParams.substr(0,urlParams.length-1)
  4110 + //End LSQ 2022/1/17
  4111 + if (!title) {
  4112 + title = "状态指标";
  4113 + }
  4114 + view('commonViewModel').render("template/detail/line").then(function (res) {
  4115 + layer.open({
  4116 + title: [title, 'font-size:18px;'],
  4117 + type: 2,
  4118 + area: ['80%', '90%'],
  4119 + shadeClose: true,//开启遮罩层
  4120 + id: 'kpi_line_chart_div',
  4121 + content: ['/vue3/index.html#/vue3/connectScatter?'+urlParams, 'no'],
  4122 + cancel: function () {
  4123 + clearTimeout(obj.lineTimer);
  4124 + }
  4125 + });
  4126 + });
  4127 + }
  4128 + //end lsq 2022-05-19
4094 //监听过滤压制等事件 4129 //监听过滤压制等事件
4095 function filterSuppressMonitor(resId){ 4130 function filterSuppressMonitor(resId){
4096 //菜单按钮点击事件 4131 //菜单按钮点击事件
@@ -4144,58 +4179,103 @@ layui.define(['laytpl', 'admin', 'form', 'table', 'echarts', 'sessions', 'xmSele @@ -4144,58 +4179,103 @@ layui.define(['laytpl', 'admin', 'form', 'table', 'echarts', 'sessions', 'xmSele
4144 if (flag) { 4179 if (flag) {
4145 flag = flag.replace(/^\s+|\s+$/g, ""); 4180 flag = flag.replace(/^\s+|\s+$/g, "");
4146 } 4181 }
4147 -  
4148 - //菜单点击事件  
4149 - $("#detail_menubox_id ul>li").unbind("click").on("click",function (){  
4150 - var type = $(this).attr("type");  
4151 - var params = {  
4152 - resId: resId,  
4153 - kpiId: id,  
4154 - flag: flag,  
4155 - warning:isWarning,  
4156 - ident:ident,  
4157 - trend:trend,  
4158 - unit:unit,  
4159 - // Start Wang 2022/2/8 14:28 BUG#273 【性能曲线】测试名称重复  
4160 - // name:kpiName + " " + name,  
4161 - name:kpiName,  
4162 - // End Wang 2022/2/8 14:29  
4163 - subFlag: subFlag,  
4164 - resType: resType  
4165 - };  
4166 - switch (type){  
4167 - case 'w':  
4168 - setKPIAlarmConfig(params);  
4169 - break;  
4170 - case 's':  
4171 - setKpiFilter(params,true);  
4172 - break;  
4173 - case 'm':  
4174 - setKpiFilter(params,false);  
4175 - break;  
4176 - case 't':  
4177 - //性能趋势  
4178 - if ($.inArray('back:details:trend', checkList) == -1) {  
4179 - layer.msg('暂无权限!', {icon: 7, time: 3000}); 4182 + //start lsq 根据kpiid获取是否是指标状态 2022-05-23
  4183 + admin.req({
  4184 + url: common.domainName + '/api-web/manage/kpi/page?' +
  4185 + 'isWarning=&isTrend=&kpiLevel=&ignoreCnt=&startTime=&endTime=&kpiPower=',
  4186 + data: {
  4187 + page:1,limit:99999,
  4188 + kpiName: '',resType: '',kpiIdent: 2,kpiCategory: '',
  4189 + kpiDataType:'',kpiUnit:'',isWarning:'',isTrend:'',
  4190 + kpiLevel:'',ignoreCnt:'',startTime:'',endTime:'',kpiPower:''
  4191 + },
  4192 + success(response) {
  4193 + let arr=[];
  4194 + if (response && response.success) {
  4195 + arr=response.data;
  4196 + let idArr=[];
  4197 + let idStr='';
  4198 + if(id.indexOf(',')!=-1){
  4199 + idArr=id.split(',');
  4200 + idStr=idArr[0];
4180 }else{ 4201 }else{
4181 - // Start Wang 2022/2/8 14:28 BUG#273 【性能曲线】测试名称重复  
4182 - // common.openLineChart(kpiName + " " + name, params);  
4183 - common.openLineChart(kpiName, params);  
4184 - // End Wang 2022/2/8 14:29 4202 + idStr=id;
4185 } 4203 }
4186 - break;  
4187 - case 'n':  
4188 - setKpiPressTimes(params);  
4189 - break;  
4190 - case 'ca-cancel':  
4191 - caCancel(params, $menu);  
4192 - break;  
4193 - case 'ca-add':  
4194 - caAdd(params, $menu);  
4195 - break; 4204 + let isKpi=false;
  4205 + arr.map(item=>{
  4206 + if(idStr==item.kpiId){
  4207 + isKpi=true;
  4208 + }
  4209 + })
  4210 + if(isKpi){
  4211 + let menuboxStr = '<li type="link-status-kpi"><i class="layui-icon">&#xe758;</i>状态指标</li>';
  4212 + $("#detail_menubox_id ul").append(menuboxStr)
  4213 + }
  4214 + } else {
  4215 + // layer.msg('状态指标获取失败!', {icon: 2});
  4216 + }
  4217 + },
  4218 + error(){
  4219 + // layer.msg('状态指标获取失败!', {icon: 2});
4196 } 4220 }
4197 -  
4198 }); 4221 });
  4222 + setTimeout(function (){
  4223 + //end lsq 2022-05-23
  4224 + //菜单点击事件
  4225 + $("#detail_menubox_id ul>li").unbind("click").on("click",function (){
  4226 + var type = $(this).attr("type");
  4227 + var params = {
  4228 + resId: resId,
  4229 + kpiId: id,
  4230 + flag: flag,
  4231 + warning:isWarning,
  4232 + ident:ident,
  4233 + trend:trend,
  4234 + unit:unit,
  4235 + // Start Wang 2022/2/8 14:28 BUG#273 【性能曲线】测试名称重复
  4236 + // name:kpiName + " " + name,
  4237 + name:kpiName,
  4238 + // End Wang 2022/2/8 14:29
  4239 + subFlag: subFlag,
  4240 + resType: resType
  4241 + };
  4242 + switch (type){
  4243 + case 'w':
  4244 + setKPIAlarmConfig(params);
  4245 + break;
  4246 + case 's':
  4247 + setKpiFilter(params,true);
  4248 + break;
  4249 + case 'm':
  4250 + setKpiFilter(params,false);
  4251 + break;
  4252 + case 't':
  4253 + //性能趋势
  4254 + if ($.inArray('back:details:trend', checkList) == -1) {
  4255 + layer.msg('暂无权限!', {icon: 7, time: 3000});
  4256 + }else{
  4257 + // Start Wang 2022/2/8 14:28 BUG#273 【性能曲线】测试名称重复
  4258 + // common.openLineChart(kpiName + " " + name, params);
  4259 + common.openLineChart(kpiName, params);
  4260 + // End Wang 2022/2/8 14:29
  4261 + }
  4262 + break;
  4263 + case 'n':
  4264 + setKpiPressTimes(params);
  4265 + break;
  4266 + case 'ca-cancel':
  4267 + caCancel(params, $menu);
  4268 + break;
  4269 + case 'ca-add':
  4270 + caAdd(params, $menu);
  4271 + break;
  4272 + //lsq 连接状态指标事件2022-05-19
  4273 + case 'link-status-kpi':
  4274 + connectStatus(params);
  4275 + break;
  4276 + }
  4277 + });
  4278 + },300)
4199 }); 4279 });
4200 //点击空白处隐藏弹出菜单 4280 //点击空白处隐藏弹出菜单
4201 $(document).click(function(event){ 4281 $(document).click(function(event){
@@ -121,6 +121,11 @@ const routes = [{ @@ -121,6 +121,11 @@ const routes = [{
121 name: 'pingIndex', 121 name: 'pingIndex',
122 component: () => myImport('views/ping/index'), 122 component: () => myImport('views/ping/index'),
123 }, 123 },
  124 + {
  125 + path: '/vue3/connectScatter',
  126 + name: 'connectScatter',
  127 + component: () => myImport('views/connectScatter/index')
  128 + },
124 ]; 129 ];
125 130
126 // hash模式: createWebHashHistory 131 // hash模式: createWebHashHistory
  1 +<div class="pie-detail-line-container" >
  2 +
  3 + <div class="pie-detail-content">
  4 + <el-row class="detail-content-title">
  5 + <el-col :span="8"></el-col>
  6 + <el-col :span="16" class="pie-flex-end">
  7 + <div class="pie-date-range">
  8 +<!-- <cm-date-range-influx v-if="dateType=='custom'" :keys="keys" @callbackinflux="getInfluxOption" @callbacksure="getOptionData" @callbacktime="callbacktime" @callbackrate="callbackrate"></cm-date-range-influx>-->
  9 + </div>
  10 + <div class="line-filter pie-line-filter">
  11 + <div class="linechartfrequency line-filter-content">
  12 + <div v-if="dateType!='custom'" @click="changeInterval('oneDay')" :class="['line-filter-item', {'active':dateType=='oneDay'}]" data-value="oneDay" >近24小时</div>
  13 + <div v-if="dateType!='custom'" @click="changeInterval('week')" :class="['line-filter-item', {'active':dateType=='week'}]" data-value="week">一周</div>
  14 + <div v-if="dateType!='custom'" @click="changeInterval('month')" :class="['line-filter-item', {'active':dateType=='month'}]" data-value="month">一月</div>
  15 +<!-- <div v-if="dateType!='custom'" @click="changeInterval('YEAR')" :class="['line-filter-item', {'active':dateType=='YEAR'}]" data-value="YEAR">一年</div>-->
  16 +<!-- <div v-if="dateType!='custom'" @click="changeInterval('custom')" :class="['line-filter-item', {'active':dateType=='custom'}]" data-value="custom">自定义</div>-->
  17 +<!-- <div v-if="dateType=='custom'" @click="changeInterval('DAY')" :class="['line-filter-item', {'active':dateType=='custom'}]" data-value="custom">返 回</div>-->
  18 + </div>
  19 + </div>
  20 +
  21 + </el-col>
  22 +
  23 + </el-row>
  24 + <el-row class="detail-content">
  25 + <el-col :span="24" class="detail_linechart">
  26 + <LineChart :optionData="optionData" v-if="optionData"></LineChart>
  27 +
  28 +<!-- <div class="detail_linechart" id="indentKpiLineChart"></div>-->
  29 + <!-- <div class="detail_linechart" id="warningKpiLineChart" style="margin-top:35px;"></div>-->
  30 + <!-- <div class="detail_linechart" id="line-tingyun-trendKpiLineChart" style="margin-top:35px;"></div>-->
  31 +
  32 +
  33 + </el-col>
  34 + </el-row>
  35 + </div>
  36 +
  37 +</div>
  38 +
  1 +export default {
  2 + name: 'pieDetailLine',
  3 + template: '',
  4 + components:{
  5 + 'LineChart': Vue.defineAsyncComponent(
  6 + () => myImport('views/page/components/lineChart/index')
  7 + )
  8 + },
  9 + data() {
  10 + return{}
  11 + },
  12 + setup(props, {attrs, slots, emit}) {
  13 + const {proxy} = Vue.getCurrentInstance();
  14 + let dateType=Vue.ref('oneDay');
  15 + let optionData=Vue.ref('');
  16 + //series接口无数据时默认数据
  17 + let seriesData = Vue.ref([{
  18 + "data": [['2022-05-13','02:00'],['2022-05-15','03:00'],['2022-05-17','04:00']],
  19 + // "name": kpiName.value
  20 + "name": '成功'
  21 + },{
  22 + "data": [['2022-05-14','08:00'],['2022-05-16','09:00'],['2022-05-17','10:00']],
  23 + // "name": kpiName.value
  24 + "name": '失败'
  25 + }]);
  26 + let series = Vue.ref([]);
  27 + let rateData = Vue.ref([]);
  28 + let kpiUnit = Vue.ref('');
  29 + let kpiName = Vue.ref('');//指标名称
  30 + let colorsArr=Vue.ref([
  31 + {
  32 + start: '#46d6d8',
  33 + end: '#2883d0'
  34 + },
  35 + {
  36 + start: '#facf5b',
  37 + end: '#f77623'
  38 + },
  39 + {
  40 + start: '#C04DD8',
  41 + end: '#D81F72'
  42 + },
  43 + {
  44 + start: '#F5A1EB',
  45 + end: '#A04DE2'
  46 + },
  47 + {
  48 + start: '#F36093',
  49 + end: '#FF465C'
  50 + },
  51 + {
  52 + start: '#C2E74D',
  53 + end: '#00AE8B'
  54 + },
  55 + {
  56 + start: '#3DC3FF',
  57 + end: '#01FFFF'
  58 + },
  59 + {
  60 + start: '#B850ED',
  61 + end: '#9062EF'
  62 + },
  63 + {
  64 + start: '#305be6',
  65 + end: '#36a7d3'
  66 + },
  67 + {
  68 + start: '#FFA500',
  69 + end: '#FFEE00'
  70 + },
  71 + {
  72 + start: '#C4E64C',
  73 + end: '#2de078'
  74 + },
  75 + {
  76 + start: '#30ffb3',
  77 + end: '#01FFFF'
  78 + },
  79 + {
  80 + start: '#FF4488',
  81 + end: '#F13EFF'
  82 + },
  83 + {
  84 + start: '#A64CE2',
  85 + end: '#625AE7'
  86 + },
  87 + {
  88 + start: '#5AEBC7',
  89 + end: '#5FC9F8'
  90 + },
  91 + {
  92 + start: '#FFA500',
  93 + end: '#FFEE00'
  94 + },
  95 + {
  96 + start: '#00AAD6',
  97 + end: '#625AE7'
  98 + },
  99 + {
  100 + start: '#E48BDE',
  101 + end: '#FF9262'
  102 + },
  103 + {
  104 + start: '#B2797B',
  105 + end: '#FF4B51'
  106 + },
  107 + {
  108 + start: '#ffe393',
  109 + end: '#feff5b'
  110 + }
  111 + ])
  112 +
  113 + const changeInterval=(val)=>{
  114 + dateType.value=val;
  115 + if(val=='custom'){
  116 + }else{
  117 + getMonthDay();
  118 + getLineChart();
  119 +
  120 + }
  121 + }
  122 +
  123 + const getLineChart=()=>{
  124 + let params=proxy.$route.query
  125 + let resourceId=params.resId;//资源ID
  126 + let kpiId =params.kpiId; //指标ID
  127 + let resType=params.resType;//资源类型
  128 + let idArr=[];
  129 + let idStr='';
  130 + if(kpiId.indexOf(',')!=-1){
  131 + idArr=kpiId.split(',');
  132 + if(idArr.length<=2){
  133 + idStr=idArr[0];
  134 + }else{
  135 + idStr=kpiId;
  136 + }
  137 + }else{
  138 + idStr=kpiId;
  139 + }
  140 + kpiName.value = params.name;//指标名称
  141 + let url = '/api-web/scatter/getByResId?dateType=' + dateType.value +
  142 + '&resId=' + resourceId + '&kpiId=' + idStr + '&resType=' + resType;
  143 + proxy.$http.get(url, {},function (res){
  144 + kpiUnit.value = (!res.data || res.data.kpiUnit == null) ? "" : res.data.kpiUnit;
  145 + if (res.data && res.data.length == 0) {
  146 + rateData.value = {
  147 + series: seriesData.value,
  148 + kpiUnit: kpiUnit.value
  149 + }
  150 + } else {
  151 + rateData.value = res.data;
  152 + }
  153 + setSeries();
  154 + },function (error){
  155 + rateData.value = {
  156 + series: seriesData.value,
  157 + kpiUnit: kpiUnit.value
  158 + }
  159 + setSeries();
  160 + })
  161 +
  162 + }
  163 + const setSeries=()=>{
  164 + series.value=[];
  165 + $.each(rateData.value,function (i,v) {
  166 + if(v.x && v.x.length>0){
  167 + let nameArr=[];
  168 + v.x.map(item=>{
  169 + nameArr.unshift(item);
  170 +
  171 + })
  172 + xAxisData.value=nameArr;
  173 + }
  174 + series.value.push({
  175 + name: v.name,
  176 + type: 'scatter',
  177 + data: v.date,
  178 + /* symbolSize: 12,
  179 + symbol: 'circle',*/
  180 + itemStyle: {
  181 + normal: {
  182 + color: colorsArr.value[i]?colorsArr.value[i].start:colorsArr.value[0].start //图标颜色
  183 + }
  184 + },
  185 + lineStyle: {
  186 + normal: {
  187 + width: 3, //连线粗细
  188 + color: colorsArr.value[i]?colorsArr.value[i].end:colorsArr.value[0].end //连线颜色
  189 + }
  190 + }
  191 + })
  192 + });
  193 + optionDataInit();
  194 + }
  195 + const optionDataInit=()=>{
  196 + optionData.value = {
  197 + tooltip: {
  198 + trigger: 'axis',
  199 + formatter:function (param) {
  200 + // var tips = kpiName.value+" "+param[0].name +"<br/>";
  201 + var tips =kpiName.value +"<br/>";
  202 + $.each(param,function (i,v) {
  203 + // tips += v.marker+" "+v.seriesName + ":"+v.value +kpiUnit.value+"</br>"
  204 + tips += "<div style='display: flex;align-content: flex-start;'><span>"+v.marker+"</span> <span>"+
  205 + v.seriesName + ":"+v.value +"</span></div>"
  206 + });
  207 + return tips;
  208 + }
  209 + },
  210 + legend: {
  211 + show: true
  212 + },
  213 + grid: {
  214 + top: '10%',
  215 + left: '3%',
  216 + right: '4%',
  217 + bottom: '15%',
  218 + containLabel: true
  219 + },
  220 + toolbox: {
  221 + feature: {
  222 + saveAsImage: {
  223 + show: false
  224 + }
  225 + }
  226 + },
  227 + xAxis: {
  228 + type: 'category',
  229 + data: xAxisData.value,
  230 + axisLine: {
  231 + lineStyle: {
  232 + color: '#c9c9c9'
  233 + }
  234 + },
  235 + axisLabel: {
  236 + color: '#232425',
  237 + showMaxLabel: true
  238 + },
  239 + splitArea: {
  240 + show: true,
  241 + areaStyle: {
  242 + color: ['rgba(200,200,200,0.1)', 'transparent'
  243 + ]
  244 + }
  245 + }
  246 + },
  247 + yAxis: {
  248 + // data: ['00:00', '01:00', '02:00', '03:00', '04:00', '05:00', '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00'],
  249 + data:YAxisData.value,
  250 + scale: true,
  251 + boundaryGap: ['10%', '10%'],
  252 + axisLabel: {
  253 + interval:59,//label无间隔
  254 + formatter: '{value} 时'
  255 +
  256 + },
  257 + axisLine: {
  258 + lineStyle: {
  259 + color: '#232425'
  260 + },
  261 + show: false
  262 + },
  263 + axisTick: {
  264 + show: false
  265 + },
  266 + splitLine: {
  267 + lineStyle: {
  268 + color: ['#ccc']
  269 + }
  270 + }
  271 + },
  272 + // x轴拖动
  273 + dataZoom: [
  274 + {
  275 + type: "slider",
  276 + realtime: true, //拖动滚动条时是否动态的更新图表数据
  277 + height: 25, //滚动条高度
  278 + start: 40, //滚动条开始位置(共100等份)
  279 + end: 65 //结束位置(共100等份)
  280 + }
  281 + ],
  282 + series:series.value
  283 + };
  284 + }
  285 +
  286 + //获取近30天
  287 + let xAxisData=Vue.ref([]);
  288 + const getMonthDay=()=>{
  289 + let m=24;
  290 + if(dateType.value=='oneDay'){
  291 + m=24;
  292 + }else if(dateType.value=='week'){
  293 + m=7;
  294 + }else if(dateType.value=='month'){
  295 + m=30;
  296 + }
  297 + let dateArr=[];
  298 + for(let i=0;i<=m;i++){
  299 + let myDate=new Date();
  300 + if(dateType.value=='oneDay'){
  301 + myDate.setHours(myDate.getHours()-i)
  302 + }else if(dateType.value=='week' || dateType.value=='month'){
  303 + myDate.setDate(myDate.getDate() - i);
  304 + }
  305 + let lowData =getDateTime(myDate); //用了上面转年月日的方法
  306 + dateArr.unshift(lowData)
  307 + }
  308 + xAxisData.value=dateArr;
  309 + }
  310 + //获取时间点 转年月日的方法
  311 + const getDateTime=(newDate)=>{
  312 + let dateTime='';
  313 + let year=newDate.getFullYear();//获取当前年
  314 + let month1=(newDate.getMonth()+1)+'';
  315 + let month=timeFormat(month1);//获取当前月
  316 + let day=timeFormat(newDate.getDate());//获取当前日
  317 + let hours=timeFormat(newDate.getHours()+'');//获取当前时
  318 + let minutes=timeFormat(newDate.getMinutes()+'');//获取当前分
  319 + let seconds=timeFormat(newDate.getSeconds()+'');//获取当前秒
  320 + if(day < 10){
  321 + day = '0'+day;
  322 + }
  323 + if(dateType.value=='oneDay'){
  324 + dateTime= year+'-'+month+'-'+day+' '+hours+':00';//+minutes;//+':'+seconds;
  325 + }else{
  326 + dateTime= year+'-'+month+'-'+day;//+' '+hours+':'+minutes+':'+seconds;
  327 + }
  328 + return dateTime;
  329 + }
  330 + //转换个位数为 00
  331 + let timeFormat =(number)=> {
  332 + return number.length == 1 ? ('0' + number) : number
  333 + }
  334 + //00:00-23:59数据
  335 + let YAxisData=Vue.ref([]);
  336 + let getYAxisData=()=>{
  337 + let arr1=[];
  338 + for(let i=0;i<24;i++){
  339 + for(let j=0;j<60;j++){
  340 + if(i<10){
  341 + if(j<10){
  342 + arr1.push('0'+i+':0'+j);
  343 + }else{
  344 + arr1.push('0'+i+':'+j);
  345 + }
  346 +
  347 + }else{
  348 + if(j<10){
  349 + arr1.push(i+':0'+j);
  350 + }else{
  351 + arr1.push(i+':'+j);
  352 + }
  353 + }
  354 + }
  355 +
  356 + }
  357 + YAxisData.value=arr1;
  358 + }
  359 + // 挂载完
  360 + Vue.onMounted(() => {
  361 + getYAxisData();
  362 + getMonthDay();
  363 + getLineChart();
  364 + })
  365 + return {
  366 + xAxisData,
  367 + YAxisData,
  368 + getMonthDay,
  369 + timeFormat,
  370 + dateType,
  371 + optionData,
  372 + seriesData,
  373 + series,
  374 + rateData,
  375 + kpiUnit,
  376 + kpiName,
  377 + optionDataInit,
  378 + getLineChart,
  379 + changeInterval
  380 + }
  381 + }
  382 +}
@@ -216,6 +216,11 @@ const routes = [{ @@ -216,6 +216,11 @@ const routes = [{
216 name: 'pingIndex', 216 name: 'pingIndex',
217 component: () => myImport('views/ping/index'), 217 component: () => myImport('views/ping/index'),
218 }, 218 },
  219 + {
  220 + path: '/vue3/connectScatter',
  221 + name: 'connectScatter',
  222 + component: () => myImport('views/connectScatter/index')
  223 + },
219 ]; 224 ];
220 225
221 // hash模式: createWebHashHistory 226 // hash模式: createWebHashHistory