Add bulk pricing retrieval for products in region: Implement getAllProductPricesInRegion method in FalukantService, update FalukantController and router to support new endpoint, and modify BranchView to utilize bulk request for improved performance.
This commit is contained in:
@@ -182,6 +182,13 @@ class FalukantController {
|
|||||||
}
|
}
|
||||||
return this.service.getProductPriceInRegion(userId, productId, regionId);
|
return this.service.getProductPriceInRegion(userId, productId, regionId);
|
||||||
});
|
});
|
||||||
|
this.getAllProductPricesInRegion = this._wrapWithUser((userId, req) => {
|
||||||
|
const regionId = parseInt(req.query.regionId, 10);
|
||||||
|
if (Number.isNaN(regionId)) {
|
||||||
|
throw new Error('regionId is required');
|
||||||
|
}
|
||||||
|
return this.service.getAllProductPricesInRegion(userId, regionId);
|
||||||
|
});
|
||||||
this.getProductPricesInCities = this._wrapWithUser((userId, req) => {
|
this.getProductPricesInCities = this._wrapWithUser((userId, req) => {
|
||||||
const productId = parseInt(req.query.productId, 10);
|
const productId = parseInt(req.query.productId, 10);
|
||||||
const currentPrice = parseFloat(req.query.currentPrice);
|
const currentPrice = parseFloat(req.query.currentPrice);
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ router.get('/politics/open', falukantController.getOpenPolitics);
|
|||||||
router.post('/politics/open', falukantController.applyForElections);
|
router.post('/politics/open', falukantController.applyForElections);
|
||||||
router.get('/cities', falukantController.getRegions);
|
router.get('/cities', falukantController.getRegions);
|
||||||
router.get('/products/price-in-region', falukantController.getProductPriceInRegion);
|
router.get('/products/price-in-region', falukantController.getProductPriceInRegion);
|
||||||
|
router.get('/products/prices-in-region', falukantController.getAllProductPricesInRegion);
|
||||||
router.get('/products/prices-in-cities', falukantController.getProductPricesInCities);
|
router.get('/products/prices-in-cities', falukantController.getProductPricesInCities);
|
||||||
router.get('/branches/:branchId/taxes', falukantController.getBranchTaxes);
|
router.get('/branches/:branchId/taxes', falukantController.getBranchTaxes);
|
||||||
router.get('/vehicles/types', falukantController.getVehicleTypes);
|
router.get('/vehicles/types', falukantController.getVehicleTypes);
|
||||||
|
|||||||
@@ -566,7 +566,13 @@ class FalukantService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getBranches(hashedUserId) {
|
async getBranches(hashedUserId) {
|
||||||
|
const startTime = Date.now();
|
||||||
|
console.log(`[getBranches] Start für userId: ${hashedUserId}`);
|
||||||
|
|
||||||
const u = await getFalukantUserOrFail(hashedUserId);
|
const u = await getFalukantUserOrFail(hashedUserId);
|
||||||
|
const userTime = Date.now();
|
||||||
|
console.log(`[getBranches] User geladen in ${userTime - startTime}ms`);
|
||||||
|
|
||||||
const bs = await Branch.findAll({
|
const bs = await Branch.findAll({
|
||||||
where: { falukantUserId: u.id },
|
where: { falukantUserId: u.id },
|
||||||
include: [
|
include: [
|
||||||
@@ -591,6 +597,8 @@ class FalukantService extends BaseService {
|
|||||||
attributes: ['id', 'regionId'],
|
attributes: ['id', 'regionId'],
|
||||||
order: [['branchTypeId', 'ASC']]
|
order: [['branchTypeId', 'ASC']]
|
||||||
});
|
});
|
||||||
|
const branchesTime = Date.now();
|
||||||
|
console.log(`[getBranches] Branches geladen (${bs.length} Stück) in ${branchesTime - userTime}ms`);
|
||||||
|
|
||||||
// Lade Wetter explizit für alle Regionen, um sicherzustellen, dass es korrekt geladen wird
|
// Lade Wetter explizit für alle Regionen, um sicherzustellen, dass es korrekt geladen wird
|
||||||
const regionIds = [...new Set(bs.map(b => b.regionId))];
|
const regionIds = [...new Set(bs.map(b => b.regionId))];
|
||||||
@@ -601,8 +609,10 @@ class FalukantService extends BaseService {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
const weatherMap = new Map(weathers.map(w => [w.regionId, w.weatherType?.tr || null]));
|
const weatherMap = new Map(weathers.map(w => [w.regionId, w.weatherType?.tr || null]));
|
||||||
|
const weatherTime = Date.now();
|
||||||
|
console.log(`[getBranches] Weather geladen in ${weatherTime - branchesTime}ms`);
|
||||||
|
|
||||||
return bs.map(b => {
|
const result = bs.map(b => {
|
||||||
const branchJson = b.toJSON();
|
const branchJson = b.toJSON();
|
||||||
// Verwende das explizit geladene Wetter, falls vorhanden, sonst das aus der Include-Beziehung
|
// Verwende das explizit geladene Wetter, falls vorhanden, sonst das aus der Include-Beziehung
|
||||||
const weather = weatherMap.get(b.regionId) || branchJson.region?.weather?.weatherType?.tr || null;
|
const weather = weatherMap.get(b.regionId) || branchJson.region?.weather?.weatherType?.tr || null;
|
||||||
@@ -612,6 +622,11 @@ class FalukantService extends BaseService {
|
|||||||
weather: weather
|
weather: weather
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const totalTime = Date.now() - startTime;
|
||||||
|
console.log(`[getBranches] Gesamtzeit: ${totalTime}ms für ${result.length} Branches`);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createBranch(hashedUserId, cityId, branchTypeId) {
|
async createBranch(hashedUserId, cityId, branchTypeId) {
|
||||||
@@ -4217,6 +4232,74 @@ class FalukantService extends BaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAllProductPricesInRegion(hashedUserId, regionId) {
|
||||||
|
const startTime = Date.now();
|
||||||
|
console.log(`[getAllProductPricesInRegion] Start für userId: ${hashedUserId}, regionId: ${regionId}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const user = await this.getFalukantUserByHashedId(hashedUserId);
|
||||||
|
const userTime = Date.now();
|
||||||
|
console.log(`[getAllProductPricesInRegion] User geladen in ${userTime - startTime}ms`);
|
||||||
|
|
||||||
|
const character = await FalukantCharacter.findOne({ where: { userId: user.id } });
|
||||||
|
if (!character) {
|
||||||
|
throw new Error(`No FalukantCharacter found for user with id ${user.id}`);
|
||||||
|
}
|
||||||
|
const characterTime = Date.now();
|
||||||
|
console.log(`[getAllProductPricesInRegion] Character geladen in ${characterTime - userTime}ms`);
|
||||||
|
|
||||||
|
// Lade alle Produkte auf einmal
|
||||||
|
const products = await ProductType.findAll({
|
||||||
|
attributes: ['id', 'sellCost']
|
||||||
|
});
|
||||||
|
const productsTime = Date.now();
|
||||||
|
console.log(`[getAllProductPricesInRegion] ${products.length} Produkte geladen in ${productsTime - characterTime}ms`);
|
||||||
|
|
||||||
|
// Lade alle Knowledge-Werte für diesen Character auf einmal
|
||||||
|
const knowledges = await Knowledge.findAll({
|
||||||
|
where: { characterId: character.id },
|
||||||
|
attributes: ['productId', 'knowledge']
|
||||||
|
});
|
||||||
|
const knowledgeMap = new Map(knowledges.map(k => [k.productId, k.knowledge || 0]));
|
||||||
|
const knowledgeTime = Date.now();
|
||||||
|
console.log(`[getAllProductPricesInRegion] ${knowledges.length} Knowledge-Werte geladen in ${knowledgeTime - productsTime}ms`);
|
||||||
|
|
||||||
|
// Lade alle TownProductWorth-Werte für diese Region auf einmal
|
||||||
|
const townWorths = await TownProductWorth.findAll({
|
||||||
|
where: { regionId: regionId },
|
||||||
|
attributes: ['productId', 'worthPercent']
|
||||||
|
});
|
||||||
|
const worthMap = new Map(townWorths.map(tw => [tw.productId, tw.worthPercent || 50]));
|
||||||
|
const worthTime = Date.now();
|
||||||
|
console.log(`[getAllProductPricesInRegion] ${townWorths.length} Worth-Werte geladen in ${worthTime - knowledgeTime}ms`);
|
||||||
|
|
||||||
|
// Berechne Preise für alle Produkte
|
||||||
|
const prices = {};
|
||||||
|
for (const product of products) {
|
||||||
|
if (product.sellCost === null || product.sellCost === undefined) {
|
||||||
|
continue; // Überspringe Produkte ohne sellCost
|
||||||
|
}
|
||||||
|
|
||||||
|
const knowledgeFactor = knowledgeMap.get(product.id) || 0;
|
||||||
|
const worthPercent = worthMap.get(product.id) || 50;
|
||||||
|
|
||||||
|
// Verwende calcRegionalSellPrice mit bereits geladenem worthPercent
|
||||||
|
const price = await calcRegionalSellPrice(product, knowledgeFactor, regionId, worthPercent);
|
||||||
|
prices[product.id] = price;
|
||||||
|
}
|
||||||
|
const calcTime = Date.now();
|
||||||
|
console.log(`[getAllProductPricesInRegion] Preise berechnet in ${calcTime - worthTime}ms`);
|
||||||
|
|
||||||
|
const totalTime = Date.now() - startTime;
|
||||||
|
console.log(`[getAllProductPricesInRegion] Gesamtzeit: ${totalTime}ms für ${Object.keys(prices).length} Produkte`);
|
||||||
|
|
||||||
|
return { prices };
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[getAllProductPricesInRegion] Error for regionId=${regionId}:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async getProductPricesInCities(hashedUserId, productId, currentPrice, currentRegionId = null) {
|
async getProductPricesInCities(hashedUserId, productId, currentPrice, currentRegionId = null) {
|
||||||
const user = await this.getFalukantUserByHashedId(hashedUserId);
|
const user = await this.getFalukantUserByHashedId(hashedUserId);
|
||||||
const character = await FalukantCharacter.findOne({ where: { userId: user.id } });
|
const character = await FalukantCharacter.findOne({ where: { userId: user.id } });
|
||||||
|
|||||||
@@ -572,27 +572,42 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lade Preise für alle Produkte in der aktuellen Region
|
// Lade alle Preise für die Region auf einmal (Bulk-Request)
|
||||||
const prices = {};
|
try {
|
||||||
for (const product of this.products) {
|
const startTime = performance.now();
|
||||||
try {
|
const { data } = await apiClient.get('/api/falukant/products/prices-in-region', {
|
||||||
const { data } = await apiClient.get('/api/falukant/products/price-in-region', {
|
params: {
|
||||||
params: {
|
regionId: this.selectedBranch.regionId
|
||||||
productId: product.id,
|
}
|
||||||
regionId: this.selectedBranch.regionId
|
});
|
||||||
}
|
const loadTime = performance.now() - startTime;
|
||||||
});
|
console.log(`[BranchView] Product prices loaded in ${loadTime.toFixed(2)}ms`);
|
||||||
prices[product.id] = data.price;
|
this.productPricesCache = data.prices || {};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error loading price for product ${product.id}:`, error);
|
console.error(`Error loading product prices for region ${this.selectedBranch.regionId}:`, error);
|
||||||
// Fallback auf Standard-Berechnung
|
// Fallback: Lade Preise einzeln (alte Methode)
|
||||||
const knowledgeFactor = product.knowledges?.[0]?.knowledge || 0;
|
console.warn('[BranchView] Falling back to individual product price requests');
|
||||||
const maxPrice = product.sellCost;
|
const prices = {};
|
||||||
const minPrice = maxPrice * 0.6;
|
for (const product of this.products) {
|
||||||
prices[product.id] = minPrice + (maxPrice - minPrice) * (knowledgeFactor / 100);
|
try {
|
||||||
|
const { data } = await apiClient.get('/api/falukant/products/price-in-region', {
|
||||||
|
params: {
|
||||||
|
productId: product.id,
|
||||||
|
regionId: this.selectedBranch.regionId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
prices[product.id] = data.price;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Error loading price for product ${product.id}:`, err);
|
||||||
|
// Fallback auf Standard-Berechnung
|
||||||
|
const knowledgeFactor = product.knowledges?.[0]?.knowledge || 0;
|
||||||
|
const maxPrice = product.sellCost;
|
||||||
|
const minPrice = maxPrice * 0.6;
|
||||||
|
prices[product.id] = minPrice + (maxPrice - minPrice) * (knowledgeFactor / 100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
this.productPricesCache = prices;
|
||||||
}
|
}
|
||||||
this.productPricesCache = prices;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
formatPercent(value) {
|
formatPercent(value) {
|
||||||
|
|||||||
Reference in New Issue
Block a user