repairs: тип масла в блоке замены (двигатель/вариатор/АКПП)

Для отчётов СТО по замене масла (задача 4078) нужно различать двигатель и
трансмиссию. В блоке «Замена масла» добавлен выбор типа oil_type
(engine|cvt|akpp) и он уходит в payload create. Для вариатора/АКПП поле
«следующая через (км)» скрыто — интервал задаётся по модели в отчёте СТО.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-29 13:12:08 +10:00
co-authored by Claude Opus 4.8
parent a5bd7308b5
commit 3c27b794dd
2 changed files with 45 additions and 11 deletions
@@ -61,6 +61,7 @@ export interface CreateOilChangePayload {
enabled: boolean;
mileage_at_change: number | null;
next_in_km: number;
oil_type: string; // engine | cvt | akpp
sticker_photo_uuid: string | null;
sticker_extension: string | null;
}
@@ -61,11 +61,14 @@ interface PartRow {
qty: number;
}
type OilKind = "engine" | "cvt" | "akpp";
interface OilChangeState {
enabled: boolean;
mileage_at_change: number | null;
mileage_is_dirty: boolean; // У24: мягкая подписка с шапочным
next_in_km: number;
oil_type: OilKind;
sticker: PhotoState | null;
}
@@ -98,6 +101,7 @@ export default function CreateRepairPage() {
mileage_at_change: null,
mileage_is_dirty: false,
next_in_km: 10000,
oil_type: "engine",
sticker: null,
});
@@ -302,6 +306,7 @@ export default function CreateRepairPage() {
enabled: true,
mileage_at_change: oilChange.mileage_at_change,
next_in_km: oilChange.next_in_km,
oil_type: oilChange.oil_type,
sticker_photo_uuid:
oilChange.sticker?.status === "uploaded"
? oilChange.sticker.presign.photo_uuid
@@ -579,6 +584,27 @@ export default function CreateRepairPage() {
</label>
{oilChange.enabled && (
<div className="mt-3 space-y-3">
<div>
<Label className="text-sm">Тип масла</Label>
<div className="mt-1 grid grid-cols-3 gap-2">
{([["engine", "Двигатель"], ["cvt", "Вариатор"], ["akpp", "АКПП"]] as [OilKind, string][]).map(
([v, l]) => (
<button
type="button"
key={v}
onClick={() => setOilChange((oc) => ({ ...oc, oil_type: v }))}
className={`rounded-md border px-2 py-2 text-sm ${
oilChange.oil_type === v
? "border-primary bg-primary/10 font-medium text-primary"
: "border-input"
}`}
>
{l}
</button>
),
)}
</div>
</div>
<div>
<Label className="text-sm">Пробег на момент замены</Label>
<Input
@@ -594,17 +620,24 @@ export default function CreateRepairPage() {
}
/>
</div>
<div>
<Label className="text-sm">Следующая замена через (км)</Label>
<Input
type="number"
min={0}
value={oilChange.next_in_km}
onChange={(e) =>
setOilChange((oc) => ({ ...oc, next_in_km: Number(e.target.value) || 0 }))
}
/>
</div>
{oilChange.oil_type === "engine" ? (
<div>
<Label className="text-sm">Следующая замена через (км)</Label>
<Input
type="number"
min={0}
value={oilChange.next_in_km}
onChange={(e) =>
setOilChange((oc) => ({ ...oc, next_in_km: Number(e.target.value) || 0 }))
}
/>
</div>
) : (
<p className="text-xs text-muted-foreground">
Интервал {oilChange.oil_type === "cvt" ? "вариатора" : "АКПП"} задаётся по модели авто в
отчёте СТО.
</p>
)}
<div>
<Label className="text-sm">Фото стикера (одно)</Label>
<label className="mt-1 block border-2 border-dashed rounded-md p-4 text-center cursor-pointer hover:bg-accent/40">