329 lines
13 KiB
HTML
329 lines
13 KiB
HTML
{% extends "layouts/base.html" %}
|
|
{% load i18n static %}
|
|
|
|
{% block title %}{% trans "HIS Log" %} #{{ log.request_id }} - PX360{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.channel-badge {
|
|
display: inline-block;
|
|
padding: 6px 16px;
|
|
border-radius: 12px;
|
|
font-size: 1rem;
|
|
font-weight: 500;
|
|
}
|
|
.channel-email { background: #eff6ff; color: #3b82f6; }
|
|
.channel-sms { background: #fff7ed; color: #f97316; }
|
|
.channel-his_event { background: #f0fdf4; color: #22c55e; }
|
|
.status-badge {
|
|
display: inline-block;
|
|
padding: 6px 16px;
|
|
border-radius: 12px;
|
|
font-size: 1rem;
|
|
font-weight: 500;
|
|
}
|
|
.status-success, .status-sent { background: #dcfce7; color: #16a34a; }
|
|
.status-failed { background: #fee2e2; color: #dc2626; }
|
|
.status-partial { background: #fef3c7; color: #d97706; }
|
|
.json-display {
|
|
background: #f5f5f5;
|
|
padding: 15px;
|
|
border-radius: 8px;
|
|
font-family: 'Courier New', monospace;
|
|
font-size: 0.85rem;
|
|
overflow-x: auto;
|
|
max-height: 400px;
|
|
}
|
|
.related-object {
|
|
background: #eff6ff;
|
|
border-left: 4px solid #3b82f6;
|
|
padding: 12px;
|
|
margin-bottom: 10px;
|
|
border-radius: 8px;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
<!-- Page Header -->
|
|
<div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-8 gap-4">
|
|
<div>
|
|
<h2 class="text-3xl font-bold text-gray-800 mb-2 flex items-center gap-2">
|
|
<i data-lucide="bot" class="w-8 h-8 text-navy"></i>
|
|
{% trans "HIS Log" %} #{{ log.request_id }}
|
|
</h2>
|
|
<p class="text-gray-500">{% trans "Request and response details" %}</p>
|
|
</div>
|
|
<a href="{% url 'simulator:logs_list' %}" class="bg-gray-100 text-gray-700 px-6 py-3 rounded-xl font-bold hover:bg-gray-200 transition flex items-center gap-2">
|
|
<i data-lucide="arrow-left" class="w-5 h-5"></i> {% trans "Back to Logs" %}
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Basic Information -->
|
|
<div class="bg-white rounded-2xl shadow-sm border border-gray-50 mb-6 p-6">
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Channel" %}:</strong>
|
|
<br>
|
|
<span class="channel-badge channel-{{ log.channel }} mt-2 inline-block">
|
|
{% if log.channel == 'email' %}📧 {% trans "Email" %}
|
|
{% elif log.channel == 'sms' %}📱 {% trans "SMS" %}
|
|
{% else %}🏥 {% trans "HIS Event" %}{% endif %}
|
|
</span>
|
|
</div>
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Status" %}:</strong>
|
|
<br>
|
|
<span class="status-badge status-{{ log.status }} mt-2 inline-block">
|
|
{{ log.get_status_display_with_icon }}
|
|
</span>
|
|
</div>
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Timestamp" %}:</strong>
|
|
<br>
|
|
<span class="text-gray-800 mt-2 block">{{ log.timestamp|date:"Y-m-d H:i:s" }}</span>
|
|
</div>
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Processing Time" %}:</strong>
|
|
<br>
|
|
<span class="text-gray-800 mt-2 block">
|
|
{% if log.processing_time_ms %}
|
|
{{ log.processing_time_ms }}ms
|
|
{% else %}
|
|
-
|
|
{% endif %}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{% if log.ip_address or log.user_agent %}
|
|
<hr class="my-6 border-gray-100">
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
{% if log.ip_address %}
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "IP Address" %}:</strong>
|
|
<br>
|
|
<code class="bg-gray-100 px-3 py-1 rounded-lg text-sm">{{ log.ip_address }}</code>
|
|
</div>
|
|
{% endif %}
|
|
{% if log.user_agent %}
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "User Agent" %}:</strong>
|
|
<br>
|
|
<small class="text-gray-600">{{ log.user_agent|truncatechars:100 }}</small>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Related Objects -->
|
|
{% if related_objects %}
|
|
<div class="bg-white rounded-2xl shadow-sm border border-gray-50 mb-6 p-6">
|
|
<h3 class="font-bold text-gray-800 mb-4 flex items-center gap-2">
|
|
<i data-lucide="link" class="w-5 h-5 text-navy"></i>
|
|
{% trans "Related Objects" %}
|
|
</h3>
|
|
|
|
{% if related_objects.patient %}
|
|
<div class="related-object">
|
|
<strong class="text-gray-800"><i data-lucide="user" class="w-4 h-4 inline mr-1"></i> {% trans "Patient" %}</strong>
|
|
<div class="mt-2">
|
|
<strong class="text-gray-800">{{ related_objects.patient.name }}</strong><br>
|
|
<small class="text-gray-500">MRN: {{ related_objects.patient.mrn }}</small><br>
|
|
<small class="text-gray-500">
|
|
<i data-lucide="phone" class="w-3 h-3 inline mr-1"></i> {{ related_objects.patient.phone }} |
|
|
<i data-lucide="mail" class="w-3 h-3 inline mr-1"></i> {{ related_objects.patient.email }}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if related_objects.journey %}
|
|
<div class="related-object">
|
|
<strong class="text-gray-800"><i data-lucide="route" class="w-4 h-4 inline mr-1"></i> {% trans "Journey" %}</strong>
|
|
<div class="mt-2">
|
|
<strong class="text-gray-800">{{ related_objects.journey.encounter_id }}</strong><br>
|
|
<small class="text-gray-500">
|
|
{% trans "Type" %}: {{ related_objects.journey.journey_type }} |
|
|
{% trans "Status" %}: {{ related_objects.journey.status }}
|
|
</small><br>
|
|
<small class="text-gray-500">
|
|
<i data-lucide="user" class="w-3 h-3 inline mr-1"></i> {{ related_objects.journey.patient_name }}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if related_objects.survey %}
|
|
<div class="related-object">
|
|
<strong class="text-gray-800"><i data-lucide="clipboard-list" class="w-4 h-4 inline mr-1"></i> {% trans "Survey" %}</strong>
|
|
<div class="mt-2">
|
|
<strong class="text-gray-800">ID: {{ related_objects.survey.id }}</strong><br>
|
|
<small class="text-gray-500">
|
|
{% trans "Type" %}: {{ related_objects.survey.survey_type }} |
|
|
{% trans "Status" %}: {{ related_objects.survey.status }}
|
|
</small>
|
|
{% if related_objects.survey.total_score %}
|
|
<br>
|
|
<small class="text-gray-500">
|
|
<i data-lucide="star" class="w-3 h-3 inline mr-1"></i> {% trans "Score" %}: {{ related_objects.survey.total_score }}
|
|
</small>
|
|
{% endif %}
|
|
<br>
|
|
<small class="text-gray-500">
|
|
<i data-lucide="user" class="w-3 h-3 inline mr-1"></i> {{ related_objects.survey.patient_name }}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Channel-Specific Details -->
|
|
<div class="bg-white rounded-2xl shadow-sm border border-gray-50 mb-6 p-6">
|
|
<h3 class="font-bold text-gray-800 mb-4 flex items-center gap-2">
|
|
<i data-lucide="info" class="w-5 h-5 text-navy"></i>
|
|
{% trans "Request Details" %}
|
|
</h3>
|
|
|
|
{% if log.recipient %}
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Recipient" %}:</strong>
|
|
<br>
|
|
<code class="bg-gray-100 px-3 py-1 rounded-lg text-sm">{{ log.recipient }}</code>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if log.subject %}
|
|
<div class="grid grid-cols-1 gap-4 mb-4">
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Subject" %}:</strong>
|
|
<br>
|
|
{{ log.subject }}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if log.event_type %}
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Event Type" %}:</strong>
|
|
<br>
|
|
<code class="bg-gray-100 px-3 py-1 rounded-lg text-sm">{{ log.event_type }}</code>
|
|
</div>
|
|
{% if log.visit_type %}
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Visit Type" %}:</strong>
|
|
<br>
|
|
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-bold bg-gray-100 text-gray-700">{{ log.visit_type|upper }}</span>
|
|
</div>
|
|
{% endif %}
|
|
{% if log.department %}
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Department" %}:</strong>
|
|
<br>
|
|
{{ log.department }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if log.hospital_code %}
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Hospital" %}:</strong>
|
|
<br>
|
|
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-bold bg-blue-100 text-blue-700">{{ log.hospital_code }}</span>
|
|
</div>
|
|
{% if log.patient_id %}
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Patient MRN" %}:</strong>
|
|
<br>
|
|
<code class="bg-gray-100 px-3 py-1 rounded-lg text-sm">{{ log.patient_id }}</code>
|
|
</div>
|
|
{% endif %}
|
|
{% if log.journey_id %}
|
|
<div>
|
|
<strong class="text-gray-700 text-sm uppercase">{% trans "Journey ID" %}:</strong>
|
|
<br>
|
|
<code class="bg-gray-100 px-3 py-1 rounded-lg text-sm">{{ log.journey_id }}</code>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Request Payload -->
|
|
<div class="bg-white rounded-2xl shadow-sm border border-gray-50 mb-6 p-6">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="font-bold text-gray-800 flex items-center gap-2">
|
|
<i data-lucide="file-code" class="w-5 h-5 text-navy"></i>
|
|
{% trans "Request Payload" %}
|
|
</h3>
|
|
<button class="px-4 py-2 text-gray-600 bg-gray-100 rounded-lg hover:bg-gray-200 transition text-sm font-medium" onclick="copyToClipboard('payload-content')">
|
|
<i data-lucide="copy" class="w-4 h-4 inline mr-1"></i> {% trans "Copy" %}
|
|
</button>
|
|
</div>
|
|
<div class="json-display" id="payload-content">{{ payload_formatted }}</div>
|
|
</div>
|
|
|
|
<!-- Response Data -->
|
|
{% if response_formatted %}
|
|
<div class="bg-white rounded-2xl shadow-sm border border-gray-50 mb-6 p-6">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="font-bold text-gray-800 flex items-center gap-2">
|
|
<i data-lucide="reply" class="w-5 h-5 text-navy"></i>
|
|
{% trans "Response Data" %}
|
|
</h3>
|
|
<button class="px-4 py-2 text-gray-600 bg-gray-100 rounded-lg hover:bg-gray-200 transition text-sm font-medium" onclick="copyToClipboard('response-content')">
|
|
<i data-lucide="copy" class="w-4 h-4 inline mr-1"></i> {% trans "Copy" %}
|
|
</button>
|
|
</div>
|
|
<div class="json-display" id="response-content">{{ response_formatted }}</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Error Message -->
|
|
{% if log.error_message %}
|
|
<div class="bg-white rounded-2xl shadow-sm border-l-4 border-l-red-500 border-gray-50 mb-6 p-6">
|
|
<h3 class="font-bold text-red-600 mb-3 flex items-center gap-2">
|
|
<i data-lucide="alert-triangle" class="w-5 h-5"></i>
|
|
{% trans "Error Details" %}
|
|
</h3>
|
|
<pre class="text-red-600 text-sm bg-red-50 p-4 rounded-lg overflow-auto">{{ log.error_message }}</pre>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Message Preview -->
|
|
{% if log.message_preview %}
|
|
<div class="bg-white rounded-2xl shadow-sm border border-gray-50 p-6">
|
|
<h3 class="font-bold text-gray-800 mb-4 flex items-center gap-2">
|
|
<i data-lucide="mail" class="w-5 h-5 text-navy"></i>
|
|
{% trans "Message Preview" %}
|
|
</h3>
|
|
<div class="bg-blue-50 border border-blue-100 rounded-xl p-4 text-gray-700">
|
|
{{ log.message_preview }}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
lucide.createIcons();
|
|
});
|
|
|
|
function copyToClipboard(elementId) {
|
|
const text = document.getElementById(elementId).textContent;
|
|
navigator.clipboard.writeText(text).then(function() {
|
|
alert('{% trans "Copied to clipboard!" %}');
|
|
}, function(err) {
|
|
console.error('Failed to copy: ', err);
|
|
});
|
|
}
|
|
</script>
|
|
{% endblock %} |