Files
yourpart3/frontend/src/components/falukant/ProductionSection.vue
Torsten Schulz (local) 3aac0476df Add 'sleep' status to Production model and update related components
- Introduced a new 'sleep' boolean field in the Production model to indicate if production is suspended.
- Updated FalukantService to include 'sleep' in the production attributes.
- Enhanced MessagesDialog and ProductionSection components to display the production status and handle branch names.
- Added corresponding translations for 'status', 'sleep', and 'active' in both German and English locale files.
2026-01-14 15:29:53 +01:00

208 lines
7.8 KiB
Vue

<template>
<div class="production-section">
<div v-if="productions && productions.length > 0">
<h4>{{ $t('falukant.branch.production.current') }}</h4>
<table>
<thead>
<tr>
<th>{{ $t('falukant.branch.production.product') }}</th>
<th>{{ $t('falukant.branch.production.quantity') }}</th>
<th>{{ $t('falukant.branch.production.ending') }}</th>
<th>{{ $t('falukant.branch.production.remainingTime') }}</th>
<th>{{ $t('falukant.branch.production.status') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="production in productions" :key="production.id">
<td>{{ $t(`falukant.product.${production.productType.labelTr}`) }}</td>
<td>{{ production.quantity }}</td>
<td>{{ calculateEndDateTime(production.startTimestamp, production.productType.productionTime) }}</td>
<td>{{ production.sleep ? '-' : calculateRemainingTime(production.startTimestamp, production.productType.productionTime) + ' s' }}</td>
<td>
<span v-if="production.sleep" class="production-sleep">{{ $t('falukant.branch.production.sleep') }}</span>
<span v-else>{{ $t('falukant.branch.production.active') }}</span>
</td>
</tr>
</tbody>
</table>
</div>
<div v-if="(!productions || productions.length < 2)">
<div>
<label for="product">{{ $t('falukant.branch.production.selectProduct') }}</label>
<select name="product" id="product" v-model="selectedProduct">
<option v-for="product in products" :key="product.id" :value="product.id">
{{ $t(`falukant.product.${product.labelTr}`) }}
</option>
</select>
</div>
<div>
<label for="quantity">{{ $t('falukant.branch.production.quantity') }}</label>
<input type="number" id="quantity" v-model.number="productionQuantity" min="1" max="200"/>
</div>
<div>
<p>
{{ $t('falukant.branch.production.storageAvailable') }}:
<strong>{{ freeStorage }}</strong>
</p>
<p>{{ $t('falukant.branch.production.cost') }}:
<strong>{{ calculateProductionCost() }}</strong>
</p>
<p>{{ $t('falukant.branch.production.duration') }}:
<strong>{{ calculateProductionDuration(selectedProduct) }}</strong>
</p>
<p>{{ $t('falukant.branch.production.revenue') }}:
<strong>{{ calculateProductionRevenue() }}</strong>
</p>
</div>
<button @click="startProduction" :disabled="!selectedProduct || productionQuantity < 1">
{{ $t('falukant.branch.production.start') }}
</button>
</div>
</div>
</template>
<script>
import apiClient from '@/utils/axios.js';
export default {
name: "ProductionSection",
props: {
branchId: { type: Number, required: true },
products: { type: Array, required: true },
},
data() {
return {
productions: [],
selectedProduct: null,
productionQuantity: 1,
currentTime: Date.now(),
timer: null,
currentStorage: 0,
maxStorage: 0,
};
},
computed: {
freeStorage() {
const diff = this.maxStorage - this.currentStorage;
return diff > 0 ? diff : 0;
},
},
async mounted() {
await this.loadProductions();
await this.loadStorage();
this.timer = setInterval(() => {
this.currentTime = Date.now();
}, 1000);
},
beforeUnmount() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
methods: {
async loadProductions() {
try {
const response = await apiClient.get(`/api/falukant/branches/${this.branchId}`);
this.productions = response.data.productions.sort((a, b) => {
const endTimeA = new Date(a.startTimestamp).getTime() + a.productType.productionTime * 60 * 1000;
const endTimeB = new Date(b.startTimestamp).getTime() + b.productType.productionTime * 60 * 1000;
return endTimeA - endTimeB;
});
} catch (error) {
console.error('Error loading productions:', error);
}
},
async loadStorage() {
try {
const { data } = await apiClient.get(`/api/falukant/storage/${this.branchId}`);
this.currentStorage = data.totalUsedCapacity;
this.maxStorage = data.maxCapacity;
} catch (error) {
console.error('Error loading storage for production section:', error);
}
},
calculateProductionCost() {
if (!this.products) return 0;
const product = this.products.find(p => p.id === this.selectedProduct);
return product ? 6 * product.category * this.productionQuantity : 0;
},
calculateProductionDuration(productId) {
if (!this.products || !productId) return 0;
const product = this.products.find(p => p.id === productId);
if (!product) return 0;
const totalMinutes = product.productionTime * 60;
return (totalMinutes / 60).toFixed(2).replace('.', ':');
},
calculateProductionRevenue() {
if (!this.selectedProduct || !this.products) return 0;
const product = this.products.find(p => p.id === this.selectedProduct);
if (!product) return 0;
const revenue = this.calculateProductRevenue(product).absolute * this.productionQuantity;
return revenue.toFixed(2).toLocaleString();
},
calculateEndDateTime(startTimestamp, productionTime) {
const start = new Date(startTimestamp);
const end = new Date(start.getTime() + productionTime * 60 * 1000);
return end.toLocaleString();
},
calculateRemainingTime(startTimestamp, productionTime) {
const start = new Date(startTimestamp).getTime();
const end = start + productionTime * 60 * 1000;
const secondsLeft = Math.max(Math.floor((end - this.currentTime) / 1000), 0);
return secondsLeft;
},
async startProduction() {
if (this.selectedProduct && this.productionQuantity > 0) {
this.productionQuantity = Math.min(this.productionQuantity, 200);
let productionQuantity = this.productionQuantity;
while (productionQuantity > 0) {
const sendQuantitiy = Math.min(productionQuantity, 100);
productionQuantity -= sendQuantitiy;
try {
await apiClient.post(`/api/falukant/production`, {
branchId: this.branchId,
productId: this.selectedProduct,
quantity: sendQuantitiy,
});
this.loadProductions();
} catch (error) {
alert(this.$t(`falukant.branch.production.error${error.response.data.error}`));
}
}
}
},
calculateProductRevenue(product) {
if (!product.knowledges || product.knowledges.length === 0) {
return { absolute: 0, perMinute: 0 };
}
const knowledgeFactor = product.knowledges[0].knowledge || 0;
const maxPrice = product.sellCost;
const minPrice = maxPrice * 0.6;
const revenuePerUnit = minPrice + (maxPrice - minPrice) * (knowledgeFactor / 100);
const perMinute = product.productionTime > 0 ? revenuePerUnit / product.productionTime : 0;
return {
absolute: revenuePerUnit.toFixed(2),
perMinute: perMinute.toFixed(2),
};
},
},
};
</script>
<style scoped>
.production-section {
border: 1px solid #ccc;
margin: 10px 0;
border-radius: 4px;
padding: 10px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 8px;
border: 1px solid #ddd;
}
</style>