diff --git a/mechanic-pwa/frontend/src/api/repairsCreate.ts b/mechanic-pwa/frontend/src/api/repairsCreate.ts index 4524ab6..2d56f3c 100644 --- a/mechanic-pwa/frontend/src/api/repairsCreate.ts +++ b/mechanic-pwa/frontend/src/api/repairsCreate.ts @@ -72,7 +72,8 @@ export interface CreateRepairPayload { works: CreateWorkPayload[]; parts: CreatePartPayload[]; photos: CreatePhotoPayload[]; - oil_change: CreateOilChangePayload | null; + // 1:N — за один заезд бывает несколько замен (двигатель + коробка). + oil_changes: CreateOilChangePayload[]; } export interface CreateRepairResponse { diff --git a/mechanic-pwa/frontend/src/pages/repairs/CreateRepairPage.tsx b/mechanic-pwa/frontend/src/pages/repairs/CreateRepairPage.tsx index ca129b6..54130d4 100644 --- a/mechanic-pwa/frontend/src/pages/repairs/CreateRepairPage.tsx +++ b/mechanic-pwa/frontend/src/pages/repairs/CreateRepairPage.tsx @@ -61,14 +61,13 @@ interface PartRow { qty: number; } -type OilKind = "engine" | "cvt" | "akpp"; - interface OilChangeState { enabled: boolean; - mileage_at_change: number | null; + mileage_at_change: number | null; // общий одометр — один на все замены заезда mileage_is_dirty: boolean; // У24: мягкая подписка с шапочным - next_in_km: number; - oil_type: OilKind; + next_in_km: number; // интервал двигателя + // Какие масла меняли за заезд (можно оба сразу): + types: { engine: boolean; transmission: boolean }; sticker: PhotoState | null; } @@ -101,7 +100,7 @@ export default function CreateRepairPage() { mileage_at_change: null, mileage_is_dirty: false, next_in_km: 10000, - oil_type: "engine", + types: { engine: true, transmission: false }, sticker: null, }); @@ -272,6 +271,8 @@ export default function CreateRepairPage() { if (works.length === 0) return "Добавьте хотя бы одну работу"; const unlockedNoComment = works.find((w) => w.unlocked && !w.override_comment.trim()); if (unlockedNoComment) return "Укажите комментарий к ручной правке цены"; + if (oilChange.enabled && !oilChange.types.engine && !oilChange.types.transmission) + return "Выберите тип масла (двигатель и/или коробка) или снимите «Была замена масла»"; return ""; }; @@ -301,22 +302,25 @@ export default function CreateRepairPage() { })), parts: parts.map((p) => ({ name: p.name, qty: p.qty })), photos: photoPayload, - oil_change: oilChange.enabled - ? { - 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 - : null, - sticker_extension: - oilChange.sticker?.status === "uploaded" - ? oilChange.sticker.presign.extension - : null, - } - : null, + oil_changes: oilChange.enabled + ? (["engine", "transmission"] as const) + .filter((t) => oilChange.types[t]) + .map((t, idx) => ({ + enabled: true, + mileage_at_change: oilChange.mileage_at_change, + next_in_km: t === "engine" ? oilChange.next_in_km : 0, + oil_type: t, + // Стикер прикрепляем к первой выбранной замене (обычно двигатель). + sticker_photo_uuid: + idx === 0 && oilChange.sticker?.status === "uploaded" + ? oilChange.sticker.presign.photo_uuid + : null, + sticker_extension: + idx === 0 && oilChange.sticker?.status === "uploaded" + ? oilChange.sticker.presign.extension + : null, + })) + : [], }, idemKey.current, ); @@ -585,25 +589,34 @@ export default function CreateRepairPage() { {oilChange.enabled && (
Выберите хотя бы один тип масла.
+ )}- Интервал {oilChange.oil_type === "cvt" ? "вариатора" : "АКПП"} задаётся по модели авто в - отчёте СТО. + Интервал коробки задаётся по модели авто в отчёте СТО.
)}