Browse Source

feat: 监控无人机态增加当前任务块

飞行状态与控制区之间展示任务进度;无任务时空态,有 taskId 可跳任务页。
main
xiaosi 3 weeks ago
parent
commit
d2689ff09a
  1. 8
      src/styles/prototype.css
  2. 77
      src/views/MonitorView/MonitorView.vue

8
src/styles/prototype.css

@ -226,6 +226,8 @@ svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width:
.metric-grid strong small { font-size: 11px; margin-left: 2px; color: var(--muted); } .metric-grid strong small { font-size: 11px; margin-left: 2px; color: var(--muted); }
.metric-grid .success { color: var(--green); font-size: 14px; } .metric-grid .success { color: var(--green); font-size: 14px; }
.mission-state { padding: 3px 6px; border-radius: 3px; background: #e7f0fc; color: #2568b5 !important; } .mission-state { padding: 3px 6px; border-radius: 3px; background: #e7f0fc; color: #2568b5 !important; }
.mission-progress .table-empty { min-height: 42px; display: grid; place-items: center; color: var(--muted); font-size: 11px; }
.mission-name { display: flex; align-items: center; justify-content: space-between; }.mission-name > span { display: flex; flex-direction: column; gap: 3px; }.mission-name strong { font-size: 13px; }.mission-name small { color: var(--muted); font-size: 10px; }.mission-name > b { color: var(--blue); font-size: 16px; } .mission-name { display: flex; align-items: center; justify-content: space-between; }.mission-name > span { display: flex; flex-direction: column; gap: 3px; }.mission-name strong { font-size: 13px; }.mission-name small { color: var(--muted); font-size: 10px; }.mission-name > b { color: var(--blue); font-size: 16px; }
.progress-track { height: 5px; margin-top: 10px; overflow: hidden; border-radius: 3px; background: #e7ebef; }.progress-track i { display: block; width: 50%; height: 100%; background: var(--blue); }.progress-meta { margin-top: 8px; display: flex; justify-content: space-between; color: var(--muted); font-size: 10px; } .progress-track { height: 5px; margin-top: 10px; overflow: hidden; border-radius: 3px; background: #e7ebef; }.progress-track i { display: block; width: 50%; height: 100%; background: var(--blue); }.progress-meta { margin-top: 8px; display: flex; justify-content: space-between; color: var(--muted); font-size: 10px; }
.return-action { background: #176b61; }.return-action:hover { background: #10584f; } .return-action { background: #176b61; }.return-action:hover { background: #10584f; }
@ -760,6 +762,12 @@ svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width:
.metric-grid strong { font-size: 15px; } .metric-grid strong { font-size: 15px; }
.metric-grid .success { font-size: 13px; } .metric-grid .success { font-size: 13px; }
.environment-row strong { font-size: 11px; } .environment-row strong { font-size: 11px; }
.mission-name strong { font-size: 12px; }
.mission-name small { font-size: 9px; }
.mission-name > b { font-size: 14px; }
.progress-track { margin-top: 8px; }
.progress-meta { margin-top: 6px; font-size: 9px; }
.mission-progress .table-empty { min-height: 36px; font-size: 10px; }
.workflow-actions { gap: 6px; } .workflow-actions { gap: 6px; }
.workflow-action { min-height: 44px; padding: 0 8px; gap: 6px; } .workflow-action { min-height: 44px; padding: 0 8px; gap: 6px; }
.workflow-action > svg { width: 17px; } .workflow-action > svg { width: 17px; }

77
src/views/MonitorView/MonitorView.vue

@ -250,6 +250,29 @@
</div> </div>
</section> </section>
<section v-if="isDrone" class="mission-progress">
<div class="section-title">
<h3>当前任务</h3>
<button class="text-button" type="button" :disabled="!missionDetail.taskId" @click="goMissionDetail">任务详情</button>
</div>
<template v-if="missionDetail.hasMission">
<div class="mission-name">
<span>
<strong>{{ missionDetail.name }}</strong>
<small>{{ missionDetail.route }}</small>
</span>
<b>{{ missionDetail.progressText }}</b>
</div>
<div class="progress-track"><i :style="{ width: missionDetail.progressWidth }"></i></div>
<div class="progress-meta">
<span>{{ missionDetail.waypointText }}</span>
<span>{{ missionDetail.elapsedText }}</span>
<span>{{ missionDetail.distanceText }}</span>
</div>
</template>
<div v-else class="table-empty">暂无任务</div>
</section>
<!-- Drone only: mission --> <!-- Drone only: mission -->
<section class="environment-section"> <section class="environment-section">
<div class="section-title"> <div class="section-title">
@ -763,6 +786,60 @@ const doorSummary = computed(() => {
const dockControlMode = computed(() => record.value?.mode || displayValue(rt('controlMode'))) const dockControlMode = computed(() => record.value?.mode || displayValue(rt('controlMode')))
function formatDuration(seconds) {
const total = Math.max(0, Math.floor(Number(seconds) || 0))
if (!Number.isFinite(total) || total <= 0) return '--'
const mm = String(Math.floor(total / 60)).padStart(2, '0')
const ss = String(total % 60).padStart(2, '0')
return `${mm}:${ss}`
}
function formatDistance(meters) {
const value = Number(meters)
if (!Number.isFinite(value) || value < 0) return '--'
if (value >= 1000) return `${(value / 1000).toFixed(1)} km`
return `${Math.round(value)} m`
}
const missionDetail = computed(() => {
const rec = record.value
const nameRaw = rec?.mission || rt('missionName', 'mission')
const name = nameRaw && nameRaw !== '--' && nameRaw !== '无' ? String(nameRaw) : ''
const route = displayValue(rt('routeName', 'routeCode', 'route'))
const progressRaw = rt('missionProgress', 'progressPercent', 'progress')
const progressNum = Number(progressRaw)
const hasProgress = Number.isFinite(progressNum)
const currentWp = rt('currentWaypoint', 'waypointIndex', 'waypoint')
const totalWp = rt('waypointCount', 'totalWaypoints', 'waypoints')
const elapsed = rt('missionElapsed', 'elapsed', 'flightDuration', 'elapsedSeconds')
const distance = rt('distanceToHome', 'distanceFromDock', 'homeDistance', 'distance')
const taskId = rt('taskId', 'missionId') || rec?.taskId || null
const active = !!name || rec?.statusClass === 'mission'
return {
hasMission: active,
name: name || (rec?.statusClass === 'mission' ? (rec.status || '执行中任务') : '暂无任务'),
route: route === '--' ? '航线 --' : `航线 ${route}`,
progressText: hasProgress ? `${Math.max(0, Math.min(100, Math.round(progressNum)))}%` : '--',
progressWidth: hasProgress ? `${Math.max(0, Math.min(100, progressNum))}%` : '0%',
waypointText: (currentWp != null || totalWp != null)
? `航点 ${displayValue(currentWp)} / ${displayValue(totalWp)}`
: '航点 -- / --',
elapsedText: `已飞行 ${formatDuration(elapsed)}`,
distanceText: `距离机巢 ${formatDistance(distance)}`,
taskId,
}
})
function goMissionDetail() {
const id = missionDetail.value.taskId
if (!id) {
ui.toast('暂无任务详情')
return
}
router.push({ name: 'tasks', query: { taskId: String(id) } })
}
const isAutoMode = computed(() => { const isAutoMode = computed(() => {
const mode = String(rt('controlMode') || record.value?.mode || '').toLowerCase() const mode = String(rt('controlMode') || record.value?.mode || '').toLowerCase()

Loading…
Cancel
Save