You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1133 lines
33 KiB

<template>
<div class="floating-header">
<div class="header-left">
<div class="system-title">
<!-- 按照实际路径引入logo.jpg -->
<img
src="@/views/childRoom/logo.png"
class="logo-icon mr-2"
alt="系统logo"
style="width:24px; height:24px; object-fit:contain;"
>
<span class="title-text blue-title">{{ $t('topHeader.systemTitle') }}</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="newPlan">{{ $t('topHeader.file.newPlan') }}</el-dropdown-item>
<el-dropdown-item @click.native="openPlan">{{ $t('topHeader.file.open') }}</el-dropdown-item>
<el-dropdown-item @click.native="savePlan">{{ $t('topHeader.file.save') }}</el-dropdown-item>
<el-dropdown-item class="submenu-item">
<span>{{ $t('topHeader.file.import') }}</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">{{ $t('topHeader.file.importPlan') }}</el-dropdown-item>
<el-dropdown-item @click.native="importACD">{{ $t('topHeader.file.importACD') }}</el-dropdown-item>
<el-dropdown-item @click.native="importATO">{{ $t('topHeader.file.importATO') }}</el-dropdown-item>
<el-dropdown-item @click.native="importLayer">{{ $t('topHeader.file.importLayer') }}</el-dropdown-item>
<el-dropdown-item @click.native="importRoute">{{ $t('topHeader.file.importRoute') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-dropdown-item>
<el-dropdown-item class="submenu-item">
<span>{{ $t('topHeader.file.export') }}</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="exportRoute">{{ $t('topHeader.file.exportRoute') }}</el-dropdown-item>
<el-dropdown-item @click.native="exportPlan">{{ $t('topHeader.file.exportPlan') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</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">{{ $t('topHeader.edit.routeEdit') }}</el-dropdown-item>
<el-dropdown-item @click.native="militaryMarking">{{ $t('topHeader.edit.militaryMarking') }}</el-dropdown-item>
<el-dropdown-item @click.native="iconEdit">{{ $t('topHeader.edit.iconEdit') }}</el-dropdown-item>
<el-dropdown-item @click.native="attributeEdit">{{ $t('topHeader.edit.attributeEdit') }}</el-dropdown-item>
<el-dropdown-item class="submenu-item">
<span>{{ $t('topHeader.edit.deductionEdit') }}</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">{{ $t('topHeader.edit.timeSettings') }}</el-dropdown-item>
<el-dropdown-item @click.native="aircraftSettings">{{ $t('topHeader.edit.aircraftSettings') }}</el-dropdown-item>
<el-dropdown-item @click.native="keyEventEdit">{{ $t('topHeader.edit.keyEventEdit') }}</el-dropdown-item>
<el-dropdown-item @click.native="missileLaunch">{{ $t('topHeader.edit.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">{{ is2DMode ? $t('topHeader.view.view3D') : $t('topHeader.view.view2D') }}</el-dropdown-item>
<el-dropdown-item @click.native="toggleRuler">{{ isRulerVisible ? $t('topHeader.view.hideRuler') : $t('topHeader.view.showRuler') }}</el-dropdown-item>
<el-dropdown-item @click.native="toggleGrid">{{ $t('topHeader.view.grid') }}</el-dropdown-item>
<el-dropdown-item @click.native="toggleScale">{{ $t('topHeader.view.scale') }}</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">{{ $t('topHeader.map.loadTerrain') }}</el-dropdown-item>
<el-dropdown-item @click.native="changeProjection">{{ $t('topHeader.map.projection') }}</el-dropdown-item>
<el-dropdown-item @click.native="loadAeroChart">{{ $t('topHeader.map.aeroChart') }}</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">{{ $t('topHeader.airspace.powerZone') }}</el-dropdown-item>
<el-dropdown-item @click.native="threatZone">{{ $t('topHeader.airspace.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">{{ $t('topHeader.tools.routeCalculation') }}</el-dropdown-item>
<el-dropdown-item @click.native="conflictDisplay">{{ $t('topHeader.tools.conflictDisplay') }}</el-dropdown-item>
<el-dropdown-item @click.native="dataMaterials">{{ $t('topHeader.tools.dataMaterials') }}</el-dropdown-item>
<el-dropdown-item @click.native="coordinateConversion">{{ $t('topHeader.tools.coordinateConversion') }}</el-dropdown-item>
<el-dropdown-item @click.native="generateGanttChart">{{ $t('topHeader.tools.generateGanttChart') }}</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>{{ $t('topHeader.options.settings') }}</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">{{ $t('topHeader.options.pageLayout') }}</el-dropdown-item>
<el-dropdown-item @click.native="dataStoragePath">{{ $t('topHeader.options.dataStoragePath') }}</el-dropdown-item>
<el-dropdown-item @click.native="externalParams">{{ $t('topHeader.options.externalParams') }}</el-dropdown-item>
<el-dropdown-item @click.native="toggleAirport">{{ isAirportVisible ? $t('topHeader.options.hideAirport') : $t('topHeader.options.showAirport') }}</el-dropdown-item>
<el-dropdown-item @click.native="toggleLandmark">{{ isLandmarkVisible ? $t('topHeader.options.hideLandmark') : $t('topHeader.options.showLandmark') }}</el-dropdown-item>
<el-dropdown-item @click.native="toggleRoute">{{ isRouteVisible ? $t('topHeader.options.hideRoute') : $t('topHeader.options.showRoute') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-dropdown-item>
<el-dropdown-item @click.native="systemDescription">{{ $t('topHeader.options.systemDescription') }}</el-dropdown-item>
<el-dropdown-item @click.native="toggleLanguage">
<i class="el-icon-s-tools"></i>
{{ $t('topHeader.options.language') }}
<span style="float: right; color: #8492a6; font-size: 13px">{{ $i18n.locale === 'zh' ? '中文' : 'English' }}</span>
</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">{{ $t('topHeader.favorites.layerFavorites') }}</el-dropdown-item>
<el-dropdown-item @click.native="routeFavorites">{{ $t('topHeader.favorites.routeFavorites') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
<div class="header-right">
<!-- 地图拖动开关:点击小手图标后才允许拖动地图 -->
<div
class="map-drag-toggle"
:class="{ active: mapDragEnabled }"
:title="mapDragEnabled ? '已开启拖动,点击可关闭' : '点击开启地图拖动'"
@click="$emit('toggle-map-drag')"
>
<svg class="hand-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="20" height="20">
<path d="M18 11.5V9a2 2 0 0 0-2-2 2 2 0 0 0-2 2v1.4" />
<path d="M14 10V8a2 2 0 0 0-2-2 2 2 0 0 0-2 2v2" />
<path d="M10 9.9V9a2 2 0 0 0-2-2 2 2 0 0 0-2 2v5" />
<path d="M6 14a2 2 0 0 0-2-2 2 2 0 0 0-2 2" />
<path d="M18 11a2 2 0 1 1 4 0v3a8 8 0 0 1-8 8h-4a8 8 0 0 1-8-8 2 2 0 1 1 4 0" />
</svg>
<span class="map-drag-label">{{ mapDragEnabled ? '拖动开' : '拖动' }}</span>
</div>
<!-- 作战信息区域 -->
<div class="combat-info-group">
<div
class="info-box room-name-box clickable"
@click="handleBackToSelectRoom"
>
<i class="el-icon-office-building info-icon"></i>
<div class="info-content">
<div class="info-label">{{ $t('topHeader.info.roomName') }}</div>
<div class="info-value">{{ roomDisplayName }}</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">{{ $t('topHeader.info.onlineCount') }}</div>
<div class="info-value">{{ onlineCount }}{{ $t('topHeader.info.people') }}</div>
</div>
</div>
<div
class="info-box combat-time-box"
:class="{ 'clickable': !(childRoomKTimes && childRoomKTimes.length > 0) && canSetKTime }"
>
<i class="el-icon-timer info-icon"></i>
<div class="info-content combat-time-content">
<template v-if="childRoomKTimes && childRoomKTimes.length > 0">
<el-dropdown trigger="click" @command="handleSelectChildKTime" class="k-time-dropdown">
<div class="combat-k-time k-time-selectable">
<span class="k-time-label">{{ currentChildKTimeItem.name }}:</span>
<span class="k-time-value">{{ formatChildKTime(currentChildKTimeItem.kAnchorTime) }}</span>
<i class="el-icon-arrow-down k-time-arrow"></i>
</div>
<el-dropdown-menu slot="dropdown" class="k-time-dropdown-menu">
<el-dropdown-item v-for="(item, idx) in childRoomKTimes" :key="idx" :command="idx">
{{ item.name }}: {{ formatChildKTime(item.kAnchorTime) }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<div v-else-if="kTimeDisplay" class="combat-k-time" @click="canSetKTime && $emit('set-k-time')">
<span class="k-time-label">K </span>
<span class="k-time-value">{{ kTimeDisplay }}</span>
</div>
<div class="combat-time-row">
<span class="info-label">{{ $t('topHeader.info.combatTime') }}</span>
<span class="combat-time-value">
{{ combatTime }}
<i v-if="canSetKTime" class="el-icon-edit-outline set-k-hint" title="点击设定或修改 K 时(房主/管理员可随时更改)"></i>
</span>
</div>
</div>
</div>
<div class="info-box">
<i class="el-icon-sunny info-icon"></i>
<div class="info-content">
<div class="info-label">{{ $t('topHeader.info.astroTime') }}</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>
<!-- 比例尺弹窗 -->
<scale-dialog
v-model="scaleDialogVisible"
:scale="currentScale"
@save="saveScale"
/>
<!-- 外部参数弹窗 -->
<external-params-dialog
v-model="externalParamsDialogVisible"
:external-params="currentExternalParams"
@save="saveExternalParams"
@import-airport="importAirport"
@import-route-data="importRoute"
@import-landmark="importLandmark"
/>
</div>
</template>
<script>
import ScaleDialog from '../dialogs/ScaleDialog'
import ExternalParamsDialog from '../dialogs/ExternalParamsDialog'
export default {
name: 'TopHeader',
components: {
ScaleDialog,
ExternalParamsDialog
},
props: {
roomCode: {
type: String,
default: 'JTF-7-ALPHA'
},
onlineCount: {
type: Number,
default: 30
},
combatTime: {
type: String,
default: 'K+01:30:45'
},
/** 格式化的 K 时基准时刻,如 "2025-02-06 08:00:00";小房间时使用 */
kTimeDisplay: {
type: String,
default: ''
},
/** 大房间时多个子房间的 K 时,格式 [{ name, kAnchorTime }],有值时优先展示此列表 */
childRoomKTimes: {
type: Array,
default: () => []
},
/** 大房间时当前选中的子房间索引 */
selectedChildKTimeIndex: {
type: Number,
default: 0
},
astroTime: {
type: String,
default: ''
},
roomDetail: {
type: Object,
default: null
},
canSetKTime: {
type: Boolean,
default: false
},
userAvatar: {
type: String,
default: 'https://cube.elemecdn.com/0/88dd03f9bf287d08f58fbcf58fddbf4a8c6/avatar.png'
},
isIconEditMode: {
type: Boolean,
default: false
},
currentScaleConfig: {
type: Object,
default: () => ({
scaleNumerator: 1,
scaleDenominator: 1000,
unit: 'm'
})
},
/** 是否允许地图拖动(与小手图标联动) */
mapDragEnabled: {
type: Boolean,
default: false
}
},
data() {
return {
activeTopNav: 'file',
scaleDialogVisible: false,
currentScale: {},
externalParamsDialogVisible: false,
currentExternalParams: {},
is2DMode: true,
isRulerVisible: true,
isAirportVisible: true,
isLandmarkVisible: true,
isRouteVisible: true
}
},
computed: {
/** 大房间时当前选中的子房间 K 时项 */
currentChildKTimeItem() {
if (!this.childRoomKTimes || this.childRoomKTimes.length === 0) return { name: '-', kAnchorTime: null };
const idx = Math.max(0, Math.min(this.selectedChildKTimeIndex, this.childRoomKTimes.length - 1));
return this.childRoomKTimes[idx];
},
/** 显示数据库房间名,无则回退为房间编号;大房间时追加标识 */
roomDisplayName() {
const name = (this.roomDetail && this.roomDetail.name) ? this.roomDetail.name : this.roomCode;
const isParentRoom = this.roomDetail && this.roomDetail.parentId == null;
return isParentRoom ? `${name}(大房间)` : name;
},
topNavItems() {
return [
{ id: 'file', name: this.$t('topHeader.nav.file'), icon: 'el-icon-document' },
{ id: 'edit', name: this.$t('topHeader.nav.edit'), icon: 'el-icon-edit' },
{ id: 'view', name: this.$t('topHeader.nav.view'), icon: 'el-icon-view' },
{ id: 'map', name: this.$t('topHeader.nav.map'), icon: 'el-icon-map-location' },
{ id: 'airspace', name: this.$t('topHeader.nav.airspace'), icon: 'el-icon-s-grid' },
{ id: 'tools', name: this.$t('topHeader.nav.tools'), icon: 'el-icon-setting' },
{ id: 'options', name: this.$t('topHeader.nav.options'), icon: 'el-icon-s-tools' },
{ id: 'favorites', name: this.$t('topHeader.nav.favorites'), icon: 'el-icon-star-on' }
]
}
},
watch: {
currentScaleConfig: {
deep: true,
handler(newVal) {
if (newVal) {
this.currentScale = { ...newVal }
}
}
}
},
methods: {
/** 点击房间名称:弹窗确认是否回到选择房间页面 */
handleBackToSelectRoom() {
this.$confirm('是否返回选择房间页面?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
}).then(() => {
this.$router.push({ path: '/selectRoom' }).catch(() => {})
}).catch(() => {})
},
selectTopNav(item) {
this.$emit('select-nav', item)
},
// 文件下拉菜单新增方法
newPlan() {
this.$emit('new-plan')
},
openPlan() {
this.$emit('open-plan')
},
// 文件下拉菜单方法
savePlan() {
if (this.isIconEditMode) {
this.$emit('toggle-icon-edit', false)
} else {
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')
},
exportRoute() {
this.$emit('export-routes')
},
exportPlan() {
this.$emit('export-plan')
},
// 编辑下拉菜单方法
routeEdit() {
this.$emit('route-edit')
},
militaryMarking() {
this.$emit('military-marking')
},
iconEdit() {
if (this.isIconEditMode) {
this.$emit('toggle-icon-edit', false)
} else {
this.$emit('toggle-icon-edit', true)
}
},
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.is2DMode = !this.is2DMode
this.$emit('toggle-2d-3d', this.is2DMode)
},
toggleRuler() {
this.isRulerVisible = !this.isRulerVisible
this.$emit('toggle-ruler', this.isRulerVisible)
},
toggleGrid() {
this.$emit('toggle-grid')
},
toggleScale() {
this.scaleDialogVisible = true
this.currentScale = {}
},
// 地图下拉菜单方法
loadTerrain() {
this.$emit('load-terrain')
},
changeProjection() {
this.$emit('change-projection')
},
loadAeroChart() {
this.$emit('load-aero-chart')
},
// 空域下拉菜单方法
powerZone() {
this.$emit('start-power-zone-drawing')
},
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.externalParamsDialogVisible = true
this.currentExternalParams = {}
},
toggleAirport() {
this.isAirportVisible = !this.isAirportVisible
this.$emit('toggle-airport', this.isAirportVisible)
},
toggleLandmark() {
this.isLandmarkVisible = !this.isLandmarkVisible
this.$emit('toggle-landmark', this.isLandmarkVisible)
},
toggleRoute() {
this.isRouteVisible = !this.isRouteVisible
this.$emit('toggle-route', this.isRouteVisible)
},
generateGanttChart() {
this.$emit('generate-gantt-chart')
},
systemDescription() {
this.$emit('system-description')
},
toggleLanguage() {
const newLocale = this.$i18n.locale === 'zh' ? 'en' : 'zh'
this.$i18n.locale = newLocale
localStorage.setItem('language', newLocale)
this.$emit('language-changed', newLocale)
},
// 收藏下拉菜单方法
layerFavorites() {
this.$emit('layer-favorites')
},
routeFavorites() {
this.$emit('route-favorites')
},
showOnlineMembersDialog() {
this.$emit('show-online-members')
},
handleSelectChildKTime(idx) {
this.$emit('select-child-k-time', idx);
},
formatChildKTime(val) {
if (!val) return '-'
const d = new Date(val)
if (isNaN(d.getTime())) return '-'
const y = d.getFullYear()
const m = (d.getMonth() + 1).toString().padStart(2, '0')
const day = d.getDate().toString().padStart(2, '0')
const h = d.getHours().toString().padStart(2, '0')
const min = d.getMinutes().toString().padStart(2, '0')
const s = d.getSeconds().toString().padStart(2, '0')
return `${y}-${m}-${day} ${h}:${min}:${s}`
},
// 威力区弹窗方法
savePowerZone(powerZone) {
this.$emit('save-power-zone', powerZone)
},
// 比例尺弹窗方法
saveScale(scale) {
this.$emit('save-scale', scale)
},
// 外部参数弹窗方法
saveExternalParams(externalParams) {
this.$emit('save-external-params', externalParams)
},
importAirport(path) {
this.$emit('import-airport', path)
},
importRoute(path) {
this.$emit('import-route-data', path)
},
importLandmark(path) {
this.$emit('import-landmark', path)
}
}
}
</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.3);
border-bottom: 1px solid rgba(0, 138, 255, 0.1);
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
}
.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;
}
/* 新增logo图片样式,保证显示效果 */
.logo-icon {
width: 24px;
height: 24px;
object-fit: contain;
}
.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.9);
border: 1px solid rgba(0, 138, 255, 0.1);
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.9);
border: 1px solid rgba(0, 138, 255, 0.1);
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;
}
.map-drag-toggle {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 10px;
border-radius: 6px;
cursor: pointer;
color: #909399;
transition: color 0.2s, background 0.2s;
}
.map-drag-toggle:hover {
color: #409eff;
background: rgba(64, 158, 255, 0.08);
}
.map-drag-toggle.active {
color: #409eff;
background: rgba(64, 158, 255, 0.12);
}
.map-drag-toggle .hand-icon {
flex-shrink: 0;
}
.map-drag-toggle .map-drag-label {
font-size: 13px;
white-space: nowrap;
}
.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.5);
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
border: 1px solid rgba(0, 138, 255, 0.05);
}
.info-box:hover {
background: rgba(0, 138, 255, 0.1);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 138, 255, 0.1);
}
/* 作战时间区域:显示 K 时 + 当前作战时间 */
.combat-time-box {
min-width: 180px;
}
.k-time-dropdown {
width: 100%;
}
.k-time-selectable {
cursor: pointer;
display: flex;
align-items: center;
gap: 6px;
padding: 2px 0;
}
.k-time-selectable:hover {
color: #008aff;
}
.k-time-arrow {
font-size: 12px;
margin-left: 4px;
color: #008aff;
}
.k-time-dropdown-menu .el-dropdown-menu__item {
padding: 8px 16px;
}
.combat-time-content {
gap: 6px;
flex-wrap: wrap;
}
.combat-k-time {
display: flex;
align-items: center;
gap: 6px;
font-size: 11px;
color: #666;
}
.combat-k-time .k-time-label {
color: #008aff;
font-weight: 600;
flex-shrink: 0;
}
.combat-k-time .k-time-value {
color: #333;
font-weight: 500;
}
.combat-time-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.combat-time-row .info-label {
flex-shrink: 0;
}
.combat-time-value {
font-size: 14px;
color: #008aff;
font-weight: 700;
letter-spacing: 0.5px;
}
.combat-info-group .info-box:nth-child(4) .info-value {
color: #67c23a;
font-weight: 600;
}
.info-box.clickable {
cursor: pointer;
}
.info-box .set-k-hint {
margin-left: 4px;
font-size: 12px;
color: #008aff;
vertical-align: middle;
}
.combat-time-box .set-k-hint {
opacity: 0.85;
}
.combat-time-box .set-k-hint:hover {
opacity: 1;
}
.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.1);
}
</style>