Добавлено формирование отчета

И индикатор реанимации
This commit is contained in:
brusnitsyn
2026-04-24 16:44:58 +09:00
parent 1de9fd3ef8
commit fd0e6ee817
5 changed files with 259 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Exports;
use App\Exports\Sheets\ArraySheetExport;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
class ReportPageExport implements WithMultipleSheets
{
public function __construct(
private readonly array $summaryRows,
private readonly array $patientRows
) {}
public function sheets(): array
{
return [
new ArraySheetExport('Сводка', $this->summaryRows),
new ArraySheetExport('Пациенты', $this->patientRows),
];
}
}

View File

@@ -0,0 +1,92 @@
<?php
namespace App\Exports\Sheets;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
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;
class ArraySheetExport implements FromArray, WithTitle, WithStyles, ShouldAutoSize
{
public function __construct(
private readonly string $sheetTitle,
private readonly array $rows
) {}
public function array(): array
{
return $this->rows;
}
public function title(): string
{
return $this->sheetTitle;
}
public function styles(Worksheet $sheet): array
{
$sheet->getPageSetup()->setPaperSize(PageSetup::PAPERSIZE_A4);
$sheet->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE);
$sheet->getPageSetup()->setFitToPage(true);
$sheet->getPageSetup()->setFitToWidth(1);
$sheet->getPageSetup()->setFitToHeight(0);
$sheet->getPageMargins()->setTop(0.2);
$sheet->getPageMargins()->setBottom(0.2);
$sheet->getPageMargins()->setLeft(0.2);
$sheet->getPageMargins()->setRight(0.2);
$highestRow = $sheet->getHighestRow();
$highestColumn = $sheet->getHighestColumn();
$sheet->getStyle("A1:{$highestColumn}{$highestRow}")->applyFromArray([
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_LEFT,
'vertical' => Alignment::VERTICAL_CENTER,
'wrapText' => true,
],
'borders' => [
'allBorders' => [
'borderStyle' => Border::BORDER_THIN,
'color' => ['argb' => 'D0D7DE'],
],
],
]);
$sheet->getStyle("A1:{$highestColumn}1")->applyFromArray([
'font' => [
'bold' => true,
],
'fill' => [
'fillType' => Fill::FILL_SOLID,
'startColor' => ['argb' => 'EEF2FF'],
],
]);
for ($row = 1; $row <= $highestRow; $row++) {
$firstCell = (string) $sheet->getCell("A{$row}")->getValue();
$secondCell = (string) $sheet->getCell("B{$row}")->getValue();
// Строки секций (МИС / Спец. контингент)
if (in_array($firstCell, ['МИС', 'Спец. контингент'], true) && $secondCell === '') {
$sheet->getStyle("A{$row}:{$highestColumn}{$row}")->applyFromArray([
'font' => ['bold' => true],
'fill' => [
'fillType' => Fill::FILL_SOLID,
'startColor' => ['argb' => 'F4F6F8'],
],
]);
}
}
$sheet->freezePane('A2');
return [];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ReanimationPatientIndicator extends Model
{
protected $primaryKey = 'reanimation_patient_indicator_id';
protected $fillable = [
'rf_department_id',
'rf_report_id',
'rf_medicalhistory_id',
'indicator',
'comment',
'created_by',
];
}

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('reanimation_patient_indicators', function (Blueprint $table) {
$table->id('reanimation_patient_indicator_id');
$table->unsignedBigInteger('rf_department_id');
$table->unsignedBigInteger('rf_report_id')->nullable();
$table->unsignedBigInteger('rf_medicalhistory_id');
$table->string('indicator', 100);
$table->text('comment')->nullable();
$table->unsignedBigInteger('created_by')->nullable();
$table->timestamps();
$table->index(
['rf_department_id', 'rf_medicalhistory_id', 'created_at'],
'idx_reanimation_indicator_department_history_created_at'
);
$table->index(['rf_report_id'], 'idx_reanimation_indicator_report');
});
}
public function down(): void
{
Schema::dropIfExists('reanimation_patient_indicators');
}
};

View File

@@ -0,0 +1,92 @@
<script setup>
import {computed, reactive, watch} from "vue";
import {NButton, NForm, NFormItem, NInput, NModal, NSelect} from "naive-ui";
import {useReportStore} from "../../../Stores/report.js";
const show = defineModel('show')
const props = defineProps({
patient: {
type: Object,
default: null,
},
})
const reportStore = useReportStore()
const form = reactive({
indicator: '',
comment: '',
})
const indicatorOptions = [
{ label: 'Стабильный', value: 'stable' },
{ label: 'Средней тяжести', value: 'moderate' },
{ label: 'Тяжелый', value: 'severe' },
{ label: 'Критический', value: 'critical' },
]
const isDisabled = computed(() => !props.patient?.medical_history_id)
watch(
() => props.patient,
(patient) => {
form.indicator = patient?.reanimation_indicator ?? ''
form.comment = patient?.reanimation_comment ?? ''
},
{ immediate: true }
)
const handleSave = async () => {
if (isDisabled.value || !form.indicator) {
return
}
await reportStore.saveReanimationIndicator({
medical_history_id: props.patient.medical_history_id,
indicator: form.indicator,
comment: form.comment || null,
})
show.value = false
}
</script>
<template>
<NModal
v-model:show="show"
preset="card"
title="Индикатор состояния"
class="max-w-lg"
:mask-closable="false"
>
<NForm :model="form">
<NFormItem label="Состояние">
<NSelect
v-model:value="form.indicator"
:options="indicatorOptions"
placeholder="Выберите состояние"
/>
</NFormItem>
<NFormItem label="Комментарий">
<NInput
v-model:value="form.comment"
type="textarea"
:rows="4"
:resizable="false"
placeholder="Дополнительная информация"
/>
</NFormItem>
</NForm>
<template #action>
<div class="flex justify-end">
<NButton
type="primary"
:disabled="isDisabled || !form.indicator"
@click="handleSave"
>
Сохранить
</NButton>
</div>
</template>
</NModal>
</template>