feat(admin): add potential fathers retrieval for character management
All checks were successful
Deploy to production / deploy (push) Successful in 2m47s

- Implemented a new method in AdminService to fetch potential fathers for a given character based on existing relationships.
- Updated AdminController to expose this functionality via a new API endpoint.
- Enhanced adminRouter to include the route for retrieving potential fathers.
- Modified frontend components to allow selection of potential fathers during pregnancy and birth management.
- Updated internationalization files to include new translation keys related to father selection.
This commit is contained in:
Torsten Schulz (local)
2026-03-31 08:50:56 +02:00
parent ee11a989a0
commit 9a78bc7c4b
30 changed files with 3907 additions and 45 deletions

View File

@@ -43,6 +43,14 @@
<span class="lesson-meta-label">{{ $t('socialnetwork.vocab.courses.lessonTypeLabel') }}</span>
<strong>{{ getLessonTypeLabel(lesson.lessonType) }}</strong>
</div>
<div class="lesson-meta-item" v-if="lessonPedagogy.phaseLabel">
<span class="lesson-meta-label">Phase</span>
<strong>{{ getPhaseLabel(lessonPedagogy.phaseLabel) }}</strong>
</div>
<div class="lesson-meta-item" v-if="lessonPedagogy.didacticMode">
<span class="lesson-meta-label">Fokus</span>
<strong>{{ getDidacticModeLabel(lessonPedagogy.didacticMode) }}</strong>
</div>
<div class="lesson-meta-item">
<span class="lesson-meta-label">{{ $t('socialnetwork.vocab.courses.recommendedDuration') }}</span>
<strong>{{ formatTargetMinutes(lesson.targetMinutes) }}</strong>
@@ -51,9 +59,22 @@
<span class="lesson-meta-label">{{ $t('socialnetwork.vocab.courses.exerciseLoad') }}</span>
<strong>{{ effectiveExercises?.length || 0 }} {{ $t('socialnetwork.vocab.courses.exercisesShort') }}</strong>
</div>
<div class="lesson-meta-item" v-if="lessonPedagogy.newUnitTarget">
<span class="lesson-meta-label">Neue Einheiten</span>
<strong>{{ lessonPedagogy.newUnitTarget }}</strong>
</div>
<div class="lesson-meta-item" v-if="lessonPedagogy.reviewWeight != null">
<span class="lesson-meta-label">Wiederholung</span>
<strong>{{ lessonPedagogy.reviewWeight }}%</strong>
</div>
</div>
</div>
<div v-if="lessonPedagogy.isIntensiveReview" class="lesson-intensity-banner">
<strong>Intensive Wiederholungsphase</strong>
<p>Diese Lektion priorisiert Wiederholung und Vertiefung. Neuer Stoff wird bewusst reduziert, damit vorhandene Muster stabil werden.</p>
</div>
<div class="learn-grid">
<div v-if="lesson && lesson.description" class="lesson-description-box">
<h4>{{ $t('socialnetwork.vocab.courses.lessonDescription') }}</h4>
@@ -872,6 +893,17 @@ export default {
practicalTasks: []
};
},
lessonPedagogy() {
return this.lesson?.pedagogy || {
didacticMode: null,
phaseLabel: null,
blockNumber: null,
difficultyWeight: null,
newUnitTarget: null,
reviewWeight: null,
isIntensiveReview: false
};
},
assistantAvailable() {
if (!this.assistantSettings) {
return false;
@@ -1280,6 +1312,36 @@ export default {
};
return labels[lessonType] || lessonType || this.$t('socialnetwork.vocab.courses.lessonTypeVocab');
},
getPhaseLabel(phaseLabel) {
switch (phaseLabel) {
case 'quickstart':
return 'Schnellstart';
case 'daily_life':
return 'Alltag';
case 'stabilization':
return 'Stabilisierung';
default:
return 'Lernphase';
}
},
getDidacticModeLabel(didacticMode) {
switch (didacticMode) {
case 'core_input':
return 'Neuer Stoff';
case 'guided_dialogue':
return 'Geführter Dialog';
case 'pattern_drill':
return 'Mustertraining';
case 'real_life_scenario':
return 'Alltagsszenario';
case 'intensive_review':
return 'Wiederholungsphase';
case 'checkpoint':
return 'Checkpoint';
default:
return 'Lernfokus';
}
},
formatTargetMinutes(targetMinutes) {
const minutes = Number(targetMinutes);
if (!minutes) {
@@ -2187,6 +2249,24 @@ export default {
color: #7a6848;
}
.lesson-intensity-banner {
margin-bottom: 18px;
padding: 14px 16px;
border-radius: 12px;
border: 1px solid rgba(207, 78, 78, 0.24);
background: rgba(255, 242, 242, 0.95);
color: #8e3d3d;
}
.lesson-intensity-banner strong,
.lesson-intensity-banner p {
margin: 0;
}
.lesson-intensity-banner p {
margin-top: 6px;
}
.learn-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));