Browse Source

Merge branch 'lixin' of gitadmin/tuoheng_lc_web into develop

tags/v1.2.0
lixin 1 year ago
parent
commit
025f7c59ed
10 changed files with 433 additions and 174 deletions
  1. +9
    -0
      src/api/dashboard/index.js
  2. +27
    -0
      src/utils/style.js
  3. +1
    -0
      src/views/dashboard/components/ControlPanel.vue
  4. +0
    -124
      src/views/dashboard/components/Echarts.vue
  5. +33
    -2
      src/views/dashboard/components/Extend.vue
  6. +59
    -23
      src/views/dashboard/components/FireAlarm.vue
  7. +10
    -6
      src/views/dashboard/components/OneMap.vue
  8. +145
    -0
      src/views/dashboard/components/SpeedChart.vue
  9. +108
    -9
      src/views/dashboard/components/Underlay.vue
  10. +41
    -10
      src/views/dashboard/components/WarningDrawer.vue

+ 9
- 0
src/api/dashboard/index.js View File

@@ -145,6 +145,15 @@ export function confirmWarning(params) {
})
}

// 定点飞行
export function pointflight(params) {
return request({
url: `/airport/pointflight`,
method: 'POST',
params
})
}

// 预警已确认
export function emergencyList(params = { airportFlyType: 2, statusList: 2 }) {
return request({

+ 27
- 0
src/utils/style.js View File

@@ -0,0 +1,27 @@
import { Style, Icon, Stroke } from 'ol/style'
import imgGeo from '@/assets/point/geo.png'
export const styleList = {
route: new Style({
stroke: new Stroke({
width: 2,
color: 'red'
})
}),
geoMarker: new Style({
image: new Icon({
anchor: [0.5, 0.5],
src: imgGeo,
crossOrigin: '',
scale: [1, 1],
rotateWithView: true
})
}),
lineRoute: new Style({
stroke: new Stroke({
width: 2,
color: 'yellow',
lineDash: [5]
})
})
}


+ 1
- 0
src/views/dashboard/components/ControlPanel.vue View File

@@ -217,6 +217,7 @@ export default defineComponent({
align-items: center;
justify-content: space-around;
overflow: hidden;
margin: 0 5px 0 0;
.crcle__panel{
width: 180px;
height: 180px;

+ 0
- 124
src/views/dashboard/components/Echarts.vue View File

@@ -1,124 +0,0 @@
<template>
<div class="content" id="myChart">

</div>
</template>
<script>
import * as echarts from 'echarts'
import { ref, reactive, toRefs, watch, onMounted } from 'vue'
export default {
name: 'Echarts',
setup(props) {

const initMyChart = () => {
const chartDom = document.getElementById('myChart');
const myChart = echarts.init(chartDom);
var option;
option = {
legend: {
top: '12',
data: ['速度', '高度'],
icon: 'roundRect',
itemHeight: 1,
itemWidth: 31,
textStyle: {
color: '#ffffff'
}

},
grid: {
top: '60',
bottom: '23',
left: '50',
right: '60'
},
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
show: false
},
yAxis: [
{
type: 'value',
name: '速度(m/s)',
nameTextStyle: {
color: "rgba(255,255,255,1)"
},
axisLabel: {
show: true,
textStyle: {
color: 'rgba(255,255,255,1)'
}
}
},
{
type: 'value',
name: '高度(s)',
position: "right",
nameTextStyle: {
color: "rgba(255,255,255,1)"
},
axisLabel: {
textStyle: {
color: "rgba(255,255,255,1)",
},
formatter: "{value}",
},

}
],
series: [
{
name: '速度',
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line',
symbol: 'none',
smooth: true,
itemStyle: {
normal: {
color: 'rgba(255,141,26,1)',
width: 2
}
},
yAxisIndex: 0,
},
{
name: '高度',
data: [500, 2000, 3000, 1000, 1200, 1300, 2310],
type: 'line',
smooth: true,
symbol: 'none',
yAxisIndex: 1,
itemStyle: {
normal: {
color: 'rgba(165, 214, 63, 1)',
width: 2
}
}
}
]
};

option && myChart.setOption(option);
}
onMounted(
() => {
initMyChart()
})
}
}
</script>
<style>
.content {
position: absolute;
bottom: 16px;
left: 24px;
background-color: rgba(0, 0, 0, 1);
width: 734px;
height: 216px;
font-size: 16px;
font-weight: 400;
color: rgba(255, 255, 255, 1)
}
</style>

+ 33
- 2
src/views/dashboard/components/Extend.vue View File

@@ -39,13 +39,19 @@
<span>{{ statusList[item.status] }}</span>
<n-popconfirm
v-if="item.status == 1"
@positive-click="handlePositiveClick(item)"
@negative-click="handleNegativeClick"
>
<template #trigger>
<span class="table__operate">执行</span>
</template>
是否立即开始执行任务?
</n-popconfirm>
<span v-else class="table__operate live">直播</span>
<span
v-else
class="table__operate live"
@click="liveShow(item)"
>直播</span>
</li>
</ul>
</div>
@@ -90,6 +96,7 @@

<script>
import { onMounted, reactive, toRefs } from 'vue'
import { useRouter } from 'vue-router'
import { startOfDay } from 'date-fns/esm'
import { getMissionList, getQuestionList } from '@/api/dashboard/index.js'
import { cameraList } from '@/api/basic/monitor.js'
@@ -103,6 +110,7 @@ import fireHazard_icon from '@/assets/images/fireHazard.png'
import camera from '@/assets/icon/camera.png'
import materials from '@/assets/icon/materials.png'
import personnel from '@/assets/icon/personnel.png'
import { implement } from '@/api/task/index.js'
const ICON_LIST = {
'002000': problemSpot_icon,
'002001': deadTree_icon,
@@ -113,6 +121,7 @@ export default {
name: 'MapExtend',
emits: ['send'],
setup(props, { emit }) {
const router = useRouter()
const data = reactive({
selectedTab: 0,
extendList: [
@@ -266,6 +275,18 @@ export default {
emit('send', { tabs: data.selectedTab, data: ques.message, type: value, ops: 'select' })
}

/**
* 展示直播视频
*/
const liveShow = (rowInfo) => {
rowInfo = JSON.stringify(rowInfo)

router.push({
path: '/taskManage/all',
query: { rowInfo: rowInfo }
})
}

return {
...toRefs(data),
...toRefs(warn),
@@ -278,7 +299,17 @@ export default {
handlePageChange,
handleDateChange,
handleWarnChange,
handleQuesChange
handleQuesChange,
handlePositiveClick(row) {
$message.info('机场设备开始自检,请稍等')
implement(row.id).then((res) => {
if (res.code === 0) {
$message.info('操作成功')
}
})
},
handleNegativeClick() {},
liveShow
}
}
}

+ 59
- 23
src/views/dashboard/components/FireAlarm.vue View File

@@ -25,7 +25,7 @@
<p class="alarm-title">机场调度</p>
<p class="dispatch-detail">
<span>选择机场:</span>
<n-select v-model:value="airValue" placeholder="请选择机场" :options="airpotOptions" />
<n-select v-model:value="airportId" placeholder="请选择机场" :options="airpotOptions" />
<a @click="checkAirport">可用机场列表</a>
</p>
<p class="dispatch-detail">
@@ -39,7 +39,7 @@
<li v-for="(item, index) in recoedList" :key="index">
<span class="task-time">{{ item.time }}</span>
<span class="task-name">{{ item.name }}</span>
<span v-if="item.statusNum === 1" class="task-status on-fly">{{ item.status }}</span>
<span v-if="item.statusNum === 2" class="task-status on-fly" @click="handleExecute(item.emergencyMissionId)">{{ item.status }}</span>
<span v-else class="task-status">{{ item.status }}</span>
</li>
</ul>
@@ -93,7 +93,7 @@

import { reactive, toRefs, watch } from 'vue'
import { EARLY_SOURCE, TASK_STATUS } from '@/utils/dictionary.js'
import { getWarningRecord, getWarningInfo, ignoreWarning, confirmWarning } from '@/api/dashboard/index.js'
import { getWarningRecord, getWarningInfo, ignoreWarning, confirmWarning, pointflight } from '@/api/dashboard/index.js'
// turf 用于简单的空间计算
import * as turf from '@turf/turf'
export default {
@@ -121,7 +121,7 @@ export default {
airportShow: false,
warningInfo: {},
airportSelect: '',
airValue: 0,
airportId: null,
warningPic: null,
recoedList: [],
warningShow: false,
@@ -148,22 +148,33 @@ export default {
})
data.fireDetail.time = value?.createTime

Promise.all([await getWarningInfo(value.id), await getWarningRecord({ warningId: value.id })])
.then(([info, record]) => {
// 分析后的图片
data.warningPic = info?.data?.fileMarkerUrl || null
// 任务id
data.missionId = info?.data?.missionId || null
showUsableAirport(info)
showWarningRecord(record)
})
.catch(err => {
console.log(err)
})
getRecord(value.id)
getAirport(value.id)
}

// 获取记录
const getAirport = async(id) => {
const info = await getWarningInfo(id)
if (info.code === 0) {
// 分析后的图片
data.warningPic = info?.data?.fileMarkerUrl || null
// 任务id
data.missionId = info?.data?.missionId
showUsableAirport(info)
}
}

// 获取记录
const getRecord = async(id) => {
const record = await getWarningRecord({ warningId: id })
if (record.code === 0) {
showWarningRecord(record)
}
}

// 预警记录列表
const showWarningRecord = (record) => {
// 清空原来的应急任务列表
data.recoedList.length = 0
var status = ''
var statusNum = 0
@@ -175,10 +186,16 @@ export default {
}
})
data.recoedList.push({
// 应急任务创建时间
time: item.createTime,
// 应急任务名称
name: item.name,
// 状态
status: status,
statusNum: statusNum
// 状态编号
statusNum: statusNum,
// 应急任务id
emergencyMissionId: item.emergencyMissionId
})
})
}
@@ -205,7 +222,7 @@ export default {
label: item.name
})
})
data.airValue = data.airpotOptions[0]?.value || null
data.airportId = data.airpotOptions[0]?.value || null
}

const checkAirport = () => {
@@ -221,9 +238,27 @@ export default {
data.warningShow = false
}

const test = () => {
handleExecute()
console.log(data.warningInfo)
const test = async() => {
var airportName = ''
data.airpotOptions?.map((item) => {
if (item.value === data.airportId) {
airportName = item.label
}
})
const res = await pointflight({
airportId: parseInt(data.airportId),
airportName: airportName,
warningId: parseInt(data.warningInfo?.id),
missionId: parseInt(data.missionId),
alt: String(data.flyHeight),
lon: String(data.warningInfo.lng),
lat: String(data.warningInfo.lat)
})

if (res.code === 0) {
getRecord(parseInt(data.warningInfo?.id))
handleExecute(parseInt(data.missionId))
}
}

// 忽略预警
@@ -249,8 +284,9 @@ export default {
return value + 'm'
}

const handleExecute = () => {
emit('start')
const handleExecute = (id) => {
// console.log(id)
emit('start', id)
}

return {

+ 10
- 6
src/views/dashboard/components/OneMap.vue View File

@@ -32,7 +32,7 @@
<fire-alarm ref="Warning" :data="warningDetail" :airport="airportsAll" @start="handleExecute" />

<WarningDrawer v-model:visible="drawerShow" />
</template>

<script>
@@ -49,7 +49,7 @@ import { Style, Icon, Text, Fill } from 'ol/style'
import * as control from 'ol/control'
import uav_icon from '@/assets/images/airport.png'
import warningIcon from '@/assets/gis/images/fire.png'
import { reactive, toRefs, onMounted, computed, ref, watch, onBeforeUnmount } from 'vue'
import { reactive, toRefs, onMounted, computed, ref, watch, onBeforeUnmount, provide } from 'vue'
import { Point } from 'ol/geom'
import {
airportList, getWarning
@@ -110,8 +110,8 @@ export default {
warningList: [],
warningLayers: [],
warningDetail: {},
drawerShow: false
drawerShow: false,
missionId: 0
})

const getMapOptions = computed(() => {
@@ -679,8 +679,11 @@ export default {
monitorVideo.value?.disposeVideo()
}

const handleExecute = () => {
let abc = ref()
const handleExecute = (id) => {
data.drawerShow = true
abc = id
provide('test', abc)
}

onMounted(() => {
@@ -711,7 +714,8 @@ export default {
hideProblemInfo,
getMaxZOverlay,
Warning,
handleExecute
handleExecute,
abc
}
}
}

+ 145
- 0
src/views/dashboard/components/SpeedChart.vue View File

@@ -0,0 +1,145 @@
<template>
<div id="myChart" class="my-chart" />
</template>
<script>
import * as echarts from 'echarts'
import { onMounted, reactive, toRefs, watch } from 'vue'
export default {
name: 'SpeedChart',
props: {
data: {
type: Object,
default: () => {}
}
},
setup(props) {
const data = reactive({
myChart: null,
chartOption: {},
chartDom: null,
chartData: {}
})

watch(() => props.data, (value) => {
if (JSON.stringify(value) !== '{}') {
data.chartData = value
data.myChart.dispose()
initChart()
}
})

const initChart = () => {
data.chartDom = document.getElementById('myChart')
data.myChart = echarts.init(data.chartDom)
data.chartOption = {
legend: {
top: '12',
data: ['速度', '高度'],
icon: 'roundRect',
itemHeight: 1,
itemWidth: 31,
textStyle: {
color: '#ffffff'
}

},
grid: {
top: '60',
bottom: '23',
left: '50',
right: '60'
},
xAxis: {
type: 'category',
data: [0, 1],
show: false
},
yAxis: [
{
type: 'value',
name: '速度(m/s)',
nameTextStyle: {
color: 'rgba(255,255,255,1)'
},
axisLabel: {
show: true,
textStyle: {
color: 'rgba(255,255,255,1)'
}
}
},
{
type: 'value',
name: '高度(s)',
position: 'right',
nameTextStyle: {
color: 'rgba(255,255,255,1)'
},
axisLabel: {
textStyle: {
color: 'rgba(255,255,255,1)'
},
formatter: '{value}'
}

}
],
series: [
{
name: '速度',
data: data.chartData?.speed,
type: 'line',
symbol: 'none',
smooth: true,
itemStyle: {
normal: {
color: 'rgba(255,141,26,1)',
width: 2
}
},
yAxisIndex: 0
},
{
name: '高度',
data: data.chartData?.alt,
type: 'line',
smooth: true,
symbol: 'none',
yAxisIndex: 1,
itemStyle: {
normal: {
color: 'rgba(165, 214, 63, 1)',
width: 2
}
}
}
]
}

data.myChart.setOption(data.chartOption)
}

onMounted(
() => {
initChart()
})

return {
...toRefs(data)
}
}
}
</script>
<style>
.my-chart {
position: relative;
z-index: 99;
background-color: rgba(0, 0, 0, 1);
width: 734px;
height: 220px;
font-size: 16px;
font-weight: 400;
color: rgba(255, 255, 255, 1);
margin: 0 5px 0 0;
}
</style>

+ 108
- 9
src/views/dashboard/components/Underlay.vue View File

@@ -3,27 +3,42 @@
</template>

<script>
import { Map, View } from 'ol'
import { XYZ } from 'ol/source'

import { reactive, toRefs, onMounted, computed, watch, onBeforeUnmount, inject, ref } from 'vue'
import { Map, View, Feature } from 'ol'
import 'ol/ol.css'
import { Tile, Vector as VectorLayer } from 'ol/layer'
import TileWMS from 'ol/source/TileWMS.js'
import { Tile } from 'ol/layer'
import { transform } from 'ol/proj'
import LineString from 'ol/geom/LineString'
import Point from 'ol/geom/Point'
import { XYZ, Vector as VectorSource } from 'ol/source'
import { transform, fromLonLat } from 'ol/proj'
import { getVectorContext } from 'ol/render'
import * as control from 'ol/control'
import { reactive, toRefs, onMounted, computed, ref, onBeforeUnmount } from 'vue'
import { styleList } from '@/utils/style.js'
import { getTrackList } from '@/api/task/index.js'

export default {
name: 'OneMap',
name: 'UnderLay',
props: {
id: {
type: String,
default: 'underlay'
},
data: {
type: Number,
default: 0
}
},
setup(props) {
const monitorVideo = ref()
const data = reactive({
map: null,
drawerShow: false
drawerShow: false,
trackLayer: null,
trackInfo: null,
// 轨迹数据
trackList: [],
id: 0
})

const getMapOptions = computed(() => {
@@ -32,6 +47,22 @@ export default {
}
})

let abc = ref()
abc = inject('test')

watch(() => abc, (value) => {
if (value) {
console.log('hhh', value)
} else {
console.log('hhh', value)
}
// getTrackData(id).then(res => {
// if (res.trackList.length > 0) {
// initTrack(formatTradeList(res.trackList), 'route')
// }
// })
})

/**
* 初始化地图
*/
@@ -68,12 +99,80 @@ export default {
wmsSource.setOpacity(0.3)
}

/* 获取轨迹数据 */
const getTrackData = async function(id) {
const res = await getTrackList(id)
const trackList = res.data
data.trackList = trackList
// const trackList = data.trackList
return Promise.resolve({
trackList
})
}

/* 处理轨迹列表 */
const formatTradeList = function(trackList) {
return trackList.map((item) =>
fromLonLat([parseFloat(item.lng), parseFloat(item.lat)])
)
}

/* 初始化轨迹 */
const initTrack = function(coordinate, routeType) {
let vectorLayer = null
const route = new LineString(coordinate)
const routeFeature = new Feature({
type: routeType,
geometry: route
})
const startMarker = new Feature({
type: 'icon',
geometry: new Point(route.getFirstCoordinate())
})
const position = startMarker.getGeometry().clone()
const geoMarker = new Feature({
type: 'geoMarker',
geometry: position
})
geoMarker.setProperties({ type: 'geoMarker' }, false)
if (data.trackLayer) {
data.trackLayer.setSource(
new VectorSource({
features: [geoMarker, routeFeature]
})
)
vectorLayer = data.trackLayer
} else {
vectorLayer = new VectorLayer({
source: new VectorSource({
features: [geoMarker, routeFeature]
}),
style: function(feature) {
return styleList[feature.get('type')]
}
})
}
data.mapData.addLayer(vectorLayer)
data.mapView.fit(route, { padding: [50, 50, 50, 50] })
vectorLayer.on('postrender', moveFeature.bind())
function moveFeature(event) {
/* 计算飞行的百分比 */
const percent = data.videoInfo.currentTime / data.videoInfo.duration
const currentCoordinate = route.getCoordinateAt(percent)
position.setCoordinates(currentCoordinate)
geoMarker.setGeometry(null)
const vectorContext = getVectorContext(event)
vectorContext.setStyle(styleList['geoMarker'])
vectorContext.drawGeometry(position)
data.mapData?.render()
}
}

onMounted(() => {
initMap()
})

onBeforeUnmount(() => {
monitorVideo.value?.disposeVideo()
})

return {

+ 41
- 10
src/views/dashboard/components/WarningDrawer.vue View File

@@ -9,7 +9,7 @@
<p class="side__title">操作</p>
<div class="side__control">
<n-button>抛投</n-button>
<n-button>喊话</n-button>
<n-button @click="fanhang">喊话</n-button>
<n-button @click="handleOperate">{{ operate }}</n-button>
<n-button @click="handleControl">{{ control }}</n-button>
<n-button class="control__special" round @click="handleBack">返航</n-button>
@@ -48,9 +48,11 @@
</div>

<div class="control__panel">
<ControlPanel v-if="showControl" mode="camera" />
<ControlPanel v-if="showControl" mode="locus" />
<SpeedChart :data="chartData" />
<ControlPanel v-if="showControl" mode="camera" @start="startOrder" @reset="endOrder" />
<ControlPanel v-if="showControl" mode="locus" @start="startOrder" @reset="endOrder" />
</div>

</div>
<div ref="mapRef" class="warn__back">
<Underlay />
@@ -58,7 +60,6 @@
<div ref="videoRef" class="inner">
111111111111
</div>
<Echarts/>
</n-drawer-content>
</n-drawer>
</template>
@@ -67,10 +68,10 @@
import { defineComponent, ref, reactive, toRefs, computed, watch, nextTick } from 'vue'
import Underlay from './Underlay.vue'
import ControlPanel from './ControlPanel.vue'
import Echarts from './Echarts.vue'
import SpeedChart from './SpeedChart.vue'
export default defineComponent({
name: 'WarningDrawer',
components: { Underlay, ControlPanel,Echarts },
components: { Underlay, ControlPanel, SpeedChart },
props: {
/* 可见 */
visible: {
@@ -81,6 +82,10 @@ export default defineComponent({
data: {
type: Object,
default: () => {}
},
id: {
type: Number,
default: 0
}
},
emits: {
@@ -91,12 +96,13 @@ export default defineComponent({
const sideRef = ref()
const mapRef = ref()
const videoRef = ref()

const data = reactive({
hasChanged: false,
showControl: false,
operate: '悬停',
control: '手动控制'
control: '手动控制',
chartData: {},
missionId: 0
})

/* 获取抽屉的信息 */
@@ -128,6 +134,21 @@ export default defineComponent({
window.dispatchEvent(new Event('resize'))
}

const fanhang = () => {
data.chartData = {
speed: [300, 200],
alt: [500, 510]
}
}

const startOrder = (params) => {
console.log(params)
}

const endOrder = (params) => {
console.log(params)
}

watch(() => props.visible, (value) => {
if (value) {
nextTick(() => {
@@ -141,6 +162,13 @@ export default defineComponent({
}
})

watch(() => props.id, (id) => {
if (id) {
data.missionId = id
console.log(data.missionId)
}
})

const handleOperate = () => {
data.operate = data.operate === '悬停' ? '继续飞行' : '悬停'
}
@@ -175,7 +203,10 @@ export default defineComponent({
handleChange,
handleOperate,
handleControl,
handleBack
handleBack,
fanhang,
startOrder,
endOrder
}
}
})
@@ -242,7 +273,7 @@ export default defineComponent({
}
}

.control__panel{
.control__panel {
position: absolute;
bottom: 0;
display: flex;

Loading…
Cancel
Save