【发布时间】:2018-03-06 04:18:24
【问题描述】:
我对 Google Apps 脚本比较陌生,并且在使用下面的代码时遇到了困难。基本上,它绑定到充当工作流的工作表。我使用已安装的 onEdit 触发器,它会循环查看哪些单元格已更改,然后根据已更改的单元格添加时间戳、发送电子邮件或保护范围。
我遇到了时间戳并不总是持久的问题,电子邮件并不总是发送,而且保护措施永远存在。
有没有更有效的方法来做到这一点?
function onEditFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
// CHECKS FOR CHANGE IN "UPDATES" SHEET ONLY
if (sheet.getSheetName() == "Updates") {
var activeRange = sheet.getActiveCell();
var activeRow = activeRange.getRow();
var activeColumn = activeRange.getColumn();
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Updates');
var sss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('LookUps');
var email = Session.getActiveUser().getEmail();
var timestamp = new Date();
var itemAttributes = sheet.getRange(activeRow, 1,activeRow,19).getValues();
// CHECKS FOR CHANGE IN ITEM COLUMN (A)
// if column A clear out the other cells
if (activeColumn == 1) {
var r = sheet.getActiveRange();
// CHECKS IF NUMBER OF ROWS INDICATES A PASTED RANGE
// if pasted range is more than one row in size, then loop through and do validation on all impacted rows
if (r.getNumRows() > 1) {
SpreadsheetApp.getActiveSpreadsheet().toast('Updating.....please wait.', 'Status', -1);
var l = r.getNumRows()
sheet.getRange(activeRow, 2, l, 13).clearContent();
for (var x = 0; x < l; x++) {
var ac = activeRow + x
if(ss.getRange(ac, 1).getvalue != '') {
sheet.getRange(ac, 12).setValue(email);
}
ss.getRange(ac, 1).copyTo(sss.getRange('G1'), {contentsOnly:true})
var dynamicList = sss.getRange('G2:G15'); // set to your sheet and range
var arrayValues = dynamicList.getValues();
var rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(arrayValues);
ss.getRange(ac, 2).setDataValidation(rangeRule); // set range to your range
//SpreadsheetApp.flush();
var NewItemCheck = sss.getRange('G2').getValues()
if (NewItemCheck == "" && ss.getRange(ac, 1).getvalue != '') {
sheet.getRange(ac, 10).setValue("NEW ITEM")
}
} // END FOR LOOP THROUGH ROWS OF RANGE
SpreadsheetApp.getActiveSpreadsheet().toast('DONE', 'Status', 2);
} // END IF RANGE IS GREATER THAN 1 ROW
else
{
sheet.getRange(activeRow, 2, 1, 13).clearContent();
if(itemAttributes[0][0] != '') {
sheet.getRange(activeRow, 12).setValue(email);
}
sss.getRange('G1').setValue(itemAttributes[0][0]);
var dynamicList = sss.getRange('G2:G15');
var arrayValues = dynamicList.getValues();
var rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(arrayValues);
ss.getRange(activeRow, 2).setDataValidation(rangeRule);
//SpreadsheetApp.flush();
var NewItemCheck = sss.getRange('G2').getValues()
if (NewItemCheck == "" && itemAttributes[0][0] != '') {
sheet.getRange(activeRow, 10).setValue("NEW ITEM")
}
}
}
// CHANGE IN Vendor Name / ID - LOC COLUMN (B)
if (activeColumn == 2) {
// if column B in Sheet UPDATES is changed, update adjacent drops downs
sheet.getRange(activeRow, 5).clearContent();
sss.getRange('H1').setValue(itemAttributes[0][1])
var dynamicList = sss.getRange('H2:H15');
var arrayValues = dynamicList.getValues();
var rangeRule = SpreadsheetApp.newDataValidation().requireValueInList(arrayValues);
ss.getRange(activeRow, 5).setDataValidation(rangeRule);
var a = itemAttributes[0][1].slice(-9);
var b = a.split(" ");
var c = itemAttributes[0][1].slice(-2);
var vendLocCombo = [[b,c]];
var vendLocComboRange = ss.getRange(activeRow, 3, 1, 2);
vendLocComboRange.setValues(vendLocCombo);
}
// SUBMITTED
if (activeColumn == 11 && itemAttributes[0][10] ){
// if column K in Sheet UPDATES is changed to TRUE (checked), email
// cost analysts in var CostEmail, and protect submitted info
sheet.getRange(activeRow, 13).setValue(timestamp);
SpreadsheetApp.flush();
var Prange = sheet.getRange('A'+activeRow+':M'+activeRow);
var protection = Prange.protect().setDescription('SubmitLock A'+activeRow+':M'+activeRow);
protection.removeEditors(protection.getEditors());
protection.addEditors(['emailhere.com','emailhere.com']);
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
// COMPLETED
if (activeColumn == 15 && itemAttributes[0][14]) {
// if column O in Sheet is changed to TRUE (checked) then user email and timestamp columns Q and R
sheet.getRange(activeRow, 17).setValue(email);
SpreadsheetApp.flush();
sheet.getRange(activeRow, 18).setValue(timestamp);
SpreadsheetApp.flush();
var Prange = sheet.getRange('N'+activeRow+':S'+activeRow);
var protection = Prange.protect().setDescription('CompleteLock N'+activeRow+':S'+activeRow);
protection.removeEditors(protection.getEditors());
protection.addEditors(['emailhere.com','emailhere.com']);
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
// DENIED
if (activeColumn == 16 && itemAttributes[0][15]) {
// if column P in Sheet is checked (true) send email to original submitter in column M
sheet.getRange(activeRow, 17).setValue(email);
sheet.getRange(activeRow, 18).setValue(timestamp);
var Prange = sheet.getRange('O'+activeRow+':T'+activeRow);
var protection = Prange.protect().setDescription('CompleteLock O'+activeRow+':T'+activeRow);
protection.removeEditors(protection.getEditors());
protection.addEditors(['emailhere.com','emailhere.com']);
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
var DeniedEmailAddress = itemAttributes[0][11];
var message = " Comments : "+itemAttributes[0][13];
var subject = "[Denied - Contracted Cost Request] "+itemAttributes[0][0];
MailApp.sendEmail(DeniedEmailAddress, subject, message,{
name: 'Contracted Cost Update',
attachments: []
});
sheet.getRange(activeRow, 19).setValue("X");
}
}
}
编辑:
function onEditFunction(e) {
if (e.source.getActiveSheet().getSheetName() == "Updates") {
// CHECKS FOR CHANGE IN "UPDATES" SHEET ONLY
var sheet = e.source.getActiveSheet();
var protectionDescription;
var protectedRange;
var i;
var protection;
var removeEditorsArray =
["group1@email.com","group2@email"];
var activeColumn = e.range.getColumn();
switch(activeColumn){
case 1: //Item
changeItem(e, sheet, activeColumn);
break;
case 2: //Vendor Name/ID - Loc
changeVendor(e, sheet, activeColumn);
break;
case 11: //SUBMIT check box
changeSubmit(e, sheet, activeColumn, protectionDescription, protectedRange, removeEditorsArray);
break;
case 15: //COMPLETE check box
changeComplete(e, sheet, activeColumn);
break;
case 16: //DENIED check box
changeDenied(e, sheet, activeColumn);
break;
}
}
}
function changeSubmit(e, sheet, activeColumn, protectionDescription, protectedRange, removeEditorsArray){
// if column K in Sheet UPDATES is changed to TRUE (checked), enter a timestamp and protect submitted info
var activeRow = e.range.getRow();
var timestamp = new Date();
var removeLen = removeEditorsArray.length
sheet.getRange(activeRow, 13).setValue(timestamp);
protectedRange = 'A'+activeRow+':M'+activeRow;
protectionDescription = 'SubmitLock A'+activeRow+':M'+activeRow;
protectRanges(sheet, protectionDescription, protectedRange, removeEditorsArray)
}
function protectRanges(sheet, protectionDescription, protectedRange, removeEditorsArray) {
var i=0;
var Len = removeEditorsArray.length;
protectedRange = sheet.getRange(protectedRange);
protectionDescription = protectedRange.protect().setDescription(protectionDescription);
for (i; i < Len; i++) {
protectionDescription.removeEditor(removeEditorsArray[i]);
}
}
【问题讨论】:
-
你已经发布了很多代码,而且都是一个函数——我建议至少将这个函数分成 3 个函数,每个函数处理你想要执行的单个任务。接收
onEdit触发器的函数将使用逻辑调用所需的函数,并传递任何相关参数。我还建议访问可用于onEdit触发函数的event object。 -
我必须在这里第二次 tehhowch。您的活动电子表格、活动单元格,甚至更改前后单元格中的值都可以通过事件对象访问(例如,您可以编写
onEdit(e),e将包含您需要的内容。请拆分代码,因为它需要一次全部完成。关于执行操作的逻辑的快速提示,使用switch而不是单独的if语句 -
@tehhowch - 感谢您的建议!我已经编辑了代码——我按功能分解了它,并利用了事件对象。现在,我可以更清楚地查看执行脚本,并且该脚本运行所需的 80-90 秒中有 98% 位于“Protection.removeEditor”上。我为此使用了一个数组,但我也尝试过仅使用一个文本字段的“Protection.removeEditorS”,它仍然需要大约相同的大量时间。我基本上是在尝试从编辑器列表中删除工作表中给定受保护范围的 2 个组名(对工作表具有编辑访问权限)。
-
@Vytautas - 谢谢!我编辑了,现在使用 switch 功能。更容易分析正在发生的事情以及进行编辑时。也使用(e)。从范围中移除保护仍然需要很长时间。有什么想法吗?
-
@Three-D,绝对是一个进步,干得好。我会更进一步(您错误地引用了
e.source.getActiveSheet()而不是e.range.getSheet()- 用户可以在此函数运行时更改选项卡),parameter passing 未来可能会出现问题。我只会将保护变量移到需要它们的地方(在changeSubmit内,并作为protectRanges的参数)。我还建议只使用批处理方法removeEditors(String[])。保护区有多大?
标签: google-apps-script google-sheets