1
This commit is contained in:
464
app/components/ConsoleInfoPanel.vue
Normal file
464
app/components/ConsoleInfoPanel.vue
Normal file
@@ -0,0 +1,464 @@
|
||||
<template>
|
||||
<div class="console-info-panel">
|
||||
<h2 class="panel-title">系统状态</h2>
|
||||
|
||||
<div class="info-grid">
|
||||
<!-- 用户登录状态 -->
|
||||
<div class="info-card">
|
||||
<div class="info-label">用户登录状态</div>
|
||||
<div class="info-value">
|
||||
<span :class="['status-badge', isLoggedIn ? 'status-success' : 'status-error']">
|
||||
{{ isLoggedIn ? '已登录' : '未登录' }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="isLoggedIn && userName" class="info-detail">
|
||||
<span class="detail-label">账号:</span>
|
||||
<span class="detail-value">{{ userName }}</span>
|
||||
</div>
|
||||
<div v-if="isLoggedIn && remainingDays !== null" class="info-detail">
|
||||
<span class="detail-label">剩余天数:</span>
|
||||
<span :class="['detail-value', remainingDays <= 0 ? 'text-error' : remainingDays <= 3 ? 'text-warning' : '']">
|
||||
{{ remainingDays }} 天
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 当前平台 -->
|
||||
<div class="info-card">
|
||||
<div class="info-label">当前平台</div>
|
||||
<div class="info-value">{{ currentPlatform }}</div>
|
||||
<div class="info-detail">
|
||||
<span class="detail-label">平台登录:</span>
|
||||
<span :class="['status-badge', isPlatformLoggedIn ? 'status-success' : 'status-warning']">
|
||||
{{ isPlatformLoggedIn ? '已登录' : '未登录' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 设备信息 -->
|
||||
<div class="info-card">
|
||||
<div class="info-label">设备信息</div>
|
||||
<div class="info-detail">
|
||||
<span class="detail-label">设备SN码:</span>
|
||||
<span class="detail-value">{{ snCode || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-detail">
|
||||
<span class="detail-label">设备ID:</span>
|
||||
<span class="detail-value">{{ deviceId || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 系统信息 -->
|
||||
<div class="info-card system-info-card">
|
||||
<div class="info-label">系统信息</div>
|
||||
<div class="system-info-grid">
|
||||
<div class="system-info-item">
|
||||
<span class="system-info-label">运行时间:</span>
|
||||
<span class="system-info-value">{{ uptime }}</span>
|
||||
</div>
|
||||
<div class="system-info-item">
|
||||
<span class="system-info-label">CPU:</span>
|
||||
<span class="system-info-value">{{ cpuUsage }}</span>
|
||||
</div>
|
||||
<div class="system-info-item">
|
||||
<span class="system-info-label">内存:</span>
|
||||
<span class="system-info-value">{{ memUsage }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务区域 -->
|
||||
<div class="task-section">
|
||||
<!-- 当前执行任务 - 100%宽度 -->
|
||||
<div class="info-card task-card-full">
|
||||
<div class="info-label">当前执行任务</div>
|
||||
<div v-if="currentTask" class="task-info">
|
||||
<div class="task-name">{{ currentTask.taskName || currentTask.taskType || '-' }}</div>
|
||||
<div class="task-status">
|
||||
<span :class="['status-badge', getTaskStatusClass(currentTask.status)]">
|
||||
{{ getTaskStatusText(currentTask.status) }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="currentTask.progress !== null" class="task-progress">
|
||||
<div class="progress-bar">
|
||||
<div
|
||||
class="progress-fill"
|
||||
:style="{ width: currentTask.progress + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
<span class="progress-text">{{ currentTask.progress }}%</span>
|
||||
</div>
|
||||
<div v-if="currentTask.currentStep" class="task-step">
|
||||
<span class="step-label">当前步骤:</span>
|
||||
<span class="step-value">{{ currentTask.currentStep }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-task">
|
||||
<span class="no-task-text">暂无执行中的任务</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 即将执行的任务列表 -->
|
||||
<div class="info-card task-card-full pending-tasks-card">
|
||||
<div class="info-label">即将执行的任务</div>
|
||||
<div v-if="pendingTasks && pendingTasks.length > 0" class="pending-tasks-list">
|
||||
<div v-for="(task, index) in pendingTasks" :key="index" class="pending-task-item">
|
||||
<div class="pending-task-name">{{ task.taskName || task.taskType || '未知任务' }}</div>
|
||||
<div class="pending-task-meta">
|
||||
<span :class="['status-badge', getTaskStatusClass(task.status)]">
|
||||
{{ getTaskStatusText(task.status) }}
|
||||
</span>
|
||||
<span v-if="task.scheduledTime" class="task-time">
|
||||
计划时间: {{ formatTime(task.scheduledTime) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-task">
|
||||
<span class="no-task-text">暂无待执行的任务</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ConsoleInfoPanel',
|
||||
props: {
|
||||
isLoggedIn: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
userName: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
remainingDays: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
currentPlatform: {
|
||||
type: String,
|
||||
default: '-'
|
||||
},
|
||||
isPlatformLoggedIn: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
snCode: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
deviceId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
currentTask: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
pendingTasks: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
uptime: {
|
||||
type: String,
|
||||
default: '0分钟'
|
||||
},
|
||||
cpuUsage: {
|
||||
type: String,
|
||||
default: '0%'
|
||||
},
|
||||
memUsage: {
|
||||
type: String,
|
||||
default: '0MB'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatTime(timeStr) {
|
||||
if (!timeStr) return '-';
|
||||
try {
|
||||
const date = new Date(timeStr);
|
||||
return date.toLocaleString('zh-CN', {
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
} catch (e) {
|
||||
return timeStr;
|
||||
}
|
||||
},
|
||||
getTaskStatusClass(status) {
|
||||
const statusMap = {
|
||||
'running': 'status-info',
|
||||
'pending': 'status-warning',
|
||||
'completed': 'status-success',
|
||||
'failed': 'status-error',
|
||||
'timeout': 'status-error',
|
||||
'cancelled': 'status-warning'
|
||||
};
|
||||
return statusMap[status] || 'status-warning';
|
||||
},
|
||||
|
||||
getTaskStatusText(status) {
|
||||
const statusMap = {
|
||||
'running': '执行中',
|
||||
'pending': '待执行',
|
||||
'completed': '已完成',
|
||||
'failed': '失败',
|
||||
'timeout': '超时',
|
||||
'cancelled': '已取消'
|
||||
};
|
||||
return statusMap[status] || status || '未知';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.console-info-panel {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 20px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.info-card {
|
||||
background: #fff;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
|
||||
}
|
||||
|
||||
.task-section {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.task-card-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pending-tasks-card {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.pending-tasks-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.pending-task-item {
|
||||
padding: 12px;
|
||||
background: #f9f9f9;
|
||||
border-radius: 6px;
|
||||
border-left: 3px solid #ff9800;
|
||||
|
||||
.pending-task-name {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.pending-task-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
font-size: 12px;
|
||||
|
||||
.task-time {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.info-detail {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 8px;
|
||||
font-size: 14px;
|
||||
|
||||
.detail-label {
|
||||
color: #666;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
|
||||
&.text-error {
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
&.text-warning {
|
||||
color: #ff9800;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
|
||||
&.status-success {
|
||||
background: #e8f5e9;
|
||||
color: #4caf50;
|
||||
}
|
||||
|
||||
&.status-error {
|
||||
background: #ffebee;
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
&.status-warning {
|
||||
background: #fff3e0;
|
||||
color: #ff9800;
|
||||
}
|
||||
|
||||
&.status-info {
|
||||
background: #e3f2fd;
|
||||
color: #2196f3;
|
||||
}
|
||||
}
|
||||
|
||||
.task-info {
|
||||
.task-name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.task-status {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.task-progress {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.progress-bar {
|
||||
flex: 1;
|
||||
height: 8px;
|
||||
background: #e0e0e0;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #4caf50, #8bc34a);
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
min-width: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.task-step {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
|
||||
.step-label {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.step-value {
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-task {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: #999;
|
||||
|
||||
.no-task-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.system-info-card {
|
||||
.system-info-grid {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.system-info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.system-info-label {
|
||||
font-weight: 500;
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.system-info-value {
|
||||
color: #333;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.info-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.task-section {
|
||||
grid-column: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user