// ==UserScript== // @name o2o编辑系统多语言切换 (智能监控版) // @namespace https://bbs.tampermonkey.net.cn/ // @version 1.3.0 // @description 自动监控页面状态,解决刷新才显示的问题,支持拖拽与自动加载 // @author PJ // @match https://o2omanage.o2o.co/manage/siteEdit/* // @match https://o2omanage.o2o.co/manage/siteEdit/buildWeb/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @connect products-api-o2o-prod.gs-souvenir.com // ==/UserScript== (function() { 'use strict'; // 样式注入 GM_addStyle(` #o2o-page-helper-btn { position: fixed; top: 10px; left: 60%; z-index: 99999; background: #1890ff; color: white; padding: 10px 15px; border-radius: 4px; cursor: move; box-shadow: 0 4px 12px rgba(0,0,0,0.2); font-size: 14px; user-select: none; transition: background 0.2s, box-shadow 0.2s; display: flex; align-items: center; justify-content: center; } #o2o-page-helper-btn:active { box-shadow: 0 2px 6px rgba(0,0,0,0.3); } #o2o-page-helper-panel { position: fixed; top: 53px; left: 60%; z-index: 99999; background: white; border: 1px solid #ddd; border-radius: 4px; box-shadow: 0 4px 16px rgba(0,0,0,0.2); width: 300px; max-height: 400px; display: none; font-family: Arial, sans-serif; flex-direction: column; } .o2o-panel-header { padding: 10px; border-bottom: 1px solid #eee; font-weight: bold; display: flex; justify-content: space-between; background: #f5f5f5; cursor: move; user-select: none; } .o2o-content { overflow-y: auto; flex: 1; min-height: 50px; } .o2o-close-btn { cursor: pointer; color: #999; padding: 0 5px; } .o2o-close-btn:hover { color: #333; } .o2o-list-item { padding: 10px; border-bottom: 1px solid #f0f0f0; cursor: pointer; transition: background 0.2s; display: block; text-decoration: none; color: #333; } .o2o-list-item:hover { background: #e6f7ff; } .o2o-tag { background: #e6f7ff; color: #1890ff; border: 1px solid #91d5ff; padding: 2px 6px; border-radius: 4px; font-size: 12px; margin-right: 8px; } .o2o-current { background: #fffbe6; } .o2o-loading { padding: 15px; text-align: center; color: #666; font-size: 13px; } .o2o-error { padding: 15px; color: red; font-size: 13px; } `); // --- 工具函数 --- function getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); return null; } function getQueryParam(name) { const urlParams = new URLSearchParams(window.location.search); return urlParams.get(name); } function makeDraggable(element, handle) { let isDragging = false; let startX, startY, initialLeft, initialTop; const dragHandle = handle || element; dragHandle.addEventListener('mousedown', (e) => { if (e.target.classList.contains('o2o-close-btn')) return; isDragging = true; startX = e.clientX; startY = e.clientY; const rect = element.getBoundingClientRect(); initialLeft = rect.left; initialTop = rect.top; element.style.right = 'auto'; element.style.bottom = 'auto'; element.style.left = `${initialLeft}px`; element.style.top = `${initialTop}px`; dragHandle.style.cursor = 'grabbing'; element.dataset.isDragging = "true"; element.dataset.hasMoved = "false"; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; e.preventDefault(); const dx = e.clientX - startX; const dy = e.clientY - startY; if (Math.abs(dx) > 2 || Math.abs(dy) > 2) element.dataset.hasMoved = "true"; element.style.left = `${initialLeft + dx}px`; element.style.top = `${initialTop + dy}px`; }); document.addEventListener('mouseup', () => { if (isDragging) { isDragging = false; dragHandle.style.cursor = 'move'; setTimeout(() => { element.dataset.isDragging = "false"; }, 0); } }); } // --- 核心业务逻辑 --- function fetchDataAndBuildDom() { const panel = document.querySelector('#o2o-page-helper-panel'); const contentDiv = panel.querySelector('.o2o-content'); contentDiv.innerHTML = '
数据自动加载中...
'; const currentId = getQueryParam('id'); const token = getCookie('manageToken'); const proId = getCookie('otoManageProId'); if (!currentId || !token || !proId) { contentDiv.innerHTML = '
等待参数就绪...
'; return; } GM_xmlhttpRequest({ method: "POST", url: "https://products-api-o2o-prod.gs-souvenir.com/retailer/page/listAllPagesNoTree", headers: { "accept": "application/json, text/plain, */*", "content-type": "application/json;charset=UTF-8", "token": token }, data: JSON.stringify({ "proId": parseInt(proId), "language": "en-us" }), onload: function(response) { try { if (response.status !== 200) throw new Error(response.statusText); const res = JSON.parse(response.responseText); const list = res.data; if (!Array.isArray(list)) throw new Error('数据格式错误'); const currentPageObj = list.find(item => item.id == currentId); if (!currentPageObj) { contentDiv.innerHTML = `
未找到当前ID: ${currentId}
`; return; } const targetRoutingName = currentPageObj.routingName; const filteredList = list.filter(item => item.routingName === targetRoutingName); if (filteredList.length === 0) { contentDiv.innerHTML = '
无同系列页面
'; } else { let html = ''; filteredList.forEach(item => { const link = `https://o2omanage.o2o.co/manage/siteEdit/buildWeb/?id=${item.id}&type=1&language=${item.language}`; const isCurrent = item.id == currentId ? 'o2o-current' : ''; html += `
${item.language}${isCurrent ? '(当前)' : ''}
${item.pageName}
${item.routingName}
`; }); contentDiv.innerHTML = html; } } catch (e) { contentDiv.innerHTML = `
Error: ${e.message}
`; } }, onerror: () => contentDiv.innerHTML = '
网络请求失败
' }); } function initUI() { // 如果已经存在,就不重复创建 if (document.getElementById('o2o-page-helper-btn')) return; // 创建按钮 const btn = document.createElement('div'); btn.id = 'o2o-page-helper-btn'; btn.innerText = '🔍 语言切换'; btn.onclick = (e) => { if (btn.dataset.hasMoved === "true") return; const panel = document.getElementById('o2o-page-helper-panel'); panel.style.display = (panel.style.display === 'flex') ? 'none' : 'flex'; }; document.body.appendChild(btn); // 创建面板 const panel = document.createElement('div'); panel.id = 'o2o-page-helper-panel'; panel.innerHTML = `
页面列表
`; document.body.appendChild(panel); // 绑定拖拽 makeDraggable(btn); makeDraggable(panel, panel.querySelector('.o2o-panel-header')); // 立即开始请求数据 fetchDataAndBuildDom(); } // --- 监控与启动逻辑 --- // 为了解决刷新才显示的问题,我们使用定时器检测环境 // 1. 确保在编辑页面 (URL包含 buildWeb) // 2. 确保 Cookie 已经存在 (登录状态就绪) // 3. 确保 URL 中有 ID 参数 function monitorAndInit() { const checkInterval = setInterval(() => { // 1. 检查是否在目标页面 if (window.location.href.indexOf('/manage/siteEdit/buildWeb/') === -1) { // 如果不在编辑页,但 UI 存在,可以考虑隐藏或移除(这里选择移除以保持干净) const btn = document.getElementById('o2o-page-helper-btn'); const panel = document.getElementById('o2o-page-helper-panel'); if (btn) btn.remove(); if (panel) panel.remove(); return; } // 2. 检查必要参数是否就绪 const token = getCookie('manageToken'); const proId = getCookie('otoManageProId'); const currentId = getQueryParam('id'); if (token && proId && currentId) { // 3. 参数就绪,检查 UI 是否已存在 if (!document.getElementById('o2o-page-helper-btn')) { // UI 不存在,进行初始化 initUI(); } } }, 1000); // 每秒检查一次 } // 启动监控 monitorAndInit(); })();