Новая логика поисковой выдачи
И добавлена кнопка Добавить карту в архив
This commit is contained in:
@@ -38,7 +38,7 @@ class ArchiveHistoryController extends Controller
|
||||
'employee_post' => 'nullable|string',
|
||||
'comment' => 'nullable|string',
|
||||
'has_lost' => 'boolean',
|
||||
'archive_info_id' => 'required|numeric',
|
||||
'history_id' => 'required',
|
||||
'type' => 'required|string',
|
||||
]);
|
||||
|
||||
@@ -55,9 +55,16 @@ class ArchiveHistoryController extends Controller
|
||||
->format('Y-m-d');
|
||||
}
|
||||
|
||||
$archiveInfo = ArchiveInfo::whereId($data['archive_info_id'])->first();
|
||||
if ($data['type'] === 'mis') {
|
||||
$archiveHistory = $archiveInfo->misHistory->archiveHistory()->create([
|
||||
$patient = \App\Models\Mis\SttMedicalHistory::where('MedicalHistoryID', $data['history_id'])->first();
|
||||
} else {
|
||||
$patient = \App\Models\Si\SttMedicalHistory::where('keykarta', $data['history_id'])->first();
|
||||
}
|
||||
|
||||
// $archiveInfo = ArchiveInfo::whereId($data['archive_info_id'])->first();
|
||||
|
||||
if ($data['type'] === 'mis') {
|
||||
$archiveHistory = $patient->archiveHistory()->create([
|
||||
'issue_at' => $data['issue_at'],
|
||||
'return_at' => $data['return_at'],
|
||||
'org_id' => $data['org_id'],
|
||||
@@ -65,10 +72,10 @@ class ArchiveHistoryController extends Controller
|
||||
'employee_post' => $data['employee_post'],
|
||||
'comment' => $data['comment'],
|
||||
'has_lost' => $data['has_lost'],
|
||||
'mis_history_id' => $archiveInfo->mis_history_id
|
||||
'mis_history_id' => $patient->MedicalHistoryID
|
||||
]);
|
||||
} else {
|
||||
$archiveHistory = $archiveInfo->foxproHistory->archiveHistory()->create([
|
||||
$archiveHistory = $patient->archiveHistory()->create([
|
||||
'issue_at' => $data['issue_at'],
|
||||
'return_at' => $data['return_at'],
|
||||
'org_id' => $data['org_id'],
|
||||
@@ -76,7 +83,7 @@ class ArchiveHistoryController extends Controller
|
||||
'employee_post' => $data['employee_post'],
|
||||
'comment' => $data['comment'],
|
||||
'has_lost' => $data['has_lost'],
|
||||
'foxpro_history_id' => $archiveInfo->foxpro_history_id,
|
||||
'foxpro_history_id' => $patient->keykarta,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -131,10 +138,9 @@ class ArchiveHistoryController extends Controller
|
||||
$data['post_in'] = Carbon::createFromTimestampMs($data['post_in'])->format('Y-m-d');
|
||||
}
|
||||
|
||||
$archiveInfo = ArchiveInfo::whereId($patientId)->first();
|
||||
$archiveInfo = ArchiveInfo::whereId($data['id'])->first();
|
||||
|
||||
$archiveInfo->updateOrCreate(
|
||||
['id' => $patientId],
|
||||
$archiveInfo->update(
|
||||
[
|
||||
'archive_num' => $data['num'],
|
||||
'post_in' => $data['post_in'],
|
||||
|
||||
38
app/Http/Controllers/ArchiveInfoController.php
Normal file
38
app/Http/Controllers/ArchiveInfoController.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\ArchiveInfo;
|
||||
use App\Models\Mis\SttMedicalHistory;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class ArchiveInfoController extends Controller
|
||||
{
|
||||
public function store(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'id' => 'required',
|
||||
'num' => 'required',
|
||||
'post_in' => 'required'
|
||||
]);
|
||||
|
||||
// Преобразуем timestamp в дату, если пришли числа
|
||||
if (isset($data['post_in']) && is_numeric($data['post_in'])) {
|
||||
$data['post_in'] = Carbon::createFromTimestampMs($data['post_in'])
|
||||
->setTimezone(config('app.timezone'))
|
||||
->format('Y-m-d');
|
||||
}
|
||||
|
||||
$history = SttMedicalHistory::where('MedicalHistoryID', $data['id'])->first();
|
||||
|
||||
$hasCreated = ArchiveInfo::create([
|
||||
'mis_num' => $history->MedCardNum,
|
||||
'mis_history_id' => $data['id'],
|
||||
'archive_num' => $data['num'],
|
||||
'post_in' => $data['post_in'],
|
||||
]);
|
||||
|
||||
return $hasCreated;
|
||||
}
|
||||
}
|
||||
@@ -2,21 +2,25 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Resources\IndexSttMedicalHistoryResource;
|
||||
use App\Http\Resources\SI\SttMedicalHistoryResource as SiSttMedicalHistoryResource;
|
||||
use App\Http\Resources\Mis\SttMedicalHistoryResource as MisSttMedicalHistoryResource;
|
||||
use App\Models\ArchiveStatus;
|
||||
use App\Models\SI\SttMedicalHistory;
|
||||
use App\Repositories\MedicalHistoryRepository;
|
||||
use App\Services\ArchiveCardService;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class IndexController extends Controller
|
||||
{
|
||||
private MedicalHistoryRepository $repository;
|
||||
private ArchiveCardService $cardService;
|
||||
|
||||
public function __construct(MedicalHistoryRepository $repository)
|
||||
public function __construct(MedicalHistoryRepository $repository, ArchiveCardService $cardService)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->cardService = $cardService;
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
@@ -27,7 +31,15 @@ class IndexController extends Controller
|
||||
$dateExtractTo = $request->get('date_extract_to', null);
|
||||
$status = $request->get('status', null);
|
||||
|
||||
$data = $this->repository->unifiedSearch(
|
||||
// $data = $this->repository->unifiedSearch(
|
||||
// $searchText,
|
||||
// $dateExtractFrom,
|
||||
// $dateExtractTo,
|
||||
// $status,
|
||||
// $pageSize
|
||||
// );
|
||||
|
||||
$data = $this->cardService->get(
|
||||
$searchText,
|
||||
$dateExtractFrom,
|
||||
$dateExtractTo,
|
||||
@@ -35,6 +47,8 @@ class IndexController extends Controller
|
||||
$pageSize
|
||||
);
|
||||
|
||||
// dd($data);
|
||||
|
||||
$statuses = ArchiveStatus::all()->map(function ($status) {
|
||||
return [
|
||||
'value' => $status->id,
|
||||
@@ -42,13 +56,8 @@ class IndexController extends Controller
|
||||
];
|
||||
});
|
||||
|
||||
$statuses->push([
|
||||
'value' => 0,
|
||||
'label' => 'Нет в архиве',
|
||||
]);
|
||||
|
||||
return Inertia::render('Home/Index', [
|
||||
'cards' => MisSttMedicalHistoryResource::collection($data),
|
||||
'cards' => IndexSttMedicalHistoryResource::collection($data),
|
||||
'statuses' => $statuses,
|
||||
'filters' => array_merge($request->only([
|
||||
'search', 'date_extract_from', 'date_extract_to',
|
||||
|
||||
@@ -33,7 +33,7 @@ class MedicalHistoryController extends Controller
|
||||
'can_be_issued' => $patient->canBeIssued()
|
||||
],
|
||||
'journal' => $archiveJournal,
|
||||
'archiveInfo' => $archiveInfo
|
||||
'archiveInfo' => $archiveInfo ? ArchiveInfoResource::make($archiveInfo) : null
|
||||
];
|
||||
|
||||
return response()->json($patientInfo);
|
||||
|
||||
74
app/Http/Controllers/MisHistoryController.php
Normal file
74
app/Http/Controllers/MisHistoryController.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Mis\SttMedicalHistory;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MisHistoryController extends Controller
|
||||
{
|
||||
public function search(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'query' => 'required|string'
|
||||
]);
|
||||
|
||||
$searchText = $data['query'];
|
||||
$searchParts = preg_split('/\s+/', trim($searchText));
|
||||
|
||||
$query = SttMedicalHistory::query();
|
||||
|
||||
// Проверяем, начинается ли строка с цифры (вероятно, это номер карты)
|
||||
$isCardNumberSearch = is_numeric($searchParts[0]);
|
||||
|
||||
if ($isCardNumberSearch) {
|
||||
// Паттерн: № Ф И О
|
||||
$query->where('MedCardNum', 'ILIKE', "$searchParts[0]%");
|
||||
|
||||
// ФИО начинается со второй части
|
||||
$fioStartIndex = 1;
|
||||
} else {
|
||||
// Паттерн: Ф И О (без номера)
|
||||
$fioStartIndex = 0;
|
||||
}
|
||||
|
||||
// Ищем ФИО в зависимости от количества оставшихся частей
|
||||
$fioPartsCount = count($searchParts) - $fioStartIndex;
|
||||
|
||||
if ($fioPartsCount === 1) {
|
||||
// Одно слово - ищем в фамилии, имени или отчестве
|
||||
$query->where(function ($q) use ($searchParts, $fioStartIndex) {
|
||||
$q->where('FAMILY', 'ILIKE', "{$searchParts[$fioStartIndex]}%")
|
||||
->orWhere('Name', 'ILIKE', "{$searchParts[$fioStartIndex]}%")
|
||||
->orWhere('OT', 'ILIKE', "{$searchParts[$fioStartIndex]}%");
|
||||
});
|
||||
} elseif ($fioPartsCount === 2) {
|
||||
// Два слова - фамилия и инициал имени
|
||||
$query->where(function ($q) use ($searchParts, $fioStartIndex) {
|
||||
$q->where('FAMILY', 'ILIKE', "{$searchParts[$fioStartIndex]}%")
|
||||
->where('Name', 'ILIKE', "{$searchParts[$fioStartIndex + 1]}%");
|
||||
});
|
||||
} elseif ($fioPartsCount === 3) {
|
||||
// Три слова - полное ФИО
|
||||
$query->where(function ($q) use ($searchParts, $fioStartIndex) {
|
||||
$q->where('FAMILY', 'ILIKE', "{$searchParts[$fioStartIndex]}%")
|
||||
->where('Name', 'ILIKE', "{$searchParts[$fioStartIndex + 1]}%")
|
||||
->where('OT', 'ILIKE', "{$searchParts[$fioStartIndex + 2]}%");
|
||||
});
|
||||
}
|
||||
|
||||
// Также ищем полную строку в объединенных полях
|
||||
$query->orWhereRaw("CONCAT(\"MedCardNum\", ' ', \"FAMILY\", ' ', \"Name\", ' ', \"OT\") ILIKE ?", ["{$searchText}%"]);
|
||||
|
||||
$results = $query->select([
|
||||
'MedicalHistoryID', 'MedCardNum', 'FAMILY', 'Name', 'OT'
|
||||
])->get()->map(function ($item) {
|
||||
return [
|
||||
'label' => "$item->MedCardNum - $item->FAMILY $item->Name $item->OT",
|
||||
'value' => $item->MedicalHistoryID
|
||||
];
|
||||
});
|
||||
|
||||
return response()->json($results);
|
||||
}
|
||||
}
|
||||
85
app/Http/Resources/IndexSttMedicalHistoryResource.php
Normal file
85
app/Http/Resources/IndexSttMedicalHistoryResource.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use App\Models\ArchiveStatus;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class IndexSttMedicalHistoryResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
// Получаем оригинальную модель
|
||||
$model = $this->resource;
|
||||
|
||||
$archiveInfo = $model->archiveInfo;
|
||||
$historyType = $archiveInfo->historyType();
|
||||
|
||||
$inArchive = $archiveInfo->exists;
|
||||
$hasMisType = $historyType === 'mis';
|
||||
|
||||
$family = $hasMisType ? $model->FAMILY : $model->fam;
|
||||
$im = $hasMisType ? $this->Name : $this->im;
|
||||
$ot = $hasMisType ? $this->OT : $this->ot;
|
||||
|
||||
$fio = "$family $im $ot";
|
||||
|
||||
$birthDate = $hasMisType ? $this->BD : $this->dr;
|
||||
$dateRecipient = $hasMisType ? $this->DateRecipient : $this->mpostdate;
|
||||
$dateExtract = $hasMisType ? $this->DateExtract : $this->menddate;
|
||||
$postIn = $inArchive ? $archiveInfo->post_in : null;
|
||||
|
||||
$formattedBirthDate = $birthDate ? Carbon::parse($birthDate)->format('d.m.Y') : null;
|
||||
$formattedDateRecipient = $dateRecipient ? Carbon::parse($dateRecipient)->format('d.m.Y') : null;
|
||||
$formattedDateExtract = $dateExtract ? Carbon::parse($dateExtract)->format('d.m.Y') : null;
|
||||
$formattedPostIn = $postIn ? Carbon::parse($postIn)->format('d.m.Y') : null;
|
||||
|
||||
$id = $historyType === 'mis' ? $this->MedicalHistoryID : $this->keykarta;
|
||||
$archiveNum = $inArchive ? $archiveInfo->archive_num : null;
|
||||
$status = $inArchive ? $archiveInfo->status : ArchiveStatus::find(5)->first();
|
||||
|
||||
$misCardNumber = $this->MedCardNum;
|
||||
$foxproCardNumber = $this->nkarta;
|
||||
|
||||
$archiveInfoMisCardNumber = $inArchive ? $archiveInfo->mis_num : null;
|
||||
$archiveInfoFoxproCardNumber = $inArchive ? $archiveInfo->foxpro_num : null;
|
||||
|
||||
$hasDividerCardNumber = isset($archiveInfoMisCardNumber) && isset($archiveInfoFoxproCardNumber);
|
||||
|
||||
$cardNumber = $hasDividerCardNumber
|
||||
? "$archiveInfoMisCardNumber / $archiveInfoFoxproCardNumber"
|
||||
: $archiveInfoMisCardNumber ?? $archiveInfoFoxproCardNumber;
|
||||
|
||||
return [
|
||||
'id' => $id,
|
||||
'history_type' => $historyType,
|
||||
|
||||
// Основные данные
|
||||
'fullname' => $fio,
|
||||
'family' => $family,
|
||||
'name' => $im,
|
||||
'ot' => $ot,
|
||||
'dr' => $formattedBirthDate,
|
||||
'daterecipient' => $formattedDateRecipient,
|
||||
'dateextract' => $formattedDateExtract,
|
||||
|
||||
// Номера карт
|
||||
'medcardnum' => $cardNumber, // MIS номер или FoxPro номер
|
||||
'card_num' => $archiveNum, // Архивный номер
|
||||
'datearhiv' => $formattedPostIn,
|
||||
|
||||
// Статус и возможности
|
||||
'status' => $status,
|
||||
'status_id' => $this->resource['status_id'] ?? 0,
|
||||
'can_be_issued' => $this->resource['can_be_issued'] ?? false,
|
||||
'can_add_to_archive' => $this->resource['can_add_to_archive'] ?? false,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -23,16 +23,12 @@ class ArchiveHistory extends Model
|
||||
|
||||
public function updateArchiveInfoStatus()
|
||||
{
|
||||
// Получаем связанную модель через морф
|
||||
$historyable = $this->historyable;
|
||||
|
||||
if (!$historyable) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Проверяем, есть ли у модели архивная информация
|
||||
if (method_exists($historyable, 'archiveInfo') && $historyable->archiveInfo) {
|
||||
$historyable->archiveInfo->update([
|
||||
if ($this->mis_history_id) {
|
||||
$this->misHistory->archiveInfo->update([
|
||||
'status_id' => $this->determineStatusId()
|
||||
]);
|
||||
} else {
|
||||
$this->foxproHistory->archiveInfo->update([
|
||||
'status_id' => $this->determineStatusId()
|
||||
]);
|
||||
}
|
||||
@@ -70,12 +66,12 @@ class ArchiveHistory extends Model
|
||||
|
||||
public function foxproHistory()
|
||||
{
|
||||
return $this->belongsTo(SiMedicalHistory::class, 'keykarta', 'foxpro_history_id');
|
||||
return $this->belongsTo(SiMedicalHistory::class, 'foxpro_history_id', 'keykarta');
|
||||
}
|
||||
|
||||
public function misHistory()
|
||||
{
|
||||
return $this->belongsTo(MisMedicalHistory::class, 'MedicalHistoryID', 'mis_history_id');
|
||||
return $this->belongsTo(MisMedicalHistory::class, 'mis_history_id', 'MedicalHistoryID');
|
||||
}
|
||||
|
||||
public function historyType()
|
||||
|
||||
140
app/Services/ArchiveCardService.php
Normal file
140
app/Services/ArchiveCardService.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\ArchiveInfo;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ArchiveCardService
|
||||
{
|
||||
public function get(?string $searchText,
|
||||
?string $dateExtractFrom,
|
||||
?string $dateExtractTo,
|
||||
?int $status,
|
||||
string $pageSize
|
||||
) : LengthAwarePaginator
|
||||
{
|
||||
$query = ArchiveInfo::with(['misHistory', 'foxproHistory'])
|
||||
->orderBy('post_in', 'desc');
|
||||
|
||||
// Поиск по тексту (если передан)
|
||||
if (!empty($searchText)) {
|
||||
$query->where(function ($q) use ($searchText) {
|
||||
// Разбиваем строку поиска на части (по пробелам)
|
||||
$searchParts = preg_split('/\s+/', trim($searchText));
|
||||
|
||||
$q->where(function ($subQuery) use ($searchParts, $searchText) {
|
||||
// Сначала проверяем MIS историю
|
||||
$subQuery->whereHas('misHistory', function ($misQuery) use ($searchParts, $searchText) {
|
||||
$this->applySearchToHistory($misQuery, $searchParts, $searchText, 'mis');
|
||||
});
|
||||
|
||||
// ИЛИ проверяем Foxpro историю (только если нет MIS истории)
|
||||
$subQuery->orWhere(function ($orWhereSubQuery) use ($searchParts, $searchText) {
|
||||
$orWhereSubQuery->whereNull('mis_history_id') // Нет MIS истории
|
||||
->whereHas('foxproHistory', function ($foxproQuery) use ($searchParts, $searchText) {
|
||||
$this->applySearchToHistory($foxproQuery, $searchParts, $searchText, 'foxpro');
|
||||
});
|
||||
});
|
||||
})
|
||||
// Ищем по архивным номерам
|
||||
->orWhere('archive_num', 'ILIKE', "{$searchText}%")
|
||||
->orWhere('mis_num', 'ILIKE', "{$searchText}%")
|
||||
->orWhere('foxpro_num', 'ILIKE', "{$searchText}%");
|
||||
});
|
||||
}
|
||||
|
||||
// Фильтрация по дате выписки
|
||||
if (!empty($dateExtractFrom)) {
|
||||
$query->where(function ($q) use ($dateExtractFrom) {
|
||||
$q->whereHas('misHistory', function ($misQuery) use ($dateExtractFrom) {
|
||||
$misQuery->whereDate('DateExtract', '>=', $dateExtractFrom);
|
||||
})->orWhereHas('foxproHistory', function ($foxproQuery) use ($dateExtractFrom) {
|
||||
$foxproQuery->whereDate('menddate', '>=', $dateExtractFrom);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!empty($dateExtractTo)) {
|
||||
$query->where(function ($q) use ($dateExtractTo) {
|
||||
$q->whereHas('misHistory', function ($misQuery) use ($dateExtractTo) {
|
||||
$misQuery->whereDate('DateExtract', '<=', $dateExtractTo);
|
||||
})->orWhereHas('foxproHistory', function ($foxproQuery) use ($dateExtractTo) {
|
||||
$foxproQuery->whereDate('menddate', '<=', $dateExtractTo);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Фильтрация по статусу (если передан)
|
||||
if (!empty($status)) {
|
||||
$query->where('status_id', $status);
|
||||
}
|
||||
|
||||
// Получаем результаты с пагинацией
|
||||
$results = $query->paginate($pageSize)
|
||||
->through(function ($archiveInfo) {
|
||||
// Приоритет MIS истории
|
||||
if ($archiveInfo->misHistory) {
|
||||
$history = $archiveInfo->misHistory;
|
||||
$history->history_type = 'mis';
|
||||
} else {
|
||||
$history = $archiveInfo->foxproHistory;
|
||||
$history->history_type = 'foxpro';
|
||||
}
|
||||
|
||||
return $history;
|
||||
});
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
private function applySearchToHistory($query, $searchParts, $searchText, $type)
|
||||
{
|
||||
if ($type === 'mis') {
|
||||
$query->where('MedCardNum', 'ILIKE', "{$searchText}%");
|
||||
|
||||
// Ищем ФИО в зависимости от количества частей
|
||||
if (count($searchParts) === 1) {
|
||||
$query->orWhere('FAMILY', 'ILIKE', "{$searchParts[0]}%")
|
||||
->orWhere('Name', 'ILIKE', "{$searchParts[0]}%")
|
||||
->orWhere('OT', 'ILIKE', "{$searchParts[0]}%");
|
||||
} elseif (count($searchParts) === 2) {
|
||||
$query->orWhere(function ($subQuery) use ($searchParts) {
|
||||
$subQuery->where('FAMILY', 'ILIKE', "{$searchParts[0]}%")
|
||||
->where('Name', 'ILIKE', "{$searchParts[1]}%");
|
||||
});
|
||||
} elseif (count($searchParts) === 3) {
|
||||
$query->orWhere(function ($subQuery) use ($searchParts) {
|
||||
$subQuery->where('FAMILY', 'ILIKE', "{$searchParts[0]}%")
|
||||
->where('Name', 'LIKE', "{$searchParts[1]}%")
|
||||
->where('OT', 'ILIKE', "{$searchParts[2]}%");
|
||||
});
|
||||
}
|
||||
|
||||
$query->orWhereRaw("CONCAT(\"FAMILY\", ' ', \"Name\", ' ', \"OT\") ILIKE ?", ["{$searchText}%"]);
|
||||
} else { // foxpro
|
||||
$query->where('nkarta', 'ILIKE', "{$searchText}%");
|
||||
|
||||
if (count($searchParts) === 1) {
|
||||
$query->orWhere('fam', 'ILIKE', "{$searchParts[0]}%")
|
||||
->orWhere('im', 'ILIKE', "{$searchParts[0]}%")
|
||||
->orWhere('ot', 'ILIKE', "{$searchParts[0]}%");
|
||||
} elseif (count($searchParts) === 2) {
|
||||
$query->orWhere(function ($subQuery) use ($searchParts) {
|
||||
$subQuery->where('fam', 'ILIKE', "{$searchParts[0]}%")
|
||||
->where('im', 'ILIKE', "{$searchParts[1]}%");
|
||||
});
|
||||
} elseif (count($searchParts) === 3) {
|
||||
$query->orWhere(function ($subQuery) use ($searchParts) {
|
||||
$subQuery->where('fam', 'ILIKE', "{$searchParts[0]}%")
|
||||
->where('im', 'ILIKE', "{$searchParts[1]}%")
|
||||
->where('ot', 'ILIKE', "{$searchParts[2]}%");
|
||||
});
|
||||
}
|
||||
|
||||
$query->orWhereRaw("CONCAT(fam, ' ', im, ' ', ot) ILIKE ?", ["{$searchText}%"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
104
resources/js/Pages/Home/ArchiveHistoryCreateModal/Index.vue
Normal file
104
resources/js/Pages/Home/ArchiveHistoryCreateModal/Index.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<script setup>
|
||||
import { NModal, NSelect, NSpace, NFlex, NButton, NForm, NFormItem, NInput, NDatePicker, NDivider, NSpin, NTag } from 'naive-ui'
|
||||
import ArchiveHistoryMoveModal from '../ArchiveHistoryMoveModal/Index.vue'
|
||||
import {computed, ref, watch} from "vue";
|
||||
import {useMedicalHistoryFilter} from "../../../Composables/useMedicalHistoryFilter.js";
|
||||
import {useNotification} from "../../../Composables/useNotification.js";
|
||||
import {useDebounceFn} from "@vueuse/core";
|
||||
|
||||
const open = defineModel('open')
|
||||
|
||||
const {errorApi} = useNotification()
|
||||
const loading = ref(false)
|
||||
const archiveInfo = ref({
|
||||
id: null,
|
||||
num: null,
|
||||
post_in: null,
|
||||
})
|
||||
const loadingFilterPatients = ref(false)
|
||||
|
||||
const emits = defineEmits(['historyUpdated', 'closeWithoutSave'])
|
||||
|
||||
const onResetData = () => {
|
||||
archiveInfo.value = {
|
||||
id: null,
|
||||
num: null,
|
||||
post_in: null,
|
||||
}
|
||||
}
|
||||
|
||||
const onCloseWithoutSave = () => {
|
||||
emits('closeWithoutSave')
|
||||
open.value = false
|
||||
}
|
||||
|
||||
const filteredPatients = ref([])
|
||||
|
||||
const debounceSearchCard = useDebounceFn(async (query) => {
|
||||
loadingFilterPatients.value = true
|
||||
await axios.post('/api/mis/patients/search', {
|
||||
query
|
||||
}).then(res => {
|
||||
filteredPatients.value = res.data
|
||||
}).finally(() => {
|
||||
loadingFilterPatients.value = false
|
||||
})
|
||||
}, 1000)
|
||||
|
||||
const handleSearchCard = (query) => {
|
||||
debounceSearchCard(query)
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await axios.post(`/api/archive/create`, archiveInfo.value).then(res => {
|
||||
open.value = false
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
errorApi(error)
|
||||
console.error(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NModal v-model:show="open" preset="card" class="max-w-xl relative overflow-clip" closable @close="onCloseWithoutSave">
|
||||
<template #header>
|
||||
Добавить карту в архив
|
||||
</template>
|
||||
<NFlex class="w-full" :wrap="false">
|
||||
<NForm class="w-full">
|
||||
<NFormItem label="Пациент">
|
||||
<NSelect placeholder="№ карты фамилия имя отчество или фамилия имя отчество" size="large" :remote filterable :loading="loadingFilterPatients" :options="filteredPatients" v-model:value="archiveInfo.id" @search="handleSearchCard" />
|
||||
</NFormItem>
|
||||
<NFormItem size="large" label="№ в архиве">
|
||||
<NInput v-model:value="archiveInfo.num" />
|
||||
</NFormItem>
|
||||
<NFormItem size="large" label="Дата поступления карты в архив">
|
||||
<NDatePicker class="w-full" v-model:value="archiveInfo.post_in" format="dd.MM.yyyy" />
|
||||
</NFormItem>
|
||||
</NForm>
|
||||
</NFlex>
|
||||
<template #action>
|
||||
<NFlex justify="end" align="center">
|
||||
<NSpace align="center" :size="0">
|
||||
<NButton secondary type="primary" @click="onSubmit">
|
||||
Добавить карту
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</NFlex>
|
||||
</template>
|
||||
|
||||
<div v-show="loading" class="absolute inset-0 z-10 backdrop-blur flex items-center justify-center">
|
||||
<NSpin :show="true" />
|
||||
</div>
|
||||
</NModal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -73,10 +73,10 @@ const loadPatientData = async () => {
|
||||
const onShowArchiveHistoryModal = (id) => {
|
||||
if (id === null) {
|
||||
isCreateNewArchiveHistoryModal.value = true
|
||||
selectedArchiveHistoryId.value = props.patientInfo.id
|
||||
selectedArchiveHistoryId.value = Number(props.patientInfo.id)
|
||||
} else {
|
||||
isCreateNewArchiveHistoryModal.value = false
|
||||
selectedArchiveHistoryId.value = id
|
||||
selectedArchiveHistoryId.value = Number(id)
|
||||
}
|
||||
selectedArchiveHistoryType.value = props.patientInfo.type
|
||||
showArchiveHistoryModal.value = true
|
||||
@@ -159,7 +159,7 @@ watch(() => props.patientInfo, async (newId) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NModal v-model:show="open" preset="card" class="max-w-4xl relative" closable @close="onCloseWithoutSave">
|
||||
<NModal v-model:show="open" preset="card" class="max-w-4xl relative overflow-clip" closable @close="onCloseWithoutSave">
|
||||
<template #header>
|
||||
{{ patient.info?.medcardnum }} {{ patient.info?.family }} {{ patient.info?.name }} {{ patient.info?.ot }}
|
||||
</template>
|
||||
@@ -203,7 +203,7 @@ watch(() => props.patientInfo, async (newId) => {
|
||||
</NFlex>
|
||||
</template>
|
||||
|
||||
<div v-show="loading" class="absolute inset-0 z-10 bg-white flex items-center justify-center">
|
||||
<div v-show="loading" class="absolute inset-0 z-10 backdrop-blur flex items-center justify-center">
|
||||
<NSpin :show="true" />
|
||||
</div>
|
||||
</NModal>
|
||||
|
||||
@@ -44,7 +44,7 @@ const orgs = ref([])
|
||||
|
||||
const onResetData = () => {
|
||||
archiveHistory.value = {
|
||||
archive_info_id: props.archiveHistoryId,
|
||||
history_id: props.archiveHistoryId,
|
||||
type: props.type,
|
||||
issue_at: null,
|
||||
org_id: null,
|
||||
@@ -111,7 +111,7 @@ watch(() => props.archiveHistoryId, async (newId) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NModal v-model:show="open" preset="card" class="max-w-2xl relative" closable @close="onCloseWithoutSave">
|
||||
<NModal v-model:show="open" preset="card" class="max-w-2xl relative overflow-clip" closable @close="onCloseWithoutSave">
|
||||
<template #header>
|
||||
{{ isCreateNew ? 'Добавить' : 'Редактировать' }} запись выдачи
|
||||
</template>
|
||||
@@ -153,7 +153,7 @@ watch(() => props.archiveHistoryId, async (newId) => {
|
||||
</NFlex>
|
||||
</template>
|
||||
|
||||
<div v-show="loading" class="absolute inset-0 z-10 bg-white flex items-center justify-center">
|
||||
<div v-show="loading" class="absolute inset-0 z-10 backdrop-blur flex items-center justify-center">
|
||||
<NSpin :show="true" />
|
||||
</div>
|
||||
</NModal>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script setup>
|
||||
import AppLayout from "../../Layouts/AppLayout.vue"
|
||||
import TableCards from './DataTable/Index.vue'
|
||||
import { NInput, NFlex, NDivider, NDatePicker, NSpace, NFormItem, NRadioButton, NH1, NTabs, NTabPane, NSelect } from 'naive-ui'
|
||||
import ArchiveHistoryCreateModal from './ArchiveHistoryCreateModal/Index.vue'
|
||||
import { NInput, NFlex, NDivider, NDatePicker, NSpace, NFormItem, NRadioButton, NH1, NTabs, NButton, NSelect } from 'naive-ui'
|
||||
import {useMedicalHistoryFilter} from "../../Composables/useMedicalHistoryFilter.js";
|
||||
import {ref} from "vue";
|
||||
|
||||
@@ -20,6 +21,7 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const ArchiveHistoryCreateModalShow = ref(false)
|
||||
const {
|
||||
isLoading, applyFilters, filtersRef, handleSearch, dateRange, searchValue,
|
||||
handleDateRangeChange, handleViewTypeChange, handleStatusChange
|
||||
@@ -58,10 +60,16 @@ const handleBeforeLeave = (tabName) => {
|
||||
<NFormItem class="w-[340px]" label="Статус карты" :show-feedback="false">
|
||||
<NSelect :options="statuses" @update:value="val => handleStatusChange(val)" clearable size="large" />
|
||||
</NFormItem>
|
||||
<NFormItem class="w-[340px]" :show-feedback="false">
|
||||
<NButton type="primary" @click="ArchiveHistoryCreateModalShow = true" secondary size="large">
|
||||
Добавить карту в архив
|
||||
</NButton>
|
||||
</NFormItem>
|
||||
</NFlex>
|
||||
</NSpace>
|
||||
</template>
|
||||
<TableCards :filters="filters" :data="cards.data" :meta="cards.meta" min-height="calc(100vh - 212px)" max-height="calc(100vh - 320px)" />
|
||||
<ArchiveHistoryCreateModal v-model:open="ArchiveHistoryCreateModalShow" />
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -13,6 +13,12 @@ Route::prefix('si')->group(function () {
|
||||
});
|
||||
});
|
||||
|
||||
Route::prefix('mis')->group(function () {
|
||||
Route::prefix('patients')->group(function () {
|
||||
Route::post('search', [\App\Http\Controllers\MisHistoryController::class, 'search']);
|
||||
});
|
||||
});
|
||||
|
||||
Route::prefix('archive')->group(function () {
|
||||
Route::prefix('histories')->group(function () {
|
||||
Route::get('{id}', [\App\Http\Controllers\ArchiveHistoryController::class, 'show']);
|
||||
@@ -24,6 +30,8 @@ Route::prefix('archive')->group(function () {
|
||||
Route::post('{patientId}', [\App\Http\Controllers\ArchiveHistoryController::class, 'infoUpdate']);
|
||||
});
|
||||
});
|
||||
|
||||
Route::post('create', [\App\Http\Controllers\ArchiveInfoController::class, 'store']);
|
||||
});
|
||||
|
||||
Route::prefix('orgs')->group(function () {
|
||||
|
||||
2
storage/debugbar/.gitignore
vendored
Normal file
2
storage/debugbar/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
Reference in New Issue
Block a user