Browse Source
# Conflicts: # ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml # ruoyi-ui/src/views/cesiumMap/index.vue # ruoyi-ui/src/views/selectRoom/index.vuemaster
13 changed files with 2947 additions and 2169 deletions
Binary file not shown.
@ -0,0 +1,128 @@ |
|||
<template> |
|||
<div class="drawing-toolbar" v-if="drawDomClick"> |
|||
<div class="toolbar-icons"> |
|||
<div |
|||
v-for="item in toolbarItems" |
|||
:key="item.id" |
|||
class="toolbar-item" |
|||
:class="{ active: drawingMode === item.id }" |
|||
@click="handleItemClick(item)" |
|||
:title="item.name" |
|||
> |
|||
<i :class="item.icon"></i> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'DrawingToolbar', |
|||
props: { |
|||
drawDomClick: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
drawingMode: { |
|||
type: String, |
|||
default: null |
|||
}, |
|||
hasEntities: { |
|||
type: Boolean, |
|||
default: false |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
toolbarItems: [ |
|||
{ id: 'point', name: '点', icon: 'el-icon-location' }, |
|||
{ id: 'line', name: '线', icon: 'el-icon-edit-outline' }, |
|||
{ id: 'polygon', name: '面', icon: 'el-icon-s-grid' }, |
|||
{ id: 'rectangle', name: '矩形', icon: 'el-icon-s-data' }, |
|||
{ id: 'circle', name: '圆形', icon: 'el-icon-circle-plus-outline' }, |
|||
{ id: 'locate', name: '定位', icon: 'el-icon-aim' }, |
|||
{ id: 'clear', name: '清除', icon: 'el-icon-delete' }, |
|||
{ id: 'import', name: '导入', icon: 'el-icon-upload' }, |
|||
{ id: 'export', name: '导出', icon: 'el-icon-download' } |
|||
] |
|||
} |
|||
}, |
|||
methods: { |
|||
handleItemClick(item) { |
|||
if (item.id === 'clear') { |
|||
this.$emit('clear-all') |
|||
} else if (item.id === 'export') { |
|||
this.$emit('export-data') |
|||
} else if (item.id === 'import') { |
|||
this.$emit('import-data') |
|||
} else if (item.id === 'locate') { |
|||
this.$emit('locate') |
|||
} else { |
|||
this.$emit('toggle-drawing', item.id) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.drawing-toolbar { |
|||
position: absolute; |
|||
top: 70px; |
|||
right: 20px; |
|||
width: 40px; |
|||
background: rgba(255, 255, 255, 0.3); |
|||
backdrop-filter: blur(10px); |
|||
border: 1px solid rgba(0, 138, 255, 0.1); |
|||
border-radius: 8px; |
|||
z-index: 90; |
|||
box-shadow: 0 4px 12px rgba(0, 138, 255, 0.2); |
|||
padding: 15px 5px; |
|||
transition: all 0.3s ease; |
|||
overflow: hidden; |
|||
opacity: 1; |
|||
transform: translateX(0); |
|||
} |
|||
|
|||
.toolbar-icons { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10px; |
|||
margin-top: 30px; |
|||
} |
|||
|
|||
.toolbar-item { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 40px; |
|||
cursor: pointer; |
|||
color: #555; |
|||
font-size: 20px; |
|||
position: relative; |
|||
transition: all 0.3s; |
|||
border-radius: 4px; |
|||
padding: 0 5px; |
|||
background: rgba(255, 255, 255, 0.8); |
|||
backdrop-filter: blur(5px); |
|||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.toolbar-item:hover { |
|||
background: rgba(0, 138, 255, 0.1); |
|||
color: #008aff; |
|||
transform: translateY(-2px); |
|||
box-shadow: 0 4px 10px rgba(0, 138, 255, 0.2); |
|||
} |
|||
|
|||
.toolbar-item.active { |
|||
background: rgba(0, 138, 255, 0.15); |
|||
color: #008aff; |
|||
box-shadow: 0 2px 8px rgba(0, 138, 255, 0.3); |
|||
} |
|||
|
|||
.toolbar-item:disabled { |
|||
opacity: 0.5; |
|||
cursor: not-allowed; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,104 @@ |
|||
<template> |
|||
<div class="measurement-panel"> |
|||
<div class="measurement-content"> |
|||
<h5>测量结果</h5> |
|||
<div class="measurement-item" v-if="result.distance"> |
|||
<span>长度:</span> |
|||
<strong>{{ result.distance.toFixed(2) }} 米</strong> |
|||
</div> |
|||
<div class="measurement-item" v-if="result.area"> |
|||
<span>面积:</span> |
|||
<strong>{{ result.area.toFixed(2) }} 平方米</strong> |
|||
</div> |
|||
<div class="measurement-item" v-if="result.radius"> |
|||
<span>半径:</span> |
|||
<strong>{{ result.radius.toFixed(2) }} 米</strong> |
|||
</div> |
|||
<button @click="handleClose" class="close-btn">关闭</button> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'MeasurementPanel', |
|||
props: { |
|||
result: { |
|||
type: Object, |
|||
default: null |
|||
} |
|||
}, |
|||
methods: { |
|||
handleClose() { |
|||
this.$emit('close') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.measurement-panel { |
|||
position: absolute; |
|||
bottom: 20px; |
|||
right: 80px; |
|||
z-index: 85; |
|||
background: rgba(255, 255, 255, 0.95); |
|||
backdrop-filter: blur(10px); |
|||
border-radius: 12px; |
|||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); |
|||
padding: 20px; |
|||
min-width: 250px; |
|||
} |
|||
|
|||
.measurement-content h5 { |
|||
margin: 0 0 15px 0; |
|||
font-size: 16px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
border-bottom: 2px solid #409EFF; |
|||
padding-bottom: 8px; |
|||
} |
|||
|
|||
.measurement-item { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 12px; |
|||
font-size: 14px; |
|||
color: #666; |
|||
} |
|||
|
|||
.measurement-item strong { |
|||
color: #409EFF; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.close-btn { |
|||
width: 100%; |
|||
padding: 10px; |
|||
background: #409EFF; |
|||
color: white; |
|||
border: none; |
|||
border-radius: 6px; |
|||
cursor: pointer; |
|||
font-size: 14px; |
|||
font-weight: 500; |
|||
transition: all 0.3s; |
|||
margin-top: 15px; |
|||
} |
|||
|
|||
.close-btn:hover { |
|||
background: #66b1ff; |
|||
transform: translateY(-2px); |
|||
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3); |
|||
} |
|||
|
|||
@media (max-width: 768px) { |
|||
.measurement-panel { |
|||
bottom: 10px; |
|||
right: 10px; |
|||
left: 10px; |
|||
min-width: auto; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,428 @@ |
|||
<template> |
|||
<div class="bottom-left-panel"> |
|||
<div class="panel-toggle" @click="togglePanel" :title="isExpanded ? '收起' : '展开'"> |
|||
<i :class="isExpanded ? 'el-icon-s-fold' : 'el-icon-s-unfold'"></i> |
|||
<span v-if="!isExpanded" class="toggle-text">工具</span> |
|||
</div> |
|||
|
|||
<div class="panel-content" :class="{ expanded: isExpanded }"> |
|||
<div class="panel-item" @click="showTimeline"> |
|||
<i class="el-icon-time"></i> |
|||
<span>时间线</span> |
|||
</div> |
|||
<div class="panel-item" @click="showProgress"> |
|||
<i class="el-icon-s-data"></i> |
|||
<span>进度检查</span> |
|||
</div> |
|||
<div class="panel-item" @click="showSixSteps"> |
|||
<i class="el-icon-s-operation"></i> |
|||
<span>六步法</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<el-dialog |
|||
:visible.sync="dialogVisible" |
|||
:title="dialogTitle" |
|||
width="350px" |
|||
:modal="false" |
|||
custom-class="panel-dialog" |
|||
> |
|||
<div class="dialog-content"> |
|||
<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" :class="{ current: item.current }"> |
|||
<div class="timeline-dot"></div> |
|||
<div class="timeline-info"> |
|||
<div class="timeline-time">{{ item.time }}</div> |
|||
<div class="timeline-event">{{ item.event }}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div v-if="activeTab === 'progress'" class="progress-content"> |
|||
<h3>进度检查</h3> |
|||
<div class="progress-list"> |
|||
<div v-for="(item, index) in progressData" :key="index" class="progress-item"> |
|||
<div class="progress-label">{{ item.label }}</div> |
|||
<el-progress :percentage="item.percentage" :status="item.status"></el-progress> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div v-if="activeTab === 'sixsteps'" class="sixsteps-content"> |
|||
<h3>六步法</h3> |
|||
<div class="steps-container"> |
|||
<div v-for="(step, index) in sixStepsData" :key="index" class="step-item" :class="{ active: step.active, completed: step.completed }"> |
|||
<div class="step-number">{{ index + 1 }}</div> |
|||
<div class="step-content"> |
|||
<div class="step-title">{{ step.title }}</div> |
|||
<div class="step-desc">{{ step.desc }}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'BottomLeftPanel', |
|||
data() { |
|||
return { |
|||
isExpanded: false, |
|||
dialogVisible: false, |
|||
dialogTitle: '', |
|||
activeTab: '', |
|||
timelineData: [ |
|||
{ 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' }, |
|||
{ label: '资源调配', percentage: 80, status: '' }, |
|||
{ label: '任务执行', percentage: 45, status: '' }, |
|||
{ label: '任务监控', percentage: 20, status: 'exception' }, |
|||
{ label: '任务完成', percentage: 0, status: '' } |
|||
], |
|||
sixStepsData: [ |
|||
{ title: '理解', desc: '明确任务目标和要求', active: true, completed: true }, |
|||
{ title: '判断', desc: '评估可用资源和能力', active: false, completed: true }, |
|||
{ title: '规划', desc: '制定详细执行方案', active: false, completed: false }, |
|||
{ title: '准备', desc: '识别和评估潜在风险', active: false, completed: false }, |
|||
{ title: '执行', desc: '实时监控执行过程', active: false, completed: false }, |
|||
{ title: '评估', desc: '评估任务完成效果', active: false, completed: false } |
|||
] |
|||
} |
|||
}, |
|||
methods: { |
|||
togglePanel() { |
|||
this.isExpanded = !this.isExpanded |
|||
}, |
|||
showTimeline() { |
|||
this.activeTab = 'timeline' |
|||
this.dialogTitle = '时间线' |
|||
this.dialogVisible = true |
|||
}, |
|||
showProgress() { |
|||
this.activeTab = 'progress' |
|||
this.dialogTitle = '进度检查' |
|||
this.dialogVisible = true |
|||
}, |
|||
showSixSteps() { |
|||
this.activeTab = 'sixsteps' |
|||
this.dialogTitle = '六步法' |
|||
this.dialogVisible = true |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.bottom-left-panel { |
|||
position: absolute; |
|||
bottom: 20px; |
|||
left: 20px; |
|||
z-index: 100; |
|||
} |
|||
|
|||
.panel-toggle { |
|||
width: 50px; |
|||
height: 50px; |
|||
background: rgba(0, 138, 255, 0.9); |
|||
border-radius: 50%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
cursor: pointer; |
|||
color: white; |
|||
font-size: 20px; |
|||
box-shadow: 0 4px 12px rgba(0, 138, 255, 0.4); |
|||
transition: all 0.3s; |
|||
} |
|||
|
|||
.panel-toggle:hover { |
|||
transform: scale(1.1); |
|||
box-shadow: 0 6px 16px rgba(0, 138, 255, 0.6); |
|||
} |
|||
|
|||
.toggle-text { |
|||
font-size: 10px; |
|||
margin-top: 2px; |
|||
} |
|||
|
|||
.panel-content { |
|||
position: absolute; |
|||
bottom: 60px; |
|||
left: 0; |
|||
background: rgba(255, 255, 255, 0.95); |
|||
backdrop-filter: blur(10px); |
|||
border-radius: 12px; |
|||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); |
|||
padding: 10px; |
|||
min-width: 150px; |
|||
opacity: 0; |
|||
transform: translateY(20px); |
|||
pointer-events: none; |
|||
transition: all 0.3s; |
|||
} |
|||
|
|||
.panel-content.expanded { |
|||
opacity: 1; |
|||
transform: translateY(0); |
|||
pointer-events: auto; |
|||
} |
|||
|
|||
.panel-item { |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 12px 15px; |
|||
cursor: pointer; |
|||
border-radius: 8px; |
|||
transition: all 0.3s; |
|||
color: #333; |
|||
} |
|||
|
|||
.panel-item:hover { |
|||
background: rgba(0, 138, 255, 0.1); |
|||
color: #008aff; |
|||
transform: translateX(5px); |
|||
} |
|||
|
|||
.panel-item i { |
|||
font-size: 18px; |
|||
margin-right: 10px; |
|||
color: #008aff; |
|||
} |
|||
|
|||
.panel-item span { |
|||
font-size: 14px; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.dialog-content { |
|||
padding: 0; |
|||
} |
|||
|
|||
.timeline-content h3, |
|||
.progress-content h3, |
|||
.sixsteps-content h3 { |
|||
margin: 0 0 15px 0; |
|||
font-size: 14px; |
|||
color: #333; |
|||
border-bottom: 2px solid #409EFF; |
|||
padding-bottom: 8px; |
|||
} |
|||
|
|||
.timeline-list { |
|||
max-height: 280px; |
|||
overflow-y: auto; |
|||
} |
|||
|
|||
.timeline-item { |
|||
display: flex; |
|||
align-items: flex-start; |
|||
margin-bottom: 12px; |
|||
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; |
|||
left: 5px; |
|||
top: 15px; |
|||
bottom: -12px; |
|||
width: 2px; |
|||
background: #e0e0e0; |
|||
} |
|||
|
|||
.timeline-item:last-child::before { |
|||
display: none; |
|||
} |
|||
|
|||
.timeline-dot { |
|||
width: 12px; |
|||
height: 12px; |
|||
background: #409EFF; |
|||
border-radius: 50%; |
|||
margin-right: 10px; |
|||
flex-shrink: 0; |
|||
box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.2); |
|||
} |
|||
|
|||
.timeline-info { |
|||
flex: 1; |
|||
} |
|||
|
|||
.timeline-time { |
|||
font-size: 12px; |
|||
color: #409EFF; |
|||
font-weight: 600; |
|||
margin-bottom: 3px; |
|||
} |
|||
|
|||
.timeline-event { |
|||
font-size: 12px; |
|||
color: #666; |
|||
} |
|||
|
|||
.progress-list { |
|||
max-height: 280px; |
|||
overflow-y: auto; |
|||
} |
|||
|
|||
.progress-item { |
|||
margin-bottom: 15px; |
|||
} |
|||
|
|||
.progress-label { |
|||
font-size: 12px; |
|||
color: #333; |
|||
margin-bottom: 5px; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.steps-container { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 8px; |
|||
} |
|||
|
|||
.step-item { |
|||
display: flex; |
|||
align-items: flex-start; |
|||
padding: 10px; |
|||
background: #f5f7fa; |
|||
border-radius: 6px; |
|||
transition: all 0.3s; |
|||
border-left: 3px solid #dcdfe6; |
|||
} |
|||
|
|||
.step-item.active { |
|||
background: rgba(64, 158, 255, 0.1); |
|||
border-left-color: #409EFF; |
|||
} |
|||
|
|||
.step-item.completed { |
|||
background: rgba(103, 194, 58, 0.1); |
|||
border-left-color: #67c23a; |
|||
} |
|||
|
|||
.step-number { |
|||
width: 24px; |
|||
height: 24px; |
|||
background: #dcdfe6; |
|||
border-radius: 50%; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
font-size: 12px; |
|||
font-weight: 600; |
|||
color: #909399; |
|||
margin-right: 10px; |
|||
flex-shrink: 0; |
|||
} |
|||
|
|||
.step-item.active .step-number { |
|||
background: #409EFF; |
|||
color: white; |
|||
} |
|||
|
|||
.step-item.completed .step-number { |
|||
background: #67c23a; |
|||
color: white; |
|||
} |
|||
|
|||
.step-content { |
|||
flex: 1; |
|||
} |
|||
|
|||
.step-title { |
|||
font-size: 13px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
margin-bottom: 3px; |
|||
} |
|||
|
|||
.step-desc { |
|||
font-size: 11px; |
|||
color: #666; |
|||
} |
|||
</style> |
|||
|
|||
<style> |
|||
.panel-dialog { |
|||
position: absolute !important; |
|||
left: 170px !important; |
|||
bottom: 20px !important; |
|||
top: auto !important; |
|||
margin: 0 !important; |
|||
max-height: 400px; |
|||
} |
|||
|
|||
.panel-dialog .el-dialog__header { |
|||
padding: 12px 15px; |
|||
background: #409EFF; |
|||
color: white; |
|||
} |
|||
|
|||
.panel-dialog .el-dialog__title { |
|||
color: white; |
|||
font-size: 14px; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.panel-dialog .el-dialog__headerbtn .el-dialog__close { |
|||
color: white; |
|||
} |
|||
|
|||
.panel-dialog .el-dialog__body { |
|||
padding: 15px; |
|||
max-height: 350px; |
|||
overflow-y: auto; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,139 @@ |
|||
<template> |
|||
<div |
|||
class="floating-left-menu" |
|||
:class="{ 'hidden': isHidden }" |
|||
@mouseenter="showTooltip = true" |
|||
@mouseleave="showTooltip = false" |
|||
> |
|||
<!-- 隐藏按钮(>箭头)。 --> |
|||
<div class="hide-btn" @click="handleHide" title="隐藏菜单"> |
|||
<i class="el-icon-arrow-left"></i> |
|||
</div> |
|||
|
|||
<!-- 一级菜单 --> |
|||
<div class="menu-icons"> |
|||
<div |
|||
v-for="item in menuItems" |
|||
:key="item.id" |
|||
class="menu-item" |
|||
:class="{ active: activeMenu === item.id }" |
|||
@click="handleSelectMenu(item)" |
|||
:title="item.name" |
|||
> |
|||
<i :class="item.icon"></i> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'LeftMenu', |
|||
props: { |
|||
isHidden: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
menuItems: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
activeMenu: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}, |
|||
methods: { |
|||
handleHide() { |
|||
this.$emit('hide') |
|||
}, |
|||
|
|||
handleSelectMenu(item) { |
|||
this.$emit('select', item) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
/* 左侧菜单栏 - 蓝色主题 。*/ |
|||
.floating-left-menu { |
|||
position: absolute; |
|||
top: 70px; |
|||
left: 20px; |
|||
width: 40px; |
|||
background: rgba(255, 255, 255, 0.3); |
|||
backdrop-filter: blur(10px); |
|||
border: 1px solid rgba(0, 138, 255, 0.1); |
|||
border-radius: 8px; |
|||
z-index: 90; |
|||
box-shadow: 0 4px 12px rgba(0, 138, 255, 0.2); |
|||
padding: 15px 5px; |
|||
transition: all 0.3s ease; |
|||
overflow: hidden; |
|||
opacity: 1; |
|||
transform: translateX(0); |
|||
} |
|||
|
|||
.floating-left-menu.hidden { |
|||
opacity: 0; |
|||
transform: translateX(-100%); |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.hide-btn { |
|||
position: absolute; |
|||
top: 15px; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
width: 24px; |
|||
height: 24px; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
cursor: pointer; |
|||
color: #008aff; |
|||
font-size: 16px; |
|||
transition: all 0.3s; |
|||
background: rgba(255, 255, 255, 0.5); |
|||
border-radius: 4px; |
|||
z-index: 10; |
|||
} |
|||
|
|||
.menu-icons { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10px; |
|||
margin-top: 30px; |
|||
} |
|||
|
|||
.menu-item { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 40px; |
|||
cursor: pointer; |
|||
color: #555; |
|||
font-size: 20px; |
|||
position: relative; |
|||
transition: all 0.3s; |
|||
border-radius: 4px; |
|||
padding: 0 5px; |
|||
background: rgba(255, 255, 255, 0.8); |
|||
backdrop-filter: blur(5px); |
|||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.menu-item:hover { |
|||
background: rgba(0, 138, 255, 0.1); |
|||
color: #008aff; |
|||
transform: translateY(-2px); |
|||
box-shadow: 0 4px 10px rgba(0, 138, 255, 0.2); |
|||
} |
|||
|
|||
.menu-item.active { |
|||
background: rgba(0, 138, 255, 0.15); |
|||
color: #008aff; |
|||
box-shadow: 0 2px 8px rgba(0, 138, 255, 0.3); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,723 @@ |
|||
<template> |
|||
<div> |
|||
<!-- 右侧外部隐藏按钮。 --> |
|||
<div |
|||
class="right-external-hide-btn" |
|||
:class="{ hidden: isHidden }" |
|||
@click="handleHide" |
|||
title="隐藏右侧面板" |
|||
> |
|||
<i class="el-icon-arrow-right"></i> |
|||
</div> |
|||
|
|||
<!-- 右侧实体列表(浮动)- 蓝色主题 --> |
|||
<div |
|||
class="floating-right-panel blue-theme" |
|||
:class="{ 'hidden': isHidden }" |
|||
> |
|||
<!-- 方案内容 --> |
|||
<div v-if="activeTab === 'plan'" class="tab-content plan-content"> |
|||
<div class="section"> |
|||
<div class="section-title">航线列表</div> |
|||
<div class="route-list"> |
|||
<div |
|||
v-for="route in routes" |
|||
:key="route.id" |
|||
class="route-item" |
|||
:class="{ selected: selectedRouteId === route.id }" |
|||
@click="handleSelectRoute(route)" |
|||
> |
|||
<i class="el-icon-map-location"></i> |
|||
<div class="route-info"> |
|||
<div class="route-name">{{ route.name }}</div> |
|||
<div class="route-meta">{{ route.points }}个航点</div> |
|||
</div> |
|||
<el-tag |
|||
v-if="route.conflict" |
|||
size="mini" |
|||
type="danger" |
|||
class="conflict-tag" |
|||
> |
|||
冲突 |
|||
</el-tag> |
|||
<div class="route-actions"> |
|||
<i class="el-icon-edit" title="编辑" @click.stop="handleOpenRouteDialog(route)"></i> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div v-if="selectedRouteDetails" class="section"> |
|||
<div class="section-title">航点列表</div> |
|||
<div class="waypoint-list"> |
|||
<div |
|||
v-for="point in selectedRouteDetails.waypoints" |
|||
:key="point.name" |
|||
class="waypoint-item" |
|||
@click="handleOpenWaypointDialog(point)" |
|||
> |
|||
<i class="el-icon-location"></i> |
|||
<div class="waypoint-info"> |
|||
<div class="waypoint-name">{{ point.name }}</div> |
|||
<div class="waypoint-meta">高度: {{ point.altitude }}m | 速度: {{ point.speed }}</div> |
|||
</div> |
|||
<div class="waypoint-actions"> |
|||
<i class="el-icon-edit" title="编辑" @click.stop="handleOpenWaypointDialog(point)"></i> |
|||
<i class="el-icon-delete" title="删除"></i> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="action-buttons"> |
|||
<el-button type="primary" size="mini" icon="el-icon-circle-plus" class="blue-btn" @click="handleAddWaypoint"> |
|||
添加航点 |
|||
</el-button> |
|||
<el-button size="mini" class="blue-btn" @click="handleCancelRoute"> |
|||
取消 |
|||
</el-button> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 冲突内容 --> |
|||
<div v-if="activeTab === 'conflict'" class="tab-content conflict-content"> |
|||
<div v-if="conflicts.length > 0" class="conflict-list"> |
|||
<div |
|||
v-for="conflict in conflicts" |
|||
:key="conflict.id" |
|||
class="conflict-item" |
|||
> |
|||
<div class="conflict-header"> |
|||
<i class="el-icon-warning" style="color: #f56c6c;"></i> |
|||
<span class="conflict-title">{{ conflict.title }}</span> |
|||
<el-tag size="mini" type="danger">严重</el-tag> |
|||
</div> |
|||
<div class="conflict-details"> |
|||
<div class="detail-item"> |
|||
<span class="label">涉及航线:</span> |
|||
<span class="value">{{ conflict.routes.join('、') }}</span> |
|||
</div> |
|||
<div class="detail-item"> |
|||
<span class="label">冲突时间:</span> |
|||
<span class="value">{{ conflict.time }}</span> |
|||
</div> |
|||
<div class="detail-item"> |
|||
<span class="label">冲突位置:</span> |
|||
<span class="value">{{ conflict.position }}</span> |
|||
</div> |
|||
</div> |
|||
<div class="conflict-actions"> |
|||
<el-button type="text" size="mini" class="blue-text-btn" @click="handleViewConflict(conflict)"> |
|||
查看详情 |
|||
</el-button> |
|||
<el-button type="text" size="mini" class="blue-text-btn" @click="handleResolveConflict(conflict)"> |
|||
解决冲突 |
|||
</el-button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div v-else class="no-conflict"> |
|||
<i class="el-icon-success" style="color: #67c23a; font-size: 24px;"></i> |
|||
<p>暂无冲突</p> |
|||
<el-button size="mini" class="blue-btn" @click="handleRunConflictCheck"> |
|||
重新检测 |
|||
</el-button> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 平台内容 --> |
|||
<div v-if="activeTab === 'platform'" class="tab-content platform-content"> |
|||
<div class="platform-categories"> |
|||
<el-tabs v-model="activePlatformTab" type="card" size="mini" class="blue-tabs"> |
|||
<el-tab-pane label="空中" name="air"> |
|||
<div class="platform-list"> |
|||
<div |
|||
v-for="platform in airPlatforms" |
|||
:key="platform.id" |
|||
class="platform-item" |
|||
@click="handleOpenPlatformDialog(platform)" |
|||
> |
|||
<div class="platform-icon" :style="{ color: platform.color }"> |
|||
<i :class="platform.icon"></i> |
|||
</div> |
|||
<div class="platform-info"> |
|||
<div class="platform-name">{{ platform.name }}</div> |
|||
<div class="platform-type">{{ platform.type }}</div> |
|||
</div> |
|||
<div class="platform-status"> |
|||
<span class="status-dot" :class="platform.status"></span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</el-tab-pane> |
|||
|
|||
<el-tab-pane label="海上" name="sea"> |
|||
<div class="platform-list"> |
|||
<div |
|||
v-for="platform in seaPlatforms" |
|||
:key="platform.id" |
|||
class="platform-item" |
|||
@click="handleOpenPlatformDialog(platform)" |
|||
> |
|||
<div class="platform-icon" :style="{ color: platform.color }"> |
|||
<i :class="platform.icon"></i> |
|||
</div> |
|||
<div class="platform-info"> |
|||
<div class="platform-name">{{ platform.name }}</div> |
|||
<div class="platform-type">{{ platform.type }}</div> |
|||
</div> |
|||
<div class="platform-status"> |
|||
<span class="status-dot" :class="platform.status"></span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</el-tab-pane> |
|||
|
|||
<el-tab-pane label="地面" name="ground"> |
|||
<div class="platform-list"> |
|||
<div |
|||
v-for="platform in groundPlatforms" |
|||
:key="platform.id" |
|||
class="platform-item" |
|||
@click="handleOpenPlatformDialog(platform)" |
|||
> |
|||
<div class="platform-icon" :style="{ color: platform.color }"> |
|||
<i :class="platform.icon"></i> |
|||
</div> |
|||
<div class="platform-info"> |
|||
<div class="platform-name">{{ platform.name }}</div> |
|||
<div class="platform-type">{{ platform.type }}</div> |
|||
</div> |
|||
<div class="platform-status"> |
|||
<span class="status-dot" :class="platform.status"></span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</el-tab-pane> |
|||
</el-tabs> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'RightPanel', |
|||
props: { |
|||
isHidden: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
activeTab: { |
|||
type: String, |
|||
default: 'plan' |
|||
}, |
|||
routes: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
selectedRouteId: { |
|||
type: [String, Number], |
|||
default: null |
|||
}, |
|||
selectedRouteDetails: { |
|||
type: Object, |
|||
default: null |
|||
}, |
|||
conflicts: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
conflictCount: { |
|||
type: Number, |
|||
default: 0 |
|||
}, |
|||
airPlatforms: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
seaPlatforms: { |
|||
type: Array, |
|||
default: () => [] |
|||
}, |
|||
groundPlatforms: { |
|||
type: Array, |
|||
default: () => [] |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
activePlatformTab: 'air' |
|||
} |
|||
}, |
|||
methods: { |
|||
handleHide() { |
|||
this.$emit('hide') |
|||
}, |
|||
|
|||
handleSelectRoute(route) { |
|||
this.$emit('select-route', route) |
|||
}, |
|||
|
|||
handleOpenRouteDialog(route) { |
|||
this.$emit('open-route-dialog', route) |
|||
}, |
|||
|
|||
handleOpenWaypointDialog(point) { |
|||
this.$emit('open-waypoint-dialog', point) |
|||
}, |
|||
|
|||
handleAddWaypoint() { |
|||
this.$emit('add-waypoint') |
|||
}, |
|||
|
|||
handleCancelRoute() { |
|||
this.$emit('cancel-route') |
|||
}, |
|||
|
|||
handleViewConflict(conflict) { |
|||
this.$emit('view-conflict', conflict) |
|||
}, |
|||
|
|||
handleResolveConflict(conflict) { |
|||
this.$emit('resolve-conflict', conflict) |
|||
}, |
|||
|
|||
handleRunConflictCheck() { |
|||
this.$emit('run-conflict-check') |
|||
}, |
|||
|
|||
handleOpenPlatformDialog(platform) { |
|||
this.$emit('open-platform-dialog', platform) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
/* 右侧外部隐藏按钮 */ |
|||
.right-external-hide-btn { |
|||
position: absolute; |
|||
top: 80px; |
|||
right: 20px; |
|||
width: 30px; |
|||
height: 30px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
cursor: pointer; |
|||
color: #008aff; |
|||
font-size: 18px; |
|||
background: rgba(255, 255, 255, 0.5); |
|||
border-radius: 50%; |
|||
z-index: 85; |
|||
box-shadow: 0 2px 8px rgba(0, 138, 255, 0.3); |
|||
transition: all 0.3s; |
|||
backdrop-filter: blur(5px); |
|||
} |
|||
|
|||
.right-external-hide-btn:hover { |
|||
color: #0066cc; |
|||
background: rgba(0, 138, 255, 0.2); |
|||
transform: scale(1.1); |
|||
} |
|||
|
|||
.right-external-hide-btn.hidden { |
|||
opacity: 0; |
|||
transform: translateX(100%); |
|||
pointer-events: none; |
|||
} |
|||
|
|||
/* 右侧浮动面板 - 蓝色主题 */ |
|||
.floating-right-panel { |
|||
position: absolute; |
|||
top: 70px; |
|||
right: 20px; |
|||
width: 300px; |
|||
border-radius: 0 8px 8px 8px; |
|||
z-index: 90; |
|||
color: #333; |
|||
overflow: hidden; |
|||
box-shadow: 0 4px 20px rgba(0, 138, 255, 0.2); |
|||
background: rgba(255, 255, 255, 0.95); |
|||
backdrop-filter: blur(15px); |
|||
transition: all 0.3s ease; |
|||
opacity: 1; |
|||
transform: translateX(0); |
|||
} |
|||
|
|||
.floating-right-panel.hidden { |
|||
opacity: 0; |
|||
transform: translateX(100%); |
|||
pointer-events: none; |
|||
} |
|||
|
|||
.tab-content { |
|||
padding: 15px; |
|||
max-height: 500px; |
|||
overflow-y: auto; |
|||
background: rgba(255, 255, 255, 0.95); |
|||
backdrop-filter: blur(10px); |
|||
} |
|||
|
|||
.section { |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.section-title { |
|||
font-size: 14px; |
|||
font-weight: 600; |
|||
color: #008aff; |
|||
margin-bottom: 10px; |
|||
padding-bottom: 8px; |
|||
border-bottom: 2px solid rgba(0, 138, 255, 0.2); |
|||
} |
|||
|
|||
.route-list { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 8px; |
|||
} |
|||
|
|||
.route-item { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 10px; |
|||
padding: 10px; |
|||
background: rgba(255, 255, 255, 0.8); |
|||
border-radius: 6px; |
|||
cursor: pointer; |
|||
transition: all 0.3s; |
|||
border: 1px solid rgba(0, 138, 255, 0.1); |
|||
position: relative; |
|||
} |
|||
|
|||
.route-item:hover { |
|||
background: rgba(0, 138, 255, 0.1); |
|||
transform: translateX(-2px); |
|||
box-shadow: 0 2px 8px rgba(0, 138, 255, 0.15); |
|||
} |
|||
|
|||
.route-item.selected { |
|||
background: rgba(0, 138, 255, 0.15); |
|||
border-color: rgba(0, 138, 255, 0.3); |
|||
box-shadow: 0 2px 10px rgba(0, 138, 255, 0.25); |
|||
} |
|||
|
|||
.route-info { |
|||
flex: 1; |
|||
} |
|||
|
|||
.route-name { |
|||
font-size: 14px; |
|||
font-weight: 500; |
|||
color: #333; |
|||
} |
|||
|
|||
.route-meta { |
|||
font-size: 12px; |
|||
color: #999; |
|||
} |
|||
|
|||
.route-actions { |
|||
display: flex; |
|||
gap: 8px; |
|||
} |
|||
|
|||
.route-actions i { |
|||
cursor: pointer; |
|||
color: #008aff; |
|||
font-size: 14px; |
|||
padding: 4px; |
|||
border-radius: 4px; |
|||
transition: all 0.2s; |
|||
} |
|||
|
|||
.route-actions i:hover { |
|||
background: rgba(0, 138, 255, 0.1); |
|||
transform: scale(1.2); |
|||
} |
|||
|
|||
.waypoint-list { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 8px; |
|||
} |
|||
|
|||
.waypoint-item { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 10px; |
|||
padding: 10px; |
|||
background: rgba(255, 255, 255, 0.8); |
|||
border-radius: 6px; |
|||
cursor: pointer; |
|||
transition: all 0.3s; |
|||
border: 1px solid rgba(0, 138, 255, 0.1); |
|||
} |
|||
|
|||
.waypoint-item:hover { |
|||
background: rgba(0, 138, 255, 0.1); |
|||
transform: translateX(-2px); |
|||
box-shadow: 0 2px 8px rgba(0, 138, 255, 0.15); |
|||
} |
|||
|
|||
.waypoint-info { |
|||
flex: 1; |
|||
} |
|||
|
|||
.waypoint-name { |
|||
font-size: 14px; |
|||
font-weight: 500; |
|||
color: #333; |
|||
} |
|||
|
|||
.waypoint-meta { |
|||
font-size: 12px; |
|||
color: #999; |
|||
} |
|||
|
|||
.waypoint-actions { |
|||
display: flex; |
|||
gap: 8px; |
|||
} |
|||
|
|||
.waypoint-actions i { |
|||
cursor: pointer; |
|||
color: #008aff; |
|||
font-size: 14px; |
|||
padding: 4px; |
|||
border-radius: 4px; |
|||
transition: all 0.2s; |
|||
} |
|||
|
|||
.waypoint-actions i:hover { |
|||
background: rgba(0, 138, 255, 0.1); |
|||
transform: scale(1.2); |
|||
} |
|||
|
|||
.action-buttons { |
|||
display: flex; |
|||
gap: 10px; |
|||
padding: 10px 0; |
|||
} |
|||
|
|||
.conflict-list { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 12px; |
|||
} |
|||
|
|||
.conflict-item { |
|||
background: rgba(255, 255, 255, 0.8); |
|||
border-radius: 6px; |
|||
padding: 12px; |
|||
border: 1px solid rgba(245, 108, 108, 0.2); |
|||
transition: all 0.3s; |
|||
} |
|||
|
|||
.conflict-item:hover { |
|||
background: rgba(245, 108, 108, 0.1); |
|||
box-shadow: 0 2px 8px rgba(245, 108, 108, 0.15); |
|||
} |
|||
|
|||
.conflict-header { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 8px; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.conflict-title { |
|||
flex: 1; |
|||
font-weight: 600; |
|||
color: #f56c6c; |
|||
} |
|||
|
|||
.conflict-details { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 8px; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.detail-item { |
|||
display: flex; |
|||
gap: 8px; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.detail-item .label { |
|||
color: #999; |
|||
min-width: 70px; |
|||
} |
|||
|
|||
.detail-item .value { |
|||
color: #333; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.conflict-actions { |
|||
display: flex; |
|||
gap: 10px; |
|||
} |
|||
|
|||
.no-conflict { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
gap: 15px; |
|||
padding: 40px 20px; |
|||
color: #999; |
|||
} |
|||
|
|||
.platform-categories { |
|||
height: 100%; |
|||
} |
|||
|
|||
.platform-list { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 10px; |
|||
max-height: 450px; |
|||
overflow-y: auto; |
|||
} |
|||
|
|||
.platform-item { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 12px; |
|||
padding: 12px; |
|||
background: rgba(255, 255, 255, 0.8); |
|||
border-radius: 6px; |
|||
cursor: pointer; |
|||
transition: all 0.3s; |
|||
border: 1px solid rgba(0, 138, 255, 0.1); |
|||
} |
|||
|
|||
.platform-item:hover { |
|||
background: rgba(0, 138, 255, 0.1); |
|||
transform: translateX(-2px); |
|||
box-shadow: 0 2px 8px rgba(0, 138, 255, 0.15); |
|||
} |
|||
|
|||
.platform-icon { |
|||
width: 40px; |
|||
height: 40px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
font-size: 20px; |
|||
background: rgba(255, 255, 255, 0.9); |
|||
border-radius: 50%; |
|||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.platform-info { |
|||
flex: 1; |
|||
} |
|||
|
|||
.platform-name { |
|||
font-size: 14px; |
|||
font-weight: 500; |
|||
color: #333; |
|||
} |
|||
|
|||
.platform-type { |
|||
font-size: 12px; |
|||
color: #999; |
|||
} |
|||
|
|||
.platform-status { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.status-dot { |
|||
width: 8px; |
|||
height: 8px; |
|||
border-radius: 50%; |
|||
display: inline-block; |
|||
} |
|||
|
|||
.status-dot.online { |
|||
background: #67c23a; |
|||
box-shadow: 0 0 6px rgba(103, 194, 58, 0.6); |
|||
} |
|||
|
|||
.status-dot.offline { |
|||
background: #999; |
|||
} |
|||
|
|||
.status-dot.operating { |
|||
background: #008aff; |
|||
animation: pulse 2s infinite; |
|||
box-shadow: 0 0 10px rgba(0, 138, 255, 0.8); |
|||
} |
|||
|
|||
@keyframes pulse { |
|||
0%, 100% { |
|||
opacity: 1; |
|||
} |
|||
50% { |
|||
opacity: 0.5; |
|||
} |
|||
} |
|||
|
|||
.blue-btn { |
|||
background: rgba(0, 138, 255, 0.1); |
|||
color: #008aff; |
|||
border: 1px solid rgba(0, 138, 255, 0.3); |
|||
} |
|||
|
|||
.blue-btn:hover { |
|||
background: rgba(0, 138, 255, 0.2); |
|||
border-color: rgba(0, 138, 255, 0.5); |
|||
} |
|||
|
|||
.blue-text-btn { |
|||
color: #008aff; |
|||
} |
|||
|
|||
.blue-text-btn:hover { |
|||
color: #0066cc; |
|||
} |
|||
|
|||
.blue-badge { |
|||
background: rgba(245, 108, 108, 0.1); |
|||
color: #f56c6c; |
|||
border: 1px solid rgba(245, 108, 108, 0.3); |
|||
} |
|||
|
|||
.blue-tabs >>> .el-tabs__item { |
|||
color: #666; |
|||
transition: all 0.3s; |
|||
} |
|||
|
|||
.blue-tabs >>> .el-tabs__item:hover { |
|||
color: #008aff; |
|||
} |
|||
|
|||
.blue-tabs >>> .el-tabs__item.is-active { |
|||
color: #008aff; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.blue-tabs >>> .el-tabs__active-bar { |
|||
background-color: #008aff; |
|||
box-shadow: 0 0 6px rgba(0, 138, 255, 0.5); |
|||
} |
|||
|
|||
.blue-tabs >>> .el-tabs__nav-wrap::after { |
|||
background-color: rgba(0, 138, 255, 0.3); |
|||
} |
|||
|
|||
.blue-success { |
|||
color: #67c23a; |
|||
} |
|||
|
|||
.blue-warning { |
|||
color: #e6a23c; |
|||
} |
|||
</style> |
|||
@ -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> |
|||
File diff suppressed because it is too large
Loading…
Reference in new issue