/** * 汇总检查弹窗模块 * @module ui/modals/summary-check */ import { getGlobalSettings, isMultiAIAvailable } from '@config/config-manager'; import { enableModalDrag } from './index'; /** * 显示汇总检查弹窗 * @param {string} summaryContent - 记忆摘要内容 * @param {string} editorContent - 剧情优化内容(可选) * @returns {Promise<{action: 'confirm'|'regenerate'|'multi-regenerate'|'cancel', editedSummary?: string, editedEditor?: string}>} 用户操作结果 */ export function showSummaryCheckModal(summaryContent, editorContent = "") { return new Promise((resolve) => { // 创建弹窗容器 - 无遮罩模式,允许与主界面交互 const modal = document.createElement("div"); modal.className = "mm-modal mm-modal-visible"; modal.style.zIndex = "999999"; modal.style.position = "fixed"; modal.style.top = "0"; modal.style.left = "0"; modal.style.right = "0"; modal.style.bottom = "0"; modal.style.background = "transparent"; modal.style.display = "flex"; modal.style.alignItems = "center"; modal.style.justifyContent = "center"; modal.style.pointerEvents = "none"; // 允许点击穿透到下层 // 应用当前主题 const settings = getGlobalSettings(); const theme = settings.theme || "default"; if (theme !== "default") { modal.setAttribute("data-mm-theme", theme); } // 创建弹窗内容 const content = document.createElement("div"); content.className = "mm-modal-content mm-modal-large"; content.style.width = "100%"; content.style.maxWidth = "800px"; content.style.maxHeight = "80vh"; content.style.overflow = "hidden"; content.style.display = "flex"; content.style.flexDirection = "column"; content.style.background = "var(--mm-bg)"; content.style.borderRadius = "var(--mm-radius)"; content.style.boxShadow = "0 4px 20px rgba(0, 0, 0, 0.3)"; content.style.pointerEvents = "auto"; // 弹窗内容可交互 // 创建弹窗头部 const header = document.createElement("div"); header.className = "mm-modal-header"; header.style.display = "flex"; header.style.justifyContent = "space-between"; header.style.alignItems = "center"; header.style.padding = "15px 20px"; header.style.borderBottom = "1px solid var(--mm-border)"; header.style.flexShrink = "0"; const title = document.createElement("h4"); title.textContent = editorContent ? "汇总检查 - 记忆摘要 + 剧情优化" : "汇总检查 - AI 生成的记忆摘要"; title.style.margin = "0"; title.style.fontSize = "16px"; title.style.color = "var(--mm-text)"; const closeBtn = document.createElement("button"); closeBtn.className = "mm-modal-close mm-btn mm-btn-icon"; closeBtn.innerHTML = ``; header.appendChild(title); header.appendChild(closeBtn); content.appendChild(header); // 启用弹窗拖拽移动 enableModalDrag(modal, content, header); // 创建弹窗主体 const body = document.createElement("div"); body.className = "mm-modal-body"; body.style.flex = "1"; body.style.overflowY = "auto"; body.style.padding = "20px"; body.style.display = "flex"; body.style.flexDirection = "column"; // 提示信息 const hint = document.createElement("div"); hint.style.marginBottom = "15px"; hint.style.padding = "10px 15px"; hint.style.background = "var(--mm-bg-secondary)"; hint.style.borderRadius = "var(--mm-radius)"; hint.style.fontSize = "13px"; hint.style.color = "var(--mm-text-muted)"; hint.innerHTML = ` 以下是将注入到对话中的内容。您可以直接编辑内容,然后选择确认发送或重新生成。`; body.appendChild(hint); // 记忆摘要内容区域 const summaryContainer = document.createElement("div"); summaryContainer.style.background = "var(--mm-bg-card)"; summaryContainer.style.borderRadius = "var(--mm-radius)"; summaryContainer.style.padding = "15px"; summaryContainer.style.border = "1px solid var(--mm-border)"; summaryContainer.style.marginBottom = editorContent ? "15px" : "0"; const summaryLabel = document.createElement("div"); summaryLabel.style.fontWeight = "bold"; summaryLabel.style.marginBottom = "10px"; summaryLabel.style.color = "var(--mm-primary)"; summaryLabel.innerHTML = `记忆摘要内容`; summaryContainer.appendChild(summaryLabel); // 创建可调整高度的容器 const resizableContainer = document.createElement("div"); resizableContainer.style.position = "relative"; resizableContainer.style.minHeight = "150px"; // 使用 textarea 替代 div,支持编辑 const summaryText = document.createElement("textarea"); summaryText.style.width = "100%"; summaryText.style.boxSizing = "border-box"; summaryText.style.whiteSpace = "pre-wrap"; summaryText.style.wordBreak = "break-word"; summaryText.style.fontSize = "14px"; summaryText.style.lineHeight = "1.6"; summaryText.style.color = "var(--mm-text)"; summaryText.style.height = editorContent ? "200px" : "300px"; summaryText.style.minHeight = "100px"; summaryText.style.overflowY = "auto"; summaryText.style.padding = "10px"; summaryText.style.background = "var(--mm-bg-secondary)"; summaryText.style.borderRadius = "4px 4px 0 0"; summaryText.style.resize = "none"; summaryText.style.border = "1px solid var(--mm-border)"; summaryText.style.fontFamily = "inherit"; summaryText.value = summaryContent || "(无内容)"; resizableContainer.appendChild(summaryText); // 创建拖动手柄(使用统一的 CSS 类) const resizeHandle = document.createElement("div"); resizeHandle.className = "mm-resize-handle"; resizableContainer.appendChild(resizeHandle); // 拖动调整高度逻辑 let isResizing = false; let startY = 0; let startHeight = 0; const maxScreenHeight = window.innerHeight * 0.8; // 最大高度为屏幕的80% const onResizeMouseDown = (e) => { isResizing = true; startY = e.clientY || e.touches?.[0]?.clientY || 0; startHeight = summaryText.offsetHeight; document.body.style.cursor = "ns-resize"; document.body.style.userSelect = "none"; e.preventDefault(); }; const onResizeMouseMove = (e) => { if (!isResizing) return; const clientY = e.clientY || e.touches?.[0]?.clientY || 0; const deltaY = clientY - startY; const newHeight = Math.max(100, Math.min(maxScreenHeight, startHeight + deltaY)); summaryText.style.height = newHeight + "px"; }; const onResizeMouseUp = () => { if (isResizing) { isResizing = false; document.body.style.cursor = ""; document.body.style.userSelect = ""; } }; resizeHandle.addEventListener("mousedown", onResizeMouseDown); document.addEventListener("mousemove", onResizeMouseMove); document.addEventListener("mouseup", onResizeMouseUp); resizeHandle.addEventListener("touchstart", onResizeMouseDown, { passive: false }); document.addEventListener("touchmove", onResizeMouseMove, { passive: false }); document.addEventListener("touchend", onResizeMouseUp); summaryContainer.appendChild(resizableContainer); body.appendChild(summaryContainer); // 剧情优化内容的 textarea 引用(在条件块外声明以便后续访问) let editorTextarea = null; // 如果有剧情优化内容,添加 Editor 区域 if (editorContent) { const editorContainer = document.createElement("div"); editorContainer.style.background = "var(--mm-bg-card)"; editorContainer.style.borderRadius = "var(--mm-radius)"; editorContainer.style.padding = "15px"; editorContainer.style.border = "1px solid var(--mm-border)"; editorContainer.style.borderLeftColor = "#9d7cd8"; // 紫色边框标识 editorContainer.style.borderLeftWidth = "3px"; const editorLabel = document.createElement("div"); editorLabel.style.fontWeight = "bold"; editorLabel.style.marginBottom = "10px"; editorLabel.style.color = "#9d7cd8"; editorLabel.innerHTML = `剧情优化内容 (Editor)`; editorContainer.appendChild(editorLabel); // 创建可调整高度的容器 const editorResizableContainer = document.createElement("div"); editorResizableContainer.style.position = "relative"; editorResizableContainer.style.minHeight = "100px"; // 使用 textarea 替代 div,支持编辑 editorTextarea = document.createElement("textarea"); editorTextarea.style.width = "100%"; editorTextarea.style.boxSizing = "border-box"; editorTextarea.style.whiteSpace = "pre-wrap"; editorTextarea.style.wordBreak = "break-word"; editorTextarea.style.fontSize = "14px"; editorTextarea.style.lineHeight = "1.6"; editorTextarea.style.color = "var(--mm-text)"; editorTextarea.style.height = "150px"; editorTextarea.style.minHeight = "80px"; editorTextarea.style.maxHeight = "none"; editorTextarea.style.overflowY = "auto"; editorTextarea.style.padding = "10px"; editorTextarea.style.background = "var(--mm-bg-secondary)"; editorTextarea.style.borderRadius = "4px 4px 0 0"; editorTextarea.style.resize = "none"; editorTextarea.style.border = "1px solid var(--mm-border)"; editorTextarea.style.fontFamily = "inherit"; editorTextarea.value = editorContent; editorResizableContainer.appendChild(editorTextarea); // 创建拖动手柄 const editorResizeHandle = document.createElement("div"); editorResizeHandle.className = "mm-resize-handle"; editorResizableContainer.appendChild(editorResizeHandle); // 拖动调整高度逻辑 let isEditorResizing = false; let editorStartY = 0; let editorStartHeight = 0; editorResizeHandle.addEventListener("mousedown", (e) => { isEditorResizing = true; editorStartY = e.clientY; editorStartHeight = editorTextarea.offsetHeight; document.body.style.cursor = "ns-resize"; document.body.style.userSelect = "none"; e.preventDefault(); }); document.addEventListener("mousemove", (e) => { if (!isEditorResizing) return; const deltaY = e.clientY - editorStartY; const newHeight = Math.max(80, editorStartHeight + deltaY); editorTextarea.style.height = newHeight + "px"; }); document.addEventListener("mouseup", () => { if (isEditorResizing) { isEditorResizing = false; document.body.style.cursor = ""; document.body.style.userSelect = ""; } }); editorContainer.appendChild(editorResizableContainer); body.appendChild(editorContainer); } content.appendChild(body); // 创建弹窗底部按钮 const footer = document.createElement("div"); footer.className = "mm-modal-footer"; footer.style.display = "flex"; footer.style.justifyContent = "flex-end"; footer.style.gap = "10px"; footer.style.padding = "15px 20px"; footer.style.borderTop = "1px solid var(--mm-border)"; footer.style.flexShrink = "0"; const cancelBtn = document.createElement("button"); cancelBtn.className = "mm-btn mm-btn-secondary"; cancelBtn.innerHTML = `取消发送`; const regenerateBtn = document.createElement("button"); regenerateBtn.className = "mm-btn mm-btn-secondary"; regenerateBtn.innerHTML = `重新生成`; // 多AI生成按钮 - 仅在功能可用时显示 let multiAIBtn = null; if (isMultiAIAvailable()) { multiAIBtn = document.createElement("button"); multiAIBtn.className = "mm-btn mm-btn-secondary"; multiAIBtn.style.background = "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"; multiAIBtn.style.color = "#fff"; multiAIBtn.style.border = "none"; multiAIBtn.innerHTML = `多AI生成`; multiAIBtn.title = "使用多个AI并发生成回复,然后选择其中一个"; } const confirmBtn = document.createElement("button"); confirmBtn.className = "mm-btn mm-btn-primary"; confirmBtn.innerHTML = `确认发送`; footer.appendChild(cancelBtn); footer.appendChild(regenerateBtn); if (multiAIBtn) { footer.appendChild(multiAIBtn); } footer.appendChild(confirmBtn); content.appendChild(footer); modal.appendChild(content); document.body.appendChild(modal); const cleanup = () => { document.body.removeChild(modal); }; // 确认发送 - 返回编辑后的内容 confirmBtn.addEventListener("click", () => { const editedSummary = summaryText.value; const editedEditor = editorTextarea ? editorTextarea.value : ""; cleanup(); resolve({ action: "confirm", editedSummary, editedEditor }); }); // 重新生成 regenerateBtn.addEventListener("click", () => { cleanup(); resolve({ action: "regenerate" }); }); // 多AI生成 if (multiAIBtn) { multiAIBtn.addEventListener("click", () => { cleanup(); resolve({ action: "multi-regenerate" }); }); } // 取消发送 cancelBtn.addEventListener("click", () => { cleanup(); resolve({ action: "cancel" }); }); // 关闭按钮 closeBtn.addEventListener("click", () => { cleanup(); resolve({ action: "cancel" }); }); }); }