// ==UserScript== // @name DeepSeek 增强工具集 // @namespace http://tampermonkey.net/ // @version 2.1 // @description 为DeepSeek添加批量删除、历史对话搜索和侧边栏折叠功能 // @author Assistant // @match https://chat.deepseek.com/* // @grant GM_addStyle // ==/UserScript== (function() { 'use strict'; // ---------- 配置选择器 ---------- const SELECTORS = { // 开启新对话按钮 newChatBtn: '#root > div > div > div.c3ecdb44 > div.dc04ec1d > div > div._5a8ac7a.a084f19e', // 左侧历史对话列表容器 leftList: '#root > div > div > div.c3ecdb44 > div.dc04ec1d > div', // 单个对话项(用于点击跳转) chatItem: 'a', // 历史对话滚动区域(批量删除需要) scrollArea: '.ds-scroll-area' }; // ---------- 全局变量 ---------- let searchBtn = null; let modalPanel = null; let panelListContainer = null; let searchInput = null; let isPanelVisible = false; let leftObserver = null; let rootObserver = null; let itemElementMap = new Map(); // 批量删除相关变量 let btnBatchDelete = null; let btnCancel = null; let btnReverse = null; let btnConfirm = null; let checkboxes = []; let batchContainer = null; let actionContainer = null; let originalNewChatBtn = null; let batchDeleteObserver = null; // ---------- 添加自定义样式 ---------- GM_addStyle(` /* 浮层面板 */ .ds-history-modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 600px; height: 400px; background: var(--dsw-alias-bg-primary, #fff); border-radius: 16px; box-shadow: 0 20px 35px -12px rgba(0,0,0,0.3), 0 0 0 1px rgba(0,0,0,0.05); display: flex; flex-direction: column; z-index: 10000; overflow: hidden; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; } @media (prefers-color-scheme: dark) { .ds-history-modal { background: #1e1e2f; color: #e4e4e7; box-shadow: 0 20px 35px -12px rgba(0,0,0,0.5); } .ds-history-modal input { background: #2a2a36; color: #fff; border-color: #3e3e4a; } .ds-history-modal .ds-chat-item:hover { background: #2a2a36; } } .ds-modal-header { display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; border-bottom: 1px solid var(--dsw-alias-border-divider, #e5e5e7); font-weight: 600; font-size: 18px; color: #3964fe; } .ds-modal-header .close-btn { cursor: pointer; font-size: 24px; line-height: 1; background: none; border: none; color: #3964fe; opacity: 0.7; } .ds-modal-header .close-btn:hover { opacity: 1; } .ds-search-input-wrapper { padding: 12px 20px; border-bottom: 1px solid var(--dsw-alias-border-divider, #e5e5e7); } .ds-search-input-wrapper input { width: 100%; padding: 10px 14px; font-size: 14px; border: 1px solid var(--dsw-alias-border-input, #ccc); border-radius: 10px; background: var(--dsw-alias-bg-secondary, #f9f9fb); outline: none; transition: 0.2s; box-sizing: border-box; } .ds-search-input-wrapper input:focus { border-color: #3b82f6; box-shadow: 0 0 0 2px rgba(59,130,246,0.2); } .ds-list-container { flex: 1; overflow-y: auto; padding: 12px 8px; } .ds-group-title { font-size: 12px; font-weight: 500; color: var(--dsw-alias-label-tertiary, #8e8e93); padding: 8px 12px; letter-spacing: 0.3px; } .ds-chat-item { display: flex; align-items: center; gap: 10px; padding: 10px 12px; margin: 2px 0; border-radius: 10px; cursor: pointer; transition: background 0.2s; color: var(--dsw-alias-label-primary, #1f1f1f); text-decoration: none; } .ds-chat-item:hover { background: var(--dsw-alias-fill-hover, #f2f2f5); } .ds-chat-item svg { flex-shrink: 0; width: 18px; height: 18px; color: var(--dsw-alias-label-tertiary, #8e8e93); } .ds-chat-item .title { flex: 1; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .ds-modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.4); z-index: 9999; backdrop-filter: blur(2px); } .ds-no-results { text-align: center; padding: 40px 20px; color: var(--dsw-alias-label-tertiary, #8e8e93); font-size: 14px; } /* 折叠按钮样式 */ .ds-collapse-btn { display: flex; align-items: center; justify-content: space-between; width: 100%; padding: 8px 12px; margin: 8px 0; background: transparent; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500; color: var(--dsw-alias-label-secondary, #666); transition: all 0.2s ease; } .ds-collapse-btn:hover { background-color: var(--dsw-alias-fill-hover, rgba(0,0,0,0.05)); color: var(--dsw-alias-label-primary, #1f1f1f); } .ds-collapse-btn svg { width: 16px; height: 16px; fill: currentColor; transition: transform 0.2s ease; } .ds-collapse-btn.collapsed svg { transform: rotate(-90deg); } .ds-history-collapsed ._3098d02 { display: none; } .ds-list-container ._3098d02 { margin-bottom: 16px; } .ds-list-container ._546d736 { display: flex; align-items: center; gap: 10px; padding: 10px 12px; margin: 2px 0; border-radius: 10px; cursor: pointer; transition: background 0.2s; color: var(--dsw-alias-label-primary, #1f1f1f); text-decoration: none; } .ds-list-container ._546d736:hover { background: var(--dsw-alias-fill-hover, #f2f2f5); } .ds-list-container .f3d18f6a { font-size: 12px; font-weight: 500; color: var(--dsw-alias-label-tertiary, #8e8e93); padding: 8px 12px; letter-spacing: 0.3px; } /* 批量删除按钮样式 */ .btn::after { content: "";} .btn-danger { color: var(--dsw-alias-state-error-primary); overflow: hidden} .btn-danger::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0); transition: background-color .2s; pointer-events: none; } .btn-danger:hover::before { background-color: var(--dsw-alias-interactive-bg-hover-danger); } .ds-button-container { display: flex; flex-direction: column; gap: 12px; margin-bottom: 12px; } .ds-button-row { display: flex; gap: 12px; } `); // ---------- 辅助函数 ---------- function waitForElement(selector, timeout = 10000) { return new Promise((resolve) => { const el = document.querySelector(selector); if (el) return resolve(el); const obs = new MutationObserver(() => { const target = document.querySelector(selector); if (target) { obs.disconnect(); resolve(target); } }); obs.observe(document.body, { childList: true, subtree: true }); setTimeout(() => { obs.disconnect(); resolve(null); }, timeout); }); } // 获取原始左侧列表中的对话项(克隆时过滤复选框) function getOriginalChatGroups() { let leftContainer = document.querySelector(SELECTORS.leftList); if (!leftContainer) { leftContainer = document.querySelector('#root > div > div > div.c3ecdb44 > div.dc04ec1d'); } if (!leftContainer) return []; const groups = []; const chatItems = leftContainer.querySelectorAll('a'); if (chatItems.length > 0) { const container = document.createElement('div'); container.className = '_3098d02'; chatItems.forEach(item => { if (item.textContent.trim() !== '') { const clonedItem = item.cloneNode(true); // 过滤掉批量删除添加的复选框 const checkbox = clonedItem.querySelector('input[type="checkbox"]'); if (checkbox) checkbox.remove(); container.appendChild(clonedItem); } }); if (container.children.length > 0) { groups.push(container); } } return groups; } // 渲染搜索面板列表 function renderPanelList(searchTerm = '') { if (!panelListContainer) return; let groups = getOriginalChatGroups(); panelListContainer.innerHTML = ''; itemElementMap.clear(); let hasAnyVisible = false; const lowerSearch = searchTerm.toLowerCase().trim(); if (groups.length === 0) { const container = document.createElement('div'); container.className = '_3098d02'; const sampleItems = [ { title: '测试对话 1', href: '#' }, { title: '测试对话 2', href: '#' }, { title: '测试对话 3', href: '#' } ]; sampleItems.forEach(item => { const link = document.createElement('a'); link.href = item.href; link.className = '_546d736'; link.style.cssText = 'display:block; padding:10px 12px; margin:2px 0; border-radius:10px; cursor:pointer; color:var(--dsw-alias-label-primary, #1f1f1f); text-decoration:none;'; link.innerHTML = `${item.title}`; link.addEventListener('click', (e) => { e.stopPropagation(); hideModal(); }); container.appendChild(link); }); groups.push(container); } for (const group of groups) { const clonedGroup = group.cloneNode(true); if (lowerSearch) { const chatItems = clonedGroup.querySelectorAll(SELECTORS.chatItem); let groupHasVisible = false; chatItems.forEach(item => { const titleSpan = item.querySelector('.c08e6e93'); const title = titleSpan ? titleSpan.innerText.trim() : item.textContent.trim(); if (title.toLowerCase().includes(lowerSearch)) { groupHasVisible = true; } else { item.remove(); } }); if (!groupHasVisible) continue; } hasAnyVisible = true; const clonedChatItems = clonedGroup.querySelectorAll(SELECTORS.chatItem); clonedChatItems.forEach(item => { item.addEventListener('click', (e) => { e.stopPropagation(); const href = item.getAttribute('href'); if (href) { const originalItem = document.querySelector(`${SELECTORS.chatItem}[href="${href}"]`); if (originalItem && originalItem.click) { originalItem.click(); hideModal(); } else { hideModal(); } } else { hideModal(); } }); }); panelListContainer.appendChild(clonedGroup); } if (!hasAnyVisible && lowerSearch !== '') { const noResults = document.createElement('div'); noResults.className = 'ds-no-results'; noResults.textContent = '没有找到相关对话'; panelListContainer.appendChild(noResults); } else if (groups.length === 0) { const noResults = document.createElement('div'); noResults.className = 'ds-no-results'; noResults.textContent = '暂无历史对话'; panelListContainer.appendChild(noResults); } } let currentSearchTerm = ''; function syncPanelList() { if (panelListContainer && isPanelVisible) { renderPanelList(currentSearchTerm); } } function startObservingLeftList() { const leftContainer = document.querySelector(SELECTORS.leftList); if (!leftContainer) return; if (leftObserver) leftObserver.disconnect(); leftObserver = new MutationObserver(() => { syncPanelList(); }); leftObserver.observe(leftContainer, { childList: true, subtree: true, attributes: false }); } function showModal() { if (!modalPanel) return; renderPanelList(currentSearchTerm); modalPanel.style.display = 'flex'; if (!document.querySelector('.ds-modal-overlay')) { const overlay = document.createElement('div'); overlay.className = 'ds-modal-overlay'; overlay.addEventListener('click', hideModal); document.body.appendChild(overlay); } isPanelVisible = true; if (searchInput) { searchInput.focus(); searchInput.value = currentSearchTerm; renderPanelList(currentSearchTerm); } } function hideModal() { if (modalPanel) modalPanel.style.display = 'none'; const overlay = document.querySelector('.ds-modal-overlay'); if (overlay) overlay.remove(); isPanelVisible = false; } // 添加历史对话折叠按钮(防重复) function addCollapseButton() { const leftList = document.querySelector(SELECTORS.leftList); if (!leftList) return; if (document.querySelector('.ds-collapse-btn')) return; const collapseBtn = document.createElement('button'); collapseBtn.className = 'ds-collapse-btn collapsed'; collapseBtn.innerHTML = ` 历史对话 `; leftList.insertBefore(collapseBtn, leftList.firstChild); leftList.classList.add('ds-history-collapsed'); collapseBtn.addEventListener('click', () => { const isCollapsed = leftList.classList.contains('ds-history-collapsed'); if (isCollapsed) { leftList.classList.remove('ds-history-collapsed'); collapseBtn.classList.remove('collapsed'); } else { leftList.classList.add('ds-history-collapsed'); collapseBtn.classList.add('collapsed'); } }); } // ---------- 折叠与展开辅助函数(批量删除耦合) ---------- function expandHistoryIfCollapsed() { const leftList = document.querySelector(SELECTORS.leftList); if (!leftList) return; // 如果当前是折叠状态,则展开 if (leftList.classList.contains('ds-history-collapsed')) { leftList.classList.remove('ds-history-collapsed'); const collapseBtn = document.querySelector('.ds-collapse-btn'); if (collapseBtn && collapseBtn.classList.contains('collapsed')) { collapseBtn.classList.remove('collapsed'); } } } // ---------- 搜索功能(独立模块)---------- async function initSearch() { // 创建模态框 modalPanel = document.createElement('div'); modalPanel.className = 'ds-history-modal'; modalPanel.style.display = 'none'; modalPanel.innerHTML = `