feat(reporting) : add Reporting dashboard front layer

LST-59 (3.1) front. Completes the Reporting module.

- New frontend/modules/reporting/ layer (auto-detected): /reporting page
  (admin middleware) consuming the 4 read-only report endpoints.
- Filters (period presets + custom dates, project, user). 4 sections (time per
  project, time per user, tasks by status, absences by type) each with a
  DataTable + a Chart.js chart (reused global registration).
- Front-side CSV export per section (useCsvExport: BOM UTF-8, ; separator).
- i18n keys (reporting.*, sidebar.admin.reporting).

nuxt build passes; /reporting routed; no route regression.
This commit is contained in:
Matthieu
2026-06-21 00:16:03 +02:00
parent b3b29fd753
commit f4ffc02028
9 changed files with 713 additions and 1 deletions
@@ -0,0 +1,51 @@
import type {
AbsencesByType,
ReportFilters,
TasksByStatus,
TimePerProject,
TimePerUser,
} from './dto/reporting'
import type { AnyObject } from '~/shared/composables/useApi'
import type { HydraCollection } from '~/utils/api'
import { extractHydraMembers } from '~/utils/api'
function buildQuery(filters: Partial<ReportFilters>, keys: (keyof ReportFilters)[]): AnyObject {
const query: AnyObject = {}
for (const key of keys) {
const value = filters[key]
if (value !== undefined && value !== null && value !== '') {
query[key] = value
}
}
return query
}
export function useReportingService() {
const api = useApi()
async function timePerProject(filters: ReportFilters): Promise<TimePerProject[]> {
const query = buildQuery(filters, ['from', 'to', 'userId', 'projectId'])
const data = await api.get<HydraCollection<TimePerProject>>('/reports/time-per-project', query, { toast: false })
return extractHydraMembers(data)
}
async function timePerUser(filters: ReportFilters): Promise<TimePerUser[]> {
const query = buildQuery(filters, ['from', 'to', 'projectId'])
const data = await api.get<HydraCollection<TimePerUser>>('/reports/time-per-user', query, { toast: false })
return extractHydraMembers(data)
}
async function tasksByStatus(filters: ReportFilters): Promise<TasksByStatus[]> {
const query = buildQuery(filters, ['projectId'])
const data = await api.get<HydraCollection<TasksByStatus>>('/reports/tasks-by-status', query, { toast: false })
return extractHydraMembers(data)
}
async function absencesByType(filters: ReportFilters): Promise<AbsencesByType[]> {
const query = buildQuery(filters, ['from', 'to', 'userId'])
const data = await api.get<HydraCollection<AbsencesByType>>('/reports/absences-by-type', query, { toast: false })
return extractHydraMembers(data)
}
return { timePerProject, timePerUser, tasksByStatus, absencesByType }
}