Spell Learn Dialog Anzeige funktioniert
This commit is contained in:
@@ -0,0 +1,691 @@
|
||||
<template>
|
||||
<div v-if="show" class="modal-overlay" @click.self="closeDialog">
|
||||
<div class="modal-content modal-wide">
|
||||
<h3>{{ $t('spells.learn.title') }}</h3>
|
||||
|
||||
<!-- Aktuelle Ressourcen -->
|
||||
<div class="current-resources">
|
||||
<div class="resource-display-card">
|
||||
<span class="resource-icon">⚡</span>
|
||||
<div class="resource-info">
|
||||
<div class="resource-label">Erfahrungspunkte</div>
|
||||
<div class="resource-amount">{{ character.erfahrungsschatz?.ep || 0 }} EP</div>
|
||||
<div class="resource-remaining">
|
||||
<small :class="{ 'text-warning': remainingEP < 50, 'text-danger': remainingEP <= 0 }">
|
||||
Verbleibend: {{ remainingEP }} EP
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-display-card">
|
||||
<span class="resource-icon">💰</span>
|
||||
<div class="resource-info">
|
||||
<div class="resource-label">Gold</div>
|
||||
<div class="resource-amount">{{ character.vermoegen?.goldstücke || 0 }} GS</div>
|
||||
<div class="resource-remaining">
|
||||
<small :class="{ 'text-warning': remainingGold < 20, 'text-danger': remainingGold <= 0 }">
|
||||
Nach Lernen: {{ remainingGold }} GS
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Belohnungsart, Suche und Sortierung -->
|
||||
<div class="form-group form-row">
|
||||
<div class="form-col form-col-main">
|
||||
<label>Lernen als Belohnung:</label>
|
||||
<select v-model="selectedRewardType" :disabled="isLoadingRewardTypes">
|
||||
<option value="" disabled>
|
||||
{{ isLoadingRewardTypes ? 'Lade Belohnungsarten...' : 'Belohnungsart wählen' }}
|
||||
</option>
|
||||
<option
|
||||
v-for="rewardType in availableRewardTypes"
|
||||
:key="rewardType.value"
|
||||
:value="rewardType.value"
|
||||
>
|
||||
{{ rewardType.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-col form-col-input">
|
||||
<label>{{ $t('spells.learn.search.label') }}</label>
|
||||
<input
|
||||
v-model="searchTerm"
|
||||
type="text"
|
||||
:placeholder="$t('spells.learn.search.placeholder')"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-col form-col-input">
|
||||
<label>Sortierung:</label>
|
||||
<select v-model="sortBy">
|
||||
<option value="name">Name</option>
|
||||
<option value="epCost">EP Kosten</option>
|
||||
<option value="goldCost">Gold Kosten</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Schule Buttons -->
|
||||
<div class="form-group">
|
||||
<label>{{ $t('spells.learn.school.label') }}</label>
|
||||
<div class="school-buttons">
|
||||
<button
|
||||
class="school-btn"
|
||||
:class="{ 'active': selectedSchool === '' }"
|
||||
@click="selectedSchool = ''"
|
||||
>
|
||||
{{ $t('spells.learn.school.all') }}
|
||||
</button>
|
||||
<button
|
||||
v-for="school in availableSchools"
|
||||
:key="school"
|
||||
class="school-btn"
|
||||
:class="{ 'active': selectedSchool === school }"
|
||||
@click="selectedSchool = school"
|
||||
>
|
||||
{{ school }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Verfügbare Zauber -->
|
||||
<div class="form-group">
|
||||
<label>{{ $t('spells.learn.available') }}</label>
|
||||
<div v-if="filteredSpells.length > 0" class="learning-levels">
|
||||
<div
|
||||
v-for="spell in filteredSpells"
|
||||
:key="spell.name"
|
||||
class="level-option"
|
||||
:class="{ 'selected': selectedSpell?.name === spell.name }"
|
||||
@click="selectSpell(spell)"
|
||||
>
|
||||
<div class="level-header">
|
||||
<span class="level-target">{{ spell.name }}</span>
|
||||
<span class="level-cost">
|
||||
<span v-if="spell.epCost">{{ spell.epCost }} EP</span>
|
||||
<span v-if="spell.epCost && spell.goldCost"> + </span>
|
||||
<span v-if="spell.goldCost">{{ spell.goldCost }} GS</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="!isLoading" class="no-spells">
|
||||
Keine Zauber verfügbar
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ausgewählter Zauber Details -->
|
||||
<div v-if="selectedSpell" class="form-group">
|
||||
<div class="selection-summary">
|
||||
<strong>Ausgewählt:</strong> {{ selectedSpell.name }}
|
||||
<br>
|
||||
<span class="cost-summary">
|
||||
Lernkosten:
|
||||
<span v-if="selectedSpell.epCost">{{ selectedSpell.epCost }} EP</span>
|
||||
<span v-if="selectedSpell.epCost && selectedSpell.goldCost"> + </span>
|
||||
<span v-if="selectedSpell.goldCost">{{ selectedSpell.goldCost }} GS</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="isLoading" class="loading-message">
|
||||
{{ $t('common.loading') }}
|
||||
</div>
|
||||
|
||||
<div class="modal-actions">
|
||||
<button
|
||||
@click="learnSpell"
|
||||
class="btn-confirm"
|
||||
:disabled="!selectedSpell || isLoading"
|
||||
>
|
||||
{{ isLoading ? 'Wird gelernt...' : $t('spells.learn.action') }}
|
||||
</button>
|
||||
<button @click="closeDialog" class="btn-cancel" :disabled="isLoading">
|
||||
{{ $t('common.cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import API from '@/utils/api'
|
||||
|
||||
export default {
|
||||
name: "SpellLearnDialog",
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
character: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
emits: ['close', 'spell-learned'],
|
||||
data() {
|
||||
return {
|
||||
searchTerm: '',
|
||||
selectedSchool: '',
|
||||
selectedRewardType: '',
|
||||
sortBy: 'name',
|
||||
spellsBySchool: {},
|
||||
selectedSpell: null,
|
||||
isLoading: false,
|
||||
availableRewardTypes: [],
|
||||
isLoadingRewardTypes: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
remainingEP() {
|
||||
const currentEP = this.character.erfahrungsschatz?.ep || 0;
|
||||
const spellEPCost = this.selectedSpell?.epCost || 0;
|
||||
return Math.max(0, currentEP - spellEPCost);
|
||||
},
|
||||
|
||||
remainingGold() {
|
||||
const currentGold = this.character.vermoegen?.goldstücke || 0;
|
||||
const spellGoldCost = this.selectedSpell?.goldCost || 0;
|
||||
return Math.max(0, currentGold - spellGoldCost);
|
||||
},
|
||||
|
||||
totalCosts() {
|
||||
if (!this.selectedSpell) return 0;
|
||||
return (this.selectedSpell.epCost || 0) + (this.selectedSpell.goldCost || 0);
|
||||
},
|
||||
|
||||
filteredSpells() {
|
||||
let allSpells = [];
|
||||
|
||||
// Sammle alle Zauber aus allen Schulen
|
||||
Object.keys(this.spellsBySchool).forEach(school => {
|
||||
if (!this.selectedSchool || school === this.selectedSchool) {
|
||||
allSpells = allSpells.concat(this.spellsBySchool[school]);
|
||||
}
|
||||
});
|
||||
|
||||
// Filter nach Suchterm
|
||||
let filtered = allSpells.filter(spell => {
|
||||
const matchesSearch = !this.searchTerm ||
|
||||
spell.name.toLowerCase().includes(this.searchTerm.toLowerCase());
|
||||
|
||||
return matchesSearch;
|
||||
});
|
||||
|
||||
// Sortierung
|
||||
return filtered.sort((a, b) => {
|
||||
switch (this.sortBy) {
|
||||
case 'epCost':
|
||||
return (a.epCost || 0) - (b.epCost || 0);
|
||||
case 'goldCost':
|
||||
return (a.goldCost || 0) - (b.goldCost || 0);
|
||||
case 'name':
|
||||
default:
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
availableSchools() {
|
||||
return Object.keys(this.spellsBySchool).sort();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show(newVal) {
|
||||
if (newVal) {
|
||||
this.resetForm();
|
||||
this.loadRewardTypes();
|
||||
}
|
||||
},
|
||||
selectedRewardType() {
|
||||
if (this.selectedRewardType) {
|
||||
this.loadAvailableSpells();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$api = API;
|
||||
},
|
||||
methods: {
|
||||
closeDialog() {
|
||||
this.$emit('close');
|
||||
},
|
||||
|
||||
resetForm() {
|
||||
this.searchTerm = '';
|
||||
this.selectedSchool = '';
|
||||
this.selectedRewardType = '';
|
||||
this.sortBy = 'name';
|
||||
this.spellsBySchool = {};
|
||||
this.selectedSpell = null;
|
||||
this.availableRewardTypes = [];
|
||||
},
|
||||
|
||||
async loadRewardTypes() {
|
||||
const token = localStorage.getItem('token');
|
||||
if (!token) {
|
||||
console.error('No authentication token available');
|
||||
this.availableRewardTypes = [{
|
||||
value: 'error',
|
||||
label: 'Anmeldung erforderlich'
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
this.isLoadingRewardTypes = true;
|
||||
try {
|
||||
const response = await this.$api.get(`/api/characters/${this.character.id}/reward-types`, {
|
||||
params: {
|
||||
learning_type: 'spell',
|
||||
skill_name: 'spell',
|
||||
current_level: 0,
|
||||
skill_type: 'spell'
|
||||
}
|
||||
});
|
||||
|
||||
this.availableRewardTypes = response.data.reward_types || [];
|
||||
|
||||
// Setze Default-Belohnungsart wenn verfügbar
|
||||
if (this.availableRewardTypes.length > 0 && !this.selectedRewardType) {
|
||||
const defaultReward = this.availableRewardTypes.find(r => r.value === 'default');
|
||||
this.selectedRewardType = defaultReward ? defaultReward.value : this.availableRewardTypes[0].value;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Belohnungsarten:', error);
|
||||
this.availableRewardTypes = [{
|
||||
value: 'default',
|
||||
label: 'Standard'
|
||||
}];
|
||||
this.selectedRewardType = 'default';
|
||||
} finally {
|
||||
this.isLoadingRewardTypes = false;
|
||||
}
|
||||
},
|
||||
|
||||
performInitialSearch() {
|
||||
// Beim Öffnen alle Zauber laden
|
||||
this.loadAvailableSpells();
|
||||
},
|
||||
|
||||
async loadAvailableSpells() {
|
||||
if (!this.selectedRewardType) return;
|
||||
|
||||
try {
|
||||
this.isLoading = true;
|
||||
|
||||
// Erstelle LernCostRequest wie vom Backend erwartet
|
||||
const request = {
|
||||
char_id: this.character.id,
|
||||
type: 'spell',
|
||||
action: 'learn',
|
||||
use_pp: 0,
|
||||
use_gold: 0,
|
||||
reward: this.selectedRewardType
|
||||
};
|
||||
|
||||
const response = await this.$api.post('/api/characters/available-spells-new', request);
|
||||
this.spellsBySchool = response.data.spells_by_school || {};
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der verfügbaren Zauber:', error);
|
||||
this.spellsBySchool = {};
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
selectSpell(spell) {
|
||||
this.selectedSpell = this.selectedSpell?.name === spell.name ? null : spell;
|
||||
},
|
||||
|
||||
async learnSpell() {
|
||||
if (!this.selectedSpell || this.isLoading) return;
|
||||
|
||||
try {
|
||||
this.isLoading = true;
|
||||
|
||||
const response = await this.$api.post(`/characters/${this.character.id}/learn-spell-new`, {
|
||||
char_id: this.character.id,
|
||||
name: this.selectedSpell.name,
|
||||
type: 'spell',
|
||||
action: 'learn',
|
||||
use_pp: 0,
|
||||
use_gold: 0,
|
||||
reward: this.selectedRewardType
|
||||
});
|
||||
|
||||
this.$emit('spell-learned', {
|
||||
spell: this.selectedSpell,
|
||||
response: response.data
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Lernen des Zaubers:', error);
|
||||
alert('Fehler beim Lernen des Zaubers: ' + (error.response?.data?.message || error.message));
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Modal Styles */
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: 100vw;
|
||||
max-height: 100vh;
|
||||
overflow-y: auto;
|
||||
animation: modalSlideIn 0.3s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.modal-wide {
|
||||
max-width: 100vw;
|
||||
}
|
||||
|
||||
/* Ressourcen-Anzeige im Dialog */
|
||||
.current-resources {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.resource-display-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 12px 16px;
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 8px;
|
||||
flex: 1;
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
.resource-display-card .resource-icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.resource-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.resource-label {
|
||||
font-size: 12px;
|
||||
color: #6c757d;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.resource-amount {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.resource-remaining {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.resource-remaining small {
|
||||
color: #6c757d;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.text-warning {
|
||||
color: #f0ad4e !important;
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: #d9534f !important;
|
||||
}
|
||||
|
||||
/* Filter und Sortierung */
|
||||
.school-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.school-btn {
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
background: white;
|
||||
color: #495057;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.school-btn:hover {
|
||||
background: #f8f9fa;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
.school-btn.active {
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
/* Zauber-Auswahl */
|
||||
.selection-summary {
|
||||
background: #e7f3ff;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 10px;
|
||||
border-left: 4px solid #007bff;
|
||||
}
|
||||
|
||||
.cost-summary {
|
||||
color: #28a745;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.learning-levels {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 6px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.level-option {
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #f1f1f1;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.level-option:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.level-option:hover:not(.disabled) {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.level-option.selected {
|
||||
background: #e7f3ff;
|
||||
border-left: 4px solid #007bff;
|
||||
}
|
||||
|
||||
.level-option.disabled {
|
||||
background: #f8f9fa;
|
||||
color: #6c757d;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.level-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.level-target {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.level-cost {
|
||||
color: #28a745;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.level-option.disabled .level-cost {
|
||||
color: #dc3545;
|
||||
}
|
||||
|
||||
.no-spells {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: #6c757d;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.loading-message {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
@keyframes modalSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9) translateY(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
color: #333;
|
||||
border-bottom: 2px solid #1da766;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.form-col {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.form-col-main {
|
||||
flex: 2;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.form-col-input {
|
||||
flex: 1;
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select,
|
||||
.form-group textarea {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
height: 80px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.help-text {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
color: #6c757d;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.modal-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
margin-top: 20px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
padding: 8px 20px;
|
||||
background: #1da766;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-confirm:hover:not(:disabled) {
|
||||
background: #16a085;
|
||||
}
|
||||
|
||||
.btn-confirm:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
padding: 8px 20px;
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-cancel:hover:not(:disabled) {
|
||||
background: #5a6268;
|
||||
}
|
||||
</style>
|
||||
@@ -1,10 +1,25 @@
|
||||
<template>
|
||||
<div class="cd-view">
|
||||
<h2>{{ character.name }}'s Zauber</h2>
|
||||
<!-- Header mit Lernmodus-Kontrollen -->
|
||||
<div class="header-section">
|
||||
<h2>{{ character.name }}'s Zauber</h2>
|
||||
|
||||
<div class="learning-mode-controls">
|
||||
<!-- Lernmodus Toggle Button -->
|
||||
<button
|
||||
@click="showLearnNewDialog"
|
||||
class="btn-learning-mode"
|
||||
title="Neuen Zauber lernen"
|
||||
>
|
||||
<span class="icon">🎓</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cd-list">
|
||||
<table class="cd-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<tr class="cd-table-header">
|
||||
<th>{{ $t('spell.name') }}</th>
|
||||
<th>{{ $t('spell.description') }}</th>
|
||||
<th>{{ $t('spell.bonus') }}</th>
|
||||
@@ -12,7 +27,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="spell in character.zauber">
|
||||
<template v-for="spell in character.zauber" :key="spell.id || spell.name">
|
||||
<tr>
|
||||
<td>{{ spell.name || '-' }}</td>
|
||||
<td>{{ spell.beschreibung || '-' }}</td>
|
||||
@@ -23,22 +38,103 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div> <!--- end cd-list-->
|
||||
|
||||
<!-- Dialog für neue Zauber lernen -->
|
||||
<SpellLearnDialog
|
||||
:character="character"
|
||||
:show="showLearnDialog"
|
||||
@close="closeDialogs"
|
||||
@spell-learned="handleSpellLearned"
|
||||
/>
|
||||
</div> <!--- end character -datasheet-->
|
||||
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.cd-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cd-table-header {
|
||||
background-color: #1da766;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Header mit Lernmodus-Kontrollen */
|
||||
.header-section {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.learning-mode-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
/* Lernmodus Toggle Button */
|
||||
.btn-learning-mode {
|
||||
padding: 8px 16px;
|
||||
border: 2px solid #1da766;
|
||||
background: white;
|
||||
color: #1da766;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.btn-learning-mode:hover {
|
||||
background: #1da766;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script>
|
||||
import API from '@/utils/api'
|
||||
import SpellLearnDialog from './SpellLearnDialog.vue'
|
||||
|
||||
export default {
|
||||
name: "SpellView",
|
||||
components: {
|
||||
SpellLearnDialog
|
||||
},
|
||||
props: {
|
||||
character: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showLearnDialog: false,
|
||||
isLoading: false
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.$api = API;
|
||||
},
|
||||
methods: {
|
||||
showLearnNewDialog() {
|
||||
this.showLearnDialog = true;
|
||||
},
|
||||
|
||||
closeDialogs() {
|
||||
this.showLearnDialog = false;
|
||||
},
|
||||
|
||||
handleSpellLearned(eventData) {
|
||||
this.$emit('character-updated');
|
||||
this.closeDialogs();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
+31
-3
@@ -78,10 +78,34 @@ export default {
|
||||
wirkungsbereich:'Wirkungsbereich',
|
||||
wirkungsdauer:'Wirkungsdauer',
|
||||
ursprung:'Ursprung',
|
||||
quelle:'Quelle',
|
||||
system:'System',
|
||||
bonus:'Bonus',
|
||||
|
||||
quelle:'Quelle',
|
||||
},
|
||||
spells: {
|
||||
learn: {
|
||||
title: 'Neuen Zauber lernen',
|
||||
search: {
|
||||
label: 'Suche',
|
||||
placeholder: 'Zauber suchen...'
|
||||
},
|
||||
school: {
|
||||
label: 'Schule',
|
||||
all: 'Alle Schulen'
|
||||
},
|
||||
available: 'Verfügbare Zauber',
|
||||
selected: 'Ausgewählter Zauber',
|
||||
costs: {
|
||||
title: 'Lernkosten',
|
||||
ep: 'Erfahrungspunkte',
|
||||
gold: 'Gold',
|
||||
total: 'Gesamt'
|
||||
},
|
||||
action: 'Zauber lernen'
|
||||
},
|
||||
costs: {
|
||||
ep: 'EP',
|
||||
gold: 'Gold'
|
||||
}
|
||||
},
|
||||
Spell:'Zauber',
|
||||
weapon:{
|
||||
@@ -128,6 +152,10 @@ export default {
|
||||
},
|
||||
search:'Suche',
|
||||
Skill:'Fertigkeit',
|
||||
common: {
|
||||
loading: 'Laden...',
|
||||
cancel: 'Abbrechen'
|
||||
},
|
||||
experience: {
|
||||
title: 'Erfahrung & Vermögen',
|
||||
experience_points: 'Erfahrungspunkte',
|
||||
|
||||
Reference in New Issue
Block a user