Javascript 谷歌脚本:当特定单元格更改值时播放声音

Javascript 谷歌脚本:当特定单元格更改值时播放声音,javascript,audio,google-apps-script,google-sheets,Javascript,Audio,Google Apps Script,Google Sheets,情况: 表:支持 列:H具有以下函数“=IF(D:D>0;IF($B$1>=$G:G;“调用”;“及时”);”),该函数根据结果更改值 问题: 我需要: 当H列中的单元格在“支持”页上变为“调用”时播放声音 此功能需要每5分钟运行一次。 声音是否需要上传到硬盘,或者我可以使用URL中的声音 我将感谢任何能在这方面提供帮助的人。。。我看到了很多代码,但我不太理解。这是一个相当棘手的问题,但可以通过一个边栏定期轮询H列以了解更改 代码.gs // creates a custom menu w

情况:



表:支持
列:H具有以下函数“=IF(D:D>0;IF($B$1>=$G:G;“调用”;“及时”);”),该函数根据结果更改值

问题:

我需要:

  • 当H列中的单元格在“支持”页上变为“调用”时播放声音
  • 此功能需要每5分钟运行一次。
  • 声音是否需要上传到硬盘,或者我可以使用URL中的声音

  • 我将感谢任何能在这方面提供帮助的人。。。我看到了很多代码,但我不太理解。

    这是一个相当棘手的问题,但可以通过一个边栏定期轮询H列以了解更改

    代码.gs

    // creates a custom menu when the spreadsheet is opened
    function onOpen() {
      var ui = SpreadsheetApp.getUi()
        .createMenu('Call App')
        .addItem('Open Call Notifier', 'openCallNotifier')
        .addToUi();
    
      // you could also open the call notifier sidebar when the spreadsheet opens
      // if you find that more convenient
      // openCallNotifier();
    }
    
    // opens the sidebar app
    function openCallNotifier() {
      // get the html from the file called "Page.html"
      var html = HtmlService.createHtmlOutputFromFile('Page') 
        .setTitle("Call Notifier");
    
      // open the sidebar
      SpreadsheetApp.getUi()
        .showSidebar(html);
    }
    
    // returns a list of values in column H
    function getColumnH() {
      var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Support");
    
      // get the values in column H and turn the rows into a single values
      return sheet.getRange(1, 8, sheet.getLastRow(), 1).getValues().map(function (row) { return row[0]; });
    }
    
    Page.html

    <!DOCTYPE html>
    <html>
      <head>
        <base target="_top">
      </head>
      <body>
        <p id="message">Checking for calls...</p>
    
        <audio id="call">
          <source src="||a URL is best here||" type="audio/mp3">
          Your browser does not support the audio element.
        </audio>
    
        <script>
        var lastTime = []; // store the last result to track changes
    
        function checkCalls() {
    
          // This calls the "getColumnH" function on the server
          // Then it waits for the results
          // When it gets the results back from the server,
          // it calls the callback function passed into withSuccessHandler
          google.script.run.withSuccessHandler(function (columnH) {
            for (var i = 0; i < columnH.length; i++) {
    
              // if there's a difference and it's a call, notify the user
              if (lastTime[i] !== columnH[i] && columnH[i] === "Call") {
                notify();
              }
            }
    
            // store results for next time
            lastTime = columnH;
    
            console.log(lastTime);
    
            // poll again in x miliseconds
            var x = 1000; // 1 second
            window.setTimeout(checkCalls, x);
          }).getColumnH();
        }
    
        function notify() {
          document.getElementById("call").play();
        }
    
        window.onload = function () {
          checkCalls();
        }
    
        </script>
      </body>
    </html>
    
    
    

    检查呼叫


  • 递归调用checkCalls()最终导致错误,因为我实现了给出的主要答案(这基本上是正确的,非常有用,谢谢!)

    //注意:但是最初的实现可以正常工作一段时间,比如说90分钟,然后崩溃。通常需要1秒的调用将需要300秒,执行将停止。它看起来像是因为不断递归地调用自己而毁掉了堆栈。当移动到单次调用check()并正确退出函数时,它就会工作

    在运行JavaScript时登录Chrome的控制台说: ERR_QUIC_PROTOCOL_ERROR.QUIC_TOO_MANY_RTOS 200

    经过多次调查,我找到了一个更好的方法。。。它不需要递归(因此不会破坏堆栈)

    删除此行: //设置超时(checkCalls,500)

    并在脚本末尾使用如下内容:

      // This function returns a Promise that resolves after "ms" Milliseconds
    
            // The current best practice is to create a Promise...
      function timer(ms) {
       return new Promise(res => setTimeout(res, ms));
      }
    
      
      async function loopthis () { // We need to wrap the loop into an async function for the await call (to the Promise) to work.  [From web: "An async function is a function declared with the async keyword. Async functions are instances of the AsyncFunction constructor, and the await keyword is permitted within them. The async and await keywords enable asynchronous, promise-based behavior to be written in a cleaner style, avoiding the need to explicitly configure promise chains."]
        for (var i = 0; i >= 0; i++) {
          console.log('Number of times function has been run: ' + i);
          checkCalls();
          await timer(3000);
        }
      }
    
    
      window.onload = function () {
        loopthis();
      }
    
    </script>
    
    //此函数返回在“ms”毫秒后解析的承诺
    //目前的最佳实践是创造一个承诺。。。
    功能计时器(毫秒){
    返回新承诺(res=>setTimeout(res,ms));
    }
    异步函数loopthis(){//我们需要将循环包装成一个异步函数,以使wait调用(对Promise)工作。[来自web:“异步函数是使用async关键字声明的函数。异步函数是AsyncFunction构造函数的实例,其中允许使用await关键字。async和await关键字使基于承诺的异步行为能够以更简洁的样式编写,避免了显式配置承诺链的需要。”]
    对于(变量i=0;i>=0;i++){
    log('函数已运行的次数:'+i);
    checkCalls();
    等待定时器(3000);
    }
    }
    window.onload=函数(){
    loopthis();
    }
    
    Great正在工作……但我有一个问题,侧边栏不清楚声音何时结束。是否可能在声音结束时自动关闭?否,侧边栏需要保持打开状态,以便可以使用
    window.setTimeout(checkCalls,x)检查H列
    。也许你可以设计更多的侧边栏,添加更多的功能,这样用户就有更多的理由让它保持打开状态。Josh,我在google.script.host.close()中找到了这个功能,但我可以找到使用它的方法…声音需要2秒钟才能运行…我正在试图找到执行google.script.host.close()的方法5秒后…此功能关闭侧边栏使用一个事件处理程序,在音频播放结束时触发:我找到了代码…是否有任何方式可以使音频发出声音,即使它不在打开电子表格的浏览器翻盖中?因为它只会在我打开电子表格的翻盖上发出声音。