305 lines
9.7 KiB
HTML
305 lines
9.7 KiB
HTML
{% extends "admin/base_site.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}爬虫状态 - {{ site_title|default:_('Django site admin') }}{% endblock %}
|
|
|
|
{% block extrastyle %}
|
|
<style>
|
|
.status-card {
|
|
background: white;
|
|
border: 1px solid #ddd;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin: 20px 0;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.status-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 10px;
|
|
border-bottom: 2px solid #f0f0f0;
|
|
}
|
|
|
|
.status-title {
|
|
font-size: 24px;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.stats-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 20px;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.stat-card {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
text-align: center;
|
|
}
|
|
|
|
.stat-number {
|
|
font-size: 32px;
|
|
font-weight: bold;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 14px;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
.nodes-section, .batches-section {
|
|
margin-top: 30px;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
margin-bottom: 15px;
|
|
color: #333;
|
|
}
|
|
|
|
.node-item, .batch-item {
|
|
background: #f8f9fa;
|
|
border: 1px solid #e9ecef;
|
|
border-radius: 6px;
|
|
padding: 15px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.node-header, .batch-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.node-name, .batch-id {
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.node-status, .batch-status {
|
|
padding: 4px 8px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.status-active {
|
|
background: #d4edda;
|
|
color: #155724;
|
|
}
|
|
|
|
.status-running {
|
|
background: #fff3cd;
|
|
color: #856404;
|
|
}
|
|
|
|
.status-completed {
|
|
background: #d1ecf1;
|
|
color: #0c5460;
|
|
}
|
|
|
|
.status-failed {
|
|
background: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
|
|
.node-details, .batch-details {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
gap: 10px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.detail-item {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.detail-label {
|
|
color: #666;
|
|
}
|
|
|
|
.detail-value {
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.progress-bar {
|
|
width: 100%;
|
|
height: 8px;
|
|
background: #e9ecef;
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.progress-fill {
|
|
height: 100%;
|
|
background: linear-gradient(90deg, #28a745, #20c997);
|
|
transition: width 0.3s ease;
|
|
}
|
|
|
|
.refresh-btn {
|
|
background: #007bff;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 16px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.refresh-btn:hover {
|
|
background: #0056b3;
|
|
}
|
|
|
|
.no-data {
|
|
text-align: center;
|
|
color: #666;
|
|
padding: 40px;
|
|
font-style: italic;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="status-card">
|
|
<div class="status-header">
|
|
<h1 class="status-title">爬虫状态监控</h1>
|
|
<button class="refresh-btn" onclick="location.reload()">刷新</button>
|
|
</div>
|
|
|
|
<!-- 统计卡片 -->
|
|
<div class="stats-grid">
|
|
<div class="stat-card">
|
|
<div class="stat-number">{{ task_stats.total_nodes }}</div>
|
|
<div class="stat-label">活跃节点</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-number">{{ task_stats.active_tasks }}</div>
|
|
<div class="stat-label">运行中任务</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-number">{{ task_stats.total_batches }}</div>
|
|
<div class="stat-label">总批次</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-number">{{ nodes|length }}</div>
|
|
<div class="stat-label">在线节点</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 节点状态 -->
|
|
<div class="nodes-section">
|
|
<h2 class="section-title">爬虫节点状态</h2>
|
|
{% if nodes %}
|
|
{% for node in nodes %}
|
|
<div class="node-item">
|
|
<div class="node-header">
|
|
<span class="node-name">{{ node.node_id }}</span>
|
|
<span class="node-status status-active">{{ node.status }}</span>
|
|
</div>
|
|
<div class="node-details">
|
|
<div class="detail-item">
|
|
<span class="detail-label">活跃任务:</span>
|
|
<span class="detail-value">{{ node.active_tasks }}</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">完成任务:</span>
|
|
<span class="detail-value">{{ node.completed_tasks }}</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">失败任务:</span>
|
|
<span class="detail-value">{{ node.failed_tasks }}</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">最后心跳:</span>
|
|
<span class="detail-value">
|
|
{% if node.last_heartbeat %}
|
|
{{ node.last_heartbeat|date:"H:i:s" }}
|
|
{% else %}
|
|
未知
|
|
{% endif %}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<div class="no-data">
|
|
暂无活跃的爬虫节点
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- 批次状态 -->
|
|
<div class="batches-section">
|
|
<h2 class="section-title">最近批次</h2>
|
|
{% if batches %}
|
|
{% for batch in batches %}
|
|
<div class="batch-item">
|
|
<div class="batch-header">
|
|
<span class="batch-id">{{ batch.batch_id }}</span>
|
|
<span class="batch-status status-{{ batch.status }}">
|
|
{% if batch.status == 'running' %}
|
|
运行中
|
|
{% elif batch.status == 'completed' %}
|
|
已完成
|
|
{% elif batch.status == 'failed' %}
|
|
失败
|
|
{% else %}
|
|
{{ batch.status }}
|
|
{% endif %}
|
|
</span>
|
|
</div>
|
|
<div class="batch-details">
|
|
<div class="detail-item">
|
|
<span class="detail-label">总任务:</span>
|
|
<span class="detail-value">{{ batch.total_tasks }}</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">已完成:</span>
|
|
<span class="detail-value">{{ batch.completed_tasks }}</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">失败:</span>
|
|
<span class="detail-value">{{ batch.failed_tasks }}</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">进度:</span>
|
|
<span class="detail-value">{{ batch.progress|floatformat:1 }}%</span>
|
|
</div>
|
|
</div>
|
|
{% if batch.status == 'running' %}
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" style="width: {{ batch.progress }}%"></div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<div class="no-data">
|
|
暂无批次记录
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// 自动刷新页面
|
|
setTimeout(function () {
|
|
location.reload();
|
|
}, 30000); // 30秒刷新一次
|
|
</script>
|
|
{% endblock %}
|