在Google日历中添加额外的全天事件。

huangapple go评论66阅读模式
英文:

Add Additional All-Day Events to Google Calendar

问题

基于Fernando Lara在这里的答案https://stackoverflow.com/questions/73322743/google-app-script-add-or-update-calendar-event/73325010#comment135147780_73325010,我正在尝试在Google日历上创建新事件。以下是我的脚本:

function updateCal(){
  var cal = CalendarApp.getCalendarById("CalendarID");
  var data = SpreadsheetApp.getActive().getSheetByName("Sheet1");
  const rows = data.getDataRange().getValues();
  rows.forEach(function(row, index){
    if (index === 0) return;
    var eventdate = data.getRange(index, 4, 1, 1).getValue();
    var eventtitle = data.getRange(index,1,1,1).getValue();
    var eventdescription = data.getRange(index,2,1,1).getValue();
    console.log(eventdate + eventtitle + eventdescription)
    const eventdate1 = new Date(eventdate)
    const events = cal.getEventsForDay(eventdate1);
    if (events.length == 0){          //错误在这一行
      cal.createAllDayEvent(eventtitle,eventdate1,{description: eventdescription});
    } else {
      ev = events[0];
      ev.setDescription(eventdescription)
    }

  })

}

上述脚本成功地添加了一个新事件或修改了现有事件的描述。然而,有一个主要缺陷。脚本不允许在已经存在事件的日期上创建另一个全天事件。我尝试手动从电子表格中删除原始事件,然后为同一天添加一个具有不同标题和不同描述的新事件。在Google日历上,标题保持不变,但描述发生了变化。

我认为下面这行代码是错误的,但我不确定如何修复它:

if (events.length == 0)

有人能指导我正确的方向吗?

流程顺序:

  • 此脚本由基于时间的触发器运行。
  • 管理员提交表单,如果员工缺勤、迟到或提前离开,则员工姓名是日历事件标题。详细信息(缺勤、迟到或提前离开)是描述。
  • 电子表格会筛选出仅查找给定日期的给定员工的最后一条记录。这样,如果员工的出勤状态发生变化,只会评估最后记录的状态。 (因此,我的脚本目前可以根据描述更新状态的重要性。)
  • 需要能够安排/记录同一天多名员工的出勤状态。(脚本目前无法执行此任务。)
  • 虽然可以通过在Google日历上手动输入来完成这项任务,但我正在使用链接到Google电子表格的Gravity Form。数据被输入和记录。使用电子表格可以更好地监控特定员工的出勤记录。
英文:

Based off of Fernando Lara's answer here https://stackoverflow.com/questions/73322743/google-app-script-add-or-update-calendar-event/73325010#comment135147780_73325010 I am trying to create new events on Google Calendar. Here is my script:

function updateCal(){
  var cal = CalendarApp.getCalendarById("CalendarID");
  var data = SpreadsheetApp.getActive().getSheetByName("Sheet1");
  const rows = data.getDataRange().getValues();
  rows.forEach(function(row, index){
    if (index === 0) return;
    var eventdate = data.getRange(index, 4, 1, 1).getValue();
    var eventtitle = data.getRange(index,1,1,1).getValue();
    var eventdescription = data.getRange(index,2,1,1).getValue();
    console.log(eventdate + eventtitle + eventdescription)
    const eventdate1 = new Date(eventdate)
    const events = cal.getEventsForDay(eventdate1);
    if (events.length == 0){          //The error was in this line
      cal.createAllDayEvent(eventtitle,eventdate1,{description: eventdescription});
    } else {
      ev = events[0];
      ev.setDescription(eventdescription)
    }

  })

}

The above script is successful at adding a new event or modifying an existing event if the description changes. There is one major flaw, however. The script does not allow for the creation of another all-day event on a day that already has an existing event. I tried deleting the original event from the spreadsheet manually and adding a new event for the same day with a different title and different description. The title remained the same on Google Calendar, but the description changed.

I believe this line below is incorrect, but I am not sure how to fix it:

if (events.length == 0)

Can anyone point me in the right direction?

Order of Process:

  • This script is run with a time-based trigger.
  • Managers submit form if employee is absent, late, or leaving early. The employee name is the Calendar event title. The details (absent, late, or leaving early) are the description.
  • Spreadsheet filters out responses to only find the last record of a given employee on a given date. That way, if an employee's attendance status changes, only the last recorded status is evaluated. (Therefore, the importance of being able to update status based on description which my script does currently.)
  • Need to be able to schedule/record the attendance status of multiple employees for the same day. (The script does not currently perform this task.)
  • While this could be done via manual entry on Google Calendar, I am using a Gravity Form linked to a Google spreadsheet. The data gets entered and recorded. A particular employee's attendance record can be better monitored with a spreadsheet.

答案1

得分: 2

修改点:

  • 从您的脚本中,如何检查事件标题?我猜您的目标可能可以通过检查事件日期和事件标题来实现。
  • 在您的脚本中,getValue() 在循环中使用。在这种情况下,处理成本会变得很高。

当这些点反映在您的脚本中时,以下修改如何?

修改后的脚本:

function updateCal() {
  var cal = CalendarApp.getCalendarById("CalendarID");
  var data = SpreadsheetApp.getActive().getSheetByName("Sheet1");
  const [, ...rows] = data.getDataRange().getValues();
  rows.forEach(([eventtitle, eventdescription, , eventdate]) => {
    console.log(eventdate + eventtitle + eventdescription)
    const eventdate1 = new Date(eventdate)
    const events = cal.getEventsForDay(eventdate1);
    if (events.length == 0 || (events.length > 0 && !events.some(e => e.getTitle() == eventtitle))) {
      cal.createAllDayEvent(eventtitle, eventdate1, { description: eventdescription });
    } else {
      ev = events[0];
      ev.setDescription(eventdescription)
    }
  });
}
  • 通过此修改,cal.createAllDayEvent 将通过检查事件日期和事件标题来运行。

  • 从您的脚本中,我猜您可能想跳过标题行。但是,如果您不想跳过它,请将 const [, ...rows] = data.getDataRange().getValues(); 修改为 const rows = data.getDataRange().getValues();

  • 如果您想检查描述,请将 if (events.length == 0 || (events.length > 0 && !events.some(e => e.getTitle() == eventtitle))) { 修改为 if (events.length == 0 || (events.length > 0 && !events.some(e => e.getTitle() == eventtitle) && !events.some(e => e.getDescription() == eventdescription))) {

添加部分:

根据您的以下回复,

但有一个大问题。当我在电子表格中更改事件的描述时,与以前一样,日历中的描述不会更改。

以下修改后的脚本如何?

function updateCal() {
  var cal = CalendarApp.getCalendarById("CalendarID");
  var data = SpreadsheetApp.getActive().getSheetByName("Sheet1");
  const [, ...rows] = data.getDataRange().getValues();
  rows.forEach(([eventtitle, eventdescription, , eventdate]) => {
    console.log(eventdate + eventtitle + eventdescription)
    const eventdate1 = new Date(eventdate)
    const events = cal.getEventsForDay(eventdate1);
    if (events.length == 0 || (events.length > 0 && !events.some(e => e.getTitle() == eventtitle) && !events.some(e => e.getDescription() == eventdescription))) {
      cal.createAllDayEvent(eventtitle, eventdate1, { description: eventdescription });
    } else {
      events.forEach(e => {
        if (e.getTitle() == eventtitle && e.getDescription() != eventdescription) {
          e.setDescription(eventdescription);
        }
      });
    }
  });
}
  • 根据您的回复,如果您当前的脚本是 rows.forEach(([eventtitle, eventdescription, eventdate]) => {,请将 rows.forEach(([eventtitle, eventdescription, , eventdate]) => { 修改为它。
英文:

Modification points:

  • From your script, how about checking the event title? I guessed that your goal might be able to be achieved by checking both the event date and the event title.
  • In your script, getValue() is used in a loop. In this case, the process cost will become high.

When these points are reflected in your script, how about the following modification?

Modified script:

function updateCal() {
  var cal = CalendarApp.getCalendarById("CalendarID");
  var data = SpreadsheetApp.getActive().getSheetByName("Sheet1");
  const [, ...rows] = data.getDataRange().getValues();
  rows.forEach(([eventtitle, eventdescription, , eventdate]) => {
    console.log(eventdate + eventtitle + eventdescription)
    const eventdate1 = new Date(eventdate)
    const events = cal.getEventsForDay(eventdate1);
    if (events.length == 0 || (events.length > 0 && !events.some(e => e.getTitle() == eventtitle))) {
      cal.createAllDayEvent(eventtitle, eventdate1, { description: eventdescription });
    } else {
      ev = events[0];
      ev.setDescription(eventdescription)
    }
  });
}
  • By this modification, cal.createAllDayEvent is run by checking both the event date and the event title.

  • In your script, I guessed that you might have wanted to skip the header row. But, if you don't want to skip it, please modify const [, ...rows] = data.getDataRange().getValues(); to const rows = data.getDataRange().getValues();.

  • If you want to check the description, please modify if (events.length == 0 || (events.length > 0 && !events.some(e => e.getTitle() == eventtitle))) { to if (events.length == 0 || (events.length > 0 && !events.some(e => e.getTitle() == eventtitle) && !events.some(e => e.getDescription() == eventdescription))) {.

Added:

From your following reply,

> One big problem, however. When I change the description of an event in the spreadsheet, the description does not change in the calendar as it did before.

How about the following modified script?

function updateCal() {
  var cal = CalendarApp.getCalendarById("CalendarID");
  var data = SpreadsheetApp.getActive().getSheetByName("Sheet1");
  const [, ...rows] = data.getDataRange().getValues();
  rows.forEach(([eventtitle, eventdescription, , eventdate]) => { // Now [eventtitle, eventdescription, eventdate] ?
    console.log(eventdate + eventtitle + eventdescription)
    const eventdate1 = new Date(eventdate)
    const events = cal.getEventsForDay(eventdate1);
    if (events.length == 0 || (events.length > 0 && !events.some(e => e.getTitle() == eventtitle) && !events.some(e => e.getDescription() == eventdescription))) {
      cal.createAllDayEvent(eventtitle, eventdate1, { description: eventdescription });
    } else {
      events.forEach(e => {
        if (e.getTitle() == eventtitle && e.getDescription() != eventdescription) {
          e.setDescription(eventdescription);
        }
      });
    }
  });
}
  • From your reply, if your current script is rows.forEach(([eventtitle, eventdescription, eventdate]) => {, please modify rows.forEach(([eventtitle, eventdescription, , eventdate]) => { to it.

答案2

得分: 1

以下是翻译好的部分:


注意:如果您认为您的问题被误解了,请澄清一下,并包含您数据的虚拟表格以及您实际期望的结果。

在我理解您的问题的基础上,这是您流程的步骤:

  1. 如果根据日期不存在员工,添加一个新事件。
  2. 如果现有员工有新的描述,更新事件。
  3. 重复步骤 1 和/或步骤 2 以处理其他具有相同日期的员工。

也许您可以尝试以下示例作为您实际项目的指南。此脚本将获取您的“Sheet1”中的所有数据,并遍历每一行数据。对于每一行数据,它将检索日期并根据日期获取当前事件。然后它会检查该行的员工是否已经存在。

如果员工尚不存在,它将被添加为一个新事件。另一方面,如果员工已经存在,脚本将更新现有事件。由于您使用的是表格,假设最新的数据按增量顺序在底部,如果有多次更新相同员工但具有不同的描述,将使用该员工在表格中的最后一条数据作为更新的事件数据。

示例调整后的脚本如下:

// 将此设置为全局变量以便轻松访问
const cal = CalendarApp.getCalendarById("■■■■■■■■■■■■■■■■■"); 

function updateCal() {
  var sheetData = SpreadsheetApp.getActive().getSheetByName('Sheet1').getDataRange().getValues();

  // 移除表头
  sheetData.shift();

  sheetData.forEach(row => {
    var events = getEvents(new Date(row[3]));
    events.length == 0 && addEvent(row[0], row[1], row[3]); // 如果基于日期没有事件,则添加第一个事件。
    var eventRecords = events.map(x => [x.getTitle(),x.getDescription(),x.getStartTime(),x.getId()]); // 作为数组获取基于日期的当前事件。
    var currentEvent = eventRecords.filter(x => x[0] == row[0]); // 检查当前行的员工是否已经有事件。
    console.log(`添加 "${row[0]}"?\n[${currentEvent.length == 0 ? addEvent(row[0],row[1],row[3]) : updateEvent(currentEvent[0][3],row[0],row[1],row[3]) }]\n描述: "${row[1]}"\n日期: "${row[3]}" `)});
}

function getEvents(date) {
  var events = cal.getEventsForDay(date);
  return events;
}

function updateEvent(eventID,title,eventDescription,date){
  var event = cal.getEventById(eventID);
  event.setDescription(eventDescription)
  event.setAllDayDate(new Date(date));
  return `"${title}" (id: ${eventID}) 已更新。`
}

function addEvent(title, eventDescription, date) {
  cal.createAllDayEvent(title, date, { description: eventDescription });
  return `"${title}" 已添加为新事件。`;
}

演示:

  • 虚拟的 "Sheet1":(例如,"John Appleseed"尚未添加,而另一个 "Jon Doe" 存在,但其描述已更新需要更新。)

  • 基于日期的当前日历事件:(目前包含 "Jon Doe",其描述设置为 "Late")

  • 运行 updateCal() 后:(显示供审查和阅读的日志。)

  • 新的更新后的日历事件:("Jon Doe"的描述已更新为 "Leaving Early",并且已添加 "John Appleseed")

英文:

Suggestion

> NOTE: If you think your question has been misinterpreted, kindly clarify it again and include a dummy sheet of your data and your actual desired results.

In my understanding of your question, here's the flow of your process:

  1. If an employee does not exist based on the date, add a new event.
  2. If an existing employee has a new description, update the event.
  3. Repeat step 1 and/or step 2 for the rest of the other employees with the same date.

Perhaps you could try the sample below as a guide for your actual project. This script will fetch all data from your Sheet1 and iterate through each row. For each row of data, it will retrieve the date and fetch the current events based on the date. It will then check if the row's employee already exists or not.

If the employee does not exist yet, it will be added as a new event. On the other hand, if the employee already exists, the script will update the existing event. Since you are using a sheet, assuming the most updated data is at the bottom in incremental order, if there are multiple updates for the same employee but with different descriptions, the very last data in the sheet for that employee will be used as the updated event data.

Sample Tweaked Script

> I have broken down your script into manageable pieces for maintainability.

//Set this as a global variable for easy access
const cal = CalendarApp.getCalendarById("■■■■■■■■■■■■■■■■■"); 
function updateCal() {
var sheetData = SpreadsheetApp.getActive().getSheetByName('Sheet1').getDataRange().getValues();
//remove sheet headers.
sheetData.shift();
sheetData.forEach(row => {
var events = getEvents(new Date(row[3]));
events.length == 0 && addEvent(row[0], row[1], row[3]); //Add the first event if the base 'date' has no events yet.
var eventRecords = events.map(x => [x.getTitle(),x.getDescription(),x.getStartTime(),x.getId()]);//get current events from the base 'date' as an array.
var currentEvent = eventRecords.filter(x => x[0] == row[0]);//Checks if the current row 'employee' already has an event or not yet.
console.log(`Add "${row[0]}"?\n[${currentEvent.length == 0 ? //If current event exists.
addEvent(row[0],row[1],row[3]) : //[true] add the event.
updateEvent(currentEvent[0][3],row[0],row[1],row[3]) //otherwise [false] update the current event
}]\nDescription: "${row[1]}"\nDate: "${row[3]}" `)});
}
function getEvents(date) {
var events = cal.getEventsForDay(date);
return events;
}
function updateEvent(eventID,title,eventDescription,date){
var event = cal.getEventById(eventID);
event.setDescription(eventDescription)
event.setAllDayDate(new Date(date));
return `"${title}" (id: ${eventID}) has been updated.`
}
function addEvent(title, eventDescription, date) {
cal.createAllDayEvent(title, date, { description: eventDescription });
return `"${title}" has been added as a New Event.`;
}

Demo

  • Dummy Sheet1:<br> (E.g. "John Appleseed" has not been added yet & another "Jon Doe" exists but has an updated description which needs to be updated.)

> 在Google日历中添加额外的全天事件。

  • Current calendar event based on date: <br> (It currently contains "Jon Doe" & its description is set to Late)

> 在Google日历中添加额外的全天事件。

  • After running theupdateCal(): <br> (Shows logs for review & readability.)

> 在Google日历中添加额外的全天事件。

  • The new updated calendar events: <br> (Jon Doe's Description has been updated to Leaving Early & John Appleseed has been added)

> 在Google日历中添加额外的全天事件。

Reference

huangapple
  • 本文由 发表于 2023年7月10日 23:55:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76655429.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定