我是一名高中教师,正试图让他们的学校使用"realsmpart" voTer script在Google Apps中以电子方式投票,并且它没有按预期工作。
以下是设置它的YouTube video about the script。
这是脚本:
function voTer(){
var sss = SpreadsheetApp.getActiveSpreadsheet();
var form = sss.getSheetByName("Sheet1");
var range = form.getRange(1,2,form.getLastRow(),1);
var lastEntry = range.getCell(form.getLastRow(),1).getValue();
var data = form.getRange(1,2,form.getLastRow()-1,1).getValues();
for (var i = 0; i < data.length; i++) {
var row = data[i];
var entry = row[0];
if (entry == lastEntry){
var subject = "You Have Submitted!"; //Email subject
var recipient = lastEntry;
var body = "Hi there,<br><br>You've already submitted this form before, so this
submission will not count.<br>Please contact ***, if you do want to change your answer.
<br><br>Best,<br>***"; //Email body
if (recipient!=''){
MailApp.sendEmail(recipient, subject, body,{htmlBody:body});
}
form.getRange(form.getLastRow(),2,1,form.getLastColumn()).clear();
break;
}
}
}
我们不需要指定范围,所以相反(为了不再获取此错误消息)我们将写入脚本以简单地忽略它。添加下面带有错误的区域旁边的脚本。
//ignore this warning
以下是关于如何使用脚本的the instructions,我已遵循该脚本但仍无法使脚本生效。
答案 0 :(得分:1)
原始剧本是为“老人”编写的。表格提供,并没有更新。因此,对Sheet1
的硬编码引用是错误的,因为&#39; new&#39;表格将创建一个&#34;表格回复&#34;片。对列数的依赖是“脆弱的”,因为该脚本假设受访者&#39;电子邮件地址将位于时间戳之后的第2列(B)中。实际上,电子表格中的问题顺序取决于它们添加到表单的顺序 - 并且由于新表单是由虚拟问题预先填充的,并且电子邮件地址列在表单中被视为隐藏问题,即使您删除了虚拟问题,电子邮件地址也绝不会在第2列。这样脆弱的代码现在就被打破了。
那整个//ignore this warning
的事情?它只是一个评论,它不会阻止检测到错误。
好消息是有更好的方法。
我们可以利用提供给触发器功能的Event对象,而不是硬编码细节。阅读Sheets Form Submit事件对象。
为了索引特定的列,我已经包含了一个辅助函数columnNum()
。它是作为电子表格自定义函数编写的,因此它产生了基于1的索引,以便与内置函数兼容。
此脚本比原始&#34; voTer&#34;更容易自定义,因为您需要摆弄的所有变量都位于顶部。如有必要,可以修改电子邮件的正文 - 每一行在数组中显示为单独的字符串。
/**
* To customize the email sent to re-voters, change the values
* of the following variables.
*/
var subject = "Invalid Vote Received"; //Email subject
var electoralOfficer = "your electoral officer"; // Person to contact for re-vote
var emailSignature = "Election committee"; // Signature on email
var timezone = Session.getScriptTimeZone(); // Timezone - use caution
function oneVote(vote) {
var colUserName = columnNum("Username");
// use the provided event object to get references to required objects
var sheet = vote.range.getSheet();
var ballot = vote.range.getRowIndex();
var voter = vote.namedValues["Username"][0];
// Get list of all previous votes
var prevVoters = sheet.getRange(1, colUserName, ballot-1)
.getValues() // Get email addresses as 2-dim array
.join(',') // Join into a comma-deliminated string
.split(',') // Then split into one-dimensional array
// Check whether this voter previously voted
var previousVote = prevVoters.indexOf(voter);
// if they did, remind them then delete the new vote
if (previousVote > -1) {
var previousVoteTime = sheet.getRange(previousVote+1,columnNum("Timestamp")).getValue();
var body = //Email body
["Hi there,",
"",
"You previously voted on #TIMESTAMP#, so this submission will not count.",
"Please contact #ELECTORALOFFICER# if you do want to change your vote.",
"",
"Thanks,",
"#SIGNATURE#"
].join('<br>')
.replace('#TIMESTAMP#',Utilities.formatDate(previousVoteTime, timezone, "MMM d 'at' h:mm a"))
.replace('#ELECTORALOFFICER#', electoralOfficer)
.replace('#SIGNATURE#', emailSignature)
MailApp.sendEmail(voter, subject, body,{htmlBody:body});
sheet.deleteRow(ballot); // Could move to a "spoiled ballots" list instead.
}
}
/**
* Get the index of columnName.
* @customfunction
*
* @param {String} columnName Column header to find
* @param {Number} headerRow Column headers row index (Optional, default 1)
* @returns {Number} Column index, 0 if not found
*/
function columnNum(columnName,headerRow) {
headerRow = headerRow ? headerRow - 1 : 0; // Default: assume column headers in first row
var rows = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
// Validate input
if (headerRow < 0 || headerRow >= rows.length)
throw new Error( "headerRow out of range 1..maxRows" );
var headers = rows[headerRow];
return headers.indexOf(columnName)+1;
}
请务必设置触发器,以便在提交表单时运行。
为了测试触发功能,最好模拟在正常操作下接收的事件。此函数读取现有表单响应并将其作为新提交提供给oneVote()
。见How can I test a trigger function in GAS?
/**
* Test function simulates multiple form submission events for oneVote()
* trigger function, by reading "active" spreadsheet. Make sure your
* spreadsheet session is open to the Form Responses first.
*
* From https://stackoverflow.com/a/16089067
*/
function test_oneVote() {
var dataRange = SpreadsheetApp.getActiveSheet().getDataRange();
var data = dataRange.getValues();
var headers = data[0];
// Start at last row, work backwards to allow for deletions, skip headers in row 0
for (var row=data.length-1; row > 0; row--) {
var e = {};
e.values = data[row];
e.range = dataRange.offset(row,0,1,data[0].length);
e.namedValues = {};
// Loop through headers to create values & namedValues properties
for (var col=0; col<headers.length; col++) {
e.namedValues[headers[col]] = [e.values[col]];
}
// Skip invalid rows
if (e.namedValues["Username"] === '') continue;
// Pass the simulated event to oneVote
oneVote(e);
}
}