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

667 lines
35 KiB
HTML

{% extends 'base.html' %}
{% load static %}
{% block title %}{% if metric %}Edit Metric Definition{% else %}Create Metric Definition{% 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 metric %}Edit Metric Definition{% else %}Create New Metric Definition{% endif %}</h4>
<h6>{% if metric %}Update metric configuration{% else %}Define a new analytics metric{% endif %}</h6>
</div>
<div class="page-btn">
<a href="{% url 'analytics:metric_definition_list' %}" class="btn btn-secondary">
<i class="fas fa-arrow-left me-1"></i>Back to Metrics
</a>
</div>
</div>
</div>
</div>
<form method="post" id="metricForm">
{% csrf_token %}
<div class="row">
<!-- Main Form -->
<div class="col-lg-8">
<!-- Basic Information -->
<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-8">
<div class="form-group">
<label for="name" class="form-label">Metric Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="name" name="name"
value="{{ metric.name|default:'' }}"
placeholder="Enter metric name" required>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="status" class="form-label">Status</label>
<select class="form-select" id="status" name="status">
<option value="draft" {% if metric.status == 'draft' or not metric %}selected{% endif %}>Draft</option>
<option value="active" {% if metric.status == 'active' %}selected{% endif %}>Active</option>
<option value="inactive" {% if metric.status == 'inactive' %}selected{% endif %}>Inactive</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 what this metric measures and its purpose">{{ metric.description|default:'' }}</textarea>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label for="category" class="form-label">Category <span class="text-danger">*</span></label>
<select class="form-select" id="category" name="category" required>
<option value="">Select category</option>
<option value="clinical" {% if metric.category == 'clinical' %}selected{% endif %}>Clinical</option>
<option value="financial" {% if metric.category == 'financial' %}selected{% endif %}>Financial</option>
<option value="operational" {% if metric.category == 'operational' %}selected{% endif %}>Operational</option>
<option value="quality" {% if metric.category == 'quality' %}selected{% endif %}>Quality</option>
<option value="patient_satisfaction" {% if metric.category == 'patient_satisfaction' %}selected{% endif %}>Patient Satisfaction</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="metric_type" class="form-label">Metric Type <span class="text-danger">*</span></label>
<select class="form-select" id="metric_type" name="metric_type" required onchange="updateFormulaHelp()">
<option value="">Select type</option>
<option value="count" {% if metric.metric_type == 'count' %}selected{% endif %}>Count</option>
<option value="percentage" {% if metric.metric_type == 'percentage' %}selected{% endif %}>Percentage</option>
<option value="average" {% if metric.metric_type == 'average' %}selected{% endif %}>Average</option>
<option value="sum" {% if metric.metric_type == 'sum' %}selected{% endif %}>Sum</option>
<option value="ratio" {% if metric.metric_type == 'ratio' %}selected{% endif %}>Ratio</option>
<option value="custom" {% if metric.metric_type == 'custom' %}selected{% endif %}>Custom</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="unit" class="form-label">Unit</label>
<input type="text" class="form-control" id="unit" name="unit"
value="{{ metric.unit|default:'' }}"
placeholder="e.g., %, $, days, patients">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="data_source" class="form-label">Data Source</label>
<select class="form-select" id="data_source" name="data_source">
<option value="">Select data source</option>
{% for source in data_sources %}
<option value="{{ source.id }}" {% if metric.data_source_id == source.id %}selected{% endif %}>
{{ source.name }}
</option>
{% endfor %}
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="calculation_frequency" class="form-label">Calculation Frequency</label>
<select class="form-select" id="calculation_frequency" name="calculation_frequency">
<option value="manual" {% if metric.calculation_frequency == 'manual' %}selected{% endif %}>Manual</option>
<option value="hourly" {% if metric.calculation_frequency == 'hourly' %}selected{% endif %}>Hourly</option>
<option value="daily" {% if metric.calculation_frequency == 'daily' %}selected{% endif %}>Daily</option>
<option value="weekly" {% if metric.calculation_frequency == 'weekly' %}selected{% endif %}>Weekly</option>
<option value="monthly" {% if metric.calculation_frequency == 'monthly' %}selected{% endif %}>Monthly</option>
</select>
</div>
</div>
</div>
</div>
</div>
<!-- Formula Configuration -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-code me-2"></i>Formula Configuration
</h5>
</div>
<div class="card-body">
<div class="form-group">
<label for="formula" class="form-label">Calculation Formula</label>
<textarea class="form-control" id="formula" name="formula" rows="4"
placeholder="Enter the calculation formula">{{ metric.formula|default:'' }}</textarea>
<div class="form-text">
<div id="formulaHelp">
Use mathematical expressions and field references. Example: (field1 + field2) / field3 * 100
</div>
</div>
</div>
<div class="form-group">
<label for="sql_query" class="form-label">SQL Query (Optional)</label>
<textarea class="form-control" id="sql_query" name="sql_query" rows="6"
placeholder="SELECT ... FROM ... WHERE ...">{{ metric.sql_query|default:'' }}</textarea>
<div class="form-text">
Advanced: Custom SQL query for complex calculations. Leave empty to use formula above.
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="validate_formula" name="validate_formula" checked>
<label class="form-check-label" for="validate_formula">
Validate formula syntax
</label>
</div>
</div>
</div>
</div>
<!-- Parameters -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-sliders-h me-2"></i>Parameters
</h5>
<div class="card-tools">
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addParameter()">
<i class="fas fa-plus me-1"></i>Add Parameter
</button>
</div>
</div>
<div class="card-body">
<div id="parametersContainer">
{% if metric.parameters %}
{% for param in metric.parameters %}
<div class="parameter-row">
<div class="row">
<div class="col-md-3">
<div class="form-group">
<label class="form-label">Parameter Name</label>
<input type="text" class="form-control" name="param_name[]"
value="{{ param.name }}" placeholder="parameter_name">
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label class="form-label">Type</label>
<select class="form-select" name="param_type[]">
<option value="string" {% if param.type == 'string' %}selected{% endif %}>String</option>
<option value="number" {% if param.type == 'number' %}selected{% endif %}>Number</option>
<option value="date" {% if param.type == 'date' %}selected{% endif %}>Date</option>
<option value="boolean" {% if param.type == 'boolean' %}selected{% endif %}>Boolean</option>
</select>
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label class="form-label">Default Value</label>
<input type="text" class="form-control" name="param_default[]"
value="{{ param.default_value }}" placeholder="default">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="form-label">Description</label>
<input type="text" class="form-control" name="param_description[]"
value="{{ param.description }}" placeholder="Parameter description">
</div>
</div>
<div class="col-md-1">
<div class="form-group">
<label class="form-label">&nbsp;</label>
<button type="button" class="btn btn-outline-danger btn-sm d-block" onclick="removeParameter(this)">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% if not metric.parameters %}
<div class="text-center py-3" id="noParametersMessage">
<i class="fas fa-sliders-h fa-2x text-muted mb-2"></i>
<p class="text-muted mb-0">No parameters defined. Click "Add Parameter" to create configurable parameters for this metric.</p>
</div>
{% endif %}
</div>
</div>
<!-- Display Configuration -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-palette me-2"></i>Display Configuration
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label for="format" class="form-label">Number Format</label>
<select class="form-select" id="format" name="format">
<option value="default" {% if metric.format == 'default' %}selected{% endif %}>Default</option>
<option value="integer" {% if metric.format == 'integer' %}selected{% endif %}>Integer (1,234)</option>
<option value="decimal" {% if metric.format == 'decimal' %}selected{% endif %}>Decimal (1,234.56)</option>
<option value="percentage" {% if metric.format == 'percentage' %}selected{% endif %}>Percentage (12.34%)</option>
<option value="currency" {% if metric.format == 'currency' %}selected{% endif %}>Currency ($1,234.56)</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="decimal_places" class="form-label">Decimal Places</label>
<input type="number" class="form-control" id="decimal_places" name="decimal_places"
value="{{ metric.decimal_places|default:'2' }}" min="0" max="10">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label for="color" class="form-label">Display Color</label>
<input type="color" class="form-control form-control-color" id="color" name="color"
value="{{ metric.color|default:'#007bff' }}">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="target_value" class="form-label">Target Value (Optional)</label>
<input type="number" class="form-control" id="target_value" name="target_value"
value="{{ metric.target_value|default:'' }}" step="0.01"
placeholder="Target or goal value">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="threshold_type" class="form-label">Threshold Type</label>
<select class="form-select" id="threshold_type" name="threshold_type">
<option value="none" {% if metric.threshold_type == 'none' %}selected{% endif %}>None</option>
<option value="higher_better" {% if metric.threshold_type == 'higher_better' %}selected{% endif %}>Higher is Better</option>
<option value="lower_better" {% if metric.threshold_type == 'lower_better' %}selected{% endif %}>Lower is Better</option>
<option value="target_range" {% if metric.threshold_type == 'target_range' %}selected{% endif %}>Target Range</option>
</select>
</div>
</div>
</div>
</div>
</div>
<!-- Tags and Metadata -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-tags me-2"></i>Tags & Metadata
</h5>
</div>
<div class="card-body">
<div class="form-group">
<label for="tags" class="form-label">Tags</label>
<input type="text" class="form-control" id="tags" name="tags"
value="{{ metric.tags_string|default:'' }}"
placeholder="Enter tags separated by commas">
<div class="form-text">
Use tags to organize and categorize metrics. Separate multiple tags with commas.
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="version" class="form-label">Version</label>
<input type="text" class="form-control" id="version" name="version"
value="{{ metric.version|default:'1.0' }}"
placeholder="1.0">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="owner" class="form-label">Owner</label>
<input type="text" class="form-control" id="owner" name="owner"
value="{{ metric.owner|default:'' }}"
placeholder="Metric owner or responsible person">
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Formula Validation -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-check-circle me-2"></i>Formula Validation
</h5>
</div>
<div class="card-body">
<div class="text-center">
<button type="button" class="btn btn-outline-primary" onclick="validateFormula()">
<i class="fas fa-check me-1"></i>Validate Formula
</button>
<div id="validationResult" class="mt-3" style="display: none;">
<!-- Validation result will be shown here -->
</div>
</div>
</div>
</div>
<!-- Test Calculation -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-calculator me-2"></i>Test Calculation
</h5>
</div>
<div class="card-body">
<div class="text-center">
<button type="button" class="btn btn-outline-success" onclick="testCalculation()">
<i class="fas fa-play me-1"></i>Test Calculate
</button>
<div id="testResult" class="mt-3" style="display: none;">
<!-- Test result will be shown here -->
</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 metric %}Update Metric{% else %}Create Metric{% endif %}
</button>
{% if metric %}
<button type="button" class="btn btn-outline-secondary" onclick="calculateAfterSave()">
<i class="fas fa-calculator me-1"></i>Save & Calculate
</button>
{% endif %}
<a href="{% url 'analytics:metric_definition_list' %}" class="btn btn-outline-danger">
<i class="fas fa-times me-1"></i>Cancel
</a>
</div>
</div>
</div>
<!-- Help -->
<div class="card">
<div class="card-header">
<h5 class="card-title">
<i class="fas fa-question-circle me-2"></i>Help
</h5>
</div>
<div class="card-body">
<div class="help-content">
<h6>Metric Types:</h6>
<ul class="list-unstyled">
<li><strong>Count:</strong> Simple counting metrics</li>
<li><strong>Percentage:</strong> Ratio expressed as percentage</li>
<li><strong>Average:</strong> Mean value calculation</li>
<li><strong>Sum:</strong> Total aggregation</li>
<li><strong>Ratio:</strong> Division of two values</li>
<li><strong>Custom:</strong> Complex custom formulas</li>
</ul>
<h6 class="mt-3">Formula Examples:</h6>
<ul class="list-unstyled small">
<li><code>COUNT(*)</code> - Count records</li>
<li><code>(A / B) * 100</code> - Percentage</li>
<li><code>SUM(field)</code> - Total sum</li>
<li><code>AVG(field)</code> - Average value</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
<script>
function updateFormulaHelp() {
const metricType = document.getElementById('metric_type').value;
const helpDiv = document.getElementById('formulaHelp');
const examples = {
'count': 'Example: COUNT(*) WHERE condition',
'percentage': 'Example: (numerator / denominator) * 100',
'average': 'Example: AVG(field_name)',
'sum': 'Example: SUM(field_name)',
'ratio': 'Example: field1 / field2',
'custom': 'Example: CASE WHEN condition THEN value1 ELSE value2 END'
};
helpDiv.textContent = examples[metricType] || 'Use mathematical expressions and field references.';
}
function addParameter() {
const container = document.getElementById('parametersContainer');
const noMessage = document.getElementById('noParametersMessage');
if (noMessage) {
noMessage.style.display = 'none';
}
const parameterRow = document.createElement('div');
parameterRow.className = 'parameter-row';
parameterRow.innerHTML = `
<div class="row">
<div class="col-md-3">
<div class="form-group">
<label class="form-label">Parameter Name</label>
<input type="text" class="form-control" name="param_name[]" placeholder="parameter_name">
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label class="form-label">Type</label>
<select class="form-select" name="param_type[]">
<option value="string">String</option>
<option value="number">Number</option>
<option value="date">Date</option>
<option value="boolean">Boolean</option>
</select>
</div>
</div>
<div class="col-md-2">
<div class="form-group">
<label class="form-label">Default Value</label>
<input type="text" class="form-control" name="param_default[]" placeholder="default">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="form-label">Description</label>
<input type="text" class="form-control" name="param_description[]" placeholder="Parameter description">
</div>
</div>
<div class="col-md-1">
<div class="form-group">
<label class="form-label">&nbsp;</label>
<button type="button" class="btn btn-outline-danger btn-sm d-block" onclick="removeParameter(this)">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
</div>
`;
container.appendChild(parameterRow);
}
function removeParameter(button) {
const parameterRow = button.closest('.parameter-row');
parameterRow.remove();
const container = document.getElementById('parametersContainer');
const noMessage = document.getElementById('noParametersMessage');
if (container.children.length === 0 && noMessage) {
noMessage.style.display = 'block';
}
}
function validateFormula() {
const formula = document.getElementById('formula').value;
const resultDiv = document.getElementById('validationResult');
if (!formula.trim()) {
resultDiv.innerHTML = `
<div class="alert alert-warning">
<i class="fas fa-exclamation-triangle me-2"></i>
Please enter a formula to validate.
</div>
`;
resultDiv.style.display = 'block';
return;
}
// Simulate validation
setTimeout(() => {
resultDiv.innerHTML = `
<div class="alert alert-success">
<i class="fas fa-check-circle me-2"></i>
Formula syntax is valid!
</div>
`;
resultDiv.style.display = 'block';
}, 1000);
}
function testCalculation() {
const formula = document.getElementById('formula').value;
const resultDiv = document.getElementById('testResult');
if (!formula.trim()) {
resultDiv.innerHTML = `
<div class="alert alert-warning">
<i class="fas fa-exclamation-triangle me-2"></i>
Please enter a formula to test.
</div>
`;
resultDiv.style.display = 'block';
return;
}
// Simulate test calculation
setTimeout(() => {
resultDiv.innerHTML = `
<div class="alert alert-success">
<i class="fas fa-calculator me-2"></i>
Test result: <strong>42.5</strong>
<br><small class="text-muted">Calculation completed in 0.15s</small>
</div>
`;
resultDiv.style.display = 'block';
}, 1500);
}
function calculateAfterSave() {
document.getElementById('calculate_after_save').value = 'true';
}
// Form validation
document.getElementById('metricForm').addEventListener('submit', function(e) {
const name = document.getElementById('name').value.trim();
const category = document.getElementById('category').value;
const metricType = document.getElementById('metric_type').value;
if (!name || !category || !metricType) {
e.preventDefault();
alert('Please fill in all required fields');
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 delay (in real app, handled by form submission)
setTimeout(() => {
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
}, 2000);
});
// Initialize
document.addEventListener('DOMContentLoaded', function() {
updateFormulaHelp();
});
</script>
<style>
.parameter-row {
margin-bottom: 20px;
padding: 15px;
border: 1px solid #e9ecef;
border-radius: 8px;
background: #f8f9fa;
}
.help-content h6 {
color: #2c3e50;
font-weight: 600;
margin-bottom: 10px;
}
.help-content ul li {
margin-bottom: 5px;
font-size: 0.875rem;
}
.help-content ul li strong {
color: #2c3e50;
}
.help-content code {
background: #e9ecef;
padding: 2px 4px;
border-radius: 3px;
font-size: 0.8rem;
}
@media (max-width: 768px) {
.page-btn {
margin-top: 15px;
}
.help-content {
font-size: 0.875rem;
}
.parameter-row .row {
flex-direction: column;
}
.parameter-row .col-md-1 {
margin-top: 10px;
}
}
</style>
{% endblock %}