Доработал отчет для экономистов
This commit is contained in:
296
app/Exports/Sheets/StatisticsEconomistData.php
Normal file
296
app/Exports/Sheets/StatisticsEconomistData.php
Normal file
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exports\Sheets;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Maatwebsite\Excel\Concerns\FromArray;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
use Maatwebsite\Excel\Concerns\WithStyles;
|
||||
use Maatwebsite\Excel\Concerns\WithTitle;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Alignment;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Border;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
|
||||
class StatisticsEconomistData implements FromArray, WithHeadings, WithMapping, WithStyles, WithTitle
|
||||
{
|
||||
/**
|
||||
* Сводная строка + строки по отделениям, в порядке отображения на листе.
|
||||
*/
|
||||
private array $allRows;
|
||||
|
||||
public function __construct(
|
||||
private string $sheetTitle,
|
||||
private string $reportName,
|
||||
private array $rows,
|
||||
private array $dateRange,
|
||||
private User $user,
|
||||
private array $grandTotals = [],
|
||||
private array $profitTypes = []
|
||||
) {
|
||||
$summary = [
|
||||
['isGroupHeader' => true, 'groupName' => 'СВОДНАЯ ИНФОРМАЦИЯ (ВСЕ ОТДЕЛЕНИЯ)'],
|
||||
array_merge(['isTotalRow' => true], $this->grandTotals),
|
||||
];
|
||||
|
||||
$this->allRows = array_merge($summary, $this->rows);
|
||||
}
|
||||
|
||||
public function title(): string
|
||||
{
|
||||
return $this->sheetTitle;
|
||||
}
|
||||
|
||||
public function array(): array
|
||||
{
|
||||
return $this->allRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Заголовки (с вложенной структурой)
|
||||
*/
|
||||
public function headings(): array
|
||||
{
|
||||
$profitTypeLabels = array_values($this->profitTypes);
|
||||
$countTypes = count($profitTypeLabels);
|
||||
|
||||
$topRow = array_merge(
|
||||
['Отделение', 'Поступило по типу оплаты'],
|
||||
array_fill(0, max($countTypes - 1, 0), ''),
|
||||
['Всего']
|
||||
);
|
||||
|
||||
$subRow = array_merge([''], $profitTypeLabels, ['']);
|
||||
|
||||
return [
|
||||
// Шапка отчета (первые 3 строки)
|
||||
[$this->reportName],
|
||||
['Дата создания: '.now()->format('d.m.Y H:i:s')],
|
||||
[$this->formatDateRange()],
|
||||
[], // Пустая строка для отступа
|
||||
|
||||
// Первый уровень заголовков (с объединением)
|
||||
$topRow,
|
||||
|
||||
// Второй уровень заголовков (детализация по типам оплаты)
|
||||
$subRow,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Форматирование дат для шапки
|
||||
*/
|
||||
protected function formatDateRange(): string
|
||||
{
|
||||
if (isset($this->dateRange[0]) && isset($this->dateRange[1])) {
|
||||
$startAt = Carbon::create($this->dateRange[0])->format('d.m.Y H:i');
|
||||
$endAt = Carbon::create($this->dateRange[1])->format('d.m.Y H:i');
|
||||
|
||||
return 'Период: '.$startAt.' - '.$endAt;
|
||||
}
|
||||
|
||||
return 'Период: За весь период';
|
||||
}
|
||||
|
||||
/**
|
||||
* Маппинг данных для каждой строки
|
||||
*/
|
||||
public function map($row): array
|
||||
{
|
||||
$profitTypeIds = array_keys($this->profitTypes);
|
||||
|
||||
// Заголовок группы (название группы отделений / "Сводная информация")
|
||||
if (isset($row['isGroupHeader']) && $row['isGroupHeader']) {
|
||||
return array_merge([$row['groupName']], array_fill(0, count($profitTypeIds) + 1, ''));
|
||||
}
|
||||
|
||||
// Обычное отделение и итоговые строки имеют одинаковую форму: department/counts/total
|
||||
$counts = $row['counts'] ?? [];
|
||||
|
||||
$cells = [$row['department'] ?? ''];
|
||||
foreach ($profitTypeIds as $profitTypeId) {
|
||||
$cells[] = $this->formatZero($counts[$profitTypeId] ?? 0);
|
||||
}
|
||||
$cells[] = $this->formatZero($row['total'] ?? 0);
|
||||
|
||||
return $cells;
|
||||
}
|
||||
|
||||
/**
|
||||
* Стилизация Excel файла
|
||||
*/
|
||||
public function styles(Worksheet $sheet)
|
||||
{
|
||||
// Поля (уменьшаем для экономии места)
|
||||
$sheet->getPageMargins()->setLeft(0.2);
|
||||
$sheet->getPageMargins()->setRight(0.2);
|
||||
$sheet->getPageMargins()->setTop(0.2);
|
||||
$sheet->getPageMargins()->setBottom(0.2);
|
||||
|
||||
$sheet->getPageSetup()->setPaperSize(PageSetup::PAPERSIZE_A4);
|
||||
$sheet->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE);
|
||||
|
||||
$sheet->getPageSetup()->setFitToPage(true);
|
||||
$sheet->getPageSetup()->setFitToWidth(1);
|
||||
$sheet->getPageSetup()->setFitToHeight(1);
|
||||
|
||||
$highestRow = $sheet->getHighestRow();
|
||||
|
||||
$countTypes = count($this->profitTypes);
|
||||
$totalColumns = $countTypes + 2; // Отделение + типы оплаты + Всего
|
||||
$highestColumn = Coordinate::stringFromColumnIndex($totalColumns);
|
||||
$firstTypeColumn = Coordinate::stringFromColumnIndex(2); // B
|
||||
$lastTypeColumn = Coordinate::stringFromColumnIndex(1 + $countTypes);
|
||||
|
||||
// ОБЪЕДИНЕНИЕ ЯЧЕЕК ДЛЯ ШАПКИ (строки 1-3)
|
||||
$sheet->mergeCells('A1:'.$highestColumn.'1');
|
||||
$sheet->mergeCells('A2:'.$highestColumn.'2');
|
||||
$sheet->mergeCells('A3:'.$highestColumn.'3');
|
||||
|
||||
// ОБЪЕДИНЕНИЕ ДЛЯ ОБЫЧНЫХ ЗАГОЛОВКОВ (Отделение, Всего — по одной колонке на 2 строки)
|
||||
$sheet->mergeCells('A5:A6');
|
||||
$sheet->mergeCells($highestColumn.'5:'.$highestColumn.'6');
|
||||
|
||||
// ОБЪЕДИНЕНИЕ ДЛЯ ВЛОЖЕННОГО ЗАГОЛОВКА "Поступило по типу оплаты"
|
||||
$sheet->mergeCells($firstTypeColumn.'5:'.$lastTypeColumn.'5');
|
||||
$sheet->setCellValue($firstTypeColumn.'5', 'Поступило по типу оплаты');
|
||||
|
||||
// СТИЛИ ДЛЯ ШАПКИ ОТЧЕТА (строки 1-3)
|
||||
$sheet->getStyle('A1:A3')->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
'size' => 14,
|
||||
],
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_LEFT,
|
||||
'vertical' => Alignment::VERTICAL_CENTER,
|
||||
],
|
||||
]);
|
||||
|
||||
// СТИЛИ ДЛЯ ЗАГОЛОВКОВ (строки 5 и 6)
|
||||
$sheet->getStyle('A5:'.$highestColumn.'6')->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
'color' => ['argb' => '000000'],
|
||||
'size' => 11,
|
||||
],
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
||||
'vertical' => Alignment::VERTICAL_CENTER,
|
||||
'wrapText' => true,
|
||||
],
|
||||
'borders' => [
|
||||
'allBorders' => [
|
||||
'borderStyle' => Border::BORDER_THIN,
|
||||
'color' => ['argb' => '2d2d30'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
// СТИЛИ ДЛЯ ВСЕХ СТРОК С ДАННЫМИ
|
||||
$indexData = 0;
|
||||
for ($row = 7; $row <= $highestRow; $row++) {
|
||||
$currentRowInData = $this->allRows[$indexData];
|
||||
|
||||
// Заголовки групп (Сводная информация, Хирургические отделения, Терапевтические отделения...)
|
||||
if (array_key_exists('isGroupHeader', $currentRowInData)) {
|
||||
$sheet->getStyle('A'.$row.':'.$highestColumn.$row)->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
'size' => 11,
|
||||
],
|
||||
'fill' => [
|
||||
'fillType' => Fill::FILL_SOLID,
|
||||
'startColor' => ['argb' => 'D9E1F2'], // Светло-синий
|
||||
],
|
||||
]);
|
||||
|
||||
$sheet->mergeCells('A'.$row.':'.$highestColumn.$row);
|
||||
}
|
||||
|
||||
// Итоговые строки (ИТОГО:, ОБЩИЕ ИТОГИ:)
|
||||
if (array_key_exists('isTotalRow', $currentRowInData)) {
|
||||
$sheet->getStyle('A'.$row.':'.$highestColumn.$row)->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
],
|
||||
'fill' => [
|
||||
'fillType' => Fill::FILL_SOLID,
|
||||
'startColor' => ['argb' => 'F2F2F2'], // Серый
|
||||
],
|
||||
'borders' => [
|
||||
'top' => [
|
||||
'borderStyle' => Border::BORDER_MEDIUM,
|
||||
'color' => ['argb' => '000000'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
if ($indexData < count($this->allRows) - 1) {
|
||||
$indexData++;
|
||||
}
|
||||
}
|
||||
|
||||
// ГРАНИЦЫ ДЛЯ ВСЕЙ ТАБЛИЦЫ
|
||||
$sheet->getStyle('A5:'.$highestColumn.$highestRow)->applyFromArray([
|
||||
'borders' => [
|
||||
'allBorders' => [
|
||||
'borderStyle' => Border::BORDER_THIN,
|
||||
'color' => ['argb' => '000000'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
// ВЫРАВНИВАНИЕ ДЛЯ ЧИСЛОВЫХ КОЛОНОК
|
||||
$sheet->getStyle('B7:'.$highestColumn.$highestRow)->applyFromArray([
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
||||
],
|
||||
]);
|
||||
|
||||
// ВЫРАВНИВАНИЕ ДЛЯ НАЗВАНИЙ ОТДЕЛЕНИЙ
|
||||
$sheet->getStyle('A7:A'.$highestRow)->applyFromArray([
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_LEFT,
|
||||
'vertical' => Alignment::VERTICAL_CENTER,
|
||||
],
|
||||
]);
|
||||
|
||||
// Ширина колонок
|
||||
$sheet->getColumnDimension('A')->setWidth(30); // Отделение
|
||||
for ($colIndex = 2; $colIndex <= $totalColumns; $colIndex++) {
|
||||
$sheet->getColumnDimension(Coordinate::stringFromColumnIndex($colIndex))->setWidth(16);
|
||||
}
|
||||
|
||||
// Увеличиваем высоту строк с заголовками
|
||||
$sheet->getRowDimension(5)->setRowHeight(30);
|
||||
$sheet->getRowDimension(6)->setRowHeight(25);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Форматирование нулевых значений
|
||||
*/
|
||||
protected function formatZero($value)
|
||||
{
|
||||
if (is_null($value) || $value === '' || $value === []) {
|
||||
return '—';
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
if (is_numeric($value) && $value == 0) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
414
app/Exports/Sheets/StatisticsMainDataExport.php
Normal file
414
app/Exports/Sheets/StatisticsMainDataExport.php
Normal file
@@ -0,0 +1,414 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exports\Sheets;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Maatwebsite\Excel\Concerns\FromArray;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
use Maatwebsite\Excel\Concerns\WithStyles;
|
||||
use Maatwebsite\Excel\Concerns\WithTitle;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Alignment;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Border;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
|
||||
readonly class StatisticsMainDataExport implements FromArray, WithHeadings, WithMapping, WithStyles, WithTitle
|
||||
{
|
||||
public function __construct(
|
||||
private string $sheetTitle,
|
||||
private string $reportName,
|
||||
private array $rows,
|
||||
private array $dateRange,
|
||||
private User $user
|
||||
) {}
|
||||
|
||||
public function title(): string
|
||||
{
|
||||
return $this->sheetTitle;
|
||||
}
|
||||
|
||||
|
||||
public function array(): array
|
||||
{
|
||||
return $this->rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Заголовки (с вложенной структурой)
|
||||
*/
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
// Шапка отчета (первые 3 строки)
|
||||
[$this->reportName],
|
||||
['Дата создания: '.now()->format('d.m.Y H:i:s')],
|
||||
[$this->formatDateRange()],
|
||||
[], // Пустая строка для отступа
|
||||
|
||||
// Первый уровень заголовков (с объединением)
|
||||
[
|
||||
'Отделение',
|
||||
'Кол-во коек',
|
||||
'Поступило', // Будет объединено с 4 колонками
|
||||
'', '', '', // Пустые для заполнения
|
||||
'Выбыло',
|
||||
'Состоит',
|
||||
'Ср. койко-день',
|
||||
'Пред. опер. койко-день',
|
||||
'% загруженности',
|
||||
'% летальности',
|
||||
'Операции', // Будет объединено с 2 колонками
|
||||
'', // Пустые для заполнения
|
||||
'Умерло',
|
||||
'Мед. персонал',
|
||||
],
|
||||
|
||||
// Второй уровень заголовков (детализация)
|
||||
[
|
||||
'',
|
||||
'',
|
||||
'Всего',
|
||||
'План',
|
||||
'Экстр',
|
||||
'Перевод',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'Э',
|
||||
'П',
|
||||
'',
|
||||
'',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Форматирование дат для шапки
|
||||
*/
|
||||
protected function formatDateRange(): string
|
||||
{
|
||||
if (isset($this->dateRange[0]) && isset($this->dateRange[1])) {
|
||||
$startAt = Carbon::create($this->dateRange[0])->format('d.m.Y H:i');
|
||||
$endAt = Carbon::create($this->dateRange[1])->format('d.m.Y H:i');
|
||||
|
||||
return 'Период: '.$startAt.' - '.$endAt;
|
||||
}
|
||||
|
||||
return 'Период: За весь период';
|
||||
}
|
||||
|
||||
/**
|
||||
* Маппинг данных для каждой строки
|
||||
*/
|
||||
public function map($row): array
|
||||
{
|
||||
// Заголовок группы (Хирургические отделения, Терапевтические отделения)
|
||||
if (isset($row['isGroupHeader']) && $row['isGroupHeader']) {
|
||||
return [
|
||||
$row['groupName'], // Название группы
|
||||
'', '', '', '', '', '', '', '', '', '', '', '', '',
|
||||
];
|
||||
}
|
||||
|
||||
// Итоговая строка
|
||||
if (isset($row['isTotalRow']) && $row['isTotalRow']) {
|
||||
return [
|
||||
$row['department'],
|
||||
$row['beds'] ?? '',
|
||||
$this->formatZero($row['recipients']['all'] ?? 0),
|
||||
$this->formatZero($row['recipients']['plan'] ?? 0),
|
||||
$this->formatZero($row['recipients']['emergency'] ?? 0),
|
||||
$this->formatZero($row['recipients']['transferred'] ?? 0),
|
||||
$this->formatZero($row['outcome'] ?? 0),
|
||||
$this->formatZero($row['consist'] ?? 0),
|
||||
$this->formatZero($row['averageBedDays'] ?? 0),
|
||||
$this->formatZero($row['preoperativeDays'] ?? 0),
|
||||
$this->formatZero($row['percentLoadedBeds'] ?? 0),
|
||||
$this->formatZero($row['overallLethality'] ?? 0),
|
||||
$this->formatZero($row['surgical']['emergency'] ?? 0),
|
||||
$this->formatZero($row['surgical']['plan'] ?? 0),
|
||||
$this->formatZero($row['deceased'] ?? 0),
|
||||
$this->formatZero($row['countStaff'] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
// Обычное отделение
|
||||
return [
|
||||
$row['department'] ?? '',
|
||||
$this->formatZero($row['beds'] ?? 0),
|
||||
$this->formatZero($row['recipients']['all'] ?? 0),
|
||||
$this->formatZero($row['recipients']['plan'] ?? 0),
|
||||
$this->formatZero($row['recipients']['emergency'] ?? 0),
|
||||
$this->formatZero($row['recipients']['transferred'] ?? 0),
|
||||
$this->formatZero($row['outcome'] ?? 0),
|
||||
$this->formatZero($row['consist'] ?? 0),
|
||||
$this->formatZero($row['averageBedDays'] ?? 0),
|
||||
$this->formatZero($row['preoperativeDays'] ?? 0),
|
||||
$this->formatZero($row['percentLoadedBeds'] ?? 0),
|
||||
$this->formatZero($row['lethality'] ?? 0),
|
||||
$this->formatZero($row['surgical']['emergency'] ?? 0),
|
||||
$this->formatZero($row['surgical']['plan'] ?? 0),
|
||||
$this->formatZero($row['deceased'] ?? 0),
|
||||
$this->formatZero($row['countStaff'] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Стилизация Excel файла
|
||||
*/
|
||||
public function styles(Worksheet $sheet)
|
||||
{
|
||||
// Поля (уменьшаем для экономии места)
|
||||
$sheet->getPageMargins()->setLeft(0.2);
|
||||
$sheet->getPageMargins()->setRight(0.2);
|
||||
$sheet->getPageMargins()->setTop(0.2);
|
||||
$sheet->getPageMargins()->setBottom(0.2);
|
||||
|
||||
$sheet->getPageSetup()->setPaperSize(PageSetup::PAPERSIZE_A4);
|
||||
$sheet->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE);
|
||||
|
||||
$sheet->getPageSetup()->setFitToPage(true);
|
||||
$sheet->getPageSetup()->setFitToWidth(1); // 1 страница в ширину
|
||||
$sheet->getPageSetup()->setFitToHeight(1); // 1 страница в высоту (опционально)
|
||||
|
||||
// $sheet->getPageSetup()->setScale(90);
|
||||
|
||||
$highestRow = $sheet->getHighestRow();
|
||||
$highestColumn = $sheet->getHighestColumn();
|
||||
|
||||
// ОБЪЕДИНЕНИЕ ЯЧЕЕК ДЛЯ ШАПКИ (строки 1-3)
|
||||
$sheet->mergeCells('A1:'.$highestColumn.'1'); // Наименование
|
||||
$sheet->mergeCells('A2:'.$highestColumn.'2'); // Дата создания
|
||||
$sheet->mergeCells('A3:'.$highestColumn.'3'); // Временной интервал
|
||||
|
||||
// ОБЪЕДИНЕНИЕ ДЛЯ ОБЫЧНЫХ ЗАГОЛОВКОВ
|
||||
$sheet->mergeCells('A5:A6');
|
||||
$sheet->mergeCells('B5:B6');
|
||||
$sheet->mergeCells('G5:G6');
|
||||
$sheet->mergeCells('H5:H6');
|
||||
$sheet->mergeCells('I5:I6');
|
||||
$sheet->mergeCells('J5:J6');
|
||||
$sheet->mergeCells('K5:K6');
|
||||
$sheet->mergeCells('L5:L6');
|
||||
$sheet->mergeCells('O5:O6');
|
||||
$sheet->mergeCells('P5:P6');
|
||||
|
||||
// ОБЪЕДИНЕНИЕ ДЛЯ ВЛОЖЕННЫХ ЗАГОЛОВКОВ
|
||||
// Строка 5 (первый уровень заголовков)
|
||||
$sheet->mergeCells('C5:F5'); // Объединяем "Поступило" (колонки C, D, E, F)
|
||||
$sheet->mergeCells('M5:N5'); // Объединяем "Операции" (колонки M, N)
|
||||
|
||||
// Устанавливаем значения для объединенных ячеек
|
||||
$sheet->setCellValue('C5', 'Поступило');
|
||||
$sheet->setCellValue('M5', 'Операции');
|
||||
|
||||
// СТИЛИ ДЛЯ ШАПКИ ОТЧЕТА (строки 1-3)
|
||||
$sheet->getStyle('A1:A3')->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
'size' => 14,
|
||||
],
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_LEFT,
|
||||
'vertical' => Alignment::VERTICAL_CENTER,
|
||||
],
|
||||
]);
|
||||
|
||||
// СТИЛИ ДЛЯ ЗАГОЛОВКОВ (строки 5 и 6)
|
||||
$sheet->getStyle('A5:'.$highestColumn.'6')->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
'color' => ['argb' => '000000'],
|
||||
'size' => 11,
|
||||
],
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
||||
'vertical' => Alignment::VERTICAL_CENTER,
|
||||
'wrapText' => true,
|
||||
],
|
||||
'borders' => [
|
||||
'allBorders' => [
|
||||
'borderStyle' => Border::BORDER_THIN,
|
||||
'color' => ['argb' => '2d2d30'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
// ДОПОЛНИТЕЛЬНЫЕ СТИЛИ ДЛЯ ОБЪЕДИНЕННЫХ ЗАГОЛОВКОВ
|
||||
$sheet->getStyle('C5')->applyFromArray([
|
||||
'font' => ['bold' => true, 'color' => ['argb' => '000000']],
|
||||
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
|
||||
]);
|
||||
|
||||
$sheet->getStyle('M5')->applyFromArray([
|
||||
'font' => ['bold' => true, 'color' => ['argb' => '000000']],
|
||||
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
|
||||
]);
|
||||
|
||||
// СТИЛИ ДЛЯ ВСЕХ СТРОК С ДАННЫМИ
|
||||
$indexData = 0;
|
||||
for ($row = 7; $row <= $highestRow; $row++) {
|
||||
$cellValue = $sheet->getCell('A'.$row)->getValue();
|
||||
|
||||
$currentRowInData = $this->rows[$indexData];
|
||||
// Заголовки групп (Хирургические отделения, Терапевтические отделения)
|
||||
if (array_key_exists('isGroupHeader', $currentRowInData)) {
|
||||
$sheet->getStyle('A'.$row.':'.$highestColumn.$row)->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
'size' => 11,
|
||||
],
|
||||
'fill' => [
|
||||
'fillType' => Fill::FILL_SOLID,
|
||||
'startColor' => ['argb' => 'D9E1F2'], // Светло-синий
|
||||
],
|
||||
]);
|
||||
|
||||
// Объединяем ячейки для группы
|
||||
$sheet->mergeCells('A'.$row.':'.$highestColumn.$row);
|
||||
}
|
||||
|
||||
// Итоговые строки (ИТОГО:)
|
||||
if (array_key_exists('isTotalRow', $currentRowInData)) {
|
||||
$sheet->getStyle('A'.$row.':'.$highestColumn.$row)->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
],
|
||||
'fill' => [
|
||||
'fillType' => Fill::FILL_SOLID,
|
||||
'startColor' => ['argb' => 'F2F2F2'], // Серый
|
||||
],
|
||||
'borders' => [
|
||||
'top' => [
|
||||
'borderStyle' => Border::BORDER_MEDIUM,
|
||||
'color' => ['argb' => '000000'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
if ($indexData < count($this->rows)) {
|
||||
$indexData++;
|
||||
}
|
||||
}
|
||||
|
||||
// ГРАНИЦЫ ДЛЯ ВСЕЙ ТАБЛИЦЫ
|
||||
$sheet->getStyle('A5:'.$highestColumn.$highestRow)->applyFromArray([
|
||||
'borders' => [
|
||||
'allBorders' => [
|
||||
'borderStyle' => Border::BORDER_THIN,
|
||||
'color' => ['argb' => '000000'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
// ВЫРАВНИВАНИЕ ДЛЯ ЧИСЛОВЫХ КОЛОНОК
|
||||
$sheet->getStyle('B7:'.$highestColumn.$highestRow)->applyFromArray([
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_CENTER,
|
||||
],
|
||||
]);
|
||||
|
||||
// ВЫРАВНИВАНИЕ ДЛЯ НАЗВАНИЙ ОТДЕЛЕНИЙ
|
||||
$sheet->getStyle('A7:A'.$highestRow)->applyFromArray([
|
||||
'alignment' => [
|
||||
'horizontal' => Alignment::HORIZONTAL_LEFT,
|
||||
'vertical' => Alignment::VERTICAL_CENTER,
|
||||
],
|
||||
]);
|
||||
|
||||
// Устанавливаем ширину колонок
|
||||
$sheet->getColumnDimension('A')->setWidth(25); // Отделение
|
||||
$sheet->getColumnDimension('B')->setWidth(8); // Кол-во коек
|
||||
$sheet->getColumnDimension('C')->setWidth(8); // Всего
|
||||
$sheet->getColumnDimension('D')->setWidth(8); // План
|
||||
$sheet->getColumnDimension('E')->setWidth(8); // Экстр
|
||||
$sheet->getColumnDimension('F')->setWidth(10); // Перевод
|
||||
$sheet->getColumnDimension('G')->setWidth(10); // Выбыло
|
||||
$sheet->getColumnDimension('H')->setWidth(10); // Состоит
|
||||
$sheet->getColumnDimension('I')->setWidth(10); // Ср. койко-день
|
||||
$sheet->getColumnDimension('J')->setWidth(10); // Пред. опер. койко-день
|
||||
$sheet->getColumnDimension('K')->setWidth(10); // % загруженности
|
||||
$sheet->getColumnDimension('L')->setWidth(8); // % летальности
|
||||
$sheet->getColumnDimension('M')->setWidth(8); // Операции Э
|
||||
$sheet->getColumnDimension('N')->setWidth(8); // Операции П
|
||||
$sheet->getColumnDimension('O')->setWidth(10); // Умерло
|
||||
$sheet->getColumnDimension('P')->setWidth(10); // Мед. персонал
|
||||
|
||||
// Увеличиваем высоту строк с заголовками
|
||||
$sheet->getRowDimension(5)->setRowHeight(30);
|
||||
$sheet->getRowDimension(6)->setRowHeight(25);
|
||||
|
||||
// Добавляем примечание внизу
|
||||
// $this->addFootnote($sheet, $highestRow, $highestColumn);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Форматирование нулевых значений
|
||||
*/
|
||||
protected function formatZero($value)
|
||||
{
|
||||
// Если значение null или пустая строка - возвращаем "0"
|
||||
if (is_null($value) || $value === '' || $value === []) {
|
||||
return '—';
|
||||
}
|
||||
|
||||
// Если это массив (для recipients или surgical) - такого не должно быть,
|
||||
// но на всякий случай обработаем
|
||||
if (is_array($value)) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
// Если это число с плавающей точкой и оно равно 0
|
||||
if (is_numeric($value) && $value == 0) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавить примечание в конец файла
|
||||
*/
|
||||
public function addFootnote(Worksheet $sheet, int $startRow, string $highestColumn): void
|
||||
{
|
||||
$footnoteRow = $startRow + 2; // Отступаем 2 строки от таблицы
|
||||
|
||||
$sheet->setCellValue('A'.$footnoteRow, 'ПРИМЕЧАНИЕ:');
|
||||
|
||||
$sheet->setCellValue('B'.$footnoteRow, '• % загруженности актуален на дату формирования отчёта ('.now()->format('d.m.Y').')');
|
||||
$sheet->mergeCells('B'.$footnoteRow.':'.$highestColumn.$footnoteRow);
|
||||
|
||||
$sheet->setCellValue('B'.($footnoteRow + 1), '• Поступление, выбытие, операции — за указанный в шапке период');
|
||||
$sheet->mergeCells('B'.($footnoteRow + 1).':'.$highestColumn.($footnoteRow + 1));
|
||||
|
||||
// Стили для примечания
|
||||
$sheet->getStyle('A'.$footnoteRow.':'.$highestColumn.($footnoteRow + 1))->applyFromArray([
|
||||
'font' => [
|
||||
'italic' => true,
|
||||
'size' => 9,
|
||||
'color' => ['argb' => '666666'],
|
||||
],
|
||||
'alignment' => [
|
||||
'vertical' => Alignment::VERTICAL_CENTER,
|
||||
],
|
||||
]);
|
||||
|
||||
// Жирный шрифт для слова "ПРИМЕЧАНИЕ"
|
||||
$sheet->getStyle('A'.$footnoteRow)->applyFromArray([
|
||||
'font' => [
|
||||
'bold' => true,
|
||||
'color' => ['argb' => '000000'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user