打开/关闭搜索
搜索
打开/关闭菜单
933
1525
112
1.4万
植物大战僵尸杂交版Wiki
导航
首页
最近更改
随机页面
MediaWiki帮助
特殊页面
上传文件
打开/关闭外观设置菜单
notifications
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。
user-interface-preferences
个人工具
创建账号
登录
查看“︁用户:EditBot/console”︁的源代码
来自植物大战僵尸杂交版Wiki
查看
阅读
查看源代码
查看历史
associated-pages
用户页
讨论
更多操作
←
用户:EditBot/console
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
<div id="bot-console" style="position:fixed;bottom:20px;right:20px;width:400px;max-height:500px;background:rgba(0,0,0,0.9);border-radius:12px;padding:16px;color:#00ff00;font-family:monospace;font-size:12px;z-index:999999;box-shadow:0 8px 30px rgba(0,0,0,0.8);overflow:hidden;border:2px solid #00ff00;resize:both;min-width:300px;"> <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;cursor:move;"> <span style="font-weight:bold;color:#00ff00;">🤖 EditBot 控制台</span> <div> <span id="bot-status" style="color:#ffaa00;font-size:10px;">● 运行中</span> <button id="bot-toggle" style="background:#ff4444;border:none;color:#fff;padding:2px 10px;border-radius:4px;cursor:pointer;font-size:11px;">停止</button> <button id="bot-close" style="background:#555;border:none;color:#fff;padding:2px 8px;border-radius:4px;cursor:pointer;font-size:11px;">✕</button> </div> </div> <div style="border-top:1px solid #333;padding-top:8px;"> <div style="display:flex;gap:8px;margin-bottom:6px;flex-wrap:wrap;"> <span style="color:#888;">用户: <span id="bot-user" style="color:#00ff00;">加载中...</span></span> <span style="color:#888;">检测: <span id="bot-count" style="color:#00ff00;">0</span> 人</span> <span style="color:#888;">写入: <span id="bot-writes" style="color:#00ff00;">0</span> 次</span> </div> <div id="bot-log" style="height:200px;overflow-y:auto;background:#111;border-radius:6px;padding:6px;font-size:11px;line-height:1.6;"> <div style="color:#888;">⏳ 等待启动...</div> </div> <div style="display:flex;gap:6px;margin-top:6px;"> <input id="bot-interval" type="number" value="3" style="width:50px;background:#222;border:1px solid #444;color:#fff;border-radius:4px;padding:2px 4px;font-size:11px;"> <span style="color:#888;font-size:10px;">秒</span> <button id="bot-scan" style="background:#0088ff;border:none;color:#fff;padding:2px 12px;border-radius:4px;cursor:pointer;font-size:11px;">立即扫描</button> <button id="bot-clear" style="background:#555;border:none;color:#fff;padding:2px 12px;border-radius:4px;cursor:pointer;font-size:11px;">清空日志</button> </div> </div> </div> <style> #bot-log::-webkit-scrollbar { width: 4px; } #bot-log::-webkit-scrollbar-track { background: #111; } #bot-log::-webkit-scrollbar-thumb { background: #444; border-radius: 2px; } #bot-console .log-success { color: #00ff00; } #bot-console .log-warning { color: #ffaa00; } #bot-console .log-error { color: #ff4444; } #bot-console .log-info { color: #66ccff; } #bot-console .log-editor { color: #ff66aa; } </style> <script> (function() { 'use strict'; // ============ 配置 ============ var BOT_NAME = mw.config.get('wgUserName') || 'EditBot'; var CHECK_INTERVAL = 3000; var running = false; var timer = null; var writeCount = 0; var scanCount = 0; var detectedEditors = {}; var logLines = []; // ============ DOM 引用 ============ var logEl = document.getElementById('bot-log'); var statusEl = document.getElementById('bot-status'); var toggleBtn = document.getElementById('bot-toggle'); var countEl = document.getElementById('bot-count'); var writesEl = document.getElementById('bot-writes'); var userEl = document.getElementById('bot-user'); var intervalInput = document.getElementById('bot-interval'); userEl.textContent = BOT_NAME; // ============ 日志系统 ============ function log(msg, type) { type = type || 'info'; var time = new Date().toLocaleTimeString(); var colors = { success: '#00ff00', warning: '#ffaa00', error: '#ff4444', info: '#66ccff', editor: '#ff66aa', mute: '#555' }; var color = colors[type] || '#ffffff'; var line = '<div style="color:' + color + ';">[' + time + '] ' + msg + '</div>'; logEl.innerHTML += line; logEl.scrollTop = logEl.scrollHeight; if (logEl.children.length > 500) { logEl.removeChild(logEl.firstChild); } } // ============ 核心检测 ============ function scanAllEditors() { if (!running) return; var api = new mw.Api(); scanCount++; api.get({ action: 'query', list: 'recentchanges', rclimit: 200, rcprop: 'user|title|timestamp', rcshow: '!bot', rcnamespace: 0, format: 'json' }).then(function(data) { var pageMap = {}; var activeUsers = new Set(); if (data.query && data.query.recentchanges) { data.query.recentchanges.forEach(function(rc) { var title = rc.title; var user = rc.user; var timeDiff = Date.now() - new Date(rc.timestamp).getTime(); if (timeDiff < 60000 && user !== BOT_NAME) { if (!pageMap[title]) pageMap[title] = new Set(); pageMap[title].add(user); activeUsers.add(user); } }); } var totalEditors = 0; var writePromises = []; for (var page in pageMap) { var editors = Array.from(pageMap[page]); totalEditors += editors.length; editors.forEach(function(editor) { if (editor === BOT_NAME) return; var otherEditors = editors.filter(function(e) { return e !== editor && e !== BOT_NAME; }); writePromises.push(writeUserStatus(editor, page, otherEditors)); }); } // 清理不在线的用户状态 var cleanupPromise = cleanupOldStatus(activeUsers); Promise.all(writePromises).then(function() { countEl.textContent = totalEditors; if (totalEditors > 0) { var editorList = Array.from(activeUsers).slice(0, 5).join('、'); log('📊 检测到 ' + totalEditors + ' 位活跃用户:' + editorList + (activeUsers.size > 5 ? ' ...' : ''), 'editor'); } else { log('📊 暂无活跃用户', 'mute'); } }).catch(function(err) { log('⚠️ 写入失败: ' + err.message, 'warning'); }); }).fail(function(err) { log('❌ 扫描失败: ' + (err.error?.info || err.message || '未知错误'), 'error'); }); } // ============ 写入用户状态 ============ function writeUserStatus(username, page, editors) { return new Promise(function(resolve, reject) { var statusPage = 'User:' + username + '/edit-status'; var api = new mw.Api(); var statusData = { page: page, editors: editors.map(function(e) { return { user: e, timestamp: Date.now() }; }), timestamp: Date.now(), checkedBy: BOT_NAME, status: editors.length > 0 ? 'editing' : 'idle' }; api.postWithEditToken({ action: 'edit', title: statusPage, text: JSON.stringify(statusData, null, 2), summary: '🤖 ' + BOT_NAME + ' 检测编辑状态', minor: true, bot: true }).then(function() { writeCount++; writesEl.textContent = writeCount; resolve(); }).fail(function(err) { reject(err); }); }); } // ============ 清理过期状态 ============ function cleanupOldStatus(activeUsers) { return new Promise(function(resolve) { var api = new mw.Api(); api.get({ action: 'query', list: 'allpages', apnamespace: 2, apprefix: 'edit-status', aplimit: 100, format: 'json' }).then(function(data) { if (!data.query || !data.query.allpages) { resolve(); return; } var promises = []; data.query.allpages.forEach(function(page) { var username = page.title.replace('User:', '').replace('/edit-status', ''); if (username === BOT_NAME || activeUsers.has(username)) return; var p = new mw.Api().get({ action: 'query', titles: page.title, prop: 'revisions', rvprop: 'content', rvlimit: 1, format: 'json' }).then(function(contentData) { var pages = contentData.query.pages; for (var id in pages) { if (pages[id].revisions && pages[id].revisions[0]) { try { var status = JSON.parse(pages[id].revisions[0]['*']); if (status.status === 'editing' && (Date.now() - status.timestamp) > 60000) { var api2 = new mw.Api(); var statusData = { page: status.page || '', editors: [], timestamp: Date.now(), checkedBy: BOT_NAME, status: 'idle' }; return api2.postWithEditToken({ action: 'edit', title: page.title, text: JSON.stringify(statusData, null, 2), summary: '🤖 ' + BOT_NAME + ' 清理过期状态', minor: true, bot: true }); } } catch(e) {} } } return Promise.resolve(); }); promises.push(p); }); Promise.all(promises).then(resolve); }).fail(function() { resolve(); }); }); } // ============ 执行一轮 ============ function doRound() { if (!running) return; log('🔄 扫描中...', 'info'); scanAllEditors(); } // ============ 控制功能 ============ function startBot() { if (running) return; running = true; var interval = parseInt(intervalInput.value) || 3; CHECK_INTERVAL = interval * 1000; statusEl.textContent = '● 运行中'; statusEl.style.color = '#00ff00'; toggleBtn.textContent = '停止'; toggleBtn.style.background = '#ff4444'; log('✅ 机器人已启动,间隔 ' + interval + ' 秒', 'success'); doRound(); timer = setInterval(doRound, CHECK_INTERVAL); } function stopBot() { if (!running) return; running = false; if (timer) { clearInterval(timer); timer = null; } statusEl.textContent = '● 已停止'; statusEl.style.color = '#ff4444'; toggleBtn.textContent = '启动'; toggleBtn.style.background = '#44aa44'; log('⏹️ 机器人已停止', 'warning'); } function toggleBot() { if (running) { stopBot(); } else { startBot(); } } // ============ 拖拽支持 ============ var consoleEl = document.getElementById('bot-console'); var isDragging = false; var startX, startY, origX, origY; consoleEl.querySelector('div:first-child').addEventListener('mousedown', function(e) { if (e.target.tagName === 'BUTTON') return; isDragging = true; startX = e.clientX; startY = e.clientY; origX = consoleEl.offsetLeft; origY = consoleEl.offsetTop; consoleEl.style.cursor = 'grabbing'; e.preventDefault(); }); document.addEventListener('mousemove', function(e) { if (!isDragging) return; var dx = e.clientX - startX; var dy = e.clientY - startY; consoleEl.style.left = (origX + dx) + 'px'; consoleEl.style.top = (origY + dy) + 'px'; consoleEl.style.right = 'auto'; consoleEl.style.bottom = 'auto'; }); document.addEventListener('mouseup', function() { isDragging = false; consoleEl.style.cursor = 'default'; }); // ============ 按钮绑定 ============ document.getElementById('bot-toggle').addEventListener('click', toggleBot); document.getElementById('bot-close').addEventListener('click', function() { if (running) stopBot(); consoleEl.style.display = 'none'; log('📦 控制台已隐藏,重新打开请运行 showBot()', 'info'); }); document.getElementById('bot-scan').addEventListener('click', function() { if (running) { log('🔄 手动扫描...', 'info'); doRound(); } else { log('⚠️ 机器人已停止,请先启动', 'warning'); } }); document.getElementById('bot-clear').addEventListener('click', function() { logEl.innerHTML = ''; log('🗑️ 日志已清空', 'info'); }); intervalInput.addEventListener('change', function() { var val = parseInt(this.value) || 3; if (val < 1) this.value = 1; if (val > 30) this.value = 30; if (running) { log('⏱️ 间隔已改为 ' + this.value + ' 秒,重启生效', 'info'); stopBot(); startBot(); } }); // ============ 暴露全局 ============ window.showBot = function() { consoleEl.style.display = 'block'; log('📦 控制台已显示', 'info'); }; window.hideBot = function() { consoleEl.style.display = 'none'; }; // ============ 自动启动 ============ log('🤖 ' + BOT_NAME + ' 控制台已加载', 'success'); log('💡 点击 "启动" 开始检测,或拖拽移动控制台', 'info'); // 自动启动 startBot(); })(); </script>
返回
用户:EditBot/console
。
查看“︁用户:EditBot/console”︁的源代码
来自植物大战僵尸杂交版Wiki