fina/backup/first -fina app/app/templates/predictions.html
2025-12-26 00:52:56 +00:00

355 lines
14 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ _('predictions.title') }} - FINA{% endblock %}
{% block content %}
<div class="container-fluid px-4">
<!-- Header -->
<div class="row mb-4">
<div class="col-12">
<h1 class="h3 mb-2">
<i class="fas fa-chart-line me-2"></i>
{{ _('predictions.title') }}
</h1>
<p class="text-muted">{{ _('predictions.subtitle') }}</p>
</div>
</div>
{% if predictions.total_months < 3 %}
<!-- Not enough data warning -->
<div class="row">
<div class="col-12">
<div class="alert alert-info">
<h5 class="alert-heading">
<i class="fas fa-info-circle me-2"></i>
{{ _('predictions.no_data') }}
</h5>
<p class="mb-0">{{ _('predictions.no_data_desc') }}</p>
</div>
</div>
</div>
{% else %}
<!-- Summary Cards -->
<div class="row mb-4">
<div class="col-md-4">
<div class="card">
<div class="card-body">
<h6 class="text-muted mb-2">{{ _('predictions.total_predicted') }}</h6>
<h3 class="mb-0">{{ predictions.total.amount|round(2) }} RON</h3>
<small class="text-muted">
{{ _('predictions.based_on', n=predictions.total_months) }}
</small>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-body">
<h6 class="text-muted mb-2">{{ _('predictions.confidence') }}</h6>
<h3 class="mb-0">
{% if predictions.total.confidence == 'high' %}
<span class="badge bg-success">{{ _('predictions.confidence_high') }}</span>
{% elif predictions.total.confidence == 'medium' %}
<span class="badge bg-warning">{{ _('predictions.confidence_medium') }}</span>
{% else %}
<span class="badge bg-secondary">{{ _('predictions.confidence_low') }}</span>
{% endif %}
</h3>
<small class="text-muted">{{ predictions.total.months_of_data }} {{ _('predictions.month') }}</small>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-body">
<h6 class="text-muted mb-2">{{ _('predictions.trend') }}</h6>
<h3 class="mb-0">
{% if predictions.total.trend == 'increasing' %}
<i class="fas fa-arrow-up text-danger"></i>
{{ _('predictions.trend_increasing') }}
{% elif predictions.total.trend == 'decreasing' %}
<i class="fas fa-arrow-down text-success"></i>
{{ _('predictions.trend_decreasing') }}
{% else %}
<i class="fas fa-minus text-info"></i>
{{ _('predictions.trend_stable') }}
{% endif %}
</h3>
</div>
</div>
</div>
</div>
<!-- Smart Insights -->
{% if insights %}
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-lightbulb me-2"></i>
{{ _('predictions.insights') }}
</h5>
</div>
<div class="card-body">
<ul class="list-unstyled mb-0">
{% for insight in insights %}
<li class="mb-2">
<i class="fas fa-check-circle text-success me-2"></i>
{{ insight }}
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
{% endif %}
<!-- Predictions Chart -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="mb-0">{{ _('predictions.forecast') }}</h5>
</div>
<div class="card-body">
<canvas id="predictionsChart" height="100"></canvas>
</div>
</div>
</div>
</div>
<!-- Category Breakdown -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="mb-0">{{ _('predictions.by_category') }}</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>{{ _('common.category') }}</th>
<th>{{ _('predictions.amount') }}</th>
<th>{{ _('predictions.confidence') }}</th>
<th>{{ _('predictions.trend') }}</th>
<th>{{ _('common.actions') }}</th>
</tr>
</thead>
<tbody>
{% for category_name, prediction in predictions.by_category.items() %}
<tr>
<td>
<i class="fas fa-tag me-2"></i>
{{ category_name }}
</td>
<td>
<strong>{{ prediction.predicted_amount|round(2) }} RON</strong>
</td>
<td>
{% if prediction.confidence == 'high' %}
<span class="badge bg-success">{{ _('predictions.confidence_high') }}</span>
{% elif prediction.confidence == 'medium' %}
<span class="badge bg-warning">{{ _('predictions.confidence_medium') }}</span>
{% else %}
<span class="badge bg-secondary">{{ _('predictions.confidence_low') }}</span>
{% endif %}
</td>
<td>
{% if prediction.trend == 'increasing' %}
<i class="fas fa-arrow-up text-danger"></i>
{{ _('predictions.trend_increasing') }}
{% elif prediction.trend == 'decreasing' %}
<i class="fas fa-arrow-down text-success"></i>
{{ _('predictions.trend_decreasing') }}
{% else %}
<i class="fas fa-minus text-info"></i>
{{ _('predictions.trend_stable') }}
{% endif %}
</td>
<td>
<button class="btn btn-sm btn-outline-primary"
onclick="showCategoryForecast({{ prediction.category_id }}, '{{ category_name }}')">
{{ _('predictions.view_details') }}
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Methodology Info -->
<div class="row">
<div class="col-12">
<div class="card bg-light">
<div class="card-body">
<h6 class="mb-2">
<i class="fas fa-info-circle me-2"></i>
{{ _('predictions.methodology') }}
</h6>
<p class="mb-0 text-muted small">
{{ _('predictions.methodology_desc') }}
</p>
</div>
</div>
</div>
</div>
{% endif %}
</div>
<!-- Category Forecast Modal -->
<div class="modal fade" id="categoryForecastModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="categoryForecastTitle"></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<canvas id="categoryForecastChart" height="100"></canvas>
</div>
</div>
</div>
</div>
<script>
// Predictions data
const predictionsData = {{ predictions|tojson }};
// Main predictions chart
const ctx = document.getElementById('predictionsChart');
if (ctx && predictionsData.by_category) {
const categories = Object.keys(predictionsData.by_category);
const amounts = categories.map(cat => predictionsData.by_category[cat].predicted_amount);
const colors = [
'rgba(255, 99, 132, 0.7)',
'rgba(54, 162, 235, 0.7)',
'rgba(255, 206, 86, 0.7)',
'rgba(75, 192, 192, 0.7)',
'rgba(153, 102, 255, 0.7)',
'rgba(255, 159, 64, 0.7)',
'rgba(201, 203, 207, 0.7)'
];
new Chart(ctx, {
type: 'bar',
data: {
labels: categories,
datasets: [{
label: '{{ _("predictions.total_predicted") }}',
data: amounts,
backgroundColor: colors.slice(0, categories.length),
borderColor: colors.slice(0, categories.length).map(c => c.replace('0.7', '1')),
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
tooltip: {
callbacks: {
label: function(context) {
return context.parsed.y.toFixed(2) + ' RON';
}
}
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) {
return value + ' RON';
}
}
}
}
}
});
}
// Show category forecast
async function showCategoryForecast(categoryId, categoryName) {
try {
const response = await fetch(`/api/predictions/category/${categoryId}`);
const data = await response.json();
if (data.error) {
alert(data.error);
return;
}
// Update modal title
document.getElementById('categoryForecastTitle').textContent =
'{{ _("predictions.forecast") }}: ' + categoryName;
// Create chart
const modalCtx = document.getElementById('categoryForecastChart');
// Destroy existing chart if any
if (window.categoryChart) {
window.categoryChart.destroy();
}
window.categoryChart = new Chart(modalCtx, {
type: 'line',
data: {
labels: data.forecast.map(f => f.month),
datasets: [{
label: '{{ _("predictions.amount") }}',
data: data.forecast.map(f => f.amount),
borderColor: 'rgb(75, 192, 192)',
backgroundColor: 'rgba(75, 192, 192, 0.2)',
tension: 0.1,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
tooltip: {
callbacks: {
label: function(context) {
return context.parsed.y.toFixed(2) + ' RON';
}
}
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) {
return value + ' RON';
}
}
}
}
}
});
// Show modal
new bootstrap.Modal(document.getElementById('categoryForecastModal')).show();
} catch (error) {
console.error('Error fetching forecast:', error);
alert('{{ _("common.error") }}');
}
}
</script>
{% endblock %}