LSSE-front/src/views/subsystem/scene/index.vue

364 lines
11 KiB
Vue
Raw Normal View History

2025-09-18 09:34:18 +08:00
<template>
<Flex fd="co" class="page-scene">
<Flex ai="c" jc="sb" class="page-scene-header">
<span class="page-scene-title">场景编辑子系统</span>
<span class="page-scene-title">推演想定{{ roomName }}-{{ scenarioName }}</span>
<span class="page-scene-title">剩余 {{ roomInfo.remainTimeStr }}</span>
</Flex>
<Grid class="page-scene-main flex-1 oh" :columns="['320px', 1, '320px']" :rows="['30px', 1]" gap="0px">
2025-09-20 22:24:04 +08:00
<div class="tool-wrapper" style="grid-area: 1 / 1 / 2 / 4">
<a-menu :selectedKeys="[]" mode="horizontal" theme="dark">
<a-menu-item @click="() => {}"> 统计分析 </a-menu-item>
</a-menu>
</div>
2025-09-18 09:34:18 +08:00
<div
ref="scene-cesium-container"
class="scene-cesium-container"
id="scene-cesium-container"
style="grid-area: 2 / 1 / 3 / 4"
></div>
<div class="pr zi1" style="grid-area: 2 / 1 / 3 / 2">
2025-09-20 16:58:19 +08:00
<ModuleWrapper title="作战/保障力量" height="60%">
2025-09-18 09:34:18 +08:00
<div class="normal" style="padding: 5px; overflow-y: auto">
<a-tree
class="simulation-tree"
2025-09-20 16:58:19 +08:00
:treeData="zzbzllTreeData"
2025-09-18 09:34:18 +08:00
:selectedKeys.sync="zzbzll.selectedKeys"
2025-09-20 22:24:04 +08:00
:replaceFields="{ children: 'children', title: 'resourceName', key: 'id' }"
2025-09-18 09:34:18 +08:00
@select="handleSelectZzbzll"
>
</a-tree>
</div>
</ModuleWrapper>
2025-09-20 16:58:19 +08:00
<ModuleWrapper title="日志" height="40%">
<div class="normal"></div>
2025-09-18 09:34:18 +08:00
</ModuleWrapper>
</div>
2025-09-20 16:58:19 +08:00
<Grid class="pr zi1" :rows="rightRows" gap="0px" style="grid-area: 2 / 3 / 3 / 4">
<ModuleWrapper title="兵力编组">
2025-09-18 09:34:18 +08:00
<template #extra>
2025-09-20 16:58:19 +08:00
<Zoom :max="rightViewer === 'blbz'" @zoom-max="rightViewer = 'blbz'" @zoom-min="rightViewer = ''" />
2025-09-18 09:34:18 +08:00
</template>
<div class="normal" style="padding: 5px; overflow-y: auto">
<a-tree
class="simulation-tree"
:treeData="showBlbzCheckedTreeData"
:selectable="false"
:replaceFields="{ children: 'children', title: 'title', key: 'id' }"
>
</a-tree>
</div>
</ModuleWrapper>
2025-09-20 16:58:19 +08:00
<ModuleWrapper title="基础属性">
<template #extra>
<Zoom :max="rightViewer === 'jcsx'" @zoom-max="rightViewer = 'jcsx'" @zoom-min="rightViewer = ''" />
2025-09-18 09:34:18 +08:00
</template>
<div class="normal" style="padding: 15px 0">
2025-09-20 16:58:19 +08:00
<Jcsx
ref="jcsx"
v-if="zzbzllSelectedFd"
:scenarioId="scenarioId"
2025-09-20 22:24:04 +08:00
:resourceId="zzbzllSelectedFd.sdzy.id"
2025-09-21 04:34:46 +08:00
:originResourceId="zzbzllSelectedFd.sdzy.resourceId"
2025-09-20 22:24:04 +08:00
:resourceName="zzbzllSelectedFd.sdzy.resourceName"
:resourceType="zzbzllSelectedFd.sdzy.resourceType"
:type="zzbzllSelectedFd.sdzy.type"
2025-09-20 16:58:19 +08:00
:modelData="jcsxModelData"
:readonly="true"
/>
2025-09-18 09:34:18 +08:00
</div>
</ModuleWrapper>
2025-09-20 22:24:04 +08:00
<ModuleWrapper :title="xdrw.resourceTypeMapTitle[zzbzllSelectedFd?.sdzy.resourceType] || '行动任务'">
2025-09-20 16:58:19 +08:00
<template #extra>
<Zoom :max="rightViewer === 'xdrw'" @zoom-max="rightViewer = 'xdrw'" @zoom-min="rightViewer = ''" />
</template>
<div class="normal" style="padding: 0">
<Zzxd
ref="xdrw"
v-if="zzbzllSelectedFd"
:scenarioId="scenarioId"
2025-09-20 22:24:04 +08:00
:resourceId="zzbzllSelectedFd.sdzy.id"
:resourceType="zzbzllSelectedFd.sdzy.resourceType"
2025-09-20 16:58:19 +08:00
:actionList="xdrwActionList"
:readonly="true"
/>
</div>
</ModuleWrapper>
</Grid>
2025-09-18 09:34:18 +08:00
</Grid>
</Flex>
</template>
<script>
2025-09-20 16:58:19 +08:00
import { getAction } from '@/api/manage'
import Zoom from './components/Zoom.vue'
2025-09-18 09:34:18 +08:00
import Jcsx from './components/Jcsx.vue'
import Zzxd from './components/Zzxd.vue'
export default {
name: 'SubsystemScene',
components: {
2025-09-20 16:58:19 +08:00
Zoom,
2025-09-18 09:34:18 +08:00
Jcsx,
Zzxd,
},
data() {
return {
2025-09-20 22:24:04 +08:00
initial: false,
2025-09-18 09:34:18 +08:00
ws: null,
roomInfo: {
remainTimeStr: '',
remainTime: '',
duringTime: '',
2025-09-20 16:58:19 +08:00
roomData: [],
2025-09-18 09:34:18 +08:00
},
roomId: '',
roomName: '',
scenarioId: '',
scenarioName: '',
cesium: null,
2025-09-20 23:44:46 +08:00
scenarioDetail: null,
2025-09-18 09:34:18 +08:00
zzbzll: {
selectedKeys: [],
},
blbz: {
treeData: [],
},
2025-09-20 16:58:19 +08:00
rightViewer: '',
xdrw: {
resourceTypeMapTitle: {
5: '作战行动',
6: '保障任务',
2025-09-18 09:34:18 +08:00
},
},
}
},
computed: {
2025-09-20 16:58:19 +08:00
zzbzllTreeData() {
2025-09-20 22:24:04 +08:00
const zzbzllTreeData = [
{
id: '0',
resourceName: '红方',
selectable: false,
children: [],
},
{
id: '1',
resourceName: '蓝方',
selectable: false,
children: [],
},
]
this.roomInfo.roomData.forEach((item) => {
zzbzllTreeData[item.sdzy.type].children.push(item.sdzy)
})
return zzbzllTreeData
2025-09-20 16:58:19 +08:00
},
zzbzllSelectedFd() {
if (this.zzbzll.selectedKeys.length === 0) {
return null
}
2025-09-20 22:24:04 +08:00
return this.roomInfo.roomData.find((item) => item.sdzy.id === this.zzbzll.selectedKeys[0])
2025-09-20 16:58:19 +08:00
},
rightRows() {
switch (this.rightViewer) {
case 'blbz':
return [8, 1, 1]
case 'jcsx':
return [1, 8, 1]
case 'xdrw':
return [1, 1, 8]
default:
return [4, 3, 3]
}
},
blbzShowKeys() {
2025-09-20 22:24:04 +08:00
return this.zzbzllSelectedFd?.orgPostList.map((item) => item.orgId) || []
2025-09-20 16:58:19 +08:00
},
2025-09-18 09:34:18 +08:00
showBlbzCheckedTreeData() {
const target = []
2025-09-20 16:58:19 +08:00
this.getTree(target, this.blbz.treeData, this.blbzShowKeys)
2025-09-18 09:34:18 +08:00
return target
},
2025-09-20 16:58:19 +08:00
jcsxModelData() {
2025-09-20 22:24:04 +08:00
return this.zzbzllSelectedFd?.jbxx || {}
2025-09-20 16:58:19 +08:00
},
xdrwActionList() {
2025-09-20 22:24:04 +08:00
return this.zzbzllSelectedFd?.scenarioTasks || []
2025-09-20 16:58:19 +08:00
},
2025-09-18 09:34:18 +08:00
},
created() {
this.roomId = this.$route.params.roomId
this.roomName = this.$route.params.roomName
this.scenarioId = this.$route.params.scenarioId
this.scenarioName = this.$route.params.scenarioName
2025-09-20 16:58:19 +08:00
this.getBlbzTreeData()
2025-09-18 20:31:52 +08:00
},
mounted() {
this.cesium = new window.MyCesium('scene-cesium-container')
2025-09-20 23:44:46 +08:00
this.getScenarioDetail()
2025-09-18 09:34:18 +08:00
this.initWebsocket()
2025-09-18 19:57:55 +08:00
window.addEventListener('beforeunload', (e) => {
this.closeWebsocket()
return true
})
2025-09-18 09:34:18 +08:00
},
methods: {
2025-09-20 16:58:19 +08:00
getTree(target, treeData, showKeys) {
treeData.forEach((item) => {
const newChildren = []
if (item.children && item.children.length > 0) {
this.getTree(newChildren, item.children, showKeys)
}
2025-09-21 04:34:46 +08:00
if (newChildren.length > 0 || showKeys.includes(+item.key)) {
2025-09-20 16:58:19 +08:00
target.push({ ...item, children: newChildren })
}
})
},
2025-09-20 23:44:46 +08:00
async getScenarioDetail() {
try {
const res = await getAction(`/baseData/scenario/${this.scenarioId}`)
const {
leftUpLng,
leftUpLat,
rightUpLng,
rightUpLat,
rightBottomLng,
rightBottomLat,
leftBottomLng,
leftBottomLat,
} = res.data
this.cesium.setClientByAllCorner(
[+leftUpLng, +leftUpLat],
[+rightUpLng, +rightUpLat],
[+rightBottomLng, +rightBottomLat],
[+leftBottomLng, +leftBottomLat]
)
} catch (error) {
console.log(error)
}
},
2025-09-18 09:34:18 +08:00
initWebsocket() {
this.ws = new window.MyWebsocket(`/ws/${this.scenarioId}/${this.roomId}`, (error, response) => {
if (error) return this.$message.error(error.message)
switch (response.cmdType) {
case 'update_time':
this.roomInfo.remainTimeStr = response.data.update_time_str
this.roomInfo.remainTime = response.data.remain_time
this.roomInfo.duringTime = response.data.during_time
break
2025-09-18 20:31:52 +08:00
case 'path_init':
2025-09-21 04:34:46 +08:00
this.cesium.drawRouteByCoordinates(response.data.points, response.data.resourceId, ['red', 'blue'][response.data.teamType])
2025-09-18 20:31:52 +08:00
break
case 'path_update':
2025-09-19 11:08:10 +08:00
this.cesium.movePlotByCoordinates(response.data.resourceId, response.data.points)
2025-09-18 20:31:52 +08:00
break
2025-09-20 22:24:04 +08:00
case 'editScenarioInfo':
if (this.initial === false) {
this.roomInfo.roomData = JSON.parse(response.data)
this.initPlots()
this.initial = true
}
break
case 'updScenarioInfo':
{
const data = JSON.parse(response.data)
const targetIndex = this.roomInfo.roomData.findIndex((item) => item.sdzy.id === data.sdzy.id)
this.$set(this.roomInfo.roomData, targetIndex, data)
}
2025-09-20 16:58:19 +08:00
break
2025-09-18 09:34:18 +08:00
default:
2025-09-20 22:24:04 +08:00
// console.log(response.cmdType, response.data)
2025-09-18 09:34:18 +08:00
break
}
})
2025-09-21 04:34:46 +08:00
// 初始化数据
2025-09-20 22:24:04 +08:00
this.ws.send({ cmdType: 'editScenarioInfo' })
2025-09-21 04:34:46 +08:00
// 初始化路径
this.ws.send({ cmdType: 'get_init_path' })
2025-09-18 09:34:18 +08:00
},
closeWebsocket() {
this.ws && this.ws.close()
2025-09-18 19:57:55 +08:00
this.ws = null
2025-09-18 09:34:18 +08:00
},
2025-09-20 16:58:19 +08:00
async getBlbzTreeData() {
2025-09-18 09:34:18 +08:00
try {
2025-09-20 16:58:19 +08:00
const res = await getAction('/tree/organization')
this.blbz.treeData = res.data
2025-09-18 09:34:18 +08:00
} catch (error) {
console.log(error)
}
},
2025-09-20 16:58:19 +08:00
2025-09-20 22:24:04 +08:00
initPlots() {
this.roomInfo.roomData.forEach((item) => {
if (item.sdzy.lng && item.sdzy.lat) {
this.cesium.addPlotByLonLat(item.sdzy.imgBase64, { lon: +item.sdzy.lng, lat: +item.sdzy.lat }, item.sdzy.id)
2025-09-18 09:34:18 +08:00
}
})
},
2025-09-18 19:57:55 +08:00
2025-09-18 09:34:18 +08:00
handleSelectZzbzll(selectedKeys, { node }) {
2025-09-20 22:24:04 +08:00
this.cesium.setClientByCenter({
longitude: +this.zzbzllSelectedFd.sdzy.lng,
latitude: +this.zzbzllSelectedFd.sdzy.lat,
})
2025-09-18 09:34:18 +08:00
},
},
}
</script>
<style lang="less" scoped>
.page-scene {
height: 100%;
color: #ffffff;
.page-scene-header {
height: 50px;
background-color: #0a2a3d;
padding: 0 20px;
.page-scene-title {
color: #00d5fe;
font-size: 18px;
font-weight: bolder;
letter-spacing: 2px;
}
}
.page-scene-main {
background-color: #022234;
}
}
2025-09-20 22:24:04 +08:00
.ant-menu-horizontal {
line-height: 30px;
}
2025-09-18 09:34:18 +08:00
.scene-cesium-container {
width: 100%;
height: 100%;
overflow: hidden;
}
::v-deep {
2025-09-18 19:57:55 +08:00
.distance-legend {
left: 320px;
}
2025-09-18 09:34:18 +08:00
.compass {
right: 320px;
}
.navigation-controls {
right: 350px;
}
}
.simulation-tree::v-deep {
color: #a1c2d0;
li .ant-tree-node-content-wrapper {
color: #a1c2d0;
}
li .ant-tree-node-content-wrapper.ant-tree-node-selected {
background-color: #bae7ff44;
}
li .ant-tree-node-content-wrapper:hover {
background-color: #bae7ff22;
}
}
</style>