minerva-online assistant

此脚本能更方便使用minerva-online平台,可在顶端菜单栏右下角的按钮处设置功能开关,并查看功能详情

目前為 2021-10-29 提交的版本,檢視 最新版本

// ==UserScript==
// @name         minerva-online assistant
// @namespace    https://space.bilibili.com/17846288
// @version      2.4.7
// @description  此脚本能更方便使用minerva-online平台,可在顶端菜单栏右下角的按钮处设置功能开关,并查看功能详情
// @author       inoki
// @match        https://www.minerva-online.com/*
// @require      https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @noframes
// ==/UserScript==

/*jshint esversion: 9*/

(()=>{
    'use strict';

    const $=window.$;
    const SET=[
        {
            'id':0,
            'name':'置顶置底',
            'func':()=>{GOTOPBOTTOM();},
            'unfunc':()=>{unGOTOPBOTTOM();},
            'detail':
            `在平台域名所有可滚动页面生效,页面右下方添加置顶置底按钮<br>
            按钮会根据页面滚动方向自动切换置顶和置底,按钮样式可在代码中自定义中修改`,
            'switch':1,
        },
        {
            'id':1,
            'name':'菜单遮罩',
            'func':()=>{COVERMENU();},
            'unfunc':()=>{unCOVERMENU();},
            'detail':
            `在有顶端菜单栏的页面生效<br>
            让菜单栏需要点击一次后才可展开,防止鼠标经过时误触 (默认关闭)`,
            'switch':0,
        },
        {
            'id':2,
            'name':'附件下载',
            'func':()=>{DOWNLOADFILE();},
            'unfunc':()=>{unDOWNLOADFILE();},
            'detail':
            `在问卷管理页面生效,每份报告前添加↓按钮<br>
            点击↓加载附件列表,点击√下载全部附件,点击附件名下载单个附件,鼠标悬停可预览图片`,
            'switch':1,
        },
        {
            'id':3,
            'name':'扣分标记',
            'func':()=>{MARKQUESTION();},
            'unfunc':()=>{unMARKQUESTION();},
            'detail':
            `在单店报告页面生效<br>
            将题目中勾选扣分和n/a项标色,选项更改后需保存报告才会刷新标记,方便快速检查相关题评论<br>
            可在简介上方分别设置扣分(默认为红)和N/A(默认为绿)的标记颜色,点击√保存更改`,
            'switch':1,
        },
        {
            'id':4,
            'name':'评论编辑',
            'func':()=>{COMMENTEDIT();},
            'unfunc':()=>{unCOMMENTEDIT();},
            'detail':
            `在单店报告页面生效,右下方按钮展开操作界面<br>
            使用前请注意阅读操作界面最上方的【点击获取提示】<br>
            输入匹配内容(支持正则)会即时显示匹配的评论框数量并标灰,点击一键替换可批量修改所有评论框内容<br>
            点击首字母大写可智能将所有句首字母变为大写,并标灰发生过修改的评论框,只对英文生效<br>
            点击评论翻译会调用百度翻译(由于需要跨域请求,弹出提示后选“总是允许”),在每个评论框下方输出目标语言翻译,点击↑可将下方内容添加至评论框`,
            'switch':1,
        },
        {
            'id':5,
            'name':'验证输出',
            'func':()=>{VERIFYEXPORT();},
            'unfunc':()=>{unVERIFYEXPORT();},
            'detail':
            `在问卷管理页面生效,表头上方添加按钮<br>
            点击按钮弹出确认提示,确认后会验证输出当前页面勾选的所有报告,成功后会在每份报告下方小窗口显示绿色保存成功提示<br>
            (电脑配置较低时一次输出太多份可能导致页面卡死,请根据浏览器最多同时能开几个报告页面量力而行)`,
            'switch':1,
        },
    ];


    /*在顶端菜单栏添加MOassist设置按钮*/
    const menu=$('div#menu');
    if(menu.length){
        menu.find('ul.tools').append(`
        <li class="MOassist">
            <a class="toolsLink">
                <div class="iconTools" style="background: url('/images/icons/menu/x16/tools-settings.png')"></div>
                <ul class="textArea" style="visibility:visible; display:none">
                    <li>MO助手设置</li>
                </ul>
                <ul id="MOoption" class="innerItemFirst" style="z-index: 11; display:none; top:25px; right:0px"></ul>
            </a>
        </li>
        `);
        menu.find('li.MOassist').on('click',function(){
            MOListSwitch(this);
        }).find('ul#MOoption').on('click',e=>{
            e.stopPropagation();//让之后添加的功能列表不继承click事件
        });
        //导入所有功能列表并显示开关状态
        for(let i in SET){
            menu.find('ul#MOoption').append(`
            <li id="MOoptions" class="MOassist" style="width:100%">
                <div class="menuItemText" style="color:#4C5057">${SET[i].name}</div>
                <input type=checkbox id=${SET[i].id} class=menuIconSmall></input>
                <ul class="textArea" style="visibility:visible; display: none; margin-top:0px; right:120px">
                    <li style="padding:0px 5px !important">${SET[i].detail}</li>
                </ul>
            </li>
            `);
            //运行开启状态的功能并打勾
            if(GM_getValue(SET[i].name,SET[i].switch)){
                SET[i].func();
                menu.find('input#'+SET[i].id).attr('checked',true);
            }
        }
        //根据是否选中即时启用或卸载功能并记录开关状态
        menu.find('li#MOoptions').on('click',function(){
            const checkbox=$(this).find('input');
            const id=$(checkbox).attr('id');
            if($(checkbox).attr('checked')){
                SET[id].unfunc();
                $(checkbox).attr('checked',false);
                GM_setValue(SET[id].name,0);
            }
            else{
                SET[id].func();
                $(checkbox).attr("checked",true);
                GM_setValue(SET[id].name,1);
            }
        }).children('ul.textArea').on('click',e=>{
            e.stopPropagation();
        });
        //鼠标聚焦时显示详情 【https://www.minerva-online.com/portal/menu/js/v2/menuRender.js?version=21-08 createToolOption : 】
        menu.find('li.MOassist').hover(function(){
            $(this).find('ul:first').stop().show(200);
        },function(){
            $(this).find('ul:first').stop().hide(200);
        });
        setMarkQuestionColor(menu);
    }
    else{
        for(let i in SET) if(GM_getValue(SET[i].name,SET[i].switch)) SET[i].func();//没有menu也执行开启的功能
    }

    //功能列表开关
    function MOListSwitch(self){
        const on=$(self).find('ul#MOoption').css('display');
        if(on==='none'){
            $(self).find('ul#MOoption').stop().slideDown(200);
        }
        else{
            $(self).find('ul#MOoption').stop().slideUp(200);
        }
    }

    //添加扣分标记颜色设置界面
    function setMarkQuestionColor(menu){
        $(menu).find('input#3.menuIconSmall').next('ul').prepend(`
        <div style="padding:0px 5px">
        <b id=de>扣分颜色:</b>
        <form id=de>
            <input type=radio name=de value=red>红</input>
            <input type=radio name=de value=orange>橙</input>
            <input type=radio name=de value=yellow>黄</input>
            <input type=radio name=de value=green>绿</input>
            <input type=radio name=de value=blue>蓝</input>
            <input type=radio name=de value=purple>紫</input>
            <input type=radio name=de value=custom>自定义</input>
            <input type=color class=selectedColor></input>
            <input type=button value=√ style="padding:1px 6px"></input>
        </form>
        <b id=na>N/A颜色:</b>
        <form id=na>
            <input type=radio name=na value=red>红</input>
            <input type=radio name=na value=orange>橙</input>
            <input type=radio name=na value=yellow>黄</input>
            <input type=radio name=na value=green>绿</input>
            <input type=radio name=na value=blue>蓝</input>
            <input type=radio name=na value=purple>紫</input>
            <input type=radio name=na value=custom>自定义</input>
            <input type=color class=selectedColor></input>
            <input type=button value=√ style="padding:1px 6px"></input>
        </form>
        </div>
        `);
        //颜色选项初始化
        $('form#de,form#na').each(function(){
            const curColor= $(this).attr('id')==='de'?
                  GM_getValue($(this).prev().text(),'red') : GM_getValue($(this).prev().text(),'green');
            $(this).prev().css('color',curColor);
            $(this).children('.selectedColor').attr('id',curColor);
            if(curColor.indexOf('#')<0){
                $(this).children('input[value='+curColor+']').attr('checked',true);
                $(this).children('.selectedColor').hide();
            }
            else{
                $(this).children('input[value=custom]').attr('checked',true);
                $(this).children('.selectedColor').val(curColor);
            }
        });
        //点击选项颜色改变
        $('form#de,form#na').children(':radio').on('click',function(){
            if($(this).val()==='custom'){
                $(this).next().show();
                $(this).next().attr('id',$(this).next().val());
            }
            else{
                $(this).nextAll('.selectedColor').hide();
                $(this).nextAll('.selectedColor').attr('id',$(this).val());
            }
            $(this).parent().prev().css('color',$(this).nextAll('.selectedColor').attr('id'));
        });
        //自定义颜色改变
        $('form#de,form#na').children('.selectedColor').on('input',function(){
            $(this).attr('id',$(this).val());
            $(this).parent().prev().css('color',$(this).val());
        });
        //确认更改
        $('form#de,form#na').children(':button').on('click',function(){
            GM_setValue($(this).parent().prev().text(),$(this).prev().attr('id'));
            $(this).after('<b>保存成功</b>');
            setTimeout(()=>{
                $(this).next().remove();
            },3000);
        });
    }
    /*在顶端菜单栏添加MOassist设置按钮*/


    /*置顶置底*/
    function GOTOPBOTTOM(){
        const scrollBar=$(document).height()>(window.innerHeight+1||document.documentElement.clientHeight);//如有滚动条
        if(scrollBar&&document.location.href.indexOf('alias=knowledgebase')===-1){//knowledgebase页面自带置顶按钮,不启用
            const goTopBottomButton=document.createElement('div');
            const toggleButton=document.createElement('img');
            $(toggleButton).appendTo(goTopBottomButton);
            $(goTopBottomButton).appendTo($('body')[0]);
            $(goTopBottomButton).css({'position':'fixed','zIndex':10000}).attr('id','goTopBottom');
            $(toggleButton).css({'display':'block','cursor':'pointer'}).attr('src','/knowledgebase/images/arrow_back_to_top.svg');//按钮显示图片(向下箭头)

            //以下按钮参数可自定义修改
            goTopBottomButton.style.bottom='50px';//按钮距离网页底部50px
            goTopBottomButton.style.right='30px';//按钮距离网页右边30px
            toggleButton.style.width='25px';//按钮图片宽25px
            toggleButton.style.height='25px';//按钮图片高25px
            toggleButton.style.opacity=0.5;//按钮不透明度,0.0(完全透明)到1.0(完全不透明)
            toggleButton.style.backgroundColor='grey';//按钮背景颜色,也可使用在excel等软件的自定义颜色界面的16进制代码
            const clickScrollTime=500;//点击按钮时,网页滚动到顶部或底部需要的时间,单位是毫秒

            //点击按钮时网页滚动到顶部或底部
            let scrollDirection='down';
            toggleButton.addEventListener('click',()=>{
                if(scrollDirection==='up'){
                    $('html,body').animate({scrollTop:'0px'},clickScrollTime);
                }
                else{
                    $('html,body').animate({scrollTop:$(document).height()},clickScrollTime);
                }
            });
            //页面滚动监听
            let scrollAction=window.pageYOffset;
            $(window).scroll(()=>{
                const diffY=scrollAction-window.pageYOffset;
                scrollAction=window.pageYOffset;
                scrollDirection= diffY<0? 'down' : 'up';
                toggleButton.style.transform= diffY<0? 'rotate(0deg)' : 'rotate(180deg)';
                if(getScrollTop()===0){
                    scrollDirection='down';
                    toggleButton.style.transform='rotate(0deg)';
                }
                if(getScrollTop()+window.innerHeight+20>=$(document).height()){
                    scrollDirection='up';
                    toggleButton.style.transform='rotate(180deg)';
                }
            });
        }
    }

    //获取垂直方向滑动距离
    function getScrollTop(){
        let scrollTop=0;
        if(document.documentElement&&document.documentElement.scrollTop){
            scrollTop=document.documentElement.scrollTop;
        }
        else if(document.body){
            scrollTop=document.body.scrollTop;
        }
        return scrollTop;
    }
    /*置顶置底*/

    /*卸载置顶置底*/
    function unGOTOPBOTTOM(){
        if($('div#goTopBottom').length) $('div#goTopBottom').remove();
    }
    /*卸载置顶置底*/


    /*菜单遮罩*/
    function COVERMENU(){
        const menu=$('div#menu');
        if(menu.length){
            //若存在menu则添加cover层
            const cover = document.createElement('div');
            cover.className = 'layout';
            cover.style = 'top:'+menu[0].style.top+';opacity:0.3;z-index:10000;right:10%';
            $(cover).appendTo($('body')[0]).attr('id','cover');
            //点击时将cover层下置
            cover.addEventListener('click',()=>{
                cover.style.zIndex = -1;
            });
            //离开menu时cover层还原
            menu[0].addEventListener('mouseleave',()=>{
                cover.style.zIndex = 10000;
            });
            //cover层位置跟随menu 【https://www.minerva-online.com/portal/menu/js/v2/menuRender.js?version=21-08 onScrollEventHandler : 】
            $(window).scroll(()=>{
                const SM=unsafeWindow.SM;
                const ind = SM.ui.headerHeight - SM.ui.getScrollTop();
                cover.style.top= ind>0? ind+'px' : '0px';
            });
        }
    }
    /*菜单遮罩*/

    /*卸载菜单遮罩*/
    function unCOVERMENU(){
        if($('div#cover').length) $('div#cover').remove();
    }
    /*卸载菜单遮罩*/


    /*附件下载*/
    function DOWNLOADFILE(){
        if (document.location.href.indexOf('alias=smngr.surveyexplorer')>=0&&$('tr.persist-header').length){
            $('tr.persist-header').each(function(){
                $(this).children().first().after($(this).children().first().clone(true));
            });
            $('div.sticky-wrap').find(':checkbox').each(function(){//checkbox后添加下载按钮
                const surveyid=$(this).val();
                $(this).parent().after('<td><button type=button id='+surveyid+' class=download><b>↓</td>');
                $('#'+surveyid+'.download').one('click',()=>{
                    DownloadButton(surveyid);
                });
            });
        }
    }

    //获取附件列表
    function DownloadButton(surveyid){
        $('button#'+surveyid+'.download').hide();
        $('button#'+surveyid+'.download').after('<p id='+surveyid+' class=loading><b>......');
        $.get('/open/data.asp?post={"action":"exec","dataset":{"datasetname":"/Apps/SM/Survey/SurveyInstanceGetData"},"parameters":[{"name":"SurveyInstanceID","value":"'+surveyid+'"}]}',(data,status)=>{//调用API获取当前survey数据[SurveyInstanceGetData]
            if (status==='success'){
                const filedata=data.dataset.data[3];
                const fileno=filedata.length;
                $('p#'+surveyid+'.loading').after('<ol id='+surveyid+' class=filelist>\t#='+fileno+'');
                if (fileno>0){
                    for(let i in filedata){
                        const filename=filedata[i].FileName+'.'+filedata[i].FileExtension;
                        const fileid=filedata[i].AttachmentID;
                        const fileurl='/mystservices/Attachments/getAttachment.asp?Attachment='+fileid+'&Password='+filedata[i].Password+'';
                        let filesize=Number(filedata[i].FileSizeInBytes)/1024;
                        filesize= (filesize>1024)? (filesize/1024).toFixed(2)+' MB' : filesize.toFixed(2)+' KB';
                        $('<tr id='+fileid+'>').appendTo('ol#'+surveyid+'.filelist');
                        $(`<td><li><a id=${surveyid} class='${filedata[i].AttachmentType} mailboxlink' href=${fileurl}>${filename}</a>`).appendTo('tr#'+fileid);
                        $('<td>'+filesize+'</td>').appendTo('tr#'+fileid);
                    }
                    $('a#'+surveyid+'.I,a#'+surveyid+'.V').mouseenter(function(){
                        FilePreview(1,$(this).attr('href'));
                    }).mouseleave(()=>{
                        FilePreview(0);
                    });
                    $('ol#'+surveyid+'.filelist').prepend('<button type=button id='+surveyid+' class=yes><b>√');
                    $('button#'+surveyid+'.yes').on('click',()=>{
                        DownloadAll(surveyid);
                    });
                    DownloadButton0(surveyid);
                }
                else {
                    DownloadButton0(surveyid);
                }
            }
            else {
                DownloadButton0(surveyid);
            }
        },"json");
    }

    //预览附件图片
    function FilePreview(show,src){
        if(show){
            const imgid=src.split('=')[2];
            if($('img#'+imgid+'.filepreview').length===0){
                $('<div><img id='+imgid+' class=filepreview>').appendTo('body');
                $('img#'+imgid+'.filepreview').attr('src',src+'&getThumbnail=1').css('height','200px')//视频附件预览图&getThumbnail=1
                    .parent().css({'position':'fixed','zIndex':10000,'height':'200px','background':'url(/images/icons/filtersv2/loading06.gif)'});
            }
            $('img#'+imgid+'.filepreview').parent().css({'top':event.clientY-200+'px','left':event.clientX+100+'px'});
            $('img#'+imgid+'.filepreview').show();
        }
        else{
            $('img.filepreview').hide();
        }
    }

    //按钮变为关闭
    function DownloadButton0(surveyid){
        $('p#'+surveyid+'.loading').remove();
        $('button#'+surveyid+'.download').one('click',()=>{
            DownloadButton1(surveyid);
        });
        $('button#'+surveyid+'.download').text('×');
        $('button#'+surveyid+'.download').show();
    }

    //按钮重置为初始
    function DownloadButton1(surveyid){
        $('ol').remove('#'+surveyid);
        $('button#'+surveyid+'.download').one('click',()=>{
            DownloadButton(surveyid);
        });
        $('button#'+surveyid+'.download').text('↓');
    }

    //下载全部
    function DownloadAll(surveyid){
        $('button#'+surveyid+'.yes').hide();
        const iframe=$('ol#'+surveyid+'.filelist').find('iframe');
        if(iframe.length)iframe.remove();
        setTimeout(()=>{
            $('button#'+surveyid+'.yes').show();
        },1000*$('ol#'+surveyid+'.filelist').find('a').length);//有几个附件就隐藏按钮几秒
        $('ol#'+surveyid+'.filelist').find('a').each(function(){
            $('<iframe src='+$(this).attr('href')+'>').appendTo(this).hide();
        });
        $('button#'+surveyid+'.yes').text('〇');
    }
    /*附件下载*/

    /*卸载附件下载*/
    function unDOWNLOADFILE(){
        if (document.location.href.indexOf('alias=smngr.surveyexplorer')>=0&&$('tr.persist-header').length){
            $('tr.persist-header').each(function(){
                $(this).children().first().remove();
            });
            $('button.download').each(function(){
                $(this).parent().remove();
            });
        }
    }
    /*卸载附件下载*/


    /*扣分标记*/
    function MARKQUESTION(){
        if(document.location.href.indexOf('alias=survey.view')>=0){
            $('span.surveyansweroption').each(function(){
                if($(this).prev('input').is(':checked')){
                    if($(this).prev('input').val()==='__na__'){
                        $(this).css('color',GM_getValue('N/A颜色:','green'));//默认标绿N/A项
                    }
                }
            });
            //获取所有扣分的题目
            const qidmark=[];
            $.get('/mystservices/v2new/getSurvey.asp?InstanceID='+$('input#instanceID').val(),(data,status)=>{
                if (status==='success'){
                    $(data).find('nobr').each(function(){
                        const score=$(this).text();
                        if(score!=''&&score.indexOf('%')===-1){//排除空值与section总分
                            const pts=score.split('/');
                            if(pts[0]<pts[1]){
                                const QidANS=$(this).parent().parent().parent().parent().parent('td.surveyquestioncell').prev().find('div').attr('id');
                                qidmark.push(QidANS);
                            }
                        }
                    });
                    for(let i in qidmark){
                        $('div#'+qidmark[i]).find('span.surveyansweroption').css('color',GM_getValue('扣分颜色:','red'));//默认标红扣分项
                    }
                }
            });
        }
    }
    /*扣分标记*/

    /*卸载扣分标记*/
    function unMARKQUESTION(){
        if(document.location.href.indexOf('alias=survey.view')>=0) $('span.surveyansweroption').removeAttr('style');
    }
    /*卸载扣分标记*/


    /*评论编辑*/
    function COMMENTEDIT(){
        if(document.location.href.indexOf('alias=survey.view')>=0){
            $('<div id=commentEdit>').appendTo($('body')[0])
                .css({'position':'fixed','zIndex':10000,
                      'right':'30px','bottom':'80px','height':'25px','width':'25px',
                      'background':'url("/images/icons/menu/x32/survet.png") 100%/100% #4C5157'})
                .on('click',()=>{
                commentEditSwitch();
            });
            $('<div id=commentFunc>').appendTo('div#commentEdit')
                .css({'position':'fixed','right':'60px','bottom':'50px'}).hide()
                .on('click',e=>{
                e.stopPropagation();//阻止子元素执行父元素click事件
            });
            //提示开关
            $('<b id=hint>【点击获取提示】</b>').appendTo('div#commentFunc');
            $('b#hint').on('click',function(){
                hintSwitch(this);
            });
            //评论匹配与替换
            $('<button type=button id=replaceAll class=surveyBottomButton>一键替换</button>').appendTo('div#commentFunc');
            $('button#replaceAll')
                .before('<textarea id=find placeholder=匹配内容></textarea><b id=commentMark>↓↓↓</b><textarea id=replace placeholder=替换内容></textarea>')
                .before('<b id=findNum>#</b>');
            $('textarea#find,textarea#replace').on('keydown',e=>{
                e.stopPropagation();//阻止页面自带keydown事件修改textarea的class值
            });
            $('b#commentMark').on('click',()=>{
                commentMark();
            });
            $('textarea#find').on('input',function(){
                commentMatch(this);
            });
            $('button#replaceAll').on('click',()=>{
                commentReplace();
            });
            //首字母大写
            $('<button type=button id=initialUpper class=surveyBottomButton>首字母大写</button>').appendTo('div#commentFunc');
            $('button#initialUpper').on('click',()=>{
                initialUpper();
            });
            //评论翻译
            $('<button type=button id=commentTrans class=surveyBottomButton>评论翻译</button>').appendTo('div#commentFunc');
            $('<select id=toLang><option value=en>→英文</option><option value=zh>→中文</option>').appendTo('div#commentFunc');
            $('button#commentTrans').on('click',()=>{
                commentTranslate($('select#toLang option:selected').val());
            });
            $('div#commentFunc').children().css({'display':'block','text-align':'center','margin':'5px auto'});
        }
    }

    //评论替换开关
    function commentEditSwitch(){
        const on=$('div#commentFunc').css('display');
        if(on==='none'){
            $('div#commentFunc').show();
            commentMatch($('textarea#find'));
        }
        else{
            $('div#commentFunc').hide();
            $('textarea.surveycomment,textarea.active').css('background','');
        }
    }

    //插入或移除提示
    function hintSwitch(self){
        if($(self).children().length){
            $(self).text('【点击获取提示】').children().remove();
        }
        else{
            $(self).text('【点击关闭提示】')
                .append('<a class=mailboxlink target=_blank href=https://tool.oschina.net/uploads/apidocs/jquery/regexp.html>匹配支持正则表达式</a>')
                .append('<a class=mailboxlink target=_blank href=https://c.runoob.com/front-end/854/>正则表达式测试</a>')
                .append(`
                <ol>
                    <li>正则实例:[。|.]$ 可匹配末尾处中英文句号;^[a-z] 可匹配开头处小写字母;甲|乙|丙 可匹配甲或乙或丙</li>
                    <li>可当作一般替换使用,如需替换一些特殊字符(\^$*+?.等,参照第一个链接中所列字符),请在前面使用\\标记转义,避免识别为正则表达</li>
                    <li>评论框激活后按Ctrl可切换评论框是否标红,标红的评论框将被排除在修改范围之外,点击两框间的↓↓↓可快速切换全部评论框标红与否</li>
                    <li>匹配内容为空时会匹配所有字符</li>
                </ol>
                `);
            $(self).children().css('display','block').on('click',e=>{
                e.stopPropagation();
            });
            $(self).find('li').css({'text-align':'left','width':'200px'});
        }
    }

    //切换所有评论框标红与否
    function commentMark(){
        $('textarea.surveycomment,textarea.active').each(function(){
            if($(this).attr('class')==='active'){
                $(this).attr('class','surveycomment');
            }
            else{
                $(this).attr('class','active');
            }
        });
    }

    //即时标灰匹配到的评论框并计数
    function commentMatch(self){
        let find;
        try{//若不是正则表达式,按普通字符处理
            find=new RegExp($(self).val(),'gm');
        }
        catch(e){
            find=$(self).val();
        }
        let findNum=0;
        $('textarea.active').css('background','');
        $('textarea.surveycomment').each(function(){
            try{//
                if($(this).val().search(find)>=0){//search只接受正则
                    findNum++;
                    $(this).css('background','lightgrey');
                }
                else{
                    $(this).css('background','');
                }
            }
            catch(e){
                if($(this).val().indexOf(find)>=0){//indexOf只接受字符
                    findNum++;
                    $(this).css('background','lightgrey');
                }
                else{
                    $(this).css('background','');
                }
            }
        });
        $('b#findNum').text('#='+findNum);
    }

    //判断是否为正则并进行评论替换
    function commentReplace(){
        $('textarea.surveycomment').each(function(){
            let find;
            try{
                find=new RegExp($('textarea#find').val(),'gm');
            }
            catch(e){
                find=$('textarea#find').val();
            }
            const replace=$('textarea#replace').val();
            const text=$(this).val().replace(find,replace);
            $(this).val(text);
        });
    }

    //首字母大写
    function initialUpper(){
        $('textarea.surveycomment').each(function(){
            const match=new Set($(this).val().match(/(^|\.|\?|!)("|'|) *[a-z]/gm));
            if(match.size){
                let text=$(this).val();
                for(let m of match){
                    const trans=m.search(/ {2,}/)? m.replace(/ {2,}/,' ') : m;
                    text=text.replace(trans,trans.toUpperCase());
                }
                $(this).val(text);
                $(this).css('background','lightgrey');
            }
            else{
                $(this).css('background','');
            }
        });
    }

    //调用百度翻译进行评论翻译
    async function commentTranslate(toLang){
        await translate_baidu_startup();
        $('textarea.surveycomment').each(async function(){
            if($(this).val()&&$(this).next().is('input:hidden')){
                $(this).after('<textarea id=trans style=overflow:hidden rows='+$(this).attr('rows')+' cols='+$(this).attr('cols')+'>')
                    .after('<button type=button class=attachmentBtn style="display:block;height:1.5em;width:1.5em;margin:5px 0">↑</button>');
            }
            if($(this).val()){
                const translated=await translate_baidu(toLang,$(this).val());
                $(this).next().next('textarea').val(translated);
                unsafeWindow.updrowH($(this).next().next('textarea')[0]);//调用页面自带函数来调整评论框高度
                $(this).next('button').on('click',function(){
                    const prev=$(this).prev().val();
                    const next=$(this).next().val();
                    $(this).prev().val(prev+'\n\n'+next);
                    unsafeWindow.updrowH($(this).prev()[0]);
                    $(this).next().remove();
                    $(this).remove();
                });
            }
        });
        $('textarea#trans').on('keydown',e=>{
            e.stopPropagation();//阻止页面自带keydown事件修改textarea的class值
        });
    }

    //百度翻译 参考https://gf.qytechs.cn/scripts/378277
    async function translate_baidu_startup(){
        if(window.sessionStorage.getItem('baidu_gtk')&&window.sessionStorage.getItem('baidu_token'))return;
        const options = {
            method:'GET',
            url:'https://fanyi.baidu.com',
        };
        const res = await Request(options);
        window.sessionStorage.setItem('baidu_gtk',/window\.gtk = '(.*?)'/.exec(res.responseText)[1]);
        window.sessionStorage.setItem('baidu_token',/token: '(.*?)'/.exec(res.responseText)[1]);
    }

    async function translate_baidu(toLang,raw,fromLang){
        if(!fromLang){
            fromLang = await check_lang(raw);
        }
        const proc_raw = raw.length>30? (raw.substr(0,10)+raw.substr(~~(raw.length/2)-5,10)+raw.substr(-10)) : raw;//process
        const tk_key = window.sessionStorage.getItem('baidu_gtk');
        const token = window.sessionStorage.getItem('baidu_token');//get token
        const options = {
            method:"POST",
            url:'https://fanyi.baidu.com/v2transapi',
            data:'from='+fromLang+'&to='+toLang+'&query='+encodeURIComponent(raw)+'&transtype=translang&simple_means_flag=3&sign='+tk(proc_raw,tk_key)+"&token="+token+"&domain=common",
            headers: {
                "referer": 'https://fanyi.baidu.com',
                "Content-Type": 'application/x-www-form-urlencoded; charset=UTF-8',
            },
        };
        return await BaseTranslate('百度翻译',raw,options,res=>JSON.parse(res).trans_result.data.map(item=>item.dst).join('\n'));
    }

    async function check_lang(raw){
        const options = {
            method:"POST",
            url:'https://fanyi.baidu.com/langdetect',
            data:'query='+encodeURIComponent(raw.replace(/[\uD800-\uDBFF]$/, "").slice(0,50)),
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
            }
        };
        const res = await Request(options);
        try{
            return JSON.parse(res.responseText).lan;
        }catch(err){
            console.log(err);
            return;
        }
    }

    //根据翻译字符获取sign值
    function tk(a,b){
        var d = b.split(".");
        b = Number(d[0]) || 0;
        for (var e = [], f = 0, g = 0; g < a.length; g++) {
            var k = a.charCodeAt(g);
            128 > k ?
                e[f++] = k : (
                2048 > k ?
                e[f++] = k >> 6 | 192 : (
                    55296 == (k & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (
                        k = 65536 + ((k & 1023) << 10) + (a.charCodeAt(++g) & 1023),
                        e[f++] = k >> 18 | 240,
                        e[f++] = k >> 12 & 63 | 128
                    ) :
                    e[f++] = k >> 12 | 224,
                    e[f++] = k >> 6 & 63 | 128
                ),
                e[f++] = k & 63 | 128
            );
        }
        a = b;
        for (f = 0; f < e.length; f++)a = Fo(a+e[f], "+-a^+6");
        a = Fo(a, "+-3^+b+-f");
        a ^= Number(d[1]) || 0;
        0 > a && (a = (a & 2147483647) + 2147483648);
        a %= 1E6;
        return a.toString() + "." + (a ^ b);
    }

    function Fo(a,b) {
        for (var c = 0; c < b.length - 2; c += 3) {
            var d = b.charAt(c + 2);
            d = "a" <= d ? d.charCodeAt(0) - 87 : Number(d);
            d = "+" == b.charAt(c + 1) ? a >>> d : a << d;
            a = "+" == b.charAt(c) ? a + d & 4294967295 : a ^ d;
        }
        return a;
    }

    //异步请求包装工具
    async function PromiseRetryWrap(task,options,...values){
        const {RetryTimes,ErrProcesser} = options||{};
        let retryTimes = RetryTimes||5;
        const usedErrProcesser = ErrProcesser || (err =>{throw err;});
        if(!task)return;
        while(true){
            try{
                return await task(...values);
            }catch(err){
                if(!--retryTimes){
                    console.log(err);
                    return usedErrProcesser(err);
                }
            }
        }
    }

    async function BaseTranslate(name,raw,options,processer){
        const toDo = async ()=>{
            let tmp;
            try{
                const data = await Request(options);
                tmp = data.responseText;
                const result = await processer(tmp);
                window.sessionStorage.setItem(name+'-'+raw,result);
                return result;
            }catch(err){
                throw {
                    responseText: tmp,
                    err: err
                };
            }
        };
        return await PromiseRetryWrap(toDo,{RetryTimes:3,ErrProcesser:()=>"翻译出错"});
    }

    function Request(options){
        return new Promise((reslove,reject)=>GM_xmlhttpRequest({...options,onload:reslove,onerror:reject}));
    }
    /*评论编辑*/


    /*卸载评论编辑*/
    function unCOMMENTEDIT(){
        if($('div#commentEdit').length) $('div#commentEdit').remove();
    }
    /*卸载评论编辑*/


    /*验证输出*/
    function VERIFYEXPORT(){
        if (document.location.href.indexOf('alias=smngr.surveyexplorer')>=0&&$('div#filterdiv').length){
            $('div#filterdiv').before('<button type=button id=verifyExport class="rm-btn rm-btn-default">验证输出勾选的报告</button>');
            $('button#verifyExport').css({'margin':'10px 0px','display':'block'}).on('click',()=>{
                verifyExportAll();
            });
        }
    }

    //验证输出全部报告
    function verifyExportAll(){
        const apply=confirm('请确认是否要验证输出当前页面勾选的所有报告(电脑配置低请勿一次性输出过多报告)');
        if(apply){
            $('table#reporttable tbody').find('tr').each(function(){
                if($(this).find('input:checkbox').eq(0).is(':checked')){
                    const a=$(this).find('a.mailboxlink')[0];
                    const src=$(a).attr('href');
                    const iframe=document.createElement('iframe');
                    iframe.src=src;
                    iframe.style='height:80px; width:250px';
                    $(a).after(iframe);
                    iframe.onload=function(){
                        const doc=$(this).contents();
                        $(doc).find('div#addInfo,div#menu,div#pathContainer').remove();
                        if($(doc).find('input#scrverN').is(':checked')&&$(doc).find('input#questVerN').is(':checked')){//前2点均为否时才进行操作
                            $(doc).find('input#scrverY').click();
                            $(doc).find('input#questVerY').click();
                            $(doc).find('button#save').click();
                        }
                    };
                }
            });
            alert('请耐心等待所有小窗口加载完成,显示绿色保存成功提示后,再刷新页面检查是否全部验证输出成功');
        }
    }
    /*验证输出*/

    /*卸载验证输出*/
    function unVERIFYEXPORT(){
        if($('button#verifyExport').length) $('button#verifyExport').remove();
    }
    /*卸载验证输出*/


})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址