У меня есть две отдельные таблицы: одна для администратора и одна для пользователя. Администратор может заблокировать или разблокировать определенные диапазоны для пятницы, субботы, воскресенья или праздников с помощью триггера onEdit (т. е. Fridaycheck(). Когда флажок снят, те же самые диапазоны удаляются. Проблема в том, что администратор отмечает все флажки сразу и перед любыми отдельных сценариев могут быть завершены. Когда они наконец завершаются, для каждого дня существует несколько экземпляров защиты. Когда администратор проверяет один день и скрипту разрешено завершиться, все работает нормально. Пытаюсь предотвратить запуск нескольких экземпляров защиты. вставлены ИЛИ удалите все экземпляры, когда галочка снята. Вот сценарии для проверки, блокировки и разблокировки Fri onEdit. Мы будем очень признательны за любые предложения. Спасибо, Пол .
function fridaycheck() {
let admincheck = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Admin")
let activeCell = admincheck.getRange("AE9")
let reference = activeCell.getA1Notation()
let sheetName = activeCell.getSheet().getName()
let activeValue = activeCell.getValue()
if (reference == "AE9" && sheetName == "Admin" && activeValue == true)
LockFriday();
else
UnlockFriday();
}
function LockFriday() {
var protectRange = 'C8:D60';
var description = 'AA Lock Friday Cells';
var spreadsheet =
SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxxx');
spreadsheet.getRange(protectRange).activate();
spreadsheet.setCurrentCell(spreadsheet.getRange('D60'));
var p = spreadsheet.getProtections(SpreadsheetApp.ProtectionType.RANGE).find(e =>
e.getRange().getA1Notation() == protectRange && e.getDescription() == description);
if (p) return;
var protection = spreadsheet.getRange(protectRange).protect();
var all = protection.getEditors();
protection.setDescription(description).removeEditors(all);
protection.setDescription(description).addEditor('[email protected]');
protection.setDescription(description).addEditor('[email protected]');
var ss = SpreadsheetApp.getActive();
var checkbox = ss.getRange("AE9").getValue();
if (checkbox==false){
ss.getRange("AE9").setValue("true");
}
}
function UnlockFriday() {
var spreadsheet = SpreadsheetApp.openById('XXXXXXXXXXXXX');
spreadsheet.getRange('C8:D60').activate();
var allProtections =
spreadsheet.getActiveSheet().getProtections(SpreadsheetApp.ProtectionType.RANGE);
var matchingProtection1 = allProtections.find(existingProtection => existingProtection.getRange().getA1Notation() == 'C8:D60');
if (!matchingProtection1) return;
matchingProtection1.remove();
var ss = SpreadsheetApp.getActive();
var checkbox = ss.getRange("AE9").getValue();
if (checkbox==true){
ss.getRange("AE9").setValue("false");
}
}
Судя по вашему сообщению, я понимаю, что вы хотите обеспечить отсутствие дубликатов описаний защищенного диапазона, а сохранить только один уникальный защищенный диапазон.
Я предлагаю вам использовать расширенную службу Google для API Google Sheet, поскольку расширенные службы обычно оптимизированы по производительности, что может привести к сокращению времени выполнения.
Я подправил ваш скрипт и добавил, как вы можете добавить пример функции checkDupes
. Вот пример измененного скрипта:
function fridaycheck() {
let admincheck = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Admin")
let activeCell = admincheck.getRange("AE9")
let reference = activeCell.getA1Notation()
let sheetName = activeCell.getSheet().getName()
let activeValue = activeCell.getValue()
if (reference == "AE9" && sheetName == "Admin" && activeValue == true)
LockFriday();
else
UnlockFriday();
}
function LockFriday() {
var protectRange = 'C8:D60';
var description = 'AA Lock Friday Cells';
var userSheetID = "XXXXXXXXXXXXXXXXXXX"; //[UPDATED], placed the Sheet ID you are using in this 'userSheetID' variable for your 'LockFriday' function.
var spreadsheet =
SpreadsheetApp.openById(userSheetID); //[UPDATED], placed the 'userSheetID' variable to where it is needed
spreadsheet.getRange(protectRange).activate();
spreadsheet.setCurrentCell(spreadsheet.getRange('D60'));
var p = spreadsheet.getProtections(SpreadsheetApp.ProtectionType.RANGE).find(e =>
e.getRange().getA1Notation() == protectRange && e.getDescription() == description);
if (p) return;
var protection = spreadsheet.getRange(protectRange).protect();
var all = protection.getEditors();
protection.setDescription(description).removeEditors(all);
protection.setDescription(description).addEditor('[email protected]');
protection.setDescription(description).addEditor('[email protected]');
var ss = SpreadsheetApp.getActive();
var checkbox = ss.getRange("AE9").getValue();
if (checkbox == false) {
ss.getRange("AE9").setValue("true");
}
checkDupes(userSheetID); //[UPDATED], added this function with the idea that every time a new protection is added, regardless of whether it is another duplicate, this function runs to make sure they are deleted.
}
function checkDupes(userSheetID) {
var spreadsheetData = Sheets.Spreadsheets.get(userSheetID); //Get data from the user spreadsheet via sheet ID
var columns = Array.from({ length: 26 }, (_, i) => String.fromCharCode(97 + i).toUpperCase());
//Function to trasnform result function into readable A1 notation range with description.
let getReadableRanges = (p) => {
return p.protectedRanges.map(r =>
[r.protectedRangeId, r.description, `${columns.filter((_, i) => r.range.startColumnIndex == i)}${r.range.startRowIndex + 1}:${columns.filter((_, i) => (r.range.endColumnIndex - 1) == i)}${r.range.endRowIndex}`]);
}
let cleanDupeProtectedRange = (p, userSheetID) => {
let protectedRangeIds = p.map(x => `{"deleteProtectedRange": {"protectedRangeId":${x[0]}}}`)
let requestbuilder = `{"requests": [${protectedRangeIds.join(',')}]}`
return Sheets.Spreadsheets.batchUpdate(requestbuilder, userSheetID);
}
let pullExistingProtectedRanges = spreadsheetData.sheets.map(p => getReadableRanges(p));
let protectRange = pullExistingProtectedRanges.flat().reduce((accumulator, currentValue) => {
const existingItem = accumulator.find(item => item[1] === currentValue[1]);
if (!existingItem) {
accumulator.push(currentValue);
}
return accumulator;
}, []);
var rangeToRemoved = pullExistingProtectedRanges.flat().filter(y => !protectRange.join('*').match(y[0]));
try {
cleanDupeProtectedRange(rangeToRemoved, userSheetID)
} catch {
console.info('No duplicate found')
}
}
function UnlockFriday() {
var spreadsheet = SpreadsheetApp.openById('XXXXXXXXXXXXX');
spreadsheet.getRange('C8:D60').activate();
var allProtections =
spreadsheet.getActiveSheet().getProtections(SpreadsheetApp.ProtectionType.RANGE);
var matchingProtection1 = allProtections.find(existingProtection => existingProtection.getRange().getA1Notation() == 'C8:D60');
if (!matchingProtection1) return;
matchingProtection1.remove();
var ss = SpreadsheetApp.getActive();
var checkbox = ss.getRange("AE9").getValue();
if (checkbox == true) {
ss.getRange("AE9").setValue("false");
}
}
Узнайте, как использовать расширенный сервис Sheet API:
Демо
Пример листа пользователя с повторяющимися защищенными диапазонами
После запуска функции checkDupes
Рекомендации
Включите Advances Google Service для Sheets API
Именованные и защищенные диапазоны Sheets API
@ PT109 PT109 Я обновил свой ответ, в котором изменил ваш реальный сценарий, чтобы показать вам, как вы можете использовать образец функции checkDupes
.
Работает отлично!! Ты мужчина!! Огромное спасибо, я много узнал о расширенном сервисе Google для Google Sheet API. Определенно гораздо быстрее.
Кроме того, ваше решение вообще предотвращает дублирование. Второй ответ удаляет дубликаты на бэкэнде. Ваш намного лучше и эффективнее. Еще раз спасибо.
Удалось собрать воедино ответ, который работает. Все несколько экземпляров защищенных ячеек одного диапазона удаляются. Флажок изменен с «истина» на «ложь».
function UnlockFriday() {
var spreadsheet = SpreadsheetApp.openById('xxxxxxxxxxxxxx');
var protections = spreadsheet.getActiveSheet().getProtections(SpreadsheetApp.ProtectionType.RANGE);
spreadsheet.getRange('C8:D60').activate();
for (var i = 0; i < protections.length; i++) {
if (protections[i].getDescription() == 'AA Lock Friday Cells') {
protections[i].remove();
}
}
var ss = SpreadsheetApp.getActive();
var checkbox = ss.getRange("AE9").getValue();
if (checkbox==true){
ss.getRange("AE9").setValue("false");
}
}
Спасибо за ваш ответ. Очень хочется попробовать! Пожалуйста, знайте, что я не программист, но знаю достаточно, чтобы обойтись. Я ввел идентификатор своего листа во вторую строку. а потом попробуй сохранить. Синтаксическая ошибка: неожиданный токен '{', строка 8. Кроме того, в строке 14 после построителя запроса следует заменить тот же идентификатор листа, что и в строке 2?