// ==UserScript== // @name 自然资源标准PDF下载 // @namespace http://tampermonkey.net/ // @version 2025.3.7 // @description 自然资源标准化信息服务平台下载pdf功能 // @author Shuaima // @match *://www.nrsis.org.cn/mnr_kfs/file/read/* // @require https://unpkg.com/pdf-lib@^1.17.1 // @require https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js // @grant GM_xmlhttpRequest // @grant GM_download // ==/UserScript== (function() { 'use strict'; const { PDFDocument } = PDFLib; let currentCode = ''; let totalPages = 0; let loadedPages = 0; // 创建进度条 function createProgressBar() { const container = document.createElement('div'); container.style = ` position: fixed; top: 70px; left: 20px; width: 200px; background: #f1f1f1; border-radius: 4px; padding: 10px; z-index: 9999; box-shadow: 0 2px 5px rgba(0,0,0,0.2); display: none; `; const progressBar = document.createElement('div'); progressBar.style = ` height: 20px; background: #e0e0e0; border-radius: 10px; overflow: hidden; margin-bottom: 8px; `; const progressFill = document.createElement('div'); progressFill.style = ` width: 0%; height: 100%; background: linear-gradient(90deg, #219677, #27ae60); transition: width 0.3s ease; `; const progressText = document.createElement('div'); progressText.style = ` text-align: center; font-size: 12px; color: #666; `; progressText.textContent = '准备中...'; progressBar.appendChild(progressFill); container.appendChild(progressBar); container.appendChild(progressText); document.body.appendChild(container); return { container, progressFill, progressText }; } // 创建下载按钮 function createDownloadBtn() { const btn = document.createElement('button'); btn.style = ` position: fixed; top: 20px; left: 20px; padding: 7px 15px; background: #219677; color: white; border: none; border-radius: 4px; cursor: pointer; z-index: 9999; box-shadow: 0 2px 5px rgba(0,0,0,0.3); transition: all 0.3s; `; btn.textContent = '下载PDF'; btn.onclick = startDownloadProcess; document.body.appendChild(btn); } // 从URL获取code function getCodeFromURL() { const pathSegments = window.location.pathname.split('/'); const code = pathSegments[pathSegments.length - 1]; return code || ''; } // 更新进度条 function updateProgress(progressData) { progressData.progressFill.style.width = `${(loadedPages / totalPages * 100).toFixed(1)}%`; progressData.progressText.textContent = `已下载 ${loadedPages}/${totalPages} 页 (${(loadedPages / totalPages * 100).toFixed(1)}%)`; } // 获取全部页面数据 async function fetchAllPages(progressData) { const pdfDoc = await PDFDocument.create(); totalPages = Page.size; loadedPages = 0; progressData.container.style.display = 'block'; updateProgress(progressData); for (let i = 1; i <= totalPages; i++) { const pageData = await fetchPage(i); const pageDoc = await PDFDocument.load(pageData); const [copiedPage] = await pdfDoc.copyPages(pageDoc, [0]); pdfDoc.addPage(copiedPage); loadedPages++; updateProgress(progressData); } return await pdfDoc.save(); } // 获取单页数据 function fetchPage(pageNum) { return new Promise((resolve) => { GM_xmlhttpRequest({ method: "POST", url: "/mnr_kfs/file/readPage", headers: { "Content-Type": "application/x-www-form-urlencoded" }, data: `code=${currentCode}&page=${pageNum}`, responseType: "text", onload: (res) => { const base64Data = res.response; const binaryData = base64ToArrayBuffer(base64Data); resolve(binaryData); } }); }); } // 启动下载流程 async function startDownloadProcess() { const progressData = createProgressBar(); try { currentCode = getCodeFromURL(); if (!currentCode) { alert('无法获取文档编号,请确认当前页面正确'); return; } const pdfBytes = await fetchAllPages(progressData); const blob = new Blob([pdfBytes], { type: 'application/pdf' }); GM_download({ url: URL.createObjectURL(blob), name: `自然资源标准_${currentCode}.pdf`, saveAs: true }); // 下载完成后隐藏进度条 setTimeout(() => { progressData.container.style.display = 'none'; }, 2000); } catch (err) { console.error('下载失败:', err); progressData.progressText.textContent = '下载失败,请刷新重试'; progressData.progressFill.style.background = '#ff4757'; } } // 初始化 (function init() { window.render = function() {}; // 禁用原渲染 createDownloadBtn(); })(); // Base64转换工具 function base64ToArrayBuffer(base64) { const binaryString = atob(base64); const len = binaryString.length; const bytes = new Uint8Array(len); for (let i = 0; i < len; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes.buffer; } })();