map服务,系统控制子系统想定信息展示,图形数据库

This commit is contained in:
liaoboping 2025-08-26 17:32:02 +08:00
parent 456a6fc1d0
commit a93db081dc
6 changed files with 278 additions and 67 deletions

8
public/config.js vendored
View File

@ -1,5 +1,5 @@
window._CONFIG = {
ImageryProviderUrl: "http://localhost:8090/mapWX/{z}/{x}/{y}.jpg",
RoadProviderUrl: "",
TerrainProviderUrl: "http://localhost:8090/mapDem/",
};
ImageryProviderUrl: '/map/mapWX/{z}/{x}/{y}.jpg',
RoadProviderUrl: '',
TerrainProviderUrl: '/map/mapDem/',
}

View File

@ -3,9 +3,9 @@ import CesiumNavigation from 'cesium-navigation-es6'
import 'cesium/Build/Cesium/Widgets/widgets.css'
export default class MyCesium {
static ImageryProviderUrl = 'http://localhost:8090/mapWX/{z}/{x}/{y}.jpg'
static ImageryProviderUrl = '/map/mapWX/{z}/{x}/{y}.jpg'
static RoadProviderUrl = ''
static TerrainProviderUrl = 'http://localhost:8090/mapDem/'
static TerrainProviderUrl = '/map/mapDem/'
static center = [116.39742, 39.90906, 2000000]
static ENTITY_TYPES = {
WARZONE: 1,

View File

@ -22,7 +22,7 @@
<script>
export default {
props: {
value: { type: Number, required: true },
value: { validator: (v) => v == undefined || typeof v === 'number', required: true },
countFormat: { validator: (v) => ['D', 'H', 'm', 's'].includes(v), default: 'm' },
showDay: { type: Boolean, default: true },
showHour: { type: Boolean, default: true },

View File

@ -18,7 +18,7 @@
</div>
</Grid>
</ModuleWrapper>
<ModuleWrapper title="全部房间" style="grid-column: 1 / 3">
<ModuleWrapper v-if="!enterRoom" title="全部房间" style="grid-column: 1 / 3">
<template #extra>
<a-button type="primary" @click="handleOpenScenarioModal()">新建房间</a-button>
<a-button type="primary" icon="sync" @click="getRoomList()"></a-button>
@ -45,6 +45,117 @@
/>
</div>
</ModuleWrapper>
<ModuleWrapper v-if="enterRoom" title="想定信息">
<template #extra>
<a-button type="primary" shape="circle" icon="close" @click="handleLeaveRoom()" />
</template>
<Flex class="normal" fd="co" v-loading="roomInfo.loading">
<Flex ai="c" jc="sb">
<Flex ai="c">
<div style="color: #92bacb">运行方式</div>
<a-select style="width: 240px" v-model="roomInfo.runningMode">
<a-select-option value="1">人在回路</a-select-option>
<a-select-option value="2">人不在回路</a-select-option>
</a-select>
</Flex>
<Flex ai="c">
<a-button type="primary" icon="caret-right">开始</a-button>
<a-button type="primary" icon="pause">暂停</a-button>
<a-button type="primary" icon="stop">中止</a-button>
<a-button type="primary" icon="step-backward">快退X1</a-button>
<a-button type="primary" icon="step-forward">快进X1</a-button>
</Flex>
</Flex>
<Flex fd="co" class="scenario-info-wrapper flex-1">
<a-radio-group v-model="roomInfo.radioType" button-style="solid" style="margin-bottom: 20px">
<a-radio-button value="xdsj">想定时间</a-radio-button>
<a-radio-button value="xdqy">想定区域</a-radio-button>
<a-radio-button value="xdsm">想定说明</a-radio-button>
</a-radio-group>
<a-row v-if="roomInfo.radioType === 'xdsj'">
<a-col :span="24">
<div>想定当前时间</div>
<div>
<a-date-picker :value="roomInfo.scenarioDetail.planDate" valueFormat="YYYY-MM-DD" style="width: 100%" />
<a-time-picker :value="roomInfo.scenarioDetail.planTime" valueFormat="HH:mm:ss" style="width: 100%" />
</div>
</a-col>
<a-col :span="24">
<div>想定开始时间</div>
<div>
<a-date-picker
:value="roomInfo.scenarioDetail.startDate"
valueFormat="YYYY-MM-DD"
style="width: 100%"
/>
<a-time-picker :value="roomInfo.scenarioDetail.startTime" valueFormat="HH:mm:ss" style="width: 100%" />
</div>
</a-col>
<a-col :span="24">
<div>想定持续时间</div>
<div>
<DurationPicker v-model="roomInfo.scenarioDetail.continueTime" />
</div>
</a-col>
<a-col :span="24">
<div>想定消耗时间</div>
<div>
<DurationPicker v-model="roomInfo.scenarioDetail.wasterTime" />
</div>
</a-col>
</a-row>
<Flex v-if="roomInfo.radioType === 'xdqy'" class="flex-1">
<div style="width: 150px">
<div>经纬度坐标</div>
<div>左上</div>
<a-input v-model="roomInfo.scenarioDetail.leftUpLon" style="width: 100%" />
<a-input v-model="roomInfo.scenarioDetail.leftUpLat" style="width: 100%" />
<div>右上</div>
<a-input v-model="roomInfo.scenarioDetail.rightUpLon" style="width: 100%" />
<a-input v-model="roomInfo.scenarioDetail.rightUpLat" style="width: 100%" />
<div>右下</div>
<a-input v-model="roomInfo.scenarioDetail.rightDownLon" style="width: 100%" />
<a-input v-model="roomInfo.scenarioDetail.rightDownLat" style="width: 100%" />
<div>左下</div>
<a-input v-model="roomInfo.scenarioDetail.leftDownLon" style="width: 100%" />
<a-input v-model="roomInfo.scenarioDetail.leftDownLat" style="width: 100%" />
</div>
<div class="flex-1" style="position: relative">
<div id="jwd-cesium" style="width: 100%; height: 100%"></div>
<div style="position: absolute; left: 0; top: 0; width: 100%; height: 100%"></div>
</div>
</Flex>
<a-row v-if="roomInfo.radioType === 'xdsm'" style="flex: 1; padding: 10px 16px; overflow-y: auto">
<a-col :span="12" class="flex ai-c">
<div>想定名称</div>
<div>{{ roomInfo.scenarioDetail.planName }}</div>
</a-col>
<a-col :span="12" class="flex ai-c">
<div>作者</div>
<div>{{ roomInfo.scenarioDetail.author }}</div>
</a-col>
<a-col :span="24">
<div>想定说明</div>
<div class="xdsm-wrapper">
<WangEditor v-model="roomInfo.scenarioDetail.planDesc" />
<!-- <iframe v-html="roomInfo.scenarioDetail.planDesc" frameborder="0"></iframe> -->
</div>
</a-col>
</a-row>
</Flex>
</Flex>
</ModuleWrapper>
<ModuleWrapper v-if="enterRoom" title="输入输出事件">
<template #extra>
<a-checkbox v-model="roomInfo.visibility">显示</a-checkbox>
</template>
<div class="io-event-list">
<div v-for="item in roomInfo.ioEventList" :key="item.id" class="io-event-item">
<span style="margin-right: 20px">{{ item.eventTime }}</span>
<span>{{ item.eventDesc }}</span>
</div>
</div>
</ModuleWrapper>
<a-modal
v-model="scenarioModal.visible"
title="选择想定"
@ -116,8 +227,17 @@ export default {
zzbzllLoading: false,
expandedKeys: [],
},
enterRoom: false,
roomInfo: {
roomId: '',
scenarioId: '',
runningMode: '1',
loading: false,
scenarioDetail: {},
radioType: 'xdsj',
cesium: null,
visibility: false,
ioEventList: [],
},
}
},
@ -130,6 +250,17 @@ export default {
systemPathMap: (state) => state.simulation.systemPathMap,
}),
},
watch: {
'roomInfo.radioType'(v) {
if (v === 'xdqy') {
this.$nextTick(() => {
this.initCesium()
})
} else {
this.roomInfo.cesium = null
}
},
},
created() {
this.getSystemModules()
this.getRoomList()
@ -253,6 +384,53 @@ export default {
},
handleJoinRoom(item) {
this.roomInfo.roomId = item.roomId
this.roomInfo.scenarioId = item.scenarioId
this.enterRoom = true
this.getScenarioDetail()
},
handleLeaveRoom() {
this.enterRoom = false
this.clearRoomInfo()
},
clearRoomInfo() {
this.roomInfo = {
roomId: '',
scenarioId: '',
runningMode: '1',
loading: false,
scenarioDetail: {},
radioType: 'xdsj',
cesium: null,
visibility: false,
ioEventList: [],
}
},
async getScenarioDetail() {
try {
this.roomInfo.loading = true
const res = await this.$http({
url: `/baseData/scenario/${this.roomInfo.scenarioId}`,
method: 'get',
})
this.roomInfo.scenarioDetail = JSON.parse(res.data.decodingContent)
} catch (error) {
console.log(error)
} finally {
this.roomInfo.loading = false
}
},
initCesium() {
const { leftUpLat, rightUpLat, rightDownLat, leftDownLat, leftUpLon, rightUpLon, rightDownLon, leftDownLon } =
this.roomInfo.scenarioDetail
const centerLon = (leftUpLon + rightUpLon + rightDownLon + leftDownLon) / 4
const centerLat = (leftUpLat + rightUpLat + rightDownLat + leftDownLat) / 4
this.roomInfo.cesium = new window.MyCesium('jwd-cesium', { center: [centerLon, centerLat] })
this.roomInfo.cesium.setViewerByAllCorner(
[leftUpLon, leftUpLat],
[rightUpLon, rightUpLat],
[rightDownLon, rightDownLat],
[leftDownLon, leftDownLat]
)
},
},
}
@ -356,65 +534,7 @@ export default {
}
}
.scenario-wrapper {
flex: 1;
width: 100%;
overflow: hidden;
margin-bottom: 20px;
}
.scenario-item {
position: relative;
cursor: pointer;
.scenario-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.scenario-mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.scenario-brief {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 60px;
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 1));
padding-left: 10px;
.scenario-name {
font-size: 20px;
line-height: 36px;
}
.scenario-author {
font-size: 12px;
line-height: 24px;
}
}
.scenario-reload {
position: absolute;
right: 20px;
bottom: 10px;
width: 40px;
height: 40px;
font-size: 40px;
line-height: 1;
display: none;
}
&:hover .scenario-reload {
display: block;
}
.scenario-reload:hover {
color: #00f2fe;
}
}
.scenario-info-wrapper {
flex: 1;
border: 1px solid #06445f;
background-color: #0f3b4f;
overflow: auto;

View File

@ -1,10 +1,93 @@
<template>
<div>txsjk</div>
<page-header-wrapper>
<Grid>
<a-card class="my-card">
<AntQueryTable
height="100%"
ref="tx-table"
:queryConfig="txTable.queryConfig"
:tableConfig="txTable.tableConfig"
:pageConfig="txTable.pageConfig"
:showTool="txTable.showTool"
>
<template #toolbar-left>
<a-button type="primary" icon="plus" @click="handleOpenAddModal">新增</a-button>
</template>
</AntQueryTable>
</a-card>
</Grid>
<AntFormModal
:visible.sync="AEModal.visible"
:title="AEModal.title"
:formItems="AEModal.formItems"
:formRules="AEModal.formRules"
:formData="AEModal.formData"
:onSubmit="handleSubmitAE"
@success="handleSubmitAESuccess"
></AntFormModal>
</page-header-wrapper>
</template>
<script>
export default {
name: 'Txsjk',
data() {
return {
txTable: {
queryConfig: false,
tableConfig: {
query: () => ({ data: [] }),
columns: [
{ dataIndex: 'serial' },
{ dataIndex: 'jbmc', title: '军标名称', width: 'auto' },
{ dataIndex: 'jblj', title: '军标路径', width: 'auto' },
{ dataIndex: 'tyf', title: '推演方', width: 'auto' },
],
},
pageConfig: false,
showTool: true,
},
AEModal: {
visible: false,
title: '新增图形',
formItems: [
{ label: '军标名称', prop: 'jbmc' },
{ label: '军标路径', prop: 'jblj' },
{
label: '推演方',
prop: 'tyf',
component: 'AntOriginSelect',
options: {
dataSource: () => ({
data: [
{ title: '红方', id: '1' },
{ title: '蓝方', id: '2' },
],
}),
},
},
],
formRules: {},
formData: {},
},
}
},
methods: {
handleOpenAddModal() {
this.AEModal.formData = {}
this.AEModal.visible = true
},
handleSubmitAE(formData) {
return this.$http({
url: '/tx/save',
method: 'post',
data: formData,
})
},
handleSubmitAESuccess() {
this.$refs['tx-table'].commitAction('query')
},
},
}
</script>

View File

@ -118,6 +118,14 @@ const vueConfig = {
'^/api': '',
},
},
'/map': {
target: 'http://localhost:8090/',
ws: false,
changeOrigin: true,
pathRewrite: {
'^/map': '',
},
},
},
},
publicPath: '/',