职业技能标准PDF下载
// ==UserScript==
// @name 职业技能标准PDF下载
// @namespace http://tampermonkey.net/
// @version 2025.3.6
// @description 职业标准系统下载pdf功能
// @author Shuaima
// @match *://www.osta.org.cn/skillStandard*
// @grant none
// @run-at document-body
// @require https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-y/jquery/3.6.0/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';
// 创建一个Map对象,用于缓存PDF文件
const pdfCacheMap = new Map();
// 监听页面中带有类名.plugin-tool的元素的点击事件
$(document).on('click', '.plugin-tool', async function() {
// 获取点击元素的data-type属性值
const type = $(this).data('type');
// 获取点击元素的data-item属性值
const item = $(this).data('item');
// 如果item为空,弹出提示并返回
if (!item) {
return alert('获取数据失败');
}
// 从item中获取code、fileName和name
const code = item.code;
const fileName = item.standardInfo;
const name = item.standardInfoName;
// 如果pdfCacheMap中已经缓存了该code对应的PDF文件
if (pdfCacheMap.has(code)) {
// 获取缓存的数据
const cachedData = pdfCacheMap.get(code);
// 增加缓存数据的访问次数
cachedData.times++;
// 处理PDF数据
processPdfData(type, name, code, cachedData.data);
// 如果访问次数超过2次,从缓存中删除该数据
if (cachedData.times > 2) {
pdfCacheMap.delete(code);
}
return;
}
// 如果layer库存在,显示加载动画
if (layer) {
layer.load(0, {
shade: [0.5, '#000'],
});
}
try {
// 发起请求,下载PDF文件
const response = await fetch(`http://www.osta.org.cn/api/sys/downloadFile/decrypt?fileName=${fileName}`);
// 将响应转换为Blob对象
const pdfBlob = await response.blob();
// 将Blob对象缓存到pdfCacheMap中
pdfCacheMap.set(code, {
data: pdfBlob,
times: 1
});
// 处理PDF数据
processPdfData(type, name, code, pdfBlob);
} catch (error) {
// 捕获并打印错误信息
console.error('Failed to fetch PDF:', error);
} finally {
// 无论成功或失败,关闭加载动画
if (layer) {
layer.closeAll();
}
}
});
// 处理PDF数据的函数
function processPdfData(type, name, code, pdfData) {
// 将PDF数据转换为Blob对象
const blob = new Blob([pdfData], { type: 'application/pdf' });
// 创建Blob对象的URL
const url = window.URL.createObjectURL(blob);
// 创建一个a标签,用于下载PDF文件
const a = document.createElement('a');
a.download = name;
a.href = url;
a.click();
// 释放URL对象
window.URL.revokeObjectURL(url);
}
// 创建一个Map对象,用于缓存请求内容
const requestContentMap = new Map();
// 自定义事件触发器,用于触发ajax相关事件
function ajaxEventTrigger(event) {
const ajaxEvent = new CustomEvent(event, { detail: this });
window.dispatchEvent(ajaxEvent);
}
// 保存原始的XMLHttpRequest对象
const oldXHR = window.XMLHttpRequest;
// 创建一个新的XMLHttpRequest对象,并添加事件监听
function newTestXHR() {
const realXHR = new oldXHR();
realXHR.addEventListener('readystatechange', function() {
ajaxEventTrigger.call(this, 'ajaxReadyStateChange');
}, false);
return realXHR;
}
// 替换全局的XMLHttpRequest对象为新的XMLHttpRequest对象
window.XMLHttpRequest = newTestXHR;
// 监听ajaxReadyStateChange事件
window.addEventListener('ajaxReadyStateChange', function (e) {
// 获取请求的URL
const url = e.detail.responseURL;
// 如果URL包含'skillStandardList'并且请求状态为4(完成)
if (url && url.includes('skillStandardList') && e.detail.readyState === 4) {
// 获取响应文本并解析为JSON对象
const responseText = e.detail.responseText || '';
const data = JSON.parse(responseText) || [];
// 延迟500毫秒后调用rebuildTable函数
setTimeout(() => rebuildTable(data), 500);
}
});
// 重新构建表格的函数
function rebuildTable(data) {
// 从data中获取列表数据
const list = (data && data.body && data.body.list) || [];
// 将列表数据转换为Map对象,key为code,value为item
const listMap = new Map(list.map(item => [item.code, item]));
// 移除页面中已有的.plugin-tool元素
$('.plugin-tool').remove();
// 遍历表格中的每一行
$('.arco-table-element tbody > tr').each(function() {
// 获取当前行的code
const code = $(this).find('td').eq(2).text();
// 从listMap中获取对应的item
const item = listMap.get(code);
// 如果item不存在,跳过当前行
if (!item) {
return;
}
// 获取当前行的第5列
const toolTd = $(this).find('td').eq(5);
// 修改第5列中的a标签文本为“网站查看”
toolTd.find('a').text('网站查看');
// 在第5列中添加一个PDF下载的链接
toolTd.find('.arco-table-td-content').append('<a class="arco-link arco-link-status-normal plugin-tool" data-type="download">PDF下载</a>');
// 为新增的PDF下载链接设置data-item属性
toolTd.find('.plugin-tool').data('item', item);
});
}
})();