装备军标

This commit is contained in:
liaoboping 2025-09-09 16:58:39 +08:00
parent ab1e7b8b23
commit 5f68826986
10 changed files with 370 additions and 798 deletions

View File

@ -110,13 +110,13 @@ export default {
.jc-fe { .jc-fe {
justify-content: flex-end; justify-content: flex-end;
} }
.fr-w { .fw-w {
flex-wrap: wrap; flex-wrap: wrap;
} }
.fr-n { .fw-n {
flex-wrap: nowrap; flex-wrap: nowrap;
} }
.fr-wr { .fw-wr {
flex-wrap: wrap-reverse; flex-wrap: wrap-reverse;
} }

View File

@ -0,0 +1,13 @@
<template>
<div class="icon-selector"></div>
</template>
<script>
export default {
props: {
value: { validator: () => true, required: true },
},
}
</script>
<style lang="less" scoped></style>

View File

@ -38,6 +38,7 @@ export default {
reader.readAsDataURL(file) reader.readAsDataURL(file)
reader.onload = (e) => { reader.onload = (e) => {
this.imageSrc = e.target.result this.imageSrc = e.target.result
this.$emit('change', e.target.result, file)
} }
}, },
}, },

View File

@ -8,6 +8,7 @@ import AntOriginSelect from './Form/AntOriginSelect.vue'
import AntOriginTreeSelect from './Form/AntOriginTreeSelect.vue' import AntOriginTreeSelect from './Form/AntOriginTreeSelect.vue'
import DurationPicker from './Form/DurationPicker.vue' import DurationPicker from './Form/DurationPicker.vue'
import Image2Base64 from './Form/Image2Base64.vue' import Image2Base64 from './Form/Image2Base64.vue'
import IconSelector from './Form/IconSelector.vue'
import WangEditor from './WangEditor/Index.vue' import WangEditor from './WangEditor/Index.vue'
@ -30,6 +31,7 @@ export default {
Vue.component('AntOriginTreeSelect', AntOriginTreeSelect) Vue.component('AntOriginTreeSelect', AntOriginTreeSelect)
Vue.component('DurationPicker', DurationPicker) Vue.component('DurationPicker', DurationPicker)
Vue.component('Image2Base64', Image2Base64) Vue.component('Image2Base64', Image2Base64)
Vue.component('IconSelector', IconSelector)
Vue.component('WangEditor', WangEditor) Vue.component('WangEditor', WangEditor)

View File

@ -0,0 +1,24 @@
<template>
<Grid
:columns="[5, 3, 2]"
:rows="[2, 3, 5]"
gap="0px"
:style="{ width: size, height: size, cursor: 'pointer' }"
title="修改军标"
v-on="$listeners"
>
<a-icon type="picture" :style="{ fontSize: `calc(${size} * 8 / 10)`, gridColumn: '1 / 3', gridRow: '2 / 4' }" />
<a-icon type="setting" :style="{ fontSize: `calc(${size} * 5 / 10)`, gridColumn: '2 / 4', gridRow: '1 / 3' }" />
</Grid>
</template>
<script>
export default {
props: {
size: { type: String, default: '30px' },
},
}
</script>
<style lang="less" scoped>
</style>

View File

@ -50,7 +50,7 @@ export default {
columns: [ columns: [
{ dataIndex: 'serial' }, { dataIndex: 'serial' },
{ dataIndex: 'iconName', title: '军标名称', width: 'auto', align: 'center' }, { dataIndex: 'iconName', title: '军标名称', width: 'auto', align: 'center' },
{ dataIndex: 'iconBase64', title: '军标路径', width: 'auto', align: 'center' }, { dataIndex: 'iconBase64', title: '军标图片', width: 'auto', align: 'center' },
{ dataIndex: 'action' }, { dataIndex: 'action' },
], ],
}, },
@ -62,7 +62,7 @@ export default {
title: '新增图形', title: '新增图形',
formItems: [ formItems: [
{ label: '军标名称', prop: 'iconName' }, { label: '军标名称', prop: 'iconName' },
{ label: '军标路径', prop: 'iconBase64', component: 'Image2Base64' }, { label: '军标图片', prop: 'iconBase64', component: 'Image2Base64' },
], ],
formRules: {}, formRules: {},
formData: {}, formData: {},

View File

@ -19,7 +19,7 @@
> >
<template #title="scope"> <template #title="scope">
<a-dropdown :trigger="['contextmenu']"> <a-dropdown :trigger="['contextmenu']">
<span>{{ scope.title }}{{ $console.log(scope) }}</span> <span>{{ scope.title }}</span>
<template #overlay> <template #overlay>
<Flex class="contextmenu-zz"> <Flex class="contextmenu-zz">
<a-button <a-button
@ -46,6 +46,14 @@
title="详情" title="详情"
@click="handleViewZbfl(scope.key)" @click="handleViewZbfl(scope.key)"
></a-button> ></a-button>
<a-button
type="text-primary"
title="修改军标"
style="padding: 0 8px"
@click="handleOpenEditZbjbModal(scope.key, scope.dataRef.data)"
>
<EditIcon size="16px" />
</a-button>
</Flex> </Flex>
</template> </template>
</a-dropdown> </a-dropdown>
@ -111,6 +119,15 @@
> >
</a-table> </a-table>
</a-modal> </a-modal>
<AntFormModal
:visible.sync="zbjbModal.visible"
:title="zbjbModal.title"
:formItems="zbjbModal.formItems"
:formRules="zbjbModal.formRules"
:formData="zbjbModal.formData"
:onSubmit="handleSubmitZbjb"
@success="handleSubmitZbjbSuccess"
></AntFormModal>
<InfoDataModal <InfoDataModal
:visible="AECModal.visible" :visible="AECModal.visible"
@ -127,6 +144,8 @@
<script> <script>
import InfoDataModal from './modules/infoData.vue' import InfoDataModal from './modules/infoData.vue'
import EditIcon from './components/EditIcon.vue'
import { postAction } from '@/api/manage'
const listGridInfo = { const listGridInfo = {
Aircraft: [ Aircraft: [
@ -267,6 +286,7 @@ export default {
name: 'Zbsjk', name: 'Zbsjk',
components: { components: {
InfoDataModal, InfoDataModal,
EditIcon,
}, },
data() { data() {
return { return {
@ -289,7 +309,6 @@ export default {
this.$http({ this.$http({
url: '/basedata/entity/getTreeNode', url: '/basedata/entity/getTreeNode',
method: 'get', method: 'get',
params: { parentId: '-1' },
}).then((res) => ({ data: [{ key: -1, title: '根级分类' }].concat(res.data) })), }).then((res) => ({ data: [{ key: -1, title: '根级分类' }].concat(res.data) })),
valueKey: 'key', valueKey: 'key',
}, },
@ -308,6 +327,14 @@ export default {
visible: false, visible: false,
data: {}, data: {},
}, },
zbjbModal: {
visible: false,
title: '',
mode: '',
formItems: [{ label: '军标图片', prop: 'iconId', component: 'IconSelector' }],
formRules: {},
formData: {},
},
zb: { zb: {
entityType: '', entityType: '',
parentId: '', parentId: '',
@ -516,6 +543,19 @@ export default {
console.log(error) console.log(error)
} }
}, },
handleOpenEditZbjbModal(id, data) {
this.zbjbModal.title = '修改军标'
this.zbjbModal.formData = {}
this.zbjbModal.formData.id = id
this.zbjbModal.formData.iconId = data.iconId
this.zbjbModal.visible = true
},
handleSubmitZbjb(formData) {
return postAction('/basedata/entity/setIcon', formData)
},
handleSubmitZbjbSuccess() {
this.getZzTree()
},
handleOpenAddZbModal() { handleOpenAddZbModal() {
this.AECModal.opType = 1 this.AECModal.opType = 1
this.AECModal.title = '添加 ' + this.zb.entityName + ' 实体' this.AECModal.title = '添加 ' + this.zb.entityName + ' 实体'

View File

@ -0,0 +1,201 @@
<template>
<Grid :columns="['320px', 1, '320px']" :rows="['30px', 1]" gap="0px">
<div class="tool-wrapper"></div>
<div>
<ModuleWrapper title="作战/保障力量" height="45%">
<div class="normal" style="padding: 5px; overflow-y: auto">
<a-tree
class="simulation-tree"
:treeData="zzbzll.treeData"
:selectedKeys.sync="zzbzll.selectedKeys"
:replaceFields="{ children: 'children', title: 'name', key: 'id' }"
@select="handleSelectZzbzll"
></a-tree>
</div>
</ModuleWrapper>
<ModuleWrapper height="55%">
<template #title>
<a-radio-group v-model="model.type" button-style="solid">
<a-radio-button value="zbys">装备元素</a-radio-button>
<a-radio-button value="jbkj">基本控件</a-radio-button>
</a-radio-group>
</template>
<Flex class="normal" fd="co" style="padding: 5px">
<template v-if="model.type === 'zbys'">
<a-input-search
v-model="model.queryParams.keyword"
placeholder="输入关键词搜索..."
@search="getZbysListData()"
/>
<Flex>
<AntOriginSelect
v-model="model.queryParams.force"
:dataSource="() => ({ data: model.forceOptions })"
width="100px"
:allowClear="false"
/>
<AntOriginSelect
v-model="model.queryParams.type"
:dataSource="() => ({ data: model.typeOptions })"
class="flex-1"
:allowClear="false"
@change="getZbysListData()"
/>
</Flex>
<Flex class="flex-1 scroller-y" fw="w">
<Flex v-for="item in model.listData" :key="item.id" class="model-item" fd="co" ai="c">
<img class="model-image" :src="item.imgBase64" :draggable="true" />
<span class="model-name">{{ item.name }}</span>
</Flex>
</Flex>
</template>
</Flex>
</ModuleWrapper>
</div>
<div class="cesium-container" id="cesium-container" style="grid-column: 2 / 3; overflow: hidden"></div>
<div>
<ModuleWrapper height="100%">
<template #title>
<a-radio-group v-model="modelInfo.type" button-style="solid">
<a-radio-button value="jcsx">基础属性</a-radio-button>
<a-radio-button value="zzxd">作战行动</a-radio-button>
</a-radio-group>
</template>
</ModuleWrapper>
</div>
</Grid>
</template>
<script>
import { getAction } from '@/api/manage'
export default {
props: {
scenarioId: { validator: () => true, required: true },
},
data() {
return {
zzbzll: {
treeData: [],
selectedKeys: [],
},
model: {
type: 'zbys',
forceOptions: [
{ title: '红方', id: 1 },
{ title: '蓝方', id: 2 },
],
typeOptions: [
{ title: '飞机', id: 1 },
{ title: '地面设施与兵力', id: 2 },
{ title: '舰船', id: 3 },
{ title: '潜艇', id: 4 },
{ title: '作战分队', id: 5 },
{ title: '保障分队', id: 6 },
],
queryParams: {
keyword: '',
force: 1,
type: 1,
},
listData: [],
},
modelInfo: {
type: 'jcsx',
data: {},
},
}
},
created() {
this.getZzbzllTreeData()
this.getZbysListData()
},
mounted() {
this.cesium = new window.MyCesium('cesium-container')
},
methods: {
async getZzbzllTreeData() {
try {
const res = await getAction(`/scenario/power/${this.scenarioId}`)
this.zzbzll.treeData = [
{
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.blue.fight },
{ id: '2-2', name: '保障力量', selectable: false, children: res.data.blue.guarantee },
// { id: '2-3', name: '', selectable: false, children: res.data.blue.command },
],
},
]
} catch (error) {
console.log(error)
}
},
handleSelectZzbzll(selectedKeys, { node }) {
this.modelInfo.data = node.dataRef
this.modelInfo.checkedAction = null
},
async getZbysListData() {
try {
const res = await getAction(`/baseData/scenario/resources/${this.model.queryParams.type}`, {
keyword: this.model.queryParams.keyword,
})
this.model.listData = res.data
console.log(this.model.listData)
} catch (error) {
console.log(error)
}
},
},
}
</script>
<style lang="less" scoped>
.tool-wrapper {
grid-column: ~'1 / 4';
}
.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;
}
}
.model-item {
width: calc(100% / 3);
.model-image {
width: 74px;
height: 62px;
object-fit: cover;
margin: 16px 0 8px;
}
.model-name {
white-space: nowrap;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
}
.model-item:hover {
.model-name {
overflow: visible;
}
}
</style>

View File

@ -1,817 +1,76 @@
<template> <template>
<Grid class="scene-editing-page" :columns="['320px', 1, '320px']" :rows="[45, 30, 25]" gap="0px"> <ModuleWrapper>
<ModuleWrapper title="作战/保障力量" style="grid-column: 1 / 2; grid-row: 1 / 2">
<div class="normal" style="padding: 5px; overflow-y: auto">
<a-tree
class="simulation-tree"
: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">
<div class="normal flex-c" style="padding: 5px">
<a-input-search v-model="ys.queryParams.keyword" placeholder="输入关键词搜索..." @search="onSearch" />
<Flex>
<AntOriginSelect
v-model="ys.queryParams.force"
:dataSource="() => ({ data: ys.forceOptions })"
width="100px"
:allowClear="false"
/>
<AntOriginSelect
v-model="ys.queryParams.type"
:dataSource="() => ({ data: ys.typeOptions })"
class="flex-1"
:allowClear="false"
/>
</Flex>
<div class="flex-1" style="overflow-y: auto">
<a-row>
<template v-for="item in ys.ysList">
<a-col :key="item.id" :span="24">{{ item.title }}</a-col>
<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>
<ModuleWrapper style="grid-column: 3 / 4; grid-row: 1 / 4">
<template #title> <template #title>
<a-radio-group v-model="right.radioType" button-style="solid"> <div class="scene-editing-page-header">
<a-radio-button value="jcsx">基础属性</a-radio-button> <a-icon type="left" title="返回" @click="handleBack" />
<a-radio-button value="zzxd">作战行动</a-radio-button> <span>场景编辑子系统</span>
<!-- <a-radio-button value="dzsx">单装属性</a-radio-button> --> </div>
</a-radio-group>
</template> </template>
<div class="normal" style="padding: 15px 0"> <template #extra>
<div style="height: 100%; padding: 0 15px; overflow-y: auto"> <a-icon type="logout" title="退出系统" style="font-size: 18px" @click="handleQuitSystem" />
<div v-if="right.radioType === 'jcsx'"> </template>
<a-collapse class="simulation-collapse" :defaultActiveKey="['1', '2', '3', '4', '5', '6', '7', '8', '9']"> <div v-if="scenarioId" class="scenario-name">{{ scenarioId }}{{ scenarioName }}</div>
<a-collapse-panel class="simulation-collapse-item" key="1" header="基础信息"> <SceneEditing class="normal" v-if="scenarioId" :scenarioId="scenarioId" style="padding: 0"></SceneEditing>
<img class="image" :src="right.detail.image || '/mockData/fe6ad2d8-da11-04d8-f447-0d8175826e28.png'" />
<div class="name">
{{ right.detail.name }}
<a-button v-if="hasDetail" type="text-primary" icon="edit" @click="handleOpenMcModal"></a-button>
</div>
<!-- <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>{{ right.detail.position.deduceTypeName }}</span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">类型</span>
<span>{{ right.detail.position.logisticType | logisticTypeFormat }}</span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">方向</span>
<span>{{ right.detail.position.direction | numberFormat }}°</span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">速度</span>
<span>{{ right.detail.position.speed }} 公里/</span>
</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 v-if="hasDetail" type="text-primary" icon="edit" @click="handleOpenLonlatModal"></a-button>
</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 v-if="hasDetail" type="text-primary" icon="edit" @click="handleOpenLonlatModal"></a-button>
</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 v-if="hasDetail" type="text-primary" icon="edit" @click="handleOpenHdModal()"></a-button>
</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>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">当前人数</span>
<span>{{ right.detail.personStatistic.current }} </span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">死亡人数</span>
<span>{{ right.detail.personStatistic.death }} </span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">受伤人数</span>
<span>{{ right.detail.personStatistic.injured }} </span>
</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>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">野战食物当前量()</span>
<span>{{ right.detail.foodInfo.currentNum }}</span>
</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>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">用水当前量()</span>
<span>{{ right.detail.waterInfo.currentNum }}</span>
<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>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">油料当前量()</span>
<span>{{ right.detail.oilInfo.currentNum }}</span>
</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>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">药材当前量()</span>
<span>{{ right.detail.medicalInfo.currentNum }}</span>
</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>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">压制武器弹药量()</span>
<span>{{ right.detail.ammunition.suppressing }}</span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">反坦克武器弹药量()</span>
<span>{{ right.detail.ammunition.antiTank }}</span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">防空反导武器弹药量()</span>
<span>{{ right.detail.ammunition.antiAircraft }}</span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">布扫雷装备弹药量()</span>
<span>{{ right.detail.ammunition.mineLaying }}</span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">爆破器材弹药量()</span>
<span>{{ right.detail.ammunition.explosiveDevice }}</span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">烟火装备弹药量()</span>
<span>{{ right.detail.ammunition.smokeDevice }}</span>
</div>
<div class="zt-item flex ai-c">
<span style="min-width: 100px">防化消耗弹药量()</span>
<span>{{ right.detail.ammunition.antiChemical }}</span>
</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'" class="zzxd-wrapper flex-v">
<div class="zzxd-header flex ai-c jc-sb">
<div class="zzxd-title">作战行动</div>
<div>
<a-button type="text-primary" icon="menu"></a-button>
<a-button type="text-primary" icon="plus" @click="handleOpenAddActionModal"></a-button>
<a-button type="text-primary" icon="edit" @click="handleOpenEditActionModal"></a-button>
<a-button type="text-primary" icon="delete" @click="handleDeleteAction"></a-button>
</div>
</div>
<div class="flex-1" style="overflow-y: auto">
<div
v-for="item in right.detail.actionList"
:key="item.id"
class="action-item flex"
@click="right.checkedAction = item"
>
<div class="action-icon">
<div class="action-line"></div>
<a-radio
:checked="right.checkedAction && right.checkedAction.id === item.id"
style="margin-right: 0"
></a-radio>
</div>
<div class="flex-1">
<div class="action-title">{{ item.typeName || '- -' }}</div>
<div class="action-time">开始时间{{ item.beginDateTime }}</div>
<div class="action-time">结束时间{{ item.endDateTime }}</div>
</div>
</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> </ModuleWrapper>
<a-modal
v-model="mcModal.visible"
title="编辑单元名称"
:maskClosable="false"
width="400px"
:destroyOnClose="true"
@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"
:destroyOnClose="true"
@ok="handleSubmilLonlat"
>
<LonLatInput :lon.sync="lonlatModal.lon" :lat.sync="lonlatModal.lat" />
</a-modal>
<a-modal
v-model="hdModal.visible"
title="设置单元高度/深度"
:maskClosable="false"
width="400px"
:destroyOnClose="true"
@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>
<a-modal
v-model="actionModal.visible"
:title="actionModal.title"
:maskClosable="false"
:destroyOnClose="true"
@ok="handleSubmilAction"
>
<a-form-model
:model="actionModal.formData"
layout="horizontal"
:labelCol="{ span: 6 }"
:wrapperCol="{ span: 15 }"
>
<a-form-model-item v-for="item in actionModal.formItems" :key="item.prop" v-bind="item">
<component
:is="item.component || 'a-input'"
v-model="actionModal.formData[item.prop]"
v-bind="item.options"
/>
</a-form-model-item>
</a-form-model>
</a-modal>
</Grid>
</template> </template>
<script> <script>
import LonLatInput from './components/LonLatInput.vue' import SceneEditing from './components/SceneEditing.vue'
export default { export default {
name: 'SimulationSceneSceneEditing', name: 'SimulationSceneSceneEditing',
components: { components: {
LonLatInput, SceneEditing,
},
filters: {
logisticTypeFormat(v) {
return {
1: '信息对抗分队',
2: '边防作战分队',
3: '防化保障分队',
4: '火力打击分队',
5: '餐饮保障分队',
6: '运输保障分队',
7: '医疗分队',
8: '工兵分队',
}[v]
},
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() { data() {
return { return {
cesium: null, scenarioId: '',
scenarioId: null, scenarioName: '',
zb: { zbTreeData: [], selectedKeys: [] }, scenarioRedirectUrl: '',
ys: {
forceOptions: [
{ title: '红方', id: 1 },
{ title: '蓝方', id: 2 },
],
typeOptions: [
{ title: '飞机', id: 1 },
{ title: '地面设施与兵力', id: 2 },
{ title: '舰船', id: 3 },
{ title: '潜艇', id: 4 },
{ title: '作战分队', id: 5 },
{ title: '保障分队', id: 6 },
],
queryParams: {
keyword: '',
force: 1,
type: 1,
},
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' },
],
},
],
},
right: {
radioType: 'jcsx',
detail: {
position: {},
personStatistic: {},
foodInfo: {},
waterInfo: {},
oilInfo: {},
medicalInfo: {},
ammunition: {},
actionList: [],
// equipmentList: [],
},
checkedAction: null,
},
mcModal: {
visible: false,
mc: '',
},
lonlatModal: {
visible: false,
lon: 0,
lat: 0,
},
hdModal: {
visible: false,
hd: 0,
},
actionModal: {
visible: false,
formItems: [
{ label: '事件名称', prop: 'typeName' },
{
label: '事件类型',
prop: 'typeType',
component: 'AntOriginSelect',
options: {
dataSource: () => ({
data: [
{ id: '1', title: '阵地进攻' },
{ id: '2', title: '机动进攻' },
{ id: '3', title: '城镇进攻' },
{ id: '4', title: '山地进攻' },
{ id: '5', title: '阵地防御' },
{ id: '6', title: '机动防御' },
{ id: '7', title: '城镇防御' },
{ id: '8', title: '山地防御' },
],
}),
},
},
{ label: '开始时间', prop: 'beginDateTime', component: 'a-date-picker', options: { showTime: true } },
{ label: '结束时间', prop: 'endDateTime', component: 'a-date-picker', options: { showTime: true } },
{ label: '目标经度', prop: 'lon', component: 'a-input-number' },
{ label: '目标纬度', prop: 'lat', component: 'a-input-number' },
],
formData: {},
},
} }
}, },
computed: { created() {
hasDetail() { this.scenarioId = window.localStorage.getItem('scenarioId')
return Boolean(this.right.detail.id) this.scenarioName = window.localStorage.getItem('scenarioName')
}, this.scenarioRedirectUrl = window.localStorage.getItem('scenarioRedirectUrl')
},
mounted() {
this.cesium = new window.MyCesium('cesium-container')
this.scenarioId = 2733
this.getZbTree()
}, },
methods: { methods: {
async getZbTree() { handleBack() {
try { if (this.scenarioRedirectUrl) {
const res = await this.$http({ this.$router.push({ name: this.scenarioRedirectUrl })
url: `/scenario/power/${this.scenarioId}`, return
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.blue.fight },
{ id: '2-2', name: '保障力量', selectable: false, children: res.data.blue.guarantee },
{ id: '2-3', name: '指挥力量', selectable: false, children: res.data.blue.command },
],
},
]
} catch (error) {
console.log(error)
} }
this.$router.go(-1)
}, },
handleSelectTree(selectedKeys, { node }) { handleQuitSystem() {
this.right.detail = node.dataRef this.$router.push({ name: 'thirdLogin' })
this.right.checkedAction = null
},
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: `/scenario/power/modifyUnit/${this.scenarioId}`,
method: 'post',
data: {
id: this.right.detail.id,
name: this.mcModal.mc,
},
})
this.$message.success('编辑单元名称成功')
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
this.lonlatModal.visible = true
},
async handleSubmilLonlat() {
try {
this.$http({
url: `/scenario/power/modifyUnit/${this.scenarioId}`,
method: 'post',
data: {
id: this.right.detail.id,
position: {
lng: this.lonlatModal.lon,
lat: this.lonlatModal.lat,
},
},
})
this.$message.success('修改单元经纬度成功')
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: `/scenario/power/modifyUnit/${this.scenarioId}`,
method: 'post',
data: {
id: this.right.detail.id,
position: {
height: this.hdModal.hd,
},
},
})
this.$message.success('修改单元高度/深度成功')
this.right.detail.position.height = this.hdModal.hd
this.hdModal.visible = false
} catch (error) {
console.log(error)
}
},
handleOpenAddActionModal() {
this.actionModal.title = '添加事件信息'
this.actionModal.formData = {}
this.actionModal.visible = true
},
handleOpenEditActionModal() {
this.actionModal.title = '修改事件信息'
this.actionModal.formData = { ...this.right.checkedAction }
this.actionModal.visible = true
},
async handleSubmilAction() {
try {
await this.$http({
url: '/save',
method: 'post',
data: this.actionModal.formData,
})
this.$message.success(`${this.actionModal.title}成功`)
} catch (error) {
console.log(error)
}
},
async handleDeleteAction() {
try {
await this.$confirm('确认删除所选事件吗?')
await this.$http({
url: '/delete',
method: 'delete',
params: { id: this.right.checkedAction.id },
})
this.$message.success(`删除事件成功`)
} catch (error) {
this.$message.success(`删除事件失败`)
console.log(error)
}
}, },
}, },
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.scene-editing-page { .scene-editing-page-header {
padding-top: 20px; font-size: 18px;
} font-weight: bold;
.simulation-tree::v-deep { line-height: 26px;
color: #a1c2d0; letter-spacing: 2px;
li .ant-tree-node-content-wrapper { color: #00deff;
color: #a1c2d0; padding: 0 8px;
} .anticon {
li .ant-tree-node-content-wrapper.ant-tree-node-selected { margin-right: 10px;
background-color: #bae7ff44;
}
li .ant-tree-node-content-wrapper:hover {
background-color: #bae7ff22;
} }
} }
.ys-image { .scenario-name {
width: 74px; position: fixed;
height: 62px; left: 50%;
object-fit: cover; top: 0;
margin: 16px 0 8px; transform: translateX(-50%);
} height: 50px;
.simulation-collapse::v-deep { line-height: 50px;
background-color: transparent; font-size: 18px;
color: #bbdded; font-weight: bold;
font-size: 16px; letter-spacing: 2px;
line-height: 30px; color: #00deff;
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;
}
.simulation-select::v-deep {
.ant-select-selection {
background-color: #10475f;
border: solid 1px #1d5777;
color: #bbdded;
}
.ant-select-arrow {
color: #bbdded;
}
}
.zzxd-wrapper {
height: 100%;
.zzxd-header {
padding: 5px 0;
border-bottom: 1px solid #00baff22;
.zzxd-title {
color: #00baff;
}
}
}
.action-item {
cursor: pointer;
padding: 5px 0;
.action-icon {
padding: 5px 16px;
position: relative;
flex-shrink: 0;
.action-line {
position: absolute;
right: 50%;
top: 21px;
width: 1px;
height: 100%;
background-color: #00baff;
}
}
}
.action-item:last-of-type {
.action-line {
display: none;
}
}
.action-item:hover {
background-color: #bae7ff44;
}
</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> </style>

View File

@ -1,6 +1,9 @@
<template> <template>
<Grid class="trainer-page" :columns="[1, 1]"> <Grid class="trainer-page" :columns="[1, 1]">
<ModuleWrapper title="想定列表"> <ModuleWrapper title="想定列表">
<template #extra>
<a-icon title="新建想定" type="plus" style="font-size: 30px" @click="handleOpenAddScenarioModal()" />
</template>
<Flex fd="co" class="normal"> <Flex fd="co" class="normal">
<div class="scenario-list flex-1"> <div class="scenario-list flex-1">
<Flex v-for="item in scenario.listData" :key="item.id" ai="c" class="scenario-item"> <Flex v-for="item in scenario.listData" :key="item.id" ai="c" class="scenario-item">
@ -38,7 +41,7 @@
<div class="room-item" v-for="item in room.listData" :key="item.id"> <div class="room-item" v-for="item in room.listData" :key="item.id">
<Flex class="room-card"> <Flex class="room-card">
<Flex fd="co" jc="c" class="room-info flex-1"> <Flex fd="co" jc="c" class="room-info flex-1">
<div class="room-name"><a-icon type="home" style="margin-right: 10px;" />{{ item.roomName }}</div> <div class="room-name"><a-icon type="home" style="margin-right: 10px" />{{ item.roomName }}</div>
<div class="room-scenario-relation">想定编号{{ item.scenarioId }}</div> <div class="room-scenario-relation">想定编号{{ item.scenarioId }}</div>
<div class="room-create-time">{{ item.createTime.slice(0, 19).replace('T', ' ') }}</div> <div class="room-create-time">{{ item.createTime.slice(0, 19).replace('T', ' ') }}</div>
</Flex> </Flex>
@ -60,6 +63,15 @@
</Flex> </Flex>
</Flex> </Flex>
</ModuleWrapper> </ModuleWrapper>
<AntFormModal
:visible.sync="scenarioModal.visible"
:title="scenarioModal.title"
:formItems="scenarioModal.formItems"
:formRules="scenarioModal.formRules"
:formData="scenarioModal.formData"
:onSubmit="handleSubmitScenario"
@success="handleSubmitScenarioSuccess"
></AntFormModal>
<AntFormModal <AntFormModal
:visible.sync="roomModal.visible" :visible.sync="roomModal.visible"
:title="roomModal.title" :title="roomModal.title"
@ -91,6 +103,14 @@ export default {
pageSize: 10, pageSize: 10,
}, },
}, },
scenarioModal: {
visible: false,
title: '',
mode: '',
formItems: [{ label: '想定名称', prop: 'name', required: true }],
formRules: {},
formData: {},
},
room: { room: {
listData: [], listData: [],
pagination: { pagination: {
@ -146,8 +166,20 @@ export default {
console.log(error) console.log(error)
} }
}, },
handleOpenAddScenarioModal() {
this.scenarioModal.title = '新建想定'
this.scenarioModal.formData = {}
this.scenarioModal.visible = true
},
handleSubmitScenario(formData) {
return postAction('/baseData/scenario/save', formData)
},
handleSubmitScenarioSuccess() {
this.getScenarioList()
},
handleOpenSetting(scenarioItem) { handleOpenSetting(scenarioItem) {
window.localStorage.setItem('scenarioId', scenarioItem.id) window.localStorage.setItem('scenarioId', scenarioItem.id)
window.localStorage.setItem('scenarioName', scenarioItem.name)
window.localStorage.setItem('scenarioRedirectUrl', 'SimulationSceneTrainer') window.localStorage.setItem('scenarioRedirectUrl', 'SimulationSceneTrainer')
this.$router.push({ name: 'SimulationSceneSceneEditing' }) this.$router.push({ name: 'SimulationSceneSceneEditing' })
}, },