Refactor FalukantService and SaleSection components: Optimize product and knowledge retrieval by using Promise.all for concurrent database queries, improving performance. Additionally, reorganize the speedLabel method for better readability and maintainability, ensuring accurate localization handling for transport speed values.

This commit is contained in:
Torsten Schulz (local)
2026-01-29 15:20:38 +01:00
parent 1839c3c57b
commit c5ab17ad99
2 changed files with 55 additions and 74 deletions

View File

@@ -4445,79 +4445,61 @@ class FalukantService extends BaseService {
throw new Error(`No FalukantCharacter found for user with id ${user.id}`); throw new Error(`No FalukantCharacter found for user with id ${user.id}`);
} }
// Produkt abrufen const [product, knowledge, cities, townWorths] = await Promise.all([
const product = await ProductType.findOne({ where: { id: productId } }); ProductType.findOne({ where: { id: productId } }),
Knowledge.findOne({
where: { characterId: character.id, productId: productId }
}),
RegionData.findAll({
attributes: ['id', 'name'],
include: [
{
model: RegionType,
as: 'regionType',
where: { labelTr: 'city' },
attributes: ['labelTr']
},
{
model: Branch,
as: 'branches',
where: { falukantUserId: user.id },
include: [
{
model: BranchType,
as: 'branchType',
attributes: ['labelTr']
}
],
attributes: ['branchTypeId'],
required: false
}
]
}),
TownProductWorth.findAll({
where: { productId: productId },
attributes: ['regionId', 'worthPercent']
})
]);
if (!product) { if (!product) {
throw new Error(`Product not found with id ${productId}`); throw new Error(`Product not found with id ${productId}`);
} }
// Knowledge für dieses Produkt abrufen
const knowledge = await Knowledge.findOne({
where: { characterId: character.id, productId: productId }
});
const knowledgeFactor = knowledge?.knowledge || 0; const knowledgeFactor = knowledge?.knowledge || 0;
// Alle Städte abrufen
const cities = await RegionData.findAll({
attributes: ['id', 'name'],
include: [
{
model: RegionType,
as: 'regionType',
where: { labelTr: 'city' },
attributes: ['labelTr']
},
{
model: Branch,
as: 'branches',
where: { falukantUserId: user.id },
include: [
{
model: BranchType,
as: 'branchType',
attributes: ['labelTr']
}
],
attributes: ['branchTypeId'],
required: false
}
]
});
// TownProductWorth für alle Städte und dieses Produkt einmalig abrufen
// (vermeidet N+1 Query Problem)
const townWorths = await TownProductWorth.findAll({
where: { productId: productId },
attributes: ['regionId', 'worthPercent']
});
const worthMap = new Map(townWorths.map(tw => [tw.regionId, tw.worthPercent])); const worthMap = new Map(townWorths.map(tw => [tw.regionId, tw.worthPercent]));
// Berechne den regionalen Preis für die aktuelle Region (falls angegeben) let currentRegionalPrice = currentPrice;
// WICHTIG: Ignoriere den übergebenen currentPrice, da er möglicherweise nicht
// den regionalen Faktor berücksichtigt. Berechne stattdessen immer den korrekten
// regionalen Preis basierend auf currentRegionId.
let currentRegionalPrice = currentPrice; // Fallback auf übergebenen Preis
if (currentRegionId) { if (currentRegionId) {
const currentWorthPercent = worthMap.get(currentRegionId) || 50; const currentWorthPercent = worthMap.get(currentRegionId) || 50;
// Verwende calcRegionalSellPrice mit bereits geladenem worthPercent (keine DB-Query) currentRegionalPrice = calcRegionalSellPriceSync(product, knowledgeFactor, currentWorthPercent) ?? currentPrice;
currentRegionalPrice = await calcRegionalSellPrice(product, knowledgeFactor, currentRegionId, currentWorthPercent);
} }
// Für jede Stadt den Preis berechnen und Branch-Typ bestimmen
const results = []; const results = [];
const PRICE_TOLERANCE = 0.01;
for (const city of cities) { for (const city of cities) {
// Aktuelle Stadt ausschließen if (currentRegionId && city.id === currentRegionId) continue;
if (currentRegionId && city.id === currentRegionId) {
continue;
}
const worthPercent = worthMap.get(city.id) || 50; const worthPercent = worthMap.get(city.id) || 50;
// Verwende calcRegionalSellPrice mit bereits geladenem worthPercent (keine DB-Query) const priceInCity = calcRegionalSellPriceSync(product, knowledgeFactor, worthPercent);
const priceInCity = await calcRegionalSellPrice(product, knowledgeFactor, city.id, worthPercent); if (priceInCity == null) continue;
// Nur Städte zurückgeben, wo der Preis höher ist
// Kleine Toleranz (0.01) für Rundungsfehler bei Gleitkommaberechnungen
const PRICE_TOLERANCE = 0.01;
if (priceInCity > currentRegionalPrice - PRICE_TOLERANCE) { if (priceInCity > currentRegionalPrice - PRICE_TOLERANCE) {
// Branch-Typ bestimmen // Branch-Typ bestimmen
let branchType = null; // null = kein Branch let branchType = null; // null = kein Branch

View File

@@ -252,20 +252,6 @@
}); });
}, },
}, },
methods: {
speedLabel(value) {
if (value == null) return this.$t('falukant.branch.transport.speed.unknown') || '—';
if (typeof value === 'object') {
const k = value.tr ?? value.id ?? 'unknown';
const tKey = `falukant.branch.transport.speed.${k}`;
const t = this.$t(tKey);
return (t && t !== tKey) ? t : String(k);
}
const key = String(value);
const tKey = `falukant.branch.transport.speed.${key}`;
const translated = this.$t(tKey);
return (!translated || translated === tKey) ? key : translated;
},
async mounted() { async mounted() {
await this.loadInventory(); await this.loadInventory();
await this.loadTransports(); await this.loadTransports();
@@ -281,6 +267,19 @@
} }
}, },
methods: { methods: {
speedLabel(value) {
if (value == null) return this.$t('falukant.branch.transport.speed.unknown') || '—';
if (typeof value === 'object') {
const k = value.tr ?? value.id ?? 'unknown';
const tKey = `falukant.branch.transport.speed.${k}`;
const t = this.$t(tKey);
return (t && t !== tKey) ? t : String(k);
}
const key = String(value);
const tKey = `falukant.branch.transport.speed.${key}`;
const translated = this.$t(tKey);
return (!translated || translated === tKey) ? key : translated;
},
async loadInventory() { async loadInventory() {
try { try {
const response = await apiClient.get(`/api/falukant/inventory/${this.branchId}`); const response = await apiClient.get(`/api/falukant/inventory/${this.branchId}`);