Spiel erweitert
This commit is contained in:
186
frontend/src/views/falukant/HealthView.vue
Normal file
186
frontend/src/views/falukant/HealthView.vue
Normal file
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div>
|
||||
<StatusBar />
|
||||
<h2>{{ $t('falukant.healthview.title') }}</h2>
|
||||
<div class="content-container">
|
||||
<div class="info-panel">
|
||||
<p>{{ $t('falukant.healthview.age') }}: {{ age }}</p>
|
||||
<p>{{ $t('falukant.healthview.status') }}: {{ healthState }}</p>
|
||||
</div>
|
||||
|
||||
<div class="measures-panel">
|
||||
<h3>{{ $t('falukant.healthview.measuresTaken') }}</h3>
|
||||
<table class="measures-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ $t('falukant.healthview.measure') }}</th>
|
||||
<th>{{ $t('falukant.healthview.date') }}</th>
|
||||
<th>{{ $t('falukant.healthview.success') }}</th>
|
||||
<th>{{ $t('falukant.healthview.cost') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="entry in measuresTaken" :key="entry.id">
|
||||
<td>{{ $t(`falukant.healthview.measures.${entry.tr}`) }}</td>
|
||||
<td>{{ formatDate(entry.createdAt) }}</td>
|
||||
<td>{{ entry.success }}</td>
|
||||
<td>{{ formatPrice(entry.cost) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="actions">
|
||||
<label>
|
||||
{{ $t('falukant.healthview.selectMeasure') }}:
|
||||
<select v-model="selectedTr">
|
||||
<option value="" disabled>{{ $t('falukant.healthview.choose') }}</option>
|
||||
<option v-for="m in availableMeasures" :key="m.tr" :value="m.tr">
|
||||
{{ $t(`falukant.healthview.measures.${m.tr}`) }} ({{ formatPrice(m.cost) }})
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<button @click="performMeasure" :disabled="!selectedMeasure">
|
||||
{{ $t('falukant.healthview.perform') }}
|
||||
<span v-if="selectedMeasure"> ({{ formatPrice(selectedMeasure.cost) }})</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import StatusBar from '@/components/falukant/StatusBar.vue';
|
||||
import apiClient from '@/utils/axios.js';
|
||||
import { mapState } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'HealthView',
|
||||
components: { StatusBar },
|
||||
data() {
|
||||
return {
|
||||
age: 0,
|
||||
healthStatus: 0,
|
||||
measuresTaken: [],
|
||||
availableMeasures: [],
|
||||
selectedTr: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['daemonSocket']),
|
||||
/**
|
||||
* Selected measure object based on selectedTr
|
||||
*/
|
||||
selectedMeasure() {
|
||||
return this.availableMeasures.find(m => m.tr === this.selectedTr) || null;
|
||||
},
|
||||
/**
|
||||
* Health state translation key based on status
|
||||
*/
|
||||
healthState() {
|
||||
if (this.healthStatus > 90) return this.$t('falukant.health.amazing');
|
||||
if (this.healthStatus > 75) return this.$t('falukant.health.good');
|
||||
if (this.healthStatus > 50) return this.$t('falukant.health.normal');
|
||||
if (this.healthStatus > 25) return this.$t('falukant.health.bad');
|
||||
return this.$t('falukant.health.very_bad');
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadHealthData();
|
||||
if (this.daemonSocket) {
|
||||
this.daemonSocket.addEventListener('message', this.handleDaemonMessage);
|
||||
}
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.daemonSocket) {
|
||||
this.daemonSocket.removeEventListener('message', this.handleDaemonMessage);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadHealthData() {
|
||||
try {
|
||||
const { data } = await apiClient.get('/api/falukant/health');
|
||||
this.age = data.age;
|
||||
this.healthStatus = data.status;
|
||||
this.measuresTaken = data.history;
|
||||
this.availableMeasures = data.healthActivities;
|
||||
} catch (err) {
|
||||
console.error('Error loading health data', err);
|
||||
}
|
||||
},
|
||||
formatDate(dateStr) {
|
||||
const d = new Date(dateStr);
|
||||
return d.toLocaleDateString();
|
||||
},
|
||||
async performMeasure() {
|
||||
if (!this.selectedMeasure) return;
|
||||
try {
|
||||
await apiClient.post('/api/falukant/health', {
|
||||
measureTr: this.selectedTr
|
||||
});
|
||||
await this.loadHealthData();
|
||||
this.selectedTr = '';
|
||||
} catch (err) {
|
||||
console.error('Error performing measure', err);
|
||||
}
|
||||
},
|
||||
handleDaemonMessage(evt) {
|
||||
if (evt.data === 'ping') return;
|
||||
const msg = JSON.parse(evt.data);
|
||||
if (msg.event === 'healthupdated') {
|
||||
this.loadHealthData();
|
||||
}
|
||||
},
|
||||
formatPrice(value) {
|
||||
return new Intl.NumberFormat('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(value);
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
h2 {
|
||||
padding-top: 20px;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.info-panel {
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.measures-panel {
|
||||
flex: 2;
|
||||
padding: 10px;
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.measures-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.measures-table th,
|
||||
.measures-table td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 6px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user