feat: add lab tests, patient file management, and prescription improvements

This commit is contained in:
SajjadMahmoody
2026-04-17 20:15:38 +03:30
parent 6a301c5529
commit bf0ada051f
53 changed files with 3201 additions and 387 deletions
+153 -46
View File
@@ -4,6 +4,7 @@
namespace App\Filament\Resources;
use App\Filament\Resources\PrescriptionResource\Pages;
use App\Models\LabTest;
use App\Models\Medication;
use App\Models\Patient;
use App\Models\Prescription;
@@ -18,11 +19,14 @@
use Filament\Actions\EditAction;
use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Select;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Tabs;
use Filament\Schemas\Components\Tabs\Tab;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
@@ -95,60 +99,131 @@ public static function form(Schema $schema): Schema
->columns(2)
->columnSpanFull(),
Section::make(__('prescriptions.sections.medications'))
Section::make()
->schema([
CheckboxList::make('medication_ids')
->label(__('prescriptions.fields.medication_ids'))
->options(fn () => Medication::where('is_active', true)
->orderBy('name')
->get()
->mapWithKeys(fn ($m) => [
$m->id => implode(' ', array_filter([
$m->dosage_form,
$m->name,
$m->strength,
$m->quantity ? '#' . $m->quantity : null,
$m->timing,
])),
])
->toArray()
)
->columns(3)
->live()
->afterStateUpdated(function (array $state, callable $set) {
if (empty($state)) {
$set('content', null);
return;
}
$medications = Medication::whereIn('id', $state)
->orderBy('name')
->get();
$html = '<ul>' . $medications->map(fn ($m) =>
'<li>' . implode(' ', array_filter([
$m->dosage_form,
$m->name,
$m->strength,
$m->quantity ? '#' . $m->quantity : null,
$m->timing,
])) . '</li>'
)->implode('') . '</ul>';
$set('content', $html);
})
->columnSpanFull(),
])
->columnSpanFull(),
Tabs::make()
->tabs([
Tab::make(__('prescriptions.sections.medications'))
->icon('heroicon-o-clipboard-document-list')
->schema([
Hidden::make('medication_order'),
Section::make(__('prescriptions.sections.content'))
->schema([
RichEditor::make('content')
->label(__('prescriptions.fields.content'))
CheckboxList::make('medication_ids')
->label(__('prescriptions.fields.medication_ids'))
->options(fn () => Medication::where('is_active', true)
->orderBy('name')
->get()
->mapWithKeys(fn ($m) => [
$m->id => implode(' ', array_filter([
$m->dosage_form,
$m->name,
$m->strength,
$m->quantity ? '#' . $m->quantity : null,
$m->timing,
])),
])
->toArray()
)
->columns(3)
->live()
->afterStateUpdated(function (array $state, callable $set, callable $get) {
$currentOrder = array_map('intval', (array) ($get('medication_order') ?: []));
$state = array_map('intval', $state);
$newOrder = array_values(
array_filter($currentOrder, fn ($id) => in_array($id, $state))
);
foreach ($state as $id) {
if (! in_array($id, $newOrder)) {
$newOrder[] = $id;
}
}
$set('medication_order', $newOrder);
if (empty($newOrder)) {
$set('content', null);
return;
}
$medications = Medication::whereIn('id', $newOrder)->get()->keyBy('id');
$html = '<ul>' . collect($newOrder)
->map(fn ($id) => isset($medications[$id])
? '<li>' . implode(' ', array_filter([
$medications[$id]->dosage_form,
$medications[$id]->name,
$medications[$id]->strength,
$medications[$id]->quantity ? '#' . $medications[$id]->quantity : null,
$medications[$id]->timing,
])) . '</li>'
: ''
)
->filter()
->implode('') . '</ul>';
$set('content', $html);
})
->columnSpanFull(),
RichEditor::make('content')
->label(__('prescriptions.fields.content'))
->columnSpanFull(),
]),
Tab::make(__('prescriptions.sections.lab_tests'))
->icon('heroicon-o-beaker')
->schema([
Hidden::make('lab_test_order'),
CheckboxList::make('lab_test_ids')
->label(__('prescriptions.fields.lab_test_ids'))
->options(fn () => LabTest::where('is_active', true)
->orderBy('name')
->get()
->mapWithKeys(fn ($t) => [$t->id => $t->name])
->toArray()
)
->columns(3)
->live()
->afterStateUpdated(function (array $state, callable $set, callable $get) {
$currentOrder = array_map('intval', (array) ($get('lab_test_order') ?: []));
$state = array_map('intval', $state);
$newOrder = array_values(
array_filter($currentOrder, fn ($id) => in_array($id, $state))
);
foreach ($state as $id) {
if (! in_array($id, $newOrder)) {
$newOrder[] = $id;
}
}
$set('lab_test_order', $newOrder);
if (empty($newOrder)) {
$set('lab_content', null);
return;
}
$tests = LabTest::whereIn('id', $newOrder)->get()->keyBy('id');
$html = '<ul>' . collect($newOrder)
->map(fn ($id) => isset($tests[$id])
? '<li>' . $tests[$id]->name . '</li>'
: ''
)
->filter()
->implode('') . '</ul>';
$set('lab_content', $html);
})
->columnSpanFull(),
RichEditor::make('lab_content')
->label(__('prescriptions.fields.lab_content'))
->columnSpanFull(),
]),
])
->columnSpanFull(),
])
->columnSpanFull()
->footerActions([
fn (string $operation) => Action::make('createAndPrint')
->label(__('prescriptions.actions.save_and_print'))
->color('warning')
->color('primary')
->icon('heroicon-o-printer')
->action(function ($livewire) {
$livewire->printType = 'prescription';
@@ -156,6 +231,26 @@ public static function form(Schema $schema): Schema
})
->visible($operation === 'create'),
fn (string $operation) => Action::make('createAndPrintLab')
->label(__('prescriptions.actions.print_lab'))
->color('gray')
->icon('heroicon-o-beaker')
->action(function ($livewire) {
$livewire->printType = 'lab';
$livewire->create();
})
->visible($operation === 'create'),
fn (string $operation) => Action::make('createAndPrintBoth')
->label(__('prescriptions.actions.save_and_print_both'))
->color('warning')
->icon('heroicon-o-document-duplicate')
->action(function ($livewire) {
$livewire->printType = 'both';
$livewire->create();
})
->visible($operation === 'create'),
fn (string $operation) => Action::make('cancelCreate')
->label(__('filament-panels::resources/pages/create-record.form.actions.cancel.label'))
->url(static::getUrl('index'))
@@ -237,6 +332,18 @@ public static function table(Table $table): Table
])
->defaultSort('created_at', 'desc')
->recordActions([
Action::make('printBoth')
->label(__('prescriptions.actions.print_both'))
->icon('heroicon-o-document-duplicate')
->color('purple')
->modalContent(fn ($record) => view('filament.prescription-print-modal', [
'url' => route('prescription.print', ['prescription' => $record, 'type' => 'both']),
]))
->modalHeading(fn ($record) => ($record->patientRecord?->full_name ?? '') . ' — نسخه و آزمایش')
->modalWidth('7xl')
->modalSubmitAction(false)
->modalCancelActionLabel('بستن'),
Action::make('printPrescription')
->label(__('prescriptions.actions.print_prescription'))
->icon('heroicon-o-printer')