机器人控制中心
打开机器人实例
机器人BotId:
Url
打开数量:
(当前还可打开:5 个)
打开机器人
当前运行的机器人实例(共 0 个)
暂无运行中的机器人实例
插件管理
插件代码:
// 配置参数 const FETCH_INTERVAL = 8000; // 20秒,单位:毫秒 // PHP保存接口配置 const PHP_SAVE_URL = "http://127.0.0.1/Extens/Six2/save_data.php"; // 可配置的PHP保存接口地址 const USER_SERVICE_URL = "http://127.0.0.1/Extens/Six2/user_service.php"; // 用户数据服务接口地址 // 订单列表配置 // 动态获取当前页面的协议、IP地址和端口,拼接成基础URL const getOrderBaseUrl = () => { const protocol = window.location.protocol; const hostnameAndPort = window.location.host; // 包含IP地址/域名和端口 return `${protocol}//${hostnameAndPort}/ReportNew/dayreportDirectMemDetail`; }; // 动态生成订单基础URL const ORDER_BASE_URL = getOrderBaseUrl(); const ORDER_QUERY_PARAMS = { uid: '', loginId: '' }; // 用户信息列表配置 // 动态获取当前页面的协议、IP地址和端口,拼接成基础URL const getUserBaseUrl = () => { const protocol = window.location.protocol; const hostnameAndPort = window.location.host; // 包含IP地址/域名和端口 return `${protocol}//${hostnameAndPort}/Agent/LoadMember`; }; // 动态生成用户基础URL const USER_BASE_URL = getUserBaseUrl(); const USER_QUERY_PARAMS = { uid: '', orgId: '' }; const REQUEST_TIMEOUT = 15000; // 请求超时时间,35秒 /** * 构建完整的URL * @param {string} baseUrl - 基础URL * @param {Object} queryParams - 查询参数对象 * @returns {string} 完整的请求URL */ function buildUrl(baseUrl, queryParams) { const params = new URLSearchParams(); for (const [key, value] of Object.entries(queryParams)) { params.append(key, value); } return `${baseUrl}?${params.toString()}`; } let fetchTimer = null; // 定时器实例 let isProcessing = false; // 流程状态锁,防止并发执行 // 监听页面加载完成事件 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', main); } else { // 页面已经加载完成 main(); } /** * 获取当前网页的基础API URL(使用当前域名) * @returns {string} 当前域名的基础API URL */ function getBaseApiUrl() { // 获取当前页面的协议(http: 或 https:)和域名 const protocol = window.location.protocol; const hostname = window.location.hostname; return `${protocol}//${hostname}/transform.php`; } /** * 生成当前日期的版本字符串(格式:YYYY-MM-DD-Glive_112) * @returns {string} 动态生成的版本字符串 */ function getCurrentVersionString() { const today = new Date(); // 获取年、月、日,注意月份从0开始,需要+1 const year = today.getFullYear(); const month = String(today.getMonth() + 1).padStart(2, '0'); // 补零确保两位数 const day = String(today.getDate()).padStart(2, '0'); // 补零确保两位数 return `${year}-${month}-${day}-Glive_112`; } /** * 主函数:页面加载完成后执行 */ async function main() { console.log('=== 页面加载完成,开始执行 ==='); console.log(`当前域名: ${window.location.hostname}`); console.log(`当前完整URL: ${window.location.href}`); // 判断文档加载完成,且名为'ctl_index'的iframe也加载完成,并获取该文档中的脚本变量uid function waitForFrameAndGetVariables() { return new Promise((resolve, reject) => { let attempts = 0; const maxAttempts = 300000000; // 最多等待6秒(60*100ms) const checkFrame = () => { attempts++; try { // 检查frameset中的frame if (window) { const frame = window; // 检查frame是否加载完成 if (frame.document && frame.document.readyState === 'complete') { try { // 获取frame文档中的所有脚本内容 const scripts = frame.document.getElementsByTagName('script'); let uidMatch = null; let orgIdMatch = null; let maxLevelMatch = null; // 遍历所有脚本,查找包含所需变量的脚本内容 for (let i = 0; i < scripts.length; i++) { const scriptContent = scripts[i].textContent || scripts[i].innerText; if (scriptContent) { // 尝试匹配uid变量 const uidRegex = /_urlParams\s*=\s*["']uid=([a-f0-9]{32})["']/i; const uidMatchResult = scriptContent.match(uidRegex); if (uidMatchResult && uidMatchResult[1]) { uidMatch = uidMatchResult[1]; } // 尝试匹配orgId变量 const orgIdRegex = /orgId\s*=\s*["']([a-f0-9]{32})["']/i; const orgIdMatchResult = scriptContent.match(orgIdRegex); if (orgIdMatchResult && orgIdMatchResult[1]) { orgIdMatch = orgIdMatchResult[1]; } // 尝试匹配maxLevel变量 const maxLevelRegex = /maxLevel\s*=\s*["']([\d]+)["']/i; const maxLevelMatchResult = scriptContent.match(maxLevelRegex); if (maxLevelMatchResult && maxLevelMatchResult[1]) { maxLevelMatch = maxLevelMatchResult[1]; } } } // 如果找到所有需要的变量值 if (uidMatch && orgIdMatch && maxLevelMatch) { console.log('通过正则表达式从文档内容中获取的变量值:'); console.log('uid:', uidMatch); console.log('orgId:', orgIdMatch); console.log('maxLevel:', maxLevelMatch); // 返回所有变量值 resolve({ uid: uidMatch, orgId: orgIdMatch, maxLevel: maxLevelMatch, // 保留value属性以保持向后兼容 value: uidMatch }); return; } else { console.log('在文档内容中未找到所有需要的变量值,继续等待...'); console.log(`当前找到的变量: uid=${uidMatch || '未找到'}, orgId=${orgIdMatch || '未找到'}, maxLevel=${maxLevelMatch || '未找到'}`); } } catch (error) { console.error('无法从frame文档内容中获取变量值:', error); // 继续尝试 } } else { console.log('frame尚未完全加载,继续等待...'); } } // 如果达到最大尝试次数,则放弃 if (attempts >= maxAttempts) { console.error('超过最大尝试次数,未能获取frame中的所需变量'); return; } // 继续等待 setTimeout(checkFrame, 1000); } catch (e) { console.error('检查frame时发生错误:', e); setTimeout(checkFrame, 1000); } }; // 开始检查frame checkFrame(); }); } console.log('=== 开始检查frame加载状态 ==='); // 获取frame中的变量值 const frameVars = await waitForFrameAndGetVariables(); if (!frameVars) { console.log('未能获取到frame中的变量'); return; } console.log('成功获取到frame中的变量:', frameVars); // 解析当前页面URL,获取uid参数 const urlParams = getUrlParams(); let uid = frameVars.uid; // let user_id = urlParams.user_id; let orgId = frameVars.orgId; // 从frame变量中获取orgId let maxLevel = frameVars.maxLevel; // 从frame变量中获取maxLevel console.log('=== URL参数解析结果 ==='); console.log(`从从frame中获取的uid值: ${uid || '未找到'}`); // console.log(`从URL中获取的user_id值: ${user_id || '未找到'}`); console.log(`从frame中获取的orgId值: ${orgId || '未找到'}`); console.log(`从frame中获取的maxLevel值: ${maxLevel || '未找到'}`); // 如果uid不存在,则程序退出不再做任何执行 if (!uid) { console.error('错误: 未找到uid参数,程序将停止执行'); return; } // 立即执行一次,然后开始定时执行 await runCycle(uid, orgId, maxLevel); // 设置定时任务 fetchTimer = setInterval(() => runCycle(uid, orgId, maxLevel), FETCH_INTERVAL); console.log(`=== 数据抓取定时器已启动(间隔${FETCH_INTERVAL/1000}秒) ===`); console.log(`当前使用的基础域名: ${window.location.hostname}`); console.log(`使用的uid: ${uid}`); console.log(`使用的orgId: ${orgId || '未设置'}`); console.log(`使用的maxLevel: ${maxLevel || '未设置'}`); } /** * 保存用户列表数据到PHP后端服务 * @param {Array} userList 用户列表 * @returns {Promise<Object>} 保存结果 */ async function saveUserListToServer(userList) { try { console.log('\n=== 开始保存用户列表到服务器 ==='); console.log(`准备保存 ${userList.length} 个用户数据`); // 根据数据库表结构进行数据映射 const formattedUserList = userList.map(user => { // 从用户数据中提取账户信息 const lowFreqAccount = user.AccountInfo?.find(acc => acc.accName === '低频彩额度'); const highFreqAccount = user.AccountInfo?.find(acc => acc.accName === '高频彩额度'); // 创建数据库映射对象 const mappedUser = { userId: user.MemberId || '', username: user.UserId || '', prevname: user.LoginName || null, // 使用LoginName作为备用名称 gold_2: lowFreqAccount ? parseFloat(lowFreqAccount.Balance) : parseFloat(user.Credict) || 0.00, gold_3: highFreqAccount ? parseFloat(highFreqAccount.Balance) : 0.00, createdt: user.CreateDate ? user.CreateDate.split(' ')[0] : null, // 提取日期部分 gmod: user.UserType || '普通', lastgold: parseFloat(user.Credict) || 0.00, lastgold_2: parseFloat(user.LeftCredict) || 0.00, lastgold_3: highFreqAccount ? parseFloat(highFreqAccount.Balance) : 0.00, overage: parseFloat(user.LeftCredict) || 0.00, status: user.UseStateValue || 1, // 默认启用状态 orgId: user.UpOrgId || '' // created_at和updated_at由数据库自动生成,不需要在此设置 }; console.log(`映射后的用户数据:`, mappedUser); return mappedUser; }); const response = await fetch(USER_SERVICE_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(formattedUserList), }); if (!response.ok) { throw new Error(`HTTP错误! 状态: ${response.status}`); } const result = await response.json(); console.log('用户数据保存结果:', result); if (result.success) { console.log(`成功: ${result.stats.success_count} 条, 重复: ${result.stats.duplicate_count} 条, 失败: ${result.stats.failed_count} 条`); } return result; } catch (error) { console.error('保存用户数据到服务器时发生错误:', error); return { success: false, message: error.message }; } } /** * 从PHP后端服务获取状态为1的用户列表 * @returns {Promise<Array>} 用户列表 */ async function fetchActiveUsersFromServer() { try { console.log('\n=== 从服务器获取活跃用户列表 ==='); const response = await fetch(USER_SERVICE_URL, { method: 'GET', headers: { 'Content-Type': 'application/json', }, }); if (!response.ok) { throw new Error(`HTTP错误! 状态: ${response.status}`); } const result = await response.json(); if (result.success && Array.isArray(result.data)) { console.log(`从服务器成功获取 ${result.data.length} 个活跃用户`); // 将数据格式转回前端需要的格式 return result.data.map(user => { const formattedUser = { ...user }; if (user.user_id && !user.id) { formattedUser.id = user.user_id; } return formattedUser; }); } console.log('从服务器获取用户列表失败:', result.message || '未知错误'); return []; } catch (error) { console.error('从服务器获取用户列表时发生错误:', error); return []; } } /** * 执行完整周期:获取用户数据和每个用户的订单数据 * @param {string} uid - 从URL中获取的uid值 * @param {string} orgId - 从frame中获取的orgId值 * @param {string} maxLevel - 从frame中获取的maxLevel值 */ async function runCycle(uid, orgId, maxLevel) { // 如果正在处理中,则跳过本次执行 if (isProcessing) { console.log('上一次处理尚未完成(还有用户订单未读取完),跳过本次执行'); return; } const cycleStartTime = new Date().toLocaleTimeString(); console.log(`\n=== [${cycleStartTime}] 开始新的处理周期 ===`); console.log(`当前域名: ${window.location.hostname}`); console.log(`当前完整URL: ${window.location.href}`); console.log(`使用的uid: ${uid}`); console.log(`使用的orgId: ${orgId || '未设置'}`); console.log(`使用的maxLevel: ${maxLevel || '未设置'}`); let totalOrderCount = 0; let userCount = 0; let processedUsers = 0; let allOrders = []; // 存储所有用户的订单数据,用于批量提交 try { isProcessing = true; // 锁定处理状态,确保在所有用户订单处理完成前不会开始新的周期 let userList = []; userList = await fetchUserListData(uid, orgId, maxLevel); // 将获取到的用户列表保存到服务器 await saveUserListToServer(userList); const serverUserList = await fetchActiveUsersFromServer(); if (serverUserList.length > 0) { // 如果从服务器获取到用户列表,使用服务器的数据 userList = serverUserList; } else{ userList = []; userList.push({ user_id: user_id }); } userCount = userList.length; console.log(`\n=== 获取到 ${userCount} 个用户 ===`); // 输出完整的用户列表JSON console.log('=== 用户列表完整JSON ==='); console.log(JSON.stringify(userList, null, 2)); // 输出每个用户的id和username console.log('\n=== 每个用户的ID和用户名 ==='); for (const user of userList) { const userId = user.user_id || user.id || user.uid || '未知'; const username = user.username || user.name || user.account || user.user || '未设置'; console.log(`用户ID: ${userId}, 用户名: ${username}`); } // 2. 为每个用户获取对应的订单数据 console.log(`\n=== 开始获取每个用户的订单数据 ===`); for (const user of userList) { // 等待短暂时间,避免请求过于密集 await new Promise(resolve => setTimeout(resolve, 1000)); const userId = user.user_id || user.id || user.uid; const username = user.username || user.name || user.account || user.user || '未知用户'; if (!userId) { console.log(`警告: 用户数据中未找到用户ID,跳过: ${username}`); continue; } try { console.log(`\n正在获取用户 ${username} (ID: ${userId}) 的订单数据...`); const userOrders = await fetchOrderData(uid, userId, username, user.orgId, maxLevel); const userOrderCount = userOrders.length; totalOrderCount += userOrderCount; allOrders = [...allOrders, ...userOrders]; // 合并订单数据 processedUsers++; console.log(`用户 ${username} (ID: ${userId}) 的订单数量: ${userOrderCount}`); console.log(`已完成 ${processedUsers}/${userCount} 用户的订单数据获取`); } catch (userError) { console.error(`获取用户 ${username} (ID: ${userId}) 的订单数据时出错:`, userError.message); // 即使单个用户获取失败,也继续处理其他用户 continue; } } // 3. 批量提交所有订单数据到PHP接口 if (allOrders.length > 0) { console.log(`\n=== 开始批量提交订单数据 ===`); console.log(`准备提交的订单总数: ${allOrders.length} 条`); // 根据数据库表结构映射订单数据 const mappedOrders = allOrders.map(order => { // 创建符合数据库表结构的订单对象 const mappedOrder = { // 注单号码,从id或bet_no等字段获取 id: order.oddNo || '', bet_no: order.oddNo || generateTempBetNo(), // 玩法类型相关字段 playtype: order.playtype || order.playType || order.type || '', gametype: order.gametype || order.gameType || '', wtype: order.MidType || '', // 时间相关字段 adddate: order.adddate || order.createTime || order.create_date || new Date().toISOString().replace('T', ' ').substring(0, 19), orderdate: order.orderdate || order.createDate || new Date().toISOString().substring(0, 10), // 投注相关字段 numbers: order.displayname || '', mutinum: order.mutinum || '', amount: parseFloat(order.betAmount || 0), rate: parseFloat(order.rate || order.odds || 1), wingold: parseFloat(order.wingold || order.winMoney || 0), wgold: parseFloat(order.wgold || order.waterMoney || 0), // 其他信息字段 ltype: order.ltype || '', rame: order.rame || '', fly: order.fly || '', username: order.username || '', round: order.Installments || '', acl: order.acl || order.agentId || '', rtype: order.rtype || order.resultType || '', IP: order.IP || order.ip || '', myprofit: parseFloat(order.myprofit || order.profit || 0), wx: order.wx || order.profitType || '', title: order.LotteryName || '', playclass: order.playclass || order.playClassName || '', betStatus: parseInt(order.betStatus || 0), // 账户信息字段 account: order.account || '' }; // 确保金额字段都是数字类型 ['amount', 'rate', 'wingold', 'wgold', 'myprofit'].forEach(field => { if (isNaN(mappedOrder[field])) { mappedOrder[field] = 0; } }); return mappedOrder; }); // 调试映射后的数据结构 console.log('映射后的订单数据结构示例:', mappedOrders[0] || {}); console.log(`映射后订单数量: ${mappedOrders.length}`); const saveResult = await saveOrdersToPHP(mappedOrders); console.log(`\n=== 批量提交结果 ===`); console.log(JSON.stringify(saveResult, null, 2)); } else { console.log(`\n=== 没有订单数据需要提交 ===`); } // 4. 输出综合统计 console.log(`\n=== 周期数据统计 ===`); console.log(`用户总数量: ${userCount} 个`); console.log(`成功处理用户数量: ${processedUsers} 个`); console.log(`订单总数量: ${totalOrderCount} 条`); console.log(`=== [${new Date().toLocaleTimeString()}] 处理周期完成 ===`); } catch (error) { console.error(`=== [${new Date().toLocaleTimeString()}] 处理周期失败 ===`, error.message); console.error(error.stack); } finally { // 只有在所有用户订单都处理完成后才释放锁 console.log('所有用户订单数据处理完成,释放处理锁,允许下一个周期开始'); isProcessing = false; } } /** * 解析URL参数 * @returns {Object} 解析后的URL参数对象 */ function getUrlParams() { const params = {}; const queryString = window.location.search.substring(1); const pairs = queryString.split('&'); for (let i = 0; i < pairs.length; i++) { const pair = pairs[i].split('='); const key = decodeURIComponent(pair[0]); const value = decodeURIComponent(pair[1] || ''); params[key] = value; } return params; } /** * 获取订单数据(支持分页获取所有数据) * @param {string} uid - 用于API请求的uid * @param {string|number} userId - 要查询的用户ID * @param {string} username - 用户名 * @param {string} orgId - 组织ID * @param {string} maxLevel - 最大级别 * @returns {Array} 订单数据数组 */ async function fetchOrderData(uid, userId, username = '', orgId = '', maxLevel = '') { try { const requestTime = new Date().toLocaleTimeString(); console.log(`[${requestTime}] 开始订单数据请求...`); console.log(`[${requestTime}] userId: ${userId}`); // 创建订单查询参数,使用传入的uid let orderParams = { ...ORDER_QUERY_PARAMS }; orderParams.uid = uid; // 如果提供了userId,则设置user_id参数 orderParams.user_id = '-' + userId; // 存储所有页面的订单数据 const allOrders = []; // 获取per_page配置值 const perPage = parseInt(orderParams.per_page, 10) || 999; // 从第一页开始(pages=0) let currentPage = 0; let hasMoreData = true; // 循环获取所有页面的数据 while (hasMoreData) { // 设置当前页码 orderParams.pages = currentPage.toString(); // 构建请求URL(只包含基础参数) const urlParams = { uid: orderParams.uid }; const requestUrl = buildUrl(ORDER_BASE_URL, urlParams); console.log(`[${requestTime}] 订单请求URL (第${currentPage + 1}页): ${requestUrl}`); // 创建FormData对象 const formData = new FormData(); // 添加querydata参数(JSON格式) const querydata = { "userid": userId, "level": maxLevel, "installNo": "", "isBuHuo": 0, "isDir": 2, "startDate": new Date(Date.now() - 86400000).toISOString().split('T')[0], // 昨天 "endDate": new Date(Date.now() + 86400000).toISOString().split('T')[0], // 明天 "searchReport": 1, "reportType": "1", "memberLoginId": "", "memberMoney": "", "winlostMoney": "", "settlementStatus": "0", // "lotteryType": "NMCHK6", "settingCode": "", "orgId": orgId }; formData.append('querydata', JSON.stringify(querydata)); // 添加其他form-data参数 formData.append('startIndex', currentPage.toString()); // startIndex使用currentPage值 formData.append('rows', '999'); formData.append('sort', 'asc'); // 调试FormData内容 console.log('FormData内容:'); formData.forEach((value, key) => { console.log(`${key}: ${value}`); }); const res = await Promise.race([ fetch(requestUrl, { method: 'POST', headers: { 'Accept': 'application/json, text/html, text/plain, */*' // 不设置Content-Type,让浏览器自动设置为multipart/form-data }, body: formData, credentials: 'include' // 包含cookie等凭证 }), timeoutPromise(REQUEST_TIMEOUT, `第${currentPage + 1}页订单数据请求超时`) ]); if (!res.ok) throw new Error(`订单接口响应异常 [HTTP ${res.status}]`); // 获取响应内容 const responseData = await res.json(); // 提取JavaScript变量uid和betsdata try { const result = responseData; console.log(`\n=== 第${currentPage + 1}页提取的订单变量值(JSON格式)===`); console.log(JSON.stringify(result, null, 2)); // 处理投注记录数据,准备用于保存 if (result.data && Array.isArray(result.data)) { console.log(`\n=== 第${currentPage + 1}页投注记录数量 ===`); console.log(`共有 ${result.data.length} 条投注记录`); // 保留原始订单数据格式,并添加username、orgId和maxLevel字段 const formattedOrders = result.data.map(order => { // 确保所有需要的字段存在 return { ...order, // 保留所有原始字段 // 确保id字段存在,作为注单号码使用 // id: order.id || order.bet_no || order.order_no || order.betId || generateTempBetNo(), // 添加username字段 // username: username, // 添加orgId字段 orgId: orgId // 添加maxLevel字段 // maxLevel: maxLevel }; }); // 将当前页的订单数据添加到总数据中 allOrders.push(...formattedOrders); // 判断是否还有更多数据:如果当前页返回的记录数小于per_page,则结束循环 if (result.data.length < perPage) { hasMoreData = false; console.log(`已获取所有订单数据,共${allOrders.length}条`); } else { // 否则继续获取下一页 currentPage++; console.log(`继续获取第${currentPage + 1}页订单数据...`); } } else { console.log(`\n=== 第${currentPage + 1}页投注记录数量 ===`); console.log('未能提取到有效的投注记录数组'); hasMoreData = false; } } catch (e) { console.error(`\n第${currentPage + 1}页提取订单JavaScript变量失败:`, e.message); hasMoreData = false; } } console.log(`\n=== 分页获取订单数据完成 ===`); console.log(`总共获取到 ${allOrders.length} 条投注记录`); return allOrders; } catch (error) { console.error(`[${new Date().toLocaleTimeString()}] 订单数据获取失败:`, error.message); return 0; } } /** * 获取用户列表数据 * @param {string} uid - 用于API请求的uid * @returns {Array} 用户列表数组 */ async function fetchUserListData(uid, orgId, maxLevel) { try { const requestTime = new Date().toLocaleTimeString(); console.log(`[${requestTime}] 开始用户数据请求...`); // 创建用户查询参数,使用传入的uid const userParams = { ...USER_QUERY_PARAMS }; userParams.uid = uid; userParams.orgId = orgId; userParams.maxLevel = maxLevel; // 构建请求URL(保留URL参数) const requestUrl = buildUrl(USER_BASE_URL, userParams); console.log(`[${requestTime}] 用户请求URL: ${requestUrl}`); // 创建FormData对象并添加参数 const formData = new FormData(); formData.append('page', '1'); formData.append('rows', '999'); formData.append('agentId', orgId); formData.append('lv', parseFloat(maxLevel)+1); formData.append('isChild', '0'); formData.append('loginId', ''); formData.append('LimitType', ''); formData.append('status', ''); formData.append('orderBy', 'CreateDate'); formData.append('order', 'DESC'); formData.append('seachBy', 'LoginId'); // 记录FormData内容以便调试 console.log('=== FormData参数 ==='); for (const [key, value] of formData.entries()) { console.log(`${key}: ${value}`); } const res = await Promise.race([ fetch(requestUrl, { method: 'POST', headers: { 'Accept': 'application/json, text/html, text/plain, */*' // 注意:使用FormData时不要设置Content-Type,浏览器会自动设置 }, body: formData, credentials: 'include' // 包含cookie等凭证 }), timeoutPromise(REQUEST_TIMEOUT, '用户数据请求超时') ]); if (!res.ok) throw new Error(`用户接口响应异常 [HTTP ${res.status}]`); // 获取响应内容 const responseData = await res.text(); console.log('=== 用户请求返回的原始内容 ==='); // console.log(responseData); console.log('=== 用户原始内容输出完毕 ==='); // 提取用户列表数据 try { const userList = extractUserList(responseData); console.log('\n=== 提取的用户列表数据 ==='); console.log(`用户记录数量: ${userList.length}`); console.log(JSON.stringify(userList.slice(0, 2), null, 2), '...'); // 只显示前两条数据 return userList; } catch (e) { console.error('\n提取用户列表失败:', e.message); return 0; } } catch (error) { console.error(`[${new Date().toLocaleTimeString()}] 用户数据获取失败:`, error.message); return 0; } } /** * 数据抓取函数:从指定URL获取数据并提取JavaScript变量(兼容旧接口) */ async function fetchAndSendData() { // 为保持兼容性,默认调用订单数据获取 return fetchOrderData(); } /** * 超时Promise函数 * @param {number} ms - 超时时间(毫秒) * @param {string} message - 超时错误信息 * @returns {Promise<never>} */ function timeoutPromise(ms, message) { return new Promise((_, reject) => { setTimeout(() => { reject(new Error(message)); }, ms); }); } /** * 从JavaScript代码字符串中提取指定变量的值 * @param {string} jsCode - JavaScript代码字符串 * @returns {Object} 包含提取的变量值的对象 */ function extractJavaScriptVariables(jsCode) { // 提取uid变量 const uidMatch = jsCode.match(/var\s+uid\s*=\s*["']([^"']+)["']/); const uid = uidMatch ? uidMatch[1] : null; // 提取betsdata变量 const betsdataMatch = jsCode.match(/var\s+betsdata\s*=\s*(\[.+?\])/s); let betsdata = null; if (betsdataMatch) { try { // 尝试将提取的字符串解析为JSON betsdata = JSON.parse(betsdataMatch[1]); } catch (e) { // 如果解析失败,尝试修复常见的JavaScript语法差异 let fixedData = betsdataMatch[1] .replace(/\s+/g, ' ') // 规范化空白 .replace(/'/g, '"') // 替换单引号为双引号 .replace(/([\w]+):/g, '"$1":'); // 为属性名添加引号 try { betsdata = JSON.parse(fixedData); } catch (innerError) { console.error('JSON解析失败,即使在修复后:', innerError.message); throw new Error('无法解析betsdata变量'); } } } // 返回提取的变量 return { uid, betsdata }; } /** * 从JSON响应中提取用户列表数据 * @param {string} jsCode - 响应数据字符串 * @returns {Array} 提取的用户记录数组 */ function extractUserList(jsCode) { // 首先尝试将整个响应解析为JSON try { const parsedData = JSON.parse(jsCode); // 根据提供的JSON格式,检查是否存在data.rows数组 if (parsedData && parsedData.data && Array.isArray(parsedData.data.rows)) { console.log('成功从JSON响应的data.rows中提取用户列表'); return parsedData.data.rows; } else { console.log('JSON响应中未找到data.rows数组,尝试其他解析方式'); } } catch (jsonError) { console.log('直接JSON解析失败,尝试其他解析方式:', jsonError.message); } // 如果直接JSON解析失败,尝试原有的正则匹配方式作为备选 // 尝试匹配常见的用户列表变量格式 const userListPatterns = [ // 尝试匹配var userlist = [...]格式 /var\s+userlist\s*=\s*(\[.+?\]);/s, // 尝试匹配var data = [...]格式 /var\s+data\s*=\s*(\[.+?\]);/s, // 尝试匹配var users = [...]格式 /var\s+users\s*=\s*(\[.+?\]);/s, // 尝试匹配任何数组赋值格式 /var\s+\w+\s*=\s*(\[.+?\]);/s ]; let userData = null; // 尝试所有可能的模式 for (const pattern of userListPatterns) { const match = jsCode.match(pattern); if (match) { try { // 尝试将提取的字符串解析为JSON userData = JSON.parse(match[1]); break; // 找到并解析成功后退出循环 } catch (e) { // 如果解析失败,尝试修复常见的JavaScript语法差异 try { let fixedData = match[1] .replace(/\s+/g, ' ') .replace(/'/g, '"') .replace(/([\w]+):/g, '"$1":'); userData = JSON.parse(fixedData); break; // 修复并解析成功后退出循环 } catch (innerError) { console.error('尝试修复后仍无法解析:', innerError.message); // 继续尝试下一个模式 continue; } } } } if (userData === null) { throw new Error('未能从响应中提取用户列表数据'); } // 确保返回的是数组 return Array.isArray(userData) ? userData : []; } /** * 批量保存订单数据到PHP接口 * @param {Array} orders - 订单数据数组 * @returns {Object} 保存结果 */ async function saveOrdersToPHP(orders) { try { const requestTime = new Date().toLocaleTimeString(); console.log(`[${requestTime}] 开始提交订单数据到PHP接口...`); console.log(`PHP接口地址: ${PHP_SAVE_URL}`); const response = await fetch(PHP_SAVE_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ orders: orders }) }); if (!response.ok) { throw new Error(`PHP接口响应异常 [HTTP ${response.status}]`); } const result = await response.json(); console.log(`[${new Date().toLocaleTimeString()}] PHP接口调用完成`); return result; } catch (error) { console.error(`[${new Date().toLocaleTimeString()}] 保存订单到PHP接口失败:`, error.message); return { success: false, message: error.message, stats: { total: orders.length, inserted: 0, duplicated: 0, failed: orders.length } }; } } /** * 生成临时注单号(用于没有注单号的情况) * @returns {string} 临时注单号 */ function generateTempBetNo() { const timestamp = Date.now(); const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0'); return `TEMP_${timestamp}_${random}`; } /** * 将数据发送到控制台输出(为保持函数兼容性而保留) * @param {string} data - 待输出的数据 */ async function sendToBackend(data) { console.log('数据输出到控制台:', data); return { success: true }; } /** * 创建一个超时Promise * @param {number} ms - 超时毫秒数 * @param {string} message - 超时错误信息 * @returns {Promise} 超时Promise */ function timeoutPromise(ms, message) { return new Promise((_, reject) => { setTimeout(() => reject(new Error(message)), ms); }); }
更新并重新加载插件
操作日志