登記參加會議

程式設計層級:新手
時間長度:5 分鐘
專案類型:使用自訂選單事件導向觸發條件進行自動化作業

目標

  • 瞭解解決方案的功能。
  • 瞭解 Apps Script 服務在解決方案中的功能。
  • 設定指令碼。
  • 執行指令碼。

認識這項解決方案

建立端對端活動登錄系統,如果您目前有即將舉行的活動 (例如會議),可以為會議時段設定新日曆、建立註冊表單,還可以自動透過電子郵件,將個人化的行程與會者傳送給參與者。

從 Google 試算表轉移至表單和日曆的資訊

運作方式

這項解決方案會使用 Google 試算表中的自訂選單,實作自動事件登錄系統。這個指令碼會建立日曆,並將活動會列於試算表試算表中。然後,這個指令碼會建立表單,列出參與者可以申請的活動清單。參與者填妥表單後,這個指令碼會將參與者新增至日曆活動,並透過電子郵件傳送行程給他們。

Apps Script 服務

這項解決方案使用下列服務:

  • 試算表服務:將事件資訊提供給其他服務。
  • 日曆服務:建立活動的新日曆、將活動新增至日曆,然後將參與者加入他們註冊的活動。
  • 屬性服務:儲存由日曆服務建立的日曆 ID。當使用者從自訂「會議」選單按一下「設定會議」時,屬性服務會檢查日曆 ID 屬性是否存在,藉此檢查事件登錄系統是否已設定完成。這樣做可以避免建立重複的表單和日曆。
  • 表單服務:根據試算表中的資訊建立表單,讓參與者註冊工作階段。
  • 指令碼服務:建立在有參與者填寫表單時觸發的觸發條件。
  • 文件服務:取得參與者註冊事件的事件資訊,並將事件清單新增至新文件。指令碼會將文件的編輯權限授予參與者。
  • 郵件服務:以電子郵件將行程文件傳送給參與者。

必要條件

如要使用這個範例,您必須具備以下必要條件:

  • Google 帳戶 (Google Workspace 帳戶可能需要取得管理員核准)。
  • 可連上網際網路的網路瀏覽器。

設定指令碼

  1. 點選下方按鈕,複製「Create a sign up for session of a meeting (會議中會議的工作階段)」範例試算表。這項解決方案的 Apps Script 專案已附加到試算表。
    建立副本
  2. 依序按一下「會議」>「設定會議」。您可能需要重新整理頁面,系統才會顯示這個自訂選單。
  3. 出現提示訊息時,請授權執行指令碼。如果 OAuth 同意畫面顯示警告「This app has not verification」(這個應用程式尚未驗證),請依序選取「Advanced」(進階) >「Go to {Project Name} (unsafe)」 (前往 {Project Name} (不安全))

  4. 按一下「會議」>「設定會議」

執行指令碼

  1. 依序點選「工具」>「管理表單」>「前往即時表單」
  2. 填寫並提交表單。
  3. 前往 calendar.google.com
  4. 確認左側的「會議日曆」旁邊的方塊已勾選。
  5. 前往報名活動的日期,確認您是該活動的參與者。

(選用) 重設解決方案

如果您想要再次嘗試使用這項解決方案,或是加以自訂以使用自己的事件資訊,則需要重設在首次執行指令碼時設定的項目。如要查看重設解決方案的步驟,請點選下方的「Reset the solution」

重設解決方案

步驟 1:重設已儲存的指令碼屬性

如果您嘗試多次執行指令碼,系統會提示您「會議已設定完成。」前往 Google 雲端硬碟尋找報名表單! 這是因為建立會議日曆後,系統會將日曆 ID 儲存為指令碼屬性。指令碼執行時,會檢查日曆 ID 屬性是否已存在,並在執行時停止執行。

請按照下列步驟移除現有的日曆 ID 資源:

  1. 在試算表中依序按一下「擴充功能」>「Apps Script」
  2. 在 Apps Script 編輯器中,從函式下拉式清單中選取 resetProperties,然後按一下「執行」

步驟 2:刪除會議日曆

每次執行指令碼時,系統都會建立新日曆。如果不想保留建立的原始日曆,請按照下列步驟操作:

  1. 前往 calendar.google.com
  2. 在「會議日曆」旁邊,依序按一下「會議日曆的選項」圖示 > 「設定和共用」
  3. 捲動至設定底部,然後按一下「刪除」

步驟 3:刪除表單提交觸發條件

每次執行指令碼時,指令碼都會建立觸發表單提交動作。為避免有多個觸發條件導致電子郵件重複,請移除原本的觸發條件。步驟如下:

  1. 在試算表中依序按一下「擴充功能」>「Apps Script」
  2. 在 Apps Script 專案中,按一下左側的「觸發條件」圖示
  3. 依序點選觸發條件旁的「更多」圖示 >「刪除觸發條件」

每次執行指令碼時,系統都會建立新表單。如要將表單與試算表取消連結並刪除,請按照下列步驟操作:

  1. 在試算表中,在「表單回應」工作表上按一下滑鼠右鍵,然後依序點選「取消表單連結」>>「確定」
  2. 再次在「表單回覆」工作表上按一下滑鼠右鍵,然後依序點選「刪除」 >「確定」
  3. 前往 forms.google.com
  4. 在「會議表單」上按一下滑鼠右鍵,然後依序點選「移除」>「移至垃圾桶」

重設解決方案之後,您可以自行新增資料,也可以繼續使用範例資料並重新執行指令碼。

查看程式碼

如要查看這項解決方案的 Apps Script 程式碼,請點選下方的「查看原始碼」

查看原始碼

Code.gs

solutions/automations/event-session-signup/Code.js
// To learn how to use this script, refer to the documentation:
// https://developers.google.com/apps-script/samples/automations/event-session-signup

/*
Copyright 2022 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * Inserts a custom menu when the spreadsheet opens.
 */
function onOpen() {
  SpreadsheetApp.getUi().createMenu('Conference')
      .addItem('Set up conference', 'setUpConference_')
      .addToUi();
}

/**
 * Uses the conference data in the spreadsheet to create
 * Google Calendar events, a Google Form, and a trigger that allows the script
 * to react to form responses.
 */
function setUpConference_() {
  let scriptProperties = PropertiesService.getScriptProperties();
  if (scriptProperties.getProperty('calId')) {
    Browser.msgBox('Your conference is already set up. Look in Google Drive for your'
                   + ' sign-up form!');
                   return;
  }
  let ss = SpreadsheetApp.getActive();
  let sheet = ss.getSheetByName('Conference Setup');
  let range = sheet.getDataRange();
  let values = range.getValues();
  setUpCalendar_(values, range);
  setUpForm_(ss, values);
  ScriptApp.newTrigger('onFormSubmit').forSpreadsheet(ss).onFormSubmit()
      .create();
}

/**
 * Creates a Google Calendar with events for each conference session in the
 * spreadsheet, then writes the event IDs to the spreadsheet for future use.
 * @param {Array<string[]>} values Cell values for the spreadsheet range.
 * @param {Range} range A spreadsheet range that contains conference data.
 */
function setUpCalendar_(values, range) {
  let cal = CalendarApp.createCalendar('Conference Calendar');
  // Start at 1 to skip the header row.
  for (let i = 1; i < values.length; i++) {
    let session = values[i];
    let title = session[0];
    let start = joinDateAndTime_(session[1], session[2]);
    let end = joinDateAndTime_(session[1], session[3]);
    let options = {location: session[4], sendInvites: true};
    let event = cal.createEvent(title, start, end, options)
        .setGuestsCanSeeGuests(false);
    session[5] = event.getId();
  }
  range.setValues(values);

  // Stores the ID for the Calendar, which is needed to retrieve events by ID.
  let scriptProperties = PropertiesService.getScriptProperties();
  scriptProperties.setProperty('calId', cal.getId());
}

/**
 * Creates a single Date object from separate date and time cells.
 *
 * @param {Date} date A Date object from which to extract the date.
 * @param {Date} time A Date object from which to extract the time.
 * @return {Date} A Date object representing the combined date and time.
 */
function joinDateAndTime_(date, time) {
  date = new Date(date);
  date.setHours(time.getHours());
  date.setMinutes(time.getMinutes());
  return date;
}

/**
 * Creates a Google Form that allows respondents to select which conference
 * sessions they would like to attend, grouped by date and start time in the
 * caller's time zone.
 *
 * @param {Spreadsheet} ss The spreadsheet that contains the conference data.
 * @param {Array<String[]>} values Cell values for the spreadsheet range.
 */
function setUpForm_(ss, values) {
  // Group the sessions by date and time so that they can be passed to the form.
  let schedule = {};
  // Start at 1 to skip the header row.
  for (let i = 1; i < values.length; i++) {
    let session = values[i];
    let day = session[1].toLocaleDateString();
    let time = session[2].toLocaleTimeString();
    if (!schedule[day]) {
      schedule[day] = {};
    }
    if (!schedule[day][time]) {
      schedule[day][time] = [];
    }
    schedule[day][time].push(session[0]);
  }

  // Creates the form and adds a multiple-choice question for each timeslot.
  let form = FormApp.create('Conference Form');
  form.setDestination(FormApp.DestinationType.SPREADSHEET, ss.getId());
  form.addTextItem().setTitle('Name').setRequired(true);
  form.addTextItem().setTitle('Email').setRequired(true);
  Object.keys(schedule).forEach(function(day) {
    let header = form.addSectionHeaderItem().setTitle('Sessions for ' + day);
    Object.keys(schedule[day]).forEach(function(time) {
      let item = form.addMultipleChoiceItem().setTitle(time + ' ' + day)
          .setChoiceValues(schedule[day][time]);
    });
  });
}

/**
 * Sends out calendar invitations and a
 * personalized Google Docs itinerary after a user responds to the form.
 *
 * @param {Object} e The event parameter for form submission to a spreadsheet;
 *     see https://developers.google.com/apps-script/understanding_events
 */
function onFormSubmit(e) {
  let user = {name: e.namedValues['Name'][0], email: e.namedValues['Email'][0]};

  // Grab the session data again so that we can match it to the user's choices.
  let response = [];
  let values = SpreadsheetApp.getActive().getSheetByName('Conference Setup')
      .getDataRange().getValues();
  for (let i = 1; i < values.length; i++) {
    let session = values[i];
    let title = session[0];
    let day = session[1].toLocaleDateString();
    let time = session[2].toLocaleTimeString();
    let timeslot = time + ' ' + day;

    // For every selection in the response, find the matching timeslot and title
    // in the spreadsheet and add the session data to the response array.
    if (e.namedValues[timeslot] && e.namedValues[timeslot] == title) {
      response.push(session);
    }
  }
  sendInvites_(user, response);
  sendDoc_(user, response);
}

/**
 * Add the user as a guest for every session he or she selected.
 * @param {object} user An object that contains the user's name and email.
 * @param {Array<String[]>} response An array of data for the user's session choices.
 */
function sendInvites_(user, response) {
  let id = ScriptProperties.getProperty('calId');
  let cal = CalendarApp.getCalendarById(id);
  for (let i = 0; i < response.length; i++) {
    cal.getEventSeriesById(response[i][5]).addGuest(user.email);
  }
}

/**
 * Creates and shares a personalized Google Doc that shows the user's itinerary.
 * @param {object} user An object that contains the user's name and email.
 * @param {Array<string[]>} response An array of data for the user's session choices.
 */
function sendDoc_(user, response) {
  let doc = DocumentApp.create('Conference Itinerary for ' + user.name)
      .addEditor(user.email);
  let body = doc.getBody();
  let table = [['Session', 'Date', 'Time', 'Location']];
  for (let i = 0; i < response.length; i++) {
    table.push([response[i][0], response[i][1].toLocaleDateString(),
      response[i][2].toLocaleTimeString(), response[i][4]]);
  }
  body.insertParagraph(0, doc.getName())
      .setHeading(DocumentApp.ParagraphHeading.HEADING1);
  table = body.appendTable(table);
  table.getRow(0).editAsText().setBold(true);
  doc.saveAndClose();

  // Emails a link to the Doc as well as a PDF copy.
  MailApp.sendEmail({
    to: user.email,
    subject: doc.getName(),
    body: 'Thanks for registering! Here\'s your itinerary: ' + doc.getUrl(),
    attachments: doc.getAs(MimeType.PDF),
  });
}

/**
 * Removes the calId script property so that the 'setUpConference_()' can be run again.
 */
function resetProperties(){
  let scriptProperties = PropertiesService.getScriptProperties();
  scriptProperties.deleteAllProperties();
}

貢獻者

本範例是由 Google 在 Google Developers 專家的協助下維護。

後續步驟