У меня есть несколько сотрудников, которые вводят свой день в календарь очков, а я беру данные и веду статистику. На данный момент я могу брать данные только из одного календаря за раз. Как мне взять этот скрипт и заставить его работать на нескольких календарях?
Обратите внимание, что у каждого календаря есть свой целевой лист. Я пытался продублировать сценарий, но работает только одна версия.
function export_gcal_to_gsheet() {
var mycal = "person email";
var cal = CalendarApp.getCalendarById(mycal);
var events = cal.getEvents(new Date("July 01, 2022 00:00:00 UTC"), new Date());
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("PersonCalendar");
sheet.clearContents();
var calColor = cal.getColor();
var colors = Calendar.Colors.get().calendar;
var header = ["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event", "Color"];
var offset = 6;
var { v, c } = events.reverse().reduce((o, e, i) => {
var color = e.getColor();
var row = offset + i + 1;
var c = colors[color] ? colors[color].background : calColor;
var f = `=(HOUR(F${row})+(MINUTE(F${row})/60))-(HOUR(E${row})+(MINUTE(E${row})/60))`;
o.v.push([mycal, events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), f, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent(), c]);
o.c.push([c]);
return o;
}, { v: [], c: [] });
var values = [header, ...v];
sheet.getRange(6, 1, values.length, values[0].length).setValues(values);
sheet.getRange(7, 7, v.length - 1).setNumberFormat('.00');
sheet.getRange(7, 15, c.length).setBackgrounds(c);
}
В вашем сценарии используется только один идентификатор календаря. Чтобы использовать несколько идентификаторов календаря, когда ваш сценарий показа изменен для использования нескольких идентификаторов календаря, как насчет следующей модификации?
В этой модификации все значения вынесены на лист "PersonCalendar".
function export_gcal_to_gsheet() {
var calendarIds = ["person email1", "person email2",,,]; // Please set your Calendar IDs.
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("PersonCalendar");
sheet.clearContents();
var header = ["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event", "Color"];
var colors = Calendar.Colors.get().calendar;
var { vv, cc } = calendarIds.reduce((oo, mycal) => {
var cal = CalendarApp.getCalendarById(mycal);
var events = cal.getEvents(new Date("July 01, 2022 00:00:00 UTC"), new Date());
var calColor = cal.getColor();
var offset = 6;
var { v, c } = events.reverse().reduce((o, e, i) => {
var color = e.getColor();
var row = offset + i + 1;
var c = colors[color] ? colors[color].background : calColor;
var f = `=(HOUR(F${row})+(MINUTE(F${row})/60))-(HOUR(E${row})+(MINUTE(E${row})/60))`;
o.v.push([mycal, events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), f, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent(), c]);
o.c.push([c]);
return o;
}, { v: [], c: [] });
oo.vv = [...oo.vv, ...v];
oo.cc = [...oo.cc, ...c];
return oo;
}, { vv: [], cc: [] });
var values = [header, ...vv];
sheet.getRange(6, 1, values.length, values[0].length).setValues(values);
sheet.getRange(7, 7, vv.length - 1).setNumberFormat('.00');
sheet.getRange(7, 15, cc.length).setBackgrounds(cc);
}
В этой модификации значения каждого календаря вынесены на каждый лист.
function export_gcal_to_gsheet() {
var obj = [{ mycal: "person email1", sheetName: "PersonCalendar" }];
var colors = Calendar.Colors.get().calendar;
var ss = SpreadsheetApp.getActiveSpreadsheet();
obj.forEach(({ mycal, sheetName }) => {
var cal = CalendarApp.getCalendarById(mycal);
var events = cal.getEvents(new Date("July 01, 2022 00:00:00 UTC"), new Date());
var sheet = ss.getSheetByName(sheetName);
sheet.clear(); // or sheet.clearContents();
var calColor = cal.getColor();
var header = ["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event", "Color"];
var offset = 6;
var { v, c } = events.reverse().reduce((o, e, i) => {
var color = e.getColor();
var row = offset + i + 1;
var c = colors[color] ? colors[color].background : calColor;
var f = `=(HOUR(F${row})+(MINUTE(F${row})/60))-(HOUR(E${row})+(MINUTE(E${row})/60))`;
o.v.push([mycal, events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), f, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent(), c]);
o.c.push([c]);
return o;
}, { v: [], c: [] });
var values = [header, ...v];
sheet.getRange(6, 1, values.length, values[0].length).setValues(values);
sheet.getRange(7, 7, v.length - 1).setNumberFormat('.00');
sheet.getRange(7, 15, c.length).setBackgrounds(c);
});
}
В этой модификации значения каждого календаря вынесены на каждый лист. А при использовании Sheets API стоимость процесса немного снижается по сравнению с «Измененным скриптом 2». Итак, пожалуйста, включите Sheets API в расширенных сервисах Google.
function export_gcal_to_gsheet() {
var obj = [{ mycal: "person email1", sheetName: "PersonCalendar" },,,]; // Please set calendar IDs and sheet names.
var colors = Calendar.Colors.get().calendar;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var { valuesBatchUpdate, batchUpdate } = obj.reduce((oo, { mycal, sheetName }) => {
var cal = CalendarApp.getCalendarById(mycal);
var calColor = cal.getColor();
var events = cal.getEvents(new Date("July 01, 2022 00:00:00 UTC"), new Date());
var header = ["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event", "Color"];
var offset = 6;
var { v, c } = events.reverse().reduce((o, e, i) => {
var color = e.getColor();
var row = offset + i + 1;
var c = colors[color] ? colors[color].background : calColor;
var f = `=(HOUR(F${row})+(MINUTE(F${row})/60))-(HOUR(E${row})+(MINUTE(E${row})/60))`;
o.v.push([mycal, events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), (events[i].getStartTime().getTime() / 1000 / 86400) + 25569, (events[i].getEndTime().getTime() / 1000 / 86400) + 25569, f, ('' + events[i].getVisibility()), (events[i].getDateCreated().getTime() / 1000 / 86400) + 25569, (events[i].getLastUpdated().getTime() / 1000 / 86400) + 25569, events[i].getMyStatus().toString(), events[i].getCreators().join(","), events[i].isAllDayEvent(), events[i].isRecurringEvent(), c]);
o.c.push([c]);
return o;
}, { v: [], c: [] });
var sheetId = ss.getSheetByName(sheetName).getSheetId();
var hexToRgb = hex => { // Ref: https://stackoverflow.com/a/11508164
var bigint = parseInt(hex, 16);
var red = ((bigint >> 16) & 255) / 255;
var green = ((bigint >> 8) & 255) / 255;
var blue = (bigint & 255) / 255;
return { red, green, blue }
};
oo.valuesBatchUpdate.push({ range: `'${sheetName}'!A6`, values: [header, ...v] });
oo.batchUpdate.push(
{ updateCells: { fields: "*", range: { sheetId } } },
{ repeatCell: { range: { sheetId, startRowIndex: 6, endRowIndex: 6 + v.length, startColumnIndex: 6, endColumnIndex: 7 }, cell: { userEnteredFormat: { numberFormat: { pattern: '.00', type: "NUMBER" } } }, fields: "userEnteredFormat.numberFormat" } },
{ repeatCell: { range: { sheetId, startRowIndex: 6, endRowIndex: 6 + v.length, startColumnIndex: 4, endColumnIndex: 6 }, cell: { userEnteredFormat: { numberFormat: { pattern: 'yyyy/MM/dd', type: "DATE" } } }, fields: "userEnteredFormat.numberFormat" } },
{ repeatCell: { range: { sheetId, startRowIndex: 6, endRowIndex: 6 + v.length, startColumnIndex: 8, endColumnIndex: 10 }, cell: { userEnteredFormat: { numberFormat: { pattern: 'yyyy/MM/dd', type: "DATE" } } }, fields: "userEnteredFormat.numberFormat" } },
{ updateCells: { rows: c.map(([hex]) => ({ values: [{ userEnteredFormat: { backgroundColor: hexToRgb(hex.replace("#", "")) } }] })), range: { sheetId, startRowIndex: 6, endRowIndex: 6 + c.length, startColumnIndex: 14, endColumnIndex: 15 }, fields: "userEnteredFormat.backgroundColor" } }
);
return oo;
}, { valuesBatchUpdate: [], batchUpdate: [] });
var ssId = ss.getId();
Sheets.Spreadsheets.batchUpdate({ requests: batchUpdate }, ssId);
Sheets.Spreadsheets.Values.batchUpdate({ data: valuesBatchUpdate, valueInputOption: "USER_ENTERED" }, ssId);
}
Привет, Танайке, я получаю эту ошибку в Mod 1: 6:19:29 AM Error TypeError: Не удается прочитать свойство getEvents нулевого calendarIds.reduce.vv @ Untitled.gs:10 export_gcal_to_gsheet @ Untitled.gs:8
Мод 2 работает отлично, спасибо вам. Я буду тестировать другие моды, но я даю себе только 1 час каждое утро, чтобы работать над кодированием, так что потерпите меня, и я свяжусь с вами по другим модам.
@RoosterMagic22 Спасибо за ответ. Что касается Mod 2 works perfectly
, результат «Измененного сценария 3» такой же, как и «Измененный сценарий 2». Разница только в стоимости процесса.
Я знаю, что не могу понять, что я делаю неправильно, на самом деле это меня немного раздражает. Я уверен, что это что-то простое.
@RoosterMagic22 Спасибо за ответ. Я глубоко извиняюсь за это.
извините, приятель, я не знаю, что делаю, я все еще получаю следующие ошибки в моде 3 9:05:57 AM Error TypeError: Cannot read property 'toString' of null events.reverse.reduce.v @ Code.gs :17 obj.reduce.valuesBatchUpdate @ Code.gs:12 export_gcal_to_gsheet @ Code.gs:6
@RoosterMagic22 Спасибо за ответ. Я должен извиниться за мое плохое знание английского языка. К сожалению, я не могу понять I don't know what I'm doing, Im still getting the following erros on mod 3 9:05:57 AM Error TypeError: Cannot read property 'toString' of null events.reverse.reduce.v @ Code.gs:17 obj.reduce.valuesBatchUpdate @ Code.gs:12 export_gcal_to_gsheet @ Code.gs:6
. Могу я спросить вас о деталях этого?
Оба следующих метода распределяют вывод по отдельным листам и оставляют большую часть исходного кода нетронутой.
function exportcalenders() {
const calids = [{ id: "calid", shnam: "Sheet Name"}];
calids.forEach(obj => {
var cal = CalendarApp.getCalendarById(obj.id);
var events = cal.getEvents(new Date(new Date().getFullYear(),newDate().getMonth(),1),new Date());
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(obj.shnam);
sheet.clearContents();
var calColor = cal.getColor();
var colors = Calendar.Colors.get().calendar;
var header = ["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event", "Color"];
var offset = 6;
var { v, c } = events.reverse().reduce((o, e, i) => {
var color = e.getColor();
var row = offset + i + 1;
var c = colors[color] ? colors[color].background : calColor;
var f = `=(HOUR(F${row})+(MINUTE(F${row})/60))-(HOUR(E${row})+(MINUTE(E${row})/60))`;
o.v.push([mycal, events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), f, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent(), c]);
o.c.push([c]);
return o;
}, { v: [], c: [] });
var values = [header, ...v];
sheet.getRange(6, 1, values.length, values[0].length).setValues(values);
sheet.getRange(7, 7, v.length - 1).setNumberFormat('.00');
sheet.getRange(7, 15, c.length).setBackgrounds(c);
});
}
Вот еще один способ использования рекурсии:
В этой версии предполагается, что все календари доступны вам и поэтому доступны через getAllCalendars. Переменная inclCals позволяет вам включать только определенные календари из списка getAllCalendars, а snames — это список листов, которым вы хотите назначить два календаря. Переменная obj передает всю эту информацию в main cal через cacheService.
function xportcals() {
let inclCals = ["CalName1", "CalName2", "CalName3", "CalName4"];
let snames = ["Sheet1","Sheet2","Sheet3","Sheet4"]
let obj = CalendarApp.getAllCalendars().reduce((a, c, i) => {
let idx = inclCals.indexOf(c.getName());
if (~idx) {
a["cal"].push({ id: c.getId(), name: c.getName(),sheetname:snames[idx]});
}
return a;
}, { cal: [], proc: { level: 0, som: 1, sod: 1 } });
CacheService.getScriptCache().put("cals", JSON.stringify(obj), 300);
maincals();
}
function maincals() {
let obj = JSON.parse(CacheService.getScriptCache().get("cals"));
var cal = CalendarApp.getCalendarById(obj.cal[obj.proc.level]);
var events = cal.getEvents(new Date(new Date().getFullYear(), newDate().getMonth() - obj.proc.som , obj.proc.sod), new Date());
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(obj.cal.sheetname);
sheet.clearContents();
var calColor = cal.getColor();
var colors = Calendar.Colors.get().calendar;
var header = ["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event", "Color"];
var offset = 6;
var { v, c } = events.reverse().reduce((o, e, i) => {
var color = e.getColor();
var row = offset + i + 1;
var c = colors[color] ? colors[color].background : calColor;
var f = `=(HOUR(F${row})+(MINUTE(F${row})/60))-(HOUR(E${row})+(MINUTE(E${row})/60))`;
o.v.push([mycal, events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), f, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent(), c]);
o.c.push([c]);
return o;
}, { v: [], c: [] });
var values = [header, ...v];
sheet.getRange(6, 1, values.length, values[0].length).setValues(values);
sheet.getRange(7, 7, v.length - 1).setNumberFormat('.00');
sheet.getRange(7, 15, c.length).setBackgrounds(c);
obj.proc.level += 1;//increment the level counter
CacheService.getScriptCache().put("cals", JSON.stringify(obj), 60);//save obj in cacheService
if (obj.proc.level < obj.cal.length) {
maincals();
}
return;
}
Я не тестировал эту конкретную версию, но я протестировал более простую версию, и большинство частей, которые не являются общими для того, что я тестировал, являются вашим исходным кодом, который предположительно работает.
О, эта рекурсия выглядит интересной, и я вижу, как она будет работать — позвольте мне реализовать ее со своей стороны и вернуться к вам.
Привет, Купер. Я пробую реверсивное кодирование и получаю следующие ошибки, есть идеи? 6:07:49 AM Error TypeError: Не удается прочитать свойство getEvents нулевых maincals @ Code.gs: 18 xportcals @ Code.gs: 12
Хорошо, тогда кал должен быть нулевым, так как же выглядит obj
.
Доступны ли вам все календари, с которыми вы работаете? Если нет, то это let obj = CalendarApp.getAllCalendars().reduce((a, c, i) => {
может не сработать для вас.
Что вы имеете в виду, когда спрашиваете, как выглядит OBJ? Означает ли это, что окончательный сценарий?
Да, календари определенно доступны мне, я вижу их в календаре Google, и когда я пробую отдельный скрипт, он работает нормально.
Вы понимаете, как работает функция сокращения?
Я понимаю это на очень базовом уровне, приятель, я буду продолжать тестировать, а также тестировать другие моды, но я даю себе только 1 час каждое утро, чтобы работать над кодированием, так что потерпите меня, и я свяжусь с вами. У вас, вероятно, есть дела поважнее, но я подумал, что вам может быть интересно, как это происходит - в любом случае спасибо за вашу помощь.
Спасибо, Танайке, как всегда. Позвольте мне реализовать это на моем конце и посмотреть, как все это работает. Меня беспокоит стоимость процесса, поэтому на данном этапе я определенно склоняюсь к моду 3.