minerva-online assistant

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

当前为 2021-12-23 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name minerva-online assistant
  3. // @namespace https://space.bilibili.com/17846288
  4. // @version 2.6.5
  5. // @license MIT
  6. // @description 此脚本能更方便使用minerva-online平台,可在顶端菜单栏右下角的按钮处设置功能开关,并查看功能详情
  7. // @author inoki
  8. // @include https://www.minerva-online.com/*
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // @grant GM_xmlhttpRequest
  12. // @connect fanyi.baidu.com
  13. // @noframes
  14. // ==/UserScript==
  15.  
  16. /*jshint esversion: 9*/
  17.  
  18. (()=>{
  19. 'use strict';
  20.  
  21. const SET=[
  22. {
  23. 'id':0,
  24. 'name':'置顶置底',
  25. 'func':()=>{GOTOPBOTTOM();},
  26. 'unfunc':()=>{unGOTOPBOTTOM();},
  27. 'detail':
  28. `在平台域名所有可滚动页面生效,页面右下方添加【方向图标】按钮<br>
  29. 【方向图标】点击会根据页面滚动方向自动置顶或置底,按钮样式可在代码中自定义中修改`,
  30. 'switch':1
  31. },
  32. {
  33. 'id':1,
  34. 'name':'菜单遮罩',
  35. 'func':()=>{COVERMENU();},
  36. 'unfunc':()=>{unCOVERMENU();},
  37. 'detail':
  38. `在有顶端菜单栏的页面生效<br>
  39. 让菜单栏需要点击一次后才可展开,防止鼠标经过时误触
  40. (默认关闭)`,
  41. 'switch':0
  42. },
  43. {
  44. 'id':2,
  45. 'name':'附件下载',
  46. 'func':()=>{DOWNLOADFILE();},
  47. 'unfunc':()=>{unDOWNLOADFILE();},
  48. 'detail':
  49. `在问卷管理页面生效,每份报告前添加【↓】按钮<br>
  50. 【↓】点击可加载附件列表<br>
  51. 【√】点击可下载全部附件,之后会变为【〇】<br>
  52. 【×】点击关闭附件列表<br>
  53. 附件名点击可下载单个附件,鼠标悬停可预览图片`,
  54. 'switch':1
  55. },
  56. {
  57. 'id':3,
  58. 'name':'扣分标记',
  59. 'func':()=>{MARKQUESTION();},
  60. 'unfunc':()=>{unMARKQUESTION();},
  61. 'detail':
  62. `在单店报告页面生效,可醒目标记扣分或N/A的题目,方便快速检查相关题评论<br>
  63. 将题目中勾选扣分和N/A项标色,选项更改后需保存报告才会刷新标记<br>
  64. 可在上方设置扣分(默认为红)和N/A(默认为绿)的标记颜色,点击【√】保存更改<br>
  65. 颜色更改后关开此功能可在报告页面即时刷新颜色`,
  66. 'switch':1
  67. },
  68. {
  69. 'id':4,
  70. 'name':'评论编辑',
  71. 'func':()=>{COMMENTEDIT();},
  72. 'unfunc':()=>{unCOMMENTEDIT();},
  73. 'detail':
  74. `在单店报告页面生效,右下方【问卷图标】按钮展开操作界面<br>
  75. 使用前请注意阅读操作界面最上方的【点击获取提示】<br>
  76. 【一键替换】点击可批量修改所有评论框内容,输入匹配内容(支持正则)会即时显示匹配的评论框数量并标灰<br>
  77. 【首字母大写】点击可智能将所有句首字母变为大写,并标灰发生过修改的评论框,只对英文生效<br>
  78. 【评论翻译】点击会调用百度翻译,在每个评论框下方输出目标语言翻译,点击↑可将下方内容添加至评论框`,
  79. 'switch':1
  80. },
  81. {
  82. 'id':5,
  83. 'name':'验证输出',
  84. 'func':()=>{VERIFYEXPORT();},
  85. 'unfunc':()=>{unVERIFYEXPORT();},
  86. 'detail':
  87. `在问卷管理页面生效,表头上方添加【验证输出勾选的报告】按钮<br>
  88. 【验证输出勾选的报告】点击并确认后会验证输出当前页面勾选的所有报告,成功输出的报告下方小窗口会显示绿色提示<br>
  89. (电脑配置较低时一次输出太多份可能导致页面卡死,请根据浏览器最多同时能开几个报告页面量力而行,默认关闭)`,
  90. 'switch':0
  91. },
  92. {
  93. 'id':6,
  94. 'name':'定制汇总',
  95. 'func':()=>{CUSTOMROLLUP();},
  96. 'unfunc':()=>{unCUSTOMROLLUP();},
  97. 'detail':
  98. `在定制汇总页面生效,在汇总表格上方添加【复制表格】按钮<br>
  99. 【复制表格】点击可一键复制表格全部内容,方便复制到excel等软件中编辑`,
  100. 'switch':1
  101. },
  102. {
  103. 'id':7,
  104. 'name':'报告存档',
  105. 'func':()=>{SURVEYAUTOSAVE();},
  106. 'unfunc':()=>{unSURVEYAUTOSAVE();},
  107. 'detail':
  108. `在单店报告页面生效,右下方【书本图标】按钮展开操作界面,可查看自动/手动存档列表<br>
  109. 【存档】点击可进行手动存档,每次对报告内容进行修改时,将在本地进行自动存档<br>
  110. 【预览】点击可查看存档内容,并对需要读档写入的题目进行勾选<br>
  111. 【读档】点击可将选中的存档全部内容写入到当前报告,或只写入预览界面勾选的题目<br>
  112. 【删除】点击可删除选中的存档,自动/手动存档上限各为10个,超出时自动删除此类最早存档<br>
  113. (“评论编辑”功能造成的修改不会触发自动存档,可在修改后点击任意评论框触发自动存档)`,
  114. 'switch':1
  115. },
  116. ];
  117.  
  118. //如网页无jQuery则引入3.6.0
  119. var $=unsafeWindow.$;
  120. if(!$){
  121. const jq=document.createElement('script');
  122. jq.src='https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js';
  123. document.head.appendChild(jq);
  124. jq.onload=()=>{
  125. $=unsafeWindow.jQuery;
  126. init();
  127. };
  128. }else{
  129. init();
  130. }
  131.  
  132. /*在顶端菜单栏添加MOassist设置按钮*/
  133. function init(){
  134. console.log('jQuery',$.fn.jquery);
  135. const menu=$('div#menu');
  136. if(menu.length){
  137. menu.find('ul.tools').append(`
  138. <li class="MOassist">
  139. <a class="toolsLink">
  140. <div class="iconTools" style="background: url('/images/icons/menu/x16/tools-settings.png')"></div>
  141. <ul class="textArea" style="visibility:visible; display:none">
  142. <li>MO助手设置</li>
  143. </ul>
  144. <ul id="MOoption" class="innerItemFirst" style="z-index: 11; display:none; top:25px; right:0px"></ul>
  145. </a>
  146. </li>
  147. `);
  148. menu.find('li.MOassist').on('click',function(){
  149. MOListSwitch(this);
  150. }).find('ul#MOoption').on('click',e=>{
  151. e.stopPropagation();//让之后添加的功能列表不继承click事件
  152. });
  153. //导入所有功能列表并显示开关状态
  154. for(let i in SET){
  155. menu.find('ul#MOoption').append(`
  156. <li id="MOoptions" class="MOassist" style="width:100%">
  157. <div class="menuItemText" style="color:#4C5057">${SET[i].name}</div>
  158. <input type=checkbox id=${SET[i].id} class=menuIconSmall>
  159. <ul class="textArea" style="visibility:visible; display: none; margin-top:0px; right:120px">
  160. <li style="padding:0px 5px !important">${SET[i].detail}</li>
  161. </ul>
  162. </li>
  163. `);
  164. //运行开启状态的功能并打勾
  165. if(GM_getValue(SET[i].name,SET[i].switch)){
  166. SET[i].func();
  167. menu.find('input#'+SET[i].id).prop('checked',true);
  168. }
  169. }
  170. //根据是否选中即时启用或卸载功能并记录开关状态
  171. menu.find('li#MOoptions').on('click',function(e){
  172. const checkbox=$(this).children('input:checkbox');
  173. const id=$(checkbox).attr('id');
  174. if(GM_getValue(SET[id].name,SET[id].switch)){
  175. SET[id].unfunc();
  176. $(checkbox).prop('checked',false);
  177. GM_setValue(SET[id].name,0);
  178. }else{
  179. SET[id].func();
  180. $(checkbox).prop('checked',true);
  181. GM_setValue(SET[id].name,1);
  182. }
  183. }).children('ul.textArea').on('click',e=>{
  184. e.stopPropagation();
  185. });
  186. //鼠标聚焦时显示详情 【https://www.minerva-online.com/portal/menu/js/v2/menuRender.js?version=21-08 createToolOption : 】
  187. menu.find('li.MOassist').hover(function(){
  188. $(this).find('ul:first').stop().show(200);
  189. },function(){
  190. $(this).find('ul:first').stop().hide(200);
  191. });
  192. setMarkQuestionColor(menu);
  193. }else{
  194. for(let i in SET) if(GM_getValue(SET[i].name,SET[i].switch)) SET[i].func();//没有menu也执行开启的功能
  195. }
  196. }
  197.  
  198. //功能列表开关
  199. function MOListSwitch(el){
  200. if($(el).find('ul#MOoption').css('display')==='none'){
  201. $(el).find('ul#MOoption').stop().slideDown(200);
  202. }else{
  203. $(el).find('ul#MOoption').stop().slideUp(200);
  204. }
  205. }
  206.  
  207. //添加扣分标记颜色设置界面
  208. function setMarkQuestionColor(menu){
  209. $(menu).find('input#3.menuIconSmall').next('ul').prepend(`
  210. <div style="padding:0px 5px">
  211. <b id=de>扣分颜色:</b>
  212. <form id=de>
  213. <input type=radio name=de value=red>红
  214. <input type=radio name=de value=orange>橙
  215. <input type=radio name=de value=yellow>黄
  216. <input type=radio name=de value=green>绿
  217. <input type=radio name=de value=blue>蓝
  218. <input type=radio name=de value=purple>紫
  219. <input type=radio name=de value=custom>自定义
  220. <input type=color class=selectedColor>
  221. <input type=button class=rm-btn value=√ style="padding:1px 6px">
  222. </form>
  223. <b id=na>N/A颜色:</b>
  224. <form id=na>
  225. <input type=radio name=na value=red>红
  226. <input type=radio name=na value=orange>橙
  227. <input type=radio name=na value=yellow>黄
  228. <input type=radio name=na value=green>绿
  229. <input type=radio name=na value=blue>蓝
  230. <input type=radio name=na value=purple>紫
  231. <input type=radio name=na value=custom>自定义
  232. <input type=color class=selectedColor>
  233. <input type=button class=rm-btn value=√ style="padding:1px 6px">
  234. </form>
  235. </div>
  236. `);
  237. //颜色选项初始化
  238. $(menu).find('form#de,form#na').each(function(){
  239. const curColor= $(this).attr('id')==='de'?
  240. GM_getValue($(this).prev().text(),'red') : GM_getValue($(this).prev().text(),'green');
  241. $(this).prev().css('color',curColor);
  242. $(this).children('.selectedColor').attr('id',curColor);
  243. if(curColor.indexOf('#')<0){
  244. $(this).children('input[value='+curColor+']').attr('checked',true);
  245. $(this).children('.selectedColor').hide();
  246. }else{
  247. $(this).children('input[value=custom]').attr('checked',true);
  248. $(this).children('.selectedColor').val(curColor);
  249. }
  250. });
  251. //点击选项颜色改变
  252. $('form#de,form#na').children(':radio').on('click',function(){
  253. if($(this).val()==='custom'){
  254. $(this).next().show();
  255. $(this).next().attr('id',$(this).next().val());
  256. }else{
  257. $(this).nextAll('.selectedColor').hide();
  258. $(this).nextAll('.selectedColor').attr('id',$(this).val());
  259. }
  260. $(this).parent().prev().css('color',$(this).nextAll('.selectedColor').attr('id'));
  261. });
  262. //自定义颜色改变
  263. $('form#de,form#na').children('.selectedColor').on('input',function(){
  264. $(this).attr('id',$(this).val());
  265. $(this).parent().prev().css('color',$(this).val());
  266. });
  267. //确认更改
  268. $('form#de,form#na').children(':button').on('click',function(){
  269. GM_setValue($(this).parent().prev().text(),$(this).prev().attr('id'));
  270. if(!$(this).next().is('b')){
  271. $(this).after('<b>保存成功</b>');
  272. setTimeout(()=>{
  273. $(this).next().remove();
  274. },3000);
  275. }
  276. });
  277. }
  278. /*在顶端菜单栏添加MOassist设置按钮*/
  279.  
  280.  
  281. /*置顶置底*/
  282. function GOTOPBOTTOM(){
  283. const scrollBar=$(document).height()>(window.innerHeight+1||document.documentElement.clientHeight);//如有滚动条
  284. if(scrollBar&&document.location.href.indexOf('alias=knowledgebase')===-1){//knowledgebase页面自带置顶按钮,不启用
  285. const goTopBottomButton=document.createElement('div');
  286. const toggleButton=document.createElement('img');
  287. $(toggleButton).appendTo(goTopBottomButton);
  288. $(goTopBottomButton).appendTo($('body')[0]);
  289. $(goTopBottomButton).css({'position':'fixed','zIndex':10000}).attr('id','goTopBottom');
  290. $(toggleButton).css({'display':'block','cursor':'pointer'}).attr('src','/knowledgebase/images/arrow_back_to_top.svg');//按钮显示图片(向下箭头)
  291.  
  292. //以下按钮参数可自定义修改
  293. goTopBottomButton.style.bottom='50px';//按钮距离网页底部50px
  294. goTopBottomButton.style.right='30px';//按钮距离网页右边30px
  295. toggleButton.style.width='25px';//按钮图片宽25px
  296. toggleButton.style.height='25px';//按钮图片高25px
  297. toggleButton.style.opacity=0.5;//按钮不透明度,0.0(完全透明)到1.0(完全不透明)
  298. toggleButton.style.backgroundColor='grey';//按钮背景颜色,也可使用在excel等软件的自定义颜色界面的16进制代码
  299. const clickScrollTime=500;//点击按钮时,网页滚动到顶部或底部需要的时间,500毫秒
  300.  
  301. //点击按钮时网页滚动到顶部或底部
  302. let scrollDirection='down';
  303. toggleButton.addEventListener('click',()=>{
  304. if(scrollDirection==='up'){
  305. $('html,body').animate({scrollTop:'0px'},clickScrollTime);
  306. }else{
  307. $('html,body').animate({scrollTop:$(document).height()},clickScrollTime);
  308. }
  309. });
  310. //页面滚动监听
  311. let scrollAction=window.pageYOffset;
  312. $(window).scroll(()=>{
  313. const diffY=scrollAction-window.pageYOffset;
  314. scrollAction=window.pageYOffset;
  315. scrollDirection= diffY<0? 'down' : 'up';
  316. toggleButton.style.transform= diffY<0? 'rotate(0deg)' : 'rotate(180deg)';
  317. if(getScrollTop()===0){
  318. scrollDirection='down';
  319. toggleButton.style.transform='rotate(0deg)';
  320. }
  321. if(getScrollTop()+window.innerHeight+20>=$(document).height()){
  322. scrollDirection='up';
  323. toggleButton.style.transform='rotate(180deg)';
  324. }
  325. });
  326. }
  327. }
  328.  
  329. //获取垂直方向滑动距离
  330. function getScrollTop(){
  331. let scrollTop=0;
  332. if(document.documentElement&&document.documentElement.scrollTop){
  333. scrollTop=document.documentElement.scrollTop;
  334. }else if(document.body){
  335. scrollTop=document.body.scrollTop;
  336. }
  337. return scrollTop;
  338. }
  339. /*置顶置底*/
  340.  
  341. /*卸载置顶置底*/
  342. function unGOTOPBOTTOM(){
  343. if($('div#goTopBottom').length) $('div#goTopBottom').remove();
  344. }
  345. /*卸载置顶置底*/
  346.  
  347.  
  348. /*菜单遮罩*/
  349. function COVERMENU(){
  350. if($('div#menu').length){
  351. //若存在menu则添加cover层
  352. const menu=$('div#menu')[0];
  353. const zidx=parseInt(getComputedStyle(menu).zIndex)+1;
  354. const cover = document.createElement('div');
  355. cover.className = 'layout';
  356. cover.style = 'top:'+menu.style.top+';opacity:0.3;z-index:'+zidx+';right:10%';
  357. $(cover).appendTo($('body')[0]).attr('id','cover');
  358. //点击时将cover层下置
  359. cover.addEventListener('click',()=>{
  360. cover.style.zIndex = -1;
  361. });
  362. //离开menu时cover层还原
  363. menu.addEventListener('mouseleave',()=>{
  364. cover.style.zIndex = zidx;
  365. });
  366. //cover层位置跟随menu 【https://www.minerva-online.com/portal/menu/js/v2/menuRender.js?version=21-08 onScrollEventHandler : 】
  367. $(window).scroll(()=>{
  368. const SM=unsafeWindow.SM;
  369. const ind = SM.ui.headerHeight - SM.ui.getScrollTop();
  370. cover.style.top= ind>0? ind+'px' : '0px';
  371. });
  372. }
  373. }
  374. /*菜单遮罩*/
  375.  
  376. /*卸载菜单遮罩*/
  377. function unCOVERMENU(){
  378. if($('div#cover').length) $('div#cover').remove();
  379. }
  380. /*卸载菜单遮罩*/
  381.  
  382.  
  383. /*附件下载*/
  384. function DOWNLOADFILE(){
  385. if (document.location.href.indexOf('alias=smngr.surveyexplorer')>=0&&$('tr.persist-header').length){
  386. $('tr.persist-header').each(function(){
  387. $(this).children().first().after($(this).children().first().clone(true));
  388. });
  389. $('div.sticky-wrap').find(':checkbox').each(function(){//checkbox后添加下载按钮
  390. const surveyid=$(this).val();
  391. $(this).parent().after('<td><button type=button id='+surveyid+' class="download rm-btn"><b>↓</td>');
  392. $('#'+surveyid+'.download').one('click',()=>{
  393. DownloadButton(surveyid);
  394. });
  395. });
  396. }
  397. }
  398.  
  399. //获取附件列表
  400. function DownloadButton(surveyid){
  401. $('button#'+surveyid+'.download').hide();
  402. $('button#'+surveyid+'.download').after('<p id='+surveyid+' class=loading><b>......');
  403. $.get(`
  404. /open/data.asp?post={
  405. "action":"exec",
  406. "dataset":{"datasetname":"/Apps/SM/Survey/SurveyInstanceGetData"},
  407. "parameters":[{"name":"SurveyInstanceID","value":"${surveyid}"}]
  408. }`,(data,status)=>{//调用API获取当前survey数据[SurveyInstanceGetData]
  409. if (status==='success'){
  410. try{
  411. const fd=data.dataset.data[3];
  412. }catch(e){
  413. $('p#'+surveyid+'.loading').after('<b id='+surveyid+'>登录失效!</b>');
  414. DownloadButton0(surveyid);
  415. }
  416. const filedata=data.dataset.data[3];
  417. const fileno=filedata.length;
  418. $('p#'+surveyid+'.loading').after('<ol id='+surveyid+' class=filelist>\t#='+fileno+'');
  419. if (fileno>0){
  420. for(let i in filedata){
  421. const filename=filedata[i].FileName+'.'+filedata[i].FileExtension;
  422. const fileid=filedata[i].AttachmentID;
  423. const fileurl='/mystservices/Attachments/getAttachment.asp?Attachment='+fileid+'&Password='+filedata[i].Password+'';
  424. let filesize=Number(filedata[i].FileSizeInBytes)/1024;
  425. filesize= (filesize>1024)? (filesize/1024).toFixed(2)+' MB' : filesize.toFixed(2)+' KB';
  426. $('<tr id='+fileid+'>').appendTo('ol#'+surveyid+'.filelist');
  427. $(`<td><li><a id=${surveyid} class='${filedata[i].AttachmentType} mailboxlink' href=${fileurl}>${filename}</a>`)
  428. .appendTo('tr#'+fileid);
  429. $('<td>'+filesize+'</td>').appendTo('tr#'+fileid);
  430. }
  431. $('a#'+surveyid+'.I,a#'+surveyid+'.V').mouseenter(function(){
  432. FilePreview(1,$(this).attr('href'));
  433. }).mouseleave(()=>{
  434. FilePreview(0);
  435. });
  436. $('ol#'+surveyid+'.filelist').prepend('<button type=button id='+surveyid+' class="yes rm-btn rm-btn-default">√</button>');
  437. $('button#'+surveyid+'.yes').on('click',()=>{
  438. DownloadAll(surveyid);
  439. });
  440. }
  441. }else{
  442. $('p#'+surveyid+'.loading').after('<b id='+surveyid+'>网络错误!</b>');
  443. }
  444. DownloadButton0(surveyid);
  445. },"json");
  446. }
  447.  
  448. //预览附件图片
  449. function FilePreview(show,src){
  450. if(show){
  451. const imgid=src.split('=')[2];
  452. if($('img#'+imgid+'.filepreview').length===0){
  453. $('<div><img id='+imgid+' class=filepreview>').appendTo('body');
  454. $('img#'+imgid+'.filepreview').attr('src',src+'&getThumbnail=1').css('height','200px')//视频附件预览图&getThumbnail=1
  455. .parent().css({'position':'fixed','zIndex':10000,'height':'200px','background':'url(/images/icons/filtersv2/loading06.gif)'});
  456. }
  457. $('img#'+imgid+'.filepreview').parent().css({'top':event.clientY-200+'px','left':event.clientX+100+'px'});
  458. $('img#'+imgid+'.filepreview').show();
  459. }else{
  460. $('img.filepreview').hide();
  461. }
  462. }
  463.  
  464. //按钮变为关闭
  465. function DownloadButton0(surveyid){
  466. $('p#'+surveyid+'.loading').remove();
  467. $('button#'+surveyid+'.download').one('click',()=>{
  468. DownloadButton1(surveyid);
  469. });
  470. $('button#'+surveyid+'.download').text('×');
  471. $('button#'+surveyid+'.download').show();
  472. }
  473.  
  474. //按钮重置为初始
  475. function DownloadButton1(surveyid){
  476. $('ol,b').remove('#'+surveyid);
  477. $('button#'+surveyid+'.download').one('click',()=>{
  478. DownloadButton(surveyid);
  479. });
  480. $('button#'+surveyid+'.download').text('↓');
  481. }
  482.  
  483. //下载全部
  484. function DownloadAll(surveyid){
  485. $('button#'+surveyid+'.yes').hide();
  486. const iframe=$('ol#'+surveyid+'.filelist').find('iframe');
  487. if(iframe.length)iframe.remove();
  488. setTimeout(()=>{
  489. $('button#'+surveyid+'.yes').show();
  490. },1000*$('ol#'+surveyid+'.filelist').find('a').length);//有几个附件就隐藏按钮几秒
  491. $('ol#'+surveyid+'.filelist').find('a').each(function(){
  492. $('<iframe src='+$(this).attr('href')+'>').appendTo(this).hide();
  493. });
  494. $('button#'+surveyid+'.yes').text('〇');
  495. }
  496. /*附件下载*/
  497.  
  498. /*卸载附件下载*/
  499. function unDOWNLOADFILE(){
  500. if (document.location.href.indexOf('alias=smngr.surveyexplorer')>=0&&$('tr.persist-header').length){
  501. $('tr.persist-header').each(function(){
  502. $(this).children().first().remove();
  503. });
  504. $('button.download').each(function(){
  505. $(this).parent().remove();
  506. });
  507. }
  508. }
  509. /*卸载附件下载*/
  510.  
  511.  
  512. /*扣分标记*/
  513. function MARKQUESTION(){
  514. if(document.location.href.indexOf('alias=survey.view')>=0){
  515. $('span.surveyansweroption').each(function(){
  516. if($(this).prev('input').is(':checked')){
  517. if($(this).prev('input').val()==='__na__'){
  518. $(this).css('color',GM_getValue('N/A颜色:','green'));//默认标绿N/A项
  519. }
  520. }
  521. });
  522. //获取所有扣分的题目
  523. const qidmark=[];
  524. $.get('/mystservices/v2new/getSurvey.asp?InstanceID='+$('input#instanceID').val(),(data,status)=>{
  525. if (status==='success'){
  526. $(data).find('nobr').each(function(){
  527. const score=$(this).text();
  528. if(score!=''&&score.indexOf('%')===-1){//排除空值与section总分
  529. const pts=score.split('/');
  530. if(pts[0]<pts[1]){
  531. const QidANS=$(this).parents('td.surveyquestioncell').prev().find('div').attr('id');
  532. qidmark.push(QidANS);
  533. }
  534. }
  535. });
  536. for(let i in qidmark){
  537. $('div#'+qidmark[i]).find('span.surveyansweroption').css('color',GM_getValue('扣分颜色:','red'));//默认标红扣分项
  538. }
  539. }
  540. });
  541. }
  542. }
  543. /*扣分标记*/
  544.  
  545. /*卸载扣分标记*/
  546. function unMARKQUESTION(){
  547. if(document.location.href.indexOf('alias=survey.view')>=0) $('span.surveyansweroption').removeAttr('style');
  548. }
  549. /*卸载扣分标记*/
  550.  
  551.  
  552. /*评论编辑*/
  553. function COMMENTEDIT(){
  554. if(document.location.href.indexOf('alias=survey.view')>=0){
  555. $('<div id=commentEdit>').appendTo($('body')[0])
  556. .css({'position':'fixed','zIndex':10000,
  557. 'right':'30px','bottom':'80px','height':'25px','width':'25px',
  558. 'background':'url("/images/icons/menu/x32/survet.png") 50%/80% no-repeat #4C5157'})
  559. .on('click',function(){
  560. commentEditSwitch(this);
  561. });
  562. $('<div id=commentFunc>').appendTo('div#commentEdit')
  563. .css({'position':'fixed','right':'60px','bottom':'50px'}).hide()
  564. .on('click',e=>{
  565. e.stopPropagation();//阻止子元素执行父元素click事件
  566. });
  567. //提示开关
  568. $('<b id=hint>【点击获取提示】</b>').appendTo('div#commentFunc');
  569. $('b#hint').on('click',function(){
  570. hintSwitch(this);
  571. });
  572. //评论匹配与替换
  573. $('<button type=button id=replaceAll class=surveyBottomButton>一键替换</button>').appendTo('div#commentFunc');
  574. $('button#replaceAll')
  575. .before('<textarea id=find placeholder=匹配内容></textarea><b id=commentMark>↓↓↓</b><textarea id=replace placeholder=替换内容></textarea>')
  576. .before('<b id=findNum>#</b>');
  577. $('textarea#find,textarea#replace').on('keydown',e=>{
  578. e.stopPropagation();//阻止页面自带keydown事件修改textarea的class值
  579. });
  580. $('b#commentMark').on('click',()=>{
  581. commentMark();
  582. });
  583. $('textarea#find').on('input',function(){
  584. commentMatch(this);
  585. });
  586. $('button#replaceAll').on('click',()=>{
  587. commentReplace();
  588. });
  589. //首字母大写
  590. $('<button type=button id=initialUpper class=surveyBottomButton>首字母大写</button>').appendTo('div#commentFunc');
  591. $('button#initialUpper').on('click',()=>{
  592. initialUpper();
  593. });
  594. //评论翻译
  595. $('<button type=button id=commentTrans class=surveyBottomButton>评论翻译</button>').appendTo('div#commentFunc');
  596. $(`<select id=toLang>
  597. <option value=en>→英文</option>
  598. <option value=jp>→日文</option>
  599. <option value=zh>→中文(简体)</option>
  600. <option value=cht>→中文(繁体)</option>
  601. <option value=yue>→中文(粤语)</option>
  602. <option value=fj>繁体→简体</option>`).appendTo('div#commentFunc');
  603. $('button#commentTrans').on('click',()=>{
  604. commentTranslate($('select#toLang option:selected').val());
  605. });
  606. $('div#commentFunc').children().css({'display':'block','text-align':'center','margin':'5px auto'});
  607. }
  608. }
  609.  
  610. //评论替换开关
  611. function commentEditSwitch(el){
  612. if($(el).children(':last').css('display')==='none'){
  613. $(el).children(':last').show();
  614. commentMatch($('textarea#find'));
  615. }else{
  616. $(el).children(':last').hide();
  617. $('textarea.surveycomment,textarea.active').css('background','');
  618. }
  619. }
  620.  
  621. //插入或移除提示
  622. function hintSwitch(el){
  623. if($(el).children().length){
  624. $(el).text('【点击获取提示】').children().remove();
  625. }else{
  626. $(el).text('【点击关闭提示】')
  627. .append('<a class=mailboxlink target=_blank href=https://tool.oschina.net/uploads/apidocs/jquery/regexp.html>匹配支持正则表达式</a>')
  628. .append('<a class=mailboxlink target=_blank href=https://c.runoob.com/front-end/854/>正则表达式测试</a>')
  629. .append(`
  630. <ol>
  631. <li>正则实例:[。|.]$ 可匹配末尾处中英文句号;^[a-z] 可匹配开头处小写字母;甲|乙|丙 可匹配甲或乙或丙</li>
  632. <li>可当作一般替换使用,如需替换一些特殊字符(\^$*+?.等,参照第一个链接中所列字符),请在前面使用\\标记转义,避免识别为正则表达</li>
  633. <li>评论框激活后按Ctrl可切换评论框是否标红,标红的评论框将被排除在修改范围之外,点击两框间的↓↓↓可快速切换全部评论框标红与否</li>
  634. <li>匹配内容为空时会匹配所有字符</li>
  635. </ol>
  636. `);
  637. $(el).children().css('display','block').on('click',e=>{
  638. e.stopPropagation();
  639. });
  640. $(el).find('li').css({'text-align':'left','width':'200px'});
  641. }
  642. }
  643.  
  644. //切换所有评论框标红与否
  645. function commentMark(){
  646. $('textarea.surveycomment,textarea.active').each(function(){
  647. if($(this).attr('class')==='active'){
  648. $(this).attr('class','surveycomment');
  649. }else{
  650. $(this).attr('class','active');
  651. }
  652. });
  653. }
  654.  
  655. //即时标灰匹配到的评论框并计数
  656. function commentMatch(self){
  657. let find;
  658. try{//若不是正则表达式,按普通字符处理
  659. find=new RegExp($(self).val(),'gm');
  660. }catch(e){
  661. find=$(self).val();
  662. }
  663. let findNum=0;
  664. $('textarea.active').css('background','');
  665. $('textarea.surveycomment').each(function(){
  666. try{//
  667. if($(this).val().search(find)>=0){//search只接受正则
  668. findNum++;
  669. $(this).css('background','lightgrey');
  670. }else{
  671. $(this).css('background','');
  672. }
  673. }catch(e){
  674. if($(this).val().indexOf(find)>=0){//indexOf只接受字符
  675. findNum++;
  676. $(this).css('background','lightgrey');
  677. }else{
  678. $(this).css('background','');
  679. }
  680. }
  681. });
  682. $('b#findNum').text('#='+findNum);
  683. }
  684.  
  685. //判断是否为正则并进行评论替换
  686. function commentReplace(){
  687. $('textarea.surveycomment').each(function(){
  688. let find;
  689. try{
  690. find=new RegExp($('textarea#find').val(),'gm');
  691. }catch(e){
  692. find=$('textarea#find').val();
  693. }
  694. const replace=$('textarea#replace').val();
  695. const text=$(this).val().replaceAll(find,replace);
  696. $(this).val(text);
  697. });
  698. }
  699.  
  700. //首字母大写
  701. function initialUpper(){
  702. $('textarea.surveycomment').each(function(){
  703. const match=new Set($(this).val().match(/(^|\.|\?|!)("|'|) *[a-z]/gm));
  704. if(match.size){
  705. let text=$(this).val();
  706. for(let m of match){
  707. const r=new RegExp(`(^|\\.|\\?|!)("|'|) *`+m,'gm');
  708. text=text.replaceAll(r,m.toUpperCase());
  709. }
  710. $(this).val(text);
  711. $(this).css('background','lightgrey');
  712. }else{
  713. $(this).css('background','');
  714. }
  715. });
  716. }
  717.  
  718. //调用百度翻译进行评论翻译
  719. async function commentTranslate(toLang){
  720. await translate_baidu_startup();
  721. $('textarea.surveycomment').each(async function(){
  722. if($(this).val()&&$(this).next().is('input:hidden')){
  723. $(this).after('<textarea id=trans style=overflow:hidden rows='+$(this).attr('rows')+' cols='+$(this).attr('cols')+'>')
  724. .after('<button type=button class=attachmentBtn style="display:block;height:1.5em;width:1.5em;margin:5px 0">↑</button>');
  725. }
  726. if($(this).val()){
  727. const fromLang= toLang==='f→j'? 'cht' : null;
  728. toLang= toLang==='f→j'? 'zh' : toLang;
  729. const translated=await translate_baidu(toLang,$(this).val(),fromLang);
  730. $(this).next().next('textarea').val(translated);
  731. unsafeWindow.updrowH($(this).next().next('textarea')[0]);//调用页面自带函数来调整评论框高度
  732. $(this).next('button').on('click',function(){
  733. const prev=$(this).prev().val();
  734. const next=$(this).next().val();
  735. $(this).prev().val(prev+'\n\n'+next);
  736. unsafeWindow.updrowH($(this).prev()[0]);
  737. $(this).next().remove();
  738. $(this).remove();
  739. });
  740. }
  741. });
  742. $('textarea#trans').on('keydown',e=>{
  743. e.stopPropagation();//阻止页面自带keydown事件修改textarea的class值
  744. });
  745. }
  746.  
  747. //百度翻译 参考https://greasyfork.org/scripts/378277
  748. async function translate_baidu_startup(){
  749. if(window.sessionStorage.getItem('baidu_gtk')&&window.sessionStorage.getItem('baidu_token'))return;
  750. const options={
  751. method:'GET',
  752. url:'https://fanyi.baidu.com',
  753. };
  754. const res=await Request(options);
  755. window.sessionStorage.setItem('baidu_gtk',/window\.gtk = '(.*?)'/.exec(res.responseText)[1]);
  756. window.sessionStorage.setItem('baidu_token',/token: '(.*?)'/.exec(res.responseText)[1]);
  757. }
  758.  
  759. async function translate_baidu(toLang,raw,fromLang){
  760. if(!fromLang){
  761. fromLang=await check_lang(raw);
  762. }
  763. const proc_raw= raw.length>30? (raw.substr(0,10)+raw.substr(~~(raw.length/2)-5,10)+raw.substr(-10)) : raw;//process
  764. const tk_key=window.sessionStorage.getItem('baidu_gtk');
  765. const token=window.sessionStorage.getItem('baidu_token');//get token
  766. const options={
  767. method:"POST",
  768. url:'https://fanyi.baidu.com/v2transapi',
  769. data:`from=${fromLang}&to=${toLang}&query=${encodeURIComponent(raw)}&transtype=translang&simple_means_flag=3&sign=${tk(proc_raw,tk_key)}&token=${token}&domain=common`,
  770. headers:{
  771. "referer":'https://fanyi.baidu.com',
  772. 'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
  773. },
  774. };
  775. return await BaseTranslate('百度翻译',raw,options,res=>JSON.parse(res).trans_result.data.map(item=>item.dst).join('\n'));
  776. }
  777.  
  778. async function check_lang(raw){
  779. const options={
  780. method:"POST",
  781. url:'https://fanyi.baidu.com/langdetect',
  782. data:'query='+encodeURIComponent(raw.replace(/[\uD800-\uDBFF]$/,'').slice(0,50)),
  783. headers:{
  784. 'Content-Type':'application/x-www-form-urlencoded',
  785. }
  786. };
  787. const res=await Request(options);
  788. try{
  789. return JSON.parse(res.responseText).lan;
  790. }catch(e){
  791. console.log(e);
  792. return;
  793. }
  794. }
  795.  
  796. //根据翻译字符获取sign值
  797. function tk(a,b){
  798. var d=b.split('.');
  799. b=Number(d[0]) || 0;
  800. for(var e=[],f=0,g=0;g<a.length;g++){
  801. var k=a.charCodeAt(g);
  802. 128>k?
  803. e[f++]=k : (
  804. 2048>k?
  805. e[f++]=k>>6|192 : (
  806. 55296==(k&64512)&&g+1<a.length&&56320==(a.charCodeAt(g+1)&64512)? (
  807. k=65536+((k&1023)<<10)+(a.charCodeAt(++g)&1023),
  808. e[f++]=k>>18|240,
  809. e[f++]=k>>12&63|128
  810. ) :
  811. e[f++]=k>>12|224,
  812. e[f++]=k>>6&63|128
  813. ),
  814. e[f++]=k&63|128
  815. );
  816. }
  817. a=b;
  818. for(f=0;f<e.length;f++) a=Fo(a+e[f],'+-a^+6');
  819. a=Fo(a,'+-3^+b+-f');
  820. a^=Number(d[1])||0;
  821. 0>a&&(a=(a&2147483647)+2147483648);
  822. a%=1E6;
  823. return a.toString()+'.'+(a^b);
  824. }
  825.  
  826. function Fo(a,b){
  827. for(var c=0;c<b.length-2;c+=3){
  828. var d=b.charAt(c+2);
  829. d= "a"<=d? d.charCodeAt(0)-87 : Number(d);
  830. d= "+"==b.charAt(c + 1)? a>>>d : a<<d;
  831. a= "+"==b.charAt(c)? a+d&4294967295 : a^d;
  832. }
  833. return a;
  834. }
  835.  
  836. //异步请求包装工具
  837. async function PromiseRetryWrap(task,options,...values){
  838. const {RetryTimes,ErrProcesser}=options||{};
  839. let retryTimes=RetryTimes||5;
  840. const usedErrProcesser=ErrProcesser||(err=>{throw err;});
  841. if(!task)return;
  842. while(true){
  843. try{
  844. return await task(...values);
  845. }catch(e){
  846. if(!--retryTimes){
  847. console.log(e);
  848. return usedErrProcesser(e);
  849. }
  850. }
  851. }
  852. }
  853.  
  854. async function BaseTranslate(name,raw,options,processer){
  855. const toDo=async ()=>{
  856. let tmp;
  857. try{
  858. const data=await Request(options);
  859. tmp=data.responseText;
  860. const result=await processer(tmp);
  861. window.sessionStorage.setItem(name+'-'+raw,result);
  862. return result;
  863. }catch(e){
  864. throw {
  865. responseText: tmp,
  866. err: e
  867. };
  868. }
  869. };
  870. return await PromiseRetryWrap(toDo,{RetryTimes:3,ErrProcesser:()=>"翻译出错"});
  871. }
  872.  
  873. function Request(options){
  874. return new Promise((reslove,reject)=>GM_xmlhttpRequest({...options,onload:reslove,onerror:reject}));
  875. }
  876. /*评论编辑*/
  877.  
  878.  
  879. /*卸载评论编辑*/
  880. function unCOMMENTEDIT(){
  881. if($('div#commentEdit').length) $('div#commentEdit').remove();
  882. }
  883. /*卸载评论编辑*/
  884.  
  885.  
  886. /*验证输出*/
  887. function VERIFYEXPORT(){
  888. if (document.location.href.indexOf('alias=smngr.surveyexplorer')>=0&&$('div#filterdiv').length){
  889. $('div#filterdiv').before('<button type=button id=verifyExport class="rm-btn rm-btn-default">验证输出勾选的报告</button>');
  890. $('button#verifyExport').css({'margin':'10px 0px','display':'block'}).on('click',()=>{
  891. verifyExportAll();
  892. });
  893. }
  894. }
  895.  
  896. //验证输出全部报告
  897. function verifyExportAll(){
  898. const apply=confirm('请确认是否要验证输出当前页面勾选的所有报告(电脑配置低请勿一次性输出过多报告)');
  899. if(apply){
  900. $('table#reporttable tbody').find('tr').each(function(){
  901. if($(this).find('input:checkbox').eq(0).is(':checked')){
  902. const a=$(this).find('a.mailboxlink')[0];
  903. const src=$(a).attr('href');
  904. const iframe=document.createElement('iframe');
  905. iframe.src=src;
  906. iframe.style='height:80px; width:250px';
  907. $(a).after(iframe);
  908. iframe.onload=function(){
  909. const doc=$(this).contents();
  910. $(doc).find('div#addInfo,div#menu,div#pathContainer').remove();
  911. if($(doc).find('input#scrverN').is(':checked')&&$(doc).find('input#questVerN').is(':checked')){//前2点均为否时才进行操作
  912. $(doc).find('input#scrverY').click();
  913. $(doc).find('input#questVerY').click();
  914. $(doc).find('button#save').click();
  915. }
  916. };
  917. }
  918. });
  919. alert('请耐心等待所有小窗口加载完成,显示绿色保存成功提示后,再刷新页面检查是否全部验证输出成功');
  920. }
  921. }
  922. /*验证输出*/
  923.  
  924. /*卸载验证输出*/
  925. function unVERIFYEXPORT(){
  926. if($('button#verifyExport').length) $('button#verifyExport').remove();
  927. }
  928. /*卸载验证输出*/
  929.  
  930.  
  931. /*定制汇总*/
  932. function CUSTOMROLLUP(){
  933. if(document.location.href.indexOf('alias=clientaccess.customrollups')>=0){
  934. if($('table.reporttable,table.incCrossTabTableClass').length){
  935. $('table.reporttable,table.incCrossTabTableClass')
  936. .before('<button type=button id=copyBtnCR>复制表格</button>');
  937. $(window).scroll(()=>{//必要时隐藏按钮避免影响冻结首行效果
  938. if($('table.sticky-thead'.length)){
  939. $('table.sticky-thead').css('z-index')>0?
  940. $('button#copyBtnCR').hide() : $('button#copyBtnCR').show();
  941. }
  942. });
  943. $('button#copyBtnCR').on('click',function(){
  944. window.getSelection().removeAllRanges();
  945. const content=$(this).next('table').children('tbody')[0].innerText;
  946. if($(this).prevAll('textarea').length===0){
  947. $(this).before('<textarea>');
  948. }
  949. $(this).prev('textarea').show();
  950. $(this).prev('textarea').val(content).select();
  951. document.execCommand('copy');
  952. $(this).prev('textarea').hide();
  953. window.getSelection().removeAllRanges();
  954. document.execCommand('copy')?
  955. $(this).text('复制成功!') : $(this).text('复制失败...');
  956. setTimeout(()=>{
  957. $(this).text('复制表格');
  958. },3000);
  959. });
  960. }
  961. }
  962. }
  963. /*定制汇总*/
  964.  
  965. /*卸载定制汇总*/
  966. function unCUSTOMROLLUP(){
  967. if($('button#copyBtnCR').length) $('button#copyBtnCR').remove();
  968. }
  969. /*卸载定制汇总*/
  970.  
  971.  
  972. /*报告存档*/
  973. function SURVEYAUTOSAVE(){
  974. if(document.location.href.indexOf('alias=survey.view')>=0){
  975. //监听表单内点击和评论失焦触发存档事件
  976. let Form=$('form#frmSurvey').serialize();
  977. $('form#frmSurvey').on('click.autosave',()=>{
  978. Form=autoSave(Form);
  979. });
  980. $('textarea.surveycomment,textarea.active').on('blur.autosave',()=>{
  981. Form=autoSave(Form);
  982. });
  983. //插入操作界面
  984. $('<div id=surveySaves>').appendTo($('body')[0])
  985. .css({'position':'fixed','zIndex':10000,
  986. 'right':'30px','bottom':'110px','height':'25px','width':'25px',
  987. 'background':'url("/images/icons/menu/x16/KB-icon.png") 50%/80% no-repeat #4C5157'});
  988. //存档列表开关
  989. $('div#surveySaves').on('click',function(){
  990. if($(this).children(':last').css('display')==='none'){
  991. $(this).children(':last').show();
  992. refreshList();
  993. }else{
  994. $(this).children(':last').hide();
  995. }
  996. });
  997. $('<div id=surveySavesList>').appendTo('div#surveySaves')
  998. .css({'position':'fixed','right':'60px','bottom':'50px','background':'lightgrey'}).hide()
  999. .on('click',e=>{
  1000. e.stopPropagation();//阻止子元素执行父元素click事件
  1001. });
  1002. $('div#surveySavesList').append(`
  1003. <div style=margin:5px>
  1004. <button type=button id=Show class=rm-btn>预览</button>
  1005. <button type=button id=Load class=rm-btn>读档</button>
  1006. <button type=button id=Save class=rm-btn>存档</button>
  1007. <button type=button id=Dele class=rm-btn>删除</button>
  1008. </div>
  1009. <div id=tab style=margin:5px>
  1010. <label><input type=radio name=tab value=autosaves checked>自动存档</label>
  1011. <label><input type=radio name=tab value=selfsaves>手动存档</label>
  1012. </div>
  1013. <table cellpadding=5 style=margin:5px>
  1014. <thead id=saves>
  1015. <tr>
  1016. <td></td>
  1017. <td>保存时间</td>
  1018. <td>问卷标题</td>
  1019. <td>店铺ID</td>
  1020. <td>报告ID</td>
  1021. </tr>
  1022. </thead>
  1023. <thead id=questions>
  1024. <tr>
  1025. <td><input type=checkbox name=questions checked></td>
  1026. <td>QID</td>
  1027. <td>题目</td>
  1028. <td>选项</td>
  1029. <td>评论</td>
  1030. </tr>
  1031. </thead>
  1032. <tbody id=autosaves></tbody>
  1033. <tbody id=selfsaves></tbody>
  1034. <tbody id=questions style=height:300px;overflow:scroll></tbody>
  1035. </table>
  1036. `);
  1037. $('div#surveySaves').find('thead,tbody').css('display','block');
  1038. $('div#surveySaves').find('#selfsaves,#questions').hide();
  1039. $('button#Show').on('click',()=>{
  1040. showData();
  1041. });
  1042. $('button#Load').on('click',()=>{
  1043. loadData();
  1044. });
  1045. $('button#Save').on('click',()=>{
  1046. saveData('selfsaves');
  1047. });
  1048. $('button#Dele').on('click',()=>{
  1049. deleteData();
  1050. });
  1051. //切换存档列表页
  1052. $('div#tab').on('click',function(){
  1053. $('div#surveySaves').find('input[name=saves]:checked').prop('checked',false);//将存档的选中状态重置
  1054. const checked=$(this).find('input:checked').val();
  1055. const unchecked= checked==='autosaves'? 'selfsaves' : 'autosaves';
  1056. $(this).parent().find('tbody#'+unchecked).hide();
  1057. $(this).parent().find('tbody#'+checked).show();
  1058. refreshList(checked);
  1059. theadWidth($('thead#saves'),$('tbody#'+checked));
  1060. });
  1061. //预览界面一键勾选与取消
  1062. $('thead#questions tr td input').on('click',function(){
  1063. if($(this).is(':checked')){
  1064. $(this).parents('table').find('input[name=questions]').prop('checked',true);
  1065. }else{
  1066. $(this).parents('table').find('input[name=questions]').prop('checked',false);
  1067. }
  1068. });
  1069. }
  1070. }
  1071.  
  1072. //表单变化时自动存档
  1073. function autoSave(prvForm){
  1074. const curForm=$('form#frmSurvey').serialize();
  1075. if(prvForm!=curForm){//如表单数据改变
  1076. saveData('autosaves');
  1077. }
  1078. return curForm;
  1079. }
  1080.  
  1081. //刷新存档列表
  1082. function refreshList(fromSave){
  1083. if($('div#surveySavesList').css('display')==='none') return;//界面隐藏时不刷新
  1084. if(!fromSave) fromSave=$('div#surveySaves').find('input[name=tab]:checked').val();//无参数自动判断当前页
  1085. const curChecked=$('tbody#'+fromSave).find('input[name=saves]:checked').parent('td').next().text();//记录当前选中存档
  1086. $('div#surveySaves').find('tbody#'+fromSave).empty();
  1087. const saves=GM_getValue(fromSave,{});
  1088. const k=Object.keys(saves);
  1089. if(k.length){
  1090. for(let i in k){
  1091. const line= i%2===1? 'reporttable_odd' : 'reporttable_even';
  1092. $('div#surveySaves').find('tbody#'+fromSave).prepend(`
  1093. <tr class=${line}>
  1094. <td><input type=radio name=saves></td>
  1095. <td>${k[i]}</td>
  1096. <td>${saves[k[i]].surveytitle}</td>
  1097. <td>${saves[k[i]].formhead.LOCATION}</td>
  1098. <td>${saves[k[i]].surveyid}</td>
  1099. </tr>
  1100. `);
  1101. if(curChecked===k[i]) $('tbody#'+fromSave).children('tr:first').find('input').prop('checked',true);//还原存档选中状态
  1102. }
  1103. //如为当前存档页则同步表头宽度
  1104. if($('div#surveySaves').find('input[name=tab]:checked').val()===fromSave){
  1105. theadWidth($('thead#saves'),$('tbody#'+fromSave));
  1106. }
  1107. }else{
  1108. const w=getComputedStyle($('tbody#'+fromSave)[0]).width;
  1109. $('div#surveySaves').find('tbody#'+fromSave).append('<td colspan=5 style=width:'+w+';text-align:center>无数据!</td>');
  1110. }
  1111. }
  1112.  
  1113. //预览
  1114. function showData(){
  1115. if($('div#surveySaves').find('thead#questions').css('display')==='none'){
  1116. const [save]=checkSave();
  1117. if(!save) return;
  1118. const head=save.formhead;
  1119. for(let h in head){
  1120. const line='reporttable_odd';
  1121. $('div#surveySaves').find('tbody#questions').append(`
  1122. <tr class=${line}>
  1123. <td><input type=checkbox name=questions></td>
  1124. <td colspan=2>${h}</td>
  1125. <td colspan=2>${head[h]}</td>
  1126. </tr>
  1127. `);
  1128. }
  1129. const body=save.formbody;
  1130. for(let b of body){
  1131. if(Object.keys(b).indexOf('ans')===-1) b.ans='×';
  1132. if(Object.keys(b).indexOf('cmt')===-1) b.cmt='×';
  1133. const line='reporttable_even';
  1134. $('div#surveySaves').find('tbody#questions').append(`
  1135. <tr class=${line}>
  1136. <td><input type=checkbox name=questions></td>
  1137. <td>${b.qid}</td>
  1138. <td>${b.qtx}</td>
  1139. <td>${b.ans}</td>
  1140. <td>${b.cmt}</td>
  1141. </tr>
  1142. `);
  1143. }
  1144. if($('thead#questions').find('input').is(':checked')){
  1145. $('tbody#questions').find('input').prop('checked',true);
  1146. }else{
  1147. $('tbody#questions').find('input').prop('checked',false);
  1148. }
  1149. $('div#surveySaves').find('button#Show').text('←');
  1150. $('div#surveySaves').find('button#Save,button#Dele,div#tab,[id$=saves]').hide();
  1151. $('div#surveySaves').find('table #questions').show();
  1152. theadWidth($('thead#questions'),$('tbody#questions'));//在显示后同步宽度,隐藏时会默认为auto
  1153.  
  1154. }else{
  1155. $('div#surveySaves').find('tbody#questions').empty();
  1156. $('div#surveySaves').find('button#Show').text('预览');
  1157. $('div#surveySaves').find('table #questions').hide();
  1158. $('div#surveySaves').find('button#Save,button#Dele,div#tab,#saves,tbody#'+$('input[name=tab]:checked').val()).show();
  1159. }
  1160. }
  1161.  
  1162. //读档
  1163. function loadData(){
  1164. const [save]=checkSave();
  1165. if(!save) return;
  1166. //如当前报告id与存档报告id不相等,询问是否执行
  1167. if(save.surveyid!=unsafeWindow.SurveyInstanceID){
  1168. //将文本,是否确认,确认后执行的方法传给feedback(text,ifConfirm,yesFunc)生成确认提示
  1169. feedback(
  1170. '报告ID不同,仅会修改当前报告中和存档中相匹配的题目,是否继续?',
  1171. 1,
  1172. ()=>{execLoadData(save);}
  1173. );
  1174. }else{
  1175. execLoadData(save);
  1176. }
  1177. }
  1178.  
  1179. //执行读档
  1180. function execLoadData(save){
  1181. const qidArr=[];
  1182. if($('div#surveySaves').find('thead#questions').css('display')!='none'){
  1183. if($('div#surveySaves').find('input[name=questions]:checked').length===0){
  1184. feedback('请勾选题目!');
  1185. return;
  1186. }
  1187. $('div#surveySaves').find('input[name=questions]:checked').each(function(){
  1188. qidArr.push($(this).parent().next().text());
  1189. });
  1190. }
  1191. const setAnswer=unsafeWindow.sm_setmultipleanswer;
  1192. const setComment=unsafeWindow.sm_setcomment;
  1193. const head=save.formhead;
  1194. let count=0;
  1195. for(let h in head){
  1196. if(qidArr.length&&qidArr.indexOf(h)<0) continue;
  1197. if(h==='DATE'){
  1198. const date=head[h].split('-');
  1199. $('form#frmSurvey').find('select#dsYear').children('[value='+date[0]+']').prop('selected',true);
  1200. $('form#frmSurvey').find('select#dsMonth').children('[value='+date[1]+']').prev().prop('selected',true);
  1201. $('form#frmSurvey').find('select#dsDay').children('[value='+date[2]+']').prev().prop('selected',true);
  1202. }
  1203. if(h==='TIME'){
  1204. const time=head[h].split(':');
  1205. $('form#frmSurvey').find('select#tsHoursHEAD_TIME').children('[value='+time[0]+']').prop('selected',true);
  1206. $('form#frmSurvey').find('select#tsMinutesHEAD_TIME').children('[value='+time[1]+']').prop('selected',true);
  1207. }
  1208. $('form#frmSurvey').find('input[name=HEAD_'+h+']').val(head[h]);
  1209. count++;
  1210. }
  1211. const body=save.formbody;
  1212. for(let b of body){
  1213. if(qidArr.length&&qidArr.indexOf(b.qid)<0) continue;
  1214. const key=Object.keys(b);
  1215. if(key.indexOf('ans')>=0) setAnswer(b.qid,b.ans);
  1216. if(key.indexOf('cmt')>=0){
  1217. setComment(b.qid,b.cmt);
  1218. unsafeWindow.updrowH(document.querySelector('textarea#C'+b.qid+'C'));//调整评论框高度
  1219. }
  1220. count++;
  1221. }
  1222. feedback('读档成功。(共修改'+count+'题)');
  1223. }
  1224.  
  1225.  
  1226. //存档
  1227. function saveData(toSave){
  1228. const save={
  1229. 'surveytitle':$('h1.surveytitle').text(),
  1230. 'surveyid':unsafeWindow.SurveyInstanceID,
  1231. 'formhead':{
  1232. 'LOCATION':$('input[name=HEAD_LOCATION]').val(),
  1233. 'SHOPPER':$('input[name=HEAD_SHOPPER]').val(),
  1234. 'DATE':$('input[name=HEAD_DATE]').val(),
  1235. 'TIME':$('input[name=HEAD_TIME]').val()
  1236. },
  1237. 'formbody':[]
  1238. };
  1239. const hasAnswer=unsafeWindow.sm_getanswer;
  1240. const getAnswer=unsafeWindow.sm_getmultipleanswer;
  1241. const getComment=unsafeWindow.sm_getcomment;
  1242. $('a.surveyquestionnobreak').each(function(){
  1243. const qtx=$(this).find('span.surveyquestion').text();
  1244. const qid=$(this).attr('name').replace('qstn','');
  1245. const ans= hasAnswer(qid)===undefined? hasAnswer(qid) : getAnswer(qid);
  1246. //ans 已填写:'1,2'||'__na__';未填写:'';无选项列:undefined
  1247. const cmt= getComment(qid);
  1248. //cmt 已填写:'xxx';未填写:'';无评论框:undefined
  1249. save.formbody.push({
  1250. 'qtx':qtx,
  1251. 'qid':qid,
  1252. 'ans':ans,
  1253. 'cmt':cmt
  1254. });
  1255. });
  1256. const saves=GM_getValue(toSave,{});
  1257. saves[new Date().toLocaleString()]=save;
  1258. //存档超过10个覆盖最早存档
  1259. if(Object.keys(saves).length>10) delete saves[Object.keys(saves)[0]];
  1260. GM_setValue(toSave,saves);
  1261. refreshList(toSave);
  1262. if(toSave==='autosaves') feedback('自动存档成功。');
  1263. if(toSave==='selfsaves') feedback('手动存档成功。');
  1264. }
  1265.  
  1266. //删除
  1267. function deleteData(){
  1268. const [save,time,saves,fromSave]=checkSave();
  1269. if(!save) return;
  1270. delete saves[time];
  1271. GM_setValue(fromSave,saves);
  1272. refreshList();
  1273. feedback('删除成功。');
  1274.  
  1275. }
  1276.  
  1277. //检查存档有效性
  1278. function checkSave(){
  1279. if($('div#surveySaves').find('input[name=saves]:checked').length===0){
  1280. feedback('请选择存档!');
  1281. return [];
  1282. }
  1283. const fromSave=$('div#surveySaves').find('input[name=saves]:checked').parents('tbody').attr('id');
  1284. const saves=GM_getValue(fromSave,{});
  1285. const time=$('div#surveySaves').find('input[name=saves]:checked').parent().next().text();
  1286. if(Object.keys(saves).indexOf(time)===-1){
  1287. feedback('无此存档!(可能已被覆盖)');
  1288. return [];
  1289. }
  1290. return [saves[time],time,saves,fromSave];
  1291. }
  1292.  
  1293. //操作反馈提示
  1294. function feedback(text,ifConfirm,yesFunc){
  1295. if($('div#surveySaves').find('b#feedback').length===0){
  1296. $('div#surveySaves').find('div#tab').before('<b id=feedback style=margin:5px></b>');
  1297. }
  1298. $('div#surveySaves').find('b#feedback').text(text).append('<br>');
  1299. if(ifConfirm){
  1300. $('<input type=button value=√ class="rm-btn rm-btn-default">').appendTo('b#feedback')
  1301. .on('click',function(){
  1302. $(this).parents('b#feedback').remove();
  1303. yesFunc();
  1304. });
  1305. $('<input type=button value=× class="rm-btn rm-btn-default">').appendTo('b#feedback')
  1306. .on('click',function(){
  1307. $(this).parents('b#feedback').remove();
  1308. });
  1309. $('div#surveySaves').find('input:button').css('margin','5px');
  1310. }else{
  1311. setTimeout(()=>{
  1312. $('div#surveySaves').find('b#feedback').remove();
  1313. },3000);
  1314. }
  1315. }
  1316.  
  1317. //将表头宽度同步为表身
  1318. function theadWidth(thead,tbody){
  1319. if($(tbody).find('td').text()==='无数据!') return;
  1320. $(thead).find('tr td').each(function(){
  1321. const i=$(this).index();
  1322. const w=getComputedStyle($(tbody).children('tr:last').children()[i]).width;
  1323. $(this).css('width',w);
  1324. });
  1325. }
  1326. /*报告存档*/
  1327.  
  1328. /*卸载报告存档*/
  1329. function unSURVEYAUTOSAVE(){
  1330. if($('div#surveySaves').length) $('div#surveySaves').remove();
  1331. if(document.location.href.indexOf('alias=survey.view')>=0){
  1332. $('form#frmSurvey').off('click.autosave');
  1333. $('textarea.surveycomment,textarea.active').off('blur.autosave');
  1334. }
  1335. }
  1336. /*卸载报告存档*/
  1337.  
  1338.  
  1339. })();