// ==UserScript== // @name 职业技能标准PDF工具 // @namespace http://tampermonkey.net/ // @version 2025.8.18 // @description 为职业标准系统添加PDF浏览器查看和下载功能(修复初始化问题) // @author Shuaima // @match *://www.osta.org.cn/skillStandard* // @grant none // @run-at document-end // @require https://lib.baomitu.com/jquery/1.8.3/jquery.min.js // @require https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/layer/3.5.1/layer.min.js // @license MIT // ==/UserScript== (function() { 'use strict'; // 日志工具 const logger = { log: (msg) => console.log(`[PDF工具] ${msg}`), error: (msg) => console.error(`[PDF工具] ${msg}`) }; // 确保TableModifier先定义(解决函数未初始化问题) const TableModifier = { // 标记是否已初始化 initialized: false, /** * 初始化表格修改器 */ init: function() { if (this.initialized) return; this.initialized = true; logger.log('TableModifier初始化完成'); }, /** * 重建表格,添加自定义操作按钮 */ rebuildTable: function(data) { // 确保初始化 this.init(); try { const standardsList = (data?.body?.list) || []; const standardsMap = {}; // 映射数据 standardsList.forEach(item => { standardsMap[item.code] = item; }); // 移除旧按钮 $('.plugin-tool').remove(); // 检查表格是否存在 const $tableRows = $(".arco-table-element tbody > tr"); if (!$tableRows.length) { logger.error('未找到表格行,无法添加按钮'); return; } // 遍历行添加按钮 $tableRows.each(function() { const $row = $(this); const code = $row.find('td').eq(2).text().trim(); const item = standardsMap[code]; if (!item) return; const $actionCell = $row.find('td').eq(5); if (!$actionCell.length) return; // 修改原有链接文本 $actionCell.find('a').text('网站查看'); // 添加新按钮 $actionCell.find('.arco-table-td-content').append(` 浏览器查看
PDF下载 `); // 绑定数据 $actionCell.find(".plugin-tool").data('item', item); }); logger.log(`已为${$tableRows.length}行添加操作按钮`); } catch (error) { logger.error(`rebuildTable执行失败: ${error.message}`); } } }; // PDF处理工具 const PdfHandler = { cache: {}, apiUrl: '//www.osta.org.cn/api/sys/downloadFile/decrypt', handleClick: async function(event) { try { const $btn = $(event.currentTarget); const actionType = $btn.data('type'); const item = $btn.data('item'); if (!item) { alert('数据获取失败,请刷新页面'); return; } const { code, standardInfo: fileName, standardInfoName: displayName } = item; // 缓存逻辑 if (this.cache[code]) { this.cache[code].accessCount++; this.processPdfData(actionType, displayName, code, this.cache[code].blobData); if (this.cache[code].accessCount > 10) delete this.cache[code]; return; } // 加载动画 const loading = layer.load(0, { shade: [0.5, '#000'] }); // 请求PDF const response = await fetch(`${this.apiUrl}?fileName=${encodeURIComponent(fileName)}`); if (!response.ok) throw new Error(`HTTP错误: ${response.status}`); const pdfBlob = await response.blob(); this.cache[code] = { blobData: pdfBlob, accessCount: 1 }; this.processPdfData(actionType, displayName, code, pdfBlob); } catch (error) { logger.error(`处理失败: ${error.message}`); alert(`操作失败: ${error.message}`); } finally { layer.closeAll('loading'); } }, processPdfData: function(actionType, displayName, code, pdfBlob) { const blob = new Blob([pdfBlob], { type: 'application/pdf' }); const url = URL.createObjectURL(blob); if (actionType === 'open') { window.open(url); } else if (actionType === 'download') { const a = document.createElement('a'); a.download = this.sanitizeFileName(displayName); a.href = url; a.click(); setTimeout(() => URL.revokeObjectURL(url), 1000); } }, sanitizeFileName: function(name) { const clean = name.replace(/[\\/:*?"<>|]/g, ''); return clean.endsWith('.pdf') ? clean : `${clean}.pdf`; } }; // AJAX监控器 const AjaxMonitor = { init: function() { // 确保TableModifier已初始化 TableModifier.init(); const originalXHR = window.XMLHttpRequest; window.XMLHttpRequest = function() { const xhr = new originalXHR(); xhr.addEventListener('readystatechange', function() { const event = new CustomEvent('ajaxReadyStateChange', { detail: this }); window.dispatchEvent(event); }); return xhr; }; window.addEventListener('ajaxReadyStateChange', (e) => this.handleResponse(e)); logger.log('AJAX监控已启动'); }, handleResponse: function(event) { const xhr = event.detail; if (xhr.readyState === 4 && xhr.responseURL?.includes('skillStandardList')) { try { const data = JSON.parse(xhr.responseText || '{}'); // 确保TableModifier已定义 if (TableModifier && typeof TableModifier.rebuildTable === 'function') { setTimeout(() => TableModifier.rebuildTable(data), 500); } else { logger.error('TableModifier未初始化,无法重建表格'); } } catch (error) { logger.error(`解析响应失败: ${error.message}`); } } } }; // 主初始化函数 function init() { try { // 初始化依赖链 TableModifier.init(); AjaxMonitor.init(); // 绑定事件 $(document).on('click', '.plugin-tool', PdfHandler.handleClick.bind(PdfHandler)); // 尝试手动触发一次表格重建(针对页面已加载完成的情况) setTimeout(() => { logger.log('尝试手动触发表格初始化'); TableModifier.rebuildTable({ body: { list: [] } }); }, 1000); logger.log('插件初始化完成'); } catch (error) { logger.error(`初始化失败: ${error.message}`); // 重试机制 setTimeout(init, 2000); } } // 页面加载完成后启动 if (document.readyState === 'complete') { init(); } else { window.addEventListener('load', init); } })();