Update maintenance Component for Weapons
This commit is contained in:
@@ -13,6 +13,53 @@
|
||||
|
||||
<div class="cd-view">
|
||||
<div class="cd-list">
|
||||
<!-- Filter Row -->
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<label>{{ $t('weapon.skillrequired') }}:</label>
|
||||
<select v-model="filterSkillRequired">
|
||||
<option value="">{{ $t('all') || 'All' }}</option>
|
||||
<option v-for="skill in availableSkillsRequired" :key="skill" :value="skill">{{ skill }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>{{ $t('weapon.damage') }}:</label>
|
||||
<select v-model="filterDamage">
|
||||
<option value="">{{ $t('all') || 'All' }}</option>
|
||||
<option v-for="dmg in availableDamages" :key="dmg" :value="dmg">{{ dmg }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>{{ $t('weapon.rangenear') }}:</label>
|
||||
<select v-model="filterRangeNear">
|
||||
<option value="">{{ $t('all') || 'All' }}</option>
|
||||
<option v-for="range in availableRangesNear" :key="range" :value="range">{{ range }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>{{ $t('weapon.rangemiddle') }}:</label>
|
||||
<select v-model="filterRangeMiddle">
|
||||
<option value="">{{ $t('all') || 'All' }}</option>
|
||||
<option v-for="range in availableRangesMiddle" :key="range" :value="range">{{ range }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>{{ $t('weapon.rangefar') }}:</label>
|
||||
<select v-model="filterRangeFar">
|
||||
<option value="">{{ $t('all') || 'All' }}</option>
|
||||
<option v-for="range in availableRangesFar" :key="range" :value="range">{{ range }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>{{ $t('weapon.quelle') }}:</label>
|
||||
<select v-model="filterQuelle">
|
||||
<option value="">{{ $t('all') || 'All' }}</option>
|
||||
<option v-for="quelle in availableQuellen" :key="quelle" :value="quelle">{{ quelle }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<button @click="clearFilters" class="btn-clear-filters">{{ $t('clearFilters') || 'Clear Filters' }}</button>
|
||||
</div>
|
||||
|
||||
<div class="tables-container">
|
||||
<table class="cd-table">
|
||||
<thead>
|
||||
@@ -20,9 +67,13 @@
|
||||
<th class="cd-table-header">{{ $t('weapon.id') }}</th>
|
||||
<!-- <th class="cd-table-header">{{ $t('weapon.category') }}<button @click="sortBy('category')">-{{ sortField === 'category' ? (sortAsc ? '↑' : '↓') : '' }}</button></th> -->
|
||||
<th class="cd-table-header">{{ $t('weapon.name') }} <button @click="sortBy('name')">-{{ sortField === 'name' ? (sortAsc ? '↑' : '↓') : '' }}</button></th>
|
||||
<th class="cd-table-header">{{ $t('weapon.skillrequired') || 'Skill Required' }}</th>
|
||||
<th class="cd-table-header">{{ $t('weapon.weight') }}</th>
|
||||
<th class="cd-table-header">{{ $t('weapon.value') }}</th>
|
||||
<th class="cd-table-header">{{ $t('weapon.damage') }}</th>
|
||||
<th class="cd-table-header">{{ $t('weapon.rangenear') || 'Range Near' }}</th>
|
||||
<th class="cd-table-header">{{ $t('weapon.rangemiddle') || 'Range Middle' }}</th>
|
||||
<th class="cd-table-header">{{ $t('weapon.rangefar') || 'Range Far' }}</th>
|
||||
<th class="cd-table-header">{{ $t('weapon.description') }}</th>
|
||||
<th class="cd-table-header">{{ $t('weapon.quelle') }}</th>
|
||||
<th class="cd-table-header">{{ $t('weapon.personal_item') }}</th>
|
||||
@@ -34,39 +85,121 @@
|
||||
<template v-for="(dtaItem, index) in filteredAndSortedWeaponss" :key="dtaItem.id">
|
||||
<tr v-if="editingIndex !== index">
|
||||
<td>{{ dtaItem.id || '' }}</td>
|
||||
<!-- <td>{{ dtaItem.category|| '-' }}</td> -->
|
||||
<td>{{ dtaItem.name || '-' }}</td>
|
||||
<td>{{ dtaItem.skill_required || '-' }}</td>
|
||||
<td>{{ dtaItem.gewicht || '-' }}</td>
|
||||
<td>{{ dtaItem.wert || '-' }}</td>
|
||||
<td>{{ dtaItem.damage || '-' }}</td>
|
||||
<td>{{ dtaItem.range_near || '-' }}</td>
|
||||
<td>{{ dtaItem.range_middle || '-' }}</td>
|
||||
<td>{{ dtaItem.range_far || '-' }}</td>
|
||||
<td>{{ dtaItem.beschreibung || '-' }}</td>
|
||||
<td>{{ dtaItem.quelle || '-' }}</td>
|
||||
<td>{{ dtaItem.personal_item || '0' }}</td>
|
||||
<td>{{ formatQuelle(dtaItem) }}</td>
|
||||
<td><input type="checkbox" :checked="dtaItem.personal_item" disabled /></td>
|
||||
<td>{{ dtaItem.system || 'midgard' }}</td>
|
||||
<td>
|
||||
<button @click="startEdit(index)">Edit</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Edit Mode -->
|
||||
<tr v-else>
|
||||
<td><input v-model="editedItem.id" style="width:20px;"/></td>
|
||||
<!-- <td><select v-model="editedItem.category" style="width:80px;">
|
||||
<option v-for="category in mdata['weaponscategories']"
|
||||
:key="category"
|
||||
:value="category">
|
||||
{{ category }}
|
||||
</option>
|
||||
</select></td> -->
|
||||
<td><input v-model="editedItem.name"/></td>
|
||||
<td><input v-model.number="editedItem.gewicht" type="number" style="width:40px;"/></td>
|
||||
<td><input v-model="editedItem.wert" /></td>
|
||||
<td><input v-model="editedItem.damage" /></td>
|
||||
<td><input v-model="editedItem.beschreibung" /></td>
|
||||
<td><input v-model="editedItem.quelle" style="width:80px;"/></td>
|
||||
<td><input type="checkbox" :checked="true" v-model="editedItem.personal_item" style="width:50px;"/></td>
|
||||
<td><input v-model="editedItem.system" style="width:80px;"/></td>
|
||||
<td>
|
||||
<button @click="saveEdit(index)">Save</button>
|
||||
<button @click="cancelEdit">Cancel</button>
|
||||
<td><input v-model="editedItem.id" style="width:20px;" disabled /></td>
|
||||
<td colspan="11">
|
||||
<!-- Expanded edit form -->
|
||||
<div class="edit-form">
|
||||
<div class="edit-row">
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.name') }}:</label>
|
||||
<input v-model="editedItem.name" />
|
||||
</div>
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.skillrequired') || 'Skill Required' }}:</label>
|
||||
<input v-model="editedItem.skill_required" style="width:150px;" />
|
||||
</div>
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.weight') }}:</label>
|
||||
<input v-model.number="editedItem.gewicht" type="number" style="width:80px;" />
|
||||
</div>
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.value') }}:</label>
|
||||
<input v-model="editedItem.wert" style="width:100px;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="edit-row">
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.damage') }}:</label>
|
||||
<input v-model="editedItem.damage" style="width:100px;" />
|
||||
</div>
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.rangenear') || 'Range Near' }}:</label>
|
||||
<input v-model.number="editedItem.range_near" type="number" style="width:80px;" />
|
||||
</div>
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.rangemiddle') || 'Range Middle' }}:</label>
|
||||
<input v-model.number="editedItem.range_middle" type="number" style="width:80px;" />
|
||||
</div>
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.rangefar') || 'Range Far' }}:</label>
|
||||
<input v-model.number="editedItem.range_far" type="number" style="width:80px;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="edit-row">
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.bonusskill') || 'Bonus' }}:</label>
|
||||
<select v-model="editedItem.bonuseigenschaft" style="width:80px;">
|
||||
<option value="">-</option>
|
||||
<option value="St">St</option>
|
||||
<option value="Gs">Gs</option>
|
||||
<option value="Gw">Gw</option>
|
||||
<option value="Ko">Ko</option>
|
||||
<option value="In">In</option>
|
||||
<option value="Zt">Zt</option>
|
||||
<option value="Au">Au</option>
|
||||
<option value="pA">pA</option>
|
||||
<option value="Wk">Wk</option>
|
||||
<option value="B">B</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.personal_item') }}:</label>
|
||||
<input type="checkbox" v-model="editedItem.personal_item" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="edit-row">
|
||||
<div class="edit-field full-width">
|
||||
<label>{{ $t('weapon.description') }}:</label>
|
||||
<input v-model="editedItem.beschreibung" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="edit-row">
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.quelle') }}:</label>
|
||||
<select v-model="editedItem.sourceCode" style="width:100px;">
|
||||
<option value="">-</option>
|
||||
<option v-for="source in availableSources" :key="source.code" :value="source.code">
|
||||
{{ source.code }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.page') || 'Page' }}:</label>
|
||||
<input v-model.number="editedItem.page_number" type="number" style="width:60px;" />
|
||||
</div>
|
||||
<div class="edit-field">
|
||||
<label>{{ $t('weapon.system') }}:</label>
|
||||
<input v-model="editedItem.system" style="width:100px;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="edit-actions">
|
||||
<button @click="saveEdit(index)" class="btn-save">Save</button>
|
||||
<button @click="cancelEdit" class="btn-cancel">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
@@ -141,82 +274,214 @@ export default {
|
||||
sortField: 'name',
|
||||
sortAsc: true,
|
||||
editingIndex: -1,
|
||||
editedItem: null
|
||||
editedItem: null,
|
||||
filterSkillRequired: '',
|
||||
filterDamage: '',
|
||||
filterRangeNear: '',
|
||||
filterRangeMiddle: '',
|
||||
filterRangeFar: '',
|
||||
filterQuelle: '',
|
||||
enhancedWeapons: [],
|
||||
availableSources: []
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.loadEnhancedWeapons()
|
||||
},
|
||||
computed: {
|
||||
filteredAndSortedWeaponss() {
|
||||
if (!this.mdata?.weapons) return [];
|
||||
|
||||
return [...this.mdata.weapons]
|
||||
.filter(weapons => {
|
||||
const searchLower = this.searchTerm.toLowerCase();
|
||||
return !this.searchTerm ||
|
||||
weapons.name?.toLowerCase().includes(searchLower)
|
||||
//|| weapons.category?.toLowerCase().includes(searchLower);
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const aValue = (a[this.sortField] || '').toLowerCase();
|
||||
const bValue = (b[this.sortField] || '').toLowerCase();
|
||||
return this.sortAsc
|
||||
? aValue.localeCompare(bValue)
|
||||
: bValue.localeCompare(aValue);
|
||||
});
|
||||
availableSkillsRequired() {
|
||||
const skills = new Set()
|
||||
this.enhancedWeapons.forEach(w => {
|
||||
if (w.skill_required) skills.add(w.skill_required)
|
||||
})
|
||||
return Array.from(skills).sort()
|
||||
},
|
||||
sortedWeaponss() {
|
||||
return [...this.mdata.weapons].sort((a, b) => {
|
||||
const aValue = (a[this.sortField] || '').toLowerCase();
|
||||
const bValue = (b[this.sortField] || '').toLowerCase();
|
||||
return this.sortAsc
|
||||
? aValue.localeCompare(bValue)
|
||||
: bValue.localeCompare(aValue);
|
||||
});
|
||||
availableDamages() {
|
||||
const damages = new Set()
|
||||
this.enhancedWeapons.forEach(w => {
|
||||
if (w.damage) damages.add(w.damage)
|
||||
})
|
||||
return Array.from(damages).sort()
|
||||
},
|
||||
availableRangesNear() {
|
||||
const ranges = new Set()
|
||||
this.enhancedWeapons.forEach(w => {
|
||||
if (w.range_near !== null && w.range_near !== undefined) ranges.add(w.range_near)
|
||||
})
|
||||
return Array.from(ranges).sort((a, b) => a - b)
|
||||
},
|
||||
availableRangesMiddle() {
|
||||
const ranges = new Set()
|
||||
this.enhancedWeapons.forEach(w => {
|
||||
if (w.range_middle !== null && w.range_middle !== undefined) ranges.add(w.range_middle)
|
||||
})
|
||||
return Array.from(ranges).sort((a, b) => a - b)
|
||||
},
|
||||
availableRangesFar() {
|
||||
const ranges = new Set()
|
||||
this.enhancedWeapons.forEach(w => {
|
||||
if (w.range_far !== null && w.range_far !== undefined) ranges.add(w.range_far)
|
||||
})
|
||||
return Array.from(ranges).sort((a, b) => a - b)
|
||||
},
|
||||
availableQuellen() {
|
||||
const quellen = new Set()
|
||||
this.enhancedWeapons.forEach(w => {
|
||||
if (w.source_id && this.availableSources.length > 0) {
|
||||
const source = this.availableSources.find(s => s.id === w.source_id)
|
||||
if (source) {
|
||||
quellen.add(source.code)
|
||||
}
|
||||
}
|
||||
})
|
||||
return Array.from(quellen).sort()
|
||||
},
|
||||
filteredAndSortedWeaponss() {
|
||||
let filtered = [...this.enhancedWeapons]
|
||||
|
||||
// Apply search filter
|
||||
if (this.searchTerm) {
|
||||
const searchLower = this.searchTerm.toLowerCase()
|
||||
filtered = filtered.filter(w =>
|
||||
w.name?.toLowerCase().includes(searchLower) ||
|
||||
w.skill_required?.toLowerCase().includes(searchLower)
|
||||
)
|
||||
}
|
||||
|
||||
// Apply skill_required filter
|
||||
if (this.filterSkillRequired) {
|
||||
filtered = filtered.filter(w => w.skill_required === this.filterSkillRequired)
|
||||
}
|
||||
|
||||
// Apply damage filter
|
||||
if (this.filterDamage) {
|
||||
filtered = filtered.filter(w => w.damage === this.filterDamage)
|
||||
}
|
||||
|
||||
// Apply range_near filter
|
||||
if (this.filterRangeNear !== '') {
|
||||
filtered = filtered.filter(w => w.range_near === this.filterRangeNear)
|
||||
}
|
||||
|
||||
// Apply range_middle filter
|
||||
if (this.filterRangeMiddle !== '') {
|
||||
filtered = filtered.filter(w => w.range_middle === this.filterRangeMiddle)
|
||||
}
|
||||
|
||||
// Apply range_far filter
|
||||
if (this.filterRangeFar !== '') {
|
||||
filtered = filtered.filter(w => w.range_far === this.filterRangeFar)
|
||||
}
|
||||
|
||||
// Apply Quelle filter (only by source code, ignoring page number)
|
||||
if (this.filterQuelle) {
|
||||
filtered = filtered.filter(w => {
|
||||
if (w.source_id && this.availableSources.length > 0) {
|
||||
const source = this.availableSources.find(s => s.id === w.source_id)
|
||||
return source && source.code === this.filterQuelle
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
// Apply sorting
|
||||
filtered.sort((a, b) => {
|
||||
const aValue = (a[this.sortField] || '').toString().toLowerCase()
|
||||
const bValue = (b[this.sortField] || '').toString().toLowerCase()
|
||||
return this.sortAsc ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue)
|
||||
})
|
||||
|
||||
return filtered
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
startEdit(index) {
|
||||
this.editingIndex = index;
|
||||
this.editedItem = { ...this.filteredAndSortedWeaponss[index] };
|
||||
async loadEnhancedWeapons() {
|
||||
try {
|
||||
const response = await API.get('/api/maintenance/weapons-enhanced')
|
||||
this.enhancedWeapons = response.data.weapons || []
|
||||
this.availableSources = response.data.sources || []
|
||||
} catch (error) {
|
||||
console.error('Failed to load enhanced weapons:', error)
|
||||
}
|
||||
},
|
||||
saveEdit(index) {
|
||||
//this.$emit('update-weapons', { index, weapons: this.editedItem });
|
||||
this.handleWeaponsUpdate( { index, weapons: this.editedItem });
|
||||
this.editingIndex = -1;
|
||||
this.editedItem = null;
|
||||
startEdit(index) {
|
||||
const weapon = this.filteredAndSortedWeaponss[index]
|
||||
this.editedItem = {
|
||||
...weapon,
|
||||
sourceCode: this.getSourceCode(weapon.source_id)
|
||||
}
|
||||
this.editingIndex = index
|
||||
},
|
||||
async saveEdit(index) {
|
||||
try {
|
||||
// Find source ID from code
|
||||
const source = this.availableSources.find(s => s.code === this.editedItem.sourceCode)
|
||||
|
||||
const updateData = {
|
||||
...this.editedItem,
|
||||
source_id: source ? source.id : null,
|
||||
page_number: this.editedItem.page_number || 0
|
||||
}
|
||||
|
||||
const response = await API.put(
|
||||
`/api/maintenance/weapons-enhanced/${this.editedItem.id}`,
|
||||
updateData
|
||||
)
|
||||
|
||||
// Update the weapon in the list using splice for proper reactivity
|
||||
const weaponIndex = this.enhancedWeapons.findIndex(w => w.id === this.editedItem.id)
|
||||
if (weaponIndex !== -1) {
|
||||
this.enhancedWeapons.splice(weaponIndex, 1, response.data)
|
||||
}
|
||||
|
||||
this.editingIndex = -1
|
||||
this.editedItem = null
|
||||
} catch (error) {
|
||||
console.error('Failed to save weapon:', error)
|
||||
alert('Failed to save weapon: ' + (error.response?.data?.error || error.message))
|
||||
}
|
||||
},
|
||||
cancelEdit() {
|
||||
this.editingIndex = -1;
|
||||
this.editedItem = null;
|
||||
this.editingIndex = -1
|
||||
this.editedItem = null
|
||||
},
|
||||
sortBy(field) {
|
||||
if (this.sortField === field) {
|
||||
this.sortAsc = !this.sortAsc;
|
||||
this.sortAsc = !this.sortAsc
|
||||
} else {
|
||||
this.sortField = field;
|
||||
this.sortAsc = true;
|
||||
this.sortField = field
|
||||
this.sortAsc = true
|
||||
}
|
||||
},
|
||||
async handleWeaponsUpdate({ index, weapons }) {
|
||||
try {
|
||||
const response = await API.put(
|
||||
`/api/maintenance/weapons/${weapons.id}`, weapons,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem('token')}` ,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
)
|
||||
if (response.status !== 200) throw new Error('Update failed');
|
||||
const updatedSkill = response.data;
|
||||
// Update the weapons in mdata
|
||||
this.mdata.weapons = this.mdata.weapons.map(s =>
|
||||
s.id === updatedSkill.id ? updatedSkill : s
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to update weapons:', error);
|
||||
formatQuelle(weapon) {
|
||||
if (weapon.source_id && this.availableSources.length > 0) {
|
||||
const source = this.availableSources.find(s => s.id === weapon.source_id)
|
||||
if (source) {
|
||||
if (weapon.page_number) {
|
||||
return `${source.code}:${weapon.page_number}`
|
||||
} else {
|
||||
// No page number - show code and quelle if available
|
||||
const quelle = weapon.quelle ? ` (${weapon.quelle})` : ''
|
||||
return `${source.code}${quelle}`
|
||||
}
|
||||
}
|
||||
}
|
||||
return weapon.quelle || '-'
|
||||
},
|
||||
getSourceCode(sourceId) {
|
||||
if (!sourceId || !this.availableSources.length) return ''
|
||||
const source = this.availableSources.find(s => s.id === sourceId)
|
||||
return source ? source.code : ''
|
||||
},
|
||||
clearFilters() {
|
||||
this.searchTerm = ''
|
||||
this.filterSkillRequired = ''
|
||||
this.filterDamage = ''
|
||||
this.filterRangeNear = ''
|
||||
this.filterRangeMiddle = ''
|
||||
this.filterRangeFar = ''
|
||||
this.filterQuelle = ''
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -107,6 +107,7 @@ export default {
|
||||
improvable:'verbesserbar',
|
||||
category:'Kategorie',
|
||||
initialwert:'Startwert',
|
||||
difficulty:'Schwierigkeit',
|
||||
},
|
||||
spell:{
|
||||
id:'ID',
|
||||
@@ -169,6 +170,11 @@ export default {
|
||||
personal_item:'Pers',
|
||||
quelle:'Quelle',
|
||||
system:'System',
|
||||
skillrequired:'Waffenfertigkeit',
|
||||
rangenear:'Reichweite Nah',
|
||||
rangemiddle:'Reichweite Mittel',
|
||||
rangefar:'Reichweite Fern',
|
||||
page:'Seite',
|
||||
add: 'Waffe hinzufügen',
|
||||
addWeapon: 'Waffe hinzufügen',
|
||||
search: 'Suche',
|
||||
|
||||
@@ -166,6 +166,11 @@ export default {
|
||||
personal_item:'Pers',
|
||||
quelle:'Source',
|
||||
system:'System',
|
||||
skillrequired:'Weapon Skill',
|
||||
rangenear:'Range Near',
|
||||
rangemiddle:'Range Middle',
|
||||
rangefar:'Range Far',
|
||||
page:'Page',
|
||||
add: 'Add Weapon',
|
||||
addWeapon: 'Add Weapon',
|
||||
search: 'Search',
|
||||
|
||||
Reference in New Issue
Block a user