// ==UserScript== // @name o2o编辑系统多语言切换 (支持拖拽) // @namespace https://bbs.tampermonkey.net.cn/ // @version 1.1.0 // @description 根据当前页面ID查找所有同路由的页面并提供跳转列表,支持拖拽 // @author PJ // @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; /* 鼠标样式改为移动 */ cursor: pointer; 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; } #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; display: flex; 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; } .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; } .o2o-error { padding: 15px; color: red; } `); // --- 通用拖拽函数 --- 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; // 将定位方式强制转换为 left/top,防止 right/bottom 干扰拖拽 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'; // 延迟一小段时间重置拖拽状态,确保 click 事件能读取到 hasMoved setTimeout(() => { element.dataset.isDragging = "false"; }, 0); } }); } // 工具:获取Cookie function getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); return null; } // 工具:获取URL参数 function getQueryParam(name) { const urlParams = new URLSearchParams(window.location.search); return urlParams.get(name); } // 主逻辑:获取数据并处理 function fetchAndRender() { const panel = document.querySelector('#o2o-page-helper-panel'); const contentDiv = panel.querySelector('.o2o-content'); // 显示面板 (如果在左边或者其他地方,保持位置,只控制 display) panel.style.display = 'flex'; contentDiv.innerHTML = '
加载中...
'; // 1. 获取基础参数 const currentId = getQueryParam('id'); const token = getCookie('manageToken'); const proId = getCookie('otoManageProId'); if (!currentId) { contentDiv.innerHTML = '
无法获取当前URL中的id参数,请确认在编辑页使用。
'; return; } if (!token || !proId) { contentDiv.innerHTML = '
无法获取Cookie中的 token 或 proId,请尝试刷新页面。
'; return; } // 2. 发起请求 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('API请求失败: ' + response.statusText); } const res = JSON.parse(response.responseText); const list = res.data; if (!Array.isArray(list)) { throw new Error('返回数据格式不是数组'); } // 3. 找到当前页面的信息 const currentPageObj = list.find(item => item.id == currentId); if (!currentPageObj) { contentDiv.innerHTML = `
在列表中未找到当前ID (${currentId}) 对应的页面。
`; return; } // const targetPageName = currentPageObj.pageName; // 4. 过滤同名页面 (全匹配) // const filteredList = list.filter(item => item.pageName === targetPageName); const targetRoutingName = currentPageObj.routingName; // 4. 过滤同名页面 (全匹配) const filteredList = list.filter(item => item.routingName === targetRoutingName); // 5. 渲染列表 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) { console.error(e); contentDiv.innerHTML = `
处理出错: ${e.message}
`; } }, onerror: function(err) { console.error(err); contentDiv.innerHTML = '
网络请求发生错误。
'; } }); } // 初始化UI function initUI() { // 创建触发按钮 const btn = document.createElement('div'); btn.id = 'o2o-page-helper-btn'; btn.innerText = '🔍 查找所有语言页面'; // 点击事件处理:如果是拖拽结束,则不触发点击 btn.onclick = (e) => { if (btn.dataset.hasMoved === "true") { // 是拖拽行为,不执行点击 return; } fetchAndRender(); }; document.body.appendChild(btn); // 创建展示面板 const panel = document.createElement('div'); panel.id = 'o2o-page-helper-panel'; panel.style.display = 'none'; // 初始隐藏 panel.innerHTML = `
页面列表
`; document.body.appendChild(panel); // 应用拖拽逻辑 makeDraggable(btn); // 按钮整体可拖拽 makeDraggable(panel, panel.querySelector('.o2o-panel-header')); // 面板通过头部拖拽 } // 启动 initUI(); })();