这是我面临的一个复杂而奇怪的问题,我希望任何人都可以带给我,即使不是解决问题的方法,也可以避开它。从一开始,我是一所学校的管理员,该学校使用Google Suite for Education和Classroom管理与学生的课程作业,特别是现在我们被迫在家工作。
[我们认为使用Classroom API来更好地了解学生的工作及其整体评分是一个好主意。因此,我们制作了一个电子表格和一个脚本以获取报告,该报告显示了学生所参加的所有科目(“课堂”中的课程)及其所有课程的成绩。到目前为止,在解决了对API的一些误解之后,我们设法编写了脚本。
[此后,我们尝试放大脚本,以便一次可以为一组学生报告,这是一大进步,因为单独编写30份报告非常耗时。并不是很困难,因为我们在工作表中列出了所有学生和小组的列表,并且或多或少是通过循环完成的。它奏效了,我们可以获得小组中所有学生的完整报告,包括他们在所有学科中的所有课程工作。
但是问题出在我们开始运行此脚本时,我们在某些小组,某些学生中遇到错误,我们不知道为什么。经过一些调查,我们发现对Classroom.Courses.list(optionalArgs)
的调用提供了430门课程,尽管我们在报告中为学生使用了一个过滤器。 430门课程的数量不是很高,但是所有课程的循环,即使考虑到该学生尚未入学,也要花费1800 s以上的时间,并且脚本会出现“超时错误”。令人惊讶的是,如果我在该组的循环内运行相同的函数,但直接调用,则该函数可以正常工作,并且没有错误。在这种情况下,给出上一个错误的学生没有参加任何课程,因此对Classroom.Courses.list(optionalArgs)
的调用使我获得了一组空课程,并且该函数几乎立即返回而未进行任何报告。我正在显示完整的脚本代码,但是其中有趣的部分并不长。它有很多部分可以支持任务,例如从其他工作表获取数据或在屏幕上显示HTML对话框。
最好的问候拉斐尔
P.S。对不起,我的内容很长,但是代码更长了,我认为解释这种情况可以改善对我们问题的理解。
// Menu function onOpen() { var ui = SpreadsheetApp.getUi(); ui.createMenu('Functions') .addItem('Group report','fReportGroupHtml') .addItem('Student report','fStudentReportHtml') .addToUi(); } //------------------------------------------------------------------------ // Report for 1 student // Opens HTML dialog to select group and student //------------------------------------------------------------------------ function fStudentReportHtml() { // Html dialog try { var output = HtmlService.createHtmlOutputFromFile('SelecStudent'); SpreadsheetApp.getUi().showModalDialog(output,'Select student'); } catch(err) { Logger.log(err); return; } } //--------------------------------------------------------------------------- // Report for 1 student // Receives information from dialog and makes report //------------------------------------------------------------------------ function fStudentReport(form_data) { // Form information var nameStudent=form_data.student; // Split students name and surname var posco=nameStudent.indexOf(','); var surname=nameStudent.substring(0,posco); var name=nameStudent.substring(posco+2); // Gets student email var idStudent=getUserEmail(name,surname); // List student coursework var ssCourses=SpreadsheetApp.getActive(); var hWorks=ssCourses.getSheetByName("StWork"); fListStudentWork(idStudent,hWorks,nameStudent); } //--------------------------------------------------------------------------- // Report for all students in a group // Opens HTML dialog to select group function fReportGroupHtml() { // Html dialog try { var output = HtmlService.createHtmlOutputFromFile('SelecGroup'); SpreadsheetApp.getUi().showModalDialog(output,'Select group'); } catch(err) { Logger.log(err); return; } } //--------------------------------------------------------------------------- // Report for all students in a group // Receives information from dialog and makes report function fReportGroup(form_data) { var idStudents="1wvjqUFZcRwjTKSspjyQOE1JHio33f7seyx8xCO8qHBQ"; var idTemplateInf="1K6YgZvh195eo4b-DLtRHuvjFdG3SOBJILodzS4CUnBs"; var idCarpInf="16nH3BhAwHPP3BcAUK9eW_FQdWRM6B87T"; var valAlu=[[]]; // Opens students sheet var ss = SpreadsheetApp.openById(idStudents); var coursesSS = ss.getSheetByName("Students"); var lastrow=coursesSS.getLastRow(); var rangeA=coursesSS.getRange(2,2,lastrow-1,3).getValues(); // First student in the group for(var ii=0; ii<lastrow-1; ii++) { if (rangeA[ii][2]==form_data.groupAlu) break; } var ini=ii; // Opens sheet for messaging var ssClass = SpreadsheetApp.getActive(); // Copies template sheet into a new file var idNewFileInf = DriveApp.getFileById(idTemplateInf).makeCopy(idCarpInf).getId(); DriveApp.getFileById(idNewFileInf).setName('Report '+form_data.groupAlu); // Opens new sheet and writes general information var ssInf = SpreadsheetApp.openById(idNewFileInf); var hjInfAlu = ssInf.getSheetByName("Students"); hjInfAlu.getRange(2,1).setValue("GRUPO: "+form_data.groupAlu); var dateToday=new Date(); hjInfAlu.getRange(3,1).setValue("FECHA: "+Utilities.formatDate(dateToday,"GMT+1","dd/MM/yyyy")); // All students in the group var iiAlu=1; while(rangeA[ii][2]==form_data.groupAlu) { // Gets student's information var surname=rangeA[ii][0]; var name=rangeA[ii][1]; var nameStudent=surname+", "+name; // Gets student email var idStudent=getUserEmail(name,surname); // Copies sheet var hjInfWork = ssInf.getSheetByName("Works").copyTo(ssInf).setName(nameStudent); // Makes report of student's work and submissions var mens="Creando informe de student: "+nameStudent; ssClass.toast(mens, "Informe de tareas",-1); var states=fListStudentWork(idStudent,hjInfWork,nameStudent); // Writes student information in first sheet valAlu[0][0]=iiAlu; valAlu[0][1]=nameStudent; valAlu[0][2]=states[0]; valAlu[0][3]=states[1]; valAlu[0][4]=states[2]; hjInfAlu.getRange(iiAlu+5, 1, 1, 5).setValues(valAlu); ii++; iiAlu++; } // Deletes sheet 'Works' ssInf.deleteSheet(ssInf.getSheetByName("Works")); // Final message ssClass.toast("Fin del informe", "Informe de tareas",5); } //--------------------------------------------------------------------------- // List coursework for a student function fListStudentWork(idStudent, dataSheet, nameStudent) { // Variables var ii=0; var lWorks=[[]]; var stateWork=[0,0,0]; var pageToken = null; var pageToken2 = null; var colorCourse1= "#ddffdd"; var colorCourse2= "#f9e9b0"; var iiColor=0; var optionalArgs= { pageToken: pageToken, courseStates: 'ACTIVE', studentId: idStudent, pageSize: 0 }; var optionalArgs2= { userId: idStudent, pageSize: 0 }; // Date today var now = new Date(); var year=now.getFullYear(); var month=now.getMonth(); // Date starting term if (month>=8) var cadfecha="September 1, "+year.toString(); else var cadfecha="September 1, "+(year-1).toString(); var fechaini=new Date(cadfecha); // Empty sheet var rowWorks=dataSheet.getLastRow(); var colWorks=dataSheet.getLastColumn(); if (rowWorks>3) { var rnWorks=dataSheet.getRange(4, 1, rowWorks-3, colWorks); rnWorks.clearContent().clearFormat(); } // General information in sheet if (!nameStudent) nameStudent=getUserName(idStudent); Logger.log("INI: "+nameStudent); dataSheet.getRange(1, 1).setValue("ENTREGAS DEL ALUMNO: "+nameStudent); var dateToday=new Date(); dataSheet.getRange(2, 1).setValue("FECHA: "+Utilities.formatDate(dateToday,"GMT+1","dd/MM/yyyy")); // First: courses for the student var response = Classroom.Courses.list(optionalArgs); var courses = response.courses; if (!courses || courses.length === 0) dataSheet.getRange(4, 2).setValue("No hay clases"); else { Logger.log(" courses: "+courses.length); for (course in courses) { var fechaCourse=new Date(courses[course].creationTime); if (fechaCourse>=fechaini) { // Information from the course var idCourse=courses[course].id; var nomprof=getUserName(courses[course].ownerId); var colorCourse=(iiColor==0)? colorCourse1 : colorCourse2; iiColor=1-iiColor; // Gets coursework from the course var responseT = Classroom.Courses.CourseWork.list(idCourse); var works = responseT.courseWork; if (!works || works.length === 0) dataSheet.getRange(4, 2).setValue("No hay información"); else { for (work in works) { var idWork=works[work].id; var maxPoints=(works[work].maxPoints==null)? "" : works[work].maxPoints; // Gets submissions try { var responseE = Classroom.Courses.CourseWork.StudentSubmissions.list(idCourse, idWork, optionalArgs2); var submis = responseE.studentSubmissions; } catch(ee) { var submis=null; } if (submis && submis.length >0) { for (subm in submis) { lWorks[0][0]=ii+1; lWorks[0][1]=courses[course].name; lWorks[0][2]=nomprof; lWorks[0][3]=works[work].title; var dateWork=works[work].dueDate; if (dateWork==null) lWorks[0][4]="--/--/----"; else lWorks[0][4]=dateWork.day+"/"+dateWork.month+"/"+dateWork.year; var points=(submis[subm].assignedGrade==null)? "" : submis[subm].assignedGrade; lWorks[0][5]=points+" / "+maxPoints; var dateSubmis=submis[entrega].creationTime; if (dateSubmis==null) lWorks[0][6]="--/--/----"; else lWorks[0][6]=Utilities.formatDate(new Date(dateSubmis), "GMT+1","dd/MM/yyyy"); var state=submis[subm].state; // Gets state of submission var cState=""; var lateSubmis=0; if ((state=="RETURNED")||(state=="TURNED_IN")) { cState="ENTREGADO"; stateWork[0]++; } else { // Checks if late or not handed if (dateWork!=null) { var dateEnd=new Date(dateWork.year,dateWork.month-1,dateWork.day); if (dateEnd.valueOf()<dateToday.valueOf()) { cState="NO ENTREGADO"; stateWork[1]++; lateSubmis=1; } else stateWork[2]++; } } lWorks[0][7]=cState; dataSheet.getRange(ii+4, 1, 1, 8).setValues(lWorks).setBackground(colorCourse); if (lateSubmis) dataSheet.getRange(ii+4, 8).setFontColor("red").setFontWeight("bold"); else dataSheet.getRange(ii+4, 8).setFontColor("black").setFontWeight("normal"); ii++; } } } } } } } return(stateWork); } ///////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------ // Gets list of groups function listGroups() { var idStudents="1wvjqUFZcRwjTKSspjyQOE1JHio33f7seyx8xCO8qHBQ"; try { // Opens students sheet var ss = SpreadsheetApp.openById(idStudents); var coursesSS = ss.getSheetByName("Students"); var lastrow=coursesSS.getLastRow(); var rangeA=coursesSS.getRange(2,4,lastrow-1,1).getValues(); var courses = []; var courseant=""; for(var ii=0; ii<lastrow-1; ii++) { if (rangeA[ii][0]!=courseant) { courseant=rangeA[ii][0]; courses.push(courseant); } } return courses; } catch(err) { Logger.log(err); } } //------------------------------------------------------------------------ // Gets list of students in group function listStudents(group) { var idStudents="1wvjqUFZcRwjTKSspjyQOE1JHio33f7seyx8xCO8qHBQ"; try { // Opens students sheet var ss = SpreadsheetApp.openById(idStudents); var coursesSS = ss.getSheetByName("Students"); var lastrow=coursesSS.getLastRow(); var rangeA=coursesSS.getRange(2,1,lastrow-1,4).getValues(); // First student for(var ii=0; ii<lastrow-1; ii++) { if (rangeA[ii][3]==group) break; } var ini=ii; // Last student while(rangeA[ii][3]==group) ii++; // Gets array of students var students=coursesSS.getRange(2+ini,2,ii-ini,2).getValues(); return students; } catch(err) { Logger.log(err); } } //------------------------------------------------------------------------ // Gets list of courses function listCourses() { try { // Opens courses sheet var ss = SpreadsheetApp.getActive(); var coursesSS = ss.getSheetByName("Courses"); var lastrow=coursesSS.getLastRow(); var courses=coursesSS.getRange(3,2,lastrow-2,4).getValues(); return courses; } catch(err) { Logger.log(err); } } //--------------------------------------------------------------------------- // Gets user name from ID function getUserName(usid) { var result = AdminDirectory.Users.get(usid, {fields:'name'}); var fullname = result.name.fullName; return fullname; } //---------------------------------------------------------------------------- // Gets user email from name function getUserEmail(name,surname) { var userIds = AdminDirectory.Users.list({domain:"iesciudadjardin.com", query:"givenName:'"+name+"' familyName:'"+surname+"'"}).users; if ((userIds==undefined)||(userIds.length!=1)) return null; else return userIds[0].primaryEmail; }
附加信息
我知道问题太大,所以我将尝试用尽可能少的代码来解释问题。本质上,我的代码有效。有时它与一些学生一起挂起。它的主要部分是函数fListStudentWork
:// List coursework for a student function fListStudentWork(idStudent, dataSheet, nameStudent) { var optionalArgs= { pageToken: pageToken, courseStates: 'ACTIVE', studentId: idStudent, pageSize: 0 }; // First: courses for the student var response = Classroom.Courses.list(optionalArgs); var courses = response.courses; if (!courses || courses.length === 0) // NO COURSES else { // MAKE REPORT } }
现在,如果我和一个特殊的学生一起打电话,它会工作,返回空的课程集,因为约翰·史密斯没有参加任何课程(也有参加某些课程的学生也发生过:]
function OneStudentReport() { fListStudentWork("[email protected]",mySheet,"John Smith"); }
但是如果我和一组学生一起循环,约翰·史密斯是其中的一员,以前的所有学生报告都可以,当循环到达他时,它将返回我学校的所有课程,并且脚本会随着时间的流逝而中止错误。
function fReportGroup(form_data) { // All students in the group while(StudentGroup=="MYGROUP") { // Gets student's information var surname=rangeA[ii][0]; var name=rangeA[ii][1]; var nameStudent=surname+", "+name; // Gets student email var idStudent=getUserEmail(name,surname); // Makes report of student's work and submissions var states=fListStudentWork(idStudent,MySheet,nameStudent); } }
P.S。如果管理员认为我由于太长而应该删除带有完整代码的消息的第一部分,请告诉我。谢谢
这是我面临的一个复杂而奇怪的问题,我希望任何人都可以带给我,即使不是解决问题的方法,也可以避开它。从头开始,我是......>