Add reputation actions feature to Falukant module
- Introduced new endpoints for retrieving and executing reputation actions in FalukantController and falukantRouter. - Implemented service methods in FalukantService to handle reputation actions, including daily limits and action execution logic. - Updated the frontend ReputationView component to display available actions and their details, including cost and potential reputation gain. - Added translations for reputation actions in both German and English locales. - Enhanced initialization logic to set up reputation action types in the database.
This commit is contained in:
@@ -782,6 +782,33 @@
|
||||
"type": "Festart",
|
||||
"cost": "Kosten",
|
||||
"date": "Datum"
|
||||
},
|
||||
"actions": {
|
||||
"title": "Aktionen",
|
||||
"description": "Mit diesen Aktionen kannst du Reputation gewinnen. Je öfter du dieselbe Aktion ausführst, desto weniger Reputation bringt sie (unabhängig von den Kosten).",
|
||||
"action": "Aktion",
|
||||
"cost": "Kosten",
|
||||
"gain": "Reputation",
|
||||
"timesUsed": "Bereits genutzt",
|
||||
"execute": "Ausführen",
|
||||
"running": "Läuft...",
|
||||
"none": "Keine Aktionen verfügbar.",
|
||||
"dailyLimit": "Heute noch verfügbar: {remaining} / {cap} Reputation (durch Aktionen).",
|
||||
"success": "Aktion erfolgreich! Reputation +{gain}, Kosten {cost}.",
|
||||
"successSimple": "Aktion erfolgreich!",
|
||||
"type": {
|
||||
"library_donation": "Spende für eine Bibliothek",
|
||||
"orphanage_build": "Waisenhaus aufbauen",
|
||||
"statue_build": "Statue errichten",
|
||||
"hospital_donation": "Krankenhaus/Heilhaus stiften",
|
||||
"school_funding": "Schule/Lehrstuhl finanzieren",
|
||||
"well_build": "Brunnen/Wasserwerk bauen",
|
||||
"bridge_build": "Straßen-/Brückenbau finanzieren",
|
||||
"soup_kitchen": "Armenspeisung organisieren",
|
||||
"patronage": "Kunst & Mäzenatentum",
|
||||
"church_hospice": "Hospiz-/Kirchenspende",
|
||||
"scholarships": "Stipendienfonds finanzieren"
|
||||
}
|
||||
}
|
||||
},
|
||||
"party": {
|
||||
|
||||
@@ -206,6 +206,33 @@
|
||||
},
|
||||
"party": {
|
||||
"title": "Parties"
|
||||
},
|
||||
"actions": {
|
||||
"title": "Actions",
|
||||
"description": "These actions let you gain reputation. The more often you repeat the same action, the less reputation it yields (independent of cost).",
|
||||
"action": "Action",
|
||||
"cost": "Cost",
|
||||
"gain": "Reputation",
|
||||
"timesUsed": "Times used",
|
||||
"execute": "Execute",
|
||||
"running": "Running...",
|
||||
"none": "No actions available.",
|
||||
"dailyLimit": "Available today: {remaining} / {cap} reputation (from actions).",
|
||||
"success": "Action successful! Reputation +{gain}, cost {cost}.",
|
||||
"successSimple": "Action successful!",
|
||||
"type": {
|
||||
"library_donation": "Donate to a library",
|
||||
"orphanage_build": "Build an orphanage",
|
||||
"statue_build": "Erect a statue",
|
||||
"hospital_donation": "Found a hospital/infirmary",
|
||||
"school_funding": "Fund a school/chair",
|
||||
"well_build": "Build a well/waterworks",
|
||||
"bridge_build": "Fund roads/bridges",
|
||||
"soup_kitchen": "Organize a soup kitchen",
|
||||
"patronage": "Arts & patronage",
|
||||
"church_hospice": "Hospice/church donation",
|
||||
"scholarships": "Fund scholarships"
|
||||
}
|
||||
}
|
||||
},
|
||||
"branchProduction": {
|
||||
|
||||
@@ -142,6 +142,44 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="activeTab === 'actions'">
|
||||
<p>
|
||||
{{ $t('falukant.reputation.actions.description') }}
|
||||
</p>
|
||||
<p v-if="reputationActionsDailyCap != null" class="reputation-actions-daily">
|
||||
{{ $t('falukant.reputation.actions.dailyLimit', { remaining: reputationActionsDailyRemaining, cap: reputationActionsDailyCap }) }}
|
||||
</p>
|
||||
|
||||
<table v-if="reputationActions.length">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ $t('falukant.reputation.actions.action') }}</th>
|
||||
<th>{{ $t('falukant.reputation.actions.cost') }}</th>
|
||||
<th>{{ $t('falukant.reputation.actions.gain') }}</th>
|
||||
<th>{{ $t('falukant.reputation.actions.timesUsed') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="a in reputationActions" :key="a.id">
|
||||
<td>{{ $t('falukant.reputation.actions.type.' + a.tr) }}</td>
|
||||
<td>{{ Number(a.cost || 0).toLocaleString($i18n.locale) }}</td>
|
||||
<td>+{{ Number(a.currentGain || 0) }}</td>
|
||||
<td>{{ Number(a.timesUsed || 0) }}</td>
|
||||
<td>
|
||||
<button type="button" :disabled="runningActionId === a.id"
|
||||
@click.prevent="executeReputationAction(a)">
|
||||
{{ runningActionId === a.id ? $t('falukant.reputation.actions.running') : $t('falukant.reputation.actions.execute') }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p v-else>
|
||||
{{ $t('falukant.reputation.actions.none') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -159,7 +197,8 @@ export default {
|
||||
activeTab: 'overview',
|
||||
tabs: [
|
||||
{ value: 'overview', label: 'falukant.reputation.overview.title' },
|
||||
{ value: 'party', label: 'falukant.reputation.party.title' }
|
||||
{ value: 'party', label: 'falukant.reputation.party.title' },
|
||||
{ value: 'actions', label: 'falukant.reputation.actions.title' }
|
||||
],
|
||||
newPartyView: false,
|
||||
newPartyTypeId: null,
|
||||
@@ -174,6 +213,11 @@ export default {
|
||||
inProgressParties: [],
|
||||
completedParties: [],
|
||||
reputation: null,
|
||||
reputationActions: [],
|
||||
reputationActionsDailyCap: null,
|
||||
reputationActionsDailyUsed: null,
|
||||
reputationActionsDailyRemaining: null,
|
||||
runningActionId: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -211,6 +255,41 @@ export default {
|
||||
this.reputation = null;
|
||||
}
|
||||
},
|
||||
async loadReputationActions() {
|
||||
try {
|
||||
const { data } = await apiClient.get('/api/falukant/reputation/actions');
|
||||
this.reputationActionsDailyCap = data?.dailyCap ?? null;
|
||||
this.reputationActionsDailyUsed = data?.dailyUsed ?? null;
|
||||
this.reputationActionsDailyRemaining = data?.dailyRemaining ?? null;
|
||||
this.reputationActions = Array.isArray(data?.actions) ? data.actions : [];
|
||||
} catch (e) {
|
||||
console.error('Failed to load reputation actions', e);
|
||||
this.reputationActions = [];
|
||||
this.reputationActionsDailyCap = null;
|
||||
this.reputationActionsDailyUsed = null;
|
||||
this.reputationActionsDailyRemaining = null;
|
||||
}
|
||||
},
|
||||
async executeReputationAction(action) {
|
||||
if (!action?.id) return;
|
||||
if (this.runningActionId) return;
|
||||
this.runningActionId = action.id;
|
||||
try {
|
||||
const { data } = await apiClient.post('/api/falukant/reputation/actions', { actionTypeId: action.id });
|
||||
const gain = data?.gain ?? null;
|
||||
const cost = data?.cost ?? null;
|
||||
const msg = gain != null
|
||||
? this.$t('falukant.reputation.actions.success', { gain, cost })
|
||||
: this.$t('falukant.reputation.actions.successSimple');
|
||||
this.$root.$refs.messageDialog?.open(this.$t('falukant.reputation.actions.title'), msg);
|
||||
await Promise.all([this.loadReputation(), this.loadReputationActions()]);
|
||||
} catch (e) {
|
||||
const errText = e?.response?.data?.error || e?.message || String(e);
|
||||
this.$root.$refs.messageDialog?.open(this.$t('falukant.reputation.actions.title'), errText);
|
||||
} finally {
|
||||
this.runningActionId = null;
|
||||
}
|
||||
},
|
||||
async loadNobilityTitles() {
|
||||
this.nobilityTitles = await apiClient.get('/api/falukant/nobility/titels').then(r => r.data)
|
||||
},
|
||||
@@ -256,13 +335,14 @@ export default {
|
||||
},
|
||||
async mounted() {
|
||||
const tabFromQuery = this.$route?.query?.tab;
|
||||
if (['overview','party'].includes(tabFromQuery)) {
|
||||
if (['overview','party','actions'].includes(tabFromQuery)) {
|
||||
this.activeTab = tabFromQuery;
|
||||
}
|
||||
await this.loadPartyTypes();
|
||||
await this.loadNobilityTitles();
|
||||
await this.loadParties();
|
||||
await this.loadReputation();
|
||||
await this.loadReputationActions();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -323,4 +403,9 @@ table th {
|
||||
border-top: 1px solid #ccc;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.reputation-actions-daily {
|
||||
margin: 0.5rem 0 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user