Генерация PDF-файлов — одна из тех вещей, которые Oracle JET не предлагает. Если вы хотите сделать это, вы должны использовать стороннюю библиотеку. В этой истории я покажу вам, как создать и загрузить PDF-документ из заданного пользовательского объекта. Вы можете применить показанные концепции к любому другому варианту использования. На этом пути есть несколько ловушек, которых вы, надеюсь, сможете избежать благодаря этому руководству.
Редактировать: Тем временем мы перенесли генерацию PDF из внешнего интерфейса в бэкенд (подробнее о причинах читайте в нашей Истории успеха Travelcost). Тем не менее, есть веские причины для создания PDF-файлов во внешнем интерфейсе, поэтому, пожалуйста, читайте дальше.
Альтернативой этому подходу может быть использование функции window.print
, которая вызывает представление печати для конкретного браузера. Большинство браузеров позволяют пользователю создавать PDF-файл из этого представления. Однако в большинстве случаев вам нужен больший контроль над тем, что печатается и как это выглядит. Кроме того, пользовательский опыт значительно улучшился, потому что (1) прямая загрузка сокращает количество шагов, которые должен выполнить пользователь, и (2) если быть честными, многие пользователи даже не знают, что они могут экспортировать PDF через диалог печати.
Я предполагаю, что вы уже разобрались с основами JET. Вам понадобится небольшое запущенное веб-приложение, чтобы интегрировать в него генерацию PDF. Если у вас нет подходящего шаблона, вы также можете использовать базовый начальный шаблон, который создает генератор Yeoman (сгенерируйте его с помощью yo oraclejet:app --template basic pdfmake-example
).
Результирующий документ будет выглядеть так для моих собственных пользовательских данных:
Настраивать
Мы будем использовать замечательную библиотеку pdfmake для создания и печати файла PDF. Загрузите его через npm install --save pdfmake
. Эту новую зависимость необходимо настроить для включения в команду grunt build
. Для этого добавьте следующую строку в массив copyCustomLibsToStaging.fileList
в файле scripts/grunt/config/oraclejet-build.js
:
{ cwd: 'node_modules/pdfmake/build', src: ['*.js'], // matches pdfmake.js and vfs_fonts.js dest: 'web/js/libs/pdfmake' }
Это добавит все файлы JavaScript из node_modules/pdfmake/build/
в вашу папку lib. Это файлы pdfmake.js
/pdfmake.min.js
(фактическая логика генерации PDF) и vfs_fonts.js
(шрифты, используемые библиотекой pdfmake). Не забудьте потом запустить grunt build
.
Вам понадобится и логика, и шрифты для создания PDF-файлов, поэтому их нужно загрузить через RequireJS. Именно здесь я изначально боролся, потому что сначала нужно загрузить шрифты, а затем библиотеку pdfmake. К счастью, в RequireJS есть что-то под названием shims именно для этих проблем (подробнее о shims). На самом деле вы уже используете прокладку jQuery в своем приложении JET. Измените объект shim
в вызове requirejs.config
следующим образом (прокладка jQuery уже должна быть там):
shim: { 'jquery': { exports: ['jQuery', '$'] }, 'vfsfonts': { deps: ['pdfmake'] } }
Эти зависимости, конечно, также должны быть добавлены к paths
, которые предоставляются для вызова requirejs.config
:
'pdfmake': 'libs/pdfmake/pdfmake', 'vfsfonts': 'libs/pdfmake/vfs_fonts'
Модуль pdfCreator
Я рекомендую поместить вашу логику PDF в отдельный модуль. Создайте файл pdfCreator.js
и добавьте стандартную логику определения модуля RequireJS:
define([], function () { function createPDF (user) { /* ... */ } return { fromUser: createPDF }; });
Это экспортирует функцию fromUser
, которую вы вызовете через pdfCreator.fromUser(user)
позже. Но сначала нам нужно потребовать необходимые зависимости. Вы можете сделать это, передав массив ['pdfmake', 'vfsfonts']
в качестве первого параметра в вызов define
. Прокладка, которую мы настроили на этапе настройки, гарантирует, что все загружается в правильном порядке. Поскольку мы хотим вызывать функции в библиотеке pdfmake, нам нужно передать pdfmake
в функцию, реализующую наш модуль. Полное определение модуля должно выглядеть так:
define(['pdfmake', 'vfsfonts'], function (pdfmake) { function createPDF (travel) { /* ... */ } return { fromUser: createPDF }; });
С учетом этого давайте добавим логику генерации PDF. В pdfmake документы описываются как простые объекты JavaScript. Объект документа должен как минимум содержать свойство content
. Здесь объявляется фактическое содержимое PDF. Мы хотим отображать пользовательские данные в табличном формате, поэтому сначала записываем пользовательские данные в двумерный массив:
var table = [ [ {text: 'User', style: 'tableHeader'}, {text: '', style: 'tableHeader'} ], [ 'Name', user.name ], [ 'Twitter Handle', user.twitter ], [ 'Favorite Band', user.band ] ];
Это определяет таблицу 4*2, где первая строка предназначена для заголовка. Обратите внимание, что мы намеренно установили второй заголовок в пустую строку, потому что нам нужен только заголовок для первого столбца. Текст может быть определен либо непосредственно как строка, либо через объект, имеющий свойство text
. Поскольку table
— это простой массив JavaScript, мы можем динамически добавлять больше контента, если захотим:
if (user.color) { table.push(['Favorite Color', user.color]); }
Нам также нужен красивый заголовок для нашего документа. Мы создаем объект, который хранит текст и имеет стиль header
:
var title = { text: 'User Info for ' + user.name, style: 'header' };
Но pdfmake еще не знает, что означает этот стиль header
, поэтому мы должны определить эти стили сейчас. pdfmake также позволяет стилизовать документ с помощью пар ключ-значение, подобных CSS. Они могут быть объявлены встроенными, но в большинстве случаев вы хотите сохранить их в объекте, который передается в свойство styles
объекта документа. Таким образом, вы можете повторно использовать их для разных частей документа. Мы вводим стиль для заголовка документа и заголовка таблицы следующим образом:
var styles = { header: { fontSize: 18, bold: true, margin: [0, 0, 0, 10] }, tableHeader: { bold: true, fontSize: 13, color: 'black' } };
Последнее, что вы можете сделать, это отобразить какой-нибудь логотип в заголовке. Многие официальные документы имеют логотип компании-эмитента, напечатанный в верхнем правом или верхнем левом углу. Это немного сложно, потому что вы не можете, например, просто установить display: inline
, как в CSS. Вместо этого мы делаем это:
var image = { image: 'data:image/png;base64,iVBORw0KGgoAAAANS...', width: 73, height: 28, alignment: 'right', margin: [0, 25, 25, 0] };
Обратите внимание, что мы установили выравнивание на right
, потому что мы поместили изображение в верхний правый угол документа. Ему также назначается поле в 25 пикселей, сверху и справа. Поскольку мы запускаем приложение в браузере, мы не можем получить доступ к файловой системе. Поэтому изображение кодируется base64. Для этого можно использовать онлайн-сервис, я использовал base64-image.de.
Наши различные части документа теперь могут быть объединены в определение документа следующим образом:
var document = { background: image, content: [ title, { table: { widths: [200, '*'], headerRows: 1, body: table }, layout: 'headerLineOnly', margin: [0, 10, 0, 0] } ], styles: styles };
Обратите внимание на свойство content
, которое определено как массив в pdfmake. Здесь мы устанавливаем title
и описываем таблицу. Определение таблицы предполагает наличие двумерного массива в качестве body
(которое мы определили ранее). Мы также устанавливаем widths
столбцов таблицы, сообщаем таблице, что первой строкой должно быть headerRow
, и устанавливаем конкретное предопределенное layout
, чтобы оно выглядело красиво. Мы также установили логотип в качестве фонового изображения. Это важно, потому что в противном случае документ будет испорчен. Не стесняйтесь добавлять изображение в content
и посмотрите, как это повлияет на макет.
Опять же, вот скриншот окончательного PDF-документа:
Это завершает определение документа. Теперь нам просто нужно создать PDF-файл через pdfmake.createPdf(document)
, что позволит нам инициировать загрузку PDF-файла через pdf.download()
. Вы также можете создавать функции для печати PDF или открытия его в браузере через print()
и open()
соответственно.
Теперь вы можете запросить этот модуль в любом месте вашего приложения Oracle JET и использовать его функцию fromUser
для загрузки PDF-файла с данными пользователей. Вы можете сделать гораздо больше с pdfmake — отправляйтесь на игровую площадку, если хотите глубже изучить. Полный пример pdfCreator доступен в виде краткого описания на github.
Заключение / TL;DR
- используйте pdfmake для создания файлов PDF
- настроить прокладку так, чтобы RequireJS знал, как загружать pdfmake и его шрифты
- определять данные документа и таблицы, используя простые объекты и массивы JavaScript
- создайте PDF через
pdfmake.createPdf(document)
, а затем загрузите черезpdf.download()