Browse Source

Merge branch 'lbj' of http://124.70.32.114:3100/woka/cesium-map-object into wxp

# Conflicts:
#	ruoyi-ui/src/views/childRoom/index.vue
lbj
wangxinping 2 months ago
parent
commit
6fe49fe29a
  1. 57
      ruoyi-ui/src/views/cesiumMap/index.vue
  2. 49
      ruoyi-ui/src/views/childRoom/BottomLeftPanel.vue
  3. 768
      ruoyi-ui/src/views/childRoom/TopHeader.vue
  4. 1541
      ruoyi-ui/src/views/childRoom/index.vue

57
ruoyi-ui/src/views/cesiumMap/index.vue

@ -1002,31 +1002,34 @@ export default {
return entity
},
addCircleEntity(center, radius) {
this.entityCounter++
const id = `circle_${this.entityCounter}`
//
const validRadius = Math.max(radius, 1)
this.entityCounter++
const id = `circle_${this.entityCounter}`
const entity = this.viewer.entities.add({
id: id,
name: `圆形 ${this.entityCounter}`,
position: center, //
// 使 ellipse ()
ellipse: {
semiMinorAxis: radius, // =
semiMajorAxis: radius, // =
material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color)
.withAlpha(this.defaultStyles.circle.opacity),
outline: true,
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color),
outlineWidth: this.defaultStyles.circle.width
}
})
const entity = this.viewer.entities.add({
id: id,
name: `圆形 ${this.entityCounter}`,
position: center, //
// entity
this.allEntities.push(entity)
// 使 ellipse ()
ellipse: {
semiMinorAxis: validRadius, // =
semiMajorAxis: validRadius, // =
material: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color)
.withAlpha(this.defaultStyles.circle.opacity),
outline: true,
outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.circle.color),
outlineWidth: this.defaultStyles.circle.width
}
})
return entity
},
// entity
this.allEntities.push(entity)
return entity
},
// ================== ==================
@ -1418,11 +1421,17 @@ export default {
break
case 'circle':
//
const radius = entityData.data.radius || 1000
if (radius <= 0) {
this.$message.error('圆形半径必须大于0')
return
}
entity = this.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(entityData.data.center.lng, entityData.data.center.lat),
ellipse: {
semiMinorAxis: entityData.data.radius,
semiMajorAxis: entityData.data.radius,
semiMinorAxis: radius,
semiMajorAxis: radius,
material: Cesium.Color.fromCssColorString(color).withAlpha(0.5),
outline: true,
outlineColor: Cesium.Color.fromCssColorString(color),

49
ruoyi-ui/src/views/childRoom/BottomLeftPanel.vue

@ -31,7 +31,7 @@
<div v-if="activeTab === 'timeline'" class="timeline-content">
<h3>时间线</h3>
<div class="timeline-list">
<div v-for="(item, index) in timelineData" :key="index" class="timeline-item">
<div v-for="(item, index) in timelineData" :key="index" class="timeline-item" :class="{ current: item.current }">
<div class="timeline-dot"></div>
<div class="timeline-info">
<div class="timeline-time">{{ item.time }}</div>
@ -78,11 +78,11 @@ export default {
dialogTitle: '',
activeTab: '',
timelineData: [
{ time: 'K-02:00', event: '任务准备阶段' },
{ time: 'K-01:00', event: '资源调配' },
{ time: 'K时', event: '任务执行' },
{ time: 'K+01:00', event: '任务监控' },
{ time: 'K+02:00', event: '任务完成' }
{ time: 'K-02:00', event: '任务准备阶段', current: false },
{ time: 'K-01:00', event: '资源调配', current: false },
{ time: 'K时', event: '任务执行', current: true },
{ time: 'K+01:00', event: '任务监控', current: false },
{ time: 'K+02:00', event: '任务完成', current: false }
],
progressData: [
{ label: '任务准备', percentage: 100, status: 'success' },
@ -233,6 +233,43 @@ export default {
position: relative;
}
.timeline-item.current {
background: rgba(64, 158, 255, 0.1);
border-radius: 6px;
padding: 8px;
}
.timeline-item.current .timeline-dot {
background: #ff6600;
box-shadow: 0 0 0 4px rgba(255, 102, 0, 0.3);
animation: pulse 2s infinite;
}
.timeline-item.current .timeline-time {
color: #ff6600;
font-weight: 700;
}
.timeline-item.current .timeline-event {
color: #333;
font-weight: 600;
}
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.2);
opacity: 0.7;
}
100% {
transform: scale(1);
opacity: 1;
}
}
.timeline-item::before {
content: '';
position: absolute;

768
ruoyi-ui/src/views/childRoom/TopHeader.vue

@ -0,0 +1,768 @@
<template>
<div class="floating-header">
<div class="header-left">
<div class="system-title">
<i class="el-icon-s-promotion mr-2 logo-icon"></i>
<span class="title-text blue-title">联合任务筹划系统</span>
</div>
<!-- 顶部导航菜单 -->
<div class="top-nav-menu">
<div
v-for="item in topNavItems"
:key="item.id"
class="top-nav-item"
:class="{ active: activeTopNav === item.id }"
@click="selectTopNav(item)"
>
<i :class="item.icon" class="nav-icon"></i>
<span class="nav-text">{{ item.name }}</span>
<!-- 文件下拉菜单 -->
<el-dropdown
v-if="item.id === 'file'"
trigger="click"
placement="bottom-start"
:hide-on-click="false"
class="file-dropdown"
>
<div class="dropdown-trigger"></div>
<el-dropdown-menu slot="dropdown" class="file-dropdown-menu">
<el-dropdown-item @click.native="savePlan">保存</el-dropdown-item>
<!-- 导入二级菜单 -->
<el-dropdown-item class="submenu-item">
<span>导入</span>
<el-dropdown
trigger="hover"
placement="right-start"
class="submenu-dropdown"
>
<div class="submenu-trigger"></div>
<el-dropdown-menu slot="dropdown" class="submenu">
<el-dropdown-item @click.native="importPlanFile">导入计划</el-dropdown-item>
<el-dropdown-item @click.native="importACD">导入ACD</el-dropdown-item>
<el-dropdown-item @click.native="importATO">导入ATO</el-dropdown-item>
<el-dropdown-item @click.native="importLayer">导入图层</el-dropdown-item>
<el-dropdown-item @click.native="importRoute">导入航线</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-dropdown-item>
<el-dropdown-item @click.native="exportPlan">导出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- 编辑下拉菜单 -->
<el-dropdown
v-if="item.id === 'edit'"
trigger="click"
placement="bottom-start"
:hide-on-click="false"
class="file-dropdown"
>
<div class="dropdown-trigger"></div>
<el-dropdown-menu slot="dropdown" class="file-dropdown-menu">
<el-dropdown-item @click.native="routeEdit">航线编辑</el-dropdown-item>
<el-dropdown-item @click.native="militaryMarking">军事标绘</el-dropdown-item>
<el-dropdown-item @click.native="iconEdit">图标编辑</el-dropdown-item>
<el-dropdown-item @click.native="attributeEdit">属性修改</el-dropdown-item>
<!-- 推演编辑二级菜单 -->
<el-dropdown-item class="submenu-item">
<span>推演编辑</span>
<el-dropdown
trigger="hover"
placement="right-start"
class="submenu-dropdown"
>
<div class="submenu-trigger"></div>
<el-dropdown-menu slot="dropdown" class="submenu">
<el-dropdown-item @click.native="timeSettings">时间设置</el-dropdown-item>
<el-dropdown-item @click.native="aircraftSettings">机型设置</el-dropdown-item>
<el-dropdown-item @click.native="keyEventEdit">关键事件编辑</el-dropdown-item>
<el-dropdown-item @click.native="missileLaunch">导弹发射</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- 视图下拉菜单 -->
<el-dropdown
v-if="item.id === 'view'"
trigger="click"
placement="bottom-start"
:hide-on-click="false"
class="file-dropdown"
>
<div class="dropdown-trigger"></div>
<el-dropdown-menu slot="dropdown" class="file-dropdown-menu">
<el-dropdown-item @click.native="toggle2D3D">2D/3D切换</el-dropdown-item>
<el-dropdown-item @click.native="toggleRuler">显示/隐藏标尺</el-dropdown-item>
<el-dropdown-item @click.native="toggleGrid">网格</el-dropdown-item>
<el-dropdown-item @click.native="toggleScale">比例尺</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- 地图下拉菜单 -->
<el-dropdown
v-if="item.id === 'map'"
trigger="click"
placement="bottom-start"
:hide-on-click="false"
class="file-dropdown"
>
<div class="dropdown-trigger"></div>
<el-dropdown-menu slot="dropdown" class="file-dropdown-menu">
<el-dropdown-item @click.native="loadTerrain">加载/切换地形</el-dropdown-item>
<el-dropdown-item @click.native="changeProjection">投影</el-dropdown-item>
<el-dropdown-item @click.native="loadAeroChart">航空图</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- 空域下拉菜单 -->
<el-dropdown
v-if="item.id === 'airspace'"
trigger="click"
placement="bottom-start"
:hide-on-click="false"
class="file-dropdown"
>
<div class="dropdown-trigger"></div>
<el-dropdown-menu slot="dropdown" class="file-dropdown-menu">
<el-dropdown-item @click.native="powerZone">威力区</el-dropdown-item>
<el-dropdown-item @click.native="threatZone">威胁区</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- 工具下拉菜单 -->
<el-dropdown
v-if="item.id === 'tools'"
trigger="click"
placement="bottom-start"
:hide-on-click="false"
class="file-dropdown"
>
<div class="dropdown-trigger"></div>
<el-dropdown-menu slot="dropdown" class="file-dropdown-menu">
<el-dropdown-item @click.native="routeCalculation">航线计算</el-dropdown-item>
<el-dropdown-item @click.native="conflictDisplay">冲突显示</el-dropdown-item>
<el-dropdown-item @click.native="dataMaterials">数据资料</el-dropdown-item>
<el-dropdown-item @click.native="coordinateConversion">坐标换算</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- 选项下拉菜单 -->
<el-dropdown
v-if="item.id === 'options'"
trigger="click"
placement="bottom-start"
:hide-on-click="false"
class="file-dropdown"
>
<div class="dropdown-trigger"></div>
<el-dropdown-menu slot="dropdown" class="file-dropdown-menu">
<!-- 设置二级菜单 -->
<el-dropdown-item class="submenu-item">
<span>设置</span>
<el-dropdown
trigger="hover"
placement="right-start"
class="submenu-dropdown"
>
<div class="submenu-trigger"></div>
<el-dropdown-menu slot="dropdown" class="submenu">
<el-dropdown-item @click.native="pageLayout">页面布局</el-dropdown-item>
<el-dropdown-item @click.native="dataStoragePath">数据存储路径</el-dropdown-item>
<el-dropdown-item @click.native="externalParams">外部参数</el-dropdown-item>
<el-dropdown-item @click.native="toggleAirport">显示/隐藏机场</el-dropdown-item>
<el-dropdown-item @click.native="toggleLandmark">显示/隐藏地标</el-dropdown-item>
<el-dropdown-item @click.native="toggleRoute">显示/隐藏航线</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-dropdown-item>
<el-dropdown-item @click.native="systemDescription">系统说明</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- 收藏下拉菜单 -->
<el-dropdown
v-if="item.id === 'favorites'"
trigger="click"
placement="bottom-start"
:hide-on-click="false"
class="file-dropdown"
>
<div class="dropdown-trigger"></div>
<el-dropdown-menu slot="dropdown" class="file-dropdown-menu">
<el-dropdown-item @click.native="layerFavorites">图层收藏</el-dropdown-item>
<el-dropdown-item @click.native="routeFavorites">航线收藏</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
<div class="header-right">
<!-- 作战信息区域 -->
<div class="combat-info-group">
<!-- 房间编号 -->
<div class="info-box">
<i class="el-icon-office-building info-icon"></i>
<div class="info-content">
<div class="info-label">房间编号</div>
<div class="info-value">{{ roomCode }}</div>
</div>
</div>
<!-- 在线人数 -->
<div class="info-box" @click="showOnlineMembersDialog">
<i class="el-icon-user info-icon"></i>
<div class="info-content">
<div class="info-label">在线人数</div>
<div class="info-value">{{ onlineCount }}</div>
</div>
</div>
<!-- 作战时间 -->
<div class="info-box">
<i class="el-icon-timer info-icon"></i>
<div class="info-content">
<div class="info-label">作战时间</div>
<div class="info-value">{{ combatTime }}</div>
</div>
</div>
<!-- 天文时间 -->
<div class="info-box">
<i class="el-icon-sunny info-icon"></i>
<div class="info-content">
<div class="info-label">天文时间</div>
<div class="info-value">{{ astroTime }}</div>
</div>
</div>
</div>
<!-- 用户状态区域 -->
<div class="user-status-area">
<!-- 用户头像 -->
<el-avatar :size="32" :src="userAvatar" class="user-avatar" />
</div>
</div>
</div>
</template>
<script>
export default {
name: 'TopHeader',
props: {
roomCode: {
type: String,
default: 'JTF-7-ALPHA'
},
onlineCount: {
type: Number,
default: 30
},
combatTime: {
type: String,
default: 'K+01:30:45'
},
astroTime: {
type: String,
default: ''
},
userAvatar: {
type: String,
default: 'https://cube.elemecdn.com/0/88dd03f9bf287d08f58fbcf58fddbf4a8c6/avatar.png'
}
},
data() {
return {
activeTopNav: 'file',
topNavItems: [
{ id: 'file', name: '文件', icon: 'el-icon-document' },
{ id: 'edit', name: '编辑', icon: 'el-icon-edit' },
{ id: 'view', name: '视图', icon: 'el-icon-view' },
{ id: 'map', name: '地图', icon: 'el-icon-map-location' },
{ id: 'airspace', name: '空域', icon: 'el-icon-s-grid' },
{ id: 'tools', name: '工具', icon: 'el-icon-setting' },
{ id: 'options', name: '选项', icon: 'el-icon-s-tools' },
{ id: 'favorites', name: '收藏', icon: 'el-icon-star-on' }
]
}
},
methods: {
selectTopNav(item) {
this.$emit('select-nav', item)
},
//
savePlan() {
this.$emit('save-plan')
},
importPlanFile() {
this.$emit('import-plan-file')
},
importACD() {
this.$emit('import-acd')
},
importATO() {
this.$emit('import-ato')
},
importLayer() {
this.$emit('import-layer')
},
importRoute() {
this.$emit('import-route')
},
exportPlan() {
this.$emit('export-plan')
},
//
routeEdit() {
this.$emit('route-edit')
},
militaryMarking() {
this.$emit('military-marking')
},
iconEdit() {
this.$emit('icon-edit')
},
attributeEdit() {
this.$emit('attribute-edit')
},
timeSettings() {
this.$emit('time-settings')
},
aircraftSettings() {
this.$emit('aircraft-settings')
},
keyEventEdit() {
this.$emit('key-event-edit')
},
missileLaunch() {
this.$emit('missile-launch')
},
//
toggle2D3D() {
this.$emit('toggle-2d-3d')
},
toggleRuler() {
this.$emit('toggle-ruler')
},
toggleGrid() {
this.$emit('toggle-grid')
},
toggleScale() {
this.$emit('toggle-scale')
},
//
loadTerrain() {
this.$emit('load-terrain')
},
changeProjection() {
this.$emit('change-projection')
},
loadAeroChart() {
this.$emit('load-aero-chart')
},
//
powerZone() {
this.$emit('power-zone')
},
threatZone() {
this.$emit('threat-zone')
},
//
routeCalculation() {
this.$emit('route-calculation')
},
conflictDisplay() {
this.$emit('conflict-display')
},
dataMaterials() {
this.$emit('data-materials')
},
coordinateConversion() {
this.$emit('coordinate-conversion')
},
//
pageLayout() {
this.$emit('page-layout')
},
dataStoragePath() {
this.$emit('data-storage-path')
},
externalParams() {
this.$emit('external-params')
},
toggleAirport() {
this.$emit('toggle-airport')
},
toggleLandmark() {
this.$emit('toggle-landmark')
},
toggleRoute() {
this.$emit('toggle-route')
},
systemDescription() {
this.$emit('system-description')
},
//
layerFavorites() {
this.$emit('layer-favorites')
},
routeFavorites() {
this.$emit('route-favorites')
},
showOnlineMembersDialog() {
this.$emit('show-online-members')
}
}
}
</script>
<style scoped>
/* 顶部导航栏 - 最终优化设计 */
.floating-header {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 60px;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: space-between;
z-index: 100;
backdrop-filter: blur(15px);
background: rgba(255, 255, 255, 0.85);
border-bottom: 1px solid rgba(0, 138, 255, 0.2);
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.header-left {
display: flex;
align-items: center;
gap: 25px;
flex: 1;
}
.system-title {
display: flex;
align-items: center;
font-size: 18px;
font-weight: bold;
min-width: 180px;
}
.system-title i {
font-size: 24px;
color: #008aff;
}
.blue-title {
color: #008aff !important;
}
/* 顶部导航菜单 - 优化为简洁文字效果 */
.top-nav-menu {
display: flex;
gap: 0;
flex: 1;
overflow-x: auto;
max-width: 800px;
padding: 5px 0;
scrollbar-width: thin;
}
.top-nav-menu::-webkit-scrollbar {
height: 3px;
}
.top-nav-menu::-webkit-scrollbar-track {
background: rgba(0, 138, 255, 0.1);
border-radius: 2px;
}
.top-nav-menu::-webkit-scrollbar-thumb {
background: rgba(0, 138, 255, 0.3);
border-radius: 2px;
}
.top-nav-item {
display: flex;
align-items: center;
gap: 6px;
padding: 8px 12px;
cursor: pointer;
font-size: 13px;
font-weight: 600;
color: #333;
transition: all 0.3s;
border-radius: 4px;
white-space: nowrap;
min-width: 60px;
justify-content: center;
margin: 0 1px;
position: relative;
flex-shrink: 0;
}
.top-nav-item:hover {
color: #008aff;
background: rgba(0, 138, 255, 0.05);
}
.top-nav-item.active {
color: #008aff;
font-weight: 700;
}
/* 移除了蓝色指示条 */
.top-nav-item.active::after {
display: none;
}
.nav-icon {
font-size: 16px;
transition: all 0.3s;
}
.top-nav-item:hover .nav-icon,
.top-nav-item.active .nav-icon {
transform: scale(1.1);
}
.nav-text {
font-size: 13px;
font-weight: 600;
transition: all 0.3s;
}
/* 下拉菜单样式 */
.file-dropdown {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.dropdown-trigger {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.file-dropdown-menu {
margin-top: 5px;
margin-bottom: 0;
border: none;
border-radius: 6px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(15px);
background: rgba(255, 255, 255, 0.85);
border: 1px solid rgba(0, 138, 255, 0.2);
padding: 0;
min-width: auto;
width: fit-content;
}
.file-dropdown-menu .el-dropdown-menu__item {
padding: 8px 16px;
font-size: 14px;
color: #333;
transition: all 0.2s ease;
margin: 0;
}
.file-dropdown-menu .el-dropdown-menu__item:hover {
background: rgba(0, 138, 255, 0.1);
color: #008aff;
}
.file-dropdown-menu .el-dropdown-menu__item:not(:last-child) {
border-bottom: 1px solid rgba(0, 138, 255, 0.1);
}
.file-dropdown-menu .el-dropdown-menu__item:last-child {
border-bottom: none;
}
.submenu-item {
position: relative;
}
.submenu-dropdown {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.submenu-trigger {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.submenu {
margin-left: 5px;
margin-bottom: 0;
border: none;
border-radius: 6px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(15px);
background: rgba(255, 255, 255, 0.85);
border: 1px solid rgba(0, 138, 255, 0.2);
padding: 0;
min-width: auto;
width: fit-content;
}
.submenu .el-dropdown-menu__item {
padding: 8px 16px;
font-size: 14px;
color: #333;
transition: all 0.2s ease;
margin: 0;
}
.submenu .el-dropdown-menu__item:hover {
background: rgba(0, 138, 255, 0.1);
color: #008aff;
}
.submenu .el-dropdown-menu__item:not(:last-child) {
border-bottom: 1px solid rgba(0, 138, 255, 0.1);
}
.submenu .el-dropdown-menu__item:last-child {
border-bottom: none;
}
/* 右侧信息区域 */
.header-right {
display: flex;
align-items: center;
gap: 20px;
}
.combat-info-group {
display: flex;
align-items: center;
gap: 15px;
}
.info-box {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: rgba(255, 255, 255, 0.6);
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
border: 1px solid rgba(0, 138, 255, 0.1);
}
.info-box:hover {
background: rgba(0, 138, 255, 0.1);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 138, 255, 0.2);
}
.combat-info-group .info-box:nth-child(3) .info-value {
color: #409EFF;
font-weight: 600;
}
.combat-info-group .info-box:nth-child(4) .info-value {
color: #67c23a;
font-weight: 600;
}
.info-icon {
font-size: 20px;
color: #008aff;
}
.info-content {
display: flex;
flex-direction: column;
gap: 2px;
}
.info-label {
font-size: 11px;
color: #666;
}
.info-value {
font-size: 13px;
color: #333;
font-weight: 600;
}
.user-status-area {
display: flex;
align-items: center;
}
.user-avatar {
cursor: pointer;
transition: all 0.3s;
}
.user-avatar:hover {
transform: scale(1.1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
</style>

1541
ruoyi-ui/src/views/childRoom/index.vue

File diff suppressed because it is too large
Loading…
Cancel
Save