CN-268 feat: panel重构--entity详情、ip基础信息等(部分)

This commit is contained in:
chenjinsong
2022-01-18 23:12:03 +08:00
parent bfb6f087c6
commit 8863544f1b
18 changed files with 874 additions and 786 deletions

View File

@@ -86,9 +86,6 @@
font-weight:normal;
}
.cn-panel-crypto {
grid-template-columns: repeat(36, 1fr) !important;
}
.cn-chart:not(.cn-chart__group):not(.cn-chart__block) {
&>.cn-chart__body {
height: 100%;
@@ -672,7 +669,7 @@
height: 100%;
width: 100%;
overflow: auto;
&>div {
/*&>div {
display: grid;
grid-template-columns: repeat(30, 1fr);
grid-auto-flow: row;
@@ -701,7 +698,7 @@
}
}
}
}
}*/
}
}
.el-overlay {

View File

@@ -1,5 +1,5 @@
@import 'components/advancedSearch/advanced-search';
@import './components/charts/panel';
// @import './components/charts/panel';
@import 'components/common/TimeRange/date-time-range';
@import 'components/common/TimeRange/time-refresh';
@import './components/common/pagination';

File diff suppressed because it is too large Load Diff

View File

@@ -68,6 +68,7 @@
height: calc(100% - 28px);
flex: 1;
padding: 10px;
overflow: auto;
background-color: $--content-right-background-color;
&>.cn-entity-detail .entity-detail__body>.cn-panel {

View File

@@ -16,7 +16,15 @@ const locale = require('element-plus/lib/locale')
const debounce = require('lodash/debounce')
const ElScrollbar = require('element-plus/lib/el-scrollbar')
const union = require('lodash/union')
const utc = require('dayjs/plugin/utc')
const timezone = require('dayjs/plugin/timezone')
const advancedFormat = require('dayjs/plugin/advancedFormat')
const weekday = require('dayjs/plugin/weekday')
dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.extend(advancedFormat)
dayjs.extend(weekday)
window.$dayJs = dayjs
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e } }
const dayjs__default = /* #__PURE__ */_interopDefaultLegacy(window.$dayJs)

View File

@@ -19,15 +19,17 @@ import timezone from 'dayjs/plugin/timezone'
import advancedFormat from 'dayjs/plugin/advancedFormat'
import weekday from 'dayjs/plugin/weekday'
import DateTimeRange from '@/components/common/TimeRange/DateTimeRange'
import TimeRefresh from '@/components/common/TimeRange/TimeRefresh'
import PanelChartList from '@/views/charts/PanelChartList'
const _ = require('lodash') // lodash工具
dayjs.extend(utc)
/*dayjs.extend(utc)
dayjs.extend(timezone)
dayjs.extend(advancedFormat)
dayjs.extend(weekday)
window.$dayJs = dayjs
window.$dayJs = dayjs*/
const app = createApp(App)
@@ -47,6 +49,8 @@ app.config.globalProperties.$_ = _
app.mixin(commonMixin)
app.component('date-time-range', DateTimeRange)
app.component('time-refresh', TimeRefresh)
app.component('panel-chart-list', PanelChartList)
app.mount('#app')

View File

@@ -8,7 +8,7 @@ import { storageKey } from '@/utils/constants'
import { loadI18n } from '@/i18n'
const loginWhiteList = ['/login', '/'] // 免登陆白名单
const permissionWhiteList = [...loginWhiteList] // 权限白名单
const permissionWhiteList = [...loginWhiteList, '/entityDetail'] // 权限白名单
router.beforeEach(async (to, from, next) => {
// 加载iso-3166-2资源

View File

@@ -1,6 +1,6 @@
<template>
<div class="cn-chart">
<loading :loading="loading && !isTabs"></loading>
<loading :loading="loading && !isTabs && !isBlock"></loading>
<chart-no-data v-if="isNoData"></chart-no-data>
<template v-else>
@@ -8,13 +8,15 @@
v-if="isTabs"
:chart-info="chartInfo"
:query-params="queryParams"
:entity="entity"
></chart-tabs>
<chart-map
v-else-if="isMap"
v-else-if="isMap && !isIpBasicInfo"
:chart-info="chartInfo"
:chart-data="chartData"
:query-params="queryParams"
:entity="entity"
@showLoading="showLoading"
></chart-map>
@@ -26,7 +28,19 @@
@showLoading="showLoading"
></chart-single-value>
<div v-else style="height: 100%; width: 100%; background-color: lightcyan;"></div>
<chart-block
v-else-if="isBlock"
:chart-info="chartInfo"
:chart-data="chartData"
:entity="entity"
></chart-block>
<ip-basic-info
v-else-if="isIpBasicInfo"
:chart-info="chartInfo"
:chart-data="chartData"
:entity="entity"
></ip-basic-info>
<chart-echart-line
v-else-if="isEchartsLine"
@@ -47,6 +61,8 @@ import ChartNoData from './charts/ChartNoData'
import ChartTabs from './charts/ChartTabs'
import ChartMap from './charts/ChartMap'
import ChartSingleValue from './charts/ChartSingleValue'
import ChartBlock from './charts/ChartBlock'
import IpBasicInfo from '@/views/charts/charts/IpBasicInfo'
import ChartEchartLine from './charts/ChartEchartLine'
import {
isEcharts,
@@ -84,12 +100,14 @@ import _ from 'lodash'
export default {
name: 'chart',
components: {
IpBasicInfo,
ChartSingleValue,
Loading,
ChartNoData,
ChartTabs,
ChartMap,
ChartEchartLine
ChartEchartLine,
ChartBlock
},
props: {
chartInfo: Object,
@@ -100,6 +118,7 @@ export default {
isFullscreen: Boolean,
loading: Boolean,
panelLock: Boolean,
entity: Object,
isError: Boolean
},
computed: {

View File

@@ -1,21 +1,30 @@
<template>
<div class="chart-header" :class="{'chart-header--title-chart': isTitle}">
<div class="chart-header__title">{{chartInfo.name}}</div>
<div class="chart-header__title" :class="{'chart-header__title--block': isBlock}">{{chartInfo.name}}</div>
<chart-error :isError="isError" :errorInfo="errorInfo"></chart-error>
<div class="chart-header__tools" v-if="!isTitle && !isTabs">
<el-popover trigger="click" placement="top" :content="chartInfo.remark" v-if="chartInfo.remark">
<template #reference>
<span class="header__operation-btn"><i class="cn-icon el-icon-info"></i></span>
</template>
</el-popover>
<span class="header__operation-btn" @click="refresh"><i class="cn-icon cn-icon-refresh"></i></span>
<div class="panel__time" v-if="chartInfo.params && chartInfo.params.showTimeTool">
<date-time-range class="date-time-range" :start-time="chartTimeFilter.startTime" :end-time="chartTimeFilter.endTime" ref="dateTimeRange" @change="reload"/>
<time-refresh class="date-time-range" @change="timeRefreshChange" :end-time="chartTimeFilter.endTime"/>
</div>
<template v-else-if="!isBlock">
<el-popover trigger="click" placement="top" :content="chartInfo.remark" v-if="chartInfo.remark">
<template #reference>
<span class="header__operation-btn"><i class="cn-icon el-icon-info"></i></span>
</template>
</el-popover>
<span class="header__operation-btn" @click="refresh"><i class="cn-icon cn-icon-refresh"></i></span>
</template>
</div>
</div>
</template>
<script>
import { isTitle, isTabs } from './charts/tools'
import { isTitle, isTabs, isBlock } from './charts/tools'
import ChartError from '@/components/charts/ChartError'
import { getNowTime } from '@/utils/date-util'
import { ref } from 'vue'
export default {
name: 'ChartHeader',
props: {
@@ -41,11 +50,29 @@ export default {
methods: {
refresh () {
this.$emit('refresh')
},
timeRefreshChange () {
if (!this.$refs.dateTimeRange.isCustom) {
const value = this.chartTimeFilter.dateRangeValue
this.$refs.dateTimeRange.quickChange(value)
}
},
reload (s, e, v) {
this.dateTimeRangeChange(s, e, v)
},
dateTimeRangeChange (s, e, v) {
this.chartTimeFilter = { startTime: s, endTime: e, dateRangeValue: v }
}
},
setup (props) {
const dateRangeValue = 60
const { startTime, endTime } = getNowTime(dateRangeValue)
// entity详情内的chart时间工具不是公共的需要单独定义
const chartTimeFilter = ref({ startTime, endTime, dateRangeValue })
return {
chartTimeFilter,
isTitle: isTitle(props.chartInfo.type),
isBlock: isBlock(props.chartInfo.type),
isTabs: isTabs(props.chartInfo.type)
}
}

View File

@@ -2,8 +2,8 @@
<div style="padding: 10px 10px 20px 10px; overflow: auto" v-if="!isEntityDetail">
<div id="cn-panel" class="cn-panel2">
<div class="panel__time">
<DateTimeRange class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" ref="dateTimeRange" @change="reload"/>
<TimeRefresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>
<date-time-range class="date-time-range" :start-time="timeFilter.startTime" :end-time="timeFilter.endTime" ref="dateTimeRange" @change="reload"/>
<time-refresh class="date-time-range" @change="timeRefreshChange" :end-time="timeFilter.endTime"/>
</div>
<panel-chart-list
:time-filter="timeFilter"
@@ -11,46 +11,26 @@
:panel-lock="panelLock"
>
</panel-chart-list>
<!-- <chart
v-for="chart in chartList"
:key="chart.id"
:chart="chart"
:time-filter="timeFilter"
:ref="`chart-${chart.id}`"
:entity="entity"
@getCurrentTimeRange="getCurrentTimeRange"
></chart>-->
<!-- <grid-layout v-model:layout="chartList"
:col-num="12"
:row-height="30"
:is-draggable="draggable"
:is-resizable="resizable"
:vertical-compact="compact"
:use-css-transforms="true"
>
<grid-item v-for="item in chartList" :key="item.i"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
>
<span class="text">{{ item.i }}</span>
</grid-item>
</grid-layout>-->
</div>
</div>
<div class="cn-entity-detail" id="cn-entity-detail" v-else>
<div class="entity-detail__body">
<div class="cn-panel" @scroll="scroll" id="cn-panel">
<template v-for="chart in chartList" :key="chart.id">
<!-- <chart
<div class="cn-panel2" id="cn-panel">
<panel-chart-list
:time-filter="timeFilter"
:data-list="chartList"
:panel-lock="panelLock"
:entity="entity"
>
</panel-chart-list>
<!-- <template v-for="chart in chartList" :key="chart.id">
<chart
:chart="chart"
:ref="`chart-${chart.id}`"
:entity="entity"
@getCurrentTimeRange="getCurrentTimeRange"
></chart>-->
</template>
></chart>
</template>-->
</div>
</div>
</div>
@@ -62,8 +42,6 @@ import { ref } from 'vue'
import { panelTypeAndRouteMapping } from '@/utils/constants'
import { api, getPanelList, getChartList } from '@/utils/api'
import { getNowTime } from '@/utils/date-util'
import DateTimeRange from '@/components/common/TimeRange/DateTimeRange'
import TimeRefresh from '@/components/common/TimeRange/TimeRefresh'
export default {
name: 'Panel',
@@ -72,10 +50,6 @@ export default {
isEntityDetail: Boolean,
typeName: String
},
components: {
DateTimeRange,
TimeRefresh
},
data () {
return {
chartList: [], // 普通panel的chart
@@ -125,16 +99,13 @@ export default {
this.chartList = allCharts
setTimeout(() => {
this.$emit('chartLoaded', allCharts)
})
}, 1000)
}
},
changeTab ({ index }) {
this.currentTab = this.detailTabs[index].id + ''
this.detailChartList = this.detailTabs[index].children
},
scroll (e) {
this.$emit('scroll', { top: e.target.scrollTop })
},
recursionParamsConvert (chart) {
chart.params = chart.params ? JSON.parse(chart.params) : null
if (!this.$_.isEmpty(chart.children)) {
@@ -165,9 +136,6 @@ export default {
this.chartList.forEach(chart => {
this.$refs[`chart-${chart.id}`] && this.$refs[`chart-${chart.id}`].reloadChart()
})
},
jumpToTop (top) {
document.querySelector('#cn-panel').scrollTop = top
}
}
}

View File

@@ -1,9 +1,13 @@
<template>
<!-- chart外层箱子 -->
<div :class="{'panel-chart--fullscreen': isFullscreen, 'panel-chart--title-chart': isTitle}" class="panel-chart" :id="isFullscreen ? ('chart-screen-' + chartInfo.id ) : ('chart-local-' + chartInfo.id)">
<div
:class="{'panel-chart--fullscreen': isFullscreen, 'panel-chart--title-chart': isTitle}"
class="panel-chart"
:id="isFullscreen ? ('chart-screen-' + chartInfo.id ) : ('chart-local-' + chartInfo.id)"
>
<!-- title和工具栏支持浮动 -->
<chart-header
v-if="!isFullscreen && showHeader && !isSingleValue"
v-if="!isFullscreen && showHeader && !isSingleValue && !isTabs"
:is-error="isError"
:error-info="errorInfo"
:chart-data="chartData"
@@ -16,7 +20,7 @@
<!-- 数据查询后传入chart组件chart组件内不查询只根据接传递的数据来渲染 -->
<chart
ref="chart"
v-if="(!isGroup || !chartInfo.param.collapse) && !isTitle"
v-if="(!isGroup || !(chartInfo.params && chartInfo.params.collapse)) && !isTitle"
:chart-data="chartData"
:result-type="resultType"
:chart-info="chartInfo"
@@ -24,6 +28,7 @@
:panel-lock="panelLock"
:is-error="isError"
:loading="loading"
:entity="entity"
:is-fullscreen="isFullscreen"
@showLoading="showLoading"
></chart>
@@ -80,6 +85,7 @@ export default {
timeFilter: Object, // 时间范围
isFullscreen: Boolean,
panelLock: Boolean,
entity: Object,
showHeader: {
type: Boolean,
default: true

View File

@@ -25,12 +25,14 @@
:isResizable = "item.type === 'group' ? false: null"
dragAllowFrom=".chart-header"
dragIgnoreFrom=".chart-header__tools"
v-bind="anchorPoint(item)"
>
<panel-chart
:ref="'chart' + item.id"
:chart-info="item"
:show-header="true"
:time-filter="timeFilter"
:entity="entity"
@showFullscreen="showFullscreen"
></panel-chart>
</grid-item>
@@ -64,6 +66,7 @@
import PanelChart from '@/views/charts/PanelChart'
import VueGridLayout from 'vue-grid-layout'
import { getTypeCategory } from './charts/tools'
import _ from 'lodash'
export default {
name: 'PanelChartList',
@@ -76,6 +79,7 @@ export default {
timeFilter: Object, // 时间范围
panelLock: { type: Boolean, default: true },
isGroup: Boolean,
entity: Object,
dataList: Array // 看板中所有图表信息
},
data () {
@@ -109,9 +113,21 @@ export default {
this.fullscreen.visible = show
}
},
computed: {
anchorPoint () {
return function (chart) {
if (!_.isEmpty(chart.params && chart.params.anchorPoint)) {
return { 'anchor-point': chart.params.anchorPoint }
} else {
return ''
}
}
}
},
watch: {
dataList: {
deep: true,
immediate: true,
handler (n, o) {
this.gridLayoutShow = false
this.gridLayoutLoading = true

View File

@@ -0,0 +1,23 @@
<template>
<panel-chart-list
:time-filter="timeFilter"
:data-list="chartInfo.children"
:panel-lock="true"
:entity="entity"
>
</panel-chart-list>
</template>
<script>
import chartMixin from '@/views/charts/charts/chart-mixin'
export default {
name: 'ChartBlock',
mixins: [chartMixin],
props: {
timeFilter: Object
},
mounted () {
}
}
</script>

View File

@@ -4,21 +4,16 @@
</template>
<script>
import * as L from 'leaflet'
import * as am4Core from '@amcharts/amcharts4/core'
import * as am4Maps from '@amcharts/amcharts4/maps'
import { getGeoData, replaceUrlPlaceholder } from '@/utils/tools'
import { storageKey } from '@/utils/constants'
import 'leaflet/dist/leaflet.css'
import icon from 'leaflet/dist/images/marker-icon.png'
import iconShadow from 'leaflet/dist/images/marker-shadow.png'
import {
isIpBasicInfo,
isMapBlock
} from './tools'
import { isMapBlock } from './tools'
import unitConvert, { valueToRangeValue } from '@/utils/unit-convert'
import { HeatLegend } from '@/components/amcharts/heatLegend'
import { getData } from '@/utils/api'
import chartMixin from './chart-mixin'
export default {
name: 'ChartMap',
@@ -31,88 +26,50 @@ export default {
countrySeries: null // 下钻国家series
}
},
props: {
chartInfo: Object,
chartData: [Array, Object],
queryParams: Object
},
mixins: [chartMixin],
methods: {
initMap (id) {
if (this.isIpBasicInfo) {
L.Marker.prototype.options.icon = L.icon({
iconUrl: icon,
shadowUrl: iconShadow
})
const map = L.map(`chart${this.chartInfo.id}`, {
minZoom: 3,
maxZoom: 7,
zoom: 5,
attributionControl: false,
zoomControl: false,
maxBounds: L.latLngBounds(L.latLng(-90, -180), L.latLng(90, 180))
})
L.tileLayer(
this.mapPictureUrl,
{ 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) */
this.myChart = map
this.loadLeafletMap()
} else {
const chart = am4Core.create(id, am4Maps.MapChart)
chart.geodata = getGeoData(storageKey.iso36112WorldLow)
chart.projection = new am4Maps.projections.Miller()
this.myChart = chart
const polygonSeries = chart.series.push(new am4Maps.MapPolygonSeries())
polygonSeries.useGeodata = true
polygonSeries.exclude = ['AQ'] // 排除南极洲
polygonSeries.tooltip.getFillFromObject = false
polygonSeries.tooltip.background.fill = am4Core.color('#FFFFFF')
this.polygonSeries = polygonSeries
const polygonTemplate = polygonSeries.mapPolygons.template
polygonTemplate.tooltipHTML = this.generateTooltipHTML()
polygonTemplate.nonScalingStroke = true
polygonTemplate.strokeWidth = 0.5
polygonTemplate.fill = am4Core.color('rgba(176,196,222,.5)')
this.loadAm4ChartMap(this.polygonSeries)
// 地图点击事件
polygonTemplate.events.on('hit', async ev => {
const countryId = ev.target.dataItem.dataContext.id
if (countryId) {
ev.target.series.chart.zoomToMapObject(ev.target)
ev.target.isHover = false
this.countrySeries = chart.series.push(new am4Maps.MapPolygonSeries())
this.countrySeries.tooltip.getFillFromObject = false
this.countrySeries.tooltip.background.fill = am4Core.color('#FFFFFF')
const countryTemplate = this.countrySeries.mapPolygons.template
countryTemplate.tooltipHTML = this.generateTooltipHTML()
countryTemplate.nonScalingStroke = true
countryTemplate.strokeWidth = 0.5
countryTemplate.fill = am4Core.color('rgba(176,196,222,.5)')
const geoData = getGeoData(countryId)
if (geoData) {
this.countrySeries.geodata = geoData
this.polygonSeries.hide()
const country = ev.target.dataItem.dataContext.serverCountry
const queryParams = { ...this.queryParams, country }
const chartData = await getData(replaceUrlPlaceholder(this.chartInfo.params.url, queryParams))
this.loadAm4ChartMap(this.countrySeries, ev.target.dataItem.dataContext.serverCountry, chartData)
}
const chart = am4Core.create(id, am4Maps.MapChart)
chart.geodata = getGeoData(storageKey.iso36112WorldLow)
chart.projection = new am4Maps.projections.Miller()
this.myChart = chart
const polygonSeries = chart.series.push(new am4Maps.MapPolygonSeries())
polygonSeries.useGeodata = true
polygonSeries.exclude = ['AQ'] // 排除南极洲
polygonSeries.tooltip.getFillFromObject = false
polygonSeries.tooltip.background.fill = am4Core.color('#FFFFFF')
this.polygonSeries = polygonSeries
const polygonTemplate = polygonSeries.mapPolygons.template
polygonTemplate.tooltipHTML = this.generateTooltipHTML()
polygonTemplate.nonScalingStroke = true
polygonTemplate.strokeWidth = 0.5
polygonTemplate.fill = am4Core.color('rgba(176,196,222,.5)')
this.loadAm4ChartMap(this.polygonSeries)
// 地图点击事件
polygonTemplate.events.on('hit', async ev => {
const countryId = ev.target.dataItem.dataContext.id
if (countryId) {
ev.target.series.chart.zoomToMapObject(ev.target)
ev.target.isHover = false
this.countrySeries = chart.series.push(new am4Maps.MapPolygonSeries())
this.countrySeries.tooltip.getFillFromObject = false
this.countrySeries.tooltip.background.fill = am4Core.color('#FFFFFF')
const countryTemplate = this.countrySeries.mapPolygons.template
countryTemplate.tooltipHTML = this.generateTooltipHTML()
countryTemplate.nonScalingStroke = true
countryTemplate.strokeWidth = 0.5
countryTemplate.fill = am4Core.color('rgba(176,196,222,.5)')
const geoData = getGeoData(countryId)
if (geoData) {
this.countrySeries.geodata = geoData
this.polygonSeries.hide()
const country = ev.target.dataItem.dataContext.serverCountry
const queryParams = { ...this.queryParams, country }
const chartData = await getData(replaceUrlPlaceholder(this.chartInfo.params.url, queryParams))
this.loadAm4ChartMap(this.countrySeries, ev.target.dataItem.dataContext.serverCountry, chartData)
}
})
}
}
})
},
loadAm4ChartMap (polygonSeries, country, chartData) {
if (chartData) {
@@ -196,20 +153,6 @@ export default {
}
}
},
loadLeafletMap () {
this.$emit('showLoading', true)
try {
this.myChart.setView([this.chartData.latitude, this.chartData.longitude], 5)
const myIcon = L.divIcon({
className: 'cn-icon cn-icon-position2 position-icon'
})
L.marker([this.chartData.latitude, this.chartData.longitude], { icon: myIcon }).addTo(this.myChart)
} finally {
setTimeout(() => {
this.$emit('showLoading', false)
}, 200)
}
},
mapBack () {
this.countrySeries.hide()
this.$nextTick(() => {
@@ -264,7 +207,6 @@ export default {
},
setup (props) {
return {
isIpBasicInfo: isIpBasicInfo(props.chartInfo.type),
isMapBlock: isMapBlock(props.chartInfo.type)
}
}

View File

@@ -15,6 +15,7 @@
:time-filter="timeFilter"
:data-list="tab.children"
:panel-lock="true"
:entity="entity"
>
</panel-chart-list>
</el-tab-pane>
@@ -23,14 +24,10 @@
<script>
import _ from 'lodash'
import chartMixin from '@/views/charts/charts/chart-mixin'
export default {
name: 'ChartTabs',
props: {
chartInfo: Object,
chartData: [Object, Array, String], // 数据在父组件查询后传入,本组件内不查询,只根据接传递的数据来渲染
queryParams: Object // 接口请求参数
},
computed: {
timeFilter () {
return {
@@ -39,6 +36,7 @@ export default {
}
}
},
mixins: [chartMixin],
methods: {
showFullscreen () {

View File

@@ -0,0 +1,115 @@
<template>
<div class="cn-chart__ip-basic">
<el-descriptions :column="1">
<el-descriptions-item label="ASN:">{{(chartData && chartData.asn) || '-'}}</el-descriptions-item>
<el-descriptions-item label="AS Org:">{{(chartData && chartData.asOrganization) || '-'}}</el-descriptions-item>
<el-descriptions-item :label="$t('entities.asSubnet') + ':'">{{(chartData && chartData.asSubnet) || '-'}}</el-descriptions-item>
<el-descriptions-item label="ISP:">{{(chartData && chartData.isp) || '-'}}</el-descriptions-item>
<el-descriptions-item label="DNS PTR:">{{(chartData && chartData.dnsPtr) || '-'}}</el-descriptions-item>
</el-descriptions>
<div class="chart-location">
<el-descriptions :column="1">
<el-descriptions-item :label="$t('overall.location') + ':'">{{location}}</el-descriptions-item>
</el-descriptions>
<div class="chart-drawing" style="padding: 0 36px 30px 0;" :id="`chart${chartInfo.id}`"></div>
</div>
</div>
</template>
<script>
import chartMixin from '@/views/charts/charts/chart-mixin'
import * as L from 'leaflet'
import icon from 'leaflet/dist/images/marker-icon.png'
import iconShadow from 'leaflet/dist/images/marker-shadow.png'
import 'leaflet/dist/leaflet.css'
export default {
name: 'IpBasicInfo',
mixins: [chartMixin],
data () {
return {
myChart: null,
mapPictureUrl: '/Tiles/{z}/{x}/{y}.png'
}
},
computed: {
location () {
let location = ''
if (this.chartInfo) {
if (this.chartInfo.country) {
location = this.chartInfo.country
if (this.chartInfo.province) {
location += ', '
location += this.chartInfo.province
if (this.chartInfo.city) {
location += ', '
location += this.chartInfo.city
}
}
} else if (this.chartInfo.province) {
location = this.chartInfo.province
if (this.chartInfo.city) {
location += ', '
location += this.chartInfo.city
}
} else if (this.chartInfo.city) {
location = this.chartInfo.city
}
}
return location
}
},
methods: {
initMap (id) {
L.Marker.prototype.options.icon = L.icon({
iconUrl: icon,
shadowUrl: iconShadow
})
const map = L.map(`chart${this.chartInfo.id}`, {
minZoom: 3,
maxZoom: 7,
zoom: 5,
attributionControl: false,
zoomControl: false,
maxBounds: L.latLngBounds(L.latLng(-90, -180), L.latLng(90, 180))
})
L.tileLayer(
this.mapPictureUrl,
{ 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) */
this.myChart = map
this.loadLeafletMap()
},
loadLeafletMap () {
if (this.chartData.latitude && this.chartData.longitude) {
this.myChart.setView([this.chartData.latitude, this.chartData.longitude], 5)
const myIcon = L.divIcon({
className: 'cn-icon cn-icon-position2 position-icon'
})
L.marker([this.chartData.latitude, this.chartData.longitude], { icon: myIcon }).addTo(this.myChart)
}
}
},
watch: {
chartData: {
deep: true,
handler (n) {
this.initMap(`chart${this.chartInfo.id}`)
}
}
}
}
</script>

View File

@@ -0,0 +1,8 @@
export default {
props: {
chartInfo: Object,
chartData: [Object, Array, String], // 数据在父组件查询后传入,本组件内不查询,只根据接传递的数据来渲染
entity: Object,
queryParams: Object // 接口请求参数
}
}

View File

@@ -12,13 +12,12 @@
</div>
</template>
</div>
<div class="entity-detail__content">
<div class="entity-detail__content" @scroll="scroll" id="detailWrapper">
<cn-panel
ref="cnPanel"
:entity="entityData"
:is-entity-detail="true"
@chartLoaded="chartLoaded"
@scroll="scroll"
></cn-panel>
</div>
</main>
@@ -75,16 +74,16 @@ export default {
chartLoaded (chartList) {
this.anchorPoints = []
let anchorPoints = []
const panelDom = document.querySelector('#cn-panel')
const panelDom = document.querySelector('#detailWrapper')
this.scrollHeight = panelDom.scrollHeight
this.clientHeight = panelDom.clientHeight
chartList.forEach(chart => {
if (chart.params.anchorPoint) {
const dom = document.querySelector(`#${chart.params.anchorPoint}`)
anchorPoints.push({
const dom = document.querySelector(`[anchor-point='${chart.params.anchorPoint}']`)
dom && anchorPoints.push({
id: chart.params.anchorPoint,
label: chart.i18n ? this.$t(chart.i18n) : chart.name,
top: dom.offsetTop/* ,
top: dom.offsetTop + 10/* ,
height: document.querySelector(`#${chart.params.anchorPoint}}`).scrollHeight */
})
}
@@ -98,12 +97,12 @@ export default {
}
this.anchorPoints = anchorPoints
},
scroll ({ top }) {
this.top = top || 0
scroll (e) {
this.top = (e.target.scrollTop + 10) || 0
},
jumpToAnchor (anchor) {
this.top = anchor.top
this.$refs.cnPanel.jumpToTop(anchor.top)
document.querySelector('#detailWrapper').scrollTop = this.top
}
},
computed: {
@@ -133,7 +132,7 @@ export default {
},
currentAnchor () {
let currentAnchor = null
if (this.top + this.clientHeight === this.scrollHeight) {
if (this.top + this.clientHeight - 10 === this.scrollHeight) {
currentAnchor = this.anchorPoints[this.anchorPoints.length - 1]
} else {
this.anchorPoints.forEach(anchor => {