1 Commits

Author SHA1 Message Date
e7b5a1ce09 feat: Cron列表移至底部并添加概述分析 2026-04-14 10:40:09 +08:00

143
app.py
View File

@@ -244,7 +244,7 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
</div>
<!-- 统计卡片 -->
<div class="grid grid-cols-2 md:grid-cols-5 gap-4 mb-8">
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
<div class="card rounded-xl p-4">
<div class="flex items-center justify-between">
<div>
@@ -281,34 +281,6 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
<i class="ri-terminal-box-line text-3xl text-purple-400 opacity-50"></i>
</div>
</div>
<div class="card rounded-xl p-4">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-400 text-sm">系统Cron</p>
<p id="systemCronCount" class="text-2xl font-bold text-orange-400">-</p>
</div>
<i class="ri-timer-line text-3xl text-orange-400 opacity-50"></i>
</div>
</div>
</div>
<!-- 系统 Cron 列表 -->
<div class="card rounded-xl p-6 mb-8">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-bold flex items-center gap-2">
<i class="ri-timer-line text-orange-400"></i>
主机 Cron 列表
</h2>
<button onclick="loadCrons()" class="btn bg-orange-600 hover:bg-orange-700 px-3 py-1 rounded text-sm flex items-center gap-1">
<i class="ri-refresh-line"></i> 刷新
</button>
</div>
<div id="cronsList" class="space-y-3">
<div class="text-center py-8 text-gray-400">
<i class="ri-loader-4-line text-2xl animate-spin"></i>
<p class="mt-2 text-sm">加载中...</p>
</div>
</div>
</div>
<!-- 筛选器 -->
@@ -337,6 +309,33 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
<p class="mt-2">加载中...</p>
</div>
</div>
<!-- 系统 Cron 列表 -->
<div class="card rounded-xl p-6 mt-8">
<div class="flex items-center justify-between mb-4">
<h2 class="text-xl font-bold flex items-center gap-2">
<i class="ri-timer-line text-orange-400"></i>
主机 Cron 列表
<span id="systemCronCount" class="text-sm text-gray-400 ml-2">-</span>
</h2>
<button onclick="loadCrons()" class="btn bg-orange-600 hover:bg-orange-700 px-3 py-1 rounded text-sm flex items-center gap-1">
<i class="ri-refresh-line"></i> 刷新
</button>
</div>
<!-- Cron 概述 -->
<div id="cronSummary" class="mb-4 p-4 bg-gray-800/50 rounded-lg border border-gray-700">
<div class="text-center py-4 text-gray-400 text-sm">加载中...</div>
</div>
<!-- Cron 详细列表 -->
<div id="cronsList" class="space-y-3">
<div class="text-center py-8 text-gray-400">
<i class="ri-loader-4-line text-2xl animate-spin"></i>
<p class="mt-2 text-sm">加载中...</p>
</div>
</div>
</div>
</div>
<!-- 日志模态框 -->
@@ -686,6 +685,7 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
function renderCrons(crons) {
const list = document.getElementById('cronsList');
document.getElementById('systemCronCount').textContent = `${crons.length} 个`;
if (crons.length === 0) {
list.innerHTML = `
@@ -697,6 +697,54 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
return;
}
// 分类统计并生成概述
const userCrons = crons.filter(c => c.source === 'user');
const systemCrons = crons.filter(c => c.source === 'system');
const cronDCrons = crons.filter(c => c.source === 'cron.d');
// 分析用户任务用途
const userTaskTypes = analyzeUserCrons(userCrons);
// 生成概述
let summaryHtml = `
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="bg-blue-500/10 rounded-lg p-3 border border-blue-500/30">
<div class="flex items-center gap-2 mb-2">
<i class="ri-user-line text-blue-400"></i>
<span class="text-blue-400 font-medium">用户任务</span>
<span class="text-blue-300 text-sm">${userCrons.length} 个</span>
</div>
<div class="text-gray-300 text-sm space-y-1">
${userTaskTypes.map(t => `<div><span class="text-gray-400">${t.count}个</span> ${t.name}</div>`).join('')}
</div>
</div>
<div class="bg-red-500/10 rounded-lg p-3 border border-red-500/30">
<div class="flex items-center gap-2 mb-2">
<i class="ri-settings-line text-red-400"></i>
<span class="text-red-400 font-medium">系统任务</span>
<span class="text-red-300 text-sm">${systemCrons.length} 个</span>
</div>
<div class="text-gray-300 text-sm space-y-1">
<div><span class="text-gray-400">每小时</span> 执行 cron.hourly</div>
<div><span class="text-gray-400">每天</span> 执行 cron.daily</div>
<div><span class="text-gray-400">每周</span> 执行 cron.weekly</div>
<div><span class="text-gray-400">每月</span> 执行 cron.monthly</div>
</div>
</div>
<div class="bg-green-500/10 rounded-lg p-3 border border-green-500/30">
<div class="flex items-center gap-2 mb-2">
<i class="ri-file-list-line text-green-400"></i>
<span class="text-green-400 font-medium">cron.d</span>
<span class="text-green-300 text-sm">${cronDCrons.length} 个</span>
</div>
<div class="text-gray-300 text-sm space-y-1">
${cronDCrons.map(c => `<div><span class="text-gray-400">${c.file}</span> ${c.description || ''}</div>`).join('')}
</div>
</div>
</div>
`;
document.getElementById('cronSummary').innerHTML = summaryHtml;
const sourceColors = {
'user': { bg: 'bg-blue-500/20', text: 'text-blue-400', label: '用户' },
'system': { bg: 'bg-red-500/20', text: 'text-red-400', label: '系统' },
@@ -735,6 +783,43 @@ HTML_TEMPLATE = '''<!DOCTYPE html>
list.innerHTML = html;
}
function analyzeUserCrons(crons) {
const types = [];
// 服务监控
const monitors = crons.filter(c => c.command.includes('service-monitor') || c.command.includes('monitor.py') || c.command.includes('cpu-monitor') || c.command.includes('disk-monitor'));
if (monitors.length > 0) types.push({ name: '系统监控', count: monitors.length });
// 股票/板块相关
const stocks = crons.filter(c => c.command.includes('stock') || c.command.includes('board_monitor'));
if (stocks.length > 0) types.push({ name: 'A股数据/板块监控', count: stocks.length });
// 每日总结
const summaries = crons.filter(c => c.command.includes('daily-summary') || c.command.includes('summary'));
if (summaries.length > 0) types.push({ name: '每日总结', count: summaries.length });
// 清理脚本
const cleanups = crons.filter(c => c.command.includes('cleanup') || c.command.includes('clean'));
if (cleanups.length > 0) types.push({ name: '清理脚本', count: cleanups.length });
// 其他
const others = crons.filter(c =>
!c.command.includes('service-monitor') &&
!c.command.includes('monitor.py') &&
!c.command.includes('cpu-monitor') &&
!c.command.includes('disk-monitor') &&
!c.command.includes('stock') &&
!c.command.includes('board_monitor') &&
!c.command.includes('daily-summary') &&
!c.command.includes('summary') &&
!c.command.includes('cleanup') &&
!c.command.includes('clean')
);
if (others.length > 0) types.push({ name: '其他任务', count: others.length });
return types;
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;