|
|
|
@ -1,97 +1,74 @@ |
|
|
|
<template> |
|
|
|
<div |
|
|
|
v-show="visible" |
|
|
|
class="four-t-panel" |
|
|
|
:class="{ 'four-t-panel-ready': layoutReady }" |
|
|
|
:style="panelStyle" |
|
|
|
> |
|
|
|
<div class="four-t-panel-header" @mousedown="onDragStart"> |
|
|
|
<span class="four-t-panel-title">4T</span> |
|
|
|
<div class="four-t-header-actions" @mousedown.stop> |
|
|
|
<el-button |
|
|
|
v-if="!isEditMode" |
|
|
|
type="primary" |
|
|
|
size="mini" |
|
|
|
<!-- 4T 悬浮窗:空军 4T 作战任务面板样式 --> |
|
|
|
<div v-show="visible" class="four-t-panel" :class="{ 'four-t-panel-ready': layoutReady }"> |
|
|
|
<div class="panel-container" :style="panelStyle"> |
|
|
|
<!-- 十字分割线 --> |
|
|
|
<div class="cross-line-v"></div> |
|
|
|
<div class="cross-line-h"></div> |
|
|
|
<!-- 十字中心点 --> |
|
|
|
<div class="cross-center"></div> |
|
|
|
|
|
|
|
<!-- 顶部操作栏:左侧编辑/完成,右侧关闭 --> |
|
|
|
<div class="panel-actions" @mousedown="onDragStart"> |
|
|
|
<button |
|
|
|
class="btn-edit" |
|
|
|
:class="{ complete: isEditMode }" |
|
|
|
@mousedown.stop |
|
|
|
@click="enterEditMode" |
|
|
|
@click="isEditMode ? saveAndExitEdit() : enterEditMode()" |
|
|
|
> |
|
|
|
编辑 |
|
|
|
</el-button> |
|
|
|
<template v-else> |
|
|
|
<el-button |
|
|
|
type="success" |
|
|
|
size="mini" |
|
|
|
@mousedown.stop |
|
|
|
@click="saveAndExitEdit" |
|
|
|
> |
|
|
|
保存 |
|
|
|
</el-button> |
|
|
|
<el-button |
|
|
|
size="mini" |
|
|
|
@mousedown.stop |
|
|
|
@click="cancelEdit" |
|
|
|
> |
|
|
|
取消 |
|
|
|
</el-button> |
|
|
|
</template> |
|
|
|
<i class="el-icon-close close-btn" @mousedown.stop @click="$emit('update:visible', false)" title="关闭"></i> |
|
|
|
{{ isEditMode ? '完成' : '编辑' }} |
|
|
|
</button> |
|
|
|
<button class="btn-close" @mousedown.stop @click="$emit('update:visible', false)">×</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="four-t-panel-body"> |
|
|
|
<div |
|
|
|
v-for="section in sections" |
|
|
|
:key="section.key" |
|
|
|
class="four-t-section" |
|
|
|
> |
|
|
|
<div class="four-t-section-header"> |
|
|
|
<span class="four-t-section-title">{{ section.title }}</span> |
|
|
|
<div |
|
|
|
v-if="isEditMode" |
|
|
|
class="four-t-add-btn four-t-add-btn-inline" |
|
|
|
@click="addImage(section.key)" |
|
|
|
title="插入图片" |
|
|
|
> |
|
|
|
<i class="el-icon-plus"></i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="four-t-section-content four-t-content-box"> |
|
|
|
<el-input |
|
|
|
v-model="localData[section.key].text" |
|
|
|
type="textarea" |
|
|
|
:autosize="{ minRows: 2, maxRows: 8 }" |
|
|
|
:placeholder="isEditMode ? '请输入文本内容' : ''" |
|
|
|
:disabled="!isEditMode" |
|
|
|
class="four-t-textarea" |
|
|
|
/> |
|
|
|
<div v-if="localData[section.key].images.length > 0" class="four-t-images-inline"> |
|
|
|
<div |
|
|
|
v-for="(img, idx) in localData[section.key].images" |
|
|
|
:key="idx" |
|
|
|
class="four-t-image-item" |
|
|
|
> |
|
|
|
<img :src="img" alt="插入的图片" /> |
|
|
|
<i |
|
|
|
v-if="isEditMode" |
|
|
|
class="el-icon-close remove-img" |
|
|
|
@click="removeImage(section.key, idx)" |
|
|
|
></i> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 四个象限 --> |
|
|
|
<div class="quadrant quadrant-top-left"> |
|
|
|
<div class="quadrant-title">THREAT</div> |
|
|
|
<textarea |
|
|
|
class="quadrant-content" |
|
|
|
:readonly="!isEditMode" |
|
|
|
v-model="localData.threat.text" |
|
|
|
placeholder="请输入威胁描述..." |
|
|
|
></textarea> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="quadrant quadrant-top-right"> |
|
|
|
<div class="quadrant-title">TARGET</div> |
|
|
|
<textarea |
|
|
|
class="quadrant-content" |
|
|
|
:readonly="!isEditMode" |
|
|
|
v-model="localData.target.text" |
|
|
|
placeholder="请输入打击目标..." |
|
|
|
></textarea> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="quadrant quadrant-bottom-left"> |
|
|
|
<div class="quadrant-title">TASK</div> |
|
|
|
<textarea |
|
|
|
class="quadrant-content" |
|
|
|
v-model="localData.task.text" |
|
|
|
:readonly="!isEditMode" |
|
|
|
placeholder="请输入任务内容..." |
|
|
|
></textarea> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="quadrant quadrant-bottom-right"> |
|
|
|
<div class="quadrant-title">TACTIC</div> |
|
|
|
<textarea |
|
|
|
class="quadrant-content" |
|
|
|
v-model="localData.tactic.text" |
|
|
|
:readonly="!isEditMode" |
|
|
|
placeholder="请输入战术方案..." |
|
|
|
></textarea> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 右下角拖拽调整大小 --> |
|
|
|
<div |
|
|
|
class="four-t-resize-handle" |
|
|
|
@mousedown="onResizeStart" |
|
|
|
title="拖动调整大小" |
|
|
|
></div> |
|
|
|
</div> |
|
|
|
<div |
|
|
|
class="four-t-resize-handle" |
|
|
|
@mousedown="onResizeStart" |
|
|
|
title="拖动调整大小" |
|
|
|
></div> |
|
|
|
<input |
|
|
|
ref="fileInput" |
|
|
|
type="file" |
|
|
|
accept="image/*" |
|
|
|
style="display: none" |
|
|
|
@change="onFileSelected" |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
@ -358,207 +335,253 @@ export default { |
|
|
|
</script> |
|
|
|
|
|
|
|
<style scoped> |
|
|
|
/* 根容器:覆盖全屏,居中显示 4T 面板 */ |
|
|
|
.four-t-panel { |
|
|
|
position: fixed; |
|
|
|
inset: 0; |
|
|
|
display: flex; |
|
|
|
justify-content: center; |
|
|
|
align-items: center; |
|
|
|
background: rgba(0, 0, 0, 0.12); /* 轻微遮罩,突出面板 */ |
|
|
|
z-index: 200; |
|
|
|
opacity: 0; |
|
|
|
pointer-events: none; |
|
|
|
transition: opacity 0.15s ease-out; |
|
|
|
background: rgba(255, 255, 255, 0.95); |
|
|
|
backdrop-filter: blur(10px); |
|
|
|
border: 1px solid rgba(0, 138, 255, 0.2); |
|
|
|
border-radius: 8px; |
|
|
|
box-shadow: 0 4px 20px rgba(0, 138, 255, 0.15); |
|
|
|
z-index: 200; |
|
|
|
overflow: hidden; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-panel-header { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
padding: 8px 12px; |
|
|
|
background: rgba(0, 138, 255, 0.1); |
|
|
|
border-bottom: 1px solid rgba(0, 138, 255, 0.15); |
|
|
|
cursor: move; |
|
|
|
user-select: none; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-panel-title { |
|
|
|
font-weight: 600; |
|
|
|
color: #008aff; |
|
|
|
font-size: 14px; |
|
|
|
.four-t-panel.four-t-panel-ready { |
|
|
|
opacity: 1; |
|
|
|
pointer-events: auto; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-header-actions { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
gap: 8px; |
|
|
|
/* 面板容器 */ |
|
|
|
.panel-container { |
|
|
|
position: fixed; |
|
|
|
width: 100%; |
|
|
|
max-width: 800px; |
|
|
|
height: 600px; |
|
|
|
background-color: #ffffff; |
|
|
|
border-radius: 16px; |
|
|
|
box-shadow: 0 8px 24px rgba(25, 148, 254, 0.1); |
|
|
|
overflow: hidden; |
|
|
|
border: 1px solid #e0edff; |
|
|
|
z-index: 201; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-header-actions .el-button { |
|
|
|
margin: 0; |
|
|
|
/* 十字分割线 */ |
|
|
|
.cross-line-v { |
|
|
|
position: absolute; |
|
|
|
left: 50%; |
|
|
|
top: 20px; |
|
|
|
bottom: 20px; |
|
|
|
width: 1px; |
|
|
|
background-color: #1994fe; |
|
|
|
transform: translateX(-50%); |
|
|
|
z-index: 10; |
|
|
|
opacity: 0.6; |
|
|
|
} |
|
|
|
|
|
|
|
.close-btn { |
|
|
|
cursor: pointer; |
|
|
|
font-size: 16px; |
|
|
|
color: #606266; |
|
|
|
} |
|
|
|
.close-btn:hover { |
|
|
|
color: #008aff; |
|
|
|
.cross-line-h { |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
left: 20px; |
|
|
|
right: 20px; |
|
|
|
height: 1px; |
|
|
|
background-color: #1994fe; |
|
|
|
transform: translateY(-50%); |
|
|
|
z-index: 10; |
|
|
|
opacity: 0.6; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-panel-body { |
|
|
|
display: grid; |
|
|
|
grid-template-columns: 1fr 1fr; |
|
|
|
grid-template-rows: 1fr 1fr; |
|
|
|
gap: 12px; |
|
|
|
padding: 12px; |
|
|
|
flex: 1; |
|
|
|
min-height: 0; |
|
|
|
overflow-y: auto; |
|
|
|
/* 十字中心点 */ |
|
|
|
.cross-center { |
|
|
|
position: absolute; |
|
|
|
top: 50%; |
|
|
|
left: 50%; |
|
|
|
width: 8px; |
|
|
|
height: 8px; |
|
|
|
background-color: #1994fe; |
|
|
|
border-radius: 50%; |
|
|
|
transform: translate(-50%, -50%); |
|
|
|
z-index: 15; |
|
|
|
box-shadow: 0 0 6px rgba(25, 148, 254, 0.2); |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-section { |
|
|
|
/* 象限容器 */ |
|
|
|
.quadrant { |
|
|
|
position: absolute; |
|
|
|
width: 50%; |
|
|
|
height: 50%; |
|
|
|
padding: 24px; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 8px; |
|
|
|
background: #fff; |
|
|
|
border: 1px solid #e4e7ed; |
|
|
|
border-radius: 6px; |
|
|
|
padding: 10px; |
|
|
|
min-height: 0; |
|
|
|
flex: 1; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-section-header { |
|
|
|
display: flex; |
|
|
|
justify-content: center; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
flex-shrink: 0; |
|
|
|
gap: 8px; |
|
|
|
text-align: center; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-section-title { |
|
|
|
font-weight: 600; |
|
|
|
font-size: 12px; |
|
|
|
color: #606266; |
|
|
|
user-select: none; |
|
|
|
.quadrant-top-left { |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-add-btn-inline { |
|
|
|
flex-shrink: 0; |
|
|
|
width: 28px; |
|
|
|
height: 28px; |
|
|
|
font-size: 14px; |
|
|
|
.quadrant-top-right { |
|
|
|
top: 0; |
|
|
|
right: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-section-content { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
flex: 1; |
|
|
|
min-height: 0; |
|
|
|
gap: 0; |
|
|
|
.quadrant-bottom-left { |
|
|
|
bottom: 0; |
|
|
|
left: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-content-box { |
|
|
|
border: 1px solid #dcdfe6; |
|
|
|
border-radius: 4px; |
|
|
|
padding: 8px; |
|
|
|
background: #fff; |
|
|
|
overflow-y: auto; |
|
|
|
flex: 1; |
|
|
|
min-height: 60px; |
|
|
|
.quadrant-bottom-right { |
|
|
|
bottom: 0; |
|
|
|
right: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-section-content .four-t-textarea { |
|
|
|
flex: 0 0 auto; |
|
|
|
display: block; |
|
|
|
margin-bottom: 0; |
|
|
|
/* 标题样式 */ |
|
|
|
.quadrant-title { |
|
|
|
font-size: 18px; |
|
|
|
font-weight: 600; |
|
|
|
color: #0078e0; |
|
|
|
margin-bottom: 16px; |
|
|
|
letter-spacing: 0.5px; |
|
|
|
text-transform: uppercase; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-section-content .four-t-textarea >>> .el-textarea { |
|
|
|
margin-bottom: 0; |
|
|
|
/* 文本区域样式 */ |
|
|
|
.quadrant-content { |
|
|
|
width: 92%; |
|
|
|
height: 80%; |
|
|
|
border: 1px solid #cce5ff; |
|
|
|
border-radius: 10px; |
|
|
|
padding: 16px; |
|
|
|
font-size: 15px; |
|
|
|
color: #263238; |
|
|
|
resize: none; |
|
|
|
background-color: #f9fcff; |
|
|
|
transition: all 0.2s ease; |
|
|
|
line-height: 1.6; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-section-content .four-t-textarea >>> textarea.el-textarea__inner { |
|
|
|
font-size: 12px; |
|
|
|
border: none !important; |
|
|
|
padding: 0 !important; |
|
|
|
resize: none; |
|
|
|
box-sizing: border-box; |
|
|
|
min-height: 36px !important; |
|
|
|
background: transparent !important; |
|
|
|
.quadrant-content:focus { |
|
|
|
outline: none; |
|
|
|
border-color: #1994fe; |
|
|
|
background-color: #ffffff; |
|
|
|
box-shadow: 0 0 0 4px rgba(25, 148, 254, 0.1); |
|
|
|
} |
|
|
|
.four-t-section-content >>> .el-textarea.is-disabled .el-textarea__inner { |
|
|
|
background: transparent !important; |
|
|
|
color: #606266; |
|
|
|
|
|
|
|
/* 只读状态 */ |
|
|
|
.quadrant-content[readonly] { |
|
|
|
background-color: #e8f4ff; |
|
|
|
color: #0078e0; |
|
|
|
font-weight: 500; |
|
|
|
cursor: default; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-images-inline { |
|
|
|
/* 操作栏 */ |
|
|
|
.panel-actions { |
|
|
|
position: absolute; |
|
|
|
top: 20px; |
|
|
|
left: 20px; |
|
|
|
right: 20px; |
|
|
|
z-index: 20; |
|
|
|
display: flex; |
|
|
|
flex-wrap: wrap; |
|
|
|
gap: 6px; |
|
|
|
margin-top: 8px; |
|
|
|
align-items: flex-start; |
|
|
|
flex-shrink: 0; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
/* 放大可拖动区域,并使用十字拖拽光标 */ |
|
|
|
padding: 8px 0; |
|
|
|
cursor: move; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-image-item { |
|
|
|
position: relative; |
|
|
|
width: 64px; |
|
|
|
height: 64px; |
|
|
|
flex-shrink: 0; |
|
|
|
/* 编辑按钮 */ |
|
|
|
.btn-edit { |
|
|
|
background-color: #f0f7ff; |
|
|
|
color: #1994fe; |
|
|
|
border: 1px solid #cce5ff; |
|
|
|
padding: 6px 12px; |
|
|
|
border-radius: 6px; |
|
|
|
font-size: 13px; |
|
|
|
font-weight: 500; |
|
|
|
transition: all 0.2s ease; |
|
|
|
cursor: pointer; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-image-item img { |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
object-fit: cover; |
|
|
|
border-radius: 4px; |
|
|
|
border: 1px solid #e4e7ed; |
|
|
|
display: block; |
|
|
|
.btn-edit.complete { |
|
|
|
background-color: #f0fff4; |
|
|
|
color: #00c853; |
|
|
|
border: 1px solid #ccffdd; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-image-item .remove-img { |
|
|
|
position: absolute; |
|
|
|
top: -4px; |
|
|
|
right: -4px; |
|
|
|
width: 16px; |
|
|
|
height: 16px; |
|
|
|
background: #f56c6c; |
|
|
|
color: #fff; |
|
|
|
border-radius: 50%; |
|
|
|
font-size: 10px; |
|
|
|
cursor: pointer; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
.btn-edit:hover { |
|
|
|
background-color: #e8f4ff; |
|
|
|
border-color: #1994fe; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-edit.complete:hover { |
|
|
|
background-color: #e6fffa; |
|
|
|
border-color: #00c853; |
|
|
|
color: #00a142; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-add-btn { |
|
|
|
width: 36px; |
|
|
|
height: 36px; |
|
|
|
border: 1px dashed #dcdfe6; |
|
|
|
border-radius: 4px; |
|
|
|
/* 关闭按钮 */ |
|
|
|
.btn-close { |
|
|
|
background-color: #f0f7ff; |
|
|
|
border: 1px solid #cce5ff; |
|
|
|
font-size: 14px; |
|
|
|
color: #1994fe; |
|
|
|
width: 30px; |
|
|
|
height: 30px; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: center; |
|
|
|
border-radius: 50%; |
|
|
|
transition: all 0.2s ease; |
|
|
|
cursor: pointer; |
|
|
|
color: #909399; |
|
|
|
font-size: 18px; |
|
|
|
transition: all 0.2s; |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-add-btn:hover { |
|
|
|
border-color: #008aff; |
|
|
|
color: #008aff; |
|
|
|
background: rgba(0, 138, 255, 0.05); |
|
|
|
.btn-close:hover { |
|
|
|
background-color: #e8f4ff; |
|
|
|
color: #0078e0; |
|
|
|
} |
|
|
|
|
|
|
|
/* 响应式适配 */ |
|
|
|
@media (max-width: 768px) { |
|
|
|
.panel-container { |
|
|
|
height: 500px; |
|
|
|
max-width: 95%; |
|
|
|
} |
|
|
|
|
|
|
|
.quadrant { |
|
|
|
padding: 16px; |
|
|
|
} |
|
|
|
|
|
|
|
.quadrant-title { |
|
|
|
font-size: 16px; |
|
|
|
margin-bottom: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.quadrant-content { |
|
|
|
font-size: 14px; |
|
|
|
padding: 12px; |
|
|
|
width: 95%; |
|
|
|
height: 75%; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-edit { |
|
|
|
padding: 5px 10px; |
|
|
|
font-size: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.btn-close { |
|
|
|
width: 28px; |
|
|
|
height: 28px; |
|
|
|
font-size: 13px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 右下角拖拽调整大小手柄 */ |
|
|
|
.four-t-resize-handle { |
|
|
|
position: absolute; |
|
|
|
right: 0; |
|
|
|
@ -568,15 +591,10 @@ export default { |
|
|
|
cursor: nwse-resize; |
|
|
|
user-select: none; |
|
|
|
z-index: 10; |
|
|
|
/* 右下角三角形拖拽区域 */ |
|
|
|
background: linear-gradient(to top left, transparent 50%, rgba(0, 138, 255, 0.2) 50%); |
|
|
|
} |
|
|
|
.four-t-resize-handle:hover { |
|
|
|
background: linear-gradient(to top left, transparent 50%, rgba(0, 138, 255, 0.4) 50%); |
|
|
|
background: linear-gradient(to top left, transparent 50%, rgba(25, 148, 254, 0.2) 50%); |
|
|
|
} |
|
|
|
|
|
|
|
.four-t-panel.four-t-panel-ready { |
|
|
|
opacity: 1; |
|
|
|
pointer-events: auto; |
|
|
|
.four-t-resize-handle:hover { |
|
|
|
background: linear-gradient(to top left, transparent 50%, rgba(25, 148, 254, 0.4) 50%); |
|
|
|
} |
|
|
|
</style> |
|
|
|
|