554 lines
17 KiB
Vue
554 lines
17 KiB
Vue
<template>
|
||
<div class="statistics">
|
||
<div class="banner">
|
||
<el-dropdown @command="handleCommand">
|
||
<span class="titles">{{ currentTitle }}<i class="el-icon-arrow-down el-icon--right" /></span>
|
||
<el-dropdown-menu slot="dropdown">
|
||
<el-dropdown-item command="全部遥控潜水器">全部遥控潜水器</el-dropdown-item>
|
||
<el-dropdown-item v-for="item in titles" :key="item.tsy_id" :command="item.report_name">
|
||
{{ item.report_name }}
|
||
</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</el-dropdown>
|
||
<div class="numbers">
|
||
<div v-for="(item, index) in numbers" :key="index" class="item">
|
||
<div class="value">{{ item.value }}<span class="unit">{{ item.unit }}</span></div>
|
||
<div class="label">{{ item.label }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- 地图板块-->
|
||
<div class="map-module">
|
||
<div class="bezel">
|
||
<div class="map-title">下潜单位</div>
|
||
<div id="workUnitMap_rov" ref="workUnitMap_rov" style="height: 100%;width:100%;" />
|
||
</div>
|
||
<div class="bezel">
|
||
<div class="map-title">下潜地图</div>
|
||
<div id="voyageMap_rov" ref="voyageMap_rov" style="height: 100%;width:100%;" />
|
||
</div>
|
||
</div>
|
||
<!-- echarts板块-->
|
||
<div class="echarts-module">
|
||
<div class="bezel">
|
||
<BarChart :title="barData1.title" :chart-data="barData1.salesData" :categories="barData1.productCategories"
|
||
chart-type="single" />
|
||
</div>
|
||
<div class="bezel">
|
||
<BarChart :title="barData2.title" :chart-data="barData2.salesData" :categories="barData2.productCategories"
|
||
chart-type="stacked" stack-name="新增单位数" />
|
||
</div>
|
||
<div class="bezel">
|
||
<BarChart :title="barData3.title" :chart-data="barData3.salesData" :categories="barData3.productCategories" />
|
||
</div>
|
||
<div class="bezel">
|
||
<BarChart :title="barData4.title" :chart-data="barData4.salesData" :categories="barData4.productCategories" />
|
||
</div>
|
||
<div class="bezel">
|
||
<BarChart :title="barData5.title" :chart-data="barData5.salesData" :categories="barData5.productCategories" />
|
||
</div>
|
||
<div class="bezel">
|
||
<PieChart :chart-data="pieData" title="下潜单位类型" chart-type="ring" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import BarChart from './components/BarChart.vue'
|
||
import PieChart from './components/PieChart.vue'
|
||
import { setImageryViewModels } from '../../utils/common'
|
||
import { reportList, platformRov, rovUnit, rovUnitYear, rovDiving } from '../../api/statistics'
|
||
import { filterDictItems } from '../../utils/index'
|
||
import { initMapbox, handleWheel, initSprites, triggerLayerClick } from "@/utils/mapbox-utils";
|
||
import { loadVectorLayer, loadJsonLineFeature, loadJsonPointFeature, highlightFeaturesByProperty } from '@/utils/vector-layer-utils'
|
||
import { ColorGenerator } from '@/utils/color-generator';
|
||
const Cesium = window.Cesium
|
||
|
||
export default {
|
||
components: {
|
||
BarChart,
|
||
PieChart
|
||
},
|
||
data() {
|
||
return {
|
||
currentTitle: '全部遥控潜水器',
|
||
titles: [],
|
||
numbers: [
|
||
{
|
||
label: '潜次数',
|
||
value: '',
|
||
unit: '次'
|
||
},
|
||
{
|
||
label: '下潜人数',
|
||
value: '',
|
||
unit: '人'
|
||
},
|
||
{
|
||
label: '下潜单位',
|
||
value: '',
|
||
unit: '家'
|
||
},
|
||
{
|
||
label: '数据样品个数',
|
||
value: '',
|
||
unit: '个'
|
||
}
|
||
],
|
||
// Cesium相关 - 参航单位地图
|
||
baiduCesiumViewer: null,
|
||
baiduCesiumEntities: [], // 存储参航单位标记实体
|
||
viewer: null,
|
||
// 地图图层基础地址
|
||
CesiumHostAddr: `${window.location.protocol}//${window.location.hostname}:${window.location.port}/`,
|
||
trackLineLayers: [],
|
||
barData1: {},
|
||
barData2: {},
|
||
barData3: {},
|
||
barData4: {},
|
||
barData5: {},
|
||
pieData: []
|
||
}
|
||
},
|
||
created() {
|
||
this.getTypeList()
|
||
this.getRovList()
|
||
this.getRovUnit()
|
||
this.gitRovDiving()
|
||
this.gitRovUnitYear()
|
||
this.getChartBar({ year: '2025' })
|
||
},
|
||
mounted() {
|
||
initMapbox("workUnitMap_rov", {
|
||
tileKey: "gaode",
|
||
zoom: 3,
|
||
center: [110, 31],
|
||
minZoom: 2,
|
||
maxZoom: 29
|
||
});
|
||
initMapbox("voyageMap_rov", {
|
||
tileKey: "GEBCO_basemap_NCEI",
|
||
zoom: 4,
|
||
center: [113, 15],
|
||
minZoom: 2,
|
||
maxZoom: 29
|
||
});
|
||
|
||
// this.imageryViewModels = setImageryViewModels(this.CesiumHostAddr)
|
||
// this.initCesium() // 初始化航次地图
|
||
// this.initBaiduCesium() // 初始化参航单位地图
|
||
},
|
||
beforeDestroy() {
|
||
// 清理Cesium资源
|
||
if (this.baiduCesiumViewer) {
|
||
this.baiduCesiumViewer.destroy()
|
||
}
|
||
if (this.viewer) {
|
||
this.viewer.destroy()
|
||
}
|
||
},
|
||
methods: {
|
||
// 遥控潜水器数据
|
||
getTypeList() {
|
||
reportList().then(res => {
|
||
this.titles = filterDictItems(res.array, '遥控潜水器')
|
||
})
|
||
},
|
||
// 选择遥控潜水器
|
||
handleCommand(command) {
|
||
this.currentTitle = command
|
||
this.removeSingleLineImg()
|
||
if (command === '全部遥控潜水器') {
|
||
this.getRovList()
|
||
this.gitRovDiving()
|
||
this.gitRovUnitYear()
|
||
this.getChartBar({ year: '2025' })
|
||
} else {
|
||
this.getRovList({ platform_name: command })
|
||
this.gitRovDiving({ platform_name: command })
|
||
this.gitRovUnitYear({ platform_name: command })
|
||
this.getChartBar({ year: '2025', platform_name: command })
|
||
}
|
||
},
|
||
// 汇总统计数据
|
||
getRovList(params = {}) {
|
||
platformRov(params).then(res => {
|
||
const obj = res.array[0]
|
||
this.numbers[0].value = obj.diving_total
|
||
this.numbers[1].value = obj.driver_member_total
|
||
this.numbers[2].value = obj.unit_total
|
||
this.numbers[3].value = obj.dataset_total
|
||
})
|
||
},
|
||
// 下潜单位统计
|
||
getRovUnit() {
|
||
rovUnit().then(res => {
|
||
let geojson = {
|
||
type: "FeatureCollection",
|
||
features: []
|
||
};
|
||
res.array.forEach(element => {
|
||
geojson.features.push({
|
||
type: "Feature",
|
||
geometry: {
|
||
type: "Point",
|
||
coordinates: [element.unit_lon, element.unit_lat]
|
||
},
|
||
properties: {
|
||
unit_name: element.unit_name,
|
||
unit_type: element.unit_type,
|
||
create_time: element.create_time,
|
||
tsy_id: element.tsy_id
|
||
}
|
||
});
|
||
});
|
||
loadJsonPointFeature("workUnit", "blue", geojson, "unit_name", "workUnitMap_rov");
|
||
|
||
// // 清除之前的标记
|
||
// this.clearBaiduCesiumMarkers()
|
||
|
||
// // 创建参航单位标记
|
||
// this.createBaiduCesiumMarkers(res.array)
|
||
const typeCount = res.array.reduce((acc, unit) => {
|
||
const type = unit.unit_type
|
||
acc[type] = (acc[type] || 0) + 1 // 如果类型已存在则计数+1,否则初始化为1
|
||
return acc
|
||
}, {})
|
||
this.pieData = Object.entries(typeCount).map(([type, count]) => ({
|
||
name: type,
|
||
value: count
|
||
}))
|
||
})
|
||
},
|
||
// 创建参航单位Cesium标记点
|
||
createBaiduCesiumMarkers(units) {
|
||
if (!this.baiduCesiumViewer) return
|
||
|
||
const entities = []
|
||
|
||
units.forEach((item, index) => {
|
||
// 创建标记实体
|
||
const entity = this.baiduCesiumViewer.entities.add({
|
||
position: Cesium.Cartesian3.fromDegrees(item.unit_lon, item.unit_lat),
|
||
billboard: {
|
||
image: '../../../static/img/01.png', // 正常状态的图标
|
||
width: 32,
|
||
height: 32,
|
||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER
|
||
},
|
||
label: {
|
||
text: item.unit_name,
|
||
font: '14pt monospace',
|
||
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
||
outlineWidth: 2,
|
||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||
pixelOffset: new Cesium.Cartesian2(0, -40), // 标签在标记下方
|
||
fillColor: Cesium.Color.WHITE,
|
||
outlineColor: Cesium.Color.BLACK
|
||
},
|
||
unitData: item, // 存储原始数据
|
||
index: index // 存储索引
|
||
})
|
||
entities.push(entity)
|
||
})
|
||
|
||
this.baiduCesiumEntities = entities
|
||
|
||
// 调整视角以显示所有标记
|
||
if (entities.length > 0) {
|
||
this.baiduCesiumViewer.zoomTo(entities)
|
||
}
|
||
},
|
||
// 清除参航单位标记
|
||
clearBaiduCesiumMarkers() {
|
||
if (this.baiduCesiumViewer && this.baiduCesiumEntities.length > 0) {
|
||
this.baiduCesiumEntities.forEach(entity => {
|
||
this.baiduCesiumViewer.entities.remove(entity)
|
||
})
|
||
this.baiduCesiumEntities = []
|
||
}
|
||
},
|
||
// 潜次统计
|
||
gitRovDiving(params = {}) {
|
||
rovDiving(params).then(res => {
|
||
let i = 0;
|
||
const colors = ColorGenerator.generateDivergingColors(res.array.length);
|
||
// 添加轨迹图层
|
||
res.array.forEach(item => {
|
||
// 加载轨迹图层
|
||
loadVectorLayer(item.diving_sn, ["line", "symbol"], [colors[i], "#FFFFFF"], "visible", "voyageMap_rov", "dsds");
|
||
i++;
|
||
|
||
// this.addSingleLineImg(item)
|
||
})
|
||
})
|
||
},
|
||
// 初始化Cesium - 参航单位地图
|
||
initBaiduCesium() {
|
||
this.baiduCesiumViewer = new Cesium.Viewer(this.$refs.workUnitMap_rov, {
|
||
sceneMode: Cesium.SceneMode.SCENE2D,
|
||
shadows: false,
|
||
timeline: false,
|
||
baseLayerPicker: false,
|
||
imageryProviderViewModels: this.imageryViewModels,
|
||
terrainProviderViewModels: [],
|
||
fullscreenButton: false,
|
||
selectionIndicator: false,
|
||
homeButton: false,
|
||
sceneModePicker: false,
|
||
animation: false,
|
||
infoBox: false,
|
||
geocoder: false,
|
||
navigationHelpButton: false
|
||
})
|
||
this.baiduCesiumViewer._cesiumWidget._creditContainer.style.display = 'none'
|
||
this.baiduCesiumViewer.scene.sun.show = false
|
||
this.baiduCesiumViewer.scene.moon.show = false
|
||
this.baiduCesiumViewer.scene.fog.enabled = false
|
||
this.baiduCesiumViewer.scene.skyAtmosphere.show = false
|
||
this.baiduCesiumViewer.scene.sun.show = false
|
||
this.baiduCesiumViewer.scene.skyBox.show = false
|
||
this.baiduCesiumViewer.scene.globe.enableLighting = false
|
||
this.baiduCesiumViewer.shadowMap.darkness = 0.8
|
||
this.baiduCesiumViewer.scene._sunBloom = false
|
||
this.baiduCesiumViewer.scene.globe.showGroundAtmosphere = false
|
||
this.baiduCesiumViewer.scene.postProcessStages.fxaa.enabled = true
|
||
|
||
this.baiduCesiumViewer.camera.setView({
|
||
destination: Cesium.Cartesian3.fromDegrees(114.4040, 30.5196, 4000000)
|
||
})
|
||
},
|
||
// 初始化cesium
|
||
initCesium() {
|
||
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkY2Y5NWY2Ni1mODQ1LTQ3YTUtYjc4Zi1jYzhjMGI2YzcxMWYiLCJpZCI6MTI5ODMwLCJpYXQiOjE2Nzk0Njk5NTd9.DTH54ioOH-HLqeNIetBe9hFyrPOX2Vp1AQmZzw8TIZ4'
|
||
this.viewer = new Cesium.Viewer('cesiumContainer', {
|
||
sceneMode: Cesium.SceneMode.SCENE2D,
|
||
shadows: false,
|
||
timeline: false,
|
||
baseLayerPicker: false,
|
||
// 设置自定义底图
|
||
imageryProviderViewModels: this.imageryViewModels,
|
||
// 关闭默认的地形底图
|
||
terrainProviderViewModels: [],
|
||
fullscreenButton: false,
|
||
selectionIndicator: false,
|
||
homeButton: false,
|
||
sceneModePicker: false,
|
||
animation: false,
|
||
infoBox: false,
|
||
geocoder: false,
|
||
navigationHelpButton: false
|
||
})
|
||
this.viewer._cesiumWidget._creditContainer.style.display = 'none'
|
||
this.viewer.scene.sun.show = false
|
||
this.viewer.scene.moon.show = false
|
||
this.viewer.scene.fog.enabled = false
|
||
this.viewer.scene.skyAtmosphere.show = false
|
||
this.viewer.scene.sun.show = false
|
||
this.viewer.scene.skyBox.show = false
|
||
this.viewer.scene.globe.enableLighting = false
|
||
this.viewer.shadowMap.darkness = 0.8
|
||
this.viewer.scene._sunBloom = false
|
||
this.viewer.scene.globe.showGroundAtmosphere = false
|
||
this.viewer.scene.postProcessStages.fxaa.enabled = true
|
||
|
||
this.viewer.camera.setView({
|
||
// 指定相机初始位置
|
||
destination: Cesium.Cartesian3.fromDegrees(112, 18, 4000000)
|
||
})
|
||
},
|
||
// 添加轨迹图层
|
||
addSingleLineImg(item) {
|
||
const trackLine = new Cesium.WebMapTileServiceImageryProvider(
|
||
{
|
||
url: `${this.CesiumHostAddr}geoserver/gwc/service/wmts/rest/dsds:${item.diving_sn}/{TileMatrixSet}/{TileMatrixSet}:{TileMatrix}/{TileRow}/{TileCol}?format=image/png`,
|
||
layer: `dsds:${item.diving_sn}`,
|
||
style: 'default',
|
||
format: 'image/png',
|
||
tileMatrixSetID: 'EPSG:4326',
|
||
tilingScheme: new Cesium.GeographicTilingScheme()
|
||
}
|
||
)
|
||
const trackLineLayer = this.viewer.imageryLayers.addImageryProvider(trackLine)
|
||
this.trackLineLayers.push(trackLineLayer)
|
||
},
|
||
// 移除轨迹图层
|
||
removeSingleLineImg() {
|
||
if (this.trackLineLayers.length) {
|
||
this.trackLineLayers.forEach(line => {
|
||
this.viewer.imageryLayers.remove(line)
|
||
})
|
||
}
|
||
},
|
||
// 参潜单位年度
|
||
gitRovUnitYear(params = {}) {
|
||
rovUnitYear(params).then(res => {
|
||
const originalData = res.array
|
||
const sortedData = originalData.sort((a, b) => a.voyage_year - b.voyage_year)
|
||
this.barData2 = {
|
||
title: '年度参潜单位',
|
||
salesData: [
|
||
{
|
||
name: '参潜单位',
|
||
data: sortedData.map(item => item.unit_total),
|
||
stack: '新增单位数'
|
||
},
|
||
{
|
||
name: '新增单位',
|
||
data: sortedData.map(item => item.year_unit_total),
|
||
stack: '新增单位数'
|
||
}
|
||
],
|
||
productCategories: sortedData.map(item => item.voyage_year.toString())
|
||
}
|
||
})
|
||
},
|
||
// 柱状图数据
|
||
getChartBar(params) {
|
||
platformRov(params).then(res => {
|
||
const originalData = res.array
|
||
const sortedData = originalData.sort((a, b) => a.year - b.year)
|
||
this.barData1 = {
|
||
title: '年度潜次数',
|
||
salesData: sortedData.map(item => item.diving_total),
|
||
productCategories: sortedData.map(item => item.year.toString())
|
||
}
|
||
this.barData3 = {
|
||
title: '样品集个数',
|
||
salesData: sortedData.map(item => item.dataset_total),
|
||
productCategories: sortedData.map(item => item.year.toString())
|
||
}
|
||
this.barData4 = {
|
||
title: '水中时间',
|
||
salesData: sortedData.map(item => item.water_total),
|
||
productCategories: sortedData.map(item => item.year.toString())
|
||
}
|
||
this.barData5 = {
|
||
title: '水中作业时间',
|
||
salesData: sortedData.map(item => item.job_total),
|
||
productCategories: sortedData.map(item => item.year.toString())
|
||
}
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.statistics {
|
||
background-color: #ebf1f7;
|
||
|
||
.banner {
|
||
background-image: url(../../../static/images/bannerny1.jpg);
|
||
width: 100%;
|
||
height: 480px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
color: #fff;
|
||
|
||
.titles {
|
||
margin-bottom: 40px;
|
||
font-size: 56px;
|
||
color: #fff;
|
||
font-weight: bold;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.numbers {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 80px;
|
||
|
||
.item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
|
||
.value {
|
||
font-size: 56px;
|
||
font-weight: bold;
|
||
|
||
.unit {
|
||
font-size: 26px;
|
||
}
|
||
}
|
||
|
||
.label {
|
||
font-size: 18px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.map-module {
|
||
padding: 50px 50px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 50px;
|
||
|
||
.bezel {
|
||
flex: 1;
|
||
width: 100%;
|
||
height: 520px;
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
border: 1px solid #ccc;
|
||
position: relative;
|
||
|
||
.map-title {
|
||
position: absolute;
|
||
top: 20px;
|
||
left: 20px;
|
||
color: white;
|
||
z-index: 8888;
|
||
font-size: 22px;
|
||
}
|
||
|
||
.map-year {
|
||
position: absolute;
|
||
top: 20px;
|
||
right: 20px;
|
||
color: white;
|
||
z-index: 8888;
|
||
width: 100px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.echarts-module {
|
||
padding: 0 50px 50px;
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 50px;
|
||
grid-auto-rows: 300px;
|
||
|
||
.bezel {
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
border: 1px solid #ccc;
|
||
position: relative;
|
||
|
||
.map-title {
|
||
position: absolute;
|
||
top: 20px;
|
||
left: 20px;
|
||
color: white;
|
||
z-index: 8888;
|
||
font-size: 22px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.el-icon-arrow-down {
|
||
font-size: 12px
|
||
}
|
||
</style>
|