您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
支持账号管理、切换、删除、确认切号、切号后刷新页面。仅在指定页面生效。
当前为
// ==UserScript== // @name UPhone 切号工具(账号管理+删除+刷新) // @namespace http://tampermonkey.net/ // @license MIT // @version 3.0 // @description 支持账号管理、切换、删除、确认切号、切号后刷新页面。仅在指定页面生效。 // @author GPT // @match https://uphone.wo-adv.cn/cloudphone/* // @grant none // ==/UserScript== (function () { 'use strict'; window.addEventListener('load', () => { const hash = location.hash; if (!['#/personal', '#/discover', '#/home'].includes(hash)) return; const storageKey = '__uphone_token_accounts__'; const getAccounts = () => JSON.parse(localStorage.getItem(storageKey) || '{}'); const saveAccounts = (obj) => localStorage.setItem(storageKey, JSON.stringify(obj)); let isExpanded = false; const container = document.createElement('div'); container.style.position = 'fixed'; container.style.top = '150px'; container.style.right = '0'; container.style.width = '10px'; container.style.height = '40px'; container.style.zIndex = '99999'; container.style.backgroundColor = 'rgba(64,158,255,0.5)'; container.style.borderTopLeftRadius = '6px'; container.style.borderBottomLeftRadius = '6px'; container.style.cursor = 'pointer'; container.style.transition = 'width 0.3s ease'; const panel = document.createElement('div'); panel.style.display = 'none'; panel.style.width = '240px'; panel.style.backgroundColor = '#fff'; panel.style.border = '1px solid #ccc'; panel.style.borderRadius = '6px'; panel.style.boxShadow = '0 0 5px rgba(0,0,0,0.2)'; panel.style.padding = '10px'; panel.style.position = 'absolute'; panel.style.right = '70px'; panel.style.top = '0'; panel.style.fontSize = '14px'; panel.style.color = '#333'; const title = document.createElement('div'); title.textContent = '账号列表'; title.style.fontWeight = 'bold'; title.style.marginBottom = '5px'; panel.appendChild(title); const accountList = document.createElement('div'); panel.appendChild(accountList); const refreshAccountList = () => { accountList.innerHTML = ''; const accounts = getAccounts(); if (Object.keys(accounts).length === 0) { accountList.innerHTML = '<div style="color:gray;">暂无账号</div>'; return; } for (const [name, token] of Object.entries(accounts)) { const row = document.createElement('div'); row.style.display = 'flex'; row.style.justifyContent = 'space-between'; row.style.alignItems = 'center'; row.style.marginBottom = '5px'; const btn = document.createElement('button'); btn.textContent = name; btn.style.flex = '1'; btn.style.marginRight = '5px'; btn.style.padding = '4px 6px'; btn.style.fontSize = '12px'; btn.style.cursor = 'pointer'; btn.onclick = () => { if (!confirm(`确定切换到账号「${name}」吗?`)) return; const baseInfoStr = localStorage.getItem('baseInfo'); if (!baseInfoStr) return alert('baseInfo 不存在'); try { const baseInfo = JSON.parse(baseInfoStr); baseInfo.data.token = token; baseInfo.data.userInfo = {}; localStorage.setItem('baseInfo', JSON.stringify(baseInfo)); location.reload(); // 自动刷新页面 } catch (e) { alert('baseInfo 解析失败'); console.error(e); } }; const del = document.createElement('button'); del.textContent = '🗑️'; del.style.padding = '3px 5px'; del.style.fontSize = '12px'; del.style.cursor = 'pointer'; del.style.color = '#f00'; del.onclick = () => { if (confirm(`确定删除账号「${name}」?`)) { delete accounts[name]; saveAccounts(accounts); refreshAccountList(); } }; row.appendChild(btn); row.appendChild(del); accountList.appendChild(row); } }; const addBtn = document.createElement('button'); addBtn.textContent = '+ 添加账号'; addBtn.style.marginTop = '5px'; addBtn.style.padding = '4px 8px'; addBtn.style.fontSize = '12px'; addBtn.style.cursor = 'pointer'; addBtn.onclick = () => { const name = prompt('请输入账号名称:'); if (!name) return; const token = prompt('请输入该账号的 token:'); if (!token) return; const accounts = getAccounts(); accounts[name] = token; saveAccounts(accounts); refreshAccountList(); }; panel.appendChild(addBtn); const toggleBtn = document.createElement('div'); toggleBtn.textContent = '📱'; toggleBtn.style.width = '40px'; toggleBtn.style.height = '40px'; toggleBtn.style.backgroundColor = '#409EFF'; toggleBtn.style.color = '#fff'; toggleBtn.style.fontSize = '22px'; toggleBtn.style.textAlign = 'center'; toggleBtn.style.lineHeight = '40px'; toggleBtn.style.borderRadius = '50%'; // 圆形按钮 toggleBtn.style.border = '2px solid #2c7cd1'; toggleBtn.style.boxShadow = '0 2px 6px rgba(64,158,255,0.6)'; toggleBtn.style.userSelect = 'none'; toggleBtn.style.display = 'none'; toggleBtn.style.cursor = 'pointer'; toggleBtn.style.transition = 'background-color 0.3s ease, box-shadow 0.3s ease'; toggleBtn.onclick = () => { isExpanded = !isExpanded; if (isExpanded) { refreshAccountList(); panel.style.display = 'block'; container.style.width = '70px'; } else { panel.style.display = 'none'; container.style.width = '10px'; } }; container.appendChild(toggleBtn); container.appendChild(panel); document.body.appendChild(container); // 悬停显示按钮(不触发面板) container.addEventListener('mouseenter', () => { if (!isExpanded) { container.style.width = '70px'; toggleBtn.style.display = 'block'; } }); container.addEventListener('mouseleave', () => { if (!isExpanded) { container.style.width = '10px'; toggleBtn.style.display = 'none'; } }); // 拖动吸附 let dragging = false; let offsetX = 0, offsetY = 0; container.addEventListener('mousedown', (e) => { dragging = true; offsetX = e.clientX - container.getBoundingClientRect().left; offsetY = e.clientY - container.getBoundingClientRect().top; e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (dragging) { container.style.top = `${e.clientY - offsetY}px`; container.style.left = `${e.clientX - offsetX}px`; container.style.right = 'auto'; } }); document.addEventListener('mouseup', () => { if (dragging) { dragging = false; const winWidth = window.innerWidth; const winHeight = window.innerHeight; const rect = container.getBoundingClientRect(); const snapLeft = rect.left < winWidth / 2; container.style.left = snapLeft ? '0px' : 'auto'; container.style.right = snapLeft ? 'auto' : '0px'; if (rect.top < 10) container.style.top = '10px'; if (rect.top > winHeight - rect.height - 10) container.style.top = (winHeight - rect.height - 10) + 'px'; } }); }); })();