deepseek-question-list

展示网页版deepseek当前对话的所有提问

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         deepseek-question-list
// @namespace    https://github.com/firesahc/deepseek-question-list
// @version      1.7.2
// @description  展示网页版deepseek当前对话的所有提问
// @author       firesahc
// @match        https://chat.deepseek.com/*
// @license      MIT
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

let observer = null;
let isObserving = false;
let debounceTimer = null;

function createParserInit() {
    const existingList = document.getElementById('xpath-parser-list');
    if (existingList) existingList.remove();

    const listContainer = document.createElement('div');
    listContainer.id = 'xpath-parser-list';
    listContainer.style.cssText = `
        top: 10px;
        right: 50px;
        gap: 8px;
        overflow-y: auto;
        background: white;
        z-index: 10000;
        font-family: Arial, sans-serif;
        font-size: 14px;
        display: flex;
        flex-direction: column;
    `;

    const topButtonBar = document.createElement('div');
    topButtonBar.style.cssText = `
        display: flex;
        gap: 8px;
        background: white;
        flex-wrap: wrap;
    `;

    const contentArea = document.createElement('div');
    contentArea.id = 'xpath-list-content';
    contentArea.style.cssText = `
        flex: 1;
        overflow-y: auto;
        padding: 4px;
    `;
    
    addTopButtons(topButtonBar, listContainer, contentArea);
    
    listContainer.appendChild(topButtonBar);
    listContainer.appendChild(contentArea);
    
    // 延迟启动观察器
    clearTimeout(debounceTimer);
    debounceTimer = setTimeout(() => {
        addQuestionCollapseButtons();

        // 将列表框添加到 class="c3ecdb44" 的元素内部
        const targetContainer = document.querySelector('.c3ecdb44');
        if (targetContainer) {
            targetContainer.appendChild(listContainer);
        }
    }, 350)
}

function startObservation(contentArea) {
    if (isObserving) return true;

    observer = new MutationObserver((mutations) => {
        let shouldParse = false;
        for (const mutation of mutations) {
            // 检查目标元素的类名
            const targetClass = mutation.target.className;
            
            // 情况1: 直接检测到 dad65929 的变化
            if (mutation.type === 'childList' &&
                typeof targetClass === 'string' &&
                targetClass.includes('dad65929')) {
                shouldParse = true;
                break;
            }
            
            // 情况2: 检测到滚动区域的变化,且涉及 dad65929 节点
            if (mutation.type === 'childList' &&
                typeof targetClass === 'string' &&
                targetClass.includes('_0f72b0b') &&
                targetClass.includes('ds-scroll-area')) {
                // 检查添加的节点
                if (mutation.addedNodes.length > 0) {
                    for (const node of mutation.addedNodes) {
                        if (node.nodeType === Node.ELEMENT_NODE &&
                            node.classList &&
                            node.classList.contains('dad65929')) {
                            shouldParse = true;
                            break;
                        }
                    }
                }
                // 检查移除的节点
                else if (mutation.removedNodes.length > 0) {
                    for (const node of mutation.removedNodes) {
                        if (node.nodeType === Node.ELEMENT_NODE &&
                            node.classList &&
                            node.classList.contains('dad65929')) {
                            shouldParse = true;
                            break;
                        }
                    }
                }
                if (shouldParse) break;
            }

            // 情况3: 检测到class属性移除了"_3111eee"
            if (mutation.type === 'attributes' &&
                typeof mutation.oldValue === 'string' &&
                mutation.oldValue.includes('_9663006') &&
                mutation.oldValue.includes('_3111eee')) {
                if (!targetClass.includes('_3111eee')) {
                    shouldParse = true;
                    break;
                }
            }
        }

        if (shouldParse) {
            clearTimeout(debounceTimer);
            debounceTimer = setTimeout(() => {
                const messageElements = parseElements(contentArea);
                contentArea.innerHTML = '';
                addListMessages(contentArea, messageElements);

                // 为每个目标元素添加收起按钮(仅当内容较长时)
                addElementCollapseButtons(messageElements);
            }, 300);
        }
    });

    // 获取目标元素
    const targetElement = document.querySelector('._0f72b0b.ds-scroll-area');
    if (!targetElement) {
        return false;
    }
    
    try {
        // 开始观察目标元素
        observer.observe(targetElement, {
            childList: true,
            subtree: true,
            attributes: true,
            attributeFilter: ['class'],
            attributeOldValue: true,
            characterData: false
        });
        isObserving = true;
        return true;
    } catch (error) {
        isObserving = false;
        return false;
    }
}

function stopObservation() {
    if (observer) {
        observer.disconnect();
        observer = null;
        isObserving = false;
        clearTimeout(debounceTimer);
    }
}

function parseElements(contentArea) {
    try {
        contentArea.innerHTML = '';
        const targetElements = document.querySelectorAll('.fbb737a4');
        if (targetElements.length === 0) {
            return;
        }

        const messageElements = [];
        targetElements.forEach(element => {
            messageElements.push({
                targetElement: element
            });
        });
        if (messageElements.length === 0) {
            return;
        }
        else{
            return messageElements;
        }
    } catch (error) {
        return;
    }
}

function addElementCollapseButtons(messageElements) {
    messageElements.forEach((item, index) => {
        const element = item.targetElement;
        
        // 检查是否已经添加过按钮
        if (element.hasAttribute('data-collapse-button-added')) {
            return;
        }

        // 如果内容高度不超过400px,不需要添加收起按钮
        if (element.scrollHeight <= 400) {
            return;
        }

        // 标记已添加按钮
        element.setAttribute('data-collapse-button-added', 'true');

        // 确保元素有相对定位,以便按钮可以绝对定位
        const originalPosition = element.style.position;
        if (!originalPosition || originalPosition === 'static') {
            element.style.position = 'relative';
        }

        // 创建收起按钮
        const collapseButton = document.createElement('button');
        collapseButton.textContent = '收起';
        collapseButton.style.cssText = `
            position: absolute;
            top: 5px;
            left: 5px;
            z-index: 1000;
            background: rgba(100, 100, 100, 0.8);
            color: white;
            border: none;
            border-radius: 4px;
            padding: 4px 8px;
            font-size: 12px;
            cursor: pointer;
            opacity: 0.8;
            transition: opacity 0.2s;
        `;

        // 存储原始高度和溢出状态
        const originalHeight = element.style.height;
        const originalOverflow = element.style.overflow;
        let isCollapsed = false;

        collapseButton.addEventListener('mouseenter', () => {
            collapseButton.style.opacity = '1';
        });

        collapseButton.addEventListener('mouseleave', () => {
            collapseButton.style.opacity = '0.8';
        });

        collapseButton.addEventListener('click', (e) => {
            e.stopPropagation();
            if (isCollapsed) {
                // 展开
                element.style.height = originalHeight || '';
                element.style.overflow = originalOverflow || '';
                collapseButton.textContent = '收起';
                isCollapsed = false;
            } else {
                // 收起
                element.style.height = '110px';
                element.style.overflow = 'hidden';
                collapseButton.textContent = '展开';
                isCollapsed = true;
            }
        });

        // 添加按钮到元素
        element.appendChild(collapseButton);
    });
}

function addQuestionCollapseButtons(){
    // 尝试查找目标元素
    const questionElement = document.querySelector('._871cbca');
    if (!questionElement) {
        return;
    }
    
    const toggleButton = document.createElement('button');
    // 获取目标容器元素
    const containerElement = document.querySelector('._7780f2e');
    if (!containerElement) {
        return;
    } else {
        toggleButton.textContent = '▼';
        // 设置容器元素为相对定位,以便按钮可以相对于它定位
        containerElement.style.position = 'relative';
        // 将按钮添加到容器元素内部
        containerElement.appendChild(toggleButton);
        // 设置按钮样式 - 在容器元素内部居中
        toggleButton.style.cssText = `
            position: absolute;
            bottom: 0; 
            left: 50%; /* 水平居中定位 */
            transform: translateX(-50%); /* 水平居中调整 */
            z-index: 1000;
            padding: 8px 20px;
            background-color: rgba(255, 255, 255, 0.3);
            color: #000;
            border: 1px solid rgba(0, 0, 0, 0.1);
            border-bottom: none;
            border-radius: 8px 8px 0 0;
            cursor: pointer;
            backdrop-filter: blur(12px);
            -webkit-backdrop-filter: blur(12px);
            font-size: 10px;
            font-weight: bold;
            box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease;
        `;
    }

    // 添加点击事件
    toggleButton.addEventListener('click', function () {
        if (questionElement.style.display === 'none') {
            questionElement.style.display = 'block';
            toggleButton.textContent = '▼';
        } else {
            questionElement.style.display = 'none';
            toggleButton.textContent = '▲';
        };
    });
}

function addListMessages(contentArea, messageElements) {
    const list = document.createElement('ul');
    list.style.cssText = `
        list-style: none;
        margin: 0;
        padding: 0;
    `;

    messageElements.forEach((item, index) => {
        const listItem = createListItem(item, index);
        list.appendChild(listItem);
    });

    contentArea.appendChild(list);
}

function createListItem(item, index) {
    const listItem = document.createElement('li');
    listItem.style.cssText = `
        margin-bottom: 4px;
        padding: 4px;
        border: 1px solid #e0e0e0;
        border-radius: 6px;
        background: #fafafa;
        cursor: pointer;
        transition: all 0.2s ease;
    `;

    listItem.addEventListener('mouseenter', () => {
        listItem.style.background = '#f0f8ff';
        listItem.style.borderColor = '#4CAF50';
    });

    listItem.addEventListener('mouseleave', () => {
        listItem.style.background = '#fafafa';
        listItem.style.borderColor = '#e0e0e0';
    });

    const indexInfo = document.createElement('div');
    indexInfo.style.cssText = `
        font-weight: bold;
        color: #2196F3;
        font-size: 14px;
    `;
    indexInfo.textContent = `问题 ${index + 1}`;

    const contentPreview = document.createElement('div');
    contentPreview.style.cssText = `
        color: #333;
        font-size: 13px;
        line-height: 1.4;
        background: white;
        padding: 4px;
        border-radius: 4px;
        border: 1px solid #e0e0e0;
    `;
    
    const textContent = item.targetElement.textContent?.trim() || '';
    contentPreview.textContent = textContent ?
        (textContent.length > 120 ? 
             textContent.substring(0, 120) + '...' : 
             textContent
        ) :
        '[空内容]';

    listItem.appendChild(indexInfo);
    listItem.appendChild(contentPreview);

    //点击跳转到问题起始
    listItem.addEventListener('click', () => {
        item.targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
    });

    return listItem;
}

function addTopButtons(buttonContainer, listContainer, contentArea) {
    const buttonStyle = `
        padding: 6px 6px;
        border: none;
        border-radius: 4px;
        cursor: pointer;
        font-size: 12px;
        font-weight: bold;
        transition: all 0.2s ease;
        flex: 1;
        min-width: 30px;
    `;

    // 从油猴存储中读取 isContentVisible 的值,默认值为 true(显示状态)
    let isContentVisible = GM_getValue('isContentVisible', true);

    // 根据存储的值初始化内容区域的显示状态
    contentArea.style.display = isContentVisible ? 'block' : 'none';
    listContainer.style.padding = isContentVisible ? '6px' : '0px';
    listContainer.style.border = isContentVisible ? '2px solid #f5f5f5' : '';
    listContainer.style.position =isContentVisible ? '':' fixed';
    listContainer.style.width=isContentVisible ? '240px':' 100px';

    const parseButton = createButton(isObserving? '停止解析':'开始解析', '#2196F3', '#1976D2', () => {
        if (isObserving) {
            // 停止解析
            stopObservation();
            parseButton.textContent = '开始解析';
        } else {
            // 开始解析
            const success = startObservation(contentArea);
            if (success) {
                parseButton.textContent = '停止解析';
                // 立即执行一次解析
                const messageElements = parseElements(contentArea);
                contentArea.innerHTML = '';
                addListMessages(contentArea, messageElements);

                // 为每个目标元素添加收起按钮(仅当内容较长时)
                addElementCollapseButtons(messageElements);
            }
        }
    });

    const toggleButton = createButton(isContentVisible ? '隐藏列表' : '显示列表', '#FF9800', '#F57C00', () => {
        isContentVisible = !isContentVisible;
        toggleButton.textContent = isContentVisible ? '隐藏列表' : '显示列表';
        contentArea.style.display = isContentVisible ? 'block' : 'none';
        listContainer.style.padding = isContentVisible ? '6px' : '0px';
        listContainer.style.border = isContentVisible ? '2px solid #f5f5f5' : '';
        listContainer.style.position =isContentVisible ? '':' fixed';
        listContainer.style.width=isContentVisible ? '240px':' 100px';
        // 将新的 isContentVisible 值保存到油猴存储中
        GM_setValue('isContentVisible', isContentVisible);
    });

    buttonContainer.appendChild(parseButton);
    buttonContainer.appendChild(toggleButton);
}

function createButton(text, bgColor, hoverColor, clickHandler) {
    const button = document.createElement('button');
    button.textContent = text;
    button.style.cssText = `
        padding: 6px 6px;
        border: none;
        border-radius: 4px;
        cursor: pointer;
        font-size: 12px;
        font-weight: bold;
        transition: all 0.2s ease;
        flex: 1;
        min-width: 30px;
        background: ${bgColor};
        color: white;
    `;

    button.addEventListener('mouseenter', () => {
        button.style.background = hoverColor;
    });

    button.addEventListener('mouseleave', () => {
        button.style.background = bgColor;
    });

    button.addEventListener('click', clickHandler);
    return button;
}

if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', createParserInit);
} else {
    createParserInit();
}

window.createParser = createParserInit;
window.parseTarget = function() {
    const contentArea = document.getElementById('xpath-list-content');
    if (contentArea) {
        const messageElements = parseElements(contentArea);
        contentArea.innerHTML = '';
        addListMessages(contentArea, messageElements);

        // 为每个目标元素添加收起按钮(仅当内容较长时)
        addElementCollapseButtons(messageElements);
    }
};