diff --git a/static/app.js b/static/app.js
index 0c8d1aa..aec3441 100644
--- a/static/app.js
+++ b/static/app.js
@@ -79,10 +79,28 @@ function taskStatusBadge(t) {
return '未运行';
}
+const GROUPS = [
+ { key: "batch", label: "📄 批量爬取", desc: "一次性爬取指定网址列表" },
+ { key: "scheduled", label: "⏰ 定时爬取", desc: "按间隔或 cron 表达式定时执行" },
+ { key: "auto", label: "🤖 自动爬取", desc: "从起始网址自动发现链接并爬取" },
+];
+
function renderTasks() {
const box = $("taskList");
$("emptyState").classList.toggle("hidden", state.tasks.length > 0);
- box.innerHTML = state.tasks.map(taskCard).join("");
+ box.innerHTML = GROUPS.map((g) => {
+ const items = state.tasks.filter((t) => t.mode === g.key);
+ if (!items.length) return "";
+ return `
+
+
+ ${g.label}
+ ${g.desc}
+ ${items.length} 个任务
+
+
${items.map(taskCard).join("")}
+
`;
+ }).join("");
}
function taskCard(t) {
diff --git a/static/style.css b/static/style.css
index 863414c..7684ffb 100644
--- a/static/style.css
+++ b/static/style.css
@@ -85,6 +85,16 @@ main { padding: 20px 24px; max-width: 1500px; margin: 0 auto; }
.stat-num.num-run { color: var(--accent); }
.stat-label { font-size: 12px; color: var(--muted); margin-top: 3px; }
+/* ---------- 分组展示 ---------- */
+.group { display: flex; flex-direction: column; gap: 12px; margin-bottom: 24px; }
+.group-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
+.group-title { font-size: 16px; font-weight: 700; }
+.group-desc { font-size: 12px; color: var(--muted); }
+.group-count {
+ font-size: 11px; padding: 2px 10px; border-radius: 10px;
+ background: var(--panel2); border: 1px solid var(--border); color: var(--muted);
+}
+
/* ---------- task grid ---------- */
.task-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); gap: 16px; }
.card {