v1.0.4: 基本搜索功能 - 按网址/标题/任务名子串匹配查找已爬内容, 支持跳转预览

This commit is contained in:
2026-08-11 15:21:31 +08:00
parent e70a3a877f
commit e8541a8545
5 changed files with 164 additions and 2 deletions
+74 -1
View File
@@ -161,6 +161,76 @@ async function delTask(tid) {
} catch (e) { toast(e.message, true); }
}
/* ---------------- 搜索 ---------------- */
async function doSearch() {
const q = $("searchInput").value.trim();
if (!q) { toast("请输入搜索关键词", true); return; }
try {
const d = await api(`/api/search?q=${encodeURIComponent(q)}`);
renderSearch(d);
showModal("searchModal");
} catch (e) { toast(e.message, true); }
}
function renderSearch(d) {
const body = $("searchBody");
if (!d.results.length) {
body.innerHTML = `<div class="empty" style="padding:40px 0"><div class="empty-icon">🔍</div><p>没有找到与「${esc(d.q)}」相关的内容</p></div>`;
return;
}
const items = d.results.map((r) => {
const badge = `<span class="badge ${esc(r.mode)}">${MODE_LABEL[r.mode] || esc(r.mode)}</span>`;
if (r.type === "task") {
return `
<div class="search-item">
<div class="row">
${badge}
<span class="title">📋 ${esc(r.task_name)}</span>
<span class="badge">任务</span>
</div>
<div class="url">${r.seed_url ? "起始: " + esc(r.seed_url) : "网址 " + (r.urls_count || 0) + " 个"} · 创建于 ${esc(r.created_at || "")}</div>
<div class="row">
<button class="btn sm" onclick="searchOpenDetail('${r.task_id}')">📋 查看任务</button>
</div>
</div>`;
}
const stCls = r.status === "OK" ? "t-ok" : "t-fail";
const html = r.html_file ? `<span class="file-link" onclick="searchPreview('${r.task_id}','${esc(r.html_file)}','HTML: ${esc(r.url)}')">HTML</span>` : "";
const txt = r.txt_file ? `<span class="file-link" onclick="searchPreview('${r.task_id}','${esc(r.txt_file)}','文本: ${esc(r.url)}')">TXT</span>` : "";
const meta = r.meta_file ? `<span class="file-link" onclick="searchMeta('${r.task_id}','${esc(r.meta_file)}')">📋 元数据</span>` : "";
return `
<div class="search-item">
<div class="row">
${badge}
<span class="title" title="${esc(r.title)}">${esc(r.title) || "(无标题)"}</span>
<span class="badge ${stCls}">${r.status}</span>
<span class="badge">${esc(r.run_status)}</span>
<span class="card-line">${esc(r.crawl_time || "")}</span>
</div>
<div class="url">🌐 ${esc(r.url)}${r.images ? ` · 🖼️ ${r.images}` : ""}</div>
<div class="row">
${html}${txt}${meta}
<button class="btn sm" onclick="searchOpenDetail('${r.task_id}')">📋 任务详情</button>
</div>
</div>`;
}).join("");
body.innerHTML = `<div class="probe-summary"><span>关键词: <b>${esc(d.q)}</b></span><span>共 <b>${d.count}</b> 条结果</span></div>${items}`;
}
/* 搜索结果的跳转动作: 先关搜索弹窗再打开目标 */
function searchOpenDetail(tid) {
hideModal("searchModal");
openDetail(tid);
}
function searchPreview(tid, path, title) {
hideModal("searchModal");
previewFile(tid, path, title);
}
function searchMeta(tid, metaFile) {
hideModal("searchModal");
showMeta(tid, metaFile);
}
/* ---------------- 回收站 ---------------- */
async function openTrash() {
try {
@@ -700,6 +770,8 @@ $("btnNew").onclick = openCreate;
$("btnNew2").onclick = openCreate;
$("btnRefresh").onclick = loadTasks;
$("btnTrash").onclick = openTrash;
$("btnSearch").onclick = doSearch;
$("searchInput").addEventListener("keydown", (e) => { if (e.key === "Enter") doSearch(); });
$("btnProbe").onclick = () => {
const p = collectProbeFromForm();
if (!p.seed_url) { toast("请先填写起始网址", true); return; }
@@ -718,6 +790,7 @@ document.querySelectorAll("[data-close-preview]").forEach((b) => b.onclick = ()
document.querySelectorAll("[data-close-probe]").forEach((b) => b.onclick = () => hideModal("probeModal"));
document.querySelectorAll("[data-close-meta]").forEach((b) => b.onclick = () => hideModal("metaModal"));
document.querySelectorAll("[data-close-trash]").forEach((b) => b.onclick = () => hideModal("trashModal"));
document.querySelectorAll("[data-close-search]").forEach((b) => b.onclick = () => hideModal("searchModal"));
/* 表单改动监听 -> 脏标记 */
$("taskForm").addEventListener("input", () => { formDirty = true; });
@@ -744,7 +817,7 @@ document.addEventListener("keydown", (e) => {
}
stopLogPoll();
$("previewFrame").src = "about:blank";
["detailModal", "probeModal", "metaModal", "trashModal", "previewModal"].forEach((id) => $(id).classList.add("hidden"));
["detailModal", "probeModal", "metaModal", "trashModal", "searchModal", "previewModal"].forEach((id) => $(id).classList.add("hidden"));
}
});