Spiel erweitert
This commit is contained in:
300
frontend/src/views/falukant/EducationView.vue
Normal file
300
frontend/src/views/falukant/EducationView.vue
Normal file
@@ -0,0 +1,300 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user