// ==UserScript== // @name 通义千问提问自动折叠 // @namespace http://tampermonkey.net/ // @version 2.1 // @description 适配通义千问新版DOM结构,自动折叠长文本提问。极简统一风格日志,仅记录关键操作。 // @author anyphasy // @match https://www.qianwen.com/chat/* // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAG4AAABuCAYAAADGWyb7AAASjklEQVR4nO1de3Bc1Xn/nXPv3t2VVrIlWc9daS3Jlq3V28JgAuUZXiGEFgwzNMmENGlKA5OZthMync5k+k/btEP/oDShTRMgBGIClJdJbQNxwUN4GGTJli1jy7IlrZ5gg21Zq927957TP+5dSV7vSvu4L9n9zdxZrfbec75zv/Od833f+c53gP/HigSxm4Bl4K1av/2HlPhKOJfnFv9AQAUQQrVvVACoQIgogYgSIYKLCqtrYsrge9OffOXHdhBuNpzMOFLXOrBddDffnmsBnM1+eqLXFwQQNZAuR4DaTcASKBGlxms5V6LZXOCqDK7KnMcjhBZWVK97/Ud2N8QMiHYTkAaFwfbxt0AkHwFTAJJ1ByMgFOBMKui6E8BPAMSMJ9M+OFLiajbs+y/BVdMFrsq5ME2DxjjBVdNVGzr0AgC3oUTaDCcyrtTtC90OMGVB+cgVhIKrsssbuqMq9Pt/MIY8Z8BpjKP+ziPbCNzF2td8GZcAZ5LQeCUuIqlzGuPKPbTxOoAzw0okVARniigFv1S58Xd/a1i5NsNJjKPB1qO/5kSQNMYZJW0L8LjabsVFInVOYlyZKDVca6i0JUCoCK7KglR7RVXjK39tePk2wCmM8wU7xndxQkWzpE0DZy5P83UABHPKtw5OYBz1Nx99SRBrusBzs9kygt4pXJ6mm/3Ne38JZ7Q9ZzjB5VVe3y0PEwiS9tUsadPBmQIiSLORt/5l+vBNfwdATbpjuXdClvhMvpJ/jwGI50p6NkSaDeLvOPSqWwzdAa7KmlRYAc4AKqrKpwNMPTsJEKo5rUU3IYKkOa0JPd+OJFS/CAGhGq2EgggS0ZzcIoggAYSSxG/znVAb/ll8+uDwgaqrAZzJtwV2M251Q9fcCVB3sblzWypozDO3/AvrU+WJ3pF+/3UAzuZTup3jPKkN9fwU1LPa1LktffUUYErCKT1/gSnGXJwtME/rlJwrUUGq6fJvPPQM8hQaO53Mq0R3860AZ/m7tnJF8nBoYj0ASEJB8la3AlgN4ItcS7RL4lYHOybfIdRbav0QaScIBWcKpSX1Ne19/4k8pM6OFyYEWkZ3CmJVe37e/xUKoi830brLAKzKtRg7Xlqp5PV3G+P9X4nQGEeFkvq6loNPIUeps/rFkbqW3sfAqQh+KQ2RqcAZddVdjhylzuoXVyq6W++0VyFxAhJSV1QdbB3ZAU1RyQpWvryS+o7J3TDN+z9vIC9xOQmaOSK467b4OwdfRJa8sKoxYm3r1B4iVrXbY7Ml4EQGMkWi1W0AyrN5yqpGuER3aYNzhkgn0AAs2HeFFYGuod8iC35Y1wDHKSNOogUQUboWDmQcJcRVoLmCzMJiF9NKA2fxyIHXcOFKRVpYxThZoWfHzXXqJpBg4HJMdAKTdUc3m/t8/Mi1DwPgmT5pFePiox+tbonHBt9MqMLWVLuYicmXU8DZnLz/ZWQZsGv1sk5x/ab4NDExIGjlQOs8TD09MtxX1oIsGWf1i5tl8al+zdnqpF5vA7g2TMZmP3kLOYTHLydxLmjhbBQLTF7umcQ4PYvUy/T+xm4+xh01XFkNbbSJRfY+NX54y18AyFppW4oJxfWdXxwgwupgLqSpykTvyH7/VQDmkn4Sarun+lyoCF2aw6UmaVydmTzRV1yPHDejpH1pgeb3/5UIq4OcK9H5Vd3k1eJUF5jCeTwiiDVd1S3vPZqiaDXcU/U1bUXYTPPAyeBMnut9EYCcawnp1PMCl7vldoCzhcAXIFOvBwEVAaZIYtN1ADy4cGPhmEJnJkVWVG1tkJDd0KSNKacGx49c+yNkof4nIxUj3IGWQ88Roag656GMaMs2gli23t+055EUd8RHPypuUqKDb4IIEi4VydMVsqgy8AYunEKyQvIcR6qb9j7pLdr8rfwlQQ9JU0+PDPeVtqQhtLB+U3SCQPTkXo+5yFWJImk6PId87sS+gloAkXzoSmZMkcfXdqdhe9P0ld7atqEd4f7G23Ah8yJqbPg90bPh1vzqMg9GG7pzZz58GnkyDTifLlLd8u7PvJ6rHjBy3uFclQkRPVG5d9tE/6Y/TXGLr65l38+pWLkRPD7HuRJLBJ4CWmQU55wBqm5acKYNOZxzcEZAaOJzoSV6gCqoQOY74EKZGpjK521JpmpKlRoHV2KAGudckTlXYtA+Zf0elXNVAZh6nh1KCAWooAXVutyEiBIhLg+h7kIQt4+AUEILSmLq6L7JQ1c9hBzU/2QsZlxhfefZQW1uM3LNLOEhODc93LdqAzT7bilakidskuJ/uSBZeIwoM9v6Datz3qgObHz3ESLoWp6htpXmJaFCsb8q9PY/LnEjR+qGGdVYnnRZDUPrTDDILXrazYsF0UPSPFLoZgCS4eVfgqAAXIFQ39M0H/V/WeiBoEL5xqqGl/7K+PIvPZBAy+gHkqf2CvOXOrROocanDowcqLkcBm03cgBELGxPpki/DWvx34lhUwUwk0ulpGET54BV3gvNcyDP7X9hbKDz61j5zPPVXXZyn4uVrc/lYZUBw32kEDmYB1RmQ/9rXQCPtmNF8nbcU9H08t9YU6dpIDUb+p4Qedl6DlXmhDNOmJL2gionX1TgDMCaXCqnY33rblHVU8esWhnWfJ9M8XouvxcrOwNCmaeo/e7znRVLxHQSKp536fevbT/xLHKw8ymAuDw79C5ARWu89Zp5ILhquqpCu//J/PpMAfV3Hv0NeGJBOBd/rv4MLWsEUJQ1AQAwOXjlQ0p08E1CRI8l8Ri6eeB2tdyClSl1NR5h/U35uQa1SGYqFFUH28bfBlCSzdOJSmOjh5ruYOz0iDXBPHqCNLEiVNt84DdYWcyjwbbjz3LAgFhRPQxdqumq7Z58G1mk8VhcqSwrx/+AeYLMhp4graDtrur17/+7+fUZhnJBqr9GkzajNHGmiHxVAIAv0ycWM45P9Hc/uOA9sWrIZIrbF7oNQKHp9eWPorr2sd8Z+260eZIQb2l1695UEQMpkSzmZ2U2+gGQ2L9mNnQ/Ji32V7d+8G/m15cXaCA0vFN0+bsN37iiz5NuofFqZLhfLrlyNtZb/2U5OrB9YTuUyUgQLTZdD6DA9PpyR7lUULfF2CEyAV1REUsb61oG/xsZhE2muiE2dqjlXqbOTFqmqHBVpkJJvX/DOz8xt66cQYNtx7YtqP9mgTNBqulABnNdOs7G1NiJP1gWuKpLnegJ3QItuMhpWMjsZ5qXSRMSQgvW1LUd345lmJeOCB4+3PE9zpUo5jPamQldLRbXNNU29z0NLRDXKSgMto/v0rzCZseBau9BlOqvCXSd2IElhsyliDgtq0d2WRewmjAPOu6p2PCaU1LOU3/z4KtaYm8rd9IyxYXKEICytIQt8TQf3996P+fR0/pXi0LGmeJxd30NzpC6SnfhuhutTe2h71Kl3tLAptHtSMOj5YiZifPpAcvMAz0eU3QFNpevf/4h0+tbGkKga+QlLdDBjlB5ziSUNSJNRobliFHHetferMrjPdbMdQvweq68D/bmGiuXaN0WTSGxOtJa1+ZJwZpgW3gnUrjCMulFsyP9gdsXepzJzNPzJ4tSYHNl/XMPmlrXElTUtfQ/DgD2RllzRl0VzUghdZmK/0kWP7HHmq3ACXDmLrr6m7Anf3KpyxP6qu2Z/cAZIa6CuvbwDiR5VDIlSh0+0PAn2s4dwBKpA2eiy99ds/G9x2HtBkxvsG1sF593Pti5DUwLshJdgc2BruOvYdGCazZEnYnziT4r/ZicK1FP4ZV/vqbxyW+bX59Wac2Gnl8Ikgn+yJwp0m07fr6ikg1h6lhv8IZ47MhOq/yYRDdIvd6r74M1Q2aJx9ex1VmZ/TQ6qFDsD3Qem/djZkvcXPjgxrs4i5y0xI+pmwcu97oby9c//wNT6wJITVvvzwBBcl4yHQDgTER5E/SA4lyIm5Mj+1+2egO+17P5LphrHpR5XE7N7JfY+VTsrw0deh7Aqlx3EbnXdk7vo0JFyNgNImmQOCvg1LPfnx7+xuMm1ECDrUd3Cu71Nzl/hyyhqhI7m+sLl8FmTwKwKMwBADiTfFvugTlzXZngWXejPcZ2luCqLLjcxbkyrpCIlSEAGe8LzwuJ7OHuxutrNu55FMYyrzjYMfGGFhS+AlJ4ECpCPT2S00uvbPifhwkpWGNtMmxt9cBT+EcPGqioCIGW0TcEsbrTMep/WuhnF7DZz473lrTlQqjHW7zlG/ZN4kzxei7fCmOkrlLy1l7h/HkN+pTEWXRm92MAZrJ98STQ/P5jVCipt6WHJlYPpOCXKppe/mGepYm1m8Zft2WLY9bQhISxM+HJY3f+M5C9OVAgeTq32q8yc+bxbN6K/MyDSonUdK0MhUTb5RSd6XsZ+v7xbF6+uzZ0aBuoZ7WtPrxFfkz/hvcfR25Dpri2Y+J1XR9xdo4VrkWVxSIf/GLq2PXzO5wyffmkZkPPEy6vflyY7ZO45sd0+7Z8tyzw0605FOCnYnWnOaF2RkIbDTiPR8YPX/kDAPNab6YMKHb72v7YST68eT/mqqu3IrttSquCnZ+9YW6aYYOgu96U6OEdSEqrlQkTSHXr3kcJXAWO8uHpiorkad+6pvHJP8vwKRpoCb8pCGuaHNWWlNDnXi6fCw90fhdJWRsyIXy1V+q4236FJD283mu+iczaUiN5A5tXjvpPaFT5ZCdS7BNfrrG0ruXgkyCSz/5FxRTQwxxc7oZry4M///oyd4tr28MvWa7+c6ZwrsqcqzI4U867lsoZTQjliJ2dONDxHaTIkbJcrysW3euuXwmuILfvqnsAPIf0CQFKBFdgM7dSIdGd49l78jUhkSOjHyJNVoalGuBa2z70imOlLQF9T7nk3nBLVeO2B6aG7nssxV2eutahF3giD5hVQz4VJCU2/G5cHv6YUo+PEE8RoW4fiFRAiFRAiOgGET2EiG5AkLRPjbY4m9g/frjpbqTJSLRcZwg2dM312XP4bIbQe3V87uAr4YG2u7FIZdZB/BsHtrsLm2+3bm7TDOb4XM8z4YHL7kf6I6vTHUXNoRnaaQf25RgxFienhhzJsPPAWTx2eA8uZBoAVLp9VjONULC5z8MDl30PqU/vSOQTY/qlQmNUHFq63ziWyf21bEBseF/gq5xZHYaeIXRpU+Txnqmhe1MNkWJt98QOS4fHeW3w8E5cmNLYMGTSmM8UenbCuuiu7BGbPbgLqXNAVrlQ3WndMK9rgzx6eqK/+wGYmKUvk8ao4Z7Ka5g8dcDqMPQlwTUvjiIPvzt9/La/T3EHCbYe+eVCYlIraNKdwecObgdwzsyqMu2Fp4b7q2/QAmKtPBtnOVAxcubtp5B6HqkQ3U03W+f91+qJRw68OHl0c0rby0hkM3ycVmPhjxyhqOhzW2zm94+cHP32EynuKA52Tu/mlvkj9aGYK9Hw4Y77YUFyuawCYkcPNd6lKSo2Sl1CIYmd2DN+9Mupju6itS1juwWhImSZP1KvR57b9xwMSJSdCbJt1FmFzkzZL3WcRWd2/QdSD0dVLq+/21L1n1CRs7nPxw5veSgNTYYjWwYo4Z6KmwA156NF8oK+qChHB7Z/OvKX21LcQfydR560VPtNqP+z/a8iz0MgskEukjMRx8mjWrY9VV7SUWrwxaEt4kZnPnw1DW1+j9B0MwBYJ22EMvbFicmjV3zf/PoWkEvjWLin6rr6jrP9RCyqNpyiJUCI5ItFPv71ydHv/CrFz4WNmyL7FxQSi+Y2IkixcwO7YKKxnQr5HGRRHmg+9ltvYVkDmbfvFu9aTU6+CYDoBzZwzkEIAefnzweECgtKD6HgTFfztSWQM59/+Mz00C0/Rmpju7hxE/uCW3YGZcIf2bstPLDpW7A4TXG+zSRYSCCd6qCHXMpLN7lzLH9q79qGTcoR04dJfa5lymefDO+v7IQNuaXzbWAmL9NKhBUhckpkRp9WkgqEynMfvwCbEoJbfbitFQg1dLN+8/yT+pEz7Ex4uLc0BIvntgTs94IYj0FViJ7WnOImeE4WglNfgU1MAy5OxsVH9hZ0MHYmbHzCVF2LjHz0q6ljNzxsXLnZ42IcKhMINnSz48YVx/WDDGcmh/tW1cPmwy4uRolLYApM1pdWDJA63UMSn9tnm0KyGBezxAFAa+NlvJ/nvbNIm9eYcvLo8P7yNuRxmrBRuJglDgAGFSEeyXs1Q/d9ymz0YziAacDFL3EA0NnQzXoSRnP2j+vqP4+cGt5X1Ij0J05aiotd4gBgiLkI1ZLqZINFrjpQUZ4d3A2HMA24NCQOADY2dM69T0R3ceZzHWcJKY1Hj78zenDdV2Cj3ZaMS4VxgJak24Xz/aGJAFQs+t/iT67/HkHqmE3b8H/H3X4QCWWsBwAAAABJRU5ErkJggg== // @grant none // ==/UserScript== (function() { 'use strict'; // ==================== 极简日志工具 ==================== const Logger = { // 统一样式:紫色背景,白色文字,简洁前缀 style: 'background: #9d80b7; color: #fff; padding: 2px 6px; border-radius: 3px; font-size: 11px; margin-right: 5px;', log: (msg) => { console.log(`%c[QW]`, Logger.style, msg); } }; // ==================== 1. 常量定义 ==================== const CONFIG = { STORAGE_KEY: 'qianwen_auto_collapse_v2_enabled', SWITCH_BTN_ID: 'qianwen-collapse-switch-v2', // 匹配所有拥有 data-chat-list-key 的容器,不再限制后缀 CONTAINER_ATTR: 'div[data-chat-list-key]', BOTTOM_ICON_CONTAINER_CLASS: '.qs-bottom', COLLAPSE_SVG_CLASS: '.qs-bottom-icon-svg', ROTATED_CLASS: 'qs-bottom-icon-svg-rotate', SCROLL_DEBOUNCE_MS: 150, POLL_INTERVAL_MS: 1000, BTN_POSITION: { top: 13, right: 85, zIndex: 9999 } }; // ==================== 2. 状态管理 ==================== const state = { autoCollapseEnabled: false, observer: null, scrollTimer: null, pollTimer: null, switchBtn: null }; // ==================== 3. 本地存储 ==================== const Storage = { get: () => { try { const saved = localStorage.getItem(CONFIG.STORAGE_KEY); return saved === null ? true : JSON.parse(saved); } catch (e) { return true; } }, set: (enabled) => { localStorage.setItem(CONFIG.STORAGE_KEY, JSON.stringify(enabled)); } }; // ==================== 4. 核心折叠逻辑 ==================== function collapseUnfoldedText(triggerSource = 'Unknown') { if (!state.autoCollapseEnabled) return; const containers = document.querySelectorAll(CONFIG.CONTAINER_ATTR); if (!containers.length) return; let foldedCount = 0; containers.forEach((container) => { // 查找折叠按钮 SVG const collapseSvg = container.querySelector(`${CONFIG.BOTTOM_ICON_CONTAINER_CLASS} ${CONFIG.COLLAPSE_SVG_CLASS}`); // 如果没有找到 SVG(可能是回答项或其他),跳过 if (!collapseSvg) return; // 如果已折叠(有旋转类),跳过 if (collapseSvg.classList.contains(CONFIG.ROTATED_CLASS)) return; // 执行折叠 const btnParent = collapseSvg.closest('.qs-bottom-icon'); if (btnParent) { btnParent.click(); foldedCount++; } }); // 仅在有实际操作时输出日志 if (foldedCount > 0) { Logger.log(`[${triggerSource}] 折叠了 ${foldedCount} 个问题`); } } // ==================== 5. 开关按钮 ==================== const SwitchButton = { create: () => { if (state.switchBtn && document.body.contains(state.switchBtn)) return state.switchBtn; const btn = document.createElement('button'); btn.id = CONFIG.SWITCH_BTN_ID; const bgColor = state.autoCollapseEnabled ? '#1677ff' : '#f5f5f5'; const textColor = state.autoCollapseEnabled ? '#fff' : '#666'; const statusText = state.autoCollapseEnabled ? '自动折叠: 开' : '自动折叠: 关'; btn.style.cssText = ` position: fixed; top: ${CONFIG.BTN_POSITION.top}px; right: ${CONFIG.BTN_POSITION.right}px; z-index: ${CONFIG.BTN_POSITION.zIndex}; padding: 6px 10px; border: 1px solid rgba(0,0,0,0.1); border-radius: 4px; background: ${bgColor}; color: ${textColor}; font-size: 12px; cursor: pointer; box-shadow: 0 2px 4px rgba(0,0,0,0.1); transition: all 0.2s; user-select: none; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; `; btn.innerText = statusText; let isClicking = false; btn.addEventListener('click', () => { if (isClicking) return; isClicking = true; state.autoCollapseEnabled = !state.autoCollapseEnabled; const newBg = state.autoCollapseEnabled ? '#1677ff' : '#f5f5f5'; const newColor = state.autoCollapseEnabled ? '#fff' : '#666'; const newText = state.autoCollapseEnabled ? '自动折叠: 开' : '自动折叠: 关'; btn.style.background = newBg; btn.style.color = newColor; btn.innerText = newText; Storage.set(state.autoCollapseEnabled); if (state.autoCollapseEnabled) { Logger.log('功能已开启,正在整理页面...'); collapseUnfoldedText('Switch_On'); } else { Logger.log('功能已关闭'); } setTimeout(() => isClicking = false, 200); }); document.body.appendChild(btn); state.switchBtn = btn; return btn; } }; // ==================== 6. 监控管理 ==================== const Monitor = { init: () => { // 1. MutationObserver state.observer = new MutationObserver((mutations) => { if (!state.autoCollapseEnabled) return; let hasAddedNodes = false; for (const mutation of mutations) { if (mutation.addedNodes.length > 0) { hasAddedNodes = true; break; } } if (hasAddedNodes) { clearTimeout(state.scrollTimer); state.scrollTimer = setTimeout(() => collapseUnfoldedText('Observer'), 50); } }); const targetNode = document.querySelector('.chat-content') || document.querySelector('#chat-container') || document.body; state.observer.observe(targetNode, { childList: true, subtree: true }); // 2. 滚动监听 window.addEventListener('scroll', Monitor.handleScroll, { passive: true }); // 3. 定时巡检 state.pollTimer = setInterval(() => { if (state.autoCollapseEnabled) { collapseUnfoldedText('Poller'); } }, CONFIG.POLL_INTERVAL_MS); }, handleScroll: () => { if (!state.autoCollapseEnabled) return; clearTimeout(state.scrollTimer); state.scrollTimer = setTimeout(() => collapseUnfoldedText('Scroll'), CONFIG.SCROLL_DEBOUNCE_MS); }, destroy: () => { if (state.observer) { state.observer.disconnect(); state.observer = null; } clearTimeout(state.scrollTimer); clearInterval(state.pollTimer); window.removeEventListener('scroll', Monitor.handleScroll); } }; // ==================== 7. 初始化入口 ==================== function init() { state.autoCollapseEnabled = Storage.get(); SwitchButton.create(); Monitor.init(); if (state.autoCollapseEnabled) { setTimeout(() => { Logger.log('脚本已启动 (状态: 开启)'); collapseUnfoldedText('Init_Load'); }, 500); } else { Logger.log('脚本已启动 (状态: 关闭)'); } window.addEventListener('beforeunload', Monitor.destroy); } // ==================== 8. 启动脚本 ==================== if (document.readyState === 'complete') { init(); } else { window.addEventListener('load', init); } })();