Создание диалогового окна в скрипте приложений Google для листов Google с использованием HTML

Я разрабатываю электронную таблицу для отслеживания своих расходов и попутно использую appscript, чтобы добавить больше функциональности. Есть несколько вещей, которые я хотел бы сделать, но которые кажутся невозможными в приложениях и требуют для работы HTML, но я понятия не имею, с чего начать, и у меня нет опыта кодирования HTML.

У меня есть скрипт, привязанный к простому триггеру onOpen(e).

function addMenu() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu("Operations")
  .addSubMenu(ui.createMenu("Add").addItem(TypeCategory, addCategory.name).addItem(TypeBill, addBill.name).addItem(TypeTarget, addTarget.name))
  .addSubMenu(ui.createMenu("Delete").addItem(TypeCategory, deleteCategory.name).addItem(TypeBill, deleteBill.name).addItem(TypeTarget, deleteTarget.name))
  .addSubMenu(ui.createMenu("Transfer").addItem(TypeCategory, transferCategories.name).addItem(TypeBill, transferBills.name).addItem(TypeTarget, transferTargets.name))
  .addSubMenu(ui.createMenu("Modify").addItem(TypeCategory, "test").addItem(TypeBill, "test").addItem(TypeTarget, "test"))
  .addToUi();
}


Просто сосредоточьтесь на скрипте transferCategory в подменю Transfer:

function transferCategories() {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  let transferRange = sheet.getRange("G7:G9");
  let categoryRange = sheet.getRange("F12:F");
  let amount2Add    = sheet.getRange("G9");
  let originCategory = sheet.getRange("G7");
  let destinationCategory = sheet.getRange("G8");

  if (originCategory.isBlank() && destinationCategory.isBlank() && amount2Add.isBlank()) { Browser.msgBox("Please specify all fields!"); return }
  if (!originCategory.isBlank() && destinationCategory.isBlank() && amount2Add.isBlank()) { Browser.msgBox("Please specify all fields!"); return }
  if (originCategory.isBlank() && !destinationCategory.isBlank() && amount2Add.isBlank()) { Browser.msgBox("Please specify all fields!"); return }
  if (!originCategory.isBlank() && !destinationCategory.isBlank() && amount2Add.isBlank()) { Browser.msgBox("Please specify an amount to transfer!"); return }
  if (originCategory.isBlank() && !destinationCategory.isBlank() && !amount2Add.isBlank()) { Browser.msgBox("Please specify an origin category!"); return }
  if (!originCategory.isBlank() && destinationCategory.isBlank() && !amount2Add.isBlank()) { Browser.msgBox("Please specify a destination category!"); return }

  if ((originCategory.getValue() === destinationCategory.getValue()) && amount2Add.getValue() < 0) { 
  Browser.msgBox("Cannot transfer between categories of the same name!\\nAmount to transfer must be greater than zero!"); 
  return; 
  }
  if ((originCategory.getValue() === destinationCategory.getValue()) && isNaN(amount2Add.getValue())) { 
  Browser.msgBox("Cannot transfer between categories of the same name!\\nAmount to transfer must be a number!"); 
  return; 
  }
  if ((originCategory.getValue() === destinationCategory.getValue()) && !isNaN(amount2Add.getValue()) && amount2Add.getValue() >= 0) { 
  Browser.msgBox("Cannot transfer between categories of the same name!"); 
  return; 
  }
  if ((originCategory.getValue() != destinationCategory.getValue()) && amount2Add.getValue() < 0) { 
  Browser.msgBox("Amount to transfer must be greater than zero!"); 
  return; 
  }
  if ((originCategory.getValue() != destinationCategory.getValue()) && isNaN(amount2Add.getValue())) { 
  Browser.msgBox("Amount to transfer must be a number!"); 
  return; 
  }

  let overflowColumn                  = 10;
  let allocatedAmountRow              = 12; //Row number of first value
  let allocationAmountColumn          = 8;
  let previousAllocationAmountColumn  = 7; 
  let rowOrigin                       = categoryRange.getValues().filter(r => r!= "").flat().indexOf(originCategory.getValue());
  let rowDestination                  = categoryRange.getValues().filter(r => r!= "").flat().indexOf(destinationCategory.getValue());

  //Confirm that amount to deduct from origin category is enough
  let originCell    = sheet.getRange(allocatedAmountRow + rowOrigin, overflowColumn);
  let originAmount  = originCell.getValue();

  if (originAmount < amount2Add.getValue()) { Browser.msgBox("Not enough funds to transfer!"); return; }

  //Move values
  let originAllocationCell        = sheet.getRange(allocatedAmountRow + rowOrigin, allocationAmountColumn);
  let remainingAllocationAmount   = originAllocationCell.getValue() - amount2Add.getValue();

  if (remainingAllocationAmount < 0) {
    let prevAllocationCell    = sheet.getRange(allocatedAmountRow + rowOrigin, previousAllocationAmountColumn);
    let destinationAllocation = sheet.getRange(allocatedAmountRow + rowDestination, allocationAmountColumn);
    prevAllocationCell.setValue(parseFloat(prevAllocationCell.getValue()) - parseFloat(Math.abs(remainingAllocationAmount)));
    originAllocationCell.setValue(0);
    destinationAllocation.setValue(destinationAllocation.getValue() + parseFloat(amount2Add.getValue()));
    transferRange.clearContent();
    return;
    }
    originAllocationCell.setValue(originAllocationCell.getValue() - amount2Add.getValue());
    let destinationAllocation = sheet.getRange(allocatedAmountRow + rowDestination, allocationAmountColumn);
    destinationAllocation.setValue(parseInt(destinationAllocation.getValue()) + parseFloat(amount2Add.getValue()));
    transferRange.clearContent();
    return;
}

По сути, этот скрипт позволяет пользователю переносить суммы распределения между двумя категориями расходов.

Обратите внимание, что этот сценарий изначально был написан с намерением, чтобы пользователь вводил все, что есть в самом листе, в две ячейки с раскрывающимися списками, которые ссылаются на категории расходов, с указанием категории происхождения и назначения. В отдельной ячейке также будет указана сумма для перевода. Сам скрипт изначально был привязан к кликабельному рисунку. Метод довольно длинный, но важно то, что я хочу переместить все в поле ввода браузера. Проведя небольшое исследование, я понял, что класс Browser не позволяет вводить несколько элементов, которые вы выбираете из раскрывающихся окон. Видимо, мне нужен класс HtmlService. К сожалению, документация не очень полезна.

Короче говоря, мне нужно окно, похожее по стилю на окно Browser.msgBox():

В окне будет соответствующая подсказка с заголовком и желательно три окна или поля (панель параметров?), два с именованными раскрывающимися списками, которые связаны со столбцами на листе, из которых можно выбирать, и одно, в котором можно ввести сумму. Предпочтительно, чтобы были кнопки «ОК» и «Отмена» (с регулируемым положением). Когда нажата кнопка «ОК», вызывается transferCategory, и все связанные сообщения об ошибках передаются в новое окно, в котором отображается соответствующее сообщение, из которого пользователь может выбрать попытку еще раз или отменить операцию. В случае успешной передачи также отображается сообщение с подтверждением. Я заметил, что класс Browser приостанавливает выполнение сценария, тогда как в примерах, которые я видел для HTMLService, это не так. Я думаю, что пауза здесь не нужна.

Буду признателен за шаблон о том, как начать работу.

Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
1
0
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, вам нужна боковая панель. Похоже, вы захотите использовать шаблонный HTML для создания контента на боковой панели. Вы можете создать массивы двух описанных вами категорий, превратить их в раскрывающиеся списки с помощью HTML и добавить поле ввода для суммы.

Вот основная идея, с которой можно начать.

код.gs

var testVariable = ['option1','option2','option3'];

function onOpen() {
  var ui = SpreadsheetApp.getUi()
  var menu = ui.createMenu('Testing');
  menu.addItem('Test', 'testFunction').addToUi();
}

function testFunction() {
  var ui = SpreadsheetApp.getUi();
  var tmp = HtmlService.createTemplateFromFile('page.html');
  tmp.testVariable = testVariable;
  var html = tmp.evaluate();
  html.setTitle('My custom sidebar');
  ui.showSidebar(html);
}

страница.html

<!DOCTYPE html>
<html>
  <head>
    <base target = "_top">
  </head>
  <body>

    <script>
    <? var data = testVariable ?>
    </script>

    <div id = "targetDiv">
      <label for = "category">Choose a category:</label>
      <select name = "category" id = "category">
        <? for (var i = 0 ; i < data.length ; i++) { ?>
        <option value = "<?= data[i] ?>"><?= data[i] ?></option>
        <? } ?>

    </div>

  </body>
</html>

Вам придется немного больше прочитать, чтобы изучить HTML и настроить форму. Вам также необходимо прочитать документацию google.script.run, чтобы передать вашу форму обратно в Apps Script. (И, возможно, прочитайте немного CSS, чтобы стилизовать свою форму, если вам интересно.)

Документация Google для ознакомления:

https://developers.google.com/apps-script/guides/dialogs
https://developers.google.com/apps-script/guides/html/templates
https://developers.google.com/apps-script/guides/html/communication

Это здорово, я попробую. Для начала я также прохожу несколько руководств по HTML. Не могли бы вы рассказать, почему, по вашему мнению, боковая панель более уместна?

J_code 18.06.2024 05:24

Главным образом потому, что я не думаю, что какие-либо другие элементы диалога будут работать для того, что вам нужно (2 раскрывающихся списка + кнопки ввода + очистки/отправки). Кажется, что боковая панель охватывает ваши базы, оставаясь при этом внутри самого Google Sheet. Для этого вам не нужно изучать огромный объем HTML, особенно если это предназначено только для вас или небольшой группы пользователей.

Kreeszh 18.06.2024 13:04

Другие вопросы по теме