2 Commits
V1.2 ... v1.3.1

Author SHA1 Message Date
78c67cd097 update:更新海豚实验室域名 2025-05-20 14:49:30 +08:00
a3032692b2 fix:修复了部分bug 2025-03-27 18:38:10 +08:00

View File

@@ -1,400 +1,432 @@
// ==UserScript== // ==UserScript==
// @name 海豚自动化工具 // @name 海豚自动化工具
// @namespace http://tampermonkey.net/ // @namespace http://tampermonkey.net/
// @version 1.2 // @version 1.3
// @description 自动从代码块复制内容到编辑器,保存并重启笔记本 // @description 自动从代码块复制内容到编辑器,保存并重启笔记本
// @author Kakune55 Carryc // @author Kakune55 Carryc
// @match https://labs.wd.dolphin-labs.com/data-analysis/* // @match https://labs.wd.dolphin-labs.com/data-analysis/*
// @grant none // @match https://labs.wd.dilabs.cn/data-analysis/*
// @run-at document-end // @grant none
// ==/UserScript== // @run-at document-idle
(function() { // ==/UserScript==
'use strict';
(function() {
// 通知管理器 - 管理多个通知的位置 'use strict';
const NotificationManager = {
notifications: [], // 通知管理器 - 管理多个通知的位置
baseTop: 70, // 初始顶部位置 const NotificationManager = {
gap: 10, // 通知间距 notifications: [],
add: function(element) { baseTop: 45, // 初始顶部位置
let topPosition = this.baseTop; gap: 10, // 通知间距
this.notifications.forEach(notification => { add: function(element) {
if (notification.isConnected) { let topPosition = this.baseTop;
const height = notification.offsetHeight; this.notifications.forEach(notification => {
topPosition += height + this.gap; if (notification.isConnected) {
} const height = notification.offsetHeight;
}); topPosition += height + this.gap;
this.notifications = this.notifications.filter(n => n.isConnected); }
element.style.top = topPosition + 'px'; });
this.notifications.push(element); this.notifications = this.notifications.filter(n => n.isConnected);
return element; element.style.top = topPosition + 'px';
}, this.notifications.push(element);
remove: function(element) { return element;
const index = this.notifications.indexOf(element); },
if (index > -1) { remove: function(element) {
this.notifications.splice(index, 1); const index = this.notifications.indexOf(element);
} if (index > -1) {
this.updatePositions(); this.notifications.splice(index, 1);
}, }
updatePositions: function() { this.updatePositions();
let topPosition = this.baseTop; },
this.notifications.forEach(notification => { updatePositions: function() {
if (notification.isConnected) { let topPosition = this.baseTop;
notification.style.top = topPosition + 'px'; this.notifications.forEach(notification => {
topPosition += notification.offsetHeight + this.gap; if (notification.isConnected) {
} notification.style.top = topPosition + 'px';
}); topPosition += notification.offsetHeight + this.gap;
} }
}; });
}
// 添加样式到页面 };
function addStyles() {
const styleSheet = document.createElement('style'); // 添加样式到页面
styleSheet.textContent = ` function addStyles() {
@keyframes slideInRight { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } const styleSheet = document.createElement('style');
@keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } styleSheet.textContent = `
@keyframes fadeIn { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } } @keyframes slideInRight { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes fadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } }
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @keyframes fadeIn { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } }
@keyframes ripple { to { transform: scale(3); opacity: 0; } } @keyframes fadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } }
#dolphin-auto-btn { animation: slideInRight 0.5s ease-out; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.dolphin-notification { animation: fadeIn 0.3s ease-out; display: flex; align-items: center; border-left: 4px solid; } @keyframes ripple { to { transform: scale(3); opacity: 0; } }
.dolphin-notification.hiding { animation: fadeOut 0.5s ease-in forwards; } #dolphin-auto-btn { animation: slideInRight 0.5s ease-out; }
.notification-icon { margin-right: 12px; font-size: 20px; } .dolphin-notification { animation: fadeIn 0.3s ease-out; display: flex; align-items: center; border-left: 4px solid; }
.loader { display: inline-block; width: 15px; height: 15px; border: 2px solid rgba(255,255,255,0.3); border-radius: 50%; border-top-color: #fff; animation: spin 0.8s linear infinite; margin-right: 8px; } .dolphin-notification.hiding { animation: fadeOut 0.5s ease-in forwards; }
`; .notification-icon { margin-right: 12px; font-size: 20px; }
document.head.appendChild(styleSheet); .loader { display: inline-block; width: 15px; height: 15px; border: 2px solid rgba(255,255,255,0.3); border-radius: 50%; border-top-color: #fff; animation: spin 0.8s linear infinite; margin-right: 8px; }
} `;
document.head.appendChild(styleSheet);
// 等待保存成功消息 }
function waitForMessage(callback) {
const messageDiv = document.querySelector('.ivu-message'); // 等待保存成功消息
if (messageDiv && messageDiv.textContent.includes('保存成功')) { function waitForMessage(callback) {
console.log('保存成功'); const messageDiv = document.querySelector('.ivu-message');
callback(); if (messageDiv && messageDiv.textContent.includes('保存成功')) {
} else { console.log('保存成功');
setTimeout(() => waitForMessage(callback), 100); callback();
} } else {
} setTimeout(() => waitForMessage(callback), 100);
}
// 等待模态框并点击确认 }
function waitForRestartModal() {
console.log('等待重启确认模态框...'); // 等待模态框并点击确认
const checkModal = setInterval(() => { function waitForRestartModal() {
const modals = [...document.querySelectorAll('.ivu-modal')]; console.log('等待重启确认模态框...');
const targetModal = modals.find(modal => modal.textContent.includes('重新启动内核并重新运行整个笔记本')); const checkModal = setInterval(() => {
if (targetModal) { const modals = [...document.querySelectorAll('.ivu-modal')];
const confirmButton = targetModal.querySelector('.ivu-btn-primary'); const targetModal = modals.find(modal =>
if (confirmButton) { modal.textContent.includes('重新启动内核并重新运行整个笔记本')
confirmButton.click(); );
console.log('已点击"确定"按钮');
clearInterval(checkModal); if (targetModal) {
setTimeout(() => { const confirmButton = targetModal.querySelector('.ivu-btn-primary');
showNotification('自动化执行完成:代码已复制、保存并重启', 'success'); if (confirmButton) {
}, 1000); confirmButton.click();
} console.log('已点击"确定"按钮');
} clearInterval(checkModal);
}, 200); // 执行完成后通知用户
} setTimeout(() => {
showNotification('自动化执行完成:代码已复制、保存并重启!若无警告,等待所有代码块执行完成后自行保存退出!', 'success', 6000);
// 提取代码文本 }, 1000);
function extractCodeText(codeBlock) { }
return codeBlock.innerText || [...codeBlock.querySelectorAll('span')].reduce((text, span) => text + span.textContent, ''); }
} }, 200);
}
// 显示美化的通知
function showNotification(message, type = 'info') { // 查找所有目标代码块(包括“代码示例”和练习答案)
const notification = document.createElement('div'); function findAllCodeBlocks() {
notification.className = 'dolphin-notification'; const textCellWraps = Array.from(document.querySelectorAll('.text-cell-wrap'));
let iconHTML = '';
let borderColor = ''; const allCodeBlocks = [];
if (type === 'success') { function findCodeBlock(container) {
iconHTML = '<div class="notification-icon">✅</div>'; if (!container) return null;
borderColor = '#4CAF50'; const codeBlock = container.querySelector('pre code');
} else if (type === 'error') { return codeBlock || findCodeBlock(container.nextElementSibling);
iconHTML = '<div class="notification-icon">❌</div>'; }
borderColor = '#F44336';
} else { textCellWraps.forEach((cellWrap, index) => {
iconHTML = '<div class="notification-icon"></div>'; console.log(`处理容器 ${index + 1}`, cellWrap);
borderColor = '#2196F3';
} // 优先查找“代码示例”代码块
notification.innerHTML = iconHTML + `<div>${message}</div>`; const exampleMarker = cellWrap.querySelector('.alert.alert-success.alertsuccess');
notification.style.cssText = ` if (exampleMarker && exampleMarker.textContent.includes('代码示例')) {
position: fixed; right: 300px; padding: 15px 20px; background: white; color: #333; border-radius: 6px; const codeBlock = findCodeBlock(cellWrap);
box-shadow: 0 4px 15px rgba(0,0,0,0.15); z-index: 10000; max-width: 350px; font-size: 14px; border-left-color: ${borderColor}; if (codeBlock) {
display: flex; align-items: center; transition: top 0.3s ease; allCodeBlocks.push(codeBlock);
`; console.log(`找到“代码示例”代码块内容:`, codeBlock.textContent.trim());
document.body.appendChild(notification); } else {
NotificationManager.add(notification); console.warn(`未找到“代码示例”代码块!`);
}
let timeoutId; }
notification.addEventListener('mouseenter', () => clearTimeout(timeoutId));
notification.addEventListener('mouseleave', () => startHideTimeout()); // 然后查找练习答案代码块
const collapseDiv = cellWrap.querySelector('.collapse');
function startHideTimeout() { if (collapseDiv) {
timeoutId = setTimeout(() => { const codeBlocks = collapseDiv.querySelectorAll('pre code');
notification.classList.add('hiding'); if (codeBlocks.length > 0) {
setTimeout(() => { codeBlocks.forEach((codeBlock) => {
notification.remove(); allCodeBlocks.push(codeBlock);
NotificationManager.remove(notification); console.log(`找到练习答案代码块内容:`, codeBlock.textContent.trim());
}, 500); });
}, 3000); } else {
} console.warn(`容器 ${index + 1} 中未找到练习答案代码块!`);
startHideTimeout(); }
}
notification.addEventListener('click', () => { });
clearTimeout(timeoutId);
notification.classList.add('hiding'); return allCodeBlocks;
setTimeout(() => { }
notification.remove();
NotificationManager.remove(notification); // 主函数:自动化流程
}, 500); function runAutomation() {
}); const button = document.getElementById('dolphin-auto-btn');
return notification; setButtonState(button, 'running'); // 修改按钮状态为“执行中”
}
try {
// 设置按钮状态 // 1. 查找所有目标代码块
function setButtonState(button, state) { const allCodeBlocks = findAllCodeBlocks();
if (!button) return; console.log(`共找到 ${allCodeBlocks.length} 个有效代码块:`);
const states = { allCodeBlocks.forEach((codeBlock, index) => {
idle: { text: '运行自动化', backgroundColor: '#2196F3', disabled: false, html: '运行自动化' }, console.log(`代码块 ${index + 1}:`, codeBlock.textContent.trim());
running: { text: '执行中', backgroundColor: '#FFA000', disabled: true, html: '<div class="loader"></div> 执行中' }, });
completed: { text: '已完成', backgroundColor: '#4CAF50', disabled: true, html: '✅ 已完成' },
failed: { text: '执行失败', backgroundColor: '#F44336', disabled: false, html: '❌ 重试' } // 2. 获取所有 CodeMirror 编辑器实例
}; const codeMirrors = Array.from(document.querySelectorAll('.CodeMirror'))
const newState = states[state]; .map(cmElement => cmElement.CodeMirror)
button.style.transition = 'all 0.3s ease'; .filter(cmInstance => !!cmInstance);
button.disabled = newState.disabled;
button.innerHTML = newState.html; console.log(`找到 ${codeMirrors.length} 个 CodeMirror 实例:`);
button.style.backgroundColor = newState.backgroundColor;
if (state === 'completed') { if (allCodeBlocks.length === 0 || codeMirrors.length === 0) {
button.style.animation = 'pulse 0.5s ease-in-out'; throw new Error("未找到足够的代码块或编辑器!");
setTimeout(() => setButtonState(button, 'idle'), 3000); }
}
} // 3. 将代码块内容填充到 CodeMirror 编辑器
showNotification(`正在填充 ${Math.min(allCodeBlocks.length, codeMirrors.length)} 个代码块...`, 'info');
// 查找所有目标代码块(包括“代码示例”和练习答案) const minCount = Math.min(allCodeBlocks.length, codeMirrors.length);
function findAllCodeBlocks() { for (let i = 0; i < minCount; i++) {
// 找到所有包含“代码示例”的父容器 const codeText = allCodeBlocks[i].textContent.trim();
const textCellWraps = Array.from(document.querySelectorAll('.text-cell-wrap')) const cmInstance = codeMirrors[i];
.filter(cellWrap => cellWrap.querySelector('.alert.alert-success.alertsuccess')?.textContent.includes('代码示例')); if (cmInstance) {
cmInstance.setValue(codeText); // 使用 CodeMirror API 填充内容
// 收集紧跟在“代码示例”后面的 <pre><code> 元素 console.log(`已填充代码块 ${i + 1} 到 CodeMirror ${i + 1}`);
const exampleCodeBlocks = []; } else {
try {
// 辅助函数:递归查找 <pre><code> const textarea = codeMirrors[i].querySelector('textarea');
function findCodeBlock(container) { if (textarea) {
if (!container) return null; textarea.value = codeText; // 使用替代方法填充内容
const codeBlock = container.querySelector('pre code'); console.log(`使用替代方法填充代码块 ${i + 1}`);
return codeBlock || findCodeBlock(container.nextElementSibling); }
} } catch (e) {
console.error(`无法填充代码块 ${i + 1}:`, e);
textCellWraps.forEach((cellWrap, index) => { }
console.log(`处理代码示例 ${index + 1} 的父容器:`, cellWrap); }
const codeBlock = findCodeBlock(cellWrap); }
if (codeBlock) {
exampleCodeBlocks.push(codeBlock); // 4. 检查多余的 CodeMirror 实例并通知用户
console.log(`找到“代码示例”代码块内容:`, codeBlock.textContent.trim()); if (codeMirrors.length > allCodeBlocks.length) {
} else { const extraCount = codeMirrors.length - allCodeBlocks.length;
console.warn(`未找到“代码示例”代码块!`); console.warn(`多余的 CodeMirror 实例未被填充: 多出 ${extraCount} 个实例`);
} showNotification(
}); `多余的 CodeMirror 实例未被填充: 多出 ${extraCount} 个实例,请检查最后是否有练习,手动填充`,
'warning',
// 找到所有练习答案区域中的 <pre><code> 10000 // 通知停留时间设置为 10 秒
const answerCodeBlocks = []; );
const collapseDivs = Array.from(document.querySelectorAll('.collapse')); }
console.log(`找到 ${collapseDivs.length} 个练习答案区域:`);
collapseDivs.forEach((collapseDiv, index) => { // 5. 点击保存按钮
console.log(`检查练习答案区域 ${index + 1}`, collapseDiv); console.log('准备点击保存按钮...');
const codeBlocks = collapseDiv.querySelectorAll('pre code'); showNotification('正在保存笔记本...', 'info');
if (codeBlocks.length > 0) { const saveButton = findSaveButton();
codeBlocks.forEach((codeBlock) => { if (!saveButton) {
answerCodeBlocks.push(codeBlock); throw new Error("未找到保存按钮!");
console.log(`找到练习答案代码块内容:`, codeBlock.textContent.trim()); }
}); saveButton.click();
} else { console.log('已点击保存按钮');
console.warn(`练习答案区域 ${index + 1} 中未找到 <pre><code>`);
} // 6. 等待保存成功后重启
}); waitForMessage(() => {
console.log('准备点击重启按钮...');
// 合并所有代码块 showNotification('正在重启笔记本...', 'info');
return [...exampleCodeBlocks, ...answerCodeBlocks]; const restartButton = findRestartButton();
} if (!restartButton) {
throw new Error("未找到重启按钮!");
// 主函数 }
function runAutomation() { restartButton.click();
const button = document.getElementById('dolphin-auto-btn'); console.log('找到重启按钮,点击中...');
setButtonState(button, 'running'); waitForRestartModal(); // 等待模态框确认
setButtonState(button, 'completed'); // 修改按钮状态为“已完成”
// 查找所有目标代码块 });
const allCodeBlocks = findAllCodeBlocks();
console.log(`共找到 ${allCodeBlocks.length} 个有效代码块:`); } catch (error) {
allCodeBlocks.forEach((codeBlock, index) => { console.error(error.message);
console.log(`代码块 ${index + 1}:`, codeBlock.textContent.trim()); showNotification(`自动化执行失败:${error.message}`, 'error'); // 显示错误通知
}); setButtonState(button, 'failed'); // 修改按钮状态为“失败”
}
// 查找所有 CodeMirror 编辑器实例 }
const codeMirrors = Array.from(document.querySelectorAll('.CodeMirror'))
.map(cmElement => cmElement.CodeMirror) // 辅助函数:查找保存按钮
.filter(cmInstance => !!cmInstance); function findSaveButton() {
return document.querySelector('.btn-wrap .btn-name') ||
console.log(`找到 ${codeMirrors.length} 个 CodeMirror 实例:`); document.querySelector('[title="保存"]') ||
[...document.querySelectorAll('button')].find(btn => btn.textContent.includes('保存'));
if (allCodeBlocks.length > 0 && codeMirrors.length > 0) { }
showNotification(`正在填充 ${Math.min(allCodeBlocks.length, codeMirrors.length)} 个代码块...`, 'info');
// 辅助函数:查找重启按钮
// 将代码块内容复制到编辑器 function findRestartButton() {
allCodeBlocks.forEach((codeBlock, index) => { const menuItems = [...document.querySelectorAll('.ivu-dropdown-item, [role="menuitem"], .menu-item')];
if (index < codeMirrors.length) { const possibleTexts = ['重启 & 运行所有', '重启并运行所有', '重启&运行所有', '重启和运行所有'];
const codeText = extractCodeText(codeBlock); return menuItems.find(item => {
const cm = codeMirrors[index]; const text = item.textContent.trim();
if (cm) { return possibleTexts.some(pt => text.includes(pt));
cm.setValue(codeText); });
console.log(`已填充代码块 ${index + 1}`); }
} else {
try { // 设置按钮状态
const textarea = codeMirrors[index].querySelector('textarea'); function setButtonState(button, state) {
if (textarea) { if (!button) return;
textarea.value = codeText; const states = {
console.log(`使用替代方法填充代码块 ${index + 1}`); idle: { text: '运行自动化', backgroundColor: '#2196F3', disabled: false, html: '运行自动化' },
} running: { text: '执行中', backgroundColor: '#FFA000', disabled: true, html: '<div class="loader"></div> 执行中' },
} catch (e) { completed: { text: '已完成', backgroundColor: '#4CAF50', disabled: true, html: '✅ 已完成' },
console.error(`无法填充代码块 ${index + 1}:`, e); failed: { text: '执行失败', backgroundColor: '#F44336', disabled: false, html: '❌ 重试' }
} };
} const newState = states[state];
} button.style.transition = 'all 0.3s ease';
}); button.disabled = newState.disabled;
button.innerHTML = newState.html;
// 点击保存按钮 button.style.backgroundColor = newState.backgroundColor;
console.log('准备点击保存按钮...');
showNotification('正在保存笔记本...', 'info'); if (state === 'completed') {
const saveButton = document.querySelector('.btn-wrap .btn-name') || button.style.animation = 'pulse 0.5s ease-in-out';
document.querySelector('[title="保存"]') || setTimeout(() => setButtonState(button, 'idle'), 3000);
[...document.querySelectorAll('button')].find(btn => }
btn.textContent.includes('保存')); }
if (saveButton) {
saveButton.click(); // 显示美化的通知
console.log('已点击保存按钮'); function showNotification(message, type = 'info', duration = 3000) {
// 等待保存成功后重启 const notification = document.createElement('div');
waitForMessage(() => { notification.className = 'dolphin-notification';
console.log('准备点击重启按钮...'); let iconHTML = '';
showNotification('正在重启笔记本...', 'info'); let borderColor = '';
const menuItems = [...document.querySelectorAll('.ivu-dropdown-item, [role="menuitem"], .menu-item')];
const possibleTexts = ['重启 & 运行所有', '重启并运行所有', '重启&运行所有', '重启和运行所有']; if (type === 'success') {
const restartButton = menuItems.find(item => { iconHTML = '<div class="notification-icon">✅</div>';
const text = item.textContent.trim(); borderColor = '#4CAF50';
return possibleTexts.some(pt => text.includes(pt)); } else if (type === 'error') {
}); iconHTML = '<div class="notification-icon">❌</div>';
if (restartButton) { borderColor = '#F44336';
console.log('找到重启按钮,点击中...'); } else if (type === 'warning') {
restartButton.click(); iconHTML = '<div class="notification-icon">⚠️</div>';
waitForRestartModal(); borderColor = '#FFA000';
setButtonState(button, 'completed'); } else {
} else { iconHTML = '<div class="notification-icon"></div>';
console.error('未找到重启按钮!'); borderColor = '#2196F3';
console.log('可用菜单项:'); }
menuItems.forEach((item, i) => console.log(`${i+1}. "${item.textContent.trim()}"`));
// 执行遇到错误,通知用户 notification.innerHTML = iconHTML + `<div>${message}</div>`;
showNotification('自动化执行失败:未找到重启按钮!', 'error'); notification.style.cssText = `
setButtonState(button, 'failed'); position: fixed;
} right: 300px;
}); padding: 15px 20px;
} else { background: white;
console.error('未找到保存按钮!'); color: #333;
// 执行遇到错误,通知用户 border-radius: 6px;
showNotification('自动化执行失败:未找到保存按钮!', 'error'); box-shadow: 0 4px 15px rgba(0,0,0,0.15);
setButtonState(button, 'failed'); z-index: 10000;
} max-width: 350px;
} else { font-size: 14px;
console.error("未找到足够的代码块或编辑器!"); border-left-color: ${borderColor};
// 执行遇到错误,通知用户 display: flex;
showNotification('自动化执行失败:未找到足够的代码块或编辑器!', 'error'); align-items: center;
setButtonState(button, 'failed'); transition: top 0.3s ease;
} `;
} document.body.appendChild(notification);
NotificationManager.add(notification);
// 创建悬浮按钮
function createFloatingButton() { let timeoutId;
const button = document.createElement('button'); notification.addEventListener('mouseenter', () => clearTimeout(timeoutId));
button.id = 'dolphin-auto-btn'; notification.addEventListener('mouseleave', () => startHideTimeout());
button.innerHTML = '运行自动化';
button.style.cssText = ` function startHideTimeout() {
position: fixed; timeoutId = setTimeout(() => {
top: 20px; notification.classList.add('hiding');
right: 300px; /* 距离右侧300像素 */ setTimeout(() => {
z-index: 10000; notification.remove();
padding: 12px 20px; NotificationManager.remove(notification);
background-color: #2196F3; }, 500);
color: white; }, duration); // 使用传递的 duration 参数控制显示时间
border: none; }
border-radius: 6px; startHideTimeout();
cursor: pointer;
font-size: 14px; notification.addEventListener('click', () => {
box-shadow: 0 3px 10px rgba(33, 150, 243, 0.3); clearTimeout(timeoutId);
transition: all 0.3s ease; notification.classList.add('hiding');
display: flex; setTimeout(() => {
align-items: center; notification.remove();
justify-content: center; NotificationManager.remove(notification);
min-width: 140px; }, 500);
font-weight: 600; });
`; return notification;
// 鼠标悬停效果,缓慢放大并加深颜色 }
button.addEventListener('mouseover', () => {
button.style.transform = 'translateY(-2px)'; // 创建悬浮按钮
button.style.boxShadow = '0 5px 15px rgba(33, 150, 243, 0.4)'; function createFloatingButton() {
button.style.backgroundColor = '#1976D2'; const button = document.createElement('button');
}); button.id = 'dolphin-auto-btn';
button.addEventListener('mouseout', () => { button.innerHTML = '运行自动化';
button.style.transform = ''; button.style.cssText = `
button.style.boxShadow = '0 3px 10px rgba(33, 150, 243, 0.3)'; position: fixed;
if (!button.disabled) { top: 0px;
button.style.backgroundColor = '#2196F3'; right: 300px;
} z-index: 10000;
}); padding: 12px 20px;
// 添加点击波纹效果 background-color: #2196F3;
button.addEventListener('mousedown', (e) => { color: white;
const ripple = document.createElement('span'); border: none;
const rect = button.getBoundingClientRect(); border-radius: 6px;
const size = Math.max(rect.width, rect.height); cursor: pointer;
const x = e.clientX - rect.left - size / 2; font-size: 14px;
const y = e.clientY - rect.top - size / 2; box-shadow: 0 3px 10px rgba(33, 150, 243, 0.3);
ripple.style.cssText = ` transition: all 0.3s ease;
position: absolute; display: flex;
top: ${y}px; align-items: center;
left: ${x}px; justify-content: center;
width: ${size}px; min-width: 140px;
height: ${size}px; font-weight: 600;
background-color: rgba(255, 255, 255, 0.7); `;
border-radius: 50%;
transform: scale(0); // 鼠标悬停效果
animation: ripple 0.6s linear; button.addEventListener('mouseover', () => {
pointer-events: none; button.style.transform = 'translateY(-2px)';
`; button.style.boxShadow = '0 5px 15px rgba(33, 150, 243, 0.4)';
button.appendChild(ripple); button.style.backgroundColor = '#1976D2';
setTimeout(() => { });
ripple.remove();
}, 600); button.addEventListener('mouseout', () => {
}); button.style.transform = '';
// 点击事件 button.style.boxShadow = '0 3px 10px rgba(33, 150, 243, 0.3)';
button.addEventListener('click', () => { if (!button.disabled) {
if (!button.disabled) { button.style.backgroundColor = '#2196F3';
runAutomation(); }
} });
});
document.body.appendChild(button); // 点击波纹效果
return button; button.addEventListener('mousedown', (e) => {
} const ripple = document.createElement('span');
const rect = button.getBoundingClientRect();
// 初始化函数 const size = Math.max(rect.width, rect.height);
function init() { const x = e.clientX - rect.left - size / 2;
addStyles(); const y = e.clientY - rect.top - size / 2;
const button = createFloatingButton(); ripple.style.cssText = `
// 显示欢迎通知 position: absolute;
setTimeout(() => { top: ${y}px;
showNotification('海豚自动化工具已加载,点击按钮开始自动化操作', 'info'); left: ${x}px;
}, 1000); width: ${size}px;
} height: ${size}px;
background-color: rgba(255, 255, 255, 0.7);
// 页面加载后初始化 border-radius: 50%;
setTimeout(init, 1000); transform: scale(0);
animation: ripple 0.6s linear;
pointer-events: none;
`;
button.appendChild(ripple);
setTimeout(() => {
ripple.remove();
}, 600);
});
// 点击事件
button.addEventListener('click', () => {
if (!button.disabled) {
runAutomation();
}
});
document.body.appendChild(button);
return button;
}
// 初始化函数
function init() {
addStyles();
const button = createFloatingButton();
// 显示欢迎通知
setTimeout(() => {
showNotification('海豚自动化工具 v1.3 已加载,点击按钮开始自动化操作', 'info', 5000); // 通知显示 5 秒
}, 1000);
}
// 页面加载后初始化
setTimeout(init, 1000);
})(); })();