多目标轨迹回放
This commit is contained in:
parent
e6446622c2
commit
d20d91b0fc
BIN
public/images/icons/text/文字报.png
Normal file
BIN
public/images/icons/text/文字报.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
src/assets/image/multiTraj/开.png
Normal file
BIN
src/assets/image/multiTraj/开.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 740 B |
BIN
src/assets/image/multiTraj/编组.png
Normal file
BIN
src/assets/image/multiTraj/编组.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
@ -11,7 +11,10 @@ import HisImages from '../BaseMB/components/HisImages/index.vue'
|
||||
import Hangjing from '../Hangjing/index.vue'
|
||||
import Mubiao from '../Mubiao/index.vue'
|
||||
import MubiaoHisTrajectory from '../Mubiao/components/HisTrajectory/index.vue'
|
||||
import MultiHisTrajectory from '../Mubiao/components/MultiHisTrajectory/index.vue'
|
||||
// import MultiHisTrajectory from '../Mubiao/components/MultiHisTrajectory/index.vue'
|
||||
|
||||
import MultiHisTrajectory from '../MultiTrajPlayback/components/MultiHisTrajectory.vue'
|
||||
import MultiTrajPlayback from '../MultiTrajPlayback'
|
||||
// import YsHangjing from '../YsHangjing/index.vue'
|
||||
|
||||
import Daodan from '../Daodan'
|
||||
@ -25,7 +28,9 @@ import DaodanTestConfig from '../Daodan/components/ConfigContainer'
|
||||
import { useTextReport } from '../TextReport/hooks/text'
|
||||
import { useHisImage } from '../BaseMB/components/HisImages/hooks/hisImage'
|
||||
import { useMBTrajectory } from '../Mubiao/components/HisTrajectory/hooks/mbTraj'
|
||||
import { useMultiMBTrajectory } from '../Mubiao/components/MultiHisTrajectory/hooks/multiMbTraj'
|
||||
// import { useMultiMBTrajectory } from '../Mubiao/components/MultiHisTrajectory/hooks/multiMbTraj'
|
||||
import { useMultiTraj } from '../MultiTrajPlayback/hooks/useMultiTraj'
|
||||
|
||||
import { useDaodan } from '../Daodan/ddHooks'
|
||||
// import { useWeather } from '../Weather/hooks/weather'
|
||||
import DetailsModal from './components/DetailsModal/index.vue'
|
||||
@ -34,7 +39,7 @@ const { getTextConfigs, initWebSocket } = useTextReport()
|
||||
|
||||
const { showHisImageCom } = useHisImage()
|
||||
const { showHisTrajCom } = useMBTrajectory()
|
||||
const { showMultiHisTrajCom } = useMultiMBTrajectory()
|
||||
const { showMultiHisTrajCom, showMultiHisTrajDrawer } = useMultiTraj()
|
||||
const { showDdConfigCom } = useDaodan()
|
||||
const getConfig = async () => {
|
||||
const res = await getTextConfigs()
|
||||
@ -205,27 +210,41 @@ const showOrHideTextReport = () => {
|
||||
<!-- <heat-map class="z-20"></heat-map> -->
|
||||
</div>
|
||||
<!-- <div class="z-20 grid grid-cols-1 grid-rows-3 gap-1"> -->
|
||||
<div>
|
||||
<div class="">
|
||||
<div
|
||||
class="btn-transform z-20 w-h-full"
|
||||
:class="showTextReport ? '' : 'btn-transform-pos'"
|
||||
>
|
||||
<n-button
|
||||
<div
|
||||
class="absolute -left-[16px] top-7 z-40 h-6 w-6 cursor-pointer"
|
||||
@click="showOrHideTextReport"
|
||||
>
|
||||
<img
|
||||
src="/images/icons/text/文字报.png"
|
||||
class="z-40 h-full w-full"
|
||||
/>
|
||||
</div>
|
||||
<!-- <n-button
|
||||
class="absolute -left-[16px] top-5 z-30 border border-[#29baf1] bg-[var(--color-bg)]"
|
||||
size="tiny"
|
||||
@click="showOrHideTextReport"
|
||||
>
|
||||
>git a
|
||||
<n-icon
|
||||
class="btn-transform"
|
||||
:class="showTextReport ? '' : 'icon-transform'"
|
||||
>
|
||||
<arrow-right />
|
||||
</n-icon>
|
||||
</n-button>
|
||||
</n-button> -->
|
||||
<!-- <transition name="slide2">.slice(0, 3) -->
|
||||
<panel title="文字报"><text-report :tabs="types" /></panel>
|
||||
<!-- </transition> -->
|
||||
</div>
|
||||
|
||||
<multi-traj-playback
|
||||
class="btn-transform absolute left-0 top-0"
|
||||
:class="showMultiHisTrajDrawer ? '' : 'btn-transform-pos'"
|
||||
/>
|
||||
<!-- <div class="w-h-full">
|
||||
<panel title="文字报"
|
||||
><text-report :tabs="types.slice(3, 6)"
|
||||
@ -254,6 +273,7 @@ const showOrHideTextReport = () => {
|
||||
v-if="showHisImageCom"
|
||||
class="z-30 h-[260px] w-full"
|
||||
></his-images>
|
||||
<!-- v-show="true" -->
|
||||
<daodan-test-config
|
||||
v-show="showDdConfigCom"
|
||||
class="z-30 h-[90%] w-[75%]"
|
||||
|
@ -83,11 +83,11 @@ export default defineComponent({
|
||||
showPosIcon={false}
|
||||
/>
|
||||
))}
|
||||
<div>
|
||||
{/* <div>
|
||||
<NButton type="primary" onClick={addIntercept}>
|
||||
添加拦截
|
||||
</NButton>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
|
@ -154,13 +154,13 @@ export default defineComponent({
|
||||
<div>
|
||||
<div class="flex justify-between">
|
||||
<div class="detail-item-title">{props.title}</div>
|
||||
<div>
|
||||
{/* <div>
|
||||
{props.title.indexOf('拦截') > -1 && (
|
||||
<NButton quaternary type="error" onClick={remove}>
|
||||
删除拦截
|
||||
</NButton>
|
||||
)}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
<NDataTable data={trajData.value} columns={columns} />
|
||||
</div>
|
||||
|
198
src/views/MultiTrajPlayback/components/MultiHisTrajectory.vue
Normal file
198
src/views/MultiTrajPlayback/components/MultiHisTrajectory.vue
Normal file
@ -0,0 +1,198 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Play as PlayIcon,
|
||||
Pause as PauseIcon,
|
||||
Refresh as ResetIcon,
|
||||
} from '@vicons/ionicons5'
|
||||
import { Ship as ShipIcon } from '@vicons/tabler'
|
||||
import { h } from 'vue'
|
||||
import type { VNode } from 'vue'
|
||||
import Panel from '@/components/Panel/index.vue'
|
||||
import { useMultiTraj } from '../hooks/useMultiTraj'
|
||||
|
||||
const {
|
||||
showOrHideMultiHisTraj,
|
||||
times,
|
||||
loadMultiHisTraj,
|
||||
customElapsedTime,
|
||||
isAnimationRunning,
|
||||
isPaused,
|
||||
play,
|
||||
pause,
|
||||
reset,
|
||||
setSpeed,
|
||||
animationSpeed,
|
||||
changeTime,
|
||||
} = useMultiTraj()
|
||||
|
||||
const timeRange = ref<string[]>()
|
||||
|
||||
const rangeShortcuts = {
|
||||
近一天: () => {
|
||||
const cur = new Date().getTime()
|
||||
return [cur - 24 * 60 * 60 * 1000, cur]
|
||||
},
|
||||
近一周: () => {
|
||||
const cur = new Date().getTime()
|
||||
return [cur - 7 * 24 * 60 * 60 * 1000, cur]
|
||||
},
|
||||
近一月: () => {
|
||||
const cur = new Date().getTime()
|
||||
return [cur - 30 * 24 * 60 * 60 * 1000, cur]
|
||||
},
|
||||
近一年: () => {
|
||||
const cur = new Date().getTime()
|
||||
return [cur - 365 * 24 * 60 * 60 * 1000, cur]
|
||||
},
|
||||
}
|
||||
|
||||
// const timeArray = [time, time + 3 * 60 * 60 * 1000]
|
||||
const timelineValue = ref<number>(0)
|
||||
|
||||
watch(customElapsedTime, newTime => {
|
||||
timelineValue.value = newTime
|
||||
})
|
||||
|
||||
const updateTimeline = (val: number) => {
|
||||
changeTime(new Date(val).getTime())
|
||||
}
|
||||
|
||||
const marks = ref({})
|
||||
|
||||
const speedOptions = [
|
||||
{
|
||||
label: 1,
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 5,
|
||||
value: 5,
|
||||
},
|
||||
{
|
||||
label: 10,
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
label: 20,
|
||||
value: 20,
|
||||
},
|
||||
]
|
||||
watch(times, timeArray => {
|
||||
const segments = divideTimeRangeIntoParts(
|
||||
timeArray[0],
|
||||
timeArray[timeArray.length - 1],
|
||||
8
|
||||
)
|
||||
marks.value = segments.reduce<{ [key: string]: VNode }>((acc, cur, index) => {
|
||||
// console.log(new Date(cur).toLocaleString())
|
||||
acc[cur] = h('div', { class: 'text-center' }, [
|
||||
h('div', { class: 'text-xs' }, new Date(cur).toLocaleDateString()),
|
||||
h('div', { class: 'text-xs' }, new Date(cur).toLocaleTimeString()),
|
||||
h(
|
||||
'div',
|
||||
{ class: 'text-xs' },
|
||||
index === 0 ? '开始' : index === segments.length - 1 ? '结束' : ''
|
||||
),
|
||||
])
|
||||
return acc
|
||||
}, {})
|
||||
})
|
||||
function divideTimeRangeIntoParts(
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
parts: number
|
||||
): number[] {
|
||||
const totalDuration = endTime - startTime
|
||||
const segmentDuration = totalDuration / parts
|
||||
const segments = [startTime]
|
||||
for (let i = 0; i < parts; i++) {
|
||||
const end = startTime + (i + 1) * segmentDuration
|
||||
segments.push(end)
|
||||
}
|
||||
return segments
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<panel
|
||||
title="多目标轨迹回放"
|
||||
showClose
|
||||
:closeClick="showOrHideMultiHisTraj"
|
||||
>
|
||||
<div class="flex h-full flex-col justify-center">
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<n-date-picker
|
||||
v-model:formatted-value="timeRange"
|
||||
clearable
|
||||
type="datetimerange"
|
||||
:shortcuts="rangeShortcuts"
|
||||
:update-value-on-close="true"
|
||||
format="yyyy-MM-dd HH:mm:ss"
|
||||
/>
|
||||
<n-button type="primary" @click="loadMultiHisTraj(timeRange)">
|
||||
加载轨迹
|
||||
</n-button>
|
||||
<n-divider vertical />
|
||||
<div class="flex items-center">
|
||||
<label class="w-[48px]">速度:</label
|
||||
><n-select
|
||||
class="w-[100px]"
|
||||
v-model:value="animationSpeed"
|
||||
:options="speedOptions"
|
||||
@update:value="setSpeed"
|
||||
>
|
||||
</n-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<n-empty class="m-auto flex" v-if="times.length < 2"></n-empty>
|
||||
<div v-else class="flex flex-1 gap-2 pt-14">
|
||||
<n-button
|
||||
tertiary
|
||||
circle
|
||||
@click="pause"
|
||||
v-show="isAnimationRunning && !isPaused"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon><pause-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button
|
||||
tertiary
|
||||
circle
|
||||
@click="play(timelineValue || times[0])"
|
||||
v-show="!isAnimationRunning || isPaused"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon><play-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button tertiary circle @click="reset">
|
||||
<template #icon>
|
||||
<n-icon><reset-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-slider
|
||||
class="px-10"
|
||||
v-model:value="timelineValue"
|
||||
show-tooltip
|
||||
:format-tooltip="value => new Date(value).toLocaleString()"
|
||||
:step="1000"
|
||||
:min="times[0]"
|
||||
:max="times[times.length - 1]"
|
||||
:marks="marks"
|
||||
@update:value="updateTimeline"
|
||||
>
|
||||
<template #thumb>
|
||||
<n-icon-wrapper :size="24" :border-radius="12">
|
||||
<n-icon :size="18" :component="ShipIcon" />
|
||||
</n-icon-wrapper>
|
||||
</template>
|
||||
</n-slider>
|
||||
</div>
|
||||
</div>
|
||||
</panel>
|
||||
</div>
|
||||
</template>
|
91
src/views/MultiTrajPlayback/hooks/useMultiTraj.js
Normal file
91
src/views/MultiTrajPlayback/hooks/useMultiTraj.js
Normal file
@ -0,0 +1,91 @@
|
||||
import { ref } from 'vue'
|
||||
import { useMultiTrajReq } from './useMultiTrajReq'
|
||||
|
||||
export function useMultiTraj() {
|
||||
const timesMap = ref(new Map())
|
||||
const times = ref([])
|
||||
|
||||
const customElapsedTime = ref(0)
|
||||
const animationSpeed = ref(1)
|
||||
// const lastFrameTime = ref<number>(performance.now())
|
||||
const isAnimationRunning = ref(false)
|
||||
const isPaused = ref(false)
|
||||
|
||||
function play() {
|
||||
isAnimationRunning.value = true
|
||||
isPaused.value = false
|
||||
}
|
||||
function pause() {
|
||||
isAnimationRunning.value = false
|
||||
isPaused.value = true
|
||||
}
|
||||
|
||||
function reset() {
|
||||
isAnimationRunning.value = false
|
||||
isPaused.value = false
|
||||
customElapsedTime.value = 0
|
||||
}
|
||||
|
||||
function setSpeed(speed) {
|
||||
animationSpeed.value = speed
|
||||
}
|
||||
|
||||
function changeTime(time) {
|
||||
customElapsedTime.value = time
|
||||
}
|
||||
return {
|
||||
checkedAllKeys,
|
||||
showMultiHisTrajCom,
|
||||
showOrHideMultiHisTraj,
|
||||
times,
|
||||
isAnimationRunning,
|
||||
isPaused,
|
||||
play,
|
||||
pause,
|
||||
reset,
|
||||
animationSpeed,
|
||||
setSpeed,
|
||||
changeTime,
|
||||
customElapsedTime,
|
||||
loadMultiHisTraj,
|
||||
showMultiHisTrajDrawer,
|
||||
showOrHideMultiHisTrajDrawer,
|
||||
}
|
||||
}
|
||||
|
||||
const checkedAllKeys = ref({
|
||||
zb: [],
|
||||
dd: [],
|
||||
satellite: [],
|
||||
hj: [],
|
||||
})
|
||||
|
||||
const showMultiHisTrajCom = ref(false)
|
||||
|
||||
const showMultiHisTrajDrawer = ref(false)
|
||||
|
||||
function showOrHideMultiHisTrajDrawer() {
|
||||
showMultiHisTrajDrawer.value = !showMultiHisTrajDrawer.value
|
||||
}
|
||||
|
||||
function showOrHideMultiHisTraj() {
|
||||
showMultiHisTrajCom.value = !showMultiHisTrajCom.value
|
||||
}
|
||||
|
||||
const { getZBHisTraj } = useMultiTrajReq()
|
||||
|
||||
function loadMultiHisTraj(timeRange) {
|
||||
console.log(timeRange)
|
||||
|
||||
const dictFunc = {
|
||||
zb: getZBHisTraj,
|
||||
dd: null,
|
||||
satellite: null,
|
||||
hj: null,
|
||||
}
|
||||
Object.keys(checkedAllKeys.value).forEach(key => {
|
||||
checkedAllKeys.value[key].forEach(item => {
|
||||
typeof dictFunc[key] === 'function' && dictFunc[key](item, timeRange)
|
||||
})
|
||||
})
|
||||
}
|
96
src/views/MultiTrajPlayback/hooks/useMultiTrajReq.js
Normal file
96
src/views/MultiTrajPlayback/hooks/useMultiTrajReq.js
Normal file
@ -0,0 +1,96 @@
|
||||
import { ref } from 'vue'
|
||||
import { getMubiao, getMubiaoHisTraj } from '../../../api/Mubiao'
|
||||
import { getSatellite } from '../../../api/Satellite'
|
||||
import { getHangjing } from '../../../api/Hangjing'
|
||||
import { getDaodanTree } from '../../../api/Daodan'
|
||||
|
||||
export function useMultiTrajReq() {
|
||||
return { allTreeData, getAllTree, getZBHisTraj }
|
||||
}
|
||||
|
||||
const allTreeData = ref([])
|
||||
|
||||
function getAllTree() {
|
||||
Promise.all([getZBTree(), getDDTree(), getSatelliteTree(), getHJTree()])
|
||||
.then(res => {
|
||||
allTreeData.value = {
|
||||
zb: [res[0]],
|
||||
dd: [res[1]],
|
||||
satellite: res[2],
|
||||
hj: [res[3]],
|
||||
}
|
||||
})
|
||||
.catch(err => {})
|
||||
}
|
||||
async function getZBTree() {
|
||||
const { code, data } = await getMubiao()
|
||||
if (code === '200') {
|
||||
data.nodeName = '装备'
|
||||
return data
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
async function getDDTree() {
|
||||
const { code, data } = await getDaodanTree()
|
||||
if (code === '200') {
|
||||
data.nodeName = 'DD'
|
||||
return data
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
async function getSatelliteTree() {
|
||||
const { code, data } = await getSatellite()
|
||||
if (code === '200') {
|
||||
return data
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
async function getHJTree() {
|
||||
const { code, data } = await getHangjing()
|
||||
if (code === '200') {
|
||||
data.nodeName = 'hj'
|
||||
return data
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
async function getZBHisTraj(id, params) {
|
||||
const [timeBegin, timeEnd] = params
|
||||
const { code, data } = await getMubiaoHisTraj({
|
||||
target_id: id,
|
||||
timeBegin,
|
||||
timeEnd,
|
||||
})
|
||||
if (code === '200') {
|
||||
return data
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
async function getSatelliteHisTraj(id, params) {
|
||||
const { timeBegin, timeEnd } = params
|
||||
const { code, data } = await getSatellite()
|
||||
if (code === '200') {
|
||||
}
|
||||
}
|
||||
|
||||
async function getDDHisTraj(id, params) {
|
||||
const { timeBegin, timeEnd } = params
|
||||
const { code, data } = await getSatellite()
|
||||
if (code === '200') {
|
||||
}
|
||||
}
|
||||
|
||||
async function getHJHisTraj(id, params) {
|
||||
const { timeBegin, timeEnd } = params
|
||||
const { code, data } = await getSatellite()
|
||||
if (code === '200') {
|
||||
}
|
||||
}
|
95
src/views/MultiTrajPlayback/index.jsx
Normal file
95
src/views/MultiTrajPlayback/index.jsx
Normal file
@ -0,0 +1,95 @@
|
||||
import { defineComponent, onMounted } from 'vue'
|
||||
import { NButton, NIcon, NScrollbar } from 'naive-ui'
|
||||
import Panel from '@/components/Panel/index.vue'
|
||||
import Tree from '@/components/Tree/index.vue'
|
||||
import TabsCom from '@/components/Tabs/index.vue'
|
||||
|
||||
import Bg from '@/assets/image/multiTraj/编组.png'
|
||||
import RadarSwitch from '@/assets/image/multiTraj/开.png'
|
||||
import { useMultiTrajReq } from './hooks/useMultiTrajReq'
|
||||
import { useMultiTraj } from './hooks/useMultiTraj'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MultiTrajPlayback',
|
||||
setup() {
|
||||
const { allTreeData, getAllTree } = useMultiTrajReq()
|
||||
onMounted(() => {
|
||||
getAllTree()
|
||||
})
|
||||
|
||||
const dict = {
|
||||
satellite: '卫星',
|
||||
zb: '装备',
|
||||
dd: 'dd',
|
||||
hj: 'hj',
|
||||
}
|
||||
function renderSuffix({ option }) {
|
||||
return option.data ? (
|
||||
<div class="">
|
||||
<NIcon
|
||||
size={14}
|
||||
class="cursor-pointer text-gray-500 hover:text-blue-600"
|
||||
onClick={() => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<img src={RadarSwitch} class="h-full w-full" />
|
||||
</NIcon>
|
||||
</div>
|
||||
) : undefined
|
||||
}
|
||||
|
||||
const {
|
||||
checkedAllKeys,
|
||||
showOrHideMultiHisTraj,
|
||||
showOrHideMultiHisTrajDrawer,
|
||||
} = useMultiTraj()
|
||||
|
||||
const multiTrajAllTreeTabConfig = computed(() => {
|
||||
return Object.keys(allTreeData.value).map((key, index) => {
|
||||
return {
|
||||
name: dict[key],
|
||||
value: key,
|
||||
component: () => (
|
||||
<Tree
|
||||
data={allTreeData.value[key]}
|
||||
key-field={key === 'satellite' ? 'id' : 'dataId'}
|
||||
label-field={key === 'satellite' ? 'name' : 'nodeName'}
|
||||
showSearch
|
||||
renderSuffix={renderSuffix}
|
||||
v-model:checked={checkedAllKeys.value[key]}
|
||||
/>
|
||||
),
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
function playMultiTraj() {
|
||||
// TODO: 轨迹回放
|
||||
showOrHideMultiHisTraj()
|
||||
}
|
||||
|
||||
return () => (
|
||||
<div class="btn-transform z-20 w-h-full">
|
||||
<div
|
||||
class="absolute -left-[16px] top-20 z-30 h-6 w-6 cursor-pointer"
|
||||
onClick={showOrHideMultiHisTrajDrawer}
|
||||
>
|
||||
<img src={Bg} class="h-full w-full" />
|
||||
</div>
|
||||
|
||||
<Panel title={'多目标轨迹回放'}>
|
||||
<div class="flex flex-col gap-4 w-h-full">
|
||||
<div class="h-0 flex-1">
|
||||
{multiTrajAllTreeTabConfig.value.length && (
|
||||
<TabsCom tabs={multiTrajAllTreeTabConfig.value} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<NButton onClick={playMultiTraj}>轨迹回放</NButton>
|
||||
</div>
|
||||
</Panel>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
Loading…
Reference in New Issue
Block a user