Browse Source

Changes

lbj
sd 3 months ago
parent
commit
f73fdb933d
  1. BIN
      ruoyi-ui/node_modules.zip
  2. 2
      ruoyi-ui/package.json
  3. 2
      ruoyi-ui/src/permission.js
  4. 4
      ruoyi-ui/src/views/cesiumMap/index.vue
  5. 1352
      ruoyi-ui/src/views/childRoom/index.vue
  6. 486
      ruoyi-ui/src/views/dialogs/OnlineMembersDialog.vue
  7. 295
      ruoyi-ui/src/views/dialogs/PlatformEditDialog.vue
  8. 229
      ruoyi-ui/src/views/dialogs/RouteEditDialog.vue
  9. 227
      ruoyi-ui/src/views/dialogs/WaypointEditDialog.vue

BIN
ruoyi-ui/node_modules.zip

Binary file not shown.

2
ruoyi-ui/package.json

@ -50,6 +50,8 @@
"vuex": "3.6.0"
},
"devDependencies": {
"@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6",
"@babel/plugin-transform-optional-chaining": "^7.28.6",
"@vue/cli-plugin-babel": "4.4.6",
"@vue/cli-service": "4.4.6",
"babel-plugin-dynamic-import-node": "2.3.3",

2
ruoyi-ui/src/permission.js

@ -9,7 +9,7 @@ import { isRelogin } from '@/utils/request'
NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/register']
const whiteList = ['/login', '/register', '/selectRoom', '/childRoom']
const isWhiteList = (path) => {
return whiteList.some(pattern => isPathMatch(pattern, path))

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

@ -1260,9 +1260,9 @@ export default {
.main-toolbar {
position: absolute;
top: 100px;
top: 365px;
/* left: 50px; */
right: 20px;
left: 62px;
z-index: 1000;
display: flex;

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

File diff suppressed because it is too large

486
ruoyi-ui/src/views/dialogs/OnlineMembersDialog.vue

@ -0,0 +1,486 @@
<template>
<div v-if="value" class="online-members-dialog">
<!-- 遮罩层 -->
<div class="dialog-overlay" @click="closeDialog"></div>
<!-- 弹窗内容 -->
<div class="dialog-content">
<div class="dialog-header">
<h3>在线成员与操作日志</h3>
<div class="close-btn" @click="closeDialog">×</div>
</div>
<div class="dialog-body">
<el-tabs v-model="activeTab" type="card" size="small">
<!-- 在线成员 -->
<el-tab-pane label="在线成员" name="members">
<div class="members-list">
<div
v-for="member in onlineMembers"
:key="member.id"
class="member-item"
:class="{ active: member.isEditing }"
>
<div class="member-avatar">
<el-avatar :size="36" :src="member.avatar">{{ member.name.charAt(0) }}</el-avatar>
</div>
<div class="member-info">
<div class="member-name">{{ member.name }}</div>
<div class="member-role">{{ member.role }}</div>
</div>
<div class="member-status">
<span class="status-dot online"></span>
<span class="status-text">{{ member.status }}</span>
</div>
<div v-if="member.isEditing" class="editing-badge">编辑中</div>
</div>
</div>
</el-tab-pane>
<!-- 编辑/选中状态 -->
<el-tab-pane label="当前操作" name="current">
<div class="current-operation">
<div class="operation-section">
<h4>编辑状态</h4>
<div class="status-item">
<span class="status-label">当前编辑者</span>
<span class="status-value">{{ currentEditor || '无' }}</span>
</div>
<div class="status-item">
<span class="status-label">编辑对象</span>
<span class="status-value">{{ editingObject || '无' }}</span>
</div>
<div class="status-item">
<span class="status-label">编辑时间</span>
<span class="status-value">{{ editingTime || '无' }}</span>
</div>
</div>
<div class="operation-section">
<h4>选中状态</h4>
<div class="status-item">
<span class="status-label">选中对象</span>
<span class="status-value">{{ selectedObject || '无' }}</span>
</div>
<div class="status-item">
<span class="status-label">选中数量</span>
<span class="status-value">{{ selectedCount }} </span>
</div>
</div>
</div>
</el-tab-pane>
<!-- 操作日志与回滚 -->
<el-tab-pane label="操作日志" name="logs">
<div class="operation-logs">
<div class="logs-header">
<h4>对象级操作日志</h4>
<el-button
type="warning"
size="mini"
@click="showRollbackConfirm"
:disabled="operationLogs.length === 0"
>
<i class="el-icon-refresh-right"></i> 回滚操作
</el-button>
</div>
<el-timeline>
<el-timeline-item
v-for="log in operationLogs"
:key="log.id"
:timestamp="log.time"
:type="log.type"
>
<div class="log-content">
<div class="log-user">{{ log.user }}</div>
<div class="log-action">{{ log.action }}</div>
<div class="log-object">对象{{ log.object }}</div>
<div class="log-detail">{{ log.detail }}</div>
</div>
</el-timeline-item>
</el-timeline>
<!-- 回滚确认弹窗 -->
<el-dialog
title="操作回滚确认"
:visible.sync="showRollbackDialog"
width="400px"
center
>
<div class="rollback-confirm">
<p>确定要回滚到所选操作吗</p>
<p class="text-warning mt-2">此操作将撤销该操作及其后的所有更改不可恢复</p>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="showRollbackDialog = false">取消</el-button>
<el-button type="primary" @click="rollbackOperation">确定回滚</el-button>
</span>
</el-dialog>
</div>
</el-tab-pane>
</el-tabs>
</div>
<div class="dialog-footer">
<el-button @click="closeDialog">关闭</el-button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'OnlineMembersDialog',
props: {
value: {
type: Boolean,
default: false
}
},
data() {
return {
activeTab: 'members',
showRollbackDialog: false,
// 线
onlineMembers: [
{ id: 1, name: '张三', role: '指挥官', status: '在线', isEditing: true, avatar: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png' },
{ id: 2, name: '李四', role: '参谋', status: '在线', isEditing: false, avatar: 'https://cube.elemecdn.com/1/88/03b0d39583f48206768a7534e55bcpng.png' },
{ id: 3, name: '王五', role: '操作员', status: '在线', isEditing: false, avatar: 'https://cube.elemecdn.com/2/88/03b0d39583f48206768a7534e55bcpng.png' },
{ id: 4, name: '赵六', role: '观察员', status: '在线', isEditing: false, avatar: 'https://cube.elemecdn.com/3/88/03b0d39583f48206768a7534e55bcpng.png' },
{ id: 5, name: '孙七', role: '分析师', status: '在线', isEditing: false, avatar: 'https://cube.elemecdn.com/4/88/03b0d39583f48206768a7534e55bcpng.png' }
],
//
currentEditor: '张三',
editingObject: 'J-20 歼击机',
editingTime: 'K+00:45:23',
selectedObject: 'Alpha进场航线',
selectedCount: 1,
//
operationLogs: [
{
id: 1,
user: '张三',
action: '修改',
object: 'J-20 歼击机',
detail: '更新了速度参数从800km/h到850km/h',
time: 'K+00:45:23',
type: 'success'
},
{
id: 2,
user: '李四',
action: '选择',
object: 'Alpha进场航线',
detail: '选中了Alpha进场航线进行编辑',
time: 'K+00:42:15',
type: 'primary'
},
{
id: 3,
user: '王五',
action: '添加',
object: 'WP5',
detail: '在Beta巡逻航线上添加了新航点WP5',
time: 'K+00:38:47',
type: 'info'
},
{
id: 4,
user: '赵六',
action: '删除',
object: '旧侦察航线',
detail: '删除了过期的侦察航线',
time: 'K+00:35:12',
type: 'warning'
},
{
id: 5,
user: '孙七',
action: '修改',
object: 'HQ-9防空系统',
detail: '更新了射程参数从120km到150km',
time: 'K+00:32:08',
type: 'success'
}
]
};
},
methods: {
closeDialog() {
this.$emit('input', false);
},
showRollbackConfirm() {
this.showRollbackDialog = true;
},
rollbackOperation() {
this.showRollbackDialog = false;
this.$message.success('操作回滚成功');
//
}
}
};
</script>
<style scoped>
.online-members-dialog {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.dialog-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(2px);
}
.dialog-content {
position: relative;
background: white;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 700px;
max-height: 90vh;
overflow-y: auto;
animation: dialog-fade-in 0.3s ease;
}
@keyframes dialog-fade-in {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.dialog-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
border-bottom: 1px solid #e8e8e8;
}
.dialog-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.close-btn {
font-size: 20px;
color: #999;
cursor: pointer;
transition: color 0.3s;
}
.close-btn:hover {
color: #666;
}
.dialog-body {
padding: 20px;
}
.dialog-footer {
display: flex;
align-items: center;
justify-content: flex-end;
padding: 16px 20px;
border-top: 1px solid #e8e8e8;
gap: 10px;
}
/* 在线成员样式 */
.members-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.member-item {
display: flex;
align-items: center;
padding: 12px;
border-radius: 8px;
background: rgba(240, 242, 245, 0.8);
transition: all 0.3s;
}
.member-item:hover {
background: rgba(220, 233, 255, 0.8);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0, 138, 255, 0.15);
}
.member-item.active {
background: rgba(190, 220, 255, 0.8);
border: 1px solid rgba(0, 138, 255, 0.3);
box-shadow: 0 2px 10px rgba(0, 138, 255, 0.2);
}
.member-avatar {
margin-right: 12px;
}
.member-info {
flex: 1;
}
.member-name {
font-weight: 600;
color: #333;
margin-bottom: 4px;
}
.member-role {
font-size: 12px;
color: #666;
}
.member-status {
display: flex;
align-items: center;
gap: 6px;
margin-right: 12px;
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
.status-dot.online {
background: #52c41a;
box-shadow: 0 0 4px rgba(82, 196, 26, 0.8);
}
.status-text {
font-size: 12px;
color: #666;
}
.editing-badge {
background: #ff7875;
color: white;
font-size: 11px;
padding: 2px 8px;
border-radius: 10px;
}
/* 当前操作样式 */
.current-operation {
display: flex;
flex-direction: column;
gap: 20px;
}
.operation-section {
background: rgba(240, 242, 245, 0.8);
padding: 16px;
border-radius: 8px;
}
.operation-section h4 {
margin: 0 0 12px 0;
font-size: 14px;
font-weight: 600;
color: #333;
}
.status-item {
display: flex;
margin-bottom: 8px;
}
.status-label {
width: 100px;
font-size: 13px;
color: #666;
}
.status-value {
font-size: 13px;
color: #333;
font-weight: 500;
}
/* 操作日志样式 */
.operation-logs {
position: relative;
}
.logs-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.logs-header h4 {
margin: 0;
font-size: 14px;
font-weight: 600;
color: #333;
}
.log-content {
background: rgba(240, 242, 245, 0.8);
padding: 12px;
border-radius: 6px;
margin-left: 16px;
}
.log-user {
font-weight: 600;
color: #333;
margin-bottom: 4px;
}
.log-action {
font-size: 13px;
color: #666;
margin-bottom: 4px;
}
.log-object {
font-size: 12px;
color: #008aff;
margin-bottom: 2px;
}
.log-detail {
font-size: 12px;
color: #999;
}
/* 回滚确认样式 */
.rollback-confirm {
text-align: center;
}
.text-warning {
color: #fa8c16;
}
</style>

295
ruoyi-ui/src/views/dialogs/PlatformEditDialog.vue

@ -0,0 +1,295 @@
<template>
<div v-if="value" class="platform-edit-dialog">
<!-- 遮罩层 -->
<div class="dialog-overlay" @click="closeDialog"></div>
<!-- 弹窗内容 -->
<div class="dialog-content">
<div class="dialog-header">
<h3>平台编辑</h3>
<div class="close-btn" @click="closeDialog">×</div>
</div>
<div class="dialog-body">
<el-form :model="formData" :rules="rules" ref="formRef" label-width="80px" size="small">
<!-- 基本信息 -->
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入平台名称"></el-input>
</el-form-item>
<el-form-item label="位置">
<div class="location-inputs">
<el-input v-model="formData.location.lat" placeholder="纬度" style="width: 120px;"></el-input>
<span class="location-separator">,</span>
<el-input v-model="formData.location.lng" placeholder="经度" style="width: 120px;"></el-input>
</div>
</el-form-item>
<el-form-item label="速度" prop="speed">
<el-input v-model="formData.speed" placeholder="请输入速度" suffix="km/h"></el-input>
</el-form-item>
<el-form-item label="油耗表" prop="fuelConsumption">
<el-input-number
v-model="formData.fuelConsumption"
:min="0"
:precision="2"
placeholder="请输入油耗"
style="width: 100%;"
suffix="L/km"
></el-input-number>
</el-form-item>
<el-form-item label="高度限制">
<div class="altitude-inputs">
<el-input-number
v-model="formData.altitude.min"
:min="0"
placeholder="最低高度"
style="width: 120px;"
suffix="m"
></el-input-number>
<span class="altitude-separator">~</span>
<el-input-number
v-model="formData.altitude.max"
:min="0"
placeholder="最高高度"
style="width: 120px;"
suffix="m"
></el-input-number>
</div>
</el-form-item>
<el-form-item label="威力区/扇区">
<div class="sector-inputs">
<el-input-number
v-model="formData.sector.radius"
:min="0"
placeholder="半径"
style="width: 100px;"
suffix="km"
></el-input-number>
<el-input-number
v-model="formData.sector.angle"
:min="0"
:max="360"
placeholder="角度"
style="width: 100px;"
suffix="°"
></el-input-number>
</div>
</el-form-item>
</el-form>
</div>
<div class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="savePlatform">保存</el-button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'PlatformEditDialog',
props: {
value: {
type: Boolean,
default: false
},
platform: {
type: Object,
default: () => ({})
}
},
data() {
return {
formData: {
name: '',
location: {
lat: '',
lng: ''
},
speed: '',
fuelConsumption: 0,
altitude: {
min: 0,
max: 0
},
sector: {
radius: 0,
angle: 0
}
},
rules: {
name: [
{ required: true, message: '请输入平台名称', trigger: 'blur' }
],
speed: [
{ required: true, message: '请输入速度', trigger: 'blur' },
{ type: 'number', message: '速度必须为数字', trigger: 'blur' }
],
fuelConsumption: [
{ type: 'number', message: '油耗必须为数字', trigger: 'blur' }
]
}
};
},
watch: {
value(newVal) {
if (newVal && this.platform) {
this.initFormData();
}
},
platform(newVal) {
if (this.value && newVal) {
this.initFormData();
}
}
},
methods: {
initFormData() {
// 使使
this.formData = {
name: this.platform.name || '',
location: {
lat: this.platform.lat || '',
lng: this.platform.lng || ''
},
speed: this.platform.speed || '',
fuelConsumption: this.platform.fuelConsumption || 0,
altitude: {
min: this.platform.minAltitude || 0,
max: this.platform.maxAltitude || 0
},
sector: {
radius: this.platform.sectorRadius || 0,
angle: this.platform.sectorAngle || 0
}
};
},
closeDialog() {
this.$emit('input', false);
},
savePlatform() {
this.$refs.formRef.validate((valid) => {
if (valid) {
//
this.$emit('save', {
...this.platform,
...this.formData,
lat: this.formData.location.lat,
lng: this.formData.location.lng,
minAltitude: this.formData.altitude.min,
maxAltitude: this.formData.altitude.max,
sectorRadius: this.formData.sector.radius,
sectorAngle: this.formData.sector.angle
});
this.closeDialog();
}
});
}
}
};
</script>
<style scoped>
.platform-edit-dialog {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.dialog-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(2px);
}
.dialog-content {
position: relative;
background: white;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
animation: dialog-fade-in 0.3s ease;
}
@keyframes dialog-fade-in {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.dialog-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
border-bottom: 1px solid #e8e8e8;
}
.dialog-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.close-btn {
font-size: 20px;
color: #999;
cursor: pointer;
transition: color 0.3s;
}
.close-btn:hover {
color: #666;
}
.dialog-body {
padding: 20px;
}
.location-inputs,
.altitude-inputs,
.sector-inputs {
display: flex;
align-items: center;
gap: 10px;
}
.location-separator,
.altitude-separator {
color: #999;
margin: 0 5px;
}
.dialog-footer {
display: flex;
align-items: center;
justify-content: flex-end;
padding: 16px 20px;
border-top: 1px solid #e8e8e8;
gap: 10px;
}
</style>

229
ruoyi-ui/src/views/dialogs/RouteEditDialog.vue

@ -0,0 +1,229 @@
<template>
<div v-if="value" class="route-edit-dialog">
<!-- 遮罩层 -->
<div class="dialog-overlay" @click="closeDialog"></div>
<!-- 弹窗内容 -->
<div class="dialog-content">
<div class="dialog-header">
<h3>航线编辑</h3>
<div class="close-btn" @click="closeDialog">×</div>
</div>
<div class="dialog-body">
<el-form :model="formData" :rules="rules" ref="formRef" label-width="80px" size="small">
<!-- 基本信息 -->
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入航线名称"></el-input>
</el-form-item>
<el-form-item label="航向" prop="heading">
<el-input-number
v-model="formData.heading"
:min="0"
:max="360"
placeholder="请输入航向"
style="width: 100%;"
suffix="°"
></el-input-number>
</el-form-item>
<el-form-item label="时间" prop="time">
<el-input v-model="formData.time" placeholder="请输入时间(如:K+00:40:00)"></el-input>
</el-form-item>
<el-form-item label="速度" prop="speed">
<el-input v-model="formData.speed" placeholder="请输入速度" suffix="km/h"></el-input>
</el-form-item>
<el-form-item label="距离" prop="distance">
<el-input-number
v-model="formData.distance"
:min="0"
:precision="2"
placeholder="请输入距离"
style="width: 100%;"
suffix="km"
></el-input-number>
</el-form-item>
</el-form>
</div>
<div class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="saveRoute">保存</el-button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'RouteEditDialog',
props: {
value: {
type: Boolean,
default: false
},
route: {
type: Object,
default: () => ({})
}
},
data() {
return {
formData: {
name: '',
heading: 0,
time: '',
speed: '',
distance: 0
},
rules: {
name: [
{ required: true, message: '请输入航线名称', trigger: 'blur' }
],
heading: [
{ type: 'number', message: '航向必须为数字', trigger: 'blur' },
{ min: 0, max: 360, message: '航向必须在0-360度之间', trigger: 'blur' }
],
time: [
{ required: true, message: '请输入时间', trigger: 'blur' }
],
speed: [
{ required: true, message: '请输入速度', trigger: 'blur' },
{ type: 'number', message: '速度必须为数字', trigger: 'blur' }
],
distance: [
{ type: 'number', message: '距离必须为数字', trigger: 'blur' }
]
}
};
},
watch: {
value(newVal) {
if (newVal && this.route) {
this.initFormData();
}
},
route(newVal) {
if (this.value && newVal) {
this.initFormData();
}
}
},
methods: {
initFormData() {
// 线使使
this.formData = {
name: this.route.name || '',
heading: this.route.heading || 0,
time: this.route.time || '',
speed: this.route.speed || '',
distance: this.route.distance || 0
};
},
closeDialog() {
this.$emit('input', false);
},
saveRoute() {
this.$refs.formRef.validate((valid) => {
if (valid) {
//
this.$emit('save', {
...this.route,
...this.formData
});
this.closeDialog();
}
});
}
}
};
</script>
<style scoped>
.route-edit-dialog {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.dialog-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(2px);
}
.dialog-content {
position: relative;
background: white;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
animation: dialog-fade-in 0.3s ease;
}
@keyframes dialog-fade-in {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.dialog-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
border-bottom: 1px solid #e8e8e8;
}
.dialog-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.close-btn {
font-size: 20px;
color: #999;
cursor: pointer;
transition: color 0.3s;
}
.close-btn:hover {
color: #666;
}
.dialog-body {
padding: 20px;
}
.dialog-footer {
display: flex;
align-items: center;
justify-content: flex-end;
padding: 16px 20px;
border-top: 1px solid #e8e8e8;
gap: 10px;
}
</style>

227
ruoyi-ui/src/views/dialogs/WaypointEditDialog.vue

@ -0,0 +1,227 @@
<template>
<div v-if="value" class="waypoint-edit-dialog">
<!-- 遮罩层 -->
<div class="dialog-overlay" @click="closeDialog"></div>
<!-- 弹窗内容 -->
<div class="dialog-content">
<div class="dialog-header">
<h3>航点编辑</h3>
<div class="close-btn" @click="closeDialog">×</div>
</div>
<div class="dialog-body">
<el-form :model="formData" :rules="rules" ref="formRef" label-width="80px" size="small">
<!-- 基本信息 -->
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入航点名称"></el-input>
</el-form-item>
<el-form-item label="高度" prop="altitude">
<el-input-number
v-model="formData.altitude"
:min="0"
placeholder="请输入高度"
style="width: 100%;"
suffix="m"
></el-input-number>
</el-form-item>
<el-form-item label="速度" prop="speed">
<el-input v-model="formData.speed" placeholder="请输入速度" suffix="km/h"></el-input>
</el-form-item>
<el-form-item label="时间" prop="eta">
<el-input v-model="formData.eta" placeholder="请输入到达时间(如:K+00:40:00)"></el-input>
</el-form-item>
<el-form-item label="转弯半径" prop="turnRadius">
<el-input-number
v-model="formData.turnRadius"
:min="0"
placeholder="请输入转弯半径"
style="width: 100%;"
suffix="m"
></el-input-number>
</el-form-item>
</el-form>
</div>
<div class="dialog-footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="saveWaypoint">保存</el-button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'WaypointEditDialog',
props: {
value: {
type: Boolean,
default: false
},
waypoint: {
type: Object,
default: () => ({})
}
},
data() {
return {
formData: {
name: '',
altitude: 0,
speed: '',
eta: '',
turnRadius: 0
},
rules: {
name: [
{ required: true, message: '请输入航点名称', trigger: 'blur' }
],
altitude: [
{ required: true, message: '请输入高度', trigger: 'blur' },
{ type: 'number', message: '高度必须为数字', trigger: 'blur' }
],
speed: [
{ required: true, message: '请输入速度', trigger: 'blur' },
{ type: 'number', message: '速度必须为数字', trigger: 'blur' }
],
eta: [
{ required: true, message: '请输入到达时间', trigger: 'blur' }
],
turnRadius: [
{ type: 'number', message: '转弯半径必须为数字', trigger: 'blur' }
]
}
};
},
watch: {
value(newVal) {
if (newVal && this.waypoint) {
this.initFormData();
}
},
waypoint(newVal) {
if (this.value && newVal) {
this.initFormData();
}
}
},
methods: {
initFormData() {
// 使使
this.formData = {
name: this.waypoint.name || '',
altitude: this.waypoint.altitude || 0,
speed: this.waypoint.speed || '',
eta: this.waypoint.eta || '',
turnRadius: this.waypoint.turnRadius || 0
};
},
closeDialog() {
this.$emit('input', false);
},
saveWaypoint() {
this.$refs.formRef.validate((valid) => {
if (valid) {
//
this.$emit('save', {
...this.waypoint,
...this.formData
});
this.closeDialog();
}
});
}
}
};
</script>
<style scoped>
.waypoint-edit-dialog {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
.dialog-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(2px);
}
.dialog-content {
position: relative;
background: white;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
animation: dialog-fade-in 0.3s ease;
}
@keyframes dialog-fade-in {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.dialog-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
border-bottom: 1px solid #e8e8e8;
}
.dialog-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.close-btn {
font-size: 20px;
color: #999;
cursor: pointer;
transition: color 0.3s;
}
.close-btn:hover {
color: #666;
}
.dialog-body {
padding: 20px;
}
.dialog-footer {
display: flex;
align-items: center;
justify-content: flex-end;
padding: 16px 20px;
border-top: 1px solid #e8e8e8;
gap: 10px;
}
</style>
Loading…
Cancel
Save