Revert "Refactor DirectorInfo and SaleSection components to unify speedLabel logic and remove unnecessary watch properties"

This reverts commit 8c40144734.
This commit is contained in:
Torsten Schulz (local)
2026-02-09 15:56:48 +01:00
parent 9c91d99bed
commit a7688e4ed5
12 changed files with 2245 additions and 515 deletions

View File

@@ -360,6 +360,7 @@ export default {
vehicles: [],
activeTab: 'production',
productPricesCache: {}, // Cache für regionale Preise: { productId: price }
productPricesCacheRegionId: null, // regionId, für die der Cache gültig ist
tabs: [
{ value: 'production', label: 'falukant.branch.tabs.production' },
{ value: 'inventory', label: 'falukant.branch.tabs.inventory' },
@@ -569,30 +570,46 @@ export default {
async loadProductPricesForCurrentBranch() {
if (!this.selectedBranch || !this.selectedBranch.regionId) {
this.productPricesCache = {};
this.productPricesCacheRegionId = null;
return;
}
// Lade Preise für alle Produkte in der aktuellen Region
const prices = {};
for (const product of this.products) {
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 (error) {
console.error(`Error loading price for product ${product.id}:`, error);
// 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);
}
if (this.productPricesCacheRegionId === this.selectedBranch.regionId && Object.keys(this.productPricesCache).length > 0) {
return;
}
try {
const { data } = await apiClient.get('/api/falukant/products/prices-in-region', {
params: {
regionId: this.selectedBranch.regionId
}
});
this.productPricesCache = data.prices || {};
this.productPricesCacheRegionId = this.selectedBranch.regionId;
} catch (error) {
console.error(`Error loading product prices for region ${this.selectedBranch.regionId}:`, error);
// Fallback: Lade Preise einzeln (alte Methode)
console.warn('[BranchView] Falling back to individual product price requests');
const prices = {};
for (const product of this.products) {
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.productPricesCacheRegionId = this.selectedBranch?.regionId ?? null;
}
this.productPricesCache = prices;
},
formatPercent(value) {
@@ -704,13 +721,17 @@ export default {
},
speedLabel(value) {
// Expect numeric speeds 1..4; provide localized labels as fallback to raw value
const key = value == null ? 'unknown' : String(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);
// If translation returns the key (no translation found), fall back to the numeric value
if (!translated || translated === tKey) return value;
return translated;
return (!translated || translated === tKey) ? key : translated;
},
transportModeLabel(mode) {

View File

@@ -25,7 +25,7 @@
</tr>
<tr>
<td>{{ $t('falukant.family.spouse.mood') }}</td>
<td>{{ $t(`falukant.mood.${relationships[0].character2.mood.tr}`) }}</td>
<td>{{ relationships[0].character2.mood?.tr ? $t(`falukant.mood.${relationships[0].character2.mood.tr}`) : '—' }}</td>
</tr>
<tr>
<td>{{ $t('falukant.family.spouse.status') }}</td>

View File

@@ -9,6 +9,12 @@
<button @click="fetchMoneyHistory(1)">{{ $t('falukant.moneyHistory.search') }}</button>
</div>
<div class="graph-section">
<button @click="openGraphDialog">
{{ $t('falukant.moneyHistory.graph.open') }}
</button>
</div>
<table>
<thead>
<tr>
@@ -42,17 +48,21 @@
{{ $t('falukant.moneyHistory.next') }}
</button>
</div>
<MoneyHistoryGraphDialog ref="graphDialog" />
</div>
</template>
<script>
import StatusBar from '@/components/falukant/StatusBar.vue'
import MoneyHistoryGraphDialog from '@/dialogues/falukant/MoneyHistoryGraphDialog.vue'
import apiClient from '@/utils/axios.js';
export default {
name: 'MoneyHistoryView',
components: {
StatusBar,
MoneyHistoryGraphDialog,
},
computed: {
locale() {
@@ -97,6 +107,9 @@ export default {
}
return translation !== key ? translation : activity;
},
openGraphDialog() {
this.$refs.graphDialog.open();
},
},
};
</script>
@@ -106,6 +119,10 @@ export default {
margin-bottom: 1rem;
}
.graph-section {
margin-bottom: 1rem;
}
table {
width: 100%;
border-collapse: collapse;

View File

@@ -23,7 +23,7 @@
</tr>
</thead>
<tbody>
<tr v-for="pos in currentPositions" :key="pos.id">
<tr v-for="pos in currentPositions" :key="pos.id" :class="{ 'own-position': isOwnPosition(pos) }">
<td>{{ $t(`falukant.politics.offices.${pos.officeType.name}`) }}</td>
<td>{{ pos.region.name }}</td>
<td>
@@ -57,6 +57,7 @@
<!-- OPEN Tab: hier zeigen wir 'openPolitics' -->
<div v-else-if="activeTab === 'openPolitics'" class="tab-pane">
<p class="politics-age-requirement">{{ $t('falukant.politics.open.ageRequirement') }}</p>
<div v-if="loading.openPolitics" class="loading">{{ $t('loading') }}</div>
<div v-else class="table-scroll">
<table class="politics-table">
@@ -65,7 +66,7 @@
<th>{{ $t('falukant.politics.open.office') }}</th>
<th>{{ $t('falukant.politics.open.region') }}</th>
<th>{{ $t('falukant.politics.open.date') }}</th>
<th>{{ $t('falukant.politics.open.candidacy') }}</th>
<th>{{ $t('falukant.politics.open.candidacyWithAge') }}</th>
</tr>
</thead>
<tbody>
@@ -74,13 +75,13 @@
<td>{{ e.region.name }}</td>
<td>{{ formatDate(e.date) }}</td>
<!-- Checkbox ganz am Ende -->
<td>
<td :title="e.canApplyByAge === false ? $t('falukant.politics.open.minAgeHint') : null">
<input
type="checkbox"
:id="`apply-${e.id}`"
v-model="selectedApplications"
:value="e.id"
:disabled="e.alreadyApplied"
:disabled="e.alreadyApplied || e.canApplyByAge === false"
/>
</td>
</tr>
@@ -193,6 +194,7 @@ export default {
elections: [],
selectedCandidates: {},
selectedApplications: [],
ownCharacterId: null,
loading: {
current: false,
openPolitics: false,
@@ -210,6 +212,7 @@ export default {
}
},
mounted() {
this.loadOwnCharacterId();
this.loadCurrentPositions();
},
methods: {
@@ -229,9 +232,12 @@ export default {
this.loading.current = true;
try {
const { data } = await apiClient.get('/api/falukant/politics/overview');
console.log('[PoliticsView] loadCurrentPositions - API response:', data);
console.log('[PoliticsView] loadCurrentPositions - ownCharacterId at load time:', this.ownCharacterId);
this.currentPositions = data;
console.log('[PoliticsView] loadCurrentPositions - Loaded', data.length, 'positions');
} catch (err) {
console.error('Error loading current positions', err);
console.error('[PoliticsView] Error loading current positions', err);
} finally {
this.loading.current = false;
}
@@ -241,10 +247,10 @@ export default {
this.loading.openPolitics = true;
try {
const { data } = await apiClient.get('/api/falukant/politics/open');
this.openPolitics = data;
this.openPolitics = Array.isArray(data) ? data : [];
// Bereits beworbene Positionen vorselektieren, damit die Checkbox
// sichtbar markiert bleibt.
this.selectedApplications = data
this.selectedApplications = this.openPolitics
.filter(e => e.alreadyApplied)
.map(e => e.id);
} catch (err) {
@@ -330,6 +336,44 @@ export default {
});
},
async loadOwnCharacterId() {
try {
const { data } = await apiClient.get('/api/falukant/info');
console.log('[PoliticsView] loadOwnCharacterId - API response:', data);
console.log('[PoliticsView] loadOwnCharacterId - data.character:', data.character);
console.log('[PoliticsView] loadOwnCharacterId - data.character?.id:', data.character?.id);
if (data.character && data.character.id) {
this.ownCharacterId = data.character.id;
console.log('[PoliticsView] loadOwnCharacterId - Set ownCharacterId to:', this.ownCharacterId);
} else {
console.warn('[PoliticsView] loadOwnCharacterId - No character ID found in response', {
hasCharacter: !!data.character,
characterKeys: data.character ? Object.keys(data.character) : null,
characterId: data.character?.id
});
}
} catch (err) {
console.error('[PoliticsView] Error loading own character ID', err);
}
},
isOwnPosition(pos) {
console.log('[PoliticsView] isOwnPosition - Checking position:', {
posId: pos.id,
posCharacter: pos.character,
posCharacterId: pos.character?.id,
ownCharacterId: this.ownCharacterId,
match: pos.character?.id === this.ownCharacterId
});
if (!this.ownCharacterId || !pos.character) {
console.log('[PoliticsView] isOwnPosition - Returning false (missing ownCharacterId or pos.character)');
return false;
}
const isMatch = pos.character.id === this.ownCharacterId;
console.log('[PoliticsView] isOwnPosition - Result:', isMatch);
return isMatch;
},
async submitApplications() {
try {
const response = await apiClient.post(
@@ -346,6 +390,10 @@ export default {
.map(e => e.id);
} catch (err) {
console.error('Error submitting applications', err);
const msg = err?.response?.data?.error === 'too_young'
? this.$t('falukant.politics.too_young')
: (err?.response?.data?.error || err?.message || this.$t('falukant.politics.applyError'));
this.$root.$refs?.messageDialog?.open?.(msg, this.$t('falukant.politics.title'));
}
}
}
@@ -384,6 +432,13 @@ h2 {
overflow: hidden;
}
.politics-age-requirement {
flex: 0 0 auto;
margin: 0 0 10px 0;
font-size: 0.95em;
color: #555;
}
.table-scroll {
flex: 1;
overflow-y: auto;
@@ -411,6 +466,11 @@ h2 {
border: 1px solid #ddd;
}
.politics-table tbody tr.own-position {
background-color: #e0e0e0;
font-weight: bold;
}
.loading {
text-align: center;
font-style: italic;