美团搬菜(支持超市水果店)

从美团将菜单导入到搬菜平台

目前為 2025-02-18 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name 美团搬菜(支持超市水果店)
  3. // @description 从美团将菜单导入到搬菜平台
  4. // @version v2.0.1MAX
  5. // @author mirari、ChengPP(后续)
  6. // @copyright 2023, mirari (https://github.com/mirari)
  7. // @match https://cactivityapi-sc.waimai.meituan.com/h5*
  8. // @match https://h5.waimai.meituan.com/waimai/mindex*
  9. // @run-at document-idle
  10. // @grant unsafeWindow
  11. // @grant GM_xmlhttpRequest
  12. // @connect raw.githubusercontent.com
  13. // @connect mv.nianxiang.net.cn
  14. // @connect localhost
  15. // @connect *
  16. // @icon https://himg.bdimg.com/sys/portrait/item/pp.1.61637635.q_9U7gFy_biR3yojcvZygw.jpg?tt=1732025929684
  17. // @namespace https://gf.qytechs.cn/users/1436563
  18. // ==/UserScript==
  19.  
  20. (function () {
  21. 'use strict';
  22.  
  23. let food;
  24. let autoGetting = false;
  25. let isImporting = false;
  26.  
  27. const createButtons = () => {
  28. const mainBtn = document.createElement('button');
  29. mainBtn.innerHTML = '<img src="https://himg.bdimg.com/sys/portrait/item/pp.1.61637635.q_9U7gFy_biR3yojcvZygw.jpg?tt=1732025929684" alt="☰" style="width: 30px; height: 30px;">';
  30. mainBtn.style = `
  31. position: fixed;
  32. top: 2vw;
  33. right: 2vw;
  34. z-index: 999999;
  35. background: transparent;
  36. border: none;
  37. padding: 0;
  38. cursor: pointer;
  39. transition: transform 0.3s ease-in-out, color 0.3s ease-in-out;
  40. `;
  41.  
  42. const parseBtn = document.createElement('button');
  43. parseBtn.innerHTML = '解析新结构分类';
  44. parseBtn.style = `
  45. position: fixed;
  46. top: -999vw;
  47. right: -300vw;
  48. transition: right 0.3s ease-in-out, transform 0.3s ease-in-out, background-color 0.3s ease-in-out, color 0.3s ease-in-out;
  49. z-index: 999999;
  50. background: #ffbd27;
  51. border-radius: 1.6vw;
  52. border: none;
  53. padding: 1.5vw;
  54. color: white;
  55. font-weight: bold;
  56. `;
  57.  
  58. const btnImport = document.createElement('button');
  59. btnImport.innerHTML = '导入店铺菜单';
  60. btnImport.style = `
  61. position: fixed;
  62. top: 7vw;
  63. right: -300vw;
  64. transition: right 0.3s ease-in-out, transform 0.3s ease-in-out, background-color 0.3s ease-in-out, color 0.3s ease-in-out;
  65. z-index: 999999;
  66. background: #ffbd27;
  67. border-radius: 1.6vw;
  68. border: none;
  69. padding: 1.5vw;
  70. color: white;
  71. font-weight: bold;
  72. `;
  73.  
  74. const btnShowRawData = document.createElement('button');
  75. btnShowRawData.innerHTML = '获取原始数据';
  76. btnShowRawData.style = `
  77. position: fixed;
  78. top: 12vw;
  79. right: -300vw;
  80. transition: right 0.3s ease-in-out, transform 0.3s ease-in-out, background-color 0.3s ease-in-out, color 0.3s ease-in-out;
  81. z-index: 999999;
  82. background: #ffbd27;
  83. border-radius: 1.6vw;
  84. border: none;
  85. padding: 1.5vw;
  86. color: white;
  87. font-weight: bold;
  88. `;
  89.  
  90. const btnShowCategories = document.createElement('button');
  91. btnShowCategories.innerHTML = '获取商品状态';
  92. btnShowCategories.style = `
  93. position: fixed;
  94. top: 17vw;
  95. right: -300vw;
  96. transition: right 0.3s ease-in-out, transform 0.3s ease-in-out, background-color 0.3s ease-in-out, color 0.3s ease-in-out;
  97. z-index: 999999;
  98. background: #ffbd27;
  99. border-radius: 1.6vw;
  100. border: none;
  101. padding: 1.5vw;
  102. color: white;
  103. font-weight: bold;
  104. `;
  105.  
  106. return { mainBtn, parseBtn, btnImport, btnShowRawData, btnShowCategories };
  107. };
  108.  
  109. const { mainBtn, parseBtn, btnImport, btnShowRawData, btnShowCategories } = createButtons();
  110.  
  111. let isExpanded = false;
  112. mainBtn.onclick = () => {
  113. if (isExpanded) {
  114. parseBtn.style.right = '-300vw';
  115. btnImport.style.right = '-300vw';
  116. btnShowRawData.style.right = '-300vw';
  117. btnShowCategories.style.right = '-300vw';
  118. } else {
  119. parseBtn.style.right = '2vw';
  120. btnImport.style.right = '2vw';
  121. btnShowRawData.style.right = '2vw';
  122. btnShowCategories.style.right = '2vw';
  123. }
  124. isExpanded = !isExpanded;
  125. mainBtn.style.transform = isExpanded ? 'scale(1.2)' : 'scale(1)';
  126. };
  127.  
  128. parseBtn.onclick = async () => {
  129. if (window.location.href.startsWith('https://cactivityapi-sc.waimai.meituan.com/h5/sub-trade/restaurant/restaurant?')) {
  130. parseBtn.style.backgroundColor = '#ff8000';
  131. parseBtn.style.color = 'white';
  132. parseBtn.innerHTML = '解析中...';
  133. await new Promise(resolve => setTimeout(resolve, 2000)); // 模拟解析过程
  134. alert('解析新结构分类成功...');
  135. location.reload();
  136. } else {
  137. alert('当前页面不需要解析新结构分类。');
  138. }
  139. };
  140.  
  141. btnImport.onclick = () => {
  142. if (food) {
  143. const tagCount = food.data.food_spu_tags.length;
  144. const spuCount = food.data.food_spu_tags.reduce((sum, tag) => sum + tag.spus.length, 0);
  145. console.log(food);
  146. console.log('tagCount', tagCount);
  147. console.log('spuCount', spuCount);
  148.  
  149. const incompleteTags = food.data.food_spu_tags.filter(tag => !tag.spus.length && tag.attempted !== true);
  150. const noProductTags = food.data.food_spu_tags.filter(tag => !tag.spus.length && tag.attempted === true);
  151. const incompleteTagCount = incompleteTags.length;
  152. const noProductTagCount = noProductTags.length;
  153.  
  154. let tip = '';
  155. if (incompleteTagCount > 0 || noProductTagCount > 0) {
  156. if (window.location.href.includes('https://h5.waimai.meituan.com/waimai/mindex/menu?')) {
  157. tip = `🌟Tip1:当前为分页菜单,请点击黄色的标签分类获取商品。\n🌟Tip2:当店铺商品数较多时候,请浏览完整商品页面,避免获取缺失!!!`;
  158. } else if (window.location.href.includes('https://cactivityapi-sc.waimai.meituan.com/h5') ) {
  159. tip = `🌟Tip1:商品获取情况,可用查看已获取分类按钮查看详情...\n🌟Tip2:新结构店铺商品数较多,请浏览完整商品页面,避免获取缺失!!!`;
  160. }
  161. }
  162.  
  163. let confirmMessage = ``;
  164. if (tip) {
  165. confirmMessage += `${tip}\n\n`;
  166. }
  167. confirmMessage += `获取到分类${tagCount}个,商品共计${spuCount}个(存在重复计入)。\n`;
  168.  
  169. if (incompleteTagCount > 0) {
  170. confirmMessage += `注意:当前还有${incompleteTagCount}个分类未获取完整信息。\n`;
  171. }
  172.  
  173. if (noProductTagCount > 0) {
  174. confirmMessage += `注意:当前有${noProductTagCount}个分类无商品。\n`;
  175. }
  176.  
  177. confirmMessage += `是否导入到搬店平台?`;
  178.  
  179. if (confirm(confirmMessage)) {
  180. btnImport.style.transform = 'scale(1.2)';
  181. btnImport.style.backgroundColor = '#ff8000';
  182. btnImport.style.color = 'white';
  183. btnImport.innerHTML = '正在导入中...';
  184. importData();
  185. }
  186.  
  187. } else {
  188. alert('未能监听到菜单数据。');
  189. }
  190. };
  191.  
  192. btnShowRawData.onclick = () => {
  193. if (food) {
  194. const allFoodData = JSON.stringify(food, null, 2);
  195. const blob = new Blob([allFoodData], { type: 'application/json' });
  196. const url = URL.createObjectURL(blob);
  197. window.open(url, '_blank');
  198. } else {
  199. alert('未能监听到菜单数据。');
  200. }
  201. };
  202.  
  203. btnShowCategories.onclick = () => {
  204. if (food) {
  205. const completeTags = food.data.food_spu_tags.filter(tag => tag.spus.length);
  206. const completeTagCount = completeTags.length;
  207. const totalSpuCount = completeTags.reduce((sum, tag) => sum + tag.spus.length, 0);
  208.  
  209. const incompleteTags = food.data.food_spu_tags.filter(tag => !tag.spus.length && tag.attempted !== true);
  210. const incompleteTagCount = incompleteTags.length;
  211. const incompleteTagNames = incompleteTags.map(tag => tag.name).join(', ');
  212.  
  213. const noProductTags = food.data.food_spu_tags.filter(tag => !tag.spus.length && tag.attempted === true);
  214. const noProductTagCount = noProductTags.length;
  215. const noProductTagNames = noProductTags.map(tag => tag.name).join(', ');
  216.  
  217. const totalTagCount = food.data.food_spu_tags.length;
  218.  
  219. const container = document.createElement('div');
  220. container.style = `
  221. max-height: 80vh;
  222. overflow-y: auto;
  223. padding: 10px;
  224. background-color: white;
  225. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  226. z-index: 1000000;
  227. position: fixed;
  228. top: 15vw;
  229. left: 50%;
  230. transform: translateX(-50%);
  231. width: 80vw;
  232. max-width: 600px;
  233. border-radius: 1.6vw;
  234. `;
  235.  
  236. const statsContainer = document.createElement('div');
  237. statsContainer.style = `
  238. margin-bottom: 10px;
  239. padding: 10px;
  240. background-color: #f9f9f9;
  241. border: 1px solid #ddd;
  242. border-radius: 5px;
  243. `;
  244.  
  245. const statsText = `
  246. <p>总分类数: ${totalTagCount}</p>
  247. <p>已获取分类数: ${completeTagCount}</p>
  248. <p>未获取分类数: ${incompleteTagCount}</p>
  249. <p>无商品分类数: ${noProductTagCount}</p>
  250. <p>已获取商品数: ${totalSpuCount}</p>
  251. `;
  252.  
  253. statsContainer.innerHTML = statsText;
  254.  
  255. const filterContainer = document.createElement('div');
  256. filterContainer.style = `
  257. display: flex;
  258. justify-content: space-between;
  259. align-items: center;
  260. margin-bottom: 10px;
  261. `;
  262.  
  263. const filterOptions = ['全部', '已获取', '未获取', '无商品'];
  264. const filterSelect = document.createElement('select');
  265. filterSelect.style = `
  266. padding: 5px;
  267. border: 1px solid #ccc;
  268. border-radius: 5px;
  269. `;
  270. filterOptions.forEach(option => {
  271. const opt = document.createElement('option');
  272. opt.value = option;
  273. opt.text = option;
  274. filterSelect.appendChild(opt);
  275. });
  276.  
  277. filterSelect.onchange = () => {
  278. updateTable(filterSelect.value);
  279. };
  280.  
  281. filterContainer.appendChild(filterSelect);
  282.  
  283. const closeButton = document.createElement('button');
  284. closeButton.innerHTML = '关闭';
  285. closeButton.style = `
  286. padding: 5px 10px;
  287. background-color: #ffbd27;
  288. color: white;
  289. border: none;
  290. border-radius: 5px;
  291. cursor: pointer;
  292. `;
  293. closeButton.onclick = () => {
  294. document.body.removeChild(container);
  295. };
  296. filterContainer.appendChild(closeButton);
  297.  
  298. const table = document.createElement('table');
  299. table.style = 'width: 100%; border-collapse: collapse;';
  300.  
  301. const thead = document.createElement('thead');
  302. thead.innerHTML = `
  303. <tr>
  304. <th style="border: 1px solid black; padding: 8px;">分类名称</th>
  305. <th style="border: 1px solid black; padding: 8px;">商品数量</th>
  306. <th style="border: 1px solid black; padding: 8px;">获取状态</th>
  307. </tr>
  308. `;
  309.  
  310. const tbody = document.createElement('tbody');
  311. food.data.food_spu_tags.forEach(tag => {
  312. let status;
  313. if (!tag.spus.length && tag.attempted === true) {
  314. status = '无商品';
  315. } else if (!tag.spus.length) {
  316. status = '未获取';
  317. } else {
  318. status = '已获取';
  319. }
  320. const statusColor = {
  321. '已获取': '#4caf50',
  322. '未获取': '#f44336',
  323. '无商品': '#FFA500',
  324. '失败': '#ff9800'
  325. }[status] || '#000';
  326.  
  327. tbody.innerHTML += `
  328. <tr>
  329. <td style="border: 1px solid black; padding: 8px;">${tag.name}</td>
  330. <td style="border: 1px solid black; padding: 8px; text-align: right;">${tag.spus.length}</td>
  331. <td style="border: 1px solid black; padding: 8px; color: ${statusColor};">${status}</td>
  332. </tr>
  333. `;
  334. });
  335.  
  336. table.appendChild(thead);
  337. table.appendChild(tbody);
  338.  
  339. container.appendChild(statsContainer);
  340. container.appendChild(filterContainer);
  341. container.appendChild(table);
  342.  
  343. document.body.appendChild(container);
  344.  
  345. const updateTable = (filterValue) => {
  346. const rows = tbody.getElementsByTagName('tr');
  347. Array.from(rows).forEach(row => {
  348. const statusCell = row.cells[2].innerText;
  349. if (filterValue === '全部' || statusCell === filterValue) {
  350. row.style.display = '';
  351. } else {
  352. row.style.display = 'none';
  353. }
  354. });
  355. };
  356.  
  357. updateTable(filterSelect.value);
  358. } else {
  359. alert('未能监听到菜单数据。');
  360. }
  361. };
  362.  
  363. const importData = () => {
  364. let xhr = new XMLHttpRequest();
  365. try {
  366. xhr.open("POST", 'https://mv.nianxiang.net.cn/api/admin/move/task/open/import', true);
  367. xhr.setRequestHeader("Content-Type", "application/json");
  368. xhr.onreadystatechange = function () {
  369. if (xhr.readyState === 4 && xhr.status === 200) {
  370. const res = JSON.parse(xhr.responseText);
  371. console.log(res);
  372. alert(res.data);
  373. btnImport.style.transform = 'scale(1)';
  374. btnImport.style.backgroundColor = '#ffbd27';
  375. btnImport.style.color = 'white';
  376. btnImport.innerHTML = '导入店铺菜单';
  377. }
  378. };
  379. const data = JSON.stringify({
  380. raw: JSON.stringify(food),
  381. });
  382. xhr.send(data);
  383. } catch (err) {
  384. console.log(err);
  385. alert('请求出错:' + err.message);
  386. btnImport.style.transform = 'scale(1)';
  387. btnImport.style.backgroundColor = '#ffbd27';
  388. btnImport.style.color = 'white';
  389. btnImport.innerHTML = '导入店铺菜单';
  390. }
  391. };
  392.  
  393. const originFetch = fetch;
  394. window.unsafeWindow.fetch = (url, options) => {
  395. return originFetch(url, options).then(async response => {
  396. if (response.status === 403) {
  397. alert('请切换美团账号或者清除浏览器缓存重试/页面拒绝访问!');
  398. return response;
  399. }
  400. const callback = checkRequest(url);
  401. if (callback) {
  402. callback(url, await response.clone().json());
  403. }
  404. return response;
  405. });
  406. };
  407.  
  408. const originOpen = XMLHttpRequest.prototype.open;
  409. XMLHttpRequest.prototype.open = function (_, url) {
  410. const callback = checkRequest(url);
  411. if (callback) {
  412. this.addEventListener('readystatechange', function () {
  413. if (this.readyState === 4) {
  414. if (this.status === 403) {
  415. alert('请切换美团账号或者清除浏览器缓存重试/页面拒绝访问!');
  416. return;
  417. }
  418. callback(url, JSON.parse(this.responseText));
  419. }
  420. });
  421. }
  422. originOpen.apply(this, arguments);
  423. };
  424.  
  425. function checkRequest(url) {
  426. if (url.startsWith('https://i.waimai.meituan.com/openapi/v1/poi/food?') || url.startsWith('https://wx-shangou.meituan.com/quickbuy/v1/poi/food?')) {
  427. return onGetStoreMenu;
  428. } else if (url.startsWith('https://i.waimai.meituan.com/openh5/v2/poi/menuproducts?')) {
  429. return onGetPaginatedMenuProducts;
  430. } else if (url.startsWith('https://wx-shangou.meituan.com/quickbuy/v1/poi/sputag/products?') || url.startsWith('https://wx-shangou.meituan.com/quickbuy/v1/poi/product/smooth/render?')) {
  431. return onGetNewStructureMenuProducts;
  432. }
  433. }
  434.  
  435. function onGetStoreMenu(url, res) {
  436. food = res;
  437. const tags = food.data.food_spu_tags;
  438. if (tags.length) {
  439. tags.forEach(tag => {
  440. if (tag.tags && tag.tags.length) {
  441. tag.spus = [];
  442. tag.tags.forEach(subTag => {
  443. if (subTag.spus && subTag.spus.length) {
  444. tag.spus.push(...subTag.spus);
  445. }
  446. });
  447. }
  448. });
  449.  
  450. document.body.appendChild(mainBtn);
  451. document.body.appendChild(parseBtn);
  452. document.body.appendChild(btnImport);
  453. document.body.appendChild(btnShowRawData);
  454. document.body.appendChild(btnShowCategories);
  455. refreshTabStatus();
  456. }
  457. }
  458.  
  459. function onGetPaginatedMenuProducts(url, res) {
  460. const tags = food.data.food_spu_tags;
  461. const tagId = res.data.product_tag_id;
  462. const currentTag = tags.find(tag => tag.tag === tagId);
  463. if (currentTag) {
  464. currentTag.spus = [...new Set([...currentTag.spus, ...res.data.product_spu_list])]; // 确保唯一性
  465. currentTag.attempted = true; // 标记该分类已被尝试获取
  466. refreshTabStatus();
  467. } else {
  468. alert('未找到当前标签,请刷新后重试或切换美团账号后重试');
  469. }
  470. }
  471.  
  472. function onGetNewStructureMenuProducts(url, res) {
  473. const tags = food.data.food_spu_tags;
  474. const selectedCategoryName = getSelectedCategoryName();
  475. const currentTag = tags.find(tag => tag.name === selectedCategoryName);
  476.  
  477. if (currentTag) {
  478. currentTag.spus = [...new Set([...currentTag.spus, ...res.data.product_spu_list])]; // 确保唯一性
  479. currentTag.attempted = true; // 标记该分类已被尝试获取
  480. } else {
  481. console.warn(`未找到当前标签`);
  482. alert('获取到商品数据但是匹配标签失败!!!\n1. 可尝试刷新界面重新获取\n2. 进行手动归类');
  483.  
  484. const panel = document.createElement('div');
  485. panel.style = `
  486. position: fixed;
  487. top: 15vw;
  488. right: 2vw;
  489. z-index: 1000001;
  490. background-color: white;
  491. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  492. border-radius: 1.6vw;
  493. padding: 1.5vw;
  494. width: 20vw;
  495. max-width: 300px;
  496. `;
  497.  
  498. const title = document.createElement('div');
  499. title.textContent = '选择分类';
  500. title.style = `
  501. font-size: 1.2em;
  502. margin-bottom: 1vw;
  503. font-weight: bold;
  504. `;
  505.  
  506. const select = document.createElement('select');
  507. select.style = `
  508. width: 100%;
  509. padding: 0.5vw;
  510. margin-bottom: 1vw;
  511. border: 1px solid #ccc;
  512. border-radius: 0.5vw;
  513. `;
  514.  
  515. const newOption = document.createElement('option');
  516. newOption.value = 'new';
  517. newOption.textContent = '新建自定义标签';
  518. select.appendChild(newOption);
  519.  
  520. tags.forEach(tag => {
  521. const option = document.createElement('option');
  522. option.value = tag.name;
  523. option.textContent = tag.name;
  524. select.appendChild(option);
  525. });
  526.  
  527. const input = document.createElement('input');
  528. input.type = 'text';
  529. input.placeholder = '输入新标签名称';
  530. input.style = `
  531. width: 100%;
  532. padding: 0.5vw;
  533. margin-bottom: 1vw;
  534. border: 1px solid #ccc;
  535. border-radius: 0.5vw;
  536. display: block;
  537. `;
  538.  
  539. select.onchange = () => {
  540. if (select.value === 'new') {
  541. input.style.display = 'block';
  542. } else {
  543. input.style.display = 'none';
  544. }
  545. };
  546.  
  547. const saveButton = document.createElement('button');
  548. saveButton.textContent = '保存';
  549. saveButton.style = `
  550. width: 100%;
  551. padding: 0.5vw;
  552. background-color: #ffbd27;
  553. color: white;
  554. border: none;
  555. border-radius: 0.5vw;
  556. cursor: pointer;
  557. `;
  558.  
  559. saveButton.onclick = () => {
  560. let tagName;
  561. if (select.value === 'new') {
  562. tagName = input.value.trim();
  563. if (!tagName) {
  564. alert('请输入有效的标签名称');
  565. return;
  566. }
  567. } else {
  568. tagName = select.value;
  569. }
  570.  
  571. const existingTag = tags.find(tag => tag.name.toLowerCase() === tagName.toLowerCase());
  572. if (existingTag) {
  573. existingTag.spus = [...new Set([...existingTag.spus, ...res.data.product_spu_list])]; // 确保唯一性
  574. existingTag.attempted = true; // 标记该分类已被尝试获取
  575. } else {
  576. const newTag = {
  577. tag: tagName,
  578. name: tagName,
  579. spus: res.data.product_spu_list,
  580. attempted: true
  581. };
  582. food.data.food_spu_tags.push(newTag);
  583. }
  584.  
  585. document.body.removeChild(panel);
  586. refreshTabStatus();
  587. };
  588.  
  589. panel.appendChild(title);
  590. panel.appendChild(select);
  591. panel.appendChild(input);
  592. panel.appendChild(saveButton);
  593.  
  594. document.body.appendChild(panel);
  595. }
  596. }
  597.  
  598. function refreshTabStatus() {
  599. const navEl = document.querySelector("#sqt-openh5-menulist > [class^='root_'] > [class^='panel_'] > [class^='root_'] > [class^='root_']");
  600. if (navEl) {
  601. for (let i = 0; i < navEl.children.length; i++) {
  602. navEl.children[i].style.backgroundColor = '#CCE099'; // 获取成功设置为绿色
  603. }
  604. food.data.food_spu_tags.forEach((item, index) => {
  605. if (!item.spus.length && item.attempted !== true) {
  606. const btnTab = findElementWithInnerText(navEl, item.name);
  607. if (btnTab) {
  608. btnTab.style.backgroundColor = 'yellow'; // 设置背景颜色为黄色
  609. }
  610. } else if (!item.spus.length && item.attempted === true) {
  611. const btnTab = findElementWithInnerText(navEl, item.name);
  612. if (btnTab) {
  613. btnTab.style.backgroundColor = '#FFA500'; // 设置背景颜色为橙色
  614. }
  615. }
  616. });
  617. }
  618. }
  619.  
  620. function findElementWithInnerText(el, text) {
  621. for (let i = 0; i < el.children.length; i++) {
  622. if (el.children[i].innerText.trim() === text) {
  623. return el.children[i];
  624. }
  625. }
  626. return null;
  627. }
  628.  
  629. function getSelectedCategoryName() {
  630. const activeCategory = document.querySelector('.category-cat-item-name.category-active-type-one');
  631. if (activeCategory) {
  632. return activeCategory.querySelector('.category-cat-item-text').innerText.trim();
  633. }
  634.  
  635. const mtViewCategory = document.querySelector('mt-view.p-left-sub-tab-title.mt-active');
  636. if (mtViewCategory) {
  637. const mtTextView = mtViewCategory.querySelector('mt-view.p-sub-tab-text');
  638. if (mtTextView) {
  639. return mtTextView.innerText.trim();
  640. }
  641. }
  642.  
  643. return null;
  644. }
  645.  
  646. document.body.appendChild(mainBtn);
  647. document.body.appendChild(btnImport);
  648. document.body.appendChild(btnShowRawData);
  649. document.body.appendChild(btnShowCategories);
  650.  
  651. // 添加按钮点击效果
  652. [mainBtn, parseBtn, btnImport, btnShowRawData, btnShowCategories].forEach(btn => {
  653. btn.addEventListener('mouseover', () => {
  654. btn.style.transform = 'scale(1.2)';
  655. });
  656. btn.addEventListener('mouseout', () => {
  657. btn.style.transform = 'scale(1)';
  658. });
  659. });
  660.  
  661. // 检查是否是新结构菜单界面,并决定是否显示解析新结构分类按钮
  662. if (window.location.href.startsWith('https://cactivityapi-sc.waimai.meituan.com/h5/sub-trade/restaurant/restaurant?')) {
  663.  
  664. document.body.appendChild(parseBtn);
  665. // 调整其他按钮的位置以保持在同一垂直线上
  666. parseBtn.style.top = '7vw';
  667. btnImport.style.top = '12vw';
  668. btnShowRawData.style.top = '17vw';
  669. btnShowCategories.style.top = '22vw';
  670. }
  671. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址