hospital-management/templates/radiology/report_generation.html
2025-08-12 13:33:25 +03:00

724 lines
34 KiB
HTML

{% extends 'base.html' %}
{% load static %}
{% block title %}Report Generation - Radiology{% endblock %}
{% block content %}
<div class="content">
<div class="container-fluid">
<!-- Page Header -->
<div class="row">
<div class="col-12">
<div class="page-header">
<div class="page-title">
<h4>Radiology Report Generation</h4>
<h6>Create, edit, and manage radiology reports with AI assistance</h6>
</div>
<div class="page-btn">
<div class="btn-group">
<button type="button" class="btn btn-primary" onclick="createNewReport()">
<i class="fa fa-plus"></i> New Report
</button>
<button type="button" class="btn btn-info" onclick="loadTemplates()">
<i class="fa fa-clipboard-list"></i> Templates
</button>
<button type="button" class="btn btn-success" onclick="aiAssist()">
<i class="fa fa-robot"></i> AI Assist
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Study Information -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="card-title">Study Information</h5>
<div class="card-tools">
<button type="button" class="btn btn-sm btn-outline-primary" onclick="viewImages()">
<i class="fa fa-images"></i> View Images
</button>
<button type="button" class="btn btn-sm btn-outline-info" onclick="viewPriorStudies()">
<i class="fa fa-history"></i> Prior Studies
</button>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-3">
<h6>Patient Information</h6>
<p><strong>Name:</strong> {{ study.patient_name|default:"John Smith" }}</p>
<p><strong>MRN:</strong> {{ study.patient_mrn|default:"123456" }}</p>
<p><strong>DOB:</strong> {{ study.patient_dob|default:"1980-05-15"|date:"M d, Y" }}</p>
<p><strong>Age:</strong> {{ study.patient_age|default:"43" }} years</p>
<p><strong>Sex:</strong> {{ study.patient_sex|default:"Male" }}</p>
</div>
<div class="col-md-3">
<h6>Study Details</h6>
<p><strong>Study Date:</strong> {{ study.study_date|default:"Jan 15, 2024"|date:"M d, Y" }}</p>
<p><strong>Study Time:</strong> {{ study.study_time|default:"14:30" }}</p>
<p><strong>Modality:</strong> {{ study.modality|default:"CT" }}</p>
<p><strong>Body Part:</strong> {{ study.body_part|default:"Chest" }}</p>
<p><strong>Protocol:</strong> {{ study.protocol|default:"Chest CT with Contrast" }}</p>
</div>
<div class="col-md-3">
<h6>Order Information</h6>
<p><strong>Accession #:</strong> {{ study.accession_number|default:"ACC123456" }}</p>
<p><strong>Order ID:</strong> {{ study.order_id|default:"RAD-2024-001" }}</p>
<p><strong>Referring Physician:</strong> {{ study.referring_physician|default:"Dr. Johnson" }}</p>
<p><strong>Priority:</strong> <span class="badge bg-warning">{{ study.priority|default:"Urgent" }}</span></p>
<p><strong>Clinical Indication:</strong> {{ study.clinical_indication|default:"Chest pain, rule out PE" }}</p>
</div>
<div class="col-md-3">
<h6>Report Status</h6>
<p><strong>Status:</strong> <span class="badge bg-warning">{{ report.status|default:"In Progress" }}</span></p>
<p><strong>Radiologist:</strong> {{ report.radiologist|default:"Dr. Smith" }}</p>
<p><strong>Started:</strong> {{ report.started_at|default:"Jan 15, 2024 15:00" }}</p>
<p><strong>Last Modified:</strong> {{ report.modified_at|default:"Jan 15, 2024 15:30" }}</p>
<p><strong>Report ID:</strong> {{ report.report_id|default:"RPT-2024-001" }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Report Editor -->
<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h5 class="card-title">Report Editor</h5>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-sm btn-outline-primary" onclick="insertTemplate('technique')">
<i class="fa fa-cog"></i> Technique
</button>
<button type="button" class="btn btn-sm btn-outline-primary" onclick="insertTemplate('findings')">
<i class="fa fa-search"></i> Findings
</button>
<button type="button" class="btn btn-sm btn-outline-primary" onclick="insertTemplate('impression')">
<i class="fa fa-lightbulb"></i> Impression
</button>
<button type="button" class="btn btn-sm btn-outline-success" onclick="spellCheck()">
<i class="fa fa-spell-check"></i> Spell Check
</button>
</div>
</div>
</div>
<div class="card-body">
<form id="reportForm">
<div class="mb-3">
<label class="form-label"><strong>TECHNIQUE:</strong></label>
<textarea name="technique" class="form-control" rows="3" placeholder="Describe the imaging technique used...">{{ report.technique|default:"Axial CT images of the chest were obtained following the administration of intravenous contrast material." }}</textarea>
</div>
<div class="mb-3">
<label class="form-label"><strong>COMPARISON:</strong></label>
<textarea name="comparison" class="form-control" rows="2" placeholder="Compare with prior studies if available...">{{ report.comparison|default:"No prior chest CT available for comparison." }}</textarea>
</div>
<div class="mb-3">
<label class="form-label"><strong>FINDINGS:</strong></label>
<textarea name="findings" class="form-control" rows="8" placeholder="Describe detailed findings...">{{ report.findings|default:"LUNGS: The lungs are clear bilaterally without evidence of consolidation, pleural effusion, or pneumothorax. No pulmonary nodules or masses are identified.\n\nHEART: The heart is normal in size and configuration. No pericardial effusion.\n\nMEDIASTINUM: The mediastinal structures appear normal. No lymphadenopathy.\n\nBONES: No acute osseous abnormalities." }}</textarea>
</div>
<div class="mb-3">
<label class="form-label"><strong>IMPRESSION:</strong></label>
<textarea name="impression" class="form-control" rows="4" placeholder="Provide clinical impression and recommendations...">{{ report.impression|default:"1. Normal chest CT.\n2. No evidence of pulmonary embolism.\n3. No acute cardiopulmonary abnormalities." }}</textarea>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Report Status</label>
<select name="report_status" class="form-select">
<option value="draft">Draft</option>
<option value="preliminary" selected>Preliminary</option>
<option value="final">Final</option>
<option value="amended">Amended</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Urgency</label>
<select name="urgency" class="form-select">
<option value="routine">Routine</option>
<option value="urgent" selected>Urgent</option>
<option value="stat">STAT</option>
</select>
</div>
</div>
</div>
<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="critical_result" id="criticalResult">
<label class="form-check-label" for="criticalResult">
This is a critical result requiring immediate notification
</label>
</div>
</div>
<div class="mb-3" id="criticalNotificationPanel" style="display: none;">
<label class="form-label">Critical Result Notification</label>
<div class="row">
<div class="col-md-6">
<input type="text" name="notification_recipient" class="form-control" placeholder="Physician to notify">
</div>
<div class="col-md-6">
<input type="tel" name="notification_phone" class="form-control" placeholder="Phone number">
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<!-- Tools and Templates -->
<div class="col-md-4">
<!-- AI Assistant -->
<div class="card">
<div class="card-header">
<h6 class="card-title">AI Assistant</h6>
</div>
<div class="card-body">
<div class="ai-suggestions mb-3">
<h6>Suggested Findings</h6>
<div class="suggestion-item mb-2">
<small class="text-muted">Based on image analysis:</small>
<p class="mb-1">"No acute cardiopulmonary abnormalities"</p>
<button class="btn btn-sm btn-outline-primary" onclick="insertSuggestion(1)">
<i class="fa fa-plus"></i> Insert
</button>
</div>
<div class="suggestion-item mb-2">
<small class="text-muted">Common for this study type:</small>
<p class="mb-1">"Lungs are clear bilaterally"</p>
<button class="btn btn-sm btn-outline-primary" onclick="insertSuggestion(2)">
<i class="fa fa-plus"></i> Insert
</button>
</div>
</div>
<div class="ai-actions">
<button class="btn btn-sm btn-outline-success w-100 mb-2" onclick="generateDraft()">
<i class="fa fa-magic"></i> Generate Draft Report
</button>
<button class="btn btn-sm btn-outline-info w-100 mb-2" onclick="improveLanguage()">
<i class="fa fa-language"></i> Improve Language
</button>
<button class="btn btn-sm btn-outline-warning w-100" onclick="checkConsistency()">
<i class="fa fa-check-double"></i> Check Consistency
</button>
</div>
</div>
</div>
<!-- Quick Templates -->
<div class="card mt-3">
<div class="card-header">
<h6 class="card-title">Quick Templates</h6>
</div>
<div class="card-body">
<div class="template-buttons">
<button class="btn btn-sm btn-outline-secondary w-100 mb-2" onclick="loadTemplate('normal_chest_ct')">
Normal Chest CT
</button>
<button class="btn btn-sm btn-outline-secondary w-100 mb-2" onclick="loadTemplate('pe_protocol')">
PE Protocol
</button>
<button class="btn btn-sm btn-outline-secondary w-100 mb-2" onclick="loadTemplate('trauma_chest')">
Trauma Chest
</button>
<button class="btn btn-sm btn-outline-secondary w-100 mb-2" onclick="loadTemplate('lung_nodule')">
Lung Nodule Follow-up
</button>
<button class="btn btn-sm btn-outline-secondary w-100 mb-2" onclick="loadTemplate('pneumonia')">
Pneumonia
</button>
<button class="btn btn-sm btn-outline-primary w-100" onclick="manageTemplates()">
<i class="fa fa-cog"></i> Manage Templates
</button>
</div>
</div>
</div>
<!-- Measurements -->
<div class="card mt-3">
<div class="card-header">
<h6 class="card-title">Measurements</h6>
</div>
<div class="card-body">
<div class="measurements-list">
<div class="measurement-item mb-2">
<small class="text-muted">Nodule diameter:</small>
<p class="mb-1"><strong>8.5 mm</strong></p>
<button class="btn btn-sm btn-outline-primary" onclick="insertMeasurement(1)">
<i class="fa fa-plus"></i> Insert
</button>
</div>
<div class="measurement-item mb-2">
<small class="text-muted">Cardiac width:</small>
<p class="mb-1"><strong>12.3 cm</strong></p>
<button class="btn btn-sm btn-outline-primary" onclick="insertMeasurement(2)">
<i class="fa fa-plus"></i> Insert
</button>
</div>
</div>
<button class="btn btn-sm btn-outline-info w-100" onclick="viewAllMeasurements()">
<i class="fa fa-ruler"></i> View All Measurements
</button>
</div>
</div>
<!-- Voice Recognition -->
<div class="card mt-3">
<div class="card-header">
<h6 class="card-title">Voice Dictation</h6>
</div>
<div class="card-body">
<div class="voice-controls text-center">
<button class="btn btn-outline-danger mb-2" id="voiceBtn" onclick="toggleVoiceRecognition()">
<i class="fa fa-microphone"></i> Start Dictation
</button>
<div class="voice-status">
<small class="text-muted">Click to start voice dictation</small>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Report Actions -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div class="report-actions">
<button type="button" class="btn btn-outline-secondary" onclick="saveDraft()">
<i class="fa fa-save"></i> Save Draft
</button>
<button type="button" class="btn btn-outline-info" onclick="previewReport()">
<i class="fa fa-eye"></i> Preview
</button>
<button type="button" class="btn btn-outline-warning" onclick="sendForReview()">
<i class="fa fa-user-check"></i> Send for Review
</button>
</div>
<div class="final-actions">
<button type="button" class="btn btn-success" onclick="signReport()">
<i class="fa fa-signature"></i> Sign & Finalize
</button>
<button type="button" class="btn btn-primary" onclick="sendReport()">
<i class="fa fa-paper-plane"></i> Send Report
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Report History -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="card-title">Report History & Versions</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th>Version</th>
<th>Status</th>
<th>Modified By</th>
<th>Date/Time</th>
<th>Changes</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>v1.2</strong></td>
<td><span class="badge bg-warning">Current</span></td>
<td>Dr. Smith</td>
<td>Jan 15, 2024 15:30</td>
<td>Updated impression section</td>
<td>
<button class="btn btn-sm btn-outline-primary" onclick="viewVersion('1.2')">
<i class="fa fa-eye"></i>
</button>
</td>
</tr>
<tr>
<td>v1.1</td>
<td><span class="badge bg-secondary">Previous</span></td>
<td>Dr. Smith</td>
<td>Jan 15, 2024 15:15</td>
<td>Added measurements</td>
<td>
<button class="btn btn-sm btn-outline-primary" onclick="viewVersion('1.1')">
<i class="fa fa-eye"></i>
</button>
<button class="btn btn-sm btn-outline-warning" onclick="restoreVersion('1.1')">
<i class="fa fa-undo"></i>
</button>
</td>
</tr>
<tr>
<td>v1.0</td>
<td><span class="badge bg-secondary">Previous</span></td>
<td>Dr. Smith</td>
<td>Jan 15, 2024 15:00</td>
<td>Initial draft</td>
<td>
<button class="btn btn-sm btn-outline-primary" onclick="viewVersion('1.0')">
<i class="fa fa-eye"></i>
</button>
<button class="btn btn-sm btn-outline-warning" onclick="restoreVersion('1.0')">
<i class="fa fa-undo"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
let isVoiceRecognitionActive = false;
let recognition;
document.addEventListener('DOMContentLoaded', function() {
// Initialize voice recognition if available
if ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window) {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
recognition = new SpeechRecognition();
recognition.continuous = true;
recognition.interimResults = true;
recognition.onresult = function(event) {
let finalTranscript = '';
for (let i = event.resultIndex; i < event.results.length; i++) {
if (event.results[i].isFinal) {
finalTranscript += event.results[i][0].transcript;
}
}
if (finalTranscript) {
insertTextAtCursor(finalTranscript);
}
};
}
// Critical result checkbox handler
document.getElementById('criticalResult').addEventListener('change', function() {
const panel = document.getElementById('criticalNotificationPanel');
panel.style.display = this.checked ? 'block' : 'none';
});
// Auto-save functionality
setInterval(autoSave, 30000); // Auto-save every 30 seconds
});
function createNewReport() {
if (confirm('Create a new report? Any unsaved changes will be lost.')) {
document.getElementById('reportForm').reset();
console.log('New report created');
alert('New report created. You can now start dictating or typing.');
}
}
function loadTemplates() {
console.log('Loading report templates...');
alert('Report template library would be displayed here.');
}
function aiAssist() {
console.log('Opening AI assistant...');
alert('AI assistant panel is now active. It will provide suggestions as you type.');
}
function viewImages() {
console.log('Opening image viewer...');
alert('DICOM image viewer would open here.');
}
function viewPriorStudies() {
console.log('Loading prior studies...');
alert('Prior studies comparison would be displayed here.');
}
function insertTemplate(section) {
const templates = {
'technique': 'Axial CT images of the chest were obtained following the administration of intravenous contrast material.',
'findings': 'LUNGS: The lungs are clear bilaterally without evidence of consolidation, pleural effusion, or pneumothorax.\n\nHEART: The heart is normal in size and configuration.\n\nMEDIASTINUM: The mediastinal structures appear normal.',
'impression': '1. Normal chest CT.\n2. No acute cardiopulmonary abnormalities.'
};
const template = templates[section];
if (template) {
const textarea = document.querySelector(`textarea[name="${section}"]`);
if (textarea) {
textarea.value = template;
console.log(`Inserted ${section} template`);
}
}
}
function spellCheck() {
console.log('Running spell check...');
alert('Spell check completed. No errors found.');
}
function insertSuggestion(suggestionId) {
const suggestions = {
1: 'No acute cardiopulmonary abnormalities.',
2: 'Lungs are clear bilaterally.'
};
const suggestion = suggestions[suggestionId];
if (suggestion) {
insertTextAtCursor(suggestion);
console.log(`Inserted suggestion: ${suggestion}`);
}
}
function generateDraft() {
console.log('Generating AI draft report...');
alert('AI is generating a draft report based on the images and clinical indication. This may take a few moments.');
}
function improveLanguage() {
console.log('Improving report language...');
alert('AI has reviewed and improved the language and clarity of your report.');
}
function checkConsistency() {
console.log('Checking report consistency...');
alert('Report consistency check completed. All sections are consistent.');
}
function loadTemplate(templateName) {
const templates = {
'normal_chest_ct': {
technique: 'Axial CT images of the chest were obtained following the administration of intravenous contrast material.',
findings: 'LUNGS: The lungs are clear bilaterally without evidence of consolidation, pleural effusion, or pneumothorax. No pulmonary nodules or masses are identified.\n\nHEART: The heart is normal in size and configuration. No pericardial effusion.\n\nMEDIASTINUM: The mediastinal structures appear normal. No lymphadenopathy.',
impression: '1. Normal chest CT.\n2. No acute cardiopulmonary abnormalities.'
}
};
const template = templates[templateName];
if (template) {
Object.keys(template).forEach(field => {
const textarea = document.querySelector(`textarea[name="${field}"]`);
if (textarea) {
textarea.value = template[field];
}
});
console.log(`Loaded template: ${templateName}`);
alert(`Template "${templateName}" loaded successfully.`);
}
}
function manageTemplates() {
console.log('Opening template manager...');
alert('Template management interface would open here.');
}
function insertMeasurement(measurementId) {
const measurements = {
1: 'There is a 8.5 mm nodule in the right upper lobe.',
2: 'The cardiac silhouette measures 12.3 cm in width.'
};
const measurement = measurements[measurementId];
if (measurement) {
insertTextAtCursor(measurement);
console.log(`Inserted measurement: ${measurement}`);
}
}
function viewAllMeasurements() {
console.log('Viewing all measurements...');
alert('Complete measurements list would be displayed here.');
}
function toggleVoiceRecognition() {
const voiceBtn = document.getElementById('voiceBtn');
if (!recognition) {
alert('Voice recognition is not supported in this browser.');
return;
}
if (isVoiceRecognitionActive) {
recognition.stop();
voiceBtn.innerHTML = '<i class="fa fa-microphone"></i> Start Dictation';
voiceBtn.classList.remove('btn-danger');
voiceBtn.classList.add('btn-outline-danger');
isVoiceRecognitionActive = false;
console.log('Voice recognition stopped');
} else {
recognition.start();
voiceBtn.innerHTML = '<i class="fa fa-stop"></i> Stop Dictation';
voiceBtn.classList.remove('btn-outline-danger');
voiceBtn.classList.add('btn-danger');
isVoiceRecognitionActive = true;
console.log('Voice recognition started');
}
}
function insertTextAtCursor(text) {
const activeElement = document.activeElement;
if (activeElement && activeElement.tagName === 'TEXTAREA') {
const start = activeElement.selectionStart;
const end = activeElement.selectionEnd;
const value = activeElement.value;
activeElement.value = value.substring(0, start) + text + value.substring(end);
activeElement.selectionStart = activeElement.selectionEnd = start + text.length;
activeElement.focus();
}
}
function saveDraft() {
console.log('Saving draft report...');
alert('Report draft saved successfully.');
autoSave();
}
function autoSave() {
const formData = new FormData(document.getElementById('reportForm'));
console.log('Auto-saving report...', Object.fromEntries(formData));
// In real implementation, this would save to the server
}
function previewReport() {
console.log('Generating report preview...');
alert('Report preview would be displayed in a new window.');
}
function sendForReview() {
const reviewer = prompt('Send report for review to:\n1. Senior Radiologist\n2. Department Head\n3. Attending Physician\n\nEnter number:');
if (reviewer && ['1', '2', '3'].includes(reviewer)) {
const reviewers = {
'1': 'Senior Radiologist',
'2': 'Department Head',
'3': 'Attending Physician'
};
console.log(`Sending report for review to: ${reviewers[reviewer]}`);
alert(`Report sent for review to: ${reviewers[reviewer]}`);
}
}
function signReport() {
if (confirm('Sign and finalize this report? This action cannot be undone.')) {
console.log('Signing and finalizing report...');
alert('Report has been signed and finalized. It will be sent to the referring physician.');
}
}
function sendReport() {
const method = prompt('Send report via:\n1. Electronic delivery\n2. Fax\n3. Print and mail\n4. Secure email\n\nEnter number:');
if (method && ['1', '2', '3', '4'].includes(method)) {
const methods = {
'1': 'Electronic delivery',
'2': 'Fax',
'3': 'Print and mail',
'4': 'Secure email'
};
console.log(`Sending report via: ${methods[method]}`);
alert(`Report sent via ${methods[method]} to the referring physician.`);
}
}
function viewVersion(version) {
console.log(`Viewing report version: ${version}`);
alert(`Report version ${version} would be displayed here.`);
}
function restoreVersion(version) {
if (confirm(`Restore to version ${version}? Current changes will be lost.`)) {
console.log(`Restoring to version: ${version}`);
alert(`Report restored to version ${version}.`);
}
}
</script>
<style>
.suggestion-item, .measurement-item {
border: 1px solid #dee2e6;
border-radius: 4px;
padding: 8px;
background-color: #f8f9fa;
}
.template-buttons .btn {
text-align: left;
}
.voice-controls {
padding: 1rem 0;
}
.voice-status {
margin-top: 0.5rem;
}
.report-actions .btn {
margin-right: 0.5rem;
}
.final-actions .btn {
margin-left: 0.5rem;
}
textarea {
font-family: 'Courier New', monospace;
line-height: 1.4;
}
.card-tools {
margin-left: auto;
}
@media (max-width: 768px) {
.report-actions, .final-actions {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1rem;
}
.report-actions .btn, .final-actions .btn {
margin: 0;
}
.d-flex.justify-content-between {
flex-direction: column;
}
}
</style>
{% endblock %}