Merge branch 'dev-3.5' of https://git.mesalab.cn/nezha/nezha-fronted into dev-3.5
24
nezha-fronted/package-lock.json
generated
@@ -5943,6 +5943,30 @@
|
||||
"resolved": "https://registry.npmjs.org/d3-random/-/d3-random-2.2.2.tgz",
|
||||
"integrity": "sha512-0D9P8TRj6qDAtHhRQn6EfdOtHMfsUWanl3yb/84C4DqpZ+VsgfI5iTVRNRbELCfNvRfpMr8OrqqUTQ6ANGCijw=="
|
||||
},
|
||||
"d3-sankey": {
|
||||
"version": "0.12.3",
|
||||
"resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz",
|
||||
"integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==",
|
||||
"requires": {
|
||||
"d3-array": "1 - 2",
|
||||
"d3-shape": "^1.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3-path": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
|
||||
"integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
|
||||
},
|
||||
"d3-shape": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
|
||||
"integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
|
||||
"requires": {
|
||||
"d3-path": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"d3-scale": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"cytoscape": "^3.15.2",
|
||||
"d3": "^6.7.0",
|
||||
"d3-hexbin": "^0.2.2",
|
||||
"d3-sankey": "^0.12.3",
|
||||
"d3-zoom": "^3.0.0",
|
||||
"echarts": "^5.2.2",
|
||||
"element-ui": "^2.15.3",
|
||||
|
||||
@@ -427,6 +427,7 @@ td .nz-icon-gear:before {
|
||||
}
|
||||
.chart-bar,
|
||||
.chart-gauge,
|
||||
.chart-sankey,
|
||||
.chart-time-series,
|
||||
.chart-treemap,
|
||||
.chart-pie,
|
||||
|
||||
@@ -449,8 +449,8 @@
|
||||
}
|
||||
.leaflet-pane.leaflet-my-pane {
|
||||
position: absolute;
|
||||
top: -150px;
|
||||
left: -175px;
|
||||
top: -0px;
|
||||
left: -0px;
|
||||
|
||||
.leaflet-tooltip {
|
||||
transform: unset !important;
|
||||
|
||||
1
nezha-fronted/src/assets/img/starCloud1.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 358.52 351.84"><defs><style>.cls-1{fill:#080430;}.cls-2{fill:#0a093a;}</style></defs><title>Gas-1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M79.83,335.09c33.16-34,60.94-32.19,107.59-41.09,6.37-1.22,13.19-2.6,17.72-7.24,8.86-9.07,4.05-24,5.16-36.64,1.86-21.09,20.94-36.07,39.18-46.81a395,395,0,0,1,62.72-29.84c6.13-2.28,12.5-4.5,17.37-8.87,11.86-10.6,10.78-29.42,6.5-44.74s-10.84-31.23-6.74-46.6C332.4,61.78,341,52.73,348,43.13s12.93-21.62,9.59-33c-1.19-4.06-3.81-8-7.79-9.44-2.9-1-6.1-.66-9.11,0-24.6,5.3-42.89,25.57-57.87,45.78s-29.31,42.29-51.34,54.44c-19.76,10.9-44,12.73-62.16,26.16-20.21,15-28.35,40.75-38.3,63.84s-25.94,49.95-51.07,50.85c-50.74,1.81-76.38,9-79.67,47.84S26.45,378.46,79.83,335.09Z"/><path class="cls-2" d="M142,210.5c9.94-19.16,22.64-38.16,41.83-48,9.31-4.79,19.68-7.18,29.08-11.76a68.68,68.68,0,0,0,23.51-18.81c5.75-7.19,10-15.46,15.26-23s11.95-14.61,20.62-17.74,19.6-1.3,25,6.17c3,4.19,4,9.59,3.67,14.75-.94,16.29-13.16,29.81-26.63,39s-28.83,15.62-41.46,26c-18.83,15.42-29.9,38.07-43.9,58s-34,38.73-58.31,39.33c-14.23.35-28.68-11.68-17.93-25.72,4-5.2,10.56-8.43,14.8-13.65C133.49,227.63,137.62,218.89,142,210.5Z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
1
nezha-fronted/src/assets/img/starCloud2.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 231.44 169.14"><defs><style>.cls-1{fill:#080430;}.cls-2{fill:#0a093a;}</style></defs><title>Gas-2_1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M3.5,103c-3.38,7.61-4,16.2-3.21,24.49.37,4.05,1.09,8.19,3.17,11.68,2.36,4,6.28,6.79,10.41,8.86,19,9.51,41.71,5.06,62.59,8.78,22.9,4.08,46.15,18.07,67.85,9.7,13.55-5.23,22.62-18.23,28.15-31.66s8.35-27.87,14.11-41.2a101.42,101.42,0,0,1,28-37.48c4.22-3.52,8.8-6.77,12-11.21,6.55-9,6.28-22,.08-31.25S209-.58,198,.05c-5.71.33-11.24,2-16.8,3.36-18,4.3-35.77,4-54,1.73C116.06,3.76,105,1.63,95.77,9.55c-12.7,10.92-12.49,30-23.14,42.37C63.48,62.57,49.93,68.21,37.7,74.4,24.37,81.15,9.9,88.65,3.5,103Z"/><path class="cls-2" d="M79.47,79.19c-11.15,5.47-23,12.67-26.57,24.57a16.94,16.94,0,0,0-.73,7.1c.56,4.27,3.22,8,6.46,10.87,10.84,9.49,27.65,9.41,40.69,3.3s23-17.15,32-28.39,17.55-23.11,29-31.87c7.34-5.63,16.92-12.42,14.92-21.46-4-18.18-39.93-14.87-50.84-5.78-6.76,5.62-10.83,14.14-16.16,21C100.52,68.46,90.65,73.71,79.47,79.19Z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
1
nezha-fronted/src/assets/img/starCloud3.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 353.51 256.8"><defs><style>.cls-1{fill:#080430;}</style></defs><title>Gas-3_1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M133,121.83c-11.11,2.6-22.72,1.73-34,3.26-27.86,3.76-51.53,21.52-73.8,38.68C16.2,170.67,6.89,178,2.32,188.34S-.2,212.89,9.75,218.26c8.57,4.63,19.13,1.25,28.82,2.3,11.69,1.27,21.51,8.91,31.48,15.13A148.61,148.61,0,0,0,113,253.8c19.29,4.74,41.5,5,57-7.47,17.9-14.35,22.28-41.82,41.83-53.82,23.25-14.28,59.44-1.14,76.88-22.14,8.73-10.5,8.65-25.43,10.26-39,1.83-15.45,6.59-30.89,16.1-43.21,13.56-17.55,37.14-30.34,38.45-52.48C354.55,17.27,337,1.23,318.55.11c-46.31-2.82-48.12,51.16-82.79,65.58-16.83,7-32.51,10.54-47.81,21.53C170.39,99.82,154.78,116.73,133,121.83Z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 812 B |
1
nezha-fronted/src/assets/img/starCloud4.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 356.14 220.95"><defs><style>.cls-1{fill:#080430;}.cls-2{fill:#0a093a;}</style></defs><title>Gas-4_1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M127,56.49c21-.45,41.34-6.92,62-10.69a244,244,0,0,1,46.26-3.93c9.68.11,19.72.89,28.19,5.57,15.33,8.46,22.15,27.6,37.13,36.65C312.92,91.51,328.84,91,341,98.69c15.33,9.78,20,32.94,9.65,47.89-11.09,16-34.24,20.51-44.5,37.06-4.38,7.06-6.08,15.88-12,21.66-5,4.85-12.08,6.68-18.85,8.27-31.3,7.32-65.71,12.8-94.37-1.76-20.14-10.24-34.79-29.25-55-39.35-20.06-10-44.27-10.6-63-22.93A58.63,58.63,0,0,1,38.42,115c-2.16-8.73-2.32-18-6.13-26.19-3.16-6.74-8.57-12.11-13.5-17.68C10.46,61.75,3,51,.68,38.61S2,12.14,12.32,4.9c9.51-6.7,22.89-6.17,33.11-.61,14,7.64,18.81,22.58,29.49,33.35C88.55,51.38,108.07,56.91,127,56.49Z"/><path class="cls-2" d="M246.9,98c9,5.42,16.79,13.2,26.69,16.84,3.4,1.26,7.05,2,10.09,4,7.16,4.67,8.7,14.67,7.19,23.08a47.29,47.29,0,0,1-25.44,33.6c-9.26,4.49-19.79,5.8-30.08,5.58-9.28-.19-18.63-1.6-27.18-5.21-11.8-5-21.44-13.85-31.89-21.25-21.47-15.2-46.71-24.44-68.14-39.7-16.53-11.76-30.53-26.8-43.8-42-3.08-3.53-7.33-6.11-4.27-10.55,2.41-3.5,9.28-2.77,12.65-1.93,8.72,2.18,16.37,9.87,24,14.37,24.95,14.65,56.39,12,84.36,12C203.36,86.76,227.13,86.23,246.9,98Z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
nezha-fronted/src/assets/img/starCloud5.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 281.71 151.31"><defs><style>.cls-1{fill:#0d0635;}</style></defs><title>Gas-5_1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M18.44,100.85c-10.63,6.46-20.22,17.78-18.16,30,1.68,10,11,17.48,21,19.6s20.3-.15,29.92-3.45c25.07-8.59,48.8-24.36,75.29-23.55,18.64.58,38.16,9.33,55.15,1.66,17.75-8,24.31-30.38,40.28-41.51,10.23-7.13,23.14-8.84,34.89-13s23.75-12.73,24.85-25.15c1.19-13.59-10.88-24.31-22.07-32.1S235.48-2,222.13.46C200.35,4.45,191,32,170.58,40.69c-22.72,9.65-49.74-7.61-73.08.44C81.18,46.76,69.67,63.27,57.9,75.08,46,87.06,32.75,92.17,18.44,100.85Z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 683 B |
1
nezha-fronted/src/assets/img/starCloud6.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 351.44 371.77"><defs><style>.cls-1{fill:#080430;}.cls-2{fill:#0a093a;}</style></defs><title>Gas-6_1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M12.39,255.31c1.09,6.23,4,12.1,4.39,18.41,1,15.91-13.4,28.73-16.32,44.4C-3,336.53,13.35,356,32.08,355.76c10.54-.12,21.57-5.35,31.17-1,6.5,2.94,10.54,9.6,16.59,13.38,7.77,4.85,17.81,4.27,26.6,1.7s17-6.92,25.85-9.27c14.76-3.93,30.43-2.13,45.51-4.49s31.19-11,34.35-25.93c2.37-11.23-3.25-22.9-1.38-34.23,2.8-16.91,20.57-26.62,36.8-32.16s34.52-10.55,43.64-25.06c17.51-27.85-12.18-65.72-.32-96.41,8.17-21.11,34.4-33.52,36.49-56.05.73-7.9-1.77-16.08.55-23.67,2.38-7.8,9.27-13.18,14.94-19.06s10.59-14.2,7.74-21.85c-1.3-3.48-4-6.2-6.68-8.8C336,5.1,325.12-3.2,315,1.25c-5,2.2-8.31,7.1-10.86,12-5.61,10.71-9.07,22.44-14.79,33.09S274.89,66.88,263.21,70c-9.67,2.55-19.84.08-29.8-.84s-21.3.33-27.63,8.07c-3,3.61-4.41,8.18-5.85,12.61q-5.94,18.42-12.81,36.53c-7.3,19.26-15.91,39-31.71,52.19-10.41,8.69-23.21,13.91-35.78,19-25.14,10.17-48.76,17.68-75.78,19.9C24.73,219,8.69,234.2,12.39,255.31Z"/><path class="cls-2" d="M45.15,264.26c-5.9,9.7-5.35,23.85,3.47,31,5.75,4.66,13.55,5.55,20.71,7.42,20.43,5.32,39,19.81,60,18.47,2.71-.18,5.54-.68,7.67-2.37,3-2.39,3.89-6.51,5.11-10.16A40.51,40.51,0,0,1,163.4,285c6.11-2.81,13-4.09,18.54-7.84,9.57-6.44,13.42-19.57,10.45-30.72s-11.88-20.15-22.36-25c-21-9.72-40.63,13-61.37,17.23C87,243,58.11,242.92,45.15,264.26Z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
1
nezha-fronted/src/assets/img/starCloud7.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240.93 162.09"><defs><style>.cls-1{fill:#0a093a;}</style></defs><title>Gas-7_1</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="cls-1" d="M161.5,61c-12.75,14.53-32.93,19.52-51.79,23.76L44.38,99.45C32,102.24,19,105.33,9.58,113.88s-13.38,24.46-5,34c9.2,10.49,25.75,7.44,39.67,8.5,17.52,1.33,36,10.4,51.71,2.47,11.55-5.83,17.28-19.14,27.55-27,15.89-12.2,38.55-9,57.42-15.69,28.81-10.27,43.81-41.19,55.91-69.28,10.45-24.25,1.21-56.61-31.38-44.1C183.1,11.37,176,44.51,161.5,61Z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 587 B |
@@ -134,7 +134,9 @@ export default {
|
||||
case 'table' :
|
||||
case 'stat' :
|
||||
case 'gauge' :
|
||||
case 'sankey' :
|
||||
case 'pie' :
|
||||
case 'bubble' :
|
||||
case 'treemap' :
|
||||
case 'log' :
|
||||
case 'hexagon' :
|
||||
|
||||
@@ -108,6 +108,15 @@
|
||||
:is-fullscreen="isFullscreen"
|
||||
@chartIsNoData="chartIsNoData"
|
||||
></chart-gauge>
|
||||
<chart-sankey
|
||||
:ref="'chart' + chartInfo.id"
|
||||
v-if="isSankey(chartInfo.type)"
|
||||
:chart-data="chartData"
|
||||
:chart-info="chartInfo"
|
||||
:chart-option="chartOption"
|
||||
:is-fullscreen="isFullscreen"
|
||||
@chartIsNoData="chartIsNoData"
|
||||
></chart-sankey>
|
||||
<chart-diagram
|
||||
:ref="'chart' + chartInfo.id"
|
||||
v-if="isDiagram(chartInfo.type)"
|
||||
@@ -205,6 +214,7 @@ import chartClock from './chart/chartClock'
|
||||
import chartDiagram from './chart/chartDiagram'
|
||||
import chartEndpointInfo from './chart/chartEndpointInfo'
|
||||
import chartGauge from './chart/chartGauge'
|
||||
import chartSankey from './chart/chartSankey'
|
||||
import chartGroup from './chart/chartGroup'
|
||||
import chartLog from './chart/chartLog'
|
||||
import chartNoData from './chart/chartNoData'
|
||||
@@ -220,7 +230,7 @@ import chartValue from './chart/chartValue'
|
||||
import chartHexagonD3 from './chart/chartHexagonD3'
|
||||
import chartMap from './chart/chartMap'
|
||||
import chartTopology from './chart/chartTopology'
|
||||
import { getOption, isTimeSeries, isHexagon, isUrl, isText, isChartPie, isChartBubble, isChartBar, isTreemap, isLog, isStat, isDiagram, isGroup, isAutotopology, isMap, isAssetInfo, isEndpointInfo, isTable, isGauge, isClock, isTopology } from './chart/tools'
|
||||
import { getOption, isTimeSeries, isHexagon, isUrl, isText, isChartPie, isChartBubble, isChartBar, isTreemap, isLog, isStat, isDiagram, isGroup, isAutotopology, isMap, isAssetInfo, isEndpointInfo, isTable, isGauge, isSankey, isClock, isTopology } from './chart/tools'
|
||||
import lodash from 'lodash'
|
||||
|
||||
export default {
|
||||
@@ -234,6 +244,7 @@ export default {
|
||||
chartDiagram,
|
||||
chartEndpointInfo,
|
||||
chartGauge,
|
||||
chartSankey,
|
||||
chartGroup,
|
||||
chartLog,
|
||||
chartNoData,
|
||||
@@ -321,6 +332,7 @@ export default {
|
||||
isMap,
|
||||
isTable,
|
||||
isGauge,
|
||||
isSankey,
|
||||
isClock,
|
||||
isTopology,
|
||||
chartIsNoData (flag) {
|
||||
|
||||
@@ -48,7 +48,6 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
colorList: [],
|
||||
chartDot: 2,
|
||||
isInit: true, // 是否是初始化,初始化时为true,图表初始化结束后设为false
|
||||
chartId: '',
|
||||
bubbleData: [],
|
||||
@@ -276,11 +275,7 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
this.colorList = initColor(20)
|
||||
this.chartInfo.loaded && this.initChart(this.chartOption)
|
||||
this.chartInfo.loaded && this.initChart()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -4,7 +4,54 @@
|
||||
<div :id="'map' + (isFullscreen ? '-screen-' : '' ) + chartInfo.id " style="height: 100%; width: 100%" :style="theme=='dark'? 'filter: invert(1) hue-rotate(0.5turn);opacity: 0.75;': ''"></div>
|
||||
</div>
|
||||
<!--自定义地图鼠标悬浮提示dom,避免被overflow:hidden裁剪-->
|
||||
<div :style="{'left': `${tooltip.x}px`, 'top': `${tooltip.y}px`}" class="my-pane" :class="'my-pane-' + chartId"></div>
|
||||
<div :style="{'left': `${tooltip.x}px`, 'top': `${tooltip.y}px`}" class="my-pane" :class="'my-pane-' + chartId" v-if="tooltip.show">
|
||||
<div class="leaflet-pane leaflet-my-pane">
|
||||
<div class="leaflet-tooltip leaflet-zoom-animated leaflet-tooltip-left" style="opacity: 0.9; transform: translate3d(251px, 196px, 0px);">
|
||||
<div class="nz-tooltip-bac tooltip-map" style="z-index: 11111;width: 175px">
|
||||
<div class="tooltip--title">{{dcStat.name}}</div>
|
||||
<div class="tooltip--row">
|
||||
<div class="legend-value legend-value-asset">
|
||||
<div class="map-asset">
|
||||
<div class="progress-title">{{$t('panel.assetOk')}}</div>
|
||||
<div class="success-progress progress-box">
|
||||
<div class="top-progress" :style="{width: (dcStat.asset.ok / dcStat.asset.total) * 100 + '%' }"></div>
|
||||
<div style="width: 100%" class="bottom-progress"></div>
|
||||
</div>
|
||||
<div class="success-progress progress-content">{{dcStat.asset.ok}}</div>
|
||||
</div>
|
||||
<div class="map-asset">
|
||||
<div class="progress-title">{{$t('panel.assetAlarm')}}</div>
|
||||
<div class="error-progress progress-box">
|
||||
<div class="top-progress" :style="{width: (dcStat.asset.alarm / dcStat.asset.total) * 100 + '%'}"></div>
|
||||
<div style="width: 100%" class="bottom-progress"></div>
|
||||
</div>
|
||||
<div class="error-progress progress-content">{{dcStat.asset.alarm}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="partition"></div>
|
||||
<div class="legend-value legend-value-agent">
|
||||
<div class="map-asset">
|
||||
<div class="progress-title">{{$t('overall.agent')}} {{$t('config.agent.up')}}}</div>
|
||||
<div class="success-progress progress-box">
|
||||
<div class="top-progress" :style="{width: (dcStat.agent.up / (dcStat.agent.up + dcStat.agent.down)) * 100 + '%'}"></div>
|
||||
<div style="width: 100%" class="bottom-progress"></div>
|
||||
</div>
|
||||
<div class="success-progress progress-content">{{dcStat.agent.up}}</div>
|
||||
</div>
|
||||
<div class="map-asset">
|
||||
<div class="progress-title">{{$t('overall.agent')}} {{$t('asset.down')}}</div>
|
||||
<div class="error-progress progress-box">
|
||||
<div class="top-progress" :style="{width: (dcStat.agent.down / (dcStat.agent.up + dcStat.agent.down)) * 100 + '%'}"></div>
|
||||
<div style="width: 100%" class="bottom-progress"></div>
|
||||
</div>
|
||||
<div class="error-progress progress-content">{{dcStat.agent.down}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -27,14 +74,25 @@ export default {
|
||||
map: null,
|
||||
tooltip: {
|
||||
x: 0,
|
||||
y: 0
|
||||
y: 0,
|
||||
show: false
|
||||
},
|
||||
dcStat: {},
|
||||
theme: localStorage.getItem(`nz-user-${localStorage.getItem('nz-user-id')}-theme`),
|
||||
timer: null
|
||||
timer: null,
|
||||
requestAnimationFrame: '',
|
||||
pbfUrl: {
|
||||
m: [],
|
||||
c: []
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.chartInfo.loaded && this.initChart()
|
||||
// for (let i = 0; i < 65535; i += 1) {
|
||||
// const url = 'https://api.maptiler.com/fonts/Roboto Medium,Noto Sans Regular/' + i + '-' + (i + 255) + '.pbf?key=rB2y2a2rG8i9SEjOXQXl'
|
||||
// window.open(url)
|
||||
// }
|
||||
},
|
||||
methods: {
|
||||
initChart () {
|
||||
@@ -48,26 +106,21 @@ export default {
|
||||
this.timer = setTimeout(() => {
|
||||
let loadPromise
|
||||
this.loadMapConfig().then((mapConfig) => {
|
||||
// if (mapConfig && this.map) {
|
||||
// loadPromise = this.loadDataCenterMapData()
|
||||
// }
|
||||
|
||||
})
|
||||
this.isInit = false
|
||||
return loadPromise
|
||||
}, 500)
|
||||
},
|
||||
loadMapConfig () {
|
||||
const self = this
|
||||
return new Promise(resolve => {
|
||||
const DefaultIcon = L.icon({
|
||||
iconUrl: icon,
|
||||
shadowUrl: iconShadow
|
||||
})
|
||||
L.Marker.prototype.options.icon = DefaultIcon
|
||||
const param = { paramKey: 'map_center_config' }
|
||||
this.$get('sysConfig', param).then(response => {
|
||||
if (response.code == 200) {
|
||||
const mapConfig = JSON.parse(response.data.paramKey.map_center_config)
|
||||
mapStyle.center = [Number(mapConfig.longitude), Number(mapConfig.latitude)]
|
||||
mapStyle.zoom = Number(mapConfig.zoom)
|
||||
if (this.map) {
|
||||
this.map.remove()
|
||||
this.map = null
|
||||
@@ -78,10 +131,9 @@ export default {
|
||||
style: mapStyle,
|
||||
maxZoom: 7,
|
||||
minZoom: 0,
|
||||
renderWorldCopies: false,
|
||||
// renderWorldCopies: false,
|
||||
hash: false,
|
||||
transformRequest: function (url, resourceType) {
|
||||
console.log(url, resourceType)
|
||||
if (resourceType === 'Tile' && url.indexOf('https://api.maptiler.com/tiles/v3') > -1) {
|
||||
const urlParams = url.split('.pbf')[0].split('/')
|
||||
const z = urlParams[urlParams.length - 3]
|
||||
@@ -95,8 +147,27 @@ export default {
|
||||
// Include cookies for cross-origin requests
|
||||
}
|
||||
}
|
||||
if (resourceType === 'SpriteJSON') {
|
||||
return {
|
||||
url: 'nzMap://static/Titles/sprite.json',
|
||||
credentials: 'include',
|
||||
method: 'GET'
|
||||
// Include cookies for cross-origin requests
|
||||
}
|
||||
}
|
||||
if (resourceType === 'SpriteImage') {
|
||||
return {
|
||||
url: 'nzMap://static/Titles/sprite.png',
|
||||
credentials: 'include',
|
||||
method: 'GET'
|
||||
// Include cookies for cross-origin requests
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
this.map.on('load', function () {
|
||||
self.loadDataCenterMapData()
|
||||
})
|
||||
maplibregl.addProtocol('nzMap', (params, callback) => { // 切片显示接口 防止跨域的问题
|
||||
fetch(`${params.url.split('://')[1]}`)
|
||||
.then(t => {
|
||||
@@ -119,6 +190,7 @@ export default {
|
||||
})
|
||||
},
|
||||
loadDataCenterMapData () {
|
||||
const self = this
|
||||
return new Promise(resolve => {
|
||||
const requests = [axios.get('dc?pageSize=-1'), axios.get('/stat/overview/map')]
|
||||
axios.all(requests).then(result => {
|
||||
@@ -131,9 +203,9 @@ export default {
|
||||
const dc = dcInfos.find(i => i.name === s.name)
|
||||
dc && (s = { ...s, latitude: dc.latitude, longitude: dc.longitude })
|
||||
})
|
||||
const bigScatter = 10
|
||||
const mediumScatter = 8
|
||||
const smallScatter = 6
|
||||
const bigScatter = 18
|
||||
const mediumScatter = 13
|
||||
const smallScatter = 10
|
||||
const maxAssetTotal = dcInfos[0] ? dcInfos[0].assetNum : '' // 获取asset数量最大值
|
||||
const bigBoundary = Number.parseInt(maxAssetTotal / 3 * 2) // 根据最大值定下大图标、中图标的阈值
|
||||
const mediumBoundary = Number.parseInt(maxAssetTotal / 3)
|
||||
@@ -147,85 +219,104 @@ export default {
|
||||
} else {
|
||||
symbolSize = smallScatter
|
||||
}
|
||||
let shadowMarker
|
||||
let marker
|
||||
if (dcStat.color === 1) {
|
||||
shadowMarker = L.circleMarker([dcStat.latitude, dcStat.longitude], { opacity: 0, fillOpacity: 0, radius: symbolSize + 10 })
|
||||
marker = L.circleMarker([dcStat.latitude, dcStat.longitude], { interactive: false, color: '#23BF9A', opacity: 0.42, fillColor: '#23BF9A', fillOpacity: 0.5, radius: symbolSize, className: 'real-marker' })
|
||||
} else if (dcStat.color === 2) {
|
||||
shadowMarker = L.circleMarker([dcStat.latitude, dcStat.longitude], { opacity: 0, fillOpacity: 0, radius: symbolSize + 10 })
|
||||
marker = L.circleMarker([dcStat.latitude, dcStat.longitude], { interactive: false, color: '#EC7F66', opacity: 0.42, fillColor: '#EC7F66', fillOpacity: 0.5, radius: symbolSize, className: 'real-marker error-item' })
|
||||
} else if (dcStat.color === 3) {
|
||||
shadowMarker = L.circleMarker([dcStat.latitude, dcStat.longitude], { opacity: 0, fillOpacity: 0, radius: symbolSize + 10 })
|
||||
marker = L.circleMarker([dcStat.latitude, dcStat.longitude], { interactive: false, color: '#9e9c98', opacity: 0.42, fillColor: '#9e9c98', fillOpacity: 0.5, radius: symbolSize, className: 'real-marker' })
|
||||
}
|
||||
shadowMarker.bindTooltip(this.mapTooltipFormatter(dcStat), { sticky: false, pane: 'myPane', direction: 'left', data: dcStat })
|
||||
shadowMarker.on('mouseover', (param) => {
|
||||
const point = param.containerPoint
|
||||
const event = param.originalEvent
|
||||
const boxWidth = window.innerWidth / 2
|
||||
this.tooltip.x = event.clientX + point.x - event.layerX - 5
|
||||
this.tooltip.y = event.clientY + point.y - event.layerY
|
||||
if (boxWidth > this.tooltip.x) {
|
||||
this.tooltip.x = this.tooltip.x + 175 + 10
|
||||
}
|
||||
})
|
||||
shadowMarker.addTo(this.map)
|
||||
marker.addTo(this.map)
|
||||
dcStat.symbolSize = symbolSize
|
||||
}
|
||||
})
|
||||
this.renderPoint(dcStats)
|
||||
self.map.on('mouseenter', 'pointLayer', function (param) {
|
||||
console.log('mouseenter', param)
|
||||
const point = param.point
|
||||
const event = param.originalEvent
|
||||
const boxWidth = window.innerWidth / 2
|
||||
const boxHeight = window.innerHeight / 2
|
||||
self.tooltip.x = event.clientX + point.x - event.layerX + 15
|
||||
self.tooltip.y = event.clientY + point.y - event.layerY + 15
|
||||
if (self.tooltip.x > boxWidth) {
|
||||
self.tooltip.x = self.tooltip.x - 200 - 15
|
||||
}
|
||||
if (self.tooltip.y > boxHeight) {
|
||||
self.tooltip.y = self.tooltip.y - 160 - 15
|
||||
}
|
||||
self.dcStat = {
|
||||
...param.features[0].properties,
|
||||
asset: JSON.parse(param.features[0].properties.asset),
|
||||
agent: JSON.parse(param.features[0].properties.agent)
|
||||
}
|
||||
self.tooltip.show = true
|
||||
})
|
||||
|
||||
self.map.on('mouseleave', 'pointLayer', function () {
|
||||
console.log('mouseleave')
|
||||
self.tooltip.show = false
|
||||
self.dcStat = ''
|
||||
})
|
||||
self.pointAnimation(0)
|
||||
})
|
||||
})
|
||||
},
|
||||
mapTooltipFormatter (dcStat) {
|
||||
const self = this
|
||||
return `<div class="nz-tooltip-bac tooltip-map" style="z-index: 11111;width: 175px">
|
||||
<div class="tooltip--title">${dcStat.name}</div>
|
||||
<div class="tooltip--row">
|
||||
<div class="legend-value legend-value-asset">
|
||||
<div class="map-asset">
|
||||
<div class="progress-title">${self.$t('panel.assetOk')}</div>
|
||||
<div class="success-progress progress-box">
|
||||
<div class="top-progress" style="width: ${(dcStat.asset.ok / dcStat.asset.total) * 100}%"></div>
|
||||
<div style="width: 100%" class="bottom-progress"></div>
|
||||
</div>
|
||||
<div class="success-progress progress-content">${dcStat.asset.ok}</div>
|
||||
</div>
|
||||
<div class="map-asset">
|
||||
<div class="progress-title">${self.$t('panel.assetAlarm')}</div>
|
||||
<div class="error-progress progress-box">
|
||||
<div class="top-progress" style="width: ${(dcStat.asset.alarm / dcStat.asset.total) * 100}%"></div>
|
||||
<div style="width: 100%" class="bottom-progress"></div>
|
||||
</div>
|
||||
<div class="error-progress progress-content">${dcStat.asset.alarm}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="partition"></div>
|
||||
<div class="legend-value legend-value-agent">
|
||||
<div class="map-asset">
|
||||
<div class="progress-title">${self.$t('overall.agent')} ${self.$t('config.agent.up')}</div>
|
||||
<div class="success-progress progress-box">
|
||||
<div class="top-progress" style="width: ${(dcStat.agent.up / (dcStat.agent.up + dcStat.agent.down)) * 100}%"></div>
|
||||
<div style="width: 100%" class="bottom-progress"></div>
|
||||
</div>
|
||||
<div class="success-progress progress-content">${dcStat.agent.up}</div>
|
||||
</div>
|
||||
<div class="map-asset">
|
||||
<div class="progress-title">${self.$t('overall.agent')} ${self.$t('asset.down')}</div>
|
||||
<div class="error-progress progress-box">
|
||||
<div class="top-progress" style="width: ${(dcStat.agent.down / (dcStat.agent.up + dcStat.agent.down)) * 100}%"></div>
|
||||
<div style="width: 100%" class="bottom-progress"></div>
|
||||
</div>
|
||||
<div class="error-progress progress-content">${dcStat.agent.down}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
// return tooltip;
|
||||
renderPoint (dcStats) {
|
||||
const arr = []
|
||||
dcStats.forEach(dcStat => {
|
||||
arr.push({
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
...dcStat
|
||||
},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [dcStat.longitude, dcStat.latitude]
|
||||
}
|
||||
})
|
||||
})
|
||||
this.map.addSource('pointData', {
|
||||
type: 'geojson',
|
||||
data: {
|
||||
type: 'FeatureCollection',
|
||||
features: arr
|
||||
}
|
||||
})
|
||||
this.map.addLayer({
|
||||
id: 'pointLayer',
|
||||
type: 'circle',
|
||||
source: 'pointData',
|
||||
paint: {
|
||||
'circle-radius': [
|
||||
'step',
|
||||
['get', 'symbolSize'],
|
||||
10,
|
||||
13,
|
||||
13,
|
||||
18,
|
||||
18
|
||||
],
|
||||
'circle-color': [
|
||||
'step',
|
||||
['get', 'color'],
|
||||
'#23BF9A',
|
||||
2,
|
||||
'#EC7F66',
|
||||
3,
|
||||
'#9e9c98'
|
||||
],
|
||||
'circle-opacity': 0.5
|
||||
}
|
||||
})
|
||||
},
|
||||
pointAnimation (timeStep) {
|
||||
const opacity = 0.5 + (timeStep % 1000) / 1000 / 2
|
||||
this.map.setPaintProperty('pointLayer', 'circle-opacity', [
|
||||
'step',
|
||||
['get', 'color'],
|
||||
0.5,
|
||||
2,
|
||||
opacity,
|
||||
3,
|
||||
0.5
|
||||
])
|
||||
requestAnimationFrame(this.pointAnimation)
|
||||
},
|
||||
resize () {
|
||||
this.initMap()
|
||||
this.map.resize()
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
|
||||
387
nezha-fronted/src/components/chart/chart/chartSankey.vue
Normal file
@@ -0,0 +1,387 @@
|
||||
<template>
|
||||
<div
|
||||
ref="pie-chart-box"
|
||||
class="nz-chart__component nz-chart__component--time-series" @mouseenter="mouseEnterChart"
|
||||
@mouseleave="mouseLeaveChart"
|
||||
index="300"
|
||||
>
|
||||
<div :id="`chart-canvas-${chartId}`" class="chart__canvas">
|
||||
<svg :id="`sankey-svg-${chartId}`" width="100%" height="100%"></svg>
|
||||
</div>
|
||||
<div :class="`chart-canvas-tooltip-${chartId}`" :id="`chart-canvas-tooltip-${chartId}`" class="chart-canvas-tooltip" :style="{left:tooltip.x+'px',top:tooltip.y+'px'}" v-if="tooltip.show">
|
||||
<div class="chart-canvas-tooltip-title tooltip-title">
|
||||
{{tooltip.title}}
|
||||
</div>
|
||||
<div class="chart-canvas-tooltip-content">
|
||||
<div>value</div>
|
||||
<div>
|
||||
<div v-if="tooltip.mapping && tooltip.mapping.icon" style="display: inline-block">
|
||||
<i :class="tooltip.mapping.icon" :style="{color: tooltip.mapping.color.icon}"></i>
|
||||
</div>
|
||||
<div style="display: inline-block">{{tooltip.value}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import chartMixin from '@/components/chart/chartMixin'
|
||||
import chartFormat from '@/components/chart/chartFormat'
|
||||
import * as d3 from 'd3'
|
||||
import * as d3Sankey from 'd3-sankey'
|
||||
import { getMetricTypeValue } from '@/components/common/js/tools'
|
||||
import chartDataFormat from '@/components/chart/chartDataFormat'
|
||||
import { initColor } from '@/components/chart/chart/tools'
|
||||
import { randomcolor } from '@/components/common/js/radomcolor/randomcolor'
|
||||
import lodash from 'lodash'
|
||||
|
||||
export default {
|
||||
name: 'chart-sankey',
|
||||
mixins: [chartMixin, chartFormat],
|
||||
props: {
|
||||
chartInfo: Object,
|
||||
chartData: Array,
|
||||
chartOption: Object,
|
||||
isFullscreen: Boolean
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
colorList: [],
|
||||
isInit: true, // 是否是初始化,初始化时为true,图表初始化结束后设为false
|
||||
chartId: '',
|
||||
linksData: [],
|
||||
nodesData: [],
|
||||
tooltip: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
title: 0,
|
||||
value: 0,
|
||||
mapping: {},
|
||||
show: false
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initChart () {
|
||||
this.linksData = this.initsankeyData(this.chartInfo, this.chartData) // 生成links
|
||||
this.isNoData = !this.linksData.length
|
||||
this.$emit('chartIsNoData', this.isNoData)
|
||||
if (this.isNoData) {
|
||||
return
|
||||
}
|
||||
// 根据link获取node
|
||||
this.linksData.forEach(item => {
|
||||
this.nodesData.push({ node: item.source })
|
||||
this.nodesData.push({ node: item.target })
|
||||
})
|
||||
// 去重相同的node
|
||||
for (let i = 0; i < this.nodesData.length; i++) {
|
||||
for (let j = i + 1; j < this.nodesData.length; j++) {
|
||||
if (this.nodesData[i].node === this.nodesData[j].node) {
|
||||
this.nodesData.splice(j, 1)
|
||||
j = j - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 使用setTimeout延迟渲染图表,避免样式错乱 */
|
||||
setTimeout(() => {
|
||||
this.drawSankeyChart()
|
||||
this.isInit = false
|
||||
}, 200)
|
||||
},
|
||||
initsankeyData (chartInfo, originalDatas) {
|
||||
this.linksData = []
|
||||
this.nodesData = []
|
||||
const sankeyData = []
|
||||
const decimals = this.chartInfo.param.decimals || 2
|
||||
originalDatas.forEach((originalData) => {
|
||||
originalData.forEach((data, dataIndex) => {
|
||||
this.isNoData = false
|
||||
const value = getMetricTypeValue(data.values, chartInfo.param.statistics)
|
||||
const obj = {
|
||||
value: value,
|
||||
realValue: value,
|
||||
labels: data.metric,
|
||||
dataIndex: dataIndex
|
||||
}
|
||||
if (data.metric[chartInfo.param.sourceLabel] && data.metric[chartInfo.param.targetLabel]) {
|
||||
obj.source = data.metric[chartInfo.param.sourceLabel]
|
||||
obj.target = data.metric[chartInfo.param.targetLabel]
|
||||
sankeyData.push(obj)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 汇总 source,target 相同的数据
|
||||
const links = []
|
||||
const tempObj = {}
|
||||
sankeyData.forEach((item) => {
|
||||
const key = item.source + '-' + item.target
|
||||
if (!Object.prototype.hasOwnProperty.call(tempObj, key)) {
|
||||
tempObj[key] = item
|
||||
tempObj[key].showValue = chartDataFormat.getUnit(chartInfo.unit ? chartInfo.unit : 2).compute(tempObj[key].value, null, -1, decimals)
|
||||
} else {
|
||||
const num1 = parseFloat(tempObj[key].value)
|
||||
const num2 = parseFloat(item.value)
|
||||
tempObj[key].value = num1 + num2
|
||||
tempObj[key].showValue = chartDataFormat.getUnit(chartInfo.unit ? chartInfo.unit : 2).compute(tempObj[key].value, null, -1, decimals)
|
||||
}
|
||||
})
|
||||
for (const key in tempObj) {
|
||||
links.push(tempObj[key])
|
||||
}
|
||||
return links
|
||||
},
|
||||
|
||||
drawSankeyChart () {
|
||||
this.$nextTick(() => {
|
||||
// 清空作图区域
|
||||
d3.select(`#sankey-svg-${this.chartId}`).selectAll('g').remove()
|
||||
|
||||
// 获取svg宽高 初始化画布
|
||||
const svgDom = document.getElementById(`sankey-svg-${this.chartId}`)
|
||||
const width = svgDom && svgDom.getBoundingClientRect().width
|
||||
const height = svgDom && svgDom.getBoundingClientRect().height
|
||||
const margin1 = 100
|
||||
const margin2 = 50
|
||||
const svg = d3.select(`#sankey-svg-${this.chartId}`)
|
||||
const chart = svg.append('g').attr('transform', `translate(${margin2}, ${margin2})`)
|
||||
|
||||
// 创建桑基图生成器
|
||||
const sankey = d3Sankey
|
||||
.sankey()
|
||||
.nodeWidth(20)
|
||||
.nodePadding(20)
|
||||
.size([width - 2 * margin1, height - 2 * margin2])
|
||||
.nodeId((d) => d.node)
|
||||
const nodesData = lodash.cloneDeep(this.nodesData)
|
||||
const linksData = lodash.cloneDeep(this.linksData)
|
||||
const { nodes, links } = sankey({
|
||||
nodes: nodesData,
|
||||
links: linksData
|
||||
})
|
||||
|
||||
// 设置节点颜色
|
||||
nodes.forEach((item, index) => {
|
||||
if (index >= 20) {
|
||||
const colorRandom = randomcolor()
|
||||
this.colorList.push(colorRandom)
|
||||
}
|
||||
const mapping = this.selectMapping(item.value, this.chartInfo.param.valueMapping, this.chartInfo.param.enable && this.chartInfo.param.enable.valueMapping)
|
||||
item.mapping = mapping
|
||||
item.background = mapping ? mapping.color.bac : this.colorList[index]
|
||||
const decimals = this.chartInfo.param.decimals || 2
|
||||
item.showValue = chartDataFormat.getUnit(this.chartInfo.unit ? this.chartInfo.unit : 2).compute(item.value, null, -1, decimals)
|
||||
})
|
||||
|
||||
// 创建一个连线绘制组,绑定连线数据(links)
|
||||
chart
|
||||
.append('g')
|
||||
.attr('fill', 'none')
|
||||
.selectAll()
|
||||
.data(links)
|
||||
.join('path')
|
||||
.attr('linkNodes', (d) => { // 设置与当前连线相连的节点(必须以字母开头)
|
||||
return 'i-' + d.source.index + ' ' + 'i-' + d.target.index
|
||||
})
|
||||
.attr('d', d3Sankey.sankeyLinkHorizontal())
|
||||
.attr('stroke', (d, i) => {
|
||||
return d.source.background
|
||||
})
|
||||
.attr('stroke-width', (d) => d.width)
|
||||
.style('stroke-opacity', '0.5')
|
||||
.attr('cursor', 'pointer')
|
||||
.style('transition', 'all 0.3s')
|
||||
|
||||
// 创建一个节点绘制组,绑定节点数据(nodes)。
|
||||
chart
|
||||
.append('g')
|
||||
.selectAll()
|
||||
.data(nodes)
|
||||
.join('g')
|
||||
.attr('class', 'node')
|
||||
.attr('linkNodes', (d) => { // 设置与当前节点相连的节点(必须以字母开头)
|
||||
let nodeStr = ''
|
||||
d.targetLinks.forEach(link => {
|
||||
nodeStr += 'i-' + link.source.index + ' '
|
||||
})
|
||||
nodeStr += 'i-' + d.index
|
||||
d.sourceLinks.forEach(link => {
|
||||
nodeStr += ' ' + 'i-' + link.target.index
|
||||
})
|
||||
|
||||
return nodeStr
|
||||
})
|
||||
.attr('index', (d) => { // 设置标识(必须以字母开头)
|
||||
return 'i-' + d.index
|
||||
})
|
||||
.append('rect')
|
||||
.attr('fill', (d, i) => {
|
||||
return d.background
|
||||
})
|
||||
.attr('x', (d) => d.x0)
|
||||
.attr('y', (d) => d.y0)
|
||||
.attr('height', (d) => d.y1 - d.y0)
|
||||
.attr('width', (d) => d.x1 - d.x0)
|
||||
.attr('cursor', 'pointer')
|
||||
.style('transition', 'all 0.3s')
|
||||
|
||||
// 节点添加文字
|
||||
chart
|
||||
.selectAll('.node')
|
||||
.append('foreignObject')
|
||||
// .attr('width', 20)
|
||||
.attr('height', function (d) { return d.y1 - d.y0 })
|
||||
.attr('x', function (d) { return d.x0 + 30 })
|
||||
.attr('y', function (d) { return d.y0 })
|
||||
.style('overflow', 'visible')
|
||||
.style('cursor', 'pointer')
|
||||
.style('transition', 'all 0.3s')
|
||||
.html((d) => {
|
||||
return this.sankeyFormatterLabel(d)
|
||||
})
|
||||
|
||||
// 划过连线
|
||||
chart.selectAll('path')
|
||||
.on('mouseover', (e, d) => {
|
||||
chart.selectAll('.node, path').style('fill-opacity', '0.1').style('stroke-opacity', '0.1')
|
||||
chart.selectAll('.node').selectAll('foreignObject').style('opacity', '0.1')
|
||||
const hoverNodes = d3.select(e.target).style('stroke-opacity', '0.8').attr('linkNodes').split(' ')
|
||||
hoverNodes.forEach((index) => {
|
||||
chart.selectAll('[index=' + index + ']').style('fill-opacity', '1').selectAll('foreignObject').style('opacity', '1')
|
||||
})
|
||||
// 显示悬浮框
|
||||
this.tooltip.title = d.source.node + ' ——> ' + d.target.node
|
||||
this.tooltip.value = d.showValue
|
||||
this.tooltip.mapping = ''
|
||||
this.tooltip.show = true
|
||||
this.setPosition(e)
|
||||
})
|
||||
.on('mousemove', (e) => {
|
||||
if (this.tooltip.show) {
|
||||
this.setPosition(e)
|
||||
}
|
||||
})
|
||||
.on('mouseleave', () => {
|
||||
chart.selectAll('.node, path').style('fill-opacity', '1').style('stroke-opacity', '0.5')
|
||||
chart.selectAll('.node').selectAll('foreignObject').style('opacity', '1')
|
||||
// 隐藏悬浮框
|
||||
this.tooltip.show = false
|
||||
})
|
||||
|
||||
// 划过节点
|
||||
chart.selectAll('.node')
|
||||
.on('mouseover', (e, d) => {
|
||||
chart.selectAll('.node, path').style('fill-opacity', '0.1').style('stroke-opacity', '0.1')
|
||||
chart.selectAll('.node').selectAll('foreignObject').style('opacity', '0.1')
|
||||
chart.selectAll('[linkNodes~=' + 'i-' + d.index + ']')
|
||||
.style('fill-opacity', '1')
|
||||
.style('stroke-opacity', '0.8')
|
||||
.selectAll('foreignObject')
|
||||
.style('opacity', '1')
|
||||
// 显示悬浮框
|
||||
this.tooltip.title = d.node
|
||||
this.tooltip.value = d.showValue
|
||||
this.tooltip.mapping = d.mapping
|
||||
this.tooltip.show = true
|
||||
this.setPosition(e)
|
||||
})
|
||||
.on('mousemove', (e) => {
|
||||
if (this.tooltip.show) {
|
||||
this.setPosition(e)
|
||||
}
|
||||
})
|
||||
.on('mouseleave', () => {
|
||||
chart.selectAll('.node, path').style('fill-opacity', '1').style('stroke-opacity', '0.5')
|
||||
chart.selectAll('.node').selectAll('foreignObject').style('opacity', '1')
|
||||
// 隐藏悬浮框
|
||||
this.tooltip.show = false
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
setPosition (e) {
|
||||
const windowWidth = window.innerWidth// 窗口宽度
|
||||
const windowHeight = window.innerHeight// 窗口高度
|
||||
const box = document.getElementById(`chart-canvas-tooltip-${this.chartId}`)
|
||||
if (box) {
|
||||
const boxWidth = box.offsetWidth
|
||||
const boxHeight = box.offsetHeight
|
||||
if (e.pageX < (windowWidth / 2)) { // 说明鼠标在左边放不下提示框
|
||||
this.tooltip.x = e.pageX + 15
|
||||
} else {
|
||||
this.tooltip.x = e.pageX - boxWidth - 15
|
||||
}
|
||||
if (e.pageY + 50 + boxHeight < windowHeight) { // 说明鼠标上面放不下提示框
|
||||
this.tooltip.y = e.pageY + 15
|
||||
} else {
|
||||
this.tooltip.y = e.pageY - boxHeight - 10
|
||||
}
|
||||
} else {
|
||||
this.tooltip.y = e.pageY + 15
|
||||
this.tooltip.x = e.pageX + 15
|
||||
}
|
||||
},
|
||||
|
||||
// 处理label
|
||||
sankeyFormatterLabel (data) {
|
||||
let str = ''
|
||||
let valueStr = ''
|
||||
if (this.chartInfo.param.text === 'all') {
|
||||
str += data.node
|
||||
valueStr = data.mapping && data.mapping.display ? this.handleDisplay(data.mapping.display, { value: data.showValue }) : data.showValue
|
||||
}
|
||||
if (this.chartInfo.param.text === 'value' || !this.chartInfo.param.text) {
|
||||
valueStr = data.mapping && data.mapping.display ? this.handleDisplay(data.mapping.display, { value: data.showValue }) : data.showValue
|
||||
}
|
||||
if (this.chartInfo.param.text === 'legend') {
|
||||
str += data.node
|
||||
}
|
||||
if (this.chartInfo.param.text === 'none') {
|
||||
str += ''
|
||||
}
|
||||
if (str && valueStr) {
|
||||
return `
|
||||
<div style="width:auto;height: 100%;display: flex;justify-content: center;flex-direction: column;color:#000000">
|
||||
<p style="cursor:pointer;white-space: nowrap;color: ${data.mapping && data.mapping.color && data.mapping.color.text};">
|
||||
<span>${str}</span>
|
||||
</p>
|
||||
<p style="cursor:pointer;white-space: nowrap;color: ${data.mapping && data.mapping.color && data.mapping.color.text};">
|
||||
<i class="${data.mapping && data.mapping.icon}" style="color: ${data.mapping && data.mapping.color && data.mapping.color.icon};font-size:1em;"></i>
|
||||
<span>${valueStr}</span>
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
} else if (str) {
|
||||
return `
|
||||
<div style="width:auto;height: 100%;display: flex;justify-content: center;flex-direction: column;color:#000000">
|
||||
<p style="cursor:pointer;white-space: nowrap;color: ${data.mapping && data.mapping.color && data.mapping.color.text};">
|
||||
<i class="${data.mapping && data.mapping.icon}" style="color: ${data.mapping && data.mapping.color && data.mapping.color.icon};font-size:1em;"></i>
|
||||
<span>${str}</span>
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
} else if (valueStr) {
|
||||
return `
|
||||
<div style="width:auto;height: 100%;display: flex;justify-content: center;flex-direction: column;color:#000000">
|
||||
<p style="cursor:pointer;white-space: nowrap;color: ${data.mapping && data.mapping.color && data.mapping.color.text};">
|
||||
<i class="${data.mapping && data.mapping.icon}" style="color: ${data.mapping && data.mapping.color && data.mapping.color.icon};font-size:1em;"></i>
|
||||
<span>${valueStr}</span>
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
},
|
||||
resize () {
|
||||
setTimeout(() => {
|
||||
this.drawSankeyChart()
|
||||
}, 50)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.colorList = initColor(20)
|
||||
this.chartInfo.loaded && this.initChart()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -114,6 +114,9 @@ export function isTable (type) {
|
||||
export function isGauge (type) {
|
||||
return type === chartType.gauge
|
||||
}
|
||||
export function isSankey (type) {
|
||||
return type === chartType.sankey
|
||||
}
|
||||
export function isClock (type) {
|
||||
return type === chartType.clock
|
||||
}
|
||||
|
||||
@@ -1165,7 +1165,6 @@ export default {
|
||||
/* topology 方法 */
|
||||
/* topology 方法 */
|
||||
onDrag (event, node) {
|
||||
console.log(event, node)
|
||||
this.dragFlag = false
|
||||
const timer = setTimeout(() => {
|
||||
this.dragFlag = true
|
||||
@@ -1174,7 +1173,6 @@ export default {
|
||||
event.dataTransfer.setData('Text', JSON.stringify({ ...node.data, data: { imageId: node.data.imageId } }))
|
||||
},
|
||||
dragFlagChange (node) {
|
||||
console.log(node)
|
||||
getTopology(this.topologyIndex).addPen(
|
||||
{
|
||||
...node.data,
|
||||
|
||||
32
nezha-fronted/src/components/common/copy.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="document-copy-block">
|
||||
<span class="document-copy-text">
|
||||
<slot name="copy-text"></slot>
|
||||
</span>
|
||||
<i v-if="copyData" class="nz-icon nz-icon-override" style="visibility: hidden" @click="onCopy(copyData)" :title="$t('overall.copyText')"></i>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'copy',
|
||||
props: {
|
||||
copyData: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onCopy (txt) {
|
||||
this.$copyText(txt).then(() => {
|
||||
this.$message.success({ message: this.$t('overall.copySuccess') })
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -408,6 +408,7 @@ export const chartType = {
|
||||
table: 'table',
|
||||
stat: 'stat',
|
||||
gauge: 'gauge',
|
||||
sankey: 'sankey',
|
||||
pie: 'pie',
|
||||
bubble: 'bubble',
|
||||
treemap: 'treemap',
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="input-box-item" style="margin-right: unset !important;width: 30px !important;flex:unset;" @click="mapConfigVisible = true"><i class="nz-icon nz-icon-weizhi" style="color:rgb(238, 157, 63)"></i></div>
|
||||
</div>
|
||||
<el-dialog :visible.sync="mapConfigVisible" :title="$t('config.system.basic.mapTitle')" width="calc(50% - 10px)" @close="mapClose" @opened="initMap" class=" nz-dialog map-config-dialog" :modal-append-to-body="appendToBody">
|
||||
<div id="map" style="height: 100%; width: 100%" :style="theme=='dark'? 'filter: invert(1) hue-rotate(0.5turn);opacity: 0.75;': ''"></div>
|
||||
<div id="map" style="height: 100%; width: 100%"></div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
@@ -22,9 +22,8 @@
|
||||
<script>
|
||||
// 引入Leaflet对象 挂载到Vue上,便于全局使用,也可以单独页面中单独引用
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
import * as L from 'leaflet'
|
||||
import icon from 'leaflet/dist/images/marker-icon.png'
|
||||
import iconShadow from 'leaflet/dist/images/marker-shadow.png'
|
||||
import maplibregl from 'maplibre-gl'
|
||||
import mapStyle from '@/components/chart/chart/mapStyle'
|
||||
export default {
|
||||
name: 'latlngPicker',
|
||||
props: {
|
||||
@@ -37,7 +36,7 @@ export default {
|
||||
theme: localStorage.getItem(`nz-user-${localStorage.getItem('nz-user-id')}-theme`),
|
||||
lnglat: '',
|
||||
oldlnglat: '',
|
||||
mapParam: { longitude: 116.39, latitude: 39.9, zoom: 4, minZoom: 1, maxZoom: 10 },
|
||||
mapParam: { longitude: 116.39, latitude: 39.9, zoom: 4, minZoom: 1, maxZoom: 7 },
|
||||
map: null,
|
||||
marker: null,
|
||||
mapConfigVisible: false,
|
||||
@@ -56,6 +55,16 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const arr = []
|
||||
mapStyle.layers.forEach(item => {
|
||||
if (item.layout['text-font']) {
|
||||
const font = item.layout['text-font'].join(',')
|
||||
if (arr.indexOf(font) === -1) {
|
||||
arr.push(font)
|
||||
}
|
||||
}
|
||||
})
|
||||
console.log(arr)
|
||||
},
|
||||
methods: {
|
||||
initMap () {
|
||||
@@ -64,53 +73,112 @@ export default {
|
||||
this.map = null
|
||||
}
|
||||
this.setLatlng()
|
||||
const DefaultIcon = L.icon({
|
||||
iconUrl: icon,
|
||||
iconSize: [26, 40],
|
||||
iconAnchor: [13, 40],
|
||||
shadowUrl: iconShadow
|
||||
mapStyle.center = [Number(this.mapParam.longitude), Number(this.mapParam.latitude)]
|
||||
mapStyle.zoom = Number(this.zoom)
|
||||
const mapId = document.getElementById('map')
|
||||
this.map = new maplibregl.Map({
|
||||
container: mapId,
|
||||
style: mapStyle,
|
||||
maxZoom: 7,
|
||||
minZoom: 1,
|
||||
// renderWorldCopies: false,
|
||||
hash: false,
|
||||
transformRequest: function (url, resourceType) {
|
||||
console.log(resourceType)
|
||||
if (resourceType === 'Tile' && url.indexOf('https://api.maptiler.com/tiles/v3') > -1) {
|
||||
const urlParams = url.split('.pbf')[0].split('/')
|
||||
const z = urlParams[urlParams.length - 3]
|
||||
const x = urlParams[urlParams.length - 2]
|
||||
const y = urlParams[urlParams.length - 1]
|
||||
const newUrl1 = `nzMap://static/Titles/${z}/${x}/${y}.pbf`
|
||||
return {
|
||||
url: newUrl1,
|
||||
credentials: 'include',
|
||||
method: 'GET'
|
||||
// Include cookies for cross-origin requests
|
||||
}
|
||||
}
|
||||
if (resourceType === 'SpriteJSON') {
|
||||
return {
|
||||
url: 'nzMap://static/Titles/sprite.json',
|
||||
credentials: 'include',
|
||||
method: 'GET'
|
||||
// Include cookies for cross-origin requests
|
||||
}
|
||||
}
|
||||
if (resourceType === 'SpriteImage') {
|
||||
return {
|
||||
url: 'nzMap://static/Titles/sprite.png',
|
||||
credentials: 'include',
|
||||
method: 'GET'
|
||||
// Include cookies for cross-origin requests
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
L.Marker.prototype.options.icon = DefaultIcon
|
||||
const map = L.map('map', {
|
||||
minZoom: this.mapParam.minZoom,
|
||||
maxZoom: this.mapParam.maxZoom,
|
||||
attributionControl: false,
|
||||
zoomControl: false,
|
||||
maxBounds: L.latLngBounds(L.latLng(-90, -180), L.latLng(90, 180))
|
||||
}).setView([this.mapParam.latitude, this.mapParam.longitude], this.mapParam.zoom)
|
||||
|
||||
L.tileLayer(
|
||||
'/static/Tiles/{z}/{x}/{y}.png',
|
||||
{ noWrap: true }
|
||||
).addTo(map)
|
||||
|
||||
const attribution = L.control.attribution({ position: 'bottomright', prefix: '' })
|
||||
attribution.addAttribution(' © OpenStreetMap contributors')
|
||||
attribution.addTo(map)
|
||||
|
||||
L.control.zoom({
|
||||
position: 'bottomright',
|
||||
zoomInText: '<i class="nz-icon nz-icon-enlarge"></i>',
|
||||
zoomOutText: '<i class="nz-icon nz-icon-narrow"></i>',
|
||||
zoomInTitle: '',
|
||||
zoomOutTitle: ''
|
||||
}).addTo(map)
|
||||
|
||||
const marker = L.marker([this.mapParam.latitude, this.mapParam.longitude]).addTo(map)
|
||||
map.on('click', function (e) {
|
||||
const latitude = e.latlng.lat
|
||||
const longitude = e.latlng.lng
|
||||
marker.setLatLng([latitude, longitude])
|
||||
maplibregl.addProtocol('nzMap', (params, callback) => { // 切片显示接口 防止跨域的问题
|
||||
fetch(`${params.url.split('://')[1]}`)
|
||||
.then(t => {
|
||||
if (t.status == 200) {
|
||||
t.arrayBuffer().then(arr => {
|
||||
callback(null, arr, null, null)
|
||||
})
|
||||
} else {
|
||||
callback(new Error(`Tile fetch error: ${t.statusText}`))
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
callback(new Error(e))
|
||||
})
|
||||
return { cancel: () => { } }
|
||||
})
|
||||
this.map = map
|
||||
this.marker = marker
|
||||
const marker = ''
|
||||
const self = this
|
||||
const geoJSON = {
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [Number(self.mapParam.longitude), Number(self.mapParam.latitude)]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
this.map.on('load', function () {
|
||||
self.map.addSource('centerMarker',
|
||||
{
|
||||
type: 'geojson',
|
||||
data: geoJSON
|
||||
})
|
||||
self.map.addLayer({
|
||||
id: 'centerMarkerLayer',
|
||||
type: 'circle',
|
||||
source: 'centerMarker',
|
||||
paint: {
|
||||
'circle-radius': 8,
|
||||
'circle-color': '#23BF9A',
|
||||
'circle-opacity': 1
|
||||
}
|
||||
})
|
||||
})
|
||||
// const marker = L.marker([this.mapParam.latitude, this.mapParam.longitude]).addTo(map)
|
||||
this.map.on('click', function (e) {
|
||||
console.log(e, e.lngLat)
|
||||
const coords = e.lngLat
|
||||
geoJSON.features[0].geometry.coordinates = [coords.lng, coords.lat]
|
||||
self.map.getSource('centerMarker').setData(geoJSON)
|
||||
})
|
||||
// this.marker = marker
|
||||
},
|
||||
mapClose () {
|
||||
this.changZoom = true
|
||||
this.mapConfigVisible = false
|
||||
const latlng = this.marker.getLatLng()
|
||||
this.mapParam.longitude = latlng.lng.toFixed(7)
|
||||
this.mapParam.latitude = latlng.lat.toFixed(7)
|
||||
const latlng = this.map.getSource('centerMarker')._data.features[0].geometry.coordinates
|
||||
this.mapParam.longitude = latlng[0].toFixed(7)
|
||||
this.mapParam.latitude = latlng[1].toFixed(7)
|
||||
this.lnglat = this.mapParam.longitude + ',' + this.mapParam.latitude
|
||||
this.zoom = this.map.getZoom()
|
||||
this.setLatlng()
|
||||
@@ -137,20 +205,6 @@ export default {
|
||||
this.lnglat = this.mapParam.longitude + ',' + this.mapParam.latitude
|
||||
}
|
||||
},
|
||||
changeLnglat () {
|
||||
const lnglat = this.lnglat.split(',')
|
||||
if (lnglat.length !== 2) {
|
||||
this.$message.error(this.$t('tip.lnglatError'))
|
||||
return false
|
||||
}
|
||||
const lngReg = /^[\-\+]?(0?\d{1,2}\.\d{1,7}|1[0-7]?\d{1}\.\d{1,7}|180\.0{1,7}|0?\d{1,2}|1[0-7]?\d{1}|180)$/ // 经度正则验证
|
||||
const latReg = /^[\-\+]?([1-8]?\d{1}\.\d{1,7}|90\.0{1,7}|[1-8]?\d{1}|90)$/ // 纬度正则验证
|
||||
if (!lngReg.test(lnglat[0]) || !latReg.test(lnglat[1])) {
|
||||
// this.lnglat = this.oldlnglat
|
||||
this.$message.error(this.$t('tip.lnglatError'))
|
||||
return false
|
||||
}
|
||||
},
|
||||
queryDefaultMapConfig (data) {
|
||||
return new Promise(resolve => {
|
||||
this.$get('/sysConfig?paramKey=map_center_config').then(response => {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<div class="login" id="login-bgimg">
|
||||
<div class="login" id="login-bgimg">
|
||||
<div class="model"></div>
|
||||
<div class="stars-wrapper" id="stars-wrapper" v-if="!this.bgImg">
|
||||
<img src="../../assets/img/starCloud1.svg">
|
||||
</div>
|
||||
<div class="login-main">
|
||||
<div class="logo"><img src="../../assets/img/logo-big.png"></div>
|
||||
<div class='login-box'>
|
||||
@@ -116,6 +119,8 @@
|
||||
import { mapActions } from 'vuex'
|
||||
import QRCode from 'qrcodejs2'
|
||||
import bus from '@/libs/bus.js'
|
||||
import { SVG } from '@svgdotjs/svg.js'
|
||||
import svgCloud1 from '@/assets/img/starCloud1.svg'
|
||||
import { get } from '@/http'
|
||||
export default {
|
||||
name: 'login',
|
||||
@@ -371,6 +376,26 @@ export default {
|
||||
bus.$on('profile-dialog', () => {
|
||||
this.authBindShow = true
|
||||
})
|
||||
},
|
||||
initStar () {
|
||||
document.getElementById('login-bgimg').style['background-image'] = 'url()'
|
||||
const box = document.getElementById('stars-wrapper')
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const svg = SVG().addTo(box).size('100%', '100%')
|
||||
svg.attr('class', 'stars' + i)
|
||||
svg.attr('width', '100%')
|
||||
svg.attr('height', '100%')
|
||||
svg.attr('preserveAspectRatio', 'none')
|
||||
for (let j = 0; j < 100; j++) {
|
||||
const circle = svg.circle(r(0.5, 3))
|
||||
circle.attr('class', 'star')
|
||||
circle.attr('cx', r(0, 100) + '%')
|
||||
circle.attr('cy', r(0, 100) + '%')
|
||||
}
|
||||
}
|
||||
function r (m, n) {
|
||||
return (Math.random() * (n - m) + m).toFixed(2)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -386,6 +411,8 @@ export default {
|
||||
this.bgImg = localStorage.getItem('nz-sys-bgImg')
|
||||
if (this.bgImg) {
|
||||
document.getElementById('login-bgimg').style['background-image'] = `url(${this.bgImg})`
|
||||
} else {
|
||||
this.initStar()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -406,4 +433,65 @@ export default {
|
||||
.license-upload .el-upload-list{
|
||||
display: none;
|
||||
}
|
||||
:root {
|
||||
--twinkle-duration: 4s;
|
||||
}
|
||||
.stars-wrapper {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#16161d), color-stop(#080430), to(#0D0635));
|
||||
background: linear-gradient(#16161d, #080430, #0D0635);
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
}
|
||||
.stars0,
|
||||
.stars1,
|
||||
.stars2 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
-webkit-animation: twinkle var(--twinkle-duration) ease-in-out infinite;
|
||||
animation: twinkle var(--twinkle-duration) ease-in-out infinite;
|
||||
}
|
||||
.stars0 {
|
||||
-webkit-animation-delay: calc(var(--twinkle-duration) * -0.22);
|
||||
animation-delay: calc(var(--twinkle-duration) * -0.22);
|
||||
}
|
||||
.stars1 {
|
||||
-webkit-animation-delay: calc(var(--twinkle-duration) * -0.44);
|
||||
animation-delay: calc(var(--twinkle-duration) * -0.44);
|
||||
}
|
||||
.stars2 {
|
||||
-webkit-animation-delay: calc(var(--twinkle-duration) * -0.66);
|
||||
animation-delay: calc(var(--twinkle-duration) * -0.66);
|
||||
}
|
||||
@-webkit-keyframes twinkle {
|
||||
25% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes twinkle {
|
||||
25% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
.star {
|
||||
fill: white;
|
||||
}
|
||||
.star:nth-child(3n) {
|
||||
opacity: 0.8;
|
||||
}
|
||||
.star:nth-child(7n) {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.star:nth-child(13n) {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.star:nth-child(19n) {
|
||||
opacity: 0.2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,7 +6,6 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
appPen (pen) {
|
||||
console.log(pen)
|
||||
this.modulesDiff()
|
||||
const data = pen[0]
|
||||
if (data.type === 0 && !data.data.moduleId) {
|
||||
@@ -108,7 +107,6 @@ export default {
|
||||
getTopology(this.topologyIndex).setValue(data)
|
||||
},
|
||||
pensActive (pens) {
|
||||
console.log(pens)
|
||||
this.props = {
|
||||
node: null,
|
||||
line: null,
|
||||
|
||||
@@ -340,6 +340,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="form-items--half-width-group" v-if="isGauge(chartConfig.type)">
|
||||
<!--min-->
|
||||
<el-form-item :label="$t('dashboard.panel.chartForm.min')" class="form-item--half-width">
|
||||
@@ -360,6 +361,40 @@
|
||||
show-word-limit v-model="chartConfig.param.max"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="form-items--half-width-group" v-if="isSankey(chartConfig.type)" key="sankey">
|
||||
<!--Source label-->
|
||||
<el-form-item class="form-item--half-width" :label="$t('dashboard.panel.chartForm.sourceLabel')" prop="param.sourceLabel"
|
||||
:rules="[
|
||||
{ required: true, message: $t('validate.required'), trigger: 'blur'},
|
||||
{ pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, message: $t('dashboard.panel.matchRegex'), trigger: 'blur'},
|
||||
{ validator: labelValidator,trigger: 'blur'},
|
||||
]"
|
||||
>
|
||||
<el-input
|
||||
size="small"
|
||||
style="margin-top: 2px"
|
||||
:placeholder="$t('overall.placeHolder')"
|
||||
@change="change"
|
||||
v-model="chartConfig.param.sourceLabel"/>
|
||||
</el-form-item>
|
||||
<!--Target label-->
|
||||
<el-form-item class="form-item--half-width" :label="$t('dashboard.panel.chartForm.targetLabel')" prop="param.targetLabel"
|
||||
:rules="[
|
||||
{ required: true, message: $t('validate.required'), trigger: 'blur'},
|
||||
{ pattern: /^[a-zA-Z_][a-zA-Z0-9_]*$/, message: $t('dashboard.panel.matchRegex'), trigger: 'blur'},
|
||||
{ validator: labelValidator,trigger: 'blur'},
|
||||
]"
|
||||
>
|
||||
<el-input
|
||||
size="small"
|
||||
style="margin-top: 2px"
|
||||
:placeholder="$t('overall.placeHolder')"
|
||||
@change="change"
|
||||
v-model="chartConfig.param.targetLabel"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div class="form-items--half-width-group" v-if="isShowDecimals(chartConfig.type)">
|
||||
<!--decimals-->
|
||||
<el-form-item :label="$t('overall.decimal')" class="form-item--half-width">
|
||||
@@ -898,7 +933,7 @@ import chartTypeShow from '@/components/common/rightBox/chart/chartTypeShow'
|
||||
import VueTagsInput from '@johmun/vue-tags-input'
|
||||
import draggable from 'vuedraggable'
|
||||
import { randomcolor, ColorReverse } from '@/components/common/js/radomcolor/randomcolor'
|
||||
import { isGauge } from '@/components/chart/chart/tools'
|
||||
import { isGauge, isSankey } from '@/components/chart/chart/tools'
|
||||
|
||||
export default {
|
||||
name: 'chartConfig',
|
||||
@@ -969,6 +1004,10 @@ export default {
|
||||
id: 'gauge',
|
||||
name: this.$t('dashboard.panel.chartForm.typeVal.gauge.label')
|
||||
},
|
||||
{
|
||||
id: 'sankey',
|
||||
name: this.$t('dashboard.panel.chartForm.typeVal.sankey.label')
|
||||
},
|
||||
{
|
||||
id: 'treemap',
|
||||
name: this.$t('dashboard.panel.chartForm.typeVal.treemap.label')
|
||||
@@ -995,6 +1034,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
isGauge,
|
||||
isSankey,
|
||||
beforeInit () {
|
||||
this.promqlType = this.type
|
||||
this.chartTypeList = this[this.type + 'ChartTypeList']
|
||||
@@ -1017,6 +1057,18 @@ export default {
|
||||
this.expressionChange()
|
||||
}
|
||||
},
|
||||
// 变量名校验 防止重复
|
||||
labelValidator (rule, value, callback) {
|
||||
const sourceLabel = this.chartConfig.param.sourceLabel
|
||||
const targetLabel = this.chartConfig.param.targetLabel
|
||||
setTimeout(() => {
|
||||
if (sourceLabel === targetLabel) {
|
||||
callback(new Error(this.$t('error.labelEqual')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}, 100)
|
||||
},
|
||||
chartTypeChange (type) {
|
||||
switch (type) {
|
||||
case 'line':
|
||||
@@ -1053,8 +1105,9 @@ export default {
|
||||
case 'stat':
|
||||
case 'hexagon':
|
||||
case 'gauge':
|
||||
case 'sankey':
|
||||
case 'bubble':
|
||||
if (this.oldType === 'stat' || this.oldType === 'gauge' || this.oldType === 'hexagon' || this.oldType === 'bubble') {
|
||||
if (this.oldType === 'stat' || this.oldType === 'gauge' || this.oldType === 'sankey' || this.oldType === 'hexagon' || this.oldType === 'bubble') {
|
||||
break
|
||||
}
|
||||
this.chartConfig.param = {
|
||||
|
||||
@@ -74,6 +74,7 @@ export default {
|
||||
case 'gauge':
|
||||
case 'pie':
|
||||
case 'bubble':
|
||||
case 'sankey':
|
||||
return true
|
||||
default: return false
|
||||
}
|
||||
@@ -91,6 +92,7 @@ export default {
|
||||
case 'stat':
|
||||
case 'hexagon':
|
||||
case 'gauge':
|
||||
case 'sankey':
|
||||
case 'bubble':
|
||||
return false
|
||||
default: return false
|
||||
@@ -106,6 +108,7 @@ export default {
|
||||
case 'stat':
|
||||
case 'hexagon':
|
||||
case 'gauge':
|
||||
case 'sankey':
|
||||
case 'treemap':
|
||||
case 'pie':
|
||||
case 'bubble':
|
||||
@@ -134,6 +137,7 @@ export default {
|
||||
case 'hexagon':
|
||||
case 'bar':
|
||||
case 'gauge':
|
||||
case 'sankey':
|
||||
case 'treemap':
|
||||
case 'pie':
|
||||
case 'bubble':
|
||||
@@ -151,6 +155,7 @@ export default {
|
||||
case 'stat':
|
||||
case 'hexagon':
|
||||
case 'gauge':
|
||||
case 'sankey':
|
||||
return false
|
||||
case 'line':
|
||||
case 'area':
|
||||
@@ -169,6 +174,7 @@ export default {
|
||||
case 'stat':
|
||||
case 'hexagon':
|
||||
case 'gauge':
|
||||
case 'sankey':
|
||||
return true
|
||||
case 'line':
|
||||
case 'area':
|
||||
@@ -201,6 +207,7 @@ export default {
|
||||
case 'stat':
|
||||
case 'hexagon':
|
||||
case 'gauge':
|
||||
case 'sankey':
|
||||
return true
|
||||
default: return false
|
||||
}
|
||||
|
||||
@@ -247,6 +247,10 @@ export default {
|
||||
id: 'gauge',
|
||||
name: this.$t('dashboard.panel.chartForm.typeVal.gauge.label')
|
||||
},
|
||||
{
|
||||
id: 'sankey',
|
||||
name: this.$t('dashboard.panel.chartForm.typeVal.sankey.label')
|
||||
},
|
||||
{
|
||||
id: 'treemap',
|
||||
name: this.$t('dashboard.panel.chartForm.typeVal.treemap.label')
|
||||
@@ -294,6 +298,10 @@ export default {
|
||||
id: 'gauge',
|
||||
name: this.$t('dashboard.panel.chartForm.typeVal.gauge.label')
|
||||
},
|
||||
{
|
||||
id: 'sankey',
|
||||
name: this.$t('dashboard.panel.chartForm.typeVal.sankey.label')
|
||||
},
|
||||
{
|
||||
id: 'treemap',
|
||||
name: this.$t('dashboard.panel.chartForm.typeVal.treemap.label')
|
||||
|
||||
@@ -39,16 +39,22 @@
|
||||
</template>
|
||||
<template slot-scope="scope" :column="item">
|
||||
<template v-if="item.prop === 'name'">
|
||||
<div class="document-copy-block">
|
||||
<!-- <div class="document-copy-block">
|
||||
<span class="document-copy-text">{{scope.row.name ? scope.row.name : '-'}}</span>
|
||||
<i v-if="scope.row.name" class="nz-icon nz-icon-override" style="visibility: hidden" @click="onCopy(scope.row.name)" :title="$t('overall.copyText')"></i>
|
||||
</div>
|
||||
</div> -->
|
||||
<copy :copyData='scope.row.name'>
|
||||
<template slot="copy-text">
|
||||
{{scope.row.name ? scope.row.name : '-'}}
|
||||
</template>
|
||||
</copy>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'manageIp'">
|
||||
<div class="document-copy-block">
|
||||
<span class="document-copy-text">{{scope.row.manageIp ? scope.row.manageIp : '-'}}</span>
|
||||
<i v-if="scope.row.manageIp" class="nz-icon nz-icon-override" style="visibility: hidden" @click="onCopy(scope.row.manageIp)" :title="$t('overall.copyText')"></i>
|
||||
</div>
|
||||
<copy :copyData='scope.row.manageIp'>
|
||||
<template slot="copy-text">
|
||||
{{scope.row.manageIp ? scope.row.manageIp : '-'}}
|
||||
</template>
|
||||
</copy>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'type'">{{scope.row.type ? scope.row.type.name : '-'}}</template>
|
||||
<template v-else-if="item.prop === 'state'">{{scope.row.state ? scope.row.state.name : '-'}}</template>
|
||||
@@ -188,6 +194,7 @@
|
||||
import table from '@/components/common/mixin/table'
|
||||
import { showTableTooltip, hideTableTooltip } from '@/components/common/js/tools'
|
||||
// import bus from '@/libs/bus'
|
||||
import copy from '@/components/common/copy'
|
||||
import alertLabel from '@/components/common/alert/alertLabel'
|
||||
import alertDaysInfo from '@/components/common/alert/alertDaysInfo'
|
||||
import alertLabelMixin from '@/components/common/mixin/alertLabelMixin'
|
||||
@@ -196,7 +203,8 @@ export default {
|
||||
mixins: [table, alertLabelMixin],
|
||||
components: {
|
||||
alertLabel: alertLabel,
|
||||
alertDaysInfo
|
||||
alertDaysInfo,
|
||||
copy
|
||||
},
|
||||
props: {
|
||||
showOption: {
|
||||
|
||||
@@ -37,16 +37,18 @@
|
||||
</template>
|
||||
<template slot-scope="scope" :column="item">
|
||||
<template v-if="item.prop === 'name'">
|
||||
<div class="document-copy-block">
|
||||
<span class="document-copy-text">{{scope.row.name ? scope.row.name : '-'}}</span>
|
||||
<i v-if="scope.row.name" class="nz-icon nz-icon-override" style="visibility: hidden" @click="onCopy(scope.row.name)" :title="$t('overall.copyText')"></i>
|
||||
</div>
|
||||
<copy :copyData='scope.row.name'>
|
||||
<template slot="copy-text">
|
||||
{{scope.row.name ? scope.row.name : '-'}}
|
||||
</template>
|
||||
</copy>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'type'">
|
||||
<div class="document-copy-block">
|
||||
<span class="document-copy-text">{{scope.row.type ? scope.row.type : '-'}}</span>
|
||||
<i v-if="scope.row.type" class="nz-icon nz-icon-override" style="visibility: hidden" @click="onCopy(scope.row.type)" :title="$t('overall.copyText')"></i>
|
||||
</div>
|
||||
<copy :copyData='scope.row.type'>
|
||||
<template slot="copy-text">
|
||||
{{scope.row.type ? scope.row.type : '-'}}
|
||||
</template>
|
||||
</copy>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'reporter'">
|
||||
<template>{{scope.row[item.prop] ? scope.row[item.prop].name : '-'}}</template>
|
||||
@@ -120,9 +122,14 @@
|
||||
|
||||
<script>
|
||||
import table from '@/components/common/mixin/table'
|
||||
import copy from '@/components/common/copy'
|
||||
export default {
|
||||
name: 'issueTable',
|
||||
mixins: [table],
|
||||
components: {
|
||||
copy
|
||||
},
|
||||
|
||||
props: {
|
||||
loading: Boolean
|
||||
},
|
||||
|
||||
@@ -38,10 +38,11 @@
|
||||
</template>
|
||||
<template slot-scope="scope" :column="item">
|
||||
<template v-if="item.prop === 'name'">
|
||||
<div class="document-copy-block">
|
||||
<span class="document-copy-text">{{scope.row.name ? scope.row.name : '-'}}</span>
|
||||
<i v-if="scope.row.name" class="nz-icon nz-icon-override" style="visibility: hidden" @click="onCopy(scope.row.name)" :title="$t('overall.copyText')"></i>
|
||||
</div>
|
||||
<copy :copyData='scope.row.name'>
|
||||
<template slot="copy-text">
|
||||
{{scope.row.name ? scope.row.name : '-'}}
|
||||
</template>
|
||||
</copy>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'type'">
|
||||
<template v-if="scope.row[item.prop]">
|
||||
@@ -51,10 +52,11 @@
|
||||
<template v-else>{{"-"}}</template>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'expr'">
|
||||
<div class="document-copy-block">
|
||||
<span class="document-copy-text">{{scope.row[item.prop] ? scope.row[item.prop] : '-'}}</span>
|
||||
<i v-if="scope.row[item.prop]" class="nz-icon nz-icon-override" style="visibility: hidden" @click="onCopy(scope.row[item.prop])" :title="$t('overall.copyText')"></i>
|
||||
</div>
|
||||
<copy :copyData='scope.row[item.prop]'>
|
||||
<template slot="copy-text">
|
||||
{{scope.row[item.prop] ? scope.row[item.prop] : '-'}}
|
||||
</template>
|
||||
</copy>
|
||||
</template>
|
||||
<template v-else-if="item.prop === 'inr'">
|
||||
<template>{{scope.row[item.prop] ? scope.row[item.prop] : '-'}}</template>
|
||||
@@ -134,13 +136,15 @@
|
||||
|
||||
<script>
|
||||
import lodash from 'lodash'
|
||||
import copy from '@/components/common/copy'
|
||||
import table from '@/components/common/mixin/table'
|
||||
import nzAlertTag from '../../../page/alert/nzAlertTag'
|
||||
import alertLabelMixin from '@/components/common/mixin/alertLabelMixin'
|
||||
export default {
|
||||
name: 'recordRuleTable',
|
||||
components: {
|
||||
nzAlertTag
|
||||
nzAlertTag,
|
||||
copy
|
||||
},
|
||||
mixins: [table, alertLabelMixin],
|
||||
props: {
|
||||
|
||||
BIN
nezha-fronted/static/Titles/fonts/Noto Sans Regular/0-255.pbf
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular10240-10495
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular10496-10751
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular10752-11007
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular11008-11263
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular12032-12287
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular12288-12543
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular12544-12799
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular12800-13055
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular13056-13311
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular13312-13567
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular13568-13823
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular13824-14079
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular14080-14335
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular14336-14591
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular14592-14847
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular14848-15103
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular15104-15359
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular 1536-1791
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular15360-15615
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular15616-15871
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular15872-16127
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular16128-16383
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular16384-16639
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular16640-16895
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular16896-17151
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular17152-17407
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular17408-17663
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular17664-17919
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular 1792-2047
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular17920-18175
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular18176-18431
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular18432-18687
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular18688-18943
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular18944-19199
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular19200-19455
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular19456-19711
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular19712-19967
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular19968-20223
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular20224-20479
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular 2048-2303
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular20480-20735
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular20736-20991
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular20992-21247
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular21248-21503
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular21504-21759
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular21760-22015
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular22016-22271
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular22272-22527
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular22528-22783
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular22784-23039
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular23040-23295
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular23296-23551
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular23552-23807
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular23808-24063
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular24064-24319
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular24320-24575
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular24576-24831
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular24832-25087
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular25088-25343
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular25344-25599
|
||||
BIN
nezha-fronted/static/Titles/fonts/Noto Sans Regular/256-511.pbf
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular 2560-2815
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
Noto Sans Regular25600-25855
|
||||