LSSE-front/src/views/simulationScene/sceneEditing/index.vue

616 lines
23 KiB
Vue
Raw Normal View History

2025-08-06 19:10:12 +08:00
<template>
2025-08-19 10:52:32 +08:00
<Grid class="scene-editing-page" :columns="['320px', 1, '320px']" :rows="[45, 30, 25]" gap="0px">
<ModuleWrapper title="作战/保障力量" style="grid-column: 1 / 2; grid-row: 1 / 2">
2025-08-16 10:13:46 +08:00
<div class="normal" style="padding: 5px; overflow-y: auto">
<a-tree
2025-08-16 18:25:01 +08:00
class="simulation-tree"
2025-08-16 10:13:46 +08:00
:treeData="zb.zbTreeData"
:selectedKeys.sync="zb.selectedKeys"
:replaceFields="{ children: 'children', title: 'name', key: 'id' }"
@select="handleSelectTree"
></a-tree>
</div>
</ModuleWrapper>
<ModuleWrapper title="装备元素" style="grid-column: 1 / 2; grid-row: 2 / 4">
2025-08-16 10:13:46 +08:00
<div class="normal flex-c" style="padding: 5px">
<a-input-search v-model="ys.keyword" placeholder="输入关键词搜索..." @search="onSearch" />
<div style="height: 0; flex: 1; overflow-y: auto">
<a-row>
<template v-for="item in ys.ysList">
<a-col :key="item.id" :span="24">{{ item.title }}</a-col>
2025-08-16 10:13:46 +08:00
<a-col v-for="it in item.children" :key="it.id" :span="12" class="flex-c ai-c">
<img class="ys-image" :src="it.image" alt="" />
<span>{{ it.title }}</span>
</a-col>
</template>
</a-row>
</div>
</div>
</ModuleWrapper>
<div
class="cesium-container"
id="cesium-container"
style="grid-column: 2 / 3; grid-row: 1 / 7; overflow: hidden"
></div>
2025-08-16 18:25:01 +08:00
<ModuleWrapper style="grid-column: 3 / 4; grid-row: 1 / 4">
<template #title>
<a-radio-group v-model="right.radioType" button-style="solid">
<a-radio-button value="jcsx">基础属性</a-radio-button>
<a-radio-button value="zzxd">作战行动</a-radio-button>
<a-radio-button value="dzsx">单装属性</a-radio-button>
</a-radio-group>
</template>
<div class="normal" style="padding: 15px 0">
<div style="height: 100%; padding: 0 15px; overflow-y: auto">
2025-08-16 18:25:01 +08:00
<div v-if="right.radioType === 'jcsx'">
<a-collapse class="simulation-collapse" :defaultActiveKey="['1', '2', '3', '4', '5', '6', '7', '8', '9']">
<a-collapse-panel class="simulation-collapse-item" key="1" header="基础信息">
<img class="image" :src="right.detail.image || '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png'" />
<div class="name">
{{ right.detail.name }}
<a-button type="text-primary" icon="edit" @click="handleOpenMcModal"></a-button>
</div>
2025-08-16 18:25:01 +08:00
<div class="zt-item flex ai-c jc-sb">
<span style="min-width: 100px">推演方</span>
<a-select
style="width: 120px"
class="simulation-select"
defaultValue="1"
dropdownClassName="simulation-select-dropdown"
>
<a-select-option value="1">红方</a-select-option>
<a-select-option value="2">蓝方</a-select-option>
</a-select>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">类型</span>
<span></span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">方向</span>
<span></span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">速度</span>
<span>{{ right.detail.position.speed }} 公里/</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">经度</span>
<span class="flex-1">{{ right.detail.position.lng | lonFormat }}</span>
<a-button type="text-primary" icon="edit" @click="handleOpenLonlatModal"></a-button>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">纬度</span>
<span class="flex-1">{{ right.detail.position.lat | latFormat }}</span>
<a-button type="text-primary" icon="edit" @click="handleOpenLonlatModal"></a-button>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">高度/深度</span>
<span class="flex-1">{{ right.detail.position.height | numberFormat }} (海拔)</span>
<a-button type="text-primary" icon="edit" @click="handleOpenHdModal()"></a-button>
2025-08-16 18:25:01 +08:00
</div>
</a-collapse-panel>
<a-collapse-panel class="simulation-collapse-item" key="2" header="人员状态属性">
<div class="zt-item flex ai-c">
<span style="min-width: 100px">人员编制数</span>
<span>{{ right.detail.personStatistic.total }} </span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">当前人数</span>
<span>{{ right.detail.personStatistic.current }} </span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">死亡人数</span>
<span>{{ right.detail.personStatistic.death }} </span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">受伤人数</span>
<span>{{ right.detail.personStatistic.injured }} </span>
2025-08-16 18:25:01 +08:00
</div>
</a-collapse-panel>
<a-collapse-panel class="simulation-collapse-item" key="3" header="野战食品状态属性">
<div class="zt-item flex ai-c">
<span style="min-width: 100px">野战食物初始量()</span>
<span>{{ right.detail.foodInfo.startNum }}</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">野战食物当前量()</span>
<span>{{ right.detail.foodInfo.currentNum }}</span>
2025-08-16 18:25:01 +08:00
</div>
</a-collapse-panel>
<a-collapse-panel class="simulation-collapse-item" key="4" header="用水状态属性">
<div class="zt-item flex ai-c">
<span style="min-width: 100px">用水初始量()</span>
<span>{{ right.detail.waterInfo.startNum }}</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">用水当前量()</span>
<span>{{ right.detail.waterInfo.currentNum }}</span>
2025-08-16 18:25:01 +08:00
<span></span>
</div>
</a-collapse-panel>
<a-collapse-panel class="simulation-collapse-item" key="5" header="油料状态属性">
<div class="zt-item flex ai-c">
<span style="min-width: 100px">油料初始量()</span>
<span>{{ right.detail.oilInfo.startNum }}</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">油料当前量()</span>
<span>{{ right.detail.oilInfo.currentNum }}</span>
2025-08-16 18:25:01 +08:00
</div>
</a-collapse-panel>
<a-collapse-panel class="simulation-collapse-item" key="6" header="药材状态属性">
<div class="zt-item flex ai-c">
<span style="min-width: 100px">药材初始量()</span>
<span>{{ right.detail.medicalInfo.startNum }}</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">药材当前量()</span>
<span>{{ right.detail.medicalInfo.currentNum }}</span>
2025-08-16 18:25:01 +08:00
</div>
</a-collapse-panel>
<a-collapse-panel class="simulation-collapse-item" key="7" header="武器弹药状态属性">
<div class="zt-item flex ai-c">
<span style="min-width: 100px">轻武器弹药量()</span>
<span>{{ right.detail.ammunition.lightArms }}</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">压制武器弹药量()</span>
<span>{{ right.detail.ammunition.suppressing }}</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">反坦克武器弹药量()</span>
<span>{{ right.detail.ammunition.antiTank }}</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">防空反导武器弹药量()</span>
<span>{{ right.detail.ammunition.antiAircraft }}</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">布扫雷装备弹药量()</span>
<span>{{ right.detail.ammunition.mineLaying }}</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">爆破器材弹药量()</span>
<span>{{ right.detail.ammunition.explosiveDevice }}</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">烟火装备弹药量()</span>
<span>{{ right.detail.ammunition.smokeDevice }}</span>
2025-08-16 18:25:01 +08:00
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">防化消耗弹药量()</span>
<span>{{ right.detail.ammunition.antiChemical }}</span>
2025-08-16 18:25:01 +08:00
</div>
</a-collapse-panel>
<a-collapse-panel class="simulation-collapse-item" key="8" header="保障标准信息">
<div class="zt-item flex ai-c jc-sb">
<span style="min-width: 100px">保障分配类型</span>
<a-select
style="width: 120px"
class="simulation-select"
defaultValue="1"
dropdownClassName="simulation-select-dropdown"
>
<a-select-option value="1">自动分配</a-select-option>
<a-select-option value="2">手动分配</a-select-option>
</a-select>
</div>
</a-collapse-panel>
<a-collapse-panel class="simulation-collapse-item" key="9" header="保障配置">
<div class="zt-item flex ai-c jc-sb">
<a-button type="primary">兵力编组</a-button>
<a-button type="primary">关注</a-button>
</div>
</a-collapse-panel>
</a-collapse>
</div>
<div v-if="right.radioType === 'zzxd'">
<div class="zzxd-wrapper flex-v">
<div class="zzxd-header">
<div class="zzxd-title">作战行动</div>
<div>
<a-button type="text-primary" icon="menu"></a-button>
<a-button type="text-primary" icon="plus"></a-button>
<a-button type="text-primary" icon="edit"></a-button>
<a-button type="text-primary" icon="delete"></a-button>
</div>
</div>
<div class="flex-1">
<a-steps progress-dot :current="1" direction="vertical">
<a-step
v-for="item in right.detail.actionList"
:key="item.id"
:title="item.typeName"
:description="`开始时间:${item.beginDateTime}. 结束时间:${item.endDateTime}`"
/>
</a-steps>
</div>
</div>
</div>
<div v-if="right.radioType === 'dzsx'">
<div>
<a-collapse>
<a-collapse-panel v-for="item in right.detail.equipmentList" :key="item.id" :header="item.name">
<a-collapse>
<a-collapse-panel header="无损伤">
<div v-for="(value, label) in item.equipmentParts" :key="label">
<span>{{ label }}{{ value }}</span>
</div>
</a-collapse-panel>
</a-collapse>
</a-collapse-panel>
</a-collapse>
</div>
</div>
</div>
</div>
</ModuleWrapper>
<a-modal v-model="mcModal.visible" title="编辑单元名称" :maskClosable="false" width="400px" @ok="handleSubmilMc">
<a-row>
<a-col :span="6">
<span>名称</span>
</a-col>
<a-col :span="18">
<a-input v-model="mcModal.mc" style="width: 100%" />
</a-col>
</a-row>
</a-modal>
<a-modal
v-model="lonlatModal.visible"
title="修改单元经纬度"
:maskClosable="false"
width="600px"
@ok="handleSubmilLonlat"
>
2025-08-16 18:25:01 +08:00
<LonLatInput :lon.sync="lonlatModal.lon" :lat.sync="lonlatModal.lat" />
</a-modal>
<a-modal
v-model="hdModal.visible"
title="设置单元高度/深度"
:maskClosable="false"
width="400px"
@ok="handleSubmilHd"
>
<a-row>
<a-col :span="12">
<span>高度/深度</span>
</a-col>
<a-col :span="12">
<a-input-number v-model="hdModal.hd" :min="0" style="width: 100%" />
</a-col>
</a-row>
</a-modal>
2025-08-19 10:52:32 +08:00
</Grid>
2025-08-06 19:10:12 +08:00
</template>
<script>
2025-08-16 18:25:01 +08:00
import LonLatInput from './components/LonLatInput.vue'
2025-08-06 19:10:12 +08:00
export default {
name: 'SimulationSceneSceneEditing',
2025-08-16 18:25:01 +08:00
components: {
LonLatInput,
},
filters: {
numberFormat(v) {
if (typeof v === 'number' && v) {
return +v.toFixed(2)
} else {
return v
}
},
lonFormat(v) {
const originValue = Number(v)
if (originValue) {
let result = ''
result += originValue > 0 ? '东经 ' : '西经 '
const num = Math.abs(originValue)
const d = Math.floor(num)
result += `${d}°`
const m = Math.floor(num * 60) % 60
result += `${m}`
const s = Math.floor(num * 3600) % 60
result += `${s}`
return result
} else {
return '0°00″'
}
},
latFormat(v) {
const originValue = Number(v)
if (originValue) {
let result = ''
result += originValue > 0 ? '北纬 ' : '南纬 '
const num = Math.abs(originValue)
const d = Math.floor(num)
result += `${d}°`
const m = Math.floor(num * 60) % 60
result += `${m}`
const s = Math.floor(num * 3600) % 60
result += `${s}`
return result
} else {
return '0°00″'
}
},
},
data() {
return {
cesium: null,
2025-08-16 10:13:46 +08:00
scenarioId: null,
zb: { zbTreeData: [], selectedKeys: [] },
ys: {
keyword: '',
ysList: [
{
id: '1',
title: '红方',
children: [
{ id: '1-1', title: '反坦克导弹', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '1-2', title: '红箭10反坦克导弹', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '1-3', title: '装甲突击车', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '1-4', title: 'VT5坦克', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '1-5', title: '餐饮车', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '1-6', title: '物资运输车', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '1-7', title: '油罐车', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '1-8', title: '雷达车', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
],
},
{
id: '2',
title: '蓝方',
children: [
{ id: '2-1', title: '反坦克导弹', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '2-2', title: '红箭10反坦克导弹', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '2-3', title: '装甲突击车', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '2-4', title: 'VT5坦克', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '2-5', title: '餐饮车', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '2-6', title: '物资运输车', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '2-7', title: '油罐车', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
{ id: '2-8', title: '雷达车', image: '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png' },
],
},
],
},
2025-08-16 18:25:01 +08:00
right: {
radioType: 'jcsx',
detail: {
2025-08-16 18:25:01 +08:00
position: {},
personStatistic: {},
foodInfo: {},
waterInfo: {},
oilInfo: {},
medicalInfo: {},
ammunition: {},
actionList: [],
equipmentList: [],
2025-08-16 18:25:01 +08:00
},
},
mcModal: {
visible: false,
mc: '',
},
2025-08-16 18:25:01 +08:00
lonlatModal: {
visible: false,
lon: 0,
lat: 0,
},
hdModal: {
visible: false,
hd: 0,
},
}
},
mounted() {
this.cesium = new window.MyCesium('cesium-container')
2025-08-16 10:13:46 +08:00
this.scenarioId = 2733
this.getZbTree()
},
methods: {
2025-08-16 10:13:46 +08:00
async getZbTree() {
try {
const res = await this.$http({
url: `/scenario/power/${this.scenarioId}`,
method: 'get',
})
this.zb.zbTreeData = [
{
id: '1',
name: '红方',
selectable: false,
children: [
{ id: '1-1', name: '作战力量', selectable: false, children: res.data.red.fight },
{ id: '1-2', name: '保障力量', selectable: false, children: res.data.red.guarantee },
{ id: '1-3', name: '指挥力量', selectable: false, children: res.data.red.command },
],
},
{
id: '2',
name: '蓝方',
selectable: false,
children: [
{ id: '2-1', name: '作战力量', selectable: false, children: res.data.red.fight },
{ id: '2-2', name: '保障力量', selectable: false, children: res.data.red.guarantee },
{ id: '2-3', name: '指挥力量', selectable: false, children: res.data.red.command },
],
},
]
} catch (error) {
console.log(error)
}
},
handleSelectTree(selectedKeys, { node }) {
this.right.detail = node.dataRef
2025-08-16 10:13:46 +08:00
},
onSearch(e) {
console.log('----', e, e.target.value)
},
handleOpenMcModal() {
this.mcModal.mc = this.right.detail.name
this.mcModal.visible = true
},
async handleSubmilMc() {
try {
this.$http({
url: '/save',
method: 'post',
data: {
mc: this.mcModal.mc,
},
})
this.$message('编辑单元名称成功')
this.right.detail.name = this.mcModal.mc
this.mcModal.visible = false
} catch (error) {
console.log(error)
}
},
handleOpenLonlatModal() {
this.lonlatModal.lon = Number(this.right.detail.position.lng) || 0
this.lonlatModal.lat = Number(this.right.detail.position.lat) || 0
2025-08-16 18:25:01 +08:00
this.lonlatModal.visible = true
},
async handleSubmilLonlat() {
try {
this.$http({
url: '/save',
method: 'post',
data: {
lon: this.lonlatModal.lon,
lat: this.lonlatModal.lat,
},
})
this.$message('修改单元经纬度成功')
this.right.detail.position.lng = '' + this.lonlatModal.lon
this.right.detail.position.lat = '' + this.lonlatModal.lat
this.lonlatModal.visible = false
} catch (error) {
console.log(error)
}
},
handleOpenHdModal() {
this.hdModal.hd = Number(this.right.detail.position.height) || 0
this.hdModal.visible = true
},
async handleSubmilHd() {
try {
this.$http({
url: '/save',
method: 'post',
data: {
hd: this.hdModal.hd,
},
})
this.$message('修改单元高度/深度成功')
this.right.detail.position.height = this.hdModal.hd
this.hdModal.visible = false
} catch (error) {
console.log(error)
}
},
},
2025-08-06 19:10:12 +08:00
}
</script>
<style lang="less" scoped>
.scene-editing-page {
padding-top: 20px;
}
2025-08-16 18:25:01 +08:00
.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;
}
}
.ys-image {
width: 74px;
height: 62px;
object-fit: cover;
margin: 16px 0 8px;
}
2025-08-16 18:25:01 +08:00
.simulation-collapse::v-deep {
background-color: transparent;
color: #bbdded;
font-size: 16px;
line-height: 30px;
border: none;
}
.simulation-collapse-item::v-deep {
.ant-collapse-content {
background-color: transparent;
color: #bbdded;
border-top-color: #00baff66;
> .ant-collapse-content-box {
padding: 15px 0 5px;
}
}
}
.simulation-collapse > .simulation-collapse-item::v-deep {
border: none;
> .ant-collapse-header {
padding: 0;
color: #00baff;
font-size: 16px;
line-height: 38px;
display: flex;
align-items: center;
flex-direction: row-reverse;
justify-content: space-between;
.ant-collapse-arrow {
position: initial;
font-size: 16px;
transform: translateY(0);
}
}
}
.image {
width: 100%;
padding: 20px;
background-color: #0c3040;
}
.name {
color: #00baff;
text-decoration: underline;
font-size: 16px;
}
2025-08-16 18:25:01 +08:00
.simulation-select::v-deep {
.ant-select-selection {
background-color: #10475f;
border: solid 1px #1d5777;
color: #bbdded;
}
.ant-select-arrow {
color: #bbdded;
2025-08-12 09:24:09 +08:00
}
}
2025-08-16 18:25:01 +08:00
</style>
<style lang="less">
.simulation-select-dropdown {
background-color: #10475f;
border: solid 1px #1d5777;
.ant-select-dropdown-menu-item {
color: #bbdded;
}
.ant-select-dropdown-menu-item-selected {
background-color: #bbdded33;
color: #ffffff;
font-weight: normal;
}
.ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled) {
background-color: #bbdded33;
color: #ffffff;
}
}
</style>