Izyz-Helper

Help you to use izyz easier!

// ==UserScript==
// @name         Izyz-Helper
// @namespace    https://greasyfork.org/users/1417526
// @version      0.1.3
// @description  Help you to use izyz easier!
// @author       Weichenleeeee
// @match        https://www.gdzyz.cn/*
// @icon         https://www.gdzyz.cn/assets/weblogo.1b6eba63.svg
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @grant        GM_openInTab
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @grant        GM_getResourceText
// @require      https://unpkg.com/xlsx/dist/xlsx.full.min.js
// ==/UserScript==

(function() {
    'use strict';

    var names = []; // 用实际的名字替换
    var nextButtonEnabled = false; // 是否已点击“添加补录”
    var skipButtonEnabled = false; // 是否点击了跳过按钮
    var volunteersSkipped = [];

    // 检测XLSX库是否加载成功
    setTimeout(function() {
        if (typeof XLSX === "undefined") {
            console.error("XLSX 库加载失败!");
            alert("无法加载 XLSX 库,功能无法使用!");
            return;
        } else {
            console.log("XLSX 库加载成功!");
        }
    }, 1000); // 延迟1秒检查是否加载成功

    // 添加图片上传按钮
    function createImageInput() {
        var container = document.createElement('div');
        container.style.position = 'fixed';
        container.style.bottom = '130px';
        container.style.left = '10px';
        container.style.zIndex = 9999;
        
        var label = document.createElement('span');
        label.textContent = '上传志愿者照片';
        label.style.color = '#4CAF50';
        label.style.marginRight = '10px';
        label.style.fontSize = '14px';
        container.appendChild(label);

        var input = document.createElement('input');
        input.type = 'file';
        input.accept = 'image/*'; // 限制为图片文件
        input.title = '上传志愿者照片(支持JPG/PNG格式)';
        input.style.padding = '5px';
        input.style.borderRadius = '5px';
        input.style.backgroundColor = '#4CAF50';
        input.style.color = 'white';
        input.style.border = 'none';
        input.style.cursor = 'pointer';
        input.addEventListener('change', handleImageSelect);
        container.appendChild(input);
        document.body.appendChild(container);
    }

    // 添加Excel上传按钮
    function createExcelInput() {
        var container = document.createElement('div');
        container.style.position = 'fixed';
        container.style.bottom = '90px';
        container.style.left = '10px';
        container.style.zIndex = 9999;
        
        var label = document.createElement('span');
        label.textContent = '上传志愿者名单';
        label.style.color = '#2196F3';
        label.style.marginRight = '10px';
        label.style.fontSize = '14px';
        container.appendChild(label);

        var input = document.createElement('input');
        input.type = 'file';
        input.accept = '.xlsx,.xls'; // 限制为Excel文件
        input.title = '上传志愿者名单(支持Excel格式)';
        input.style.padding = '5px';
        input.style.borderRadius = '5px';
        input.style.backgroundColor = '#2196F3';
        input.style.color = 'white';
        input.style.border = 'none';
        input.style.cursor = 'pointer';
        input.addEventListener('change', handleExcelSelect);
        container.appendChild(input);
        document.body.appendChild(container);
    }

    // 处理Excel文件选择
    function handleExcelSelect(event) {
        var file = event.target.files[0];
        if (file && (file.name.endsWith('.xlsx') || file.name.endsWith('.xls'))) {
            var reader = new FileReader();
            reader.onload = function(e) {
                var data = e.target.result;
                var workbook = XLSX.read(data, { type: 'binary' });
                var sheet = workbook.Sheets[workbook.SheetNames[0]]; // 默认取第一个工作表

                // 将工作表转换为二维数组,raw: true 确保读取原始数据而不进行格式化
                var json = XLSX.utils.sheet_to_json(sheet, { header: 1, raw: true });

                // 打印原始数据以查看第一行
                console.log('读取到的数据:', json);

                // 在整个表格中搜索"姓名"列
                var nameColumnIndex = -1;
                
                // 首先检查表头
                var header = json[0];
                nameColumnIndex = header.findIndex(col => col.trim() === "姓名");
                
                // 如果表头中没有找到,遍历所有行查找
                if (nameColumnIndex === -1) {
                    for (let i = 0; i < json.length; i++) {
                        nameColumnIndex = json[i].findIndex(col => col.trim() === "姓名");
                        if (nameColumnIndex !== -1) {
                            console.log('在第', i + 1, '行找到"姓名"列');
                            break;
                        }
                    }
                }

                if (nameColumnIndex === -1) {
                    alert('未找到“姓名”列,请确保Excel中有“姓名”列');
                    console.error('未找到姓名列');
                    return;
                }

                // 提取姓名列数据,并移除姓名前的数字,跳过表头
                names = json.slice(1).map(row => {
                    let name = row[nameColumnIndex];
                    if (name) {
                        // 使用正则表达式移除姓名前的数字
                        name = name.replace(/^\d+/, '').trim();
                    }
                    return name;
                }).filter(name => name && name !== "姓名"); // 过滤掉空值和"姓名"字符串

                console.log('已加载姓名:', names);
                alert('Excel 文件已成功加载,姓名已提取!');
            };

            reader.onerror = function(ex) {
                console.log(ex);
            };

            reader.readAsBinaryString(file);
        } else {
            alert('请上传有效的 Excel 文件');
        }
    }
    
    // 添加跳过按钮
    function createSkipButton() {
        var skipButton = document.createElement('button');
        skipButton.textContent = '跳过当前志愿者';
        skipButton.style.position = 'fixed';
        skipButton.style.bottom = '50px'; // 放在“上传文件”按钮的上方
        skipButton.style.left = '10px';
        skipButton.style.zIndex = 9999;
        skipButton.style.padding = '10px';
        skipButton.style.borderRadius = '5px';
        skipButton.style.backgroundColor = '#f44336'; // 红色按钮
        skipButton.style.color = 'white';
        skipButton.style.border = 'none';
        skipButton.style.cursor = 'pointer';
        skipButton.style.fontSize = '14px';
        skipButton.addEventListener('click', function() {
            skipButtonEnabled = true; // 设置跳过标志
            console.log('用户点击了跳过按钮1');
            console.log('skipButtonEnabled is ',skipButtonEnabled);
        });
        document.body.appendChild(skipButton);
    }

    // 百度云OCR配置
    const BAIDU_API_KEY = '4rHGTojlMzTYGov3tBHugdI6';
    const BAIDU_SECRET_KEY = 'g4dhvSh3KHXfDoljUPRFceVczdVrGued';
    let accessToken = '';

    // 获取百度云access_token
    function getAccessToken() {
        return new Promise((resolve, reject) => {
            const url = `https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${BAIDU_API_KEY}&client_secret=${BAIDU_SECRET_KEY}`;
            
            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                onload: function(response) {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data.access_token) {
                            accessToken = data.access_token;
                            console.log('百度云access_token获取成功');
                            resolve();
                        } else {
                            throw new Error('获取access_token失败');
                        }
                    } catch (error) {
                        reject(error);
                    }
                },
                onerror: function(error) {
                    reject(error);
                }
            });
        });
    }

    // 将图片文件转换为base64
    function fileToBase64(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = () => {
                const base64 = reader.result.split(',')[1];
                resolve(base64);
            };
            reader.onerror = reject;
            reader.readAsDataURL(file);
        });
    }

    // 处理图片选择
    async function handleImageSelect(event) {
        const file = event.target.files[0];
        if (!file || !file.type.startsWith('image/')) {
            alert('请上传有效的图片文件');
            return;
        }

        try {
            // 获取access_token
            await getAccessToken();
            
            // 将图片转换为base64
            const imageBase64 = await fileToBase64(file);
            
            // 调用百度云OCR API
            const ocrUrl = `https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token=${accessToken}`;
            
            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: 'POST',
                    url: ocrUrl,
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded'
                    },
                    data: `image=${encodeURIComponent(imageBase64)}&language_type=CHN_ENG`,
                    onload: function(response) {
                        try {
                            const result = JSON.parse(response.responseText);
                            if (result.words_result) {
                                names = result.words_result
                                    .map(item => item.words.trim())
                                    .filter(line => line.length > 0)
                                    .map(name => {
                                        // 移除姓名前的数字
                                        name = name.replace(/^\d+/, '').trim();
                                        // 匹配2-4个中文字符的姓名
                                        const chineseNamePattern = /^[\u4e00-\u9fa5]{2,4}$/;
                                        if (chineseNamePattern.test(name)) {
                                            return name;
                                        }
                                        return null;
                                    })
                                    .filter(name => name !== null); // 过滤掉不符合条件的项

                                // 创建选择界面
                                const modal = document.createElement('div');
                                modal.style.position = 'fixed';
                                modal.style.top = '0';
                                modal.style.left = '0';
                                modal.style.width = '100%';
                                modal.style.height = '100%';
                                modal.style.backgroundColor = 'rgba(0,0,0,0.5)';
                                modal.style.zIndex = 10000;
                                
                                const content = document.createElement('div');
                                content.style.position = 'absolute';
                                content.style.top = '50%';
                                content.style.left = '50%';
                                content.style.transform = 'translate(-50%, -50%)';
                                content.style.backgroundColor = 'white';
                                content.style.padding = '20px';
                                content.style.borderRadius = '5px';
                                content.style.width = '400px';
                                
                                const title = document.createElement('h3');
                                title.textContent = '请选择要添加的姓名';
                                title.style.marginBottom = '15px';
                                content.appendChild(title);
                                
                                const list = document.createElement('div');
                                list.style.maxHeight = '300px';
                                list.style.overflowY = 'auto';
                                list.style.marginBottom = '15px';
                                
                                names.forEach((name, index) => {
                                    const item = document.createElement('div');
                                    item.style.display = 'flex';
                                    item.style.alignItems = 'center';
                                    item.style.marginBottom = '10px';
                                    
                                    const checkbox = document.createElement('input');
                                    checkbox.type = 'checkbox';
                                    checkbox.checked = true;
                                    checkbox.style.marginRight = '10px';
                                    
                                    const input = document.createElement('input');
                                    input.type = 'text';
                                    input.value = name;
                                    input.style.flex = '1';
                                    input.style.padding = '5px';
                                    
                                    item.appendChild(checkbox);
                                    item.appendChild(input);
                                    list.appendChild(item);
                                });
                                
                                content.appendChild(list);
                                
                                const buttonContainer = document.createElement('div');
                                buttonContainer.style.display = 'flex';
                                buttonContainer.style.justifyContent = 'flex-end';
                                
                                const confirmButton = document.createElement('button');
                                confirmButton.textContent = '确认';
                                confirmButton.style.padding = '8px 16px';
                                confirmButton.style.backgroundColor = '#4CAF50';
                                confirmButton.style.color = 'white';
                                confirmButton.style.border = 'none';
                                confirmButton.style.borderRadius = '4px';
                                confirmButton.style.cursor = 'pointer';
                                confirmButton.onclick = () => {
                                    const selectedNames = [];
                                    list.querySelectorAll('div').forEach(item => {
                                        const checkbox = item.querySelector('input[type="checkbox"]');
                                        const input = item.querySelector('input[type="text"]');
                                        if (checkbox.checked) {
                                            selectedNames.push(input.value.trim());
                                        }
                                    });
                                    names = selectedNames.filter(name => name.length > 0);
                                    document.body.removeChild(modal);
                                    console.log('用户选择的姓名:', names);
                                    alert('姓名选择完成!');
                                    resolve();
                                };
                                
                                const cancelButton = document.createElement('button');
                                cancelButton.textContent = '取消';
                                cancelButton.style.padding = '8px 16px';
                                cancelButton.style.marginRight = '10px';
                                cancelButton.style.backgroundColor = '#f44336';
                                cancelButton.style.color = 'white';
                                cancelButton.style.border = 'none';
                                cancelButton.style.borderRadius = '4px';
                                cancelButton.style.cursor = 'pointer';
                                cancelButton.onclick = () => {
                                    document.body.removeChild(modal);
                                    resolve();
                                };
                                
                                buttonContainer.appendChild(cancelButton);
                                buttonContainer.appendChild(confirmButton);
                                content.appendChild(buttonContainer);
                                
                                modal.appendChild(content);
                                document.body.appendChild(modal);
                            } else {
                                throw new Error('OCR识别失败');
                            }
                        } catch (error) {
                            reject(error);
                        }
                    },
                    onerror: function(error) {
                        reject(error);
                    }
                });
            });
        } catch (error) {
            console.error('图片识别失败:', error);
            alert('图片识别失败,请确保图片清晰且包含中文文本');
        }
    }


    // 创建并显示进度条
    function createProgressBar() {
        var progressContainer = document.createElement('div');
        progressContainer.style.position = 'fixed';
        progressContainer.style.bottom = '170px';  // 下移80px
        progressContainer.style.left = '10px';
        progressContainer.style.zIndex = 9999;
        progressContainer.style.width = '300px';
        progressContainer.style.height = '30px';
        progressContainer.style.backgroundColor = '#e0e0e0';
        progressContainer.style.borderRadius = '5px';
            
        var progressBar = document.createElement('div');
        progressBar.style.height = '100%';
        progressBar.style.width = '0%';
        progressBar.style.backgroundColor = '#4CAF50';
        progressBar.style.borderRadius = '5px';
        progressContainer.appendChild(progressBar);
    
        var progressText = document.createElement('span');
        progressText.style.position = 'absolute';
        progressText.style.top = '50%';
        progressText.style.left = '50%';
        progressText.style.transform = 'translate(-50%, -50%)';
        progressText.style.color = 'white';
        progressText.style.fontSize = '14px';
        progressContainer.appendChild(progressText);
    
        var currentVolunteerText = document.createElement('span');
        currentVolunteerText.style.position = 'fixed';
        currentVolunteerText.style.bottom = '210px';  // 下移80px
        currentVolunteerText.style.left = '10px';
        currentVolunteerText.style.zIndex = 9999;
        currentVolunteerText.style.fontSize = '14px';
        currentVolunteerText.style.color = '#4CAF50';
        currentVolunteerText.style.fontWeight = 'bold';
        currentVolunteerText.textContent = '当前录入:第 0 个志愿者';
        document.body.appendChild(currentVolunteerText);
    
        document.body.appendChild(progressContainer); // 确保进度条在页面中显示
    
        return { progressBar, progressText, currentVolunteerText };
    
    }

    // 更新进度条
    function updateProgressBar(progressBar, progressText, current, total, currentVolunteerText) {
        var percentage = Math.round((current / total) * 100);
        progressBar.style.width = percentage + '%';
        progressText.textContent = `进度:${percentage}%`;
        currentVolunteerText.textContent = `当前录入:第 ${current} 个志愿者`;
    }


    // 定义一个函数来模拟点击按钮事件
    async function clickButton(selector, delay) {
        await new Promise(resolve => setTimeout(resolve, delay));
        var button = document.querySelector(selector);
        if (button) {
            button.click();
            console.log(`${selector} 按钮已点击`);
        } else {
            console.log(`${selector} 按钮未找到`);
        }
    }

    // 定义一个函数来输入姓名
    async function inputName(name, delay) { // 将 inputText 作为参数传递
        await new Promise(resolve => setTimeout(resolve, delay));
        let input = document.querySelectorAll('.el-input__inner')[0];
        if (input) {
            input.value = name; // 使用参数 name 而不是全局变量 inputText
            var event = document.createEvent('HTMLEvents');
            event.initEvent("input", true, true);
            event.eventType = 'message';
            input.dispatchEvent(event);
            console.log('姓名已输入');
        } else {
            console.log('文本框未找到');
        }
    }

    async function waitForUserAction() {
        return new Promise(resolve => {
            let resolved = false;
            const handleClick = (event) => {
                if (resolved) return;
                
                // 处理跳过按钮点击
                const skipButton = event.target.closest('button');
                if (skipButton && skipButton.textContent.trim() === '跳过当前志愿者') {
                    console.log('用户点击了跳过按钮');
                    resolved = true;
                    resolve('SKIP');
                    return;
                }

                // 处理添加补录按钮点击
                const nextButton = event.target.closest('button.el-button.el-button--primary');
                if (nextButton && nextButton.querySelector('span')?.textContent.trim() === '添加补录') {
                    console.log('用户点击了“添加补录”按钮');
                    resolved = true;
                    resolve('CONTINUE');
                    return;
                }
            };

            // 使用捕获阶段监听,确保能捕获到动态创建的按钮
            document.addEventListener('click', handleClick, { capture: true });

            // 添加超时检查
            const timeout = setTimeout(() => {
                if (!resolved) {
                    console.log('等待用户操作超时');
                    resolved = true;
                    resolve('TIMEOUT');
                }
            }, 30000); // 30秒超时

            // 清理函数
            return () => {
                document.removeEventListener('click', handleClick, { capture: true });
                clearTimeout(timeout);
            };
        });
    }

    // 定义一个函数来勾选单选框并点击“添加补录”
    async function checkCheckbox(delay) {
        await new Promise(resolve => setTimeout(resolve, delay));
        var checkboxes = document.querySelectorAll('.el-checkbox__inner');
        if (checkboxes.length > 4) {
            console.log('超过4个单选框被找到,等待用户操作');
            alert('出现重名,请手动勾选志愿者,并点击“添加补录”');
            await waitForUserAction(); // 等待用户点击“添加补录”
        }
        else if(checkboxes.length < 4){
            // 查无此人的情况,需要手动勾选
            console.log('查无此人,提供跳过或手动选择的选项');
            alert('查无此人,请手动勾选志愿者并点击“添加补录”,或点击“跳过”按钮');
            const result = await waitForUserAction(); // 等待用户点击“添加补录”或“跳过”
            console.log(result);
            if (result === 'SKIP') {
                return 'SKIP'; // 跳过当前志愿者
            }else if (result === 'CONTINUE') {
                return 'CONTINUE';
            }
        }else{
            // 正常情况
            checkboxes.forEach((checkbox) => checkbox.click());
            console.log('单选框已勾选');
            await clickButton('.el-button.el-button--primary[style*="margin-bottom: 20px;"]', 500); // 点击“添加补录”按钮
            nextButtonEnabled = true; // 标志已完成“添加补录”
        }
    }

    // 主处理函数
    async function processNames(names){
        const { progressBar, progressText, currentVolunteerText } = createProgressBar(); // 创建进度条
        for (let i = 0; i < names.length; i++) {
            console.log(`正在处理志愿者:${names[i]}`);
    
            await clickButton('.el-button.el-button--primary', 1000); // 打开输入页面
            await inputName(names[i], 1000); // 输入志愿者姓名
            await clickButton('.queryOrgBtn', 500); // 点击查询按钮
    
            const result = await checkCheckbox(500);
            if (result === 'SKIP') {
                console.log(`跳过志愿者:${names[i]}`);
                // 记录当前志愿者的名字
                volunteersSkipped.push(names[i]);
                console.log(`记录志愿者:${names[i]}`);
                continue; // 跳过当前志愿者,进入下一个
            }else if (result === 'CONTINUE') {
                console.log(`继续处理志愿者:${names[i]}`);
            }
            // 更新进度条
            updateProgressBar(progressBar, progressText, i + 1, names.length, currentVolunteerText);
    
            // 等待用户完成“添加补录”操作
            await clickButton('.el-button.el-button--primary[style*="display: block; margin: 0px auto;"]', 500); // 点击“下一步”按钮
            console.log('“下一步”已被点击');
            nextButtonEnabled = false; // 重置标志
        };
        // 在最后显示被跳过的志愿者名字
        if (volunteersSkipped.length > 0) {
            alert(`录用完成,被跳过的的志愿者:${volunteersSkipped.join(', ')}`);
        }
    }

    // 创建按钮
    createImageInput();
    createExcelInput();
    createSkipButton();

    // 定义菜单命令:开始
    let menu1 = GM_registerMenuCommand('开始', function () {
        if (names.length === 0) {
            alert('请先上传并加载 Excel 文件!');
            return;
        }
        processNames(names);
    }, 'o');

})();