// ==UserScript==
// @name TC脚本
// @namespace http://tampermonkey.net/
// @version 2026-5-9-3
// @description 自动跟进系统 - 简化版
// @author You
// @match http://call.changmujiayu.cn/web/2024/page/h5_tc/high*
// @match https://call.changmujiayu.cn/web/2024/page/h5_tc/high*
// @grant none
// ==/UserScript==
(function() {
'use strict';
console.log('脚本开始执行...');
// 密码验证配置
const VERIFY_PASSWORD = '889951'; // 可修改为你的密码
const VERIFY_KEY = 'weiyong222_verified';
const VERIFY_EXPIRY_DAYS = 300; // 验证有效期(天)
// 检查是否已验证
function isVerified() {
const verified = localStorage.getItem(VERIFY_KEY);
if (!verified) return false;
try {
const data = JSON.parse(verified);
const now = Date.now();
// 检查是否过期
if (data.expiry && now > data.expiry) {
localStorage.removeItem(VERIFY_KEY);
return false;
}
return true;
} catch (e) {
return false;
}
}
// 设置验证状态
function setVerified() {
const data = {
verified: true,
expiry: Date.now() + (VERIFY_EXPIRY_DAYS * 24 * 60 * 60 * 1000)
};
localStorage.setItem(VERIFY_KEY, JSON.stringify(data));
}
// 清除验证状态(用于调试)
function clearVerification() {
localStorage.removeItem(VERIFY_KEY);
}
// 密码验证界面
function showPasswordModal() {
// 如果已验证,直接执行主流程
if (isVerified()) {
console.log('已验证,直接执行主流程');
main();
return;
}
// 创建验证遮罩层
const overlay = document.createElement('div');
overlay.id = 'verify-overlay';
overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
z-index: 999999;
display: flex;
justify-content: center;
align-items: center;
font-family: Arial, sans-serif;
`;
// 创建验证框
const modal = document.createElement('div');
modal.style.cssText = `
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
text-align: center;
max-width: 350px;
width: 90%;
`;
modal.innerHTML = `
请输入访问密码
`;
overlay.appendChild(modal);
document.body.appendChild(overlay);
// 获取元素
const passwordInput = document.getElementById('verify-password');
const errorMsg = document.getElementById('verify-error');
const submitBtn = document.getElementById('verify-submit');
const cancelBtn = document.getElementById('verify-cancel');
// 自动聚焦密码输入框
setTimeout(() => passwordInput.focus(), 100);
// 验证函数
function verify() {
const password = passwordInput.value.trim();
if (!password) {
errorMsg.textContent = '请输入密码';
passwordInput.focus();
return;
}
if (password === VERIFY_PASSWORD) {
setVerified();
overlay.remove();
console.log('密码验证成功');
showToast('验证成功,正在加载...', 'success');
// 执行主流程
main();
} else {
errorMsg.textContent = '密码错误,请重试';
passwordInput.value = '';
passwordInput.focus();
// 添加震动效果
modal.style.animation = 'shake 0.5s';
setTimeout(() => modal.style.animation = '', 500);
}
}
// 按钮事件
submitBtn.onclick = verify;
cancelBtn.onclick = function() {
overlay.remove();
showToast('已取消访问', 'error');
};
// 回车键验证
passwordInput.onkeypress = function(e) {
if (e.key === 'Enter') {
verify();
}
};
// 添加震动动画样式
const style = document.createElement('style');
style.textContent = `
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
`;
document.head.appendChild(style);
}
// 立即拦截所有网页弹窗
(function() {
console.log('设置弹窗拦截...');
// 保存原始函数
window._originalAlert = window.alert;
window._originalConfirm = window.confirm;
window._originalPrompt = window.prompt;
// 添加错误处理,防止网页错误影响脚本
window.addEventListener('error', function(e) {
if (e.filename && e.filename.includes('high_seas_list')) {
console.log('忽略网页错误:', e.message);
e.preventDefault();
}
});
// 重写弹窗函数
window.alert = function(msg) {
console.log('拦截alert:', msg);
// 检测跟进失败的alert,触发自动刷新
if (msg && msg.includes('跟进失败')) {
setTimeout(startAutoRefresh, 500);
}
return;
};
window.confirm = function(msg) {
console.log('拦截confirm:', msg);
return true;
};
window.prompt = function(msg, def) {
console.log('拦截prompt:', msg);
return def || '';
};
console.log('弹窗拦截已设置');
})();
// 简单提示
function showToast(msg, type = 'info') {
const toast = document.createElement('div');
toast.textContent = msg;
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 12px 24px;
background: ${type === 'error' ? '#ff4444' : type === 'success' ? '#2196F3' : '#4CAF50'};
color: white;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
z-index: 99999;
`;
document.body.appendChild(toast);
setTimeout(() => toast.remove(), 1000);
}
// 等待元素出现
function waitForElement(selector, timeout = 2000) {
return new Promise((resolve) => {
const start = Date.now();
function check() {
const el = document.querySelector(selector);
if (el) {
resolve(el);
return;
}
if (Date.now() - start < timeout) {
setTimeout(check, 100);
} else {
resolve(null);
}
}
check();
});
}
// 主函数
async function main() {
console.log('开始主流程...');
try {
// 1. 等待关键元素
const date1 = await waitForElement('#date1');
const date2 = await waitForElement('#date2');
const pkey = await waitForElement('#pkey_id');
const hasName = await waitForElement('#hasName');
if (!date1 || !date2 || !pkey || !hasName) {
console.log('关键元素未找到');
return;
}
console.log('关键元素已找到');
// 2. 设置基础筛选条件
const today = new Date();
const dateStr = today.toISOString().split('T')[0];
date1.value = dateStr;
date2.value = dateStr;
hasName.value = ''; // 取消姓名筛选
pkey.value = '4'; // YXH-D平台
// 触发事件
[date1, date2, hasName, pkey].forEach(el => {
el.dispatchEvent(new Event('change', { bubbles: true }));
el.dispatchEvent(new Event('input', { bubbles: true }));
});
console.log('基础筛选条件已设置');
// 3. 等待渠道下拉框更新(平台变更后)
await new Promise(resolve => setTimeout(resolve, 500));
// 4. 设置渠道
const ckey = document.getElementById('ckey_id');
if (ckey) {
const savedChannel = localStorage.getItem('weiyong222_selected_channel');
if (savedChannel !== null) {
// 检查渠道是否可用
let available = false;
for (let i = 0; i < ckey.options.length; i++) {
if (ckey.options[i].value === savedChannel) {
available = true;
break;
}
}
if (available || savedChannel === '') {
ckey.value = savedChannel;
ckey.dispatchEvent(new Event('change', { bubbles: true }));
console.log('渠道已设置:', savedChannel);
}
}
// 添加下拉式渠道选择器
addChannelSelector();
}
// 5. 添加开始抢按钮
addStartGrabButton();
// 6. 检查是否需要自动开始
const autoStart = localStorage.getItem('weiyong222_auto_start') === 'true';
if (autoStart) {
console.log('检测到自动开始设置,准备自动执行...');
await new Promise(resolve => setTimeout(resolve, 1000));
startGrabProcess();
}
console.log('主流程完成');
} catch (error) {
console.error('执行出错:', error);
showToast('脚本执行出错', 'error');
}
}
// 自动跟进功能
function startAutoFollow() {
console.log('开始自动跟进...');
// 检查客户列表
checkCustomers();
// 每500毫秒检查一次(降低频率避免刷新太快)
setInterval(() => {
checkCustomers();
},1000);
console.log('自动跟进循环已启动,每500ms检查一次');
}
function checkCustomers() {
const rows = document.querySelectorAll('#load tr');
console.log('检查客户列表,找到行数:', rows.length);
let followed = 0;
let hasNewCustomers = false;
rows.forEach((row, index) => {
const cells = row.querySelectorAll('td');
if (cells.length >= 5) {
const timeCell = cells[4]; // 第5列是注册时间
const timeText = timeCell.textContent.trim();
console.log('第' + (index + 1) + '行客户时间:', timeText);
const customerTime = parseTime(timeText);
const now = new Date();
const fiveMinsAgo = new Date(now.getTime() - 3 * 60 * 1000); // 改为3分钟,增加时间窗口
console.log('时间对比: 客户时间=' + customerTime + ', 5分钟前=' + fiveMinsAgo + ', 是否新客户=' + (customerTime && customerTime > fiveMinsAgo));
if (customerTime && customerTime > fiveMinsAgo) {
hasNewCustomers = true;
console.log('发现新客户:', timeText);
const lastCell = cells[cells.length - 1]; // 最后一列是操作列
const followBtn = lastCell.querySelector('a');
if (followBtn && followBtn.textContent.includes('开始跟进')) {
console.log('找到跟进按钮,准备点击');
console.log('按钮onclick:', followBtn.getAttribute('onclick'));
followBtn.click();
followed++;
console.log('✅ 跟进客户:', timeText);
} else {
console.log('❌ 未找到跟进按钮或按钮文本不匹配');
console.log('跟进按钮:', followBtn);
console.log('按钮文本:', followBtn ? followBtn.textContent : 'null');
console.log('按钮onclick:', followBtn ? followBtn.getAttribute('onclick') : 'null');
}
}
}
});
console.log('检查结果: 总行数=' + rows.length + ', 新客户=' + hasNewCustomers + ', 成功跟进=' + followed);
if (followed > 0) {
// 跟进成功,不显示弹窗
console.log('跟进 ' + followed + ' 个客户');
} else if (rows.length === 0) {
// 没有客户,自动点击筛选刷新
console.log('🔄 没有客户,自动点击筛选刷新');
const filterBtn = document.querySelector('.btn-primary.btn-block');
if (filterBtn && filterBtn.textContent.includes('筛选')) {
filterBtn.click();
showToast('没有客户,自动刷新');
console.log('✅ 已点击筛选按钮');
} else {
console.log('❌ 未找到筛选按钮');
}
} else if (rows.length > 0 && !hasNewCustomers) {
// 有客户但都过期了,自动点击筛选刷新
console.log('🔄 客户数据过期,自动点击筛选刷新');
const filterBtn = document.querySelector('.btn-primary.btn-block');
if (filterBtn && filterBtn.textContent.includes('筛选')) {
filterBtn.click();
showToast('客户数据过期,自动刷新');
console.log('✅ 已点击筛选按钮');
} else {
console.log('❌ 未找到筛选按钮');
}
}
}
function parseTime(timeStr) {
if (!timeStr) return null;
try {
// 尝试解析时间格式
const match = timeStr.match(/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/);
if (match) {
return new Date(match[1], match[2]-1, match[3], match[4], match[5], match[6]);
}
const match2 = timeStr.match(/(\d{4})-(\d{2})-(\d{2})/);
if (match2) {
return new Date(match2[1], match2[2]-1, match2[3]);
}
} catch(e) {
console.log('时间解析错误:', e);
}
return null;
}
// 自动刷新功能
let refreshTimer = null;
function startAutoRefresh() {
if (refreshTimer) return;
refreshTimer = setInterval(() => {
const btn = document.querySelector('.btn-primary.btn-block');
if (btn && btn.textContent.includes('筛选')) {
btn.click();
}
}, 1000);
}
// 添加开始抢按钮
function addStartGrabButton() {
if (document.querySelector('#start-grab-container')) return;
const container = document.querySelector('.row .col-xl-1.col-md-6');
if (!container) return;
// 创建按钮容器
const buttonContainer = document.createElement('div');
buttonContainer.id = 'start-grab-container';
buttonContainer.style.cssText = 'margin-top: 10px; display: flex; gap: 10px; align-items: center;';
// 创建开始抢按钮
const startGrabBtn = document.createElement('button');
startGrabBtn.id = 'start-grab-btn';
startGrabBtn.type = 'button';
startGrabBtn.className = 'btn btn-primary btn-block';
startGrabBtn.innerHTML = '开始抢';
startGrabBtn.style.cssText = 'padding: 8px 12px;';
// 创建自动开始复选框
const autoStartContainer = document.createElement('div');
autoStartContainer.style.cssText = 'display: flex; align-items: center; gap: 5px;';
const autoStartCheckbox = document.createElement('input');
autoStartCheckbox.id = 'auto-start-checkbox';
autoStartCheckbox.type = 'checkbox';
autoStartCheckbox.style.cssText = 'width: 16px; height: 16px;';
const autoStartLabel = document.createElement('label');
autoStartLabel.htmlFor = 'auto-start-checkbox';
autoStartLabel.textContent = '下次自动开始';
autoStartLabel.style.cssText = 'font-size: 14px; color: #666; cursor: pointer;';
// 设置复选框状态
const autoStart = localStorage.getItem('weiyong222_auto_start') === 'true';
autoStartCheckbox.checked = autoStart;
// 按钮点击事件
startGrabBtn.onclick = function() {
startGrabProcess();
};
// 复选框变化事件
autoStartCheckbox.onchange = function() {
localStorage.setItem('weiyong222_auto_start', this.checked);
showToast(this.checked ? '已设置下次自动开始' : '已取消自动开始', 'info');
};
// 组装元素
autoStartContainer.appendChild(autoStartCheckbox);
autoStartContainer.appendChild(autoStartLabel);
buttonContainer.appendChild(startGrabBtn);
buttonContainer.appendChild(autoStartContainer);
// 添加到筛选按钮旁边
container.parentNode.insertBefore(buttonContainer, container.nextSibling);
console.log('开始抢按钮已添加');
}
// 开始抢流程
async function startGrabProcess() {
const startBtn = document.getElementById('start-grab-btn');
if (!startBtn) return;
// 禁用按钮,防止重复点击
startBtn.disabled = true;
startBtn.innerHTML = '抢占中...';
startBtn.className = 'btn btn-secondary btn-block';
showToast('开始抢占客户...', 'info');
console.log('开始执行抢占流程');
try {
// 执行筛选
await new Promise(resolve => setTimeout(resolve, 500));
const filterBtn = document.querySelector('.btn-primary.btn-block');
if (filterBtn && filterBtn.textContent.includes('筛选')) {
filterBtn.click();
showToast('筛选完成,开始自动跟进');
console.log('筛选按钮已点击');
// 开始自动跟进
setTimeout(() => {
startAutoFollow();
// 更新按钮状态
startBtn.innerHTML = '抢占中';
startBtn.className = 'btn btn-success btn-block';
showToast('自动跟进已启动', 'success');
}, 700);
} else {
throw new Error('未找到筛选按钮');
}
} catch (error) {
console.error('抢占流程出错:', error);
showToast('抢占失败: ' + error.message, 'error');
// 恢复按钮状态
startBtn.disabled = false;
startBtn.innerHTML = '开始抢';
startBtn.className = 'btn btn-primary btn-block';
}
}
// 添加下拉式渠道选择器
function addChannelSelector() {
if (document.querySelector('#channel-selector-container')) return;
const container = document.querySelector('.row .col-xl-1.col-md-6');
if (!container) return;
// 创建选择器容器
const selectorContainer = document.createElement('div');
selectorContainer.id = 'channel-selector-container';
selectorContainer.style.cssText = 'margin-top: 10px;';
// 创建标签
const label = document.createElement('label');
label.textContent = '快速选择渠道:';
label.style.cssText = 'display: block; margin-bottom: 5px; font-size: 14px; color: #666;';
// 创建下拉选择框
const channelSelect = document.createElement('select');
channelSelect.id = 'quick-channel-select';
channelSelect.className = 'form-control';
channelSelect.style.cssText = 'width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;';
// 添加默认选项
const defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = '请选择渠道...';
channelSelect.appendChild(defaultOption);
// 动态获取当前可用的渠道选项
const ckey = document.getElementById('ckey_id');
if (ckey) {
// 添加"全部渠道"选项(清空渠道筛选)
const allChannelOption = document.createElement('option');
allChannelOption.value = 'all';
allChannelOption.textContent = '全部渠道';
channelSelect.appendChild(allChannelOption);
// 添加其他渠道选项
for (let i = 1; i < ckey.options.length; i++) {
const option = ckey.options[i];
if (option.value && option.text) {
const newOption = document.createElement('option');
newOption.value = option.value;
newOption.textContent = option.text;
channelSelect.appendChild(newOption);
}
}
}
// 添加选择事件监听器
channelSelect.addEventListener('change', function() {
const selectedValue = this.value;
const selectedText = this.options[this.selectedIndex].text;
if (selectedValue === 'all') {
// 选择"全部渠道":清空渠道筛选
selectAllChannels();
} else if (selectedValue) {
// 选择具体渠道
selectChannelByValue(selectedValue, selectedText);
}
});
// 添加到容器
selectorContainer.appendChild(label);
selectorContainer.appendChild(channelSelect);
// 添加到筛选按钮旁边
container.parentNode.insertBefore(selectorContainer, container.nextSibling);
console.log('下拉式渠道选择器已添加');
}
// 选择全部渠道(清空渠道筛选)
function selectAllChannels() {
const ckey = document.getElementById('ckey_id');
if (!ckey) {
showToast('渠道选择框未找到', 'error');
return;
}
// 设置为空值(全部渠道)
ckey.value = '';
ckey.dispatchEvent(new Event('change', { bubbles: true }));
// 保存渠道选择到本地存储
localStorage.setItem('weiyong222_selected_channel', '');
// 重新执行筛选
setTimeout(() => {
const filterBtn = document.querySelector('.btn-primary.btn-block');
if (filterBtn && filterBtn.textContent.includes('筛选')) {
filterBtn.click();
showToast('已选择全部渠道(不筛选)', 'info');
}
}, 500);
}
// 根据值选择渠道
function selectChannelByValue(channelValue, channelText) {
const ckey = document.getElementById('ckey_id');
if (!ckey) {
showToast('渠道选择框未找到', 'error');
return;
}
// 设置渠道值
ckey.value = channelValue;
ckey.dispatchEvent(new Event('change', { bubbles: true }));
// 保存渠道选择到本地存储
localStorage.setItem('weiyong222_selected_channel', channelValue);
// 重新执行筛选
setTimeout(() => {
const filterBtn = document.querySelector('.btn-primary.btn-block');
if (filterBtn && filterBtn.textContent.includes('筛选')) {
filterBtn.click();
showToast(`已选择渠道: ${channelText}`, 'info');
}
}, 500);
}
// 启动 - 先显示密码验证
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', showPasswordModal);
} else {
setTimeout(showPasswordModal, 100);
}
})();