Files
yourpart3/frontend/src/views/falukant/EducationView.vue
Torsten Schulz 5029be81e9 Spiel erweitert
2025-06-02 11:26:45 +02:00

301 lines
12 KiB
Vue

<template>
<div class="contenthidden">
<StatusBar />
<div class="contentscroll">
<h2>{{ $t('falukant.education.title') }}</h2>
<SimpleTabs v-model="activeTab" :tabs="tabs" />
<!-- SELF -->
<div v-if="activeTab === 'self'">
<table>
<thead>
<tr>
<th>{{ $t('falukant.education.table.article') }}</th>
<th>{{ $t('falukant.education.table.knowledge') }}</th>
<th>{{ $t('falukant.education.table.activity') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="product in products" :key="product.id">
<td>{{ $t(`falukant.product.${product.labelTr}`) }}</td>
<td>{{ product.knowledges[0].knowledge }} %</td>
<td>
<button
v-if="ownRunningEducations.length === 0"
@click="learnItem(product.id, 'self')"
>
{{ $t('falukant.education.learn') }}
({{ formatCost(getSelfCost(product.knowledges[0].knowledge)) }})
</button>
</td>
</tr>
</tbody>
</table>
<div>
<button
v-if="ownRunningEducations.length === 0"
@click="learnAll('self')"
>
{{ $t('falukant.education.learnAll') }}
({{ formatCost(getSelfAllCost()) }})
</button>
</div>
</div>
<!-- CHILDREN -->
<div v-else-if="activeTab === 'children'">
<div>
<select v-model="activeChild">
<option v-for="child in children" :key="child.id" :value="child.id">
{{ child.name }} ({{ child.age }})
</option>
</select>
</div>
<table v-if="activeChild">
<thead>
<tr>
<th>{{ $t('falukant.education.table.article') }}</th>
<th>{{ $t('falukant.education.table.knowledge') }}</th>
<th>{{ $t('falukant.education.table.activity') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="product in products" :key="product.id">
<td>{{ $t(`falukant.product.${product.labelTr}`) }}</td>
<td>{{ getChildKnowledge(product.id) }} %</td>
<td>
<button
v-if="childNotInLearning()"
@click="learnItem(product.id, 'children', activeChild)"
>
{{ $t('falukant.education.learn') }}
({{ formatCost(getChildCost(product.id)) }})
</button>
</td>
</tr>
</tbody>
</table>
<div>
<button
v-if="childrenRunningEducations.length === 0"
@click="learnAll('children', activeChild)"
>
{{ $t('falukant.education.learnAll') }}
({{ formatCost(getChildrenAllCost(activeChild)) }})
</button>
</div>
</div>
<!-- DIRECTOR -->
<div v-else-if="activeTab === 'director'">
<div>
<select v-model="activeDirector">
<option v-for="director in directors" :key="director.id" :value="director.id">
{{ director.character.nobleTitle.tr }}
{{ director.character.definedFirstName.name }}
{{ director.character.definedLastName.name }}
</option>
</select>
</div>
<table v-if="activeDirector">
<thead>
<tr>
<th>{{ $t('falukant.education.table.article') }}</th>
<th>{{ $t('falukant.education.table.knowledge') }}</th>
<th>{{ $t('falukant.education.table.activity') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="product in products" :key="product.id">
<td>{{ $t(`falukant.product.${product.labelTr}`) }}</td>
<td>{{ getDirectorKnowledge(product.id) }} %</td>
<td>
<button
v-if="directorNotInLearning()"
@click="learnItem(product.id, 'director', getDirectorCharacterId())"
>
{{ $t('falukant.education.learn') }}
({{ formatCost(getDirectorCost(product.id)) }})
</button>
</td>
</tr>
</tbody>
</table>
<div v-if="activeDirector">
<button
v-if="directorNotInLearning()"
@click="learnAll('director', getDirectorCharacterId())"
>
{{ $t('falukant.education.learnAll') }}
({{ formatCost(getDirectorAllCost(getDirectorCharacterId())) }})
</button>
</div>
</div>
</div>
</div>
</template>
<script>
import StatusBar from '@/components/falukant/StatusBar.vue';
import MessageDialog from '@/dialogues/standard/MessageDialog.vue';
import ErrorDialog from '@/dialogues/standard/ErrorDialog.vue';
import apiClient from '@/utils/axios.js';
import SimpleTabs from '@/components/SimpleTabs.vue'
const KNOWLEDGE_MAX = 99;
const COST_CONFIG = {
one: { min: 50, max: 5000 },
all: { min: 400, max: 40000 }
};
export default {
name: 'EducationView',
components: { StatusBar, MessageDialog, ErrorDialog, SimpleTabs },
data() {
return {
activeTab: 'self',
tabs: [
{ value: 'self', label: 'falukant.education.self.title' },
{ value: 'children', label: 'falukant.education.children.title' },
{ value: 'director', label: 'falukant.education.director.title' }
],
products: [],
ownRunningEducations: [],
childrenRunningEducations: [],
directorRunningEducations: [],
directors: [],
activeDirector: null,
children: [],
activeChild: null,
}
},
async mounted() {
await this.loadProducts();
await this.loadEducations();
await this.loadDirectors();
await this.loadChildren();
},
methods: {
// Basis-Funktion: lineare Interpolation
computeCost(knowledgePercent, type = 'one') {
const cfg = COST_CONFIG[type];
const f = Math.min(Math.max(knowledgePercent, 0), KNOWLEDGE_MAX) / KNOWLEDGE_MAX;
return cfg.min + (cfg.max - cfg.min) * f;
},
formatCost(value) {
return Math.round(value).toLocaleString(this.$i18n.locale || 'de-DE');
},
// SELF
getSelfCost(knowledge) {
return this.computeCost(knowledge, 'one');
},
getSelfAllCost() {
const avg = this.products.reduce((sum, p) => sum + (p.knowledges[0].knowledge||0), 0) / this.products.length;
return this.computeCost(avg, 'all');
},
// CHILD
getChildKnowledge(productId) {
const child = this.children.find(c => c.id === this.activeChild);
if (!child?.knowledge) return 0;
const e = child.knowledge.find(k => k.id === productId);
return e ? e.knowledge : 0;
},
getChildCost(productId) {
return this.computeCost(this.getChildKnowledge(productId), 'one');
},
getChildrenAllCost(childId) {
const child = this.children.find(c => c.id === childId);
const avg = (child.knowledge || []).reduce((s,k) => s + k.knowledge, 0) / (child.knowledge?.length||1);
return this.computeCost(avg, 'all');
},
childNotInLearning() {
const child = this.children.find(c => c.id === this.activeChild);
return !this.childrenRunningEducations.some(e => e.learningCharacter.id === child.id);
},
// DIRECTOR
getDirectorKnowledge(productId) {
const dir = this.directors.find(d => d.id === this.activeDirector);
const know = dir?.character?.knowledges?.find(k => k.productId === productId);
return know ? know.knowledge : 0;
},
getDirectorCost(productId) {
return this.computeCost(this.getDirectorKnowledge(productId), 'one');
},
getDirectorAllCost(dirCharId) {
const dir = this.directors.find(d => d.character.id === dirCharId);
const avg = (dir.character.knowledges || []).reduce((s,k) => s + k.knowledge, 0) / (dir.character.knowledges.length||1);
return this.computeCost(avg, 'all');
},
getDirectorCharacterId() {
return this.directors.find(d => d.id === this.activeDirector)?.character?.id;
},
directorNotInLearning() {
const dirCharId = this.getDirectorCharacterId();
return !this.directorRunningEducations.some(e => e.learningCharacter.id === dirCharId);
},
// Laden & Aktionen
async loadProducts() {
const r = await apiClient.get('/api/falukant/products');
this.products = r.data;
},
async loadEducations() {
const r = await apiClient.get('/api/falukant/education');
this.ownRunningEducations = r.data.filter(e => e.recipient.tr === 'self');
this.childrenRunningEducations = r.data.filter(e => e.recipient.tr === 'children');
this.directorRunningEducations = r.data.filter(e => e.recipient.tr === 'director');
},
async loadDirectors() {
const r = await apiClient.get('/api/falukant/directors');
this.directors = r.data;
this.activeDirector = this.directors[0]?.id;
},
async loadChildren() {
const r = await apiClient.get('/api/falukant/family/children');
this.children = r.data;
this.activeChild = this.children[0]?.id;
},
async learnItem(item, student, studentId) {
await apiClient.post('/api/falukant/education', { item, student, studentId });
await this.loadEducations();
},
async learnAll(student, studentId) {
await apiClient.post('/api/falukant/education', { item: 'all', student, studentId });
await this.loadEducations();
}
}
}
</script>
<style scoped>
h2 {
padding-top: 20px;
}
.simple-tabs {
display: flex;
margin-top: 1rem;
}
.simple-tab {
padding: 0.5rem 1rem;
background: #fff;
border: none;
cursor: pointer;
transition: background 0.2s;
}
.simple-tab.active {
background: #F9A22C;
color: #000;
}
.tab-content {
margin-top: 1rem;
}
</style>