feat(certificate): add score breakdown and recommendations for certificate progression

This commit is contained in:
Torsten Schulz (local)
2026-08-28 11:50:30 +02:00
parent 89215793ab
commit 4bcf9041af
4 changed files with 121 additions and 0 deletions

View File

@@ -196,6 +196,12 @@
"notReady": "Für Stufe {next} müssen sowohl die Mindestanforderungen als auch die Wertungsgrenze von {threshold} erfüllt sein."
},
"scoreHowToRaise": "Die Wertungsgrenze steigt über gewichtete Punkte: Wissen (45%), abgeschlossene Produktionen (30%), Amtsstatus (8%), Ansehensstatus (7%), Hausstatus (5%) und Adelsstatus (5%). Für schnelle Fortschritte sind Wissen + viele abgeschlossene Produktionen die stärksten Hebel.",
"scoreBreakdown": {
"title": "So erreichst du die nächste Wertung",
"gap": "Es fehlen noch {gap} Wertungspunkte bis {threshold}.",
"nextStep": "Nächste Stufe: von {current} auf {next} erhöhen (+{gain} Wertung).",
"maxed": "Bereits ausgeschöpft weitere Steigerungen erhöhen die Wertung nicht."
},
"factors": "Aktuelle Werte",
"requirements": "Bedingungen für die nächste Stufe",
"productionsSince": "Nur Produktionen ab {date} zählen (seit letztem Aufstieg, Bankrott oder Erbfolge).",

View File

@@ -195,6 +195,12 @@
"notReady": "Pour le niveau {next}, les exigences minimales et la limite de notation de {threshold} doivent être remplies."
},
"scoreHowToRaise": "Le seuil de note monte via des points pondérés : connaissance (45%), productions terminées (30%), statut d'office (8%), statut de réputation (7%), statut de maison (5%) et statut de noblesse (5%). Pour progresser vite, concentrez-vous sur la connaissance et de nombreuses productions terminées.",
"scoreBreakdown": {
"title": "Comment atteindre la prochaine note",
"gap": "Il manque encore {gap} point(s) de note pour atteindre {threshold}.",
"nextStep": "Prochaine étape : passer de {current} à {next} (+{gain} de note).",
"maxed": "Déjà au maximum : d'autres progrès n'augmentent pas la note."
},
"factors": "Valeurs actuelles",
"requirements": "Conditions pour la prochaine étape",
"productionsSince": "Seules les productions à partir du {date} comptent (depuis la dernière promotion, faillite ou succession).",

View File

@@ -123,6 +123,32 @@
{{ $t('falukant.overview.certificate.scoreHowToRaise') }}
</p>
<article v-if="certificateProgress.scoreBreakdown?.length" class="certificate-panel__block certificate-panel__breakdown">
<h4>{{ $t('falukant.overview.certificate.scoreBreakdown.title') }}</h4>
<p>
{{ $t('falukant.overview.certificate.scoreBreakdown.gap', {
gap: formatCertificateValue(certificateProgress.scoreGap, 2),
threshold: formatCertificateValue(certificateProgress.nextScoreThreshold, 1),
}) }}
</p>
<div class="certificate-score-components">
<div v-for="component in certificateProgress.scoreBreakdown" :key="component.key" class="certificate-score-components__item">
<div>
<span>{{ certificateRequirementLabel(component.key) }}</span>
<strong>{{ component.points }}/{{ component.maxPoints }} · {{ formatCertificateValue(component.contribution, 2) }}</strong>
</div>
<p v-if="!component.maxed">
{{ $t('falukant.overview.certificate.scoreBreakdown.nextStep', {
current: formatCertificateValue(component.current, 1),
next: formatCertificateValue(component.nextValue, 1),
gain: formatCertificateValue(component.gain, 2),
}) }}
</p>
<p v-else>{{ $t('falukant.overview.certificate.scoreBreakdown.maxed') }}</p>
</div>
</div>
</article>
<div class="certificate-panel__grid">
<article class="certificate-panel__block">
<h4>{{ $t('falukant.overview.certificate.factors') }}</h4>
@@ -1033,6 +1059,40 @@ export default {
font-size: 0.92rem;
}
.certificate-panel__breakdown {
margin: 0 0 16px;
}
.certificate-panel__breakdown > p {
margin: 0 0 10px;
color: var(--color-text-secondary);
}
.certificate-score-components {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
.certificate-score-components__item {
padding: 10px;
border: 1px solid rgba(123, 93, 49, 0.16);
border-radius: 8px;
background: rgba(255, 252, 245, 0.72);
}
.certificate-score-components__item > div {
display: flex;
justify-content: space-between;
gap: 10px;
}
.certificate-score-components__item p {
margin: 6px 0 0;
color: var(--color-text-secondary);
font-size: 0.86rem;
}
.certificate-panel__productions-since {
margin: 6px 0 0;
font-size: 0.85rem;