Demo ready dashboard
This commit is contained in:
parent
0b596cdc37
commit
612566d2a6
@ -1,23 +1,61 @@
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SimpleLIS.Models;
|
||||
using SimpleLIS.Services;
|
||||
|
||||
namespace SimpleLIS.Controllers;
|
||||
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private readonly ILogger<HomeController> _logger;
|
||||
private readonly MessageService _messageService;
|
||||
private readonly PatientService _patientService;
|
||||
private readonly ObservationService _observationService;
|
||||
|
||||
public HomeController(ILogger<HomeController> logger)
|
||||
public HomeController(
|
||||
ILogger<HomeController> logger,
|
||||
MessageService messageService,
|
||||
PatientService patientService,
|
||||
ObservationService observationService)
|
||||
{
|
||||
_logger = logger;
|
||||
_messageService = messageService;
|
||||
_patientService = patientService;
|
||||
_observationService = observationService;
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
public async Task<IActionResult> Index()
|
||||
{
|
||||
var patients = await _patientService.ListPatientsAsync();
|
||||
var messages = await _messageService.ListMessagesAsync();
|
||||
var observations = await _observationService.ListObservationsAsync();
|
||||
|
||||
ViewBag.TotalPatients = patients.Count();
|
||||
ViewBag.TotalMessages = messages.Count();
|
||||
ViewBag.TotalObservations = observations.Count();
|
||||
ViewBag.RecentMessages = messages.OrderByDescending(m => m.Timestamp).Take(5);
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Patients()
|
||||
{
|
||||
var patients = await _patientService.ListPatientsAsync();
|
||||
return View(patients);
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Messages()
|
||||
{
|
||||
var messages = await _messageService.ListMessagesAsync();
|
||||
return View(messages.OrderByDescending(m => m.Timestamp));
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Observations()
|
||||
{
|
||||
var observations = await _observationService.ListObservationsAsync();
|
||||
return View(observations);
|
||||
}
|
||||
|
||||
public IActionResult Privacy()
|
||||
{
|
||||
return View();
|
||||
|
||||
@ -28,7 +28,10 @@ public class MessageService
|
||||
|
||||
public async Task<IEnumerable<Message>> ListMessagesAsync()
|
||||
{
|
||||
return await _context.Messages.Include(m => m.Observations).ToListAsync();
|
||||
return await _context.Messages
|
||||
.Include(m => m.Observations)
|
||||
.Include(m => m.Patient)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<Message> UpdateMessageAsync(Message message)
|
||||
|
||||
@ -28,7 +28,10 @@ public class ObservationService
|
||||
|
||||
public async Task<IEnumerable<Observation>> ListObservationsAsync()
|
||||
{
|
||||
return await _context.Observations.Include(o => o.Message).ToListAsync();
|
||||
return await _context.Observations
|
||||
.Include(o => o.Message)
|
||||
.ThenInclude(m => m.Patient)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<Observation> UpdateObservationAsync(Observation observation)
|
||||
|
||||
@ -38,7 +38,9 @@ public class PatientService
|
||||
|
||||
public async Task<IEnumerable<Patient>> ListPatientsAsync()
|
||||
{
|
||||
return await _context.Patients.ToListAsync();
|
||||
return await _context.Patients
|
||||
.Include(p => p.Messages)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<Patient> UpdatePatientAsync(Patient patient)
|
||||
|
||||
@ -1,8 +1,145 @@
|
||||
@{
|
||||
ViewData["Title"] = "Home Page";
|
||||
ViewData["Title"] = "Dashboard";
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="display-4">Welcome</h1>
|
||||
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h1 class="display-4 mb-0">Dashboard</h1>
|
||||
<p class="text-muted">Laboratory Information System - Real-time HL7 Message Processing</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistics Cards -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card text-white bg-primary">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="card-title text-white-50 text-uppercase mb-1">Total Patients</h6>
|
||||
<h2 class="mb-0">@ViewBag.TotalPatients</h2>
|
||||
</div>
|
||||
<div class="fs-1 opacity-50">
|
||||
<i class="bi bi-people-fill"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card text-white bg-success">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="card-title text-white-50 text-uppercase mb-1">HL7 Messages</h6>
|
||||
<h2 class="mb-0">@ViewBag.TotalMessages</h2>
|
||||
</div>
|
||||
<div class="fs-1 opacity-50">
|
||||
<i class="bi bi-envelope-fill"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card text-white bg-info">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="card-title text-white-50 text-uppercase mb-1">Lab Observations</h6>
|
||||
<h2 class="mb-0">@ViewBag.TotalObservations</h2>
|
||||
</div>
|
||||
<div class="fs-1 opacity-50">
|
||||
<i class="bi bi-clipboard2-pulse-fill"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Messages -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white">
|
||||
<h5 class="mb-0">Recent HL7 Messages</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (ViewBag.RecentMessages != null && ((IEnumerable<SimpleLIS.Models.Message>)ViewBag.RecentMessages).Any())
|
||||
{
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Control ID</th>
|
||||
<th>Message Type</th>
|
||||
<th>Patient</th>
|
||||
<th>Sending Facility</th>
|
||||
<th>Timestamp</th>
|
||||
<th>Observations</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var message in (IEnumerable<SimpleLIS.Models.Message>)ViewBag.RecentMessages)
|
||||
{
|
||||
<tr>
|
||||
<td><code>@message.ControlId</code></td>
|
||||
<td><span class="badge bg-primary">@message.MessageType</span></td>
|
||||
<td>@message.Patient.FirstName @message.Patient.LastName</td>
|
||||
<td>@message.SendingFacility</td>
|
||||
<td>@message.Timestamp.ToString("yyyy-MM-dd HH:mm:ss")</td>
|
||||
<td><span class="badge bg-info">@message.Observations.Count tests</span></td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-info mb-0">
|
||||
<strong>No messages yet.</strong> Start Mirth Connect and send HL7 messages to see them appear here!
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="card-footer bg-white">
|
||||
<a asp-controller="Home" asp-action="Messages" class="btn btn-sm btn-primary">View All Messages</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white">
|
||||
<h5 class="mb-0">Quick Actions</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-2">
|
||||
<a asp-controller="Home" asp-action="Patients" class="btn btn-outline-primary btn-lg w-100">
|
||||
<i class="bi bi-people"></i> View All Patients
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 mb-2">
|
||||
<a asp-controller="Home" asp-action="Messages" class="btn btn-outline-success btn-lg w-100">
|
||||
<i class="bi bi-envelope"></i> View All Messages
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-4 mb-2">
|
||||
<a asp-controller="Home" asp-action="Observations" class="btn btn-outline-info btn-lg w-100">
|
||||
<i class="bi bi-clipboard2-pulse"></i> View Observations
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
115
Views/Home/Messages.cshtml
Normal file
115
Views/Home/Messages.cshtml
Normal file
@ -0,0 +1,115 @@
|
||||
@model IEnumerable<SimpleLIS.Models.Message>
|
||||
@{
|
||||
ViewData["Title"] = "HL7 Messages";
|
||||
}
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h1 class="display-4 mb-0">HL7 Messages</h1>
|
||||
<p class="text-muted">All received HL7 messages from Mirth Connect</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">Message Log</h5>
|
||||
<span class="badge bg-success">@Model.Count() Total</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (Model.Any())
|
||||
{
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover" id="messagesTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Message ID</th>
|
||||
<th>Control ID</th>
|
||||
<th>Type</th>
|
||||
<th>Patient</th>
|
||||
<th>Sending</th>
|
||||
<th>Receiving</th>
|
||||
<th>Timestamp</th>
|
||||
<th>Version</th>
|
||||
<th>Tests</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var message in Model)
|
||||
{
|
||||
<tr>
|
||||
<td><code>@message.MessageId</code></td>
|
||||
<td><code>@message.ControlId</code></td>
|
||||
<td><span class="badge bg-primary">@message.MessageType</span></td>
|
||||
<td>
|
||||
<strong>@message.Patient.LastName, @message.Patient.FirstName</strong>
|
||||
<br />
|
||||
<small class="text-muted">ID: @message.Patient.HL7PatientId</small>
|
||||
</td>
|
||||
<td>
|
||||
<strong>@message.SendingApp</strong>
|
||||
<br />
|
||||
<small class="text-muted">@message.SendingFacility</small>
|
||||
</td>
|
||||
<td>
|
||||
<strong>@message.ReceivingApp</strong>
|
||||
<br />
|
||||
<small class="text-muted">@message.ReceivingFacility</small>
|
||||
</td>
|
||||
<td>
|
||||
@message.Timestamp.ToString("yyyy-MM-dd")
|
||||
<br />
|
||||
<small class="text-muted">@message.Timestamp.ToString("HH:mm:ss")</small>
|
||||
</td>
|
||||
<td><span class="badge bg-secondary">@message.Version</span></td>
|
||||
<td>
|
||||
<span class="badge bg-info">@message.Observations.Count</span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-info mb-0">
|
||||
<strong>No messages received yet.</strong>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12">
|
||||
<a asp-controller="Home" asp-action="Index" class="btn btn-secondary">
|
||||
<i class="bi bi-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
@if (Model.Any())
|
||||
{
|
||||
<text>
|
||||
$(document).ready(function() {
|
||||
// Add search functionality
|
||||
$('#messagesTable').before('<div class="mb-3"><input type="text" id="searchInput" class="form-control" placeholder="Search messages..."></div>');
|
||||
|
||||
$('#searchInput').on('keyup', function() {
|
||||
var value = $(this).val().toLowerCase();
|
||||
$('#messagesTable tbody tr').filter(function() {
|
||||
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
|
||||
});
|
||||
});
|
||||
});
|
||||
</text>
|
||||
}
|
||||
</script>
|
||||
}
|
||||
261
Views/Home/Observations.cshtml
Normal file
261
Views/Home/Observations.cshtml
Normal file
@ -0,0 +1,261 @@
|
||||
@model IEnumerable<SimpleLIS.Models.Observation>
|
||||
@{
|
||||
ViewData["Title"] = "Lab Observations";
|
||||
}
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h1 class="display-4 mb-0">Laboratory Observations</h1>
|
||||
<p class="text-muted">All lab test results and observations</p>
|
||||
</div>
|
||||
</div>
|
||||
@if (Model.Any())
|
||||
{
|
||||
var abnormalCount = Model.Count(o => !string.IsNullOrEmpty(o.AbnormalFlag) && o.AbnormalFlag != "N");
|
||||
var finalCount = Model.Count(o => o.ResultStatus == "F");
|
||||
var uniqueTests = Model.Select(o => o.ObservationCode).Distinct().Count();
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card text-white bg-success">
|
||||
<div class="card-body text-center">
|
||||
<h3>@Model.Count()</h3>
|
||||
<p class="mb-0">Total Observations</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card text-white bg-warning">
|
||||
<div class="card-body text-center">
|
||||
<h3>@abnormalCount</h3>
|
||||
<p class="mb-0">Abnormal Results</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card text-white bg-info">
|
||||
<div class="card-body text-center">
|
||||
<h3>@uniqueTests</h3>
|
||||
<p class="mb-0">Unique Test Types</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">Test Results</h5>
|
||||
<span class="badge bg-info">@Model.Count() Total</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (Model.Any())
|
||||
{
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover" id="observationsTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Observation ID</th>
|
||||
<th>Patient</th>
|
||||
<th>Test Code</th>
|
||||
<th>Result Value</th>
|
||||
<th>Units</th>
|
||||
<th>Abnormal Flag</th>
|
||||
<th>Status</th>
|
||||
<th>Message Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var obs in Model)
|
||||
{
|
||||
<tr>
|
||||
<td><code>@obs.ObservationId</code></td>
|
||||
<td>
|
||||
<strong>@obs.Message.Patient.LastName, @obs.Message.Patient.FirstName</strong>
|
||||
<br />
|
||||
<small class="text-muted">@obs.Message.Patient.HL7PatientId</small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-secondary">@obs.ObservationCode</span>
|
||||
</td>
|
||||
<td>
|
||||
<strong class="@(obs.AbnormalFlag != null && obs.AbnormalFlag != "N" && obs.AbnormalFlag != "" ? "text-danger" : "")">
|
||||
@obs.ObservationValue
|
||||
</strong>
|
||||
</td>
|
||||
<td>@obs.Units</td>
|
||||
<td>
|
||||
@if (string.IsNullOrEmpty(obs.AbnormalFlag) || obs.AbnormalFlag == "N")
|
||||
{
|
||||
<span class="badge bg-success">Normal</span>
|
||||
}
|
||||
else if (obs.AbnormalFlag == "H")
|
||||
{
|
||||
<span class="badge bg-danger">High</span>
|
||||
}
|
||||
else if (obs.AbnormalFlag == "L")
|
||||
{
|
||||
<span class="badge bg-warning">Low</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="badge bg-dark">@obs.AbnormalFlag</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (obs.ResultStatus == "F")
|
||||
{
|
||||
<span class="badge bg-success">Final</span>
|
||||
}
|
||||
else if (obs.ResultStatus == "P")
|
||||
{
|
||||
<span class="badge bg-warning">Preliminary</span>
|
||||
}
|
||||
else if (obs.ResultStatus == "C")
|
||||
{
|
||||
<span class="badge bg-info">Corrected</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="badge bg-secondary">@obs.ResultStatus</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@obs.Message.Timestamp.ToString("yyyy-MM-dd")
|
||||
<br />
|
||||
<small class="text-muted">@obs.Message.Timestamp.ToString("HH:mm:ss")</small>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-info mb-0">
|
||||
<strong>No observations found.</strong> Lab observations will appear here once HL7 messages with OBX segments are processed.
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistics -->
|
||||
@if (Model.Any())
|
||||
{
|
||||
var abnormalCount = Model.Count(o => !string.IsNullOrEmpty(o.AbnormalFlag) && o.AbnormalFlag != "N");
|
||||
var finalCount = Model.Count(o => o.ResultStatus == "F");
|
||||
var uniqueTests = Model.Select(o => o.ObservationCode).Distinct().Count();
|
||||
|
||||
@* <div class="row mt-4">
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card text-white bg-success">
|
||||
<div class="card-body text-center">
|
||||
<h3>@Model.Count()</h3>
|
||||
<p class="mb-0">Total Observations</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card text-white bg-warning">
|
||||
<div class="card-body text-center">
|
||||
<h3>@abnormalCount</h3>
|
||||
<p class="mb-0">Abnormal Results</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card text-white bg-info">
|
||||
<div class="card-body text-center">
|
||||
<h3>@uniqueTests</h3>
|
||||
<p class="mb-0">Unique Test Types</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> *@
|
||||
|
||||
<!-- Common Test Types -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white">
|
||||
<h5 class="mb-0">Test Type Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
@foreach (var testGroup in Model.GroupBy(o => o.ObservationCode).OrderByDescending(g => g.Count()).Take(6))
|
||||
{
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="badge bg-secondary">@testGroup.Key</span>
|
||||
<span class="badge bg-primary">@testGroup.Count() results</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12">
|
||||
<a asp-controller="Home" asp-action="Index" class="btn btn-secondary">
|
||||
<i class="bi bi-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
@if (Model.Any())
|
||||
{
|
||||
<text>
|
||||
$(document).ready(function() {
|
||||
var filterHtml = '<div class="row mb-3">' +
|
||||
'<div class="col-md-8"><input type="text" id="searchInput" class="form-control" placeholder="Search observations..."></div>' +
|
||||
'<div class="col-md-4">' +
|
||||
'<select id="statusFilter" class="form-select">' +
|
||||
'<option value="">All Statuses</option>' +
|
||||
'<option value="Normal">Normal Only</option>' +
|
||||
'<option value="Abnormal">Abnormal Only</option>' +
|
||||
'</select>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
$('#observationsTable').before(filterHtml);
|
||||
|
||||
// Search functionality
|
||||
$('#searchInput').on('keyup', function() {
|
||||
var value = $(this).val().toLowerCase();
|
||||
$('#observationsTable tbody tr').filter(function() {
|
||||
var matchesSearch = $(this).text().toLowerCase().indexOf(value) > -1;
|
||||
var statusFilter = $('#statusFilter').val();
|
||||
var matchesStatus = true;
|
||||
|
||||
if (statusFilter === 'Normal') {
|
||||
matchesStatus = $(this).find('.badge.bg-success').length > 0;
|
||||
} else if (statusFilter === 'Abnormal') {
|
||||
matchesStatus = $(this).find('.badge.bg-danger, .badge.bg-warning').length > 0;
|
||||
}
|
||||
|
||||
$(this).toggle(matchesSearch && matchesStatus);
|
||||
});
|
||||
});
|
||||
|
||||
// Status filter
|
||||
$('#statusFilter').on('change', function() {
|
||||
$('#searchInput').trigger('keyup');
|
||||
});
|
||||
});
|
||||
</text>
|
||||
}
|
||||
</script>
|
||||
}
|
||||
112
Views/Home/Patients.cshtml
Normal file
112
Views/Home/Patients.cshtml
Normal file
@ -0,0 +1,112 @@
|
||||
@model IEnumerable<SimpleLIS.Models.Patient>
|
||||
@{
|
||||
ViewData["Title"] = "Patients";
|
||||
}
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h1 class="display-4 mb-0">Patients</h1>
|
||||
<p class="text-muted">All registered patients in the system</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">Patient List</h5>
|
||||
<span class="badge bg-primary">@Model.Count() Total</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (Model.Any())
|
||||
{
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover" id="patientsTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Patient ID</th>
|
||||
<th>HL7 Patient ID</th>
|
||||
<th>Name</th>
|
||||
<th>Date of Birth</th>
|
||||
<th>Age</th>
|
||||
<th>Gender</th>
|
||||
<th>Messages</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var patient in Model)
|
||||
{
|
||||
var age = DateTime.Now.Year - patient.DateOfBirth.Year;
|
||||
if (DateTime.Now.DayOfYear < patient.DateOfBirth.DayOfYear) age--;
|
||||
|
||||
<tr>
|
||||
<td><code>@patient.PatientId</code></td>
|
||||
<td><code>@patient.HL7PatientId</code></td>
|
||||
<td>
|
||||
<strong>@patient.LastName, @patient.FirstName</strong>
|
||||
</td>
|
||||
<td>@patient.DateOfBirth.ToString("yyyy-MM-dd")</td>
|
||||
<td>@age years</td>
|
||||
<td>
|
||||
@if (patient.Gender?.ToUpper() == "M")
|
||||
{
|
||||
<span class="badge bg-primary">Male</span>
|
||||
}
|
||||
else if (patient.Gender?.ToUpper() == "F")
|
||||
{
|
||||
<span class="badge bg-danger">Female</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="badge bg-secondary">@patient.Gender</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-info">@patient.Messages.Count messages</span>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-info mb-0">
|
||||
<strong>No patients found.</strong> Send HL7 messages through Mirth Connect to populate patient data.
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12">
|
||||
<a asp-controller="Home" asp-action="Index" class="btn btn-secondary">
|
||||
<i class="bi bi-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
@if (Model.Any())
|
||||
{
|
||||
<text>
|
||||
$(document).ready(function() {
|
||||
$('#patientsTable').before('<div class="mb-3"><input type="text" id="searchInput" class="form-control" placeholder="Search patients..."></div>');
|
||||
|
||||
$('#searchInput').on('keyup', function() {
|
||||
var value = $(this).val().toLowerCase();
|
||||
$('#patientsTable tbody tr').filter(function() {
|
||||
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
|
||||
});
|
||||
});
|
||||
});
|
||||
</text>
|
||||
}
|
||||
</script>
|
||||
}
|
||||
@ -5,6 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - SimpleLIS</title>
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
|
||||
<link rel="stylesheet" href="~/SimpleLIS.styles.css" asp-append-version="true" />
|
||||
</head>
|
||||
@ -20,10 +21,31 @@
|
||||
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul class="navbar-nav flex-grow-1">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">
|
||||
<i class="bi bi-speedometer2"></i> Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Patients">
|
||||
<i class="bi bi-people"></i> Patients
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Messages">
|
||||
<i class="bi bi-envelope"></i> Messages
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Observations">
|
||||
<i class="bi bi-clipboard2-pulse"></i> Observations
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" href="/swagger" target="_blank">
|
||||
<i class="bi bi-code-square"></i> API Docs
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
BIN
hl7.db-shm
BIN
hl7.db-shm
Binary file not shown.
BIN
hl7.db-wal
BIN
hl7.db-wal
Binary file not shown.
Loading…
Reference in New Issue
Block a user