系统控制子模块选择想定,保障环境分页,仿真模型树形样式

This commit is contained in:
liaoboping 2025-08-25 16:27:04 +08:00
parent 4a6ca044ad
commit dbea954613
3 changed files with 178 additions and 229 deletions

View File

@ -17,7 +17,7 @@
</ModuleWrapper> </ModuleWrapper>
<ModuleWrapper title="全部房间" style="grid-column: 1 / 3"> <ModuleWrapper title="全部房间" style="grid-column: 1 / 3">
<template #extra> <template #extra>
<a-button type="primary">新建房间</a-button> <a-button type="primary" @click="handleOpenScenarioModal()">新建房间</a-button>
</template> </template>
<div class="normal flex-c ai-c" v-loading="room.loading"> <div class="normal flex-c ai-c" v-loading="room.loading">
<Grid class="room-wrapper" :columns="[1, 1, 1, 1, 1]" :rows="[1, 1]"> <Grid class="room-wrapper" :columns="[1, 1, 1, 1, 1]" :rows="[1, 1]">
@ -41,152 +41,59 @@
/> />
</div> </div>
</ModuleWrapper> </ModuleWrapper>
<ModuleWrapper v-if="!loadedScenario" title="全部想定" style="grid-column: 1 / 3"> <a-modal
<div class="normal flex-c ai-c" v-loading="loading"> v-model="scenarioModal.visible"
<Grid class="scenario-wrapper" :columns="[1, 1, 1, 1, 1]" :rows="[1, 1]"> title="选择想定"
<div v-for="item in scenarioList" :key="item.id" class="scenario-item"> width="900px"
<img :maskClosable="false"
class="scenario-image" :destroyOnClose="true"
:src="item.image || '/mockData/68ab3707-2552-4b78-bfc0-cec3502ec62f.png'" @ok="handleConfirmScenario()"
alt="" >
/> <Grid style="height: 600px" :columns="[1, 1]">
<div class="scenario-mask"></div> <ModuleWrapper title="想定列表">
<div class="scenario-brief"> <template #extra>
<div class="scenario-name">{{ item.name }}</div> <a-icon type="sync" style="font-size: 30px; color: #00deff" @click="getScenarioListData()" />
<div class="scenario-author">{{ item.author }}</div> </template>
</div> <div
<div class="scenario-reload" title="载入想定" @click="handleLoadSenario(item)"> class="normal"
<a-icon type="reload" /> v-loading="scenarioModal.scenarioLoading"
</div> style="background-color: white; padding: 20px 0; overflow: auto"
>
<a-tree
:treeData="scenarioModal.scenarioList"
:replaceFields="{ title: 'name', key: 'id' }"
:selectedKeys.sync="scenarioModal.selectedKeys"
@select="handleChangeScenarioSelected"
>
</a-tree>
</div> </div>
</Grid> </ModuleWrapper>
<a-pagination <ModuleWrapper title="作战/保障力量">
v-model="pagination.current" <template #extra>
:pageSize.sync="pagination.pageSize" <a-icon type="sync" style="font-size: 30px; color: #00deff" @click="getZzbzllTreeData()" />
:total="pagination.total" </template>
@change="getScenarioList" <div class="normal" v-loading="scenarioModal.zzbzllLoading" style="background-color: white; overflow: auto">
/> <a-tree
</div> :treeData="scenarioModal.zzbzllTree"
</ModuleWrapper> :replaceFields="{ title: 'name', key: 'id' }"
<ModuleWrapper v-if="loadedScenario" title="想定信息"> :selected="false"
<template #extra> :expandedKeys.sync="scenarioModal.expandedKeys"
<a-button type="primary" shape="circle" icon="close" @click="handleCloseSenario()" /> >
</template> </a-tree>
<div class="normal flex-c">
<div class="flex ai-c jc-sb" style="margin-bottom: 10px">
<div class="flex ai-c">
<div style="color: #92bacb">运行方式</div>
<a-select style="width: 240px" v-model="runningMode">
<a-select-option value="1">人在回路</a-select-option>
<a-select-option value="2">人不在回路</a-select-option>
</a-select>
</div> </div>
<div class="flex ai-c"> </ModuleWrapper>
<a-button type="primary" icon="caret-right">开始</a-button> </Grid>
<a-button type="primary" icon="pause">暂停</a-button> </a-modal>
<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>
</div>
</div>
<div class="scenario-info-wrapper flex-c">
<a-radio-group v-model="radioType" button-style="solid">
<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-show="radioType === 'xdsj'">
<a-col :span="24">
<div>想定当前时间</div>
<div>
<a-date-picker :value="scenarioDetail.planDate" valueFormat="YYYY-MM-DD" style="width: 100%" />
<a-time-picker :value="scenarioDetail.planTime" valueFormat="HH:mm:ss" style="width: 100%" />
</div>
</a-col>
<a-col :span="24">
<div>想定开始时间</div>
<div>
<a-date-picker :value="scenarioDetail.startDate" valueFormat="YYYY-MM-DD" style="width: 100%" />
<a-time-picker :value="scenarioDetail.startTime" valueFormat="HH:mm:ss" style="width: 100%" />
</div>
</a-col>
<a-col :span="24">
<div>想定持续时间</div>
<div>
<DurationPicker v-model="scenarioDetail.continueTime" />
</div>
</a-col>
<a-col :span="24">
<div>想定消耗时间</div>
<div>
<DurationPicker v-model="scenarioDetail.wasterTime" />
</div>
</a-col>
</a-row>
<div v-show="radioType === 'xdqy'" class="flex-1 flex">
<div style="width: 150px">
<div>经纬度坐标</div>
<div>左上</div>
<a-input v-model="scenarioDetail.leftUpLon" style="width: 100%" />
<a-input v-model="scenarioDetail.leftUpLat" style="width: 100%" />
<div>右上</div>
<a-input v-model="scenarioDetail.rightUpLon" style="width: 100%" />
<a-input v-model="scenarioDetail.rightUpLat" style="width: 100%" />
<div>右下</div>
<a-input v-model="scenarioDetail.rightDownLon" style="width: 100%" />
<a-input v-model="scenarioDetail.rightDownLat" style="width: 100%" />
<div>左下</div>
<a-input v-model="scenarioDetail.leftDownLon" style="width: 100%" />
<a-input v-model="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>
</div>
<a-row v-show="radioType === 'xdsm'" style="flex: 1; padding: 10px 16px; overflow-y: auto">
<a-col :span="12" class="flex ai-c">
<div>想定名称</div>
<div>{{ scenarioDetail.planName }}</div>
</a-col>
<a-col :span="12" class="flex ai-c">
<div>作者</div>
<div>{{ scenarioDetail.author }}</div>
</a-col>
<a-col :span="24">
<div>想定说明</div>
<div class="xdsm-wrapper">
<WangEditor v-model="scenarioDetail.planDesc" />
<!-- <iframe v-html="scenarioDetail.planDesc" frameborder="0"></iframe> -->
</div>
</a-col>
</a-row>
</div>
</div>
</ModuleWrapper>
<ModuleWrapper v-if="loadedScenario" title="输入输出事件">
<template #extra>
<a-checkbox v-model="visible">显示</a-checkbox>
</template>
<div class="io-event-list">
<div v-for="item in ioEventList" :key="item.id" class="io-event-item">
<span style="margin-right: 20px">{{ item.eventTime }}</span>
<span>{{ item.eventDesc }}</span>
</div>
</div>
</ModuleWrapper>
</Grid> </Grid>
</template> </template>
<script> <script>
import { mapActions, mapState } from 'vuex' import { mapState, mapActions } from 'vuex'
export default { export default {
name: 'SimulationSceneCentralControl', name: 'SimulationSceneCentralControl',
data() { data() {
return { return {
ws: null,
room: { room: {
list: [], list: [],
loading: false, loading: false,
@ -196,33 +103,18 @@ export default {
total: 0, total: 0,
}, },
}, },
scenarioModal: {
scenario: { visible: false,
list: [], scenarioList: [],
scenarioLoading: false,
selectedKeys: [],
zzbzllTree: [],
zzbzllLoading: false,
expandedKeys: [],
}, },
roomInfo: {
scenarioList: [], roomId: '',
loading: false,
loadedScenario: '',
pagination: {
current: 1,
pageSize: 10,
total: 0,
}, },
runningMode: '1',
radioType: 'xdsj',
scenarioDetail: {},
cesium: null,
visible: false,
ioEventList: [
{
id: '1',
eventTime: '2021-06-26 11:50:35',
eventDesc: '加载数据中,请稍后',
},
],
} }
}, },
computed: { computed: {
@ -235,22 +127,11 @@ export default {
}), }),
}, },
created() { created() {
this.initWebsocket()
this.getSystemModules() this.getSystemModules()
this.getRoomList() this.getRoomList()
this.getScenarioList()
},
beforeDestroy() {
this.ws.close()
}, },
methods: { methods: {
...mapActions(['getSystemModules']), ...mapActions(['getSystemModules']),
initWebsocket() {
this.ws = new window.MyWebsocket('/', (error, data) => {
if (error) return
console.log('----data----', data)
})
},
async getRoomList() { async getRoomList() {
try { try {
this.loading = true this.loading = true
@ -270,58 +151,103 @@ export default {
this.loading = false this.loading = false
} }
}, },
handleJoinRoom(item) {}, handleOpenScenarioModal() {
async getScenarioList() { this.scenarioModal.visible = true
setTimeout(() => {
this.getScenarioListData()
}, 100)
},
async getScenarioListData() {
try { try {
this.loading = true this.scenarioModal.scenarioLoading = true
const res = await this.$http({ const res = await this.$http({
url: '/baseData/scenario/list', url: `/baseData/scenario/all`,
method: 'get', method: 'get',
params: {
pageNum: this.pagination.current,
pageSize: this.pagination.pageSize,
},
}) })
this.scenarioList = res.data.data this.scenarioModal.scenarioList = res.data
this.pagination.total = res.data.totalCount
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} finally { } finally {
this.loading = false this.scenarioModal.scenarioLoading = false
} }
}, },
async handleLoadSenario(item) { handleChangeScenarioSelected() {
this.getZzbzllTreeData()
},
async getZzbzllTreeData() {
try { try {
this.scenarioModal.zzbzllLoading = true
const res = await this.$http({ const res = await this.$http({
url: `/baseData/scenario/${item.id}`, url: `/scenario/power/${this.scenarioModal.selectedKeys[0]}`,
method: 'get', method: 'get',
}) })
this.scenarioDetail = JSON.parse(res.data.content) this.scenarioModal.zzbzllTree = [
console.log('----', this.scenarioDetail) {
this.loadedScenario = item.id id: '1',
this.$nextTick(() => { name: '红方',
this.initCesium() children: [
{ id: '1-1', name: '作战力量', children: res.data.red.fight },
{ id: '1-2', name: '保障力量', children: res.data.red.guarantee },
{ id: '1-3', name: '指挥力量', children: res.data.red.command },
],
},
{
id: '2',
name: '蓝方',
children: [
{ id: '2-1', name: '作战力量', children: res.data.blue.fight },
{ id: '2-2', name: '保障力量', children: res.data.blue.guarantee },
{ id: '2-3', name: '指挥力量', children: res.data.blue.command },
],
},
]
this.scenarioModal.expandedKeys = ['1', '1-1', '1-2', '1-3', '2', '2-1', '2-2', '2-3']
} catch (error) {
console.log(error)
} finally {
this.scenarioModal.zzbzllLoading = false
}
},
async handleConfirmScenario() {
const scenarioId = this.scenarioModal.selectedKeys[0]
if (!scenarioId) {
return this.$message.warning('请先选择想定!')
}
try {
this.$message.info('正在创建新房间,请稍候')
const res = await this.$http({
url: '/room/scenario/create',
method: 'get',
params: { id: scenarioId },
}) })
this.scenarioModal.visible = false
this.clearScenarioModal()
const shifou = await new Promise((resolve) => {
this.$confirm({
content: `创建新房间成功,房间编号${res.data.roomCode},是否立即进入?`,
onOk() {
resolve(true)
},
onCancel() {
resolve(false)
},
})
})
if (shifou) {
this.handleJoinRoom(res.data)
}
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
}, },
initCesium() { clearScenarioModal() {
const { leftUpLat, rightUpLat, rightDownLat, leftDownLat, leftUpLon, rightUpLon, rightDownLon, leftDownLon } = this.scenarioModal.scenarioList = []
this.scenarioDetail this.scenarioModal.selectedKeys = []
const centerLon = (leftUpLon + rightUpLon + rightDownLon + leftDownLon) / 4 this.scenarioModal.zzbzllTree = []
const centerLat = (leftUpLat + rightUpLat + rightDownLat + leftDownLat) / 4 this.scenarioModal.expandedKeys = []
this.cesium = new window.MyCesium('jwd-cesium', { center: [centerLon, centerLat] })
this.cesium.setViewerByAllCorner(
[leftUpLon, leftUpLat],
[rightUpLon, rightUpLat],
[rightDownLon, rightDownLat],
[leftDownLon, leftDownLat]
)
}, },
handleCloseSenario() { handleJoinRoom(item) {
this.loadedScenario = '' this.roomInfo.roomId = item.roomId
}, },
}, },
} }

View File

@ -106,11 +106,11 @@ export default {
tableConfig: { tableConfig: {
table: {}, table: {},
immediate: false, immediate: false,
query: () => query: (queryParams) =>
this.$http({ this.$http({
url: `/environment/weather/list`, url: `/environment/weather/list`,
method: 'get', method: 'get',
params: { id: this.xd.selectedKeys[0] }, params: { id: this.xd.selectedKeys[0], ...queryParams },
}), }),
columns: [ columns: [
{ dataIndex: 'serial' }, { dataIndex: 'serial' },
@ -167,11 +167,11 @@ export default {
tableConfig: { tableConfig: {
table: {}, table: {},
immediate: false, immediate: false,
query: () => query: (queryParams) =>
this.$http({ this.$http({
url: `/environment/ebe/list`, url: `/environment/ebe/list`,
method: 'get', method: 'get',
params: { id: this.xd.selectedKeys[0] }, params: { id: this.xd.selectedKeys[0], ...queryParams },
}), }),
columns: [ columns: [
{ dataIndex: 'serial' }, { dataIndex: 'serial' },

View File

@ -1,8 +1,15 @@
<template> <template>
<Grid class="simulation-model-page" :columns="['320px', 1, '320px']" :rows="[45, 15, 40]" gap="0px"> <Grid class="simulation-model-page" :columns="['320px', 1, '320px']" :rows="[45, 15, 40]" gap="0px">
<ModuleWrapper title="作战/保障力量" style="grid-column: 1 / 2; grid-row: 1 / 2"> <ModuleWrapper title="作战/保障力量" style="grid-column: 1 / 2; grid-row: 1 / 2">
<div class="normal" style="padding: 5px"> <div class="normal" style="padding: 5px; overflow-y: auto">
<a-tree :treeData="zb.zbTreeData"> </a-tree> <a-tree
class="simulation-tree"
:treeData="zb.zbTreeData"
:selectedKeys.sync="zb.selectedKeys"
:replaceFields="{ children: 'children', title: 'name', key: 'id' }"
@select="handleSelectTree"
>
</a-tree>
</div> </div>
</ModuleWrapper> </ModuleWrapper>
<ModuleWrapper style="grid-column: 1 / 2; grid-row: 2 / 4"> <ModuleWrapper style="grid-column: 1 / 2; grid-row: 2 / 4">
@ -57,38 +64,39 @@ export default {
zb: { zb: {
zbTreeData: [ zbTreeData: [
{ {
key: '1', id: '1',
title: '红方', name: '红方',
children: [ children: [
{ {
key: '1-1', id: '1-1',
title: '作战力量', name: '作战力量',
children: [ children: [
{ key: '1-1-1', title: '左翼夺控群火力分队' }, { id: '1-1-1', name: '左翼夺控群火力分队' },
{ key: '1-1-2', title: '左翼攻击分队' }, { id: '1-1-2', name: '左翼攻击分队' },
{ key: '1-1-3', title: '右翼攻击分队' }, { id: '1-1-3', name: '右翼攻击分队' },
{ key: '1-1-4', title: '右翼夺控群反装甲分队' }, { id: '1-1-4', name: '右翼夺控群反装甲分队' },
{ key: '1-1-5', title: '防空火力队' }, { id: '1-1-5', name: '防空火力队' },
{ key: '1-1-6', title: '左翼牵制群右翼攻击分队' }, { id: '1-1-6', name: '左翼牵制群右翼攻击分队' },
{ key: '1-1-7', title: '电子对抗兵队超短波干扰分队' }, { id: '1-1-7', name: '电子对抗兵队超短波干扰分队' },
{ key: '1-1-8', title: '纵深夺控群火力分队' }, { id: '1-1-8', name: '纵深夺控群火力分队' },
], ],
}, },
{ {
key: '1-2', id: '1-2',
title: '保障力量', name: '保障力量',
}, },
], ],
}, },
{ {
key: '2', id: '2',
title: '蓝方', name: '蓝方',
children: [ children: [
{ key: '1-1', title: '作战力量' }, { id: '1-1', name: '作战力量' },
{ key: '1-2', title: '保障力量' }, { id: '1-2', name: '保障力量' },
], ],
}, },
], ],
selectedKeys: [],
}, },
qd: { qd: {
qdlx: 'xqqd', qdlx: 'xqqd',
@ -132,6 +140,9 @@ export default {
mounted() { mounted() {
this.cesium = new window.MyCesium('cesium-container') this.cesium = new window.MyCesium('cesium-container')
}, },
methods: {
handleSelectTree() {},
},
} }
</script> </script>
@ -139,6 +150,18 @@ export default {
.simulation-model-page { .simulation-model-page {
padding-top: 20px; padding-top: 20px;
} }
.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;
}
}
.image { .image {
width: 100%; width: 100%;
padding: 20px; padding: 20px;