簡體   English   中英

獲取function外的變量值創建文件

[英]Get the value of the variable outside the function to create a file

我想知道如何返回在createOrGetFolder function 之外的folder變量中創建的文件夾的名稱,目的是能夠創建一個與創建的文件夾同名的文件,在此代碼中:

const saveDataAsCSV = (data, folderId) => DriveApp.getFolderById(folderId).createFile(folder, data);

這是.gs文件中的完整代碼:

/**
* Modified script written by Tanaike and CharlesPlucker
*
* Additional Script by Tyrone
* version 20.01.2023.1
*/

        function doGet(e) {
          return HtmlService.createTemplateFromFile('forms0101.html').evaluate();
        }
        
        
        function getOAuthToken() {
          return ScriptApp.getOAuthToken();
        }
        
        
        function getParent(){
          var ss = SpreadsheetApp.getActiveSpreadsheet();
          var id = ss.getId();
          var parent = DriveApp.getFileById(id).getParents().next().getId();
          return parent
        }
        
        function getLimitFolder(){
          var ss = SpreadsheetApp.getActiveSpreadsheet();
          var pastapai = DriveApp.getFileById(ss.getId()).getParents();
          var limitfolder = pastapai.next().getFoldersByName("_").next().getId();
          return limitfolder
        }
        
        /**
        * creates a folder under a parent folder, and returns it's id. If the folder already exists
        * then it is not created and it simply returns the id of the existing one
        */
        
        function createOrGetFolder(folderName, parentFolderId) {
          try {
            var parentFolder = DriveApp.getFolderById(parentFolderId), folder;
            if (parentFolder) {
              var foldersIter = parentFolder.getFoldersByName("Video");
              if (foldersIter.hasNext()) {
                var videoFolder = foldersIter.next();
                var nextFolderName = folderName + "-01";
                while (!folder) {
                  video_folder = videoFolder.getFoldersByName(nextFolderName);
                  if (video_folder.hasNext()) {
                    folder = video_folder.next();
                    var files = folder.getFiles();
                    if (files.hasNext()) {
                      var [a, b] = nextFolderName.split("-");
                      nextFolderName = `${a}-${String(Number(b) + 1).padStart(2, "0")}`;
                      folder = null;
                    }
                  } else {
                    folder = videoFolder.createFolder(nextFolderName);
                  }
                }
              } else {
                folder = parentFolder.createFolder("Video");
                folder = folder.createFolder(folderName);
              }
            } else {
              throw new Error("Parent Folder with id: " + parentFolderId + " not found");
            }
            return folder.getId();
          } catch (error) {
            return error;
          }
        }
        
        const saveDataAsCSV = (data, folderId) => DriveApp.getFolderById(folderId).createFile("Sample.csv", data);
    
    
    // NOTE: always make sure we use DriveApp, even if it's in a comment, for google to import those
    // libraries and allow the rest of the app to work. see https://github.com/tanaikech/Resumable_Upload_For_WebApps

請注意,在const saveDataAsCSV中,當前文件創建名稱為Sample.csv ,這是我要應用 function createOrGetFolder(folderName, parentFolderId)中的folder變量的地方

這是HTML文件的完整代碼:

/**
* Modified script written by Tanaike and CharlesPlucker
*
* Additional Script by Tyrone
* version 20.01.2023.1
*/

<!DOCTYPE html>
<html>
  <head>
    <base target="_blank">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Drive Multi Large File Upload</title>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css">
     
     <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

    <style>
      @import url('https://fonts.googleapis.com/css2?family=Rubik:wght@400;600;700&display=swap');
      
      .disclaimer{
        width: 480px; 
        color: #646464;
        margin: 20px auto;
        padding:0 16px;
        text-align:center;
        font:400 12px Rubik,sans-serif;
        }

      h5.center-align.teal-text {
        font:700 26px Rubik,sans-serif;
        color: #00F498!important;
      }

      .row {
        font:600 14px Rubik,sans-serif;
      }

      .btn {
        background-color: black;
      }

      .btn:hover {
        background-color: #00F498;
      }

      body {
        margin-top: -40px;
      }

      #progress {
        color: #00000;
      }
      
      .disclaimer a{
        color: #00BCAA;
        }

      #credit{
        display:none
        }
    </style>
  </head>
  <body>
    <form class="main" id="form" novalidate="novalidate" style="max-width: 480px;margin: 40px auto;">
 <div id="forminner">
  <h5 class="center-align teal-text" style="margin-bottom: -10px; font-size: 20px; font-family: Rubik; ">YOUR NAME</h5>
    <div class="row">
          <div class="input-field col s12">
            <input id="name01" type="text" name="Name" class="validate" required="required" aria-required="true">
            <label for="name" class="">Name</label>
          </div>
        </div>
    
      <h5 class="center-align teal-text" style="margin-bottom: -10px; font-size: 20px; font-family: Rubik; ">SOME DESCRIPTION</h5>
        <div class="row">
          <div class="input-field col s12">
            <input id="description" type="text" name="Description" class="validate" required="required" aria-required="true">
            <label for="name">Description</label>
          </div>
        </div>

    <div class="row">
      <div class="col-8 col-md-4">
        <h6>Model</h6>       
        <select class="custom-select" id="Model">
          <option selected="">Choose...</option>
          <option value="01">01</option>
          <option value="02">02</option>
          <option value="03">03</option>
        </select> 
          &nbsp;

        <h6>Color</h6>        
        <select class="custom-select" id="Color">
          <option selected="">Choose...</option>
          <option value="Red">Red</option>
          <option value="Green">Green</option>
        </select>   
      </div>
  </div>

    
        <div class="row">
          <div class="col s12">
            <h5 class="center-align teal-text">Upload the Video File</h5>
           
          </div>
        </div>
        
        <div class="row">
          <div class="file-field input-field col s12">
            <div id="input-btn" class="btn">
              <span>File</span>
              <input id="files" type="file" single="">
            </div>
            <div class="file-path-wrapper">
              <input class="file-path validate" type="text" placeholder="Select the file">
            </div>
          </div>
        </div>

        <div class="row">
          <div class="input-field col s6">
            <button id="submit-btn" class="waves-effect waves-light btn submit-btn" type="submit" onclick="submitForm(); return false;">Submit</button>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12 hide" id="update">
            <hr>
            <p>
              Por favor, aguarde enquanto seu arquivo está sendo carregado.<br><span style="color: #00000;"><b>Não feche ou atualize a janela durante o upload.</b></span>
            </p>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12" id="progress">
          </div>
        </div>
      </div>
     </div> 
      <div id="success" style="display:none">
        <h5 class="center-align teal-text">Tudo certo!</h5>
        <p>Se você já preencheu todos os campos é só fechar essa janela e clicar em enviar!</p>
        <button id="fechar" class="waves-effect waves-light btn submit-btn" style ="transform: translateX(160%);" type="button" onclick="google.script.host.close()">Fechar</button>
      </div>
    </form>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script>
    <script src="https://gumroad.com/js/gumroad.js"></script>

    <script>

      var upload_folder = "01";
      const chunkSize = 5242880;
      const uploadParentFolderId = <?=getParent()?>; // creates a folder inside of this folder
      const limitfolder = <?=getLimitFolder()?>;

      function closer(){
        google.script.host.close();
      }

      function submitForm() {

        // Added the below script.
        if ($('#submit-btn.disabled')[0]) return; // short circuit

        var name = upload_folder
        var files = [...$('#files')[0].files]; // convert from FileList to array

        
        if (files.length === 0) {
          showError("Por favor, selecione um arquivo");
          return;
        }

        var name = $('#name01').val();
        var description = $('#description').val();
        var model = $('#Model').val();
        upload_folder = model;
        var color = $('#Color').val();
        var form_values = [name, description, model, color];
        form_values = form_values.map(r => r.replaceAll(",", "#")); // Essa linha substitui todas as "," por "#" antes de gerar o .csv
        var data = form_values.join(",");
        google.script.run.saveDataAsCSV(data, uploadParentFolderId);
        google.script.run.saveDataAsCSV(data, limitfolder);

        disableForm(); // prevent re submission

        // the map and reduce are here to ensure that only one file is uploaded at a time. This allows
        // the promises to be run sequentially
        files.map(file => uploadFilePromiseFactory(file))
            .reduce((promiseChain, currentTask) => {
              return promiseChain.then(currentTask);
            }, Promise.resolve([])).then( () => {
              console.log("Completed all files upload");
              showSuccess();
            });
      }

      function disableForm() {
        $('#submit-btn').addClass('disabled');
        $('#input-btn').addClass('disabled');
        $('#update').removeClass('hide');
         $('#update').removeClass('hide');
      }

      function uploadFilePromiseFactory(file) {
        return () => {
          console.log("Processing: ", file.name);
          return new Promise((resolve, reject) => {

            showProgressMessage("Seu arquivo está sendo carregado");

            var fr = new FileReader();
            fr.fileName = file.name;
            fr.fileSize = file.size;
            fr.fileType = file.type;
            // not sure of a better way of passing the promise functions down
            fr.resolve = () => resolve();
            fr.reject = (error) => reject(error);
            fr.onload = onFileReaderLoad;
            fr.readAsArrayBuffer(file);
          });
        };
      }
      
      /**
       * Gets called once the browser has loaded a file. The main logic that creates a folder
       * and initiates the file upload resides here
       */
      function onFileReaderLoad(onLoadEvent) {
        var fr = this;

        var newFolderName = upload_folder
        createOrGetFolder(newFolderName, uploadParentFolderId).then(newFolderId => {
          console.log("Found or created guest folder with id: ", newFolderId);
          uploadFileToDriveFolder.call(fr, newFolderId).then(() => {
              fr.resolve();
            }, (error) => {
              fr.reject(error);
            });
          },
          (error) => {
            if (error) {
              showError(error.toString());
            }
            console.log("onFileReaderLoad Error2: ", error);
          });

      }

      /**
       * call to the DriveApp api. Wrapped in a promise in case I want to address timing issues between a
       * createFolder and findFolderById
       */
      function createOrGetFolder(folderName, parentFolderId) {
        return new Promise((resolve, reject) => {
          google.script.run.withSuccessHandler(response => {
            console.log("createOrGetFolder response: ", response);
            if (response && response.length) {
              resolve(response);
            }
            reject(response);
          }).createOrGetFolder(folderName, parentFolderId);
        });
      }

      /**
      * Helper functions modified from:
      * https://github.com/tanaikech/Resumable_Upload_For_WebApps
      */
      function uploadFileToDriveFolder(parentFolderId) {
        var fr = this;
        return new Promise((resolve, reject) => {
          var fileName = fr.fileName;
          var fileSize = fr.fileSize;
          var fileType = fr.fileType;
          console.log({fileName: fileName, fileSize: fileSize, fileType: fileType});
          var buf = fr.result;
          var chunkpot = getChunkpot(chunkSize, fileSize);
          var uint8Array = new Uint8Array(buf);
          var chunks = chunkpot.chunks.map(function(e) {
            return {
               data: uint8Array.slice(e.startByte, e.endByte + 1),
               length: e.numByte,
               range: "bytes " + e.startByte + "-" + e.endByte + "/" + chunkpot.total,
            };
          });
          google.script.run.withSuccessHandler(oAuthToken => {
            var xhr = new XMLHttpRequest();
            xhr.open("POST", "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable");
            xhr.setRequestHeader('Authorization', "Bearer " + oAuthToken);
            xhr.setRequestHeader('Content-Type', "application/json");
            xhr.send(JSON.stringify({
              mimeType: fileType,
              name: fileName,
              parents: [parentFolderId]
            }));
            xhr.onload = () => {
              doUpload(fileName, {
                location: xhr.getResponseHeader("location"),
                chunks: chunks,
              }).then(success => {
                resolve(success);
                console.log("Successfully uploaded: ", fileName);
              },
              error => {
                reject(error);
              });
            };

            xhr.onerror = () => {
              console.log("ERROR: ", xhr.response);
              reject(xhr.response);
            };
          }).getOAuthToken();
        });
      }

      function showSuccess() {
        $('#forminner').hide();
        $('#success').show();
        $('#fechar').show();
      }

      function showError(e) {
        $('#progress').addClass('red-text').html(e);
      }

      function showMessage(e) {
        $('#update').html(e);
      }

      function showProgressMessage(e) {
        $('#progress').removeClass('red-text').html(e);
      }

      /**
      * Helper functions modified from:
      * https://github.com/tanaikech/Resumable_Upload_For_WebApps
      */
      function doUpload(fileName, e) {
        return new Promise((resolve, reject) => {
          showProgressMessage("Carregando: <span style='color: #00F498 ;'>" + "0%</span>");
          var chunks = e.chunks;
          var location = e.location;
          var cnt = 0;
          var end = chunks.length;
          var temp = function callback(cnt) {
            var e = chunks[cnt];
            var xhr = new XMLHttpRequest();
            xhr.open("PUT", location, true);
            console.log("content range: ", e.range);
            xhr.setRequestHeader('Content-Range', e.range);
            xhr.send(e.data);
            xhr.onloadend = function() {
                var status = xhr.status;
                cnt += 1;
                console.log("Uploading: " + status + " (" + cnt + " / " + end + ")");
                showProgressMessage("Carregando: <span style='color: #00F498 ;'>" 
                       + Math.floor(100 * cnt / end) + "%</span>" );
                if (status == 308) {
                    callback(cnt);
                } else if (status == 200) {
                    $("#progress").text("Done.");
                    resolve();
                } else {
                    $("#progress").text("Error: " + xhr.response);
                    reject();
                }
            };
          }(cnt);
        });
      }

      /**
      * Helper functions modified from:
      * https://github.com/tanaikech/Resumable_Upload_For_WebApps
      */
      function getChunkpot(chunkSize, fileSize) {
        var chunkPot = {};
        chunkPot.total = fileSize;
        chunkPot.chunks = [];
        if (fileSize > chunkSize) {
            var numE = chunkSize;
            var endS = function(f, n) {
                var c = f % n;
                if (c == 0) {
                    return 0;
                } else {
                    return c;
                }
            }(fileSize, numE);
            var repeat = Math.floor(fileSize / numE);
            for (var i = 0; i <= repeat; i++) {
                var startAddress = i * numE;
                var c = {};
                c.startByte = startAddress;
                if (i < repeat) {
                    c.endByte = startAddress + numE - 1;
                    c.numByte = numE;
                    chunkPot.chunks.push(c);
                } else if (i == repeat && endS > 0) {
                    c.endByte = startAddress + endS - 1;
                    c.numByte = endS;
                    chunkPot.chunks.push(c);
                }
            }
        } else {
            var chunk = {
                startByte: 0,
                endByte: fileSize - 1,
                numByte: fileSize,
            };
            chunkPot.chunks.push(chunk);
        }
        return chunkPot;
      }

    </script>

  </body>

</html>

由於folder沒有var前綴,我認為它應該可以工作,因為理論上這使它成為一個全局變量......但是我仍然在控制台中收到folder is undefined的消息。

我還嘗試在文件創建代碼之前調用 function,如下所示:

createOrGetFolder(folderName, parentFolderId);
const saveDataAsCSV = (data, folderId) => DriveApp.getFolderById(folderId).createFile(folder, data);

但是這樣我得到消息folderName is undefined.


根據The WizEd answer's comments中的建議,這是我最后一次嘗試:

.gs文件中的修改摘錄:

const saveDataAsCSV = (data, folderId) => DriveApp.getFolderById(folderId).createFile(newFolderId, data);

HTML文件中的修改摘錄:

       var newFolderId = "";
      /**
       * call to the DriveApp api. Wrapped in a promise in case I want to address timing issues between a
       * createFolder and findFolderById
       */
      function createOrGetFolder(folderName, parentFolderId) {
        return new Promise((resolve, reject) => {
          google.script.run.withSuccessHandler(response => {
            console.log("createOrGetFolder response: ", response);
            if (response && response.length) {
              resolve(response);
            }
            reject(response);
          }).createOrGetFolder(folderName, parentFolderId);
          newFolderId = createOrGetFolder(folderName, parentFolderId);
        });
      }

這樣我仍然無法獲得創建或使用的文件夾的名稱......

我哪里錯了?

全局變量不是持久的。 這意味着當執行 function 時,實例會創建全局變量,但會在 function 或 function 鏈完成時釋放它。

這里func1()調用func2()所以全局變量的實例被保留。

但是,如果我在運行 func1( func2()之后自行運行func1() ,它將重置為空白

運行 func1()

var globalVariable = "";

function func1 () {
  try {
    console.log("globalVariable in func1 = ["+globalVariable+"]")
    globalVariable = "Hello";
    func2();
    console.log("globalVariable from func2 = ["+globalVariable+"]")
  }
  catch(err) {
    console.log("Error in func1: "+err);
  }
}

function func2 () {
  try {
    console.log("globalVariable in func2 = ["+globalVariable+"]")
    globalVariable = "Good bye";
  }
  catch(err) {
    console.log("Error in func2: "+err);
  }
}

11:53:15 AM Notice  Execution started
11:53:17 AM Info    globalVariable in func1 = []
11:53:17 AM Info    globalVariable in func2 = [Hello]
11:53:17 AM Info    globalVariable from func2 = [Good bye]
11:53:16 AM Notice  Execution completed

現在運行 func2()

11:57:38 AM Notice  Execution started
11:57:39 AM Info    globalVariable in func2 = []
11:57:39 AM Notice  Execution completed

要將 globalVariable 的值從一次執行保存到下一次執行,您需要使用PropertyService

您已經使用 Google Apps 腳本創建了一個 web 應用程序。 客戶端代碼調用服務器端 function createOrGetFolder 您希望此 function 返回分配給folder變量的文件夾 object 的名稱。

目前服務器端 function createOrGetFolder成功返回文件夾 id ( return folder.getId(); )。

要獲取文件夾名稱,您可以使用folder.getName()但更改此 function 的返回意味着對客戶端代碼進行更改。

一種選擇是添加客戶端 function 以獲取文件夾名稱。 這可以通過使用當前返回createOrGetFolder的文件夾 ID 調用服務器端 function 來完成。 另一種方法是,讓createOrGetFolder使用屬性服務、緩存服務或其他存儲文件夾名稱來存儲文件夾名稱,然后使用客戶端 function 檢索此值。 在這兩個選項中,對 html / gs 文件的更改很可能是最小的,但這不會為您的 web 應用程序提供最佳的整體性能,因為 Google Apps 腳本服務很慢。

另一種選擇是更改createOrGetFolder function 回報,但這意味着要花時間研究客戶端代碼和更改多行代碼,在程序員時間上可能比第一種選擇更昂貴,但可能保證您的 web 應用程序將具有最佳通過將對 Google Apps 腳本服務的調用保持在最低限度來提高整體性能。

資源

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM