Greasy Fork

Greasy Fork is available in English.

华医CME数据清理工具(增强版)

支持拖拽移动、折叠、半透明的华医CME数据清理工具

当前为 2025-10-18 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/553000/1679785/%E5%8D%8E%E5%8C%BBCME%E6%95%B0%E6%8D%AE%E6%B8%85%E7%90%86%E5%B7%A5%E5%85%B7%EF%BC%88%E5%A2%9E%E5%BC%BA%E7%89%88%EF%BC%89.js

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         华医CME数据清理工具(增强版)
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  支持拖拽移动、折叠、半透明的华医CME数据清理工具
// @author       您的名字
// @match        *://cme28.91huayi.com/*
// @grant        GM_deleteValue
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(function() {
    'use strict';

    // 全局状态:控制折叠和拖拽
    let isCollapsed = false;
    let isDragging = false;
    let dragStartX = 0;
    let dragStartY = 0;

    // 创建增强版清理工具界面
    function createCleanerUI() {
        if (document.getElementById('cme-cleaner-container')) return;

        // 1. 主容器(支持拖拽和半透明)
        const container = document.createElement('div');
        container.id = 'cme-cleaner-container';
        container.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 9999;
            background: rgba(255,255,255,0.9); /* 初始半透明 */
            backdrop-filter: blur(3px);
            padding: 0;
            border-radius: 8px;
            box-shadow: 0 2px 15px rgba(0,0,0,0.15);
            width: 300px;
            font-family: Arial, sans-serif;
            transition: all 0.3s ease;
            cursor: move; /* 初始拖拽光标 */
        `;

        // 2. 标题栏(拖拽触发区 + 折叠按钮)
        const header = document.createElement('div');
        header.id = 'cme-cleaner-header';
        header.style.cssText = `
            padding: 10px 15px;
            background: #4096ff;
            color: white;
            border-top-left-radius: 8px;
            border-top-right-radius: 8px;
            font-weight: bold;
            display: flex;
            justify-content: space-between;
            align-items: center;
        `;
        header.textContent = '华医CME数据清理';

        // 折叠/展开按钮
        const toggleBtn = document.createElement('button');
        toggleBtn.id = 'cme-cleaner-toggle';
        toggleBtn.innerHTML = '−'; // 初始折叠符号
        toggleBtn.style.cssText = `
            background: transparent;
            border: none;
            color: white;
            font-size: 18px;
            cursor: pointer;
            padding: 0 5px;
            line-height: 1;
        `;
        header.appendChild(toggleBtn);
        container.appendChild(header);

        // 3. 内容区(可折叠)
        const content = document.createElement('div');
        content.id = 'cme-cleaner-content';
        content.style.cssText = `
            padding: 15px;
            display: block; /* 初始展开 */
            transition: all 0.3s ease;
        `;

        // 批量清理按钮
        const clearAllBtn = document.createElement('button');
        clearAllBtn.textContent = '清理所有数据';
        clearAllBtn.style.cssText = `
            width: 100%;
            padding: 8px;
            background: #dc3545;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            margin-bottom: 15px;
            font-weight: bold;
            transition: background 0.2s;
        `;
        clearAllBtn.addEventListener('click', clearAllData);
        content.appendChild(clearAllBtn);

        // 单独清理区域标题
        const singleTitle = document.createElement('p');
        singleTitle.textContent = '单独清理项:';
        singleTitle.style.cssText = 'margin: 10px 0 5px; color: #666; font-size: 14px;';
        content.appendChild(singleTitle);

        // 数据项列表
        const dataItems = [
            { id: 'courseList', type: 'GM', name: '课程列表' },
            { id: 'dept_id2', type: 'GM', name: '部门ID' },
            { id: 'title_id', type: 'GM', name: '标题ID' },
            { id: 'savedQuestions', type: 'GM', name: '保存的问题' },
            { id: 'currentCourseIndex', type: 'local', name: '当前课程索引' },
            { id: 'allCourseLinks', type: 'local', name: '所有课程链接' },
            { id: 'videolinks', type: 'local', name: '视频链接' },
            { id: 'examIndex', type: 'local', name: '考试索引' },
            { id: 'savedLoginName', type: 'local', name: '保存的登录名' }
        ];

        // 创建单独清理按钮
        dataItems.forEach(item => {
            const itemDiv = document.createElement('div');
            itemDiv.style.cssText = 'margin-bottom: 6px; display: flex; justify-content: space-between; align-items: center;';

            const itemName = document.createElement('span');
            itemName.textContent = item.name;
            itemName.style.cssText = 'font-size: 13px;';

            const itemBtn = document.createElement('button');
            itemBtn.textContent = '清理';
            itemBtn.style.cssText = `
                padding: 3px 8px;
                background: #6c757d;
                color: white;
                border: none;
                border-radius: 3px;
                cursor: pointer;
                font-size: 12px;
                transition: background 0.2s;
            `;
            itemBtn.addEventListener('click', () => clearSingleItem(item.id, item.type, item.name));

            itemDiv.appendChild(itemName);
            itemDiv.appendChild(itemBtn);
            content.appendChild(itemDiv);
        });

        // 状态提示
        const statusDiv = document.createElement('div');
        statusDiv.id = 'cme-cleaner-status';
        statusDiv.style.cssText = `
            margin-top: 10px;
            padding: 5px;
            border-radius: 4px;
            font-size: 12px;
            display: none;
        `;
        content.appendChild(statusDiv);
        container.appendChild(content);

        // 4. 透明度调节(可选)
        const opacityControl = document.createElement('div');
        opacityControl.style.cssText = `
            padding: 0 15px 10px;
            display: flex;
            align-items: center;
            gap: 8px;
            font-size: 12px;
            color: #666;
        `;
        opacityControl.innerHTML = `
            <span>透明度:</span>
            <input type="range" min="50" max="100" value="90" id="cme-opacity-slider">
            <span id="cme-opacity-value">90%</span>
        `;
        container.appendChild(opacityControl);

        document.body.appendChild(container);

        // 绑定核心交互事件
        bindInteractions();
    }

    // 绑定拖拽、折叠、透明度调节事件
    function bindInteractions() {
        const container = document.getElementById('cme-cleaner-container');
        const header = document.getElementById('cme-cleaner-header');
        const content = document.getElementById('cme-cleaner-content');
        const toggleBtn = document.getElementById('cme-cleaner-toggle');
        const opacitySlider = document.getElementById('cme-opacity-slider');
        const opacityValue = document.getElementById('cme-opacity-value');

        // 1. 拖拽功能
        header.addEventListener('mousedown', (e) => {
            isDragging = true;
            // 记录初始拖拽位置(鼠标相对于容器的偏移)
            dragStartX = e.clientX - container.offsetLeft;
            dragStartY = e.clientY - container.offsetTop;
            container.style.cursor = 'grabbing';
        });

        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            // 计算新位置(避免鼠标超出窗口)
            const newLeft = e.clientX - dragStartX;
            const newTop = e.clientY - dragStartY;
            // 限制在可视窗口内
            const maxLeft = window.innerWidth - container.offsetWidth;
            const maxTop = window.innerHeight - container.offsetHeight;
            container.style.left = `${Math.max(0, Math.min(newLeft, maxLeft))}px`;
            container.style.top = `${Math.max(0, Math.min(newTop, maxTop))}px`;
            // 取消固定右定位(避免拖拽冲突)
            container.style.right = 'auto';
        });

        document.addEventListener('mouseup', () => {
            if (isDragging) {
                isDragging = false;
                container.style.cursor = 'move';
            }
        });

        // 2. 折叠/展开功能
        toggleBtn.addEventListener('click', () => {
            isCollapsed = !isCollapsed;
            if (isCollapsed) {
                content.style.display = 'none';
                opacitySlider.style.display = 'none'; // 折叠时隐藏透明度调节
                opacityValue.style.display = 'none';
                toggleBtn.innerHTML = '+'; // 展开符号
                container.style.width = '180px'; // 缩小宽度
            } else {
                content.style.display = 'block';
                opacitySlider.style.display = 'inline-block';
                opacityValue.style.display = 'inline-block';
                toggleBtn.innerHTML = '−'; // 折叠符号
                container.style.width = '300px'; // 恢复宽度
            }
        });

        // 3. 透明度调节
        opacitySlider.addEventListener('input', (e) => {
            const value = e.target.value;
            opacityValue.textContent = `${value}%`;
            container.style.background = `rgba(255,255,255,${value / 100})`;
        });

        // 4. 内容区点击取消拖拽光标(避免按钮hover异常)
        content.addEventListener('mouseenter', () => {
            if (!isDragging) container.style.cursor = 'default';
        });
        content.addEventListener('mouseleave', () => {
            if (!isDragging) container.style.cursor = 'move';
        });
    }

    // 显示操作状态提示
    function showStatus(message, isError = false) {
        const statusDiv = document.getElementById('cme-cleaner-status');
        statusDiv.textContent = message;
        statusDiv.style.display = 'block';
        statusDiv.style.backgroundColor = isError ? 'rgba(248,215,218,0.9)' : 'rgba(212,237,218,0.9)';
        statusDiv.style.color = isError ? '#721c24' : '#155724';
        // 3秒后自动隐藏
        setTimeout(() => statusDiv.style.display = 'none', 3000);
    }

    // 清理单个数据项
    function clearSingleItem(id, type, name) {
        try {
            if (type === 'GM') {
                typeof GM_deleteValue === 'function'
                    ? (GM_deleteValue(id), showStatus(`已清理:${name}`))
                    : showStatus('GM_deleteValue函数不可用', true);
            } else {
                localStorage.removeItem(id);
                showStatus(`已清理:${name}`);
            }
        } catch (e) {
            showStatus(`清理失败:${e.message}`, true);
        }
    }

    // 清理所有数据(带确认提示)
    function clearAllData() {
        if (!confirm('确定要清理所有数据吗?此操作不可恢复!')) return;
        try {
            // 清理GM存储
            ['courseList', 'dept_id2', 'title_id', 'savedQuestions'].forEach(id => {
                typeof GM_deleteValue === 'function' && GM_deleteValue(id);
            });
            // 清理localStorage
            ['currentCourseIndex', 'allCourseLinks', 'videolinks', 'examIndex', 'savedLoginName'].forEach(id => {
                localStorage.removeItem(id);
            });
            showStatus('所有数据已清理完成');
        } catch (e) {
            showStatus(`清理失败:${e.message}`, true);
        }
    }

    // 页面加载完成后初始化
    window.addEventListener('load', createCleanerUI);
})();