HH/templates/simulator/log_list.html

360 lines
15 KiB
HTML

{% extends "layouts/base.html" %}
{% load i18n static %}
{% block title %}{% trans "HIS Logs" %} - PX360{% endblock %}
{% block extra_css %}
<style>
.stats-card {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
.stat-value {
font-size: 2rem;
font-weight: bold;
color: #2c3e50;
}
.stat-label {
color: #7f8c8d;
font-size: 0.9rem;
margin-top: 5px;
}
.stat-success { color: #27ae60; }
.stat-failed { color: #e74c3c; }
.stat-partial { color: #f39c12; }
.channel-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 0.85rem;
font-weight: 500;
}
.channel-email { background: #e3f2fd; color: #1976d2; }
.channel-sms { background: #fff3e0; color: #f57c00; }
.channel-his_event { background: #e8f5e9; color: #388e3c; }
.status-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 0.85rem;
font-weight: 500;
}
.status-success, .status-sent { background: #d4edda; color: #155724; }
.status-failed { background: #f8d7da; color: #721c24; }
.status-partial { background: #fff3cd; color: #856404; }
.filter-section {
background: white;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.table-hover tbody tr:hover {
background-color: #f8f9fa;
}
.json-preview {
background: #f5f5f5;
padding: 8px;
border-radius: 4px;
font-family: monospace;
font-size: 0.85rem;
max-height: 100px;
overflow: auto;
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row mb-4">
<div class="col">
<h2><i class="fas fa-robot"></i> {% trans "HIS Logs" %}</h2>
<p class="text-muted">{% trans "View all HIS requests and responses" %}</p>
</div>
<div class="col-auto">
{% if user.is_superuser or user.is_px_admin %}
<form method="post" action="{% url 'simulator:clear_logs' %}" onsubmit="return confirm('{% trans "Are you sure you want to clear all HIS logs? This cannot be undone." %}');">
{% csrf_token %}
<button type="submit" class="btn btn-danger">
<i class="fas fa-trash"></i> {% trans "Clear All Logs" %}
</button>
</form>
{% endif %}
</div>
</div>
<!-- Statistics Dashboard -->
<div class="row">
<div class="col-md-2">
<div class="stats-card text-center">
<div class="stat-value">{{ stats.total }}</div>
<div class="stat-label">{% trans "Total Requests" %}</div>
</div>
</div>
<div class="col-md-2">
<div class="stats-card text-center">
<div class="stat-value stat-success">{{ stats.success }}</div>
<div class="stat-label">{% trans "Success" %}</div>
</div>
</div>
<div class="col-md-2">
<div class="stats-card text-center">
<div class="stat-value stat-failed">{{ stats.failed }}</div>
<div class="stat-label">{% trans "Failed" %}</div>
</div>
</div>
<div class="col-md-2">
<div class="stats-card text-center">
<div class="stat-value stat-partial">{{ stats.partial }}</div>
<div class="stat-label">{% trans "Partial" %}</div>
</div>
</div>
<div class="col-md-2">
<div class="stats-card text-center">
<div class="stat-value">{{ stats.success_rate }}%</div>
<div class="stat-label">{% trans "Success Rate" %}</div>
</div>
</div>
<div class="col-md-2">
<div class="stats-card text-center">
<div class="stat-value">{{ stats.avg_processing_time }}ms</div>
<div class="stat-label">{% trans "Avg. Process Time" %}</div>
</div>
</div>
</div>
<!-- Channel Breakdown -->
<div class="row mb-4">
<div class="col-md-4">
<div class="stats-card">
<h6>{% trans "By Channel" %}</h6>
<div class="mt-3">
<span class="channel-badge channel-email me-2">
📧 {% trans "Email" %}: {{ stats.channels.email }}
</span>
<span class="channel-badge channel-sms me-2">
📱 {% trans "SMS" %}: {{ stats.channels.sms }}
</span>
<span class="channel-badge channel-his_event">
🏥 {% trans "HIS Events" %}: {{ stats.channels.his_event }}
</span>
</div>
</div>
</div>
<div class="col-md-4">
<div class="stats-card">
<h6>{% trans "By Status" %}</h6>
<div class="mt-3">
{% for stat in status_stats %}
<span class="status-badge status-{{ stat.status }} me-2">
{{ stat.status|title }}: {{ stat.count }}
</span>
{% endfor %}
</div>
</div>
</div>
<div class="col-md-4">
<div class="stats-card">
<h6>{% trans "By Hospital" %}</h6>
<div class="mt-3">
{% for stat in hospital_stats|slice:":3" %}
<span class="badge badge-secondary me-2">
{{ stat.hospital_code }}: {{ stat.count }}
</span>
{% endfor %}
</div>
</div>
</div>
</div>
<!-- Filters -->
<div class="filter-section">
<form method="get" class="row g-3">
<div class="col-md-2">
<label class="form-label">{% trans "Channel" %}</label>
<select name="channel" class="form-select">
<option value="">{% trans "All" %}</option>
<option value="email" {% if filters.channel == 'email' %}selected{% endif %}>{% trans "Email" %}</option>
<option value="sms" {% if filters.channel == 'sms' %}selected{% endif %}>{% trans "SMS" %}</option>
<option value="his_event" {% if filters.channel == 'his_event' %}selected{% endif %}>{% trans "HIS Event" %}</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label">{% trans "Status" %}</label>
<select name="status" class="form-select">
<option value="">{% trans "All" %}</option>
<option value="success" {% if filters.status == 'success' %}selected{% endif %}>{% trans "Success" %}</option>
<option value="sent" {% if filters.status == 'sent' %}selected{% endif %}>{% trans "Sent" %}</option>
<option value="failed" {% if filters.status == 'failed' %}selected{% endif %}>{% trans "Failed" %}</option>
<option value="partial" {% if filters.status == 'partial' %}selected{% endif %}>{% trans "Partial" %}</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label">{% trans "Visit Type" %}</label>
<select name="visit_type" class="form-select">
<option value="">{% trans "All" %}</option>
<option value="opd" {% if filters.visit_type == 'opd' %}selected{% endif %}>OPD</option>
<option value="inpatient" {% if filters.visit_type == 'inpatient' %}selected{% endif %}>Inpatient</option>
<option value="ems" {% if filters.visit_type == 'ems' %}selected{% endif %}>EMS</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label">{% trans "Date From" %}</label>
<input type="date" name="date_from" class="form-control" value="{{ filters.date_from }}">
</div>
<div class="col-md-2">
<label class="form-label">{% trans "Date To" %}</label>
<input type="date" name="date_to" class="form-control" value="{{ filters.date_to }}">
</div>
<div class="col-md-3">
<label class="form-label">{% trans "Search" %}</label>
<input type="text" name="search" class="form-control" placeholder="ID, MRN, recipient..." value="{{ filters.search }}">
</div>
<div class="col-md-1 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-search"></i>
</button>
</div>
</form>
</div>
<!-- Logs Table -->
<div class="card">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>{% trans "ID" %}</th>
<th>{% trans "Timestamp" %}</th>
<th>{% trans "Channel" %}</th>
<th>{% trans "Status" %}</th>
<th>{% trans "Summary" %}</th>
<th>{% trans "Details" %}</th>
<th>{% trans "Process Time" %}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for log in logs %}
<tr>
<td><strong>{{ log.request_id }}</strong></td>
<td>{{ log.timestamp|date:"Y-m-d H:i:s" }}</td>
<td>
<span class="channel-badge channel-{{ log.channel }}">
{% if log.channel == 'email' %}📧 {% trans "Email" %}
{% elif log.channel == 'sms' %}📱 {% trans "SMS" %}
{% else %}🏥 {% trans "HIS Event" %}{% endif %}
</span>
</td>
<td>
<span class="status-badge status-{{ log.status }}">
{{ log.get_status_display_with_icon }}
</span>
</td>
<td>
<strong>{{ log.get_summary }}</strong>
{% if log.patient_id %}
<br><small class="text-muted">MRN: {{ log.patient_id }}</small>
{% endif %}
{% if log.journey_id %}
<br><small class="text-muted">Journey: {{ log.journey_id }}</small>
{% endif %}
{% if log.survey_id %}
<br><small class="text-muted">Survey: {{ log.survey_id }}</small>
{% endif %}
</td>
<td>
{% if log.message_preview %}
<div class="json-preview">{{ log.message_preview|truncatechars:100 }}</div>
{% elif log.subject %}
<div><strong>{{ log.subject|truncatechars:50 }}</strong></div>
{% elif log.event_type %}
<div><strong>{{ log.event_type }}</strong></div>
{% endif %}
</td>
<td>
{% if log.processing_time_ms %}
{{ log.processing_time_ms }}ms
{% else %}
-
{% endif %}
</td>
<td>
<a href="{% url 'simulator:log_detail' log.request_id %}" class="btn btn-sm btn-info">
<i class="fas fa-eye"></i>
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="8" class="text-center py-4">
<i class="fas fa-inbox fa-3x text-muted mb-3"></i>
<p class="text-muted">{% trans "No HIS logs found." %}</p>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Pagination -->
{% if page_obj.has_other_pages %}
<nav>
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1{% for key, value in filters.items %}&{{ key }}={{ value }}{% endfor %}">
<i class="fas fa-angle-double-left"></i>
</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% for key, value in filters.items %}&{{ key }}={{ value }}{% endfor %}">
<i class="fas fa-angle-left"></i>
</a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<li class="page-item">
<a class="page-link" href="?page={{ num }}{% for key, value in filters.items %}&{{ key }}={{ value }}{% endfor %}">{{ num }}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% for key, value in filters.items %}&{{ key }}={{ value }}{% endfor %}">
<i class="fas fa-angle-right"></i>
</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% for key, value in filters.items %}&{{ key }}={{ value }}{% endfor %}">
<i class="fas fa-angle-double-right"></i>
</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
</div>
{% endblock %}