v1.0.1: 弹窗防误关确认/布局修复/定时任务首次执行时间/日间夜间双主题/总体统计区
This commit is contained in:
+69
-5
@@ -11,6 +11,7 @@ const state = {
|
||||
detail: { task: null, runId: null, logOffset: 0, timer: null },
|
||||
logTimer: null,
|
||||
};
|
||||
let formDirty = false; // 新建/编辑表单是否有未保存修改
|
||||
|
||||
/* ---------------- 工具 ---------------- */
|
||||
function toast(msg, isErr) {
|
||||
@@ -48,6 +49,21 @@ async function loadTasks() {
|
||||
} catch (e) {
|
||||
toast("加载任务失败: " + e.message, true);
|
||||
}
|
||||
loadStats();
|
||||
}
|
||||
|
||||
async function loadStats() {
|
||||
try {
|
||||
const s = await api("/api/stats");
|
||||
$("stTasks").textContent = s.tasks;
|
||||
$("stRunning").textContent = s.running;
|
||||
$("stRuns").textContent = s.runs;
|
||||
$("stOk").textContent = s.ok;
|
||||
$("stFail").textContent = s.fail;
|
||||
$("stImgs").textContent = s.images;
|
||||
$("stDisk").textContent = s.disk_mb >= 1024
|
||||
? (s.disk_mb / 1024).toFixed(1) + " GB" : s.disk_mb + " MB";
|
||||
} catch (e) { /* 统计失败忽略 */ }
|
||||
}
|
||||
|
||||
function taskStatusBadge(t) {
|
||||
@@ -156,8 +172,17 @@ function switchMode(mode, lock) {
|
||||
$("autoBox").classList.toggle("hidden", mode !== "auto");
|
||||
}
|
||||
|
||||
function toLocalInputVal(iso) {
|
||||
if (!iso) return "";
|
||||
const d = new Date(String(iso).replace(" ", "T"));
|
||||
if (isNaN(d.getTime())) return "";
|
||||
const p = (n) => String(n).padStart(2, "0");
|
||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}T${p(d.getHours())}:${p(d.getMinutes())}`;
|
||||
}
|
||||
|
||||
function openCreate() {
|
||||
state.editTask = null;
|
||||
formDirty = false;
|
||||
$("modalTitle").textContent = "新建爬取任务";
|
||||
$("taskForm").reset();
|
||||
$("taskForm").elements["delay_min"].value = 2;
|
||||
@@ -195,6 +220,7 @@ async function openEdit(tid) {
|
||||
f.elements["interval_value"].value = t.schedule.interval_value ?? 24;
|
||||
f.elements["interval_unit"].value = t.schedule.interval_unit || "hours";
|
||||
f.elements["cron"].value = t.schedule.cron || "";
|
||||
f.elements["first_run"].value = toLocalInputVal(t.schedule.next_run || "");
|
||||
}
|
||||
if (t.mode === "auto" && t.auto) {
|
||||
f.elements["seed_url"].value = t.auto.seed_url || "";
|
||||
@@ -209,6 +235,7 @@ async function openEdit(tid) {
|
||||
$("formHint").textContent = t.running
|
||||
? "⚠️ 任务运行中:参数修改将热更新(网址/规则改动下次运行生效)"
|
||||
: "";
|
||||
formDirty = false;
|
||||
switchMode(t.mode, true);
|
||||
showModal("taskModal");
|
||||
}
|
||||
@@ -259,6 +286,7 @@ async function submitForm(e) {
|
||||
interval_unit: f.elements["interval_unit"].value,
|
||||
interval_value: parseInt(f.elements["interval_value"].value) || 1,
|
||||
cron: f.elements["cron"].value.trim(),
|
||||
first_run: f.elements["first_run"].value || "",
|
||||
};
|
||||
}
|
||||
try {
|
||||
@@ -275,6 +303,7 @@ async function submitForm(e) {
|
||||
});
|
||||
toast(`任务「${t.name}」已创建`);
|
||||
}
|
||||
formDirty = false;
|
||||
hideModal("taskModal");
|
||||
loadTasks();
|
||||
} catch (err) { toast(err.message, true); }
|
||||
@@ -457,6 +486,29 @@ function previewFile(tid, path, title) {
|
||||
function showModal(id) { $(id).classList.remove("hidden"); }
|
||||
function hideModal(id) { $(id).classList.add("hidden"); }
|
||||
|
||||
/* 关闭任务弹窗: 有未保存修改时先确认 */
|
||||
function safeCloseTaskModal() {
|
||||
if (formDirty && !confirm("有未保存的修改,确定要放弃吗?")) return false;
|
||||
formDirty = false;
|
||||
hideModal("taskModal");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ---------------- 主题切换 ---------------- */
|
||||
function applyTheme(theme) {
|
||||
document.body.dataset.theme = theme;
|
||||
$("btnTheme").textContent = theme === "light" ? "🌙" : "☀️";
|
||||
try { localStorage.setItem("crawler_theme", theme); } catch (e) { /* ignore */ }
|
||||
}
|
||||
$("btnTheme").onclick = () => {
|
||||
applyTheme(document.body.dataset.theme === "light" ? "dark" : "light");
|
||||
};
|
||||
try {
|
||||
applyTheme(localStorage.getItem("crawler_theme") || "dark");
|
||||
} catch (e) {
|
||||
applyTheme("dark");
|
||||
}
|
||||
|
||||
/* ---------------- 事件绑定 ---------------- */
|
||||
$("btnNew").onclick = openCreate;
|
||||
$("btnNew2").onclick = openCreate;
|
||||
@@ -468,24 +520,36 @@ document.querySelectorAll("#modeTabs .tab").forEach((b) => {
|
||||
$("taskForm").onsubmit = submitForm;
|
||||
$("taskForm").elements["schedule_type"].onchange = syncScheduleUI;
|
||||
|
||||
document.querySelectorAll("[data-close]").forEach((b) => b.onclick = () => hideModal("taskModal"));
|
||||
document.querySelectorAll("[data-close]").forEach((b) => b.onclick = safeCloseTaskModal);
|
||||
document.querySelectorAll("[data-close-detail]").forEach((b) => b.onclick = () => { stopLogPoll(); hideModal("detailModal"); });
|
||||
document.querySelectorAll("[data-close-preview]").forEach((b) => b.onclick = () => { $("previewFrame").src = "about:blank"; hideModal("previewModal"); });
|
||||
|
||||
/* 表单改动监听 -> 脏标记 */
|
||||
$("taskForm").addEventListener("input", () => { formDirty = true; });
|
||||
$("taskForm").addEventListener("change", () => { formDirty = true; });
|
||||
|
||||
document.querySelectorAll(".modal-overlay").forEach((ov) => {
|
||||
ov.addEventListener("mousedown", (e) => {
|
||||
if (e.target === ov) {
|
||||
if (ov.id === "detailModal") stopLogPoll();
|
||||
if (ov.id === "previewModal") $("previewFrame").src = "about:blank";
|
||||
ov.classList.add("hidden");
|
||||
if (ov.id === "taskModal") {
|
||||
safeCloseTaskModal();
|
||||
} else {
|
||||
if (ov.id === "detailModal") stopLogPoll();
|
||||
if (ov.id === "previewModal") $("previewFrame").src = "about:blank";
|
||||
ov.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") {
|
||||
if (!$("taskModal").classList.contains("hidden")) {
|
||||
safeCloseTaskModal();
|
||||
return;
|
||||
}
|
||||
stopLogPoll();
|
||||
$("previewFrame").src = "about:blank";
|
||||
["taskModal", "detailModal", "previewModal"].forEach((id) => $(id).classList.add("hidden"));
|
||||
["detailModal", "previewModal"].forEach((id) => $(id).classList.add("hidden"));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user