Введение

Полезно создавать отчеты в формате PDF, поскольку их нельзя изменить, а также их можно легко распечатать. Здесь мы поговорим о том, как генерировать отчеты с помощью UniPDF в виде табличных данных. Мы рассмотрим это на примере создания индивидуальных табелей успеваемости для учащихся из заданного набора данных.

Сначала мы рассмотрим генерацию данных. Здесь мы будем использовать структуры и заполнять данные вручную, но мы могли бы легко предоставить входные данные в виде файла Excel XLSX и использовать UniOffice для загрузки данных. Возможно, мы добавим это в будущем. Дайте нам знать, если вы заинтересованы.

Затем мы рассмотрим, как UniPDF создает таблицу, как вставлять ячейки и форматировать таблицы, а также как вставлять соответствующие данные в ячейки. После этого мы напишем все это в PDF.

Генерация данных

Мы можем использовать структуры для хранения данных. Здесь мы определили две структуры. Одна структура для хранения оценок и предметов, а другая структура, которая содержит всю информацию для учащихся, как в нашем примере имя, отметки (которая является структурой) и поведение учащихся.

type studentReportCardMark struct {
  Subject string
  Mark int
}
type studentReportCard struct {
  Name string
  Marks []studentReportCardMark
  Punctual rune
  Attentive rune
  Orderly rune
  Polite rune
}

Мы сделали образцы данных для четырех студентов, чтобы создать наши табели успеваемости. Например, мы покажем один здесь.

var reportCards = []studentReportCard{
{
 Name: "Mike",
 Marks: []studentReportCardMark{
 {
 Subject: "Chemistry 101",
 Mark: 21,
 },
 {
 Subject: "Physics 101",
 Mark: 13,
 },
 {
 Subject: "English 101",
 Mark: 50,
 },
 {
 Subject: "Science 101",
 Mark: 23,
 },
 {
 Subject: "Biology 101",
 Mark: 26,
 },
 {
 Subject: "Computers 101",
 Mark: 33,
 },
 {
 Subject: "Tech 101",
 Mark: 34,
 },
 {
 Subject: "BioChem 101",
 Mark: 14,
 },
 },
 Punctual: 'C',
 Attentive: 'B',
 Orderly: 'B',
 Polite: 'A',
 }
}

Дизайн отчета

Для оформления всего табеля мы использовали таблицы из UniPDF. Для таблиц мы определили карту стилей ячеек, которая содержит данные для различных типов ячеек, которые мы хотим создать в наших таблицах для этого дизайна. Он был реализован через структуру, которая содержит свойства отдельных ячеек. Это довольно удобно и легко добавлять и изменять стили.

type cellStyle struct {
 ColSpan int
 HAlignment creator.CellHorizontalAlignment
 BackgroundColor creator.Color
 BorderSide creator.CellBorderSide
 BorderStyle creator.CellBorderStyle
 BorderWidth float64
 BorderColor creator.Color
 Indent float64
}

Один из таких примеров стиля ячейки, используемого в этом дизайне, используется для написания заголовка слева от ячейки.

var cellStyles = map[string]cellStyle{
 "heading-left": {
 BackgroundColor: creator.ColorRGBFromHex("#332f3f"),
  HAlignment: creator.CellHorizontalAlignmentLeft,
 BorderColor: creator.ColorWhite,
 BorderSide: creator.CellBorderSideAll,
 BorderStyle: creator.CellBorderStyleSingle,
 BorderWidth: 6,
 }

Точно так же в табеле успеваемости использовались разные стили ячеек для создания ячеек, которые описаны ниже.

Заголовок

Для заголовка мы использовали таблицу из 1 ячейки с выравниванием по центру и использовали прямоугольник, чтобы выделить фон заголовка табеля успеваемости. Похоже на это.

Код выглядит следующим образом. И он также включает в себя две линии в конце, которые были нарисованы с помощью функции newLine.

// Filled rectangle on top. 
rect := c.NewRectangle(0, 0, creator.PageSizeLetter[0], 120)
rect.SetFillColor(creator.ColorRGBFromHex("#dde4e5"))
rect.SetBorderWidth(0)
c.Draw(rect)
headerStyle := c.NewTextStyle()
headerStyle.FontSize = 50
// Table with 1 column to center the text.
table := c.NewTable(1)
table.SetMargins(0, 0, 20, 0)
drawCell(table, newPara(c, "Report Card", headerStyle), cellStyles["centered"])
c.Draw(table)
// Double line.
line := c.NewLine(0, 120, creator.PageSizeLetter[0], 120)
line.SetLineWidth(5)
c.Draw(line)
line = c.NewLine(0, 123, creator.PageSizeLetter[0], 123)
line.SetLineWidth(1.5)
c.Draw(line)

Создание описания ученика

Аналогичным образом, используя таблицу из 3 столбцов, для каждого учащегося было создано описание с использованием данных, которые были добавлены в образец, и некоторых общих данных для остальных столбцов.

Это было сделано с помощью функции drawCell, которая была разработана для рисования отдельных ячеек в соответствии с нашими потребностями в данной таблице.

drawCell(table, newPara(c, "Student Name: "+card.Name, studentInfoStyle), cellStyles["left"])
drawCell(table, newPara(c, "School Year: 2020", studentInfoStyle), cellStyles["left"])
drawCell(table, newPara(c, "Roll No: 320", studentInfoStyle), cellStyles["left"])
drawCell(table, newPara(c, "Date: 14/12/2020", studentInfoStyle), cellStyles["left"])
drawCell(table, newPara(c, "Department: Bachelors of Arts", studentInfoStyle), cellStyles["left"])

Таблица оценок с индивидуальными баллами по предметам

Таблица оценок была создана с использованием выборочных данных, и некоторые функции использовались для создания оценок, а затем добавления их в таблицу для отдельных предметов. Тема выравнивается по левому краю, а остальные столбцы выравниваются по центру.

Код выглядит следующим образом

for _, mark := range card.Marks {
 drawCell(table, newPara(c, " "+mark.Subject, regularStyle), cellStyles["left-highlighted"])
 s := mark.Mark
 percent := (float64(s) / 50.0) * 100.0
 drawCell(table, newPara(c, fmt.Sprintf("%d", s), regularStyle), cellStyles["centered-highlighted"])
 drawCell(table, newPara(c, fmt.Sprintf("%.0f%%", percent), regularStyle), cellStyles["centered-highlighted"])
 drawCell(table, newPara(c, calcGrade(percent), regularStyle), cellStyles["centered-highlighted"])
}

Схема оценок и колонка поведения

Остальная часть отчета состоит из схемы оценивания и поведения, которое снова было сгенерировано с использованием таблиц и отформатировано с использованием структуры Style ячейки, которую мы определили ранее. Схема оценивания представляет собой таблицу с одним столбцом, в которой показано, как были выставлены оценки, а поведение представляет собой таблицу с двумя столбцами для определения поведения каждого учащегося. Выравнивание этих таблиц было выполнено с помощью сетки выравнивания с 12 столбцами, где таблицы оценок и поведения были помещены в столбцы столбцов 1 и 8 соответственно, создавая по 3 и 5 столбцов в каждой.

// 12-column table for alignment (grid).
 grid := c.NewTable(12)
 grid.SetMargins(0, 0, 50, 0)
 gradeInfoStyle := c.NewTextStyle()
 gradeInfoStyle.Font = font
 gradeInfoStyle.FontSize = 15
 // Grading system table.
 table = c.NewTable(1)
 drawCell(table, newPara(c, "Grading System:", boldStyle), cellStyles["gradingsys-head"])
 drawCell(table, newPara(c, "\u2022 A > 80%", gradeInfoStyle), cellStyles["gradingsys-row"])
 drawCell(table, newPara(c, "\u2022 B > 70%", gradeInfoStyle), cellStyles["gradingsys-row"])
 drawCell(table, newPara(c, "\u2022 C > 60%", gradeInfoStyle), cellStyles["gradingsys-row"])
 drawCell(table, newPara(c, "\u2022 D > 50%", gradeInfoStyle), cellStyles["gradingsys-row"])
 drawCell(table, newPara(c, "\u2022 F < 50%", gradeInfoStyle), cellStyles["gradingsys-row"])
 grid.MultiColCell(3).SetContent(table)
 grid.SkipCells(4)
 // Conduct table.
 table = c.NewTable(2)
 table.SetColumnWidths(0.6, 0.4)
 drawCell(table, newPara(c, "Conduct:", boldStyle), cellStyles["conduct-head"])
 table.SkipCells(1)
 drawCell(table, newPara(c, "Punctual:", gradeInfoStyle), cellStyles["conduct-key"])
 drawCell(table, newPara(c, string(card.Punctual), gradeInfoStyle), cellStyles["conduct-val"])
 drawCell(table, newPara(c, "Attentive:", gradeInfoStyle), cellStyles["conduct-key"])
 drawCell(table, newPara(c, string(card.Attentive), gradeInfoStyle), cellStyles["conduct-val"])
 drawCell(table, newPara(c, "Orderly:", gradeInfoStyle), cellStyles["conduct-key"])
 drawCell(table, newPara(c, string(card.Orderly), gradeInfoStyle), cellStyles["conduct-val"])
 drawCell(table, newPara(c, "Polite:", gradeInfoStyle), cellStyles["conduct-key"])
 drawCell(table, newPara(c, string(card.Polite), gradeInfoStyle), cellStyles["conduct-val"])
 grid.MultiColCell(5).SetContent(table)
 c.Draw(grid)

Создание выходного файла PDF

В конце концов, PDF-файл можно сгенерировать с помощью функции WriteToFile, которая использовалась в функции generateReports.

// Write to output file.
if err := c.WriteToFile(card.Name + "_marksheet.pdf"); err != nil {
 log.Fatal(err)
}

Вся функция

func generateReports(font, fontBold *model.PdfFont, cards []studentReportCard) error {
 for _, card := range cards {
 // Creating Reports
 c := creator.New()
 c.SetPageMargins(40, 40, 0, 0)
 // Filled rectangle on top.
 rect := c.NewRectangle(0, 0, creator.PageSizeLetter[0], 120)
 rect.SetFillColor(creator.ColorRGBFromHex("#dde4e5"))
 rect.SetBorderWidth(0)
 c.Draw(rect)
  headerStyle := c.NewTextStyle()
 headerStyle.FontSize = 50
 // Table with 1 column to center the text.
 table := c.NewTable(1)
 table.SetMargins(0, 0, 20, 0)
 drawCell(table, newPara(c, "Report Card", headerStyle), cellStyles["centered"])
 c.Draw(table)
 // Double line.
 line := c.NewLine(0, 120, creator.PageSizeLetter[0], 120)
 line.SetLineWidth(5)
 c.Draw(line)
 line = c.NewLine(0, 123, creator.PageSizeLetter[0], 123)
 line.SetLineWidth(1.5)
 c.Draw(line)
 // writing Marks
 writeMarks(c, font, fontBold, card)
 // Line on bottom.
 line = c.NewLine(0, creator.PageSizeLetter[1]-3, creator.PageSizeLetter[0], creator.PageSizeLetter[1]-3)
 line.SetLineWidth(5)
 c.Draw(line)
 line = c.NewLine(0, creator.PageSizeLetter[1], creator.PageSizeLetter[0], creator.PageSizeLetter[1])
 line.SetLineWidth(1.5)
 c.Draw(line)
 // Write to output file.
 if err := c.WriteToFile(card.Name + "_marksheet.pdf"); err != nil {
 log.Fatal(err)
 }
 }
 return nil
}

Заключительный отчет

Окончательный отчет после составления всех таблиц и добавления соответствующей информации выглядит следующим образом.

Представление

Наконец, мы хотим проверить производительность генерации нашего отчета.

Добавляем в начало нашего кода

func main() {
    start := time.Now() 

и в конце основной функции

end := time.Now()
    fmt.Printf("diff: %v\n", end.Sub(start))
}

Это дает нам общее время для создания всех 5 отчетов для 5 студентов. Результат, который мы получаем,

diff: 36.193497ms 

Итак, около 36,2 мс или 7,2 мс. Это означает, что за одну секунду мы можем генерировать сотни отчетов или в веб-системе мы можем предоставлять отчеты в формате PDF в режиме реального времени одним нажатием кнопки.

Пример игровой площадки: полный табель успеваемости учащихся

Полный код и вывод на нашу игровую площадку, где его можно редактировать и перегенерировать по желанию.

https://play.unidoc.io/p/98b800fa3f735b61

Вывод

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