Files
service-finder/plans/p0_vehicle_card_fix_plan.md
2026-06-23 21:11:21 +00:00

276 lines
11 KiB
Markdown

# P0 Végrehajtási Terv: Vehicle Components & Modal Javítások
**Státusz:** Tervezés alatt
**Dátum:** 2026-06-21
**Architect:** Rendszer-Architect
---
## 1. Áttekintés
A P0 feladat a meglévő jármű komponensek 4 problémás területének javítása az Architect modul elemzése alapján. A terv 3 fájl módosítását írja elő, új komponensek létrehozása NÉLKÜL.
### Érintett fájlok:
| # | Fájl | Művelet | Hatás |
|---|------|---------|-------|
| 1 | `frontend/src/types/vehicle.ts` | `image_url` mező hozzáadása a `VehicleData` interfészhez | Type safety |
| 2 | `frontend/src/components/vehicle/VehicleCardStandard.vue` | 5 adatkötés javítás | UI adatok helyes megjelenítése |
| 3 | `frontend/src/components/vehicle/VehicleDetailModal.vue` | 5. tab (TechData) integráció + Pénzügyek tab bővítés | Teljes TCO láthatóság |
---
## 2. Részletes Módosítási Terv
### 2.1 `VehicleData` típus bővítése
**Fájl:** [`frontend/src/types/vehicle.ts`](frontend/src/types/vehicle.ts:10)
```typescript
export interface VehicleData {
// ... existing fields ...
image_url?: string | null; // ÚJ mező a kép URL tárolására
}
```
**Indoklás:** A `VehicleCardStandard.vue` `:src="vehicle.image_url"`-t használna, de a `VehicleData` interfészből hiányzik ez a mező. A backend már visszaadhat `image_url`-t az `AssetResponse`-ben (lásd [`assets.py:386`](backend/app/api/v1/endpoints/assets.py:386)).
---
### 2.2 `VehicleCardStandard.vue` - 5 adatkötés javítás
**Fájl:** [`frontend/src/components/vehicle/VehicleCardStandard.vue`](frontend/src/components/vehicle/VehicleCardStandard.vue)
| # | Probléma | Javítás | Sor |
|---|----------|---------|-----|
| 1 | `is_primary` csillag gomb (megvan, de nincs szöveges badge) | **Nem változtatunk** - a meglévő star toggle működik, a feladat csak a data bindings-okról szól | 119-131 |
| 2 | `color` mező: `vehicle.individual_equipment?.color \|\| vehicle.color \|\| '—'` | Lecserélés erre: `vehicle.individual_equipment?.color \|\| 'N/A'` | 103 |
| 3 | `engine` mező: `vehicle.engine \|\| vehicle.fuel_type \|\| '—'` | Lecserélés erre: `` `${vehicle.power_kw || '?'} kW / ${vehicle.engine_capacity || '?'} cm³` `` | 95 |
| 4 | `country_code` mező: `vehicle.countryCode \|\| vehicle.country_code` | **Hozzáadás** `registration_country` használatával | 62 |
| 5 | `image` mező: `vehicle.image` | Lecserélés `vehicle.image_url`-re, fallback SVG placeholder | 9-10 |
**Részletes módosítások:**
**2.2.a - Image (9-10. sor):**
```html
<img v-if="vehicle.image_url" :src="vehicle.image_url" alt="" class="..." />
<template v-else>
<svg ... ></svg> <!-- Meglévő placeholder SVG változatlan -->
</template>
```
**2.2.b - Country (62. sor):**
```html
<span class="...">{{ vehicle.registration_country || vehicle.countryCode || vehicle.country_code || '—' }}</span>
```
**2.2.c - Engine (95. sor):**
```html
<span class="...">{{ vehicle.power_kw ? vehicle.power_kw + ' kW' : '?' }} / {{ vehicle.engine_capacity ? vehicle.engine_capacity + ' cm³' : '?' }}</span>
```
**2.2.d - Color (103. sor):**
```html
<span class="...">{{ vehicle.individual_equipment?.color || 'N/A' }}</span>
```
---
### 2.3 `VehicleDetailModal.vue` - TechData Tab integráció
**Fájl:** [`frontend/src/components/vehicle/VehicleDetailModal.vue`](frontend/src/components/vehicle/VehicleDetailModal.vue)
#### Háttér
A [`TechDataTab.vue`](frontend/src/components/vehicles/tabs/TechDataTab.vue) LÉTEZIK (279 sor), de **NINCS integrálva** a modálba. Jelenleg 4 tab van (`basics`, `finance`, `alerts`, `servicebook`).
#### Megoldás: 5. tab hozzáadása
**a) Tab gomb hozzáadása (a meglévő tab gombok után, ~866-873. sor):**
```html
<button @click="activeTab = 'techdata'" :class="activeTab === 'techdata' ? '...' : '...'">
{{ $t('vehicle.techData') || 'Műszaki adatok' }}
</button>
```
**b) Tab content blokk hozzáadása (a servicebook tab után, ~736. sor után):**
```html
<div v-if="activeTab === 'techdata'" class="space-y-5">
<TechDataTab />
</div>
```
**c) Import hozzáadása (script section):**
```typescript
import TechDataTab from '@/components/vehicles/tabs/TechDataTab.vue';
```
**d) `provide/inject` kompatibilitás biztosítása:**
A [`TechDataTab.vue`](frontend/src/components/vehicles/tabs/TechDataTab.vue:107) `inject<computed<Vehicle | null>>('vehicle')`-t használ. A `VehicleDetailModal.vue`-ban a `vehicle` computed property már létezik. A provide-ot a modal szülőjének (vagy a modal-nak magának) kell biztosítania.
**Megvizsgálandó:** A `VehicleDetailModal.vue` jelenleg `props`-on keresztül kapja a vehicle adatokat. Ha a `TechDataTab.vue` `inject('vehicle')`-t vár, akkor vagy:
- Biztosítani kell a `provide('vehicle', computed(...))`-t a modalban, VAGY
- Át kell alakítani a TechDataTab-et, hogy elfogadjon egy prop-ot is.
**Ajánlás:** Mivel a [`OverviewTab.vue`](frontend/src/components/vehicles/tabs/OverviewTab.vue) is ugyanezt az `inject`-es mintát használja, a legegyszerűbb megoldás a `provide` hozzáadása a `VehicleDetailModal.vue`-hoz:
```typescript
// A script setup blokkban
import { provide, computed } from 'vue';
const vehicle = computed(() => props.vehicle || null);
provide('vehicle', vehicle);
```
---
### 2.4 `VehicleDetailModal.vue` - Pénzügyek Tab bővítés
#### Jelenlegi állapot
A `finance` tab (282-436. sor) csak `GET /assets/{id}/costs`-t hív (944-957. sor) és két részből áll: non-premium esetén egyszerű lista, premium esetén chart.
#### Bővítés: 3 új API hívás párhuzamosan
**Backend endpointok (már léteznek, VERIFIKÁLVA):**
| Endpoint | Visszatérési típus | Helye |
|----------|-------------------|-------|
| `GET /api/v1/assets/vehicles/{id}/financials` | `AssetFinancialsResponse` | [`assets.py:1245`](backend/app/api/v1/endpoints/assets.py:1245) |
| `GET /api/v1/assets/vehicles/{id}/insurance` | `List[VehicleInsurancePolicyResponse]` | [`assets.py:1314`](backend/app/api/v1/endpoints/assets.py:1314) |
| `GET /api/v1/assets/vehicles/{id}/tax` | `List[VehicleTaxObligationResponse]` | [`assets.py:1376`](backend/app/api/v1/endpoints/assets.py:1376) |
**Store metódusok (már léteznek, VERIFIKÁLVA):**
| Metódus | Param | Visszatérés |
|---------|-------|-------------|
| `fetchAssetFinancials(assetId)` | `string` | `Promise<AssetFinancials \| null>` | [`vehicle.ts:318`](frontend/src/stores/vehicle.ts:318) |
| `fetchInsurancePolicies(assetId)` | `string` | `Promise<VehicleInsurancePolicy[]>` | [`vehicle.ts:346`](frontend/src/stores/vehicle.ts:346) |
| `fetchTaxObligations(assetId)` | `string` | `Promise<VehicleTaxObligation[]>` | [`vehicle.ts:388`](frontend/src/stores/vehicle.ts:388) |
#### Tervezett módosítások a `VehicleDetailModal.vue`-ban:
**a) Új state változók (script setup):**
```typescript
const assetFinancials = ref<AssetFinancials | null>(null);
const insurancePolicies = ref<VehicleInsurancePolicy[]>([]);
const taxObligations = ref<VehicleTaxObligation[]>([]);
const financeLoading = ref(false);
```
**b) Párhuzamos API hívás a `loadFinanceData` függvényben (~944. sor környékén):**
```typescript
async function loadFinanceData() {
financeLoading.value = true;
try {
const vehicleId = props.vehicle?.id?.toString();
if (!vehicleId) return;
// Promise.all a 3 új híváshoz
const [financials, policies, taxes] = await Promise.all([
vehicleStore.fetchAssetFinancials(vehicleId),
vehicleStore.fetchInsurancePolicies(vehicleId),
vehicleStore.fetchTaxObligations(vehicleId),
]);
assetFinancials.value = financials;
insurancePolicies.value = policies;
taxObligations.value = taxes;
// Meglévő costs betöltés változatlan
await loadCosts();
} catch (err) {
console.error('Failed to load finance data:', err);
} finally {
financeLoading.value = false;
}
}
```
**c) Template bővítés - új szekciók a meglévő "Költségek" szekció ELÉ:**
```html
<div v-if="activeTab === 'finance'" class="space-y-5">
<!-- 1. ÚJ: Beszerzés & Lízing szekció -->
<div v-if="assetFinancials" class="...">
<h3>{{ $t('vehicle.financials.title') }}</h3>
<div class="grid grid-cols-2 gap-3">
<div>...purchase_price...</div>
<div>...leasing...residual_value...</div>
</div>
</div>
<!-- 2. ÚJ: Biztosítások szekció -->
<div v-if="insurancePolicies.length" class="...">
<h3>{{ $t('vehicle.insurance.title') }}</h3>
<div v-for="policy in insurancePolicies" :key="policy.id">
{{ policy.insurance_type }} - {{ policy.premium_amount }} - {{ policy.expiry_date }}
</div>
</div>
<!-- 3. ÚJ: Adók szekció -->
<div v-if="taxObligations.length" class="...">
<h3>{{ $t('vehicle.tax.title') }}</h3>
<div v-for="tax in taxObligations" :key="tax.id">
{{ tax.tax_type }} - {{ tax.amount }} - {{ tax.payment_status }}
</div>
</div>
<!-- 4. MEGLÉVŐ: Költségek szekció (változatlan) -->
<div v-if="!costsLoading">
<!-- ... existing costs content ... -->
</div>
</div>
```
**d) Importok hozzáadása:**
```typescript
import type { AssetFinancials, VehicleInsurancePolicy, VehicleTaxObligation } from '@/types/vehicle';
```
---
## 3. Függőségi Térkép
```mermaid
graph TD
A[vehicle.ts - VehicleData] -->|image_url mező| B[VehicleCardStandard.vue]
A -->|Vehicle típus| C[VehicleDetailModal.vue]
C -->|provide vehicle| D[TechDataTab.vue]
C -->|Promise.all| E[vehicleStore: fetchAssetFinancials]
C -->|Promise.all| F[vehicleStore: fetchInsurancePolicies]
C -->|Promise.all| G[vehicleStore: fetchTaxObligations]
E --> H[assets.py: GET /vehicles/{id}/financials]
F --> I[assets.py: GET /vehicles/{id}/insurance]
G --> J[assets.py: GET /vehicles/{id}/tax]
```
---
## 4. Végrehajtási Sorrend
| Lépés | Fájl | Művelet | Függőség |
|-------|------|---------|----------|
| 1 | `types/vehicle.ts` | `image_url` hozzáadása | Nincs |
| 2 | `VehicleCardStandard.vue` | 5 data binding javítás | 1. lépés (`image_url`) |
| 3 | `VehicleDetailModal.vue` | TechData tab + provide hozzáadás | Nincs |
| 4 | `VehicleDetailModal.vue` | Finance tab bővítés (Promise.all) | Nincs |
| 5 | - | Vite build futtatás | 1-4. lépés |
---
## 5. Kockázatok és Megjegyzések
1. **TechDataTab inject függőség:** Ha a `provide` nem működik a modalban (pl. scope issue), alternatív megoldás a `TechDataTab.vue` átírása prop-alapúra. Ez azonban többletkockázat, ezért először a `provide`-os megoldást próbáljuk.
2. **`FinancialsTab.vue` átvételének elvetése:** A `FinancialsTab.vue` (709 sor) már tartalmazza a 3 API hívást, de sötét témát (bg-slate-900) használ, ami nem kompatibilis a modal világos témájával. A kód lemásolása helyett a logikát közvetlenül a `VehicleDetailModal.vue`-ba építjük be.
3. **Nincs Compact variáns:** A keresés nem talált Compact változatot, így csak a Standard kártyát kell javítani.
4. **i18n kulcsok:** A `hu.ts` és `en.ts` fájlokba új fordítási kulcsokat kell felvenni (pl. `vehicle.financials.title`, `vehicle.insurance.title`, `vehicle.tax.title`, `vehicle.techData`).
---
## 6. Jóváhagyás
**Architect:** ✅ Terv elkészítve
**Fejlesztő:** ⏳ Jóváhagyásra vár
A terv végrehajtásához **Code módba** kell váltani.