Spiel erweitert

This commit is contained in:
Torsten Schulz
2025-06-02 11:26:45 +02:00
parent a9e6c82275
commit 5029be81e9
56 changed files with 4549 additions and 436 deletions

View 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>