// ==UserScript==
// @name BOSS 直聘助手魔改中
// @namespace http://tampermonkey.net/
// @version 1.1
// @description (1)搜索页面增加按钮:只显示当前 HR 在线的职位。\n(2)职位详情页面增加浮窗显示:HR 是否最近活跃;是否接受应届生。
// @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;
// 创建置于最顶层的悬浮弹窗
function createFloatingPopup(text, textColor) {
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: 50px;
box-shadow: 0 5px 15px rgba(0,0,0,0.5);
z-index: 2147483647;
transition: opacity 0.3s ease-in-out;
}
#closePopup {
position: absolute;
top: 5px;
right: 20px;
cursor: pointer;
font-size: 1.5em;
font-weight: bold;
}
#closePopup:hover {
color: #ddd;
}
`;
var popupHTML = `
<div id="floatingPopup">
<span id="closePopup">X</span>
<div style="margin-top: 20px; font-size: 2.0em; color: ${textColor};">${text}</div>
</div>
`;
// 添加样式
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 = document.querySelector('div.job-boss-info span.boss-active-time');
let bossname = document.querySelector('div.job-boss-info h2.name');
let gtButton = document.querySelector('a.btn.btn-startchat');
let salaryText = document.querySelector('span.salary');
let bossInfoAttr = document.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.hideJobItem(nameText, salary, bossInfo);
window.localStorage.setItem('jobDetailInfo', JSON.stringify({ salary, bossInfo, nameText })); // 将信息存储到localStorage
window.localStorage.setItem('jobDetailProcessed', 'true'); // 标记数据已处理
} else if (gtButton) {
// 按钮是"立即沟通",我们需要监听它的变化
console.log('按钮是“立即沟通”');
console.log('window.localStorage',window.localStorage)
const observer = new MutationObserver(() => {
if (gtButton.textContent.trim() === "继续沟通") {
console.log('检测到继续沟通2,执行存储职位信息');
//window.hideJobItem(salary, bossInfo, nameText);
window.localStorage.setItem('jobDetailInfo', JSON.stringify({ salary, bossInfo, nameText })); // 将信息存储到localStorage
window.localStorage.setItem('jobDetailProcessed', 'true'); // 标记数据已处理
}
});
// 监听按钮文本的变化
observer.observe(gtButton, {
childList: true,
subtree: true,
});
}
// ======== 是否接受应届生 ========
let jobName = document.querySelector('div.info-primary > div.name');
if (jobName) {
let jobNameText = jobName.textContent;
let regex = /应届.*生?/;
if (regex.test(jobNameText)) {
createFloatingPopup("接受应届生", "green");
return;
}
}
let jobDetail = document.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');
console.log('jobDetailProcessed',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;
window.hideJobItem(salary, bossInfo, nameText);
console.log('czlistItems');
}
}*/
//}
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');
// 添加点击事件监听器
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 = ['即时配送','培训/辅导机构','文化艺术/娱乐','人力资源服务','物流/仓储']//行业
const skills = ['其他平台','聊天','娱乐','客服','快手']//标签下简介
// 遍历每个 <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)
const skillss = job.skills
console.log('skillss',skillss)
// 获取当前元素的样式
let style = window.getComputedStyle(item);
// 如果没有找到 boss-online-tag 并且元素是可见的,则隐藏该 <li> 元素
// 如果元素是隐藏的,则显示它
if ((skills.some(skill => skillss.some(skillssItem => skillssItem.includes(skill))) || 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 });
/*
function startLoop() {
setTimeout(function loop() {
console.log("这是每隔一秒输出一次的消息");
console.log("document",document);
// 从localStorage获取职位信息
const jobDetailProcessed = window.localStorage.getItem('jobDetailProcessed');
console.log('jobDetailProcessed',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;
window.hideJobItem(salary, bossInfo, nameText);
console.log('czlistItems');
}
}
// 这里可以放你需要定时执行的任务
// 再次调用 setTimeout 来形成递归循环
setTimeout(loop, 1000); // 1000 毫秒,即 1 秒
}, 1000);
}*/
function startLoop() {
let isRunning = true;
// 使用 setInterval 来替代 setTimeout 避免递归堆积
const intervalId = setInterval(() => {
if (!isRunning) {
clearInterval(intervalId); // 停止循环
console.log("循环已停止");
return; // 退出循环
}
//console.log("这是每隔一秒输出一次的消息");
//console.log("document", document);
// 从 localStorage 获取职位信息
const jobDetailProcessed = window.localStorage.getItem('jobDetailProcessed');
//console.log('jobDetailProcessed', jobDetailProcessed);
if (jobDetailProcessed === 'true') {
console.log('jobDetailProcessed');
// 使用 try-catch 捕获 JSON.parse 错误
try {
let jobDetailInfo = JSON.parse(window.localStorage.getItem('jobDetailInfo'));
console.log('jobDetailInfo', jobDetailInfo);
if (jobDetailInfo) {
// 提取相关的职位信息
let { salary, bossInfo, nameText } = jobDetailInfo;
const jobListItems = document.querySelectorAll('ul.job-list-box > li');
let foundMatch = false; // 标记是否找到匹配的职位项
jobListItems.forEach(function(item) {
const itemText = item.textContent;
const matchesName = nameText === '' || itemText.includes(nameText);
const matchesSalary = salary === '' || itemText.includes(salary);
const matchesBossInfo = bossInfo === '' || itemText.includes(bossInfo);
// 检查职位项中是否包含相应的名称、薪资和老板信息
if (matchesName && matchesSalary && matchesBossInfo) {
item.style.display = 'none';
console.log(`在列表页隐藏职位项: ${nameText}`);
foundMatch = true; // 找到匹配的职位项
window.localStorage.removeItem('jobDetailInfo'); // 删除 jobDetailInfo
window.localStorage.removeItem('jobDetailProcessed'); // 删除 jobDetailProcessed
}
});
// 如果没有找到任何匹配的职位项,清除 localStorage 中的 jobDetailInfo 和 jobDetailProcessed
if (!foundMatch) {
window.localStorage.removeItem('jobDetailInfo');
window.localStorage.removeItem('jobDetailProcessed');
console.log('没有找到匹配的职位项,已清除 localStorage 中的 jobDetailInfo 和 jobDetailProcessed');
}
}
} catch (e) {
console.error('解析 jobDetailInfo 时发生错误:', e);
isRunning = false; // 错误发生时停止循环
clearInterval(intervalId); // 清除定时器
console.log('循环已停止,因发生错误');
}
}
// 这里可以放你需要定时执行的任务
}, 1000); // 1000 毫秒,即 1 秒
}
startLoop();
}
// 确保页面完全加载后再执行逻辑
//window.onload = function () {
let currentUrl = window.location.href;
console.log('currentUrl',currentUrl)
if (currentUrl.includes("/job_detail/")) {
runJobDetail();
} else if (currentUrl.includes("/geek/job")) {
console.log('jrzys')
const observer = new MutationObserver(() => {
// 确保 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');
//console.log('document2',document2)
runGeekJob();
observer.disconnect(); // 断开观察,避免重复触发
//};
//});
//};
});
// 配置 MutationObserver 来观察 DOM 变化
observer.observe(document.body, {
childList: true,
subtree: true
});
//runGeekJob();
}
//}
})();