S1摸鱼助手(excel)

把 S1 论坛伪装成 Excel 表格。公式栏变成可点击的层级目录,底部 Sheet 实现翻页。

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         S1摸鱼助手(excel)
// @namespace    http://tampermonkey.net/
// @version      3.1
// @description  把 S1 论坛伪装成 Excel 表格。公式栏变成可点击的层级目录,底部 Sheet 实现翻页。
// @author       Gemini
// @match        *://bbs.saraba1st.com/2b/*
// @match        *://stage1st.com/2b/*
// @match        *://www.stage1st.com/2b/*
// @grant        GM_addStyle
// @run-at       document-end
// @license MIT

// ==/UserScript==

(function() {
    'use strict';

    let isWorkMode = localStorage.getItem('s1_excel_mode') === 'true';

    // ==========================================
    // 1. Excel 界面 HTML
    //    变化:#formula-input 从 input 改为 div,以支持 HTML 链接
    // ==========================================
    const excelHeaderHTML = `
        <div id="excel-fake-header">
            <div class="excel-title-bar">
                <span class="excel-icon">X</span>
                <span class="excel-filename">Business_Report_2025.xlsx - Excel</span>
            </div>
            <div class="excel-menu-bar">
                <span>文件</span>
                <span class="active">开始</span>
                <span>插入</span>
                <span>页面布局</span>
                <span>公式</span>
                <span>数据</span>
                <span>审阅</span>
                <span>视图</span>
            </div>
            <div class="excel-ribbon">
                <div class="ribbon-group">
                    <div class="ribbon-btn">📋 粘贴</div>
                </div>
                <div class="ribbon-divider"></div>
                <div class="ribbon-group font-settings">
                    <select><option>DengXian</option><option>Calibri</option></select>
                    <select><option>11</option></select>
                    <div class="font-actions"><b>B</b> <i>I</i> <u>U</u></div>
                </div>
                <div class="ribbon-divider"></div>
                <div class="ribbon-group" style="color:#999; font-size:12px; margin-left:10px;">
                    <span style="margin-right:10px">自动换行</span>
                    <span>合并后居中</span>
                </div>
            </div>
            <div class="excel-formula-bar">
                <span class="name-box">A1</span>
                <span class="fx">fx</span>
                <div id="formula-bar-content"></div>
            </div>
            <div class="excel-col-headers">
                <div class="row-idx-blank"></div>
                <div style="flex:1; min-width:120px; border-right:1px solid #d4d4d4;">A (用户/ID)</div>
                <div style="flex:8; border-right:1px solid #d4d4d4;">B (主题 / 内容)</div>
            </div>
        </div>
        <div id="excel-sheet-bar-container">
            <div class="sheet-nav-arrows">
                <span>◀</span><span>▶</span>
            </div>
            <div id="excel-sheets-scroll">
                </div>
            <div class="sheet-add-btn">+</div>
        </div>
        <div id="excel-footer-bar">
            <span>就绪</span>
            <span style="float:right; margin-right:20px;">-------+ -- 100%</span>
        </div>
    `;

    const headerDiv = document.createElement('div');
    headerDiv.innerHTML = excelHeaderHTML;
    document.body.prepend(headerDiv);

    // ==========================================
    // 2. CSS 样式
    // ==========================================
    const css = `
        /* 切换按钮 (右上角) */
        #excel-toggle-btn {
            position: fixed; top: 5px; right: 5px; padding: 5px 10px;
            background: #217346; color: white; opacity: 1; z-index: 999999;
            cursor: pointer; font-size: 12px; font-weight: bold; border-radius: 4px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2); font-family: sans-serif;
        }
        #excel-toggle-btn:hover { background: #104e2b; }

        /* === 全局重置 === */
        body.excel-mode {
            background: #fff !important;
            font-family: 'DengXian', 'Calibri', sans-serif !important;
            font-size: 11pt !important;
            color: #000 !important;
            margin: 0 !important;
            padding-top: 165px !important;
            padding-bottom: 60px !important; /* 底部留出 Sheet 栏空间 */
            overflow-x: hidden !important;
        }

        /* === 隐藏 S1 界面元素 === */
        body.excel-mode #toptb,
        body.excel-mode #hd,
        body.excel-mode #nv_ph,
        body.excel-mode #scbar,
        body.excel-mode #ft,
        body.excel-mode #scrolltop,
        body.excel-mode #pt, /* 隐藏原页面面包屑 */
        body.excel-mode .bm.bml,
        body.excel-mode .bm.bmw.fl,
        body.excel-mode .pgbtn,
        body.excel-mode .focus,
        body.excel-mode .a_mu, body.excel-mode .ad,
        body.excel-mode #f_pst,
        body.excel-mode .th,
        body.excel-mode tbody[id^="separatorline"],
        body.excel-mode tbody[id^="stickthread"],
        body.excel-mode #pgt,
        body.excel-mode .pgs,
        body.excel-mode #fd_page_bottom
        { display: none !important; }

        /* === 列表页样式 === */
        body.excel-mode .wp, body.excel-mode #ct, body.excel-mode .mn, body.excel-mode .tl, body.excel-mode .bm_c {
            width: 100% !important; margin: 0 !important; padding: 0 !important; border: none !important; min-width: 0 !important;
        }
        body.excel-mode #threadlisttableid {
            width: 100% !important; border-collapse: collapse !important; table-layout: fixed !important; margin-top: -1px !important;
        }
        body.excel-mode #threadlisttableid tbody { display: table-row-group !important; border: none !important; }
        body.excel-mode #threadlisttableid tr { display: table-row !important; height: 22px !important; }
        body.excel-mode #threadlisttableid td, body.excel-mode #threadlisttableid th {
            padding: 2px 5px !important; border: 1px solid #e1e1e1 !important; height: 22px !important; line-height: 22px !important;
            font-size: 11pt !important; font-weight: normal !important; background: #fff !important; color: #000 !important;
            white-space: nowrap !important; overflow: hidden !important; text-align: left !important;
        }
        body.excel-mode #threadlisttableid tr:hover td, body.excel-mode #threadlisttableid tr:hover th {
            background: #e6f2ea !important; outline: 1px solid #217346; z-index: 10;
        }
        body.excel-mode .xst, body.excel-mode a { color: #000 !important; text-decoration: none !important; font-family: 'DengXian'; }
        /* 精确隐藏列表图标 */
        body.excel-mode #threadlisttableid td.icn,
        body.excel-mode #threadlisttableid td.o,
        body.excel-mode .tps, body.excel-mode .fico-image, body.excel-mode .fico-attachment
        { display: none !important; }
        body.excel-mode th.common em, body.excel-mode th.common em a { color: #999 !important; margin-right: 5px; }

        /* === 帖子正文页样式 === */
        body.excel-mode #postlist, body.excel-mode .plhin, body.excel-mode .pls, body.excel-mode .plc, body.excel-mode .bm {
            background: #fff !important; background-color: #fff !important; background-image: none !important; border: none !important;
        }
        body.excel-mode table.plhin { width: 100% !important; border-collapse: collapse !important; margin-bottom: -1px !important; }

        /* 左侧用户栏 */
        body.excel-mode .pls {
            width: 120px !important; border: 1px solid #e1e1e1 !important; padding: 5px !important; vertical-align: top !important;
            font-size: 11pt !important; color: #333 !important; text-align: left !important;
        }
        body.excel-mode .pls .avatar, body.excel-mode .pls .tns, body.excel-mode .pls p, body.excel-mode .pls dl, body.excel-mode .pls .md_ctrl, body.excel-mode .pls .o
        { display: none !important; }
        body.excel-mode .pls .pi { padding: 0 !important; margin: 0 !important; border: none !important; text-align: left !important; overflow: hidden; height: auto !important; }
        body.excel-mode .pls .authi { font-weight: normal !important; color: #000 !important; }

        /* 右侧内容栏 */
        body.excel-mode .plc {
            border: 1px solid #e1e1e1 !important; padding: 5px 10px !important; vertical-align: top !important; width: auto !important;
        }
        body.excel-mode .t_f {
            font-size: 11pt !important; font-family: 'DengXian', sans-serif !important; line-height: 1.4 !important; color: #000 !important;
        }
        body.excel-mode .t_f img {
            display: block !important; max-width: 98% !important; height: auto !important; opacity: 0.8; margin: 5px 0 !important;
        }

        /* 操作按钮 (可见) */
        body.excel-mode .sign, body.excel-mode .modact, body.excel-mode .a_ga { display: none !important; }
        body.excel-mode .pob { padding: 2px 0 !important; background: #fff !important; border: none !important; }
        body.excel-mode .po { text-align: right !important; padding: 0 5px 0 0 !important; margin: 0 !important; }
        body.excel-mode .po a {
            display: inline-block !important; border: 1px solid #ccc !important; padding: 1px 5px !important; margin-left: 5px !important;
            background: #f8f8f8 !important; color: #444 !important; text-decoration: none !important; font-size: 10pt !important; border-radius: 2px;
        }
        body.excel-mode .po a:hover { background: #e6f2ea !important; border-color: #217346 !important; }

        /* === Excel UI 头部样式 === */
        #excel-fake-header { display: none; }
        body.excel-mode #excel-fake-header { display: block; position: fixed; top: 0; left: 0; width: 100%; z-index: 9999; background: #f3f2f1; border-bottom: 1px solid #ccc; }
        .excel-title-bar { background: #217346; color: white; padding: 5px 10px; font-size: 12px; display: flex; align-items: center; }
        .excel-icon { background: white; color: #217346; padding: 0 4px; margin-right: 10px; font-weight: bold; border-radius: 2px; font-size: 10px;}
        .excel-menu-bar { background: #217346; color: #eee; display: flex; font-size: 13px; padding-top: 5px;}
        .excel-menu-bar span { padding: 5px 12px; cursor: pointer; }
        .excel-menu-bar span.active { background: #f3f2f1; color: #217346; border-radius: 4px 4px 0 0; }
        .excel-ribbon { height: 50px; background: #f3f2f1; display: flex; align-items: center; padding: 0 10px; border-bottom: 1px solid #d4d4d4; }
        .ribbon-divider { height: 30px; width: 1px; background: #ccc; margin: 0 10px; }
        .font-settings select { height: 20px; font-size: 11px; border: 1px solid #ccc; }
        .font-actions { margin-top: 2px; font-size: 12px; }
        .font-actions * { margin-right: 5px; cursor: pointer; padding: 0 2px;}
        .excel-formula-bar { display: flex; align-items: center; padding: 4px; background: white; }
        .name-box { width: 40px; border-right: 1px solid #ccc; text-align: center; font-size: 11px; color: #333; margin-right: 8px;}
        .fx { color: #ccc; font-weight: bold; margin-right: 8px; font-style: italic; }

        /* 公式栏 DIV 样式 (支持链接显示) */
        #formula-bar-content {
            width: 100%; height: 20px; line-height: 20px; outline: none;
            font-family: 'DengXian'; font-size: 11pt; color: #333;
            overflow: hidden; white-space: nowrap;
        }
        /* 面包屑链接样式 */
        #formula-bar-content a { color: #333; text-decoration: none; margin: 0 2px; }
        #formula-bar-content a:hover { text-decoration: underline; color: #217346; }
        #formula-bar-content em { color: #999; font-style: normal; margin: 0 2px; }
        /* 处理面包屑里的 nvhm 图标 */
        #formula-bar-content .nvhm {
            background: none !important; text-indent: 0 !important; width: auto !important;
            float: none !important; font-family: 'DengXian' !important;
        }

        .excel-col-headers { display: flex; background: #f3f2f1; border-bottom: 1px solid #d4d4d4; font-size: 11px; color: #666; text-align: center; height: 20px; line-height: 20px;}
        .excel-col-headers div { border-right: 1px solid #d4d4d4; }
        .row-idx-blank { width: 35px; background: #e6e6e6; }

        /* === 底部 Sheet 栏样式 === */
        #excel-sheet-bar-container { display: none; }
        body.excel-mode #excel-sheet-bar-container {
            display: flex; position: fixed; bottom: 22px; left: 0; width: 100%; height: 30px;
            background: #f3f2f1; border-top: 1px solid #d4d4d4; z-index: 10000; align-items: center; padding-left: 5px;
        }
        .sheet-nav-arrows span { color: #999; padding: 0 5px; cursor: pointer; font-size: 12px; }
        .sheet-nav-arrows span:hover { color: #333; }

        #excel-sheets-scroll {
            display: flex; overflow-x: auto; margin-left: 10px; scrollbar-width: none;
        }
        #excel-sheets-scroll::-webkit-scrollbar { display: none; }

        .sheet-tab {
            padding: 4px 15px; margin-right: 1px; font-size: 12px; cursor: pointer; white-space: nowrap;
            color: #000; text-decoration: none !important; border-right: 1px solid #d4d4d4;
        }
        .sheet-tab:hover { background: #e1e1e1; }
        .sheet-tab.active {
            background: #fff; color: #217346; font-weight: bold; border-bottom: 2px solid #fff; position: relative; top: 1px;
        }
        .sheet-add-btn { margin-left: 10px; color: #666; cursor: pointer; font-size: 16px; width: 20px; text-align: center;}

        /* 底部就绪状态栏 */
        #excel-footer-bar { display: none; }
        body.excel-mode #excel-footer-bar {
            display: block; position: fixed; bottom: 0; left: 0; width: 100%; height: 22px;
            background: #f3f2f1; border-top: 1px solid #d4d4d4; color: #666; font-size: 11px;
            line-height: 22px; padding-left: 10px; z-index: 10000;
        }
    `;
    GM_addStyle(css);

    // ==========================================
    // 3. JS 逻辑
    // ==========================================
    const btn = document.createElement('div');
    btn.id = 'excel-toggle-btn';
    btn.innerHTML = isWorkMode ? '退出摸鱼' : '摸鱼模式';
    btn.title = 'Ctrl+Shift+X 切换模式';
    btn.addEventListener('click', toggleMode);
    document.body.appendChild(btn);

    document.addEventListener('keydown', function(e) {
        if (e.ctrlKey && e.shiftKey && e.key.toUpperCase() === 'X') {
             e.preventDefault();
             toggleMode();
        }
    });

    if (isWorkMode) {
        enableExcel();
    }

    function toggleMode() {
        isWorkMode = !isWorkMode;
        localStorage.setItem('s1_excel_mode', isWorkMode);
        btn.innerHTML = isWorkMode ? '退出摸鱼' : '摸鱼模式';
        if (isWorkMode) enableExcel();
        else disableExcel();
    }

    function enableExcel() {
        document.body.classList.add('excel-mode');
        document.title = "Business_Report_2025.xlsx - Excel";

        forceLinksToSelf();
        initBreadcrumb(); // 初始化链接面包屑
        initSheetPagination(); // 初始化Sheet翻页
        updateFormulaBar();
    }

    function disableExcel() {
        document.body.classList.remove('excel-mode');
        document.title = "Stage1st";
    }

    function forceLinksToSelf() {
        const links = document.querySelectorAll('a.xst, a.s, #ct a[target="_blank"]');
        links.forEach(a => {
            if (a.target === '_blank') {
                a.removeAttribute('target');
                a.target = '_self';
            }
        });
    }

    // === 核心功能1:带链接的面包屑导航 ===
    function initBreadcrumb() {
        const pt = document.getElementById('pt');
        const formulaContent = document.getElementById('formula-bar-content');

        if (pt && formulaContent) {
            // 1. 克隆面包屑的 HTML
            const clone = pt.querySelector('.z').cloneNode(true);

            // 2. 清理多余元素
            // 移除图标前的空白和多余字符
            const homeLink = clone.querySelector('.nvhm');
            if(homeLink) {
                homeLink.innerText = "Stage1st"; // 恢复被图标隐藏的文字
            }

            // 3. 将清理后的 HTML 放入公式栏
            formulaContent.innerHTML = clone.innerHTML;

            // 4. 确保存储默认 HTML 供恢复使用
            formulaContent.dataset.defaultHtml = clone.innerHTML;

            // 5. 强制面包屑里的链接在当前窗口打开
            const links = formulaContent.querySelectorAll('a');
            links.forEach(a => a.target = "_self");
        }
    }

    // === 核心功能2:Sheet 翻页 ===
    function initSheetPagination() {
        const sheetContainer = document.getElementById('excel-sheets-scroll');
        sheetContainer.innerHTML = '';

        // 查找 S1 底部的翻页容器
        const s1Pager = document.querySelector('#fd_page_bottom .pg') || document.querySelector('.pgs .pg') || document.querySelector('.pg');

        if (s1Pager) {
            const elements = s1Pager.querySelectorAll('a, strong, label');

            elements.forEach(el => {
                if (el.tagName === 'LABEL') return;

                const sheetTab = document.createElement(el.tagName === 'A' ? 'a' : 'div');
                sheetTab.className = 'sheet-tab';

                let text = el.innerText;
                if (el.classList.contains('prev')) text = '◀ 上一页';
                if (el.classList.contains('nxt')) text = '下一页 ▶';
                if (text.includes('...')) text = '...';

                sheetTab.innerText = text;

                if (el.tagName === 'STRONG') {
                    sheetTab.classList.add('active');
                } else {
                    sheetTab.href = el.href;
                    sheetTab.target = '_self';
                }
                sheetContainer.appendChild(sheetTab);
            });
        } else {
            const sheet1 = document.createElement('div');
            sheet1.className = 'sheet-tab active';
            sheet1.innerText = 'Sheet1';
            sheetContainer.appendChild(sheet1);
        }
    }

    function updateFormulaBar() {
        const container = document.getElementById('formula-bar-content');

        // 鼠标移入单元格:显示纯文本内容
        document.addEventListener('mouseover', function(e) {
            if (!isWorkMode) return;
            let text = '';
            let target = e.target;

            if (target.tagName === 'A' && (target.closest('#threadlisttableid') || target.closest('.plhin'))) text = target.innerText;
            else if (target.tagName === 'TD' || target.tagName === 'TH') text = target.innerText;

            if (text && text.trim() !== "") {
                container.innerText = text.trim(); // 临时显示文本
            }
        });

        // 鼠标移出表格区域:恢复 HTML 面包屑链接
        document.addEventListener('mouseout', function(e) {
            if (!isWorkMode) return;

            // 如果鼠标移出了表格区域
            if (!e.relatedTarget || (!e.relatedTarget.closest('#threadlisttableid') && !e.relatedTarget.closest('.plhin'))) {
                const defaultHtml = container.dataset.defaultHtml;
                if (defaultHtml) {
                    container.innerHTML = defaultHtml; // 恢复 HTML 链接
                    // 重新绑定链接 target
                    container.querySelectorAll('a').forEach(a => a.target = "_self");
                }
            }
        });
    }
})();