0
function onEdit() {
var openRequests = SpreadsheetApp.getActive().getSheetByName('Open Requests');
var lastRowOpen = openRequests.getLastRow();

var closedRequests = SpreadsheetApp.getActive().getSheetByName('Closed Requests');
var lastRowClose = closedRequests.getLastRow();

var closed = openRequests.getRange(2,8,lastRowOpen,1).getValues();

for (var i = 0; i < lastRowOpen; i++)
{
    if (closed[i][0].toString() == 'Yes')
    {
        var line = i+2;
        if (closedRequests.getLastRow() == 1)
        {
            openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(2,1,1,9));
            closedRequests.getRange(2,9,1,1).setValue(new Date());
            openRequests.deleteRow(line);
        }
        else
        {
            openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(lastRowClose+1,1,1,9));
            closedRequests.getRange(lastRowClose+1,9,1,1).setValue(new Date());
            openRequests.deleteRow(line);
        }
    }
}

}

我已经设置了一个触发器来运行 onEdit。它所做的是检查一个名为的列Closed以查看它是否显示Yes. 该Closed列有一个数据验证下拉菜单,其中包含值Yes

因此,当我单击下拉菜单并选择Yes时,它应该将整行复制到另一个名为的工作Closed Requests表中,然后从名为 的电子表格中删除该行Open Requests

我遇到的问题是,大约 50% 的时间,它删除了我选择的行Yes,但它也删除了它下面的行(大约 50% 的时间发生这种情况,第二个删除的行只显示一些时间向上Closed Requests,其他时候整行会永远消失,除非我撤消)。

据我所知,该deleteRow()函数删除整行并将其下方的所有行向上移动一行以填充空白。因此,要删除的行下方的行将向上移动到同一行并被删除。我不知道为什么该函数被调用两次。

我尝试添加一些延迟,但它似乎不起作用。

4

4 回答 4

5
function onEdit(e) {
  var eRange = e.source.getActiveRange();
  var openRequests = SpreadsheetApp.getActive().getSheetByName('Open Requests');
  var closedRequests = SpreadsheetApp.getActive().getSheetByName('Closed Requests');
  var nextRowClose = (closedRequests.getLastRow()?closedRequests.getLastRow()+1:2);

  if(eRange.getSheet().getName()=="Open Requests" && eRange.getColumn()==8 && eRange.getValue()=="Yes") {
    openRequests.getRange(eRange.getRow(), 1, 1, 9)
      .copyTo(closedRequests.getRange(nextRowClose, 1));
    closedRequests.getRange(nextRowClose, 9).setValue(new Date());
    openRequests.deleteRow(eRange.getRow());
  }
}
于 2013-01-16T00:07:10.833 回答
1

可以尝试像我提到的那样向后迭代。SpreadsheetApp.flush()在删除后加入a也可能有所帮助。

于 2013-01-12T14:20:45.570 回答
1

@Jack,我有一个与您类似的用例。我的代码是 BryanP 讨论的倒退代码。我的代码或多或少在这里: “批量删除状态='完成'的任务项”。这是因为我在批处理中删除它们,所以我使用了向后的方法,即删除具有较高行号的行不会干扰具有较低行号的任何行的行号。

但是您不是在批处理模式下删除行,因此可能向后不应该有所作为(也许除非两个用户同时使用工作表并删除?)

所以想我会试试你的代码。我将您的代码插入到我的电子表格中已经存在的 onedit() 函数中(用于在一段时间不活动后将行着色为红色,并在实际参与任务后放入时间戳)。

然后为了测试,我使用了我们的一个电子表格的副本,其中已经有 50 行/任务。我连续手动填写了所需的单元格,并从带有下拉列表的单元格中选择了完成(我将您的代码更改为期望“完成”而不是“是”)。我重复了 20 行。

结果:您的代码成功了,正如您所期望的那样 20 次中的每一次……没有双重删除,总是复制数据。它对我有用,没有引入延迟,也没有引入 SpreadsheetApp.flush()。

恐怕我没有可靠的建议。顺便提一下电子表格没有正确刷新自身的已知错误,因此不显示已删除的行;这可以通过在出现此故障时手动刷新电子表格来检查。(然而,这个错误的迹象似乎在逻辑上不符合你关于重复复制两个连续行的报告。)

于 2013-01-16T01:14:12.530 回答
0

线程锁?听起来像一个线程锁定问题。尝试:

function onEdit() {

 // ****** add lock code
 var lock = LockService.getPublicLock();
 var hasMutex = lock.tryLock(100);
 if(hasMutex==false) {
   return;
 }
 // *** end

 var openRequests = SpreadsheetApp.getActive().getSheetByName('Open Requests');
 var lastRowOpen = openRequests.getLastRow();

 var closedRequests = SpreadsheetApp.getActive().getSheetByName('Closed Requests');
 var lastRowClose = closedRequests.getLastRow();

 var closed = openRequests.getRange(2,8,lastRowOpen,1).getValues();

 for (var i = 0; i < lastRowOpen; i++)
 {
    if (closed[i][0].toString() == 'Yes')
    {
       var line = i+2;
       if (closedRequests.getLastRow() == 1)
       {
          openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(2,1,1,9));
          closedRequests.getRange(2,9,1,1).setValue(new Date());
          openRequests.deleteRow(line);
       }
        else
       {

   openRequests.getRange(line,1,1,9).copyTo(closedRequests.getRange(lastRowClose+1,1,1,9));
        closedRequests.getRange(lastRowClose+1,9,1,1).setValue(new Date());
        openRequests.deleteRow(line);
        }
      }
  }


 // ****** add lock code
  lock.releaseLock();    

 // *** end

} 

问题:

1) 当时有多少人在使用电子表格。

2)它发生的频率。

于 2013-01-17T04:14:37.120 回答