爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 255|回复: 0

[经验总结] 针对广东Swift3.0简易修改的油猴脚本

[复制链接]
发表于 5 天前 | 显示全部楼层 |阅读模式

登录后查看更多精彩内容~

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 沐雨淋觞 于 2025-10-23 10:50 编辑

(额,点错区了,已经发了)

该脚本仅适用于Swift3.0实况统计-统计报表。
主要内容为:1.删除表格明细的站号列。2.自设添加水文站的镇街(方便服务)。3.删除要素分级。4.删除极大风中的镇街最大风力表。
代码添加到油猴插件后,会在右上角出现设置的按钮
3.png

初次使用需要自行勾选功能内容
4.png

其中设置对应的功能为:
1.png 2.png

要添加水文站的镇街需要自行在代码中添加。格式为const shuiwen = {"站点":"对应镇街",}

完整油猴代码如下
  1. // ==UserScript==
  2. // [url=home.php?mod=space&uid=93431]@name[/url]         swift3.0删除
  3. // @namespace    http://tampermonkey.net/
  4. // @version      0.1
  5. // @description  try to take over the world!
  6. // @author       沐雨淋觞
  7. // @match        http://10.148.16.72:83/swift/index.html
  8. // @match        http://10.148.8.131/swift/*
  9. // @icon         https://www.google.com/s2/favicons?domain=16.72
  10. // @grant        none
  11. // ==/UserScript==

  12. (function() {
  13.     'use strict';

  14.     const SettingData = [false,false,false,false]

  15.     //-----------------------设置按钮-------------------//
  16.     // 立即创建设置按钮,不等待DOMContentLoaded
  17.     createSettingsButton();


  18.     function loadSettings() {
  19.         // 删除站号
  20.         const Mode1 = localStorage.getItem('tm_Mode1') === 'true';
  21.         document.getElementById('tm-mode-1').checked = Mode1;
  22.         applyMode(Mode1,0);

  23.         // 添加水文镇街
  24.         const Mode2 = localStorage.getItem('tm_Mode2') === 'true';
  25.         document.getElementById('tm-mode-2').checked = Mode2;
  26.         applyMode(Mode2,1);

  27.         // 删除要素分级
  28.         const Mode3 = localStorage.getItem('tm_Mode3') === 'true';
  29.         document.getElementById('tm-mode-3').checked = Mode3;
  30.         applyMode(Mode3,2);

  31.         // 删除各县最大风力表
  32.         const Mode4 = localStorage.getItem('tm_Mode4') === 'true';
  33.         document.getElementById('tm-mode-4').checked = Mode4;
  34.         applyMode(Mode4,3);
  35.     }

  36.     // 设置启用和关闭
  37.     function applyMode(enabled,num) {
  38.         if (enabled) {
  39.             SettingData[num] = enabled;
  40.         } else {
  41.             SettingData[num] = enabled;
  42.         }
  43.     }

  44.     // 设置按钮设计
  45.     function createSettingsButton() {
  46.         console.log('创建设置按钮'); // 调试信息

  47.         // 创建样式
  48.         const style = document.createElement('style');
  49.         style.textContent = `
  50.             .tm-settings-btn {
  51.                 position: fixed;
  52.                 top: 0px;
  53.                 right: 100px;
  54.                 width: 50px;
  55.                 height: 50px;
  56.                 background: #2196F3;
  57.                 color: white;
  58.                 border: none;
  59.                 border-radius: 50%;
  60.                 cursor: pointer;
  61.                 font-size: 20px;
  62.                 box-shadow: 0 4px 12px rgba(0,0,0,0.3);
  63.                 z-index: 10000;
  64.                 transition: all 0.3s ease;
  65.             }

  66.             .tm-settings-btn:hover {
  67.                 transform: scale(1.1);
  68.                 background: #1976D2;
  69.             }

  70.             .tm-settings-panel {
  71.                 position: fixed;
  72.                 top: 50%;
  73.                 left: 50%;
  74.                 transform: translate(-50%, -50%);
  75.                 width: 350px;
  76.                 background: white;
  77.                 border-radius: 12px;
  78.                 box-shadow: 0 10px 30px rgba(0,0,0,0.3);
  79.                 z-index: 10002;
  80.                 display: none;
  81.                 font-family: Arial, sans-serif;
  82.             }

  83.             .tm-settings-panel.active {
  84.                 display: block;
  85.             }

  86.             .tm-settings-header {
  87.                 display: flex;
  88.                 justify-content: space-between;
  89.                 align-items: center;
  90.                 padding: 15px;
  91.                 border-bottom: 1px solid #eee;
  92.                 background: #f5f5f5;
  93.                 border-radius: 12px 12px 0 0;
  94.             }

  95.             .tm-settings-content {
  96.                 padding: 15px;
  97.             }

  98.             .tm-setting-item {
  99.                 display: flex;
  100.                 justify-content: space-between;
  101.                 align-items: center;
  102.                 margin-bottom: 15px;
  103.                 padding: 8px;
  104.             }

  105.             .tm-switch {
  106.                 position: relative;
  107.                 display: inline-block;
  108.                 width: 50px;
  109.                 height: 24px;
  110.             }

  111.             .tm-switch input {
  112.                 opacity: 0;
  113.                 width: 0;
  114.                 height: 0;
  115.             }

  116.             .tm-slider {
  117.                 position: absolute;
  118.                 cursor: pointer;
  119.                 top: 0;
  120.                 left: 0;
  121.                 right: 0;
  122.                 bottom: 0;
  123.                 background-color: #ccc;
  124.                 transition: .4s;
  125.                 border-radius: 24px;
  126.             }

  127.             .tm-slider:before {
  128.                 position: absolute;
  129.                 content: "";
  130.                 height: 16px;
  131.                 width: 16px;
  132.                 left: 4px;
  133.                 bottom: 4px;
  134.                 background-color: white;
  135.                 transition: .4s;
  136.                 border-radius: 50%;
  137.             }

  138.             input:checked + .tm-slider {
  139.                 background-color: #2196F3;
  140.             }

  141.             input:checked + .tm-slider:before {
  142.                 transform: translateX(26px);
  143.             }

  144.             .tm-overlay {
  145.                 position: fixed;
  146.                 top: 0;
  147.                 left: 0;
  148.                 width: 100%;
  149.                 height: 100%;
  150.                 background: rgba(0,0,0,0.5);
  151.                 z-index: 10001;
  152.                 display: none;
  153.             }

  154.             .tm-overlay.active {
  155.                 display: block;
  156.             }
  157.         `;
  158.         document.head.appendChild(style);

  159.         // 创建设置按钮
  160.         const settingsBtn = document.createElement('button');
  161.         settingsBtn.className = 'tm-settings-btn';
  162.         settingsBtn.innerHTML = '⚙';
  163.         settingsBtn.title = '设置';
  164.         settingsBtn.id = 'tm-settings-btn';

  165.         document.body.appendChild(settingsBtn);

  166.         // 添加点击事件
  167.         settingsBtn.addEventListener('click', function() {
  168.             console.log('设置按钮被点击'); // 调试信息
  169.             createSettingsPanel();
  170.         });
  171.         console.log('设置按钮创建完成'); // 调试信息
  172.     }

  173.     // 设置页面的功能及设计
  174.     function createSettingsPanel() {
  175.         console.log('创建设置面板'); // 调试信息

  176.         // 如果面板已存在,先移除
  177.         const existingPanel = document.getElementById('tm-settings-panel');
  178.         const existingOverlay = document.getElementById('tm-overlay');
  179.         if (existingPanel) existingPanel.remove();
  180.         if (existingOverlay) existingOverlay.remove();

  181.         // 创建设置面板
  182.         const settingsPanel = document.createElement('div');
  183.         settingsPanel.id = 'tm-settings-panel';
  184.         settingsPanel.className = 'tm-settings-panel';
  185.         settingsPanel.innerHTML = `
  186.             <div class="tm-settings-header">
  187.                 <h3 style="margin: 0; font-size: 16px;">网页设置</h3>
  188.                 <button id="tm-close-settings" style="background: none; border: none; font-size: 20px; cursor: pointer; padding: 0; width: 30px; height: 30px;">×</button>
  189.             </div>
  190.             <div class="tm-settings-content">
  191.                 <div class="tm-setting-item">
  192.                     <span style="font-size: 14px;">删除站号</span>
  193.                     <label class="tm-switch">
  194.                         <input type="checkbox" id="tm-mode-1">
  195.                         <span class="tm-slider"></span>
  196.                     </label>
  197.                 </div>

  198.                 <div class="tm-setting-item">
  199.                     <span style="font-size: 14px;">添加水文镇街</span>
  200.                     <label class="tm-switch">
  201.                         <input type="checkbox" id="tm-mode-2">
  202.                         <span class="tm-slider"></span>
  203.                     </label>
  204.                 </div>

  205.                 <div class="tm-setting-item">
  206.                     <span style="font-size: 14px;">删除要素分级</span>
  207.                     <label class="tm-switch">
  208.                         <input type="checkbox" id="tm-mode-3">
  209.                         <span class="tm-slider"></span>
  210.                     </label>
  211.                 </div>

  212.                 <div class="tm-setting-item">
  213.                     <span style="font-size: 14px;">删除各县最大风力表</span>
  214.                     <label class="tm-switch">
  215.                         <input type="checkbox" id="tm-mode-4">
  216.                         <span class="tm-slider"></span>
  217.                     </label>
  218.                 </div>
  219.             </div>
  220.         `;

  221.         // 创建遮罩层
  222.         const overlay = document.createElement('div');
  223.         overlay.id = 'tm-overlay';
  224.         overlay.className = 'tm-overlay';

  225.         document.body.appendChild(settingsPanel);
  226.         document.body.appendChild(overlay);

  227.         // 显示面板和遮罩
  228.         settingsPanel.classList.add('active');
  229.         overlay.classList.add('active');

  230.         // 添加事件监听
  231.         const closeSettings = document.getElementById('tm-close-settings');
  232.         const overlayEl = document.getElementById('tm-overlay');

  233.         closeSettings.addEventListener('click', closeSettingsPanel);
  234.         overlayEl.addEventListener('click', closeSettingsPanel);

  235.         // 加载设置状态
  236.         loadSettings();

  237.         // 添加设置变化监听
  238.         document.getElementById('tm-mode-1').addEventListener('change', function() {
  239.             localStorage.setItem('tm_Mode1', this.checked);
  240.             applyMode(this.checked,0);
  241.         });

  242.         document.getElementById('tm-mode-2').addEventListener('change', function() {
  243.             localStorage.setItem('tm_Mode2', this.checked);
  244.             applyMode(this.checked,1);
  245.         });

  246.         document.getElementById('tm-mode-3').addEventListener('change', function() {
  247.             localStorage.setItem('tm_Mode3', this.checked);
  248.             applyMode(this.checked,2);
  249.         });

  250.         document.getElementById('tm-mode-4').addEventListener('change', function() {
  251.             localStorage.setItem('tm_Mode4', this.checked);
  252.             applyMode(this.checked,3);
  253.         });

  254.         function closeSettingsPanel() {
  255.             settingsPanel.classList.remove('active');
  256.             overlay.classList.remove('active');
  257.             // 1秒后移除元素
  258.             setTimeout(() => {
  259.                 settingsPanel.remove();
  260.                 overlay.remove();
  261.             }, 300);
  262.         }
  263.     }


  264.     //-----------------------统计处理-------------------//
  265.     // 存储已处理的iframe,避免重复处理
  266.     const processedIframes = new WeakSet();

  267.     // 主要删除函数
  268.     function deleteSecondH2(element) {
  269.         const container = element || document;
  270.         const shuiwen = {'站点': '对应镇街',}


  271.         const collectDiv = container.querySelector('div.collect');
  272.         const statistDiv = container.querySelector('div#rainStatisticDetail');
  273.         const regexes = [/雨量站[^0-9]*(\d+)/ , /观测站[^0-9]*(\d+)/];
  274.         // 站点总数
  275.         let station = null;


  276.         // 处理表格站号
  277.         const raintable = container.querySelector('#rainStatisticDetail table#rainStatisticTable');
  278.         if (raintable){
  279.             const thead = raintable.querySelector('thead tr');
  280.             const header = thead.querySelectorAll('td');

  281.             const tbody = raintable.querySelector('tbody');
  282.             const rows = tbody.querySelectorAll('tr');

  283.             // 必须添加列数判定,不然全删了......
  284.             if (header[1].textContent.trim() === "站号" ){
  285.                 // 判定删除站号列的表头
  286.                 if (SettingData[0]){header[1].remove();}

  287.                 rows.forEach((row) => {
  288.                     const tdcell = row.querySelectorAll('td');

  289.                     // 删除站号功能
  290.                     if (SettingData[0]){tdcell[1].remove();}

  291.                     // 添加水文镇街
  292.                     if (SettingData[1] && tdcell[2].textContent in shuiwen) {
  293.                         tdcell[2].textContent = `${shuiwen[tdcell[2].textContent]} | ${tdcell[2].textContent}`;
  294.                     }
  295.                 });
  296.             }
  297.         }



  298.         // 针对雨量、极值温度等级
  299.         // 删除分级
  300.         if (SettingData[2]){
  301.             if (collectDiv){
  302.                 const section = collectDiv.querySelector('div.section');
  303.                 for (const regex of regexes) {
  304.                     const match = section.textContent.match(regex);
  305.                     if (match) {
  306.                         station = match[1]; // 赋值给外部变量
  307.                         break; // 找到就停止
  308.                     }
  309.                 }
  310.                 console.log(station);

  311.                 // 获取所有h2标签
  312.                 const h2Elements = collectDiv.querySelectorAll('h2');
  313.                 // 如果存在至少2个h2标签,则删除第二个
  314.                 if (h2Elements.length >= 2) {
  315.                     //console.log('找到第二个h2标签,正在删除...', h2Elements[1]);
  316.                     h2Elements[1].remove();
  317.                     const fenjitable = collectDiv.querySelectorAll('table');
  318.                     fenjitable[0].remove();

  319.                     collectDiv.classList.add('collect-h2-removed');
  320.                 }
  321.             }
  322.         }

  323.         // 针对极大风的
  324.         if (statistDiv){
  325.             const h2Elements = statistDiv.querySelectorAll('h2');
  326.             const tableElements = statistDiv.querySelectorAll('table');
  327.             if (h2Elements.length === 3) {
  328.                 if (SettingData[2]){h2Elements[1].remove();}
  329.                 if (SettingData[3]){h2Elements[0].remove();}
  330.             }
  331.             if (tableElements.length === 3) {
  332.                 if (SettingData[2]){tableElements[1].remove();}
  333.                 if (SettingData[3]){tableElements[0].remove();}
  334.             }
  335.         }
  336.     }


  337.     // 处理单个iframe
  338.     function processIframe(iframe) {
  339.         if (processedIframes.has(iframe)) {
  340.             return;
  341.         }

  342.         try {
  343.             // 检查iframe是否已加载内容
  344.             if (iframe.contentDocument && iframe.contentDocument.readyState === 'complete') {
  345.                 //console.log('处理iframe:', iframe);
  346.                 deleteSecondH2(iframe.contentDocument);
  347.                 setupIframeObserver(iframe.contentDocument);
  348.                 processedIframes.add(iframe);
  349.             } else {
  350.                 // 如果iframe未加载完成,等待其加载
  351.                 iframe.addEventListener('load', function onLoad() {
  352.                     iframe.removeEventListener('load', onLoad);
  353.                     console.log('iframe加载完成,开始处理:', iframe);
  354.                     deleteSecondH2(iframe.contentDocument);
  355.                     setupIframeObserver(iframe.contentDocument);
  356.                     processedIframes.add(iframe);
  357.                 });
  358.             }
  359.         } catch (error) {
  360.             // 处理跨域iframe访问限制
  361.             if (error.name === 'SecurityError') {
  362.                 console.warn('无法访问跨域iframe:', iframe.src);
  363.             } else {
  364.                 console.error('处理iframe时出错:', error);
  365.             }
  366.         }
  367.     }

  368.     // 为iframe设置MutationObserver
  369.     function setupIframeObserver(doc) {
  370.         try {
  371.             const iframeObserver = new MutationObserver(function(mutations) {
  372.                 let shouldCheck = false;

  373.                 for (let mutation of mutations) {
  374.                     if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
  375.                         shouldCheck = true;
  376.                         break;
  377.                     }
  378.                     if (mutation.type === 'attributes' && mutation.target.classList && mutation.target.classList.contains('collect')) {
  379.                         shouldCheck = true;
  380.                         break;
  381.                     }
  382.                 }

  383.                 if (shouldCheck) {
  384.                     setTimeout(() => deleteSecondH2(doc), 100);
  385.                 }
  386.             });

  387.             iframeObserver.observe(doc.body, {
  388.                 childList: true,
  389.                 subtree: true,
  390.                 attributes: true,
  391.                 attributeFilter: ['class']
  392.             });
  393.         } catch (error) {
  394.             console.warn('无法在iframe中设置Observer:', error);
  395.         }
  396.     }

  397.     // 查找并处理所有iframe
  398.     function processAllIframes() {
  399.         const iframes = document.querySelectorAll('iframe');
  400.         //console.log(`找到 ${iframes.length} 个iframe`);

  401.         iframes.forEach(iframe => {
  402.             processIframe(iframe);
  403.         });
  404.     }

  405.     // 主文档的MutationObserver
  406.     const mainObserver = new MutationObserver(function(mutations) {
  407.         let iframeAdded = false;

  408.         for (let mutation of mutations) {
  409.             if (mutation.type === 'childList') {
  410.                 for (let node of mutation.addedNodes) {
  411.                     // 检查新增的节点是否是iframe,或者包含iframe
  412.                     if (node.nodeName === 'IFRAME') {
  413.                         iframeAdded = true;
  414.                         setTimeout(() => processIframe(node), 100);
  415.                     } else if (node.nodeType === 1 && node.querySelector) {
  416.                         const newIframes = node.querySelectorAll('iframe');
  417.                         if (newIframes.length > 0) {
  418.                             iframeAdded = true;
  419.                             setTimeout(() => {
  420.                                 newIframes.forEach(processIframe);
  421.                             }, 100);
  422.                         }
  423.                     }
  424.                 }
  425.             }
  426.         }

  427.         if (iframeAdded) {
  428.             setTimeout(processAllIframes, 200);
  429.         } else {
  430.             // 检查普通DOM变化
  431.             let shouldCheck = false;
  432.             for (let mutation of mutations) {
  433.                 if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
  434.                     shouldCheck = true;
  435.                     break;
  436.                 }
  437.                 if (mutation.type === 'attributes' && mutation.target.classList && mutation.target.classList.contains('collect')) {
  438.                     shouldCheck = true;
  439.                     break;
  440.                 }
  441.             }

  442.             if (shouldCheck) {
  443.                 setTimeout(() => deleteSecondH2(document), 100);
  444.             }
  445.         }
  446.     });

  447.     // 初始化和启动监控
  448.     function init() {
  449.         console.log('开始监控iframe和DOM变化');

  450.         // 初始处理主文档
  451.         deleteSecondH2(document);

  452.         // 初始处理所有已存在的iframe
  453.         processAllIframes();

  454.         // 启动主文档观察器
  455.         mainObserver.observe(document.body, {
  456.             childList: true,
  457.             subtree: true,
  458.             attributes: true,
  459.             attributeFilter: ['class']
  460.         });

  461.         // 监听页面加载完成
  462.         window.addEventListener('load', function() {
  463.             setTimeout(() => {
  464.                 deleteSecondH2(document);
  465.                 processAllIframes();
  466.             }, 1000);
  467.         });

  468.         // 定期检查新iframe(针对动态加载的内容)
  469.         setInterval(processAllIframes, 3000);
  470.     }



  471.     // 等待DOM准备就绪
  472.     if (document.readyState === 'loading') {
  473.         document.addEventListener('DOMContentLoaded', init);
  474.     } else {
  475.         init();
  476.         const Mode1 = localStorage.getItem('tm_Mode1') === 'true';
  477.         const Mode2 = localStorage.getItem('tm_Mode2') === 'true';
  478.         const Mode3 = localStorage.getItem('tm_Mode3') === 'true';
  479.         const Mode4 = localStorage.getItem('tm_Mode4') === 'true';

  480.         applyMode(Mode1,0);
  481.         applyMode(Mode2,1);
  482.         applyMode(Mode3,2);
  483.         applyMode(Mode4,3);
  484.     }

  485. })();
复制代码
适用于360浏览器的油猴插件及代码,详见附件。

油猴插件 脚本.zip

1.58 MB, 下载次数: 0, 下载积分: 金钱 -5

密码修改失败请联系微信:mofangbao
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Copyright ©2011-2014 bbs.06climate.com All Rights Reserved.  Powered by Discuz! (京ICP-10201084)

本站信息均由会员发表,不代表气象家园立场,禁止在本站发表与国家法律相抵触言论

快速回复 返回顶部 返回列表