Introdução
A Classe NfsReport foi criada com o objetivo de abstrair a crição de Planilhas Eletrônicas e manter as práticas correntes desse processo no NFS.
Criar e Manipular Planilha
/**
* Cria objeto NfsReport permintindo o preenchimento e formatação.
*
* @param array $options Opções da planilha
* $options = [
* 'title' => ?string = 'título do documento'
* 'subject' => ?string = 'assunto do documento'
* 'sheetName' => ?string = 'nome da planilha'
* 'userName' => ?string = 'nome do usuário'
* ];
*/
public static function createSpreadsheet(array $options): self
/**
* Cria uma nova aba em uma Planilha.
*
* @param string $sheetName Nome da aba / worksheet
* @param int $index Índice da aba / worksheet
*/
public function createSheet(string $sheetName, int $index = 0): self
/**
* Define planilha ativa por índice.
*
* @param int $index Índice da planilha (começa no 0)
*/
public function setActiveSheetByIndex(int $index): self
/**
* Define planilha ativa pelo nome da planilha.
*
* @param string $name Nome da planilha
*/
public function setActiveSheetByName(string $name): self
/**
* Define o título da planilha.
*
* @param string $title Título da planilha
*/
public function setTitle(string $title): self
/**
* Finaliza objeto e libera recursos alocados.
*/
public function close()
Manipulação de Dados
/**
* Define valor de uma célula.
*
* @param string $cell Referência da Célula [A1|..|ZN]
* @param mixed $value Valor da célula
* @param string $dataType Tipo de dado (Referência Constantes Tipos de Dado)
*/
public function setCellValue(string $cell, mixed $value, ?string $dataType = null): self
/**
* Preenche planilha com valores do array.
*
* @param array $rows Dados a adicionar
* @param string $cell Célula de referência para preenchimento
*/
public function addFromArray(array $rows, string $cell = 'A1'): self
/**
* Mescla celulas e preenche.
*
* @param string $reference Referência para mesclagem e preenchimento
* @param mixed $value Valor de preenchimento da célula mesclada
* @param mixed $wrapText Se o valor aceita quebra de linha ou não
*/
public function mergeCells(string $reference, mixed $value = null, bool $wrapText = true): self
/**
* Define explicitamento o tipo de dados de uma célula.
*
* @param string $cell Referência da célula
* @param string $dataType $dataType Tipo de dado
*/
public function setCellDataType(string $cell, string $dataType): self
/**
* Define a formatação de campos/bloco de células.
* IMPORTANTE: usar a string do formato, não as constantes definidas na classe.
*
* @param string $reference Referência da célula ('A1'..'Z9'|) ou bloco ('A1:C3'..'A1:Z5')
* @param string $format String do formato (Referência Constantes Tipos de Dado)
*/
public function setNumberFormat(string $reference, string $format): self
/**
* Insere imagem vinculada a uma célula.
*
* @param string $base64 Base64 da imagem que será inserida
* @param string $reference Referência da célula
* @param null|array $props Propriedades da imagem
* [height, width, name, description, offSetX, offSetY, rotation]
*/
public function addImageFromBase64(string $base64, string $reference, ?array $props = []): self
Formatação de Dados
/**
* Define largura da coluna.
*
* @param string $col Referência da coluna (A..Z..AA..ZZ)
* @param float $width Largura relativa ao tamanho da fonte
*/
public function setColWidth(string $col, float $width): self
/**
* Define altura da linha.
*
* @param int $row Referência da linha
* @param float $height Altura da linha relativa ao tamanho da fonte
*/
public function setRowHeight(int $row, float $height): self
/**
* Define referência para aplicação de propriedades.
*
* @param string $reference Célula ou bloco de células
*/
public function getStyle(string $reference): self
/**
* Aplica estilos usando array de propriedades.
* IMPORTANTE: usar a string do formato, não as constantes definidas na classe.
* Usar as strings definidas em cada propriedade (de acordo com os métodos dessa classe).
*
* @param array $props Propriedades definidas (Referência Externa Estilos)
*/
public function applyFromArray(array $props): self
/**
* Define o alinhamento da célula ou celulas.
*
* @param string $reference Referência para mesclagem e preenchimento
* @param string $horAlign Alinhamento horizontal (Referência Constantes Alinhamento Horizontal)
* @param string $vertAlign Alinhamento vertical (Referência Constantes Alinhamento Vertical)
* @param bool $wrapText Se o valor aceita quebra de linha ou não
*/
public function setAlignment($reference, $horAlign = 'general', $vertAlign = 'v-top', $wrapText = false): self
/**
* Define formatação da célula ou células.
*
* @param string $reference Referência para mesclagem e preenchimento
* @param float $fontSize Tamanho da fonte
* @param string $fontColor Cor da fonte
* @param bool $fontBold Se o texto estará em negrito ou não
* @param bool $fontItalic Se o texto estará em itálico ou não
* @param string $bgColor Cor de fundo / background
*/
public function setStyle(string $reference, float $fontSize = 11, ?string $fontColor = null, bool $fontBold = false, bool $fontItalic = false, ?string $bgColor = null): self
/**
* Tenta determinar a largura de uma coluna
* Se o parâmetro não for especificado, define autosize para todas as colunas preenchidas.
*
* @param string $col Referência da coluna (A-Z..AA..ZZ)
*/
public function autoSize(?string $col = null): self
/**
* Define célula/bloco como.
*
* @param string $reference Referência célula/bloco
* @param bool $prop Se o valor aceita quebra de linha ou não
*/
public function setWrapText(string $reference, bool $prop = true): self
Quando se exporta o crud list num excel os campos LOVN são exibidos juntos, para facilitar a quebra de linha foi criado o parâmetro CRUD_LIST_LOVN_LINE_BREAK para fazer o parse no excel.
CRUD_LIST_LOVN_LINE_BREAK
Referências
Constantes Definidas
Tipo de Preenchimento de Cor de Fundo / Background
Opções: 'none', 'solid', 'linear'
Alinhamento
Opções Horizontal: 'general', 'left', 'right', 'center', 'justify'
Opções Vertical: 'v-top', 'v-center', 'v-bottom', 'v-justify'
Tipos de Dado
Opções: 'string', 'formula', 'numeric', 'boolean', 'null', 'inline', 'error'
Tipos de Borda
Opções: 'none', 'dashDot', 'dashDotDot', 'dashed', 'dotted', 'double', 'hair', 'medium', 'mediumDashDot', 'mediumDashDotDot', 'mediumDashed', 'slantDashDot', 'thick', 'thin'
Fontes Sublinhadas / Underline
Opções: 'none', 'double', 'single'
Referências Externas
- Classe Base PhpSpreadsheet{target=_blank}.
- Formatos de Número{target=_blank}
- Definição de Estilos{target=_blank}
IMPORTANTE: nos relatórios gerados através da tabela nfs_reports o nome do objeto criado pelo processo foi definido como
$sheet(na versão antiga era$objPHPExcel). {.is-warning}
Casos de Uso
Criação e Preenchimento
$report = NfsReport::createSpreadsheet([
'title' => 'Planilha',
'subject' => 'Teste de classe NfsReport',
'userName' => 'Teste Unitário',
'sheetName' => 'Planilha Teste',
]);
$report->addFromArray([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
], 'A1');
$report->CreateSheet('Planilha 2', 1);
$report->addFromArray([
['Core', 'Dev', 'Support'],
['Simova', 'NFS', 'Report'],
], 'A1');
$report->setActiveSheetByIndex(0);
$report->addFromArray([
['Core', 'Dev', 'Support'],
['Simova', 'NFS', 'Report'],
], 'A5');
Criação, Preenchimento e Formatação
$report = NfsReport::createSpreadsheet([
'title' => 'Planilha',
'subject' => 'Teste de classe NfsReport',
'userName' => 'Teste Unitário',
]);
$report->addFromArray([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
], 'A1');
$report->getStyle('A1:E1')
->applyFromArray([
'fill' => [
'fillType' => 'solid',
'color' => [
'rgb' => 'FF0000',
],
],
'font' => [
'name' => 'Calibri',
'bold' => true,
'underline' => 'double',
'color' => [
'rgb' => 'FFFFFF',
],
'size' => 14.5,
],
'borders' => [
'allBorders' => [
'borderStyle' => 'double',
'color' => [
'argb' => '000000',
],
],
],
'alignment' => [
'horizontal' => 'center',
'vertical' => 'v-center',
'wrapText' => true,
],
'quotePrefix' => true,
]);
$report->getStyle('A2:E2')
->applyFromArray([
'fill' => [
'fillType' => 'solid',
'color' => [
'rgb' => '00FF83',
],
],
'font' => [
'name' => 'Arial',
'bold' => true,
'italic' => true,
'superscript' => true,
'underline' => 'single',
'strikethrough' => true,
'color' => [
'rgb' => '808080',
],
'size' => 11,
],
'borders' => [
'allBorders' => [
'borderStyle' => 'dashDot',
'color' => [
'rgb' => 'f9a11a',
],
],
],
'alignment' => [
'horizontal' => 'center',
'vertical' => 'v-center',
'wrapText' => true,
],
'quotePrefix' => true,
]);
$report->getStyle('A3:E4')
->applyFromArray([
'font' => [
'name' => 'Tahoma',
'superscript' => true,
'color' => [
'rgb' => 'FF000000',
],
'size' => 8,
],
]);
Outro Exemplo
$display_name = 'MSI';
$sheet = NfsReport::createSpreadsheet([
'title' => $display_name,
'subject' => $display_name,
'sheetName' => $display_name
]);
$row = 1;
$styleTitleCenter = [
'font' => [
'size' => 12,
'bold' => true,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'FFFFFF']
],
'alignment' => [
'horizontal' => 'center',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'FFFFFF']
]
]
];
$styleTitleLeft = [
'font' => [
'size' => 12,
'bold' => true,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'FFFFFF']
],
'alignment' => [
'horizontal' => 'left',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'FFFFFF']
]
]
];
$styleTitleRight = [
'font' => [
'size' => 12,
'bold' => true,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'FFFFFF']
],
'alignment' => [
'horizontal' => 'right',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'FFFFFF']
]
]
];
$styleHeadCenterBlue = [
'font' => [
'size' => 11,
'bold' => true,
'color' => ['rgb' => 'FFFFFF']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => '002060']
],
'alignment' => [
'horizontal' => 'center',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => '002060']
]
]
];
$styleHeadLeftBlue = [
'font' => [
'size' => 11,
'bold' => true,
'color' => ['rgb' => 'FFFFFF']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => '002060']
],
'alignment' => [
'horizontal' => 'left',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => '002060']
]
]
];
$styleHeadRightBlue = [
'font' => [
'size' => 11,
'bold' => true,
'color' => ['rgb' => 'FFFFFF']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => '002060']
],
'alignment' => [
'horizontal' => 'right',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => '002060']
]
]
];
$styleHeadCenterPurple = [
'font' => [
'size' => 11,
'bold' => true,
'color' => ['rgb' => 'FFFFFF']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => '421c5e']
],
'alignment' => [
'horizontal' => 'center',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => '421c5e']
]
]
];
$styleHeadLeftPurple = [
'font' => [
'size' => 11,
'bold' => true,
'color' => ['rgb' => 'FFFFFF']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => '421c5e']
],
'alignment' => [
'horizontal' => 'left',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => '421c5e']
]
]
];
$styleHeadRightPurple = [
'font' => [
'size' => 11,
'bold' => true,
'color' => ['rgb' => 'FFFFFF']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => '421c5e']
],
'alignment' => [
'horizontal' => 'right',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => '421c5e']
]
]
];
$styleCenterWhite = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'FFFFFF']
],
'alignment' => [
'horizontal' => 'center',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'FFFFFF']
]
]
];
$styleLeftWhite = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'FFFFFF']
],
'alignment' => [
'horizontal' => 'left',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'FFFFFF']
]
]
];
$styleRightWhite = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'FFFFFF']
],
'alignment' => [
'horizontal' => 'right',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'FFFFFF']
]
]
];
$styleCenterBlue = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'dae3f3']
],
'alignment' => [
'horizontal' => 'center',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'dae3f3']
]
]
];
$styleLeftBlue = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'dae3f3']
],
'alignment' => [
'horizontal' => 'left',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'dae3f3']
]
]
];
$styleRightBlue = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'dae3f3']
],
'alignment' => [
'horizontal' => 'right',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'dae3f3']
]
]
];
$styleLightBlue = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'dae3f3']
],
'alignment' => [
'horizontal' => 'right',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'dae3f3']
]
]
];
$styleDarkBlue = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'b4c7e7']
],
'alignment' => [
'horizontal' => 'right',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'b4c7e7']
]
]
];
$styleCenterPurple = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'ccccff']
],
'alignment' => [
'horizontal' => 'center',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'ccccff']
]
]
];
$styleLeftPurple = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'ccccff']
],
'alignment' => [
'horizontal' => 'left',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'ccccff']
]
]
];
$styleRightPurple = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'ccccff']
],
'alignment' => [
'horizontal' => 'right',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'ccccff']
]
]
];
$styleLightPurple = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => 'ccccff']
],
'alignment' => [
'horizontal' => 'right',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => 'ccccff']
]
]
];
$styleDarkPurple = [
'font' => [
'size' => 11,
'bold' => false,
'color' => ['rgb' => '000000']
],
'fill' => [
'fillType' => 'solid',
'color' => ['rgb' => '9b9bff']
],
'alignment' => [
'horizontal' => 'right',
'vertical' => 'v-center'
],
'borders' => [
'allBorders' => [
'borderStyle' => 'thin',
'color' => ['rgb' => '9b9bff']
]
]
];
foreach (range('A','X') as $column) {
$sheet->getColumnDimension($column)->setAutoSize(true);
}
foreach ($templateData['projeto_list'] as $s) {
$sheet->getStyle("A{$row}")->applyFromArray($styleTitleLeft);
$sheet->getStyle("B{$row}:I{$row}")->applyFromArray($styleTitleCenter);
$sheet->SetCellValue("A{$row}", 'DISCIPLINA');
$sheet->SetCellValue("B{$row}", 'PROJETO');
$sheet->SetCellValue("C{$row}", 'ÁREA');
$sheet->SetCellValue("D{$row}", 'SEMANA');
$sheet->SetCellValue("E{$row}", 'INFORMAÇÃO');
$sheet->SetCellValue("F{$row}", 'PROGRAMAÇÃO');
$sheet->SetCellValue("G{$row}", 'MEDIÇÃO');
$sheet->SetCellValue("H{$row}", 'Cód');
$sheet->SetCellValue("I{$row}", 'Unid.');
$row ++;
foreach ($templateData['processo_list'][$s['CHAVE']] as $p) {
$tipo_processo = $p['TIPO_PROCESSO'];
$styleHeadCenter = $styleHeadCenterBlue;
$styleHeadLeft = $styleHeadLeftBlue;
$styleHeadRight = $styleHeadRightBlue;
if ($tipo_processo == '1') {
$styleHeadCenter = $styleHeadCenterBlue;
$styleHeadLeft = $styleHeadLeftBlue;
$styleHeadRight = $styleHeadRightBlue;
} else {
$styleHeadCenter = $styleHeadCenterPurple;
$styleHeadLeft = $styleHeadLeftPurple;
$styleHeadRight = $styleHeadRightPurple;
}
$sheet->getStyle("A{$row}:I{$row}")->applyFromArray($styleHeadCenter);
$sheet->getStyle("A{$row}")->applyFromArray($styleHeadLeft);
$sheet->SetCellValue("A{$row}", $p['DISCIPLINA']);
$sheet->SetCellValue("B{$row}", $p['PROJETO']);
$sheet->getStyle("C{$row}")->applyFromArray($styleHeadLeft);
$sheet->SetCellValue("C{$row}", $p['AREA']);
$sheet->SetCellValue("D{$row}", $p['SEMANA']);
$sheet->getStyle("E{$row}")->applyFromArray($styleHeadLeft);
$sheet->SetCellValue("E{$row}", $p['INFORMACAO']);
$sheet->getStyle("F{$row}:G{$row}")->applyFromArray($styleHeadRight);
$sheet->SetCellValue("F{$row}", $p['PROGRAMACAO']);
$sheet->SetCellValue("G{$row}", $p['MEDICAO']);
$sheet->SetCellValue("H{$row}", $p['CODIGO']);
$sheet->SetCellValue("I{$row}", $p['UNIDADE']);
$row++;
foreach ($templateData['modulo_list'][$p['CHAVE']] as $m) {
$styleCenter = $styleCenterWhite;
$styleLeft = $styleLeftWhite;
$styleRight = $styleLightBlue;
if ($tipo_processo == '1') {
if (($row%2) == 1) {
$styleCenter = $styleCenterWhite;
$styleLeft = $styleLeftWhite;
$styleRight = $styleLightBlue;
} else {
$styleCenter = $styleCenterBlue;
$styleLeft = $styleLeftBlue;
$styleRight = $styleDarkBlue;
}
} else {
if (($row%2) == 1) {
$styleCenter = $styleCenterWhite;
$styleLeft = $styleLeftWhite;
$styleRight = $styleLightBlue;
} else {
$styleCenter = $styleCenterPurple;
$styleLeft = $styleLeftPurple;
$styleRight = $styleDarkPurple;
}
}
$sheet->getStyle("A{$row}:I{$row}")->applyFromArray($styleCenter);
$sheet->getStyle("A{$row}")->applyFromArray($styleLeft);
$sheet->SetCellValue("A{$row}", $m['DISCIPLINA']);
$sheet->SetCellValue("B{$row}", $m['PROJETO']);
$sheet->getStyle("C{$row}")->applyFromArray($styleLeft);
$sheet->SetCellValue("C{$row}", $m['AREA']);
$sheet->SetCellValue("D{$row}", $m['SEMANA']);
$sheet->getStyle("E{$row}")->applyFromArray($styleLeft);
$sheet->SetCellValue("E{$row}", $m['INFORMACAO']);
$sheet->getStyle("F{$row}:G{$row}")->applyFromArray($styleRight);
$sheet->SetCellValue("F{$row}", $m['PROGRAMACAO']);
$sheet->SetCellValue("G{$row}", $m['MEDICAO']);
$sheet->SetCellValue("H{$row}", $m['CODIGO']);
$sheet->SetCellValue("I{$row}", $m['UNIDADE']);
$row++;
}
$row++;
}
$row++;
}
Exemplo de Planilha com Multiplas Abas
// IMPORTANT: The variable $sheet is required to the report works!
$sheet = NfsReport::createSpreadsheet([
'title' => 'Relatorio Horas dos Tecnicos',
'subject' => 'Horas dos Técnicos',
'sheetName' => 'Resumo Geral',
]);
// ── Styles ────────────────────────────────────────────────────────────────────
$styleTitle = [
'font' => ['size' => 24, 'bold' => true, 'color' => ['rgb' => '000000']],
'fill' => ['fillType' => 'solid', 'color' => ['rgb' => 'E5E5E5']],
'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
'borders' => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '000000']]],
];
$styleTitleCenter = [
'font' => ['size' => 12, 'bold' => true, 'color' => ['rgb' => '000000']],
'fill' => ['fillType' => 'solid', 'color' => ['rgb' => 'FFFFFF']],
'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
'borders' => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '000000']]],
];
$styleTitleCenterGray = [
'font' => ['size' => 12, 'bold' => true, 'color' => ['rgb' => '000000']],
'fill' => ['fillType' => 'solid', 'color' => ['rgb' => 'DCDCDC']],
'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
'borders' => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '000000']]],
];
$styleCenterWhite = [
'font' => ['size' => 11, 'bold' => false, 'color' => ['rgb' => '000000']],
'fill' => ['fillType' => 'solid', 'color' => ['rgb' => 'FFFFFF']],
'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
'borders' => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '000000']]],
];
$styleCenterRed = [
'font' => ['size' => 11, 'bold' => false, 'color' => ['rgb' => '000000']],
'fill' => ['fillType' => 'solid', 'color' => ['rgb' => 'FF9999']],
'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
'borders' => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '000000']]],
];
$styleCenterYellow = [
'font' => ['size' => 11, 'bold' => true, 'color' => ['rgb' => '000000']],
'fill' => ['fillType' => 'solid', 'color' => ['rgb' => 'FFFF99']],
'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
'borders' => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '000000']]],
];
$styleCenterGray = [
'font' => ['size' => 11, 'bold' => false, 'color' => ['rgb' => '000000']],
'fill' => ['fillType' => 'solid', 'color' => ['rgb' => 'DCDCDC']],
'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
'borders' => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '000000']]],
];
// ── Fake data per sheet ───────────────────────────────────────────────────────
$sheets = [
[
'name' => 'Resumo Geral',
'title' => 'CONTROLE DE TEMPO DE CHAMADO X ATENDIMENTO — GERAL',
'dados_list' => [
['DATA_CHAMADO' => '2024-03-01 08:15', 'FLAG_MAQUINA_PARADA' => 'SIM', 'NUMERO_OS' => 'OS-1001', 'TIPO_OS' => 'Corretiva', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Agro São Paulo', 'DATA_ATENDIMENTO' => '2024-03-01 09:45', 'TEMPO_ATENDIMENTO' => 1.50, 'DATA_CONCLUSAO' => '2024-03-01 14:00', 'TEMPO_CONCLUSAO' => 4.25, 'TECNICO' => 'Carlos Silva'],
['DATA_CHAMADO' => '2024-03-02 10:00', 'FLAG_MAQUINA_PARADA' => 'NÃO', 'NUMERO_OS' => 'OS-1002', 'TIPO_OS' => 'Preventiva', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Fazenda Boa Vista', 'DATA_ATENDIMENTO' => '2024-03-02 12:30', 'TEMPO_ATENDIMENTO' => 2.50, 'DATA_CONCLUSAO' => '2024-03-02 18:00', 'TEMPO_CONCLUSAO' => 5.50, 'TECNICO' => 'Marcos Oliveira'],
['DATA_CHAMADO' => '2024-03-03 07:30', 'FLAG_MAQUINA_PARADA' => 'SIM', 'NUMERO_OS' => 'OS-1003', 'TIPO_OS' => 'Corretiva', 'STATUS_OS' => 'Em andamento', 'CLIENTE' => 'Transportes Rápido','DATA_ATENDIMENTO' => '2024-03-03 11:00', 'TEMPO_ATENDIMENTO' => 3.50, 'DATA_CONCLUSAO' => '2024-03-03 17:30', 'TEMPO_CONCLUSAO' => 32.00, 'TECNICO' => 'Ana Ferreira'],
['DATA_CHAMADO' => '2024-03-04 09:00', 'FLAG_MAQUINA_PARADA' => 'NÃO', 'NUMERO_OS' => 'OS-1004', 'TIPO_OS' => 'Revisão', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Mineradora Delta', 'DATA_ATENDIMENTO' => '2024-03-04 10:00', 'TEMPO_ATENDIMENTO' => 1.00, 'DATA_CONCLUSAO' => '2024-03-04 13:00', 'TEMPO_CONCLUSAO' => 3.00, 'TECNICO' => 'João Pereira'],
['DATA_CHAMADO' => '2024-03-05 13:00', 'FLAG_MAQUINA_PARADA' => 'SIM', 'NUMERO_OS' => 'OS-1005', 'TIPO_OS' => 'Corretiva', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Logística Sul', 'DATA_ATENDIMENTO' => '2024-03-05 16:30', 'TEMPO_ATENDIMENTO' => 3.50, 'DATA_CONCLUSAO' => '2024-03-05 20:00', 'TEMPO_CONCLUSAO' => 35.00, 'TECNICO' => 'Paula Ramos'],
],
'media_atendimento' => 2.40,
'media_conclusao' => 15.95,
'dados_tecnico_list' => [
['TECNICO' => 'Carlos Silva', 'MEDIA_ATENDIMENTO' => 1.50, 'MEDIA_CONCLUSAO' => 4.25, 'TEMPO_ATENDIMENTO' => 1.50, 'QTD_ATENDIMENTO' => 1, 'TEMPO_CONCLUSAO' => 4.25],
['TECNICO' => 'Marcos Oliveira', 'MEDIA_ATENDIMENTO' => 2.50, 'MEDIA_CONCLUSAO' => 5.50, 'TEMPO_ATENDIMENTO' => 2.50, 'QTD_ATENDIMENTO' => 1, 'TEMPO_CONCLUSAO' => 5.50],
['TECNICO' => 'Ana Ferreira', 'MEDIA_ATENDIMENTO' => 3.50, 'MEDIA_CONCLUSAO' => 32.00, 'TEMPO_ATENDIMENTO' => 3.50, 'QTD_ATENDIMENTO' => 1, 'TEMPO_CONCLUSAO' => 32.00],
['TECNICO' => 'João Pereira', 'MEDIA_ATENDIMENTO' => 1.00, 'MEDIA_CONCLUSAO' => 3.00, 'TEMPO_ATENDIMENTO' => 1.00, 'QTD_ATENDIMENTO' => 1, 'TEMPO_CONCLUSAO' => 3.00],
['TECNICO' => 'Paula Ramos', 'MEDIA_ATENDIMENTO' => 3.50, 'MEDIA_CONCLUSAO' => 35.00, 'TEMPO_ATENDIMENTO' => 3.50, 'QTD_ATENDIMENTO' => 1, 'TEMPO_CONCLUSAO' => 35.00],
],
],
[
'name' => 'Carlos Silva',
'title' => 'CONTROLE DE TEMPO DE CHAMADO X ATENDIMENTO — CARLOS SILVA',
'dados_list' => [
['DATA_CHAMADO' => '2024-03-01 08:15', 'FLAG_MAQUINA_PARADA' => 'SIM', 'NUMERO_OS' => 'OS-1001', 'TIPO_OS' => 'Corretiva', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Agro São Paulo', 'DATA_ATENDIMENTO' => '2024-03-01 09:45', 'TEMPO_ATENDIMENTO' => 1.50, 'DATA_CONCLUSAO' => '2024-03-01 14:00', 'TEMPO_CONCLUSAO' => 4.25, 'TECNICO' => 'Carlos Silva'],
['DATA_CHAMADO' => '2024-03-06 08:00', 'FLAG_MAQUINA_PARADA' => 'NÃO', 'NUMERO_OS' => 'OS-1006', 'TIPO_OS' => 'Preventiva', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Frigorífico Norte', 'DATA_ATENDIMENTO' => '2024-03-06 10:30', 'TEMPO_ATENDIMENTO' => 2.50, 'DATA_CONCLUSAO' => '2024-03-06 15:00', 'TEMPO_CONCLUSAO' => 4.50, 'TECNICO' => 'Carlos Silva'],
['DATA_CHAMADO' => '2024-03-07 14:00', 'FLAG_MAQUINA_PARADA' => 'SIM', 'NUMERO_OS' => 'OS-1007', 'TIPO_OS' => 'Corretiva', 'STATUS_OS' => 'Em andamento', 'CLIENTE' => 'Construtora ABC', 'DATA_ATENDIMENTO' => '2024-03-07 17:00', 'TEMPO_ATENDIMENTO' => 3.00, 'DATA_CONCLUSAO' => '2024-03-07 22:00', 'TEMPO_CONCLUSAO' => 31.00, 'TECNICO' => 'Carlos Silva'],
],
'media_atendimento' => 2.33,
'media_conclusao' => 13.25,
'dados_tecnico_list' => [
['TECNICO' => 'Carlos Silva', 'MEDIA_ATENDIMENTO' => 2.33, 'MEDIA_CONCLUSAO' => 13.25, 'TEMPO_ATENDIMENTO' => 7.00, 'QTD_ATENDIMENTO' => 3, 'TEMPO_CONCLUSAO' => 39.75],
],
],
[
'name' => 'Marcos Oliveira',
'title' => 'CONTROLE DE TEMPO DE CHAMADO X ATENDIMENTO — MARCOS OLIVEIRA',
'dados_list' => [
['DATA_CHAMADO' => '2024-03-02 10:00', 'FLAG_MAQUINA_PARADA' => 'NÃO', 'NUMERO_OS' => 'OS-1002', 'TIPO_OS' => 'Preventiva', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Fazenda Boa Vista', 'DATA_ATENDIMENTO' => '2024-03-02 12:30', 'TEMPO_ATENDIMENTO' => 2.50, 'DATA_CONCLUSAO' => '2024-03-02 18:00', 'TEMPO_CONCLUSAO' => 5.50, 'TECNICO' => 'Marcos Oliveira'],
['DATA_CHAMADO' => '2024-03-08 07:00', 'FLAG_MAQUINA_PARADA' => 'SIM', 'NUMERO_OS' => 'OS-1008', 'TIPO_OS' => 'Corretiva', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Distribuidora Leste', 'DATA_ATENDIMENTO' => '2024-03-08 10:00', 'TEMPO_ATENDIMENTO' => 3.00, 'DATA_CONCLUSAO' => '2024-03-08 16:30', 'TEMPO_CONCLUSAO' => 33.00, 'TECNICO' => 'Marcos Oliveira'],
['DATA_CHAMADO' => '2024-03-09 09:30', 'FLAG_MAQUINA_PARADA' => 'NÃO', 'NUMERO_OS' => 'OS-1009', 'TIPO_OS' => 'Revisão', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Porto Seco Sul', 'DATA_ATENDIMENTO' => '2024-03-09 11:00', 'TEMPO_ATENDIMENTO' => 1.50, 'DATA_CONCLUSAO' => '2024-03-09 14:00', 'TEMPO_CONCLUSAO' => 3.00, 'TECNICO' => 'Marcos Oliveira'],
],
'media_atendimento' => 2.33,
'media_conclusao' => 13.83,
'dados_tecnico_list' => [
['TECNICO' => 'Marcos Oliveira', 'MEDIA_ATENDIMENTO' => 2.33, 'MEDIA_CONCLUSAO' => 13.83, 'TEMPO_ATENDIMENTO' => 7.00, 'QTD_ATENDIMENTO' => 3, 'TEMPO_CONCLUSAO' => 41.50],
],
],
[
'name' => 'Ana Ferreira',
'title' => 'CONTROLE DE TEMPO DE CHAMADO X ATENDIMENTO — ANA FERREIRA',
'dados_list' => [
['DATA_CHAMADO' => '2024-03-03 07:30', 'FLAG_MAQUINA_PARADA' => 'SIM', 'NUMERO_OS' => 'OS-1003', 'TIPO_OS' => 'Corretiva', 'STATUS_OS' => 'Em andamento', 'CLIENTE' => 'Transportes Rápido', 'DATA_ATENDIMENTO' => '2024-03-03 11:00', 'TEMPO_ATENDIMENTO' => 3.50, 'DATA_CONCLUSAO' => '2024-03-03 17:30', 'TEMPO_CONCLUSAO' => 32.00, 'TECNICO' => 'Ana Ferreira'],
['DATA_CHAMADO' => '2024-03-10 08:00', 'FLAG_MAQUINA_PARADA' => 'NÃO', 'NUMERO_OS' => 'OS-1010', 'TIPO_OS' => 'Preventiva', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Agropecuária Verde', 'DATA_ATENDIMENTO' => '2024-03-10 09:30', 'TEMPO_ATENDIMENTO' => 1.50, 'DATA_CONCLUSAO' => '2024-03-10 12:00', 'TEMPO_CONCLUSAO' => 2.50, 'TECNICO' => 'Ana Ferreira'],
['DATA_CHAMADO' => '2024-03-11 13:00', 'FLAG_MAQUINA_PARADA' => 'SIM', 'NUMERO_OS' => 'OS-1011', 'TIPO_OS' => 'Corretiva', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Usina Esperança', 'DATA_ATENDIMENTO' => '2024-03-11 16:00', 'TEMPO_ATENDIMENTO' => 3.00, 'DATA_CONCLUSAO' => '2024-03-11 20:30', 'TEMPO_CONCLUSAO' => 34.00, 'TECNICO' => 'Ana Ferreira'],
],
'media_atendimento' => 2.67,
'media_conclusao' => 22.83,
'dados_tecnico_list' => [
['TECNICO' => 'Ana Ferreira', 'MEDIA_ATENDIMENTO' => 2.67, 'MEDIA_CONCLUSAO' => 22.83, 'TEMPO_ATENDIMENTO' => 8.00, 'QTD_ATENDIMENTO' => 3, 'TEMPO_CONCLUSAO' => 68.50],
],
],
[
'name' => 'João e Paula',
'title' => 'CONTROLE DE TEMPO DE CHAMADO X ATENDIMENTO — JOÃO E PAULA',
'dados_list' => [
['DATA_CHAMADO' => '2024-03-04 09:00', 'FLAG_MAQUINA_PARADA' => 'NÃO', 'NUMERO_OS' => 'OS-1004', 'TIPO_OS' => 'Revisão', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Mineradora Delta', 'DATA_ATENDIMENTO' => '2024-03-04 10:00', 'TEMPO_ATENDIMENTO' => 1.00, 'DATA_CONCLUSAO' => '2024-03-04 13:00', 'TEMPO_CONCLUSAO' => 3.00, 'TECNICO' => 'João Pereira'],
['DATA_CHAMADO' => '2024-03-05 13:00', 'FLAG_MAQUINA_PARADA' => 'SIM', 'NUMERO_OS' => 'OS-1005', 'TIPO_OS' => 'Corretiva', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Logística Sul', 'DATA_ATENDIMENTO' => '2024-03-05 16:30', 'TEMPO_ATENDIMENTO' => 3.50, 'DATA_CONCLUSAO' => '2024-03-05 20:00', 'TEMPO_CONCLUSAO' => 35.00, 'TECNICO' => 'Paula Ramos'],
['DATA_CHAMADO' => '2024-03-12 08:30', 'FLAG_MAQUINA_PARADA' => 'NÃO', 'NUMERO_OS' => 'OS-1012', 'TIPO_OS' => 'Revisão', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Cerealista Norte', 'DATA_ATENDIMENTO' => '2024-03-12 10:00', 'TEMPO_ATENDIMENTO' => 1.50, 'DATA_CONCLUSAO' => '2024-03-12 13:30', 'TEMPO_CONCLUSAO' => 3.50, 'TECNICO' => 'João Pereira'],
['DATA_CHAMADO' => '2024-03-13 11:00', 'FLAG_MAQUINA_PARADA' => 'SIM', 'NUMERO_OS' => 'OS-1013', 'TIPO_OS' => 'Corretiva', 'STATUS_OS' => 'Concluída', 'CLIENTE' => 'Armazém Central', 'DATA_ATENDIMENTO' => '2024-03-13 14:30', 'TEMPO_ATENDIMENTO' => 3.50, 'DATA_CONCLUSAO' => '2024-03-13 19:00', 'TEMPO_CONCLUSAO' => 32.00, 'TECNICO' => 'Paula Ramos'],
],
'media_atendimento' => 2.38,
'media_conclusao' => 18.38,
'dados_tecnico_list' => [
['TECNICO' => 'João Pereira', 'MEDIA_ATENDIMENTO' => 1.25, 'MEDIA_CONCLUSAO' => 3.25, 'TEMPO_ATENDIMENTO' => 2.50, 'QTD_ATENDIMENTO' => 2, 'TEMPO_CONCLUSAO' => 6.50],
['TECNICO' => 'Paula Ramos', 'MEDIA_ATENDIMENTO' => 3.50, 'MEDIA_CONCLUSAO' => 33.50, 'TEMPO_ATENDIMENTO' => 7.00, 'QTD_ATENDIMENTO' => 2, 'TEMPO_CONCLUSAO' => 67.00],
],
],
];
// ── Build all sheets ──────────────────────────────────────────────────────────
foreach ($sheets as $index => $sheetData) {
$sheet->createSheet($sheetData['name'], $index);
$row = 1;
// Column widths
$sheet->autoSize();
$sheet->setColWidth('A', 100);
// Title
$sheet->mergeCells("A{$row}:K{$row}", $sheetData['title']);
$sheet->getStyle("A{$row}:K{$row}")->applyFromArray($styleTitle);
$sheet->setRowHeight($row, 40);
$row++;
// Header
$sheet->getStyle("A{$row}:K{$row}")->applyFromArray($styleTitleCenter);
$sheet->setCellValue("A{$row}", 'DATA/HORA DO CHAMADO');
$sheet->setCellValue("B{$row}", 'MAQUINA PARADA?');
$sheet->setCellValue("C{$row}", 'No O.S.');
$sheet->setCellValue("D{$row}", 'TIPO O.S.');
$sheet->setCellValue("E{$row}", 'STATUS O.S.');
$sheet->setCellValue("F{$row}", 'CLIENTE');
$sheet->setCellValue("G{$row}", 'DATA/HORA ATENDIMENTO');
$sheet->setCellValue("H{$row}", 'TEMPO DE ATENDIMENTO');
$sheet->setCellValue("I{$row}", 'DATA/HORA CONCLUSÃO DO SERVIÇO');
$sheet->setCellValue("J{$row}", 'TEMPO DE CONCLUSÃO DO SERVIÇO');
$sheet->setCellValue("K{$row}", 'PRODUTIVO RESPONSÁVEL');
$row++;
// Data rows
foreach ($sheetData['dados_list'] as $r) {
$styleTempoAtendimento = $r['TEMPO_ATENDIMENTO'] >= 2 ? $styleCenterRed : $styleCenterWhite;
$styleTempoConclusao = $r['TEMPO_CONCLUSAO'] >= 30 ? $styleCenterRed : $styleCenterWhite;
$sheet->getStyle("A{$row}:K{$row}")->applyFromArray($styleCenterWhite);
$sheet->setCellValue("A{$row}", $r['DATA_CHAMADO']);
$sheet->setCellValue("B{$row}", $r['FLAG_MAQUINA_PARADA']);
$sheet->setCellValue("C{$row}", $r['NUMERO_OS']);
$sheet->setCellValue("D{$row}", $r['TIPO_OS']);
$sheet->setCellValue("E{$row}", $r['STATUS_OS']);
$sheet->setCellValue("F{$row}", $r['CLIENTE']);
$sheet->setCellValue("G{$row}", $r['DATA_ATENDIMENTO']);
$sheet->getStyle("H{$row}")->applyFromArray($styleTempoAtendimento);
$sheet->setCellValue("H{$row}", $r['TEMPO_ATENDIMENTO']);
$sheet->setNumberFormat("H{$row}", '0.00');
$sheet->setCellValue("I{$row}", $r['DATA_CONCLUSAO']);
$sheet->getStyle("J{$row}")->applyFromArray($styleTempoConclusao);
$sheet->setCellValue("J{$row}", $r['TEMPO_CONCLUSAO']);
$sheet->setNumberFormat("J{$row}", '0.00');
$sheet->setCellValue("K{$row}", $r['TECNICO']);
$row++;
}
// General average
$sheet->getStyle("A{$row}:K{$row}")->applyFromArray($styleTitleCenter);
$sheet->mergeCells("A{$row}:E{$row}");
$sheet->mergeCells("F{$row}:G{$row}", 'MEDIA GERAL');
$sheet->getStyle("H{$row}")->applyFromArray($styleCenterYellow);
$sheet->setCellValue("H{$row}", $sheetData['media_atendimento']);
$sheet->setNumberFormat("H{$row}", '0.00');
$sheet->setCellValue("I{$row}", '');
$sheet->getStyle("J{$row}")->applyFromArray($styleCenterYellow);
$sheet->setCellValue("J{$row}", $sheetData['media_conclusao']);
$sheet->setNumberFormat("J{$row}", '0.00');
$sheet->setCellValue("K{$row}", '');
$row++;
// Separator
$sheet->mergeCells("A{$row}:K{$row}");
$row++;
// Per-technician section header
$sheet->mergeCells("A{$row}:E{$row}");
$sheet->getStyle("F{$row}:H{$row}")->applyFromArray($styleTitleCenter);
$sheet->mergeCells("F{$row}:H{$row}", 'CONTROLE DE MEDIA POR TECNICO');
$sheet->getStyle("I{$row}:K{$row}")->applyFromArray($styleTitleCenterGray);
$sheet->mergeCells("I{$row}:K{$row}", 'DADOS');
$row++;
$sheet->mergeCells("A{$row}:E{$row}");
$sheet->getStyle("F{$row}:H{$row}")->applyFromArray($styleTitleCenter);
$sheet->setCellValue("F{$row}", 'NOME');
$sheet->setCellValue("G{$row}", 'ATENDIMENTO');
$sheet->setCellValue("H{$row}", 'CONCLUSÃO REPARO');
$sheet->getStyle("I{$row}:K{$row}")->applyFromArray($styleTitleCenterGray);
$sheet->setCellValue("I{$row}", 'TOTAL DE TEMPO DE ATENDIMENTO');
$sheet->setCellValue("J{$row}", 'TOTAL DE ATENDIMENTOS');
$sheet->setCellValue("K{$row}", 'TOTAL DE TEMPO DE REPARO');
$row++;
// Per-technician data rows
foreach ($sheetData['dados_tecnico_list'] as $f) {
$sheet->mergeCells("A{$row}:E{$row}");
$sheet->getStyle("F{$row}:H{$row}")->applyFromArray($styleCenterWhite);
$sheet->setCellValue("F{$row}", $f['TECNICO']);
$sheet->setCellValue("G{$row}", $f['MEDIA_ATENDIMENTO']);
$sheet->setNumberFormat("G{$row}", '0.00');
$sheet->setCellValue("H{$row}", $f['MEDIA_CONCLUSAO']);
$sheet->setNumberFormat("H{$row}", '0.00');
$sheet->getStyle("I{$row}:K{$row}")->applyFromArray($styleCenterGray);
$sheet->setCellValue("I{$row}", $f['TEMPO_ATENDIMENTO']);
$sheet->setNumberFormat("I{$row}", '0.00');
$sheet->setCellValue("J{$row}", $f['QTD_ATENDIMENTO']);
$sheet->setCellValue("K{$row}", $f['TEMPO_CONCLUSAO']);
$sheet->setNumberFormat("K{$row}", '0.00');
$row++;
}
}
// Back to first sheet before saving
$sheet->setActiveSheetByIndex(0);