Medsecure / index.html
Rolaficus's picture
please work first try
b31c8fa verified
Raw History Blame Contribute Delete
19.7 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MedSecure: EMR Access Compliance Auditor</title>
<style>
body { font-family: Arial, sans-serif; margin: 0; background-color: #f4f4f9; color: #333; }
.header { background-color: #007bff; color: white; padding: 20px; text-align: center; }
.container { max-width: 1200px; margin: 30px auto; padding: 20px; background-color: #fff; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
.screen { display: none; padding: 20px; }
h1, h2, h3 { color: #007bff; border-bottom: 2px solid #eee; padding-bottom: 10px; margin-bottom: 20px; }
.back-button { background-color: #6c757d; color: white; padding: 8px 15px; border: none; border-radius: 4px; cursor: pointer; margin-bottom: 20px; display: inline-block; }
.role-button { background-color: #28a745; color: white; padding: 15px 30px; border: none; border-radius: 8px; cursor: pointer; font-size: 1.2em; margin: 10px; transition: background-color 0.3s; }
.role-button:hover { background-color: #1e7e34; }
/* Form Styling */
label { display: block; margin-top: 15px; font-weight: bold; }
input[type="text"], select, button[type="submit"] { width: 100%; padding: 12px; margin-top: 5px; border-radius: 4px; border: 1px solid #ccc; box-sizing: border-box; }
button[type="submit"] { background-color: #007bff; color: white; cursor: pointer; margin-top: 25px; }
/* Dashboard & Log Styling */
.admin-dashboard { background-color: #ffe0e0; border: 2px solid #ff4d4d; padding: 20px; border-radius: 8px; margin-top: 20px; }
.flag-result { font-weight: bold; padding: 15px; margin-top: 15px; border-radius: 4px; display: none; font-size: 1.1em; }
.violation { background-color: #ffcccc; color: #cc0000; border: 2px solid #cc0000; display: block !important; }
.compliant { background-color: #ccffcc; color: #008000; border: 2px solid #008000; display: block !important; }
.suspicious { color: #cc0000; font-weight: bold; }
.report-item { margin-bottom: 15px; padding: 10px; border-left: 5px solid #007bff; background-color: #f9f9f9; }
.shap-list li { margin-bottom: 5px; list-style-type: disc; margin-left: 20px; }
.benign-report { background-color: #f0fff0; border: 2px solid #00aa00; }
.benign-report .suspicious { color: #008000; }
/* New styling for the Suspicious Score */
#ml-score-display {
font-size: 2em;
font-weight: bold;
color: #cc0000;
display: inline-block;
margin-top: 10px;
}
/* Log Table */
.log-table-container { max-height: 300px; overflow-y: auto; margin-top: 15px; }
.access-log-table { width: 100%; border-collapse: collapse; font-size: 0.9em; }
.access-log-table th, .access-log-table td { border: 1px solid #ddd; padding: 8px; text-align: left; }
.access-log-table th { background-color: #f2f2f2; }
.log-violation { background-color: #ffdddd; }
/* Stats */
.stats-container { display: flex; justify-content: space-between; margin-top: 20px; }
.stat-box { flex-basis: 30%; padding: 15px; border-radius: 5px; text-align: center; }
.stat-box h4 { margin: 0 0 5px 0; color: #333; }
.stat-box p { font-size: 1.8em; font-weight: bold; margin: 0; }
.stat-flag { background-color: #ff4d4d; color: white; }
.stat-total { background-color: #007bff; color: white; }
</style>
</head>
<body>
<div class="header">
<h1>MedSecure: EMR Access Compliance Auditor</h1>
<p>AI-Based Detection, Verification, and Explanation System</p>
</div>
<div class="container">
<div id="landing-page" class="screen" style="display: block;">
<h2>Select Your Role to Access the Portal</h2>
<div style="text-align: center;">
<button class="role-button" onclick="showScreen('staff-access-page', 'Doctor')">Doctor Access</button>
<button class="role-button" onclick="showScreen('staff-access-page', 'Nurse')">Nurse Access</button>
<button class="role-button" onclick="showScreen('admin-dashboard', 'Admin')">Admin Dashboard</button>
</div>
</div>
<div id="staff-access-page" class="screen">
<button class="back-button" onclick="showScreen('landing-page')">← Back to Role Selection</button>
<h2 id="staff-title">EMR Access Terminal (<span id="current-user-role"></span>)</h2>
<p>Use this screen to simulate accessing a patient's Electronic Medical Record (EMR). <br>**Patient assignment is now dynamically determined by the system.**</p>
<form id="accessForm">
<label for="patientID">Patient Record ID:</label>
<input type="text" id="patientID" value="P456" placeholder="Try P456 (Assigned) or P104 (VIP/Unassigned)">
<p><strong>Assignment Status:</strong> <span id="assignment-status" style="font-weight: normal; color: #666;">Will be determined upon access attempt.</span></p>
<label for="hasEmergency">Is Access for Emergency Reasons? (Bypasses night-time check)</label>
<select id="hasEmergency">
<option value="false">No</option>
<option value="true">Yes</option>
</select>
<button type="submit">Access Patient Record (Run CSP Verification)</button>
</form>
<div id="access-details" style="margin-top: 30px; padding: 15px; border: 1px dashed #007bff; background-color: #e6f0ff;">
<h3>Patient EMR Data / Access Result</h3>
<div id="local-csp-result" class="flag-result">Awaiting access attempt...</div>
<div id="patient-data">
<p>Access status: **ACCESS GRANTED/DENIED**</p>
<p>Details will appear here upon compliant access.</p>
</div>
</div>
</div>
<div id="admin-dashboard" class="screen">
<button class="back-button" onclick="showScreen('landing-page')">← Back to Role Selection</button>
<h2>Admin Compliance Audit Dashboard</h2>
<h3>Access Statistics</h3>
<div class="stats-container">
<div class="stat-box stat-total">
<h4>Total Access Attempts</h4>
<p id="stat-total-access">0</p>
</div>
<div class="stat-box stat-flag">
<h4>CSP Policy Flags (Violations)</h4>
<p id="stat-policy-flags">0</p>
</div>
<div class="stat-box" style="background-color: #ffc107; color: #333;">
<h4>Unassigned Patient Access</h4>
<p id="stat-unassigned-access">0</p>
</div>
</div>
<h3 style="margin-top: 30px;">Access Log History</h3>
<div class="log-table-container">
<table class="access-log-table">
<thead>
<tr>
<th>Time</th>
<th>Role</th>
<th>Patient ID</th>
<th>Assigned</th>
<th>CSP Verdict</th>
<th>Message</th>
</tr>
</thead>
<tbody id="access-log-body">
</tbody>
</table>
</div>
<div id="ml-report-panel" class="admin-dashboard">
<h3 style="color: #ff4d4d;">AI-Driven Audit Report (Suspicious Session Context)</h3>
<div class="report-item">
<strong>ML Session Classification:</strong> <span id="ml-prediction-text" class="suspicious">**Loading...**</span>
</div>
<div class="report-item">
<strong>ML Suspicious Score:</strong>
<span id="ml-score-display">0.00%</span>
<p style="font-size:0.9em; color:#666;">*This is the model's confidence probability that the session is suspicious.*</p>
</div>
<div class="report-item">
<strong>XAI (Explainable AI) - Feature Contribution Analysis:</strong>
<ul id="shap-list" class="shap-list">
<li>Awaiting ML analysis from backend.</li>
</ul>
</div>
<div class="report-item">
<strong>A* Suspicious Path Analysis:</strong>
<p id="a-star-path">Path: **Loading...** | Total Suspicion Score: <strong>0.00</strong></p>
<p style="font-size:0.9em; color:#666;">*Score of 16.50 indicates the maximum severity snooping path (e.g., path to VIP patient P104).* </p>
</div>
</div>
</div>
</div>
<script>
let currentUserRole = '';
// Static Patient Database (Used only for local display in the staff screen)
const patientDB = {
"P456": { Name: "Alice Johnson", Condition: "Cancer", Room: 328, Doctor: "Dr. Smith"},
"P104": { Name: "VIP Patient (John Doe)", Condition: "Elective Surgery", Room: 450, Doctor: "Dr. Wells"},
"P999": { Name: "Unassigned Patient", Condition: "Flu", Room: 101, Doctor: "Dr. Gray"},
};
function showScreen(screenId, role = null) {
// Hide all screens
document.querySelectorAll('.screen').forEach(screen => {
screen.style.display = 'none';
});
// Show the requested screen
document.getElementById(screenId).style.display = 'block';
if (role) {
currentUserRole = role;
const staffTitle = document.getElementById('staff-title');
if (staffTitle) {
document.getElementById('current-user-role').textContent = role;
}
}
// On Admin Dashboard load, refresh the stats and log by calling the backend
if (screenId === 'admin-dashboard') {
fetchDashboardData();
}
// Clear EMR data when navigating back to role selection or to staff page
if (screenId === 'landing-page' || screenId === 'staff-access-page') {
const localCspResultDiv = document.getElementById('local-csp-result');
localCspResultDiv.className = 'flag-result';
localCspResultDiv.innerHTML = 'Awaiting access attempt...';
document.getElementById('patient-data').innerHTML = '<p>Access status: **ACCESS GRANTED/DENIED**</p><p>Details will appear here upon compliant access.</p>';
document.getElementById('assignment-status').innerHTML = 'Will be determined upon access attempt.';
}
}
function displayPatientData(patientID, isAssigned) {
const patient = patientDB[patientID] || { Name: "Patient Data (Unknown ID)", Condition: "N/A", Room: "N/A", Doctor: "N/A" };
const statusText = isAssigned ? 'Assigned' : 'Unassigned';
const statusColor = isAssigned ? 'green' : 'red';
document.getElementById('patient-data').innerHTML = `
<h4>Patient ID: ${patientID}</h4>
<p><strong>Name:</strong> ${patient.Name}</p>
<p><strong>Condition:</strong> ${patient.Condition}</p>
<p><strong>Room:</strong> ${patient.Room}</p>
<p><strong>Primary Doctor:</strong> ${patient.Doctor}</p>
<p><strong>Assignment Status:</strong> <span style="font-weight: bold; color: ${statusColor}">${statusText}</span></p>
`;
}
async function fetchDashboardData() {
try {
// IMPORTANT: This fetches data from the running Python server
const response = await fetch('/api/admin_dashboard');
const data = await response.json();
// Update Stats
document.getElementById('stat-total-access').textContent = data.stats.total;
document.getElementById('stat-policy-flags').textContent = data.stats.violations;
document.getElementById('stat-unassigned-access').textContent = data.stats.unassigned;
// Update Access Log Table
const logBody = document.getElementById('access-log-body');
logBody.innerHTML = '';
data.logs.forEach(entry => {
const row = logBody.insertRow();
if (entry.is_violation) row.classList.add('log-violation');
row.insertCell().textContent = entry.timestamp;
row.insertCell().textContent = entry.role;
row.insertCell().textContent = entry.patientID;
row.insertCell().textContent = entry.is_assigned ? 'Yes' : 'No';
row.insertCell().textContent = entry.is_violation ? 'VIOLATION (FLAG)' : 'COMPLIANT';
row.insertCell().textContent = entry.message.split(': ').length > 1 ? entry.message.split(': ')[1] : entry.message;
});
// Update ML Report
const predictionSpan = document.getElementById('ml-prediction-text');
const scoreDisplay = document.getElementById('ml-score-display');
const mlReportPanel = document.getElementById('ml-report-panel');
// Set the Classification Text
predictionSpan.textContent = `**CLASSIFIED: ${data.ml_report.prediction}**`;
// Set the Suspicious Score
scoreDisplay.textContent = `${(data.ml_report.score*100).toFixed(2)}%`;
// Style the report panel based on prediction
if (data.ml_report.prediction === 'SUSPICIOUS') {
predictionSpan.classList.add('suspicious');
scoreDisplay.style.color = '#cc0000';
mlReportPanel.classList.remove('benign-report');
mlReportPanel.style.borderColor = '#ff4d4d';
} else {
predictionSpan.classList.remove('suspicious');
scoreDisplay.style.color = '#008000';
mlReportPanel.classList.add('benign-report');
mlReportPanel.style.borderColor = '#00aa00';
}
// Update XAI Explanation
const shapList = document.getElementById('shap-list');
shapList.innerHTML = '';
if (data.ml_report.explanation.length > 0) {
data.ml_report.explanation.forEach(line => {
const li = document.createElement('li');
li.innerHTML = line;
shapList.appendChild(li);
});
} else {
shapList.innerHTML = '<li>No significant feature contributions found, session is neutral.</li>';
}
// Update A* Search
document.getElementById('a-star-path').innerHTML = `Path: <strong>${data.a_star.path}</strong> | Total Suspicion Score: <strong>${data.a_star.score.toFixed(2)}</strong>`;
} catch (error) {
console.error("Error fetching dashboard data:", error);
document.getElementById('ml-report-panel').innerHTML = '<p style="color:red;">Error fetching AI report. Check backend server.</p>';
}
}
document.getElementById('accessForm').addEventListener('submit', async function(event) {
event.preventDefault();
const role = currentUserRole;
const patientID = document.getElementById('patientID').value || 'PXXX';
const hasEmergency = document.getElementById('hasEmergency').value === 'true';
const localCspResultDiv = document.getElementById('local-csp-result');
const patientDataDiv = document.getElementById('patient-data');
const assignmentStatusSpan = document.getElementById('assignment-status');
localCspResultDiv.className = 'flag-result';
patientDataDiv.innerHTML = '';
try {
// Send data to Flask backend for CSP check and logging
const response = await fetch('/api/log_access', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
role: role,
patientID: patientID,
hasEmergency: hasEmergency
})
});
const data = await response.json();
const isAssigned = data.isAssignedStatus; // Use the calculated status from the backend
// Update the Dynamic Assignment Status Display
assignmentStatusSpan.textContent = isAssigned ? 'YES - You are assigned to this patient.' : 'NO - Unassigned patient record.';
assignmentStatusSpan.style.color = isAssigned ? 'green' : 'red';
// Update the Local Log (Staff Screen) based on backend CSP verdict
if (data.isViolation) {
localCspResultDiv.classList.add('violation');
patientDataDiv.innerHTML = `<p style="color:red; font-weight:bold;">ACCESS DENIED: Policy Violation. Audit log initiated.</p>`;
} else {
localCspResultDiv.classList.add('compliant');
if (isAssigned) {
displayPatientData(patientID, isAssigned);
} else {
// Doctor access to unassigned patient
patientDataDiv.innerHTML = `<p style="color:orange; font-weight:bold;">ACCESS GRANTED (Logged): Viewing unassigned patient record. Check Admin Dashboard for risk assessment.</p>`;
}
}
localCspResultDiv.innerHTML = `<strong>ACCESS LOG:</strong> ${data.message}`;
} catch (error) {
console.error("Error logging access:", error);
localCspResultDiv.classList.add('violation');
localCspResultDiv.innerHTML = `<strong>ERROR:</strong> Could not reach compliance backend.`;
}
});
// Initialize view to the landing page
document.addEventListener('DOMContentLoaded', () => showScreen('landing-page'));
</script>
</body>
</html>