325 lines
11 KiB
JavaScript
325 lines
11 KiB
JavaScript
document.addEventListener("DOMContentLoaded", async () => {
|
||
log("DOMContentLoaded - 页面加载完成");
|
||
|
||
const panel = document.getElementById("draggablePanel");
|
||
const header = document.querySelector(".header");
|
||
if (window.innerWidth > 900 && window.innerHeight > 700) {
|
||
log("启用全屏模式");
|
||
document.body.classList.add("fullscreen");
|
||
if (panel) {
|
||
panel.style.left = "";
|
||
panel.style.top = "";
|
||
panel.style.position = "fixed";
|
||
}
|
||
} else if (panel && header) {
|
||
log("启用可拖拽模式");
|
||
let dragging = false, offsetX = 0, offsetY = 0;
|
||
header.addEventListener("mousedown", (e) => {
|
||
dragging = true;
|
||
offsetX = e.clientX - panel.offsetLeft;
|
||
offsetY = e.clientY - panel.offsetTop;
|
||
document.body.style.userSelect = "none";
|
||
});
|
||
document.addEventListener("mousemove", (e) => {
|
||
if (dragging) {
|
||
panel.style.left = Math.max(0, e.clientX - offsetX) + "px";
|
||
panel.style.top = Math.max(0, e.clientY - offsetY) + "px";
|
||
}
|
||
});
|
||
document.addEventListener("mouseup", () => {
|
||
dragging = false;
|
||
document.body.style.userSelect = "";
|
||
});
|
||
}
|
||
|
||
// ====== 元素选择 ======
|
||
const input = document.getElementById("searchInput");
|
||
const searchBtn = document.getElementById("searchBtn");
|
||
const clearBtn = document.getElementById("clearHistoryBtn");
|
||
const historyBox = document.getElementById("historyTags");
|
||
const historyWrapper = document.getElementById("historyWrapper");
|
||
const resultBox = document.getElementById("results");
|
||
const llmResultContainer = document.getElementById("llmResultContainer");
|
||
const llmResultContent = document.getElementById("llmResultContent");
|
||
const llmInput = document.getElementById("llmInput");
|
||
const llmSendBtn = document.getElementById("llmSendBtn");
|
||
const logoutBtn = document.getElementById("logoutBtn");
|
||
const userNameLabel = document.getElementById("userName");
|
||
const userAvatar = document.getElementById("userAvatar");
|
||
const userDropdown = document.getElementById("userDropdown");
|
||
const openTabBtn = document.getElementById("openTabBtn");
|
||
|
||
const tabEs = document.getElementById("tabEs");
|
||
const tabAi = document.getElementById("tabAi");
|
||
const tabContentEs = document.getElementById("tabContentEs");
|
||
const tabContentAi = document.getElementById("tabContentAi");
|
||
|
||
// ====== 标签切换 ======
|
||
tabEs.onclick = () => {
|
||
log("切换到 ES 结果页");
|
||
tabEs.classList.add("active");
|
||
tabAi.classList.remove("active");
|
||
tabContentEs.classList.add("active");
|
||
tabContentAi.classList.remove("active");
|
||
};
|
||
tabAi.onclick = () => {
|
||
log("切换到 LLM 结果页");
|
||
tabEs.classList.remove("active");
|
||
tabAi.classList.add("active");
|
||
tabContentEs.classList.remove("active");
|
||
tabContentAi.classList.add("active");
|
||
setTimeout(() => {
|
||
llmResultContent.scrollTop = llmResultContent.scrollHeight;
|
||
}, 100);
|
||
};
|
||
|
||
function getQueryParam(name) {
|
||
const url = new URL(window.location.href);
|
||
return url.searchParams.get(name);
|
||
}
|
||
|
||
const isNewTab = getQueryParam("from") === "newtab";
|
||
|
||
let token = null;
|
||
let currentPage = 1;
|
||
let totalPages = 1;
|
||
let lastKeywords = [];
|
||
|
||
const auth = await loadToken();
|
||
if (!auth) {
|
||
log("用户未认证,执行登出");
|
||
return handleLogout();
|
||
}
|
||
token = auth.token;
|
||
userNameLabel.textContent = auth.username;
|
||
log("用户认证成功,用户名:", auth.username);
|
||
|
||
async function triggerSearch() {
|
||
const raw = input?.value?.trim();
|
||
if (!token || !raw) {
|
||
log("取消搜索:token 丢失或关键词为空");
|
||
return;
|
||
}
|
||
|
||
log("执行 triggerSearch,关键词:", raw, "是否新标签页:", isNewTab);
|
||
updateHistory(raw);
|
||
renderHistoryTags(true);
|
||
if (!isNewTab) {
|
||
fetchLLMAnswer(raw, llmResultContainer, llmResultContent);
|
||
}
|
||
fetchResults(raw, 1);
|
||
}
|
||
|
||
function parseKeywordGroups(inputStr) {
|
||
return inputStr
|
||
.trim()
|
||
.split("||")
|
||
.map(group => {
|
||
group = group.trim();
|
||
if (group.startsWith("(") && group.endsWith(")")) group = group.slice(1, -1);
|
||
return group.split(/\s+/).filter(Boolean);
|
||
})
|
||
.filter(g => g.length > 0);
|
||
}
|
||
|
||
function showLoading() {
|
||
resultBox.innerHTML = "<li>加载中...</li>";
|
||
}
|
||
|
||
function clearResults() {
|
||
log("清空结果和历史区域");
|
||
resultBox.innerHTML = "";
|
||
llmResultContent.innerHTML = "";
|
||
llmResultContainer.classList.add("hidden");
|
||
historyWrapper.classList.add("hidden");
|
||
}
|
||
|
||
function renderPagination() {
|
||
const pagination = document.createElement("div");
|
||
pagination.className = "pagination";
|
||
if (currentPage > 1) {
|
||
const prev = document.createElement("button");
|
||
prev.textContent = "上一页";
|
||
prev.onclick = () => fetchResults(lastKeywords, currentPage - 1);
|
||
pagination.appendChild(prev);
|
||
}
|
||
if (currentPage < totalPages) {
|
||
const next = document.createElement("button");
|
||
next.textContent = "下一页";
|
||
next.onclick = () => fetchResults(lastKeywords, currentPage + 1);
|
||
pagination.appendChild(next);
|
||
}
|
||
resultBox.appendChild(pagination);
|
||
}
|
||
|
||
async function fetchResults(rawInput, page) {
|
||
currentPage = page;
|
||
lastKeywords = rawInput;
|
||
log("调用 fetchResults,关键词:", rawInput, "页码:", page);
|
||
showLoading();
|
||
|
||
const keywordGroups = parseKeywordGroups(rawInput);
|
||
const requestBody = {
|
||
keywordGroups,
|
||
page: currentPage,
|
||
size: 10
|
||
};
|
||
|
||
try {
|
||
const response = await fetch("http://app.wisdompulse.cn/search", {
|
||
method: "POST",
|
||
headers: {
|
||
"Authorization": `${token}`,
|
||
"Content-Type": "application/json"
|
||
},
|
||
body: JSON.stringify(requestBody)
|
||
});
|
||
|
||
log("搜索接口响应状态:", response.status);
|
||
|
||
if (response.status === 401) {
|
||
log("token 已失效,执行登出");
|
||
return handleLogout();
|
||
}
|
||
|
||
const data = await response.json();
|
||
resultBox.innerHTML = "";
|
||
|
||
if (!data.results || data.results.length === 0) {
|
||
log("无搜索结果");
|
||
resultBox.innerHTML = "<li>未找到相关文档</li>";
|
||
return;
|
||
}
|
||
|
||
totalPages = Math.ceil(data.total / data.size);
|
||
|
||
data.results.forEach(doc => {
|
||
const li = document.createElement("li");
|
||
const path = doc.filepath.replace(/^import-data\//, "").replace(/\.md$/, ".html");
|
||
const link = document.createElement("a");
|
||
link.href = `http://share.wisdompulse.cn/public/${path}`;
|
||
link.target = "_blank";
|
||
link.textContent = doc.filename;
|
||
|
||
const snippet = document.createElement("div");
|
||
snippet.className = "summary";
|
||
snippet.innerHTML = doc.summary?.slice(0, 300) + "...";
|
||
|
||
li.appendChild(link);
|
||
li.appendChild(snippet);
|
||
resultBox.appendChild(li);
|
||
});
|
||
|
||
renderPagination();
|
||
} catch (err) {
|
||
log("搜索请求异常:", err);
|
||
resultBox.innerHTML = "<li>搜索失败,请检查网络或服务状态。</li>";
|
||
}
|
||
}
|
||
|
||
function updateHistory(keyword) {
|
||
log("更新搜索历史:", keyword);
|
||
chrome.storage.local.get(["searchHistory"], (res) => {
|
||
let history = res.searchHistory || [];
|
||
history = [keyword, ...history.filter(item => item !== keyword)];
|
||
if (history.length > 5) history = history.slice(0, 5);
|
||
chrome.storage.local.set({ searchHistory: history });
|
||
});
|
||
}
|
||
|
||
function renderHistoryTags(show = false) {
|
||
log("渲染历史标签,是否显示:", show);
|
||
chrome.storage.local.get(["searchHistory"], (res) => {
|
||
const history = res.searchHistory || [];
|
||
historyBox.innerHTML = "";
|
||
|
||
if (history.length === 0 || !show) {
|
||
historyWrapper.classList.add("hidden");
|
||
return;
|
||
}
|
||
|
||
history.forEach(tagText => {
|
||
const tag = document.createElement("span");
|
||
tag.className = "tag";
|
||
tag.textContent = tagText;
|
||
tag.onclick = () => {
|
||
input.value = tagText;
|
||
triggerSearch();
|
||
};
|
||
historyBox.appendChild(tag);
|
||
});
|
||
|
||
historyWrapper.classList.remove("hidden");
|
||
});
|
||
}
|
||
|
||
// ====== DOM 事件绑定 ======
|
||
searchBtn.addEventListener("click", () => {
|
||
log("点击搜索按钮");
|
||
triggerSearch();
|
||
});
|
||
input.addEventListener("keydown", e => {
|
||
if (e.key === "Enter") {
|
||
log("按下回车键");
|
||
triggerSearch();
|
||
}
|
||
});
|
||
input.addEventListener("focus", () => renderHistoryTags(true));
|
||
input.addEventListener("input", () => {
|
||
if (!input.value.trim()) {
|
||
log("输入清空,清除结果");
|
||
clearResults();
|
||
}
|
||
});
|
||
input.addEventListener("blur", () => setTimeout(() => historyWrapper.classList.add("hidden"), 200));
|
||
clearBtn.addEventListener("click", () => {
|
||
log("点击清空历史按钮");
|
||
chrome.storage.local.remove("searchHistory", () => renderHistoryTags());
|
||
});
|
||
|
||
logoutBtn?.addEventListener("click", () => {
|
||
log("点击退出登录按钮");
|
||
handleLogout();
|
||
});
|
||
|
||
userAvatar?.addEventListener("click", () => {
|
||
log("点击用户头像,切换菜单");
|
||
userDropdown.classList.toggle("hidden");
|
||
});
|
||
|
||
window.addEventListener("click", (e) => {
|
||
if (!userDropdown.contains(e.target) && e.target !== userAvatar) {
|
||
userDropdown.classList.add("hidden");
|
||
}
|
||
});
|
||
|
||
llmSendBtn?.addEventListener("click", () => {
|
||
const val = llmInput.value.trim();
|
||
if (!val) return;
|
||
llmInput.value = "";
|
||
log("发送 LLM 问题:", val);
|
||
fetchLLMAnswer(val, llmResultContainer, llmResultContent);
|
||
});
|
||
|
||
llmInput.addEventListener("keydown", (e) => {
|
||
if (e.key === "Enter") llmSendBtn.click();
|
||
});
|
||
|
||
openTabBtn.onclick = () => {
|
||
const val = input?.value?.trim();
|
||
const encoded = encodeURIComponent(val || "");
|
||
const url = chrome.runtime.getURL("pages/popup.html?keywords=" + encoded + "&from=newtab");
|
||
log("点击新标签页按钮,跳转到:", url);
|
||
chrome.tabs?.create({ url });
|
||
};
|
||
|
||
const autoKeywords = getQueryParam("keywords");
|
||
if (autoKeywords) {
|
||
input.value = decodeURIComponent(autoKeywords);
|
||
log("检测到 URL 参数 keywords,自动搜索:", input.value);
|
||
triggerSearch();
|
||
}
|
||
|
||
renderHistoryTags();
|
||
});
|