BUPT_自定义待办过滤助手_北京邮电大学云邮教学空间

允许用户自定义需要隐藏的待办项

// ==UserScript==
// @name         BUPT_自定义待办过滤助手_北京邮电大学云邮教学空间
// @namespace    https://ucloud.bupt.edu.cn/
// @version      2.3
// @description  允许用户自定义需要隐藏的待办项
// @match        https://ucloud.bupt.edu.cn/*
// @grant        GM_setValue
// @grant        GM_getValue
// @license      GNU GPLv3
// ==/UserScript==

(function() {
    'use strict';

    let hiddenItems = new Set(JSON.parse(localStorage.getItem('hiddenTitles') || '[]'));
    let isProcessing = false;
    let isPanelVisible = false;
    let originalTaskCount = null;

    // 创建控制面板
    function createControlPanel() {
        // 创建样式
        const style = document.createElement('style');
        style.textContent = `
            .filter-panel {
                position: fixed;
                top: 20px;
                right: 20px;
                background: white;
                padding: 15px;
                border: none;
                border-radius: 8px;
                z-index: 9999;
                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
                transition: all 0.3s ease;
            }
            .filter-panel.hidden {
                transform: translateX(calc(100% + 20px));
            }
            .filter-toggle-btn {
                position: fixed;
                top: 20px;
                right: 20px;
                padding: 8px 16px;
                background: #4CAF50;
                color: white;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                font-weight: 500;
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
                transition: all 0.2s ease;
                z-index: 10000;
            }
            .filter-toggle-btn:hover {
                background: #45a049;
                box-shadow: 0 4px 8px rgba(0,0,0,0.15);
            }
            .filter-input {
                width: 100%;
                padding: 8px 12px;
                border: 1px solid #ddd;
                border-radius: 4px;
                margin-bottom: 10px;
                font-size: 14px;
                box-sizing: border-box;
            }
            .filter-input:focus {
                border-color: #4CAF50;
                outline: none;
                box-shadow: 0 0 0 2px rgba(76,175,80,0.2);
            }
            .filter-add-btn {
                background: #4CAF50;
                color: white;
                border: none;
                padding: 8px 16px;
                border-radius: 4px;
                cursor: pointer;
                font-weight: 500;
                transition: all 0.2s ease;
            }
            .filter-add-btn:hover {
                background: #45a049;
            }
            .filter-item {
                display: flex;
                align-items: center;
                justify-content: space-between;
                padding: 8px;
                background: #f5f5f5;
                border-radius: 4px;
                margin-top: 8px;
            }
            .filter-item-text {
                margin-right: 10px;
                font-size: 14px;
                color: #333;
            }
            .filter-delete-btn {
                background: #ff4444;
                color: white;
                border: none;
                padding: 4px 8px;
                border-radius: 3px;
                cursor: pointer;
                font-size: 12px;
                transition: all 0.2s ease;
            }
            .filter-delete-btn:hover {
                background: #cc0000;
            }
            .filter-list-title {
                font-size: 14px;
                font-weight: 600;
                color: #333;
                margin-bottom: 10px;
                padding-bottom: 5px;
                border-bottom: 2px solid #4CAF50;
            }
        `;
        document.head.appendChild(style);

        // 创建切换按钮
        const toggleButton = document.createElement('button');
        toggleButton.className = 'filter-toggle-btn';
        toggleButton.textContent = '过滤设置';
        toggleButton.onclick = togglePanel;
        document.body.appendChild(toggleButton);

        // 创建主面板
        const panel = document.createElement('div');
        panel.id = 'filterControlPanel';
        panel.className = 'filter-panel' + (isPanelVisible ? '' : ' hidden');

        // 添加标题输入框
        const input = document.createElement('input');
        input.type = 'text';
        input.className = 'filter-input';
        input.placeholder = '输入要隐藏的待办项标题';
        panel.appendChild(input);

        // 添加按钮
        const addButton = document.createElement('button');
        addButton.className = 'filter-add-btn';
        addButton.textContent = '添加过滤';
        addButton.onclick = () => {
            const title = input.value.trim();
            if (title) {
                hiddenItems.add(title);
                updateHiddenItemsList();
                saveHiddenItems();
                filterItems();
                input.value = '';
            }
        };
        panel.appendChild(addButton);

        // 显示当前隐藏的项目列表
        const list = document.createElement('div');
        list.id = 'hiddenItemsList';
        list.style.marginTop = '15px';
        panel.appendChild(list);

        document.body.appendChild(panel);
        updateHiddenItemsList();
    }

    // 切换面板显示/隐藏
    function togglePanel() {
        const panel = document.getElementById('filterControlPanel');
        const toggleButton = document.querySelector('.filter-toggle-btn');

        isPanelVisible = !isPanelVisible;
        panel.className = 'filter-panel' + (isPanelVisible ? '' : ' hidden');
        toggleButton.textContent = isPanelVisible ? '隐藏设置' : '过滤设置';
    }

    // 更新隐藏项目列表显示
    function updateHiddenItemsList() {
        const list = document.getElementById('hiddenItemsList');
        list.innerHTML = '<div class="filter-list-title">当前隐藏的项目</div>';

        hiddenItems.forEach(title => {
            const item = document.createElement('div');
            item.className = 'filter-item';

            const text = document.createElement('span');
            text.className = 'filter-item-text';
            text.textContent = title;
            item.appendChild(text);

            const deleteButton = document.createElement('button');
            deleteButton.className = 'filter-delete-btn';
            deleteButton.textContent = '删除';
            deleteButton.onclick = () => {
                hiddenItems.delete(title);
                updateHiddenItemsList();
                saveHiddenItems();
                filterItems();
            };
            item.appendChild(deleteButton);

            list.appendChild(item);
        });
    }

    // 保存隐藏项目列表到localStorage
    function saveHiddenItems() {
        localStorage.setItem('hiddenTitles', JSON.stringify([...hiddenItems]));
    }

    // 更新待办数字的函数
    function updateTaskCount() {
        const taskItems = document.querySelectorAll('.teacher-task-item');
        taskItems.forEach(item => {
            const label = item.querySelector('.task-label');
            if (label && label.textContent.trim() === '待办') {
                const taskValueElement = item.querySelector('.task-value');
                if (taskValueElement) {
                    // 如果还没有记录原始数量,或者检测到新的原始数量
                    const currentCount = parseInt(taskValueElement.textContent.trim());
                    if (originalTaskCount === null || currentCount > originalTaskCount) {
                        originalTaskCount = currentCount;
                        console.log('记录/更新初始待办数:', originalTaskCount);
                    }

                    // 计算隐藏的待办项数量
                    const hiddenCount = countHiddenTasks();

                    // 计算新的待办数量
                    const newCount = Math.max(0, originalTaskCount - hiddenCount);
                    console.log('更新待办数为:', newCount, '(原始:', originalTaskCount, '隐藏:', hiddenCount, ')');

                    // 更新显示的数量
                    taskValueElement.textContent = newCount.toString();
                }
            }
        });
    }

    // 计算当前隐藏的待办项数量
    function countHiddenTasks() {
        let count = 0;
        const items = document.querySelectorAll('div.in-progress-item.home-inline-block');
        items.forEach(item => {
            const titleElement = item.querySelector('.activity-title');
            if (titleElement && [...hiddenItems].some(hiddenTitle => titleElement.innerText.includes(hiddenTitle))) {
                count++;
            }
        });
        return count;
    }

    // 过滤待办项
    function filterItems() {
        if (isProcessing) return;
        isProcessing = true;

        const items = document.querySelectorAll('div.in-progress-item.home-inline-block');
        console.log('检查到的项目数量:', items.length);

        items.forEach(item => {
            const titleElement = item.querySelector('.activity-title');
            if (titleElement) {
                const title = titleElement.innerText;
                console.log('检查标题:', title);
                updateTaskCount();
                if ([...hiddenItems].some(hiddenTitle => title.includes(hiddenTitle))) {
                    console.log('找到需要隐藏的项目:', title);
                    item.style.display = 'none';
                } else {
                    console.log('显示项目:', title);
                    item.style.display = '';
                }
            }
        });

        console.log('当前隐藏项目数:', hiddenItems.size);
        isProcessing = false;
    }

    // 初始化
    console.log('脚本开始运行');
    createControlPanel();

    // 设置观察器
    const observer = new MutationObserver((mutations) => {
        for (let mutation of mutations) {
            if (mutation.type === 'childList' ||
                mutation.type === 'characterData' ||
                mutation.target.classList?.contains('in-progress-item') ||
                mutation.target.classList?.contains('teacher-task-item')) {
                console.log('检测到相关页面变化');
                filterItems();
                break;
            }
        }
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true,
        characterData: true,
        attributes: true,
        attributeFilter: ['style', 'class']
    });

    console.log('已设置观察器');
    filterItems();
})();