Änderungen: - Anpassung der Schaltflächen zur Verhinderung von Standardaktionen mit `@click.prevent`. - Einführung einer neuen Methode `getPartyDate`, um das Datum der Partys korrekt zu berechnen. - Aktualisierung der Filterlogik in `loadParties`, um Partys der letzten 24 Stunden anzuzeigen. Diese Anpassungen verbessern die Benutzerinteraktion und die Datumsverarbeitung in der Anwendung.
308 lines
12 KiB
Vue
308 lines
12 KiB
Vue
<template>
|
|
<div class="reputation-view">
|
|
<StatusBar />
|
|
<h2>{{ $t('falukant.reputation.title') }}</h2>
|
|
|
|
<div class="simple-tabs">
|
|
<button v-for="tab in tabs" :key="tab.value" :class="['simple-tab', { active: activeTab === tab.value }]"
|
|
@click="activeTab = tab.value">
|
|
{{ $t(tab.label) }}
|
|
</button>
|
|
</div>
|
|
|
|
<div class="tab-content">
|
|
<div v-if="activeTab === 'overview'">
|
|
<p>Deine aktuelle Reputation: …</p>
|
|
</div>
|
|
|
|
<div v-else-if="activeTab === 'party'">
|
|
<button @click.prevent="toggleNewPartyView()" type="button">
|
|
{{ $t('falukant.reputation.party.newpartyview.' + (newPartyView ? 'close' : 'open')) }}
|
|
</button>
|
|
|
|
<div v-if="newPartyView" class="new-party-form">
|
|
<label>
|
|
{{ $t('falukant.reputation.party.newpartyview.type') }}:
|
|
<select v-model.number="newPartyTypeId">
|
|
<option v-for="type in partyTypes" :key="type.id" :value="type.id">
|
|
{{ $t('falukant.party.type.' + type.tr) }}
|
|
</option>
|
|
</select>
|
|
</label>
|
|
|
|
<div v-if="newPartyTypeId" class="party-options">
|
|
<label>
|
|
{{ $t('falukant.reputation.party.music.label') }}:
|
|
<select v-model.number="musicId">
|
|
<option v-for="m in musicTypes" :key="m.id" :value="m.id">
|
|
{{ $t(`falukant.reputation.party.music.${m.tr}`) }}
|
|
</option>
|
|
</select>
|
|
</label>
|
|
|
|
<label>
|
|
{{ $t('falukant.reputation.party.banquette.label') }}:
|
|
<select v-model.number="banquetteId">
|
|
<option v-for="b in banquetteTypes" :key="b.id" :value="b.id">
|
|
{{ $t(`falukant.reputation.party.banquette.${b.tr}`) }}
|
|
</option>
|
|
</select>
|
|
</label>
|
|
|
|
<label>
|
|
{{ $t('falukant.reputation.party.servants.label') }}:
|
|
<input type="number" v-model.number="servantRatio" min="1" max="50" />
|
|
{{ $t('falukant.reputation.party.servants.perPersons') }}
|
|
</label>
|
|
|
|
<label>
|
|
{{ $t('falukant.reputation.party.esteemedInvites.label') }}:
|
|
<multiselect v-model="selectedNobilityIds" :options="nobilityTitles" :multiple="true"
|
|
track-by="id" label="labelTr" :close-on-select="false" :preserve-search="true"
|
|
placeholder="">
|
|
<template #option="{ option }">
|
|
{{ $t('falukant.titles.male.' + option.labelTr) }}
|
|
</template>
|
|
<template #tag="{ option, remove }">
|
|
<span class="multiselect__tag">
|
|
{{ $t('falukant.titles.male.' + option.labelTr) }}
|
|
<i @click="remove(option.id)" class="multiselect__tag-icon"></i>
|
|
</span>
|
|
</template>
|
|
</multiselect>
|
|
</label>
|
|
|
|
<p class="total-cost">
|
|
{{ $t('falukant.reputation.party.totalCost') }}:
|
|
{{ formattedCost }}
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
<button type="button" @click="orderParty()">
|
|
{{ $t('falukant.reputation.party.order') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- In-Progress Parties -->
|
|
<div class="separator-class">
|
|
<h3>{{ $t('falukant.reputation.party.inProgress') }}</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>{{ $t('falukant.reputation.party.type') }}</th>
|
|
<th>{{ $t('falukant.reputation.party.music.label') }}</th>
|
|
<th>{{ $t('falukant.reputation.party.banquette.label') }}</th>
|
|
<th>{{ $t('falukant.reputation.party.servants.label') }}</th>
|
|
<th>{{ $t('falukant.reputation.party.cost') }}</th>
|
|
<th>{{ $t('falukant.reputation.party.date') }}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="party in inProgressParties" :key="party.id">
|
|
<td>{{ $t('falukant.party.type.' + party.partyType.tr) }}</td>
|
|
<td>{{ $t('falukant.reputation.party.music.' + party.musicType.tr) }}</td>
|
|
<td>{{ $t('falukant.reputation.party.banquette.' + party.banquetteType.tr) }}</td>
|
|
<td>{{ party.servantRatio }}</td>
|
|
<td>{{ party.cost.toLocaleString($i18n.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}</td>
|
|
<td>{{ getPartyDate(party.createdAt).toLocaleString() }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Completed Parties -->
|
|
<div class="separator-class">
|
|
<h3>{{ $t('falukant.reputation.party.completed') }}</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>{{ $t('falukant.reputation.party.type') }}</th>
|
|
<th>{{ $t('falukant.reputation.party.music.label') }}</th>
|
|
<th>{{ $t('falukant.reputation.party.banquette.label') }}</th>
|
|
<th>{{ $t('falukant.reputation.party.servants.label') }}</th>
|
|
<th>{{ $t('falukant.reputation.party.cost') }}</th>
|
|
<th>{{ $t('falukant.reputation.party.date') }}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="party in completedParties" :key="party.id">
|
|
<td>{{ $t('falukant.party.type.' + party.partyType.tr) }}</td>
|
|
<td>{{ $t('falukant.reputation.party.music.' + party.musicType.tr) }}</td>
|
|
<td>{{ $t('falukant.reputation.party.banquette.' + party.banquetteType.tr) }}</td>
|
|
<td>{{ party.servantRatio }}</td>
|
|
<td>{{ party.cost.toLocaleString($i18n.locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}</td>
|
|
<td>{{ getPartyDate(party.createdAt).toLocaleString() }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import StatusBar from '@/components/falukant/StatusBar.vue'
|
|
import apiClient from '@/utils/axios.js'
|
|
import Multiselect from 'vue-multiselect'
|
|
|
|
export default {
|
|
name: 'ReputationView',
|
|
components: { StatusBar, Multiselect },
|
|
data() {
|
|
return {
|
|
activeTab: 'overview',
|
|
tabs: [
|
|
{ value: 'overview', label: 'falukant.reputation.overview.title' },
|
|
{ value: 'party', label: 'falukant.reputation.party.title' }
|
|
],
|
|
newPartyView: false,
|
|
newPartyTypeId: null,
|
|
partyTypes: [],
|
|
musicId: null,
|
|
musicTypes: [],
|
|
banquetteId: null,
|
|
banquetteTypes: [],
|
|
nobilityTitles: [],
|
|
selectedNobilityIds: [],
|
|
servantRatio: 50,
|
|
inProgressParties: [],
|
|
completedParties: []
|
|
}
|
|
},
|
|
methods: {
|
|
toggleNewPartyView() {
|
|
this.newPartyView = !this.newPartyView
|
|
},
|
|
async loadPartyTypes() {
|
|
const { data } = await apiClient.get('/api/falukant/party/types');
|
|
this.partyTypes = data.partyTypes;
|
|
this.musicTypes = data.musicTypes;
|
|
this.banquetteTypes = data.banquetteTypes;
|
|
this.musicId = this.musicTypes[0]?.id;
|
|
this.banquetteId = this.banquetteTypes[0]?.id;
|
|
},
|
|
async loadParties() {
|
|
const { data } = await apiClient.get('/api/falukant/party');
|
|
const now = new Date();
|
|
const twentyFourHoursAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
|
|
this.inProgressParties = data.filter(party => {
|
|
const partyDate = this.getPartyDate(party.createdAt);
|
|
return partyDate > twentyFourHoursAgo;
|
|
});
|
|
this.completedParties = data.filter(party => {
|
|
const partyDate = this.getPartyDate(party.createdAt);
|
|
return partyDate <= twentyFourHoursAgo;
|
|
});
|
|
},
|
|
async loadNobilityTitles() {
|
|
this.nobilityTitles = await apiClient.get('/api/falukant/nobility/titels').then(r => r.data)
|
|
},
|
|
async orderParty() {
|
|
await apiClient.post('/api/falukant/party', {
|
|
partyTypeId: this.newPartyTypeId,
|
|
musicId: this.musicId,
|
|
banquetteId: this.banquetteId,
|
|
nobilityIds: this.selectedNobilityIds.map(n => n.id ?? n),
|
|
servantRatio: this.servantRatio
|
|
});
|
|
this.toggleNewPartyView();
|
|
},
|
|
getPartyDate(createdAt) {
|
|
// Feste finden 1 Tag nach der Bestellung statt
|
|
const partyDate = new Date(createdAt);
|
|
partyDate.setDate(partyDate.getDate() + 1);
|
|
return partyDate;
|
|
}
|
|
},
|
|
computed: {
|
|
formattedCost() {
|
|
const type = this.partyTypes.find(t => t.id === this.newPartyTypeId) || {};
|
|
const music = this.musicTypes.find(m => m.id === this.musicId) || {};
|
|
const banquette = this.banquetteTypes.find(b => b.id === this.banquetteId) || {};
|
|
let cost = (type.cost || 0) + (music.cost || 0) + (banquette.cost || 0);
|
|
cost += (50 / this.servantRatio - 1) * 1000;
|
|
let nobilityCost = this.selectedNobilityIds.reduce((sum, id) => {
|
|
const nob = this.nobilityTitles.find(n => n.id === id)
|
|
return sum + ((nob?.id ^ 5) * 1000)
|
|
}, 0);
|
|
cost += nobilityCost;
|
|
const locale = this.$i18n?.locale || 'de-DE';
|
|
return cost.toLocaleString(locale, {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
});
|
|
}
|
|
},
|
|
async mounted() {
|
|
const tabFromQuery = this.$route?.query?.tab;
|
|
if (['overview','party'].includes(tabFromQuery)) {
|
|
this.activeTab = tabFromQuery;
|
|
}
|
|
await this.loadPartyTypes();
|
|
await this.loadNobilityTitles();
|
|
await this.loadParties();
|
|
}
|
|
}
|
|
</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;
|
|
}
|
|
|
|
.new-party-form {
|
|
margin-top: 0.5rem;
|
|
}
|
|
|
|
.party-options {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.total-cost {
|
|
font-weight: bold;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.multiselect {
|
|
display: inline-block !important;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
table th {
|
|
text-align: left;
|
|
}
|
|
|
|
.separator-class {
|
|
border-top: 1px solid #ccc;
|
|
margin-top: 1em;
|
|
}
|
|
</style> |