nodeDetail.vue 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073
  1. <template>
  2. <div class="detail_box">
  3. <div v-if="AnalystData.grpc" style="border-bottom:1px dashed #eee;padding-bottom:20px">
  4. <div class='titlesty'>grpc信息</div>
  5. <div style='text-indent: 18px'>
  6. <div id='main1' class="echartsbox" v-loading="loading" style="width:100%;height:300px;"></div>
  7. </div>
  8. </div>
  9. <div v-if="AnalystData.http" style="border-bottom:1px dashed #eee;padding-bottom:20px">
  10. <div class='titlesty'>https信息</div>
  11. <div style='text-indent: 18px'>
  12. <div id='main2' class="echartsbox" style='width:100%;height:300px'></div>
  13. </div>
  14. </div>
  15. <div v-if="AnalystData.kafka" style="border-bottom:1px dashed #eee;padding-bottom:20px">
  16. <div class='titlesty'>kafka信息</div>
  17. <div style='text-indent: 18px'>
  18. <div id='main3' class="echartsbox" style='width:100%;height:300px'></div>
  19. </div>
  20. </div>
  21. </div>
  22. </template>
  23. <script>
  24. import resize from './mixins/resize'
  25. import moment from 'moment'
  26. export default {
  27. mixins: [resize],
  28. data(){
  29. return{
  30. queryParams:{
  31. start_time:1699941690,
  32. end_time:1699945290,
  33. // app_alias:'UNSET',
  34. // service_name:'frontend',
  35. app_alias:'',
  36. service_name:'',
  37. percentile:0.95
  38. },
  39. AnalystData:{},
  40. // topoUrl:'http://observe-front.cestong.com.cn',
  41. topoUrl:'',
  42. httpChart:null,
  43. grpcChart:null,
  44. kafkaChart:null,
  45. app_alias:'',
  46. }
  47. },
  48. watch:{
  49. // option:{
  50. // handler(newVal,oldVal){
  51. // if (this.chart) {
  52. // if (newVal) {
  53. // this.chart.setOption(newVal);
  54. // } else {
  55. // this.chart.setOption(oldVal);
  56. // }
  57. // }
  58. // },
  59. // deep: true
  60. // },
  61. },
  62. created(){
  63. this.queryParams.start_time = this.GetRequest().start_time; //点击应用拓扑节点获取到id
  64. this.queryParams.end_time = this.GetRequest().end_time; //点击应用拓扑节点获取到id
  65. this.queryParams.app_alias = this.GetRequest().app_alias; //点击应用拓扑节点获取到id
  66. this.app_alias = this.GetRequest().app_alias;
  67. this.queryParams.service_name = this.GetRequest().service_name; //点击应用拓扑节点获取到id
  68. this.queryParams.percentile = this.GetRequest().percentile; //点击应用拓扑节点获取到id
  69. },
  70. mounted(){
  71. if (this.queryParams.app_alias != undefined) {
  72. this.getList();
  73. }
  74. setTimeout(()=>{
  75. if(this.AnalystData.grpc != undefined){
  76. this.grpcInitChart(this.AnalystData.grpc)
  77. }
  78. if(this.AnalystData.http != undefined){
  79. this.httpInitChart(this.AnalystData.http)
  80. }
  81. if(this.AnalystData.kafka != undefined){
  82. this.kafkaInitChart(this.AnalystData.kafka)
  83. }
  84. // var iframeH = document.getElementById("detail_box").scrollHeight;
  85. // console.log(iframeH,'iframeH')
  86. // this.h=iframeH;
  87. // window.parent.postMessage({ data: iframeH }, "*");
  88. // var screenH = document.documentElement.clientHeight;
  89. // this.h = screenH;
  90. },2000)
  91. },
  92. methods:{
  93. getList() {
  94. this.loading = true
  95. // this.topoUrl = window.location.host;
  96. this.$http({
  97. // url: `${this.topoUrl}/re/api/v1/service/side`,
  98. url: '/re/api/v1/service/side',
  99. method: "get",
  100. params: this.queryParams
  101. }).then(res => {
  102. console.log(res,'res====')
  103. if(res.data.code == 200){
  104. console.log(res,'节点详情')
  105. console.log(res.data.data,'front 获取节点的信息')
  106. this.loading = false;
  107. this.AnalystData= res.data.data;
  108. }
  109. });
  110. },
  111. GetRequest() {
  112. var url = window.location.href; //获取url中"?"符后的字串
  113. // var url = `http://123.56.75.55:8208/#/iframe/nodeDetail?endpoint_id=1&id=81&ip=5.3.4.5&cmdb_tag=1`;
  114. var theRequest = new Object();
  115. if (url.indexOf("?") != -1) {
  116. // var str = url.substring(1);
  117. var str = url.substring(url.indexOf('?')+1,url.length);
  118. var strs = str.split("&");
  119. for (var i = 0; i < strs.length; i++) {
  120. theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]);
  121. }
  122. }
  123. return theRequest;
  124. },
  125. grpcInitChart(tmpData) {
  126. console.log('grpc是否有渲染')
  127. let _this = this;
  128. this.grpcChart = this.$echarts5.init(document.getElementById('main1'))
  129. console.log(this.grpcChart ,'echarts=====================')
  130. this.grpcChart.clear();
  131. let option = {
  132. title: {
  133. text: 'Latency',
  134. subtext: 'ms',
  135. textStyle:{
  136. fontSize:14
  137. },
  138. },
  139. grid: {
  140. left: '5%',
  141. right: '7%',
  142. bottom: '7%',
  143. containLabel: true
  144. },
  145. tooltip: {
  146. showDelay: 0,
  147. formatter: function (params) {
  148. let newParams = moment(params.data[0]).format('YYYY-MM-DD HH:mm:ss');
  149. let time = newParams+"<br/>"+ params.data[1]+"ms"
  150. return time;
  151. },
  152. axisPointer: {
  153. show: true,
  154. type: 'cross',
  155. lineStyle: {
  156. type: 'dashed',
  157. width: 1
  158. }
  159. }
  160. },
  161. toolbox: {
  162. show:true,
  163. showTitle: true,
  164. feature: {
  165. rect: {
  166. show: true,
  167. title: 'Trace选择'
  168. },
  169. },
  170. left:"57%", //组件离容器左侧的距离,'left', 'center', 'right','20%'
  171. top:"3%", //组件离容器上侧的距离,'top', 'middle', 'bottom','20%'
  172. right:"auto", //组件离容器右侧的距离,'20%'
  173. bottom:"auto",
  174. },
  175. brush: {
  176. toolbox: ['rect'],
  177. xAxisIndex: 0,
  178. throttleType:'debounce',
  179. throttleDelay:600
  180. },
  181. legend: {
  182. data: ['Success', 'Failed'],
  183. left: 'center',
  184. bottom: -2,
  185. itemGap: 100,
  186. textStyle: {//文字颜色
  187. fontSize: 12,
  188. padding:[0,3],//文字与图形之间的左右间距
  189. rich:{
  190. labelName:{
  191. fontSize:14,
  192. color:'#333',
  193. fontWeight:500
  194. }
  195. }
  196. },
  197. formatter: function (params) {
  198. // 获取legend显示内容
  199. let data = tmpData;
  200. let sl,fl;
  201. if(data.success!=null){
  202. sl = tmpData.success.length;
  203. }else{
  204. sl = 0
  205. }
  206. if( data.failed!=null){
  207. fl = tmpData.failed.length;
  208. }else{
  209. fl = 0
  210. }
  211. var target;
  212. if(params == 'Success'){
  213. target = sl;
  214. }else if(params == 'Failed'){
  215. target = fl;
  216. }
  217. return target != undefined?params +' '+`{labelName|${target}}`:params
  218. },
  219. },
  220. xAxis: [
  221. {
  222. // type: 'category',
  223. type:'time',
  224. scale: true,
  225. gridIndex:0,
  226. axisLabel: {
  227. textStyle: {
  228. fontSize: 12,
  229. textAlign:'center'
  230. },
  231. formatter: function(params) {
  232. let newParams = moment(params).format('YYYY-MM-DD HH:mm:ss');
  233. let newArr = newParams.split(' ')
  234. let time = newArr[0] + "\n" + newArr[1]
  235. return time;
  236. }
  237. },
  238. splitLine: {
  239. show: true
  240. },
  241. }
  242. ],
  243. yAxis: [
  244. {
  245. type: 'value',
  246. scale: true,
  247. gridIndex:0,
  248. axisLabel: {
  249. formatter: '{value}'
  250. },
  251. axisLine:{
  252. show:true
  253. },
  254. axisTick:{
  255. show:true
  256. },
  257. splitLine: {
  258. show: true
  259. },
  260. data:[0,2500,5000,7500,10000],
  261. }
  262. ],
  263. series: [
  264. {
  265. name: 'Success',
  266. type: 'scatter',
  267. emphasis: {
  268. focus: 'series'
  269. },
  270. //设置散点图样式
  271. itemStyle:{
  272. color:'#13ce66'
  273. },
  274. symbolSize:10,//设置散点的大小
  275. data:tmpData.success,
  276. markArea: {
  277. silent: true,
  278. itemStyle: {
  279. color: 'transparent',
  280. borderWidth: 0,
  281. borderType: 'dashed'
  282. },
  283. },
  284. },
  285. {
  286. name: 'Failed',
  287. type: 'scatter',
  288. emphasis: {
  289. focus: 'series'
  290. },
  291. itemStyle:{
  292. color:'#ff4949'
  293. },
  294. // prettier-ignore
  295. data:tmpData.failed,
  296. // data:[],
  297. markArea: {
  298. silent: true,
  299. itemStyle: {
  300. color: 'transparent',
  301. borderWidth: 0,
  302. borderType: 'dashed'
  303. },
  304. },
  305. }
  306. ]
  307. }
  308. this.grpcChart.setOption(option,true)
  309. this.grpcChart.off("brushSelected");
  310. //框选选择数据
  311. this.grpcChart.on('brushSelected', (params) => {
  312. console.log(params,'框选事件')
  313. var brushComponent = params.batch[0];
  314. let successIndexList=[];
  315. let failIndexList =[];
  316. let successList=[];
  317. let failList=[];
  318. if(brushComponent.selected.length>1){
  319. successIndexList = brushComponent.selected[0].dataIndex
  320. failIndexList = brushComponent.selected[1].dataIndex
  321. }else{
  322. if(brushComponent.selected[0].seriesName !=undefined){
  323. if(brushComponent.selected[0].seriesName =="Failed"){
  324. failIndexList = brushComponent.selected[0].dataIndex
  325. }else{
  326. successIndexList = brushComponent.selected[0].dataIndex
  327. }
  328. }
  329. }
  330. if(successIndexList.length>0){
  331. for(let i = 0;i<tmpData.success.length;i++){
  332. for(let j=0;j<successIndexList.length;j++){
  333. if(successIndexList[j] == i){
  334. successList.push(tmpData.success[i])
  335. }
  336. }
  337. }
  338. }
  339. if(failIndexList.length>0){
  340. for(let k=0;k<tmpData.failed.length;k++){
  341. for(let l=0;l<failIndexList.length;l++){
  342. if(failIndexList[l] == k){
  343. failList.push(tmpData.failed[k])
  344. }
  345. }
  346. }
  347. }
  348. let arr =successList.concat(failList);
  349. let dataRange={};
  350. if(arr.length>0){
  351. let timeArr =[];
  352. let valueArr=[];
  353. for(let m=0;m<arr.length;m++){
  354. timeArr.push(Math.round(Date.parse(arr[m][0])/1000));
  355. valueArr.push(arr[m][1]);
  356. }
  357. let minTime = Math.min(...timeArr);
  358. let maxTime = Math.max(...timeArr);
  359. let minValue = Math.min(...valueArr);
  360. let maxValue = Math.max(...valueArr)
  361. if(minTime == maxTime){
  362. minTime = minTime-1;
  363. maxTime = maxTime+1;
  364. }
  365. if(minValue == maxValue){
  366. minValue = minValue-1;
  367. maxValue = maxValue+1;
  368. }
  369. //看是否有成功节点
  370. if(successIndexList.length>0){
  371. dataRange = {
  372. start_time:minTime,
  373. end_time:maxTime,
  374. min_duration:minValue,
  375. max_duration:maxValue,
  376. app_alias:this.app_alias
  377. }
  378. }else{
  379. dataRange = {
  380. start_time:minTime,
  381. end_time:maxTime,
  382. min_duration:minValue,
  383. max_duration:maxValue,
  384. failed:true,
  385. app_alias:this.app_alias
  386. }
  387. }
  388. let timeAndDuration = JSON.stringify(dataRange);
  389. // this.$router.push({
  390. // path:'/latency/index',
  391. // query:{
  392. // data:timeAndDuration
  393. // }
  394. // })
  395. let href = this.$router.resolve({
  396. path:'/latency/index',
  397. query:{
  398. data:timeAndDuration
  399. }
  400. })
  401. console.log(href)
  402. window.open(window.location.origin+"/"+href.href,"_blank")
  403. this.grpcChart.dispatchAction({
  404. type: 'brush',//选择action行为
  405. areas:[]//areas表示选框的集合,此时为空即可。
  406. });
  407. }
  408. });
  409. // this.chart.on("legendinverseselect", (params) => {
  410. // console.log(params)
  411. // })
  412. },
  413. httpInitChart(tmpData) {
  414. let _this = this;
  415. this.httpChart = this.$echarts5.init(document.getElementById('main2'))
  416. console.log(this.httpChart ,'echarts=====================')
  417. // var myEchart = this.$el.getElementsByClassName('echartsbox');
  418. // for(var i = 0; i < myEchart.length; i++){
  419. // var myChart = this.$echarts5.init(myEchart[i]);
  420. // }
  421. this.httpChart.clear();
  422. let option = {
  423. title: {
  424. text: 'Latency',
  425. subtext: 'ms',
  426. textStyle:{
  427. fontSize:14
  428. },
  429. },
  430. grid: {
  431. left: '3%',
  432. right: '7%',
  433. bottom: '7%',
  434. containLabel: true
  435. },
  436. tooltip: {
  437. showDelay: 0,
  438. formatter: function (params) {
  439. let newParams = moment(params.data[0]).format('YYYY-MM-DD HH:mm:ss');
  440. let time = newParams+"<br/>"+ params.data[1]+"ms"
  441. return time;
  442. },
  443. axisPointer: {
  444. show: true,
  445. type: 'cross',
  446. lineStyle: {
  447. type: 'dashed',
  448. width: 1
  449. }
  450. }
  451. },
  452. toolbox: {
  453. show:true,
  454. showTitle: true,
  455. feature: {
  456. rect: {
  457. show: true,
  458. title: 'Trace选择'
  459. },
  460. },
  461. left:"57%", //组件离容器左侧的距离,'left', 'center', 'right','20%'
  462. top:"3%", //组件离容器上侧的距离,'top', 'middle', 'bottom','20%'
  463. right:"auto", //组件离容器右侧的距离,'20%'
  464. bottom:"auto",
  465. },
  466. brush: {
  467. toolbox: ['rect'],
  468. xAxisIndex: 0,
  469. throttleType:'debounce',
  470. throttleDelay:600
  471. },
  472. legend: {
  473. data: ['Success', 'Failed'],
  474. left: 'center',
  475. bottom: -2,
  476. itemGap: 100,
  477. textStyle: {//文字颜色
  478. fontSize: 12,
  479. padding:[0,3],//文字与图形之间的左右间距
  480. rich:{
  481. labelName:{
  482. fontSize:14,
  483. color:'#333',
  484. fontWeight:500
  485. }
  486. }
  487. },
  488. formatter: function (params) {
  489. // 获取legend显示内容
  490. let data = tmpData;
  491. let sl,fl;
  492. if(data.success!=null){
  493. sl = tmpData.success.length;
  494. }else{
  495. sl = 0
  496. }
  497. if( data.failed!=null){
  498. fl = tmpData.failed.length;
  499. }else{
  500. fl = 0
  501. }
  502. var target;
  503. if(params == 'Success'){
  504. target = sl;
  505. }else if(params == 'Failed'){
  506. target = fl;
  507. }
  508. return target != undefined?params +' '+`{labelName|${target}}`:params
  509. },
  510. },
  511. xAxis: [
  512. {
  513. // type: 'category',
  514. type:'time',
  515. scale: true,
  516. gridIndex:0,
  517. axisLabel: {
  518. textStyle: {
  519. fontSize: 12,
  520. textAlign:'center'
  521. },
  522. formatter: function(params) {
  523. let newParams = moment(params).format('YYYY-MM-DD HH:mm:ss');
  524. let newArr = newParams.split(' ')
  525. let time = newArr[0] + "\n" + newArr[1]
  526. return time;
  527. }
  528. },
  529. splitLine: {
  530. show: true
  531. },
  532. }
  533. ],
  534. yAxis: [
  535. {
  536. type: 'value',
  537. scale: true,
  538. gridIndex:0,
  539. axisLabel: {
  540. formatter: '{value}'
  541. },
  542. axisLine:{
  543. show:true
  544. },
  545. axisTick:{
  546. show:true
  547. },
  548. splitLine: {
  549. show: true
  550. },
  551. data:[0,2500,5000,7500,10000],
  552. }
  553. ],
  554. series: [
  555. {
  556. name: 'Success',
  557. type: 'scatter',
  558. emphasis: {
  559. focus: 'series'
  560. },
  561. //设置散点图样式
  562. itemStyle:{
  563. color:'#13ce66'
  564. },
  565. symbolSize:10,//设置散点的大小
  566. data:tmpData.success,
  567. markArea: {
  568. silent: true,
  569. itemStyle: {
  570. color: 'transparent',
  571. borderWidth: 0,
  572. borderType: 'dashed'
  573. },
  574. },
  575. },
  576. {
  577. name: 'Failed',
  578. type: 'scatter',
  579. emphasis: {
  580. focus: 'series'
  581. },
  582. itemStyle:{
  583. color:'#ff4949'
  584. },
  585. // prettier-ignore
  586. data:tmpData.failed,
  587. // data:[],
  588. markArea: {
  589. silent: true,
  590. itemStyle: {
  591. color: 'transparent',
  592. borderWidth: 0,
  593. borderType: 'dashed'
  594. },
  595. },
  596. }
  597. ]
  598. }
  599. this.httpChart.setOption(option,true)
  600. this.httpChart.off("brushSelected");
  601. //框选选择数据
  602. this.httpChart.on('brushSelected', (params) => {
  603. console.log(params,'框选事件')
  604. var brushComponent = params.batch[0];
  605. let successIndexList=[];
  606. let failIndexList =[];
  607. let successList=[];
  608. let failList=[];
  609. if(brushComponent.selected.length>1){
  610. successIndexList = brushComponent.selected[0].dataIndex
  611. failIndexList = brushComponent.selected[1].dataIndex
  612. }else{
  613. if(brushComponent.selected[0].seriesName !=undefined){
  614. if(brushComponent.selected[0].seriesName =="Failed"){
  615. failIndexList = brushComponent.selected[0].dataIndex
  616. }else{
  617. successIndexList = brushComponent.selected[0].dataIndex
  618. }
  619. }
  620. }
  621. if(successIndexList.length>0){
  622. for(let i = 0;i<tmpData.success.length;i++){
  623. for(let j=0;j<successIndexList.length;j++){
  624. if(successIndexList[j] == i){
  625. successList.push(tmpData.success[i])
  626. }
  627. }
  628. }
  629. }
  630. if(failIndexList.length>0){
  631. for(let k=0;k<tmpData.failed.length;k++){
  632. for(let l=0;l<failIndexList.length;l++){
  633. if(failIndexList[l] == k){
  634. failList.push(tmpData.failed[k])
  635. }
  636. }
  637. }
  638. }
  639. let arr =successList.concat(failList);
  640. let dataRange={};
  641. if(arr.length>0){
  642. let timeArr =[];
  643. let valueArr=[];
  644. for(let m=0;m<arr.length;m++){
  645. timeArr.push(Math.round(Date.parse(arr[m][0])/1000));
  646. valueArr.push(arr[m][1]);
  647. }
  648. let minTime = Math.min(...timeArr);
  649. let maxTime = Math.max(...timeArr);
  650. let minValue = Math.min(...valueArr);
  651. let maxValue = Math.max(...valueArr)
  652. if(minTime == maxTime){
  653. minTime = minTime-1;
  654. maxTime = maxTime+1;
  655. }
  656. if(minValue == maxValue){
  657. minValue = minValue-1;
  658. maxValue = maxValue+1;
  659. }
  660. //看是否有成功节点
  661. if(successIndexList.length>0){
  662. dataRange = {
  663. start_time:minTime,
  664. end_time:maxTime,
  665. min_duration:minValue,
  666. max_duration:maxValue,
  667. app_alias:this.app_alias
  668. }
  669. }else{
  670. dataRange = {
  671. start_time:minTime,
  672. end_time:maxTime,
  673. min_duration:minValue,
  674. max_duration:maxValue,
  675. failed:true,
  676. app_alias:this.app_alias
  677. }
  678. }
  679. let timeAndDuration = JSON.stringify(dataRange);
  680. // this.$router.push({
  681. // path:'/latency/index',
  682. // query:{
  683. // data:timeAndDuration
  684. // }
  685. // })
  686. let href = this.$router.resolve({
  687. path:'/latency/index',
  688. query:{
  689. data:timeAndDuration
  690. }
  691. })
  692. console.log(href)
  693. window.open(window.location.origin+"/"+href.href,"_blank")
  694. this.httpChart.dispatchAction({
  695. type: 'brush',//选择action行为
  696. areas:[]//areas表示选框的集合,此时为空即可。
  697. });
  698. }
  699. });
  700. // this.chart.on("legendinverseselect", (params) => {
  701. // console.log(params)
  702. // })
  703. },
  704. kafkaInitChart(tmpData) {
  705. let _this = this;
  706. this.kafkaChart = this.$echarts5.init(document.getElementById('main3'))
  707. console.log(this.kafkaChart ,'echarts=====================')
  708. // var myEchart = this.$el.getElementsByClassName('echartsbox');
  709. // for(var i = 0; i < myEchart.length; i++){
  710. // var myChart = this.$echarts5.init(myEchart[i]);
  711. // }
  712. this.kafkaChart.clear();
  713. let option = {
  714. title: {
  715. text: 'Latency',
  716. subtext: 'ms',
  717. textStyle:{
  718. fontSize:14
  719. },
  720. },
  721. grid: {
  722. left: '3%',
  723. right: '7%',
  724. bottom: '7%',
  725. containLabel: true
  726. },
  727. tooltip: {
  728. showDelay: 0,
  729. formatter: function (params) {
  730. let newParams = moment(params.data[0]).format('YYYY-MM-DD HH:mm:ss');
  731. let time = newParams+"<br/>"+ params.data[1]+"ms"
  732. return time;
  733. },
  734. axisPointer: {
  735. show: true,
  736. type: 'cross',
  737. lineStyle: {
  738. type: 'dashed',
  739. width: 1
  740. }
  741. }
  742. },
  743. toolbox: {
  744. show:true,
  745. showTitle: true,
  746. feature: {
  747. rect: {
  748. show: true,
  749. title: 'Trace选择'
  750. },
  751. },
  752. left:"57%", //组件离容器左侧的距离,'left', 'center', 'right','20%'
  753. top:"3%", //组件离容器上侧的距离,'top', 'middle', 'bottom','20%'
  754. right:"auto", //组件离容器右侧的距离,'20%'
  755. bottom:"auto",
  756. },
  757. brush: {
  758. toolbox: ['rect'],
  759. xAxisIndex: 0,
  760. throttleType:'debounce',
  761. throttleDelay:600
  762. },
  763. legend: {
  764. data: ['Success', 'Failed'],
  765. left: 'center',
  766. bottom: -2,
  767. itemGap: 100,
  768. textStyle: {//文字颜色
  769. fontSize: 12,
  770. padding:[0,3],//文字与图形之间的左右间距
  771. rich:{
  772. labelName:{
  773. fontSize:14,
  774. color:'#333',
  775. fontWeight:500
  776. }
  777. }
  778. },
  779. formatter: function (params) {
  780. // 获取legend显示内容
  781. let data = tmpData;
  782. let sl,fl;
  783. if(data.success!=null){
  784. sl = tmpData.success.length;
  785. }else{
  786. sl = 0
  787. }
  788. if( data.failed!=null){
  789. fl = tmpData.failed.length;
  790. }else{
  791. fl = 0
  792. }
  793. var target;
  794. if(params == 'Success'){
  795. target = sl;
  796. }else if(params == 'Failed'){
  797. target = fl;
  798. }
  799. return target != undefined?params +' '+`{labelName|${target}}`:params
  800. },
  801. },
  802. xAxis: [
  803. {
  804. // type: 'category',
  805. type:'time',
  806. scale: true,
  807. gridIndex:0,
  808. axisLabel: {
  809. textStyle: {
  810. fontSize: 12,
  811. textAlign:'center'
  812. },
  813. formatter: function(params) {
  814. let newParams = moment(params).format('YYYY-MM-DD HH:mm:ss');
  815. let newArr = newParams.split(' ')
  816. let time = newArr[0] + "\n" + newArr[1]
  817. return time;
  818. }
  819. },
  820. splitLine: {
  821. show: true
  822. },
  823. }
  824. ],
  825. yAxis: [
  826. {
  827. type: 'value',
  828. scale: true,
  829. gridIndex:0,
  830. axisLabel: {
  831. formatter: '{value}'
  832. },
  833. axisLine:{
  834. show:true
  835. },
  836. axisTick:{
  837. show:true
  838. },
  839. splitLine: {
  840. show: true
  841. },
  842. data:[0,2500,5000,7500,10000],
  843. }
  844. ],
  845. series: [
  846. {
  847. name: 'Success',
  848. type: 'scatter',
  849. emphasis: {
  850. focus: 'series'
  851. },
  852. //设置散点图样式
  853. itemStyle:{
  854. color:'#13ce66'
  855. },
  856. symbolSize:10,//设置散点的大小
  857. data:tmpData.success,
  858. markArea: {
  859. silent: true,
  860. itemStyle: {
  861. color: 'transparent',
  862. borderWidth: 0,
  863. borderType: 'dashed'
  864. },
  865. },
  866. },
  867. {
  868. name: 'Failed',
  869. type: 'scatter',
  870. emphasis: {
  871. focus: 'series'
  872. },
  873. itemStyle:{
  874. color:'#ff4949'
  875. },
  876. // prettier-ignore
  877. data:tmpData.failed,
  878. // data:[],
  879. markArea: {
  880. silent: true,
  881. itemStyle: {
  882. color: 'transparent',
  883. borderWidth: 0,
  884. borderType: 'dashed'
  885. },
  886. },
  887. }
  888. ]
  889. }
  890. this.kafkaChart.setOption(option,true)
  891. this.kafkaChart.off("brushSelected");
  892. //框选选择数据
  893. this.kafkaChart.on('brushSelected', (params) => {
  894. console.log(params,'框选事件')
  895. var brushComponent = params.batch[0];
  896. let successIndexList=[];
  897. let failIndexList =[];
  898. let successList=[];
  899. let failList=[];
  900. if(brushComponent.selected.length>1){
  901. successIndexList = brushComponent.selected[0].dataIndex
  902. failIndexList = brushComponent.selected[1].dataIndex
  903. }else{
  904. if(brushComponent.selected[0].seriesName !=undefined){
  905. if(brushComponent.selected[0].seriesName =="Failed"){
  906. failIndexList = brushComponent.selected[0].dataIndex
  907. }else{
  908. successIndexList = brushComponent.selected[0].dataIndex
  909. }
  910. }
  911. }
  912. if(successIndexList.length>0){
  913. for(let i = 0;i<tmpData.success.length;i++){
  914. for(let j=0;j<successIndexList.length;j++){
  915. if(successIndexList[j] == i){
  916. successList.push(tmpData.success[i])
  917. }
  918. }
  919. }
  920. }
  921. if(failIndexList.length>0){
  922. for(let k=0;k<tmpData.failed.length;k++){
  923. for(let l=0;l<failIndexList.length;l++){
  924. if(failIndexList[l] == k){
  925. failList.push(tmpData.failed[k])
  926. }
  927. }
  928. }
  929. }
  930. let arr =successList.concat(failList);
  931. let dataRange={};
  932. if(arr.length>0){
  933. let timeArr =[];
  934. let valueArr=[];
  935. for(let m=0;m<arr.length;m++){
  936. timeArr.push(Math.round(Date.parse(arr[m][0])/1000));
  937. valueArr.push(arr[m][1]);
  938. }
  939. let minTime = Math.min(...timeArr);
  940. let maxTime = Math.max(...timeArr);
  941. let minValue = Math.min(...valueArr);
  942. let maxValue = Math.max(...valueArr)
  943. if(minTime == maxTime){
  944. minTime = minTime-1;
  945. maxTime = maxTime+1;
  946. }
  947. if(minValue == maxValue){
  948. minValue = minValue-1;
  949. maxValue = maxValue+1;
  950. }
  951. //看是否有成功节点
  952. if(successIndexList.length>0){
  953. dataRange = {
  954. start_time:minTime,
  955. end_time:maxTime,
  956. min_duration:minValue,
  957. max_duration:maxValue,
  958. app_alias:this.app_alias
  959. }
  960. }else{
  961. dataRange = {
  962. start_time:minTime,
  963. end_time:maxTime,
  964. min_duration:minValue,
  965. max_duration:maxValue,
  966. failed:true,
  967. app_alias:this.app_alias
  968. }
  969. }
  970. let timeAndDuration = JSON.stringify(dataRange);
  971. // this.$router.push({
  972. // path:'/latency/index',
  973. // query:{
  974. // data:timeAndDuration
  975. // }
  976. // })
  977. let href = this.$router.resolve({
  978. path:'/latency/index',
  979. query:{
  980. data:timeAndDuration
  981. }
  982. })
  983. console.log(href)
  984. window.open(window.location.origin+"/"+href.href,"_blank")
  985. this.kafkaChart.dispatchAction({
  986. type: 'brush',//选择action行为
  987. areas:[]//areas表示选框的集合,此时为空即可。
  988. });
  989. }
  990. });
  991. // this.chart.on("legendinverseselect", (params) => {
  992. // console.log(params)
  993. // })
  994. },
  995. }
  996. }
  997. </script>
  998. <style lang="scss" scoped>
  999. .detail_box{
  1000. background:#fff;
  1001. margin-top: -20px;
  1002. .titlesty{
  1003. font-size: 14px;
  1004. font-weight: bold;
  1005. height: 32px;
  1006. line-height: 32px;
  1007. background: rgb(238, 238, 238);
  1008. color: rgb(51, 51, 51);
  1009. padding-left: 20px;
  1010. margin: 20px auto;
  1011. padding-left: 20px;
  1012. padding-right: 15px;
  1013. background: #eee;
  1014. color:#333;
  1015. }
  1016. }
  1017. </style>>