From 4b801c8dc7975fdaa392aca4fa6c95e8689ddeb4 Mon Sep 17 00:00:00 2001 From: Cola-Echo Date: Sat, 17 Jan 2026 01:35:20 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E8=BF=9B=E5=BA=A6?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E7=A7=BB=E5=8A=A8=E7=AB=AF=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E5=92=8C=E6=8B=96=E6=8B=BD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 进度面板移动端默认定位改为左上角(参考剧情优化面板) - 修复移动端拖拽时面板消失的问题 - 使用 setProperty 设置 !important 内联样式覆盖CSS规则 - 拖拽开始时先固定当前位置防止跳变 - 移动端拖拽后保持用户自定义位置 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- index.js | 115 +++++++++++++++++++++++++++++++++++++++++++----------- style.css | 51 +++++++++++++++++------- 2 files changed, 130 insertions(+), 36 deletions(-) diff --git a/index.js b/index.js index 4cad2bc..ef80a10 100644 --- a/index.js +++ b/index.js @@ -3640,6 +3640,13 @@ y: clientY - rect.top, }; + // 先将当前位置固定为内联样式(防止拖拽时位置跳变) + // 使用 setProperty 设置 !important,以覆盖移动端CSS中的 !important 规则 + this.container.style.setProperty('left', `${rect.left}px`, 'important'); + this.container.style.setProperty('top', `${rect.top}px`, 'important'); + this.container.style.setProperty('right', 'auto', 'important'); + this.container.style.setProperty('transform', 'none', 'important'); + // 添加拖动样式 this.container.classList.add("mm-dragging"); @@ -3676,10 +3683,10 @@ newX = Math.max(0, Math.min(newX, maxX)); newY = Math.max(0, Math.min(newY, maxY)); - // 应用位置(使用 left/top 而不是 transform) - this.container.style.left = `${newX}px`; - this.container.style.top = `${newY}px`; - this.container.style.transform = "none"; + // 应用位置(使用 setProperty 设置 !important,覆盖移动端CSS) + this.container.style.setProperty('left', `${newX}px`, 'important'); + this.container.style.setProperty('top', `${newY}px`, 'important'); + this.container.style.setProperty('transform', 'none', 'important'); this.position = { x: newX, y: newY }; }; @@ -3694,9 +3701,15 @@ document.removeEventListener("touchmove", onDragMove); document.removeEventListener("touchend", onDragEnd); - // 保存位置 - if (this.position) { - this.savePosition(); + // 保存位置(如果有移动) + if (this.position && dragMoved) { + // 移动端:添加用户定位类让拖拽位置生效,但不保存到localStorage + // 桌面端:保存位置并添加用户定位类 + if (window.innerWidth >= 768) { + this.savePosition(); + } + // 移动端和桌面端都添加用户定位类,让拖拽后的位置生效 + this.container.classList.add("mm-user-positioned"); } // 判断是否为点击(短时间内没有移动) @@ -3722,8 +3735,11 @@ }, { passive: false }); } - // 保存位置到 localStorage + // 保存位置到 localStorage(仅桌面端) savePosition() { + // 移动端不保存位置 + if (window.innerWidth < 768) return; + if (this.position) { localStorage.setItem( "mm_progress_panel_position", @@ -3748,6 +3764,8 @@ this.container.style.left = `${pos.x}px`; this.container.style.top = `${pos.y}px`; this.container.style.transform = "none"; + // 添加用户定位类,防止移动端 CSS 覆盖 + this.container.classList.add("mm-user-positioned"); } } } catch (e) { @@ -3761,6 +3779,7 @@ this.container.style.left = "50%"; this.container.style.top = "80px"; this.container.style.transform = "translateX(-50%)"; + this.container.classList.remove("mm-user-positioned"); localStorage.removeItem("mm_progress_panel_position"); } @@ -3777,13 +3796,53 @@ this.hideTimeout = null; } - // 重置面板位置,让CSS初始定位生效 + // 检查是否有保存的位置 if (this.container) { - this.container.style.left = ""; - this.container.style.top = ""; - this.container.style.right = ""; - this.container.style.bottom = ""; - this.container.style.transform = ""; + // 移动端(宽度小于768px)不使用保存的位置,始终使用CSS默认位置 + const isMobile = window.innerWidth < 768; + + if (isMobile) { + // 移动端:清除所有内联样式,使用CSS默认定位 + this.container.style.left = ""; + this.container.style.top = ""; + this.container.style.right = ""; + this.container.style.bottom = ""; + this.container.style.transform = ""; + this.container.classList.remove("mm-user-positioned"); + this.position = null; + } else { + // 桌面端:尝试使用保存的位置 + const saved = localStorage.getItem("mm_progress_panel_position"); + if (saved) { + try { + const pos = JSON.parse(saved); + requestAnimationFrame(() => { + const rect = this.container.getBoundingClientRect(); + const maxX = window.innerWidth - Math.min(rect.width, 320); + const maxY = window.innerHeight - Math.min(rect.height, 100); + + if (pos.x >= 0 && pos.x <= maxX && pos.y >= 0 && pos.y <= maxY) { + this.position = pos; + this.container.style.left = `${pos.x}px`; + this.container.style.top = `${pos.y}px`; + this.container.style.transform = "none"; + this.container.classList.add("mm-user-positioned"); + } else { + this.resetPosition(); + } + }); + } catch (e) { + // 解析失败 + } + } else { + this.container.style.left = ""; + this.container.style.top = ""; + this.container.style.right = ""; + this.container.style.bottom = ""; + this.container.style.transform = ""; + this.container.classList.remove("mm-user-positioned"); + } + } } this.isVisible = true; @@ -6440,6 +6499,10 @@ async function callSingleSummaryBookAI(panel, book, userMessage, context) { const bookName = book.name; + // 创建 AbortController 用于终止任务 + const taskId = `search_${bookName}`; + const abortController = new AbortController(); + try { panel.setBookStatus(bookName, "loading", "调用AI中..."); panel.addBookAIMessage(bookName, "正在调用历史事件回忆AI..."); @@ -6467,20 +6530,21 @@ const finalSystemPrompt = getJailbreakPrefix() + "\n\n" + baseSystemPrompt; const finalUserMessage = buildUserPrompt(userMessage); - // 添加到进度追踪 - const taskId = `search_${bookName}`; + // 添加到进度追踪,并注册 AbortController if (progressTracker) { progressTracker.addTask(taskId, `搜索:${bookName}`, "search"); + progressTracker.setTaskAbortController(taskId, abortController); } try { - // 调用AI + // 调用AI(传递 signal 以支持终止) const response = await APIAdapter.callWithRetry( { ...aiConfig, category: bookName, source: bookName, taskId: taskId }, finalSystemPrompt, finalUserMessage, taskId, - 3 + 3, + abortController.signal ); // 完成进度 @@ -6506,12 +6570,19 @@ } } catch (error) { // 失败时也标记进度完成 + const isAborted = error.name === "AbortError"; if (progressTracker) { - progressTracker.completeTask(taskId, false, error.message); + progressTracker.completeTask(taskId, false, isAborted ? "已终止" : error.message); + } + if (isAborted) { + Logger.warn(`[交互式搜索] 总结世界书 "${bookName}" 已被终止`); + panel.setBookStatus(bookName, "error", "已终止"); + panel.addBookSystemMessage(bookName, "搜索已被用户终止"); + } else { + Logger.error(`[交互式搜索] 总结世界书 "${bookName}" AI调用失败:`, error.message); + panel.setBookStatus(bookName, "error", "失败"); + panel.addBookSystemMessage(bookName, `AI调用失败: ${error.message}`); } - Logger.error(`[交互式搜索] 总结世界书 "${bookName}" AI调用失败:`, error.message); - panel.setBookStatus(bookName, "error", "失败"); - panel.addBookSystemMessage(bookName, `AI调用失败: ${error.message}`); } } catch (error) { Logger.error(`[交互式搜索] 总结世界书 "${bookName}" 初始化失败:`, error.message); diff --git a/style.css b/style.css index 8c27c0c..f015a10 100644 --- a/style.css +++ b/style.css @@ -3124,11 +3124,13 @@ ============================================================================ */ @media (max-width: 768px) { - .mm-message-progress-panel { + /* 进度面板移动端基础定位(参考剧情优化面板,固定在左上角) */ + .mm-message-progress-panel:not(.mm-dragging):not(.mm-user-positioned) { width: calc(100vw - 32px); max-width: 320px; left: 16px; top: 60px; + right: auto; transform: none; } @@ -3159,10 +3161,13 @@ } @media (max-width: 480px) { - .mm-message-progress-panel { + /* 进度面板手机端基础定位(参考剧情优化面板,固定在左上角) */ + .mm-message-progress-panel:not(.mm-dragging):not(.mm-user-positioned) { width: calc(100vw - 24px); - left: 12px; - top: 50px; + left: 8px; + top: 60px; + right: auto; + transform: none; } .mm-msg-panel-header { @@ -6445,13 +6450,22 @@ transform: none; } - /* 进度面板 - 移动端安全定位 */ - .mm-message-progress-panel { - top: 10px !important; - left: 50% !important; - transform: translateX(-50%) !important; + /* 进度面板 - 移动端安全定位(参考剧情优化面板,固定在左上角) */ + .mm-message-progress-panel:not(.mm-dragging):not(.mm-user-positioned) { + top: 60px !important; + left: 16px !important; + right: auto !important; + transform: none !important; max-height: 60vh !important; } + + /* 用户手动拖动后,允许自定义位置 */ + .mm-message-progress-panel.mm-user-positioned { + top: unset !important; + left: unset !important; + right: unset !important; + transform: none !important; + } } /* 手机适配 (480px) */ @@ -6558,16 +6572,25 @@ transform: none; } - /* 进度面板 - 手机端安全定位 */ - .mm-message-progress-panel { - top: 8px !important; - left: 50% !important; - transform: translateX(-50%) !important; + /* 进度面板 - 手机端安全定位(参考剧情优化面板,固定在左上角) */ + .mm-message-progress-panel:not(.mm-dragging):not(.mm-user-positioned) { + top: 60px !important; + left: 8px !important; + right: auto !important; + transform: none !important; max-height: 55vh !important; width: calc(100vw - 24px) !important; max-width: 300px !important; } + /* 用户手动拖动后,允许自定义位置 */ + .mm-message-progress-panel.mm-user-positioned { + top: unset !important; + left: unset !important; + right: unset !important; + transform: none !important; + } + /* 汇总检查弹窗(动态创建) */ .mm-modal.mm-modal-visible .mm-modal-content { width: calc(100vw - 16px) !important;