将单个 Google 工作表 sheet 打印为 PDF 时保留公式引用

Preserve formula references when printing a single Google Sheets sheet to PDF

我想完成以下任务:

  1. 制作一个带有打印到 PDF 按钮的菜单。
  2. 让该按钮将 PDF 导出到与 google sheet.
  3. 具有相同名称和相同目标的位置

这很好用,但我发现我需要更改脚本,因为大多数人通过制作 sheet 的临时副本打印到 PDF,然后打印,最后删除临时副本。

我的原始文档中有来自其他 sheet 的引用,最终打印为 #REF! 值,因为只有一个 sheet被复制和打印,而不是我的整个文档。

我怎样才能使这个过程包括将公式烘焙为文本?

打印代码:

function onOpen() {
  var submenu = [{name: "Save PDF", functionName: "generatePdf"}];
  SpreadsheetApp.getActiveSpreadsheet().addMenu('Export', submenu);  
}

function generatePdf() {
  // Get active spreadsheet.
  var sourceSpreadsheet = SpreadsheetApp.getActive();

  // Get active sheet.
  var sheets = sourceSpreadsheet.getSheets();
  var sheetName = sourceSpreadsheet.getActiveSheet().getName();
  var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);

  // Set the output filename as sheetName.
  var pdfName = sheetName;

  // Get folder containing spreadsheet to save pdf in.
  var parents = DriveApp.getFileById(sourceSpreadsheet.getId()).getParents();
  if (parents.hasNext()) {
    var folder = parents.next();
  }
  else {
    folder = DriveApp.getRootFolder();
  }

  // Copy whole spreadsheet.
  var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(sourceSpreadsheet.getId()).makeCopy("tmp_convert_to_pdf", folder))

  // Delete redundant sheets.
  var sheets = destSpreadsheet.getSheets();
  for (i = 0; i < sheets.length; i++) {
    if (sheets[i].getSheetName() != sheetName){
      destSpreadsheet.deleteSheet(sheets[i]);
    }
  }

  var destSheet = destSpreadsheet.getSheets()[0];

  // Replace cell values with text (to avoid broken references).
  var sourceRange = sourceSheet.getRange(1, 1, sourceSheet.getMaxRows(), sourceSheet.getMaxColumns());
  var sourcevalues = sourceRange.getValues();
  var destRange = destSheet.getRange(1, 1, destSheet.getMaxRows(), destSheet.getMaxColumns());
  destRange.setValues(sourcevalues);

  // Save to pdf.
  var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
  var newFile = folder.createFile(theBlob);

  // Delete the temporary sheet.
  DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
}

将公式转换为文本的代码:

function formulasAsText() {
  var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
  for (var k = 0; k < sheets.length; k++) {
    var range = sheets[k].getDataRange();
    var values = range.getValues();
    var formulas = range.getFormulas();
    for (var i = 0; i < values.length; i++) {
      for (var j = 0; j < values[0].length; j++) {
        values[i][j] = formulas[i][j] ? "'" + formulas[i][j] : values[i][j];
      }
    }
    range.setValues(values);
  }
}

要维护公式引用,您需要修改 formulasAsText() 函数以接受输入,并且如果找到公式也不用担心编写公式。此输入可以是电子表格 ID - 即临时副本的 id - 或者它可以是 Sheet 个对象的数组。

完成这两项修改后,您将在删除临时副本中的 non-desired 工作表之前调用该函数:

/**
 * @param Sheet[] wbSheets     An array of Sheets to operate on.
 * @param String  toPreserve   The name of the sheet which should be preserved.
 */
function preserveFormulas(wbSheets, toPreserve) {
  if(!wbSheets || !wbSheets.length || !toPreserve)
    throw new Error("Missing arguments.");

  wbSheets.forEach(function (sheet) {
    if ( sheet.getName() === toPreserve ) {
      var range = sheet.getDataRange();
      // Serialize the cell's current value, be it static or derived from a formula.
      range.setValues(range.getValues());
    }
  });
}

完成我的脚本。这是我最终得到的结果。

function onOpen() {
  var submenu = [{name:"Save PDF", functionName:"generatePdf"}];
  SpreadsheetApp.getActiveSpreadsheet().addMenu('Export', submenu);  
}

function hideSheets() {

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet1 = ss.getSheetByName("sheet1");
  var sheet2 = ss.getSheetByName("PRINT SHEET");
  var sheet3 = ss.getSheetByName("sheet3");
  var sheet4 = ss.getSheetByName("sheet4");
  var sheet5 = ss.getSheetByName("sheet5");
  var sheet6 = ss.getSheetByName("sheet6");
  var sheet7 = ss.getSheetByName("sheet7");

  sheet1.hideSheet();
  sheet3.hideSheet();
  sheet4.hideSheet();
  sheet5.hideSheet();
  sheet6.hideSheet();
  sheet7.hideSheet();

}

function showSheets() {

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet1 = ss.getSheetByName("sheet1");
  var sheet2 = ss.getSheetByName("PRINT SHEET");
  var sheet3 = ss.getSheetByName("sheet3");
  var sheet4 = ss.getSheetByName("sheet4");
  var sheet5 = ss.getSheetByName("sheet5");
  var sheet6 = ss.getSheetByName("sheet6");
  var sheet7 = ss.getSheetByName("sheet7");

  sheet1.showSheet();
  sheet3.showSheet();
  sheet4.showSheet();
  sheet5.showSheet();
  sheet6.showSheet();
  sheet7.showSheet();

}

function generatePdf() {

  // Get active spreadsheet.
  var sourceSpreadsheet = SpreadsheetApp.getActive();

  // Get active sheet.
  var sheets = sourceSpreadsheet.getSheets();
  var sheetName = sourceSpreadsheet.getActiveSheet().getName();
  var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);

  // Set the output filename as BID and number (from cell C4).
  var pdfName = "BID " + sheets[0].getRange("C4").getValue() + ".pdf";


  var ui = SpreadsheetApp.getUi();

  // Get folder containing spreadsheet to save pdf in.
  var parents = DriveApp.getFileById(sourceSpreadsheet.getId()).getParents();
  if (parents.hasNext()) {
    var folder = parents.next();
  }
  else {
    folder = DriveApp.getRootFolder();
  }

  hideSheets();

  // Save to pdf.
  var theBlob = sourceSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
  var newFile = folder.createFile(theBlob);



  showSheets();
  ui.alert('Export finished');
}

谢谢。