在 Google 表格中,如果起始 sheet 的尺寸是动态的,如何使用脚本将标签复制到同一工作簿中的另一个标签?

In Google Sheets, how to copy tab to another tab in SAME workbook using Script, if the dimensions of the starting sheet are dynamic?

背景与目标:

我正在使用多个 Google 工作表,每个工作表都是多个用户的交互式界面,内置各种触发器和功能。问题是,即使有说明、突出显示和受保护的范围,人们仍然想方设法破坏 sheet 上的功能。 sheet 添加的数据需要复制、整理,然后删除,以便 sheet 恢复到其原始配置以供第二天的操作使用。我的目标是找到一种更有效的方法来做到这一点。

当前解决方案(笨拙):

目前,我使用 Apps 脚本 clearRange 函数解决了这个问题。每天晚上,它都会获取工作簿中的所有 4 个选项卡,清除格式,然后删除所有行和列,直到每个选项卡都是一个单元格。然后,脚本重建所有四个选项卡,重置条件格式,重写单元格函数,工作簿就可以在第二天使用了。

问题:

重置需要大量代码,目前 217 行 才能完全重置四个选项卡。 执行时间在 13 到 28 秒之间 并且脚本失败并出现诸如 同时调用太多 之类的错误并不少见,尤其是因为相同的函数是 运行在不同用户的多个工作簿上大致同时运行。

所需的解决方案:

我目前的想法是,最好的选择是 在工作簿中使用一个隐藏的 sheet,或者更确切地说是 4 个这样的 sheet,每个都是四个可见页面的隐藏模板,带有条件格式等等。每日重置需要适应无知和粗心的错误,而不是恶意错误,所以我不担心用户侵入和破坏隐藏模板 sheets。

因此,理想的新脚本将从将每个 sheet 削减到单个单元格开始(这仍然是必要的,以防止用户添加或删除行/列并因此破坏重置参数而导致的错误。然后,它会简单地 将单元格值和条件格式从模板 复制到可见的 sheet (选项卡)。之后,只需要几行就可以重新初始化一些IMPORTRANGE 函数等。

所需条件:

  1. 复制粘贴最好不要依赖固定的行列数字,而是select-all操作,这样如果对模板进行了任何更改,它们将被合并下次脚本 运行s 时自动执行,即使模板中的行数和列数发生变化。
  2. 该过程应消除无法遵循说明的用户对可见 sheet 造成的任何可能的错误或损坏。
  3. 该过程应包含隐藏模板的条件格式,这样就不必每晚重新编码。

那么,我该怎么做呢?我尝试使用宏,但尽管我第一次执行时复制所有粘贴有效,但脚本随后未能 运行。我进行了搜索,但所有问题似乎都是关于从一个跨页 sheet 复制到另一个,而不是在工作簿中复制,而不是复制到现有的 sheet,而不仅仅是复制。我宁愿避免 sheet 重复,因为我喜欢其中一个可见页面是 gid=0 稳定 URL。 任何帮助都会非常感激。如果我能做到这一点,我会很快乐,快乐蛤蜊。

超长期(奖金)目标:

除此之外,理想情况下,我希望能够拥有一个可以更改的主模板,然后使用一个命令将所有这些更改推送到当前的几十个工作簿中(用户之间有几个函数变量)使用相同的布局存在。就目前而言,我对一个工作簿所做的任何更改都必须在脚本中进行编码,然后必须将新代码复制到数十个副本中的每一个。我不知道是否有办法制作可以以这种方式传播出去的主模板。它似乎不存在,至少不能满足我的需要,因为:

  1. 它不能依赖像 IMPORTRANGE 这样不断更新的动态函数;整个事情已经运行慢到人们可以容忍的程度,任何增加处理负荷的事情都是不可接受的,
  2. 我不认为在多个 Google Sheets 工作簿之间复制目前会复制条件格式,这真的很有帮助,并且
  3. 似乎复制到另一个工作簿的功能都创建了一个新的 sheet,这将 运行 导致现有模板选项卡仍然是源的问题,而不是新选项卡,因此仍然需要手动更改每个工作簿。 如果有人有任何想法如何朝那个方向前进,我会洗耳恭听,但目前只解决第一个问题是必不可少的。感谢任何可以提供意见的人!

更新

我使用了 Cooper 的修复程序,它工作正常 -- 几乎完美。它在添加额外的空白行和无法复制任何空白行的单元格格式时遇到问题,如下所示:

编码如下所示:

  spreadsheet.getSheetByName('Lupin Academy page').showSheet().activate();
  spreadsheet.getRangeList(['H6','F6','A1','A6']).clearFormat().clear({contentsOnly: true, skipFilteredRows: true});
  spreadsheet.getActiveSheet().setFrozenRows(0);
  var maxColumns = spreadsheet.getActiveSheet().getMaxColumns();
  if(maxColumns>1){spreadsheet.deleteColumns(2, maxColumns-1);};
  var maxRows = spreadsheet.getActiveSheet().getMaxRows();
  if(maxRows>1) {spreadsheet.deleteRows(2, maxRows-1);};
  var ssh = ss.getSheetByName('TempAP');
  var dsh = ss.getSheetByName('Lupin Academy page');
  var srg = ssh.getRange(1,1,ssh.getLastRow(),ssh.getLastColumn());
  srg.copyTo(dsh.getRange(dsh.getLastRow() + 1, 1));

修复它(在四个选项卡中的三个选项卡上)的是交换代码的一部分,如下所示:

  var srg = ssh.getRange(1,1,ssh.getMaxRows(),ssh.getLastColumn());
  srg.copyTo(dsh.getRange(dsh.getLastRow() + 1, 1));

仅从源中使用 GetMaxRows 捕获了正确数量的空白行,并且 that 保留了目标上的格式 sheet.

但是,搜索选项卡仍然在做一件奇怪的事情。与模板相比,它增加了五行。奇怪的是它们不是空白的。它为每个人添加了一个复选框。如果我更改模板上的行数,它总是会在总数上增加五行。这不是交易破坏者,但我很想知道为什么。代码是:

  spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Student search page'), true);
  spreadsheet.getRangeList(['A1','B6']).clearFormat().clear({contentsOnly: true, skipFilteredRows: true});
  spreadsheet.getActiveSheet().setFrozenRows(0);
  var maxColumns = spreadsheet.getActiveSheet().getMaxColumns();
  if(maxColumns>1){spreadsheet.deleteColumns(2, maxColumns-1);};
  var maxRows = spreadsheet.getActiveSheet().getMaxRows();
  if(maxRows>1) {spreadsheet.deleteRows(2, maxRows-1);};
  var ssh = ss.getSheetByName('TempSP');
  var dsh = ss.getSheetByName('Student search page');
  var srg = ssh.getRange(1,1,ssh.getMaxRows(),ssh.getLastColumn());
  srg.copyTo(dsh.getRange(dsh.getLastRow() + 1, 1));
  spreadsheet.getRange('B6').setFormula('=iferror(query(\'Imported student list\'!A6:F,"Select A,B,C,D where LOWER(A) contains LOWER(\'"&B3&"\') LIMIT 30",0),"None")');
  spreadsheet.getActiveSheet().setColumnWidth(1, 80)
  .setColumnWidth(2, 240)
  .setColumnWidth(3, 80)
  .setColumnWidth(4, 220)
  .setColumnWidth(5, 370)
  .setFrozenRows(5);
  spreadsheet.getActiveSheet().protect().setUnprotectedRanges([spreadsheet.getRange('A6:A35'), spreadsheet.getRange('B3')])
  .setWarningOnly(true);

但是,如果我向包含文本的模板添加最后一行,则 CopyTo 函数会再添加五行完全空白的行。有任何想法吗?这太奇怪了:

我试过更改公式,更改公式在页面构建中的位置,这导致了有关越界列的错误消息。

function copyFromOneShtToAnother() {
  const ss = SpreadsheetApp.getActive();
  const sh = ss.getSheetByName('Sheet0');
  const dsh = ss.getSheetByName('Sheet1');
  const srg = sh.getRange(1,1,sh.getLastRow(),sh.getLastColumn());
  srg.copyTo(dsh.getRange(dsh.getLastRow() + 1, 1));
}