Add product price retrieval feature in cities
- Implemented a new endpoint in FalukantController to fetch product prices in various cities based on product ID and current price. - Developed the corresponding service method in FalukantService to calculate and return prices, considering user knowledge and city branches. - Updated frontend components (RevenueSection and SaleSection) to display better prices for products, including loading logic and UI enhancements for price visibility. - Added styling for price indicators based on branch types to improve user experience.
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
<th>{{ $t('falukant.branch.revenue.perMinute') }}</th>
|
||||
<th>{{ $t('falukant.branch.revenue.profitAbsolute') }}</th>
|
||||
<th>{{ $t('falukant.branch.revenue.profitPerMinute') }}</th>
|
||||
<th>Bessere Preise</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -26,6 +27,16 @@
|
||||
<td>{{ calculateProductRevenue(product).perMinute }}</td>
|
||||
<td>{{ calculateProductProfit(product).absolute }}</td>
|
||||
<td>{{ calculateProductProfit(product).perMinute }}</td>
|
||||
<td>
|
||||
<div v-if="product.betterPrices && product.betterPrices.length > 0" class="price-cities">
|
||||
<span v-for="city in product.betterPrices" :key="city.regionId"
|
||||
:class="['city-price', getCityPriceClass(city.branchType)]"
|
||||
:title="`${city.regionName}: ${formatPrice(city.price)}`">
|
||||
{{ city.regionName }}
|
||||
</span>
|
||||
</div>
|
||||
<span v-else class="no-better-prices">—</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -34,6 +45,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import apiClient from '@/utils/axios.js';
|
||||
|
||||
export default {
|
||||
name: "RevenueSection",
|
||||
props: {
|
||||
@@ -44,6 +57,7 @@
|
||||
data() {
|
||||
return {
|
||||
isRevenueTableOpen: false,
|
||||
loadingPrices: new Set(),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -56,9 +70,64 @@
|
||||
}, null);
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
if (this.isRevenueTableOpen) {
|
||||
await this.loadPricesForAllProducts();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isRevenueTableOpen(newVal) {
|
||||
if (newVal) {
|
||||
this.loadPricesForAllProducts();
|
||||
}
|
||||
},
|
||||
products: {
|
||||
handler() {
|
||||
if (this.isRevenueTableOpen) {
|
||||
this.loadPricesForAllProducts();
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleRevenueTable() {
|
||||
this.isRevenueTableOpen = !this.isRevenueTableOpen;
|
||||
if (this.isRevenueTableOpen) {
|
||||
this.loadPricesForAllProducts();
|
||||
}
|
||||
},
|
||||
async loadPricesForAllProducts() {
|
||||
for (const product of this.products) {
|
||||
if (this.loadingPrices.has(product.id)) continue;
|
||||
this.loadingPrices.add(product.id);
|
||||
try {
|
||||
const currentPrice = parseFloat(this.calculateProductRevenue(product).absolute);
|
||||
const { data } = await apiClient.get('/api/falukant/products/prices-in-cities', {
|
||||
params: {
|
||||
productId: product.id,
|
||||
currentPrice: currentPrice
|
||||
}
|
||||
});
|
||||
this.$set(product, 'betterPrices', data || []);
|
||||
} catch (error) {
|
||||
console.error(`Error loading prices for product ${product.id}:`, error);
|
||||
this.$set(product, 'betterPrices', []);
|
||||
} finally {
|
||||
this.loadingPrices.delete(product.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
getCityPriceClass(branchType) {
|
||||
if (branchType === 'store') return 'city-price-green';
|
||||
if (branchType === 'production') return 'city-price-orange';
|
||||
return 'city-price-red';
|
||||
},
|
||||
formatPrice(price) {
|
||||
return new Intl.NumberFormat(navigator.language, {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
}).format(price);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -94,5 +163,32 @@
|
||||
.highlight {
|
||||
background-color: #dfffd6;
|
||||
}
|
||||
.price-cities {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.3em;
|
||||
}
|
||||
.city-price {
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 3px;
|
||||
font-size: 0.85em;
|
||||
cursor: help;
|
||||
}
|
||||
.city-price-green {
|
||||
background-color: #90EE90;
|
||||
color: #000;
|
||||
}
|
||||
.city-price-orange {
|
||||
background-color: #FFA500;
|
||||
color: #000;
|
||||
}
|
||||
.city-price-red {
|
||||
background-color: #FF6B6B;
|
||||
color: #fff;
|
||||
}
|
||||
.no-better-prices {
|
||||
color: #999;
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user