You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在关闭Dialog时更新Google Workspace Add-on的Card?

解决Google Apps Script中关闭Picker Dialog后更新Card的超时问题

问题背景

在Google Apps Script开发场景中,点击Card内按钮调用showDialog函数弹出集成Google Picker的模态Dialog,用于选择表格,需要实现关闭Dialog时更新Card的功能。此前尝试开发者元数据+循环检测的方案,但因Google的响应时间限制频繁触发超时错误,需寻求正确实现方式。

错误方案分析

之前的方案在showDialog中弹出Dialog后,试图通过循环检测开发者元数据来触发Card更新,但Google Apps Script服务端函数有严格的执行时间限制,这种同步轮询的方式会直接触发超时,且不符合Card Service的异步响应机制。

正确实现方案

核心思路:利用google.script.run的异步回调机制,在Picker选择完成后直接调用服务端的Card更新函数,通过返回ActionResponse完成Card更新。注意:showModalDialog是异步操作,服务端showDialog函数会立即返回,无法同步等待Dialog交互结果。

完整代码示例

服务端代码

// Card内按钮触发的函数,仅负责弹出Dialog
function showDialog() {
  const html = HtmlService.createHtmlOutputFromFile('dialog.html')
    .setWidth(600)
    .setHeight(425)
    .setSandboxMode(HtmlService.SandboxMode.IFRAME);
  SpreadsheetApp.getUi().showModalDialog(html, '选择表格');
}

// 客户端Picker回调触发的服务端函数,负责更新Card
function callback(selectedSpreadsheet) {
  // 根据选中的表格信息构建新Card
  const card = CardService.newCardBuilder()
    .setHeader(CardService.newCardHeader().setTitle('已选择表格'))
    .addSection(CardService.newCardSection()
      .addWidget(CardService.newTextParagraph().setText(`表格ID:${selectedSpreadsheet.id}\n表格名称:${selectedSpreadsheet.name}`)))
    .build();

  // 返回更新Card的响应
  return CardService.newActionResponseBuilder()
    .setNavigation(CardService.newNavigation().updateCard(card))
    .setNotification(CardService.newNotification().setText('导入成功'))
    .build();
}

// 用于获取OAuth令牌,供Google Picker使用
function getOAuthToken() {
  return ScriptApp.getOAuthToken();
}

dialog.html代码

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
  <script>
    let pickerApiLoaded = false;

    function onApiLoad() {
      gapi.load('picker', {'callback': () => {
        pickerApiLoaded = true;
        // 获取OAuth令牌,初始化Picker
        google.script.run.withSuccessHandler(createPicker)
          .getOAuthToken();
      }});
    }

    function createPicker(token) {
      if (pickerApiLoaded && token) {
        const picker = new google.picker.PickerBuilder()
          .addView(new google.picker.DocsView(google.picker.ViewId.SPREADSHEETS)
            .setMode(google.picker.DocsViewMode.LIST))
          .setOAuthToken(token)
          .setCallback(pickerCallback)
          .setTitle('选择要导入的表格')
          .build();
        picker.setVisible(true);
      } else {
        alert('无法加载文件选择器');
      }
    }

    function pickerCallback(data) {
      const action = data[google.picker.Response.ACTION];
      if (action == google.picker.Action.PICKED) {
        // 提取选中表格的关键信息
        const doc = data[google.picker.Response.DOCUMENTS][0];
        const selectedSpreadsheet = {
          id: doc[google.picker.Document.ID],
          name: doc[google.picker.Document.NAME]
        };
        // 调用服务端更新Card,成功后关闭Dialog
        google.script.run.withSuccessHandler(() => {
          google.script.host.close();
        }).callback(selectedSpreadsheet);
      } else if (action == google.picker.Action.CANCEL) {
        google.script.host.close();
      }
    }
  </script>
</head>
<body>
  <script src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
</html>

关键说明

  1. 异步回调逻辑:Picker选择完成后,通过google.script.run调用服务端callback函数,该函数返回ActionResponse触发Card更新,避免同步等待导致超时。
  2. Card更新机制:callback函数必须返回CardService.ActionResponse类型,Google Workspace会自动识别并更新对应的Card。
  3. Dialog关闭时机:使用withSuccessHandler确保服务端完成Card更新后再关闭Dialog,避免更新失败但Dialog已关闭的异常情况。

内容的提问来源于stack exchange,提问作者Hamu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 00:10:45