DSDSWeb/src/views/statistics/RovStatistics.vue

554 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>