Greasy Fork

BOSS 直聘助手魔改中

(1)搜索页面增加按钮:只显示当前 HR 在线的职位。(2)职位详情页面增加浮窗显示:HR 是否最近活跃;是否接受应届生。以下是新增功能 还在完善中 1 改进了去世相关的 2 可以隐藏职业跟行业 我用了其他人搞的好多都会封号我就魔改了下不会封号版本的 自用中

目前为 2025-01-04 提交的版本。查看 最新版本

// ==UserScript==
// @name         BOSS 直聘助手魔改中
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  (1)搜索页面增加按钮:只显示当前 HR 在线的职位。(2)职位详情页面增加浮窗显示:HR 是否最近活跃;是否接受应届生。以下是新增功能  还在完善中 1 改进了去世相关的  2 可以隐藏职业跟行业  我用了其他人搞的好多都会封号我就魔改了下不会封号版本的  自用中
// @author       Rostal
// @license      MIT
// @icon         https://www.zhipin.com/favicon.ico
// @match        https://www.zhipin.com/job_detail/*
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';
    let document1, document2;
    let listPageDocument = null;



    // 创建置于最顶层的悬浮弹窗
    function createFloatingPopup(text, textColor) {
        var iframe = document.createElement('iframe');
        iframe.style.position = 'fixed';
        iframe.style.top = '10px';
        iframe.style.left = '50%';
        iframe.style.transform = 'translateX(-50%)';
        iframe.style.width = '80%';
        iframe.style.height = 'auto';
        iframe.style.backgroundColor = 'transparent'; // 透明背景
        iframe.style.border = 'none';
        iframe.style.zIndex = '2147483647'; // 保证弹窗在最上层
        iframe.style.boxShadow = '0 5px 15px rgba(0,0,0,0.5)';
        iframe.style.borderRadius = '10px';
        //iframe.sandbox = 'allow-same-origin'; // 添加 sandbox 属性
        // 将 iframe 添加到页面中
        //document.body.appendChild(iframe);
        /*
        var style = `
                #floatingPopup {
                    position: fixed;
                    top: 10px;
                    left: 50%;
                    transform: translateX(-50%);
                    width: 80%;
                    background: rgba(0, 0, 0, 0.9);
                    color: white;
                    padding: 20px;
                    box-sizing: border-box;
                    text-align: center;
                    border-radius: 10px;
                    box-shadow: 0 5px 15px rgba(0,0,0,0.5);
                    z-index: 2147483647;
                    transition: opacity 0.3s ease-in-out;
                    filter: grayscale(0%) !important;
                }
                #floatingPopup div {
            filter: none; /* 取消文本的灰色滤镜 */
        //  color: ${textColor}!important; /* 文本颜色 */
        /* }
                #closePopup {
                    position: absolute;
                    top: 5px;
                    right: 10px;
                    cursor: pointer;
                    font-size: 1.5em;
                    font-weight: bold;
                }
                #closePopup:hover {
                    color: #ddd;
                }
            `;*/
        const randomParam = Math.random();
        let iframeSrcdoc = `
        <html>
            <head>
             </head>
            <body>
                <span id="closePopup">X</span>
                <div id="popupContent">
                    ${text}
                </div>
                <script>
                    document.getElementById('closePopup').addEventListener('click', function() {
                        parent.document.body.removeChild(document.getElementById('iframePopup'));
                    });
                </script>
            </body>
        </html>
    `;
        iframe.srcdoc = `${iframeSrcdoc}?${randomParam}`;

        //iframe.srcdoc = iframeSrcdoc;
        document.body.appendChild(iframe);
        iframe.onload = function() {
            const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
            if (iframeDocument) {
                const style = document.createElement('style');
                style.textContent = `
                    html, body {
                            background-color: rgba(0, 0, 0, 0.9);
                            font-family: Arial, sans-serif;
                         }
                        body {
                           color: ${textColor};
                           fill: ${textColor};
                        }
                        #closePopup {
                            position: absolute;
                            top: 5px;
                            right: 10px;
                            cursor: pointer;
                            font-size: 1.5em;
                            font-weight: bold;
                            background: rgba(0, 0, 0, 0.6);
                            border-radius: 50%;
                            width: 30px;
                            height: 30px;
                            text-align: center;
                            color: white;
                            display: flex;
                            justify-content: center;
                            align-items: center;
                            transition: background 0.3s;
                        }
                        #closePopup:hover {
                           background: rgba(0, 0, 0, 0.8);
                        }
                        #popupContent {
                            margin-top: 30px;
                            font-size: 2em;
                            font-weight: bold;
                            padding: 10px;
                            color: ${textColor};
                            fill: ${textColor};
                        }
                   `;
           iframeDocument.head.appendChild(style);
       }
        };
        /*
        iframe.onload = function() {
            const setIframeStyles = () => {
                try {
                      const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;

                      if(iframeDocument && iframeDocument.body){
                         const body = iframeDocument.body;
                            body.style.color = `${textColor} !important`;
                              const popupContent = iframeDocument.getElementById('popupContent');
                              if(popupContent){
                                popupContent.style.color = `${textColor} !important`;
                             }
                       } else {
                          requestAnimationFrame(setIframeStyles);
                       }
                } catch (e) {
                    console.error('Failed to apply styles to iframe:', e);
                }
            };
       requestAnimationFrame(setIframeStyles);
    };*/
        // iframe 内的内容,使用 srcdoc 来定义 HTML 内容
        //iframe.srcdoc = iframeSrcdoc;
        // 给 iframe 添加 ID 方便关闭时引用
        iframe.id = 'iframePopup';
        // 将 iframe 添加到页面中
        //document.body.appendChild(iframe);
        /*
        iframe.onload = function() {
       // 创建独立的样式表
        const style = document.createElement('style');
         style.textContent = `
             body {
               font-family: Arial, sans-serif;
                        margin: 0;
                        padding: 0;
                        background-color: rgba(0, 0, 0, 0.9);
                        color: ${textColor} !important; /* 明确设置文字颜色为红色 */
        /*       text-align: center;
                        overflow: hidden;
                    }
           #closePopup {
                        position: absolute;
                        top: 5px;
                        right: 10px;
                        cursor: pointer;
                        font-size: 1.5em;
                        font-weight: bold;
                        background: rgba(0, 0, 0, 0.6);
                        border-radius: 50%;
                        width: 30px;
                        height: 30px;
                        text-align: center;
                        color: white;
                        display: flex;
                        justify-content: center;
                        align-items: center;
                        transition: background 0.3s;
                    }
                    #closePopup:hover {
                        background: rgba(0, 0, 0, 0.8);
                    }
                    #popupContent {
                        margin-top: 30px;
                        font-size: 2.0em;
                        padding: 10px;
                    }
        `;
            // 使用 DOMParser 解析 srcdoc
            /*
        const parser = new DOMParser();
        const doc = parser.parseFromString(iframeSrcdoc, 'text/html');
        const head = doc.querySelector('head');
       head.appendChild(style);
        iframe.srcdoc = doc.documentElement.outerHTML
        */
    };


    /*iframe.srcdoc = `
                <div id="floatingPopup">
            <span id="closePopup">X</span>
            <div style="margin-top: 20px; font-size: 2.0em;">${text}</div>
        </div>
            `;*/
    // 给 iframe 添加 ID 方便关闭时引用
    /*iframe.id = 'iframePopup';
         // 将 iframe 添加到页面中
    document.body.appendChild(iframe);
        // 在父页面中取消滤镜影响
        setTimeout(() => { // 使用 setTimeout 确保 iframe 已经插入 DOM
        const popups = document.querySelectorAll('iframe');
        popups.forEach(popup => {
            popup.style.filter = 'invert(100%)'; // 使用 invert 反转滤镜
        });
        }, 0)
/*
        // 添加样式
        var styleElement = document.createElement('style');
        styleElement.type = 'text/css';
        styleElement.innerHTML = style;
        document.head.appendChild(styleElement);
*/
    // 将弹窗添加到页面中
    //document.body.insertAdjacentHTML('afterbegin', popupHTML);
    /*
        // 关闭弹窗的事件处理
        document.getElementById('closePopup').addEventListener('click', function () {
            var popup = document.getElementById('floatingPopup');
            popup.style.opacity = '0';
            setTimeout(function () {
                popup.style.display = 'none';
            }, 300);
        });*/

    function createGrayOverlay() {
        // 创建一个全屏的灰色遮罩层
        let overlay = document.createElement('div');
        overlay.id = 'grayOverlay';
        overlay.style.position = 'fixed';
        overlay.style.top = '0';
        overlay.style.left = '0';
        overlay.style.width = '100vw';
        overlay.style.height = '100vh';
        overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
        overlay.style.zIndex = '9999';
        overlay.style.display = 'none';
        document.body.appendChild(overlay);
        return overlay;
    }
    function showGrayOverlay() {
        let overlay = document.getElementById('grayOverlay');
        if (!overlay) {
            overlay = createGrayOverlay();
        }
        overlay.style.display = 'block';
    }
    function enableGrayMode() {
        // 获取 body 或 html 元素
        let body = document.body;
        let overlay = document.createElement('div');
        // 设置全局样式,应用灰色滤镜,并禁用页面交互(如果需要)
        body.style.filter = 'grayscale(100%)';
        body.style.pointerEvents = 'none'; // 禁用交互,如果需要
        /*
        let popups = document.querySelectorAll('iframe');
        popups.forEach(popup => {
        popup.style.filter = 'none'; // 取消弹窗的灰色滤镜
        popup.style.pointerEvents = 'auto'; // 重新启用弹窗的交互
    });*/
    }


    function runJobDetail() {
        console.log('jrxq');
        // ======== HR 是否最近活跃 ========

        let hrDeadTexts = ["在线", "刚刚活跃", "今日活跃"];
        let bossActiveTime = document1.querySelector('div.job-boss-info span.boss-active-time');
        let bossname = document1.querySelector('div.job-boss-info h2.name');
        let gtButton = document1.querySelector('a.btn.btn-startchat');
        let salaryText = document1.querySelector('span.salary');
        let bossInfoAttr = document1.querySelector('div.boss-info-attr');
        let salary = salaryText ? salaryText.textContent.trim() : '';
        let bossInfo = bossInfoAttr ? bossInfoAttr.textContent.trim().split('·')[0] : '';
        let nameText = bossname ? bossname.textContent.trim().split(' ')[0].split('\n')[0] : null;
        if (bossActiveTime) {
            let bossActiveTimeText = bossActiveTime.textContent;
            if (!hrDeadTexts.includes(bossActiveTimeText)) {
                enableGrayMode();
                createFloatingPopup("SB"+nameText+"已去世| 请允许我们在此献上最后的告别,以纪念其在Boss直聘中留下的足迹与回忆🕯🕯🕯", "red");
                return;
            }
        }
        // 如果按钮是“继续沟通”,就存储职位信息
        if (gtButton && gtButton.textContent.trim() === "继续沟通") {
            console.log('检测到继续沟通1,执行存储职位信息');
            window.localStorage.setItem('jobDetailInfo', JSON.stringify({ salary, bossInfo, nameText })); // 将信息存储到localStorage
            window.localStorage.setItem('jobDetailProcessed', 'true'); // 标记数据已处理
            console.log('localStorage',localStorage)
            runGeekJob()
            //window.location.href = '/geek/job'; // 跳转到列表页面
        } else if (gtButton) {
            // 按钮是"立即沟通",我们需要监听它的变化
            console.log('按钮是“立即沟通”');
            console.log('window.localStorage',window.localStorage)
            const observer = new MutationObserver(() => {
                if (gtButton.textContent.trim() === "继续沟通") {
                    console.log('检测到继续沟通2,执行存储职位信息');
                    window.localStorage.setItem('jobDetailInfo', JSON.stringify({ salary, bossInfo, nameText })); // 将信息存储到localStorage
                    window.localStorage.setItem('jobDetailProcessed', 'true'); // 标记数据已处理
                    //window.location.href = '/geek/job'; // 跳转到列表页面
                    runGeekJob()
                }
            });
            // 监听按钮文本的变化
            observer.observe(gtButton, {
                childList: true,
                subtree: true,
            });
        }
        // ======== 是否接受应届生 ========

        let jobName = document1.querySelector('div.info-primary > div.name');
        if (jobName) {
            let jobNameText = jobName.textContent;

            let regex = /应届.*生?/;
            if (regex.test(jobNameText)) {
                createFloatingPopup("接受应届生", "green");
                return;
            }
        }

        let jobDetail = document1.querySelector('div.job-detail div.job-sec-text');
        if (jobDetail) {
            let jobDetailText = jobDetail.textContent;

            let regex = /接受.*应届.*生/;
            let regex2 = /应届.*生.*可/;
            let regex3 = /欢迎.*应届.*生/;
            let regex4 = /应届.*生.*优先/;
            if (regex.test(jobDetailText) || regex2.test(jobDetailText) || regex3.test(jobDetailText) || regex4.test(jobDetailText)) {
                createFloatingPopup("接受应届生", "green");
                return;
            }
        }
    }
    function onlineFilter() {
        console.log('1. bfEle 不存在,执行添加');
        const bfEle = document.querySelector('.__boss_filter.condition-filter-select');
        if (bfEle) {
            console.log('1. bfEle 已经存在');
            // 先移除选中样式
            bfEle.classList.remove('is-select');
        } else {
            // 不存在则创建并添加到DOM树中
            try {
                runGeekJob();
            } catch (error) {
                console.log('新增筛选出错', error);
            }
        }
    }


    function runGeekJob() {
        console.log('dyrunGeekJob')
        // 保存原始的 XMLHttpRequest
        const originalXHR = XMLHttpRequest;

        // 重写 XMLHttpRequest 构造函数
        XMLHttpRequest = function() {
            const xhr = new originalXHR();

            // 重写 open 方法
            const originalOpen = xhr.open;
            xhr.open = function(method, url) {
                //console.log('捕获到请求 URL:', url); // 输出请求的 URL
                if (url.includes('joblist.json')) {
                    //console.log('捕获到 joblist.json 请求:', url);
                }
                return originalOpen.apply(this, arguments);  // 调用原始的 open 方法
            };
            // 重写 send 方法
            const originalSend = xhr.send;
            xhr.send = function(data) {
                // 在请求完成时处理响应
                xhr.onload = function() {
                    if (xhr.status === 200) {
                        try {
                            // 确保响应类型是 JSON 格式
                            const data = JSON.parse(xhr.responseText);
                            //console.log('解析后的数据:', data);

                            if (data.zpData && data.zpData.jobList) {
                                const jobList = data.zpData.jobList;
                                jobList.forEach((job, index) => {
                                    //console.log('job',job)
                                    //console.log('职位名称:', job.jobName);
                                    //console.log('公司名称:', job.brandName);
                                    //console.log('bossName',job.bossName)
                                    //console.log('ProxyJob:', job.proxyJob); // 若该字段存在
                                    //console.log('ProxyType:', job.proxyType); // 若该字段
                                    window.localStorage.setItem('jobListData', JSON.stringify(data.zpData.jobList));
                                });
                            }
                        } catch (e) {
                            console.error('解析 joblist.json 响应出错:', e);
                        }
                    } else {
                        console.error('请求失败,状态码:', xhr.status);
                    }
                };
                return originalSend.apply(this, arguments); // 调用原始的 send 方法
            }

            return xhr;
        };
        // 从localStorage获取职位信息
        /*  const jobDetailProcessed = window.localStorage.getItem('jobDetailProcessed');
        if (jobDetailProcessed === 'true') {
            console.log('jobDetailProcessed')
            //try {
            let jobDetailInfo = JSON.parse(window.localStorage.getItem('jobDetailInfo'));
            console.log('jobDetailInfo',jobDetailInfo)
            if (jobDetailInfo) {
                // 提取相关的职位信息
                let { salary, bossInfo, nameText } = jobDetailInfo;
                console.log('czlistItems');
                console.log('document',document);
                console.log('document.querySelectorAll',document.querySelectorAll);
                console.log('window.onload',document.referrer)
                //window.onload = function() {
        const savedLIState = JSON.parse(localStorage.getItem('liState'));
                console.log('savedLIState',savedLIState)
                console.log('savedLIState.length',savedLIState.length)
                    if (savedLIState && savedLIState.length > 0) {
                        console.log('jrpd',window.opener.document)
            savedLIState.forEach(savedState => {
                const li = window.opener.document.querySelectorAll('li')[savedState.index];
                if (li) {
                    li.style.display = 'none'; // 修改原页面的 <li> 元素
                }
            });
                let listItems = document.querySelectorAll('ul.job-list-box > li');
                //console.log('listItems',listItems);
                listItems.forEach(function (item) {
                    let itemSalary = item.querySelector('span.salary') ? item.querySelector('span.salary').textContent.trim() : '';
                    let itemBossInfo = item.querySelector('div.boss-info-attr') ? item.querySelector('div.boss-info-attr').textContent.trim() : '';
                    let itemName = item.querySelector('h2.name') ? item.querySelector('h2.name').textContent.trim().split(' ')[0] : '';
                    // 比对 salary、bossInfo 和 name,如果都相同,则隐藏该职位项
                    if (itemSalary === salary && itemBossInfo === bossInfo && itemName === nameText) {
                        console.log('找到匹配项,隐藏该职位');
                        item.style.display = 'none';
                        // 强制浏览器重新渲染,确保隐藏生效
                                  //item.offsetHeight; // 调用强制重排的方法
                    }
                });
            //}
                }
            }
        } */
        /*}catch (error) {
    // 捕获错误时,打印错误并跳过
    console.error('Error parsing jobDetailInfo from localStorage:', error);
}*/
        console.log('2. bfEle 不存在,执行添加');
        // 创建按钮元素
        let button = document.createElement('div');
        button.innerHTML = `<div class="current-select">
    <span class="placeholder-text">浪费时间GUN</span>
</div>`;
        button.classList.add('condition-filter-select', '__boss_filter');
        //let button = document.createElement('button');
        //button.innerHTML = '隐藏浪费时间货色'; // 设置按钮显示的文本
        //button.style.position = 'fixed'; // 设置按钮位置为固定
        //button.style.left = '0'; // 将按钮放置在页面的最左侧
        //button.style.top = '50%'; // 将按钮垂直居中
        //button.style.transform = 'translateY(-50%)'; // 垂直居中的偏移量
        //button.style.zIndex = '2147483647'; // 设置按钮的z-index为最大值,确保其在最高层级
        //button.style.padding = '10px'; // 设置按钮的内边距
        //button.style.cursor = 'pointer'; // 设置鼠标悬停时的光标样式
        // button.style.fontSize = '12px'; // 设置按钮字体大小

        // 添加点击事件监听器
        button.addEventListener('click', function () {
            // 获取所有的 <li> 元素
            let listItems = document.querySelectorAll('ul.job-list-box > li');
            const jobListData = JSON.parse(window.localStorage.getItem('jobListData')) || [];
            const keywords = ['主播', '直播', '不露脸','打字聊天','老师','讲师','教师'];
            const brandIndustrykey = ['即时配送','培训/辅导机构']

            // 遍历每个 <li> 元素
            listItems.forEach(function (item, index) {
                let bossOnlineTag = item.querySelector('span.boss-online-tag');
                console.log('bossOnlineTag',bossOnlineTag);
                let dz = item.querySelector('img.job-tag-icon');
                console.log('dz',dz);
                let jobname = item.querySelector('span.job-name').firstChild.textContent.trim();
                console.log('jobname',jobname);
                const bossname = item.querySelector('div.info-public').firstChild.textContent.trim();
                console.log('bossname',bossname);
                console.log('jobListDataxbossname',jobListData[index].bossName);
                const job = jobListData[index];
                console.log('job',job)
                const brandIndustry = job.brandIndustry
                console.log('brandIndustry',brandIndustry)
                // 获取当前元素的样式
                let style = window.getComputedStyle(item);
                const jobname1 = "需要一位程序员";
                const brandIndustry1 = "软件开发,互联网";

                // 如果没有找到 boss-online-tag 并且元素是可见的,则隐藏该 <li> 元素
                // 如果元素是隐藏的,则显示它
                console.log('keyword',keywords.some(keyword => jobname1.includes(keyword)));
                console.log('bossOnlineTag',!bossOnlineTag);
                console.log('dz',dz);
                console.log('job.proxyJob',job.proxyJob === 1);
                console.log('brandIndustryItem',brandIndustrykey.some(brandIndustryItem => brandIndustry1.includes(brandIndustryItem)));
                if ((brandIndustrykey.some(brandIndustryItem => brandIndustry.includes(brandIndustryItem)) || keywords.some(keyword => jobname.includes(keyword)) || !bossOnlineTag || dz || job.proxyJob === 1) && style.display !== 'none') {
                    item.style.display = 'none';
                } else if (style.display === 'none') {
                    item.style.display = ''; // 使用空字符串将元素的display属性恢复到默认值
                }
            });
        });

        // 将按钮添加到页面中
        document.body.appendChild(button);
        // 插入到父元素 .search-condition-wrapper 最后一个元素之前
        const observer = new MutationObserver(function(mutationsList, observer) {
            let parentNode = document.querySelector('.search-condition-wrapper');
            console.log('parentNode',parentNode)
            if (parentNode !== null) {
                let lastChild = parentNode.lastChild;
                parentNode.insertBefore(button, lastChild);
                observer.disconnect();
            } else {
                console.log('3. parentNode 不存在,无法插入filter');
            }
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }
    // 确保页面完全加载后再执行逻辑
    //window.onload = function () {
    let currentUrl = window.location.href;
    console.log('currentUrl',currentUrl)
    if (currentUrl.includes("/job_detail/")) {
        document1 = document;
        //console.log('document1',document1)
        runJobDetail();
    } else if (currentUrl.includes("/geek/job")) {
        console.log('jrzys')
        const observer = new MutationObserver(() => {
            document2 = document
            // 确保 DOM 加载完毕再执行 runGeekJob
            //console.log('12. bfEle 不存在,执行添加');
            //console.log('document',document.querySelector);
            //if (document.querySelector('ul.job-list-box')) {
            //console.log('23. bfEle 不存在,执行添加');
            //window.addEventListener('storage', function (event) {
            //if (event.key === 'jobDetailProcessed' && event.newValue === 'true') {
            console.log('jrzy');
            const liElements = document.querySelectorAll('li');
            const liState = [];

            liElements.forEach((li, index) => {
                liState.push({
                    index: index,
                    id: li.id,
                    style: li.style.display // 保存 display 样式
                });
            });

            // 使用 localStorage 保存状态
            localStorage.setItem('liState', JSON.stringify(liState));
            //console.log('document2',document2)
            runGeekJob();
            observer.disconnect(); // 断开观察,避免重复触发
            //};
            //});
            //};
        });
        // 配置 MutationObserver 来观察 DOM 变化
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
        //runGeekJob();
    }
    //}
})();