diff --git a/CLAUDE.md b/CLAUDE.md index e15bffa..5d95527 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -115,7 +115,7 @@ lt_janitorial_quality_control/ │ │ │ └── issues_view.html # Same photo evidence logic │ │ ├── reports/ │ │ │ ├── _subnav.html # Shared sub-nav include for all report pages -│ │ │ ├── index.html # Overview & Trends (score trend, facility scores, charts) +│ │ │ ├── index.html # Overview & Trends (score trend, facility scores + per-Contract filter, charts) │ │ │ ├── facility.html # Per-facility detail report │ │ │ ├── scorecard.html # Per-facility scorecard (trend, area scores, SLA, open issues) + PDF Summary button │ │ │ ├── inspector_performance.html # Inspector KPI table + drill-down chart @@ -1054,6 +1054,10 @@ All report pages include `{% include 'reports/_subnav.html' %}` as the first ele | Inspector Performance | admin, director | | Scheduled Reports | admin, director, project_manager | +### Reports — Overview & Trends: "Avg Score by Facility" Contract filter + +The **Avg Score by Facility** card (chart) and the **Facility Score Comparison** table on `reports/index.html` share a **Contract** ` + + {% for pid, cname in score_contracts %} + + {% endfor %} + + {% endif %} +
@@ -129,6 +139,7 @@ Facility + Contract Current Period Prior Period Change @@ -137,8 +148,9 @@ {% for row in facility_scores %} - + {{ row.name }} + {{ row.contract }} {{ '%.1f'|format(row.avg_score|float) }}% @@ -266,25 +278,52 @@ new Chart(document.getElementById('trendChart'), { } }); -// ── Facility bar chart ──────────────────────────────────────────────────────── -new Chart(document.getElementById('facilityChart'), { - type: 'bar', - data: { - labels: {{ facility_scores | map(attribute='name') | list | tojson }}, - datasets: [{ - label: 'Avg Score (%)', - data: {{ facility_scores | map(attribute='avg_score') | list | tojson }}, - backgroundColor: {{ facility_scores | map(attribute='avg_score') | list | tojson }} - .map(s => s >= 90 ? GREEN : s >= 70 ? AMBER : RED), - borderRadius: 4, - }] - }, - options: { - responsive: true, maintainAspectRatio: false, - scales: { y: { min: 0, max: 100, ticks: { callback: v => v + '%' } } }, - plugins: { legend: { display: false } } +// ── Facility bar chart (filterable by contract) ─────────────────────────────── +const FACILITY_SCORES = {{ facility_scores | tojson }}; +let facilityChartObj = null; +function _facColors(data) { return data.map(s => s >= 90 ? GREEN : s >= 70 ? AMBER : RED); } +function renderFacilityChart(pid) { + const rows = (!pid) + ? FACILITY_SCORES + : FACILITY_SCORES.filter(r => String(r.project_id) === String(pid)); + const labels = rows.map(r => r.name); + const data = rows.map(r => r.avg_score); + if (facilityChartObj) { + facilityChartObj.data.labels = labels; + facilityChartObj.data.datasets[0].data = data; + facilityChartObj.data.datasets[0].backgroundColor = _facColors(data); + facilityChartObj.update(); + } else { + facilityChartObj = new Chart(document.getElementById('facilityChart'), { + type: 'bar', + data: { labels: labels, datasets: [{ + label: 'Avg Score (%)', data: data, + backgroundColor: _facColors(data), borderRadius: 4, + }] }, + options: { + responsive: true, maintainAspectRatio: false, + scales: { y: { min: 0, max: 100, ticks: { callback: v => v + '%' } } }, + plugins: { legend: { display: false } } + } + }); } -}); +} +function filterFacilityScoreTable(pid) { + document.querySelectorAll('.facility-score-row').forEach(function (tr) { + const rp = tr.getAttribute('data-project-id'); + tr.style.display = (!pid || rp === String(pid)) ? '' : 'none'; + }); +} +(function () { + renderFacilityChart(''); + const sel = document.getElementById('scoreContractFilter'); + if (sel) { + sel.addEventListener('change', function () { + renderFacilityChart(this.value); + filterFacilityScoreTable(this.value); + }); + } +})(); // ── Severity doughnut ───────────────────────────────────────────────────────── const sevData = {{ issue_severity | tojson }};