LSSE-front/src/views/subsystem/scene/presetting.vue
wangwenhua 53cacb507c a
2025-09-26 19:44:54 +08:00

708 lines
23 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<Flex fd="co" class="page-scene-presetting">
<Flex ai="c" jc="sb" class="page-scene-presetting-header">
<span class="page-scene-presetting-title">场景编辑子系统</span>
<span class="page-scene-presetting-title">
编辑想定{{ scenarioId }}-{{ scenarioName }}
<a-popover v-if="scenarioDetail" title="想定信息">
<template slot="content">
<div>
<Flex>
<span>开始时间:</span>
<span style="max-width: 200px">{{ scenarioDetail.startTime }}</span>
</Flex>
<Flex>
<span>结束时间:</span>
<span style="max-width: 200px">{{ scenarioDetail.endTime }}</span>
</Flex>
<Flex>
<span>想定说明:</span>
<span style="max-width: 200px">{{ scenarioDetail.mark }}</span>
</Flex>
</div>
</template>
<a-button type="text-primary" icon="exclamation-circle"></a-button>
</a-popover>
</span>
<span class="page-scene-presetting-title" style="color: transparent">场景编辑子系统</span>
</Flex>
<Grid class="page-scene-presetting-main flex-1 oh" :columns="['320px', 1, '320px']" :rows="['30px', 1]" gap="0px">
<div class="tool_btn" style="grid-area: 1 / 1 / 2 / 4">
<a-menu :selectedKeys="[]" mode="horizontal" theme="dark">
<a-menu-item @click="handleOpenGuaranteeProcessPage()"> 保障流程 </a-menu-item>
</a-menu>
</div>
<div
ref="scene-presetting-cesium-container"
class="scene-presetting-cesium-container"
id="scene-presetting-cesium-container"
style="grid-area: 2 / 1 / 3 / 4"
></div>
<div class="pr zi1" style="grid-area: 2 / 1 / 3 / 2">
<ModuleWrapper title="作战/保障力量" height="45%">
<template #extra>
<a-button type="text-primary" icon="sync" style="font-size: 20px" @click="getZzbzllTreeData()"></a-button>
</template>
<div v-loading.dark="zzbzll.loading" class="normal" style="padding: 5px; overflow-y: auto">
<a-tree
class="simulation-tree"
:treeData="zzbzll.treeData"
:selectedKeys.sync="zzbzll.selectedKeys"
:replaceFields="{ children: 'children', title: 'title', key: 'id' }"
@select="handleSelectZzbzll"
>
<template #title="{ id, dataRef }">
<a-dropdown :trigger="['contextmenu']">
<span>{{ dataRef.resourceName || dataRef.title }}</span>
<template #overlay>
<Flex>
<a-button
type="text-primary"
icon="edit"
title="修改名称"
@click="handleOpenEditZzbzllModal(id, dataRef)"
></a-button>
<AntFormModal
:visible.sync="zzbzllModal.visible"
:title="zzbzllModal.title"
:formItems="zzbzllModal.formItems"
:formRules="zzbzllModal.formRules"
:formData="zzbzllModal.formData"
:onSubmit="handleSubmitZzbzll"
@success="handleSubmitZzbzllSuccess"
></AntFormModal>
<a-button
type="text-danger"
icon="delete"
title="删除"
@click="handleDeleteZzbzll(id, dataRef)"
></a-button>
</Flex>
</template>
</a-dropdown>
</template>
</a-tree>
</div>
</ModuleWrapper>
<ModuleWrapper title="天气预设" height="25%">
<div>
<a-button type="primary" @click="handleAdd" icon="plus">新增</a-button>
<a-table
:columns="columns"
:dataSource="this.weatherData"
:pagination="false"
bordered
rowKey="key"
>
<!-- <template v-for="col in columns" :slot="col" slot-scope="text, record">-->
<!-- <div :key="col">-->
<!-- <a-input-->
<!-- v-if="record.editable"-->
<!-- :value="text"-->
<!-- @change="e => handleChange(e.target.value, record.key, col)"-->
<!-- />-->
<!-- <template v-else>{{ text }}</template>-->
<!-- </div>-->
<!-- </template>-->
<!-- <template slot="operation" slot-scope="text, record">-->
<!-- <template v-if="record.editable">-->
<!-- <a @click="save(record.key)">保存</a>-->
<!-- <a-divider type="vertical" />-->
<!-- <a @click="cancel(record.key)">取消</a>-->
<!-- </template>-->
<!-- <template v-else>-->
<!-- <a @click="edit(record.key)">编辑</a>-->
<!-- <a-divider type="vertical" />-->
<!-- <a-popconfirm title="确认删除?" @confirm="() => handleDelete(record.key)">-->
<!-- <a>删除</a>-->
<!-- </a-popconfirm>-->
<!-- </template>-->
<!-- </template>-->
</a-table>
</div>
</ModuleWrapper>
<ModuleWrapper height="30%">
<template #title>
<a-radio-group v-model="fd.type" button-style="solid" @change="getFdListData">
<a-radio-button :value="5">作战分队</a-radio-button>
<a-radio-button :value="6">保障分队</a-radio-button>
</a-radio-group>
</template>
<template #extra>
<AntOriginSelect v-model="fd.teamType" :dataSource="forceSource" width="80px" @change="getFdListData" />
</template>
<Flex v-loading.dark="fd.loading" class="normal" fd="co" style="padding: 5px">
<Flex class="flex-1 scroller-y" fw="w" ac="fs">
<Flex v-for="item in fd.listData" :key="item.id" class="fd-item" fd="co" ai="c">
<img class="fd-image" :src="item.imgBase64" :draggable="true" @dragend="dragend(item, $event)" />
<span class="fd-name">{{ item.name }}</span>
</Flex>
</Flex>
</Flex>
</ModuleWrapper>
</div>
<Grid class="pr zi1" :rows="rightRows" gap="0px" style="grid-area: 2 / 3 / 3 / 4">
<ModuleWrapper title="兵力编组">
<template #extra>
<template v-if="zzbzll.selectedFd">
<a-button
v-if="![13, 14, 16].includes(zzbzll.selectedFd.resourceId)"
type="text-primary"
icon="setting"
style="font-size: 20px"
@click="handleOpenBlbzModal()"
></a-button>
<BlbzModal
:visible.sync="blbz.modalVisible"
:fdData="zzbzll.selectedFd"
v-model="blbz.modalCheckedKeys"
@ok="handleSubmitBlbz"
/>
<a-button type="text-primary" icon="sync" style="font-size: 20px" @click="getBlbzTreeData()"></a-button>
</template>
<Zoom :max="rightViewer === 'blbz'" @zoom-max="rightViewer = 'blbz'" @zoom-min="rightViewer = ''" />
</template>
<div v-loading.dark="blbz.loading" 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>
<ModuleWrapper title="基础属性">
<template #extra>
<template v-if="zzbzll.selectedFd">
<a-button type="text-primary" icon="sync" style="font-size: 20px" @click="getJcsxModelData()"></a-button>
</template>
<Zoom :max="rightViewer === 'jcsx'" @zoom-max="rightViewer = 'jcsx'" @zoom-min="rightViewer = ''" />
</template>
<div v-loading.dark="jcsx.loading" class="normal" style="padding: 15px 0">
<Jcsx
ref="jcsx"
v-if="zzbzll.selectedFd"
:scenarioId="scenarioId"
:resourceId="zzbzll.selectedFd.id"
:originResourceId="zzbzll.selectedFd.resourceId"
:resourceName="zzbzll.selectedFd.resourceName || zzbzll.selectedFd.title"
:resourceType="zzbzll.selectedFd.resourceType"
:type="zzbzll.selectedFd.type"
:modelData="jcsx.modelData"
@request="getJcsxModelData()"
/>
</div>
</ModuleWrapper>
<ModuleWrapper :title="xdrw.resourceTypeMapTitle[zzbzll.selectedFd?.resourceType] || '行动任务'">
<template #extra>
<template v-if="zzbzll.selectedFd">
<a-button type="text-primary" icon="sync" style="font-size: 20px" @click="getXdrwActionList()"></a-button>
</template>
<Zoom :max="rightViewer === 'xdrw'" @zoom-max="rightViewer = 'xdrw'" @zoom-min="rightViewer = ''" />
</template>
<div v-loading.dark="xdrw.loading" class="normal" style="padding: 0">
<Zzxd
ref="xdrw"
v-if="zzbzll.selectedFd"
:scenarioId="scenarioId"
:resourceId="zzbzll.selectedFd.id"
:resourceType="zzbzll.selectedFd.resourceType"
:actionList="xdrw.actionList"
:readonly="[13, 14, 16].includes(zzbzll.selectedFd.resourceId)"
@request="getXdrwActionList()"
/>
</div>
</ModuleWrapper>
</Grid>
</Grid>
</Flex>
</template>
<script>
import { getAction, postAction } from '@/api/manage'
import Zoom from './components/Zoom.vue'
import BlbzModal from './components/BlbzModal.vue'
import Jcsx from './components/Jcsx.vue'
import Zzxd from './components/Zzxd.vue'
export default {
name: 'SubsystemScenePresetting',
components: {
Zoom,
BlbzModal,
Jcsx,
Zzxd,
},
data() {
return {
scenarioId: '',
scenarioName: '',
cesium: null,
scenarioDetail: null,
weatherData:[
{ key: '1', weatherType: '张三', lastBegTime: 32, editable: false },
{ key: '2', weatherType: '李四', lastBegTime: 42, editable: false }
],
columns: [
{ title: '天气类型', dataIndex: 'weatherType',key: 'weatherType' },
{ title: '持续开始时间', dataIndex: 'lastBegTime',key: 'lastBegTime' },
{ title: '持续结束时间', dataIndex: 'lastEndTime',key: 'lastEndTime' },
{
title: '操作',
dataIndex: 'operation',
scopedSlots: { customRender: 'operation' }
}
],
zzbzll: {
loading: false,
treeData: [],
selectedKeys: [],
selectedFd: null,
},
zzbzllModal: {
title: '修改名称',
visible: false,
formItems: [
{ label: '原名称', prop: 'originName', customRender: (text) => text },
{ label: '新名称', prop: 'resourceName', required: true },
],
formRules: {},
formData: {},
},
fd: {
teamType: 0,
type: 5,
loading: false,
listData: [],
},
blbz: {
loading: false,
treeData: [],
showKeys: [],
modalVisible: false,
fdData: null,
modalCheckedKeys: [],
},
rightViewer: '',
jcsx: {
loading: false,
modelData: {},
},
xdrw: {
resourceTypeMapTitle: {
5: '作战行动',
6: '保障任务',
},
loading: false,
actionList: [],
},
childWindow: null,
}
},
computed: {
rightRows() {
switch (this.rightViewer) {
case 'blbz':
return [8, 1, 1]
case 'jcsx':
return [1, 8, 1]
case 'xdrw':
return [1, 1, 8]
default:
return [2, 4, 4]
}
},
showBlbzCheckedTreeData() {
const target = []
this.getTree(target, this.blbz.treeData, this.blbz.showKeys)
return target
},
},
created() {
this.scenarioId = this.$route.params.scenarioId
console.log("============="+this.$route.params.scenarioId)
this.scenarioName = this.$route.params.scenarioName
this.getWeathers()
window.addEventListener('beforeunload', (e) => {
this.childWindow && this.childWindow.close()
return true // 必须设置 returnValue 才能显示确认框
})
},
mounted() {
this.cesium = new window.MyCesium('scene-presetting-cesium-container')
this.getScenarioDetail()
this.getZzbzllTreeData(true)
this.getFdListData()
},
methods: {
getWeathers(){
this.$http({
url: `/baseData/weatherResource/list`,
method: 'get',
params: { scenarioId: this.scenarioId},
}).then(res => {
this.weatherData = res.data
console.log("================="+JSON.stringify(this.weatherData))
})
},
handleChange(value, key, column) {
const newData = [...this.data];
const target = newData.find(item => key === item.key);
if (target) {
target[column] = value;
this.data = newData;
}
},
edit(key) {
const newData = [...this.data];
const target = newData.find(item => key === item.key);
if (target) {
target.editable = true;
this.data = newData;
}
},
save(key) {
const newData = [...this.data];
const target = newData.find(item => key === item.key);
if (target) {
delete target.editable;
this.data = newData;
}
},
cancel(key) {
const newData = [...this.data];
const target = newData.find(item => key === item.key);
if (target) {
// Object.assign(target, this.newData.find(item => key === item.key));
delete target.editable;
this.data = newData;
}
},
handleDelete(key) {
this.data = this.data.filter(item => item.key !== key);
},
handleAdd() {
this.data.push({
key: Date.now(),
name: '',
age: null,
address: '',
editable: true
});
},
getTree(target, treeData, showKeys) {
treeData.forEach((item) => {
const newChildren = []
if (item.children && item.children.length > 0) {
this.getTree(newChildren, item.children, showKeys)
}
if (newChildren.length > 0 || showKeys.includes(item.key)) {
target.push({ ...item, children: newChildren })
}
})
},
async getScenarioDetail() {
try {
const res = await getAction(`/baseData/scenario/${this.scenarioId}`)
this.scenarioDetail = res.data
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)
}
},
async getZzbzllTreeData(initPlot = false) {
try {
this.zzbzll.loading = true
const res = await postAction(`/scenario/resource/`, {
scenarioId: this.scenarioId,
})
this.zzbzll.treeData = [
{
id: '0',
title: '红方',
selectable: false,
children: res.data.filter((item) => item.type === 0),
},
{
id: '1',
title: '蓝方',
selectable: false,
children: res.data.filter((item) => item.type === 1),
},
]
if (initPlot) {
this.initPlot(res.data)
}
} catch (error) {
console.log(error)
} finally {
this.zzbzll.loading = false
}
},
initPlot(plots) {
plots.forEach((item) => {
if (item.lng && item.lat) {
this.cesium.addPlotByLonLat(item.imgBase64, { lon: +item.lng, lat: +item.lat }, item.id)
}
})
},
handleOpenEditZzbzllModal(id, data) {
this.zzbzllModal.formData = { id, originName: data.resourceName || data.title }
this.zzbzllModal.visible = true
this.zzbzllModal.originData = data
},
handleSubmitZzbzll(formData) {
return postAction('/scenario/resource/save', formData)
},
handleSubmitZzbzllSuccess() {
this.$set(this.zzbzllModal.originData, 'resourceName', this.zzbzllModal.formData.resourceName)
},
async handleDeleteZzbzll(id, data) {
try {
await this.$confirm({ content: `确定删除${data.resourceName || data.title}` })
const res = await getAction(`/scenario/resource/remove/${id}`)
this.$message.success(res.message)
this.cesium.removePlotById(id)
this.getZzbzllTreeData()
} catch (error) {
console.log(error)
}
},
async getFdListData() {
try {
this.fd.loading = true
const res = await getAction(`/baseData/scenario/resources/${this.fd.type}/${this.fd.teamType}`)
this.fd.listData = res.data
} catch (error) {
console.log(error)
} finally {
this.fd.loading = false
}
},
forceSource() {
return {
data: [
{ title: '红方', id: 0 },
{ title: '蓝方', id: 1 },
],
}
},
dragend(item, e) {
const minX = this.$refs['scene-presetting-cesium-container'].offsetLeft
const maxX =
this.$refs['scene-presetting-cesium-container'].offsetLeft +
this.$refs['scene-presetting-cesium-container'].offsetWidth
const minY = this.$refs['scene-presetting-cesium-container'].offsetTop
const maxY =
this.$refs['scene-presetting-cesium-container'].offsetTop +
this.$refs['scene-presetting-cesium-container'].offsetHeight
if (e.x < minX || e.x > maxX || e.Y < minY || e.Y > maxY) return
const x = e.x - this.$refs['scene-presetting-cesium-container'].offsetLeft
const y = e.y - this.$refs['scene-presetting-cesium-container'].offsetTop
const { plotId, longitude, latitude } = this.cesium.addPlotByOffset(item.imgBase64, { x, y })
this.savePlot(this.fd.teamType, item, { plotId, longitude, latitude })
},
async savePlot(teamType, item, { plotId, longitude, latitude }) {
try {
await postAction('/scenario/resource/save', {
id: plotId,
scenarioId: this.scenarioId,
type: teamType,
resourceType: item.type,
resourceId: item.id,
lng: longitude,
lat: latitude,
})
this.getZzbzllTreeData()
} catch (error) {
console.log(error)
}
},
handleSelectZzbzll(selectedKeys, { node }) {
this.cesium.setClientByCenter({ longitude: +node.dataRef.lng, latitude: +node.dataRef.lat })
this.zzbzll.selectedFd = node.dataRef
this.getBlbzTreeData()
this.getJcsxModelData()
this.getXdrwActionList()
},
async getBlbzTreeData() {
try {
this.blbz.loading = true
const { type, id: resourceId, scenarioId } = this.zzbzll.selectedFd
const res = await Promise.all([
getAction('/tree/organization'),
postAction('/scenarioOrgPost/getPost', { type, resourceId, scenarioId }),
])
this.blbz.treeData = res[0].data
this.blbz.showKeys = res[1].data
} catch (error) {
console.log(error)
} finally {
this.blbz.loading = false
}
},
async handleOpenBlbzModal() {
if (!this.zzbzll.selectedFd) {
this.$message.error('未选择分队!')
return
}
this.blbz.modalCheckedKeys = [...this.blbz.showKeys]
this.blbz.modalVisible = true
},
async handleSubmitBlbz() {
try {
const { type, id: resourceId, scenarioId } = this.zzbzll.selectedFd
const res = await postAction('/scenarioOrgPost/batchSave', {
type,
resourceId,
scenarioId,
orgIdList: this.blbz.modalCheckedKeys,
})
this.blbz.modalVisible = false
this.$message.success(res.message)
this.getBlbzTreeData()
} catch (error) {
console.log(error)
}
},
async getJcsxModelData() {
try {
this.jcsx.loading = true
const res = await getAction('/statistic/info', {
type: this.zzbzll.selectedFd.type,
resourceId: this.zzbzll.selectedFd.id,
scenarioId: this.scenarioId,
})
this.jcsx.modelData = res.data
} catch (error) {
console.log(error)
} finally {
this.jcsx.loading = false
}
},
async getXdrwActionList() {
try {
this.xdrw.loading = true
const res = await postAction('/scenarioTask/taskList', {
scenarioId: this.scenarioId,
resourceId: this.zzbzll.selectedFd.id,
})
this.xdrw.actionList = res.data
} catch (error) {
console.log(error)
} finally {
this.xdrw.loading = false
}
},
handleOpenGuaranteeProcessPage() {
this.childWindow = window.open(
'/guaranteeProcess',
'guaranteeProcess',
'height=' +
window.screen.height +
',width=600,' +
',top=0,left=0,toolbar=no,menubar=no,scrollbars=no,resizable=no,location=no,status=no'
)
},
},
}
</script>
<style lang="less" scoped>
.page-scene-presetting {
height: 100%;
color: #ffffff;
.page-scene-presetting-header {
height: 50px;
background-color: #0a2a3d;
padding: 0 20px;
.page-scene-presetting-title {
color: #00d5fe;
font-size: 18px;
font-weight: bolder;
letter-spacing: 2px;
}
}
.page-scene-presetting-main {
background-color: #022234;
height: 100px;
padding: 0 20px;
.tool_btn {
background-color: #022234;
color: #00d5fe;
font-size: 60px;
font-weight: bolder;
letter-spacing: 2px;
}
}
}
.ant-menu-horizontal {
line-height: 30px;
}
.scene-presetting-cesium-container {
width: 100%;
height: 100%;
overflow: hidden;
}
::v-deep {
.distance-legend {
left: 320px;
}
.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;
}
}
.fd-item {
width: calc(100% / 3);
.fd-image {
width: 74px;
height: 62px;
object-fit: cover;
margin: 16px 0 8px;
}
.fd-name {
white-space: nowrap;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
}
.fd-item:hover {
.fd-name {
overflow: visible;
}
}
</style>