// ==UserScript== // @name 【工单页】AI回复一键折叠 // @namespace https://greasyfork.org/users/ // @version 4.0 // @description 右下角可拖动面板 | 点击标题栏折叠 | 关闭后隐藏为边缘悬浮球 | MutationObserver 实时监听 | 完美适配 UniApp 动态渲染 // @match https://chath5.kaoshids.com/* // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @run-at document-end // ==/UserScript== (function () { 'use strict'; // ==================== 样式 ==================== GM_addStyle(` #ai-collapse-panel { position: fixed; z-index: 99999; background: #fff; border-radius: 14px; box-shadow: 0 8px 30px rgba(0,0,0,0.18); width: 230px; color: #333; border: 1px solid #e5e5e5; overflow: hidden; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; transition: box-shadow 0.2s ease; } #ai-collapse-panel:hover { box-shadow: 0 12px 40px rgba(0,0,0,0.22); } .ai-panel-header { background: linear-gradient(135deg, #4f8eff, #3a7be8); color: white; padding: 10px 14px; display: flex; align-items: center; justify-content: space-between; cursor: move; user-select: none; font-weight: 600; font-size: 14px; } .ai-panel-header .title { display: flex; align-items: center; gap: 8px; } .ai-panel-header .controls { display: flex; gap: 6px; } .ai-panel-header button { background: rgba(255,255,255,0.2); border: none; color: white; width: 22px; height: 22px; border-radius: 50%; cursor: pointer; font-size: 14px; line-height: 1; display: flex; align-items: center; justify-content: center; transition: background 0.2s; } .ai-panel-header button:hover { background: rgba(255,255,255,0.35); } .ai-panel-body { padding: 12px 14px; font-size: 14px; } .ai-panel-body button { margin: 5px 0; padding: 9px 12px; border: none; border-radius: 8px; background: #4f8eff; color: white; cursor: pointer; width: 100%; font-size: 13.5px; font-weight: 500; transition: all 0.2s; } .ai-panel-body button:hover { background: #3a7be8; transform: translateY(-1px); } .ai-panel-body label { font-size: 12.5px; display: flex; align-items: center; gap: 8px; margin-top: 10px; color: #555; } .ai-panel-collapsed .ai-panel-body { display: none; } #ai-fab { position: fixed; right: 12px; top: 50%; transform: translateY(-50%); z-index: 99998; width: 42px; height: 42px; background: linear-gradient(135deg, #4f8eff, #3a7be8); border-radius: 50%; box-shadow: 0 4px 15px rgba(79,142,255,0.4); display: flex; align-items: center; justify-content: center; color: white; font-size: 18px; font-weight: bold; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); border: none; outline: none; } #ai-fab:hover { transform: translateY(-50%) scale(1.1); box-shadow: 0 6px 20px rgba(79,142,255,0.5); } .ai-collapsed { display: none !important; } `); // ==================== 全局变量 ==================== let panel = null; let fab = null; let mutationObserver = null; let isAutoCollapseEnabled = GM_getValue('defaultCollapse', true); let isPanelCollapsed = GM_getValue('panelCollapsed', false); let isPanelHidden = GM_getValue('panelHidden', false); let panelLeft = GM_getValue('panelLeft', null); let panelTop = GM_getValue('panelTop', null); // ==================== 折叠核心函数 ==================== function collapseAIBoxes(boxes, collapsed) { let count = 0; boxes.forEach(box => { const chatItem = box.closest('.chat-item'); if (chatItem && !chatItem.classList.contains('justify-end')) { if (collapsed) { box.classList.add('ai-collapsed'); } else { box.classList.remove('ai-collapsed'); } count++; } }); if (count > 0) console.log(`[AI折叠] ${collapsed ? '折叠' : '展开'}了 ${count} 个AI回复`); return count; } function toggleAllAI(collapsed) { const aiBoxes = document.querySelectorAll('.ai-box'); collapseAIBoxes(aiBoxes, collapsed); } function handleNewNodes(addedNodes) { if (!isAutoCollapseEnabled) return; let newAIBoxes = []; addedNodes.forEach(node => { if (node.nodeType === 1) { if (node.classList && node.classList.contains('ai-box')) newAIBoxes.push(node); const childBoxes = node.querySelectorAll ? node.querySelectorAll('.ai-box') : []; childBoxes.forEach(box => newAIBoxes.push(box)); } }); if (newAIBoxes.length > 0) collapseAIBoxes(newAIBoxes, true); } function setupMutationObserver() { if (mutationObserver) mutationObserver.disconnect(); mutationObserver = new MutationObserver((mutations) => { let hasNewNodes = false; const addedNodes = []; mutations.forEach(m => { if (m.addedNodes.length > 0) { hasNewNodes = true; m.addedNodes.forEach(n => addedNodes.push(n)); } }); if (hasNewNodes) setTimeout(() => handleNewNodes(addedNodes), 50); }); mutationObserver.observe(document.body, { childList: true, subtree: true }); console.log('[AI折叠] MutationObserver 已启动'); } // ==================== 拖动逻辑 ==================== function makeDraggable(element, handle) { let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; handle.onmousedown = dragMouseDown; function dragMouseDown(e) { e.preventDefault(); pos3 = e.clientX; pos4 = e.clientY; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; } function elementDrag(e) { e.preventDefault(); pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; let newLeft = element.offsetLeft - pos1; let newTop = element.offsetTop - pos2; const maxLeft = window.innerWidth - element.offsetWidth - 10; const maxTop = window.innerHeight - element.offsetHeight - 10; newLeft = Math.max(10, Math.min(newLeft, maxLeft)); newTop = Math.max(10, Math.min(newTop, maxTop)); element.style.left = newLeft + "px"; element.style.top = newTop + "px"; } function closeDragElement() { document.onmouseup = null; document.onmousemove = null; GM_setValue('panelLeft', parseInt(element.style.left)); GM_setValue('panelTop', parseInt(element.style.top)); } } // ==================== 面板创建 ==================== function createPanel() { if (document.getElementById('ai-collapse-panel')) return; panel = document.createElement('div'); panel.id = 'ai-collapse-panel'; if (panelLeft !== null && panelTop !== null) { panel.style.left = panelLeft + 'px'; panel.style.top = panelTop + 'px'; } else { panel.style.left = (window.innerWidth - 250) + 'px'; panel.style.top = (window.innerHeight - 200) + 'px'; } panel.innerHTML = `
🤖 AI回复控制
`; document.body.appendChild(panel); const header = panel.querySelector('.ai-panel-header'); makeDraggable(panel, header); // 最小化 const btnMin = panel.querySelector('#btn-minimize'); btnMin.onclick = () => { isPanelCollapsed = !isPanelCollapsed; panel.classList.toggle('ai-panel-collapsed', isPanelCollapsed); btnMin.textContent = isPanelCollapsed ? '+' : '−'; GM_setValue('panelCollapsed', isPanelCollapsed); }; if (isPanelCollapsed) { panel.classList.add('ai-panel-collapsed'); btnMin.textContent = '+'; } // 关闭 → 悬浮球 panel.querySelector('#btn-close').onclick = hidePanelToFab; // 功能按钮 panel.querySelector('#btn-collapse').onclick = () => toggleAllAI(true); panel.querySelector('#btn-expand').onclick = () => toggleAllAI(false); const chk = panel.querySelector('#default-collapse'); chk.onchange = () => { isAutoCollapseEnabled = chk.checked; GM_setValue('defaultCollapse', isAutoCollapseEnabled); if (isAutoCollapseEnabled) toggleAllAI(true); }; if (isPanelHidden) { panel.style.display = 'none'; createFab(); } } // ==================== 边缘悬浮球 ==================== function createFab() { if (document.getElementById('ai-fab')) return; fab = document.createElement('button'); fab.id = 'ai-fab'; fab.innerHTML = '🤖'; fab.title = '点击展开 AI 控制面板'; document.body.appendChild(fab); fab.onclick = () => { if (panel) { panel.style.display = 'block'; isPanelHidden = false; GM_setValue('panelHidden', false); } fab.remove(); fab = null; }; } function hidePanelToFab() { if (!panel) return; panel.style.display = 'none'; isPanelHidden = true; GM_setValue('panelHidden', true); createFab(); } // ==================== 初始化 ==================== function init() { createPanel(); setupMutationObserver(); if (isAutoCollapseEnabled && !isPanelHidden) { setTimeout(() => { const aiBoxes = document.querySelectorAll('.ai-box'); collapseAIBoxes(aiBoxes, true); }, 800); } document.addEventListener('visibilitychange', () => { if (!document.hidden && isAutoCollapseEnabled && panel && panel.style.display !== 'none') { setTimeout(() => { const aiBoxes = document.querySelectorAll('.ai-box'); collapseAIBoxes(aiBoxes, true); }, 400); } }); console.log('[AI折叠] v4.0 UI优化版已启动(可拖动 + 可折叠 + 边缘隐藏)'); } if (document.readyState === 'loading') { window.addEventListener('load', init); } else { init(); } })();