From 5f7c95e8610cd4448f635b05e2c05f36ced3240c Mon Sep 17 00:00:00 2001 From: root Date: Wed, 29 Apr 2026 09:23:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20WebUI=20=E6=94=AF=E6=8C=81=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E6=96=87=E4=BB=B6=EF=BC=8C=E5=86=85=E5=AE=B9=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=BF=BD=E5=8A=A0=E5=88=B0=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/static/index.html | 129 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 2 deletions(-) diff --git a/ui/static/index.html b/ui/static/index.html index f28560b..505199e 100644 --- a/ui/static/index.html +++ b/ui/static/index.html @@ -164,6 +164,70 @@ body { gap: 8px; } +/* File Upload */ +.file-upload-row { + display: flex; + align-items: center; + gap: 8px; + margin-top: 6px; +} + +.file-input { + display: none; +} + +.file-upload-btn { + padding: 4px 12px; + background: var(--surface-lighten); + color: var(--text); + border: 1px dashed var(--text-muted); + border-radius: 4px; + cursor: pointer; + font-family: inherit; + font-size: 12px; + transition: all 0.2s; +} + +.file-upload-btn:hover { + border-color: var(--accent); + color: var(--accent); + background: var(--surface-darken); +} + +.file-info { + display: none; + align-items: center; + gap: 6px; + font-size: 12px; + color: var(--text-muted); + background: var(--surface-darken); + padding: 3px 8px; + border-radius: 4px; +} + +.file-info.attached { + display: inline-flex; +} + +.file-info-name { + color: var(--success); + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.file-info-remove { + cursor: pointer; + color: var(--accent); + font-weight: bold; + padding: 0 4px; +} + +.file-info-remove:hover { + color: var(--warning); +} + .btn { padding: 6px 16px; background: var(--primary); @@ -568,6 +632,14 @@ body {
+
+ + + + + + +
@@ -683,6 +755,14 @@ let activityVisible = false; const helpModal = document.getElementById('helpModal'); const closeHelpBtn = document.getElementById('closeHelp'); +// File upload +const fileInputEl = document.getElementById('fileInput'); +const fileUploadBtn = document.getElementById('fileUploadBtn'); +const fileInfoEl = document.getElementById('fileInfo'); +const fileInfoNameEl = document.getElementById('fileInfoName'); +const fileInfoRemoveEl = document.getElementById('fileInfoRemove'); +let attachedFile = null; + // Config inputs const apiKeyEl = document.getElementById('apiKey'); const baseUrlEl = document.getElementById('baseUrl'); @@ -945,10 +1025,19 @@ function clearOperationLog() { operationLogEl.innerHTML = '
操作日志
暂无操作记录
'; } +function readFileAsText(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result); + reader.onerror = () => reject(new Error('文件读取失败')); + reader.readAsText(file); + }); +} + // Send Message async function sendMessage() { - const message = messageInputEl.value.trim(); - if (!message) return; + let message = messageInputEl.value.trim(); + if (!message && !attachedFile) return; // Check if API is configured if (apiStatusEl.textContent === '未配置') { @@ -956,6 +1045,19 @@ async function sendMessage() { return; } + // If file is attached, read it and prepend to message + if (attachedFile) { + try { + const fileContent = await readFileAsText(attachedFile); + const fileBlock = `文件名:${attachedFile.name}\n内容:\n\`\`\`\n${fileContent}\n\`\`\``; + message = message ? `${fileBlock}\n\n${message}` : fileBlock; + } catch (e) { + updateLatestMessage(`❌ 文件读取失败: ${e.message}`); + return; + } + clearFile(); + } + // Add user message to UI addMessageToUI('user', message); messageInputEl.value = ''; @@ -1074,6 +1176,29 @@ function closeSidebar() { } } +// File upload helpers +function attachFile(file) { + attachedFile = file; + fileInfoNameEl.textContent = file.name; + fileInfoEl.classList.add('attached'); + fileUploadBtn.textContent = '📎 更换文件'; +} + +function clearFile() { + attachedFile = null; + fileInputEl.value = ''; + fileInfoEl.classList.remove('attached'); + fileUploadBtn.textContent = '📎 添加文件'; +} + +fileUploadBtn.addEventListener('click', () => fileInputEl.click()); +fileInputEl.addEventListener('change', () => { + if (fileInputEl.files && fileInputEl.files[0]) { + attachFile(fileInputEl.files[0]); + } +}); +fileInfoRemoveEl.addEventListener('click', clearFile); + // Event Listeners sendBtn.addEventListener('click', sendMessage); clearBtn.addEventListener('click', clearHistory);