82 lines
3.2 KiB
TypeScript
82 lines
3.2 KiB
TypeScript
import type { Evaluation, DimensionScore, TemplateDimension, Template } from "@prisma/client";
|
|
|
|
export interface EvaluationWithScores extends Evaluation {
|
|
template?: Template | null;
|
|
dimensionScores: (DimensionScore & { dimension: TemplateDimension })[];
|
|
}
|
|
|
|
/** Compute average score across dimensions (1-5 scale) */
|
|
export function computeAverageScore(scores: { score: number | null }[]): number {
|
|
const valid = scores.filter((s) => s.score != null && s.score >= 1 && s.score <= 5);
|
|
if (valid.length === 0) return 0;
|
|
return valid.reduce((a, s) => a + (s.score ?? 0), 0) / valid.length;
|
|
}
|
|
|
|
/** Generate findings paragraph from scores (deterministic template) */
|
|
export function generateFindings(
|
|
scores: { score: number | null; dimension: { name?: string; title?: string } }[]
|
|
): string {
|
|
const withScore = scores.filter((s) => s.score != null);
|
|
if (withScore.length === 0) return "Aucun score enregistré pour l'instant.";
|
|
|
|
const avg = computeAverageScore(withScore);
|
|
const dimName = (d: { name?: string; title?: string }) => d.title ?? d.name ?? "";
|
|
const weak = withScore.filter((s) => (s.score ?? 0) <= 2).map((s) => dimName(s.dimension));
|
|
const strong = withScore.filter((s) => (s.score ?? 0) >= 4).map((s) => dimName(s.dimension));
|
|
|
|
let text = `Score de maturité global : ${avg.toFixed(1)}/5. `;
|
|
if (strong.length > 0) {
|
|
text += `Points forts : ${strong.join(", ")}. `;
|
|
}
|
|
if (weak.length > 0) {
|
|
text += `Axes d'amélioration : ${weak.join(", ")}.`;
|
|
} else if (strong.length === 0) {
|
|
text += "Les scores indiquent une maturité modérée sur les dimensions.";
|
|
}
|
|
return text;
|
|
}
|
|
|
|
/** Generate recommendations (deterministic template) */
|
|
export function generateRecommendations(
|
|
scores: { score: number | null; dimension: { name?: string; title?: string } }[]
|
|
): string {
|
|
const dimName = (d: { name?: string; title?: string }) => d.title ?? d.name ?? "";
|
|
const weak = scores.filter((s) => (s.score ?? 5) <= 2).map((s) => dimName(s.dimension));
|
|
if (weak.length === 0) return "Continuer à s'appuyer sur les pratiques actuelles. Envisager le mentorat pour les juniors.";
|
|
return `Prioriser la formation et le développement pour : ${weak.join(", ")}. Envisager des programmes de montée en compétence structurés et une expertise externe si les écarts sont importants.`;
|
|
}
|
|
|
|
/** Convert evaluation to CSV rows (one per dimension + metadata row) */
|
|
export function evaluationToCsvRows(evalData: EvaluationWithScores): string[][] {
|
|
const rows: string[][] = [];
|
|
rows.push([
|
|
"candidateName",
|
|
"candidateRole",
|
|
"evaluatorName",
|
|
"evaluationDate",
|
|
"template",
|
|
"status",
|
|
"dimension",
|
|
"score",
|
|
"justification",
|
|
"examplesObserved",
|
|
"confidence",
|
|
]);
|
|
for (const ds of evalData.dimensionScores) {
|
|
rows.push([
|
|
evalData.candidateName,
|
|
evalData.candidateRole,
|
|
evalData.evaluatorName,
|
|
evalData.evaluationDate.toISOString().split("T")[0],
|
|
evalData.template?.name ?? "",
|
|
evalData.status,
|
|
(ds.dimension as { name?: string; title?: string }).title ?? (ds.dimension as { name?: string }).name ?? "",
|
|
String(ds.score ?? ""),
|
|
ds.justification ?? "",
|
|
ds.examplesObserved ?? "",
|
|
ds.confidence ?? "",
|
|
]);
|
|
}
|
|
return rows;
|
|
}
|