登記參加會議

程式碼程度:初學者
時間長度:5 分鐘
專案類型:使用自訂選單事件觸發條件的自動化功能

目標

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

認識這項解決方案

建立端對端活動報名系統。如果即將舉辦活動 (例如研討會),您可以為研討會議程設定新日曆、建立報名表單,並自動透過電子郵件傳送個人化行程給參與者。

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

運作方式

這個解決方案會使用 Google 試算表中的自訂選單,實作自動化活動註冊系統。這項指令碼會建立日曆,並列出 Google 試算表中的會議活動。接著,腳本會建立表單,列出與會者可報名的活動。與會者填寫表單後,指令碼會將他們新增至日曆活動,並透過電子郵件傳送行程。

Apps Script 服務

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

  • 試算表服務:向其他服務提供活動資訊。
  • 日曆服務:為活動建立新日曆、將活動新增至日曆,並將報名參加活動的使用者新增至活動。
  • 屬性服務:儲存日曆服務建立的日曆 ID。當使用者從自訂的「會議」選單點選「設定會議」時,屬性服務會檢查日曆 ID 屬性是否存在,藉此確認活動註冊系統是否已設定完成。這樣做有助於避免建立重複的表單和日曆。
  • 表單服務:根據試算表中的資訊建立表單,讓與會者報名參加課程。
  • 指令碼服務:建立觸發條件,在出席者填寫表單時觸發。
  • 文件服務:取得參與者註冊的活動事件資訊,並將活動清單新增至新文件中。這項指令碼會授予與會者編輯文件的權限。
  • 郵件服務:將行程文件以電子郵件傳送給與會者。

必要條件

如要使用這個範例,您必須符合下列先決條件:

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

設定指令碼

  1. 按一下下列按鈕,複製「在會議中建立課程註冊表」範例試算表。這個解決方案的 Apps Script 專案會附加至試算表。
    建立副本
  2. 依序點選「會議」「設定會議」。你可能需要重新整理頁面,自訂選單才會顯示。
  3. 出現提示訊息時,請授權執行指令碼。如果 OAuth 同意畫面顯示「這個應用程式未經驗證」警告,請依序選取「進階」>「前往『{專案名稱}』(不安全)」,繼續操作。

  4. 依序點選「會議」「再次設定會議」

執行指令碼

  1. 依序點選「工具」>「管理表單」 >「前往線上表單」
  2. 填寫並提交表單。
  3. 前往 calendar.google.com
  4. 在左側,確認已勾選「會議日曆」旁的方塊。
  5. 前往你報名的活動日期,確認自己已新增為參與者。

(選用) 重設解決方案

如要再次嘗試這個解決方案,或自訂解決方案以使用自己的事件資訊,您需要重設首次執行指令碼時設定的部分項目。如要查看重設解決方案的步驟,請按一下下方的「重設解決方案」

重設解決方案

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

如果嘗試多次執行指令碼,系統會顯示「Your conference is already set up. 請在 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. 在「Conference Form」上按一下滑鼠右鍵,然後依序點選「Remove」>「Move to trash」

重設解決方案後,您可以新增自己的資料,或繼續使用範例資料,然後再次執行指令碼。

檢查程式碼

如要查看這項解決方案的 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 開發人員專家協助。

後續步驟