新增打包导出: 任务输出目录打包为 zip, 支持网页下载或发送到指定邮箱(默认 wlq@tphai.com)
- GET /api/export?task_id= 打包输出目录为 zip 并下载 (zip 内按任务名建顶层目录) - POST /api/export/email 打包后通过 send_email.py 发送附件到邮箱, 邮箱可指定, 默认 wlq@tphai.com - 详情弹窗新增 [📦 打包下载] [📧 发邮箱] 按钮, 打包中按钮禁用防重复点击 - notify.py 重构: send_attachment(subject, body, to, attach) 通用附件发送 - 打包文件存 data/exports/, 自动清理只保留最近 10 个 - 实测: cnblogs-auto 66MB/1606文件 -> 11.9MB zip 仅1.5s; 邮件发送成功 2.2s
This commit is contained in:
@@ -606,6 +606,8 @@ function renderDetail() {
|
||||
${t.mode === "auto" ? `<button class="btn" onclick="probeTask('${t.id}')">🧪 试爬取</button>
|
||||
<button class="btn" ${t.running ? "disabled" : ""} onclick="clearCache('${t.id}')">🧹 清空缓存</button>` : ""}
|
||||
<button class="btn" onclick="openEdit('${t.id}')">✏️ 编辑配置</button>
|
||||
<button class="btn" onclick="exportZip('${t.id}')">📦 打包下载</button>
|
||||
<button class="btn" onclick="exportEmail('${t.id}')">📧 发邮箱</button>
|
||||
</div>`;
|
||||
|
||||
const chips = runs.map((r) => `
|
||||
@@ -732,6 +734,59 @@ function stopLogPoll() {
|
||||
if (state.logTimer) { clearInterval(state.logTimer); state.logTimer = null; }
|
||||
}
|
||||
|
||||
/* ---------------- 打包导出 ---------------- */
|
||||
async function exportZip(tid) {
|
||||
const btn = window.event && window.event.target;
|
||||
if (btn) { btn.disabled = true; btn.textContent = "⏳ 打包中..."; }
|
||||
try {
|
||||
const res = await fetch(`/api/export?task_id=${tid}`);
|
||||
if (!res.ok) {
|
||||
let d = null;
|
||||
try { d = await res.json(); } catch (e) { /* ignore */ }
|
||||
throw new Error((d && d.error) || `HTTP ${res.status}`);
|
||||
}
|
||||
let fname = "export.zip";
|
||||
const disp = res.headers.get("Content-Disposition") || "";
|
||||
const m = disp.match(/filename\*?=(?:UTF-8'')?"?([^";]+)"?/i);
|
||||
if (m) { try { fname = decodeURIComponent(m[1]); } catch (e) { fname = m[1]; } }
|
||||
const blob = await res.blob();
|
||||
const a = document.createElement("a");
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = fname;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
setTimeout(() => URL.revokeObjectURL(a.href), 5000);
|
||||
toast(`打包下载完成 ${fname} (${(blob.size / 1048576).toFixed(1)} MB)`);
|
||||
} catch (e) {
|
||||
toast("打包失败: " + e.message, true);
|
||||
} finally {
|
||||
if (btn) { btn.disabled = false; btn.textContent = "📦 打包下载"; }
|
||||
}
|
||||
}
|
||||
|
||||
async function exportEmail(tid) {
|
||||
const t = (state.detail.task && state.detail.task.id === tid)
|
||||
? state.detail.task : state.tasks.find((x) => x.id === tid);
|
||||
const def = (t && t.config && t.config.notify_email) || "wlq@tphai.com";
|
||||
const email = prompt("发送到邮箱(留空默认 wlq@tphai.com):", def);
|
||||
if (email === null) return; // 用户取消
|
||||
const btn = window.event && window.event.target;
|
||||
if (btn) { btn.disabled = true; btn.textContent = "⏳ 打包发送中..."; }
|
||||
try {
|
||||
const r = await api("/api/export/email", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ task_id: tid, email: email.trim() || "wlq@tphai.com" }),
|
||||
});
|
||||
toast(r.msg || "已发送");
|
||||
} catch (e) {
|
||||
toast("发送失败: " + e.message, true);
|
||||
} finally {
|
||||
if (btn) { btn.disabled = false; btn.textContent = "📧 发邮箱"; }
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------- 试爬取 ---------------- */
|
||||
function collectProbeFromForm() {
|
||||
const f = $("taskForm");
|
||||
|
||||
Reference in New Issue
Block a user