Refactor SaleSection component: Simplify sell item and sell all logic, remove unnecessary state management, and improve UI feedback. Update translations and clean up unused code in i18n files. Optimize price loading in BranchView and remove legacy product loading in MoneyHistoryView. Streamline PoliticsView by removing own character ID handling and related logic.

This commit is contained in:
Torsten Schulz (local)
2026-01-26 16:03:48 +01:00
parent 80b639b511
commit 71748f6aa0
15 changed files with 822 additions and 3815 deletions

View File

@@ -104,14 +104,6 @@
/>
{{ $t('falukant.branch.director.starttransport') }}
</label>
<label>
<input
type="checkbox"
v-model="director.mayRepairVehicles"
@change="saveSetting('mayRepairVehicles', director.mayRepairVehicles)"
/>
{{ $t('falukant.branch.director.repairVehicles') }}
</label>
</div>
<div class="field">
@@ -181,7 +173,7 @@
</div>
</div>
</div>
<NewDirectorDialog ref="newDirectorDialog" @directorHired="handleDirectorHired" />
<NewDirectorDialog ref="newDirectorDialog" />
</template>
<script>
@@ -276,11 +268,6 @@ export default {
this.$refs.newDirectorDialog.open(this.branchId);
},
async handleDirectorHired() {
// Nach dem Einstellen eines Direktors die Daten neu laden
await this.loadDirector();
},
async updateDirector() {
if (!this.director || this.editIncome == null) return;
try {

File diff suppressed because it is too large Load Diff

View File

@@ -20,10 +20,8 @@
<td>{{ item.quality }}</td>
<td>{{ item.totalQuantity }}</td>
<td>
<input type="number" v-model.number="item.sellQuantity" :min="1" :max="item.totalQuantity" :disabled="sellingItemIndex === index" />
<button @click="sellItem(index)" :disabled="sellingItemIndex === index || sellingAll">
{{ sellingItemIndex === index ? $t('falukant.branch.sale.selling') : $t('falukant.branch.sale.sellButton') }}
</button>
<input type="number" v-model.number="item.sellQuantity" :min="1" :max="item.totalQuantity" />
<button @click="sellItem(index)">{{ $t('falukant.branch.sale.sellButton') }}</button>
</td>
<td>
<div v-if="item.betterPrices && item.betterPrices.length > 0" class="price-cities">
@@ -38,12 +36,7 @@
</tr>
</tbody>
</table>
<button @click="sellAll" :disabled="sellingAll || sellingItemIndex !== null">
{{ sellingAll ? $t('falukant.branch.sale.selling') : $t('falukant.branch.sale.sellAllButton') }}
</button>
<div v-if="sellAllStatus" class="sell-all-status" :class="sellAllStatus.type">
{{ sellAllStatus.message }}
</div>
<button @click="sellAll">{{ $t('falukant.branch.sale.sellAllButton') }}</button>
</div>
<div v-else>
<p>{{ $t('falukant.branch.sale.noInventory') }}</p>
@@ -190,9 +183,6 @@
data() {
return {
inventory: [],
sellingItemIndex: null,
sellingAll: false,
sellAllStatus: null,
transportForm: {
sourceKey: null,
vehicleTypeId: null,
@@ -261,6 +251,13 @@
return new Date(a.eta).getTime() - new Date(b.eta).getTime();
});
},
speedLabel(value) {
const key = value == null ? 'unknown' : String(value);
const tKey = `falukant.branch.transport.speed.${key}`;
const translated = this.$t(tKey);
if (!translated || translated === tKey) return value;
return translated;
},
},
async mounted() {
await this.loadInventory();
@@ -277,22 +274,12 @@
}
},
methods: {
speedLabel(value) {
// Muss in methods liegen (Vue3): in computed wäre es ein Getter und keine aufrufbare Funktion.
const key = value == null ? 'unknown' : String(value);
const tKey = `falukant.branch.transport.speed.${key}`;
const translated = this.$t(tKey);
if (!translated || translated === tKey) return value;
return translated;
},
async loadInventory() {
try {
const response = await apiClient.get(`/api/falukant/inventory/${this.branchId}`);
this.inventory = response.data.map(item => ({
...item,
sellQuantity: item.totalQuantity,
// Vue3: besserPrices direkt als Property setzen (statt this.$set)
betterPrices: Array.isArray(item.betterPrices) ? item.betterPrices : [],
}));
await this.loadPricesForInventory();
} catch (error) {
@@ -313,11 +300,10 @@
currentPrice: currentPrice
}
});
// Vue3: direkte Zuweisung ist reaktiv
item.betterPrices = Array.isArray(data) ? data : [];
this.$set(item, 'betterPrices', data || []);
} catch (error) {
console.error(`Error loading prices for item ${itemKey}:`, error);
item.betterPrices = [];
this.$set(item, 'betterPrices', []);
} finally {
this.loadingPrices.delete(itemKey);
}
@@ -334,61 +320,23 @@
maximumFractionDigits: 2,
}).format(price);
},
async sellItem(index) {
if (this.sellingItemIndex !== null || this.sellingAll) return;
sellItem(index) {
const item = this.inventory[index];
const quantityToSell = item.sellQuantity || item.totalQuantity;
this.sellingItemIndex = index;
try {
await apiClient.post(`/api/falukant/sell`, {
branchId: this.branchId,
productId: item.product.id,
quantity: quantityToSell,
quality: item.quality,
});
// UI sofort freigeben (Label/Disabled zurücksetzen), dann Inventory refreshen
this.sellingItemIndex = null;
await this.loadInventory();
} catch (error) {
apiClient.post(`/api/falukant/sell`, {
branchId: this.branchId,
productId: item.product.id,
quantity: quantityToSell,
quality: item.quality,
}).catch(() => {
alert(this.$t('falukant.branch.sale.sellError'));
} finally {
this.sellingItemIndex = null;
}
});
},
async sellAll() {
if (this.sellingAll || this.sellingItemIndex !== null) return;
this.sellingAll = true;
this.sellAllStatus = null;
try {
const response = await apiClient.post(`/api/falukant/sell/all`, { branchId: this.branchId });
const revenue = response.data?.revenue || 0;
// UI sofort freigeben + Status setzen, danach Inventory refreshen
this.sellingAll = false;
this.sellAllStatus = {
type: 'success',
message: this.$t('falukant.branch.sale.sellAllSuccess', { revenue: this.formatMoney(revenue) })
};
// Inventory neu laden nach erfolgreichem Verkauf
await this.loadInventory();
} catch (error) {
// UI sofort freigeben + Fehlerstatus setzen
this.sellingAll = false;
this.sellAllStatus = {
type: 'error',
message: this.$t('falukant.branch.sale.sellAllError')
};
} finally {
// Falls noch nicht freigegeben (z.B. wenn ein unerwarteter Fehler vor Response passiert)
this.sellingAll = false;
// Status nach 5 Sekunden löschen
setTimeout(() => {
this.sellAllStatus = null;
}, 5000);
}
sellAll() {
apiClient.post(`/api/falukant/sell/all`, { branchId: this.branchId })
.catch(() => {
alert(this.$t('falukant.branch.sale.sellAllError'));
});
},
inventoryOptions() {
return this.inventory.map((item, index) => ({
@@ -627,11 +575,11 @@
cursor: help;
}
.city-price-green {
background-color: var(--color-primary-green);
background-color: #90EE90;
color: #000;
}
.city-price-orange {
background-color: var(--color-primary-orange);
background-color: #FFA500;
color: #000;
}
.city-price-red {
@@ -642,19 +590,5 @@
color: #999;
font-style: italic;
}
.sell-all-status {
margin-top: 10px;
padding: 8px;
border-radius: 4px;
}
.sell-all-status.success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.sell-all-status.error {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
</style>