添加登录逻辑
This commit is contained in:
parent
9c33a98984
commit
a12727cee4
@ -1,10 +1,13 @@
|
||||
chrome.commands.onCommand.addListener(function (command) {
|
||||
if (command === "open_plugin") {
|
||||
chrome.windows.create({
|
||||
url: "popup.html",
|
||||
type: "popup",
|
||||
width: 640,
|
||||
height: 800
|
||||
});
|
||||
// 仅在插件安装时设置默认 popup 页面,不再在 startup 中干扰当前 UI
|
||||
chrome.runtime.onInstalled.addListener(() => {
|
||||
chrome.storage.local.get(["token", "loginAt"], (res) => {
|
||||
const maxAge = 24 * 60 * 60 * 1000; // 1天有效期
|
||||
const now = Date.now();
|
||||
|
||||
if (!res.token || !res.loginAt || (now - res.loginAt > maxAge)) {
|
||||
chrome.action.setPopup({ popup: "login.html" });
|
||||
} else {
|
||||
chrome.action.setPopup({ popup: "popup.html" });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
59
login.html
Normal file
59
login.html
Normal file
@ -0,0 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>知识库系统登录</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
padding: 20px;
|
||||
width: 300px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
input, button {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
button {
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
font-size: 12px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>知识库系统登录</h2>
|
||||
<div class="form-group">
|
||||
<input id="username" placeholder="用户名" />
|
||||
<input id="password" type="password" placeholder="密码" />
|
||||
<button id="loginBtn">登录</button>
|
||||
</div>
|
||||
<div class="error" id="errorBox"></div>
|
||||
<script src="login.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
42
login.js
Normal file
42
login.js
Normal file
@ -0,0 +1,42 @@
|
||||
const TOKEN_EXPIRE_MS = 24 * 60 * 60 * 1000; // 默认保留 1天
|
||||
|
||||
document.getElementById("loginBtn").addEventListener("click", async () => {
|
||||
const username = document.getElementById("username").value.trim();
|
||||
const password = document.getElementById("password").value.trim();
|
||||
const errorBox = document.getElementById("errorBox");
|
||||
errorBox.textContent = "";
|
||||
|
||||
if (!username || !password) {
|
||||
errorBox.textContent = "请输入用户名和密码";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch("http://app.wisdompulse.cn/api/v1/user/login", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username, password })
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
if (res.ok && data.token) {
|
||||
await chrome.storage.local.set({
|
||||
token: data.token,
|
||||
username: data.username || username,
|
||||
loginAt: Date.now()
|
||||
});
|
||||
chrome.action.setPopup({ popup: "popup.html" });
|
||||
window.location.href = "popup.html";
|
||||
} else {
|
||||
errorBox.textContent = data.message || "登录失败";
|
||||
}
|
||||
} catch (err) {
|
||||
errorBox.textContent = "网络错误,请稍后重试";
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
document.getElementById("loginBtn").click();
|
||||
}
|
||||
});
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "渠道应用开发部知识库",
|
||||
"version": "1.1",
|
||||
"version": "1.2",
|
||||
"description": "通过关键词快速搜索内部文档",
|
||||
"permissions": ["storage"],
|
||||
"host_permissions": [
|
||||
@ -11,16 +11,8 @@
|
||||
"background": {
|
||||
"service_worker": "background.js"
|
||||
},
|
||||
"commands": {
|
||||
"open_plugin": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+K"
|
||||
},
|
||||
"description": "打开渠道应用开发部知识库插件"
|
||||
}
|
||||
},
|
||||
"action": {
|
||||
"default_popup": "popup.html",
|
||||
"default_popup": "login.html",
|
||||
"default_icon": {
|
||||
"16": "icon.png",
|
||||
"48": "icon.png",
|
||||
|
||||
@ -8,9 +8,15 @@
|
||||
<body>
|
||||
<div class="header">
|
||||
<img src="icon.png" alt="logo" class="logo" />
|
||||
<div class="title-box">
|
||||
<h1>渠道应用开发部知识库</h1>
|
||||
<a href="https://oa.ahrcu.com/sys/portal/page.jsp" target="_blank" class="oa-link">跳转OA</a>
|
||||
|
||||
<div class="user-menu">
|
||||
<div class="user-avatar" id="userAvatar">👤</div>
|
||||
<div class="user-dropdown hidden" id="userDropdown">
|
||||
<div id="userName">未登录</div>
|
||||
<div id="logoutBtn" class="logout-option">退出登录</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
116
popup.js
116
popup.js
@ -1,4 +1,4 @@
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
const input = document.getElementById("searchInput");
|
||||
const searchBtn = document.getElementById("searchBtn");
|
||||
const clearHistoryBtn = document.getElementById("clearHistoryBtn");
|
||||
@ -6,17 +6,48 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const historyBox = document.getElementById("historyTags");
|
||||
const historyWrapper = document.getElementById("historyWrapper");
|
||||
|
||||
const userDropdown = document.getElementById("userDropdown");
|
||||
const logoutBtn = document.getElementById("logoutBtn");
|
||||
const userNameLabel = document.getElementById("userName");
|
||||
const userAvatar = document.getElementById("userAvatar");
|
||||
|
||||
let token = null;
|
||||
let currentPage = 1;
|
||||
let totalPages = 1;
|
||||
let lastKeywords = [];
|
||||
|
||||
const TOKEN_EXPIRE_MS = 24 * 60 * 60 * 1000;
|
||||
|
||||
function log(...args) {
|
||||
try {
|
||||
const version = chrome.runtime?.getManifest?.().version || "dev";
|
||||
const version = chrome?.runtime?.getManifest?.().version || "dev";
|
||||
console.log(`[v${version}]`, ...args);
|
||||
} catch (e) {
|
||||
console.log("[v?]", ...args);
|
||||
}
|
||||
|
||||
async function loadToken() {
|
||||
return new Promise((resolve) => {
|
||||
chrome.storage.local.get(["token", "loginAt", "username"], (res) => {
|
||||
log("加载本地存储 token:", res);
|
||||
const now = Date.now();
|
||||
if (!res.token || !res.loginAt || (now - res.loginAt > TOKEN_EXPIRE_MS)) {
|
||||
log("token 不存在或已过期");
|
||||
resolve(null);
|
||||
} else {
|
||||
log("token 加载成功");
|
||||
resolve({
|
||||
token: res.token,
|
||||
username: res.username || "用户"
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleLogout() {
|
||||
log("执行退出登录逻辑");
|
||||
chrome.storage.local.remove(["token", "loginAt", "username"], () => {
|
||||
chrome.action.setPopup({ popup: "login.html" });
|
||||
window.location.href = "login.html";
|
||||
});
|
||||
}
|
||||
|
||||
function showLoading() {
|
||||
@ -50,7 +81,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
}
|
||||
|
||||
function updateHistory(keyword) {
|
||||
if (!chrome?.storage?.local) return;
|
||||
chrome.storage.local.get(["searchHistory"], (res) => {
|
||||
let history = res.searchHistory || [];
|
||||
history = [keyword, ...history.filter(item => item !== keyword)];
|
||||
@ -60,7 +90,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
}
|
||||
|
||||
function renderHistoryTags() {
|
||||
if (!chrome?.storage?.local) return;
|
||||
chrome.storage.local.get(["searchHistory"], (res) => {
|
||||
const history = res.searchHistory || [];
|
||||
historyBox.innerHTML = "";
|
||||
@ -85,6 +114,14 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
}
|
||||
|
||||
async function fetchResults(keywords, page) {
|
||||
log("执行搜索:", keywords, "page:", page);
|
||||
|
||||
if (!token) {
|
||||
log("token 未初始化,跳转 login");
|
||||
handleLogout();
|
||||
return;
|
||||
}
|
||||
|
||||
currentPage = page;
|
||||
lastKeywords = keywords;
|
||||
|
||||
@ -95,18 +132,26 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
size: 10
|
||||
};
|
||||
|
||||
log("触发搜索:", requestBody);
|
||||
showLoading();
|
||||
|
||||
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("后端返回 401,token 无效,登出");
|
||||
handleLogout();
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
resultBox.innerHTML = "";
|
||||
|
||||
@ -137,42 +182,55 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
renderPagination();
|
||||
|
||||
} catch (err) {
|
||||
console.error("[ERROR] 搜索失败:", err);
|
||||
console.error("搜索请求失败:", err);
|
||||
resultBox.innerHTML = "<li>搜索失败,请检查网络或服务状态。</li>";
|
||||
}
|
||||
}
|
||||
|
||||
function triggerSearch() {
|
||||
const inputValue = input.value.trim();
|
||||
if (!inputValue) {
|
||||
clearResults();
|
||||
if (!token) {
|
||||
log("triggerSearch 中 token 丢失,取消搜索");
|
||||
return;
|
||||
}
|
||||
const keywords = inputValue.split(/\s+/).filter(Boolean);
|
||||
updateHistory(inputValue);
|
||||
const val = input.value.trim();
|
||||
if (!val) return clearResults();
|
||||
const keywords = val.split(/\s+/);
|
||||
updateHistory(val);
|
||||
fetchResults(keywords, 1);
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
log("绑定事件成功");
|
||||
searchBtn.addEventListener("click", triggerSearch);
|
||||
input.addEventListener("keydown", e => {
|
||||
if (e.key === "Enter") triggerSearch();
|
||||
input.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
log("用户按下回车 ⏎");
|
||||
triggerSearch();
|
||||
}
|
||||
});
|
||||
|
||||
input.addEventListener("focus", renderHistoryTags);
|
||||
input.addEventListener("input", () => {
|
||||
if (!input.value.trim()) clearResults();
|
||||
});
|
||||
|
||||
input.addEventListener("blur", () => {
|
||||
setTimeout(() => historyWrapper.classList.add("hidden"), 200);
|
||||
});
|
||||
|
||||
input.addEventListener("input", () => !input.value.trim() && clearResults());
|
||||
input.addEventListener("blur", () => setTimeout(() => historyWrapper.classList.add("hidden"), 200));
|
||||
clearHistoryBtn.addEventListener("click", () => {
|
||||
chrome.storage.local.remove("searchHistory", () => {
|
||||
log("历史记录已清空");
|
||||
renderHistoryTags();
|
||||
chrome.storage.local.remove("searchHistory", renderHistoryTags);
|
||||
});
|
||||
logoutBtn.addEventListener("click", handleLogout);
|
||||
userAvatar.addEventListener("click", () => userDropdown.classList.toggle("hidden"));
|
||||
window.addEventListener("click", (e) => {
|
||||
if (!userDropdown.contains(e.target) && e.target !== userAvatar) {
|
||||
userDropdown.classList.add("hidden");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
log("插件初始化完成");
|
||||
const auth = await loadToken();
|
||||
if (!auth) {
|
||||
log("未通过认证,执行登出");
|
||||
handleLogout();
|
||||
} else {
|
||||
token = auth.token;
|
||||
userNameLabel.textContent = auth.username;
|
||||
log("用户认证通过,用户名:", auth.username);
|
||||
bindEvents();
|
||||
}
|
||||
});
|
||||
|
||||
63
styles.css
63
styles.css
@ -207,3 +207,66 @@ h1 {
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
margin-left: 10px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
margin-left: 10px;
|
||||
padding: 4px 10px;
|
||||
font-size: 12px;
|
||||
border: 1px solid #ccc;
|
||||
background: #f9f9f9;
|
||||
color: #333;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.logout-btn:hover {
|
||||
background-color: #f0f0f0;
|
||||
color: #d00;
|
||||
}
|
||||
|
||||
.user-menu {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.user-dropdown {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 30px;
|
||||
background: white;
|
||||
border: 1px solid #ccc;
|
||||
box-shadow: 0 0 4px rgba(0,0,0,0.1);
|
||||
padding: 6px 10px;
|
||||
font-size: 13px;
|
||||
width: 120px;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.user-dropdown div {
|
||||
padding: 6px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.user-dropdown div:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user