Часть 1. Базовая реализация

Привет народ! Сегодня я хочу начать серию статей о создании веб-компонента Lightning для анализа файлов XLSX в Salesforce. С каждой частью мы будем улучшать компонент и добавлять новые функции. Начнем с базовой реализации.
В этой статье мы создадим LWC, который позволит нам создавать записи из файла XLSX. Файлы CSV легко импортировать с помощью загрузчика данных или прикреплять файлы Excel к записям Salesforce. Однако на днях появилось требование, чтобы клиент хотел, чтобы конечные пользователи регулярно импортировали записи из файлов Excel и присоединяли данные в качестве дочерних записей к определенной записи. Они не хотели преобразовывать его в файл CSV или использовать коннектор Excel-Salesforce. Решение должно быть удобным для пользователя, а также должно быть доступно для выполнения нетехническими людьми. После проб и ошибок мне удалось разработать подходящее решение, объединив две библиотеки JS.
Это стек, который мы будем использовать:
- Веб-компоненты Lightning
- Пользовательские типы метаданных
- APEX (только для вставки записей и получения метаданных)
Мы будем использовать библиотеки SheetJS и Papa Parse. SheetJS имеет две версии: профессиональную и общественную. Мы будем использовать версию сообщества, так как она с открытым исходным кодом и бесплатна. Библиотека позволяет нам делать многое с Excel, например создавать файлы XLSX из массивов или, как мы будем ее использовать, читать файлы XLSX. Papa Parse станет второй частью нашей сети. Мы используем его для анализа полученных данных CSV, которые мы получим из SheetJS. Результатом будет массив JS-объектов, представляющих строки файла Excel.
Следующий сценарий служит требованием для нашей реализации: Наш клиент ежемесячно получает файл Excel для каждой из своих учетных записей, который содержит все контакты этой учетной записи. Каждый сотрудник должен нести ответственность за загрузку контактных данных в Salesforce. В рамках этого руководства нам не нужно обновлять или удалять существующие записи и т. д. Основное внимание уделяется вводу данных в систему. Когда у нас есть данные в виде JS-объектов, появляется бесчисленное множество возможностей для их дальнейшей обработки.

Время кодировать
Начнем с создания LWC с именем contactUpload. Пользовательский интерфейс будет очень простым, поскольку он состоит только из карты молнии и стандартного компонента молния-ввода.
Мы используем стиль SLDS, чтобы он выглядел немного лучше. Для HTML-файла больше ничего не нужно. Для lightning-input мы регистрируем обработчик изменений с именем handleUploadFinished. Он будет вызываться при выборе файла.
Прежде чем мы сможем начать с нашего JS-файла, нам нужно загрузить две библиотеки в качестве статических ресурсов в нашу организацию Salesforce. Я предполагаю, что вы знаете, как это работает, поэтому я не буду вдаваться в подробности. Для SheetJS просто загрузите xlsx.full.min.js с их GitHub, а Papa Parse можно загрузить с их веб-сайта www.papaparse.com. Вы также можете получить оба из моего GitHub.
Первое, что мы сделаем, — импортируем библиотеки и загрузим их с помощью функции loadScript, предоставляемой Salesforce. Мы также создаем обработчик изменений для lightning-input, где мы получаем файл из event.detail.files.
Далее мы пишем функцию, которая будет анализировать входящий файл XLSX. Функция принимает файл в качестве входных данных и использует JavaScript FileReader API для преобразования его в двоичную строку. В обработчике onLoad FileReader мы используем объект XLS, полученный от SheetJS, для работы с результатом. Там происходят две вещи:
- Мы читаем двоичную строку, чтобы создать экземпляр книги. Рабочие книги представляют собой упорядоченные списки листов в файле Excel. Чтобы получить конкретный лист, мы должны указать имя листа.
- Берем первый лист рабочей книги (возможна работа с XLSX-файлами, имеющими несколько листов) и конвертируем его в CSV.
Поскольку теперь у нас есть данные в формате CSV, мы можем создать вторую функцию для их анализа. Мы называем это parseCSV(). Глобальный объект Papa предоставляет функцию parse(), которую мы будем использовать. В качестве входных данных он принимает файл и объект config. Есть много параметров, которыми мы можем управлять с помощью объекта конфигурации (проверьте документацию для всех). Нам нужно всего четыре:
- quoteChar: символ, используемый для заключения значений в файле CSV, обычно → «…»
- разделитель. Разделитель в CSV-файле может отличаться в зависимости от наших локальных настроек. Мы оставляем его пустым, чтобы он автоматически обнаружил его.
- header: поскольку в нашем образце CSV-файла он есть, мы должны установить для него значение true.
- кодировка: здесь лучше всего использовать utf-8.
Мы также определяем два обратных вызова. Один за успех и один за неуспех. Полное свойство вызывает наш обработчик завершения, который мы определим на следующем шаге. И обработку ошибок мы пропустим в контексте этого урока.
Теперь у нас есть данные в форме объектов, из которых мы можем создавать sObjects. Но есть одна проблема: заголовки нашего excel не совпадают с именами API соответствующих полей контактов. Есть много способов справиться с этой ситуацией. Мы будем использовать Пользовательские типы метаданных для сопоставления столбцов с полями нашего объекта Salesforce.

Для этого мы создаем новый тип настраиваемых метаданных под названием Сопоставление контактов Excel. Для этого типа мы создаем настраиваемое поле раскрывающегося списка Тип поля. В этой части наш Excel содержит только строки и даты. Мы будем использовать поле Тип поля для правильного форматирования данных.
Теперь для каждого столбца в файле Excel мы создадим запись наших метаданных. Метка записи будет заголовком столбца, поле Имя (Имя разработчика) будет именем API соответствующего поля контакта. Значение поля Тип поля зависит от данных в столбце Excel.
Чтобы получить записи метаданных в нашем LWC, нам нужен APEX. Простая функция, которая возвращает все записи для сопоставления метаданных:
Теперь мы используем эту функцию в нашем LWC для извлечения записей при загрузке компонента. Мы вызываем fillMetadataMapping() в connectedCallback().
Далее мы изменим строки, чтобы они соответствовали именам API полей контактов, а также соответствовали типу данных поля. Для этого мы создаем функцию, которая будет вызываться для каждой пары ключ-значение (заголовок столбца =› значение) строки. Внутри функции необходимо выполнить следующие шаги:
- Удалите ключ (заголовок столбца) из строки.
- Получите метаданные для этого заголовка столбца.
- Сверьте тип данных с метаданными и при необходимости преобразуйте значение.
- Сохраните значение с именем API полей в качестве ключа в строке.
В нашем csvParserCompletionHandler() мы вызываем новый processRowData() для каждой строки. Строки являются объектами. Для каждой пары ключ-значение строки мы вызываем нашу функцию modifyDataProperties(). Тем самым мы добавляем в нашу строку два новых свойства: objectType и AccountId. Установив эти значения, мы можем вставить их непосредственно в качестве контактов без дальнейшей обработки в APEX. Примечание к третьей строке csvParserCompletionHandler(): иногда случалось, что PapaParse добавлял пустой объект при анализе CSV-файла. Я использую функцию filter() для удаления всех объектов без фамилии. Мы можем рассматривать это как первую небольшую проверку данных.
Чтобы вставить контакты в базу данных, нам нужна вторая функция APEX. Это будет так же просто, как и первое. Функция состоит только из оператора insert. Здесь мы игнорируем любые проверки CRUD и обработку ошибок.
Последнее, что нам нужно сделать, это импортировать новую функцию в наш LWC и вызвать ее после обработки всех строк.
Краткое содержание
Вот и все. Этот пример не является идеальным и готовым к производству компонентом, но он является отличной отправной точкой для различных типов требований. С помощью этого LWC и некоторого кода APEX мы можем загрузить файл XLSX, проанализировать его за считанные секунды и создать контакты из данных. Вы можете найти код на моем GitHub: https://github.com/maxeuler/lwc-parse-xlsx.
В следующей части серии мы расширим наш компонент, чтобы он принимал больше типов данных и проверял данные перед импортом. Следите за обновлениями!
P.S. Среди нас это первая статья, которую я когда-либо писал, так что терпите меня. И я всегда открыт для отзывов и предложений по улучшению.