1238 lines
32 KiB
Vue
1238 lines
32 KiB
Vue
<template>
|
||
<div :class="'map-pane' + (active == 1 ? ' is-station' : '')">
|
||
<!-- 操作栏开始 -->
|
||
<div class="map-pane-operators">
|
||
<div>
|
||
<img
|
||
v-if="isFullScreen"
|
||
src="@/assets/images/station-operation/full-screen-active.png"
|
||
@click="handleExitFullScreen"
|
||
/>
|
||
<img v-else src="@/assets/images/station-operation/full-screen.png" @click="handleFullScreen" />
|
||
</div>
|
||
|
||
<div class="map-pane-operators-main-operator">
|
||
<div>
|
||
<img v-if="dataStatusModalVisible" src="@/assets/images/station-operation/analyze-active.png" />
|
||
<img v-else src="@/assets/images/station-operation/analyze.png" @click="handleOpenAnalyzeModal" />
|
||
</div>
|
||
<div>
|
||
<img v-if="active == 1" src="@/assets/images/station-operation/station-operate-active.png" />
|
||
<img v-else src="@/assets/images/station-operation/station-operate.png" @click="onPaneChange(1)" />
|
||
</div>
|
||
<div>
|
||
<img v-if="active == 2" src="@/assets/images/station-operation/filter-station-active.png" />
|
||
<img v-else src="@/assets/images/station-operation/filter-station.png" @click="onPaneChange(2)" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="map-pane-operators-zoom">
|
||
<div class="map-pane-operators-zoom-map-plus" @click="handlePlus"></div>
|
||
<div class="map-pane-operators-zoom-map-minus" @click="handleMinus"></div>
|
||
</div>
|
||
</div>
|
||
<!-- 操作栏结束 -->
|
||
|
||
<!-- 主体部分开始 -->
|
||
<div class="map-pane-content">
|
||
<!-- 站点操作 -->
|
||
<div class="station-operation" v-show="active == 1">
|
||
<div class="station-operation-stations">
|
||
<div class="map-pane-content-header">
|
||
Stations
|
||
</div>
|
||
<div class="map-pane-content-main">
|
||
<div class="station-operation-stations-selection">
|
||
<a-space>
|
||
<a-button class="select-all" type="primary" @click="handleSelectAll">Select All</a-button>
|
||
<a-button class="clear-selection" type="primary" @click="handleClearSelection"
|
||
>Clear Selection</a-button
|
||
>
|
||
</a-space>
|
||
</div>
|
||
<a-divider style="background-color: #0a544e; margin: 10px 0 0;"></a-divider>
|
||
|
||
<!-- 站点选择树 -->
|
||
<div class="station-list-tree">
|
||
<custom-tree
|
||
v-model="checkedKeys"
|
||
:tree-data="treeData"
|
||
:replaceFields="{ children: 'children', title: 'stationCode', key: 'stationId' }"
|
||
></custom-tree>
|
||
</div>
|
||
<!-- 站点选择树 结束 -->
|
||
</div>
|
||
</div>
|
||
<div class="station-operation-infomation">
|
||
<div class="map-pane-content-header">
|
||
Infomation
|
||
</div>
|
||
<div class="map-pane-content-main">
|
||
<div class="station-operation-infomation-content">
|
||
<p class="radius-title">Radius</p>
|
||
<div class="radius-search">
|
||
<a-input suffix="KM" v-model="radius" type="number"></a-input>
|
||
<a-button type="primary" @click="handleSearchByRadius">
|
||
Search
|
||
</a-button>
|
||
</div>
|
||
<div class="radius-table">
|
||
<a-table
|
||
:scroll="{ y: 298 }"
|
||
:columns="columns"
|
||
:data-source="dataSource"
|
||
rowKey="index"
|
||
:pagination="false"
|
||
:loading="isGettingInfomationList"
|
||
></a-table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- 站点操作结束 -->
|
||
|
||
<!-- 站点筛选 -->
|
||
<div class="station-filter" v-show="active == 2">
|
||
<div class="map-pane-content-header">
|
||
Filter
|
||
</div>
|
||
<div class="map-pane-content-main">
|
||
<div class="station-filter-list">
|
||
<div
|
||
class="station-filter-item"
|
||
v-for="filterItem in filterList"
|
||
:key="filterItem.title"
|
||
@click="onStationTypeFilterChange(filterItem)"
|
||
>
|
||
<div class="station-filter-item-main">
|
||
<div>
|
||
<img :src="filterItem.icon" />
|
||
</div>
|
||
<span>{{ filterItem.title }}</span>
|
||
</div>
|
||
<a-checkbox v-model="filterItem.checked"></a-checkbox>
|
||
</div>
|
||
</div>
|
||
<a-divider style="background-color: #0a544e; margin: 10px 0 0;"></a-divider>
|
||
<!-- 数据质量类型 -->
|
||
<div class="station-data-quality-list">
|
||
<div
|
||
class="station-data-quality-list-item"
|
||
v-for="(stateItem, index) in dataQualityList"
|
||
:key="index"
|
||
@click="onDataQualityFilterChange(stateItem)"
|
||
>
|
||
<div>
|
||
<img :src="stateItem.icon" alt="" />
|
||
<span>{{ stateItem.title }}</span>
|
||
</div>
|
||
<a-checkbox v-model="stateItem.checked"></a-checkbox>
|
||
</div>
|
||
</div>
|
||
<!-- 数据质量结束 -->
|
||
</div>
|
||
</div>
|
||
<!-- 站点筛选结束 -->
|
||
</div>
|
||
<!-- 主体部分结束 -->
|
||
|
||
<!-- 数据监控状态弹窗开始 -->
|
||
<custom-modal
|
||
v-model="dataStatusModalVisible"
|
||
enableFullScreen
|
||
:bodyStyle="{ padding: '15px 0 10px' }"
|
||
title="Data Recevice status Monitoring"
|
||
:width="1230"
|
||
:showFooter="false"
|
||
@fullscreen="onModalFullScreen"
|
||
>
|
||
<div class="data-receive-status">
|
||
<!-- 左侧配置栏 -->
|
||
<div class="data-receive-status-list" :class="{ open: leftPaneShow }">
|
||
<div class="data-receive-status-list-container">
|
||
<div class="data-receive-status-list-item">
|
||
<div class="title">
|
||
<span>
|
||
Particulate Station
|
||
</span>
|
||
<img src="@/assets/images/station-operation/toggle.png" @click="leftPaneShow = !leftPaneShow" />
|
||
</div>
|
||
<div class="content">
|
||
<custom-tree
|
||
v-model="dataStatusCheckedKeys"
|
||
:tree-data="treeData"
|
||
:replaceFields="{ children: 'children', title: 'stationCode', key: 'stationId' }"
|
||
></custom-tree>
|
||
</div>
|
||
</div>
|
||
<div class="data-receive-status-list-item">
|
||
<div class="title">
|
||
<span>
|
||
Attribute Configuration
|
||
</span>
|
||
<img src="@/assets/images/station-operation/toggle.png" @click="leftPaneShow = !leftPaneShow" />
|
||
</div>
|
||
<div class="content">
|
||
<a-form-model class="attribute-form" layout="vertical">
|
||
<a-form-model-item label="Cache time">
|
||
<a-input-number type="number" v-model="dataRecieveStatusModel.cacheTime" :min="0"></a-input-number>
|
||
<span>day</span>
|
||
</a-form-model-item>
|
||
<a-form-model-item label="Scale interval">
|
||
<a-input-number
|
||
type="number"
|
||
v-model="dataRecieveStatusModel.scaleInterval"
|
||
:min="0"
|
||
></a-input-number>
|
||
<span>min</span>
|
||
</a-form-model-item>
|
||
<a-form-model-item label="Timeline length">
|
||
<a-input-number
|
||
type="number"
|
||
v-model="dataRecieveStatusModel.timelineLength"
|
||
:min="0"
|
||
></a-input-number>
|
||
<span>min</span>
|
||
</a-form-model-item>
|
||
<a-form-model-item label="Update interval time">
|
||
<a-input-number
|
||
type="number"
|
||
v-model="dataRecieveStatusModel.updateIntervalTime"
|
||
:min="0"
|
||
></a-input-number>
|
||
<span>min</span>
|
||
</a-form-model-item>
|
||
<div class="attribute-form-footer">
|
||
<a-button type="primary" @click="onSaveDataRecieveSettings" :loading="isSavingDataRecieveSettings">
|
||
SAVE
|
||
</a-button>
|
||
</div>
|
||
</a-form-model>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 展开左侧配置栏按钮开始 -->
|
||
<div class="data-receive-status-list-toggle-show-btn" v-if="!leftPaneShow">
|
||
<img src="@/assets/images/station-operation/toggle-2.png" @click="leftPaneShow = true" />
|
||
</div>
|
||
<!-- 展开左侧配置栏按钮结束 -->
|
||
</div>
|
||
<!-- 左侧配置栏结束 -->
|
||
|
||
<!-- 右侧图表展示栏 -->
|
||
<div class="data-receive-status-chart" :class="{ 'on-screen': !leftPaneShow }">
|
||
<!-- 图例 -->
|
||
<div class="legend">
|
||
<div class="legend-item" v-for="(legend, index) in legendList" :key="index">
|
||
<span class="legend-item-color" :style="{ backgroundColor: legend.color }"></span>
|
||
<span>{{ legend.title }}</span>
|
||
</div>
|
||
</div>
|
||
<!-- 图例结束 -->
|
||
<template v-if="showChart">
|
||
<template v-for="(item, index) in statusList">
|
||
<RealTimeDataChart :legendList="legendList" :title="item.title" :key="index" />
|
||
<a-divider :key="index + '_divider'" v-if="index !== statusList.length - 1"></a-divider>
|
||
</template>
|
||
</template>
|
||
</div>
|
||
<!-- 右侧图表展示栏结束 -->
|
||
</div>
|
||
</custom-modal>
|
||
<!-- 数据监控状态弹窗结束 -->
|
||
</div>
|
||
</template>
|
||
<script>
|
||
import CustomModal from '@/components/CustomModal/index.vue'
|
||
import CustomTree from '@/components/CustomTree/index.vue'
|
||
import RealTimeDataChart from './RealTimeDataChart.vue'
|
||
import { getAction, postAction } from '../../../api/manage'
|
||
import { MarkerType, FilterIcon } from './markerEnum'
|
||
|
||
import { Vector as VectorLayer } from 'ol/layer'
|
||
import VectorSource from 'ol/source/Vector'
|
||
import { Circle } from 'ol/geom'
|
||
import { fromLonLat } from 'ol/proj'
|
||
import Feature from 'ol/Feature'
|
||
import { Fill, Stroke, Style } from 'ol/style'
|
||
|
||
// Filter中的筛选列表
|
||
const filterList = [
|
||
{
|
||
title: 'IMS RN Station(P)',
|
||
type: MarkerType.ImsRnStationP,
|
||
icon: FilterIcon[MarkerType.ImsRnStationP],
|
||
checked: true
|
||
},
|
||
{
|
||
title: 'IMS RN Station(G)',
|
||
type: MarkerType.ImsRnStationG,
|
||
icon: FilterIcon[MarkerType.ImsRnStationG],
|
||
checked: true
|
||
},
|
||
{
|
||
title: 'NRL',
|
||
type: MarkerType.NRL,
|
||
icon: FilterIcon[MarkerType.NRL],
|
||
checked: true
|
||
},
|
||
{
|
||
title: 'Nuclear Facilities',
|
||
type: MarkerType.NuclearFacility,
|
||
icon: FilterIcon[MarkerType.NuclearFacility],
|
||
checked: true
|
||
},
|
||
{
|
||
title: 'Groud monitoring station',
|
||
type: MarkerType.GroudMonitoringStation,
|
||
icon: FilterIcon[MarkerType.GroudMonitoringStation],
|
||
checked: true
|
||
},
|
||
{
|
||
title: 'car',
|
||
type: MarkerType.Car,
|
||
icon: FilterIcon[MarkerType.Car],
|
||
checked: true
|
||
},
|
||
{
|
||
title: 'ship',
|
||
type: MarkerType.Ship,
|
||
icon: FilterIcon[MarkerType.Ship],
|
||
checked: true
|
||
}
|
||
]
|
||
|
||
// Filter中的数据质量列表
|
||
const dataQualityList = [
|
||
{
|
||
title: 'Excellent data quality',
|
||
icon: FilterIcon.State1,
|
||
checked: true
|
||
},
|
||
{
|
||
title: 'Good data quality',
|
||
icon: FilterIcon.State2,
|
||
checked: true
|
||
},
|
||
{
|
||
title: 'Poor data quality',
|
||
icon: FilterIcon.State3,
|
||
checked: true
|
||
},
|
||
{
|
||
title: 'Signal interruption',
|
||
icon: FilterIcon.State4,
|
||
checked: true
|
||
}
|
||
]
|
||
|
||
// infomation-radius 表格列
|
||
const columns = [
|
||
{
|
||
title: 'nuclearfaclity',
|
||
dataIndex: 'nuclearFacilityName',
|
||
width: 100,
|
||
ellipsis: true
|
||
},
|
||
{
|
||
title: 'station',
|
||
dataIndex: 'stationName',
|
||
width: 70,
|
||
ellipsis: true
|
||
},
|
||
{
|
||
title: 'distance',
|
||
dataIndex: 'radius',
|
||
width: 80,
|
||
ellipsis: true
|
||
}
|
||
]
|
||
|
||
const legendList = [
|
||
{
|
||
title: 'SPHDPREL',
|
||
color: '#17a840'
|
||
},
|
||
{
|
||
title: 'SPHDF',
|
||
color: '#0cbfb0'
|
||
},
|
||
{
|
||
title: 'QC',
|
||
color: '#1c82eb'
|
||
},
|
||
{
|
||
title: 'GASBKPHDPREL',
|
||
color: '#d3ad16'
|
||
},
|
||
{
|
||
title: 'GASBKPHDF',
|
||
color: '#db6423'
|
||
},
|
||
{
|
||
title: 'SOH/MET',
|
||
color: '#8852da'
|
||
}
|
||
]
|
||
|
||
// Attribute Configuration 检验规则(自定义,非a-form校验)
|
||
const rules = {
|
||
cacheTime: {
|
||
required: true,
|
||
message: 'Please Input Cache Time'
|
||
},
|
||
scaleInterval: {
|
||
required: true,
|
||
message: 'Please Input Scale Interval'
|
||
},
|
||
timelineLength: {
|
||
required: true,
|
||
message: 'Please Input Timeline Length'
|
||
},
|
||
updateIntervalTime: {
|
||
required: true,
|
||
message: 'Please Input Update Interval'
|
||
}
|
||
}
|
||
|
||
export default {
|
||
props: {
|
||
panMovePix: {
|
||
type: Number,
|
||
default: 500
|
||
},
|
||
|
||
treeData: {
|
||
type: Array
|
||
}
|
||
},
|
||
components: {
|
||
CustomModal,
|
||
CustomTree,
|
||
RealTimeDataChart
|
||
},
|
||
data() {
|
||
this.columns = columns
|
||
return {
|
||
active: 2,
|
||
isFullScreen: false, // 是否处于全屏状态
|
||
|
||
checkedKeys: [], // 选中的树节点
|
||
|
||
filterList, // 筛选类型列表
|
||
dataQualityList, // 数据质量列表
|
||
|
||
radius: 5000, // 距离
|
||
dataSource: [], // Infomation Radius 表格数据源
|
||
isGettingInfomationList: false,
|
||
|
||
dataStatusModalVisible: false, // 分析弹窗是否可见
|
||
initialDataRecieveSettings: {}, // 初始未改变的数据接收状态设置
|
||
dataStatusCheckedKeys: [], // 分析弹窗-左侧树选中的keys
|
||
dataRecieveStatusModel: {
|
||
cacheTime: 15,
|
||
scaleInterval: 120,
|
||
timelineLength: 1440,
|
||
updateIntervalTime: 5
|
||
}, // 数据接收状态配置
|
||
isSavingDataRecieveSettings: false,
|
||
|
||
leftPaneShow: true, // 左侧抽屉
|
||
|
||
legendList, // 图例列表
|
||
statusList: [], // 数据接收状态列表
|
||
isGettingStatusList: false,
|
||
showChart: true,
|
||
|
||
markerList: [] // 要在地图上展示的marker列表
|
||
}
|
||
},
|
||
created() {
|
||
this.initParentMapProps()
|
||
document.addEventListener('fullscreenchange', this.onFullScreenChange)
|
||
this.stationList = []
|
||
|
||
this.getDataRecieveSettings()
|
||
},
|
||
destroyed() {
|
||
document.removeEventListener('fullscreenchange', this.onFullScreenChange)
|
||
},
|
||
methods: {
|
||
initParentMapProps() {
|
||
const { getZoom, setZoom, maxZoom, minZoom, map } = this.$parent
|
||
this.getZoom = getZoom
|
||
this.setZoom = setZoom
|
||
this.maxZoom = maxZoom
|
||
this.minZoom = minZoom
|
||
this.map = map
|
||
this.circleLayer = new VectorLayer({
|
||
source: new VectorSource({
|
||
features: []
|
||
}),
|
||
properties: { name: 'eventCircle' }
|
||
})
|
||
this.map.addLayer(this.circleLayer)
|
||
},
|
||
|
||
handleFullScreen() {
|
||
const ele = document.querySelector('.station-operation')
|
||
ele.requestFullscreen()
|
||
},
|
||
|
||
handleExitFullScreen() {
|
||
document.exitFullscreen()
|
||
},
|
||
|
||
onFullScreenChange() {
|
||
this.isFullScreen = !!document.fullscreenElement
|
||
},
|
||
|
||
// 面板改变
|
||
onPaneChange(active) {
|
||
this.active = active
|
||
const source = this.circleLayer.getSource()
|
||
source.clear() // 清理图层
|
||
switch (active) {
|
||
case 1: // 核设施查询面板
|
||
this.drawCircle()
|
||
this.emitStationChange()
|
||
break
|
||
case 2: // 筛选面板
|
||
this.emitFilter()
|
||
break
|
||
}
|
||
},
|
||
|
||
// 根据 Filter 筛选Marker
|
||
emitFilter() {
|
||
const filterType = this.filterList.filter(item => item.checked).map(item => item.type)
|
||
const filterDataQuality = this.dataQualityList.filter(item => item.checked).map(item => item.title)
|
||
|
||
this.$emit('filterMarker', {
|
||
filterType,
|
||
filterDataQuality
|
||
})
|
||
},
|
||
|
||
// 根据 Radius 筛选 Marker
|
||
emitStationChange() {
|
||
this.$emit('changeMarker', this.markerList)
|
||
},
|
||
|
||
// 选中全部
|
||
handleSelectAll() {
|
||
this.checkedKeys = this.treeData.reduce((prev, curr) => {
|
||
prev.push(curr.stationId)
|
||
prev.push(...curr.children.map(child => child.stationId))
|
||
return prev
|
||
}, [])
|
||
},
|
||
|
||
// 反选全部
|
||
handleClearSelection() {
|
||
this.checkedKeys = []
|
||
},
|
||
|
||
// Filter 过滤单个类型
|
||
onStationTypeFilterChange(filterItem) {
|
||
filterItem.checked = !filterItem.checked
|
||
this.emitFilter()
|
||
},
|
||
|
||
// 数据质量过滤
|
||
onDataQualityFilterChange(stateItem) {
|
||
stateItem.checked = !stateItem.checked
|
||
this.emitFilter()
|
||
},
|
||
|
||
// 根据半径查询台站列表
|
||
async handleSearchByRadius() {
|
||
if (!this.radius) {
|
||
this.$message.warn('Please Input Radius To Search')
|
||
return
|
||
}
|
||
if (!this.checkedKeys.length) {
|
||
this.$message.warn('Please Select Stations That Related To')
|
||
return
|
||
}
|
||
|
||
const stationIds = this.checkedKeys.filter(key => -1 == key.toString().indexOf('root_'))
|
||
try {
|
||
this.isGettingInfomationList = true
|
||
const {
|
||
success,
|
||
result: { GIS: markerList, table },
|
||
message
|
||
} = await postAction('/jeecg-station-operation/stationOperation/getHitEquList', {
|
||
radius: this.radius,
|
||
stationIds
|
||
})
|
||
if (success) {
|
||
const source = this.circleLayer.getSource()
|
||
source.clear() // 清理图层
|
||
|
||
if (table) {
|
||
const data = table.flat()
|
||
data.forEach((item, index) => {
|
||
item.radius = parseFloat(item.radius).toFixed(3)
|
||
item.index = index
|
||
})
|
||
this.dataSource = data // 设置Infomation表格内容
|
||
|
||
this.stationList = [] // 台站列表
|
||
markerList.forEach(markerItem => {
|
||
// 返回的数据类型不符合要求,根据stationId判断是否是台站,增加台站类型和转换字段,以便进行marker的绘制
|
||
if (markerItem.stationId) {
|
||
// 是台站
|
||
markerItem.stationType = MarkerType.ImsRnStationG
|
||
this.stationList.push(markerItem)
|
||
} else {
|
||
// 是核设施
|
||
markerItem.stationType = MarkerType.NuclearFacility
|
||
markerItem.lon = markerItem.longitude
|
||
markerItem.lat = markerItem.latitude
|
||
markerItem.stationId = markerItem.facilityId
|
||
}
|
||
})
|
||
|
||
if (markerList.length) {
|
||
// 自动移动到搜出来的第一个台站那
|
||
const firstMarker = markerList[0]
|
||
this.$parent.panTo([firstMarker.lon, firstMarker.lat])
|
||
}
|
||
|
||
this.markerList = markerList
|
||
this.emitStationChange()
|
||
|
||
this.drawCircle()
|
||
} else {
|
||
this.dataSource = []
|
||
this.markerList = []
|
||
this.emitStationChange()
|
||
}
|
||
} else {
|
||
this.$message.error(message)
|
||
}
|
||
} catch (error) {
|
||
console.error(error)
|
||
} finally {
|
||
this.isGettingInfomationList = false
|
||
}
|
||
},
|
||
|
||
// 绘制圆圈
|
||
drawCircle() {
|
||
const source = this.circleLayer.getSource()
|
||
const circleFeatures = []
|
||
this.stationList.forEach(stationItem => {
|
||
circleFeatures.push(this.getCircle(stationItem))
|
||
})
|
||
source.addFeatures(circleFeatures)
|
||
},
|
||
|
||
getCircle(stationInfo) {
|
||
const { lon, lat } = stationInfo
|
||
|
||
// 定义填充颜色
|
||
const fill = new Fill({
|
||
color: 'rgba(255, 0, 0, .4)' // 红色半透明填充
|
||
})
|
||
|
||
// 定义边框样式
|
||
const stroke = new Stroke({
|
||
color: 'rgba(255, 0, 0, .4)', // 红色半透明边框
|
||
width: 1 // 边框宽度
|
||
})
|
||
|
||
// 创建样式
|
||
const style = new Style({
|
||
fill: fill,
|
||
stroke: stroke
|
||
})
|
||
|
||
const circle = new Circle(fromLonLat([lon, lat]), this.getRadius())
|
||
const feature = new Feature({
|
||
geometry: circle,
|
||
style: style
|
||
})
|
||
feature.setStyle(style)
|
||
return feature
|
||
},
|
||
|
||
// 半径计算
|
||
getRadius() {
|
||
const metersPerUnit = this.map
|
||
.getView()
|
||
.getProjection()
|
||
.getMetersPerUnit()
|
||
const circleRadius = (this.radius * 1000) / metersPerUnit
|
||
return circleRadius
|
||
},
|
||
|
||
// 打开分析弹窗
|
||
handleOpenAnalyzeModal() {
|
||
this.dataStatusModalVisible = true
|
||
},
|
||
|
||
// 地图放大
|
||
handlePlus() {
|
||
const zoom = this.getZoom()
|
||
if (zoom < this.maxZoom) {
|
||
this.setZoom(zoom + 1)
|
||
}
|
||
},
|
||
|
||
// 地图缩小
|
||
handleMinus() {
|
||
const zoom = this.getZoom()
|
||
if (zoom > this.minZoom) {
|
||
this.setZoom(zoom - 1)
|
||
}
|
||
},
|
||
|
||
// 弹窗最大化
|
||
onModalFullScreen() {
|
||
this.showChart = false
|
||
this.$nextTick(() => {
|
||
this.showChart = true
|
||
})
|
||
},
|
||
|
||
// 保存数据接收状态的配置
|
||
async onSaveDataRecieveSettings() {
|
||
if (!this.dataStatusCheckedKeys.length) {
|
||
this.$message.warn('Please Select Particulate Station')
|
||
return
|
||
}
|
||
try {
|
||
await this.validateForm(this.dataRecieveStatusModel, rules)
|
||
try {
|
||
const stationIds = this.dataStatusCheckedKeys.filter(key => -1 == key.toString().indexOf('root_'))
|
||
this.isSavingDataRecieveSettings = true
|
||
const { success, message } = await postAction(
|
||
'/jeecg-station-operation/sysUserFocusStation/saveUserFocusByUserId',
|
||
{
|
||
stationIds,
|
||
...this.dataRecieveStatusModel
|
||
}
|
||
)
|
||
if (success) {
|
||
this.$message.success('Save Success')
|
||
await this.getDataRecieveSettings()
|
||
this.startGetDataReceiveStatusList()
|
||
} else {
|
||
this.$message.error(message)
|
||
}
|
||
} catch (error) {
|
||
console.error(error)
|
||
} finally {
|
||
this.isSavingDataRecieveSettings = false
|
||
}
|
||
} catch (error) {
|
||
this.$message.warn(error)
|
||
}
|
||
},
|
||
|
||
// 验证表单
|
||
validateForm(model, rules) {
|
||
return new Promise((resolve, reject) => {
|
||
const rulesKey = Object.keys(rules)
|
||
for (const key of rulesKey) {
|
||
const rule = rules[key],
|
||
value = model[key]
|
||
if (rule.required && !value) {
|
||
reject(rule.message)
|
||
return
|
||
}
|
||
}
|
||
resolve()
|
||
})
|
||
},
|
||
|
||
// 获取数据接收状态配置
|
||
async getDataRecieveSettings() {
|
||
try {
|
||
const { success, result, message } = await getAction(
|
||
'/jeecg-station-operation/sysUserFocusStation/findUserFocusByUserId',
|
||
{
|
||
userId: this.$store.getters.userInfo.id
|
||
}
|
||
)
|
||
if (success) {
|
||
this.initialDataRecieveSettings = result
|
||
} else {
|
||
this.$message.error(message)
|
||
}
|
||
} catch (error) {
|
||
console.error(error)
|
||
this.$message.error(error)
|
||
}
|
||
},
|
||
|
||
// 开始获取数据状态列表的定时器
|
||
startGetDataReceiveStatusList() {
|
||
if (this.timer) {
|
||
clearInterval(this.timer)
|
||
}
|
||
this.getDataRecieveStatusList()
|
||
this.timer = setInterval(() => {
|
||
this.getDataRecieveStatusList()
|
||
}, this.dataRecieveStatusModel.updateIntervalTime * 60 * 1000)
|
||
},
|
||
|
||
// 获取数据接收状态列表
|
||
async getDataRecieveStatusList() {
|
||
try {
|
||
console.log('%c [ ]-777', 'font-size:13px; background:pink; color:#bf2c9f;', this.initialDataRecieveSettings)
|
||
this.isGettingStatusList = true
|
||
const res = await getAction('/jeecg-station-operation/stationOperation/getDataReceivingStatus', {
|
||
userId: this.$store.getters.userInfo.id
|
||
})
|
||
console.log('%c [ res ]-640', 'font-size:13px; background:pink; color:#bf2c9f;', res)
|
||
} catch (error) {
|
||
console.error(error)
|
||
} finally {
|
||
this.isGettingStatusList = false
|
||
}
|
||
}
|
||
},
|
||
watch: {
|
||
dataStatusModalVisible(val) {
|
||
if (val) {
|
||
this.dataStatusCheckedKeys = this.initialDataRecieveSettings.sysUserFocusStations.map(item =>
|
||
parseInt(item.stationId)
|
||
)
|
||
this.dataRecieveStatusModel = {
|
||
cacheTime: this.initialDataRecieveSettings.cacheTime,
|
||
scaleInterval: this.initialDataRecieveSettings.scaleInterval,
|
||
timelineLength: this.initialDataRecieveSettings.timelineLength,
|
||
updateIntervalTime: this.initialDataRecieveSettings.updateIntervalTime
|
||
}
|
||
|
||
this.startGetDataReceiveStatusList()
|
||
} else {
|
||
clearInterval(this.timer)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
<style lang="less" scoped>
|
||
// 地图右侧操作栏
|
||
.map-pane {
|
||
position: absolute;
|
||
right: 10px;
|
||
top: 10px;
|
||
max-height: calc(100% - 20px);
|
||
z-index: 1;
|
||
display: flex;
|
||
gap: 15px;
|
||
|
||
&.is-station {
|
||
height: calc(100% - 20px);
|
||
}
|
||
|
||
// 操作栏
|
||
&-operators {
|
||
user-select: none;
|
||
img {
|
||
cursor: pointer;
|
||
}
|
||
&-main-operator {
|
||
margin-top: 5px;
|
||
div {
|
||
width: 30px;
|
||
height: 30px;
|
||
&:not(:first-child) {
|
||
margin-top: -1px;
|
||
}
|
||
}
|
||
}
|
||
|
||
&-zoom {
|
||
margin-top: 10px;
|
||
div {
|
||
width: 30px;
|
||
height: 30px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
&-map-plus {
|
||
background: url(~@/assets/images/station-operation/map-plus.png) center no-repeat;
|
||
background-size: 100% 100%;
|
||
|
||
&:active {
|
||
background-image: url(~@/assets/images/station-operation/map-plus-active.png);
|
||
}
|
||
}
|
||
|
||
&-map-minus {
|
||
margin-top: -1px;
|
||
background: url(~@/assets/images/station-operation/map-minus.png) center no-repeat;
|
||
background-size: 100% 100%;
|
||
|
||
&:active {
|
||
background-image: url(~@/assets/images/station-operation/map-minus-active.png);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 主体部分
|
||
&-content {
|
||
width: 285px;
|
||
overflow: auto;
|
||
border: 1px solid #0a544e;
|
||
|
||
.map-pane-content-header {
|
||
padding-left: 20px;
|
||
height: 40px;
|
||
line-height: 40px;
|
||
background-color: #03353f;
|
||
letter-spacing: 2px;
|
||
font-size: 16px;
|
||
color: #0cebc9;
|
||
font-family: Arial;
|
||
}
|
||
|
||
.map-pane-content-main {
|
||
background-color: rgba(2, 26, 29, 0.9);
|
||
padding: 10px;
|
||
height: calc(100% - 40px);
|
||
overflow: auto;
|
||
}
|
||
|
||
// 站点操作面板
|
||
.station-operation {
|
||
height: 100%;
|
||
&-stations {
|
||
height: calc(100% - 443px);
|
||
overflow: hidden;
|
||
|
||
&-selection {
|
||
height: 24px;
|
||
margin-bottom: 10px;
|
||
|
||
.ant-space {
|
||
height: 100%;
|
||
|
||
.select-all,
|
||
.clear-selection {
|
||
height: 100%;
|
||
padding: 0 6px;
|
||
::v-deep {
|
||
span {
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.station-list-tree {
|
||
height: calc(100% - 35px);
|
||
overflow: auto;
|
||
}
|
||
}
|
||
|
||
&-infomation {
|
||
&-content {
|
||
height: 383px;
|
||
|
||
.radius {
|
||
&-title {
|
||
margin-bottom: 9px;
|
||
font-size: 14px;
|
||
line-height: 11px;
|
||
color: #5b9cba;
|
||
}
|
||
|
||
&-search {
|
||
display: flex;
|
||
height: 24px;
|
||
|
||
::v-deep {
|
||
.ant-input {
|
||
width: 183px;
|
||
height: 100%;
|
||
padding-left: 5px;
|
||
padding-right: 36px;
|
||
}
|
||
.ant-input-suffix {
|
||
color: #5b9cba;
|
||
}
|
||
}
|
||
|
||
.ant-btn {
|
||
width: 70px;
|
||
height: 100%;
|
||
margin-left: 10px;
|
||
padding: 0;
|
||
flex-shrink: 0;
|
||
|
||
::v-deep {
|
||
span {
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
&-table {
|
||
margin-top: 10px;
|
||
width: 264px;
|
||
|
||
::v-deep {
|
||
.ant-table {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.ant-table-thead > tr th {
|
||
padding-top: 2px !important;
|
||
padding-bottom: 2px !important;
|
||
}
|
||
|
||
.ant-table-tbody .ant-table-row td {
|
||
padding: 6px !important;
|
||
}
|
||
|
||
.ant-table-placeholder {
|
||
background-color: transparent;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 站点筛选面板
|
||
.station-filter {
|
||
&-item {
|
||
width: 260px;
|
||
height: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
|
||
&:nth-child(4) {
|
||
img {
|
||
margin-left: -10px;
|
||
}
|
||
}
|
||
|
||
&:nth-child(5) {
|
||
img {
|
||
margin-left: -12px;
|
||
}
|
||
}
|
||
|
||
&-main {
|
||
display: flex;
|
||
align-items: center;
|
||
> div {
|
||
width: 39px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.station-data-quality-list {
|
||
&-item {
|
||
margin-left: 9px;
|
||
height: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
width: 251px;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
align-items: center;
|
||
|
||
> div {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
span {
|
||
margin-left: 12px;
|
||
font-size: 16px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// 地图右侧操作栏结束
|
||
|
||
// 弹窗
|
||
.data-receive-status {
|
||
height: 700px;
|
||
overflow: hidden;
|
||
position: relative;
|
||
|
||
@borderColor: rgba(65, 111, 127, 0.5);
|
||
&-list {
|
||
float: left;
|
||
width: 230px;
|
||
height: 100%;
|
||
margin-left: 15px;
|
||
transform: translateX(-245px);
|
||
transition: transform 0.3s cubic-bezier(0.075, 0.82, 0.165, 1);
|
||
|
||
&.open {
|
||
transform: translateX(0);
|
||
}
|
||
|
||
&-container {
|
||
height: 100%;
|
||
border: 1px solid @borderColor;
|
||
border-top: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
&-item {
|
||
&:first-child {
|
||
height: calc(100% - 305px);
|
||
.content {
|
||
height: calc(100% - 50px);
|
||
overflow: auto;
|
||
margin: 7px;
|
||
margin-right: 0;
|
||
}
|
||
}
|
||
|
||
&:nth-child(2) {
|
||
.content {
|
||
padding-left: 16px;
|
||
}
|
||
}
|
||
|
||
.title {
|
||
height: 37px;
|
||
line-height: 37px;
|
||
padding-left: 18px;
|
||
background-color: #08363c;
|
||
border-top: 1px solid @borderColor;
|
||
border-bottom: 1px solid @borderColor;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding-right: 10px;
|
||
user-select: none;
|
||
img {
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
}
|
||
|
||
&-toggle-show-btn {
|
||
position: absolute;
|
||
right: -13px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.attribute-form {
|
||
.ant-input-number {
|
||
width: 173px;
|
||
height: 24px;
|
||
::v-deep {
|
||
.ant-input-number-input {
|
||
height: 24px;
|
||
line-height: 24px;
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
}
|
||
|
||
::v-deep {
|
||
.ant-form-item {
|
||
margin-bottom: 0;
|
||
padding-bottom: 0;
|
||
|
||
&-label {
|
||
padding-top: 7px;
|
||
padding-bottom: 2px;
|
||
}
|
||
|
||
&-children {
|
||
display: flex;
|
||
align-items: center;
|
||
> span {
|
||
margin-left: 7px;
|
||
color: #5b9cba;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
&-footer {
|
||
margin-top: 9px;
|
||
text-align: center;
|
||
.ant-btn {
|
||
width: 120px;
|
||
background-color: #00bded;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
&-chart {
|
||
position: absolute;
|
||
right: 15px;
|
||
width: calc(100% - 270px);
|
||
height: 100%;
|
||
overflow: auto;
|
||
padding: 0 15px 10px;
|
||
border: 1px solid @borderColor;
|
||
transition: width 0.3s cubic-bezier(0.075, 0.82, 0.165, 1);
|
||
|
||
&.on-screen {
|
||
width: calc(100% - 30px);
|
||
}
|
||
|
||
.ant-divider {
|
||
margin: 34px 0 40px;
|
||
background-color: rgba(65, 111, 127, 0.5);
|
||
}
|
||
}
|
||
|
||
.legend {
|
||
margin: 32px 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
|
||
&-item {
|
||
color: #ade6ee;
|
||
line-height: 12px;
|
||
|
||
&:not(:last-child) {
|
||
margin-right: 30px;
|
||
}
|
||
|
||
&-color {
|
||
display: inline-block;
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 4px;
|
||
margin-right: 6px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.fullscreen {
|
||
.data-receive-status {
|
||
height: calc(100vh - 70px);
|
||
}
|
||
}
|
||
// 弹窗结束
|
||
</style>
|