diff --git a/manifest.json b/manifest.json
index ae7ee66..c29ed71 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,7 +1,7 @@
{
"manifest_version": 3,
"name": "渠道应用开发部知识库",
- "version": "2.0.14",
+ "version": "2.0.15",
"description": "通过关键词快速搜索内部文档",
"permissions": ["storage"],
"host_permissions": [
diff --git a/readme.md b/readme.md
index c12476d..f5b2fdb 100644
--- a/readme.md
+++ b/readme.md
@@ -18,5 +18,6 @@
| 2025.06.24 | V2.0.12 | Luke.Ye | 添加测试页面 |
| 2025.06.28 | V2.0.13 | Luke.Ye | 优化分页展示 |
| 2025.07.03 | V2.0.14 | Luke.Ye | test页面逻辑优化 |
+| 2025.07.09 | V2.0.15 | Luke.Ye | 优化“智能助手”展示页面 |
diff --git a/scripts/llm.js b/scripts/llm.js
index a5e2eb4..4bf6a8d 100644
--- a/scripts/llm.js
+++ b/scripts/llm.js
@@ -333,6 +333,10 @@ async function getLLMToken(forceRefresh = false) {
});
}
+// 放在全局(或函数外部,确保多次渲染只绑定一次即可)
+let isUserAtBottom = true;
+let scrollListenerInited = false;
+
async function fetchLLMAnswer(question, container, contentDiv) {
if (!question || !question.trim()) return;
@@ -354,7 +358,7 @@ async function fetchLLMAnswer(question, container, contentDiv) {
const userToken = auth.token;
const url = config.apiConfig.llmChat.url;
- // ... 你的渲染用户输入的代码 ...
+ // ... 渲染用户输入 ...
const userItem = document.createElement("div");
userItem.className = "llm-msg-item llm-user";
userItem.innerHTML = `我: ${question}`;
@@ -364,10 +368,19 @@ async function fetchLLMAnswer(question, container, contentDiv) {
const msgBox = document.createElement("div");
msgBox.className = "llm-msg-item llm-assistant";
contentDiv.appendChild(msgBox);
- contentDiv.scrollTop = contentDiv.scrollHeight;
+
+ // 只绑定一次滚动监听,且在首次流式渲染时保证已绑定
+ const resultContent = document.getElementById("llmResultContent");
+ if (resultContent && !scrollListenerInited) {
+ resultContent.addEventListener("scroll", function() {
+ isUserAtBottom = resultContent.scrollTop + resultContent.clientHeight >= resultContent.scrollHeight - 20;
+ });
+ scrollListenerInited = true;
+ }
let collectedSources = [];
let jumpMap = {};
+
// LLM 问答接口流式处理
try {
const body = { llmToken, question };
@@ -436,7 +449,7 @@ async function fetchLLMAnswer(question, container, contentDiv) {
answerStr += content;
}
- // 每次都要渲染(不管内容是否为空)
+ // 渲染
let html = "";
try {
html = window.marked ? wrapHtmlWithCopyBtn(marked.parse(answerStr)) : answerStr.replace(/\n/g, "
");
@@ -450,7 +463,11 @@ async function fetchLLMAnswer(question, container, contentDiv) {
bindAllCopyButtons(msgBox);
insertCopyFullAnswerBtn(msgBox, answerStr);
- contentDiv.scrollTop = contentDiv.scrollHeight;
+
+ // === 核心优化:只在用户停留底部时才自动滚到底 ===
+ if (resultContent && isUserAtBottom) {
+ resultContent.scrollTop = resultContent.scrollHeight;
+ }
// 收尾渲染引用
if (chunk.close === true) {
diff --git a/styles/styles-llm.css b/styles/styles-llm.css
index 455009a..cb193de 100644
--- a/styles/styles-llm.css
+++ b/styles/styles-llm.css
@@ -159,7 +159,7 @@ body.fullscreen #tabContentAi.tab-content.active {
.llm-md {
font-size: 14.2px;
- line-height: 1.72;
+ line-height: 1.48;
color: #222d3b;
background: #fcfcfe;
border-radius: 7px;
@@ -170,45 +170,81 @@ body.fullscreen #tabContentAi.tab-content.active {
overflow-x: auto;
}
-/* 段落、标题、块状元素间距 */
+/* 块级元素 margin 清零,只靠外部统一间距 */
.llm-md p,
-.llm-md ul, .llm-md ol, .llm-md pre, .llm-md blockquote, .llm-md table {
- margin-top: 0;
- margin-bottom: 0;
-}
-.llm-md h1, .llm-md h2, .llm-md h3, .llm-md h4, .llm-md h5, .llm-md h6 {
- margin-top: 1.2em;
- margin-bottom: 0.6em;
- font-weight: bold;
- color: #2560de;
- line-height: 1.22;
-}
-.llm-md h1 { font-size: 1.22em; border-bottom: 2px solid #e7eaf5; padding-bottom: 3px; }
-.llm-md h2 { font-size: 1.13em; border-bottom: 1px solid #eceff5; padding-bottom: 2px;}
-.llm-md h3 { font-size: 1.07em; }
-.llm-md h4, .llm-md h5, .llm-md h6 { font-size: 1em; }
-
-.llm-md > * + * {
- margin-top: 0.74em; /* 块元素之间舒适的间隔 */
-}
-
-.llm-md ul, .llm-md ol {
- padding-left: 1.45em;
- margin-left: 0;
-}
-.llm-md li {
- margin-bottom: 0.16em;
+.llm-md ul,
+.llm-md ol,
+.llm-md pre,
+.llm-md blockquote,
+.llm-md table,
+.llm-md h1,
+.llm-md h2,
+.llm-md h3,
+.llm-md h4,
+.llm-md h5,
+.llm-md h6 {
+ margin: 0;
padding: 0;
- line-height: 1.62;
}
+/* 统一块间距 */
+.llm-md > * + * {
+ margin-top: 0.12em;
+}
+
+/* 特殊:列表或段落后直接跟标题时,间距更窄 */
+.llm-md ul + h1,
+.llm-md ul + h2,
+.llm-md ul + h3,
+.llm-md ul + h4,
+.llm-md ul + h5,
+.llm-md ul + h6,
+.llm-md ol + h1,
+.llm-md ol + h2,
+.llm-md ol + h3,
+.llm-md ol + h4,
+.llm-md ol + h5,
+.llm-md ol + h6,
+.llm-md p + h1,
+.llm-md p + h2,
+.llm-md p + h3,
+.llm-md p + h4,
+.llm-md p + h5,
+.llm-md p + h6 {
+ margin-top: 0.02em !important;
+}
+
+/* ---- 列表优化区 ---- */
+.llm-md ul,
+.llm-md ol {
+ padding-left: 1.18em;
+ margin-left: 0;
+ line-height: 1.17; /* 极紧凑,适合 IM/文档区块 */
+}
+
+.llm-md li {
+ display: list-item;
+ margin: 0;
+ padding: 0;
+ line-height: 1.17;
+ word-break: break-word;
+ /* 避免多余空间 */
+}
+
+/* 如果 markdown 渲染成
...