1

我做了什么:

如果 M 列中的任何单元格已更改,则已发送电子邮件通知以指定同一行 N 列中的地址。但我还需要一些从同一行的其他列中指定的正文。我做了一些有效的事情,但它也导致如果其他声明的列(如项目、客户、任务、执行者)已更改,则 emil 已发送到。

我需要的:

只需跟踪一个“M”列中的更改,然后将来自其他列但来自同一行的附加数据放在电子邮件正文中。并且(这就是重点)没有跟踪其他列的更改,只有在更改列 M 时才应发送电子邮件。

也许这很容易,但我很扭曲......

我根据以下内容构建此脚本:

我的脚本:

function sendNotification() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet();
  var cell = ss.getActiveCell().getA1Notation();
  var row = sheet.getActiveRange().getRow();
  var cellvalue = ss.getActiveCell().getValue().toString();
  var sendto = '';
      if(cell.indexOf('M')!=-1){ 
      sendto = sheet.getRange('N'+ sheet.getActiveCell().getRowIndex()).getValue()
      }   
  var project = ''; 
      project = sheet.getRange('C'+ sheet.getActiveCell().getRowIndex()).getValue()   
  var customer = '';
      customer = sheet.getRange('D'+ sheet.getActiveCell().getRowIndex()).getValue()      
  var task = '';
      task = sheet.getRange('E'+ sheet.getActiveCell().getRowIndex()).getValue()      
  var executor = '';
      executor = sheet.getRange('F'+ sheet.getActiveCell().getRowIndex()).getValue() 
  var deadline = '';
      deadline = LanguageApp.translate(Utilities.formatDate(sheet.getRange('I'+ sheet.getActiveCell().getRowIndex()).getValue() , "GMT" , "EEEE, dd MMMM YYYY" ),'en','pl')
  var status = '';
      status = sheet.getRange('M'+ sheet.getActiveCell().getRowIndex()).getValue()         
  var mysubject = status + ' | ' + project + ': ' + task + ' - ' + ss.getName() + ' update';
  var mybody = '\nStatus: ' + status + '\n\nproject: ' + project + '\ncustomer: ' + customer + '\ntask: ' + task + '\nexecutor: ' + executor + '\nDeadline: ' + deadline + '\n\n' + ss.getName() + ': \n' + ss.getUrl();

  MailApp.sendEmail({
    to:sendto, 
    subject:mysubject,
    body:mybody});
};
4

1 回答 1

0

我制作了一个示例脚本,您应该可以在https://docs.google.com/spreadsheets/d/11u0xkdtPlQsnVppCnPYM0CHuCTPLdmN8PcFlaW08lNw/edit#gid=0看到

您必须制作一个副本才能实际使用它。

但是......复制不会给你我设置的触发器。如果您编辑脚本,请转到菜单Reources --> Current project's triggers并使自己成为函数checkForChanges()的基于时间的触发器。出于测试目的,我将其设置为“每分钟”。

在您的专栏中,我添加了四个新专栏:

  • concat - 只是您需要监控其更改的所有行值的串联
  • 当前哈希- 由我添加到您的脚本中的一个简单函数生成
  • 上次编辑- 发送电子邮件后,脚本会为该单元格提供当前哈希值
  • 已更改- 比较上次编辑当前哈希,如果它们不同,则说 **true*。

所以......函数checkForChanges()定期在ChangeDetector范围内运行,寻找true。如果它什么也没找到,它会立即退出。

每次确实发现更改时,它都会收集该行的数据并通过电子邮件发送给它。(实际上,为了简单起见,我只是记录它。)

关键技巧是这对线:

  lastEdits[row_][0] = currentHashCodes[row_][0];
  ss_.getRangeByName("LastEdit").setValues(lastEdits);

请注意,如果您尽可能使用命名范围,您的代码会变得多么清晰。

如果示例在未来的某一天丢失,下面是代码:

/* Called from cells in column "Current Hash" */
function strHash(valCell) {
  var hash = 0;
  if (valCell.length == 0) return hash;
  for (i = 0; i < valCell.length; i++) {
    char = valCell.charCodeAt(i);
    hash = ((hash<<5)-hash)+char;
    hash = hash & hash; // Convert to 32bit integer
  }

  return hash;
}


/* Called periodically from a timed trigger. */
function checkForChanges() {

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var changeDetector = ss.getRangeByName("ChangeDetector").getValues();
  for (row in changeDetector) {
    if (row > 0) {
      changed = changeDetector[row][0];
      if (changed) notify(ss, row);
    }
  }

}


/* Called by checkForChanges(). */
function notify(ss_, row_) {

  initializeRangeArrays(ss_);

  status = statii[row_][0];
  project = projects[row_][0];
  task = tasks[row_][0];
  customer = customers[row_][0];
  executor = executors[row_][0];
  deadline = deadlines[row_][0];
  sendto = recipients[row_][0];

  var mysubject = status + ' | ' + project + ': ' + task + ' - ' + ss_.getName() + ' update';
  var mybody = '\nStatus: ' + status 
             + '\n\nproject: ' + project 
             + '\ncustomer: ' + customer 
             + '\ntask: ' + task
             + '\nexecutor: ' + executor
             + '\nDeadline: ' + deadline
             + '\n\n' + ss_.getName()
             + ': \n' + ss_.getUrl();

  Logger.log("to: " + sendto);
  Logger.log("subject: " + mysubject);
  Logger.log("body: " + mybody);
  Logger.log("");

  lastEdits[row_][0] = currentHashCodes[row_][0];
  ss_.getRangeByName("LastEdit").setValues(lastEdits);

}; 


var recipients = null;
var projects = null;
var customers = null;
var tasks = null;
var deadlines = null;
var executors = null;
var statii = null;
var lastEdits = null;
var currentHashCodes = null;

var rangeArraysInitialized = false;
/* Called by notify(). */
function initializeRangeArrays(ss_) {

  if (  !  rangeArraysInitialized  ) {
    recipients = ss_.getRangeByName("Recipient").getValues();
    projects = ss_.getRangeByName("Project").getValues();
    customers = ss_.getRangeByName("Customer").getValues();
    tasks = ss_.getRangeByName("Task").getValues();
    deadlines = ss_.getRangeByName("Date").getValues();
    statii = ss_.getRangeByName("Status").getValues();
    executors = ss_.getRangeByName("Executor").getValues();
    lastEdits = ss_.getRangeByName("LastEdit").getValues();
    currentHashCodes = ss_.getRangeByName("CurrentHash").getValues();

    rangeArraysInitialized = false;
  }
}

2014 年 9 月 22 日更新:

我在演示电子表格中做了一些更改。请看一看。

在我添加的脚本中。. .

function strArrayHash(range) {
  var ret = new Array();
  var str = "";
  for (item in range) {
    str = range[item].toString();
    if (str.length > 0) {
      ret[item] = strHash(str);
      Utilities.sleep(50);      // play with this to reduce "internal execution error"s
    } else {
      ret[item] = "";
    }
  };
  return ret;
}

在“P”列中,我替换了 . . .

=if( M2 = "", "", strHash(R2)))
=if( M3 = "", "", strHash(R3)))
      :
      :
=if( M22 = "", "", strHash(R22)))

. . . 和 。. .

=ARRAYFORMULA(if( M2:M514 = "", "", strArrayHash(R2:R514)))

. . . 在单元格“P2”中。我删除了“P3:P22”范围内所有单元格的内容

我将总行数增加到 1026

一旦值出现在 P 列中,我使用 [Paste Special] » [Paste values only] 将单元格 P2:P1026 复制到 M2:M1026 中。

在我的 i7 笔记本电脑中,重新计算并检测到第 500 行的变化需要 30 秒。

如果我尝试执行所有 1024 行,则会收到内部执行错误。

可能您需要使“if”子句复杂化,以便仅在真正需要它的行上进行哈希计算。

更新 :: 2017/02/24 没有人对此感兴趣,所以我停止了运行脚本的触发器。

于 2014-09-19T15:18:00.893 回答