Add Falukant region and transport management features

- Implemented new endpoints in AdminController for managing Falukant regions, including fetching, updating, and deleting region distances.
- Enhanced the FalukantService with methods for retrieving region distances and handling upsert operations.
- Updated the router to expose new routes for region management and transport creation.
- Introduced a transport management interface in the frontend, allowing users to create and manage transports between branches.
- Added localization for new transport-related terms and improved the vehicle management interface to include transport options.
- Enhanced the database initialization logic to support new region and transport models.
This commit is contained in:
Torsten Schulz (local)
2025-11-26 16:44:27 +01:00
parent 29dd7ec80c
commit 06ea259dc9
27 changed files with 2100 additions and 57 deletions

View File

@@ -29,7 +29,13 @@
<!-- Inventar / Verkauf -->
<div v-else-if="activeTab === 'inventory'" class="branch-tab-pane">
<SaleSection :branchId="selectedBranch.id" ref="saleSection" />
<SaleSection
:branchId="selectedBranch.id"
:vehicles="vehicles"
:branches="branches"
ref="saleSection"
@transportCreated="handleTransportCreated"
/>
</div>
<!-- Produktion + Produkt-Erträge -->
@@ -58,6 +64,48 @@
<button @click="openBuyVehicleDialog">
{{ $t('falukant.branch.transport.buy') }}
</button>
<div class="vehicle-overview" v-if="vehicles && vehicles.length">
<table class="vehicle-table">
<thead>
<tr>
<th>{{ $t('falukant.branch.transport.table.type') }}</th>
<th>{{ $t('falukant.branch.transport.table.capacity') }}</th>
<th>{{ $t('falukant.branch.transport.table.condition') }}</th>
<th>{{ $t('falukant.branch.transport.table.mode') }}</th>
<th>{{ $t('falukant.branch.transport.table.speed') }}</th>
<th>{{ $t('falukant.branch.transport.table.availableFrom') }}</th>
<th>{{ $t('falukant.branch.transport.table.status') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="v in vehicles" :key="v.id">
<td>
{{ $t(`falukant.branch.vehicles.${v.type.tr}`) }}
</td>
<td>{{ v.type.capacity }}</td>
<td>{{ conditionLabel(v.condition) }}</td>
<td>{{ v.type.transportMode }}</td>
<td>{{ v.type.speed }}</td>
<td>{{ formatDateTime(v.availableFrom) }}</td>
<td>
<span v-if="v.status === 'travelling'">
{{ $t('falukant.branch.transport.status.inUse') }}
</span>
<span v-else-if="v.status === 'building'">
{{ $t('falukant.branch.transport.status.building') }}
</span>
<span v-else>
{{ $t('falukant.branch.transport.status.free') }}
</span>
</td>
</tr>
</tbody>
</table>
</div>
<p v-else class="no-vehicles">
{{ $t('falukant.branch.transport.noVehicles') }}
</p>
</div>
</div>
<BuyVehicleDialog
@@ -102,6 +150,7 @@ export default {
branches: [],
selectedBranch: null,
products: [],
vehicles: [],
activeTab: 'production',
tabs: [
{ value: 'production', label: 'falukant.branch.tabs.production' },
@@ -175,6 +224,7 @@ export default {
regionId: branch.regionId,
cityName: branch.region.name,
type: this.$t(`falukant.branch.types.${branch.branchType.labelTr}`),
branchTypeLabelTr: branch.branchType.labelTr,
isMainBranch: branch.isMainBranch,
}));
if (!this.selectedBranch) {
@@ -197,9 +247,11 @@ export default {
async onBranchSelected(newBranch) {
this.selectedBranch = newBranch;
await this.loadProducts();
await this.loadVehicles();
this.$nextTick(() => {
this.$refs.directorInfo?.refresh();
this.$refs.saleSection?.loadInventory();
this.$refs.saleSection?.loadTransports();
this.$refs.productionSection?.loadProductions();
this.$refs.storageSection?.loadStorageData();
this.$refs.revenueSection?.refresh && this.$refs.revenueSection.refresh();
@@ -226,14 +278,21 @@ export default {
}
},
upgradeBranch() {
if (this.selectedBranch) {
alert(
this.$t(
'falukant.branch.actions.upgradeAlert',
{ branchId: this.selectedBranch.id }
)
);
async upgradeBranch() {
if (!this.selectedBranch) return;
try {
await apiClient.post('/api/falukant/branches/upgrade', {
branchId: this.selectedBranch.id,
});
await this.loadBranches();
// Ausgewählten Branch nach dem Upgrade neu setzen
const updated = this.branches.find(b => b.id === this.selectedBranch.id);
if (updated) {
await this.onBranchSelected(updated);
}
} catch (error) {
console.error('Error upgrading branch:', error);
alert(this.$t('falukant.branch.actions.upgradeAlert', { branchId: this.selectedBranch.id }));
}
},
@@ -242,6 +301,9 @@ export default {
if (main && main !== this.selectedBranch) {
this.selectedBranch = main;
}
if (this.selectedBranch) {
this.loadVehicles();
}
if (this.selectedBranch && !this.activeTab) {
this.activeTab = 'director';
}
@@ -280,6 +342,38 @@ export default {
};
},
conditionLabel(value) {
const v = Number(value) || 0;
if (v >= 95) return 'Ausgezeichnet'; // 95100
if (v >= 72) return 'Sehr gut'; // 7294
if (v >= 54) return 'Gut'; // 5471
if (v >= 39) return 'Mäßig'; // 3953
if (v >= 22) return 'Schlecht'; // 2238
if (v >= 6) return 'Sehr schlecht'; // 621
if (v >= 1) return 'Katastrophal'; // 15
return 'Unbekannt';
},
async loadVehicles() {
if (!this.selectedBranch) return;
try {
const { data } = await apiClient.get('/api/falukant/vehicles', {
params: { regionId: this.selectedBranch.regionId },
});
this.vehicles = data || [];
} catch (error) {
console.error('Error loading vehicles:', error);
this.vehicles = [];
}
},
formatDateTime(value) {
if (!value) return '';
const date = new Date(value);
if (Number.isNaN(date.getTime())) return '';
return date.toLocaleString();
},
handleEvent(eventData) {
switch (eventData.event) {
case 'production_ready':
@@ -352,6 +446,12 @@ export default {
handleVehiclesBought() {
// Refresh status bar (for updated money) and potentially other data later
this.$refs.statusBar?.fetchStatus();
this.loadVehicles();
},
handleTransportCreated() {
this.loadVehicles();
this.$refs.storageSection?.loadStorageData();
this.$refs.saleSection?.loadTransports();
},
},
};