您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
支持美团、携程、飞猪订单数据同步,点击对应按钮可导入订单信息,仅内部使用
// ==UserScript== // @name 同步数据插件 // @namespace http://sync-data-plugins.com/ // @version 0.6 // @description 支持美团、携程、飞猪订单数据同步,点击对应按钮可导入订单信息,仅内部使用 // @match https://hotel.fliggy.com/* // @match https://www.vipdlt.com/* // @match https://sfbfxg.zcfgoagain.qunar.com/* // @connect hoteluat.bingtrip.cn // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== (function () { 'use strict'; // debugger; // let send_task_host_url = "https://hotel.bingtrip.cn:34561" // 正式环境, 需要同步更新 // @connect hotel.bingtrip.cn let send_task_host_url = "http://hoteluat.bingtrip.cn:34561" // uat环境 // @connect hoteluat.bingtrip.cn // 存储原始XMLHttpRequest构造函数 const originalXHR = unsafeWindow.XMLHttpRequest; // 重写XMLHttpRequest以拦截请求 unsafeWindow.XMLHttpRequest = function () { const xhr = new originalXHR(); const originalOpen = xhr.open; const originalSend = xhr.send; // 重写open方法记录URL xhr.open = function (method, url, async, user, password) { // debugger; // 美团订单详情API if (url.includes('api/agent/v1/oversea/order/apt') && url.includes('detail')) { this.mt_url = url; } // 携程订单列表API if (url.includes('api/scrollOrderList')) { this.ctrip_url = url; } // 飞猪订单详情API if (url.includes('h5api.m.fliggy.com/h5/mtop.taobao.hotel.ebooking.order.detail')) { // debugger; this.feizhu_url = url; } originalOpen.apply(xhr, arguments); }; // 重写send方法处理响应 xhr.send = function (body) { xhr.onload = function () { // 美团响应 if (this.mt_url && xhr.responseText.includes('goodsName') && xhr.responseText.includes('checkInDateModels') && !xhr.responseText.includes('webpackJsonp')) { localStorage.setItem('meituanApiResponse', xhr.responseText); meituanCheckAndAddButton(); } // 携程响应 if (this.ctrip_url && xhr.status === 200 && xhr.responseText.includes('infoBos') && xhr.responseText.includes('channelOrderId') && !xhr.responseText.includes('webpackJsonp')) { try { const existingResponse = JSON.parse(localStorage.getItem('Vipdlt_ApiResponse') || '{"data":{"infoBos":[]}}'); const newResponse = JSON.parse(xhr.responseText); const existingIds = new Set(existingResponse.data.infoBos.map(item => item.channelOrderId)); const uniqueItems = newResponse.data.infoBos.filter(item => !existingIds.has(item.channelOrderId)); existingResponse.data.infoBos = existingResponse.data.infoBos.concat(uniqueItems); localStorage.setItem('Vipdlt_ApiResponse', JSON.stringify(existingResponse)); } catch (e) { console.error('携程响应处理错误:', e); } } // 飞猪 if (this.feizhu_url && xhr.responseText.includes('encryptSellerId')) { // debugger; try { localStorage.setItem('feizhuApiResponse', xhr.responseText); feizhuCheckAndAddButton() } catch (e) { console.log('飞猪响应处理错误:', e); } } }; originalSend.apply(xhr, arguments); }; return xhr; }; // 去哪儿 const quna_open = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function (method, url, async, user, password) { if (url.includes('/confirm/api/list/queryOrderList')) { // 监听响应数据 const originalOnReadyStateChange = this.onreadystatechange; this.onreadystatechange = function () { if (this.readyState === 4 && this.status === 200) { console.log('Intercepted Response:', this.responseText); localStorage.setItem('qunaApiResponse', this.responseText); qunaCheckAndButton() } // 确保调用原始的 onreadystatechange 处理 if (originalOnReadyStateChange) { originalOnReadyStateChange.apply(this, arguments); } }; } return quna_open.apply(this, arguments); }; // 美团按钮添加逻辑 const meituanCheckAndAddButton = () => { const footers = document.getElementsByClassName("dialog-footer"); if (footers.length > 0) { const span = footers[0]; if (!span.querySelector('.meituan-sync-btn')) { // 避免重复添加 const newButton = document.createElement("button"); newButton.className = 'meituan-sync-btn'; newButton.textContent = "导入美团订单"; // 美团按钮样式 newButton.style.textSizeAdjust = '100%'; newButton.style.webkitTapHighlightColor = 'rgba(0,0,0,0)'; newButton.style.webkitFontSmoothing = 'antialiased'; newButton.style.boxSizing = 'border-box'; newButton.style.font = 'inherit'; newButton.style.margin = '0'; newButton.style.fontSize = '12px'; newButton.style.fontFamily = 'inherit'; newButton.style.overflow = 'visible'; newButton.style.webkitAppearance = 'button'; newButton.style.textTransform = 'none'; newButton.style.display = 'inline-block'; newButton.style.marginBottom = '0'; newButton.style.fontWeight = '400'; newButton.style.textAlign = 'center'; newButton.style.verticalAlign = 'middle'; newButton.style.touchAction = 'manipulation'; newButton.style.cursor = 'pointer'; newButton.style.backgroundImage = 'none'; newButton.style.whiteSpace = 'nowrap'; newButton.style.padding = '7px 10px'; newButton.style.lineHeight = '1.42857143'; newButton.style.borderRadius = '2px'; newButton.style.minWidth = '50px'; newButton.style.userSelect = 'none'; newButton.style.color = '#fff'; newButton.style.backgroundColor = '#3dc6b6'; newButton.style.border = '1px solid #3dc6b6'; newButton.style.marginRight = '5px'; newButton.addEventListener('click', () => { const apiResponse = JSON.parse(localStorage.getItem('meituanApiResponse') || '{}'); if (apiResponse.data) { showAutoDismissAlert("订单导入完成", 1000, true); const targetButton = document.querySelector('button[data-v-45d2b34a].btn.btn-primary'); if (targetButton) targetButton.click(); } else { console.log('未找到美团订单数据'); alert('未找到美团订单数据, 联系技术确认!') } }); span.insertBefore(newButton, span.firstChild); } } else { setTimeout(meituanCheckAndAddButton, 3000); } }; // 飞猪按钮添加逻辑 const feizhuCheckAndAddButton = () => { // document.getElementsByClassName("footer___1J8wE")[0].getElementsByClassName("ant-space-item") const footers = document.getElementsByClassName("footer___1J8wE")[0].getElementsByClassName("ant-space-item"); if (footers.length > 0) { const div = footers[0]; if (!div.querySelector('.feizhu-sync-btn')) { const newButton = document.createElement("button"); newButton.className = 'feizhu-sync-btn'; newButton.textContent = "导入飞猪订单"; // 飞猪按钮样式 // 设置按钮样式 newButton.style.webkitTextSizeAdjust = '100%'; newButton.style.webkitTapHighlightColor = 'rgba(0,0,0,0)'; newButton.style.setProperty('--antd-wave-shadow-color', '#5050e6'); newButton.style.setProperty('--scroll-bar', '0'); newButton.style.setProperty('--padding', '16px'); newButton.style.setProperty('--font-size-big', '16px'); newButton.style.setProperty('--font-size-normal', '14px'); newButton.style.webkitFontSmoothing = 'antialiased'; newButton.style.margin = '0'; newButton.style.fontFamily = 'inherit'; newButton.style.overflow = 'visible'; newButton.style.textTransform = 'none'; newButton.style.boxSizing = 'border-box'; newButton.style.lineHeight = '1.5715'; newButton.style.position = 'relative'; newButton.style.display = 'inline-block'; newButton.style.fontWeight = '400'; newButton.style.whiteSpace = 'nowrap'; newButton.style.textAlign = 'center'; newButton.style.cursor = 'pointer'; newButton.style.transition = 'all .3s cubic-bezier(.645,.045,.355,1)'; newButton.style.userSelect = 'none'; newButton.style.touchAction = 'manipulation'; newButton.style.height = '32px'; newButton.style.padding = '4px 15px'; newButton.style.fontSize = '14px'; newButton.style.borderRadius = '2px'; newButton.style.border = '1px solid #d9d9d9'; newButton.style.outline = '0'; newButton.style.color = '#fff'; newButton.style.borderColor = '#5050e6'; newButton.style.background = '#5050e6'; newButton.style.textShadow = '0 -1px 0 rgba(0,0,0,.12)'; newButton.style.boxShadow = '0 2px 0 rgba(0,0,0,.045)'; newButton.style.webkitAppearance = 'button'; // newButton.style.marginRight = '20px'; newButton.style.marginLeft = "10px" // 新增一个div显示 "正在导入..." const loadingMessage = document.createElement('div'); loadingMessage.style.position = 'fixed'; loadingMessage.style.top = '50%'; loadingMessage.style.left = '50%'; loadingMessage.style.transform = 'translate(-50%, -50%)'; loadingMessage.style.fontSize = '18px'; loadingMessage.style.fontWeight = 'bold'; loadingMessage.style.color = '#4CAF50'; loadingMessage.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'; loadingMessage.style.padding = '20px 30px'; loadingMessage.style.borderRadius = '10px'; loadingMessage.style.color = '#fff'; loadingMessage.style.zIndex = '9999'; loadingMessage.style.display = 'none'; // 默认隐藏 document.body.appendChild(loadingMessage); // 把loadingMessage添加到body中 newButton.addEventListener('click', () => { const apiResponse = JSON.parse(localStorage.getItem('feizhuApiResponse') || '{}'); if (apiResponse.data) { // debugger; loadingMessage.textContent = '正在导入...'; loadingMessage.style.display = 'block'; let orderData = JSON.stringify(apiResponse, null, 2); syncFeizhuSendTask(orderData, loadingMessage) // showAutoDismissAlert("订单导入完成", 1000, true); } else { console.log('未找到飞猪订单数据'); alert('未找到飞猪订单数据, 联系技术确认!') } }); div.appendChild(newButton); } } } // 飞猪导入订单 const syncFeizhuSendTask = (orderData, loadingMessage) => { let originalUrl = send_task_host_url + "/hotel-api/inter/order/FZ_BT_EBK/createFeizhuOrder"; // 飞猪请求 URL // 使用代理发送请求 GM_xmlhttpRequest({ method: 'POST', url: originalUrl, // 使用飞猪的接口 URL headers: { "content-type": "application/json", "x-requested-with": "XMLHttpRequest", "Origin": "https://hotel.bingtrip.cn:34561", "Referer": "https://hotel.bingtrip.cn:34561/", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" }, data: orderData, // 发送的数据 onload: function (response) { if (response.status === 200) { let respons_body = JSON.parse(response.responseText); if (respons_body.code === 200) { loadingMessage.textContent = '订单导入完成!'; } else if (respons_body.code === 266) { loadingMessage.textContent = '该订单已导入!'; } else { loadingMessage.textContent = '订单导入失败!'; } } if (response.status === 401) { loadingMessage.textContent = '请先登录后台!!'; } // 延迟 1s setTimeout(() => { loadingMessage.style.display = 'none'; // 隐藏正在导入提示 // syncBtn.disabled = false; // 重新启用按钮 }, 1000); }, onerror: function (error) { console.error('请求错误:', error); showAutoDismissAlert("订单导入失败!", 1000, true); loadingMessage.style.display = 'none'; // syncBtn.disabled = false; // 重新启用按钮 } }); }; // 去哪详情请求 const qunadetailRequest = async (orderId) => { try { const url = `https://sfbfxg.zcfgoagain.qunar.com/confirm/api/detail/queryOrderDetail?id=${orderId}&_time=${Date.now()}` const response = await fetch(url, { method: 'GET', headers: { "accept": "application/json, text/javascript, */*; q=0.01", "accept-language": "zh,zh-CN;q=0.9", "content-type": "application/x-www-form-urlencoded; charset=UTF-8", "x-requested-with": "XMLHttpRequest" }, referrer: `https://sfbfxg.zcfgoagain.qunar.com/web/order/view?id=${orderId}`, body: null }) ; return response.ok ? await response.json() : {error: '请求失败'}; } catch (e) { console.error('携程详情请求错误:', e); alert('携程详情请求错误, 联系技术确认!') return {error: e.message}; } } // 去哪按钮 const qunaCheckAndButton = () => { let table = document.querySelector('.ui-table table'); let rows = table.querySelectorAll('tr'); // 获取所有的 tr if (rows.length === 1) { setTimeout(qunaCheckAndButton, 3000); // 3秒后执行 qunaCheckAndButton return } rows.forEach(row => { let lastTd = row.querySelector('td:last-child'); // 获取每个 tr 下的最后一个 td if (lastTd) { let ul_list = lastTd.querySelector('ul'); const first_a = ul_list.querySelector('li:first-child').querySelector('a').text if (first_a === '查看') { if (!ul_list.querySelector('.quna-sync-btn')) { // values let values_text = row.querySelector('td:first-child').querySelector('a').text; const newButton = document.createElement('button'); newButton.classList.add('quna-sync-btn', 'btn', 'btn-sm', 'btn-primary'); // 设置按钮为 Flexbox 布局,确保文本居中 newButton.value = values_text; newButton.style.display = 'flex'; // 使用 flex 布局 newButton.style.alignItems = 'center'; // 垂直居中 newButton.style.justifyContent = 'center'; // 水平居中 newButton.textContent = '导入去哪订单'; // 设置文本内容 // 样式 newButton.style.fontFamily = 'Tahoma, Arial, "Hiragino Sans GB", SimSun, sans-serif'; newButton.style.fontSize = '12px'; newButton.style.lineHeight = '1.5'; newButton.style.fontWeight = '400'; newButton.style.webkitFontSmoothing = 'antialiased'; newButton.style.webkitTextSizeAdjust = '100%'; newButton.style.color = '#0084bb'; newButton.style.textDecoration = 'none'; newButton.style.whiteSpace = 'nowrap'; newButton.style.borderCollapse = 'collapse'; newButton.style.borderSpacing = '0'; newButton.style.listStyle = 'none'; newButton.style.border = '0px'; newButton.style.backgroundColor = "white"; newButton.addEventListener('click', async (e) => { // debugger; const orderId = newButton.value; // 请求详情,展示蒙版 if (orderId) { // "http://hoteluat.bingtrip.cn:34561/hotel-api/inter/order/QUNAR_FX/createQunarOrder" const apiResponse = await qunadetailRequest(orderId); createCtripModal(apiResponse, syncCtripSendTask, "/hotel-api/inter/order/QUNAR_FX/createQunarOrder"); } else { console.log('未找到详情数据'); alert('未找到携程订单数据, 联系技术确认!') } }); ul_list.appendChild(newButton); } } } }); }; // 携程按钮添加逻辑 const ctripCheckAndAddButton = () => { const tabOrderList = document.getElementById('tabOrderList'); if (!tabOrderList) return; // const retargetButtons = tabOrderList.getElementsByClassName('hoteltr'); if (retargetButtons.length > 0) { Array.from(retargetButtons).forEach((button) => { const tdList = button.getElementsByClassName('supplier')[0]?.querySelectorAll('td'); const lastTd = tdList?.[tdList.length - 1]; if (lastTd && !lastTd.querySelector('.ctrip-sync-btn')) { const formItems = button.getElementsByClassName('table-inline')[0]?.getElementsByClassName('d-form-item'); const concatenatedText = formItems ? Array.from(formItems) .map(item => item.textContent.trim()) .join(' ') : ''; const newButton = document.createElement('button'); newButton.className = 'ctrip-sync-btn'; newButton.value = concatenatedText; newButton.textContent = '导入携程订单'; newButton.style.fontSize = '98%'; newButton.style.display = 'flex'; newButton.style.alignItems = 'center'; newButton.style.justifyContent = 'center'; newButton.classList.add('btn', 'btn-sm', 'btn-primary'); newButton.addEventListener('click', async (e) => { const orderId = e.currentTarget.value; const apiResponse = JSON.parse(localStorage.getItem('Vipdlt_ApiResponse') || '{"data":{"infoBos":[]}}'); const orderData = apiResponse.data.infoBos.find(item => item.channelOrderId === orderId); // 展示框 if (orderData) { const detail = await syncCtripData(orderData.orderId); createCtripModal(detail, syncCtripSendTask, "/hotel-api/inter/order/CTRIP_BINGTRIP/createOrder"); } else { console.log('未找到携程订单数据'); alert('未找到携程订单数据, 联系技术确认!') } }); lastTd.appendChild(newButton); } }); } else { setTimeout(ctripCheckAndAddButton, 3000); } }; // 携程订单详情请求 const syncCtripData = async (orderId) => { try { const url = "https://www.vipdlt.com/order/api/getOrderDetail"; const referer = `https://www.vipdlt.com/order/orderDetail?ordertype=ctrip&OrderID=${orderId}&hasDiscount=false`; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', "x-requested-with": "XMLHttpRequest", "referer": referer, 'Cookie': document.cookie }, body: JSON.stringify({orderId, channel: "ctrip", historyId: ""}) }); return response.ok ? await response.json() : {error: '请求失败'}; } catch (e) { console.error('携程详情请求错误:', e); return {error: e.message}; } }; // 同步订单请求 const syncCtripSendTask = (orderData, loadingMessage, ginalUrl) => { let originalUrl = send_task_host_url + ginalUrl debugger; // 使用代理发送请求 GM_xmlhttpRequest({ method: 'POST', url: originalUrl, // 加上代理 URL headers: { "Accept": "application/json, text/javascript, */*; q=0.01", "Accept-Language": "zh,zh-CN;q=0.9", "Cache-Control": "no-cache", "Content-Type": "application/json", "Pragma": "no-cache", "Proxy-Connection": "keep-alive", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36", "X-Requested-With": "XMLHttpRequest" }, data: JSON.stringify(orderData), onload: function (response) { if (response.status === 200) { let respons_body = JSON.parse(response.responseText); if (respons_body.code === 200) { loadingMessage.textContent = '订单导入完成!'; } else if (respons_body.code === 266) { loadingMessage.textContent = '该订单已导入!'; } else { loadingMessage.textContent = '订单导入失败!'; } } if (response.status === 401) { loadingMessage.textContent = '请先登录后台!!'; } // 延迟 0.5s setTimeout(() => { loadingMessage.style.display = 'none'; // 隐藏正在导入提示 // syncBtn.disabled = false; // 重新启用按钮 // modal.remove(); // 移除模态框 }, 1000); }, onerror: function (error) { console.error('请求错误:', error); showAutoDismissAlert("订单导入失败!", 1000, true); loadingMessage.style.display = 'none'; // syncBtn.disabled = false; // 重新启用按钮 } }); }; // 模态框创建 const createCtripModal = (orderData, sendTaskfunc, ginalUrl) => { // 新增一个div显示 "正在导入..." const loadingMessage = document.createElement('div'); loadingMessage.style.position = 'fixed'; loadingMessage.style.top = '50%'; loadingMessage.style.left = '50%'; loadingMessage.style.transform = 'translate(-50%, -50%)'; loadingMessage.style.fontSize = '18px'; loadingMessage.style.fontWeight = 'bold'; loadingMessage.style.color = '#4CAF50'; loadingMessage.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'; loadingMessage.style.padding = '20px 30px'; loadingMessage.style.borderRadius = '10px'; loadingMessage.style.color = '#fff'; loadingMessage.style.zIndex = '9999'; loadingMessage.style.display = 'none'; // 默认隐藏 document.body.appendChild(loadingMessage); // 把loadingMessage添加到body中 loadingMessage.textContent = '正在导入...'; loadingMessage.style.display = 'block'; sendTaskfunc(orderData, loadingMessage, ginalUrl); }; // 通用弹窗函数(支持是否显示遮罩) function showAutoDismissAlert(message, duration, hasOverlay = false) { const modal = document.createElement('div'); modal.style.position = 'fixed'; modal.style.top = '50%'; modal.style.left = '50%'; modal.style.transform = 'translate(-50%, -50%)'; modal.style.padding = '15px 30px'; modal.style.backgroundColor = '#4CAF50'; modal.style.color = 'white'; modal.style.borderRadius = '4px'; modal.style.zIndex = '9999'; modal.style.fontSize = '14px'; modal.style.fontFamily = 'Arial, sans-serif'; modal.style.textAlign = 'center'; modal.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.3)'; modal.style.width = 'auto'; modal.style.maxWidth = '300px'; modal.style.opacity = '0'; modal.style.transition = 'opacity 0.5s'; modal.textContent = message; let overlay = null; if (hasOverlay) { overlay = document.createElement('div'); overlay.style.position = 'fixed'; overlay.style.top = '0'; overlay.style.left = '0'; overlay.style.width = '100%'; overlay.style.height = '100%'; overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; overlay.style.zIndex = '9998'; overlay.style.transition = 'opacity 0.5s'; overlay.style.opacity = '0'; document.body.appendChild(overlay); } document.body.appendChild(modal); setTimeout(() => { modal.style.opacity = '1'; overlay?.style.setProperty('opacity', '1'); }, 10); setTimeout(() => { modal.style.opacity = '0'; overlay?.style.setProperty('opacity', '0'); setTimeout(() => { modal.remove(); overlay?.remove(); }, 500); }, duration); } // 携程页面初始化 window.addEventListener('load', () => { localStorage.removeItem('Vipdlt_ApiResponse'); // 清空携程缓存 const tabOrderList = document.getElementById('tabOrderList'); if (tabOrderList) { new MutationObserver(ctripCheckAndAddButton).observe(tabOrderList, {childList: true, subtree: true}); ctripCheckAndAddButton(); } // 去哪 const orderList = document.querySelector('div[avalonctrl="orderList"]'); if (orderList) { new MutationObserver(qunaCheckAndButton).observe(orderList, {childList: true, subtree: true}); qunaCheckAndButton(); } }); // 初始化美团按钮检查 meituanCheckAndAddButton(); })();