680 lines
27 KiB
HTML
680 lines
27 KiB
HTML
{% extends 'base.html' %}
|
||
{% load static %}
|
||
|
||
{% block title %}Widget Details - 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>{{ widget.title|default:"Revenue Trends" }}</h4>
|
||
<h6>Widget details and configuration</h6>
|
||
</div>
|
||
<div class="page-btn">
|
||
<a href="{% url 'analytics:dashboard_widget_list' dashboard.pk|default:1 %}" class="btn btn-secondary me-2">
|
||
<i class="fas fa-arrow-left me-1"></i>Back to Widgets
|
||
</a>
|
||
<a href="{% url 'analytics:dashboard_widget_update' widget.pk|default:1 %}" class="btn btn-primary">
|
||
<i class="fas fa-edit me-1"></i>Edit Widget
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<!-- Widget Preview -->
|
||
<div class="col-lg-8">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h5 class="card-title">
|
||
<i class="fas fa-eye me-2"></i>Widget Preview
|
||
</h5>
|
||
<div class="card-tools">
|
||
<button type="button" class="btn btn-outline-primary btn-sm" onclick="refreshWidget()">
|
||
<i class="fas fa-sync-alt me-1"></i>Refresh
|
||
</button>
|
||
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="toggleFullscreen()">
|
||
<i class="fas fa-expand me-1"></i>Fullscreen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="widget-preview-container" id="widgetPreview">
|
||
<!-- Revenue Trends Chart Widget -->
|
||
<div class="widget-content">
|
||
<div class="widget-header">
|
||
<h6 class="widget-title">{{ widget.title|default:"Revenue Trends" }}</h6>
|
||
<div class="widget-controls">
|
||
<select class="form-select form-select-sm" style="width: auto;">
|
||
<option>Last 30 days</option>
|
||
<option>Last 90 days</option>
|
||
<option>Last 6 months</option>
|
||
<option>Last year</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="widget-body">
|
||
<div class="chart-container">
|
||
<canvas id="revenueChart" width="400" height="200"></canvas>
|
||
</div>
|
||
|
||
<div class="widget-stats mt-3">
|
||
<div class="row">
|
||
<div class="col-md-3">
|
||
<div class="stat-item">
|
||
<h4 class="text-primary">$2.4M</h4>
|
||
<span class="text-muted">Total Revenue</span>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<div class="stat-item">
|
||
<h4 class="text-success">+12.5%</h4>
|
||
<span class="text-muted">Growth Rate</span>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<div class="stat-item">
|
||
<h4 class="text-info">$80K</h4>
|
||
<span class="text-muted">Daily Average</span>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<div class="stat-item">
|
||
<h4 class="text-warning">$95K</h4>
|
||
<span class="text-muted">Peak Day</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="widget-footer">
|
||
<small class="text-muted">
|
||
<i class="fas fa-clock me-1"></i>Last updated: 2 minutes ago
|
||
</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Widget Data -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h5 class="card-title">
|
||
<i class="fas fa-database me-2"></i>Widget Data
|
||
</h5>
|
||
<div class="card-tools">
|
||
<button type="button" class="btn btn-outline-primary btn-sm" onclick="exportData()">
|
||
<i class="fas fa-download me-1"></i>Export
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="table-responsive">
|
||
<table class="table table-striped">
|
||
<thead>
|
||
<tr>
|
||
<th>Date</th>
|
||
<th>Revenue</th>
|
||
<th>Transactions</th>
|
||
<th>Average</th>
|
||
<th>Growth</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>2024-01-15</td>
|
||
<td>$95,240</td>
|
||
<td>1,247</td>
|
||
<td>$76.40</td>
|
||
<td><span class="badge bg-success">+8.2%</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>2024-01-14</td>
|
||
<td>$88,150</td>
|
||
<td>1,156</td>
|
||
<td>$76.25</td>
|
||
<td><span class="badge bg-success">+5.1%</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>2024-01-13</td>
|
||
<td>$83,920</td>
|
||
<td>1,098</td>
|
||
<td>$76.45</td>
|
||
<td><span class="badge bg-danger">-2.3%</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>2024-01-12</td>
|
||
<td>$85,890</td>
|
||
<td>1,124</td>
|
||
<td>$76.42</td>
|
||
<td><span class="badge bg-success">+3.7%</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>2024-01-11</td>
|
||
<td>$82,760</td>
|
||
<td>1,089</td>
|
||
<td>$75.98</td>
|
||
<td><span class="badge bg-success">+1.9%</span></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<nav aria-label="Data pagination">
|
||
<ul class="pagination pagination-sm justify-content-center">
|
||
<li class="page-item disabled">
|
||
<a class="page-link" href="#" tabindex="-1">Previous</a>
|
||
</li>
|
||
<li class="page-item active">
|
||
<a class="page-link" href="#">1</a>
|
||
</li>
|
||
<li class="page-item">
|
||
<a class="page-link" href="#">2</a>
|
||
</li>
|
||
<li class="page-item">
|
||
<a class="page-link" href="#">3</a>
|
||
</li>
|
||
<li class="page-item">
|
||
<a class="page-link" href="#">Next</a>
|
||
</li>
|
||
</ul>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Widget Information -->
|
||
<div class="col-lg-4">
|
||
<!-- Basic Information -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h5 class="card-title">
|
||
<i class="fas fa-info-circle me-2"></i>Widget Information
|
||
</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="widget-info">
|
||
<div class="info-item">
|
||
<label class="form-label">Widget Title:</label>
|
||
<span class="info-value">{{ widget.title|default:"Revenue Trends" }}</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<label class="form-label">Widget Type:</label>
|
||
<span class="badge bg-primary">{{ widget.widget_type|default:"Chart" }}</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<label class="form-label">Chart Type:</label>
|
||
<span class="info-value">{{ widget.chart_type|default:"Line Chart" }}</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<label class="form-label">Data Source:</label>
|
||
<span class="info-value">{{ widget.data_source|default:"Financial Data" }}</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<label class="form-label">Refresh Interval:</label>
|
||
<span class="info-value">{{ widget.refresh_interval|default:"5 minutes" }}</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<label class="form-label">Status:</label>
|
||
<span class="badge bg-success">
|
||
<i class="fas fa-circle me-1" style="font-size: 8px;"></i>Active
|
||
</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<label class="form-label">Created By:</label>
|
||
<span class="info-value">{{ widget.created_by|default:"Dr. Sarah Johnson" }}</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<label class="form-label">Created Date:</label>
|
||
<span class="info-value">{{ widget.created_at|default:"January 10, 2024" }}</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<label class="form-label">Last Updated:</label>
|
||
<span class="info-value">{{ widget.updated_at|default:"2 minutes ago" }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Position & Layout -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h5 class="card-title">
|
||
<i class="fas fa-th-large me-2"></i>Position & Layout
|
||
</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="widget-position">
|
||
<div class="info-item">
|
||
<label class="form-label">Dashboard Position:</label>
|
||
<span class="info-value">{{ widget.position|default:"Row 1, Columns 1-8" }}</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<label class="form-label">Grid Size:</label>
|
||
<span class="info-value">{{ widget.grid_size|default:"8 columns × 4 rows" }}</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<label class="form-label">Order:</label>
|
||
<span class="info-value">{{ widget.order|default:"1" }}</span>
|
||
</div>
|
||
|
||
<div class="position-preview">
|
||
<label class="form-label">Position Preview:</label>
|
||
<div class="grid-preview">
|
||
<div class="grid-container">
|
||
<div class="grid-item active" style="grid-column: 1 / 9; grid-row: 1 / 5;">
|
||
<span>Current Widget</span>
|
||
</div>
|
||
<div class="grid-item" style="grid-column: 9 / 13; grid-row: 1 / 3;">
|
||
<span>Widget 2</span>
|
||
</div>
|
||
<div class="grid-item" style="grid-column: 9 / 13; grid-row: 3 / 5;">
|
||
<span>Widget 3</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Configuration -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h5 class="card-title">
|
||
<i class="fas fa-cog me-2"></i>Configuration
|
||
</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="widget-config">
|
||
<div class="config-section">
|
||
<h6>Display Options</h6>
|
||
<div class="config-item">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" id="showTitle" checked>
|
||
<label class="form-check-label" for="showTitle">Show Title</label>
|
||
</div>
|
||
</div>
|
||
<div class="config-item">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" id="showLegend" checked>
|
||
<label class="form-check-label" for="showLegend">Show Legend</label>
|
||
</div>
|
||
</div>
|
||
<div class="config-item">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" id="showGrid">
|
||
<label class="form-check-label" for="showGrid">Show Grid</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-section">
|
||
<h6>Data Options</h6>
|
||
<div class="config-item">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" id="autoRefresh" checked>
|
||
<label class="form-check-label" for="autoRefresh">Auto Refresh</label>
|
||
</div>
|
||
</div>
|
||
<div class="config-item">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" id="realTime">
|
||
<label class="form-check-label" for="realTime">Real-time Updates</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-section">
|
||
<h6>Interaction</h6>
|
||
<div class="config-item">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" id="allowDrilldown" checked>
|
||
<label class="form-check-label" for="allowDrilldown">Allow Drill-down</label>
|
||
</div>
|
||
</div>
|
||
<div class="config-item">
|
||
<div class="form-check form-switch">
|
||
<input class="form-check-input" type="checkbox" id="allowExport" checked>
|
||
<label class="form-check-label" for="allowExport">Allow Export</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Actions -->
|
||
<div class="card">
|
||
<div class="card-header">
|
||
<h5 class="card-title">
|
||
<i class="fas fa-tools me-2"></i>Actions
|
||
</h5>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="d-grid gap-2">
|
||
<a href="{% url 'analytics:dashboard_widget_update' widget.pk|default:1 %}" class="btn btn-primary">
|
||
<i class="fas fa-edit me-1"></i>Edit Widget
|
||
</a>
|
||
<button type="button" class="btn btn-outline-secondary" onclick="duplicateWidget()">
|
||
<i class="fas fa-copy me-1"></i>Duplicate Widget
|
||
</button>
|
||
<button type="button" class="btn btn-outline-info" onclick="moveWidget()">
|
||
<i class="fas fa-arrows-alt me-1"></i>Move Widget
|
||
</button>
|
||
<button type="button" class="btn btn-outline-warning" onclick="exportWidget()">
|
||
<i class="fas fa-download me-1"></i>Export Widget
|
||
</button>
|
||
<hr>
|
||
<a href="{% url 'analytics:dashboard_widget_delete' widget.pk|default:1 %}" class="btn btn-outline-danger">
|
||
<i class="fas fa-trash me-1"></i>Delete Widget
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// Initialize the revenue chart
|
||
initializeChart();
|
||
|
||
// Initialize configuration switches
|
||
initializeConfigSwitches();
|
||
});
|
||
|
||
function initializeChart() {
|
||
const ctx = document.getElementById('revenueChart').getContext('2d');
|
||
|
||
new Chart(ctx, {
|
||
type: 'line',
|
||
data: {
|
||
labels: ['Jan 11', 'Jan 12', 'Jan 13', 'Jan 14', 'Jan 15'],
|
||
datasets: [{
|
||
label: 'Revenue',
|
||
data: [82760, 85890, 83920, 88150, 95240],
|
||
borderColor: '#007bff',
|
||
backgroundColor: 'rgba(0, 123, 255, 0.1)',
|
||
borderWidth: 3,
|
||
fill: true,
|
||
tension: 0.4
|
||
}]
|
||
},
|
||
options: {
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
plugins: {
|
||
legend: {
|
||
display: false
|
||
}
|
||
},
|
||
scales: {
|
||
y: {
|
||
beginAtZero: false,
|
||
ticks: {
|
||
callback: function(value) {
|
||
return '$' + (value / 1000).toFixed(0) + 'K';
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
function initializeConfigSwitches() {
|
||
const switches = document.querySelectorAll('.form-check-input');
|
||
switches.forEach(switchEl => {
|
||
switchEl.addEventListener('change', function() {
|
||
console.log(`${this.id} changed to: ${this.checked}`);
|
||
// In a real application, this would update the widget configuration
|
||
});
|
||
});
|
||
}
|
||
|
||
function refreshWidget() {
|
||
const btn = event.target.closest('button');
|
||
const originalText = btn.innerHTML;
|
||
|
||
btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Refreshing...';
|
||
btn.disabled = true;
|
||
|
||
setTimeout(() => {
|
||
btn.innerHTML = originalText;
|
||
btn.disabled = false;
|
||
alert('Widget refreshed successfully!');
|
||
}, 2000);
|
||
}
|
||
|
||
function toggleFullscreen() {
|
||
const preview = document.getElementById('widgetPreview');
|
||
|
||
if (!document.fullscreenElement) {
|
||
preview.requestFullscreen().then(() => {
|
||
preview.classList.add('fullscreen-mode');
|
||
});
|
||
} else {
|
||
document.exitFullscreen().then(() => {
|
||
preview.classList.remove('fullscreen-mode');
|
||
});
|
||
}
|
||
}
|
||
|
||
function exportData() {
|
||
alert('Exporting widget data to CSV...');
|
||
}
|
||
|
||
function duplicateWidget() {
|
||
if (confirm('Create a copy of this widget?')) {
|
||
alert('Widget duplicated successfully!');
|
||
}
|
||
}
|
||
|
||
function moveWidget() {
|
||
alert('Opening widget positioning tool...');
|
||
}
|
||
|
||
function exportWidget() {
|
||
alert('Exporting widget configuration...');
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.widget-preview-container {
|
||
border: 1px solid #e9ecef;
|
||
border-radius: 8px;
|
||
background: white;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.widget-content {
|
||
padding: 20px;
|
||
}
|
||
|
||
.widget-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
padding-bottom: 15px;
|
||
border-bottom: 1px solid #e9ecef;
|
||
}
|
||
|
||
.widget-title {
|
||
font-size: 1.1rem;
|
||
font-weight: 600;
|
||
margin: 0;
|
||
color: #2c3e50;
|
||
}
|
||
|
||
.widget-controls .form-select {
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.chart-container {
|
||
position: relative;
|
||
height: 300px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.widget-stats .stat-item {
|
||
text-align: center;
|
||
padding: 15px;
|
||
background: #f8f9fa;
|
||
border-radius: 8px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.widget-stats .stat-item h4 {
|
||
font-size: 1.5rem;
|
||
font-weight: 700;
|
||
margin: 0 0 5px 0;
|
||
}
|
||
|
||
.widget-stats .stat-item span {
|
||
font-size: 0.875rem;
|
||
color: #6c757d;
|
||
}
|
||
|
||
.widget-footer {
|
||
padding-top: 15px;
|
||
border-top: 1px solid #e9ecef;
|
||
text-align: center;
|
||
}
|
||
|
||
.widget-info .info-item {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.widget-info .info-item label {
|
||
font-weight: 600;
|
||
margin-bottom: 5px;
|
||
display: block;
|
||
color: #2c3e50;
|
||
}
|
||
|
||
.widget-info .info-value {
|
||
color: #6c757d;
|
||
}
|
||
|
||
.grid-preview {
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.grid-container {
|
||
display: grid;
|
||
grid-template-columns: repeat(12, 1fr);
|
||
grid-template-rows: repeat(4, 30px);
|
||
gap: 2px;
|
||
background: #f8f9fa;
|
||
padding: 10px;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.grid-item {
|
||
background: #e9ecef;
|
||
border-radius: 4px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 0.75rem;
|
||
color: #6c757d;
|
||
}
|
||
|
||
.grid-item.active {
|
||
background: #007bff;
|
||
color: white;
|
||
}
|
||
|
||
.config-section {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.config-section h6 {
|
||
font-weight: 600;
|
||
margin-bottom: 10px;
|
||
color: #2c3e50;
|
||
border-bottom: 1px solid #e9ecef;
|
||
padding-bottom: 5px;
|
||
}
|
||
|
||
.config-item {
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.fullscreen-mode {
|
||
background: white;
|
||
padding: 40px;
|
||
}
|
||
|
||
.fullscreen-mode .widget-content {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.fullscreen-mode .chart-container {
|
||
height: 500px;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.widget-header {
|
||
flex-direction: column;
|
||
gap: 15px;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.widget-controls {
|
||
width: 100%;
|
||
}
|
||
|
||
.widget-controls .form-select {
|
||
width: 100%;
|
||
}
|
||
|
||
.widget-stats .row {
|
||
margin: 0;
|
||
}
|
||
|
||
.widget-stats .col-md-3 {
|
||
padding: 5px;
|
||
}
|
||
|
||
.chart-container {
|
||
height: 250px;
|
||
}
|
||
|
||
.grid-container {
|
||
grid-template-columns: repeat(6, 1fr);
|
||
grid-template-rows: repeat(6, 25px);
|
||
}
|
||
|
||
.grid-item {
|
||
font-size: 0.6rem;
|
||
}
|
||
}
|
||
</style>
|
||
{% endblock %}
|
||
|