Edit in skill view (#32)

* added editing to SkillView
* added bonus for leiteigenschaft to skill
This commit is contained in:
Bardioc26
2026-02-17 23:05:42 +01:00
committed by GitHub
parent 3d0a1b86de
commit b3ed03bf40
3 changed files with 231 additions and 7 deletions
+32
View File
@@ -191,6 +191,12 @@ func ToFeChar(object *models.Char) *models.FeChar {
feC := &models.FeChar{ feC := &models.FeChar{
Char: *object, Char: *object,
} }
for idx, fertigkeit := range object.Fertigkeiten {
fertigkeit.Bonus = GetSkillBonus(&object.Eigenschaften, &fertigkeit)
if fertigkeit.Bonus > 0 {
object.Fertigkeiten[idx].Bonus = fertigkeit.Bonus
}
}
skills, innateSkills, categories := splitSkills(object.Fertigkeiten) skills, innateSkills, categories := splitSkills(object.Fertigkeiten)
feC.Fertigkeiten = skills feC.Fertigkeiten = skills
feC.InnateSkills = innateSkills feC.InnateSkills = innateSkills
@@ -199,6 +205,32 @@ func ToFeChar(object *models.Char) *models.FeChar {
return feC return feC
} }
func GetSkillBonus(eigenschaften *[]models.Eigenschaft, skill *models.SkFertigkeit) int {
bonus := 0
gsmsk := skill.GetSkillByName()
if gsmsk.Bonuseigenschaft != "check" {
for _, eigenschaft := range *eigenschaften {
if eigenschaft.Name == gsmsk.Bonuseigenschaft {
if eigenschaft.Value < 6 {
bonus = -2
break
} else if eigenschaft.Value < 21 {
bonus = -1
break
} else if eigenschaft.Value > 81 && eigenschaft.Value < 96 {
bonus = 1
break
} else if eigenschaft.Value >= 96 {
bonus = 2
break
}
}
}
}
skill.Bonus = bonus
return bonus
}
func splitSkills(object []models.SkFertigkeit) ([]models.SkFertigkeit, []models.SkFertigkeit, map[string][]models.SkFertigkeit) { func splitSkills(object []models.SkFertigkeit) ([]models.SkFertigkeit, []models.SkFertigkeit, map[string][]models.SkFertigkeit) {
var normSkills []models.SkFertigkeit var normSkills []models.SkFertigkeit
var innateSkills []models.SkFertigkeit var innateSkills []models.SkFertigkeit
+12
View File
@@ -1198,3 +1198,15 @@ func TestSearchBeliefs(t *testing.T) {
}) })
} }
} }
func TestToFeChar(t *testing.T) {
// Setup test database
database.SetupTestDB(true)
defer database.ResetTestDB()
char := &models.Char{}
char.FirstID("18")
feChar := ToFeChar(char)
assert.Equal(t, "18", feChar.ID)
assert.Equal(t, 2, feChar.Fertigkeiten[6].Bonus)
}
+186 -6
View File
@@ -4,6 +4,15 @@
<div class="tables-container"> <div class="tables-container">
<div class="table-wrapper-left"> <div class="table-wrapper-left">
<div class="header-section"> <div class="header-section">
<span
v-if="isOwner"
class="help-icon"
:title="$t('characters.datasheet.editHelp')"
role="img"
:aria-label="$t('characters.datasheet.editHelp')"
>
?
</span>
<!-- Lernmodus Toggle Button --> <!-- Lernmodus Toggle Button -->
<div v-if="isOwner" class="learning-mode-controls"> <div v-if="isOwner" class="learning-mode-controls">
<!-- Ressourcen-Anzeige (nur sichtbar wenn Lernmodus aktiv) --> <!-- Ressourcen-Anzeige (nur sichtbar wenn Lernmodus aktiv) -->
@@ -64,8 +73,42 @@
</tr> </tr>
<template v-for="skill in skills"> <template v-for="skill in skills">
<tr> <tr>
<td>{{ skill.name || '-' }}</td> <td>
<td>{{ skill.fertigkeitswert || '-' }}</td> <span
v-if="!isEditingSkill(skill, 'name')"
@dblclick="isOwner ? startEditSkill(skill, 'name') : null"
:class="{ 'editable-prop': isOwner }"
>{{ skill.name || '-' }}</span>
<input
v-else
v-model="editValue"
@blur="saveEditSkill(skill, 'name')"
@keyup.enter="saveEditSkill(skill, 'name')"
@keyup.esc="cancelEditSkill"
ref="editInput"
class="prop-input"
type="text"
/>
</td>
<td>
<span
v-if="!isEditingSkill(skill, 'fertigkeitswert')"
@dblclick="isOwner ? startEditSkill(skill, 'fertigkeitswert') : null"
:class="{ 'editable-prop': isOwner }"
>{{ skill.fertigkeitswert || '-' }}</span>
<input
v-else
v-model="editValue"
@blur="saveEditSkill(skill, 'fertigkeitswert')"
@keyup.enter="saveEditSkill(skill, 'fertigkeitswert')"
@keyup.esc="cancelEditSkill"
ref="editInput"
class="prop-input"
type="number"
min="0"
max="20"
/>
</td>
<td>{{ skill.bonus || '0' }}</td> <td>{{ skill.bonus || '0' }}</td>
<td class="pp-cell"> <td class="pp-cell">
<div v-if="isOwner" class="pp-container"> <div v-if="isOwner" class="pp-container">
@@ -88,7 +131,23 @@
</div> </div>
<span v-else>{{ skill.pp || '0' }}</span> <span v-else>{{ skill.pp || '0' }}</span>
</td> </td>
<td>{{ skill.bemerkung || '-' }}</td> <td>
<span
v-if="!isEditingSkill(skill, 'bemerkung')"
@dblclick="isOwner ? startEditSkill(skill, 'bemerkung') : null"
:class="{ 'editable-prop': isOwner }"
>{{ skill.bemerkung || '-' }}</span>
<input
v-else
v-model="editValue"
@blur="saveEditSkill(skill, 'bemerkung')"
@keyup.enter="saveEditSkill(skill, 'bemerkung')"
@keyup.esc="cancelEditSkill"
ref="editInput"
class="prop-input"
type="text"
/>
</td>
<td v-if="learningMode" class="action-cell"> <td v-if="learningMode" class="action-cell">
<button <button
@click="improveSkill(skill)" @click="improveSkill(skill)"
@@ -106,8 +165,42 @@
</tr> </tr>
<template v-for="skill in character.waffenfertigkeiten"> <template v-for="skill in character.waffenfertigkeiten">
<tr> <tr>
<td>{{ skill.name || '-' }}</td> <td>
<td>{{ skill.fertigkeitswert || '-' }}</td> <span
v-if="!isEditingSkill(skill, 'name')"
@dblclick="isOwner ? startEditSkill(skill, 'name') : null"
:class="{ 'editable-prop': isOwner }"
>{{ skill.name || '-' }}</span>
<input
v-else
v-model="editValue"
@blur="saveEditSkill(skill, 'name')"
@keyup.enter="saveEditSkill(skill, 'name')"
@keyup.esc="cancelEditSkill"
ref="editInput"
class="prop-input"
type="text"
/>
</td>
<td>
<span
v-if="!isEditingSkill(skill, 'fertigkeitswert')"
@dblclick="isOwner ? startEditSkill(skill, 'fertigkeitswert') : null"
:class="{ 'editable-prop': isOwner }"
>{{ skill.fertigkeitswert || '-' }}</span>
<input
v-else
v-model="editValue"
@blur="saveEditSkill(skill, 'fertigkeitswert')"
@keyup.enter="saveEditSkill(skill, 'fertigkeitswert')"
@keyup.esc="cancelEditSkill"
ref="editInput"
class="prop-input"
type="number"
min="0"
max="20"
/>
</td>
<td>{{ skill.bonus || '0' }}</td> <td>{{ skill.bonus || '0' }}</td>
<td class="pp-cell"> <td class="pp-cell">
<div v-if="isOwner" class="pp-container"> <div v-if="isOwner" class="pp-container">
@@ -130,7 +223,23 @@
</div> </div>
<span v-else>{{ skill.pp || '0' }}</span> <span v-else>{{ skill.pp || '0' }}</span>
</td> </td>
<td>{{ skill.bemerkung || '-' }}</td> <td>
<span
v-if="!isEditingSkill(skill, 'bemerkung')"
@dblclick="isOwner ? startEditSkill(skill, 'bemerkung') : null"
:class="{ 'editable-prop': isOwner }"
>{{ skill.bemerkung || '-' }}</span>
<input
v-else
v-model="editValue"
@blur="saveEditSkill(skill, 'bemerkung')"
@keyup.enter="saveEditSkill(skill, 'bemerkung')"
@keyup.esc="cancelEditSkill"
ref="editInput"
class="prop-input"
type="text"
/>
</td>
<td v-if="learningMode" class="action-cell"> <td v-if="learningMode" class="action-cell">
<button <button
@click="improveWeaponSkill(skill)" @click="improveWeaponSkill(skill)"
@@ -318,6 +427,11 @@ export default {
selectedSkillToLearn: null, selectedSkillToLearn: null,
selectedLearningType: 'improve', // 'improve', 'learn', 'spell' selectedLearningType: 'improve', // 'improve', 'learn', 'spell'
// Inline editing
editingSkillId: null,
editingField: null,
editValue: '',
isLoading: false isLoading: false
}; };
}, },
@@ -623,6 +737,72 @@ export default {
skill.pp = ppMap[skill.name] || 0; skill.pp = ppMap[skill.name] || 0;
}); });
} }
},
// Inline editing methods
getSkillId(skill) {
// Create unique ID combining name and type
return `${skill.name}_${skill.kategorie || 'weapon'}`;
},
startEditSkill(skill, field) {
if (!this.isOwner) return;
this.editingSkillId = this.getSkillId(skill);
this.editingField = field;
this.editValue = skill[field] || '';
this.$nextTick(() => {
const input = this.$refs.editInput;
if (input) {
const element = Array.isArray(input) ? input[0] : input;
if (element) {
element.focus();
if (element.select) element.select();
}
}
});
},
async saveEditSkill(skill, field) {
if (this.editingSkillId === null) return;
let newValue = this.editValue;
// Validate and convert for fertigkeitswert
if (field === 'fertigkeitswert') {
newValue = parseInt(this.editValue);
if (isNaN(newValue) || newValue < 0 || newValue > 20) {
alert('Fertigkeitswert muss zwischen 0 und 20 liegen.');
this.cancelEditSkill();
return;
}
}
// Update local character object
skill[field] = newValue;
try {
// Save to backend
await API.put(`/api/characters/${this.character.id}`, this.character);
this.$emit('character-updated');
this.cancelEditSkill();
} catch (error) {
console.error('Failed to update skill:', error);
alert('Fehler beim Speichern: ' + (error.response?.data?.error || error.message));
this.cancelEditSkill();
}
},
cancelEditSkill() {
this.editingSkillId = null;
this.editingField = null;
this.editValue = '';
},
isEditingSkill(skill, field) {
return this.editingSkillId === this.getSkillId(skill) && this.editingField === field;
} }
} }
}; };