* связка таблицы архива с пациентами
* добавил разграничение карт по типам баз * модель для хранения изменений статуса карт * добавил окно с просмотром выдачи карты * добавил фильтрацию вывода карт
This commit is contained in:
@@ -13,17 +13,30 @@ class IndexController extends Controller
|
|||||||
{
|
{
|
||||||
$pageSize = $request->get('page_size', 15);
|
$pageSize = $request->get('page_size', 15);
|
||||||
$searchText = $request->get('search', null);
|
$searchText = $request->get('search', null);
|
||||||
|
$dateExtractFrom = $request->get('date_extract_from', null);
|
||||||
|
$dateExtractTo = $request->get('date_extract_to', null);
|
||||||
|
$viewType = $request->get('view_type', 'archive');
|
||||||
|
|
||||||
$cards = SttMedicalHistory::query();
|
$cardsQuery = SttMedicalHistory::query();
|
||||||
|
|
||||||
if (!empty($searchText)) {
|
if (!empty($searchText)) {
|
||||||
$cards = $cards->search($searchText);
|
$cardsQuery = $cardsQuery->search($searchText);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cards = SttMedicalHistoryResource::collection($cards->paginate($pageSize));
|
if (!empty($dateExtractFrom)) {
|
||||||
|
$cardsQuery = $cardsQuery->whereDate('dateextract', '>=', $dateExtractFrom);
|
||||||
|
if (!empty($dateExtractTo)) {
|
||||||
|
$cardsQuery = $cardsQuery->whereDate('dateextract', '<=', $dateExtractTo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$cards = SttMedicalHistoryResource::collection($cardsQuery->paginate($pageSize));
|
||||||
|
|
||||||
return Inertia::render('Home/Index', [
|
return Inertia::render('Home/Index', [
|
||||||
'cards' => $cards,
|
'cards' => $cards,
|
||||||
|
'filters' => $request->only([
|
||||||
|
'search', 'date_extract_from', 'date_extract_to', 'page_size', 'page', 'view_type'
|
||||||
|
]),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
app/Http/Controllers/MedicalHistoryController.php
Normal file
28
app/Http/Controllers/MedicalHistoryController.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\SI\SttMedicalHistory;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class MedicalHistoryController extends Controller
|
||||||
|
{
|
||||||
|
public function patient($id, Request $request)
|
||||||
|
{
|
||||||
|
$viewType = $request->get('view_type', 'si');
|
||||||
|
$patientId = $request->get('patient_id');
|
||||||
|
|
||||||
|
$patientInfo = null;
|
||||||
|
if ($viewType == 'si') {
|
||||||
|
$patient = SttMedicalHistory::where('id', $id)->first();
|
||||||
|
$archiveJournal = $patient->archiveHistory;
|
||||||
|
|
||||||
|
$patientInfo = [
|
||||||
|
'info' => $patient,
|
||||||
|
'journal' => $archiveJournal,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json($patientInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,14 +16,15 @@ class SttMedicalHistoryResource extends JsonResource
|
|||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
'id' => $this->id,
|
||||||
'fullname' => $this->getFullNameAttribute(),
|
'fullname' => $this->getFullNameAttribute(),
|
||||||
'mpostdate' => Carbon::parse($this->mpostdate)->format('d.m.Y'),
|
'daterecipient' => Carbon::parse($this->daterecipient)->format('d.m.Y'),
|
||||||
'menddate' => Carbon::parse($this->menddate)->format('d.m.Y'),
|
'dateextract' => Carbon::parse($this->dateextract)->format('d.m.Y'),
|
||||||
'narhiv' => $this->narhiv,
|
'narhiv' => $this->narhiv,
|
||||||
'datearhiv' => Carbon::parse($this->datearhiv)->format('d.m.Y'),
|
'datearhiv' => Carbon::parse($this->datearhiv)->format('d.m.Y'),
|
||||||
'statgod' => $this->statgod,
|
'statgod' => $this->statgod,
|
||||||
'enp' => $this->enp,
|
'enp' => $this->enp,
|
||||||
'nkarta' => $this->nkarta,
|
'medcardnum' => $this->medcardnum,
|
||||||
'dr' => Carbon::parse($this->dr)->format('d.m.Y'),
|
'dr' => Carbon::parse($this->dr)->format('d.m.Y'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ class ArchiveHistory extends Model
|
|||||||
'historyable_id',
|
'historyable_id',
|
||||||
'issue_at',
|
'issue_at',
|
||||||
'return_at',
|
'return_at',
|
||||||
'name_org',
|
'comment',
|
||||||
|
'org_id',
|
||||||
'employee_name',
|
'employee_name',
|
||||||
'employee_position',
|
'employee_post',
|
||||||
|
'has_lost',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function historyable()
|
public function historyable()
|
||||||
|
|||||||
12
app/Models/Org.php
Normal file
12
app/Models/Org.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Org extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'name'
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -10,25 +10,25 @@ class SttMedicalHistory extends Model
|
|||||||
protected $table = 'si_stt_patients';
|
protected $table = 'si_stt_patients';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'fam', // Фамилия
|
'family', // Фамилия
|
||||||
'im', // Имя
|
'name', // Имя
|
||||||
'ot', // Отчество
|
'ot', // Отчество
|
||||||
'mpostdate', // Д. пост.
|
'daterecipient', // Д. пост. (mpostdate)
|
||||||
'menddate', // Д. вып.
|
'dateextract', // Д. вып. (menddate)
|
||||||
'narhiv', // № в архиве
|
'narhiv', // № в архиве
|
||||||
'datearhiv', // Д. архив
|
'datearhiv', // Д. архив
|
||||||
'statgod', // Год нахождения в стационаре
|
'statgod', // Год нахождения в стационаре
|
||||||
'enp', // ЕНП
|
'enp', // ЕНП
|
||||||
'nkarta', // № карты
|
'medcardnum', // № карты
|
||||||
'dr', // ДР
|
'dr', // ДР
|
||||||
];
|
];
|
||||||
|
|
||||||
public function getFullNameAttribute()
|
public function getFullNameAttribute()
|
||||||
{
|
{
|
||||||
return "$this->fam $this->im $this->ot";
|
return "$this->family $this->name $this->ot";
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getArchiveHistory()
|
public function archiveHistory()
|
||||||
{
|
{
|
||||||
return $this->morphMany(ArchiveHistory::class, 'historyable');
|
return $this->morphMany(ArchiveHistory::class, 'historyable');
|
||||||
}
|
}
|
||||||
@@ -37,12 +37,12 @@ class SttMedicalHistory extends Model
|
|||||||
{
|
{
|
||||||
return $query->where(function($q) use ($searchText) {
|
return $query->where(function($q) use ($searchText) {
|
||||||
if (is_numeric($searchText)) {
|
if (is_numeric($searchText)) {
|
||||||
$q->where('nkarta', 'LIKE', "$searchText%");
|
$q->where('medcardnum', 'ILIKE', "$searchText%");
|
||||||
} else {
|
} else {
|
||||||
// Ищем по всем частям ФИО
|
// Ищем по всем частям ФИО
|
||||||
$q->where('fam', 'LIKE', "%$searchText%")
|
$q->where('family', 'ILIKE', "%$searchText%")
|
||||||
->orWhere('im', 'LIKE', "%$searchText%")
|
->orWhere('name', 'ILIKE', "%$searchText%")
|
||||||
->orWhere('ot', 'LIKE', "%$searchText%");
|
->orWhere('ot', 'ILIKE', "%$searchText%");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use Illuminate\Foundation\Configuration\Middleware;
|
|||||||
return Application::configure(basePath: dirname(__DIR__))
|
return Application::configure(basePath: dirname(__DIR__))
|
||||||
->withRouting(
|
->withRouting(
|
||||||
web: __DIR__.'/../routes/web.php',
|
web: __DIR__.'/../routes/web.php',
|
||||||
|
api: __DIR__.'/../routes/api.php',
|
||||||
commands: __DIR__.'/../routes/console.php',
|
commands: __DIR__.'/../routes/console.php',
|
||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"inertiajs/inertia-laravel": "^2.0",
|
"inertiajs/inertia-laravel": "^2.0",
|
||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
|
"laravel/sanctum": "^4.0",
|
||||||
"laravel/tinker": "^2.10.1"
|
"laravel/tinker": "^2.10.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|||||||
69
composer.lock
generated
69
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "9cc5ea89dc281a98d5bcb5bf7755b102",
|
"content-hash": "4ecf76c8e987c4f4186a17e150248317",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
@@ -1400,6 +1400,69 @@
|
|||||||
},
|
},
|
||||||
"time": "2025-11-21T20:52:52+00:00"
|
"time": "2025-11-21T20:52:52+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "laravel/sanctum",
|
||||||
|
"version": "v4.2.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/laravel/sanctum.git",
|
||||||
|
"reference": "f5fb373be39a246c74a060f2cf2ae2c2145b3664"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/laravel/sanctum/zipball/f5fb373be39a246c74a060f2cf2ae2c2145b3664",
|
||||||
|
"reference": "f5fb373be39a246c74a060f2cf2ae2c2145b3664",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-json": "*",
|
||||||
|
"illuminate/console": "^11.0|^12.0",
|
||||||
|
"illuminate/contracts": "^11.0|^12.0",
|
||||||
|
"illuminate/database": "^11.0|^12.0",
|
||||||
|
"illuminate/support": "^11.0|^12.0",
|
||||||
|
"php": "^8.2",
|
||||||
|
"symfony/console": "^7.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mockery/mockery": "^1.6",
|
||||||
|
"orchestra/testbench": "^9.15|^10.8",
|
||||||
|
"phpstan/phpstan": "^1.10"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"providers": [
|
||||||
|
"Laravel\\Sanctum\\SanctumServiceProvider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Laravel\\Sanctum\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Taylor Otwell",
|
||||||
|
"email": "taylor@laravel.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.",
|
||||||
|
"keywords": [
|
||||||
|
"auth",
|
||||||
|
"laravel",
|
||||||
|
"sanctum"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/laravel/sanctum/issues",
|
||||||
|
"source": "https://github.com/laravel/sanctum"
|
||||||
|
},
|
||||||
|
"time": "2025-11-21T13:59:03+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/serializable-closure",
|
"name": "laravel/serializable-closure",
|
||||||
"version": "v2.0.7",
|
"version": "v2.0.7",
|
||||||
@@ -9407,12 +9470,12 @@
|
|||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": [],
|
"stability-flags": {},
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "^8.2"
|
"php": "^8.2"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": {},
|
||||||
"plugin-api-version": "2.6.0"
|
"plugin-api-version": "2.6.0"
|
||||||
}
|
}
|
||||||
|
|||||||
84
config/sanctum.php
Normal file
84
config/sanctum.php
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Laravel\Sanctum\Sanctum;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Stateful Domains
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Requests from the following domains / hosts will receive stateful API
|
||||||
|
| authentication cookies. Typically, these should include your local
|
||||||
|
| and production domains which access your API via a frontend SPA.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
|
||||||
|
'%s%s',
|
||||||
|
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
|
||||||
|
Sanctum::currentApplicationUrlWithPort(),
|
||||||
|
// Sanctum::currentRequestHost(),
|
||||||
|
))),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Sanctum Guards
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This array contains the authentication guards that will be checked when
|
||||||
|
| Sanctum is trying to authenticate a request. If none of these guards
|
||||||
|
| are able to authenticate the request, Sanctum will use the bearer
|
||||||
|
| token that's present on an incoming request for authentication.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'guard' => ['web'],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Expiration Minutes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value controls the number of minutes until an issued token will be
|
||||||
|
| considered expired. This will override any values set in the token's
|
||||||
|
| "expires_at" attribute, but first-party sessions are not affected.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'expiration' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Token Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Sanctum can prefix new tokens in order to take advantage of numerous
|
||||||
|
| security scanning initiatives maintained by open source platforms
|
||||||
|
| that notify developers if they commit tokens into repositories.
|
||||||
|
|
|
||||||
|
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Sanctum Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When authenticating your first-party SPA with Sanctum you may need to
|
||||||
|
| customize some of the middleware Sanctum uses while processing the
|
||||||
|
| request. You may change the middleware listed below as required.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'middleware' => [
|
||||||
|
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
|
||||||
|
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
|
||||||
|
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
28
database/migrations/2025_11_30_063144_create_orgs_table.php
Normal file
28
database/migrations/2025_11_30_063144_create_orgs_table.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('orgs', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('orgs');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -16,9 +16,11 @@ return new class extends Migration
|
|||||||
$table->morphs('historyable');
|
$table->morphs('historyable');
|
||||||
$table->timestamp('issue_at');
|
$table->timestamp('issue_at');
|
||||||
$table->timestamp('return_at')->nullable();
|
$table->timestamp('return_at')->nullable();
|
||||||
$table->string('name_org');
|
$table->text('comment')->nullable();
|
||||||
|
$table->foreignIdFor(\App\Models\Org::class, 'org_id');
|
||||||
$table->string('employee_name');
|
$table->string('employee_name');
|
||||||
$table->string('employee_position')->nullable();
|
$table->string('employee_post')->nullable();
|
||||||
|
$table->boolean('has_lost')->default(false);
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('personal_access_tokens', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->morphs('tokenable');
|
||||||
|
$table->text('name');
|
||||||
|
$table->string('token', 64)->unique();
|
||||||
|
$table->text('abilities')->nullable();
|
||||||
|
$table->timestamp('last_used_at')->nullable();
|
||||||
|
$table->timestamp('expires_at')->nullable()->index();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('personal_access_tokens');
|
||||||
|
}
|
||||||
|
};
|
||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -9,6 +9,7 @@
|
|||||||
"@inertiajs/vue3": "^2.2.19",
|
"@inertiajs/vue3": "^2.2.19",
|
||||||
"@vitejs/plugin-vue": "^6.0.2",
|
"@vitejs/plugin-vue": "^6.0.2",
|
||||||
"@vueuse/core": "^14.1.0",
|
"@vueuse/core": "^14.1.0",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"ufo": "^1.6.1",
|
"ufo": "^1.6.1",
|
||||||
"vue": "^3.5.25"
|
"vue": "^3.5.25"
|
||||||
@@ -1655,7 +1656,6 @@
|
|||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
||||||
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"@inertiajs/vue3": "^2.2.19",
|
"@inertiajs/vue3": "^2.2.19",
|
||||||
"@vitejs/plugin-vue": "^6.0.2",
|
"@vitejs/plugin-vue": "^6.0.2",
|
||||||
"@vueuse/core": "^14.1.0",
|
"@vueuse/core": "^14.1.0",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"ufo": "^1.6.1",
|
"ufo": "^1.6.1",
|
||||||
"vue": "^3.5.25"
|
"vue": "^3.5.25"
|
||||||
|
|||||||
222
resources/js/Composables/useMedicalHistoryFilter.js
Normal file
222
resources/js/Composables/useMedicalHistoryFilter.js
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
// composables/useMedicalHistoryFilter.js
|
||||||
|
import { router, usePage } from '@inertiajs/vue3'
|
||||||
|
import {ref, computed, watch} from 'vue'
|
||||||
|
import { stringifyQuery } from 'ufo'
|
||||||
|
import {format, isValid, parse, parseISO} from 'date-fns'
|
||||||
|
import {useDebounceFn} from "@vueuse/core";
|
||||||
|
|
||||||
|
export const useMedicalHistoryFilter = (filters) => {
|
||||||
|
const page = usePage()
|
||||||
|
|
||||||
|
// Реактивные фильтры с начальными значениями из URL
|
||||||
|
const filtersRef = ref({
|
||||||
|
search: filters?.search || '',
|
||||||
|
date_extract_from: filters?.date_extract_from || null,
|
||||||
|
date_extract_to: filters?.date_extract_to || null,
|
||||||
|
page: filters?.page || 1,
|
||||||
|
page_size: filters?.page_size || 15,
|
||||||
|
sort_by: filters?.sort_by || 'date_extract',
|
||||||
|
sort_order: filters?.sort_order || 'desc',
|
||||||
|
view_type: filters?.view_type || 'archive'
|
||||||
|
})
|
||||||
|
|
||||||
|
const meta = computed(() => page.props.cards?.meta || {})
|
||||||
|
const isLoading = ref(false)
|
||||||
|
|
||||||
|
// Форматирование даты для URL
|
||||||
|
const formatDateForUrl = (date) => {
|
||||||
|
if (!date) return null
|
||||||
|
if (date instanceof Date) {
|
||||||
|
return format(date, 'yyyy-MM-dd')
|
||||||
|
}
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
|
||||||
|
// Навигация с фильтрами
|
||||||
|
const applyFilters = (updates = {}, resetPage = false) => {
|
||||||
|
// Обновляем фильтры
|
||||||
|
Object.assign(filtersRef.value, updates)
|
||||||
|
|
||||||
|
// Если сбрасываем фильтры, обнуляем страницу
|
||||||
|
if (resetPage) {
|
||||||
|
filtersRef.value.page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Подготавливаем параметры для URL
|
||||||
|
const params = {
|
||||||
|
search: filtersRef.value.search || null,
|
||||||
|
date_extract_from: formatDateForUrl(filtersRef.value.date_extract_from),
|
||||||
|
date_extract_to: formatDateForUrl(filtersRef.value.date_extract_to),
|
||||||
|
page: filtersRef.value.page,
|
||||||
|
page_size: filtersRef.value.page_size,
|
||||||
|
sort_by: filtersRef.value.sort_by,
|
||||||
|
sort_order: filtersRef.value.sort_order,
|
||||||
|
view_type: filtersRef.value.view_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Очищаем пустые значения
|
||||||
|
const cleanParams = Object.fromEntries(
|
||||||
|
Object.entries(params).filter(([_, value]) =>
|
||||||
|
value !== undefined && value !== null && value !== ''
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const query = stringifyQuery(cleanParams)
|
||||||
|
|
||||||
|
isLoading.value = true
|
||||||
|
router.visit(`/${query ? `?${query}` : ''}`, {
|
||||||
|
preserveState: true,
|
||||||
|
preserveScroll: true,
|
||||||
|
onFinish: () => {
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Дебаунсированный поиск
|
||||||
|
const debouncedSearch = useDebounceFn((value) => {
|
||||||
|
applyFilters({ search: value }, true)
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
// Обработчики событий
|
||||||
|
const handleSearch = (value) => {
|
||||||
|
filtersRef.value.search = value
|
||||||
|
debouncedSearch(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Конвертация строки даты в timestamp для NaiveUI
|
||||||
|
const convertToTimestamp = (dateString) => {
|
||||||
|
if (!dateString) return null
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Предполагаем формат yyyy-MM-dd
|
||||||
|
const date = parse(dateString, 'yyyy-MM-dd', new Date())
|
||||||
|
return isValid(date) ? date.getTime() : null
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error converting date to timestamp:', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Конвертация timestamp в строку для URL
|
||||||
|
const convertTimestampToString = (timestamp) => {
|
||||||
|
if (!timestamp) return null
|
||||||
|
|
||||||
|
try {
|
||||||
|
const date = new Date(timestamp)
|
||||||
|
return isValid(date) ? format(date, 'yyyy-MM-dd') : null
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error converting timestamp to string:', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dateRange = ref([
|
||||||
|
filtersRef.value.date_extract_from ? convertToTimestamp(filtersRef.value.date_extract_from) : null,
|
||||||
|
filtersRef.value.date_extract_to ? convertToTimestamp(filtersRef.value.date_extract_to) : null
|
||||||
|
])
|
||||||
|
|
||||||
|
const handleDateRangeChange = (timestamps) => {
|
||||||
|
dateRange.value = timestamps || [null, null]
|
||||||
|
|
||||||
|
const updates = {
|
||||||
|
date_extract_from: timestamps?.[0] ? convertTimestampToString(timestamps[0]) : null,
|
||||||
|
date_extract_to: timestamps?.[1] ? convertTimestampToString(timestamps[1]) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(filtersRef.value, updates)
|
||||||
|
applyFilters(updates, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleStatusChange = (status) => {
|
||||||
|
applyFilters({ status }, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePageChange = (page) => {
|
||||||
|
applyFilters({ page })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePageSizeChange = (size) => {
|
||||||
|
applyFilters({ page_size: size, page: 1 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleViewTypeChange = (view_type) => {
|
||||||
|
applyFilters({ view_type, page: 1 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSortChange = (sorter) => {
|
||||||
|
applyFilters({
|
||||||
|
sort_by: sorter.columnKey,
|
||||||
|
sort_order: sorter.order
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetAllFilters = () => {
|
||||||
|
filtersRef.value = {
|
||||||
|
search: '',
|
||||||
|
date_extract_from: null,
|
||||||
|
date_extract_to: null,
|
||||||
|
page: 1,
|
||||||
|
page_size: 15,
|
||||||
|
sort_by: 'created_at',
|
||||||
|
sort_order: 'desc',
|
||||||
|
view_type: 'archive',
|
||||||
|
}
|
||||||
|
applyFilters({}, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Активные фильтры для отображения
|
||||||
|
const activeFilters = computed(() => {
|
||||||
|
const active = []
|
||||||
|
if (filtersRef.value.search) {
|
||||||
|
active.push({ key: 'search', label: `Поиск: ${filtersRef.value.search}` })
|
||||||
|
}
|
||||||
|
if (filtersRef.value.date_extract_from || filtersRef.value.date_extract_to) {
|
||||||
|
const from = filtersRef.value.date_extract_from ? format(parseISO(filtersRef.value.date_extract_from), 'dd.MM.yyyy') : ''
|
||||||
|
const to = filtersRef.value.date_extract_to ? format(parseISO(filtersRef.value.date_extract_to), 'dd.MM.yyyy') : ''
|
||||||
|
active.push({ key: 'date', label: `Дата: ${from} - ${to}` })
|
||||||
|
}
|
||||||
|
// Добавьте другие фильтры по необходимости
|
||||||
|
return active
|
||||||
|
})
|
||||||
|
|
||||||
|
// Следим за изменениями в page.props.filters
|
||||||
|
watch(
|
||||||
|
() => page.props.filters,
|
||||||
|
(newFilters) => {
|
||||||
|
if (newFilters) {
|
||||||
|
// Сохраняем все фильтры, включая search!
|
||||||
|
filtersRef.value = {
|
||||||
|
...filtersRef.value,
|
||||||
|
...newFilters
|
||||||
|
}
|
||||||
|
|
||||||
|
// Синхронизируем dateRange с фильтрами
|
||||||
|
const formattedDate = [
|
||||||
|
newFilters.date_extract_from ? convertToTimestamp(newFilters.date_extract_from) : null,
|
||||||
|
newFilters.date_extract_to ? convertToTimestamp(newFilters.date_extract_to) : null
|
||||||
|
]
|
||||||
|
|
||||||
|
dateRange.value = formattedDate.every(date => date === null) ? null : formattedDate
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
filtersRef,
|
||||||
|
meta,
|
||||||
|
isLoading,
|
||||||
|
activeFilters,
|
||||||
|
dateRange,
|
||||||
|
handleViewTypeChange,
|
||||||
|
handleSearch,
|
||||||
|
handleDateRangeChange,
|
||||||
|
handleStatusChange,
|
||||||
|
handlePageChange,
|
||||||
|
handlePageSizeChange,
|
||||||
|
handleSortChange,
|
||||||
|
resetAllFilters,
|
||||||
|
applyFilters
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ const themeOverrides = {
|
|||||||
>
|
>
|
||||||
<SideMenu />
|
<SideMenu />
|
||||||
</NLayoutSider>
|
</NLayoutSider>
|
||||||
<NLayout content-class="p-6 pt-2 relative" :native-scrollbar="false">
|
<NLayout content-class="p-6 relative" :native-scrollbar="false">
|
||||||
<div>
|
<div>
|
||||||
<slot name="header" />
|
<slot name="header" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,13 +1,70 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { NModal } from 'naive-ui'
|
import { NModal, NDataTable } from 'naive-ui'
|
||||||
|
import {ref, watch} from "vue";
|
||||||
|
|
||||||
const open = defineModel('open')
|
const open = defineModel('open')
|
||||||
|
const props = defineProps({
|
||||||
|
patientId: {
|
||||||
|
type: Number,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const loading = ref(true)
|
||||||
|
const patient = ref({})
|
||||||
|
|
||||||
|
const loadPatientData = async () => {
|
||||||
|
if (!props.patientId) return
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
axios.get(`/api/si/patients/${props.patientId}`).then(res => {
|
||||||
|
patient.value = res.data
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
// message.error('Ошибка при загрузке данных пациента')
|
||||||
|
console.error(error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'Выдача',
|
||||||
|
key: 'issue_at'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Возврат',
|
||||||
|
key: 'return_at'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Организация',
|
||||||
|
key: 'org_id'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'ФИО',
|
||||||
|
key: 'employee_name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Должность',
|
||||||
|
key: 'employee_post'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
// Наблюдаем за изменением patientId
|
||||||
|
watch(() => props.patientId, (newId) => {
|
||||||
|
if (newId) {
|
||||||
|
loadPatientData()
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NModal v-model:show="open">
|
<NModal v-model:show="open" preset="card" class="max-w-4xl" closable @close="open = false">
|
||||||
<template #header>
|
<template #header>
|
||||||
|
{{ patient.info?.medcardnum }} {{ patient.info?.family }} {{ patient.info?.name }} {{ patient.info?.ot }}
|
||||||
</template>
|
</template>
|
||||||
|
<NDataTable :columns="columns" :data="patient?.journal" />
|
||||||
</NModal>
|
</NModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {NDataTable, NEllipsis} from "naive-ui"
|
import {NDataTable, NEllipsis} from "naive-ui"
|
||||||
import {h, reactive, ref} from "vue"
|
import {computed, h, reactive, ref} from "vue"
|
||||||
import {useMedicalHistory} from "../../../Composables/useMedicalHistory.js";
|
import {useMedicalHistoryFilter} from "../../../Composables/useMedicalHistoryFilter.js";
|
||||||
|
import ArchiveHistoryModal from '../ArchiveHistoryModal/Index.vue'
|
||||||
|
|
||||||
const { navigate } = useMedicalHistory('/')
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
filters: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: []
|
default: []
|
||||||
},
|
},
|
||||||
meta: {
|
data: {
|
||||||
type: Object,
|
type: Array,
|
||||||
default: {}
|
default: []
|
||||||
},
|
},
|
||||||
maxHeight: {
|
maxHeight: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -20,15 +20,17 @@ const props = defineProps({
|
|||||||
minHeight: {
|
minHeight: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null
|
default: null
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { isLoading, handlePageChange, handlePageSizeChange, meta } = useMedicalHistoryFilter(props.filters)
|
||||||
|
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
{
|
{
|
||||||
title: '№ карты',
|
title: '№ карты',
|
||||||
key: 'nkarta',
|
key: 'medcardnum',
|
||||||
width: 100,
|
width: 100,
|
||||||
render: (row) => h(NEllipsis, null, { default: () => row.nkarta })
|
render: (row) => h(NEllipsis, null, { default: () => row.medcardnum })
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'ФИО',
|
title: 'ФИО',
|
||||||
@@ -44,21 +46,21 @@ const columns = ref([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Дата поступления',
|
title: 'Дата поступления',
|
||||||
key: 'mpostdate',
|
key: 'daterecipient',
|
||||||
width: 150,
|
width: 150,
|
||||||
render: (row) => h(NEllipsis, null, { default: () => row.mpostdate })
|
render: (row) => h(NEllipsis, null, { default: () => row.daterecipient })
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Дата выписки',
|
title: 'Дата выписки',
|
||||||
key: 'menddate',
|
key: 'dateextract',
|
||||||
width: 130,
|
width: 130,
|
||||||
render: (row) => h(NEllipsis, null, { default: () => row.menddate })
|
render: (row) => h(NEllipsis, null, { default: () => row.dateextract })
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '№ архива',
|
title: '№ архива',
|
||||||
key: 'narhiv',
|
key: 'narhiv',
|
||||||
width: 120,
|
width: 120,
|
||||||
render: (row) => h(NEllipsis, null, { default: () => row.narhiv })
|
render: (row) => h(NEllipsis, null, { default: () => row.narhiv || '-' })
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Дата архива',
|
title: 'Дата архива',
|
||||||
@@ -73,28 +75,35 @@ const columns = ref([
|
|||||||
render: (row) => h(NEllipsis, null, { default: () => row.status || '-' })
|
render: (row) => h(NEllipsis, null, { default: () => row.status || '-' })
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
const showArchiveHistoryModal = ref(false)
|
||||||
|
const selectedPatientId = ref(null)
|
||||||
|
const rowProps = (row) => ({
|
||||||
|
onDblclick: () => {
|
||||||
|
selectedPatientId.value = row.id
|
||||||
|
showArchiveHistoryModal.value = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const paginationReactive = reactive({
|
const pagination = computed(() => ({
|
||||||
page: props.meta.current_page,
|
page: meta.value.current_page || 1,
|
||||||
pageCount: props.meta.last_page,
|
pageCount: meta.value.last_page || 1,
|
||||||
pageSize: props.meta.per_page,
|
pageSize: meta.value.per_page || 15,
|
||||||
itemCount: props.meta.total,
|
itemCount: meta.value.total || 0,
|
||||||
pageSizes: [15, 50, 100],
|
pageSizes: [15, 50, 100],
|
||||||
showSizePicker: true,
|
showSizePicker: true,
|
||||||
prefix({ itemCount }) {
|
prefix({ itemCount }) {
|
||||||
return `Всего карт ${itemCount}.`
|
return `Всего карт ${itemCount}.`
|
||||||
},
|
},
|
||||||
onUpdatePage(page) {
|
onUpdatePage: (page) => {
|
||||||
navigate(undefined, page)
|
handlePageChange(page)
|
||||||
},
|
},
|
||||||
onUpdatePageSize(pageSize) {
|
onUpdatePageSize: handlePageSizeChange
|
||||||
navigate(undefined, 1, pageSize)
|
}))
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NDataTable remote striped :columns="columns" :pagination="paginationReactive" :max-height="maxHeight" size="small" :min-height="minHeight" :data="data" />
|
<NDataTable remote striped :loading="isLoading" :row-props="rowProps" :columns="columns" :pagination="pagination" :max-height="maxHeight" size="small" :min-height="minHeight" :data="data" />
|
||||||
|
<ArchiveHistoryModal v-model:open="showArchiveHistoryModal" :patient-id="selectedPatientId" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,38 +1,51 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import AppLayout from "../../Layouts/AppLayout.vue"
|
import AppLayout from "../../Layouts/AppLayout.vue"
|
||||||
import TableCards from './DataTable/Index.vue'
|
import TableCards from './DataTable/Index.vue'
|
||||||
import { NInput, NFlex, NDivider, NDatePicker } from 'naive-ui'
|
import { NInput, NFlex, NDivider, NDatePicker, NSpace, NRadioGroup, NRadioButton, NH1 } from 'naive-ui'
|
||||||
import {useMedicalHistory} from "../../Composables/useMedicalHistory.js";
|
import {useMedicalHistory} from "../../Composables/useMedicalHistory.js";
|
||||||
import {useDebounceFn} from "@vueuse/core";
|
import {useDebounceFn} from "@vueuse/core";
|
||||||
|
import {useMedicalHistoryFilter} from "../../Composables/useMedicalHistoryFilter.js";
|
||||||
|
import {computed, ref} from "vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
cards: {
|
cards: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: []
|
default: []
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const { navigate } = useMedicalHistory('/')
|
const {
|
||||||
|
isLoading, applyFilters, filtersRef, handleSearch, dateRange,
|
||||||
|
handleDateRangeChange, handleViewTypeChange
|
||||||
|
} = useMedicalHistoryFilter(props.filters)
|
||||||
|
|
||||||
const search = (value) => {
|
const viewType = ref('archive')
|
||||||
navigate(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const debounceSearch = useDebounceFn((searchValue) => {
|
|
||||||
search(searchValue)
|
|
||||||
}, 500)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AppLayout>
|
<AppLayout>
|
||||||
<template #header>
|
<template #header>
|
||||||
<NFlex class="py-4" align="center" :wrap="false">
|
<NSpace vertical>
|
||||||
<NInput placeholder="Поиск по ФИО, № карты" @update:value="val => debounceSearch(val)"/>
|
<NH1 class="!my-0 mb-5">
|
||||||
|
Архив
|
||||||
|
</NH1>
|
||||||
|
<NRadioGroup v-model:value="viewType" @update:value="val => handleViewTypeChange(val)">
|
||||||
|
<NRadioButton value="archive">Архив</NRadioButton>
|
||||||
|
<NRadioButton value="mis">МИС</NRadioButton>
|
||||||
|
<NRadioButton value="softinfo">СофтИнфо</NRadioButton>
|
||||||
|
</NRadioGroup>
|
||||||
|
<NFlex class="pb-4" align="center" :wrap="false">
|
||||||
|
<NInput placeholder="Поиск по ФИО, № карты" @update:value="val => handleSearch(val)"/>
|
||||||
<NDivider vertical />
|
<NDivider vertical />
|
||||||
<NDatePicker type="daterange" clearable format="dd.MM.yyyy" start-placeholder="Дата выписки с" end-placeholder="по" />
|
<NDatePicker v-model:value="dateRange" @update:value="handleDateRangeChange" type="daterange" clearable format="dd.MM.yyyy" start-placeholder="Дата выписки с" end-placeholder="по" />
|
||||||
</NFlex>
|
</NFlex>
|
||||||
|
</NSpace>
|
||||||
</template>
|
</template>
|
||||||
<TableCards :data="cards.data" :meta="cards.meta" min-height="calc(100vh - 179px)" max-height="calc(100vh - 196px)" />
|
<TableCards :filters="filters" :data="cards.data" :meta="cards.meta" min-height="calc(100vh - 277px)" max-height="calc(100vh - 320px)" />
|
||||||
</AppLayout>
|
</AppLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
15
routes/api.php
Normal file
15
routes/api.php
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
|
Route::get('/user', function (Request $request) {
|
||||||
|
return $request->user();
|
||||||
|
})->middleware('auth:sanctum');
|
||||||
|
|
||||||
|
Route::prefix('si')->group(function () {
|
||||||
|
Route::prefix('patients')->group(function () {
|
||||||
|
Route::get('{id}', [\App\Http\Controllers\MedicalHistoryController::class, 'patient']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
//Route::get('')
|
||||||
Reference in New Issue
Block a user