您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在智慧团建网站的组织关系审批页面中自动完成姓名搜索和数据收集
// ==UserScript== // @name 智慧团建组织关系审批自动搜索 auto-search-names-in-managetransferprocessdo-at-zhtj.youth.cn // @namespace http://tampermonkey.net/ // @version 1.0.1 // @description 在智慧团建网站的组织关系审批页面中自动完成姓名搜索和数据收集 // @author PDLi // @match https://zhtj.youth.cn/* // @icon https://zhtj.youth.cn/zhtj/static/img/web_logo.png // @license MIT // ==/UserScript== (function () { 'use strict' let inputName let searchButton const keys = ['姓名', '申请时间', '完成时间', '转出团组织', '转入团组织', '处理状态', '操作'] let sleepTime = 1000 let names = [] let result = [] let jsonResult = '' let csvResult = '' function sleep(delay) { return new Promise((resolve) => setTimeout(resolve, delay)) } function createWindow() { const floatWindowWithButton = document.createElement('div') floatWindowWithButton.id = 'float-window-with-button' floatWindowWithButton.style.display = 'none' const floatWindow = document.createElement('div') floatWindow.style.width = '300px' floatWindow.style.height = '500px' floatWindow.style.background = 'white' floatWindow.style.color = 'black' floatWindow.style.position = 'fixed' floatWindow.style.bottom = '1px' floatWindow.style.right = '0px' floatWindow.style.padding = '30px' floatWindow.style.fontSize = '5px' floatWindow.style.display = 'block' floatWindow.style.border = '1px solid black' floatWindow.style.fontFamily = '黑体' floatWindow.id = 'float-window' const minButton = document.createElement('button') minButton.style.position = 'absolute' minButton.style.height = '20px' minButton.style.width = '30px' minButton.style.bottom = '481px' minButton.style.right = '0px' minButton.style.fontSize = '2px' minButton.style.fontWeight = '700' minButton.style.fontFamily = '黑体' minButton.innerText = '折叠' minButton.id = 'min-button' minButton.addEventListener('click', () => { let dispaly = floatWindow.style.display if (dispaly === 'block') { floatWindow.style.display = 'none' minButton.innerText = '展开' } else { floatWindow.style.display = 'block' minButton.innerText = '折叠' } }) const floatWindowInner = document.createElement('div') floatWindowInner.id = 'float-window-inner' const controllers = document.createElement('div') controllers.id = 'controller' const floatWindowTextContainer = document.createElement('div') floatWindowTextContainer.id = 'float-window-text-container' floatWindowTextContainer.style.marginTop = '40px' const beforeTextGrid = document.createElement('div') beforeTextGrid.style.display = 'grid' beforeTextGrid.style.gridTemplateColumns = '54% 16% 30%' const formatSelectorLabel = document.createElement('div') formatSelectorLabel.innerText = '格式:' formatSelectorLabel.style.fontWeight = '700' const formatSelector = document.createElement('select') formatSelector.id = 'format-selector' const optionJson = document.createElement('option') optionJson.text = 'JSON' optionJson.value = 'JSON' const optionCsv = document.createElement('option') optionCsv.text = 'CSV' optionCsv.value = 'CSV' formatSelector.add(optionJson) formatSelector.add(optionCsv) formatSelector.addEventListener('change', () => { displayResult() }) const floatWindowTextLabel = document.createElement('div') floatWindowTextLabel.innerText = '搜索结果:' floatWindowTextLabel.style.fontWeight = '700' const floatWindowText = document.createElement('div') floatWindowText.id = 'float-window-text' floatWindowText.style.width = '240px' floatWindowText.style.height = '200px' floatWindowText.style.padding = '2px 5px' floatWindowText.style.overflow = 'auto' floatWindowText.style.border = '1px solid black' floatWindowText.style.marginTop = '3px' const sleepTimeControllerLabel = document.createElement('label') sleepTimeControllerLabel.innerText = '每次搜索间隔时间(毫秒):' const sleepTimeController = document.createElement('input') sleepTimeController.id = 'sleep-time-controller' sleepTimeController.type = 'number' sleepTimeController.value = sleepTime sleepTimeController.addEventListener('change', () => { sleepTime = sleepTimeController.value }) const namesInputLabel = document.createElement('label') namesInputLabel.innerText = '要被搜索的姓名(以空白字符分隔):' namesInputLabel.style.marginBottom = '0' const namesInput = document.createElement('textarea') namesInput.id = 'names-input' namesInput.rows = '5' namesInput.style.resize = 'none' namesInput.style.width = '100%' namesInput.style.fontWeight = '500' namesInput.style.lineHeight = '12px' namesInput.style.padding = '2px 5px' const StartSearchButton = document.createElement('button') StartSearchButton.innerText = '开始搜索' StartSearchButton.style.margin = '-2px 0px' StartSearchButton.style.color = 'black' StartSearchButton.style.position = 'absolute' StartSearchButton.style.right = '30px' StartSearchButton.style.fontWeight = '700' StartSearchButton.addEventListener('click', async () => { inputName = document.querySelector("#pane-first > div.row > div:nth-child(3) > div > div > input") searchButton = document.querySelector("#pane-first > div.row > div.col-sm-1.floatright > button") result = [] names = namesInput.value.split(/\s+/) names = names.filter(x => x !== '') await doSearch() jsonResult = JSON.stringify(result) generateCsvResult() displayResult() }) const fileInputLabel = document.createElement('label') fileInputLabel.innerText = '从txt文件读取' fileInputLabel.style.cursor = 'pointer' fileInputLabel.style.color = 'blue' fileInputLabel.addEventListener('mouseover', () => { fileInputLabel.style.textDecoration = 'underline' }) fileInputLabel.addEventListener('mouseleave', () => { fileInputLabel.style.textDecoration = 'none' }) const fileInput = document.createElement('input') fileInput.id = 'names-file-input' fileInput.type = 'file' fileInput.accept = '.txt' fileInput.addEventListener('change', () => { const file = fileInput.files[0] const reader = new FileReader() reader.readAsText(file) reader.onload = () => { namesInput.value = reader.result } }) const exportButtonsGrid = document.createElement('div') exportButtonsGrid.style.display = 'grid' exportButtonsGrid.style.gridAutoFlow = 'column' exportButtonsGrid.style.justifyContent = 'end' exportButtonsGrid.style.marginTop = '5px' exportButtonsGrid.style.fontWeight = '700' const exportJsonButton = document.createElement('button') exportJsonButton.innerText = '导出为JSON' exportJsonButton.style.marginLeft = '5px' exportJsonButton.addEventListener('click', () => { const blob = new Blob([jsonResult], { type: 'application/json' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = new Date().toLocaleString().replace(/\s+/g, '-').replace(/[:/]/g, '-') + '.json' document.body.appendChild(a) a.click() document.body.removeChild(a) }) const exportCsvButton = document.createElement('button') exportCsvButton.innerText = '导出为CSV' exportCsvButton.style.marginLeft = '5px' exportCsvButton.addEventListener('click', () => { const url = 'data:application/csv;charset=utf-8,\ufeff' + encodeURIComponent(csvResult) const a = document.createElement('a') a.href = url a.download = new Date().toLocaleString().replace(/\s+/g, '-').replace(/[:/]/g, '-') + '.csv' document.body.appendChild(a) a.click() document.body.removeChild(a) }) sleepTimeControllerLabel.appendChild(sleepTimeController) controllers.appendChild(sleepTimeControllerLabel) namesInputLabel.appendChild(namesInput) controllers.appendChild(namesInputLabel) fileInputLabel.appendChild(fileInput) controllers.appendChild(fileInputLabel) controllers.appendChild(StartSearchButton) floatWindowInner.appendChild(controllers) beforeTextGrid.appendChild(floatWindowTextLabel) beforeTextGrid.appendChild(formatSelectorLabel) beforeTextGrid.appendChild(formatSelector) exportButtonsGrid.appendChild(exportJsonButton) exportButtonsGrid.appendChild(exportCsvButton) floatWindowTextContainer.appendChild(beforeTextGrid) floatWindowTextContainer.appendChild(floatWindowText) floatWindowTextContainer.appendChild(exportButtonsGrid) floatWindowInner.appendChild(floatWindowTextContainer) floatWindow.appendChild(floatWindowInner) floatWindowWithButton.appendChild(floatWindow) floatWindowWithButton.appendChild(minButton) document.body.appendChild(floatWindowWithButton) function displayResult() { switch (formatSelector.value) { case 'JSON': floatWindowText.innerText = jsonResult break case 'CSV': floatWindowText.innerText = csvResult break } } } function changeName(name) { const events = { foucs: new Event('focus'), input: new Event('input'), change: new Event('change'), blur: new Event('blur') } inputName.value = name inputName.dispatchEvent(events.foucs) inputName.dispatchEvent(events.input) inputName.dispatchEvent(events.change) inputName.dispatchEvent(events.blur) } async function search(name) { let res = [] changeName(name) searchButton.click() await sleep(sleepTime) const cells = document.querySelectorAll("#pane-first > div:nth-child(2) > div > div.el-table__body-wrapper.is-scrolling-none > table > tbody tr td") if (cells.length === 0) { res.push({ 姓名: name, 查询成功: '否', }) keys.forEach(key => { if (key !== '姓名') { res[0][key] = '' } }) } cells.forEach((cell, i) => { if (i % 7 === 0) res.push({}) res[parseInt(i / 7)][keys[i % 7]] = cell.innerText if (i % 7 === 0) res[parseInt(i / 7)]['查询成功'] = '是' }) res = res.filter(r => r['姓名'] === name) res.forEach(r => result.push(r)) } async function doSearch() { for (let i = 0; i < names.length; i++) { let name = names[i] await search(name) } } function generateCsvResult() { csvResult = '' let header = { 姓名: '姓名', 查询成功: '查询成功' } for (let i = 1; i < keys.length; i++) { header[keys[i]] = keys[i] } let resultCopy = JSON.parse(JSON.stringify(result)) resultCopy.unshift(header) resultCopy.map(item => { Object.keys(header).map(key => { csvResult += item[key] + ',' }) csvResult += '\r\n' }) } createWindow() setInterval(() => { const url = window.location.href if (url === 'https://zhtj.youth.cn/zhtj/center/manage/managetransferprocessdo') { document.getElementById('float-window-with-button').style.display = 'block' } else { document.getElementById('float-window-with-button').style.display = 'none' } } ,500) })()