update:更新海豚实验室域名

This commit is contained in:
kaku 2025-05-20 14:49:30 +08:00
parent a3032692b2
commit 78c67cd097

View File

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