From c98cf90704e06cab9c8740e424dc9be6f82e6156 Mon Sep 17 00:00:00 2001 From: luke Date: Mon, 16 Jun 2025 10:42:47 +0800 Subject: [PATCH] =?UTF-8?q?=C3=A4=C2=BF=E6=B7=BB=E5=8A=A0=E5=AF=B9=C3=A8?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E5=85=A5=C3=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manifest.json | 2 +- pages/popup.html | 1 + pages/uploader.html | 55 +++++++++++++++++++ readme.md | 1 + scripts/popup.js | 19 +++++++ scripts/uploader.js | 129 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 pages/uploader.html create mode 100644 scripts/uploader.js diff --git a/manifest.json b/manifest.json index 328ad89..ec102af 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "渠道应用开发部知识库", - "version": "2.0.5", + "version": "2.0.6", "description": "通过关键词快速搜索内部文档", "permissions": ["storage"], "host_permissions": [ diff --git a/pages/popup.html b/pages/popup.html index 040c4aa..76992d6 100644 --- a/pages/popup.html +++ b/pages/popup.html @@ -19,6 +19,7 @@
👤
diff --git a/pages/uploader.html b/pages/uploader.html new file mode 100644 index 0000000..1027efd --- /dev/null +++ b/pages/uploader.html @@ -0,0 +1,55 @@ + + + + + 上传文件到 MinIO/S3 + + + +
+

上传文件到 MinIO/S3

+
可拖拽或点击选择,支持多文件上传
+
+ + +
+
+ + +
+
* 如 bucket 不存在请先在 MinIO 控制台创建
+
+
拖拽文件到此上传,或点击选择文件
+ + +
+
+
+ + + diff --git a/readme.md b/readme.md index 164c963..d062c17 100644 --- a/readme.md +++ b/readme.md @@ -9,4 +9,5 @@ | 2025.06.06 | V2.0.3 | Luke.Ye | 添加跳转页面权限校验 | | 2025.06.09 | V2.0.4 | Luke.Ye | 优化es搜索展示页面 | | 2025.06.10 | V2.0.5 | Luke.Ye | 移除自动请求智能助手逻辑 | +| 2025.06.16 | V2.0.6 | Luke.Ye | 添加上传文件到对象存储功能 | diff --git a/scripts/popup.js b/scripts/popup.js index eaf80bc..35852a3 100644 --- a/scripts/popup.js +++ b/scripts/popup.js @@ -1,3 +1,4 @@ +// popup.js document.addEventListener("DOMContentLoaded", async () => { const panel = document.getElementById("draggablePanel"); const header = document.querySelector(".header"); @@ -45,6 +46,7 @@ document.addEventListener("DOMContentLoaded", async () => { const userDropdown = document.getElementById("userDropdown"); const openTabBtn = document.getElementById("openTabBtn"); const settingsBtn = document.getElementById("settingsBtn"); + const openUploaderMenu = document.getElementById("openUploaderMenu"); const tabEs = document.getElementById("tabEs"); const tabAi = document.getElementById("tabAi"); const tabContentEs = document.getElementById("tabContentEs"); @@ -263,6 +265,11 @@ document.addEventListener("DOMContentLoaded", async () => { settingsBtn?.addEventListener("click", () => { chrome.tabs.create({ url: chrome.runtime.getURL("pages/settings.html") }); }); + openUploaderMenu?.addEventListener("click", () => { + const uploaderUrl = chrome.runtime ? chrome.runtime.getURL("pages/uploader.html") : "pages/uploader.html"; + window.open(uploaderUrl, "_blank"); + userDropdown.classList.add("hidden"); + }); window.addEventListener("click", (e) => { if (!userDropdown.contains(e.target) && e.target !== userAvatar) { @@ -299,3 +306,15 @@ document.addEventListener("DOMContentLoaded", async () => { renderHistoryTags(); }); + +// 时间戳格式化辅助 +function formatLocalTime(ts) { + if (!ts) return ""; + const date = new Date(Number(ts)); + if (isNaN(date.getTime())) return ""; + return date.getFullYear() + "-" + + String(date.getMonth() + 1).padStart(2, "0") + "-" + + String(date.getDate()).padStart(2, "0") + " " + + String(date.getHours()).padStart(2, "0") + ":" + + String(date.getMinutes()).padStart(2, "0"); +} diff --git a/scripts/uploader.js b/scripts/uploader.js new file mode 100644 index 0000000..e720ed4 --- /dev/null +++ b/scripts/uploader.js @@ -0,0 +1,129 @@ +// uploader.js +const dropArea = document.getElementById("drop-area"); +const fileElem = document.getElementById("fileElem"); +const uploadList = document.getElementById("uploadList"); +const folderNameInput = document.getElementById("folderName"); +const bucketNameInput = document.getElementById("bucketName"); + +const API_UPLOAD = "http://localhost:18081/api/v1/doc/upload-files"; + +dropArea.addEventListener("click", () => fileElem.click()); +dropArea.addEventListener("dragover", e => { + e.preventDefault(); dropArea.classList.add("dragover"); +}); +dropArea.addEventListener("dragleave", e => { + e.preventDefault(); dropArea.classList.remove("dragover"); +}); +dropArea.addEventListener("drop", e => { + e.preventDefault(); dropArea.classList.remove("dragover"); + handleFiles(e.dataTransfer.files); +}); +fileElem.addEventListener("change", () => handleFiles(fileElem.files)); + +function getTargetFolder() { + let folder = (folderNameInput.value || "").trim(); + if (!folder) folder = "default"; + folder = folder.replace(/^\/+|\/+$/g, ""); + return folder; +} +function getBucketName() { + let bucket = (bucketNameInput.value || "").trim(); + return bucket.replace(/^\/+|\/+$/g, ""); +} + +// 工具:为单个文件显示进度 +function createProgressItem(filename) { + const wrapper = document.createElement("div"); + wrapper.className = "progress-item"; + wrapper.innerHTML = ` + ${filename} + + 0% + + `; + uploadList.appendChild(wrapper); + return wrapper; +} + +async function handleFiles(files) { + uploadList.innerHTML = ""; + const bucket = getBucketName(); + if (!bucket) { + showMsg("请输入 Bucket 名称", false); + return; + } + if (!files || !files.length) return; + const folder = getTargetFolder(); + + // 多文件逐个上传,每个单独显示进度 + for (const file of files) { + await uploadSingleFile(file, bucket, folder); + } +} + +function showMsg(msg, ok) { + const div = document.createElement("div"); + div.className = ok ? "success" : "error"; + div.innerHTML = msg; + uploadList.appendChild(div); +} + +// 单文件上传,带进度条 +function uploadSingleFile(file, bucket, folder) { + return new Promise((resolve) => { + const form = new FormData(); + form.append("bucket", bucket); + form.append("files", file, file.name); + + const progressItem = createProgressItem(file.name); + const progressBar = progressItem.querySelector("progress"); + const percentLabel = progressItem.querySelector(".percent-label"); + const msgSpan = progressItem.querySelector(".upload-msg"); + + const xhr = new XMLHttpRequest(); + xhr.open("POST", API_UPLOAD); + + xhr.upload.onprogress = function (e) { + if (e.lengthComputable) { + const percent = Math.round((e.loaded / e.total) * 100); + progressBar.value = percent; + percentLabel.textContent = percent + "%"; + } + }; + + xhr.onload = function () { + progressBar.value = 100; + percentLabel.textContent = "100%"; + if (xhr.status === 200) { + try { + const res = JSON.parse(xhr.responseText); + // 查找本文件上传结果 + let link = ""; + if (res.files && res.files[file.name]) { + link = `${file.name} 上传成功`; + msgSpan.innerHTML = link; + msgSpan.className = "success"; + } else { + msgSpan.innerHTML = "上传成功"; + msgSpan.className = "success"; + } + } catch (e) { + msgSpan.innerHTML = "上传成功"; + msgSpan.className = "success"; + } + } else { + msgSpan.innerHTML = "上传失败 " + xhr.status; + msgSpan.className = "error"; + } + resolve(); + }; + + xhr.onerror = function () { + msgSpan.innerHTML = "上传异常"; + msgSpan.className = "error"; + resolve(); + }; + + xhr.send(form); + }); +}