2025-08-12 13:33:25 +03:00

792 lines
39 KiB
HTML

{% extends 'base.html' %}
{% load static %}
{% block title %}{% if dashboard %}Edit Dashboard{% else %}Create Dashboard{% endif %} - Hospital Management{% 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>{% if dashboard %}Edit Dashboard{% else %}Create New Dashboard{% endif %}</h4>
<h6>{% if dashboard %}Update dashboard configuration and settings{% else %}Set up a new analytics dashboard{% endif %}</h6>
</div>
<div class="page-btn">
<a href="{% url 'analytics:dashboard_list' %}" class="btn btn-secondary">
<i class="fas fa-arrow-left me-1"></i>Back to Dashboards
</a>
</div>
</div>
</div>
</div>
<!-- Dashboard Form -->
<form method="post" id="dashboardForm">
{% csrf_token %}
<div class="row">
<!-- Basic Information -->
<div class="col-lg-8">
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-info-circle me-2"></i>Basic Information
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="name" class="form-label">Dashboard Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="name" name="name"
value="{{ dashboard.name|default:'' }}"
placeholder="Enter dashboard name" required>
<div class="form-text">Choose a descriptive name for your dashboard</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="dashboard_type" class="form-label">Dashboard Type <span class="text-danger">*</span></label>
<select class="form-select" id="dashboard_type" name="dashboard_type" required>
<option value="">Select dashboard type</option>
<option value="EXECUTIVE" {% if dashboard.dashboard_type == 'EXECUTIVE' %}selected{% endif %}>Executive Dashboard</option>
<option value="CLINICAL" {% if dashboard.dashboard_type == 'CLINICAL' %}selected{% endif %}>Clinical Dashboard</option>
<option value="OPERATIONAL" {% if dashboard.dashboard_type == 'OPERATIONAL' %}selected{% endif %}>Operational Dashboard</option>
<option value="FINANCIAL" {% if dashboard.dashboard_type == 'FINANCIAL' %}selected{% endif %}>Financial Dashboard</option>
<option value="QUALITY" {% if dashboard.dashboard_type == 'QUALITY' %}selected{% endif %}>Quality Dashboard</option>
<option value="PATIENT" {% if dashboard.dashboard_type == 'PATIENT' %}selected{% endif %}>Patient Dashboard</option>
<option value="PROVIDER" {% if dashboard.dashboard_type == 'PROVIDER' %}selected{% endif %}>Provider Dashboard</option>
<option value="DEPARTMENT" {% if dashboard.dashboard_type == 'DEPARTMENT' %}selected{% endif %}>Department Dashboard</option>
<option value="CUSTOM" {% if dashboard.dashboard_type == 'CUSTOM' %}selected{% endif %}>Custom Dashboard</option>
</select>
</div>
</div>
</div>
<div class="form-group">
<label for="description" class="form-label">Description</label>
<textarea class="form-control" id="description" name="description" rows="3"
placeholder="Describe the purpose and content of this dashboard">{{ dashboard.description|default:'' }}</textarea>
<div class="form-text">Provide a brief description of what this dashboard displays</div>
</div>
</div>
</div>
<!-- Layout Configuration -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-th-large me-2"></i>Layout Configuration
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="refresh_interval" class="form-label">Refresh Interval (seconds)</label>
<select class="form-select" id="refresh_interval" name="refresh_interval">
<option value="60" {% if dashboard.refresh_interval == 60 %}selected{% endif %}>1 minute</option>
<option value="300" {% if dashboard.refresh_interval == 300 or not dashboard %}selected{% endif %}>5 minutes</option>
<option value="600" {% if dashboard.refresh_interval == 600 %}selected{% endif %}>10 minutes</option>
<option value="900" {% if dashboard.refresh_interval == 900 %}selected{% endif %}>15 minutes</option>
<option value="1800" {% if dashboard.refresh_interval == 1800 %}selected{% endif %}>30 minutes</option>
<option value="3600" {% if dashboard.refresh_interval == 3600 %}selected{% endif %}>1 hour</option>
</select>
<div class="form-text">How often should the dashboard data refresh automatically</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="grid_columns" class="form-label">Grid Columns</label>
<select class="form-select" id="grid_columns" name="grid_columns">
<option value="12" selected>12 columns (default)</option>
<option value="8">8 columns</option>
<option value="6">6 columns</option>
<option value="4">4 columns</option>
</select>
<div class="form-text">Number of columns in the dashboard grid</div>
</div>
</div>
</div>
<div class="form-group">
<label class="form-label">Layout Options</label>
<div class="layout-options">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="auto_arrange" name="auto_arrange"
{% if dashboard.layout_config.auto_arrange %}checked{% endif %}>
<label class="form-check-label" for="auto_arrange">
Auto-arrange widgets
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="responsive_layout" name="responsive_layout"
{% if dashboard.layout_config.responsive_layout or not dashboard %}checked{% endif %}>
<label class="form-check-label" for="responsive_layout">
Responsive layout (mobile-friendly)
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="compact_mode" name="compact_mode"
{% if dashboard.layout_config.compact_mode %}checked{% endif %}>
<label class="form-check-label" for="compact_mode">
Compact mode (smaller widgets)
</label>
</div>
</div>
</div>
<!-- Theme Selection -->
<div class="form-group">
<label class="form-label">Dashboard Theme</label>
<div class="theme-selection">
<div class="row">
<div class="col-md-4">
<div class="theme-option" data-theme="light">
<div class="theme-preview light-theme">
<div class="theme-header"></div>
<div class="theme-content">
<div class="theme-widget"></div>
<div class="theme-widget"></div>
</div>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="theme" id="theme_light" value="light"
{% if dashboard.layout_config.theme == 'light' or not dashboard %}checked{% endif %}>
<label class="form-check-label" for="theme_light">Light Theme</label>
</div>
</div>
</div>
<div class="col-md-4">
<div class="theme-option" data-theme="dark">
<div class="theme-preview dark-theme">
<div class="theme-header"></div>
<div class="theme-content">
<div class="theme-widget"></div>
<div class="theme-widget"></div>
</div>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="theme" id="theme_dark" value="dark"
{% if dashboard.layout_config.theme == 'dark' %}checked{% endif %}>
<label class="form-check-label" for="theme_dark">Dark Theme</label>
</div>
</div>
</div>
<div class="col-md-4">
<div class="theme-option" data-theme="auto">
<div class="theme-preview auto-theme">
<div class="theme-header"></div>
<div class="theme-content">
<div class="theme-widget"></div>
<div class="theme-widget"></div>
</div>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="theme" id="theme_auto" value="auto"
{% if dashboard.layout_config.theme == 'auto' %}checked{% endif %}>
<label class="form-check-label" for="theme_auto">Auto (System)</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Data Sources -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-database me-2"></i>Data Sources
</h5>
</div>
<div class="card-body">
<div class="form-group">
<label class="form-label">Available Data Sources</label>
<div class="data-sources-list">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="ds_patient_data" name="data_sources" value="patient_data" checked>
<label class="form-check-label" for="ds_patient_data">
<div class="data-source-item">
<div class="ds-icon">
<i class="fas fa-users text-primary"></i>
</div>
<div class="ds-info">
<h6>Patient Data</h6>
<small class="text-muted">Demographics, visits, outcomes</small>
</div>
<div class="ds-status">
<span class="badge bg-success">Active</span>
</div>
</div>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="ds_financial_data" name="data_sources" value="financial_data" checked>
<label class="form-check-label" for="ds_financial_data">
<div class="data-source-item">
<div class="ds-icon">
<i class="fas fa-dollar-sign text-success"></i>
</div>
<div class="ds-info">
<h6>Financial Data</h6>
<small class="text-muted">Revenue, billing, costs</small>
</div>
<div class="ds-status">
<span class="badge bg-success">Active</span>
</div>
</div>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="ds_clinical_data" name="data_sources" value="clinical_data">
<label class="form-check-label" for="ds_clinical_data">
<div class="data-source-item">
<div class="ds-icon">
<i class="fas fa-heartbeat text-danger"></i>
</div>
<div class="ds-info">
<h6>Clinical Data</h6>
<small class="text-muted">Lab results, procedures, medications</small>
</div>
<div class="ds-status">
<span class="badge bg-success">Active</span>
</div>
</div>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="ds_operational_data" name="data_sources" value="operational_data">
<label class="form-check-label" for="ds_operational_data">
<div class="data-source-item">
<div class="ds-icon">
<i class="fas fa-cogs text-secondary"></i>
</div>
<div class="ds-info">
<h6>Operational Data</h6>
<small class="text-muted">Staffing, capacity, workflows</small>
</div>
<div class="ds-status">
<span class="badge bg-warning">Limited</span>
</div>
</div>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="ds_quality_data" name="data_sources" value="quality_data">
<label class="form-check-label" for="ds_quality_data">
<div class="data-source-item">
<div class="ds-icon">
<i class="fas fa-star text-warning"></i>
</div>
<div class="ds-info">
<h6>Quality Data</h6>
<small class="text-muted">Metrics, incidents, compliance</small>
</div>
<div class="ds-status">
<span class="badge bg-success">Active</span>
</div>
</div>
</label>
</div>
</div>
</div>
<div class="alert alert-info">
<i class="fas fa-info-circle me-2"></i>
<strong>Note:</strong> Selected data sources will be available for widgets in this dashboard. You can modify this selection later.
</div>
</div>
</div>
</div>
<!-- Sidebar Settings -->
<div class="col-lg-4">
<!-- Access Control -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-lock me-2"></i>Access Control
</h5>
</div>
<div class="card-body">
<div class="form-group">
<label class="form-label">Visibility</label>
<div class="form-check">
<input class="form-check-input" type="radio" name="is_public" id="visibility_private" value="false"
{% if not dashboard.is_public or not dashboard %}checked{% endif %}>
<label class="form-check-label" for="visibility_private">
<i class="fas fa-lock me-2"></i>Private
<small class="d-block text-muted">Only you can access this dashboard</small>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="is_public" id="visibility_shared" value="shared"
{% if dashboard.is_public %}checked{% endif %}>
<label class="form-check-label" for="visibility_shared">
<i class="fas fa-users me-2"></i>Shared
<small class="d-block text-muted">Share with specific users or roles</small>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="is_public" id="visibility_public" value="true">
<label class="form-check-label" for="visibility_public">
<i class="fas fa-globe me-2"></i>Public
<small class="d-block text-muted">All users can access this dashboard</small>
</label>
</div>
</div>
<div class="form-group" id="sharedUsersGroup" style="display: none;">
<label for="allowed_users" class="form-label">Shared Users</label>
<select class="form-select" id="allowed_users" name="allowed_users" multiple>
<option value="1">Dr. Sarah Johnson</option>
<option value="2">Dr. Michael Chen</option>
<option value="3">Nurse Manager Lisa Davis</option>
<option value="4">Admin John Smith</option>
<option value="5">Dr. Emily Rodriguez</option>
</select>
<div class="form-text">Select users who can access this dashboard</div>
</div>
<div class="form-group" id="sharedRolesGroup" style="display: none;">
<label for="allowed_roles" class="form-label">Shared Roles</label>
<div class="role-checkboxes">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="role_admin" name="allowed_roles" value="admin">
<label class="form-check-label" for="role_admin">Administrators</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="role_doctor" name="allowed_roles" value="doctor">
<label class="form-check-label" for="role_doctor">Doctors</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="role_nurse" name="allowed_roles" value="nurse">
<label class="form-check-label" for="role_nurse">Nurses</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="role_manager" name="allowed_roles" value="manager">
<label class="form-check-label" for="role_manager">Managers</label>
</div>
</div>
</div>
</div>
</div>
<!-- Dashboard Status -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-toggle-on me-2"></i>Dashboard Status
</h5>
</div>
<div class="card-body">
<div class="form-group">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="is_active" name="is_active"
{% if dashboard.is_active or not dashboard %}checked{% endif %}>
<label class="form-check-label" for="is_active">
Active Dashboard
</label>
</div>
<div class="form-text">Inactive dashboards are hidden from users</div>
</div>
<div class="form-group">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="is_default" name="is_default"
{% if dashboard.is_default %}checked{% endif %}>
<label class="form-check-label" for="is_default">
Default Dashboard
</label>
</div>
<div class="form-text">Users will see this dashboard by default</div>
</div>
</div>
</div>
<!-- Preview -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-eye me-2"></i>Preview
</h5>
</div>
<div class="card-body">
<div class="dashboard-preview">
<div class="preview-header">
<h6 id="previewTitle">Dashboard Name</h6>
<span class="badge bg-primary" id="previewType">Executive</span>
</div>
<div class="preview-grid">
<div class="preview-widget"></div>
<div class="preview-widget"></div>
<div class="preview-widget"></div>
<div class="preview-widget"></div>
</div>
<div class="preview-footer">
<small class="text-muted">
<i class="fas fa-clock me-1"></i>
<span id="previewRefresh">5 min refresh</span>
</small>
</div>
</div>
</div>
</div>
<!-- Form Actions -->
<div class="card">
<div class="card-body">
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">
<i class="fas fa-save me-1"></i>
{% if dashboard %}Update Dashboard{% else %}Create Dashboard{% endif %}
</button>
<button type="button" class="btn btn-outline-secondary" onclick="previewDashboard()">
<i class="fas fa-eye me-1"></i>Preview Dashboard
</button>
<a href="{% url 'analytics:dashboard_list' %}" class="btn btn-outline-danger">
<i class="fas fa-times me-1"></i>Cancel
</a>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize form
initializeForm();
// Update preview when form changes
const formInputs = document.querySelectorAll('#dashboardForm input, #dashboardForm select, #dashboardForm textarea');
formInputs.forEach(input => {
input.addEventListener('change', updatePreview);
input.addEventListener('input', updatePreview);
});
// Handle visibility changes
const visibilityRadios = document.querySelectorAll('input[name="is_public"]');
visibilityRadios.forEach(radio => {
radio.addEventListener('change', handleVisibilityChange);
});
// Initial preview update
updatePreview();
});
function initializeForm() {
// Initialize select2 for multi-select
if (typeof $ !== 'undefined' && $.fn.select2) {
$('#allowed_users').select2({
placeholder: 'Select users...',
allowClear: true
});
}
// Handle visibility on load
handleVisibilityChange();
}
function updatePreview() {
const name = document.getElementById('name').value || 'Dashboard Name';
const type = document.getElementById('dashboard_type').value || 'EXECUTIVE';
const refreshInterval = document.getElementById('refresh_interval').value || '300';
// Update preview title
document.getElementById('previewTitle').textContent = name;
// Update preview type
const typeDisplay = document.querySelector(`option[value="${type}"]`)?.textContent || 'Executive';
document.getElementById('previewType').textContent = typeDisplay.replace(' Dashboard', '');
// Update preview refresh
const refreshMinutes = Math.floor(refreshInterval / 60);
document.getElementById('previewRefresh').textContent = `${refreshMinutes} min refresh`;
// Update type badge color
const typeBadge = document.getElementById('previewType');
typeBadge.className = 'badge ' + getTypeColor(type);
}
function getTypeColor(type) {
const colors = {
'EXECUTIVE': 'bg-primary',
'CLINICAL': 'bg-success',
'OPERATIONAL': 'bg-secondary',
'FINANCIAL': 'bg-warning',
'QUALITY': 'bg-info',
'PATIENT': 'bg-danger',
'PROVIDER': 'bg-dark',
'DEPARTMENT': 'bg-light text-dark',
'CUSTOM': 'bg-purple'
};
return colors[type] || 'bg-primary';
}
function handleVisibilityChange() {
const selectedVisibility = document.querySelector('input[name="is_public"]:checked')?.value;
const sharedUsersGroup = document.getElementById('sharedUsersGroup');
const sharedRolesGroup = document.getElementById('sharedRolesGroup');
if (selectedVisibility === 'shared') {
sharedUsersGroup.style.display = 'block';
sharedRolesGroup.style.display = 'block';
} else {
sharedUsersGroup.style.display = 'none';
sharedRolesGroup.style.display = 'none';
}
}
function previewDashboard() {
// Collect form data
const formData = new FormData(document.getElementById('dashboardForm'));
const dashboardData = Object.fromEntries(formData.entries());
// Open preview in new window/modal
alert('Opening dashboard preview...\n\nDashboard: ' + dashboardData.name + '\nType: ' + dashboardData.dashboard_type);
}
// Form validation
document.getElementById('dashboardForm').addEventListener('submit', function(e) {
const name = document.getElementById('name').value.trim();
const type = document.getElementById('dashboard_type').value;
if (!name) {
e.preventDefault();
alert('Please enter a dashboard name');
document.getElementById('name').focus();
return;
}
if (!type) {
e.preventDefault();
alert('Please select a dashboard type');
document.getElementById('dashboard_type').focus();
return;
}
// Show loading state
const submitBtn = document.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Saving...';
submitBtn.disabled = true;
// Re-enable after a delay (in real app, this would be handled by form submission)
setTimeout(() => {
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
}, 2000);
});
</script>
<style>
.layout-options .form-check {
margin-bottom: 10px;
}
.theme-selection {
margin-top: 10px;
}
.theme-option {
text-align: center;
margin-bottom: 15px;
}
.theme-preview {
width: 100%;
height: 80px;
border-radius: 8px;
margin-bottom: 10px;
position: relative;
overflow: hidden;
border: 2px solid transparent;
cursor: pointer;
transition: all 0.3s ease;
}
.theme-preview:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.theme-option input[type="radio"]:checked + label .theme-preview {
border-color: #007bff;
}
.light-theme {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
}
.dark-theme {
background: linear-gradient(135deg, #343a40 0%, #212529 100%);
}
.auto-theme {
background: linear-gradient(135deg, #f8f9fa 0%, #343a40 50%, #212529 100%);
}
.theme-header {
height: 15px;
background: rgba(0,0,0,0.1);
margin-bottom: 5px;
}
.theme-content {
display: flex;
gap: 5px;
padding: 0 10px;
}
.theme-widget {
flex: 1;
height: 40px;
background: rgba(0,0,0,0.05);
border-radius: 4px;
}
.dark-theme .theme-header,
.dark-theme .theme-widget {
background: rgba(255,255,255,0.1);
}
.data-sources-list .form-check {
margin-bottom: 15px;
}
.data-source-item {
display: flex;
align-items: center;
padding: 15px;
border: 1px solid #e9ecef;
border-radius: 8px;
background: #f8f9fa;
transition: all 0.3s ease;
}
.data-source-item:hover {
background: #e9ecef;
}
.form-check-input:checked + .form-check-label .data-source-item {
background: #e7f3ff;
border-color: #007bff;
}
.ds-icon {
width: 40px;
height: 40px;
border-radius: 50%;
background: white;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
font-size: 1.2rem;
}
.ds-info {
flex: 1;
}
.ds-info h6 {
margin: 0;
font-weight: 600;
color: #2c3e50;
}
.ds-status {
margin-left: 15px;
}
.role-checkboxes .form-check {
margin-bottom: 8px;
}
.dashboard-preview {
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 15px;
background: #f8f9fa;
}
.preview-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #dee2e6;
}
.preview-header h6 {
margin: 0;
font-weight: 600;
color: #2c3e50;
}
.preview-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
margin-bottom: 15px;
}
.preview-widget {
height: 30px;
background: white;
border-radius: 4px;
border: 1px solid #dee2e6;
}
.preview-footer {
text-align: center;
padding-top: 10px;
border-top: 1px solid #dee2e6;
}
@media (max-width: 768px) {
.theme-selection .row {
flex-direction: column;
}
.theme-option {
margin-bottom: 20px;
}
.data-source-item {
flex-direction: column;
text-align: center;
}
.ds-icon {
margin-right: 0;
margin-bottom: 10px;
}
.ds-status {
margin-left: 0;
margin-top: 10px;
}
.preview-grid {
grid-template-columns: 1fr;
}
}
</style>
{% endblock %}